0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

# LLMsでゼロからヒーローへ:大規模言語モデル向けデータ準備の実践ガイド 🚀 トレーニング用データの収集、クレンジング、アノテーション、品質評価までを体系的に解説する短期実務ガイド 🔧💡 主な

Last updated at Posted at 2025-10-28

ゼロから始めるLLMs:大規模言語モデルのためのデータ準備 🚀

シリーズ第1回では、Large Language Models(LLMs)とそれを支えるTransformerアーキテクチャの基本を扱いました。まだの方はぜひ導入をご一読ください(2025年10月現在)。

この第2回では、LLM構築で見落とされがちな「データ準備」に焦点を当てます。生のテキストをそのままモデルに流し込めば良い──というのは誤解です。実務では、非構造化テキストをニューラルネットワークが解釈できる構造に変換する工程が、学習の精度・効率に大きく影響します。本記事では、テキスト前処理、トークナイゼーション、埋め込み生成、データサンプリング、特殊トークンの扱いなど、モデル学習のためのデータ準備を包括的に解説します。

なぜデータ準備が重要か

LLMが正しく動作する前提として、データは綿密に整備されている必要があります。単にテキストを小さく分割するだけでなく、クリーンで一貫性のある意味のある入力をモデルに渡すことが重要です。これが欠けると、最先端のモデルでも十分に学習できません。

主な理由は次の3点です。

  • 標準化(Standardization):複数ソースのデータを整合させ、一貫した形式にする。
  • 効率化(Efficiency):ニューラルネットワークが処理しやすい形に変換する。
  • 精度向上(Accuracy):適切に整形されたデータが、より正確な学習につながる。

以下で各ステップを順に見ていきます。

1. テキスト前処理(Text Preprocessing)

テキスト前処理は、データ準備の最初の段階で、ノイズ除去や形式統一を行います。不要な文字や記号の除去、句読点・大文字小文字の正規化、Unicode正規化(NFC/NFKC)などが含まれます。言語や用途によって必要な処理は変わります(例:ソーシャルメディアだと絵文字やハッシュタグの扱い、コードドキュメントだとインラインコードの除外など)。

例として、次のような生テキストがあります(コードブロック内はそのまま):

Hello,  World! This is an Example--testing 123.

基本的な前処理パイプラインで行う例:

  • 余分な空白の削除:"Hello, World!""Hello, World!"
  • 句読点の正規化:-- や長いダッシュを一つのダッシュやピリオドへ
  • 表記の統一:用途に応じて全て小文字化するか、固有名詞は維持するか決める
  • Unicode正規化:NFKCで全角・半角や合字を統一する(特に多言語データで重要)

簡単なPythonでの例(コードブロックは原文のまま変更していません):

import re# Sample texttext = "Hello, World! This is an Example--testing 123."# Basic Tokenization using Regular Expressionstokens = re.split(r'(\s|[,.?!])', text)tokens = [t.strip() for t in tokens if t.strip()]print(tokens)

出力例(そのまま):

['Hello', ',', 'World', '!', 'This', 'is', 'an', 'Example', 'testing', '123']

補足(実務で注意すべき点)⚠️:

  • 正規化の副作用:小文字化で固有名詞や頭字語の意味が失われることがあるため、タスクに応じて設定する。
  • 言語依存処理:形態素解析が必要な言語(日本語など)では分かち書きルールを別途設計する。
  • メタデータ保持:発話日時やソースを別フィールドで保存すると後のフィルタリングに役立つ。

2. トークナイゼーション(Tokenization)

前処理後はトークナイゼーションです。テキストを単語、サブワード、あるいは文字単位の「トークン」に分割します。LLMsはトークン列を入力として扱うため、ここでの選択がモデル性能や語彙サイズに影響します。

シンプルな単語分割の例(前節の正規表現を使った場合):

tokens = re.split(r'(\s|[,.?!])', text)tokens = [t.strip() for t in tokens if t.strip()]

ただし、単純な単語分割は未知語(OOV)が多くなりがちです。そこでよく使われるのが Byte Pair Encoding(BPE、バイトペア符号化)などのサブワード手法です。

Byte Pair Encoding(BPE)

BPEは稀な単語をサブワードに分解することで語彙数を抑え、未知語に強くします。GPT-2 / GPT-3 などで採用されています。実装例として tiktoken ライブラリを使う例(ライブラリ名はそのまま):

import tiktoken# Using BPE tokenizationtokenizer = tiktoken.get_encoding("gpt2")text = "Hello, do you like coffee?"token_ids = tokenizer.encode(text)print(token_ids)

なぜBPEが有用か:

  • 未知語への対処:学習時に見ていない語でもサブワードに分割すれば表現可能。
  • 語彙サイズと性能のバランス:語彙が爆発的に増えるのを防ぐ。
  • 一般化性能の改善:共通のサブワードを通じて未知の組み合わせに対応しやすい。

トークナイゼーションの比較(簡潔な表):

方法 長所 短所 推奨用途
単語ベース 理解しやすく人間寄り OOVが多い 小規模コーパス、言語研究
BPE / サブワード 語彙削減・未知語に強い 学習・実装が必要 大規模コーパス、LLM
文字ベース 常にカバレッジあり 長いシーケンスになる 言語に依存しない処理、特殊文字多いデータ

(参考リンク:tiktoken GitHub

3. 埋め込み(Embeddings)生成

トークンが得られたら、それをニューラルネットワークが扱える数値に変換する必要があります。埋め込みは各トークンを連続値ベクトルに変換し、意味的な類似性をベクトル空間上で表現します。例えば「king」と「queen」が近いベクトルになるように学習されます。

PyTorch を使った埋め込みの簡単な例(ブロックは原文のまま):

import torch# Create an embedding layervocab_size = 50000  # Total number of tokens in the vocabularyembedding_dim = 256  # Each token will be mapped to a 256-dimensional vectorembedding_layer = torch.nn.Embedding(vocab_size, embedding_dim)# Sample token IDstoken_ids = torch.tensor([1, 2, 3, 4])embeddings = embedding_layer(token_ids)print(embeddings.shape)

埋め込みが重要な理由:

  • トークンを数値化:ニューラルネットが扱える形式に変換するために必須。
  • 意味関係の表現:語義的に近い語が近接することで文脈理解が向上。
  • 学習による最適化:学習過程で埋め込み自体がファインチューニングされ、データセット固有の関係を捉える。

補足(実務的な注意)💡:

  • 事前学習済みの埋め込みを利用するか、モデルと一緒に学習するかはタスク依存。
  • 埋め込み次元は性能と計算コストのトレードオフ:512〜2048の範囲がよく使われますが、用途により調整。

4. スライディングウィンドウによるデータサンプリング(Sliding Window)

多くのLLMは次トークン予測を目的に学習します。長いテキストをそのまま与える代わりに、固定長のウィンドウをスライドさせてオーバーラップするシーケンスを作り、入力(コンテキスト)と出力(次のトークン)のペアを生成します。これにより、1つの長文から多くの学習例を取り出せます。

例(原文のコードブロック):

# Sample text tokenization (illustrative, assume each word is a token)token_ids = ["LLMs", "learn", "to", "predict", "one", "word", "at", "a", "time"]context_size = 4  # Number of tokens in each input contextinput_output_pairs = []for i in range(len(token_ids) - context_size):    x = token_ids[i:i + context_size]  # Input context    y = token_ids[i + context_size]     # Target word to predict    input_output_pairs.append((x, y))# Display generated input-output pairsfor x, y in input_output_pairs:    print(f"x: {x}, y: {y}")

出力例(そのまま):

x: ['LLMs', 'learn', 'to', 'predict'], y: 'one'x: ['learn', 'to', 'predict', 'one'], y: 'word'x: ['to', 'predict', 'one', 'word'], y: 'at'x: ['predict', 'one', 'word', 'at'], y: 'a'x: ['one', 'word', 'at', 'a'], y: 'time'

スライディングウィンドウの利点:

  • 学習データを増やす:同じ文章から複数の例を生成。
  • コンテキスト保持:一定長の履歴をモデルに与える。
  • 計算効率:長文を小さく分割して扱えるためバッチ処理が容易。

補足(実務的判断)🔧:

  • ステップサイズ(ウィンドウの移動幅)を小さくすると例は増えるが相関が高くなる。メモリや学習の多様性を考慮して調整する。
  • 次トークン予測以外(例えば文書分類)では、ラベルの整合性に注意してウィンドウ切り出しを行う。

5. 特殊トークンの扱い(Special Tokens)

特殊トークンはシーケンスの区切りや未知語、パディングなどを示すために重要です。一般的な特殊トークンの例:

  • <|endoftext|>:テキストの終端を示す
  • <|unk|>:語彙にない未知語を表す
  • <|pad|>:バッチ処理のためにシーケンスを詰めるパディング

正しい特殊トークンの扱いがないと、モデルは入力境界や文脈を誤解することがあります。取り扱い例(原文のコードブロック):

# Sample tokens including special tokenstokens = ["Hello", "world", ".", "<|endoftext|>", "This", "is", "an", "LLM"]# Simulated vocabulary with token IDsvocab = {    "Hello": 1,    "world": 2,    ".": 3,    "<|endoftext|>": 4,    "This": 5,    "is": 6,    "an": 7,    "LLM": 8,    "<|unk|>": 0  # ID for unknown tokens}# Convert tokens to their corresponding IDstoken_ids = [vocab.get(token, vocab["<|unk|>"]) for token in tokens]print(token_ids)

特殊トークンが重要な理由:

  • 境界検出:シーケンスの開始・終了を明示できる。
  • 未知語処理:不明な語を <|unk|> で置き換えて処理を継続できる。
  • バッチ処理の効率化:<|pad|> による長さ揃えでミニバッチ学習が可能。

データ準備パイプラインの視覚的な要約

  1. テキスト入力(例: “Hello, world.”)
  2. トークナイゼーション(例: ['Hello', ',', 'world', '.']
  3. トークンID(例: [1, 2, 3, 4]
  4. 埋め込み(例:256次元ベクトルに変換)

実務で見落としがちな追加トピック(短めの補足)

データ品質と重複排除(Deduplication)

大量データでは重複が学習バイアスを生む。シャッフル前に文単位/ドキュメント単位の重複除去を行うと効果的です。

シーケンス長とトランケーション

最大シーケンス長をどう設定するかは重要です。トランケーションは情報を失うので、重要なコンテキストを残すように前側・後側どちらを切るかを設計する必要があります。

ラベル付きデータの整形(監督学習や微調整用)

指示文(instruction)、入出力ペア、メタデータを明示的にフォーマットしておくと、微調整(fine-tuning)や評価が楽になります。

多言語・特殊文字対応

多言語コーパスでは Unicode 正規化とトークナイザーの設計(言語ごとのルール)を慎重に整えること。絵文字や制御文字の扱いも設計に入れる。

最後に(まとめ)📝

データ準備はLLMの学習における最も重要な工程の一つです。テキストをクリーンにし、適切にトークン化し、意味を保ったまま数値ベクトルへ変換することで、モデルはより効率的かつ正確に学習できます。本稿で紹介した各ステップは相互に関連しており、用途やデータ特性に応じて調整する必要があります。

次回は、ニューラルネットワークにおける「アテンション機構」の意義から始め、基本的な自己注意(self-attention)の仕組み、拡張された自己注意、そしてLLMが1トークンずつ生成するための因果的注意(causal attention)について掘り下げます。さらに、過学習対策としてのドロップアウトや、マルチヘッド注意の積み重ね方についても扱う予定です。お楽しみに。

0
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?