アノテーションでLLMをファインチューニングする
研究自身のラベルで、SFTまたはDPOによるLLM、報酬モデル、プロセス報酬モデルを学習し、それぞれをホールドアウトした項目で採点して、Hubに公開します。
v2.14.0の新機能
このチュートリアルでは、Potatoの研究で集めた答えから、4種類の言語モデルを学習します。llm-sftトレーナーは、書かれた答えや修正されたエージェントのトレースでLLMをファインチューニングし、llm-dpoはペア選択でLLMを調整し、reward-modelは比較からスカラーの報酬モデルを当てはめ、prm-rewardはステップの評価からプロセス報酬モデルを当てはめます。このページは、Potatoですでに選好データやトレースのデータを集めていて、データを別の学習スクリプトにエクスポートせずに、そのラベルから最初のモデルを作りたいチームに向けて書かれています。各セクションは、データを生むスキームを示し、Potatoの検証を通る設定を載せ、変更する価値のあるパラメーターを挙げ、ホールドアウトスコアが何を測るか、予測が事前ラベルとしてアノテーターに戻るかどうかを述べます。モデル学習の概要はTrainingページを扱い、最初のモデルを学習するは、GPUのいらない分類器で全体のループを実行します。
アノテーションスキームごとのトレーナー
このページのトレーナーは、1回の実行で1つのアノテーションスキームから学習し、Trainingページは、トレーナーが学習できるスキームに対してだけ、そのトレーナーを提示します。次の表は、各トレーナーが学習元とするスキームを挙げています。
| トレーナー | スキーム | モデルが学習すること | ホールドアウトの代表指標 | アノテーターへの表示 |
|---|---|---|---|---|
llm-sft | text | アノテーターが書いた答えを書くこと | トークンF1 | あり。生成された答えがテキストボックスに入ります |
llm-sft | trajectory_edit | エージェントのステップを、修正されたステップに書き直すこと | closer_to_correction | なし。保存して採点するだけです |
llm-dpo | binaryモードのpairwise | アノテーターが選んだ応答を好むこと | 正解率(同点は数えません) | あり。好まれた応答のカードが選択されます |
llm-dpo | trajectory_edit | 元のステップよりも修正されたステップを好むこと | closer_to_correction | なし。保存して採点するだけです |
reward-model | pairwise(binaryとscale)、ranking、bws | 応答ごとのスコア | 正解率、方向の正解率、Kendallのtau、またはbest-worstの正解率 | あり。スキーム自身の答えとして表示されます |
prm-reward | process_reward | 各ステップの、correct、neutral、wrongのいずれかの評価 | step_macro_f1 | 「AI pre-label steps」ボタンから提示されます |
始める前に
Potatoの学習用extraは、4つのトレーナーのために、PyTorch、Transformers、PEFTをインストールします。
pip install "potato-annotation[train-llm]"
pip install "potato-annotation[train-text]"1つ目のextraはllm-sftとllm-dpoを、2つ目はreward-modelとprm-rewardをカバーします。pip install "potato-annotation[train]"は、すべての学習用extraを一度にインストールします。パッケージが足りないトレーナーは、Trainingページに「not installed」と表示され、パッケージをインストールするコマンドが添えられます。
どのトレーナーも、train分割の項目が20件に満たないと、当てはめを拒否します(min_instancesパラメーター)。既定の分割では、ラベル付き項目の70%がtrain、15%がval、15%がtestに入るため、最初の実行の前に、約30件のラベル付き項目を見込んでください。valとtestの項目は学習から外され、モデルの採点に使われます。
llm-sftとllm-dpoはQwen/Qwen2.5-0.5B-Instructから、reward-modelはdistilbert/distilroberta-baseから、prm-rewardはanswerdotai/ModernBERT-baseから始まります。LLMのトレーナーはGPUで動かす前提で作られています。Potatoを動かすマシンにGPUがないときは、リモート学習が、ssh経由のGPUサーバーまたはSLURMクラスターに実行を送ります。
選好と書き直しを集める研究
最初の設定は、カスタマーサポートの各プロンプトについて、2つのことを尋ねます。アノテーターは2つの応答のうち良いほうを選び、アシスタントに望む答えを書きます。選択はllm-dpoとreward-modelを学習し、書かれた答えはllm-sftを学習します。data/answers.jsonlの各行には、プロンプトと2つの応答が入っています。
{"id": "q001", "prompt": "How do I reset my router to factory settings?", "responses": ["Hold the reset button on the back for 10 seconds until the lights blink, then wait two minutes for the router to restart.", "Routers can be reset. Check the manual."]}この設定は、プロンプトを項目のテキストとして、2つの応答をカードAとBとして表示します。
annotation_task_name: "Support answers: preferences and rewrites"
task_dir: .
data_files:
- data/answers.jsonl
item_properties:
id_key: id
text_key: prompt
output_annotation_dir: annotation_output
user_config:
allow_all_users: true
annotation_schemes:
- annotation_type: pairwise
name: preferred
description: "Which response answers the question better?"
mode: binary
items_key: responses
allow_tie: true
tie_label: "No preference"
- annotation_type: text
name: rewrite
description: "Write the answer you would want the assistant to give."
multiline: true
rows: 4
model_training:
enabled: true
writeback:
schemas: [preferred]
min_confidence: 0.7text_key: promptは2つの点で重要です。プロンプトはアノテーターが読むものであり、llm-sftが質問の後ろに置くものでもあるからです。items_key: responsesは、ペアのカードの元になるリストを、データの順序で指定するため、Aは最初の応答になります。writeback.schemasにはpreferredだけを挙げているので、アノテーターには、生成された書き直しではなく、モデルの選択が表示されます。事前ラベルはアノテーターを引きずるため、rewriteをリストに加えるのは、モデルのテキストを表示することをllm-sftの実行のホールドアウトスコアが裏付けてからにしてください。min_confidence: 0.7は、モデルの確信が低い予測をページに出さず、予測自体は保存します。サーバーを起動する前に、Potatoの検証で設定を確認します。
python -m potato.validate_cli config.yaml --strictPotatoを起動し、少なくとも30件のプロンプトにラベルを付けてから、管理者として/admin/trainingを開きます。以下の実行は、設定のadmin_api_keyを$KEYに入れて、APIから開始することもできます。
llm-sftによる教師ありファインチューニング
llm-sftは、ラベル付きの各項目を1つの学習例にします。プロンプトは、スキームのdescription(アノテーターが見た質問)に項目のテキストが続いたもので、ターゲットはアノテーターが書いた答えです。損失は答えのトークンだけにかかるため、モデルはプロンプトを繰り返すのではなく、答えることを学習します。既定では、すべての重みではなく、LoRAアダプターを学習します。
Trainingページでllm-sftとrewriteスキームを選び、Train nowをクリックするか、同じ実行をAPIから開始します。
curl -X POST -H "X-API-Key: $KEY" -H "Content-Type: application/json" \
http://localhost:8000/admin/training/api/runs \
-d '{"trainer": "llm-sft", "schemas": ["rewrite"], "params": {"max_new_tokens": 256}}'ほとんどの実行で変更するのは、この表のパラメーターだけです。
| パラメーター | 既定値 | 意味 |
|---|---|---|
model_name | Qwen/Qwen2.5-0.5B-Instruct | Hugging Face Hubにある因果言語モデル、またはローカルのディレクトリ。 |
lora | true | falseにするとすべての重みを学習し、数倍のメモリが必要です。{quantize: 4bit}は、ベースモデルを4ビットで読み込みます(QLoRAを参照)。 |
max_length | 1024 | 1例あたりのトークン数。長いプロンプトは先頭からトークンを失い、答えは残ります。 |
max_new_tokens | 256 | モデルが生成する答えの最大の長さ。 |
instruction | スキームのdescription | 各項目のテキストの前に置くテキスト。 |
system_prompt | なし | チャットテンプレートを持つモデル向けのシステムメッセージ。 |
gradient_checkpointing | false | 活性化のメモリを節約する代わりに、時間が約3分の1増えます。 |
learning_rate | LoRAありは2e-4、なしは1e-5 |
実行は、valの損失が最も低いチェックポイントを残します。チェックポイントをvalで選んだため、ホールドアウトスコアはtestから読み取られます。スコアはトークンF1で、生成された答えと書かれた答えの間の、順序を問わない単語の重なりであり、スコアの隣に完全一致も報告されます。トークンF1は、正しい単語を誤った位置で使った答えにも点を与えるため、2つの指標を合わせて読んでください。
モデルは、すべてのvalとtestの項目について、答えを貪欲法で生成します。writeback.include_unlabeled: trueのときは、誰もラベルを付けていない項目にもモデルが答えます。予測の信頼度は、モデルが生成したトークンの平均確率であり、モデルレビューキューはこの信頼度で並べ替えます。rewriteをwriteback.schemasに挙げると、アノテーターが項目を開いたときに、生成された答えがテキストボックスに入ります。
自由記述は、1項目に複数のアノテーターをつける使い方には向きません。aggregationの設定は、答えを単語ごとに比べて、複数の答えを1つに統合しますが、書かれた2つの答えが単語ごとに一致することはめったにありません。textスキームのllm-sftでは、項目ごとに書き手を1人にすると、単語ごとの比較を避けられます。
llm-dpoによる選好の調整
Direct Preference Optimization(DPO)は、開始時のモデルを凍結した参照コピーを基準にして、好まれた応答の尤度を、もう一方の応答に対して高めるようにLLMを学習します。llm-dpoは、AまたはBと答えられた各項目から1つの例を作ります。プロンプトは、項目のpromptフィールド、またはそれがなければ、項目が持つquestion、instruction、query、input、contextのうち最初のものです。同点の選択肢で答えられた項目は、同点がどちらの応答も良いと示さないため、除外されます。
llm-dpoとpreferredスキームを選ぶか、上と同じリクエストに"trainer": "llm-dpo"と"schemas": ["preferred"]を指定して送ります。既定のLoRAアダプターでは、参照モデルは、アダプターを切ったときの同じモデルなので、2つ目のコピーはメモリに保持されません。lora: falseはすべての重みを学習し、凍結したコピーを参照として保持するため、メモリは2倍になります。
| パラメーター | 既定値 | 意味 |
|---|---|---|
model_name | Qwen/Qwen2.5-0.5B-Instruct | 因果言語モデル。 |
beta | 0.1 | モデルが参照からどこまで離れてよいか。値が小さいほど、モデルはより遠くへ動けます。 |
epochs | 2 | |
learning_rate | LoRAありは5e-5、なしは5e-7 | |
max_length | 1024 | プロンプトと応答あたりのトークン数。 |
instruction | なし | 各項目のプロンプトの前に置くテキスト。 |
実行は、valでDPOの損失が最も低いチェックポイントを残し、実行ログは、モデルがvalでアノテーターの選択をどのくらいの頻度で好むかを報告します。ホールドアウトスコアは、同点と答えられなかった項目に対するtestの正解率で、正解率の隣にmacro-F1が示されます。予測は、学習したモデルが好む応答で、その好みの確率が信頼度になります。事前ラベルとしては、アノテーターが項目を開いたときに、好まれた応答のカードが選択されます。スキームでrandomize_orderを使っている場合、選択は、アノテーターに見える位置に関わらず、その応答に付いていきます。保存されたアダプターはポリシーでもあり、PEFTで読み込むとテキストを生成します。選好データそのものの集め方の背景は、RLHFと選好データの収集とペア比較を参照してください。
reward-modelによる報酬モデル
報酬モデルは、RLHFやbest-of-nサンプリング、新しい出力のランキングのために、応答を数値に写像します。reward-modelは、出力が1つのトランスフォーマーを、アノテーターが好んだ応答が高いスコアになるように学習します。損失はBradley–Terry損失、-log sigmoid(r_winner - r_loser)で、InstructGPTの報酬モデルの損失です。上のpreferredスキームは、設定を変えずにreward-modelを学習します。比較型のスキームごとに、学習の信号が異なります。
| スキーム | 学習の信号 | ホールドアウトの代表指標 |
|---|---|---|
pairwise、binary | 選ばれた応答がもう一方に勝ちます。同点は飛ばされます。 | 正解率 |
pairwise、scale | スライダーが傾いた側が勝ち、傾きの大きさで重み付けされます。中点は飛ばされます。 | 方向の正解率 |
ranking | 順序全体で、Plackett-Luce損失、またはranking_loss: pairsなら順序内のすべてのペア。 | Kendallのtau |
bws | 最良の項目がタプル内のほかのすべての項目に勝ち、ほかのすべての項目が最悪の項目に勝ちます。 | best-worstの正解率 |
項目にプロンプトのフィールドがあるときは、各報酬は、そのプロンプトを与えられた応答に対するものです。ランキングの選択肢はスキームのラベルで、それぞれが項目のテキストを与えられて採点されます。サーバーはbws_configからBWSのタプルを作るため、サーバー自身のデータからの実行にはタプルがあり、データファイルにタプルは必要ありません。
| パラメーター | 既定値 | 意味 |
|---|---|---|
model_name | distilbert/distilroberta-base | エンコーダー、またはloraを使うLLM。 |
ranking_loss | plackett_luce | rankingスキームのみ。plackett_luceまたはpairs。 |
max_length | 512 | 採点される1つのテキストあたりのトークン数。プロンプトと応答の合計。 |
learning_rate | 2e-5、LoRAありは2e-4 |
予測はスキーム自身の問いに答えるため、予測はほかのスキームの予測と同じように採点され、書き戻されます。事前ラベルは、二者択一なら選択されたカード、スケールならスライダーの位置、ランキングならリストの順序、BWSなら選択された最良と最悪です。すべての予測は、予測の元になったrewardsも保存します。意味があるのは、報酬どうしの差だけです。データを集めるための比較型の形式の比較は、ペア比較とBest-Worst Scalingにあります。
ステップの評価と修正を集める研究
2つ目の設定は、エージェントのトレースを扱います。アノテーターはトレースの各ステップを評価し、そのうえで間違ったステップを直します。ステップの評価はprm-rewardを学習し、修正はllm-sftまたはllm-dpoを学習します。data/traces.jsonlの各行には、タスク、エージェントのステップ、最終的な答えが入っています。
{"id": "traj_001", "task_description": "Find the current weather in San Francisco and report the temperature.", "steps": [{"thought": "I should look up the current weather.", "action": "web_search(queyr='San Francisco weather')"}, {"thought": "Open the first result.", "action": "open_url(results[0])"}, {"thought": "Read the temperature from the page.", "action": "extract_text('.temp')"}], "final_answer": "It is sunny."}トレーナーは、項目のtask_description、task、textの各フィールドを、この順序でタスクとして読みます。
annotation_task_name: "Agent traces: step ratings and corrections"
task_dir: .
data_files:
- data/traces.jsonl
item_properties:
id_key: id
text_key: task_description
output_annotation_dir: annotation_output
user_config:
allow_all_users: true
annotation_schemes:
- annotation_type: process_reward
name: step_quality
description: "Rate each step of the agent's trace"
steps_key: steps
step_text_key: action
mode: per_step
allow_neutral: true
ai_prelabel: true
- annotation_type: trajectory_edit
name: corrected_trace
description: "Fix the wrong steps, then correct the final answer"
steps_key: steps
step_text_key: action
editable_fields: [action]
show_diff: true
edit_final_answer: true
final_answer_key: final_answer
model_training:
enabled: true
writeback:
schemas: [step_quality]
include_unlabeled: trueallow_neutral: trueを伴うmode: per_stepは、prm-rewardが学習する3つの評価を与えます。ai_prelabel: trueはスキームに「AI pre-label steps」ボタンを置き、学習された評価はこのボタンから表示されます。writeback.schemasにはstep_qualityだけを挙げています。そこにcorrected_traceを挙げると、サーバーが起動しなくなり、検証が理由を示します。
model_training.writeback.schemas names 'corrected_trace', a trajectory_edit scheme, which has no prelabel display: its predictions are stored and scored but annotators would never see them. Leave it out of writeback.schemas.llm-sftとllm-dpoによるトレースの修復
trajectory_editの答えは、2つのトレースのペアで、エージェントの元のステップと、アノテーターの修正後のステップです。SFT/DPOのための軌跡編集はエディターを扱い、軌跡編集の記事は、ペアがどのように学習データになるかを扱います。どちらのトレーナーも、誰も編集していないトレースは除外します。
- **
llm-sft**は、タスクと元のステップをプロンプトに、修正されたステップをターゲットにするため、モデルはトレースを修復することを学習します。各ステップは、Step Nに続けてステップのフィールド(action: ...、thought: ...)として書かれ、スキームにfinal_answer_keyがあるときは、最後のステップの後に最終的な答えが続きます。 - **
llm-dpo**は、タスクをプロンプトに、修正されたステップを好まれる応答に、元のステップをもう一方の応答にします。予測は、モデルが修正(A)と元(B)のどちらを好むかを示し、修正のあるホールドアウトのトレースに対してだけ作られます。
どちらの実行も、ホールドアウトスコアとしてcloser_to_correctionを報告します。llm-dpoでは、このスコアは、モデルが修正を好むホールドアウトのトレースの割合です。llm-sftでは、書かれたステップが、トークンF1で元よりも修正に近いトレースの割合で、スコアの隣に、修正に対するtoken_f1が報告されます。
trajectory_editの実行の予測は保存されて採点されますが、アノテーターには表示されません。エディターは常にエージェントの元のトレースから始まるため、予測された書き直しを表示する場所がページにありません。予測は、実行ページか、実行のディレクトリにあるartifacts/predictions.jsonlから読んでください。
prm-rewardによるステップの評価
プロセス報酬モデルは、PRM800Kのように、最終的な答えだけでなく、トレースのステップを評価します。prm-rewardは、トレース全体を、タスクにStep 1、Step 2などが続く1つの入力として、トランスフォーマーのエンコーダーに入れます。エンコーダーは、各ステップの最後のトークンで3値の評価を学習するため、各評価は、そのステップより前のステップを見たうえで行われます。誰も評価していないステップは、損失から除外されます。既定のモデルanswerdotai/ModernBERT-baseは、8,192トークンのコンテキストを理由に選ばれました。
| パラメーター | 既定値 | 意味 |
|---|---|---|
model_name | answerdotai/ModernBERT-base | 高速なトークナイザーを持つエンコーダー。 |
max_length | 1024 | 1トレースあたりのトークン数。 |
epochs | 6 | |
batch_size | 8 | 1ステップあたりのトレース数。 |
learning_rate | 5e-5、LoRAありは3e-4 |
長いトレースは、最後のステップを失います。max_lengthトークンより長いトレースは末尾から切られ、切れ目より後のステップは、学習にも評価にも使われません。実行ログは、失われたステップを数えます。max_lengthがモデルの保持できる長さを超えるときは、実行が警告とともにmax_lengthをモデルの上限まで下げ、ほとんどのBERT系のエンコーダーでは上限は512トークンです。実行ログが失われたステップを報告したら、max_lengthを上げ、より長いトレースを保持できるコンテキストを持つモデルを選んでください。
ホールドアウトスコアはstep_macro_f1で、評価されたすべてのステップにわたる3つの評価のmacro-F1です。ほとんどのトレースでほとんどのステップは正しいため、正解率では、「wrong」と決して言わないモデルが有利に見えてしまいます。実行はstep_accuracyとfirst_error_accuracyも報告します。後者は、モデルが最初に間違いとしたステップが、アノテーターが最初に間違いとしたステップと一致するトレースの割合です。
予測は、max_lengthに収まるすべてのステップを評価し、各評価の確率をその評価の信頼度に、最も確信の低いステップをトレースの信頼度にします。スキームがwriteback.schemasにあり、ai_prelabel: trueのとき、「AI pre-label steps」ボタンが、学習された評価をアノテーターの確認用に提示します。ai_supportで設定したLLM審査は、学習された評価がある項目に対しては呼び出されません。スキームはプロセス報酬アノテーションが、データはプロセス報酬モデルのガイドが扱います。
QLoRAでより大きなモデルを収める
QLoRAは、ベースモデルの重みを4ビットで読み込み、その上でLoRAアダプターを学習します。llm-sft、llm-dpo、hf-text-classification、vlm-sft、reward-modelはlora: {quantize: 4bit}を受け付け、prm-rewardは、モデルを読み込む前にこの設定を拒否します。メモリの見積もりには、すべてのトランスフォーマーの実行が最後に記録する「Peak GPU memory」の行を使ってください。設定リファレンスのQLoRAのセクションは、ベースの重みの読み込み方と8ビットのオプションを説明しています。
上の設定にこのブロックを加えると、llm-sftの既定がQLoRAになります。
model_training:
enabled: true
trainer_params:
llm-sft:
model_name: Qwen/Qwen2.5-7B-Instruct
lora: {quantize: 4bit}
gradient_checkpointing: trueQLoRAには、CUDAのGPUと、そのマシンのCUDA向けのbitsandbytesのビルドが必要で、pip install bitsandbytesでインストールします。動作するGPUやビルドがないと、実行は、モデルを読み込む前の検証で止まります。
実行をHugging Face Hubに公開する
Potatoサーバー上にモデルがある成功した実行には、実行ページにPublish to the Hugging Face Hubがあります。プッシュは、モデルと、実行から書かれたREADME.mdのモデルカードをアップロードします。カードには、トレーナー、ベースモデルとアダプター、スキームとラベル、分割のサイズ、ホールドアウトスコアとスコアを測った対象、実行とバンドルのIDが入っています。LoRAの実行はアダプターだけを保存したため、Hubのリポジトリにはアダプターが入り、カードには、アダプターを載せるベースモデルが書かれています。
トークンはブラウザーには渡りません。Hugging Faceの設定で書き込み用のトークンを作成し、Potatoを起動する前に、サーバーの環境に設定します。
export HF_TOKEN=hf_your_write_token
potato start config.yamlフォームは環境変数名(既定はHF_TOKEN)を示し、リポジトリ名を2回尋ね、Privateを既定でオンにしています。Hugging Face Hubへの公開は、アップロードされるファイル、プッシュ前のチェック、モデルカードのライセンスを挙げています。APIからの同じプッシュは次のとおりです。
curl -X POST -H "X-API-Key: $KEY" -H "Content-Type: application/json" \
http://localhost:8000/admin/training/api/runs/RUN_ID/push-to-hub \
-d '{"repo_id": "your-org/support-dpo", "confirm_repo_id": "your-org/support-dpo", "private": true, "licence": "apache-2.0"}'ルートはコミットとともに201を返します。fetch_artifacts: falseでリモートホストに残されたモデルは、Potatoサーバーからプッシュできず、実行ページがモデルの場所を示します。公開したモデルから能動学習のループに進むには、ループ内のモデルに進んでください。
参考資料
- モデル学習の設定: すべての
model_trainingのキー、ホールドアウトスコア、書き戻し、ルート。 - トレーナー: タスク別にまとめた、38のトレーナーすべて。
- リモート学習: ssh経由のGPUサーバー、SLURMクラスター、ポーリングするエージェント。
- エージェントの軌跡のアノテーション: Potatoでトレースのデータを集める。
- アップストリームのリファレンスのセクション:
llm-sft、llm-dpo、エージェントのトレース、prm-reward、reward-model、QLoRA、Hubへの公開。
参考文献
- Dettmers, T., Pagnoni, A., Holtzman, A., and Zettlemoyer, L. (2023). QLoRA: Efficient Finetuning of Quantized LLMs. arXiv:2305.14314. arxiv.org/abs/2305.14314
- Hu, E. J., Shen, Y., Wallis, P., Allen-Zhu, Z., Li, Y., Wang, S., Wang, L., and Chen, W. (2021). LoRA: Low-Rank Adaptation of Large Language Models. arXiv:2106.09685. arxiv.org/abs/2106.09685
- Lightman, H., Kosaraju, V., Burda, Y., Edwards, H., Baker, B., Lee, T., Leike, J., Schulman, J., Sutskever, I., and Cobbe, K. (2023). Let's Verify Step by Step. arXiv:2305.20050. arxiv.org/abs/2305.20050
- Ouyang, L., Wu, J., Jiang, X., Almeida, D., Wainwright, C. L., Mishkin, P., Zhang, C., Agarwal, S., Slama, K., Ray, A., Schulman, J., Hilton, J., Kelton, F., Miller, L., Simens, M., Askell, A., Welinder, P., Christiano, P., Leike, J., and Lowe, R. (2022). Training Language Models to Follow Instructions with Human Feedback. arXiv:2203.02155. arxiv.org/abs/2203.02155
- Rafailov, R., Sharma, A., Mitchell, E., Ermon, S., Manning, C. D., and Finn, C. (2023). Direct Preference Optimization: Your Language Model is Secretly a Reward Model. arXiv:2305.18290. arxiv.org/abs/2305.18290