数百万ドルと数ヶ月のコンピューティング時間を要するので、大きな言語モデルを最初からトレーニングする必要は決してありません。Fine-tuningは、リソースのほんの一部を使用して、数時間あるいは数ヶ月ではなく、何日かで、あなたのニーズに事前にトレーニングされた言語モデルを適応させます。 このチュートリアルはあなたを あなたは、4つのコアの細かい調節テクニックを学び、Pythonで完全なトレーニングパイプラインをコードし、高価な実験から生産準備モデルを分離するテクニックを学びます。 from theory to practice LLM Fine-Tuningとは? Fine-tuning は、既存の言語モデルをデータにトレーニングして、その機能を強化します。 事前訓練されたモデルは強力な一般主義者ですが、それらを暴露します。 それらをあなたの使用ケースの専門家に変えることができます。 performance on specific tasks focused examples ゼロからモデルを構築する代わりに(膨大なコンピューティングとデータを必要とする)あなたは、医療診断、顧客サポートの自動化、感情分析、または他の特定のタスクであろうと、すでに可能なモデルに、あなたにとって重要なことのクラッシュコースを提供しています。 LLM Fine-Tuningはどのように機能しますか? Fine-tuning は、あなたの特定のデータセットを使用して、事前に訓練された言語モデルのトレーニングプロセスを継続します。 適応し、損失を最小限にすること。 updates internal weights このアプローチは、あなたの で、 そして、 いくつかのプロジェクトでは、すべてのモデルパラメータを更新するための完全なフィンタリングが必要ですが、他のプロジェクトでは、パラメータ効率の高い方法などでよりよく動作します。 小さな部分を変えるだけです。 goals available data computational resources ローラ LLM Fine-Tuning 方法 Fine-Tuning 監視 SFT はモデルに正しい質問と回答のパターンのパターンを学び、モデルの重量を正確にそれらの答えと一致させるように調整します。 これは、モデルが常にJSON形式で応答するようにする、顧客サービスのスクリプトに従って、またはあなたの会社のトーンで電子メールを書くなど、一貫した出力を望むときに使用します。 (Prompt, Ideal Response) 未監視のFine-Tuning モデルに大量の原文(質問やラベル化されたデータは必要ありません)を供給して、特定のドメインの辞書とパターンを学ぶことができます。これは技術的にContinued Pre-Training(CPT)と呼ばれるプレトレーニングプロセスですが、これは通常、初期のプレトレーニング段階の後に行われます。 優先順位の最適化 DPOは、同じ質問に対する良い対悪い答えの例を示し、それを良いものに好むように調整することによって、モデルにより良い答えを好むことを教えます。 基本的なトレーニング後にDPOを使用して、モデルが物事を作り上げるのを止めたり、あまりにも言葉がつきすぎたり、危険な答えを与えるような不快な行動を修正します。 (Prompt, Good Response, Bad Response) Fine-Tuning 補強 RLHFでは、最初に、人間がランクインした複数の応答を含むプロンプトで報酬モデルをトレーニングし、人々が好む応答を予測するように教えます。その後、強化学習を使用して、報酬モデルが判断する応答を生成するモデルを最適化し、調節します。これは、モデルが時間とともに学ぶのに役立ち、より高い得点を出力するようにします。このプロセスには、この形式のデータセットが必要です: それは、医学診断、法的研究、およびその他の複雑なドメイン特有の推論などの完璧な例を作成するよりも品質を判断するのが簡単なタスクに最適です。 (Prompt, [Response A, Response B, ...], [Rankings]) Step-by-Step Fine-Tuning LLMs チュートリアル We will walk you through every step of fine-tuning a small pre-trained model to solve word-based math problems, something it struggles with out of the box. We will use the Qwen 2.5 base model with 0.5B parameters that already has natural language processing capabilities. 私たちは、すでに自然言語処理能力を持っている 0.5Bパラメータを持つQwen 2.5ベースモデルを使用します。 【アプローチ】 : モデルの専門用語を教え、特定のタスクでのモデルのパフォーマンスを向上させ、またはあなたのドメインに適応します。 works for virtually any use case of fine-tuning LLMs 前提条件 このチュートリアルを通じて使用するいくつかのPythonパッケージをインストールします。新しいプロジェクト フォルダで、Python 仮想環境を作成してアクティベートし、それからこれらのライブラリをインストールします。 お気に入りのパッケージマネージャー: pip pip install requests datasets transformers 'transformers[torch]' Get & Load the Dataset(データセットを取得&ロード) 精密調整プロセスは、データセットを選択することから始まりますが、これは間違いなく最も重要な決定です。 . reflect the task you want your model to perform 感情分析などのシンプルなタスクには、基本的な入力出力カップルが必要です。指示に従うか質問に答えるような複雑なタスクには、文脈、例、およびさまざまな形式を含むより豊富なデータセットが必要です。 最も簡単な出発点は、 さまざまなドメインやタスクのための何千ものオープンソースのデータセットをホストするデータセットライブラリ。 または 公開データです。 Hugging Face Purchase specialized datasets build your own by スクラップ スクラップ たとえば、Amazon製品レビューのための感情分析モデルを構築したい場合は、ウェブスクラップツールを使用して実際のレビューからデータを収集したいかもしれません。 : Web Scraper API import json import requests # Web Scraper API parameters. payload = { "source": "amazon_product", # Query is the ASIN of a product. "query": "B0DZDBWM5B", "parse": True, } # Send a request to the API and get the response. response = requests.post( "https://realtime.oxylabs.io/v1/queries", # Visit https://dashboard.oxylabs.io to claim FREE API tokens. auth=("USERNAME", "PASSWORD"), json=payload, ) print(response.text) # Extract the reviews from the response. reviews = response.json()["results"][0]["content"]["reviews"] print(f"Found {len(reviews)} reviews") # Save the reviews to a JSON file. with open("reviews.json", "w") as f: json.dump(reviews, f, indent=2) For this tutorial, let’s keep it simple without building a custom data collection pipeline. Since we're teaching the base model to solve word-based math problems, we can use the openai/gsm8k dataset. It’s a collection of grade-school math problems with step-by-step solutions. Load it in your Python file: from datasets import load_dataset dataset = load_dataset("openai/gsm8k", "main") print(dataset["train"][0]) 2.Tokenize the data for processing データの処理 モデルはテキストを直接理解しないが、それらは . Tokenization はあなたのテキストをモデルが処理できるトークン(数値表示)に変換します. Each model has its own tokenizer trained alongside it, so use the one that matches your base model: numbers from transformers import AutoTokenizer tokenizer = AutoTokenizer.from_pretrained("Qwen/Qwen2.5-0.5B") tokenizer.pad_token = tokenizer.eos_token How we tokenize our data shapes what the model learns. For math problems, we want to fine-tune the model to learn how to 質問ではなく、それらを生成します。ここにトリックがあります:質問と答えを別々にトークニズムし、それから仮面テクニックを使用します。 答え 質問トークンを設定する 損失を計算する際にそれらを無視するようにトレーニングプロセスに言います. モデルは答えからのみ学び、トレーニングをより集中し、効率的にします。 -100 def tokenize_function(examples): input_ids_list = [] labels_list = [] for question, answer in zip(examples["question"], examples["answer"]): # Tokenize question and answer separately question_tokens = tokenizer(question, add_special_tokens=False)["input_ids"] answer_tokens = tokenizer(answer, add_special_tokens=False)["input_ids"] + [tokenizer.eos_token_id] # Combine question + answer for input input_ids = question_tokens + answer_tokens # Mask question tokens with -100 so loss is only computed on the answer labels = [-100] * len(question_tokens) + answer_tokens input_ids_list.append(input_ids) labels_list.append(labels) return { "input_ids": input_ids_list, "labels": labels_list, } このトークン化機能をトレーニングとテストの両方のデータセットに適用します. We filter out examples longer than 512 tokens to keep memory usage manageable and ensure the model processes complete information without truncation. Shuffling the training data helps the model learn more effectively: トレーニングデータをシャフリングすることで、モデルがより効果的に学ぶことができます: train_dataset = dataset["train"].map( tokenize_function, batched=True, remove_columns=dataset["train"].column_names, ).filter(lambda x: len(x["input_ids"]) <= 512) .shuffle(seed=42) eval_dataset = dataset["test"].map( tokenize_function, batched=True, remove_columns=dataset["test"].column_names, ).filter(lambda x: len(x["input_ids"]) <= 512) print(f"Samples: {len(dataset['train'])} → {len(train_dataset)} (after filtering)") print(f"Samples: {len(dataset['test'])} → {len(eval_dataset)} (after filtering)") Optional: 完全なトレーニングを実施する前に、パイプライン全体を迅速にテストしたいですか? サブセットのデータセットでモデルをトレーニングできます。 したがって、完全な 8.5K データセットを使用する代わりに、全体で 3K に最小化してプロセスをより速くすることができます: train_dataset = train_dataset.select(range(2000)) eval_dataset = eval_dataset.select(range(1000)) 小さなデータセットは、トレーニングデータを覚えるのではなく、一般的なパターンを学習するモデルで、過剰装備のリスクを増加させます。 Keep in mind: 3.ベースモデルを初期化する 次に、事前に訓練されたベースモデルをロードして、数学の問題解決能力を向上させることによってそれを調節します。 from transformers import AutoModelForCausalLM model = AutoModelForCausalLM.from_pretrained("Qwen/Qwen2.5-0.5B") model.config.pad_token_id = tokenizer.pad_token_id 4. Fine-Tune Using the Trainer Method (トレーナー・メソッド) TrainingArgumentsは、あなたのモデルがどのように学ぶかを制御します(最終結果の品質を決定するレシピとして考えてください)。これらの設定とハイパーパラメーターは、あなたの細かい調節を作ったり、壊したりすることができますので、異なる値で実験して、あなたの使用ケースに何が効いているかを見つけることができます。 Key parameters explained: ● より多くの時代はより多くの学習機会に等しいが、あまりにも多くの時代は過剰な装備を引き起こす。 Epochs: ● メモリの使用とトレーニングの速度に影響を与えます これらをハードウェアに基づいて調整してください。 Batch size: ● モデルがどれだけ速く調整するかを制御します。高すぎて、最適なソリューションを逃す可能性があります、低すぎて、トレーニングは永遠にかかります。 Learning rate: ● モデルが単一のパターンに過度に傾いていることを妨げることにより、過剰装備を防止するのに役立ちます. If weight decay is too large, it can lead to underfitting by preventing the model from learning the necessary patterns. Weight decay: 下記の最適な構成は、CPUトレーニングに特化しています(GPUをお持ちの場合は use_cpu=True を削除します): from transformers import TrainingArguments, Trainer, DataCollatorForSeq2Seq training_args = TrainingArguments( output_dir="./qwen-math", # Custom output directory for the fine-tuned model use_cpu=True, # Set to False or remove to use GPU if available # Training duration num_train_epochs=2, # 3 may improve reasoning at the expense of overfitting # Batch size and memory management per_device_train_batch_size=5, # Adjust depending on your PC capacity per_device_eval_batch_size=5, # Adjust depending on your PC capacity gradient_accumulation_steps=4, # Decreases memory usage, adjust if needed # Learning rate and regularization learning_rate=2e-5, # Affects learning speed and overfitting weight_decay=0.01, # Prevents overfitting by penalizing large weights max_grad_norm=1.0, # Prevents exploding gradients warmup_ratio=0.1, # Gradually increases learning rate to stabilize training lr_scheduler_type="cosine", # Smoother decay than linear # Evaluation and checkpointing eval_strategy="steps", eval_steps=100, save_strategy="steps", save_steps=100, save_total_limit=3, # Keep only the best 3 checkpoints load_best_model_at_end=True, # Load the best checkpoint at the end of training metric_for_best_model="eval_loss", greater_is_better=False, # Logging logging_steps=25, logging_first_step=True, ) # Data collator handles padding and batching data_collator = DataCollatorForSeq2Seq(tokenizer=tokenizer, model=model) # Initialize trainer trainer = Trainer( model=model, args=training_args, train_dataset=train_dataset, eval_dataset=eval_dataset, data_collator=data_collator, ) # Fine-tune the base model print("Fine-tuning started...") trainer.train() Once training completes, save your fine-tuned model: trainer.save_model("./qwen-math/final") tokenizer.save_pretrained("./qwen-math/final") 5.モデル評価 細かく調節した後、モデルのパフォーマンスを2つの共通のメトリクスを用いて測定します。 ● モデルの予測がターゲット出力からどの程度離れているかを測定し、低い値がより良いパフォーマンスを示す。 Loss: ● より直感的なスケールで同じ情報を表示し、低い値はモデルがその予測により自信を持っていることを意味します。 Perplexity (the exponential of loss): 生産環境の場合、例えばメトリックを追加することを検討します。 または 生成された応答が参照応答とどのように接近しているかを測定する。 BLEU ROUGE import math eval_results = trainer.evaluate() print(f"Final Evaluation Loss: {eval_results['eval_loss']:.4f}") print(f"Perplexity: {math.exp(eval_results['eval_loss']):.2f}") また、F1のような他のメトリクスを含むこともできますが、このメトリクスは正確な状態を維持しながら重要なものを把握するのにどれほど良いモデルかを測定します。 トランスフォーマーライブラリの使用の基本を学ぶための良い出発点です。 Hugging Face レッスン Fine-Tuning コードの例 これらの5つのステップを経て、次のコードを単一のPythonファイルに組み合わせる必要があります。 import math from datasets import load_dataset from transformers import ( AutoTokenizer, AutoModelForCausalLM, TrainingArguments, Trainer, DataCollatorForSeq2Seq, ) dataset = load_dataset("openai/gsm8k", "main") tokenizer = AutoTokenizer.from_pretrained("Qwen/Qwen2.5-0.5B") tokenizer.pad_token = tokenizer.eos_token # Tokenization function adjusted for the specific dataset format def tokenize_function(examples): input_ids_list = [] labels_list = [] for question, answer in zip(examples["question"], examples["answer"]): question_tokens = tokenizer(question, add_special_tokens=False)["input_ids"] answer_tokens = tokenizer(answer, add_special_tokens=False)["input_ids"] + [tokenizer.eos_token_id] input_ids = question_tokens + answer_tokens labels = [-100] * len(question_tokens) + answer_tokens input_ids_list.append(input_ids) labels_list.append(labels) return { "input_ids": input_ids_list, "labels": labels_list, } # Tokenize the data train_dataset = dataset["train"].map( tokenize_function, batched=True, remove_columns=dataset["train"].column_names, ).filter(lambda x: len(x["input_ids"]) <= 512) .shuffle(seed=42) eval_dataset = dataset["test"].map( tokenize_function, batched=True, remove_columns=dataset["test"].column_names, ).filter(lambda x: len(x["input_ids"]) <= 512) print(f"Samples: {len(dataset['train'])} → {len(train_dataset)} (after filtering)") print(f"Samples: {len(dataset['test'])} → {len(eval_dataset)} (after filtering)") # Optional: Use a smaller subset for faster testing # train_dataset = train_dataset.select(range(2000)) # eval_dataset = eval_dataset.select(range(1000)) model = AutoModelForCausalLM.from_pretrained("Qwen/Qwen2.5-0.5B") model.config.pad_token_id = tokenizer.pad_token_id # Configuration settings and hyperparameters for fine-tuning training_args = TrainingArguments( output_dir="./qwen-math", use_cpu=True, # Training duration num_train_epochs=2, # Batch size and memory management per_device_train_batch_size=5, per_device_eval_batch_size=5, gradient_accumulation_steps=4, # Learning rate and regularization learning_rate=2e-5, weight_decay=0.01, max_grad_norm=1.0, warmup_ratio=0.1, lr_scheduler_type="cosine", # Evaluation and checkpointing eval_strategy="steps", eval_steps=100, save_strategy="steps", save_steps=100, save_total_limit=3, load_best_model_at_end=True, metric_for_best_model="eval_loss", greater_is_better=False, # Logging logging_steps=25, logging_first_step=True, ) data_collator = DataCollatorForSeq2Seq(tokenizer=tokenizer, model=model) trainer = Trainer( model=model, args=training_args, train_dataset=train_dataset, eval_dataset=eval_dataset, data_collator=data_collator, ) # Fine-tune the base model print("Fine-tuning started...") trainer.train() # Save the final model trainer.save_model("./qwen-math/final") tokenizer.save_pretrained("./qwen-math/final") # Evaluate after fine-tuning eval_results = trainer.evaluate() print(f"Final Evaluation Loss: {eval_results['eval_loss']:.4f}") print(f"Perplexity: {math.exp(eval_results['eval_loss']):.2f}") 実行する前に、トレーナーの構成とハイパーパラメータを実際にマシンが処理できるものに基づいて調整するために、少し時間を取ってください。 あなたに現実世界の参考を与えるために、ここでは、M4チップと16GBのRAMを持つMacBook Airで私たちのためにスムーズに機能したものがあります。 ● : 7 Batch size for training ● 7 Batch size for eval: ● 5 Gradient accumulation: あなたのモデルが列車を運転するにつれて、あなたのモデルに目を留めてください。 . トレーニング損失が減少する間に増加する場合、モデルは過剰に適合します。その場合、エポックを調整し、学習率を下げ、体重崩壊を変更し、その他のハイパーパラメータを変更します。 2位 最後の混乱は、 . evaluation loss 0.496 0.469 1.60 6. Fine-Tuned モデルをテスト 真実の瞬間のために、私たちのフィンタリングは実際に成功しましたか? あなたはこのPythonコードでそれを促すことによって、フィンタリングモデルを手動でテストすることができます: from transformers import pipeline generator = pipeline( "text-generation", # Use `Qwen/Qwen2.5-0.5B` for testing the base model model="./qwen-math/final" ) output = generator( "James has 5 apples. He buys 3 times as many. Then gives half away. How many does he have?", return_full_text=False ) print(output[0]["generated_text"]) このサイド対サイド比較では、前と後モデルが同じ質問にどのように答えるかを見ることができます(正しい答えは10): サンプル化が有効になった場合、両モデルは偶然にランダム性のために正しいか間違っていることがあります。 機能は、彼らの本当の自信を明らかにします:モデルは常にその最高確率の答えを選択します。 自信の出し方 (※) )の間、 自信の出し方 (※) )これが仕事におけるフィンタウンニングです。 do_sample=False in the generator() base model -2 間違え fine-tuned model 10 正解 Fine-Tuning ベスト・プラクティス モデル選択 ● ドメイン特有のモデルと適切なコンテキストウィンドウは、モデルの既存の知識と戦うことからあなたを守ります。 Choose the right base model: ● エンコーダーのみのモデル(BERT など)は、分類タスク、テキスト生成時にデコーダーのみのモデル(GPT など)と、翻訳や概要などのトランスフォーメーションタスクでエンコーダーのみのデコーダーモデル(T5 など)で優れています。 Understand the model architecture: ● あなたのベースモデルが特定のプロンプトテンプレートでトレーニングされた場合は、同じフォーマットをフィンタウンニングで使用してください。 Match your model's input format: データ準備 ● クリーンで正確な例は、毎回巨大で騒々しいデータセットを打ち破ります。 Prioritize data quality over quantity: ● トレーニング中にモデルが評価データを見るのを決して許さないでください. This lets you catch overfitting before it ruins your model. Split training and evaluation samples: ● 迷惑のような自動メトリクスは、モデルが実際に指示に従うかどうか、あるいは単に単語を統計的に予測するかどうかを教えてくれません。 Establish a "golden set" for evaluation: トレーニング戦略 ● あなたは小さな調整を行い、それをゼロから教えていないので、攻撃的なレートは、プレトレーニング中に学んだものを消去するかもしれません。 Start with a lower learning rate: ● パラメータの1%のみをトレーニングして、90%以上のパフォーマンスを達成し、メモリと時間を減らします。 Use parameter-efficient fine-tuning (LoRA/PEFT): ● (すべてのレイヤーをターゲットに) etc.) yields models that reason significantly better, not only mimic style. それは、単にスタイルを模するだけでなく、より良い理由を示すモデルを生成します。 Target all linear layers in LoRA: q_proj, k_proj, v_proj, o_proj, ● 埋め込みのランダムノイズは規則化として機能し、記憶を妨げ、会話の品質を35%以上向上させることができます。 Use NEFTune ( ): ノイズ・インベーディング Fine-Tuning ノイズ・インベーディング Fine-Tuning ● SFTは話す方法を教え、DPOは好みのカップルから学ぶことで良いことを教えます。 After SFT, Run DPO: LLM Fine-Tuningの制限は何ですか? ● Fine-tuning は既存のニューラルパターンを上書きし、プレトレーニング中に学んだ貴重な一般的な知識を削除することができます。Multi-task learning は、一般的な例と共に専門的なタスクをトレーニングすることで、より幅広い能力を維持するのに役立ちます。 Catastrophic forgetting: ● モデルは、学習パターンの代わりにあなたのトレーニング例を記憶し、わずかに異なる入力で失敗する可能性があります。 Overfitting on small datasets: ● 数十億のパラメータを精密に調整するには、高価なGPU、重要なメモリ、数時間から数日または数週間のトレーニング時間を必要とします。 High computational cost: ● 事前に訓練されたモデルはすでにトレーニングデータから偏見を持ち、データセットが慎重に調節されていない場合、細かい調節がこれらの偏見を強化することができます。 Bias amplification: ● 新しい外部の知識は、モデル全体のトレーニングまたはRetrieval-Augmented Generation(RAG)の実装を必要とする場合がありますが、繰り返しの細かい調節はしばしばパフォーマンスを悪化させます。 Manual knowledge update: 結論 Fine-tuning は機能しますが、データがクリーンで、ハイパーパラメーターがダイレクトされている場合にのみ機能します. Combine it with prompt engineering for the best results, where fine-tuning handles the task specialization while prompt engineering guides the model's behavior at inference time. 最適な結果を得るために、スムートエンジニアリングとスムートエンジニアリングがモデルの行動を導きます。 Hugging Face からドメイン特有のフィンタウンニングのためのあなたの使用ケースに合ったモデルをキャッチし、あなたのタスクのための質の高いデータセットをスクラップまたは構築し、小さなサブセットで最初のフィンタウンニングセッションを実行します。あなたが有望な結果を見たら、スケールアップして LoRA、DPO、または NEFTune で実験してより良いパフォーマンスを圧縮します。