Bias and Weights relation between Pytorch and Tensorflow

username: peter_vala
cooked: <p>Hey everyone, I’m testing how both frameworks differ in their calculations at the same time I’m trying to make both close to same as possible. Well for this tests I use the same weights and bias parameters in Initialization for the same equivelant network arquitecture.<br>
For this specific case I’m using a SGD optimizer with momentum at 0. I also use a custom function for the optimizer in Tensorflow so it becomes as similar to Pytorch.</p>
<pre><code class="lang-auto"># Given a callable model, inputs, outputs, and a learning rate...
def train_SGD_momentum0(model, x, y, learning_rate):
  layer = 0
  with tf.GradientTape(persistent=True) as t:
    # Trainable variables are automatically tracked by GradientTape
    current_loss = loss_func_TF(y, model(x))
  for k in range(0,len(model.variables),2):
    w = model.variables[k]   #tf.Variable(model.get_weights()[0])
    b = model.variables[k+1]    #     tf.Variable(model.get_weights()[1])

    # Use GradientTape to calculate the gradients with respect to W and b
    dw, db = t.gradient(current_loss, [w,b])

    while type(model.layers[layer]) is keras.layers.MaxPooling2D or type(model.layers[layer]) is keras.layers.Dropout or  type(model.layers[layer]) is keras.layers.Flatten:
            layer=layer+1
    
    # Subtract the gradient scaled by the learning rate
    model.layers[layer].kernel.assign_sub(learning_rate * dw)
    model.layers[layer].bias.assign_sub(learning_rate * db)
    layer = layer +1

</code></pre>
<p>For the models training I’m using a costum function where i use the same inputs for Pytorch network and permute them to use it in Tensorflow training loop.</p>
<p>I run this in some different datasets and this was what i got:</p>
<p><strong>MNIST</strong><br>
<div class="lightbox-wrapper"><a class="lightbox" href="https://discuss.pytorch.org/uploads/default/original/3X/6/e/6e1bb060eca6ff36ed3e1cacb77b749b49d9b141.png" data-download-href="https://discuss.pytorch.org/uploads/default/6e1bb060eca6ff36ed3e1cacb77b749b49d9b141" title="grafico_bias_pesos"><img src="https://discuss.pytorch.org/uploads/default/optimized/3X/6/e/6e1bb060eca6ff36ed3e1cacb77b749b49d9b141_2_431x500.png" alt="grafico_bias_pesos" data-base62-sha1="fI3QoC8zKqZO7e39IyG9f6lO7ol" width="431" height="500" srcset="https://discuss.pytorch.org/uploads/default/optimized/3X/6/e/6e1bb060eca6ff36ed3e1cacb77b749b49d9b141_2_431x500.png, https://discuss.pytorch.org/uploads/default/original/3X/6/e/6e1bb060eca6ff36ed3e1cacb77b749b49d9b141.png 1.5x, https://discuss.pytorch.org/uploads/default/original/3X/6/e/6e1bb060eca6ff36ed3e1cacb77b749b49d9b141.png 2x" data-dominant-color="FAFBFB"><div class="meta"><svg class="fa d-icon d-icon-far-image svg-icon" aria-hidden="true"><use href="#far-image"></use></svg><span class="filename">grafico_bias_pesos</span><span class="informations">600×695 49.8 KB</span><svg class="fa d-icon d-icon-discourse-expand svg-icon" aria-hidden="true"><use href="#discourse-expand"></use></svg></div></a></div></p>
<p><strong>Weather dataset</strong><br>
<div class="lightbox-wrapper"><a class="lightbox" href="https://discuss.pytorch.org/uploads/default/original/3X/3/e/3ed1fb77702dbeee83c2111f39ab5e9d3144007f.png" data-download-href="https://discuss.pytorch.org/uploads/default/3ed1fb77702dbeee83c2111f39ab5e9d3144007f" title="bias_pesos_weather"><img src="https://discuss.pytorch.org/uploads/default/optimized/3X/3/e/3ed1fb77702dbeee83c2111f39ab5e9d3144007f_2_448x500.png" alt="bias_pesos_weather" data-base62-sha1="8XJugshmLFr34nZjLJICrkbG6En" width="448" height="500" srcset="https://discuss.pytorch.org/uploads/default/optimized/3X/3/e/3ed1fb77702dbeee83c2111f39ab5e9d3144007f_2_448x500.png, https://discuss.pytorch.org/uploads/default/original/3X/3/e/3ed1fb77702dbeee83c2111f39ab5e9d3144007f.png 1.5x, https://discuss.pytorch.org/uploads/default/original/3X/3/e/3ed1fb77702dbeee83c2111f39ab5e9d3144007f.png 2x" data-dominant-color="FBFBFC"><div class="meta"><svg class="fa d-icon d-icon-far-image svg-icon" aria-hidden="true"><use href="#far-image"></use></svg><span class="filename">bias_pesos_weather</span><span class="informations">563×627 32.8 KB</span><svg class="fa d-icon d-icon-discourse-expand svg-icon" aria-hidden="true"><use href="#discourse-expand"></use></svg></div></a></div></p>
<p><strong>sign language?</strong><br>
<div class="lightbox-wrapper"><a class="lightbox" href="https://discuss.pytorch.org/uploads/default/original/3X/2/7/275ed41bb189796b7182ce4cf2d5b63eea7670cf.png" data-download-href="https://discuss.pytorch.org/uploads/default/275ed41bb189796b7182ce4cf2d5b63eea7670cf" title="bias_pesos_gestos"><img src="https://discuss.pytorch.org/uploads/default/optimized/3X/2/7/275ed41bb189796b7182ce4cf2d5b63eea7670cf_2_412x500.png" alt="bias_pesos_gestos" data-base62-sha1="5ChN0XQeOFIoZulH9DdGfzm8c8L" width="412" height="500" srcset="https://discuss.pytorch.org/uploads/default/optimized/3X/2/7/275ed41bb189796b7182ce4cf2d5b63eea7670cf_2_412x500.png, https://discuss.pytorch.org/uploads/default/original/3X/2/7/275ed41bb189796b7182ce4cf2d5b63eea7670cf.png 1.5x, https://discuss.pytorch.org/uploads/default/original/3X/2/7/275ed41bb189796b7182ce4cf2d5b63eea7670cf.png 2x" data-dominant-color="FBFAFB"><div class="meta"><svg class="fa d-icon d-icon-far-image svg-icon" aria-hidden="true"><use href="#far-image"></use></svg><span class="filename">bias_pesos_gestos</span><span class="informations">555×672 37.6 KB</span><svg class="fa d-icon d-icon-discourse-expand svg-icon" aria-hidden="true"><use href="#discourse-expand"></use></svg></div></a></div></p>
<p><strong>Gtsrb</strong><br>
<div class="lightbox-wrapper"><a class="lightbox" href="https://discuss.pytorch.org/uploads/default/original/3X/f/c/fc0ae54079289591342c54750577e8c9d84d4795.png" data-download-href="https://discuss.pytorch.org/uploads/default/fc0ae54079289591342c54750577e8c9d84d4795" title="bias_pesos_sinais"><img src="https://discuss.pytorch.org/uploads/default/optimized/3X/f/c/fc0ae54079289591342c54750577e8c9d84d4795_2_414x500.png" alt="bias_pesos_sinais" data-base62-sha1="zXFFir3npL9teXC2V4KaagdpqzH" width="414" height="500" srcset="https://discuss.pytorch.org/uploads/default/optimized/3X/f/c/fc0ae54079289591342c54750577e8c9d84d4795_2_414x500.png, https://discuss.pytorch.org/uploads/default/original/3X/f/c/fc0ae54079289591342c54750577e8c9d84d4795.png 1.5x, https://discuss.pytorch.org/uploads/default/original/3X/f/c/fc0ae54079289591342c54750577e8c9d84d4795.png 2x" data-dominant-color="FAFBFB"><div class="meta"><svg class="fa d-icon d-icon-far-image svg-icon" aria-hidden="true"><use href="#far-image"></use></svg><span class="filename">bias_pesos_sinais</span><span class="informations">570×688 43.7 KB</span><svg class="fa d-icon d-icon-discourse-expand svg-icon" aria-hidden="true"><use href="#discourse-expand"></use></svg></div></a></div></p>
<p>For every figure above the first graphic represents the avarege difference of weights of both networks and the second represents the avarege difference of the biases of both networks.<br>
My question is comes in what conclusion i can take from the first three where the avarege difference of weights become higher epoch after epoch and the biases become lower. And what for the same pipeline taken in the firsts three datasets why did GTSRB become different and is diverging?<br>
Thanks a lot for all the help <img src="https://discuss.pytorch.org/images/emoji/apple/slight_smile.png?v=12" title=":slight_smile:" class="emoji" alt=":slight_smile:" loading="lazy" width="20" height="20"></p>

username: ptrblck
cooked: <p>Are you seeing these differences only between the frameworks or also if you just rerun the same training pipeline in a single framework?<br>
If you are not making sure the outputs are bitwise deterministic, I would expect to see a difference convergence behavior and a different set of final parameters even in the same framework (the final accuracy might still be approx. equal).</p>

username: peter_vala
cooked: <p>Hey <a class="mention" href="/u/ptrblck">@ptrblck</a> thanks for your reply at first place. I did a test on what really happened and what i got was this graphic:<br>
<div class="lightbox-wrapper"><a class="lightbox" href="https://discuss.pytorch.org/uploads/default/original/3X/6/5/65f3a6ea22f6e1c5428723cd1e990a2d6fc9242b.png" data-download-href="https://discuss.pytorch.org/uploads/default/65f3a6ea22f6e1c5428723cd1e990a2d6fc9242b" title="pt_pt"><img src="https://discuss.pytorch.org/uploads/default/optimized/3X/6/5/65f3a6ea22f6e1c5428723cd1e990a2d6fc9242b_2_411x500.png" alt="pt_pt" data-base62-sha1="exUfhHh5U187rP5ZlHnJ2re80Nd" width="411" height="500" srcset="https://discuss.pytorch.org/uploads/default/optimized/3X/6/5/65f3a6ea22f6e1c5428723cd1e990a2d6fc9242b_2_411x500.png, https://discuss.pytorch.org/uploads/default/original/3X/6/5/65f3a6ea22f6e1c5428723cd1e990a2d6fc9242b.png 1.5x, https://discuss.pytorch.org/uploads/default/original/3X/6/5/65f3a6ea22f6e1c5428723cd1e990a2d6fc9242b.png 2x" data-dominant-color="FBFBFB"><div class="meta"><svg class="fa d-icon d-icon-far-image svg-icon" aria-hidden="true"><use href="#far-image"></use></svg><span class="filename">pt_pt</span><span class="informations">574×697 30.7 KB</span><svg class="fa d-icon d-icon-discourse-expand svg-icon" aria-hidden="true"><use href="#discourse-expand"></use></svg></div></a></div></p>
<p>So the weights seems to diverge and bias seems to be allways the same, i also got the same acc but the loss are diferrent on the evaluation of the models. I also got some really close different losses per batch in the training loop. So am I doing something wrong and if so what it is?</p>
<p>Here is also the training loop:</p>
<pre><code class="lang-auto">niter = 10

n_samples = len(train_pt)

for epoca in range(0, niter):
    for i,(image_element,target_element) in enumerate(train_pt):
        
        optimizer.zero_grad()
        predictions = net(image_element)
        loss = loss_criterion(predictions, target_element)
        loss.backward()
        optimizer.step()
     
      
        net2.zero_grad()
        outputs2 = net2(image_element)
        loss2 = loss_criterion(outputs2, target_element)
        loss2.backward() # compute gradients
        for f in net2.parameters():
          f.data.sub_(f.grad.data * optimizer.defaults['lr'])
        
</code></pre>

username: ptrblck
cooked: <p>Differences in the 1e-6 range are expected for <code>float32</code> if no-deterministic algorithms are used due to the limited floating point precision. You would also expect to see the same or a similar behavior using the same framework and different runs in case you are only seeding but are not forcing the usage of deterministic algorithms which is why I asked you to compare different runs in the same framework first.</p>

username: peter_vala
cooked: <p>Hey <a class="mention" href="/u/ptrblck">@ptrblck</a>  thanks again for the anwser. What bother me is the fact that the difference in weights is growing and not stable or 0 which i expect in case of the run in same framework. I really wanted to understand why in some cases the biases are becoming closer but in the GTSRB looks like are diverging, Could you give me some explanation about it?. Another thing is why, in the same framework, since I’m using the same pipeline, same models , same initialization and same seeds but the average difference of weights are not constant like the biases? I expected it to produce the same floating error at least. Also how can i make my algoritms deterministic in this case?</p>
<p>Thanks in advance <img src="https://discuss.pytorch.org/images/emoji/apple/slight_smile.png?v=12" title=":slight_smile:" class="emoji" alt=":slight_smile:" loading="lazy" width="20" height="20"></p>

username: ptrblck
cooked: <aside class="quote no-group" data-username="peter_vala" data-post="5" data-topic="159245">
<div class="title">
<div class="quote-controls"></div>
<img loading="lazy" alt="" width="24" height="24" src="https://discuss.pytorch.org/user_avatar/discuss.pytorch.org/peter_vala/48/45326_2.png" class="avatar"> peter_vala:</div>
<blockquote>
<p>What bother me is the fact that the difference in weights is growing and not stable or 0 which i expect in case of the run in same framework.</p>
</blockquote>
</aside>
<p>I don’t think this is a valid expectation. Let’s assume you are indeed using non-deterministic algorithms (you haven’t confirmed it): the output would differ by a “small” amount in the forward pass, the gradients would thus also have a small error (from the small error in the output as well as from non-deterministic algorithms to compute them), and the parameter updates would eventually move the entire parameter set using these small errors. Once the parameters were updated, the next iteration will still create the expected small absolute error caused by the non-deterministic algorithms, but will also increase the overall error in the output since the parameters now also differ.<br>
I would not expect to see the model would “correct” it somehow and don’t know why it should happen, so could you explain your expectation a bit more?</p>
<aside class="quote no-group" data-username="peter_vala" data-post="5" data-topic="159245">
<div class="title">
<div class="quote-controls"></div>
<img loading="lazy" alt="" width="24" height="24" src="https://discuss.pytorch.org/user_avatar/discuss.pytorch.org/peter_vala/48/45326_2.png" class="avatar"> peter_vala:</div>
<blockquote>
<p>Another thing is why, in the same framework, since I’m using the same pipeline, same models , same initialization and same seeds but the average difference of weights are not constant like the biases?<br>
I expected it to produce the same floating error at least. Also how can i make my algoritms deterministic in this case?</p>
</blockquote>
</aside>
<p>Check the <a href="https://pytorch.org/docs/stable/notes/randomness.html">Reproducibility docs</a> which explain how to force deterministic algorithms.</p>

username: peter_vala
cooked: <p>Hey <a class="mention" href="/u/ptrblck">@ptrblck</a>, thanks again for your answer :). My goal here is to really understand how close i can get both frameworks to produce the same output. As far I as understood, there are differences than can be caused by differences in algoritms calculations or the default initializations. So the point here is to reduce the much as possible in the differences of the output  so I be able to “name” the causes to the small growing errors occuring in the training process.</p>
<p>So if I take the case of checking differences between both frameworks what i got is that even without any training and just transposing the weights and biases to the other framework it will produce an small error on the loss and the acc about 1e-6 in the evaluation of any test set <strong>tested</strong>.<br>
Due to this small small value and taking the fact that individualy calculating the loss for every input there are some that produce losses with really small differences and others which are exactly the same, i was ready for differences in the training  just like what we can see from the weights graphic. The thing is, why are the biases taking a different behaviour of the weights and getting closer. What was going on my mind was that even if the weights were “diverging” the biases in other way were converging in compensation arround the error value because it was getting in the minimum. But there we go, I found one case where biases were not taking the same behaviour of the last one and were diverging. So about this part i want to understand if Im in a good spot or if Im wrong and there are more aspects to take in mind before i can assume the value error is only because of the floating calculations.</p>
<p>Now about the differences in the same framework it bring me a new point that maybe i havent deterministic all the process. But fun fact the biases in this case take another behaviour that is being constant.</p>
<p>I tried to resume all the idea so maybe you can get better my doubt about what i have obtained.</p>

username: peter_vala
cooked: <p>Hey <a class="mention" href="/u/ptrblck">@ptrblck</a>. I have noticed that i was almost using everything for the reproducibility expect<br>
torch.use_deterministic_algorithms(True). Well for the rest I found out that for the training I had a small mistake done in the GTSRB dataset and after correct it this is how the avareage difference is:<br>
<div class="lightbox-wrapper"><a class="lightbox" href="https://discuss.pytorch.org/uploads/default/original/3X/3/b/3bfd053e64df2e00831d4d6af3bd97e8a6456cc0.png" data-download-href="https://discuss.pytorch.org/uploads/default/3bfd053e64df2e00831d4d6af3bd97e8a6456cc0" title="sinais"><img src="https://discuss.pytorch.org/uploads/default/optimized/3X/3/b/3bfd053e64df2e00831d4d6af3bd97e8a6456cc0_2_379x500.png" alt="sinais" data-base62-sha1="8yGgphzbMkzfwZs1rwLAtBljVLy" width="379" height="500" srcset="https://discuss.pytorch.org/uploads/default/optimized/3X/3/b/3bfd053e64df2e00831d4d6af3bd97e8a6456cc0_2_379x500.png, https://discuss.pytorch.org/uploads/default/original/3X/3/b/3bfd053e64df2e00831d4d6af3bd97e8a6456cc0.png 1.5x, https://discuss.pytorch.org/uploads/default/original/3X/3/b/3bfd053e64df2e00831d4d6af3bd97e8a6456cc0.png 2x" data-dominant-color="FAFAFA"><div class="meta"><svg class="fa d-icon d-icon-far-image svg-icon" aria-hidden="true"><use href="#far-image"></use></svg><span class="filename">sinais</span><span class="informations">521×687 46.9 KB</span><svg class="fa d-icon d-icon-discourse-expand svg-icon" aria-hidden="true"><use href="#discourse-expand"></use></svg></div></a></div><br>
I also rerun in the same framework the training pipeline and the result is almost the same with slightly differences in the values:<br>
<div class="lightbox-wrapper"><a class="lightbox" href="https://discuss.pytorch.org/uploads/default/original/3X/5/e/5e7f0c9a9c1a62dd0c350ed70aef2f5f3d3f3292.png" data-download-href="https://discuss.pytorch.org/uploads/default/5e7f0c9a9c1a62dd0c350ed70aef2f5f3d3f3292" title="new_pt_pt"><img src="https://discuss.pytorch.org/uploads/default/optimized/3X/5/e/5e7f0c9a9c1a62dd0c350ed70aef2f5f3d3f3292_2_370x500.png" alt="new_pt_pt" data-base62-sha1="dtX5cHSnN3iY02INNFLRXoQreb8" width="370" height="500" srcset="https://discuss.pytorch.org/uploads/default/optimized/3X/5/e/5e7f0c9a9c1a62dd0c350ed70aef2f5f3d3f3292_2_370x500.png, https://discuss.pytorch.org/uploads/default/original/3X/5/e/5e7f0c9a9c1a62dd0c350ed70aef2f5f3d3f3292.png 1.5x, https://discuss.pytorch.org/uploads/default/original/3X/5/e/5e7f0c9a9c1a62dd0c350ed70aef2f5f3d3f3292.png 2x" data-dominant-color="FAFAFA"><div class="meta"><svg class="fa d-icon d-icon-far-image svg-icon" aria-hidden="true"><use href="#far-image"></use></svg><span class="filename">new_pt_pt</span><span class="informations">507×684 39.8 KB</span><svg class="fa d-icon d-icon-discourse-expand svg-icon" aria-hidden="true"><use href="#discourse-expand"></use></svg></div></a></div><br>
Also an extra i found out that the loss value at the beginning when i eval the model with the test data is exactly the same but when it comes to training the loss slowly start to differ but in the firsts iterations is the same in 1e-15.</p>
<p>Hope this new information helps with an answer <img src="https://discuss.pytorch.org/images/emoji/apple/slight_smile.png?v=12" title=":slight_smile:" class="emoji" alt=":slight_smile:" loading="lazy" width="20" height="20"></p>