Need some help with a custom process

Hi,

I require assistance with my custom process. I want to write a custom process that iterates over the input (vectors) and assigns a duration to each vector, such that each vector is presented for a different period of time.

My process works in general, however when I apply it in my model, the index only updates for the input process, not the target process, and remains 0 during the simulation.

Here is the code for the process:

# Create Custom Process


class FlexibleDuration(nengo.Process):
    
    inputs = NdarrayParam("inputs", shape=("...",))
    presentation_time = NdarrayParam("presentation_time", shape=("...",))
    
    
    def __init__(self, inputs, presentation_time, timer, index, internal_t, **kwargs):
        self.inputs = inputs
        self.presentation_time = presentation_time
        self.timer = timer
        self.index = index
        self.internal_t = internal_t
        super().__init__(
            default_size_in=0, default_size_out=self.inputs[0].size, **kwargs
        )

    def make_step(self, shape_in, shape_out, dt, rng, state):
        assert shape_in == (0,)
        assert shape_out == (self.inputs[0].size,)
        
        n = len(self.inputs)
        inputs = self.inputs.reshape(n, -1)
        
        n1 = len(self.inputs)
        presentation_time = self.presentation_time.reshape(n1, -1)
        index = int(self.index)
        timer = int(self.timer)
        internal_t = int(self.internal_t)
        
        def step_presentinput(t):
            self.internal_t += dt
            #print(t,self.internal_t, self.timer)
            if self.internal_t > self.timer:
                self.index += 1
                
                if self.index == len(self.inputs):
                    self.index = 0 
                    
                    
                self.timer += self.presentation_time[self.index]
                #print('in loop ', self.internal_t, self.index, self.timer)
           
            return inputs[self.index]

        return step_presentinput

This is how I create the processes afterwards:

c_timer = duration_shuff[0]
c_index = 0
c_internal_t = 0 

s_timer = duration_shuff[0]
s_index = 0
s_internal_t = 0 

process_in = FlexibleDuration(c_mat_shuff, presentation_time=duration_shuff,timer=c_timer,index=c_index,internal_t=c_internal_t)
process_target = FlexibleDuration(s_mat_shuff, presentation_time=duration_shuff,timer=s_timer,index=s_index,internal_t=s_internal_t)

And this is how I integrate it in the model:

    inp = nengo.Node(process_in)
    target = nengo.Node(process_target)

I hope you can help me, thanks in advance!

Hi again,

I tried to narrow down my problem and made two processes that do exactly the same just with different names. However, the problem remains, the index is rightly updated for process_in but remains 0 for process_target. Maybe it has something to do with my model?

It’s just a simple single layer model:

model = nengo.Network()

with model:
    
    inp = nengo.Node(process_in)
    target = nengo.Node(process_target)
    
    inp_ens = nengo.Ensemble(n_neurons = 10000, dimensions = n_in,radius=1,
                            intercepts = intercept_vals,
                            encoders = encoder_vals,
                            eval_points = eval_vals,
                            neuron_type = nengo.LIF())
    nengo.Connection(inp,inp_ens)
    
    
    out = nengo.Node(None,size_in=n_out)
    learn_con = nengo.Connection(inp_ens.neurons,out,transform=np.zeros((100,10000)),
                                 synapse=0.0005,
                                 learning_rule_type=nengo.PES(learning_rate=0.001))
    
    
    error = nengo.Node(None,size_in=n_out)
    
    nengo.Connection(out,error)
    nengo.Connection(target,error,transform=-1)
    nengo.Connection(error,learn_con.learning_rule)
    
    # For visualization
    
    #inp_probe = nengo.Probe(inp)
    target_probe = nengo.Probe(target)
    #ens_spikes = nengo.Probe(inp_ens.neurons)
    #ens_probe  = nengo.Probe(inp_ens.neurons, synapse=0.01)
    out_probe = nengo.Probe(out)
    error_probe = nengo.Probe(error, synapse=0.03)
    
    
with nengo.Simulator(model) as sim:
    sim.run(20)

Thanks in advance :slight_smile:

Hi @SebVol,

I’m not seeing what you are describing (at least, not in the simple process code I’ve written). Here’s the code I’m using: test_custom_process.py (1.0 KB)

From the output plots, you can see that both processes are using their initialized values appropriately, and both are incrementing their internal index with whatever it is configured to do:

Can you boil down your code into a script I can run, and describe what you expect to see vs what you actually are seeing? Thanks!

Hi @xchoo,

thanks for your reply!

I did an additional test by copying the exact same process and renaming each variable. I then added print commands to the process, one right before “return” and one right after the index should be updated. And it looks like the elapsed time is updated but not the index. Strangely, only for the input process the updated line is printed, but for both processes the time for the next increment is updated. As you can see in the picture. Please see the attached screenshot of the output (Increment refers to when the index should be incremented next.)


:

Here I would have expected that only the values are updated if also “Inp/Tar increment …” are outputed. And if the values are updated, that both the time to the next increment and the actual index is updated.

I also attach a shortened script with dummy variables. Make sure, depending on where you run the script, that I still have “print” in the process.
test_process.py (4.6 KB)

Thanks!

Edit: typo

I’ve identified the issue with your code, and it’s these lines:

duration = np.random.uniform(low=0.0, high=0.1, size=(4859, 1))
...
c_timer = duration[0]
...
s_timer = duration[0]

If you print out these values, you’ll see that c_timer and s_timer are not floats. Rather, they are single element arrays:

>>> [0.0703325] [0.0703325]

This is because when you create a np.random.uniform matrix with the shape (4859, 1), you are actually creating a 2D array. If you create it with a shape (4859,), that will be a single dimensional array.

Because you are passing an array, when one process alters the array, the other process gets the updated values (since arrays are passed by reference, instead of by value). I’m surprised that Python is even able to evaluate internal_t > timer when one is a float, and the other is an array.

So, when the inp process triggers the logic to update the index, it also updates the self.timer value. Next, when the tar process does the check to see if internal_t > timer, since the timer value has been updated (and since both processes share a reference to the same array), the if statement fails, and thus the index is not updated for the tar process.

There are multiple ways to fix this issue. You can set the shape of duration to (4859,) (when you create it), or when you set the c_timer and s_timer values, use duration[0][0].

Thanks for your help! :slight_smile: That solved it, def. my bad never thought about the actual input and instead was looking at my process…