nengo / nengo-loihi

Run Nengo models on Intel's Loihi chip
https://www.nengo.ai/nengo-loihi/
Other
35 stars 12 forks source link

Sparse transforms throw ValueError zero-size array to reduction #245

Closed arvoelke closed 2 years ago

arvoelke commented 4 years ago
import nengo
import nengo_loihi
from nengo.transforms import Sparse

n_neurons = 2
transform = Sparse((n_neurons, n_neurons), [(0, 0)], [1])

with nengo.Network() as model:
    x = nengo.Ensemble(n_neurons, 1)
    y = nengo.Ensemble(n_neurons, 1)
    nengo.Connection(x.neurons, y.neurons, transform=transform)

with nengo_loihi.Simulator(model) as sim:
    pass
---------------------------------------------------------------------------
ValueError                                Traceback (most recent call last)
<ipython-input-29-d937869d3cbc> in <module>()
     11     nengo.Connection(x.neurons, y.neurons, transform=transform)
     12 
---> 13 with nengo_loihi.Simulator(model) as sim:
     14     pass

~/git/nengo-loihi/nengo_loihi/simulator.py in __init__(self, network, dt, seed, model, precompute, target, progress_bar, remove_passthrough, hardware_options)
    144 
    145         # Build the network into the model
--> 146         self.model.build(network)
    147 
    148         # Build the extra passthrough connections into the model

~/git/nengo-loihi/nengo_loihi/builder/builder.py in build(self, obj, *args, **kwargs)
    206             model.seeded[obj] = self.seeded[obj]
    207 
--> 208         built = model.builder.build(model, obj, *args, **kwargs)
    209         if self.build_callback is not None:
    210             self.build_callback(obj)

~/git/nengo/nengo/builder/builder.py in build(cls, model, obj, *args, **kwargs)
    225             raise BuildError("Cannot build object of type %r" % type(obj).__name__)
    226 
--> 227         return cls.builders[obj_cls](model, obj, *args, **kwargs)
    228 
    229     @classmethod

~/git/nengo/nengo/builder/network.py in build_network(model, network, progress)
     92             # TODO: Except perhaps if the connection being learned
     93             # is in a subnetwork?
---> 94             model.build(conn)
     95 
     96         logger.debug("Network step 4: Building probes")

~/git/nengo-loihi/nengo_loihi/builder/builder.py in build(self, obj, *args, **kwargs)
    206             model.seeded[obj] = self.seeded[obj]
    207 
--> 208         built = model.builder.build(model, obj, *args, **kwargs)
    209         if self.build_callback is not None:
    210             self.build_callback(obj)

~/git/nengo/nengo/builder/builder.py in build(cls, model, obj, *args, **kwargs)
    225             raise BuildError("Cannot build object of type %r" % type(obj).__name__)
    226 
--> 227         return cls.builders[obj_cls](model, obj, *args, **kwargs)
    228 
    229     @classmethod

~/git/nengo-loihi/nengo_loihi/builder/connection.py in build_connection(model, conn)
     58 
     59     if pre_onchip and post_onchip:
---> 60         build_chip_connection(model, conn)
     61 
     62     elif not pre_onchip and post_onchip:

~/git/nengo-loihi/nengo_loihi/builder/connection.py in build_chip_connection(model, conn)
    654         gain = model.params[conn.post_obj.ensemble].gain
    655         loihi_weights = scale_matrix(loihi_weights, gain)
--> 656         syn.set_weights(loihi_weights)
    657         post_obj.add_synapse(syn)
    658         model.objs[conn]["weights"] = syn

~/git/nengo-loihi/nengo_loihi/block.py in set_weights(self, weights)
    681         self.format(
    682             compression=d(b"Mw==", int),
--> 683             idx_bits=self.idx_bits(),
    684             fanout_type=d(b"MQ==", int),
    685             n_synapses=d(b"NjM=", int),

~/git/nengo-loihi/nengo_loihi/block.py in idx_bits(self)
    618 
    619     def idx_bits(self):
--> 620         bits = int(np.ceil(np.log2(self.max_ind() + 1)))
    621         assert (
    622             bits <= SynapseConfig.INDEX_BITS_MAP[-1]

~/git/nengo-loihi/nengo_loihi/block.py in max_ind(self)
    632 
    633     def max_ind(self):
--> 634         return max(i.max() if len(i) > 0 else -1 for i in self.indices)
    635 
    636     def _set_weights_indices(self, weights, indices=None):

~/git/nengo-loihi/nengo_loihi/block.py in <genexpr>(.0)
    632 
    633     def max_ind(self):
--> 634         return max(i.max() if len(i) > 0 else -1 for i in self.indices)
    635 
    636     def _set_weights_indices(self, weights, indices=None):

~/.conda/envs/dev/lib/python3.5/site-packages/numpy/core/_methods.py in _amax(a, axis, out, keepdims, initial)
     26 def _amax(a, axis=None, out=None, keepdims=False,
     27           initial=_NoValue):
---> 28     return umr_maximum(a, axis, None, out, keepdims, initial)
     29 
     30 def _amin(a, axis=None, out=None, keepdims=False,

ValueError: zero-size array to reduction operation maximum which has no identity

This occurs for both the emulator and the actual hardware. If I change n_neurons to 1 I get a different error:

---------------------------------------------------------------------------
AssertionError                            Traceback (most recent call last)
<ipython-input-30-bdf99cfd8990> in <module>()
     11     nengo.Connection(x.neurons, y.neurons, transform=transform)
     12 
---> 13 with nengo_loihi.Simulator(model) as sim:
     14     pass

~/git/nengo-loihi/nengo_loihi/simulator.py in __init__(self, network, dt, seed, model, precompute, target, progress_bar, remove_passthrough, hardware_options)
    144 
    145         # Build the network into the model
--> 146         self.model.build(network)
    147 
    148         # Build the extra passthrough connections into the model

~/git/nengo-loihi/nengo_loihi/builder/builder.py in build(self, obj, *args, **kwargs)
    206             model.seeded[obj] = self.seeded[obj]
    207 
--> 208         built = model.builder.build(model, obj, *args, **kwargs)
    209         if self.build_callback is not None:
    210             self.build_callback(obj)

~/git/nengo/nengo/builder/builder.py in build(cls, model, obj, *args, **kwargs)
    225             raise BuildError("Cannot build object of type %r" % type(obj).__name__)
    226 
--> 227         return cls.builders[obj_cls](model, obj, *args, **kwargs)
    228 
    229     @classmethod

~/git/nengo/nengo/builder/network.py in build_network(model, network, progress)
     92             # TODO: Except perhaps if the connection being learned
     93             # is in a subnetwork?
---> 94             model.build(conn)
     95 
     96         logger.debug("Network step 4: Building probes")

~/git/nengo-loihi/nengo_loihi/builder/builder.py in build(self, obj, *args, **kwargs)
    206             model.seeded[obj] = self.seeded[obj]
    207 
--> 208         built = model.builder.build(model, obj, *args, **kwargs)
    209         if self.build_callback is not None:
    210             self.build_callback(obj)

~/git/nengo/nengo/builder/builder.py in build(cls, model, obj, *args, **kwargs)
    225             raise BuildError("Cannot build object of type %r" % type(obj).__name__)
    226 
--> 227         return cls.builders[obj_cls](model, obj, *args, **kwargs)
    228 
    229     @classmethod

~/git/nengo-loihi/nengo_loihi/builder/connection.py in build_connection(model, conn)
     58 
     59     if pre_onchip and post_onchip:
---> 60         build_chip_connection(model, conn)
     61 
     62     elif not pre_onchip and post_onchip:

~/git/nengo-loihi/nengo_loihi/builder/connection.py in build_chip_connection(model, conn)
    654         gain = model.params[conn.post_obj.ensemble].gain
    655         loihi_weights = scale_matrix(loihi_weights, gain)
--> 656         syn.set_weights(loihi_weights)
    657         post_obj.add_synapse(syn)
    658         model.objs[conn]["weights"] = syn

~/git/nengo-loihi/nengo_loihi/block.py in set_weights(self, weights)
    673         else:
    674             weights = np.array(weights, copy=False, dtype=np.float32)
--> 675             assert weights.ndim == 2
    676             indices = None
    677 

AssertionError: 

And if I change the simulator to nengo.Simulator then both work. This is using nengo==3.0.0.dev0 and nengo_loihi==0.9.0.dev0.

hunse commented 4 years ago

It looks like somewhere we're assuming that each neuron has at least one input in the connection. As a workaround, you can add extra values so that each neuron has at least one input synapse (even if the weight is 0).

arvoelke commented 4 years ago

Looks like that works, although instead of exactly 0 it should be something small like 1e-20 -- zeros must be getting removed somewhere. Thanks!

n_neurons = 1000
edge_list = []
weights = []

edge_list.append((0, 0))
weights.append(1)

for i in range(1, n_neurons):
    edge_list.append((0, i))
    weights.append(1e-20)

transform = Sparse((n_neurons, n_neurons), edge_list, weights)
hunse commented 4 years ago

Fixed in #246.

hunse commented 2 years ago

I no longer get this error on master, so closing.