【体験談】num_ctxを上げたら、長文入力時にLLMが同じ文章をループし始めた話

IT

時系列で振り返る、ある一週間の記録

1日目。Ollamaで動かしている日本語LLM(Nemotron系、Q5_K_M量子化)に、長めの文章を入力するテストを重ねていた。入力が短いうちは何の問題もない。だが、入力テキストが2万文字を超えるあたりから、様子がおかしくなり始めた。

生成結果の後半で、同じような言い回しの文章が延々と繰り返される。一度同じフレーズが出始めると、そこから抜け出せずにループし続ける、いわゆる degeneration loop(退化ループ)のような現象だった。

2日目。まず疑ったのは入力テキストの中身そのものだった。特定の言い回しや表現がモデルを混乱させているのではと考え、問題が起きた入力を削って別のテキストに差し替えてみた。しかし結果は同じ。文字数がある一定のライン(だいたい25,000文字前後)を超えると、入力の中身に関わらず同じ症状が再現された。

ここで「入力の内容」ではなく「入力の長さ」そのものが原因ではないかという方向に切り替えた。

3日目。num_ctx(コンテキスト長)の設定を確認した。当時の設定はデフォルト値に近い、比較的小さい値のままだった。入力テキスト + プロンプト + 生成テキストの合計トークン数が、このnum_ctxの上限を超えた時点で、古い部分から情報が切り捨てられていく。これによってモデルが文脈を見失い、直前に生成した文章の一部を繰り返すような挙動に陥っているのではないかと仮説を立てた。

4日目。num_ctxを大幅に引き上げてみることにした。ただし、ここで新たな問題にぶつかる。num_ctxを上げると、それに比例してKVキャッシュのメモリ使用量も増える。Tesla P100(12GB VRAM)ではLLM自体のロードだけで7〜8GBを消費しているため、num_ctxを上げすぎるとVRAMを使い切ってOOM(Out of Memory)で落ちるようになった。

5日目。num_batchやnum_parallelといった周辺パラメータも同時にいじっていたことが、状況をさらに複雑にしていた。num_parallelを2以上にしていると、並列実行のたびにKVキャッシュ領域が複数確保されるため、単純にnum_ctxだけを見ていても説明のつかないVRAM消費が発生していた。ここでようやく、num_ctxとnum_parallelの掛け算でVRAM消費が決まるという構造に気づいた。

6日目。num_parallelを1に固定し、num_ctxだけを段階的に引き上げながらVRAM使用量を計測する検証を行った。10000、20000、30000、40000と試した結果、40000あたりが「25,000文字クラスの長文でも文脈を保持でき、かつVRAMにも収まる」現実的な上限だと分かった。

7日目。最終的に num_ctx 40000 / num_parallel 1 という構成に落ち着け、長文入力でのループ現象は再現しなくなった。VRAM使用量もおよそ10GB程度に収まり、12GBという上限の中でなんとか成立するギリギリのラインだった。

分かったこと

  • degeneration loop(同じ文章の繰り返し)は、モデル自体の不具合というより、コンテキスト長の上限を超えて古い情報が失われることで文脈が崩れて起きるケースがある
  • num_ctxを上げれば解決する一方で、VRAM消費とのトレードオフが常について回る
  • VRAM消費は num_ctx 単体ではなく、num_ctx × num_parallel でほぼ決まる。num_parallelを疑わずにnum_ctxだけを見ていると、原因の切り分けを誤る
  • 症状が出る文字数のボーダーライン(今回で言えば約25,000文字)を先に特定してから、num_ctxをそのライン+αに調整するというアプローチが効率的だった

結局のところ、VRAM 12GBという枠の中で num_ctx と num_parallel のバランスを取り続ける作業に、しばらく終わりは来なさそうだ。

コメント

タイトルとURLをコピーしました