Posted at

nanが出た時のメモ

More than 1 year has passed since last update.

同じ問題で時間を費やしてしまう可能性のある人(未来の自分を含む)への共有として備忘録


学習中にnanが出た

tfdbg使えという声も聞こえてきそうですが、結構大きなネットワークだったりするとデバッグ時には部分的に並列で実行していた学習が直列にされるっぽいためnanが実際に出るまで回すのにアホみたいに時間がかかります。

こんな感じのログが出ます。

For debugging, tfdbg is changing the parallel_iterations attribute of the Enter/RefEnter node "training_1/Adam/gradients/lstm_1/while/mul_5_grad/BroadcastGradientArgs/Enter" on device "/job:localhost/replica:0/task:0/device:CPU:0" from 32 to 1. (This does not affect subsequent non-debug runs.)

そのためデバッガに頼る前にある程度目星が付きそうな所はそもそも可能性として潰しておきたいというのが現実です。


sqrt

割りと色んな所で見る $\sqrt x$ です。Tensorflowでは割りと気軽に tf.sqrt() なんて書いてしまいますがちょっと気をつける点があります。

まず第一に誰もが思いつくのが(複素数を明示的に扱っている訳ではない場合に)負の数を入れたらダメだということ。

そこでこんな風にしたりします。

tf.sqrt(tf.clip_by_value(x, 0, 十分に大きい数値 or np.inf))

これで、フォワードプロパゲーションの時は問題ありません。$\sqrt 0$は0です。

しかし問題はバックプロパゲーションの際、$f(x)=\sqrt x$ を微分すると

$\frac{\mathrm{d}f(x)}{\mathrm{d}x} = \frac{1}{2}x^{-\frac{1}{2}} = \frac{1}{2\sqrt x}$

このようになるため $x$ は分母に飛んでいきます。

ここまで来ればお察しかと思いますが、 $x = 0$の時に明らかに問題となります。

前後の繋がりによってどう回避するのが最適かは異なりますので敢えてコードは書きませんが nan や inf と戦っている方は参考にどうぞ。


便利でも原理は知っておこう

ここ最近のライブラリの発展は目覚ましく、正直背景知識なんてほとんどなくてもKerasのチュートリアルを適当に触ってあとは入力データとネットワークの中をちょこちょこいじればそれっぽいものができてしまいます。

それはそれで素晴らしいのですが、背景で動いている数学的なロジックはやはり知っていたほうが可能性が圧倒的に広がると思います。というか、そうじゃない機械学習エンジニアが世に溢れて、そういう人たちが一般の認識になってしまって、本当にできる人も含めて買い叩かれてしまう世の中になってしまうと悲しいですよね。

最近それが現実になりつつあるような気がしていて、この記事を見て「なんで微分するの?」という疑問を持つ人も一定数いるような気もしています…