ehsanhaghighat/sciann

sn.set_random_seed doesn't make initialized weights and training results reproducible

Closed this issue · 3 comments

The code below doesn't reproduce the same weights when model is initialized multiple times, even after using sn.set_random_seed function.

import sciann as sn
from sciann.utils.math import diff

seed = 43634
sn.set_random_seed(seed)

for i in range(4):

    x = sn.Variable('x',dtype='float64')
    y = sn.Variable('y',dtype='float64')

    inputs = [x,y]
    p = sn.Functional('p', inputs,2*[10], activation='tanh')

    ## L1-loss
    L1 = diff(p, x, order=2) + diff(p, y, order=2)

    losses = [L1]

    m = sn.SciModel(inputs, losses)

    weights = p.get_weights()

    ## just talking a slice to compare
    compare_weights = weights[0][0][0]

    print(f'############## Weights Iter: {i}')
    print(compare_weights)

Output:

############## Weights Iter: 0
[-0.08364122 -0.39584261  0.46033181  0.699524   -0.15388536  1.13492848
  0.97746673  0.0638296   0.22659807 -0.36424939]
############## Weights Iter: 1
[-0.57727796 -0.53107439 -0.36321291 -0.17676498 -0.00334409 -0.71008476
  0.98622227 -0.13798297  0.09670978 -1.08998305]
############## Weights Iter: 2
[-1.49435514  0.80398993  0.89099648 -0.35270435 -0.87543759 -1.57591196
  0.3990877   0.57710672  0.60861149  0.06177852]
############## Weights Iter: 3
[-0.4822131   0.8055504   0.2928848   1.15362153  0.95912567  0.30233269
  0.41268821  0.85532438 -0.36524137 -0.71060004]

I was able to fix this by adding a parameter init_seed to the sciann.Functional and passing this init_seed to the "seed" parameter of prepare_default_activations_and_initializers (utils/utilities.py) method called inside the sciann.Functional.

And now if we use this init_seed then the weights initialized become reproducible (and also the training results).

import sciann as sn
from sciann.utils.math import diff

seed = 43634
sn.set_random_seed(seed)

for i in range(4):

    x = sn.Variable('x',dtype='float64')
    y = sn.Variable('y',dtype='float64')

    inputs = [x,y]
    p = sn.Functional('p', inputs,2*[10], activation='tanh',init_seed=seed) ## passing the init_seed

    ## L1-loss
    L1 = diff(p, x, order=2) + diff(p, y, order=2)

    losses = [L1]

    m = sn.SciModel(inputs, losses)

    weights = p.get_weights()

    ## just talking a slice to compare
    compare_weights = weights[0][0][0]

    print(f'############## Weights Iter: {i}')
    print(compare_weights)

Output:

############## Weights Iter: 0
[ 0.39380369  0.35950971  0.74893839  1.33222068  0.5684224  -0.50967855
 -0.63144903  0.12257833 -0.33385106  0.08463333]
############## Weights Iter: 1
[ 0.39380369  0.35950971  0.74893839  1.33222068  0.5684224  -0.50967855
 -0.63144903  0.12257833 -0.33385106  0.08463333]
############## Weights Iter: 2
[ 0.39380369  0.35950971  0.74893839  1.33222068  0.5684224  -0.50967855
 -0.63144903  0.12257833 -0.33385106  0.08463333]
############## Weights Iter: 3
[ 0.39380369  0.35950971  0.74893839  1.33222068  0.5684224  -0.50967855
 -0.63144903  0.12257833 -0.33385106  0.08463333]

@ehsanhaghighat Let me know your though on this, I can raise a pull request with the required code changes.

you need to move sn.set_random_seed(seed) to after the for loop.

With reference to your advice, I tried the implementations below but in both the implementations the initialized weights were not reproducible.

1st Variation - sn.set_random_seed in the begining of the for loop

seed = 43634
for i in range(4):
    sn.set_random_seed(seed)
    
    x = sn.Variable('x',dtype='float64')
    y = sn.Variable('y',dtype='float64')

    inputs = [x,y]
    p = sn.Functional('p', inputs,2*[10], activation='tanh')

    ## L1-loss
    L1 = diff(p, x, order=2) + diff(p, y, order=2)

    losses = [L1]

    m = sn.SciModel(inputs, losses)

    weights = p.get_weights()

    ## just talking a slice to compare
    compare_weights = weights[0][0][0]

    print(f'############## Weights Iter: {i}')
    print(compare_weights)

Output:

############## Weights Iter: 0
[ 0.17192684  0.8505472   1.5303545  -0.07131549 -0.86318325 -0.01254475
 -0.95688675 -0.56421035 -0.13802275 -0.3585783 ]
############## Weights Iter: 1
[ 0.30115654  0.45204806  1.37423179  0.07729327 -0.64992897  0.74816071
 -0.23140187  0.54765457 -0.75551972 -0.53503478]
############## Weights Iter: 2
[ 0.26492076  0.88008895 -0.41499606  1.08219736  1.27035521 -1.43900151
 -0.99588373  0.50230552 -1.13693667  0.40157258]
############## Weights Iter: 3
[ 0.31586012 -0.2186777  -0.78905957  0.98990586 -0.3413854   1.00164896
 -0.31305837  0.10532799 -0.73633277 -1.54556423]

2nd Variation - sn.set_random_seed in the end of the for loop

seed = 43634
for i in range(4):
    
    x = sn.Variable('x',dtype='float64')
    y = sn.Variable('y',dtype='float64')

    inputs = [x,y]
    p = sn.Functional('p', inputs,2*[10], activation='tanh')

    ## L1-loss
    L1 = diff(p, x, order=2) + diff(p, y, order=2)

    losses = [L1]

    m = sn.SciModel(inputs, losses)

    weights = p.get_weights()

    ## just talking a slice to compare
    compare_weights = weights[0][0][0]

    print(f'############## Weights Iter: {i}')
    print(compare_weights)
    
    sn.set_random_seed(seed)

Output:

############## Weights Iter: 0
[ 0.62614818  0.24746175  0.3359769  -0.78704616 -0.06134327 -1.02164462
 -0.07365291 -1.04365773  0.11022187  1.09975384]
############## Weights Iter: 1
[-0.98858494  0.6591131   0.00676309  0.07054628  0.34525049  0.070351
 -0.24014073 -0.24590834  0.92014918 -0.11158274]
############## Weights Iter: 2
[ 0.25006986 -0.71967126  0.44816473 -0.31196732  0.31224364  0.67646486
 -0.03281037  0.54980068  0.17476912 -1.2574309 ]
############## Weights Iter: 3
[-0.53281204  0.23683607 -0.76720324 -1.01064904  1.21020394  1.41065052
 -0.30724967 -0.11914628  0.58634421 -0.53657643]

@ehsanhaghighat Am I missing something here ?
I anyways have raised a pull request for this, you can review.