APIのfit()でのValidation精度と、訓練ループを書いたときの精度でかなり(1~2%)違うという状況に遭遇しました。特定の文を忘れただけだったのですが、解決に1日かかったのでメモとしておいておきます。TPUランタイムKerasのfit()の場合のコードCIFAR-10です。こちらの記事のコードとほとんど同じです。main()fit()に「validation_data=」で入れたときの、Validation精度は間違っていません。fitでのValidation精度と、訓練ループでValidation精度を計測したときの精度が微妙に異なることはありますが、それでも0.05%ぐらいの微小な差です(1%も2%も誤差は出ない)。KerasのfitでのValidation精度は92.5%となりました(93%以上出ることもある)。カスタム訓練ループ(間違った例)これは誤った例です。どこが誤っているのか探してみてださい。自分はこの間違い見つけるのに1日かかりました。main()Validation精度を見てみましょう。この間違った例では91.61%となりました。fitの場合より、1~1.5%ぐらい下がっています。困ったのは、このコード特にエラーも出さずに訓練が普通に進んでしまうのですよね(今後のTFで変わるかもしれません)。いろんな可能性を疑わないといけないのがつらかったです。間違いの原因では答えを。この2行を入れなかったのが間違いでした。Training用にデータセットをコンバートするためのものです。TPUのように複数のデバイスで訓練する際は、この変換が必要なのです。distribute_datasetへの返還前後での損失関数の挙動もう少し挙動を詳しく見てみましょう。tf.keras.losses.SparseCategoricalCrossentropy(reduction=tf.keras.losses.Reduction.NONE)としているため、サンプル単位の損失値が計算されます。デバイスあたりのバッチサイズとはなにかというと、バッチをデバイス数で割ったものです。バッチサイズが128で、デバイス数が8なら、デバイスあたりのバッチサイズは16となります。print(per_sample_loss)この値のshapeを見ればいいわけです。device=/job:worker/replica:0/task:0/device:CPU:0)このように、デバイスあたりのバッチサイズではなく、全体の(グローバルな)バッチサイズが損失計算上にあらわれているのです。trian_on_batchはDistributeに(デバイス単位で分散されて)計算されています。これは何を意味するのかというと、デバイス単位でデータを分割せずに、全てのデバイスで同一のデータを参照して訓練しているということになります。device=/job:worker/replica:0/task:0/device:CPU:0)shape=(16,)となり、デバイス単位でデータが分割されるようになりました。これで正しい結果になりました。正しいコード正しいコードの全体を張ります。誤ったコードに2行追加しただけです。main()Validation精度は92.64%となりました。これでやっとKerasのfitと同じ値が出ました。学習曲線Kerasのfit、カスタム訓練の間違った例、カスタム訓練の正しい例の学習曲線です。それぞれ別の学習なので、細かな差は出ています。間違った例(custom_incorrect)の方が一歩精度が低いことが確認できるでしょう。Training用のデータセットに変換しないとかなり精度が落ちる。Commentコメントをキャンセルメールアドレスが公開されることはありません。