Skip to content

pad_token無しモデルでfinish_reasonが常にlengthになる問題を修正 - #296

Merged
junya-takayama merged 1 commit into
mainfrom
fix/hf-lm-finish-reason-padless
Jul 23, 2026
Merged

pad_token無しモデルでfinish_reasonが常にlengthになる問題を修正#296
junya-takayama merged 1 commit into
mainfrom
fix/hf-lm-finish-reason-padless

Conversation

@kiakiraki

@kiakiraki kiakiraki commented Jul 19, 2026

Copy link
Copy Markdown
Contributor

問題

HuggingFaceLM で pad_token を持たないトークナイザ(GPT-2系・Llama系など)を使うと、tokenize_text_for_lm_prefixpad_token = eos_token にフォールバックします。このとき _batch_complete_text の後処理に2つの問題がありました。

  1. 出力側: 生成結果から t != pad_token_id で全 pad を除去するため、pad==eos の場合は生成を止めた本物の EOS トークンまで除去される。その結果、後段のテキストレベル stop 検索が絶対に成立せず、EOS で正常終了しても finish_reason が常に "length" になる。FinishReasonCount は全生成系セットアップに自動付与されるため、該当モデルでは finish_reason_ratio-* メトリクスがそのまま間違う。
  2. 入力側: 同じ値ベースのフィルタが、プロンプト中に本物の EOS トークンが含まれるケース(chat template のターン区切りなど)でそれも除去してしまい、decode_for_lm_continuation の境界計算が狂って出力テキストが破損し得る(SentencePiece 系では先頭スペースの欠落として顕在化)。

修正内容

finish_reason の判定をテキストレベルからトークンレベルに移しました。

  • 出力側: output_tensor 中で最初に stop_token_ids のトークンが現れる位置を探し、見つかれば finish_reason="stop" としてそれ以降(stop トークン+パディング)を破棄。generate の仕様上、生成領域で stop トークンが現れるのは生成停止位置だけなので、pad==eos でも最初の出現位置は必ず本物の停止位置です。見つからなければ従来どおり "length"(専用 pad モデル向けに pad 除去フィルタは防御として維持)
  • 入力側: 左パディングの除去を attention_mask ベースに変更し、プロンプト中の本物の EOS を保持
  • テキストレベルの stop 検索ループは維持(複数トークンからなる stop 文字列は _get_stop_token_ids が token id 化しないため、引き続き必要)

専用 pad トークンを持つモデルの挙動は完全に不変です。テキスト出力も全ケースで不変で、変わるのは pad 無しモデルの finish_reason のみです。

テスト

model.generate をスタブ化し、既知のテンソル(生成トークン+EOS+パディング)を返させて後処理を決定的に検証する方式で4件追加しました。トークナイザは既存テストで使用実績のある tokyotech-llm/Swallow-7b-instruct-hf(pad_token 無し)に統一しています。モデル本体はスタブなので重みのダウンロードは発生しません。

テスト 修正前 修正後
pad 無し tokenizer で EOS 停止 → "stop" 'length' == 'stop' で fail
EOS 無しで max_new_tokens 到達 → "length"
バッチ内混在(早期停止+完走)
プロンプト内 EOS でテキスト非破壊 'です。' == ' です。' で fail

tests/core/language_model/test_hf_lm.py 全体で 76 passed、既存テストの回帰なし。ruff check / format パス。

相談: 実生成でのエンドツーエンド検証について

本 PR のテストは model.generate をスタブ化した後処理の検証のみです。実生成でこのバグを再現するには「pad_token を持たない実モデル」が必要ですが、既存テストで実ロードしているモデル(sbintuitions/tiny-lm 系)は専用 <pad> トークンを持つため再現できません(まさにそれが原因で本バグは既存テストをすり抜けていました)。

実生成テストを追加するなら sshleifer/tiny-gpt2 のような外部の極小 pad 無しモデルの導入が必要になります。外部モデルをテストに追加するか、スタブ検証のみで許容するか、ご判断をお願いします。

🤖 Generated with Claude Code

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
@kiakiraki
kiakiraki marked this pull request as ready for review July 19, 2026 02:58

@junya-takayama junya-takayama left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM!ありがとうございます!

@junya-takayama
junya-takayama merged commit 8a07c3c into main Jul 23, 2026
8 checks passed
@junya-takayama
junya-takayama deleted the fix/hf-lm-finish-reason-padless branch July 23, 2026 07:11
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants