| | 113 | |
| | 114 | class NemoNetworkPropagate(NetworkOperation): |
| | 115 | def __init__(self, net): |
| | 116 | self.net = net |
| | 117 | self.when = 'after_connections' |
| | 118 | def __call__(self): |
| | 119 | spikes = hstack(self.net.nemo_spikes, dtype=uint32) |
| | 120 | self.net.nemo_spikes = [] |
| | 121 | spikes_ptr = spikes.ctypes.data |
| | 122 | spikes_len = len(spikes) |
| | 123 | exc_ptr, inh_ptr = tuple(self.nemo_sim.propagate(spikes_ptr, spikes_len)) |
| | 124 | N = self.net.total_neurons |
| | 125 | exc = numpy_array_from_memory(exc_ptr, N, float32) |
| | 126 | inh = numpy_array_from_memory(inh_ptr, N, float32) |
| | 127 | for G in self.net.groups: |
| | 128 | target_offset = self.net.group_offset[id(G)] |
| | 129 | #TODO: need to handle different target states with different neurons |
| | 130 | #self.target._S[self.nstate] += exc |
| | 131 | #self.target._S[self.nstate] += inh |
| | 132 | |
| | 133 | class NemoNetworkConnectionPropagate(object): |
| | 134 | def __init__(self, net, source_offset, target_offset): |
| | 135 | set.net = net |
| | 136 | self.source_offset = source_offset |
| | 137 | self.target_offset = target_offset |
| | 138 | def __call__(self, C, spikes): |
| | 139 | self.net.nemo_spikes.append(spikes+self.source_offset) |
| | 140 | |
| | 141 | class NemoNetwork(Network): |
| | 142 | def prepare(self): |
| | 143 | global _created_network |
| | 144 | if _created_network: |
| | 145 | raise NotImplementedError("Current version only supports a single run.") |
| | 146 | _created_network = True |
| | 147 | |
| | 148 | # add a NetworkOperation that will be used to carry out the propagation |
| | 149 | # by NeMo |
| | 150 | nemo_propagate = NemoNetworkPropagate(self) |
| | 151 | self.add(nemo_propagate) |
| | 152 | self.nemo_spikes = [] |
| | 153 | |
| | 154 | Network.prepare(self) |
| | 155 | |
| | 156 | if hasattr(self, 'clocks') and len(self.clocks)>1: |
| | 157 | raise NotImplementedError("Current version only supports a single clock.") |
| | 158 | |
| | 159 | # combine all groups into one meta-group for NeMo, store the offsets |
| | 160 | self.group_offset = group_offset = {} |
| | 161 | self.total_neurons = total_neurons = 0 |
| | 162 | for G in self.groups: |
| | 163 | group_offset[id(G)] = total_neurons |
| | 164 | total_neurons += len(G) |
| | 165 | |
| | 166 | # now upload to nemo |
| | 167 | self.nemo_net = nemo.Network() |
| | 168 | if pycuda is not None: |
| | 169 | self.nemo_use_gpu = False |
| | 170 | log_warn('brian.experimental.cuda.briantonemo', |
| | 171 | 'GPU available but not yet supported, using CPU.') |
| | 172 | else: |
| | 173 | self.nemo_use_gpu = False |
| | 174 | |
| | 175 | # create dummy neurons |
| | 176 | self.nemo_input_neuron_idx = self.nemo_net.add_neuron_type('Input') |
| | 177 | self.nemo_net.add_neuron(self.nemo_input_neuron_idx, |
| | 178 | range(total_neurons)) |
| | 179 | |
| | 180 | # add connections and upload synapses to nemo |
| | 181 | for C in self.connections: |
| | 182 | # check limitations |
| | 183 | if C.__class__ is not DelayConnection: |
| | 184 | raise NotImplementedError("Only DelayConnections supported at the moment.") |
| | 185 | if not isinstance(C.W[0, :], SparseConnectionVector): |
| | 186 | raise NotImplementedError("Current version only supports sparse matrix types.") |
| | 187 | |
| | 188 | source_offset = group_offset[id(C.source)] |
| | 189 | target_offset = group_offset[id(C.target)] |
| | 190 | dt = C.source.clock.dt |
| | 191 | C.propagate = NemoNetworkConnectionPropagate(self, source_offset, |
| | 192 | target_offset) |
| | 193 | # create synapses |
| | 194 | for i in xrange(len(C.source)): |
| | 195 | Wrow = self.W[i, :] |
| | 196 | Wdelay = self.delay[i, :] |
| | 197 | ind = (Wrow.ind+target_offset).tolist() |
| | 198 | delay = asarray(Wdelay/dt, dtype=int).tolist() |
| | 199 | if amax(delay)>=64: |
| | 200 | raise NotImplementedError("Current version of NeMo has a maximum delay of 64 steps.") |
| | 201 | weight = asarray(Wrow, dtype=float32).tolist() |
| | 202 | if len(ind): |
| | 203 | self.nemo_net.add_synapse(i+source_offset, ind, delay, |
| | 204 | weight, False) |
| | 205 | |
| | 206 | # configure |
| | 207 | self.nemo_conf = nemo.Configuration() |
| | 208 | if self.nemo_use_gpu: |
| | 209 | self.nemo_conf.set_cuda_backend(0) |
| | 210 | else: |
| | 211 | self.nemo_conf.set_cpu_backend() |
| | 212 | # simulation object |
| | 213 | self.nemo_sim = nemo.Simulation(self.nemo_net, self.nemo_conf) |