# オプティマイザーとスケジューラー

オプティマイザーは、学習中にモデルの重みを更新します。スケジューラーはオプティマイザーをラップし、各学習ステップで学習率を調整します。[Trainer](/docs/transformers/main/ja/main_classes/trainer#transformers.Trainer)は、[create_optimizer_and_scheduler()](/docs/transformers/main/ja/main_classes/trainer#transformers.Trainer.create_optimizer_and_scheduler)を呼び出す際に、両方を生成します。

```md
                                    ┌────────────┐         ┌──────────────┐
                                    │ Optimizer  │         │  Scheduler   │
                                    │ (adamw_torch_fused)◄─│  (linear)    │
                                    │            │         │              │
                                    │ param_groups         |              |
                                    │  └ lr       ◄────────┤              |
                                    │  └ weight_decay      │              │
                                    └──────┬─────┘         └──────────────┘
                                           │                      
  ┌──── EACH TRAINING STEP ───────────────────────────────────────────┐
  │                                        │                          │
  │   model(batch)                         │                          │
  │       │                                │                          │
  │       ▼                                │                          │
  │     loss ──► loss.backward() ──► param.grad                       │
  │                                        │                          │
  │                          ┌─────────────┘                          │
  │                          ▼                                        │
  │              optimizer.step()                                     │
  │                          │                                        │
  │                          ▼                                        │
  │                   param.data updated                              │
  │                          │                                        │
  │                          ▼                                        │
  │              lr_scheduler.step()  ──► recalculates lr             │
  │                          │            writes to optimizer         │
  │                          ▼            .param_groups['lr']         │
  │              model.zero_grad()                                    │
  │                                                                   │
  └───────────────────────────────────────────────────────────────────┘
```

`lr_scheduler_type()` や `optim()` のようなオプティマイザーとスケジューラーの動作は、[TrainingArguments](/docs/transformers/main/ja/main_classes/trainer#transformers.TrainingArguments) で設定します。デフォルト値（`adamw_torch` オプティマイザーと `linear` ウォームアップスケジューラー）は、ほとんどのファインチューニング実行において良い出発点となります。

```py
from transformers import TrainingArguments

args = TrainingArguments(
    ...,
    # Optimizer
    optim="adamw_torch",          # or "adamw_torch_fused", "adafactor", "sgd", etc.
    learning_rate=2e-5,
    weight_decay=0.01,
    adam_beta1=0.9,
    adam_beta2=0.999,
    adam_epsilon=1e-8,
    # Scheduler
    lr_scheduler_type="cosine",   # "linear", "cosine", "constant_with_warmup", etc.
    warmup_steps=500,
    lr_scheduler_kwargs={"num_cycles": 3},  # scheduler-specific extras
)
```

## メトリクスベースのスケジューラ

一部のスケジューラーは、固定のスケジュールに従うのではなく、トレーニングの動的特性に適応します。

[GreedyLR](https://huggingface.co/papers/2512.14527)は、評価結果に基づいて学習率を更新します。指標が改善し続ける場合、学習率を`factor`で割ることで引き上げ、指標が改善しない場合は学習率を`factor`倍することで引き下げます。学習率が`min_lr`で停止し、`reset_start`ステップ後に改善が見られない場合、[GreedyLR](/docs/transformers/main/ja/main_classes/optimizer_schedules#transformers.GreedyLR)は初期状態にリセットされ、新しいサイクルを開始します。

[GreedyLR](/docs/transformers/main/ja/main_classes/optimizer_schedules#transformers.GreedyLR) は、学習中に評価が必要です。`eval_strategy` を `"steps"` または `"epoch"` に設定してください。

```diff
args = TrainingArguments(
+   lr_scheduler_type="greedy",
+   lr_scheduler_kwargs={"patience": 10, "factor": 0.95, "min_lr": 1e-5},
+   eval_strategy="steps",
+   eval_steps=200,
    ...  # remaining args from the TrainingArguments intro config
)
```

> [!TIP]
> デフォルトの`mode="min"`は損失に適用できます。精度のように、値が大きいほど良い指標を追跡している場合は、`lr_scheduler_kwargs`に`"mode": "max"`を渡してください。

設定可能なパラメータの完全なリストについては、[GreedyLR](/docs/transformers/main/ja/main_classes/optimizer_schedules#transformers.GreedyLR)クラスを参照してください。

## オプティマイザーの統合

Transformers は、特殊なトレーニングシナリオ向けにサードパーティのオプティマイザーを統合しています。

| オプティマイザ | インストール | `optim="value"` | 説明 |
|---|---|---|---|
| APOLLO | `apollo-torch` | `apollo_adamw` | ランダム射影によるメモリ効率の高いフルパラメータ学習; ランク1で十分 |
| GrokAdamW | `grokadamw` | `grokadamw` | 遅延汎化(グロッキング)を対象とします |
| LOMO / AdaLomo | `lomo-optim` | `lomo` / `adalomo` | 低メモリでのフルパラメータファインチューニングのために、勾配と更新ステップを融合します |
| スケジュールフリー | `schedulefree` | `schedule_free_adamw`, `schedule_free_radam`, `schedule_free_sgd` | LR アニーリングを排除します。`lr_scheduler_type="constant"` と組み合わせて使用してください。 |
| GaLore | `galore-torch` | `galore_adamw`, `galore_adafactor`, `galore_adamw_8bit` | 勾配低ランク射影による全パラメータ学習 |
| StableAdamW | `torch-optimi` | `stable_adamw` | AdamW + AdaFactorの更新クリッピング; グラデントクリッピングは不要 |

```bash
pip install apollo-torch
```

[Approximated Gradient Scaling for Memory Efficient LLM Optimization (APOLLO)](https://huggingface.co/papers/2412.05270)は、事前学習およびファインチューニングにおける全パラメータ学習のためのメモリ効率の高いオプティマイザーです。SVDの代わりに安価なランダム射影を使用することで、SGDと同程度のメモリコストでAdamWと同等の性能を実現します。極限的なメモリ削減が必要な場合は、ランク1のバリアントであるAPOLLO-Miniを使用してください。

`optim_target_modules` パラメータを使用して、学習対象のレイヤーを指定します。

```diff
args = TrainingArguments(
+   optim="apollo_adamw",
+   optim_target_modules=[r".*.attn.*", r".*.mlp.*"],
    ...  # remaining args from the TrainingArguments intro config
)
```

`optim_args` を通して、追加のハイパーパラメータを渡します。

> [!TIP]
> `scale` を `n/r` に設定します。ここで `n` は元の空間の次元、`r` は低ランク空間の次元です。`scale` をデフォルトのままにしておいて学習率を調整しても、同様の効果が得られます。

| パラメータ | 説明 | APOLLO | APOLLO-Mini |
|---|---|---|---|
| ランク | 勾配スケーリング用の補助部分空間のランク | 256 | 1 |
| scale_type | スケーリング係数の適用方法 | `channel`（チャネルごとのスケーリング） | `tensor`（テンソルごとのスケーリング） |
| スケール | 勾配の更新を調整して、学習を安定させます | 1.0 | 128 |
| update_proj_gap | 投影行列を更新する前のステップ | 200 | 200 |
| proj | projection type | `random` | `random` |

rank-1 の設定で APOLLO-Mini を有効にします。

```py
args = TrainingArguments(
    optim="apollo_adamw",
    optim_target_modules=[r".*.attn.*", r".*.mlp.*"],
    optim_args="proj=random,rank=1,scale=128.0,scale_type=tensor,update_proj_gap=200",
    ...  # remaining args from the TrainingArguments intro config
)
```

```bash
pip install grokadamw
```

[GrokAdamW](https://github.com/cognitivecomputations/grokadamw)は、勾配がゆっくりと変化することでモデルが一般化の遅延を示す現象である*grokking*を対象としています。

```diff
args = TrainingArguments(
+   optim="grokadamw",
    ...  # remaining args from the TrainingArguments intro config
)
```

```bash
pip install lomo-optim
```

[Low-Memory Optimization (LOMO)](https://github.com/OpenLMLab/LOMO)には、低メモリでの全パラメータファインチューニング用の2つのオプティマイザー、[LOMO](https://huggingface.co/papers/2306.09782)と[AdaLomo](https://hf.co/papers/2310.10195)が含まれています。どちらも勾配の計算とパラメータの更新を1つのステップに統合します。AdaLomoは、Adamと同様に、パラメータごとの適応型学習率を追加します。

> [!TIP]
> AdaLomo は `grad_norm` を使用しない場合に最もよく機能し、パフォーマンスとスループットが向上します。

```diff
args = TrainingArguments(
+   optim="adalomo",
    learning_rate=2e-6,
    ...  # remaining args from the TrainingArguments intro config
)
```

```bash
pip install schedulefree
```

[Schedule Free optimizer (SFO)](https://hf.co/papers/2405.15682)は、モーメンタムを平均化と補間の組み合わせに置き換え、学習率のアニーリングの必要性を完全に排除します。

SFOは、RAdam（`schedule_free_radam`）、AdamW（`schedule_free_adamw`）、およびSGD（`schedule_free_sgd`）のオプティマイザーをサポートしています。RAdamスケジューラーは`warmup_steps`を必要としません。

SFOは`lr_scheduler_type="constant"`と組み合わせて使用してください。他のスケジューラタイプも動作しますが、SFOの意図した動作に影響を与えます。

```diff
args = TrainingArguments(
+   optim="schedule_free_radam",
+   lr_scheduler_type="constant",
    learning_rate=2e-6,
    ...  # remaining args from the TrainingArguments intro config
)
```

```bash
pip install torch-optimi
```

[StableAdamW](https://huggingface.co/papers/2304.13013)は、AdaFactorの更新クリッピングをAdamWに移植し、勾配クリッピングの必要性を排除します。それ以外は、AdamWのドロップイン代替として機能します。

> [!TIP]
> 大きなバッチサイズで学習している場合、または損失のスパイクがまだ観測されている場合は、`beta_2`を0.95から0.99の間に設定してみてください。

```diff
args = TrainingArguments(
+   optim="stable_adamw",
    learning_rate=2e-6,
    ...  # remaining args from the TrainingArguments intro config
)
```

```bash
pip install galore-torch trl
```

[Gradient Low-Rank Projection (GaLore)](https://hf.co/papers/2403.03507) は、LLM の学習におけるメモリ使用量を削減します。[LoRA](https://hf.co/papers/2106.09685) などの低ランク適応手法とは異なり、GaLore は*全パラメータ*学習を維持します。

`optim` を [trl.SFTConfig](https://huggingface.co/docs/trl/main/en/sft_trainer#trl.SFTConfig) で GaLore オプティマイザー(`"galore_adamw"`、`"galore_adafactor"`、または `"galore_adamw_8bit"`)に設定します。ターゲットモジュールは `optim_target_modules` で指定し、GaLore 固有のパラメータ(`rank`、`update_proj_gap`、`scale`)は `optim_args` を通して指定します。

```py
from trl import SFTConfig

args = SFTConfig(
    output_dir="./galore",
    max_steps=100,
    optim="galore_adamw",
    optim_target_modules=[r".*.attn.*", r".*.mlp.*"],
    optim_args="rank=64, update_proj_gap=100, scale=0.10",
)
```

レイヤーワイズ最適化を行う場合は、オプティマイザー名に`_layerwise`を付加します（`"galore_adamw_layerwise"`）。GaLoreの対象となる線形層のみが低ランク分解を使用し、その他の層は通常どおり最適化されます。

```py
from trl import SFTConfig, SFTTrainer

args = SFTConfig(
    output_dir="./galore",
    max_steps=100,
    optim="galore_adamw_layerwise",
    optim_target_modules=[r".*.attn.*", r".*.mlp.*"],
    optim_args="rank=64, update_proj_gap=100, scale=0.10",
)
```

Layerwiseモードは実験的な機能です。[単一のGPU](https://github.com/jiaweizzhao/GaLore?tab=readme-ov-file#train-7b-model-with-a-single-gpu-with-24gb-memory)でのみ動作し、DistributedDataParallel (DDP) には対応していません。また、勾配クリッピングやDeepSpeedが正常に動作しない場合があります。

## オプティマイザーとスケジューラーのカスタマイズ

まだ統合されていないオプティマイザーを使用したり、レイヤーごとの学習率を調整したり、カスタムロジックを適用したりするために、カスタムオプティマイザーとスケジューラーを作成します。

### クラスとkwargsを渡す

`~Trainer.optimizer_cls_and_kwargs` はカスタムオプティマイザークラスを受け取りますが、パラメータのグループ化とデバイスの割り当ては [Trainer](/docs/transformers/main/ja/main_classes/trainer#transformers.Trainer) に委譲されます。

[Trainer](/docs/transformers/main/ja/main_classes/trainer#transformers.Trainer) は [create_optimizer()](/docs/transformers/main/ja/main_classes/trainer#transformers.Trainer.create_optimizer) が実行されるまでオプティマイザーの構築を遅延させるため、モデルはすでに正しいデバイス上に配置されています。

```py
import torch

trainer = Trainer(
    ...
    optimizer_cls_and_kwargs=(
        torch.optim.SGD,
        {"momentum": 0.9, "nesterov": True}
    ),
)
```

### 事前構築されたインスタンスを渡す

`~Trainer.optimizers` に事前定義されたオプティマイザーとスケジューラーを渡します。事前構築されたインスタンスが提供されている場合、[Trainer](/docs/transformers/main/ja/main_classes/trainer#transformers.Trainer) は [create_optimizer()](/docs/transformers/main/ja/main_classes/trainer#transformers.Trainer.create_optimizer) と [create_scheduler()](/docs/transformers/main/ja/main_classes/trainer#transformers.Trainer.create_scheduler) をスキップします。スケジューラーを渡さない場合、[Trainer](/docs/transformers/main/ja/main_classes/trainer#transformers.Trainer) は自動的にスケジューラーを作成します。

> [!WARNING]
> モデルを正しいデバイスに配置した後に、オプティマイザーを構築してください。パラメーターは構築時に解決され、`Trainer`がモデルを移動する前に処理されます。分散学習では、デバイスの不一致がサイレントに誤った動作を引き起こす可能性があります。

```py
import torch
from transformers import Trainer, get_cosine_schedule_with_warmup

optimizer = torch.optim.AdamW(model.parameters(), lr=2e-5)
scheduler = get_cosine_schedule_with_warmup(
    optimizer, num_warmup_steps=500, num_training_steps=10_000
)

trainer = Trainer(
    ...
    optimizers=(optimizer, scheduler),
)
```

Prebuilt instances は [create_optimizer()](/docs/transformers/main/ja/main_classes/trainer#transformers.Trainer.create_optimizer) および [create_scheduler()](/docs/transformers/main/ja/main_classes/trainer#transformers.Trainer.create_scheduler) をバイパスするため、独自の parameter groups を指定する必要があります。

### オプティマイザーとスケジューラーのメソッドをオーバーライドする

完全な制御を行うには、[create_optimizer()](/docs/transformers/main/ja/main_classes/trainer#transformers.Trainer.create_optimizer) と [create_scheduler()](/docs/transformers/main/ja/main_classes/trainer#transformers.Trainer.create_scheduler) をサブクラス化します。これらのメソッドは [train()](/docs/transformers/main/ja/main_classes/trainer#transformers.Trainer.train) の*実行中*に呼び出されます。

[SchedulerType](/docs/transformers/main/ja/main_classes/optimizer_schedules#transformers.SchedulerType) に存在しない [OneCycleLR](https://docs.pytorch.org/docs/stable/generated/torch.optim.lr_scheduler.OneCycleLR.html) などのスケジューラを使用するには、[create_scheduler()](/docs/transformers/main/ja/main_classes/trainer#transformers.Trainer.create_scheduler) をオーバーライドします。

各メソッドでは、`self`に代入し、それを返すようにしてください。

```py
import torch
from transformers import Trainer

class MyTrainer(Trainer):

    def create_scheduler(self, num_training_steps, optimizer=None):
        optimizer = optimizer or self.optimizer
        self.lr_scheduler = torch.optim.lr_scheduler.OneCycleLR(
            optimizer,
            max_lr=0.1,
            total_steps=num_training_steps,
        )
        return self.lr_scheduler
```

デフォルトのオプティマイザーで問題がなければ、[create_optimizer()](/docs/transformers/main/ja/main_classes/trainer#transformers.Trainer.create_optimizer)をオーバーライドする必要はありません。メソッドを完全に置き換えるよりも、`super()`でメソッドを拡張する方が簡単です。例えば、他の設定をすべて維持したまま、追加のパラメータグループを1つ追加することができます。

```py
class MyTrainer(Trainer):
    def create_optimizer(self, model=None):
        super().create_optimizer(model)  # builds the default two param groups
        # add extra param group
        self.optimizer.add_param_group({
            "params": self.model.classifier.parameters(),
            "lr": self.args.learning_rate * 10,
        })
        return self.optimizer
```

