# 勾配の蓄積

大きなバッチサイズは大きなアクティベーションを生成し、GPU メモリを使い切ってしまいます。勾配蓄積（Gradient accumulation）を使用すると、勾配の計算を複数のミニバッチに分散させることで、より大きな実効バッチサイズでの学習が可能になります。

勾配は、オプティマイザーが重みを更新する前に、*n*個のミニバッチにわたって蓄積されます。例えば、デバイスごとのバッチサイズが8で、蓄積ステップ数が4の場合、実効バッチサイズは32になります。

```text
Step 1: mini-batch 1 → forward → backward → grads = G₁
Step 2: mini-batch 2 → forward → backward → grads = G₁ + G₂
Step 3: mini-batch 3 → forward → backward → grads = G₁ + G₂ + G₃
Step 4: mini-batch 4 → forward → backward → grads = G₁ + G₂ + G₃ + G₄
        → optimizer.step()  ← same update as if batch_size × 4
        → zero_grad()
```

より大きなバッチがメモリに収まらない場合のみ、勾配蓄積を使用してください。真の大きなバッチでの学習と比較して、スループットを向上させる効果はありません。

`per_device_train_batch_size` に対して `gradient_accumulation_steps` 回にわたって勾配を累積します。

```py
from transformers import TrainingArguments

args = TrainingArguments(
    ...,
    per_device_train_batch_size=8,
    gradient_accumulation_steps=4,
)
```

## 損失スケーリング

[カスタム損失関数](./trainer_recipes#custom-loss-function)を使用する場合は、`num_items_in_batch`を含めることで、[Trainer](/docs/transformers/main/ja/main_classes/trainer#transformers.Trainer)がすべてのミニバッチにわたる予測ターゲットの数で損失を割るようにします。これにより、`gradient_accumulation_steps`による固定のステップ数ではなく、トークン数で正規化されます。それ以外の場合、[Trainer](/docs/transformers/main/ja/main_classes/trainer#transformers.Trainer)は損失を`gradient_accumulation_steps`で割ります。

```py
import torch.nn.functional as F

def compute_loss(outputs, labels, num_items_in_batch=None):
    logits = outputs["logits"]
    loss = F.cross_entropy(logits, labels, reduction="sum")
    return loss / num_items_in_batch
```

因果言語モデルの場合、`num_items_in_batch` は *シフトされた* ラベルを数えます。損失関数はラベルをシフトするため、位置 `i` での予測は位置 `i + 1` のトークンを対象とし、これにより各シーケンスの位置 0 にはターゲットが存在しません。[Trainer](/docs/transformers/main/ja/main_classes/trainer#transformers.Trainer) はこれらの位置を除外し、`labels[..., 1:]` に対して集計を行うため、分母は損失関数が使用する予測ターゲットの数と一致します。データコラテーターが `shift_labels` を直接提供する場合は、例えばパディングなしのコラテーターなど、[Trainer](/docs/transformers/main/ja/main_classes/trainer#transformers.Trainer) はそのテンソルに対して集計を行います。マスクド言語モデルや分類などの他の損失タイプでは、ラベルテンソル全体を数えます。

[Trainer](/docs/transformers/main/ja/main_classes/trainer#transformers.Trainer) をサブクラス化して [compute_loss()](/docs/transformers/main/ja/main_classes/trainer#transformers.Trainer.compute_loss) をオーバーライドする場合、`loss_is_scaled_for_ga` を設定して、損失がどのように正規化されているかを指定します。`False` はバッチごとの平均値を意味し、[Trainer](/docs/transformers/main/ja/main_classes/trainer#transformers.Trainer) が `gradient_accumulation_steps` で割ります。`True` は、すでに `num_items_in_batch` で割っている場合です。

```py
class MyTrainer(Trainer):
    loss_is_scaled_for_ga = True

    def compute_loss(self, model, inputs, return_outputs=False, num_items_in_batch=None):
        ...
        return loss_sum / num_items_in_batch
```

## 次のステップ

- GPU上のメモリ使用量を駆動している要因を理解するために、[GPUメモリ使用量](./model_memory_anatomy)のドキュメントをお読みください。
- アクティベーションをキャッシュする代わりに再計算することでアクティベーションメモリを削減する方法を学ぶには、[Gradient checkpointing](./grad_checkpointing)ガイドを参照してください。
- メモリを削減し、トレーニングを高速化するために低精度のデータ型を使用する方法については、[Mixed precision training](./mixed_precision_training)ガイドを参照してください。
- 勾配の計算方法について詳しく知るには、[Gradient Accumulation Fix](https://unsloth.ai/blog/gradient)のブログ記事をお読みください。

