LLM の学習のしくみ:事前学習・指示チューニング・RLHF・DPO
ChatGPT のような大規模言語モデル(LLM)は、いきなり「質問に答えるアシスタント」として学習されるわけではありません。大きく分けて、次の 3 段階を経て作られます。
- 事前学習:大量の文章で、次のトークンを当てる学習をする。言葉と知識を身に付ける
- 指示チューニング(SFT):人が書いた「指示とお手本の答え」で追加の学習をする。質問に答える形を覚える
- 人の好みに合わせる学習(RLHF・DPO):人が 2 つの答えを比べた結果を使い、より好まれる答え方に寄せる
アテンションと Transformer のしくみ では Transformer の中身を、強化学習のしくみ では RLHF の手順を簡単に説明しました。この記事では、この 3 段階で それぞれ何を最小化・最大化しているのかを、小さな計算例で確かめます。
結論を先に書くと、次のとおりです。
- 事前学習は、次のトークンの交差エントロピーを下げる学習。損失は、データの量とモデルの大きさの釣り合いで決まり、言語そのものの不確かさより下には下がらない
- SFT も同じ「次のトークンを当てる」学習だが、お手本の答えの部分だけで損失を計算する
- 報酬モデルは、人が比べた結果から「答えの良さ」を数値にする。2 つの答えの報酬の差をシグモイドに通したものを「こちらが好まれる確率」とする
- RLHF は、報酬を上げつつ、元のモデルから離れすぎないように KL の罰則をかける。罰則の強さ β で、改善の大きさと答えの多様さが釣り合う
- DPO は、報酬モデルと強化学習を使わず、比べた結果から直接モデルを学習する。同じ最適解を、分類の学習のような簡単な形で求める
説明の途中に出てくる計算例は、Python と NumPy で実際に動かした結果です。
環境
計算例を動かした環境です。
| 項目 | バージョン |
|---|---|
| Python | 3.13 |
| NumPy | 2.5 |
事前学習:次のトークンを当てる
損失は交差エントロピー
事前学習では、ウェブページ・本・プログラムのコードなどの大量の文章を トークン に区切り、それまでのトークンから次のトークンを当てる問題をひたすら解きます。正解を人が用意する必要がなく、文章そのものが正解になるので、自己教師あり学習と呼ばれます。
モデルは、次のトークンが語彙のそれぞれである確率を出します。損失は、本当の次のトークンに付けた確率 p の −log p(交差エントロピー)の平均です。確率 1 で当てれば 0、確率が低いほど大きくなります。損失を指数関数で戻した パープレキシティ(exp(損失))は、「平均して何択まで絞り込めているか」と読めます。
データの量とモデルの大きさ
損失がどう下がるかを、小さな「言語」で確かめます。「私は」「東京で」「本を読みます」のような部品を文法どおりに並べた文を作り、直前の何文字かから次の 1 文字を当てる表(n-gram モデル)を、数え上げて作ります。直前の文字を多く見るほど、表の行が増える大きなモデルになります。学習に使う文字数を変えて、別に作った 500 文での損失を比べます。
import numpy as np
# 小さな「言語」:文法に従って文を作る
rng = np.random.default_rng(0)
subjects = ["私は", "彼は", "猫が", "犬が", "先生は", "学生が"]
places = ["東京で", "学校で", "公園で", "図書館で", "家で"]
actions = ["本を読みます", "ご飯を食べます", "友達と話します", "走ります", "勉強します", "寝ます"]
def text(n):
return "".join(subjects[rng.integers(6)] + places[rng.integers(5)] + actions[rng.integers(6)] + "。" for _ in range(n))
train, test = text(20000), text(500)
chars = sorted(set(train + test))
idx = {c: i for i, c in enumerate(chars)}
V = len(chars)
def ngram_loss(train_text, test_text, n, k=0.01):
# 直前の n-1 文字から次の 1 文字を当てる表を数えて作る(加算平滑化)
counts = {}
for i in range(n - 1, len(train_text)):
ctx = train_text[i - n + 1:i]
counts.setdefault(ctx, np.zeros(V))[idx[train_text[i]]] += 1
loss = 0.0
for i in range(n - 1, len(test_text)):
c = counts.get(test_text[i - n + 1:i], np.zeros(V))
p = (c[idx[test_text[i]]] + k) / (c.sum() + k * V)
loss -= np.log(p)
return loss / (len(test_text) - n + 1) # 1 文字あたりの交差エントロピー
print(V, len(train))
print("一様", round(np.log(V), 3), V)
for n in [1, 2, 4]:
for size in [300, 3000, 30000, len(train)]:
L = ngram_loss(train[:size], test, n)
print(n, size, round(L, 3), round(float(np.exp(L)), 2))
実行結果:
40 233205
一様 3.689 40
1 300 3.477 32.37
1 3000 3.435 31.03
1 30000 3.431 30.92
1 233205 3.431 30.91
2 300 0.588 1.8
2 3000 0.515 1.67
2 30000 0.506 1.66
2 233205 0.505 1.66
4 300 1.103 3.01
4 3000 0.478 1.61
4 30000 0.445 1.56
4 233205 0.443 1.56
1 行目は文字の種類と学習の文字数、2 行目はすべての文字を同じ確率で当てずっぽうにしたときの損失とパープレキシティ(40 択)です。3 行目からは、左から n(直前の n−1 文字を見る)、学習に使った文字数、損失、パープレキシティです。
- 直前を見ない(n=1) と、どれだけデータを増やしても損失は 3.43(約 31 択)までしか下がりません。モデルが小さすぎて、文の構造を表せないのです
- 直前の 3 文字を見る(n=4) と、データが 300 文字しかないときは損失 1.103 で、n=2 の 0.588 より悪くなります。表の行が多いのに、埋めるだけのデータがないからです。データを増やすと逆転し、0.443 まで下がりました
- n=4 では、3 万文字から 23 万文字に増やしても、損失はほとんど変わりません
最後の点には理由があります。この言語では、1 文ごとに主語・場所・動作を 6 × 5 × 6 = 180 通りから選んでいるので、どんなに賢いモデルでも、1 文あたり log 180 ≒ 5.19 の不確かさ(エントロピー)は残ります。1 文の平均は 11.67 文字なので、1 文字あたり約 0.445 です。n=4 のモデルは、この下限にほぼ届いたのです。
スケーリング則
実際の LLM でも、同じことが起きます。2020 年に OpenAI の研究者は、損失が モデルの大きさ(パラメーターの数)・データの量・計算量のそれぞれに対して、べき乗則に従って下がることを示しました(スケーリング則)。どれか 1 つだけを増やしても、ほかが足りなければ頭打ちになり、どれだけ増やしても、言語そのものの不確かさによる下限は残ります。上の計算例は、その小さな版です。
Transformer の学習に必要な計算量は、パラメーター数を N、学習するトークン数を D とすると、およそ 6ND 回の浮動小数点演算です。2022 年の Chinchilla の研究は、決まった計算量で損失をいちばん下げるには、パラメーター 1 つあたり約 20 トークンで学習するのがよいと示しました。たとえば 70 億パラメーターのモデルなら 1,400 億トークンで、計算量は 6 × 7×10⁹ × 1.4×10¹¹ ≒ 5.9×10²¹ 回になります。
ただし、最近のモデルは、この比よりずっと多くのデータで学習するのがふつうです。たとえば LLaMA 3 の 80 億パラメーターのモデルは、15 兆トークン以上で学習されています。学習の計算量は増えますが、小さなモデルのほうが使うとき(推論)の計算が安いからです。
指示チューニング:質問に答える形を覚える
事前学習だけのモデルは「続きを書く」
事前学習だけのモデルは、文章の続きを書くのは得意ですが、質問に答えるとは限りません。「日本の首都はどこですか?」と入力すると、答えるかわりに「アメリカの首都はどこですか?」と、似た質問を続けて書くことがあります。ウェブ上の文章には、質問の一覧のようなページも多いからです。
お手本の答えの部分だけで損失を計算する
そこで、人が書いた「指示(質問)」と「お手本の答え」の組を数千〜数万件用意し、追加で学習します。これを SFT(教師ありファインチューニング)や 指示チューニングと呼びます。学習の方法は事前学習と同じ「次のトークンを当てる」ですが、損失は答えの部分のトークンだけで計算し、質問の部分は当てなくてよいことにします。
入力: <ユーザー> 日本の首都はどこですか? <アシスタント> 東京です。
損失: × × × × × × × × ○ ○ ○
× の位置は損失に含めず、○ の位置(答えのトークン)だけを当てるように学習します。こうすると、モデルは「<アシスタント> の後には、質問に対する答えを書く」という形を覚えます。2021 年の FLAN の研究は、さまざまな種類の課題を指示の形に直して学習すると、学習で見ていない種類の指示にも従えるようになることを示しました。
小さな例:6 通りの答え方
ここからは、1 つの質問に対する答え方が 6 通りしかない、ごく小さな「モデル」で考えます。それぞれの答え方には、「正確か」「丁寧か」「長いか」「有害か」の特徴があります。モデルは、6 通りのそれぞれを選ぶ確率を持っています。事前学習だけのモデルは、質問を無視して続きを書く答え方を 55% の確率で選ぶとします。
SFT では、人が書いたお手本(正確で丁寧な、短い答えか長い答え)200 件の対数尤度を上げるように、勾配法で 3 周学習します。
import numpy as np
# 1 つの質問に対する 6 通りの答え方。特徴は [正確, 丁寧, 長い, 有害]
names = ["正確・丁寧・短い", "正確・丁寧・長い", "正確・ぶっきらぼう", "不正確・丁寧", "質問を無視して続きを書く", "有害"]
phi = np.array([[1, 1, 0, 0], [1, 1, 1, 0], [1, 0, 0, 0], [0, 1, 0, 0], [0, 0, 1, 0], [1, 0, 0, 1]], float)
def softmax(z):
e = np.exp(z - z.max()); return e / e.sum()
# 事前学習だけのモデル:文章の続きを書くのがいちばん得意
logits_pre = np.log(np.array([0.05, 0.05, 0.10, 0.15, 0.55, 0.10]))
show = lambda name, p: print(f"{name:8s}", np.round(p, 2))
show("事前学習", softmax(logits_pre))
# 1. SFT:人が書いたお手本(0 と 1 の答え方)の対数尤度を上げる
rng = np.random.default_rng(0)
demos = rng.choice([0, 1], size=200)
theta = logits_pre.copy()
for _ in range(3): # お手本を 3 周
for d in demos:
p = softmax(theta)
grad = -p; grad[d] += 1 # log p(d) の勾配
theta += 0.01 * grad
logits_sft = theta.copy()
show("SFT", softmax(logits_sft))
実行結果:
事前学習 [0.05 0.05 0.1 0.15 0.55 0.1 ]
SFT [0.28 0.39 0.06 0.08 0.12 0.06]
並びは names の順です。SFT のあとは、お手本と同じ「正確で丁寧な答え」を選ぶ確率が 10% から 67% に上がり、続きを書く答え方は 12% に下がりました。ただし、有害な答え方もまだ 6% 残っています。お手本は「何をすべきか」は教えますが、「何がより良く、何が悪いか」の比較は教えないからです。また、良いお手本を人が書くのは手間がかかります。
報酬モデル:比べた結果から良さを数値にする
ブラッドリー・テリーモデル
答えを一から書くより、2 つの答えを見比べて、どちらが良いかを選ぶほうが、人にとってずっと簡単です。この比較の結果から、答えの良さを数値(報酬)にするモデルを学習します。これが 報酬モデルです。
2 つの答え A・B の報酬を r(A)・r(B) とし、「A が好まれる確率」を σ(r(A) − r(B))(σ はシグモイド関数)とします。これは、スポーツの強さの比較などに使われてきた ブラッドリー・テリーモデルと同じ形です。報酬の差が大きいほど、好まれる確率は 1 に近づきます。人が選んだほうを「勝ち」として、この確率の対数尤度を上げるように学習します。深層学習以前の機械学習 で説明したロジスティック回帰と同じ計算です。
上の続きで、答え方の特徴に重みを掛けた和を報酬とする報酬モデルを作ります。人の本当の好み(モデルからは見えない)は「正確さ +2・丁寧さ +1・長さ +0.3・有害 −4」とし、この好みに従って、ランダムな 2 つの答えを比べた結果を作ります。人の判断にはばらつきがあるので、好まれる確率に従ってランダムに選びます。比較の結果のうち 700 件で学習し、残りで正解率を測ります。
# 2. 報酬モデル:人が 2 つの答えを比べた結果から、答えの良さを学ぶ
w_true = np.array([2.0, 1.0, 0.3, -4.0]) # 人の本当の好み(モデルからは見えない)
sigmoid = lambda x: 1 / (1 + np.exp(-x))
pairs = rng.choice(6, size=(1000, 2))
pairs = pairs[pairs[:, 0] != pairs[:, 1]]
prefer_first = rng.random(len(pairs)) < sigmoid(phi[pairs[:, 0]] @ w_true - phi[pairs[:, 1]] @ w_true)
win = np.where(prefer_first, pairs[:, 0], pairs[:, 1])
lose = np.where(prefer_first, pairs[:, 1], pairs[:, 0])
train, test = slice(0, 700), slice(700, None)
w = np.zeros(4)
for _ in range(2000): # ブラッドリー・テリーモデルの対数尤度を勾配法で上げる
d = phi[win[train]] - phi[lose[train]]
w += 0.5 * ((1 - sigmoid(d @ w))[:, None] * d).mean(axis=0)
print("報酬モデルの重み", np.round(w, 2))
acc = (phi[win[test]] @ w > phi[lose[test]] @ w).mean()
print("比較の正解率", round(acc, 3), "報酬", np.round(phi @ w, 2))
print("本当の好みで当てた場合", round((phi[win[test]] @ w_true > phi[lose[test]] @ w_true).mean(), 3), len(win[test]))
実行結果:
報酬モデルの重み [ 1.83 1.25 0.3 -4.25]
比較の正解率 0.899 報酬 [ 3.07 3.37 1.83 1.25 0.3 -2.43]
本当の好みで当てた場合 0.899 129
学習した重みは、人の本当の好み(2・1・0.3・−4)に近い値になりました。学習に使わなかった 129 件の比較で、人が選んだほうを報酬モデルが高く評価した割合は 89.9% です。3 行目のとおり、人の本当の好みを知っていても同じ 89.9% なので、人の判断のばらつきを考えると、これ以上は当てられません。
6 通りの答えの報酬は、「正確・丁寧・長い」がいちばん高い 3.37、「有害」がいちばん低い −2.43 になりました。
RLHF:報酬を上げつつ、元のモデルから離れすぎない
KL の罰則
報酬モデルができたら、言語モデルが出す答えの報酬が高くなるように、強化学習で学習します。これが RLHF(人間のフィードバックによる強化学習)です。
ただし、報酬だけを最大にすると困ったことが起きます。報酬モデルは限られた比較の結果から作った近似なので、報酬モデルが間違って高く評価する、おかしな答え(意味のない長文など)を見つけて、そればかり出すようになるのです。これを 報酬ハッキングと呼びます。
そこで、RLHF では **「報酬の期待値 − β × KL(今のモデル ‖ SFT のモデル)」**を最大にします。KL は KL ダイバージェンスで、2 つのモデルの確率がどれだけ違うかを表します。SFT のモデルから大きく離れるほど罰則がかかるので、報酬モデルの穴を突くような極端な答えに行きにくくなります。
β で何が変わるか
この「KL の罰則つきで報酬を最大にする」問題は、答えの数が少なければ、式で解けます。最適なモデルは、SFT のモデルの確率に exp(r / β) を掛けて、合計が 1 になるように割ったものです。上の続きで、β を変えて最適なモデルを求め、人の本当の好みで測った平均の良さと、SFT のモデルからの KL を比べます。
# 3. KL の罰則つきで報酬を最大にする方策は π ∝ π_SFT × exp(r / β)
p_sft = softmax(logits_sft)
def report(name, p):
kl = float((p * np.log(p / p_sft)).sum())
print(f"{name:8s}", np.round(p, 2), "本当の好み", round(float(p @ phi @ w_true), 2), "KL", round(kl, 2))
report("SFT", p_sft)
for beta in [2.0, 0.5, 0.1]:
report(f"β={beta}", softmax(np.log(p_sft) + phi @ w / beta))
実行結果:
SFT [0.28 0.39 0.06 0.08 0.12 0.06] 本当の好み 2.25 KL 0.0
β=2.0 [0.34 0.54 0.04 0.04 0.04 0. ] 本当の好み 2.93 KL 0.14
β=0.5 [0.28 0.71 0.01 0. 0. 0. ] 本当の好み 3.2 KL 0.4
β=0.1 [0.03 0.97 0. 0. 0. 0. ] 本当の好み 3.29 KL 0.8
SFT のモデルでは 6% 残っていた有害な答えが、β=2 でもほぼ 0 になり、人の好みで測った平均の良さが 2.25 から 2.93 に上がりました。β を小さくする(罰則を弱める)ほど、平均の良さは上がりますが、SFT のモデルからの KL も大きくなります。
β=0.1 では、報酬がいちばん高い「正確・丁寧・長い」答えを 97% の確率で選び、「正確・丁寧・短い」答えはほとんど選ばなくなりました。この例では報酬モデルが人の好みをよく近似しているので問題になりませんが、報酬モデルが少しでも間違っていれば、その間違いに全力で寄っていくことになります。たとえば、人の判断がもともと少し長い答えを好むと、罰則が弱いモデルは何でも長く答えるようになります。β は、改善の大きさと、元のモデルの多様さ・安全さとの釣り合いを決める値です。
実際の LLM では、答えの候補が数えきれないほどあるので、式では解けません。強化学習の記事 で説明した PPO で、少しずつモデルを更新します。2022 年の InstructGPT の論文では、13 億パラメーターの RLHF のモデルの答えが、100 倍以上大きい 1,750 億パラメーターの GPT-3 の答えより、人に好まれました。
DPO:比べた結果から直接学習する
報酬モデルを使わない
RLHF は、報酬モデルの学習と、PPO による強化学習の 2 段階が必要で、PPO は調整が難しく、計算も重い方法です。2023 年に発表された DPO(Direct Preference Optimization)は、上の「最適なモデルは SFT のモデル × exp(r / β)」という式を逆に使います。
式を変形すると、報酬は r(答え) = β × log(π(答え) / π_SFT(答え)) + 定数 と、モデルの確率で書けます。これをブラッドリー・テリーモデルに入れると、比較の結果だけから直接モデルを学習する損失になります。
損失 = −log σ( β × [ log(π(勝ち) / π_SFT(勝ち)) − log(π(負け) / π_SFT(負け)) ] )
人が選んだ答えの確率を SFT のモデルより上げ、選ばなかった答えの確率を下げるほど、損失は小さくなります。報酬モデルも強化学習もいらず、分類の学習と同じように勾配法で学習できます。
同じ比較の結果で DPO を学習する
上の続きで、同じ 700 件の比較の結果を使い、β=0.5 で DPO を学習します。
# 4. DPO:報酬モデルを作らず、比べた結果から直接方策を学ぶ
beta = 0.5
theta = logits_sft.copy()
for _ in range(3000):
lp = np.log(softmax(theta))
margin = beta * ((lp[win[train]] - np.log(p_sft)[win[train]]) - (lp[lose[train]] - np.log(p_sft)[lose[train]]))
g = (1 - sigmoid(margin)) * beta
grad = np.zeros(6)
np.add.at(grad, win[train], g); np.add.at(grad, lose[train], -g)
theta += 0.5 * grad / len(g)
report("DPO β=0.5", softmax(theta))
実行結果:
DPO β=0.5 [0.2 0.79 0.01 0. 0. 0. ] 本当の好み 3.23 KL 0.46
報酬モデルを作らずに、RLHF の β=0.5(本当の好み 3.2、KL 0.4)とほぼ同じ結果が得られました。確率の値が少し違うのは、報酬モデルが「特徴の重み」として報酬を学んだのに対し、DPO は 6 通りの答えそれぞれの確率を直接学んでいて、限られた比較の結果からの推定のずれ方が違うからです。
DPO は実装が簡単で安定しているため、公開されている多くのモデルの仕上げに使われています。ただし、学習の途中でモデル自身が新しい答えを出して試すことはしないので、報酬モデルと強化学習を使う方法のほうが良い結果になる場合もあり、どちらが良いかは今も研究が続いています。
その後の広がり
人のかわりに AI が比べる
比較の結果を人が大量に作るのは、時間も費用もかかります。2022 年に Anthropic が発表した Constitutional AI は、「有害な答えをしない」などの原則(憲法)を文章で与え、それに従って AI 自身が答えを比べたり直したりした結果で学習します。人のかわりに AI の判断を使う方法を RLAIF と呼びます。
正解を確かめられる問題で強化学習する
数学の問題やプログラミングの課題のように、答えが正しいかを機械的に確かめられる問題では、報酬モデルのかわりに「正解なら 1、不正解なら 0」の報酬を使って強化学習できます。報酬ハッキングが起きにくく、モデルは長く考えてから答えるようになります。2024 年の OpenAI の o1 や、2025 年の DeepSeek-R1 は、この方法で推論の力を大きく伸ばしました。DeepSeek-R1 の論文では、PPO の価値関数を使わず、同じ問題への複数の答えの報酬を比べて有利さを求める GRPO という方法が使われています。
LLM の学習の流れ
この記事で紹介した手法を年代順に並べます。
| 年 | 手法・出来事 | ポイント |
|---|---|---|
| 1952 | ブラッドリー・テリーモデル | 2 つのものの比較の結果から、それぞれの強さを推定する |
| 2017 | 人の好みからの深層強化学習(クリスティアーノら) | 人が 2 つの動きを比べた結果から報酬を学び、強化学習する |
| 2018 | GPT | Transformer で事前学習してから、課題ごとに追加で学習する |
| 2020 | スケーリング則・GPT-3 | 損失はモデル・データ・計算量のべき乗則で下がる |
| 2021 | FLAN | いろいろな課題を指示の形にして学習すると、見ていない指示にも従える |
| 2022 | Chinchilla・InstructGPT・Constitutional AI | パラメーター 1 つあたり約 20 トークン。SFT と RLHF で指示に従うモデルを作る。AI の判断で学習する |
| 2023 | DPO | 報酬モデルと強化学習を使わず、比較の結果から直接学習する |
| 2024 | LLaMA 3・o1 | 小さなモデルを大量のデータで学習する。強化学習で長く考えるモデル |
| 2025 | DeepSeek-R1 | 正解を確かめられる問題の報酬と GRPO で推論の力を伸ばす |
まとめ
- LLM は、事前学習・指示チューニング(SFT)・人の好みに合わせる学習の 3 段階で作られる
- 事前学習は次のトークンの交差エントロピーを下げる学習。損失はモデルの大きさ・データの量・計算量の釣り合いで決まり、言語そのものの不確かさより下には下がらない
- 学習の計算量はおよそ 6ND。Chinchilla はパラメーター 1 つあたり約 20 トークンを示したが、今は推論を安くするため、もっと多くのデータで小さなモデルを学習することが多い
- SFT は、お手本の答えの部分だけで損失を計算して、質問に答える形を覚えさせる
- 報酬モデルは、人が 2 つの答えを比べた結果から、ブラッドリー・テリーモデルで答えの良さを数値にする
- RLHF は KL の罰則つきで報酬を最大にする。β が小さいほど報酬は上がるが、元のモデルから離れ、報酬モデルの間違いにも寄りやすくなる
- DPO は、最適なモデルの式を逆に使って、比較の結果から直接モデルを学習する
参考
- R. A. Bradley and M. E. Terry, "Rank Analysis of Incomplete Block Designs: I. The Method of Paired Comparisons", Biometrika 1952
- P. Christiano et al., "Deep Reinforcement Learning from Human Preferences", NeurIPS 2017(arXiv:1706.03741)
- A. Radford et al., "Improving Language Understanding by Generative Pre-Training", 2018
- J. Kaplan et al., "Scaling Laws for Neural Language Models", 2020(arXiv:2001.08361)
- T. Brown et al., "Language Models are Few-Shot Learners", NeurIPS 2020(arXiv:2005.14165)
- J. Wei et al., "Finetuned Language Models Are Zero-Shot Learners", ICLR 2022(arXiv:2109.01652)
- J. Hoffmann et al., "Training Compute-Optimal Large Language Models", NeurIPS 2022(arXiv:2203.15556)
- L. Ouyang et al., "Training language models to follow instructions with human feedback", NeurIPS 2022(arXiv:2203.02155)
- Y. Bai et al., "Constitutional AI: Harmlessness from AI Feedback", 2022(arXiv:2212.08073)
- R. Rafailov et al., "Direct Preference Optimization: Your Language Model is Secretly a Reward Model", NeurIPS 2023(arXiv:2305.18290)
- A. Grattafiori et al., "The Llama 3 Herd of Models", 2024(arXiv:2407.21783)
- DeepSeek-AI, "DeepSeek-R1: Incentivizing Reasoning Capability in LLMs via Reinforcement Learning", 2025(arXiv:2501.12948)