1 / 20

Introducing LEMS-Lite

Introducing LEMS-Lite. An intermediate format for code-generation. Robert Cannon. Executing LEMS models via LEMS-Lite. Familiar old problem Published descriptions of models in neuroscience are almost always inadequate for reproducing results.

imaran
Télécharger la présentation

Introducing LEMS-Lite

An Image/Link below is provided (as is) to download presentation Download Policy: Content on the Website is provided to you AS IS for your information and personal use and may not be sold / licensed / shared on other websites without getting consent from its author. Content is provided to you AS IS for your information and personal use only. Download presentation by click this link. While downloading, if for some reason you are not able to download a presentation, the publisher may have deleted the file from their server. During download, if you can't get a presentation, the file might be deleted by the publisher.

E N D

Presentation Transcript


  1. Introducing LEMS-Lite An intermediate format for code-generation Robert Cannon

  2. Executing LEMS models via LEMS-Lite • Familiar old problem • Published descriptions of models in neuroscience are almost always inadequate for reproducing results. • You can't do much science if you can't analyze, extend, reuse or build upon other people's work. • Familiar old solution • Declarative model descriptions using basic design principles form software engineering: separate logic (equations) from data (parameter values); avoid duplication; think about your design and refactor as needed. • Implemented in LEMS/NeuroML. Related efforts include NineML, SpineML, SBML although these focus more on machine-readability, less on human writeability. Neuroscience-specific definitions Phiysics, Geometry

  3. What next? • How do you execute models? • Map NeuroML/LEMS models to existing tools, such as Neuron. • New simulators designed for the LEMS data model. jLEMS, pyLEMS • Generate code for general purpose compilers. • Generate code for custom hardware.

  4. Why generate code rather than using Neuron, Moose, Genesis, Brian, PSICS etc? • Exploit novel hardware including FPGAs and GPUs • Work with more diverse models • Neuron already involves code generation, Moose relies on custom extensions • Efficiency and memory footprint • Eg integerization of models (Mike Hull) • Why not? • Models are like programs. The obvious thing is to compile them, not just run them on a language simulator. • The alternative view is that models are like data, to be fed into specialist programs. It all depends on the completeness and diversity of your model specifications. • Reaction against nature of existing tools that is perceived as hindering investigation of novel types of model.

  5. LEMS Embeds knowledge of: Physics – dimensionality Geometry – containment, adjacency, trees, 1-D skeleton of 3-D tree Source code for general purpose hardware ? Source code for custom hardware

  6. LEMS Embeds knowledge of: Physics – dimensionality Geometry – containment, adjacency, trees, 1-D skeleton of 3-D tree Single-step code generation embeds a lot of knowledge – physics, geometry, and numerics. We've swapped a monolithic simulator for a monolithic code generator. X Source code for general purpose hardware

  7. Physics Mathematics Stage 1: Remove physics and Geometry. Keep ODEs LEMS Physics – dimensionality Geometry – containment, adjacency, trees, 1-D skeleton of 3-D tree Flat LEMS model Still expressed in LEMS Comparable to NineML Stage 2: Combine with declarative representation of numerics ODEs → update rules Numerical Integration Schemes Euler, RK4, Crank Nicolson etc LEMS-Lite Components, Arrays, Update rules, Connections No geometry No ODEs No neuroscience terms Source code for general purpose hardware Code for custom hardware Computing

  8. <LEMSLite> <DiscreteUpdateComponent name="lif_neuron"> <Interface> <Parameter name="bias"/> <Parameter name="gain"/> <Parameter name="constInput"/> <InputEventPort name="spike-in"> <Parameter name="weight"/> </InputEventPort> <OutputEventPort name="spike-out"/> <Constant name="one_over_rc_float" value="0.0488281"/> <Constant name="ptsc_scale_float" value="0.154279"/> <OutputVariable name="v"/> </Interface> <State> <StateVariable name="v"/> <StateVariable name="inp"/> <StateVariable name="ref"/> </State> <Step> <Var name="total" value="(gain * (inp + constInput)) + bias"/> <Var name="dv" value="(total-v) * one_over_rc_float"/> <Update variable="v" value="v + dv"/> <Update variable="inp" value="inp * (1. - ptsc_scale_float)"/> <Output variable="v" value="v"/> </Step> <OnEvent port="spike-in" > <Update variable="inp" value="inp + weight * one_over rc"/> </OnEvent> <OnCondition if="v .gt. 1.0"> <Update variable="v" value="0"/> <Update variable="ref" value="2"/> <Emit port="spike-out"/> </OnCondition> <OnCondition if="ref .gt. 0"> <Update variable="v" value="0"/> <Update variable="ref" value="ref-1"/> </OnCondition> </DiscreteUpdateComponent> <DataSources> <File name="mh_conv_level0" id="f_params_pop0" format="csv" shape="(5,3000)"/> <Array name="pop0_bias"> <FileSource file="f_params_pop0" column="1"/> </Array> </DataSources> <ComponentArray name="level0" component="lif_neuron" size="3000"> <Let parameter="constInput" array="pop0_constInput"/> <Let parameter="bias" array="pop0_bias"/> <Let parameter="gain" array="pop0_gain"/> <Initialize stateVariable="inp" array="pop0_inp" /> </ComponentArray> <EventConnections name="pop0_to_pop1" from="level0" to="level1"> <EventSource port="spike-out"/> <EventTarget port="spike-in"/> <SourceTargetConnector> <FromArrayConnector pre="conn01_pre" post="conn01_post"/> </SourceTargetConnector> <ConnectionProperties> <Property name="weight" array="conn01_weight"/> <Delay value="0"/> </ConnectionProperties> <EventArguments> <Arg name="weight" value="connection.weight"/> </EventArguments> </EventConnections> <Simulation name="handwriting_simulation" dt="1.0e-3" endTime="0.02"> <OutputFiles> <File id="f_out0_csv" name="f_out1.csv" format="csv"></File> </OutputFiles> <Recording startTime="0" endTime="1" interval="0.1"> <VariableRecording file="f_out0_csv" componentArray="level0" indices="1,2,3" variable="v"/> </Recording> </Simulation> </LEMSLite>

  9. Summary: LEMS-Lite • Acts as a fixed point between the LEMS specification and code generators • LEMS specification can be revised and extended without affecting downstream implementations provided we maintain the mappings to LEMS-Lite • lower-level description that nmodl, NineML etc • Describes the post-discretization version of the model • No ODEs, no neuroscience terminology • Reduces uncertainty about what is to be computed or how equations are to be solved

  10. HiveMind:Providing an efficient programming model for extreme-scale real-time neural network simulation Steven Marsh Supervised by: Dr. Simon Moore Computer Laboratory Computer Architecture Group

  11. From abstract descriptions to working simulators LEMS LEMS-Lite Generator HiveMind LEMS-Lite NeuroML Single Threaded C Parallel C BlueVec OpenCL SpiNNaker

  12. Architecture of the generated system Component Population Connection Mapping Component Updater Component List Connection List Event Emitter Population Updater Event Delay Queue Event Receiver Event Handler

  13. Example architecture Connections B to A LIF Population A Connection List Component List Event Handler LIF Component Connections C to A Connection List Connections A to B IaF Population B Connection List Component List Event Handler IaF Component Connections B to C HH Population C Connection List Component List Event Handler HH Component

  14. Challenges of code generation • Ensuring efficient memory access patterns • Reducing dynamic memory requirements • Architecting in an easy-to-parallelize way • Translation of equations strings to C equivalent • Taking a high-level declarative model into an efficient low-level implementation

  15. LIF Component behaviour (LEMS Lite) <DiscreteUpdateComponent name='lif_neuron'> <Interface> <Parameter name="bias"/> <Parameter name="gain"/> <Parameter name="constInput"/> <InputEventPort name="spike-in"> <Parameter name="weight"/> </InputEventPort> <OutputEventPort name="spike-out"/> <Constant name="one_over_rc_float" value="0.15429"/> <Constant name="dt" value="0.1E-3"/> <OutputVariable name="v"/> </Interface> <State> <StateVariable name="v"/> <StateVariable name="inp"/> <StateVariable name="ref"/> </State> <OnEvent port='spike-in' > <update variable="inp" value="inp + weight * one_over_rc_float"/> </OnEvent> <Step> <var name="total" value="(gain * (inp + constInput)) + bias"/> <var name="dv" value="(total-v) * one_over_rc_float"/> <update variable="v" value="v + dv*dt"/> <update variable="inp" value="inp * (1-one_over_rc_float)"/> <condition_check/> <output variable="v" value="v"/> </Step> <OnCondition if="v .gt. 1.0"> <update variable="v" value="0"/> <update variable="ref" value="2"/> <emit port="spike-out"/> </OnCondition> <OnCondition if="ref .gt. 0"> <update variable="v" value="0"/> <update variable="ref" value="ref-1"/> </OnCondition> </DiscreteUpdateComponent>

  16. LIF Component behaviour (Generated C) lif_neuron_OUTPUT_EVENTupdateComponent_lif_neuron(lif_neuron* component,double*output_v) { // StateVariables double v = component->v; double inp = component->inp; double ref = component->ref; // Parameters double bias = component->bias; double gain = component->gain; double constInput = component->constInput; // Variables double total = (gain * (inp + constInput)) + bias; double dv = (total - v) * one_over_rc_float; // Updates component->v = v + dv * dt; component->inp = inp * (1 - one_over_rc_float); // Conditions lif_neuron_OUTPUT_EVENT STATUS = lif_neuron_NONE; if (component->v > 1.0) { STATUS |= lif_neuron_spike_out; component->v = 0; component->ref = 2; } if (component->ref > 0) { component->v = 0; component->ref = ref - 1; } // Outputs if (output_v != NULL) { *output_v = v; } return STATUS; } void spike_in_lif_neuron(lif_neuron* component, double weight) { component->inp = component->inp + weight * one_over_rc_float; }

  17. ComponentArray declaration (LEMS-Lite) <Datasources> <Array name='pop0_bias’> <FileSource file='f_params_pop0' column='1'/> </Array> <Array name='pop0_gain’> <FileSource file='f_params_pop0' column='2'/> </Array> <Array name='pop0_constInput'> <FileSource file='f_params_pop0' column='3'/> </Array> <Array name='pop0_inp'> <FileSource file='f_params_pop0' column='4'/> </Array> <Datasources/> <ComponentArray name="level0" component="lif_neuron" size="3000"> <let parameter="constInput" array="pop0_constInput"/> <let parameter="bias" array="pop0_bias"/> <let parameter="gain" array="pop0_gain"/> <initialisestate_variable="inp" array="pop0_inp" /> </ComponentArray>

  18. ComponentArray declaration (Generated C) level0_array level0 = { .size=3000, .components={ {.constInput=-3.84473, .bias=10.31933, .inp=-0.00134, .gain=8.7792}, {.constInput=-3.84473, .bias=5.94921, .inp=-0.00134, .gain=1.37988}, {.constInput=-3.84473, .bias=0.63964, .inp=-0.00134, .gain=10.0195}, {.constInput=-3.76855, .bias=10.31933, .inp=-25.93707, .gain=8.7792}, {.constInput=-3.76855, .bias=5.94921, .inp=-25.93707, .gain=1.37988}, {.constInput=-3.76855, .bias=0.63964, .inp=-25.93707, .gain=10.0195}, {.constInput=-19.9043, .bias=10.31933, .inp=7.22445, .gain=8.7792}, … } }

  19. ComponentArray declaration (Generated C) void update_level0_array() { lif_neuron_OUTPUT_EVENTSPIKE_STATUS[3000]; double output_v[3000]; intindex = 0; for(index = 0; index < 3000; index++) { SPIKE_STATUS[index] = updateComponent_lif_neuron(&level0.components[index], &output_v[index]); } recordVariable("level0", "v", output_v, 3000); for (index = 0; index < 3000; index++) { if (SPIKE_STATUS[index] & lif_neuron_spike_out) { pop0_to_pop1_spike_in(index); } } }

  20. Benefits of HiveMind code generation • High-level declarative descriptions • Can be easily generated from existing tools • Allows neuroscientists to focus on neuroscience • Generates C: cross-platform and mature tool-chains • Avoids programming for esoteric systems • Allows static declaration of memory • Minimal yet efficient simulators • Performance comparable to hand-optimized C code

More Related