The problematic Adam stability in Automatic Mixed Precision training

username: Azerus
cooked: <p>Hello,</p>
<p>I am working on a multi-classification task (using Cross entropy loss) and I am facing an issue when working with adam optimizer and mixed precision together.</p>
<p>After few hours of trainings the loss start to go to NaN. I saw <a href="https://discuss.pytorch.org/t/adam-half-precision-nans/1765">here</a> that some people faced the same issue and advised to increase <a href="https://pytorch.org/docs/stable/generated/torch.optim.Adam.html#torch.optim.Adam" rel="noopener nofollow ugc">the <code>eps</code> term of Adam</a>, such that it will not be rounded to 0 in float16, by setting it to 1e-4 when working in half precision. (Some people used a lower eps=1e-7 as <a href="https://github.com/pytorch/pytorch/issues/26218" rel="noopener nofollow ugc">there</a> but others arguing it may not solve the problem).</p>
<p>So I tried this suggestion, but with <code>eps</code>=1e-4 my loss hardly decrease over time while the loss was decreasing quite fast when using the default <code>eps</code>=1e-8 (until it leads to NaN), the same behavior has been observed by other people, as in <a href="https://discuss.pytorch.org/t/the-effect-of-epsilon-on-adam-optimizer/102593">this post</a> it seems.</p>
<p>Is it possible to avoid those NaN without increasing too much the <code>eps</code> term of Adam ?</p>
<p>Thanks,<br>
Thomas</p>

username: tom
cooked: <p>Hi Thomas,</p>
<p>so you are using AMP with <a href="https://pytorch.org/docs/stable/amp.html#gradient-scaling" rel="noopener nofollow ugc">gradient scaling</a>?</p>
<p>Gradient hooks will slow things down a bit, but maybe not terribly.</p>
<p>One quick thing you could try is whether the problem happens with a particular (group of) parameter(s) and use a larger eps only for them (by using parameter groups).</p>
<p>Best regards</p>
<p>Thomas</p>

username: Azerus
cooked: <p>Hello Tom,</p>
<p>Thanks for your answer. Yes I do use AMP with gradient scaling following <a href="https://pytorch.org/tutorials/recipes/recipes/amp_recipe.html#all-together-automatic-mixed-precision" rel="noopener nofollow ugc">this recipe</a>.<br>
By the way, as the optimizer update is outside of the amp autocast context, is the small epsilon really problematic with respect to the precision?</p>
<p>Thanks for the suggestion to use parameter groups, it may be a good idea I will probably investigate this solution.</p>
<p>For now, I am doing few experiments with amp disabled and a batch size halved, but I will take you inform If I use back AMP.</p>
<p>thanks</p>

username: tom
cooked: <p>Let’s say I have limited insight into what exactly is happening. (For this it would be interesting to see 1) the value of the param &amp; optimizer state just before it turns NaN 2) the value of the gradient that causes the state to turn NaN.</p>
<p>So the epsilon helps when v_hat is 0, i.e. when v is 0.</p>
<aside class="quote no-group" data-username="Azerus" data-post="1" data-topic="137434">
<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/azerus/48/33745_2.png" class="avatar"> Azerus:</div>
<blockquote>
<p>So I tried this suggestion, but with <code>eps</code>=1e-4 my loss hardly decrease over time while the loss was decreasing quite fast when using the default <code>eps</code>=1e-8</p>
</blockquote>
</aside>
<p>This seems to tell me that the loss gradient is terribly small all along.</p>
<p>One other thing you might try is to switch Adam, which works at a coefficient level, for an optimizer that works at a tensor level like LAMB (there are more, and probably one that is closer to Adam in spirit, but this is the acronym I can remember).</p>
<p>Best regards</p>
<p>Thomas</p>

username: Azerus
cooked: <p>Ok, LAMB and LARS optimizer seems interesting, I’m not familiar with them. I’ll definitely give them a try.</p>
<p>Just for information, since last message:<br>
I tried training with Adam and eps=1e-6 + amp, the training start well, decreasing at a good rate, until it goes to NaN after some time.<br>
I tried training with Adam and default eps=1e-8 without amp, the training is fine.<br>
I am gonna have a look to the param values and optimizer states before the training collapse soon (I need to finish some runs before).</p>
<p>Just a question, why do you advice me to try LAMB optimizer? Is it because you think the trust ratio may help to upscale the loss gradient in the layers where the said gradient is very small?</p>
<p>Oh also, the batch size I use is relatively small as I’m limited by my gpu memory and that I work with quite heavy input data and model. This may not be ideal with LAMB or LARS, as they seems to work better on huge batch. To give a rough idea:</p>
<ul>
<li>With Adam optim without AMP, the max batch size I can use is only 3.</li>
<li>With Adam optim with AMP, the max batch size I can use is around 5.</li>
<li>With SGD or RMSPROP optim with AMP, the max batch size I can use is around 16. RMSPROP converge really slower and with significantly lower accuracy than Adam in my case. I did not tried SGD yet, but I plan to.</li>
</ul>
<p>Still a lot of thing to try and test, I’ll give an update if I found something interesting.</p>
<p>Best regards,<br>
Thomas</p>

username: tom
cooked: <p>First, I have to say you know a lot more about your situation also in training than me, so take all this with a grain of salt.</p>
<p>The key advantage of LAMB/LARS to me here is that they work at the tensor level while Adam works at the “single scalar entry” level for the adaptiveness. LARS might a more natural change from Adam than LAMB.<br>
If you are concerned about batch size for the gradient step, you could accumulate a few batches before taking an optimizer step.</p>
<p>Best regards</p>
<p>Thomas</p>

username: Azerus
cooked: <p>Hi Thomas,</p>
<p>Little updates:<br>
From my last messages, I mainly worked with Adam optimizer using float32 precision, also I started doing batch accumulation (giving smoother training, but also slightly better accuracy in average). I did not got the NaN problem in f32, but I observed some times a peak 100x higher than usual in my loss after hours of training making the model loosing its progress. It’s possible that those jumps in the loss I observed in f32 training share the same root cause as the NaN problem I got with mixed precision training. <strong>I think it may still coming from v_hat going close to 0 sometimes, and I realized that this kind of problem should be tackled by using the amsgrad variant of adam</strong>. As with amsgrad v_hat is taken from past maximum rather than moving average. I launched an experiment with amsgrad 48h ago, the training goes well so far. I’ll try it later with mixed precision to check if it solve the original problem, I still plan to play with LARS latter also.</p>
<p>Best regards,<br>
Thomas</p>

username: Azerus
cooked: <p>Hi Thomas</p>
<p>To take you inform, I implemented by myself the LARS optimizer and tested it without any fine tuning yet. Using a lr of 0.01, clipping the trust ratio in [1e-4, 1], without momentum nor weight_decay, it already slightly outperform adam optimizer. I’ll continue with LARS for now, thank you for your suggestions. As I ended up using LARS I marked your last answer as the solution. I want to highlight also that using adam with amsgrad was more stable in my case than without amsgrad.</p>
<p>Best regards,<br>
Thomas</p>