LLMの学習データは、同じ文章を1トークンずらして入力と正解にする
結論
LLMの学習方法を理解したいときは、因果言語モデルの入力と正解を、同じトークン列を1つずらした対応として見ると整理できます。未来を見ない仕組みと組み合わせることで、複数の位置について「次に来るトークン」をまとめて学習できます。
説明用の架空のトークンID列を [10, 24, 7, 31] とします。概念上は、入力側と正解側を次のように対応させます。
| その位置までの入力 | 次に来る正解 |
|---|---|
[10] |
24 |
[10, 24] |
7 |
[10, 24, 7] |
31 |
列として書けば、入力は [10, 24, 7]、正解は [24, 7, 31] です。元の列を1トークン分ずらした関係になっています。
ただし、実装で必ず2本の列を別々に保存するとは限りません。たとえばHugging Face Transformersでは、入力IDの列を正解列としても渡し、モデル側の損失計算で予測と正解の位置をずらす構成があります。
学習時は、未来側のトークンが見えないように因果マスクをかけます。複数の位置を1回の順伝播で計算しても、正解となる未来のトークンは入力から先読みできません。パディングなど、学習対象にしない位置は損失から外すこともできます。
参考:Attention Is All You Need、Causal language modeling(Hugging Face Transformers)
予測と正解のずれを数値にまとめたものが損失です。次は、その損失をどうやって重みの更新へ使うのかを見ます。
スレッドを開く スレッドを閉じる 2
前の投稿で求めた損失は、予測が正解からどれだけ外れているかを表します。ただし、損失の値だけでは、どの重みをどちらへ動かすべきかは分かりません。
学習では、次の処理を繰り返します。
- 順伝播で、各位置の次トークン予測を計算する
- 予測と正解を比べ、損失を計算する
- 逆伝播で、各重みを少し変えたときに損失がどう変わるかを勾配として求める
- オプティマイザが勾配と学習率などを使い、重みを更新する
逆伝播は、文章を後ろから読み直す処理ではありません。計算のつながりを出力側から入力側へたどり、損失に対する各パラメータの勾配を計算する仕組みです。
また、1つの文章が、特定の重みを「記憶場所」として選んで保存されるわけでもありません。1回の損失から得た更新は、多くの重みにまたがり得ます。大量の学習例でこの処理を繰り返すことで、重みが少しずつ変わります。
学習途中の再開や比較に備え、モデルやオプティマイザなどの途中状態をチェックポイントとして保存することもあります。
参考:Trainer(Hugging Face Transformers)、Automatic differentiation package(PyTorch)、torch.optim(PyTorch)
では、この反復で学習データ上の損失が下がれば、未知の入力にも良い予測ができると言えるのでしょうか。
学習データ上の損失が下がっても、それだけで未知の入力への改善は確認できません。学習に使った例へ強く合わせすぎると、訓練損失は下がっても、別に取っておいたデータでは損失が下がらないことがあります。
確認する値は、役割を分けて見ます。
| 確認するもの | 分かること |
|---|---|
| 訓練損失 | 重みの更新に使ったデータへ、予測がどれだけ合っているか |
| 検証損失 | 重みの更新に使わなかったデータへ、学習した傾向をどれだけ適用できるか |
| 用途別の評価 | 必要な形式、正確さ、振る舞いを、その用途の基準で満たすか |
訓練損失が下がり続ける一方で検証損失が悪化するなら、過学習を疑う手がかりになります。ただし、検証データが実際の用途を代表していなければ、その値だけでも判断できません。
たとえば、次トークン予測の損失が低くても、要約で重要点を残せるか、決められた形式を守れるかまでは直接分かりません。検証損失に加えて、使いたいタスクに合う入力と確認基準を用意します。
LLMの学習は、「1トークンずらした正解を作る」「損失から勾配を求めて重みを更新する」「学習に使っていないデータと用途別の基準で確かめる」という順で見ると、学習と評価を混同せずに追えます。
参考:Causal language modeling(Hugging Face Transformers)、Trainer(Hugging Face Transformers)