Open in Colab

State Variables

[1]:
# uncomment the command below to install the nnodely package
#!pip install nnodely

from nnodely import *
>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>-- nnodely_v1.5.0 --<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<

State Definition

Use the keyword ‘State’ to define a state variable (like you will do for an Input). You can specify the dimension of the variable.

[2]:
clearNames('x_state')
x_state = Input('x_state', dimensions=1)
x_out = Fir(x_state.tw(0.5))

Closed Loop

Every relation inside NNodely can update a state variable. closing a state in a loop means that at the end of each forward pass the result of the selected relation will update the selected state variable.

[3]:
clearNames('out')
x_out.closedLoop(x_state)
out = Output('out',x_out)

or you can use the ClosedLoop block

[4]:
clearNames('out')
x_out = ClosedLoop(x_out, x_state)
out = Output('out',x_out)

Connect

Every relation inside NNodely can update a state variable. connecting a relation to a state means that at each forward pass the result of the selected relation will immediately update the selected state variable.

(Note: you must re-define the relation in order to change the update of the state variable)

[5]:
clearNames()
x_out = Fir(x_state.tw(0.5))
x_out.connect(x_state)
out = Output('out',x_out)

or you can use the Connect block

[6]:
clearNames('out')
x_out = Connect(x_out, x_state)
out = Output('out',x_out)

Connect two models together

[9]:
clearNames(['a','b_t','c','d_t','b_in','shared','b','A','B','C','D','d'])
import numpy as np

def linear_function(x, k1, k2):
    return x*k1 + k2

data_a = np.arange(1,101, dtype=np.float32)
data_b_t = linear_function(data_a, 2, 3)

data_c = np.arange(1,101, dtype=np.float32)
data_b_in = np.arange(5,105, dtype=np.float32)
data_d_t = linear_function(data_c, 5, 1)

dataset = {'a': data_a, 'b_t': data_b_t, 'c':data_c, 'b_in': data_b_in, 'd_t':data_d_t }
## Model a
a = Input('a')
b_t = Input('b_t')
shared = Parameter('shared',dimensions=(1,1))
output_relation = Linear(W=shared)(a.last())+Linear(W='A')(Fir(W='B')(a.tw(0.5)))
b = Output('b',output_relation)

model = Modely(seed=42)
model.addModel('b_model', b)
model.addMinimize('b_min', b, b_t.last())
model.neuralizeModel(0.1)

# Model d
c = Input('c')
d_t = Input('d_t')
b_in = Input('b_in')
output_relation.connect(b_in)
d = Output('d',Linear(W=shared)(c.last())+Fir(W='C')(c.tw(0.5))+Fir(W='D')(b_in.tw(0.3)))

model.addModel('d_model', [b,d])
model.addMinimize('d_min', d, d_t.last())
model.neuralizeModel(0.1)
model.loadData('dataset', dataset)

params = {'num_of_epochs': 1,
        'train_batch_size': 8,
        'val_batch_size': 8,
        'test_batch_size':1,
        'lr':0.1}

## training dei parametri di tutti i modelli
_ = model.trainModel(splits=[100,0,0], training_params=params, prediction_samples=4)
================================ nnodely Model =================================
{'Constants': {},
 'Functions': {},
 'Info': {'SampleTime': 0.1,
          'nnodely_version': '1.5.0',
          'ns': [5, 0],
          'ntot': 5,
          'num_parameters': 7},
 'Inputs': {'a': {'dim': 1,
                  'ns': [5, 0],
                  'ntot': 5,
                  'sw': [-1, 0],
                  'tw': [-0.5, 0]},
            'b_t': {'dim': 1, 'ns': [1, 0], 'ntot': 1, 'sw': [-1, 0]}},
 'Minimizers': {'b_min': {'A': 'Add47', 'B': 'SamplePart49', 'loss': 'mse'}},
 'Models': 'b_model',
 'Outputs': {'b': 'Add47'},
 'Parameters': {'A': {'dim': [1, 1], 'values': [[0.600895345211029]]},
                'B': {'dim': 1,
                      'tw': 0.5,
                      'values': [[0.8822692632675171],
                                 [0.9150039553642273],
                                 [0.38286375999450684],
                                 [0.9593056440353394],
                                 [0.3904482126235962]]},
                'shared': {'dim': [1, 1], 'values': [[0.2565724849700928]]}},
 'Relations': {'Add47': ['Add', ['Linear42', 'Linear46']],
               'Fir45': ['Fir', ['TimePart44'], 'B', None, 0],
               'Linear42': ['Linear', ['SamplePart41'], 'shared', None, 0],
               'Linear46': ['Linear', ['Fir45'], 'A', None, 0],
               'SamplePart41': ['SamplePart', ['a'], -1, [-1, 0]],
               'SamplePart49': ['SamplePart', ['b_t'], -1, [-1, 0]],
               'TimePart44': ['TimePart', ['a'], -1, [-0.5, 0]]}}
================================================================================
================================ nnodely Model =================================
{'Constants': {},
 'Functions': {},
 'Info': {'SampleTime': 0.1,
          'nnodely_version': '1.5.0',
          'ns': [5, 0],
          'ntot': 5,
          'num_parameters': 15},
 'Inputs': {'a': {'dim': 1,
                  'ns': [5, 0],
                  'ntot': 5,
                  'sw': [-1, 0],
                  'tw': [-0.5, 0]},
            'b_in': {'dim': 1, 'ns': [3, 0], 'ntot': 3, 'tw': [-0.3, 0]},
            'b_t': {'dim': 1, 'ns': [1, 0], 'ntot': 1, 'sw': [-1, 0]},
            'c': {'dim': 1,
                  'ns': [5, 0],
                  'ntot': 5,
                  'sw': [-1, 0],
                  'tw': [-0.5, 0]},
            'd_t': {'dim': 1, 'ns': [1, 0], 'ntot': 1, 'sw': [-1, 0]}},
 'Minimizers': {'b_min': {'A': 'Add47', 'B': 'SamplePart49', 'loss': 'mse'},
                'd_min': {'A': 'Add60', 'B': 'SamplePart62', 'loss': 'mse'}},
 'Models': {'b_model': {'Constants': [],
                        'Functions': [],
                        'Inputs': ['b_t', 'a'],
                        'Outputs': ['b'],
                        'Parameters': ['B', 'A', 'shared'],
                        'Relations': ['SamplePart49',
                                      'TimePart44',
                                      'Fir45',
                                      'Linear46',
                                      'SamplePart41',
                                      'Linear42',
                                      'Add47']},
            'd_model': {'Constants': [],
                        'Functions': [],
                        'Inputs': ['b_in', 'c', 'a'],
                        'Outputs': ['d', 'b'],
                        'Parameters': ['D', 'C', 'shared', 'B', 'A'],
                        'Relations': ['TimePart58',
                                      'Fir59',
                                      'TimePart54',
                                      'Fir55',
                                      'SamplePart51',
                                      'Linear52',
                                      'Add56',
                                      'Add60',
                                      'TimePart44',
                                      'Fir45',
                                      'Linear46',
                                      'SamplePart41',
                                      'Linear42',
                                      'Add47']}},
 'Outputs': {'b': 'Add47', 'd': 'Add60'},
 'Parameters': {'A': {'dim': [1, 1], 'values': [[0.600895345211029]]},
                'B': {'dim': 1,
                      'tw': 0.5,
                      'values': [[0.8822692632675171],
                                 [0.9150039553642273],
                                 [0.38286375999450684],
                                 [0.9593056440353394],
                                 [0.3904482126235962]]},
                'C': {'dim': 1,
                      'tw': 0.5,
                      'values': [[0.9345980882644653],
                                 [0.5935796499252319],
                                 [0.8694044351577759],
                                 [0.5677152872085571],
                                 [0.7410940527915955]]},
                'D': {'dim': 1,
                      'tw': 0.3,
                      'values': [[0.7936413288116455],
                                 [0.9407714605331421],
                                 [0.13318592309951782]]},
                'shared': {'dim': [1, 1], 'values': [[0.2565724849700928]]}},
 'Relations': {'Add47': ['Add', ['Linear42', 'Linear46']],
               'Add56': ['Add', ['Linear52', 'Fir55']],
               'Add60': ['Add', ['Add56', 'Fir59']],
               'Fir45': ['Fir', ['TimePart44'], 'B', None, 0],
               'Fir55': ['Fir', ['TimePart54'], 'C', None, 0],
               'Fir59': ['Fir', ['TimePart58'], 'D', None, 0],
               'Linear42': ['Linear', ['SamplePart41'], 'shared', None, 0],
               'Linear46': ['Linear', ['Fir45'], 'A', None, 0],
               'Linear52': ['Linear', ['SamplePart51'], 'shared', None, 0],
               'SamplePart41': ['SamplePart', ['a'], -1, [-1, 0]],
               'SamplePart49': ['SamplePart', ['b_t'], -1, [-1, 0]],
               'SamplePart51': ['SamplePart', ['c'], -1, [-1, 0]],
               'SamplePart62': ['SamplePart', ['d_t'], -1, [-1, 0]],
               'TimePart44': ['TimePart', ['a'], -1, [-0.5, 0]],
               'TimePart54': ['TimePart', ['c'], -1, [-0.5, 0]],
               'TimePart58': ['TimePart', ['b_in'], -1, [-0.3, 0]]}}
================================================================================
============================ nnodely Model Dataset =============================
Dataset Name:                 dataset
Number of files:              1
Total number of samples:      96
Shape of d_t:                 (96, 1, 1)
Shape of b_in:                (96, 3, 1)
Shape of c:                   (96, 5, 1)
Shape of a:                   (96, 5, 1)
Shape of b_t:                 (96, 1, 1)
================================================================================
======================== nnodely Model Train Parameters ========================
models:                       ['b_model', 'd_model']
num of epochs:                1
update per epochs:            12
└>(n_samples-batch_size)/batch_size+1
shuffle _data:                True
train dataset:                dataset_train
    - num of samples:            96
    - batch size:                8
    - unused samples:            0
       └>n_samples-update_per_epochs*batch_size
minimizers:                   {'b_min': {'A': 'Add47',
                                         'B': 'SamplePart49',
                                         'loss': 'mse'},
                               'd_min': {'A': 'Add60',
                                         'B': 'SamplePart62',
                                         'loss': 'mse'}}
optimizer:                    Adam
optimizer defaults:           {'lr': 0.1}
optimizer params:             [{'params': 'A'},
                               {'params': 'B'},
                               {'params': 'C'},
                               {'params': 'D'},
                               {'params': 'shared'}]
================================================================================
=========================== nnodely Training ===========================
|  Epoch   |       b_min       |       d_min       |       Total       |
|          |        Loss       |        Loss       |        Loss       |
|          |       train       |       train       |       train       |
|----------------------------------------------------------------------|
|   1/1    |     2.324e+02     |     3.749e+02     |     3.036e+02     |
|----------------------------------------------------------------------|
============================ nnodely Training Time =============================
Total time of Training:       0.014888763427734375
================================================================================

Recurrent Train

In order to do a recurrent training of the network using the State variables is mandatory to specify the window of prediction (prediction_samples).

[13]:
import numpy as np
clearNames(['x','x_state','y_state','out'])
x = Input('x', dimensions=3)
x_state = Input('x_state', dimensions=3)
y_state = Input('y_state', dimensions=3)
x_out = Linear(output_dimension=3)(x_state.tw(0.5))
y_out = Linear(output_dimension=3)(y_state.tw(0.5))
x_out.closedLoop(x_state)
y_out.closedLoop(y_state)
out = Output('out',x_out+y_out)

test = Modely(seed=42)
test.addModel('model', out)
test.addMinimize('error', out, x.tw(0.5))

test.neuralizeModel(0.1)

dataset = {'x':np.array([np.random.uniform(1,4,300)]).reshape(100,3).tolist()}
test.loadData(name='dataset', source=dataset)

# Training non ricorrente
params = {'num_of_epochs': 10, 'train_batch_size': 1, 'val_batch_size':1, 'lr':0.01}
tp = test.trainModel(splits=[70,20,10], prediction_samples=5, shuffle_data=False, training_params=params)
print('finale state: ', test._states)
================================ nnodely Model =================================
{'Constants': {},
 'Functions': {},
 'Info': {'SampleTime': 0.1,
          'nnodely_version': '1.5.0',
          'ns': [5, 0],
          'ntot': 5,
          'num_parameters': 18},
 'Inputs': {'x': {'dim': 3, 'ns': [5, 0], 'ntot': 5, 'tw': [-0.5, 0]},
            'x_state': {'closedLoop': 'Linear92',
                        'dim': 3,
                        'local': 1,
                        'ns': [5, 0],
                        'ntot': 5,
                        'tw': [-0.5, 0]},
            'y_state': {'closedLoop': 'Linear95',
                        'dim': 3,
                        'local': 1,
                        'ns': [5, 0],
                        'ntot': 5,
                        'tw': [-0.5, 0]}},
 'Minimizers': {'error': {'A': 'Add96', 'B': 'TimePart98', 'loss': 'mse'}},
 'Models': 'model',
 'Outputs': {'out': 'Add96'},
 'Parameters': {'PLinear75W': {'dim': [3, 3],
                               'values': [[0.13318592309951782,
                                           0.9345980882644653,
                                           0.5935796499252319],
                                          [0.8694044351577759,
                                           0.5677152872085571,
                                           0.7410940527915955],
                                          [0.42940449714660645,
                                           0.8854429125785828,
                                           0.5739044547080994]]},
                'PLinear77W': {'dim': [3, 3],
                               'values': [[0.8822692632675171,
                                           0.9150039553642273,
                                           0.38286375999450684],
                                          [0.9593056440353394,
                                           0.3904482126235962,
                                           0.600895345211029],
                                          [0.2565724849700928,
                                           0.7936413288116455,
                                           0.9407714605331421]]}},
 'Relations': {'Add96': ['Add', ['Linear92', 'Linear95']],
               'Linear92': ['Linear', ['TimePart91'], 'PLinear75W', None, 0],
               'Linear95': ['Linear', ['TimePart94'], 'PLinear77W', None, 0],
               'TimePart91': ['TimePart', ['x_state'], -1, [-0.5, 0]],
               'TimePart94': ['TimePart', ['y_state'], -1, [-0.5, 0]],
               'TimePart98': ['TimePart', ['x'], -1, [-0.5, 0]]}}
================================================================================
============================ nnodely Model Dataset =============================
Dataset Name:                 dataset
Number of files:              1
Total number of samples:      96
Shape of x:                   (96, 5, 3)
================================================================================
======================== nnodely Model Train Parameters ========================
models:                       ['model']
num of epochs:                10
update per epochs:            62
└>(n_samples-batch_size-prediction_samples+1)/(batch_size+step-1)+1
prediction samples:           5
step:                         0
closed loop:                  {}
connect:                      {}
train dataset:                dataset_train
    - num of samples:            67
    - batch size:                1
    - unused samples:            0
       └>n_samples-prediction_samples-update_per_epochs*(batch_size+step-1)
val dataset:                  None
val {batch size, samples}:    {1, 19}
minimizers:                   {'error': {'A': 'Add96',
                                         'B': 'TimePart98',
                                         'loss': 'mse'}}
optimizer:                    Adam
optimizer defaults:           {'lr': 0.01}
optimizer params:             [{'params': 'PLinear75W'},
                               {'params': 'PLinear77W'}]
================================================================================
================= nnodely Training =================
|  Epoch   |       error       |       Total       |
|          |        Loss       |        Loss       |
|          |  train  |   val   |  train  |   val   |
|--------------------------------------------------|
|   1/10   |6.723e+00|7.729e+00|6.723e+00|7.729e+00|
|   2/10   |6.723e+00|7.729e+00|6.723e+00|7.729e+00|
|   3/10   |6.723e+00|7.729e+00|6.723e+00|7.729e+00|
|   4/10   |6.723e+00|7.729e+00|6.723e+00|7.729e+00|
|   5/10   |6.723e+00|7.729e+00|6.723e+00|7.729e+00|
|   6/10   |6.723e+00|7.729e+00|6.723e+00|7.729e+00|
|   7/10   |6.723e+00|7.729e+00|6.723e+00|7.729e+00|
|   8/10   |6.723e+00|7.729e+00|6.723e+00|7.729e+00|
|   9/10   |6.723e+00|7.729e+00|6.723e+00|7.729e+00|
|  10/10   |6.723e+00|7.729e+00|6.723e+00|7.729e+00|
|--------------------------------------------------|
============================ nnodely Training Time =============================
Total time of Training:       2.2795727252960205
================================================================================
finale state:  {'y_state': tensor([[[0., 0., 0.],
         [0., 0., 0.],
         [0., 0., 0.],
         [0., 0., 0.],
         [0., 0., 0.]]]), 'x_state': tensor([[[0., 0., 0.],
         [0., 0., 0.],
         [0., 0., 0.],
         [0., 0., 0.],
         [0., 0., 0.]]])}

Clear State

use the specific function to manually clear the state of a state variable

[14]:
test.resetStates()
print('finale state: ', test.states)
finale state:  {'y_state': [[[0.0, 0.0, 0.0], [0.0, 0.0, 0.0], [0.0, 0.0, 0.0], [0.0, 0.0, 0.0], [0.0, 0.0, 0.0]]], 'x_state': [[[0.0, 0.0, 0.0], [0.0, 0.0, 0.0], [0.0, 0.0, 0.0], [0.0, 0.0, 0.0], [0.0, 0.0, 0.0]]]}

State update at training time

States variables can also be created at training time. These variables will exist only during the training process.

To create the you have to define a dictionary containing {input:output}. In that case, the ‘input’ will become a state during the training process and the ‘output’ will be the relation updating it.

[15]:
import numpy as np
clearNames()
x = Input('x', dimensions=3)
x_s = Input('x_s', dimensions=3)
y_s = Input('y_s', dimensions=3)
x_out = Linear(output_dimension=3)(x_s.tw(0.5))
y_out = Linear(output_dimension=3)(y_s.tw(0.5))
out = Output('out',x_out+y_out)
out_x = Output('out_x',x_out)
out_y = Output('out_y',y_out)

test = Modely(seed=42)
test.addModel('model', [out,out_x,out_y])
test.addMinimize('error', out, x.tw(0.5))

test.neuralizeModel(0.1)

dataset = {'x':np.array([np.random.uniform(1,4,300)]).reshape(100,3).tolist()}
test.loadData(name='dataset', source=dataset)

# Training non ricorrente
params = {'num_of_epochs': 10, 'train_batch_size': 4, 'val_batch_size':4, 'test_batch_size':1, 'lr':0.01}
test.trainModel(splits=[70,20,10], prediction_samples=3, shuffle_data=False, closed_loop={'x_s':'out_x','y_s':'out_y'}, training_params=params)
print('finale state: ', test.states)
================================ nnodely Model =================================
{'Constants': {},
 'Functions': {},
 'Info': {'SampleTime': 0.1,
          'nnodely_version': '1.5.0',
          'ns': [5, 0],
          'ntot': 5,
          'num_parameters': 18},
 'Inputs': {'x': {'dim': 3, 'ns': [5, 0], 'ntot': 5, 'tw': [-0.5, 0]},
            'x_s': {'dim': 3, 'ns': [5, 0], 'ntot': 5, 'tw': [-0.5, 0]},
            'y_s': {'dim': 3, 'ns': [5, 0], 'ntot': 5, 'tw': [-0.5, 0]}},
 'Minimizers': {'error': {'A': 'Add105', 'B': 'TimePart107', 'loss': 'mse'}},
 'Models': 'model',
 'Outputs': {'out': 'Add105', 'out_x': 'Linear101', 'out_y': 'Linear104'},
 'Parameters': {'PLinear3W': {'dim': [3, 3],
                              'values': [[0.13318592309951782,
                                          0.9345980882644653,
                                          0.5935796499252319],
                                         [0.8694044351577759,
                                          0.5677152872085571,
                                          0.7410940527915955],
                                         [0.42940449714660645,
                                          0.8854429125785828,
                                          0.5739044547080994]]},
                'PLinear5W': {'dim': [3, 3],
                              'values': [[0.8822692632675171,
                                          0.9150039553642273,
                                          0.38286375999450684],
                                         [0.9593056440353394,
                                          0.3904482126235962,
                                          0.600895345211029],
                                         [0.2565724849700928,
                                          0.7936413288116455,
                                          0.9407714605331421]]}},
 'Relations': {'Add105': ['Add', ['Linear101', 'Linear104']],
               'Linear101': ['Linear', ['TimePart100'], 'PLinear3W', None, 0],
               'Linear104': ['Linear', ['TimePart103'], 'PLinear5W', None, 0],
               'TimePart100': ['TimePart', ['x_s'], -1, [-0.5, 0]],
               'TimePart103': ['TimePart', ['y_s'], -1, [-0.5, 0]],
               'TimePart107': ['TimePart', ['x'], -1, [-0.5, 0]]}}
================================================================================
============================ nnodely Model Dataset =============================
Dataset Name:                 dataset
Number of files:              1
Total number of samples:      96
Shape of x:                   (96, 5, 3)
================================================================================
======================== nnodely Model Train Parameters ========================
models:                       ['model']
num of epochs:                10
update per epochs:            16
└>(n_samples-batch_size-prediction_samples+1)/(batch_size+step-1)+1
prediction samples:           3
step:                         0
closed loop:                  {'x_s': 'out_x', 'y_s': 'out_y'}
connect:                      {}
train dataset:                dataset_train
    - num of samples:            67
    - batch size:                4
    - unused samples:            0
       └>n_samples-prediction_samples-update_per_epochs*(batch_size+step-1)
val dataset:                  None
val {batch size, samples}:    {4, 19}
minimizers:                   {'error': {'A': 'Add105',
                                         'B': 'TimePart107',
                                         'loss': 'mse'}}
optimizer:                    Adam
optimizer defaults:           {'lr': 0.01}
optimizer params:             [{'params': 'PLinear3W'}, {'params': 'PLinear5W'}]
================================================================================
================= nnodely Training =================
|  Epoch   |       error       |       Total       |
|          |        Loss       |        Loss       |
|          |  train  |   val   |  train  |   val   |
|--------------------------------------------------|
|   1/10   |6.726e+00|7.676e+00|6.726e+00|7.676e+00|
|   2/10   |6.726e+00|7.676e+00|6.726e+00|7.676e+00|
|   3/10   |6.726e+00|7.676e+00|6.726e+00|7.676e+00|
|   4/10   |6.726e+00|7.676e+00|6.726e+00|7.676e+00|
|   5/10   |6.726e+00|7.676e+00|6.726e+00|7.676e+00|
|   6/10   |6.726e+00|7.676e+00|6.726e+00|7.676e+00|
|   7/10   |6.726e+00|7.676e+00|6.726e+00|7.676e+00|
|   8/10   |6.726e+00|7.676e+00|6.726e+00|7.676e+00|
|   9/10   |6.726e+00|7.676e+00|6.726e+00|7.676e+00|
|  10/10   |6.726e+00|7.676e+00|6.726e+00|7.676e+00|
|--------------------------------------------------|
============================ nnodely Training Time =============================
Total time of Training:       0.4841020107269287
================================================================================
finale state:  {}