torch.nn.modules.module.ModuleAttributeError: 'Network' object has no attribute 'reset_'

I got an error with the title, do I need to declare it using class?

import torch
import numpy as np
from bindsnet.network import Network
from bindsnet.network.nodes import Input, LIFNodes
from bindsnet.network.topology import Connection
from bindsnet.network.monitors import Monitor


time = 25
# bulding network
network = Network()

# 5layers of neuron 
inpt = Input(n=64, sum_input=True) 
middle = LIFNodes(n=40, trace=True, sum_input=True)
center = LIFNodes(n=40, trace=True, sum_input=True)
final = LIFNodes(n=40, trace=True, sum_input=True)
out = LIFNodes(n=6, sum_input=True) # n=6はラベルと同じ数にする

# connecting of each layers
inpt_middle = Connection(source=inpt, target=middle, wmin=0, wmax=1e-1)
middle_center = Connection(source=middle, target=center, wmin=0, wmax=1e-1)
center_final = Connection(source=center, target=final, wmin=0, wmax=1e-1)
final_out = Connection(source=final, target=out, wmin=0, wmax=1e-1)

# connecting all layers to network
network.add_layer(inpt, name='A')
network.add_layer(middle, name='B')
network.add_layer(center, name='C')
network.add_layer(final,  name='D')
network.add_layer(out, name='E')

foward_connection = Connection(source=inpt, target=middle, w=0.05 + 0.1*torch.randn(inpt.n, middle.n))
network.add_connection(connection=foward_connection, source="A", target="B")
foward_connection = Connection(source=middle, target=center, w=0.05 + 0.1*torch.randn(middle.n, center.n))
network.add_connection(connection=foward_connection, source="B", target="C")
foward_connection = Connection(source=center, target=final, w=0.05 + 0.1*torch.randn(center.n, final.n))
network.add_connection(connection=foward_connection, source="C", target="D")
foward_connection = Connection(source=final, target=out, w=0.05 + 0.1*torch.randn(final.n, out.n))
network.add_connection(connection=foward_connection, source="D", target="E")
recurrent_connection = Connection(source=out, target=out, w=0.025*(torch.eye(out.n)-1),)
network.add_connection(connection=recurrent_connection, source="E", target="E")

# monitoring input's spikes and output's one
inpt_monitor = Monitor(obj=inpt, state_vars=("s", "v"), time=500,)
middle_monitor = Monitor(obj=inpt, state_vars=("s", "v"), time=500,)
center_monitor = Monitor(obj=inpt, state_vars=("s", "v"), time=500,)
final_monitor = Monitor(obj=inpt, state_vars=("s", "v"), time=500,)
out_monitor = Monitor(obj=inpt, state_vars=("s", "v"), time=500,)

# connecting monitor to network
network.add_monitor(monitor=inpt_monitor, name="A")
network.add_monitor(monitor=middle_monitor, name="B")
network.add_monitor(monitor=center_monitor, name="C")
network.add_monitor(monitor=final_monitor, name="D")
network.add_monitor(monitor=out_monitor, name="E")

for l in network.layers:
    m = Monitor(network.layers[l], state_vars=['s'], time=time)
    network.add_monitor(m, name=l)

# date loading 
npzfile = np.load("C:/Users/name/Desktop/myo-python-1.0.4/myo-armband-nn-master/data/train_set.npz")
x = npzfile['x']  # ndarray [1,64]
y = npzfile['y']  # ndarry  [1,6]

# transforming numpy to tensor
x = torch.from_numpy(x).clone()
y = torch.from_numpy(y).clone()

grads = {}
lr, lr_decay = 1e-2, 0.95
criterion = torch.nn.CrossEntropyLoss()  
spike_ims, spike_axes, weight_im = None, None, None
for i, (x, y) in enumerate(zip(x.view(-1, 64), y)):
    inputs = {'A': x.repeat(time, 1), 'E_b': torch.ones(time, 1)}
    network.run(inputs=inputs, time=time)
    y = torch.tensor(y).long()
    spikes = {l: network.monitors[l].get('s') for l in network.layers}
    summed_inputs = {l: network.layers[l].summed for l in network.layers}
    output = spikes['E'].sum(-1).float().softmax(0).view(1, -1)
    predicted = output.argmax(1).item()
    y = torch.argmax(y, dim=-1) 

    grads['dl/df'] = summed_inputs['B'].softmax(0)
    grads['dl/df'][y] -= 1
    summed_inputs['A'] = torch.squeeze(summed_inputs['A'], dim=0)
    grads['dl/df'] = torch.squeeze(grads['dl/df'], dim=0)
    grads['dl/dw'] = torch.ger(summed_inputs['A'], grads['dl/df'])
    network.connections['A', 'B'].w -= lr * grads['dl/dw']

    grads['dl/df'] = summed_inputs['C'].softmax(0)
    grads['dl/df'][y] -= 1
    summed_inputs['B'] = torch.squeeze(summed_inputs['B'], dim=0)
    grads['dl/df'] = torch.squeeze(grads['dl/df'], dim=0)
    grads['dl/dw'] = torch.ger(summed_inputs['B'], grads['dl/df'])
    network.connections['B', 'C'].w -= lr * grads['dl/dw']

    grads['dl/df'] = summed_inputs['D'].softmax(0)
    grads['dl/df'][y] -= 1
    summed_inputs['C'] = torch.squeeze(summed_inputs['C'], dim=0)
    grads['dl/df'] = torch.squeeze(grads['dl/df'], dim=0)
    grads['dl/dw'] = torch.ger(summed_inputs['C'], grads['dl/df'])
    network.connections['C', 'D'].w -= lr * grads['dl/dw']

    grads['dl/df'] = summed_inputs['E'].softmax(0)
    grads['dl/df'][y] -= 1
    summed_inputs['D'] = torch.squeeze(summed_inputs['D'], dim=0)
    grads['dl/df'] = torch.squeeze(grads['dl/df'], dim=0)
    grads['dl/dw'] = torch.ger(summed_inputs['D'], grads['dl/df'])
    network.connections['D', 'E'].w -= lr*grads['dl/dw']

    if i > 0 and i % 300 == 0:
       lr = lr_decay
    network.reset_()

error message

Traceback (most recent call last):
  File "C:/Users/name/Desktop/myo-python-1.0.4/bindsnet-master/bindsnet/preRSNN.py", line 126, in <module>
    network.reset_()
  File "C:\Python36\lib\site-packages\torch\nn\modules\module.py", line 772, in __getattr__
    type(self).__name__, name))
torch.nn.modules.module.ModuleAttributeError: 'Network' object has no attribute 'reset_'

It seems that the bindsnet library expects the network object to provide a reset_ function, which is not a default method of nn.Modules.
I would recommend to check with the authors of bindsnet and their docs how nn.Modules should be used.

I focused on [ from bindsnet.network import Network] especially Class Network.
Should we focus on the [def train] section?


from .monitors import AbstractMonitor
from .nodes import Nodes
from .topology import AbstractConnection
from ..learning.reward import AbstractReward


def load(file_name: str, map_location: str = "cpu", learning: bool = None) -> "Network":
    # language=rst
    """
    Loads serialized network object from disk.

    :param file_name: Path to serialized network object on disk.
    :param map_location: One of ``"cpu"`` or ``"cuda"``. Defaults to ``"cpu"``.
    :param learning: Whether to load with learning enabled. Default loads value from
        disk.
    """
    network = torch.load(open(file_name, "rb"), map_location=map_location)
    if learning is not None and "learning" in vars(network):
        network.learning = learning

    return network


class Network(torch.nn.Module):
    # language=rst
    """
    Central object of the ``bindsnet`` package. Responsible for the simulation and
    interaction of nodes and connections.

    **Example:**

    .. code-block:: python

        import torch
        import matplotlib.pyplot as plt

        from bindsnet         import encoding
        from bindsnet.network import Network, nodes, topology, monitors

        network = Network(dt=1.0)  # Instantiates network.

        X = nodes.Input(100)  # Input layer.
        Y = nodes.LIFNodes(100)  # Layer of LIF neurons.
        C = topology.Connection(source=X, target=Y, w=torch.rand(X.n, Y.n))  # Connection from X to Y.

        # Spike monitor objects.
        M1 = monitors.Monitor(obj=X, state_vars=['s'])
        M2 = monitors.Monitor(obj=Y, state_vars=['s'])

        # Add everything to the network object.
        network.add_layer(layer=X, name='X')
        network.add_layer(layer=Y, name='Y')
        network.add_connection(connection=C, source='X', target='Y')
        network.add_monitor(monitor=M1, name='X')
        network.add_monitor(monitor=M2, name='Y')

        # Create Poisson-distributed spike train inputs.
        data = 15 * torch.rand(100)  # Generate random Poisson rates for 100 input neurons.
        train = encoding.poisson(datum=data, time=5000)  # Encode input as 5000ms Poisson spike trains.

        # Simulate network on generated spike trains.
        inputs = {'X' : train}  # Create inputs mapping.
        network.run(inputs=inputs, time=5000)  # Run network simulation.

        # Plot spikes of input and output layers.
        spikes = {'X' : M1.get('s'), 'Y' : M2.get('s')}

        fig, axes = plt.subplots(2, 1, figsize=(12, 7))
        for i, layer in enumerate(spikes):
            axes[i].matshow(spikes[layer], cmap='binary')
            axes[i].set_title('%s spikes' % layer)
            axes[i].set_xlabel('Time'); axes[i].set_ylabel('Index of neuron')
            axes[i].set_xticks(()); axes[i].set_yticks(())
            axes[i].set_aspect('auto')

        plt.tight_layout(); plt.show()
    """

    def __init__(
        self,
        dt: float = 1.0,
        batch_size: int = 1,
        learning: bool = True,
        reward_fn: Optional[Type[AbstractReward]] = None,
    ) -> None:
        # language=rst
        """
        Initializes network object.

        :param dt: Simulation timestep.
        :param batch_size: Mini-batch size.
        :param learning: Whether to allow connection updates. True by default.
        :param reward_fn: Optional class allowing for modification of reward in case of
            reward-modulated learning.
        """
        super().__init__()

        self.dt = dt
        self.batch_size = batch_size

        self.layers = {}
        self.connections = {}
        self.monitors = {}

        self.train(learning)

        if reward_fn is not None:
            self.reward_fn = reward_fn()
        else:
            self.reward_fn = None

    def add_layer(self, layer: Nodes, name: str) -> None:
        # language=rst
        """
        Adds a layer of nodes to the network.

        :param layer: A subclass of the ``Nodes`` object.
        :param name: Logical name of layer.
        """
        self.layers[name] = layer
        self.add_module(name, layer)

        layer.train(self.learning)
        layer.compute_decays(self.dt)
        layer.set_batch_size(self.batch_size)

    def add_connection(
        self, connection: AbstractConnection, source: str, target: str
    ) -> None:
        # language=rst
        """
        Adds a connection between layers of nodes to the network.

        :param connection: An instance of class ``Connection``.
        :param source: Logical name of the connection's source layer.
        :param target: Logical name of the connection's target layer.
        """
        self.connections[(source, target)] = connection
        self.add_module(source + "_to_" + target, connection)

        connection.dt = self.dt
        connection.train(self.learning)

    def add_monitor(self, monitor: AbstractMonitor, name: str) -> None:
        # language=rst
        """
        Adds a monitor on a network object to the network.

        :param monitor: An instance of class ``Monitor``.
        :param name: Logical name of monitor object.
        """
        self.monitors[name] = monitor
        monitor.network = self
        monitor.dt = self.dt

    def save(self, file_name: str) -> None:
        # language=rst
        """
        Serializes the network object to disk.

        :param file_name: Path to store serialized network object on disk.

        **Example:**

        .. code-block:: python

            import torch
            import matplotlib.pyplot as plt

            from pathlib          import Path
            from bindsnet.network import *
            from bindsnet.network import topology

            # Build simple network.
            network = Network(dt=1.0)

            X = nodes.Input(100)  # Input layer.
            Y = nodes.LIFNodes(100)  # Layer of LIF neurons.
            C = topology.Connection(source=X, target=Y, w=torch.rand(X.n, Y.n))  # Connection from X to Y.

            # Add everything to the network object.
            network.add_layer(layer=X, name='X')
            network.add_layer(layer=Y, name='Y')
            network.add_connection(connection=C, source='X', target='Y')

            # Save the network to disk.
            network.save(str(Path.home()) + '/network.pt')
        """
        torch.save(self, open(file_name, "wb"))

    def clone(self) -> "Network":
        # language=rst
        """
        Returns a cloned network object.

        :return: A copy of this network.
        """
        virtual_file = tempfile.SpooledTemporaryFile()
        torch.save(self, virtual_file)
        virtual_file.seek(0)
        return torch.load(virtual_file)

    def _get_inputs(self, layers: Iterable = None) -> Dict[str, torch.Tensor]:
        # language=rst
        """
        Fetches outputs from network layers to use as input to downstream layers.

        :param layers: Layers to update inputs for. Defaults to all network layers.
        :return: Inputs to all layers for the current iteration.
        """
        inputs = {}

        if layers is None:
            layers = self.layers

        # Loop over network connections.
        for c in self.connections:
            if c[1] in layers:
                # Fetch source and target populations.
                source = self.connections[c].source
                target = self.connections[c].target

                if not c[1] in inputs:
                    inputs[c[1]] = torch.zeros(
                        self.batch_size, *target.shape, device=target.s.device
                    )

                # Add to input: source's spikes multiplied by connection weights.
                inputs[c[1]] += self.connections[c].compute(source.s)

        return inputs

    def run(
        self, inputs: Dict[str, torch.Tensor], time: int, one_step=False, **kwargs
    ) -> None:
        # language=rst
        """
        Simulate network for given inputs and time.

        :param inputs: Dictionary of ``Tensor``s of shape ``[time, *input_shape]`` or
                      ``[time, batch_size, *input_shape]``.
        :param time: Simulation time.
        :param one_step: Whether to run the network in "feed-forward" mode, where inputs
            propagate all the way through the network in a single simulation time step.
            Layers are updated in the order they are added to the network.

        Keyword arguments:

        :param Dict[str, torch.Tensor] clamp: Mapping of layer names to boolean masks if
            neurons should be clamped to spiking. The ``Tensor``s have shape
            ``[n_neurons]`` or ``[time, n_neurons]``.
        :param Dict[str, torch.Tensor] unclamp: Mapping of layer names to boolean masks
            if neurons should be clamped to not spiking. The ``Tensor``s should have
            shape ``[n_neurons]`` or ``[time, n_neurons]``.
        :param Dict[str, torch.Tensor] injects_v: Mapping of layer names to boolean
            masks if neurons should be added voltage. The ``Tensor``s should have shape
            ``[n_neurons]`` or ``[time, n_neurons]``.
        :param Union[float, torch.Tensor] reward: Scalar value used in reward-modulated
            learning.
        :param Dict[Tuple[str], torch.Tensor] masks: Mapping of connection names to
            boolean masks determining which weights to clamp to zero.

        **Example:**

        .. code-block:: python

            import torch
            import matplotlib.pyplot as plt

            from bindsnet.network import Network
            from bindsnet.network.nodes import Input
            from bindsnet.network.monitors import Monitor

            # Build simple network.
            network = Network()
            network.add_layer(Input(500), name='I')
            network.add_monitor(Monitor(network.layers['I'], state_vars=['s']), 'I')

            # Generate spikes by running Bernoulli trials on Uniform(0, 0.5) samples.
            spikes = torch.bernoulli(0.5 * torch.rand(500, 500))

            # Run network simulation.
            network.run(inputs={'I' : spikes}, time=500)

            # Look at input spiking activity.
            spikes = network.monitors['I'].get('s')
            plt.matshow(spikes, cmap='binary')
            plt.xticks(()); plt.yticks(());
            plt.xlabel('Time'); plt.ylabel('Neuron index')
            plt.title('Input spiking')
            plt.show()
        """
        # Parse keyword arguments.
        clamps = kwargs.get("clamp", {})
        unclamps = kwargs.get("unclamp", {})
        masks = kwargs.get("masks", {})
        injects_v = kwargs.get("injects_v", {})

        # Compute reward.
        if self.reward_fn is not None:
            kwargs["reward"] = self.reward_fn.compute(**kwargs)

        # Dynamic setting of batch size.
        if inputs != {}:
            for key in inputs:
                # goal shape is [time, batch, n_0, ...]
                if len(inputs[key].size()) == 1:
                    # current shape is [n_0, ...]
                    # unsqueeze twice to make [1, 1, n_0, ...]
                    inputs[key] = inputs[key].unsqueeze(0).unsqueeze(0)
                elif len(inputs[key].size()) == 2:
                    # current shape is [time, n_0, ...]
                    # unsqueeze dim 1 so that we have
                    # [time, 1, n_0, ...]
                    inputs[key] = inputs[key].unsqueeze(1)

            for key in inputs:
                # batch dimension is 1, grab this and use for batch size
                if inputs[key].size(1) != self.batch_size:
                    self.batch_size = inputs[key].size(1)

                    for l in self.layers:
                        self.layers[l].set_batch_size(self.batch_size)

                    for m in self.monitors:
                        self.monitors[m].reset_state_variables()

                break

        # Effective number of timesteps.
        timesteps = int(time / self.dt)

        # Simulate network activity for `time` timesteps.
        for t in range(timesteps):
            # Get input to all layers (synchronous mode).
            current_inputs = {}
            if not one_step:
                current_inputs.update(self._get_inputs())

            for l in self.layers:
                # Update each layer of nodes.
                if l in inputs:
                    if l in current_inputs:
                        current_inputs[l] += inputs[l][t]
                    else:
                        current_inputs[l] = inputs[l][t]

                if one_step:
                    # Get input to this layer (one-step mode).
                    current_inputs.update(self._get_inputs(layers=[l]))

                if l in current_inputs:
                    self.layers[l].forward(x=current_inputs[l])
                else:
                    self.layers[l].forward(x=torch.zeros(self.layers[l].s.shape))

                # Clamp neurons to spike.
                clamp = clamps.get(l, None)
                if clamp is not None:
                    if clamp.ndimension() == 1:
                        self.layers[l].s[:, clamp] = 1
                    else:
                        self.layers[l].s[:, clamp[t]] = 1

                # Clamp neurons not to spike.
                unclamp = unclamps.get(l, None)
                if unclamp is not None:
                    if unclamp.ndimension() == 1:
                        self.layers[l].s[:, unclamp] = 0
                    else:
                        self.layers[l].s[:, unclamp[t]] = 0

                # Inject voltage to neurons.
                inject_v = injects_v.get(l, None)
                if inject_v is not None:
                    if inject_v.ndimension() == 1:
                        self.layers[l].v += inject_v
                    else:
                        self.layers[l].v += inject_v[t]

            # Run synapse updates.
            for c in self.connections:
                self.connections[c].update(
                    mask=masks.get(c, None), learning=self.learning, **kwargs
                )

            # # Get input to all layers.
            # current_inputs.update(self._get_inputs())

            # Record state variables of interest.
            for m in self.monitors:
                self.monitors[m].record()

        # Re-normalize connections.
        for c in self.connections:
            self.connections[c].normalize()

    def reset_state_variables(self) -> None:
        # language=rst
        """
        Reset state variables of objects in network.
        """
        for layer in self.layers:
            self.layers[layer].reset_state_variables()

        for connection in self.connections:
            self.connections[connection].reset_state_variables()

        for monitor in self.monitors:
            self.monitors[monitor].reset_state_variables()

    def train(self, mode: bool = True) -> "torch.nn.Module":
        # language=rst
        """
        Sets the node in training mode.

        :param mode: Turn training on or off.

        :return: ``self`` as specified in ``torch.nn.Module``.
        """
        self.learning = mode
        return super().train(mode)

I thought I would probably use a function called train here, but I don’t know how to adapt it.

    def train(self, mode: bool = True) -> "torch.nn.Module":
        # language=rst
        """
        Sets the node in training mode.

        :param mode: Turn training on or off.

        :return: ``self`` as specified in ``torch.nn.Module``.
        """
        self.learning = mode
        return super().train(mode)

I’m unsure if this is a new issue and the old one is solved already.
Did you manage to figure out, which module expects the reset_ method and could you explain your new issue a bit more?

As you say, I searched for network_reset ().
An error occurred because the function was not defined. I decided to learn with epoch.

Hi
I am having the exact same problem,
‘Network’ object has no attribute ‘reset_’

How did you manage to solve this?

Could you post the complete stack trace, please?

Sorry for the late reply to the comment.
bindsnet.network You need to declare “reset_ ()” yourself as a function from the import Network.
Check “Class Network”.
In addition, these functional declarations are written in a journal named “Frontier”.
You can find it by searching for “Frontier Spiking Neural Nets”.