review20: 「val/test が 100% 日本語」問題のかみ砕き説明と分割方針の提案 / ja 連結の重複除去を実装(ja 文字数 −12%)/ tokenizer_report.md 再生成
作成日: 2026-09-27 対象: review19 確認事項 1(val/test 分割)へのご質問と、9/20 に持ち越した 2 件(ja 連結の重複対策、 tokenizer_report.md の再出力)への対応。
要旨
- 「val/test が日本語だけ」が困る理由をかみ砕くと: 英・独・仏の記事が 1 件残らず教科書(train)側に入ってしまい、「初見の文章でどれだけ当てられるか」を測る問題用紙が日本語しか無い、ということです(2 章)
- 原因を掘ると新事実: en/de/fr の収集は 2023-05-28 に同日で止まり、ja だけ 2024-02 まで続いていた。単一の日付で末尾を切れば、日本語しか残らないのは必然でした(3 章)
- 分割方針は A'(言語別・記事数ベースで末尾を切る)を推奨します。review19 の A(言語別・3 か月)は en の test が 26.6 万記事(6.7%)と過大になるため修正しました(4 章)
- ja 連結の重複除去を実装・コミット済み。ja の全記事で文字数 −12.06%(4.57 億字 → 4.02 億字)。 title の重複は記事の 87.5% で発生していました(5 章)
- トークナイザの比較レポートを再生成しました(6 章)
- ついでに HTML 残骸の規模を調べたところ 無視できる量(タグ付き本文 0.005%)でした(7 章)
確認事項 1〜3(10 章)にご回答いただければ、再エンコード(約 2 時間)を 1 回で済ませます。
1. 前提: train / val / test の役割
| 分割 | 役割 | たとえ |
|---|---|---|
| train | モデルが学習する(何周も読む) | 教科書 |
| val | 学習の途中で「ちゃんと伸びているか」「過学習していないか」を測る | 模擬試験 |
| test | 学習が終わってから、最終成績を 1 回だけ測る | 本番の試験 |
val/test は「モデルが一度も見ていない文章」でなければ意味がありません。 教科書と同じ問題を出せば、丸暗記で満点が取れてしまい、本当の実力(初見の文章への強さ)が分からないからです。
2. 「言語別パープレキシティ / en·de·fr の要約評価が測れない」をかみ砕く
2-1. パープレキシティとは
言語モデルは「次の単語(トークン)は何か」を確率で予想します。 パープレキシティ(PPL)は「次のトークンを当てるとき、平均して何択で迷っているか」を表す数字です。 PPL 20 なら「毎回 20 択くらいの迷い」、PPL 5 なら「5 択まで絞れている」。小さいほど賢い。
これを 言語別に測りたいのが成功基準 1.2 の「検証パープレキシティ(言語別)」です。英語は PPL 15 だが日本語は 40、のように、言語ごとの得意・不得意を数字で見るためです(日本語はデータがトークンベースで 3.7% しかないので、そこが弱点になると予想しており、それを定量的に確認したい)。
2-2. 何が起きているか
現在のシャード:
train: 123 シャード … en / de / fr / ja が全部入っている
val : 1 シャード … ja 100%(2,667 記事)
test : 1 シャード … ja 100%(8,734 記事)
つまり 英・独・仏の記事は 1 件残らず train(教科書)側にあります。すると:
- 英語の PPL を測ろうとしても、英語の「初見の文章」が 1 件もありません。 train から英語記事を取り出して測れば数字は出ますが、それは「教科書の丸暗記度」であって実力ではない(学習が進むほど train の PPL は下がり続けるので、いくらでも良い数字が出る)
- 日本語だけは初見の文章があるので、日本語の PPL だけは正しく測れます
- 要約評価(成功基準の 2 行目)も同じです。「本文を読ませて要約させ、付属の description と比べる」評価は、本文が train に入っていれば「description を暗記していただけ」と区別できません。en/de/fr の要約能力は測れません
一言でいえば 「4 言語のモデルを作ったのに、成績表に載せられる科目が日本語だけ」という状態です。成功基準 1.2 の「単一マシン学習比で劣化 10% 以内」を言語別に示すには、4 言語すべてに初見の問題用紙が要ります。
2-3. 副次的な問題
- 日本語の val/test も 2023-10〜2024-02 の 4 か月だけからの抜き出しなので、時期が偏っています (この期間に多いトピック — たとえば特定の政治ニュース — の当てやすさが成績に混ざる)
- 分散学習の比較実験(フェーズ 2〜3)は「方式 X と方式 Y でどちらの val 損失が低いか」で判定します。 val が日本語 3.7% 分の代表にしかなっていないと、分散方式の優劣判定そのものが日本語の出来に左右されます。ここが実は一番効く影響です
3. 原因を掘ったら分かったこと: en/de/fr は 2023-05-28 に一斉停止していた
言語別に pub_date の終端を実測しました(全 797 万件走査):
| 言語 | 記事数 | 最終 pub_date | 終盤の月間記事数 |
|---|---|---|---|
| en | 3,978,459 | 2023-05-28 | 約 62,000〜73,000 件/月(健全なまま終了) |
| de | 2,028,035 | 2023-05-28 | 約 33,000〜41,000 件/月 |
| fr | 1,115,924 | 2023-05-28 | 約 15,000〜19,000 件/月 |
| ja | 846,818 | 2024-02-12 | 約 2,600〜3,400 件/月 |
en/de/fr は同じ日に、勢いを保ったまま突然終わっています。 先細りではなく、 2023-05-28 に(欧文フィード側の収集だけが)止まったと読めます。ja は 2024-02 まで 9 か月弱、単独で続いた。
review19 の「末尾 3 か月 + 1 か月」という全言語共通の日付で切ると、その期間(2023-10 以降)に記事があるのは ja だけなので、val/test が 100% 日本語になるのは必然でした。設計ミスというより、「収集停止のタイミングが言語で違う」というデータの事実に、単一境界の設計が合っていなかった、ということです。
4. 分割方針の提案
4-1. review19 の案 A(言語別・末尾 3 か月)をそのまま適用すると
| 言語 | test 期間 | test 記事数(概算) | train からの流出 |
|---|---|---|---|
| en | 2023-02-26〜05-28 | 約 266,000 | 6.7% |
| de | 同 | 約 146,000 | 7.2% |
| fr | 同 | 約 68,000 | 6.1% |
| ja | 2023-11-13〜2024-02-12 | 約 9,900 | 1.2% |
評価に 26 万記事は要りません(数千記事・数 M トークンで十分に安定します)し、 en/de/fr の学習データを 7% 捨てるのはもったいない。よって修正します。
4-2. 推奨: 案 A'「言語別に、時系列の末尾から記事数で切る」
- 各言語について、pub_date の新しい側から test = 8,000 記事、その直前 val = 3,000 記事を取り、残りを train
- 「新しい記事で評価する」という元の設計意図(roadmap 5 章)は言語ごとに保たれる
- 4 言語の val/test サイズが揃う(PPL の比較がフェアになる)
- train からの流出は言語あたり 11,000 記事(en で 0.3%、ja で 1.3%)と小さい
- ja の test は現状(8,734 記事)とほぼ同規模なので、日本語側の評価条件は変わらない
| 案 | val/test の多言語性 | 時系列の意図 | train の流出 | 再エンコード |
|---|---|---|---|---|
| A'(推奨) 言語別・記事数 | ◎ 4 言語同サイズ | ○ 各言語の最新記事 | 極小(0.3〜1.3%) | 必要(約 2 時間) |
| A 言語別・3 か月 | ◎ | ○ | 大(en 6.7%) | 必要 |
| B 記事単位ランダム | ◎ | × 捨てる | 任意 | 必要 |
| C 現状維持 | × ja のみ | ○ | 極小 | 不要 |
実装は小さいです: boundaries.json を言語別の {lang: {val_start, test_start}} にし(記事数から日付を逆算するスクリプトを追加)、tokenize_full.py の分割判定を言語別に参照するだけ。 再エンコードは 5 章の ja 重複除去(と 7 章の HTML 除去を採るならそれも)と同時に 1 回で済ませます。
5. 「2.」ja 連結の重複除去 — 実装・実測済み
5-1. 実装(コミット 04c46b5、push 済み)
- 共通モジュール
zxell_prep/textprep.pyを新設し、clean()とcompose_ja()を置いた。extract_sample.py(トークナイザ学習サンプル)とtokenize_full.py(全量)が同じ関数を使う(両者で文の作り方が食い違うと圧縮効率の見積りが狂うため) compose_ja(title, description, content): まず description が content の冒頭付近に既にあれば省く → 次に title が(残った)テキストの冒頭付近に既にあれば省く。 description 末尾の「…」切り詰めは無視して比較。10 字未満の短い断片は偶然一致を避けるため判定しない- 両スクリプトの stats に
ja_parts_dropped(省いた部位の件数)を出力
5-2. 効果の実測(ja 全 846,818 記事)
| 項目 | 値 |
|---|---|
| 旧連結の総文字数 | 456,795,403 |
| 新連結の総文字数 | 401,686,737 |
| 削減率 | −12.06% |
| title を省いた記事 | 741,184(87.5%) |
| description を省いた記事 | 244,812(28.9%) |
| 両方省いた記事 | 244,220(28.8%) |
ja 記事の 87.5% で「本文が title から始まっている」、約 29% で「description が本文冒頭の写し」でした。削減分 5,500 万字はまるごと重複だったので、再エンコード後の ja トークン数は 0.23B → 約 0.20B になり、 日本語の学習トークンの中身が 12% 濃くなることになります(同じ文を 2 回読ませても学習効率は上がらないため)。
補足: 短い title(10 字未満)は対象外にしているため、そこだけは重複が残ります。実データの ja title で 10 字未満は少数なので実害はありません。
6. tokenizer_report.md の再生成
トークナイザの比較レポートを再生成しました。(省略: 原版が失われた経緯(サーバ障害)) 9/5 の再学習結果は 8/13 と小数第 3 位まで一致しているので内容は等価です。原版より増えた項目: 語彙 48,000 ピースの文字種構成(ラテン 61% / 日本語系 37%)、4 言語の分割実例、既知の注意点(5・7 章の件を反映)。
7. ついでに見つけた HTML 残骸 — 規模は無視できる
compose_ja の動作確認で覗いた ja の最初の記事(省略: 媒体名)の本文に <p><img src=…> が生で入っていたため、先頭 100 万行で規模を調べました:
| 言語 | タグ入り本文 | HTML エンティティ(& 等)入り |
|---|---|---|
| en | 25 件(0.00%) | 0.28% |
| de | 5 件 | 0.01% |
| fr | 19 件(0.04%) | 0.03% |
| ja | 3 件 | 0.00% |
合計 52 件 / 100 万件 = 0.005%。 特定の数チャンネル(省略: チャンネル番号)に偏っています。学習への実害はほぼありませんが、対処コストもほぼゼロ(clean() にタグ除去とエンティティ復号を 2 行足すだけ)なので、再エンコードに同乗させることを提案します(確認事項 2)。
8. その他
peek_shard.py(9/20)がそのまま今回の発見(重複・HTML)に効きました。「学習データは目で見る」は今後も習慣にします- コーパスの実効期間は en/de/fr: 〜2023-05-28、ja: 〜2024-02-12 と判明。サイト・レポートでの記述に反映が必要になったら直します
10. 確認事項
- val/test の分割方針: 案 A'(言語別・末尾から test 8,000 記事 + val 3,000 記事)で進めてよいですか? 記事数を変えたい場合はご指定ください(評価の安定性の観点では test 5,000 以上を推奨)。
- HTML 残骸の除去(タグ除去 + エンティティ復号)を再エンコードに同乗させますか?(推奨: はい)
- 再エンコードの実行許可(約 2 時間 = encode 70 分 + シャード化 50 分)。現行の 125 シャードは
shards_v1/にリネームして保管し、新シャードをshards/に出す想定です(ディスクの空きは十分なので両方置けます。不要になったら v1 を消します)。
11. 次の作業予定
- 確認事項 1〜3 の回答 → 言語別 boundaries の算出スクリプト +
tokenize_full.pyの分割判定改修 → 再エンコード - 新シャードの検証(言語構成が 4 言語揃った val/test になっていること、sha256 抜き打ち)→ 短報
- S(30M)モデルの実装(モデル定義・学習ループ・チェックポイント・評価ハーネスの PPL 部分)
- RTX 3060 機のクライアント環境(PyTorch CUDA)→ S ベースライン学習開始
zxell.ai