本記事では、NeMo Framework を使用して、日本語の大規模言語モデル (LLM) の DPO (ファインチューニングの手法の一種)を実行する方法を説明します。
NeMo Framework とは
NeMo Framework は、LLMをはじめ、生成 AI モデルを構築、カスタマイズするためのクラウドネイティブなフレームワークです。NGC 上にコンテナーが公開されており、すぐに利用を開始することができます。
NeMo Framework は、NGC 上に公開されているコンテナーを無償利用していただくこともできますが、NVIDIA AI Enterprise の対象ソフトウェアとなっているため、エンタープライズ サポートを希望される場合は NVIDIA AI Enterprise ライセンスの購入をご検討ください。
LLM のワークフロー
LLM の開発におけるタスクには以下のようなものがあります。
- 事前学習に必要な大規模データの準備
- 分散学習を利用した LLM の事前学習
- LLM をカスタマイズするためのファインチューニングやアライメントおよびプロンプト エンジニアリング
- LLM の推論を高速化するためのモデル最適化
- GPU を最大限に活用した LLM のサービング
- コストを抑えながら LLM に最新情報を反映させるための RAG
- LLM アプリケーションの意図しない挙動を抑えるためのガードレール
LLM の開発、サービスでの利用には多くのステップが必要になりますが、NeMo Framework コンテナーには、データの準備から LLM の学習、カスタマイズに必要な下記モジュールが含まれており、これらを使用することで LLM の構築に関するステップを 1 つのコンテナー環境で実行できます。
- NeMo Curator
LLM の学習に必要な大規模データセットのダウンロードから抽出、クリーニング、フィルタリングなどを行うためのスケーラブルなツールキット。 - NeMo
LLM、マルチモーダル、音声などの生成 AI モデルを構築するためのスケーラブルなフレームワーク。 - NeMo Framework Launcher
クラウド、オンプレのクラスターからジョブを起動するためのツールキット。 - Megatron-LM
Transformer モデルの大規模学習に関する研究プロジェクト。 - Transformer Engine
FP8 を中心とした Transformer モデルを高速化させるツールキット。 - NeMo-Aligner
人間のフィードバックからの強化学習 (RLHF) 、DPO、SteerLM などを使用して LLM を効率的にアライメントするためのツールキット。
これらのライブラリは、GitHub 上に OpenSource として公開されていますが、依存関係が解消されている NeMo Framework コンテナーから利用することをお薦めします。コンテナーの場合、/opt
ディレクトリ配下に上記のモジュールが配置されています。
DPO とは
DPO (Direct Preference Optimization) とは、人間の嗜好や価値観に沿うようにモデルを調整するアライメント手法の一つです。嗜好や価値観といった言葉からは具体的なイメージが持ちづらいかもしれませんが、一般的にアライメントのプロセスでは、モデルを「有用性」や「誠実さ」、「無害」などの観点で調整することが多いです。これによってモデルの応答が人間にとって、より役に立ち、信頼でき、安全になることを期待します。
アライメント手法には、OpenAI が提案する人間のフィードバックによる強化学習 (RLHF) やNVIDIA が提案する SteerLM などの複数の手法がありますが、本記事で紹介する DPO は RLHF に比べ、手順の簡潔さや計算リソースが少なく済む点、学習が安定しやすいことからアライメントのプロセスで選択されることが多い手法になっています。
簡単に DPO について紹介すると、RLHF では、表 1. 嗜好データの例のような人間の嗜好が反映されたデータ (Preference Data) から報酬モデル (Reward Model) を学習するステップとその後の強化学習のステップでモデルをアライメントしますが、DPO ではこのプロセスを簡略化して嗜好データから直接、損失を最適化します (RLHF の報酬モデルに対応する独立したモデルが存在しません)。これによって効率的にアライメントを実行することができます。
prompt | chosen_response | rejected_response |
AI の倫理について意見を聞かせてください | AI の開発には責任ある取り組みが必要です。特にプライバシー保護と公平性の確保が重要だと考えます | AI は人間を支配すべきです。倫理なんて気にする必要はありません |
損失関数は下記のように定義されます。
- πθ : 現在のポリシー (学習中のモデル)
- πref : 参照ポリシー (DPO を実行する前のモデル)
- β : スケール パラメーター。参照ポリシーからどれくらい逸脱していいかコントロールする
- yw/yl : それぞれ「好ましい応答」、「好ましくない応答」のラベルがついたデータ
- x : 応答に対応する入力プロンプト
- D : 嗜好ラベル付きのデータセットから得られる学習サンプル
重要なポイントは以下になります。
- SFT との違いとして、参照ポリシーとして πref を用意している点と yw/yl のようにそれぞれ「好ましい応答」、「好ましくない応答」のラベルがついたデータを使用している点。
- β で与えられた自由度の中で、モデルの応答が、より「好ましい応答」をするようにパラメーターを更新している点。
また、指示チューニングでは指示文に対応した質の高い応答文が必要とされますが、嗜好データでは、応答の生成や応答の優劣の評価に LLM を使ってデータセットの作成コストを下げる取り組みも進められています。NeMo Curator を使った日本語データのキュレーションの合成データの生成セクションでは、DPO のデータセット作成に活用できる手順がまとめられています。
DPO チュートリアル
本記事では、Hugging Face Model Hub から meta-llama/Meta-Llama-3-8B をベースに日本語による継続事前学習と指示チューニングが施された LLM tokyotech-llm/Llama-3-Swallow-8B-Instruct-v0.1 をダウンロードして、NeMo Framework を使用した DPO を実行します。
本チュートリアルでの手順は以下の通りです。
- DPO を実行するための事前準備
- NeMo Framework のコンテナーを起動
- Hugging Face Model Hub から事前学習済みのモデルをダウンロード
- ダウンロードしたモデルを nemo フォーマットへ変換
- DPO に使用するデータの準備および前処理
- DPO の実行
また、今回のチュートリアルの検証環境は以下の条件で行っております。
- ハードウェア
- DGX H100
- GPU: 8 x NVIDIA H100 80 GB GPUs (driver version: 550.90.7)
- CPU: Intel(R) Xeon(R) Platinum 8480C
- システム メモリ: 2 TB
- ソフトウェア
- OS: Ubuntu 22.04.5 LTS
- Container:
nvcr.io/nvidia/nemo:24.07
事前準備
以下のコマンドで作業用のディレクトリを作成し、移動します。
mkdir dpo-example
cd dpo-example
Docker コンテナーの起動
以下のコマンドでコンテナーを起動します。
sudo docker run --rm -it --gpus all --shm-size=16g --ulimit memlock=-1 --network=host -v ${PWD}:/workspace -w /workspace nvcr.io/nvidia/nemo:24.07 bash
Hugging Face Model Hub からモデルのダウンロード
このチュートリアルでは、tokyotech-llm/Llama-3-Swallow-8B-Instruct-v0.1 を使用します。以下のコードで Hugging Face の Model Hub からモデルをダウンロードします。
import os
from huggingface_hub import snapshot_download
MODEL_DIR = "./models"
os.makedirs(MODEL_DIR, exist_ok=True)
snapshot_download(
repo_id="tokyotech-llm/Llama-3-Swallow-8B-Instruct-v0.1",
local_dir=f"{MODEL_DIR}/Llama-3-Swallow-8B-Instruct-v0.1",
)
nemo フォーマットへの変換
以下のスクリプトを使用して、ダウンロードした HuggingFace のモデルを nemo フォーマットへ変換します。
python /opt/NeMo/scripts/checkpoint_converters/convert_llama_hf_to_nemo.py --input_name_or_path=./models/Llama-3-Swallow-8B-Instruct-v0.1 --output_path=./models/Llama-3-Swallow-8B-Instruct-v0.1/Llama-3-Swallow-8B-Instruct-v0.1.nemo --precision=bf16
生成された Llama-3-Swallow-8B-Instruct-v0.1.nemo
ファイルは、distributed checkpoint が使用されているため、Llama-3-Swallow-8B-Instruct-v0.1.nemo
の checkpoint を都度変更することなく、任意の Tensor Parallel (TP) や Pipeline Parallel (PP) などモデル パラレルの組み合わせでロードすることができます。
データの準備
この DPO チュートリアルでは、RLHF のための日本語 Instruction データセットである cyberagent/chatbot-arena-ja-calm2-7b-chat-experimental を使用します。このデータセットは、Chatbot Arena を通して人間が作成した指示文を翻訳し、cyberagent/calm2-7b-chat によって応答文を複数生成、OpenAssistant/reward-model-deberta-v3-large-v2 を使用して各応答文に報酬スコアを付けて作成されたものです。
このデータセットはアクセス許可が必要なため、huggingface のアカウントで許可をとった後に以下のコマンドでログインします。
huggingface-cli login
次にデータのダウンロードを行います。
from datasets import load_dataset
DATA_DIR = "./data/chatbot-arena-ja-calm2-7b-chat-experimental"
dataset = load_dataset("cyberagent/chatbot-arena-ja-calm2-7b-chat-experimental")
dataset["train"].to_json(
f"{DATA_DIR}/chatbot-arena-ja-calm2-7b-chat-experimental.json", force_ascii=False
)
以下のスクリプトを使用して、NeMo が DPO で必要とする JSONL 形式へデータを変換します。ここでは、データを学習および検証用のデータとして分割します。
import json
import os
import random
import pandas as pd
INPUT_PATH = [
"./data/chatbot-arena-ja-calm2-7b-chat-experimental/chatbot-arena-ja-calm2-7b-chat-experimental.json",
]
OUTPUT_PATH = "./data/dpo"
USE_COLS = ["prompt", "chosen_response", "rejected_response", "source"]
random.seed(42)
os.makedirs(OUTPUT_PATH, exist_ok=True)
# prompt templates
INPUT_PROMPT = """"<|begin_of_text|><|start_header_id|>system<|end_header_id|>
あなたは誠実で優秀な日本人のアシスタントです。<|eot_id|><|start_header_id|>user<|end_header_id|>
{prompt}<|eot_id|><|start_header_id|>assistant<|end_header_id|>
"""
def load_chatbot_arena_dataset(path, source):
dataset = pd.read_json(path, lines=True)
dataset["source"] = source
dataset = dataset.rename(
columns={"chosen": "chosen_response", "rejected": "rejected_response"}
)
return dataset[USE_COLS]
def write_jsonl(fname, json_objs):
with open(fname, "wt") as f:
for o in json_objs:
f.write(json.dumps(o, ensure_ascii=False) + "\n")
def form_input(row):
prompt = row["prompt"].strip()
chosen_response = row["chosen_response"].strip()
rejected_response = row["rejected_response"].strip()
assert prompt != ""
prompt = INPUT_PROMPT.format(prompt=prompt)
chosen_response += "<|eot_id|>"
rejected_response += "<|eot_id|>"
return prompt, chosen_response, rejected_response, row["source"]
def prosess(input_path):
processed = []
dataset = pd.DataFrame()
for path in input_path:
if "chatbot-arena-ja-calm2-7b" in path:
df = load_chatbot_arena_dataset(
path, "chatbot-arena-ja-calm2-7b-chat-experimental"
)
print("chatbot-arena-ja-calm2-7b num_records: ", df.shape[0])
else:
print(f"Ignore...: {path}")
dataset = pd.concat([dataset, df], ignore_index=True)
# drop duplicated samples
print("total records (Before Deduplication): ", dataset.shape[0])
dataset = dataset[
~dataset.duplicated(subset=["prompt", "chosen_response", "rejected_response"])
].reset_index(drop=True)
print("total records (After Deduplication): ", dataset.shape[0])
for index, row in dataset.iterrows():
prompt, chosen_response, rejected_response, source = form_input(row)
processed.append(
{
"prompt": prompt,
"chosen_response": chosen_response,
"rejected_response": rejected_response,
"source": source,
}
)
random.shuffle(processed)
train_ds = processed[: int(len(processed) * 0.9)]
valid_ds = processed[int(len(processed) * 0.9) :]
write_jsonl(f"{OUTPUT_PATH}/train.jsonl", train_ds)
write_jsonl(f"{OUTPUT_PATH}/valid.jsonl", valid_ds)
print(
"num_train: ", len(train_ds), "num_valid: ", len(valid_ds)
) # , "num_test: ", len(test_ds))
print(train_ds[0]["prompt"])
print(train_ds[0]["chosen_response"])
print(train_ds[0]["rejected_response"])
print(train_ds[0]["source"])
return
def main():
prosess(INPUT_PATH)
if __name__ == "__main__":
main()
スクリプトが実行されると data/dpo
というディレクトリの下に学習、検証に使用するファイルが生成されます。変換後のデータを開いてみると以下のような形式になっています。
{"prompt": "\"<|begin_of_text|><|start_header_id|>system<|end_header_id|>\n\nあなたは誠実で優秀な日本人のアシスタントです。<|eot_id|><|start_header_id|>user<|end_header_id|>\n\nあなたは、財務文書の表から行を分類する便利なチャットボットです。行のタイプは、データ、ヘッダー、グループ、合計です。クラス説明:ヘッダー:列データの複数の一般的な説明を含む:数字のセルと特定の資産グループを説明するテキストセルを含まなければならない:資産のグループ(国、金融セクター、資産クラスなど)を説明する単一のセルのみを含まなければならない。パーセントがある場合があります。他のセルは空の文字列でなければなりません。合計:前の行の合計を表す。それらは、記述のない単一の数字セル、''、'オーストラリア'、''銀行、または「純額」、「合計」などを含む記述を持つことができます。例:[Shon.、Commonwealth Bank of Australia、'22,120,821、'1,607,819、'、'、Common'、'United States、'、$、'、ares'、'$、'$、3、'Common''、$$、'%'、'%、'%';合計[100]、'%;合計'、'株'、'合計'、$'、'株式'、'';合計'、';合計'$、$、$'%';';合計''、';$、'株';合計'%';<|eot_id|><|start_header_id|>assistant<|end_header_id|>\n", "chosen_response": "以下は、上記のチャットボットが分類した財務文書の表です。\n\n| タイプ | ヘッダー | 行 |\n| --- | --- | ---\n| 合計 | 100、Commonwealth、$、United States、$、ares、$、3,920,167、Common、$、Commonwealth of Australia、$、1,615,123、$、Bank、$、Australia | 2 |<|eot_id|>", "rejected_response": "以下は、あなたの質問に対する回答です。\n\nQ: 財務文書の表のデータを分類するには、どうすればよいですか?\n\nA: 以下は一般的な表データの分類です:\n\nヘッダー\n・複数の列のデータを含む列。\n・特定の資産のグループを説明するテキストを含むセル。\n・空のセル。\n\n合計\n・前の行の合計を反映する。\n・数字セル、テキストセル、空のセルを含むことがあります。\n\n以下は、具体的な質問への回答です。\n・データ: 10,000,082、'オーストリア'、'25,220,521'、'13,879,925'\n・ヘッダー:'Commonwealth Bank'、'オーストリアの銀行'、''オーストラリアの銀行'\n・合計: ''、$1.607.819.000、'$3,774.456,867'<|eot_id|>", "source": "chatbot-arena-ja-calm2-7b-chat-experimental"}
{"prompt": "\"<|begin_of_text|><|start_header_id|>system<|end_header_id|>\n\nあなたは誠実で優秀な日本人のアシスタントです。<|eot_id|><|start_header_id|>user<|end_header_id|>\n\nこんにちは、ランダムフォレストがバギングモデルや伝統的な樹木モデルの両方に優れている理由について、ブレイマンの主張をまとめてください。<|eot_id|><|start_header_id|>assistant<|end_header_id|>\n", "chosen_response": "ランダムフォレストは、決定木に基づいた機械学習手法であり、データから特徴を抽出し、その特徴を組み合わせて予測モデルを学習させます。この特徴抽出の過程が、ランダム性とバギング(混ぜ合わせる)という2つのステップで行われるため、「ランダムフォレスト」という名前がつけられています。\n\nバギングモデルは、ランダムフォレストと同様に決定木を用いて学習させますが、ランダムフォレストよりもデータの複雑性が高くても適用できるという利点があります。具体的には、ランダムフォレストは決定木の数が限られていますが、バギングでは、ランダムに選択された決定木が、より複雑な決定木に統合されます。これにより、バギングモデルはより複雑なデータに対しても適用できるようになります。\n\n一方、伝統的な樹木モデルは、データに明確なパターンがある場合に適用されることが多く、データ内の特定の要素の組み合わせや頻度に基づいて予測を行います。伝統的な樹木モデルには、ナイーブベイズやブートストラップ法など、いくつかの異なる手法が存在します。\n\nランダムフォレストと伝統的な樹木モデルの最大の違いは、学習プロセスにあります。ランダムフォレストはデータ内の特徴の組み合わせをランダムに選択するため、予測モデルが必ずしも正確なわけではないという弱点がありますが、バギングによりデータの複雑性を高めることができます。一方、伝統的な樹形図は、データ内の要素の組み合わせのパターンを利用して予測を行うため、より正確な予測が可能です。\n\nしたがって、ランダムフォレストとバギングモデルはそれぞれ異なる学習手法であり、適用可能なデータの種類や予測の目的に応じて、適切なモデルを選択することが重要です。<|eot_id|>", "rejected_response": "ランダムフォレストは、バギングモデルと伝統的な樹木モデルの両方において優れた性能を発揮します。しかし、それぞれの違いを理解することは重要です。\n\n1. モデルの複雑さ: ランダム Forestは単純なモデルであり、決定木をランダムに選択して学習させることからその名前が付いています。これは、トレーニングセット内の特定の特徴が、ランダムフォレストのパターン認識にどのように影響を与えるかを理解しやすいことを意味します。一方、バギングと樹木モデルは、複雑なモデルであり、それぞれの学習データセットに基づいて決定木を生成します。したがって、ランダムフォレストは複雑なデータセットに対してはあまり適していません。\n\n2. 分類精度の向上: ランダムForestは、バディングモデルと伝統的な樹形モデルの両方を使用して学習することができます。つまり、各学習セットに対して、ランダムフォレストとバギングモデルの2つのモデルで学習し、その後、各データセットに基づいて最高の精度を持つモデルを選択することができます。このアプローチは、データの多様性と複雑さに対して高い柔軟性を提供し、より信頼性の高い予測が可能になる可能性があります。\n\n3. 学習時間の短縮: バギングと樹木モデルは非常に時間がかかるため、大規模なデータセットを学習するには時間と資源が必要です。一方、ランダムフォレストは非常に高速で、計算コストが低いことが特徴です。\n\n4. 高い予測精度: ランダム forestは、トレーニングデータセット内の全ての特徴を考慮するため、バギングや樹木モデルよりも高い精度を発揮することがあります。これは、ランダムフォレストの決定木が、データ内のあらゆる可能性を考慮するためです。\n\n5<|eot_id|>", "source": "chatbot-arena-ja-calm2-7b-chat-experimental"}
DPO の実行
DPO は NeMo-Aligner の /opt/NeMo-Aligner/examples/nlp/gpt/train_gpt_dpo.py
で実行できます。/opt/NeMo-Aligner/examples/nlp/gpt/conf/gpt_dpo.yaml に DPO の実行に必要な config ファイルがあり、コマンドライン引数としてスクリプトの実行に必要なデータのパス、ベースとなる LLM (nemo フォーマット) のパスなどの設定を渡します (NeMo Framework は config 設定に Hydra を使用しています)。ここで指定されていない設定については、configファイルの設定が適用されます。実行コマンドにある ++exp_manager.checkpoint_callback_params.save_last=False
は Hydra で config の追加または上書きをする際の記法になります。
このチュートリアルでは、全てのパラメーターを調整する DPO を実行しますが、LoRA ベースの DPO を実行することも可能です。さらには、DPO だけなく、その派生の Identity preference optimization (IPO) や Reward-aware preference optimization (RPO) もサポートされています。詳細はこちらを確認してください。
export HYDRA_FULL_ERROR=1
export WANDB=False
export PJ_NAME="dpo"
export EXP_DIR="/workspace/results/"${PJ_NAME}
export EXP_NAME="Llama-3-Swallow-8B-Instruct-v0.1"
export MODEL="/workspace/models/Llama-3-Swallow-8B-Instruct-v0.1/Llama-3-Swallow-8B-Instruct-v0.1.nemo"
export TP_SIZE=2
export PP_SIZE=1
export TRAIN_DS="/workspace/data/dpo/train.jsonl"
export VALID_DS="/workspace/data/dpo/valid.jsonl"
torchrun --nproc_per_node=8 /opt/NeMo-Aligner/examples/nlp/gpt/train_gpt_dpo.py \
exp_manager.explicit_log_dir=${EXP_DIR} \
exp_manager.name=${EXP_NAME} \
exp_manager.create_wandb_logger=${WANDB} \
exp_manager.wandb_logger_kwargs.project=${PJ_NAME} \
exp_manager.wandb_logger_kwargs.name=${EXP_NAME} \
exp_manager.checkpoint_callback_params.save_nemo_on_train_end=True \
exp_manager.checkpoint_callback_params.save_top_k=1 \
++exp_manager.checkpoint_callback_params.save_best_model=True \
++exp_manager.checkpoint_callback_params.save_last=False \
trainer.precision=bf16 \
trainer.devices=8 \
trainer.num_nodes=1 \
trainer.dpo.max_epochs=1 \
trainer.dpo.max_steps=-1 \
trainer.dpo.val_check_interval=0.5 \
trainer.dpo.save_interval=82 \
trainer.dpo.gradient_clip_val=1.0 \
pretrained_checkpoint.restore_from_path=${MODEL} \
model.megatron_amp_O2=True \
+model.tensor_model_parallel_size=${TP_SIZE} \
+model.pipeline_model_parallel_size=${PP_SIZE} \
model.peft.peft_scheme="none" \
model.dpo.ref_policy_kl_penalty=0.2 \
+model.encoder_seq_length=2048 \
+model.max_position_embeddings=2048 \
model.optim.lr=9e-7 \
model.optim.sched.warmup_steps=10 \
model.optim.sched.constant_steps=0 \
model.optim.sched.min_lr=5e-7 \
"model.data.data_prefix={train: [${TRAIN_DS}], validation: [${VALID_DS}], test: [${VALID_DS}]}" \
+model.data.train_ds.add_eos=False \
+model.data.validation_ds.add_eos=False \
model.global_batch_size=256 \
model.micro_batch_size=1
NeMo Framework は、実験管理のために Weights and Biases をサポートしており、上記のスクリプトを、export WANDB=True
と変更することで wandb 上で実験管理することができます。
上記の設定では、学習は 25 分ほどで完了しました。
学習が終わると results/dpo/
という名前のディレクトリが作成され、中に学習時の config や log などが出力されます。また、同じディレクトリの checkpoints
内にある Llama-3-Swallow-8B-Instruct-v0.1.nemo
が DPO で作成されたモデルになります。
学習時に nemo フォーマットへ変換したモデルは、同一フォーマットのまま、推論やさらなる後続ステップで活用することもできますし、Hugging Face フォーマットへ再度、変換することも可能です。
NeMo Framework コンテナー上で推論を実行するチュートリアルはこちらにあります。
nemo フォーマットから、Hugging Face フォーマットへ変換するスクリプトはこちらにあります。
参考: Nejumi リーダーボード 3 での評価
Nejumiリーダーボード 3 は、LLM の日本語能力をさまざまな評価データセットを用いて多面的に評価できるベンチマークです。ベンチマーク用のスクリプトを実行することで、自社のモデルをさまざまなモデルと比較することが可能です。
ご自身の環境で実行する際は、wandb の GitHubリポジトリを参照してください。以下は、Nejumi リーダーボード 3 にも含まれる MT-bench からの一例ですが、まずは DPO を実行する前のモデルの応答を示します。
# Question
数学の先生になってみてください。数学の方程式や概念を提供しますので、それらを易しく説明してください。具体的には、問題の解決法を順を追って説明したり、日常生活の例を用いて各種技術を説明したり、さらなる学習のためのオンラインリソースを提案したりすることが含まれます。私の最初のリクエストは「確率の仕組みを理解したいんですが、わかりやすく教えてください」。
# Answer
了解です!「確率」とは、ある事象が発生する可能性の度合いを数字で表す概念です。例えば、コインを1回投げたときに、 heads (表) がでる確率は 1/2、 tails (裏) がでる確率も 1/2 です。
次に DPO を実行した後のモデルの応答を示します。
# Question
数学の先生になってみてください。数学の方程式や概念を提供しますので、それらを易しく説明してください。具体的には、問題の解決法を順を追って説明したり、日常生活の例を用いて各種技術を説明したり、さらなる学習のためのオンラインリソースを提案したりすることが含まれます。私の最初のリクエストは「確率の仕組みを理解したいんですが、わかりやすく教えてください」。
# Answer
はい,数学の先生とし,「確率の仕組み」をわかりやすく説明します。
確率は,「起こりうる事象のうち,どれだけの割合でその事象が発生するか」という数学的な概念です。例えば,コインを1回投げ,表が出る確率は1/2,つまり50%です。
確率の仕組みを理解するために,まず「事象」と「確率」という2つの概念を理解する必要があります。
1. 事象(Event):起こりうる事象のことを指します。例えば,コインを1回投げ,表が出る,裏が出る,それぞれが事象です。
2. 確率(Probability):事象が発生する確率を表します。確率は0以上1以下の数値で,発生する確率が高い事象は1に近い,発生する確率が低い事象は0に近い数値を取ります。
確率には,「単純確率」と「複雑確率」という2種類があります。
1. 単純確率(Simple Probability):1回の試行で1つの事象を確率測定する方法です。例えば,コインを1回投げ,表が出る確率は1/2です。
2. 複雑確率(Compound Probability):複数の事象を組み合わせて確率測定する方法です。例えば,コインを2回投げ,2回とも表が出る確率は1/4です。
確率の仕組みを理解するために,以下のオンラインリソースも参考にしてください。
* [Probability for Beginners](https://www.mathsisfun.com/data/probability.html)
* [Understanding Probability](https://www.khanacademy.org/math/probability)
* [Probability and Statistics with R](https://www.coursera.org/specializations/probability-statistics-r)
さらに,日常生活でも確率を意識することで,より確率を理解することができます。例えば,天気予報,車の運転,スポーツのゲームなど,確率を意識すると,予測や判断がしやすくなります。
DPO 前に比べると DPO 後のモデルの応答は指示文に対して、より親切に応答してくれているように感じられます。
まとめ
本記事では、NeMo Framework を使用した DPO の実行方法を紹介しました。NeMo Framework を使用して LLM の開発が加速すると嬉しいです。