忍者ブログ
統計、機械学習、AIを学んでいきたいと思います。 お役に立てば幸いです。

【DS検定対策】指示に従うAIを作る!「インストラクションチューニング」の仕組み

事前学習(Pre-training)を終えたばかりのLLM(大規模言語モデル)は、単に「文章の続きを予測・補完する」ことしかできません。これに対し、「人間の指示に的確に従って回答する能力」を与えるための重要な学習プロセスが「インストラクションチューニング(Instruction Tuning)」です!

1. 【 問題 】

LLM(大規模言語モデル)の学習プロセスにおいて、人間が準備した「指示(Instruction)」と「理想的な応答(Output)」のペアデータを学習させ、ユーザーの意図や命令に従って適切に応答できるように微調整する手法を何と呼ぶでしょうか?

① インストラクションチューニング(Instruction Tuning)
② 事前学習(Pre-training)
③ 事後学習(Post-training)なしのゼロショット学習
④ 継続的事前学習(Continued Pre-training)


2. 【 解答 】

正解: ① インストラクションチューニング(Instruction Tuning)

3. 整理:ベースモデルと指示応答モデルの違い

事前学習のみを行ったモデル(ベースモデル)と、インストラクションチューニングを施したモデルでは、同じ入力に対する挙動が全く異なります。

モデルの段階学習データの形式「日本の首都は?」と入力した時の反応
ベースモデル
(事前学習のみ)
Web上の大量の生テキスト
(単語の穴埋め・続き予測)
「日本の首都は? アメリカの首都は? フランスの首都は?…」と、問題文の続き(クイズの列挙など)を予測・出力してしまう。
指示応答モデル
(Instruction Tuning後)
「指示」と「回答」のペア
(教師ありデータセット)
「日本の首都は東京です。」と、指示を理解して正確な回答を返す。

4. LLM開発の3ステップ(全体像の中での位置づけ)

生成AI(LLM)が完成するまでには、一般的に以下の3つの大きなステップを踏みます。

Step 1:事前学習(Pre-training)
・ネット上の数兆トークンの文章を読み込み、言語の文法や世の中の知識を学ぶ(基礎体力をつける)。

Step 2:インストラクションチューニング(SFT) ★今回のお題!
・「指示と回答のペア」を数万〜数十万件学習させ、「命令に従って応答するスタイル」を身につける。

Step 3:RLHF / DPO(人間のフィードバックによる学習)
・人間の好みや安全性(有害な出力をしない等)に合わせて回答の質や振る舞いを最終微調整する。

5. DS検定形式:実戦4択クイズ

问:大規模言語モデル(LLM)における「インストラクションチューニング(Instruction Tuning)」に関する記述として、最も適切なものはどれか。

① インターネット上のラベルのない大量のテキストデータを使い、次の単語を予測する自己教師あり学習の手法である。
② 「指示文」と「それに対する適切な応答文」のペアデータを用いてモデルを微調整し、様々なタスクや命令に意図通り従う能力を向上させる手法である。
③ モデルの出力結果に対して人間が評価(報酬)を与え、強化学習を用いてモデルの安全性を向上させる手法である。
④ 外部のデータベースから関連文書を検索・取得し、それをプロンプトに含めて回答を生成させる手法である。

【 正解: ② 】

解説: インストラクションチューニングの定義を問う標準問題です。
②が正解です。指示と回答のペアデータを用いた教師ありファインチューニング(SFT)です。
①は「事前学習(Pre-training)」の説明です。
③は「RLHF(Reinforcement Learning from Human Feedback)」の説明です。
④は「RAG(検索拡張生成)」の説明です。


6. まとめ

DS検定や資格試験で「指示と応答のペア」「SFT(教師あり微調整)」「指示に従う能力の獲得」「ベースモデルからの対話モデル化」といったキーワードが出たら、正解は「インストラクションチューニング」です! 単なる文章補完(事前学習)から対話型AI(ChatGPT等)へ橋渡しをする超重要技術として、全体の学習ステップと一緒に押さえておきましょう!

PR

【DS検定対策】自然言語処理の基本!テキストをn個ずつ区切る「n-gram」の仕組み

テキストデータをAIやプログラムで処理する際、文章をそのまま扱うことはできません。文章を「連続する n 個の文字や単語の単位」に細かく区切って分析する手法が「n-gram(エヌグラム)」です。その仕組みと種類を整理しましょう!

1. 【 問題 】

自然言語処理(NLP)において、与えられた文字列や文章に対して、隣り合う連続した n 個の文字(または単語)のまとまりに分割して抽出する手法を何と呼ぶでしょうか?

① n-gram(エヌグラム)
② TF-IDF(ティーエフ・アイディーエフ)
③ Word2Vec(ワード・ツー・ベック)
④ 形態素解析(Morphological Analysis)


2. 【 解答 】

正解: ① n-gram(エヌグラム)

3. 整理:nの値による呼び方と具体的例

「データ分析」というテキストを文字単位(文字n-gram)で分割する場合の具体例を見てみましょう。

呼び方nの値「データ分析」を文字単位で区切った結果
Unigram
(ユニグラム)
n = 1 「デ」「ー」「タ」「分」「析」
(1文字ずつバラバラに分割)
Bigram
(バイグラム)
n = 2 「デー」「ータ」「タ分」「分析」
(連続する2文字ずつスライドして抽出)
Trigram
(トライグラム)
n = 3 「データ」「ータ分」「タ分析」
(連続する3文字ずつスライドして抽出)

4. 単語n-gramと文字n-gramの違い

n-gramには「文字単位」だけでなく「単語単位」で区切るパターンもあります。

【例】「AI の 活用」という文章の場合

・文字Bigram(n=2):
「AI」「I 」「 の」「の 」「 活」「活用」 (スペースも含めて2文字ずつ区切る)

・単語Bigram(n=2):
「AI の」「の 活用」 (形態素解析などで分かち書きされた2単語ずつ区切る)

5. DS検定形式:実戦4択クイズ

問:テキストデータの前処理や特徴量抽出に関する記述として、最も適切なものはどれか。

① n-gramとは、文章中の単語の出現頻度と逆文書頻度を掛け合わせて、単語の重要度を数値化する手法である。
② 文字列を連続するn個の要素(文字または単語)のリストに分割して抽出する手法をn-gramと呼び、n=2の場合をBigramと呼ぶ。
③ n-gramを用いると、テキスト中の単語同士の文脈的・意味的な類似度を多次元ベクトル空間上の距離として自動的に表現できる。
④ 形態素解析を行わずにn-gram(単語単位)を作成することは、日本語のような分かち書きをしない言語において常に容易である。

【 正解: ② 】

解説: n-gramの基本性質を問う標準問題です。
②が正解です。連続するn個の単位に区切る手法であり、2個ずつの場合はBigramと呼びます。
①単語の出現頻度と逆文書頻度を掛け合わせる手法は「TF-IDF」の説明です。
③単語の意味や類似度を多次元ベクトル空間で表現するのは「Word2Vec」などの分散表現(単語埋め込み)の説明です。
④日本語のように単語間にスペースがない言語で「単語n-gram」を作るには、事前の形態素解析(分かち書き)が必要となります。一方、「文字n-gram」であれば辞書なしで容易に作成できるのがメリットです。


6. まとめ

DS検定や資格試験で「連続するn個の文字・単語」「1個=Unigram」「2個=Bigram」「3個=Trigram」といったキーワードが出たら、正解は「n-gram」です! 形態素解析(辞書が必要)を使わずにテキストの検索や分類を行える利点も含めて、しっかり理解しておきましょう!

【DS検定対策】確率や度合いで分類!「ソフトクラスタリング」と「ハードクラスタリング」の違い

教師なし学習の代表格である「クラスタリング」。データをグループ分けする際、1つのグループにスパッと分けるか、所属の「度合い(確率)」で柔軟に分けるかによって、大きく「ハードクラスタリング」と「ソフトクラスタリング」に分類されます。その仕組みと違いを整理しましょう!

1. 【 問題 】

クラスタリングの手法において、各データがいずれか1つのクラスタのみに属すると固定するのではなく、各クラスタへの「帰属の度合い(所属確率など)」を連続値として求める手法を何と呼ぶでしょうか?

① ソフトクラスタリング(Soft Clustering)
② ハードクラスタリング(Hard Clustering)
③ 階層的クラスタリング(Hierarchical Clustering)
④ 次元削減(Dimensionality Reduction)


2. 【 解答 】

正解: ① ソフトクラスタリング(Soft Clustering)

3. 整理:ハード vs ソフトクラスタリングの比較

両者の最大の違いは「データとグループの関係性(曖昧さを許容するかどうか)」にあります。

分類タイプ特徴・グループ分けの考え方代表的な手法
ハードクラスタリング
(Hard Clustering)
各データは「必ずいずれか1つのクラスタ」にのみ所属する(所属度は0か1の二者択一)。境界が明確。 k-means(k平均法)
階層的クラスタリング
ソフトクラスタリング
(Soft Clustering)
各データが「複数のクラスタにどれくらいの度合い(確率)で属しているか」を算出する。境界が曖昧なデータに強い。 ガウス混合モデル(GMM)
ファジィc-means(FCM)

4. 具体例でイメージ!ソフトクラスタリングの強み

例えば、「顧客を『映画好き』と『音楽好き』のグループに分ける顧客セグメンテーション」を考えてみましょう。

・ハードクラスタリング(k-means):
ある顧客を「映画好きグループ(100%)」と無理やり一方だけに判定します。

・ソフトクラスタリング(GMM等):
「映画好き度 70% + 音楽好き度 30%」のように度合いや確率で表現します。

どちらの趣味も併せ持つ「境界線上にいる曖昧なユーザー」を現実のデータに合わせて柔軟に表現できる点がソフトクラスタリング最大のメリットです。

5. DS検定形式:実戦4択クイズ

問:クラスタリング手法に関する記述として、最も適切なものはどれか。

① k-means法は、データが各クラスタに所属する確率を算出する代表的なソフトクラスタリング手法である。
② ソフトクラスタリングでは、1つのデータが複数のクラスタに対してそれぞれ異なる帰属度(所属確率など)を持つことができる。
③ ハードクラスタリングは、データ間の確率分布を前提としたEMアルゴリズムを用いてクラスタリングを行う手法の総称である。
④ ソフトクラスタリングを行う場合、最終的なクラスタの数は人間が事前に指定することが一切できない。

【 正解: ② 】

解説: ソフトとハードの性質の違いを正しく理解しているか問う問題です。
②が正解です。データごとに「A群に60%、B群に40%」のような帰属度を持たせることができます。
①k-meansは代表的な「ハードクラスタリング」です。
③EMアルゴリズムを用いて確率分布を推定するのはガウス混合モデル(GMM)などの「ソフトクラスタリング」です。
④ソフトクラスタリング(GMMやFCM等)であっても、クラスタ数はハイパーパラメータとして指定するのが一般的です。


6. まとめ

DS検定や資格試験で「帰属の度合い」「所属確率」「複数グループへの重複・曖昧な所属」といったフレーズが出たら、正解は「ソフトクラスタリング(代表例:GMM、ファジィc-means)」です! 「0か1かで明確に分けるk-means=ハード」、「確率や割合で柔軟に分けるGMM=ソフト」というセットで完璧に覚えておきましょう!

【Kaggle挑戦記】TPS Feb 2022:DNA配列データで手元CV0.995超えからの「重複行の罠」

前回のMoAコンペ(マルチラベル分類)を一区切りとし、今回はDNA配列データを扱う過去コンペ「Tabular Playground Series - Feb 2022(TPS Feb 2022)」に参戦しました。まずは手動での特徴量生成(エンジニアリング)を一切行わず、素のデータをそのままLightGBMに投入して不動のベースラインスコアを算出します。

1. コンペの概要とデータ構造

このコンペティションは、ゲノムシーケンス解析の手法をモチーフにした「10クラスの多クラス分類タスク」です。

  • データの中身: ゲノム解読機で抽出された10文字のDNA断片(10-mer)の出現カウントデータです。A0T0G0C10 から A10T0G0C0 まで、全286パターンの比率(標準化された確率)がカラム(特徴量)として並んでいます。
  • ターゲット: 10種類の細菌(大腸菌やピロリ菌、サルモネラ菌など)のいずれか。
  • 評価指標: Accuracy(正解率)

数値の意味としては、単なる割合ではなく「理論上の期待値(ランダムな発生確率)からのズレ」を示しており、プラスならその細菌特有の出現パターン、マイナスなら滅多に出現しないパターンを意味します。

2. 実装したベースラインコード

以前挑戦した「Digit Recognizer(手書き数字認識)」と同じ多クラス分類(multiclass)の枠組みを適用しました。文字列の細菌名を LabelEncoder で数値(0〜9)に変換して学習させ、最終的な予測時に元の細菌名へ復元して提出ファイルを作成します。

import pandas as pd
import numpy as np
from sklearn.model_selection import StratifiedKFold
from sklearn.preprocessing import LabelEncoder
from sklearn.metrics import accuracy_score
import lightgbm as lgb
import warnings

warnings.filterwarnings("ignore")

# 1. データの読み込み
print("Loading data...")
train = pd.read_csv('train.csv')
test = pd.read_csv('test.csv')

# 不要なID列の除去と目的変数の分離
X = train.drop(columns=['row_id', 'target'])
y_raw = train['target']
X_test = test.drop(columns=['row_id'])

# ターゲット(文字列の細菌名)を0〜9の数値に変換
le = LabelEncoder()
y = le.fit_transform(y_raw)

# 2. パラメータ設定(10クラスの多クラス分類)
params = {
    'objective': 'multiclass',
    'num_class': 10,
    'metric': 'multi_logloss',
    'verbosity': -1,
    'boosting_type': 'gbdt',
    'learning_rate': 0.1,
    'random_state': 42
}

# 3. Stratified K-Foldによる5分割交差検証
skf = StratifiedKFold(n_splits=5, shuffle=True, random_state=42)
oof_preds = np.zeros((len(train), 10))
test_preds = np.zeros((len(test), 10))

print("Starting Cross Validation...")
for fold, (train_idx, val_idx) in enumerate(skf.split(X, y)):
    X_train, y_train = X.iloc[train_idx], y[train_idx]
    X_val, y_val = X.iloc[val_idx], y[val_idx]
    
    model = lgb.LGBMClassifier(**params, n_estimators=1000)
    
    model.fit(
        X_train, y_train,
        eval_set=[(X_val, y_val)],
        callbacks=[lgb.early_stopping(stopping_rounds=50, verbose=False)]
    )
    
    oof_preds[val_idx] = model.predict_proba(X_val)
    test_preds += model.predict_proba(X_test) / skf.n_splits
    print(f" Fold {fold + 1} finished.")

# 4. 手元スコア(Accuracy)の算出
oof_classes = np.argmax(oof_preds, axis=1)
cv_accuracy = accuracy_score(y, oof_classes)

print("\n" + "=" * 30)
print(f"手元での交差検証スコア(Accuracy): {cv_accuracy:.5f}")
print("=" * 30)

# 5. 提出用ファイルの作成
test_classes_num = np.argmax(test_preds, axis=1)
test_classes_str = le.inverse_transform(test_classes_num)  # 数値を元の細菌名に戻す

submission = pd.DataFrame({
    'row_id': test['row_id'],
    'target': test_classes_str
})
submission.to_csv('submission_tps_feb2022_lgb.csv', index=False)
print("Submission file created: submission_tps_feb2022_lgb.csv")

3. 実行結果:衝撃のスコアギャップ

Macのローカル環境でコードを実行し、手元の交差検証スコア(CV)を確認したところ、驚くべき高精度を記録しました。しかし、作成した submission_tps_feb2022_lgb.csv をKaggleにLate Submitした結果は大きく異なるものでした。

Loading data...
Starting Cross Validation...
 Fold 1 finished.
 Fold 2 finished.
 Fold 3 finished.
 Fold 4 finished.
 Fold 5 finished.

==============================
手元での交差検証スコア(Accuracy): 0.99553
==============================
Submission file created: submission_tps_feb2022_lgb.csv
Kaggle Leaderboard 正解率(Accuracy):0.93937 / 0.94192

4. 考察とエンジニアとしての気づき

手元でのCVが0.99553(約99.5%)という完璧に近い数値を出していたのに対し、本番のリーダーボード(LB)では0.93937まで急降下するという大きな乖離が発生しました。これこそが、このコンペに潜む「データ重複の罠」です。

  • リークによる過学習: このデータセットには全く同じ値を持つ行(重複データ)が多数含まれています。通常の StratifiedKFold で分割すると、同じデータが「学習用」と「検証用」の両方に分散して入り込んでしまい、モデルが答えを暗記してCVが跳ね上がっていました。
  • 多クラス分類の速度感: 前回のMoA(マルチラベル)と比べ、10クラスの「multiclass」として1回の実行で済むため、20万行の処理もローカル環境で非常にスムーズでした。

「手元のCVを盲信してはいけない」というKaggleの洗礼を綺麗に浴びる形となりましたが、課題(原因)は明確です。次回はこの「重複データの除外」と「サンプルの重み付け(sample_weight)」を導入し、手元の検証環境を正しく修正した上で本番スコアの大幅更新を狙います。


次回は、重複行の処理とサンプルの重み付けを実装し、Kaggle本番スコア0.98オーバーへの到達を目指します。

【scikit-learn】交差検証(StratifiedKFold)の内部挙動と仕組み

機械学習モデルの性能を正しく評価する手法として定番の「交差検証(Cross-Validation)」。scikit-learnを使うとたった数行で実行できますが、裏側では一体どのような処理が行われているのでしょうか?今回はIrisデータセットを例に、交差検証の内部ロジックを解き明かします。

※本記事の手順は、MacBook Air(macOS 15.7.7)の環境にて実際に動作を確認したログをベースに作成しています。

1. 【 概要 】

交差検証とは、手元にあるデータを複数のグループに分割し、「学習」と「検証」を組み合わせを変えながら繰り返し行うことで、モデルの汎用的な性能を正しく測定する手法です。

今回は、scikit-learnの `StratifiedKFold`(層化k分割交差検証)と `cross_val_score` を使い、全150件のデータを10分割してモデルを評価する際、内部でどのようにデータが分割・処理されているかの全体像を整理します。


2. 【 基本手順(交差検証のコード例) 】

(1) データセット(Iris:全150件)をロードする
(2) 分割条件(10分割・層化・シャッフル)を定義する
(3) `cross_val_score` で一括して学習・検証・スコア算出を実行する

3. 整理:内部で起きていることのイメージ

`cross_val_score` が実行された瞬間、裏側で自動処理されているステップを順番に深く見ていきましょう。

【 内部の処理プロセス 】

・処理(1):モデルの準備
渡された `KNeighborsClassifier(n_neighbors=3)` は、まだ何も学習していない「空のモデル(アルゴリズムの設定)」です。

・処理(2):10回の自動ループ処理
① データを「学習用(135件)」と「検証用(15件)」に自動分割する
② 学習用データ(135件)でモデルを学習(fit)させる
③ 検証用データ(15件)でモデルを評価(score)して正解率を保存する
④ モデルを一旦リセットし、データの組み合わせを変えて ①〜③ を10回繰り返す

・処理(3):結果の返却
10回分の正解率が入った配列(リスト)を `scores` として返します。

4. 関連して押さえたい「分割件数(135件と15件)の決定プロセス」

コード内に「135」や「15」という数字を明示的に書いていないにもかかわらず、なぜこの件数で分割されるのでしょうか?

これは、読み込んだIrisデータセットの全件数(150件)と、指定した分割数 `n_splits=10` から自動的に計算されています。

・検証用データ(15件):全データ 150件 ÷ n_splits=10 = 15件
・学習用データ(135件):残りのデータ(150件 − 15件)= 135件

データ件数と分割ルールを渡すだけで、scikit-learnが裏で自動的に「135件で学習、15件で検証」を実行してくれます。


5. 補足:実際のPythonコードと出力ログ

実際にPythonで実行するコードと、算出される結果の出力ログです。
可読性を高めるため、背景は明るいグレーで統一しています。

# コード実行例
from sklearn.datasets import load_iris
from sklearn.model_selection import StratifiedKFold, cross_val_score
from sklearn.neighbors import KNeighborsClassifier

# 1. データロード
X, y = load_iris(return_X_y=True)

# 2. 分割条件(10分割・層化・シャッフル)の定義
cv = StratifiedKFold(n_splits=10, shuffle=True, random_state=42)

# 3. 交差検証の実行
scores = cross_val_score(KNeighborsClassifier(n_neighbors=3), X, y, cv=cv)

print(f"10回の正解率: {scores}")
print(f"平均正解率: {scores.mean():.4f}")

# 出力ログのイメージ
10回の正解率: [1. 1. 0.9333 0.9333 0.9333 0.9333 1. 1. 0.9333 1. ]
平均正解率: 0.9667

6. まとめ

scikit-learnの `cross_val_score` を使うことで、面倒なデータの分割・学習・評価・モデルのリセットという10回分のループ処理を一発でスマートに完結させることができます。内部で「全データ数 ÷ 分割数」の計算が自動で行われている仕組みを理解しておくことで、データ数が変わっても適切に交差検証を使いこなせるようになります!