> For the complete documentation index, see [llms.txt](https://unsloth.ai/docs/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://unsloth.ai/docs/jp/moderu/gpt-oss-how-to-run-and-fine-tune/gpt-oss-reinforcement-learning/tutorial-how-to-train-gpt-oss-with-rl.md).

# チュートリアル: RL で gpt-oss を訓練する方法

LLMは複雑な環境を伴うタスクにしばしば苦戦します。しかし、適用することで [強化学習](/docs/jp/meru/reinforcement-learning-rl-guide.md) （RL）とカスタムの [報酬関数](/docs/jp/meru/reinforcement-learning-rl-guide.md#reward-functions-verifiers)を設計することで、これらの課題は克服できます。

RLは、自動カーネル生成や戦略作成などのタスク向けに適応できます。このチュートリアルでは、2048を自律的に攻略できるように、 **gpt-oss** を [**GRPO**](/docs/jp/meru/reinforcement-learning-rl-guide.md#from-rlhf-ppo-to-grpo-and-rlvr) とUnslothで学習させる方法を示します。

| [2048ノートブック](https://colab.research.google.com/github/openai/gpt-oss/blob/main/examples/reinforcement-fine-tuning.ipynb) （OpenAI公式の例） | [カーネル生成ノートブック](https://colab.research.google.com/github/unslothai/notebooks/blob/main/nb/gpt-oss-\(20B\)-GRPO.ipynb) |
| ------------------------------------------------------------------------------------------------------------------------------------- | -------------------------------------------------------------------------------------------------------------------- |

**作成するもの：**

* モデルが自動的に2048で勝てるようにgpt-oss-20bを学習させる
* モデルがやり取りできる最小限の2048環境を作成する
* 定義する **報酬関数** 内容：
  1. 生成された戦略がコンパイルおよび実行できることを確認し、
  2. 報酬ハッキングを防止し（外部インポートを禁止）、さらに
  3. 実際のゲーム成功に報酬を与える
* 推論を実行し、モデルをエクスポートする（MXFP4 4ビットまたはマージ済みFP16）

{% hint style="info" %}
**ハードウェア：** 2048の例は無料のColab T4で動作しますが、学習は遅くなります。A100/H100のほうがはるかに高速です。4ビット読み込み + LoRA により、20Bモデルを控えめなVRAMに収めることができます。
{% endhint %}

{% stepper %}
{% step %}

#### Unslothをインストールする

ノートブックの先頭でこのセルを実行してください（Colabで動作します）。

```bash
!pip install --upgrade -qqq uv
try: import numpy; get_numpy = f"numpy=={numpy.__version__}"
except: get_numpy = "numpy"
!uv pip install -qqq \
    "torch>=2.8.0" "triton>=3.4.0" {get_numpy} torchvision bitsandbytes "transformers==4.56.2" \
    "unsloth_zoo[base] @ git+https://github.com/unslothai/unsloth-zoo" \
    "unsloth[base] @ git+https://github.com/unslothai/unsloth" \
    git+https://github.com/triton-lang/triton.git@05b2c186c1b6c9a08375389d5efe9cb4c401c075#subdirectory=python/triton_kernels
!uv pip install --upgrade --no-deps transformers==4.56.2 tokenizers
!uv pip install --no-deps trl==0.22.2
```

{% endstep %}

{% step %}

#### Unslothでgpt-ossを読み込む

メモリ効率のために20Bモデルを4ビットQLoRAで読み込み、その後LoRAアダプターでラップします。16ビットLoRAで学習させることもできますが、メモリ使用量は4倍になります。その他の設定については、当社の [設定ガイド](https://unsloth.ai/docs/jp/moderu/gpt-oss-how-to-run-and-fine-tune/gpt-oss-reinforcement-learning/pages/ae7926a0f371a1f594e3344d85571edf864a5259#id-2.-choose-the-right-model--method).

```python
from unsloth import FastLanguageModel
import torch

max_seq_length = 768        # タスクでより長い出力が必要な場合は増やす
lora_rank      = 4          # ランクが高いほど良いが、VRAM/計算量も増える

model, tokenizer = FastLanguageModel.from_pretrained(
    model_name        = "unsloth/gpt-oss-20b",  # またはH100では unsloth/gpt-oss-20b-BF16
    max_seq_length    = max_seq_length,
    load_in_4bit      = True,                    # 16ビットの場合はFalse
    offload_embedding = True,                    # 約1GBのVRAMを節約
)

model = FastLanguageModel.get_peft_model(
    model,
    r = lora_rank,
    target_modules = [
        "q_proj", "k_proj", "v_proj", "o_proj",
        "gate_proj", "up_proj", "down_proj",
    ],
    lora_alpha = lora_rank * 2,
    use_gradient_checkpointing = "unsloth",     # 大きなメモリ節約
    random_state = 3407,
)
```

{% hint style="info" %}
OOMが発生する場合は、 `max_seq_length`, `lora_rank`、または `num_generations` （後述）を下げ、 `load_in_4bit=True`.
{% endhint %}
{% endstep %}

{% step %}

#### 2048ゲーム環境（最小構成）

* A `GameBoard` クラス。以下をサポート： **W/A/S/D** 移動
* マージ/スコアのロジック
* `execute_with_time_limit` ラッパー。これにより、 poorly written な戦略でカーネルが停止し続けるのを防ぎます

簡単なポリシーですぐにスモークテストできます：

```python
def always_move_left(board):
    return "W"

steps, outcome = execute_strategy(always_move_left, GameBoard(size=8, seed=42, target=2048, probability_fours=0.10))
```

{% endstep %}

{% step %}

#### 安全なコード実行とチート防止チェック

生成される戦略は **Python関数**です。実行を安全に保ち、報酬ハッキングを防ぐために：

* **モジュールのホワイトリストチェック** — Python標準ライブラリのシンボルのみを許可：

  ```python
  from unsloth import check_python_modules
  ok, info = check_python_modules("""
  def strategy(board):
      import math
      from typing import Callable
      return "W"
  """)
  # ok == True は、Pythonレベルのインポートのみが使用されたことを意味します
  ```
* **許可されていないインポートをブロックする** （例：NumPy）：

  ```python
  sample = """
  def strategy(board):
      from numpy import matmul
      return "W"
  """
  ok, info = check_python_modules(sample)  # ok => False
  ```
* **実行をロックダウンする** サンドボックス化された関数へ：

  ```python
  from unsloth import create_locked_down_function
  function = """
  def add(a, b):
      def adder(a):
          return a + b
      return adder(b) + b
  """
  f = create_locked_down_function(function)  # グローバル変数 / インポートが使用されているとエラー
  ```
* **厳格なウォールクロック時間制限を適用する** 戦略の実行に対して：

  ```python
  from unsloth import execute_with_time_limit
  @execute_with_time_limit(2)
  def execute_strategy(strategy, game):
      # ゲームが終了するかタイムアウトするまでループ
      ...
  ```

{% endstep %}

{% step %}
\### プロンプトとデータセット

モデルに次を促します： **短い戦略関数を出力する** 三重バッククォート内に：

````
ネイティブPythonコードのみを使って、新しい短い2048戦略を作成してください。
現在の盤面状態として、数値のリストのリストが与えられます。
最適な次の一手として、「W」「A」「S」「D」のいずれか1つのアクションを出力してください。
以下の形式で、バッククォート内に新しい短い関数を出力してください：
```python
def strategy(board):
    return "W"  # 例
````

補助関数はすべて def strategy の中に入れてください。短い関数のみを出力してください `strategy`.

````

小さな合成データセットを作成し（同じプロンプトを再利用）、GRPOがサンプリングすべき補完トークン数を把握できるようにプロンプト長を計算します：

```python
from datasets import Dataset

prompt = ...  # 上記のとおり

maximum_length = len(tokenizer.apply_chat_template(
    [{"role": "user", "content": prompt}], add_generation_prompt=True
))

dataset = Dataset.from_list([
    {"prompt": [{"role": "user", "content": prompt}], "answer": 0, "reasoning_effort": "low"}
] * 1000)
````

{% hint style="info" %} このデータセットは、自分のRLタスク用の実際のプロンプトに置き換えることができます。 {% endhint %} {% endstep %}

{% step %}

#### 報酬関数の時間です！

1. **コードブロックを抽出する** モデルの応答から：

   ````python
   def extract_function(text):
       if text.count("```") >= 2:
           first = text.find("```") + 3
           second = text.find("```", first)
           fx = text[first:second].strip()
           fx = fx.removeprefix("python\n")
           fx = fx[fx.find("def"): ]
           if fx.startswith("def strategy(board):"):
               return fx
       return None
   ````
2. **`function_works`** - コンパイルでき、呼び出し可能なものを作成するか？

   ```python
   from unsloth import create_locked_down_function, check_python_modules

   def function_works(completions, **kwargs):
       scores = []
       for completion in completions:
           response = completion[0]["content"]
           function = extract_function(response)
           if function is None:
               scores.append(-2.0)
               continue
           ok, info = check_python_modules(function)
           if "error" in info:
               scores.append(-2.0)
               continue
           try:
               _ = create_locked_down_function(function)
               scores.append(1.0)
           except Exception:
               scores.append(-0.5)
       return scores
   ```
3. **`no_cheating`** - 非標準ライブラリのインポートは禁止：

   ```python
   def no_cheating(completions, **kwargs):
       scores = []
       for completion in completions:
           response = completion[0]["content"]
           function = extract_function(response)
           if function is None:
               scores.append(-1.0)
               continue
           ok, _ = check_python_modules(function)
           scores.append(1.0 if ok else -20.0)  # チートした場合は重いペナルティ
       return scores
   ```
4. **`strategy_succeeds`** - ランダムな盤面でプレイし、成功に報酬を与える：

   ```python
   import numpy as np

   PRINTER = 0  # デバッグのために時々表示

   def strategy_succeeds(completions, **kwargs):
       global PRINTER
       scores = []
       seed = np.random.randint(10000)
       for completion in completions:
           response = completion[0]["content"]
           function = extract_function(response)
           if function is None:
               scores.append(-2.0)
               continue
           try:
               new_strategy = create_locked_down_function(function)
           except Exception:
               scores.append(0.0)
               continue
           try:
               game = GameBoard(size=6, seed=seed, target=2048, probability_fours=0.10)
               steps, state = execute_strategy(new_strategy, game)
               if PRINTER % 5 == 0:
                   print(function)
                   print(f"Steps={steps} State={state}")
                   print(game.board().pretty())
               PRINTER += 1
               if state == "success":
                   scores.append(20.0)
               else:
                   scores.append(2.0)   # 動作したが2048には到達しなかった
           except TimeoutError:
               scores.append(-1.0)      # タイムアウトした
           except Exception:
               scores.append(-3.0)      # クラッシュした
       return scores
   ```

{% endstep %}

{% step %}

#### GRPOを設定する

以下を使用します： **GRPOTrainer**。プロンプト/補完の長さを設定し、その後 `GRPOConfig`を構築します。RLアルゴリズムの種類は、ほかにも [GSPO](/docs/jp/meru/reinforcement-learning-rl-guide/advanced-rl-documentation/gspo-reinforcement-learning.md) やDr. GRPOなどに設定することもできます。

```python
from trl import GRPOConfig, GRPOTrainer

max_prompt_length     = maximum_length + 1
max_completion_length = max_seq_length - max_prompt_length

training_args = GRPOConfig(
    temperature=1.0,
    learning_rate=5e-5,
    weight_decay=0.01,
    warmup_ratio=0.1,
    lr_scheduler_type="linear",
    optim="adamw_8bit",
    logging_steps=1,
    per_device_train_batch_size=1,
    gradient_accumulation_steps=1,    # より滑らかな報酬シグナルのために4に増やす
    num_generations=2,                # OOMになる場合は下げる
    max_prompt_length=max_prompt_length,
    max_completion_length=max_completion_length,
    max_steps=1000,                   # または num_train_epochs=1 を設定
    save_steps=100,
    report_to="none",
    output_dir="outputs",
)

trainer = GRPOTrainer(
    model=model,
    processing_class=tokenizer,
    reward_funcs=[function_works, no_cheating, strategy_succeeds],
    args=training_args,
    train_dataset=dataset,
    # オプションの評価分割：
    # train_dataset=new_dataset["train"],
    # eval_dataset=new_dataset["test"],
)
```

{% hint style="info" %} **ログの読み方：** 以下を見てください `reward` および `reward_std`。初期段階では報酬が低い/ゼロになるのは正常です（小さなGPUでは最初の約100～200ステップ）。 {% endhint %} {% endstep %}

{% step %}

#### モデルを学習させる

```python
trainer.train()
```

これにより完全なRLループが開始されます：補完をサンプリング → 報酬でスコア付け → 方策（LoRA）を最適化。 {% endstep %}

{% step %}

#### 推論（学習後）

学習済みアダプターで新しい戦略を生成します：

```python
from transformers import TextStreamer

text = tokenizer.apply_chat_template(
    [{"role": "user", "content": prompt}],
    tokenize=False,
    add_generation_prompt=True,
    reasoning_effort="low",
)

_ = model.generate(
    **tokenizer(text, return_tensors="pt").to("cuda"),
    temperature=1.0,
    max_new_tokens=1024,
    streamer=TextStreamer(tokenizer, skip_prompt=False)
```

{% endstep %}

{% step %}

#### ファインチューニング済みモデルを保存 / エクスポートする

* **4ビット（MXFP4）をマージして保存**

  ```
  ```

python model.save\_pretrained\_merged("finetuned\_model", tokenizer, save\_method="mxfp4") # または push model.push\_to\_hub\_merged("\<org\_or\_user>/", tokenizer, token="\<hf\_token>", save\_method="mxfp4") \`\`\`

* **16ビットをマージして保存**

  ```python
  model.save_pretrained_merged("finetuned_model", tokenizer, save_method="merged_16bit")
  # またはpush
  model.push_to_hub_merged("<org_or_user>/<repo>", tokenizer, token="<hf_token>", save_method="merged_16bit")
  ```

{% endstep %}

{% step %}

#### トラブルシューティングとヒント

* **OOM / 低速**：減らす `max_seq_length`, `num_generations`, `lora_rank`；4ビットを維持する；利用可能ならA100を試す。
* **報酬が改善しない**：学習ステップを増やす、ペナルティを弱める、またはカリキュラムを追加する（より小さい盤面 / より低いターゲットから始める）。
* **報酬ハッキング**： `check_python_modules` を厳格に保つ；複数のランダムシードで戦略の挙動を検証する。
* **不安定な学習**： `gradient_accumulation_steps` を上げて更新を滑らかにする； `learning_rate` を下げる（例：2e‑5）。
* **長時間のハング**： `execute_with_time_limit` があらゆる戦略実行をラップしていることを確認する。
  {% endstep %}

{% step %}

#### 自分のRLタスクに適応する

* 2048環境を自分の環境に置き換え、 **3つの報酬**を設定する：（a）構文/コンパイル、（b）チート防止/安全性、（c）タスク成功。
* 以下を更新する **prompt** 必要な種類の関数または出力を要求するように。
* 同じUnsloth + GRPOの足場を維持し、環境と報酬だけを入れ替えてください。
  {% endstep %}
  {% endstepper %}


---

# Agent Instructions
This documentation is published with GitBook. GitBook is the documentation platform designed so that both humans and AI agents can read, navigate, and reason over technical content effectively. Learn more at gitbook.com.

## Querying This Documentation
If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter, and the optional `goal` query parameter:

```
GET https://unsloth.ai/docs/jp/moderu/gpt-oss-how-to-run-and-fine-tune/gpt-oss-reinforcement-learning/tutorial-how-to-train-gpt-oss-with-rl.md?ask=<question>&goal=<endgoal>
```

`ask` is the immediate question: it should be specific, self-contained, and written in natural language.
`goal` is optional and describes the broader end goal you are ultimately trying to accomplish on behalf of the user. GitBook uses it to tailor the answer towards what is most useful for that goal.

The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
