データ 基礎

どんな ML パイプラインにも避けて通れない最低限のデータ配管。5 つの短いトピックで、 データセットとは何か、特徴と教師ラベルの分離、評価を歪めない訓練 / 検証 / テストの分割、 あらゆる文字列の下にあるバイト(ASCII と UTF-8 —— LLM が実際に消費する形式)、 そしてモデルが数値を見る前に静かに走る正規化と前処理をカバーする。 数学は少なめ、直感を重視。

01

データセット(Dataset)

サンプルの山 —— モデルの「知識」はすべてここから来る。

機構的に言えば データセットはただのリストだ。リスト内の各エントリは、 モデルに学ばせたいものの一例—— メール 1 通、写真 1 枚、文 1 つ、 取引 1 件、CT スキャン 1 枚。リストは 50 件でも 500 億件でも原理は同じ。 モデルが「知っている」ことは、すべてデータ中で同じパターンを十分な回数見たから知っている。

「1 つのエントリ」を指す言葉はいくつもあり、現場ではほぼ同義に混用される:サンプルインスタンスレコードデータ点観測。意味は同じ —— 訓練中にモデルが一度に見る、 1 つの完結した単位。チームの慣習に従って、用語は気にしなくていい。

最も簡単な心的モデルは 表計算ソフト(スプレッドシート): 1 行に 1 サンプル、各列はそのサンプルについての 1 つの情報。 「住宅価格を予測する」データセットのスケッチ:

  面積   寝室数   築年数  郵便番号   価格
  ────────────────────────────────────────────
   850       1        12   94110     820,000
  1450       3         8   94110   1,300,000
  2100       4        15   94114   1,720,000
  3200       5         3   94114   2,650,000
   600       0        22   94103     480,000
  ...        ...      ...   ...        ...
データセット · 1 サンプル面積寝室築年郵便価格85011294110820,000145038941101,300,0002100415941141,720,000320053941142,650,00060002294103480,000
1 / 5
各行が 1 サンプル。データセットは「行を増やす」ことで大きくなる。

この表がデータセットだ。5 サンプルだけ表示しているが、もちろん背後には数千件以上ある。 各列はその家についての 1 つの事実、各行は 1 軒の家。 スプレッドシートの比喩が通じる限り、これが「データセット」の意味するもの。

以降の節につながる、最初に押さえたい 3 つの観察:

  • サイズは重要だが、すべてではない。ディープラーニングは大きなデータを好む —— ImageNet は 120 万枚、現代の LLM は数兆トークン規模で訓練する —— が、小さくとも丁寧に集めたデータセットが巨大だが雑なものに勝つことは珍しくない。 「ゴミを入れたらゴミが出る」は ML 最古の鉄則で、今も真。
  • 行はみな似ていなければならない。各行は同じ種類のもので、 同じ列を持ち、関心のある同じ母集団から取られているべき。 「住宅価格」データセットにマンションとコンテナを混ぜると、 不要な難しさをモデルに押し付けるだけだ。
  • すべてのデータが表形式とは限らない。画像は 3 次元配列(高さ × 幅 × チャンネル)、 音声はサンプルの長い列、テキストは文字列。スプレッドシートの絵は通じる —— 各行が 1 枚の画像、1 つの文書 —— ただし各「セル」自体が巨大になり得る。

データセットが答えるべき 2 つの大問は、以降の 2 節で展開する:各行はどんな情報を運んでいるか?(特徴と教師ラベル)と、モデルが不正をしないようにするには?(訓練 / 検証 / テストの分割)。 以降の内容はすべてその 2 つの土台に乗る。

Transformer では:現代 LLM のデータセットは「集めうるすべてのテキスト」だ —— Common Crawl、GitHub、書籍、論文、コード、会話、数兆トークン。隣に「ラベル」のファイルはない; プロンプトそのものが問いで、次のトークンが答え、1 エポックで数十億回。 この記事のあとの節 —— 特徴、ラベル、分割、エンコーディング、前処理 —— は LLM にもすべて適用される、 ただし用語が「バイト列」に置き換わるだけ。

02

特徴と教師ラベル(Features & Labels)

各行を「モデルが見る部分」と「モデルが当てる部分」に分ける。

第 1 節のデータセットはただの行の山だ。これを「学習問題」に変えるには、 各行を 2 つに分ける必要がある:特徴(features)—— モデルが見られる列、 と 教師ラベル(label)—— 予測してほしい列。 この分割をデータセットのすべての行に対して行うことで、 「モデルを訓練する」という操作が初めて意味を持つ。

ほぼすべての ML 論文に共通する慣例的記法:

  • x —— 1 サンプルの特徴。たいてい数値ベクトル;ときに画像、文字列、グラフ。
  • y —— そのサンプルのラベル。1 つの数、カテゴリ、構造化されたものでも。
  • データセットの 1 行 = 1 つの (x, y) 対。データセット全体 = (x, y) 対のリスト。

第 1 節の住宅例に戻る。「家を入力したら価格を予測する」を学ばせるには、 価格の列がラベル、それ以外の列が特徴になる:

  特徴 (x)                          ラベル (y)
  ────────────────────────────────  ───────────
  面積  寝室数   築年数 郵便番号    価格
  ────────────────────────────────  ───────────
   850     1       12   94110         820,000
  1450     3        8   94110       1,300,000
  2100     4       15   94114       1,720,000
  ...
面積寝室築年郵便価格85011294110820,000145038941101,300,0002100415941141,720,000住宅表からの 3 行。
1 / 3
同じ表で 2 つの役割:モデルが見る列、当てるべき列。

どこをラベルにするかが、解いている問題のフレーミングそのものだ。 同じデータセットでもラベル次第でまったく別のモデルになる:

  • ラベル = 価格 → 住宅価値を推定するモデル。
  • ラベル = 30 日以内に売れた? → 物件が売れる速さを予測するモデル。
  • ラベル = 郵便番号(面積・寝室・築年数を特徴に)→ 建物の特徴から地区を当てるモデル。

ラベルのがモデルと損失関数の選択を決める:

  • 連続ラベル回帰(regression)。 ドル建ての価格、明日の気温、クリック率。損失はたいてい平均二乗誤差。
  • 2 値の離散ラベル二値分類。 スパムか否か、デフォルトするかしないか。損失は二値交差エントロピー。
  • 多クラスの離散ラベル多クラス分類。 ImageNet の 1000 カテゴリのどれ? 損失は交差エントロピー。
  • 構造化ラベル → 物体検出(ラベル = バウンディングボックスとクラスのリスト)、 翻訳(ラベル = 別言語の文)、生成(ラベル = 次のトークン)。

触れておきたい微妙な点:すべてのデータセットがラベル付きではない。教師なし学習は純粋な x 上で動き、自力で構造を探す —— クラスタリング、次元削減、密度推定。さらに美しい中間地点があり、自己教師あり学習と呼ばれる:データそのものがラベルを供給し、 人手アノテーション不要。画像の一部を隠してモデルに埋めさせる。文章の単語を隠して当てさせる。 「ラベル」はもとからデータの中にあった、見方を変えるだけだ。

Transformer では:LLM は世界で最も高価な自己教師あり学習モデルだ。 データセットは「大量のテキスト」。1 つの訓練サンプルの特徴は「ある列の先頭 N トークン」、 ラベルは「N+1 番目のトークン」。これだけだ。 誰一人としてラベルファイルを書いたことはない。 モデルは「次のトークンを当てる」を数十億回繰り返して学習し、 数兆トークンの訓練テキスト中には完全に整列した (x, y) 対が数十億個、 そのまま隠れている。

03

訓練 / 検証 / テスト分割

データセットを 3 つに切り、モデルが「試験」でカンニングできないようにする。

練習問題を配った後、試験で同じ問題を出す教師を想像してほしい。全員 100 点。 誰が本当に分かっていたのか、その試験からはわからない。訓練 / 検証 / テスト分割が解こうとしているのは、まさにこの問題だ。データセットを互いに重ならない 3 つに切り、それぞれ別の役割を持たせる。 報告される「モデルの性能」が記憶力ではなく本当の能力を反映するようにするためだ。

3 つの役割:

  • 訓練集合(training set) —— モデルが当てはめ時に見られる行。 オプティマイザはこれを見て重みを調整する。普通はデータセットの 70–90%。
  • 検証集合(validation set) —— モデルが決して訓練しない行で、 候補モデルから選ぶために使う。学習率は 1e-31e-4? 12 層か 24 層? 検証損失が低い方が勝ち。dev set と呼ぶことも。普通は 5–15%。
  • テスト集合(test set) —— プロジェクトの最後にたった一度開け、 最終成績を報告する。最終モデルを凍結する前に覗いた瞬間、その目的は失われる。 普通は 10–20%。

10,000 行のデータセットに対する具体的な分割:

  ┌──────────── 10,000 行 ──────────────┐
  │  訓練 8,000     検証 1,000  テスト 1,000 │
  └─────────────────────────────────────────┘
                 80%        10%        10%
10,000 行訓練8,000 · 80%検証1,000 · 10%テスト1,000 · 10%互いに重ならない 3 つ —— ⏭ で各役割を見るデータセットを 3 つに切り、各々別の仕事を持たせる。
1 / 4
3 つの役割、互いに重ならない 3 つのチャンク。テスト集合は最後まで鍵をかけたまま。

なぜ 2 つでなく 3 つか? 検証結果に基づいて何かを変えた瞬間 —— ハイパーパラメータ、アーキテクチャ、トークナイザ —— 検証集合の情報は モデルに漏れ込み始める。これを何度も繰り返すうちに「検証精度」は 新しいデータでの性能の公平な推定ではなくなる。テスト集合は、 最後まで触らないことで、フィニッシュラインで信頼できる数値を確保する。

必ず遭遇する 2 つの典型的な失敗パターン:

  • データリーク。テスト集合の行が訓練に紛れ込む。 同じ行の重複かもしれない、近重複(同じ記事の言い換え)かもしれない、 もっと微妙な場合もある(未来の情報で過去を予測)。 テストスコアが「良すぎる」ときは、たいていリークが原因。
  • 分割と現実の分布シフト。2018 年のメールを 80/10/10 で切ったが、 リリースは 2026 年。テスト集合自体は正直に分けてあるが、 4 年古い。テスト性能は素晴らしく、デプロイ性能はひどい、はあり得る。

どう分けるか? 多くのデータセットではシャッフルして切るだけでよい —— 行は互換だから、 ランダムな 80/10/10 で十分。シャッフルが誤りになる 3 つのケース:

  • 時系列。未来データを訓練に使って明日の株価を予測するのはカンニング。時間で分ける:過去で訓練、直近過去で検証、現在でテスト。
  • グループ化データ。10 匹の猫の 100 枚の写真(1 匹あたり 10 枚)。 同じ猫の異なる写真を訓練とテストに振り分けるとリーク —— モデルは「猫」ではなく「この猫」を学ぶ。猫(グループ)で分ける。
  • クラス不均衡。99% が通常トラフィック、1% が不正。 ランダム分割だとテストに不正ケースが 1 件も残らないことがある。層別サンプリングを使い、各分割でクラス比を固定する。

Transformer では:LLM の「検証 / テスト」相当は、 訓練中にモデルが決して見ない固定のホールドアウト文書だ —— 通常は訓練開始前に切り出した Common Crawl の一部に加え、 厳選されたベンチマーク(HellaSwag、MMLU、GSM8K など)。 ホールドアウト文書上の損失が研究者の言う「validation loss」「eval loss」。 ベンチマークは公開のスコアボード。リーク危険は現実だ: ベンチマーク問題が訓練コーパスに混入した瞬間、それは何の指標でもなくなる。 この種の汚染を検出・除去することが、現代 LLM の評価作業の半分を占める。

04

文字エンコーディング(Text Encoding)

「文字列」はコンピュータの中には存在しない。バイトしか存在しない。

"hello" のような「文字列」は、プログラミング言語があなたに語る親切な嘘だ。 内部では、すべてのテキストファイル、すべてのチャットメッセージ、すべてのソースコード行がバイト列 —— 0〜255 の整数の並び —— だ。文字エンコーディングとは、人が読める文字とそのバイトの対応規則のこと。 ML が気にする 2 つ:ASCII(単純な方)と UTF-8(現代インターネット全体が使う方)。

ASCII は 1963 年の原始規格で、128 個の文字に 1 バイトずつ割り当てる。 ラテン文字、数字、句読点、いくつかの制御コード —— 以上。 1963 年の英語には十分、それ以外の言語にはまるで足りない。

  "hello"  →  104  101  108  108  111
              'h'  'e'  'l'  'l'  'o'

  5 文字 → 5 バイト(各 1 バイト)。

ASCII にとって、自身が想定しなかった文字に出会った瞬間に破綻する。é? ? 👋? いずれも 7 ビット ASCII には存在しない。 解決策が Unicode:人類の文字史上に現れたあらゆる文字に、 ユニークな番号 —— コードポイント —— を割り当てる。 今や 15 万以上、文字体系・記号・数式・絵文字 —— ほぼ何でも。hU+0068U+4E2D👋U+1F44B

だがコードポイントは抽象的な番号で、バイトではない。ディスクに書いたり回線に流したりするには、 バイトに符号化する必要がある。そこで登場するのが UTF-8。 UTF-8 は可変長エンコーディング:

  • ASCII 文字(コードポイント 0–127)→ 1 バイト。ASCII と完全一致。
  • ラテン文字のアクセント付き、ギリシャ、キリル、ヘブライ、アラビア(128–2047)→ 2 バイト。
  • 中国語、日本語、韓国語、その他大半の文字(2048–65535)→ 3 バイト。
  • 絵文字、希少記号、古代文字(65536 以上)→ 4 バイト。

「文字列の長さ」が厄介な理由を示す例:

  "hi 中 👋"

  文字:             h     i   ' '   中    👋
  コードポイント:U+68  U+69  U+20  U+4E2D  U+1F44B
  UTF-8 バイト:    68    69    20  E4 B8 AD  F0 9F 91 8B
                  ─1─   ─1─   ─1─   ──3──    ───4───

  目に見える文字 5 個 → 実際は 10 バイト
文字列コードポイントUTF-8 バイトhU+0068681バイトiU+0069691バイト·U+0020201バイトU+4E2DE4B8AD3バイト👋U+1F44BF09F918B4バイト"hi 中 👋" —— エディタ上の見た目。
1 / 3
見える文字は 5 個、実体は 10 バイト。UTF-8 は ASCII に 1 バイト、中に 3 バイト、絵文字に 4 バイトを使う。

UTF-8 が既定になっている 3 つの性質:

  • ASCII に後方互換。古い ASCII ファイルはそのまま正当な UTF-8 で、 バイトが 1 ビットも違わない。40 年分の英語テキストがそのまま動く。
  • 自己同期。「文字の先頭バイト」と「文字の継続バイト」が見分けられるので、 バイト列の途中から読み始めても素早く整列を回復できる。 パケットが消失・分割されるネットワークで便利。
  • 普遍的。1 つのエンコーディングで人類の全文字体系をカバーする。 かつてエンコーディング不一致は日常的な痛みの源だった(「文字化け」: 中国語があるべきところに çåüå€)。UTF-8 がこれをほぼ絶滅させた。

覚えておきたい落とし穴:バイト数 ≠ 文字数 ≠ 表示幅。 文字列 "中" は Python では長さ 1(1 文字)、生バイトでは 3、 端末ではおよそ 2 列を占める。"👋" はユーザの目には 1 個だが、 JavaScript の .length は 2(UTF-16 では「サロゲートペア」)、 UTF-8 では 4 バイト、端末ではフォント次第で 1 列または 2 列を取る。 文字列を素朴に「100 文字に切る」と、絵文字が初めて現れたときに面白い壊れ方をする。

Transformer では:この話は他のどんな ML システムよりも LLM にとって重要だ。 LLM はテキストを扱うからだ。すべての LLM の最上層にあるトークナイザは、Unicode 文字では動かない —— UTF-8 バイトで動く。 現代のトークナイザ(GPT 系の BPE、他の多くで使われる SentencePiece)は、 生のバイト列から始め、頻繁に共起するバイト列をより大きな単位にマージすることを学ぶ。 だから 👋 のような単一の絵文字でも、しばしば複数のトークンになる —— 4 つの UTF-8 バイトがすべて 1 片にマージされるとは限らない。 非英語テキストが英語より「文字あたりのトークン数」が高くなることが多いのも同じ理由。 「モデルのコンテキスト窓は 128k」とは「128,000 トークン、約 8 万英単語、しかし中国語なら 4 万字程度かもしれない」を意味する。LLM のトークン数にまつわるあらゆる混乱は、 トークナイザの一層下にある UTF-8 に行き着く。

05

前処理(Preprocessing)

生データとモデルが実際に見るテンソルの間にある、目立たないが重要なステップ。

現実のデータは「そのまま訓練できる」状態であることはない。欠損行があり、 単位が大きく違う列があり、入力ミスがある。前処理(preprocessing)とは 「生データから、オプティマイザが見る数値テンソルまで」の全工程の総称だ。 地味な作業の集合だが、前処理の質はしばしばモデル選びより結果に効く。

前処理には繰り返し現れる 2 つの系統がある:クリーニング(誤りに対処)と 標準化(正しいがスケールが不便なものに対処)。

クリーニングはデータ衛生のチェックリスト。スキップするとモデルはゴミを学ぶ:

  • 欠損値。age = NaN の行は「ここは数値」と期待する処理に食わせられない。 選択肢:行を捨てる、列の平均 / 中央値で埋める、「欠損」を独立のカテゴリとして扱う。 いずれもトレードオフあり;最悪は「無かったことにする」。
  • 重複。同一の行が 2 つあると、その行が表す方向に勾配が傾く。 分割の前に重複排除を ——特にインターネットテキストでは同じ段落が何千回も再公開される。
  • 外れ値。1 ドルの家、999°C の気温、300 歳。たいていは入力ミス、 ときに本物だがまれな事象。どちらにせよ、1 つの極端な行が勾配を支配し得る。 頭打ちにする、クリップする、削除する —— 何をしたかは記録する。
  • 表記の不一致。同じ国に「USA」「United States」「U.S.」、 同じ日付に 2024-01-3131/01/2024。 モデルが見るのは 3 つの異なる文字列、本来欲しいのは 1 つ。早めに正規化する。

標準化はスケール問題に対処する。たとえば特徴に 住宅の面積(600〜4000)と築年数(0〜80)があるとする。 2 つは完全に別スケールに住んでいる。ニューラルネットは技術的にはこれを学べるが、 勾配降下は各特徴が同程度のレンジに揃っているほど安定する。 どこでも見る 2 つのレシピ:

  • Z スコア(標準化)。列の平均を引き、列の標準偏差で割る:x' = (x − μ) / σ。各列は平均 0・標準偏差 1 に。 ML での主流。
  • Min-max(正規化)。各列を [0, 1] に押し込める:x' = (x − min) / (max − min)。 境界つき入力が必要なときに使う(ピクセル値を [0, 1] に揃える、など)。

具体例。築年数と面積を z スコア化する前と後:

  生                        標準化後(z スコア)
  ─────────────             ─────────────────────────
  築年数 面積                築年数  面積
  ────  ──────              ──────  ──────
   12     850                -0.32   -1.21
    8    1450                -0.61   -0.55
   15    2100                -0.10    0.17
    3    3200                -0.96    1.39
   22     600                 0.40   -1.48
   ...    ...                  ...    ...

  μ      11.9   1640          ≈ 0     ≈ 0
  σ      7.0    900           ≈ 1     ≈ 1
築年数面積02212815322μ = 12.0 · σ = 6.403200850145021003200600μ = 1640 · σ = 937生の値:築年数 0–25、面積 0–4000。同じ図でも行ごとにまるで違って見える。
1 / 3
生の値はスケールがまるで違う。Z スコアで各列を共通の比較可能なレンジに揃える。

標準化に関して全員が痛い目を見て学ぶ 2 つのルール:

  • 訓練集合で当てはめ、全集合に適用。訓練集合だけから μσ を計算し、 その同じ値で訓練・検証・テストを変換する。 テスト集合で当てはめ直すのは、テストデータを前処理に反映させることに等しい —— 第 3 節で警告したリークの、標準化に化けたバリエーションだ。
  • サービング時も同じレシピ。訓練時に使った μσ は、 本番環境のあらゆる入力にも適用しなければならない。z スコアで訓練、生データで推論、 だとモデルは事実上ゴミを見ている —— 出荷した本番バグの中でもとくに恥ずかしい類のもの。

画像と音声には専用の派生形がある:

  • 画像。255 で割って [0, 1] に押し込め、 チャンネル平均(よく見るのは ImageNet の (0.485, 0.456, 0.406))を引き、 チャンネル標準偏差で割る。リサイズ・クロップ・反転・色のジッタリングは データ拡張: 無関係な要素に対する不変性をモデルに教える合成行。
  • 音声。生波形をスペクトログラムへ、振幅は対数化し、z スコアをかける。 ここまで来ると形状は画像と同じ — 2 次元テンソル — になり、以降の前処理ロジックも画像と同じ。

Transformer では:現代 LLM の前処理パイプラインは 3 段階で走る。 (1)フィルタリングと重複排除:スパム、壊れた HTML、繰り返し、低品質文書を捨てる —— これだけで、モデルサイズを倍にする以上に下流品質が変わることがある。 (2)トークナイゼーション:UTF-8 バイト列(第 4 節)を、BPE や SentencePiece で 整数のトークン ID に切り分ける。 (3)シーケンスパッキング:トークン化済みの文書を一定長に連結し、 GPU が「半分空のバッチ」を見ないようにする。整数のトークン ID に z スコア標準化は適用しない —— モデル自身が埋め込み層で各トークンを連続ベクトルに変換するからだ —— が、 モデル内部のすべての学習可能パラメータには、同種の慎重な初期化と層ごとの正規化 (LayerNorm、RMSNorm)が施され、勾配を扱いやすく保つ。 この発想は構造的には上記の「列ごとの標準化」と同じものだ。