lava-nc / lava-dl

Deep Learning library for Lava
https://lava-nc.org
BSD 3-Clause "New" or "Revised" License
149 stars 71 forks source link

Remove unused input port in Input layer. #318

Open rileywhite-noblis opened 3 months ago

rileywhite-noblis commented 3 months ago

Issue Number: #298

Objective of pull request: Remove unused input port.

Pull request checklist

Your PR fulfills the following requirements:

Pull request type

What is the current behavior?

In the latest release, the in port of the Input AbstractBlock for netx does not connect it's in port to it's neuron in port.

Load any model via netx with an input layer and connect it to data.

net = netx.hdf5.Network(trained_folder + '/network.net')
data.out.connect(net.inp)
sink.connect(net.out)

Then try to run this network, you will get an infinite hang.

What is the new behavior?

Input port is no longer available in Input layer, forcing usage of it's neuron's input port.

Does this introduce a breaking change?

Supplemental information

I will admit this change is a bit of a hack, but a better fix may be outside of my time commitment, and knowledge of the compiler. A better fix would probably be to set its input port to its neurons in_a port, but this causes issues with compilation that I was unable to sort out. Specifically:


/Users/m32005/lava-dl/tests/lava/lib/dl/netx/test_hdf5.py::TestHdf5Netx::test_tinynet failed: self = <tests.lava.lib.dl.netx.test_hdf5.TestHdf5Netx testMethod=test_tinynet>

    def test_tinynet(self) -> None:
        """Tests the output of three layer CNN."""
        steps_per_sample = 17
        net = netx.hdf5.Network(net_config=root + '/tiny.net')

        num_steps = steps_per_sample + len(net)
        sink = io.sink.RingBuffer(
            shape=net.out_layer.out.shape, buffer=num_steps
        )
        net.out_layer.out.connect(sink.a_in)

        # layer reset mechanism
        for i, l in enumerate(net.layers):
            u_resetter = io.reset.Reset(
                interval=steps_per_sample, offset=i - 1)
            v_resetter = io.reset.Reset(
                interval=steps_per_sample, offset=i - 1)
            u_resetter.connect_var(l.neuron.u)
            v_resetter.connect_var(l.neuron.v)

        if verbose:
            print(f'Network created from {net.filename}')
            print(net)
            print(f'{len(net) = }')

        # set input bias for the ground truth sample
        net.in_layer.neuron.bias_mant.init = np.load(
            root + '/gts/tinynet/input_bias.npy'
        )

        run_condition = RunSteps(num_steps=num_steps)
        run_config = TestRunConfig(select_tag='fixed_pt')
>       net.run(condition=run_condition, run_cfg=run_config)

tests/lava/lib/dl/netx/test_hdf5.py:112: 
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 
../anaconda3/envs/lava/src/lava/src/lava/magma/core/process/process.py:364: in run
    self.create_runtime(run_cfg=run_cfg, compile_config=compile_config)
../anaconda3/envs/lava/src/lava/src/lava/magma/core/process/process.py:388: in create_runtime
    executable = self.compile(run_cfg, compile_config)
../anaconda3/envs/lava/src/lava/src/lava/magma/core/process/process.py:412: in compile
    return compiler.compile(self, run_cfg)
../anaconda3/envs/lava/src/lava/src/lava/magma/compiler/compiler.py:140: in compile
    proc_builders, channel_map = self._compile_proc_groups(
../anaconda3/envs/lava/src/lava/src/lava/magma/compiler/compiler.py:247: in _compile_proc_groups
    proc_builders, channel_map = self._extract_proc_builders(
../anaconda3/envs/lava/src/lava/src/lava/magma/compiler/compiler.py:410: in _extract_proc_builders
    builders, channel_map = subcompiler.get_builders(channel_map)
../anaconda3/envs/lava/src/lava/src/lava/magma/compiler/subcompilers/py/pyproc_compiler.py:112: in get_builders
    builders[process] = self._create_builder_for_process(process)
../anaconda3/envs/lava/src/lava/src/lava/magma/compiler/subcompilers/py/pyproc_compiler.py:128: in _create_builder_for_process
    inport_initializers = self._create_inport_initializers(process)
../anaconda3/envs/lava/src/lava/src/lava/magma/compiler/subcompilers/py/pyproc_compiler.py:199: in _create_inport_initializers
    ChannelBuildersFactory.get_port_dtype(port),
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 

port = <lava.magma.core.process.ports.ports.InPort object at 0x302879a90>

    @staticmethod
    def get_port_dtype(port: AbstractPort) -> ty.Any:
        """Returns the d_type of a Process Port, as specified in the
        corresponding PortImplementation of the ProcessModel implementing the
        Process"""

        port_pm_class = ChannelBuildersFactory._get_port_process_model_class(
            port
        )
        if hasattr(port_pm_class, port.name):
            if isinstance(port, VarPort):
                return getattr(port_pm_class, port.var.name).d_type
            return getattr(port_pm_class, port.name).d_type
        elif isinstance(port, ImplicitVarPort):
            return getattr(port_pm_class, port.var.name).d_type
        # Port has different name in Process and ProcessModel
        else:
>           raise AssertionError(
                "Port {!r} not found in "
                "ProcessModel {!r}".format(port, port_pm_class)
            )
E           AssertionError: Port <lava.magma.core.process.ports.ports.InPort object at 0x302879a90> not found in ProcessModel <class 'lava.lib.dl.netx.blocks.models.PyInputModel'>

../anaconda3/envs/lava/src/lava/src/lava/magma/compiler/subcompilers/channel_builders_factory.py:225: AssertionError```