機械学習を行う上で、GPUによる計算誤差が問題となる場合があります。
- CPUとGPUで学習または推論を行った場合に結果に差が出る
- GPUの型番やソフトウェアの環境(ドライバやCUDA等)が異なる場合に差が出る
- 同じ計算を繰り返し行った場合に差が出る
など、環境間や繰り返しの再現性が確保できないといったことが起こります。
この記事ではNVIDIA製GPU(CUDA)とPyTorch環境におけるそれらの原因と対策についてまとめます。
浮動小数点計算の誤差
前提として、コンピュータで浮動小数点の計算を行う場合、CPU、GPU問わず誤差が生じるため、ニューラルネットワークのあらゆる箇所で誤差を生じる可能性があります。
原理を詳しく述べることはしませんが、そもそも一般的に使われる浮動小数点型の32bitや64bitという限られた情報量で実数を表す精度には限界があることが1つの原因です。
詳しい誤差の種類や原理については「浮動小数点 誤差」などで調べて頂くと良い解説ページが見つかると思います。
GPUで計算する際の非決定性
GPUで計算を行う場合、計算の高速化を行うため計算が非決定的となっている場合があります。つまり同じ計算を繰り返した場合に再現性が保たれません。
PyTorchでは再現性について以下のドキュメントが用意されています。
繰り返し再現性を得たい場合、前提として乱数のシードは固定する必要があります。PyTorch環境では以下のように使っているモジュール別に固定する必要があります。
import torch
import random
import numpy as np
# PyTorchのシードを固定
torch.manual_seed(0)
# 以下、必要があれば
random.seed(0) # Pythonのrandomモジュールのシード固定
np.random.seed(0) # numpyのシード固定
しかしこれらを行っても、GPUの計算の非決定性は残ります。以下のようにして決定的な計算を行うことができます。
torch.backends.cudnn.benchmark = False
torch.use_deterministic_algorithms(True)
ただし計算を決定的に出来ない場合にはエラーとなるようで、再現性が保てるかは使用している計算による(つまりモデルによる)ということになります。
GPUアーキテクチャによる差
NVIDIAアーキテクチャの場合(TensorFloat32)
NVIDIAではAmpere以降のアーキテクチャでTensorFloat32(TF32)という浮動小数点型が導入されています。
これは従来の32bit浮動小数点型(FP32)を置き換える目的で導入されているのですが、公式の解説通り値の大小を表す指数部は8bitと同様に確保されているものの、精度を表す仮数部はFP16相当のビット数しか確保されていません。
これはTF32は精度としては半精度しかないことになります。合計のビット数は符号部合わせて19bitなので、32という名前がついているのは少し疑問に思います。
NVIDIAが主張するように、多くの場合モデルの精度を落とさずに計算の高速化に寄与する可能性があるのですが、逆に言うと計算の構造によっては大きく精度が落ちる可能性があります。(実際、結果が大きく異なる計算に出くわしたことがあります)
そしてPyTorchの場合、バージョンにもよりますが32bitの計算をする場合デフォルトでこのTF32が有効になっているため、Ampere前後のアーキテクチャで計算を比較する場合には注意が必要な部分となります。
以下のようにして無効化することができます。
torch.backends.cuda.matmul.allow_tf32 = False
torch.backends.cudnn.allow_tf32 = False
NVIDIA以外のアーキテクチャの場合
上で紹介したTensorFloat32以外にも、機械学習では一般的な浮動小数点型とは異なる構造の浮動小数点型が使われることがあります。
Googleはbfloat16という半精度型の浮動小数点型を提案しており、TPUで使用可能とのことです。
このように機械学習では一般的なものとは異なる構造の浮動小数点型を使う場合があり、CPUと比較する場合やGPUのアーキテクチャ、世代等を超えて比較する場合には注意が必要です。
最後に(再現性を保つことの必要性)
ここまで見てきたように、GPUではいくつかの要因により環境間や繰り返し計算で誤差が生じる可能性があります。
再現性を確保することが重視される場合、なるべく環境を揃え、非決定的な要因を排除することになりますが、その場合パフォーマンスが落ちる可能性が高いです(そもそも誤差の要因が基本的には高速化を目指した仕組みが原因のため)。また、再現性を必ず保てるとも限りません。
そして環境をなるべく揃えようとすると、環境が固定されアップデートが難しくなります。ご存知の通り現在機械学習分野はソフトウェアもハードウェアも日進月歩なのでこれは大きなデメリットとなる可能性があります。
それでも再現性の担保が重要な場合には仕方ないのですが、多くの場合もっと柔軟にモデルの出力が妥当かを確認したほうが良い場合もあります。
モデルの出力テンソルが小数点以下◯桁で一致することが大事なのではなく、分類問題だったら正しく分類できること、生成AIなら妥当な結果が生成されること、を様々な指標を用いて素直に評価した方が良い場合が多いです。
そもそも再現性の確保が必要なのかどうか、バランスよく考える必要があります。
コメント