フェーズ1 で使った基盤のメソッド一覧 — LLM 学習に直接かかわるもの(モジュール別)
作成: 2026-10-11 対象コミット: 866b7a2(フェーズ1 の S ベースライン完走時点のコード)
0. この資料について
- 目的: 「モデルは自前実装、PyTorch 等の基盤利用は許容」(review01 の確定事項)という方針に対して、フェーズ1 のコードが実際にどの基盤のメソッドに頼っているかを、モジュール・ファイル別に一覧にする。
- 載せる範囲: LLM の学習に直接かかわる基盤のメソッドだけ。該当するのは SentencePiece(トークナイザ)と PyTorch(モデル・学習)の 2 つ。ファイル入出力や引数の処理など、学習そのものではない部分は載せていない。
- 並び順: 実際の作業の順に、
zxell_prep/(トークナイザと前処理)→zxell_model/(モデルと学習)。 - 作り方: 各ファイルを機械的に解析して呼び出しを抜き出し、コードを読んで用途の説明を付けた。「×N」はそのファイル内での呼び出し回数。
| 基盤 | 版 | 使っているモジュール | 役割 |
|---|---|---|---|
SentencePiece (sentencepiece) | 0.2.2 | zxell_prep/、zxell_model/sample.py | BPE トークナイザの学習・エンコード・デコード |
PyTorch (torch) | 2.14.0(サーバ機は CPU 版、RTX 3060 機は CUDA 版 cu128) | zxell_model/ | テンソル演算、自動微分、層の部品、最適化、混合精度 |
1. zxell_prep/(トークナイザと前処理)
前処理で LLM 学習に直接かかわる基盤は SentencePiece だけ。使っているのは 3 ファイル。
1-1. train_compare_tokenizers.py — トークナイザの学習と比較
| 呼び出し | 用途 |
|---|---|
sentencepiece.SentencePieceTrainer.train | BPE トークナイザの学習(語彙 48k と 64k の 2 つ) |
sentencepiece.SentencePieceProcessor | 学習したモデルの読み込み |
.encode | 評価セットをトークン列にして、言語別の字/トークンを測る |
SentencePieceTrainer.train に渡している主な引数:
| 引数 | 値 | 意味 |
|---|---|---|
model_type | "bpe" | BPE で学習する |
vocab_size | 48,000 / 64,000 | 語彙の大きさ(48k を採用) |
character_coverage | 0.9995 | 語彙に入れる文字の網羅率 |
byte_fallback | True | 未知の文字はバイト列に落とす(UNK を出さない) |
split_digits | True | 数字は 1 桁ずつに分ける |
normalization_rule_name | "nmt_nfkc" | 文字の正規化 |
max_sentence_length | 16,384 | 1 文として扱う長さの上限 |
input_sentence_size / shuffle_input_sentence | 2,000,000 / True | 学習ファイルから 200 万文を無作為に使う |
学習ファイルの作り方(言語別の文字数上限で配分し、ja を約 19% に厚くする)は自前のロジック。BPE の学習アルゴリズム自体は SentencePiece に任せている(review10 の決定)。
1-2. tokenize_full.py — 全量トークン化とシャード化
| 呼び出し | 用途 |
|---|---|
sentencepiece.SentencePieceProcessor | 採用した 48k モデルの読み込み |
.encode | 全記事をトークン ID の列にする(学習データそのものを作る処理) |
.eos_id | 記事と記事の間に挟む区切りトークン(EOS)の ID |
.vocab_size | 語彙が uint16(65,536 未満)に収まることの確認 |
正規化・重複除去・言語別の分割・記事単位のシャッフル・5,000 万トークンごとのシャード化・書いた直後の検証は、すべて自前のロジック。
1-3. peek_shard.py — シャードの目視確認
| 呼び出し | 用途 |
|---|---|
sentencepiece.SentencePieceProcessor | 48k モデルの読み込み |
.decode | シャードのトークン列を原文に戻して表示する(学習データに何が入っているかの確認) |
.eos_id | 記事の区切りを見つける |
1-4. 基盤のメソッドを使っていないファイル
parse_dump.py(スナップショットの作成)、extract_sample.py(サンプルの抽出)、compute_boundaries.py(分割境界の算出)、 textprep.py(テキスト整形)には、LLM 学習に直接かかわる基盤の呼び出しはない。処理はすべて自前のロジックで書いている。
2. zxell_model/(モデルと学習)
2-1. 「自前実装」と「基盤」の境界
先に結論を置く。何を自分で書き、何を PyTorch に任せたか。
| 部品 | 自前で書いたもの | PyTorch に任せたもの |
|---|---|---|
| RMSNorm | 計算式そのもの(2 乗平均の逆平方根を掛ける、fp32 に上げて計算) | torch.rsqrt、.pow・.mean、学習パラメータの入れ物 nn.Parameter |
| RoPE(回転位置埋め込み) | 周波数表の作成、前半・後半を回転させる式 | torch.arange・torch.outer・.cos・.sin・torch.cat |
| Self-Attention | Q/K/V の射影と head への分割、RoPE の適用、出力射影 | 注意の計算そのもの: F.scaled_dot_product_attention(is_causal=True)(softmax(QKᵀ/√d)V と因果マスク。GPU 向けに最適化された実装) |
| SwiGLU FFN | 構成(gate・up・down の 3 つの線形層と掛け算) | nn.Linear、活性化関数 F.silu |
| Transformer ブロック・GPT 本体 | Pre-Norm の残差構成、層の積み重ね、埋め込みと LM Head の重み共有、初期化の方針 | nn.Embedding・nn.Linear・nn.ModuleList、初期化 nn.init.normal_ |
| 損失 | 語彙 48k の logits が大きいので、4 系列ずつに分けて計算する工夫 | 交差エントロピー F.cross_entropy、逆伝播時の再計算 torch.utils.checkpoint.checkpoint |
| 学習 | 学習率スケジュール(warmup + cosine)、weight decay をかける対象の振り分け、学習データのサンプリング | 自動微分(loss.backward())、最適化(torch.optim.AdamW)、勾配クリップ、bf16 混合精度(torch.autocast) |
| 評価 | 言語別パープレキシティの集計(トークンごとに言語を割り当てる) | トークンごとの損失 F.cross_entropy、torch.exp |
| 生成 | 自己回帰ループ、temperature、top-p(累積確率で打ち切る処理) | F.softmax・.sort・.cumsum・.scatter_・torch.multinomial |
分かったこと
- 外部ライブラリは 3 つだけです。 サーバを除くと、PyTorch、NumPy、SentencePiece しか使っていません。前処理は、SentencePiece 以外すべて標準ライブラリで書かれています。
- モデルの構造と数式の組み立ては自前です。 RMSNorm、RoPE、SwiGLU、ブロックの構成、重み共有、学習率のスケジュール、top-p の生成は自分で書いています。PyTorch に用意されている出来合いの層(
nn.Transformer、nn.MultiheadAttention、nn.LayerNorm)は使っていません。 - PyTorch に任せているのは、土台の計算です。 テンソル演算、自動微分、AdamW、交差エントロピー、混合精度がこれにあたります。
- 「イチから」という観点で、基盤への依存がいちばん大きいのは 2 か所です。
- トークナイザの学習(SentencePiece)。これは review10 で決めたことです。
- 注意の中核計算(
F.scaled_dot_product_attention)。Q・K・V の射影や RoPE は自前ですが、softmax(QKᵀ/√d)V と因果マスクの計算は PyTorch の実装を使っています。自前の数行に置き換えることもできますが、速度とメモリの面で不利になります。
2 つ目の注意計算は、これまでの決定事項として明示的に確認したことがない点です。「自前実装」の範囲として気になる場合は、自前版に差し替えて、速度と損失を比べることもできます。
2-2. model.py — GPT 本体
| 呼び出し | 用途 |
|---|---|
torch.nn.Module(継承) | すべての層(RMSNorm・Attention・SwiGLU・Block・GPT)の基底クラス |
torch.nn.Parameter | RMSNorm の学習するスケール係数 |
torch.nn.Embedding | トークン埋め込み(語彙 48k × d_model) |
torch.nn.Linear ×6 | Q/K/V の射影、注意の出力射影、SwiGLU の 3 層、LM Head(いずれもバイアスなし) |
torch.nn.ModuleList | Transformer ブロックを層数ぶん並べる |
torch.nn.init.normal_ ×3 | 重みの初期化(標準偏差 0.02。残差に足し込む射影は層数に応じて小さく) |
torch.nn.functional.scaled_dot_product_attention | 因果マスクつきの注意計算 |
torch.nn.functional.silu | SwiGLU の活性化関数 |
torch.nn.functional.cross_entropy | 次トークン予測の損失 |
torch.nn.functional.softmax | 生成時に logits を確率へ |
torch.utils.checkpoint.checkpoint | LM Head + 損失を小分けにし、逆伝播のときに再計算する(logits を持ち続けないため。12GB の VRAM に収める) |
torch.ones / torch.zeros_like | RMSNorm の初期値 / top-p で確率を並べ直す入れ物 |
torch.arange ×2・torch.outer | RoPE の周波数表(位置 × 周波数) |
torch.rsqrt | RMSNorm の逆平方根 |
torch.cat ×2 | RoPE で回転させた前半・後半の結合 / 生成したトークンの連結 |
torch.multinomial | 生成時のサンプリング |
torch.no_grad(デコレータ) | 生成中は勾配を計算しない |
主なテンソルのメソッド:
| メソッド | 用途 |
|---|---|
.view・.transpose・.contiguous・.reshape | head への分割と結合、損失計算のための形の変更 |
.split・.chunk | Q/K/V の切り分け、RoPE の前半・後半、損失の小分け |
.float・.type_as | fp32 に上げて計算し、元の型(bf16)に戻す |
.pow・.mean・.cos・.sin・.unsqueeze | RMSNorm と RoPE の計算 |
.sort・.cumsum・.scatter_・.argmax・.sum・.all | top-p の打ち切り、貪欲選択、終了判定 |
.new_zeros・.numel | 損失の合計の入れ物、パラメータ数・トークン数 |
nn.Module のメソッド: .apply(初期化を全層に適用)、.named_parameters・.parameters。
2-3. data.py — 学習バッチの作成と評価
| 呼び出し | 用途 |
|---|---|
torch.from_numpy ×3 | シャードから切り出したトークン列をテンソルにする |
torch.stack ×2 | 入力(x)と正解(y = 1 つ先のトークン)をバッチにまとめる |
torch.zeros ×2 | 言語別の損失の合計と個数を入れる入れ物(fp64) |
torch.autocast | 評価時の bf16 混合精度 |
torch.nn.functional.cross_entropy | トークンごとの損失(reduction="none"。言語別に集計するため) |
torch.exp ×2 | 平均損失をパープレキシティに変換 |
torch.no_grad(デコレータ) | 評価中は勾配を計算しない |
主なメソッド: テンソルの .to(device)(GPU への転送)・.reshape・.sum・.numel、モデルの .eval・.train(評価と学習の切り替え)。
シャードのどこから切り出すかの選び方(トークン数に比例してシャードを選び、無作為な位置から ctx+1 個)と、 EOS を数えてトークンごとの言語を求める処理は自前のロジック。
2-4. train.py — 学習ループ
| 呼び出し | 用途 |
|---|---|
torch.optim.AdamW | 最適化(β 0.9 / 0.95、weight decay 0.1。CUDA では fused 実装) |
torch.autocast | bf16 混合精度(CUDA のとき) |
torch.nn.utils.clip_grad_norm_ | 勾配クリップ(上限 1.0)。返り値の勾配ノルムをログに残す |
torch.save・torch.load | チェックポイントの保存と再開(モデルの重み・最適化の状態・ステップ数) |
torch.manual_seed | 乱数の種の固定(初期化の再現性) |
torch.device・torch.cuda.is_available | CUDA があれば使う |
主なメソッド:
| メソッド | 用途 |
|---|---|
loss.backward() | 自動微分(全パラメータの勾配を求める) |
opt.step()・opt.zero_grad() | パラメータの更新、勾配の初期化 |
opt.state_dict()・opt.load_state_dict() | 最適化の状態の保存と復元 |
model.to(device)・model.train()・model.state_dict()・model.load_state_dict() | GPU への配置、学習モード、重みの保存と復元 |
.item() | 損失を数値として取り出す(ログ用) |
p.dim() | weight decay をかける対象の判定(2 次元以上の重みだけ) |
学習率のスケジュール(線形ウォームアップ → cosine 減衰、最終は 10%)は、PyTorch のスケジューラを使わず自前の式で書いている。
2-5. eval.py / sample.py
| ファイル | 呼び出し | 用途 |
|---|---|---|
| eval.py | torch.load・torch.device・torch.cuda.is_available | チェックポイントを読み、val / test の言語別パープレキシティを出す(計算は data.py の評価を使う) |
| sample.py | sentencepiece.SentencePieceProcessor | 48k モデルの読み込み |
| sample.py | .encode・.bos_id / .decode | プロンプトをトークン列に / 生成したトークン列を文章に戻す |
| sample.py | torch.tensor・torch.manual_seed・torch.device・torch.cuda.is_available | プロンプトをテンソルに、サンプリングの乱数の固定 |
config.py(S / M / L の構成の定義)と fetch_shards.py(API からのシャード取得)には、LLM 学習に直接かかわる基盤の呼び出しはない。
3. まとめ
| モジュール | 基盤 | 基盤に任せている中核 | 自前で書いている中核 |
|---|---|---|---|
zxell_prep/ | SentencePiece | BPE の学習、エンコード、デコード | 学習ファイルの配分、正規化、重複除去、言語別の分割、シャッフル、シャード化、検証 |
zxell_model/ | PyTorch(+ 生成時のみ SentencePiece) | テンソル演算、自動微分、AdamW、注意の中核計算、交差エントロピー、混合精度 | モデルの構造(RMSNorm・RoPE・SwiGLU・ブロック・重み共有)、学習率スケジュール、バッチの作り方、言語別評価、生成(top-p) |
「イチから」の観点で基盤への依存がいちばん大きいのは 2 か所:
- トークナイザの学習(
SentencePieceTrainer.train)。review10 で決めたこと。 - 注意の中核計算(
F.scaled_dot_product_attention)。Q・K・V の射影や RoPE は自前だが、softmax(QKᵀ/√d)V と因果マスクは PyTorch の実装。同じ計算を自前の数行(行列積 + マスク + softmax)に置き換えられるが、速度とメモリで不利になる。
zxell.ai