実験日: 2026-08-24
GPU: RTX 5070 Ti 16GB / WSL2 / Ollama 0.32.15
Model: Gemma 3 4B Q4_K_M
Ollamaのnum_ctxを大きくすると、長い論文やcodeを一度に読ませられます。しかし、contextを16Kへ設定しただけでは長文性能を測ったことになりません。実際に何token入力したか、必要VRAMが増えたか、先頭の情報を取り出せたかを分けて確認する必要があります。
とりあえず16Kへ設定しても、実際の入力が短ければ長文性能の確認にはなりません。
Gemma 3 4B Q4_K_Mへ約2.9K、5.7K、11.2K tokenのsynthetic研究logを入力し、秘密codeを先頭・中央・末尾へ置きました。4K・8K・16Kの全9条件でcodeを取得できました。loadを除いた最初の回答までの中央値は0.373、0.563、1.019秒、GPU peakは4,783、5,015、5,189MiBでした。
context設定を4倍にしても、このmodelと実装では総GPU使用量の増加は406MiBです。ただし、これはGemma 3のlocal/global attention構造、Q4 model、Ollama 0.32.15、単一requestの結果です。他modelへそのまま当てはめられません。
4K・8K・16Kの結果
| num_ctx | 実prompt token | 秘密code取得 | load除外TTFC | prompt処理速度 | peak GPU used |
|---|---|---|---|---|---|
| 4,096 | 2,873 | 3/3 | 0.373秒 | 7,935 tok/s | 4,783MiB |
| 8,192 | 5,663 | 3/3 | 0.563秒 | 10,339 tok/s | 5,015MiB |
| 16,384 | 11,244 | 3/3 | 1.019秒 | 11,278 tok/s | 5,189MiB |
このPCで普段の短いchatをするだけなら4Kで十分です。複数fileや長い論文断片を投入するときだけ8K、16Kへ上げます。大きいcontextは無料ではなく、入力を読む待ち時間とmemoryを増やすからです。

context windowは会話の作業領域
LLMは入力tokenと生成済みtokenをcontext window内で扱います。概念的には次の制約があります。
input tokens + output tokens + template等のoverhead <= context window
num_ctx=4096は「4,096文字」ではありません。tokenは文字より細かい場合も、複数文字をまとめる場合もあります。日本語、英語、数字、codeで文字数/token比は変わります。
またnum_ctx=16384へ設定しても、短いpromptを送れば実際のinputは短いままです。context capacityと実prompt lengthを区別します。
KV cacheは何を保存するのか
Transformerは過去tokenへattentionします。生成のたびに過去のkey/valueを最初から再計算すると無駄なので、各layerのkeyとvalueをcacheします。これがKV cacheです。
単純なfull attention modelなら、KV cacheの概算は次の要素へ比例します。
KV cache ∝ layers × context tokens × KV heads × head dimension × 2(K,V) × bytes
contextを2倍にするとKV部分も概ね増えます。ただし実modelはGrouped-Query Attention、sliding-window attention、KV量子化などを使う場合があり、全VRAMが単純に2倍になるわけではありません。weightはcontext長に関係なく大部分を占めます。
Gemma 3はlocalとglobal attentionを混ぜる
Google DeepMindのGemma 3 Technical Reportでは、local sliding-window self-attentionを5 layer、その後global self-attentionを1 layerという5:1 patternで交互に使うと説明されています。
local layerは無制限に全過去tokenを見るのではなく、近傍windowを中心に見ます。global layerは長距離情報を扱います。Gemma 3 model cardでは4B、12B、27Bが128K contextに対応します。
今回4Kから16Kでmemory増加が比較的小さかったことと、このarchitectureは整合します。しかし、実験はOllama内部のlayer別KV allocationを直接測っていません。「5:1構造だけが406MiB増の原因」と断定はできません。
実験環境とmodel
Windows 11 + WSL2 Ubuntu
NVIDIA GeForce RTX 5070 Ti 16GB
driver 595.71
Ollama 0.32.15
gemma3:4b-it-q4_K_M
temperature 0 / seed 42 / think false
前記事のQ4/Q8比較でQ4_K_MはQ8_0より約25%高速、約1.5GiB低memoryでした。今回はcontext costを見やすくするためQ4を固定しました。
実際にcontextの約70%を埋める
recordは次の形式です。
LOG 00042 | sensor=S08 | status=normal | value=0545 | note=no anomaly.
ただ同じ単語をコピーするだけでなく、番号、sensor、valueを変えました。まず100 recordをAPIへ送り、実tokenizerでprompt_eval_count=3,179を得ました。
estimated tokens per record = 3,179 / 100 = 31.79
この値から各contextの70%を目標にrecord数を決めます。
record_count = int(num_ctx * 0.70 / tokens_per_record)
実際にはtemplate、instruction、秘密recordのoverheadがあるため、最終値はAPIのprompt_eval_countを採用します。
num_ctx 4,096 90 records 2,873 tokens
num_ctx 8,192 180 records 5,663 tokens
num_ctx 16,384 360 records 11,244 tokens
どれも設定の約68.6~70.1%です。inputと短いoutputの余裕を残し、意図しない切り捨てを避けました。
needleを先頭・中央・末尾へ置く
各promptへ1つだけ秘密recordを入れます。
IMPORTANT RECORD | SECRET_CODE=CTX16384-BEGINNING-7319 | preserve this exact code.
挿入位置は次の3種類です。
- beginning: 通常logより前
- middle: 通常logの中央
- end: 通常logの後
最後に質問します。
QUESTION: IMPORTANT RECORDのSECRET_CODEは何ですか。
説明せずcodeだけを正確に出力してください。
ANSWER:
回答文字列に完全なcodeが含まれる場合だけ成功です。意味が近い、数字が1桁違う、といった曖昧な採点はしません。
prefix cacheを切って測る
Ollamaは直前のprompt prefixやKV cacheを再利用できる場合があります。同じsynthetic logを続けて送ると、2回目以降のprompt評価が不自然に速くなる可能性があります。
そこで9条件すべてで直前にmodelをunloadしました。
unload(model) # keep_alive=0
run_streamed(prompt, num_ctx=context)
model loadはAPIのload_durationとして分離できます。stream開始から最初の本文までのwall timeからload durationを引いた値を、この記事では「load除外TTFC」と呼びます。
これは厳密な内訳ではありません。並列処理やtiming境界の差を含む近似ですが、contextを読むcostを見る実用指標になります。
先頭・中央・末尾の9/9で取得できた
実際の回答です。
CTX4096-BEGINNING-7319
CTX4096-MIDDLE-7319
CTX4096-END-7319
CTX8192-BEGINNING-7319
CTX8192-MIDDLE-7319
CTX8192-END-7319
CTX16384-BEGINNING-7319
CTX16384-MIDDLE-7319
CTX16384-END-7319
今回の最大11,245 tokenでも、先頭のneedleを失いませんでした。Gemma 3のglobal attention layerが長距離情報を運べる設計と整合します。
しかし、このtestは非常に簡単です。秘密codeは1件で、質問も明示的、distractorに似たcodeはありません。9/9成功は次を証明しません。
- 長い論文を正しく要約できる
- 複数箇所の因果関係を統合できる
- 多数の似たIDから正しい1件を選べる
- 16Kの全位置で常に正確
needle retrievalは「情報が届くか」のsmoke testです。長文理解の最終benchmarkではありません。
入力が約4倍で最初の回答まで約2.7倍
実prompt tokenとload除外TTFCです。
2,873 tokens → 0.373 s
5,663 tokens → 0.563 s
11,244 tokens → 1.019 s
promptは3.91倍、TTFCは2.73倍です。完全比例より緩く見える理由の1つは固定overheadです。短いpromptではrequest、runner、GPU dispatchなどの固定costが相対的に大きくなります。
prompt evaluation速度の中央値も増えました。
4K setting 7,935 input tok/s
8K setting 10,339 input tok/s
16K setting 11,278 input tok/s
長い入力でGPUを継続的に使い、固定overheadが薄まった可能性があります。ただし各contextは位置3回だけです。温度、電力状態、background processでも変わるため、長いほど常にtok/sが上がるとは一般化しません。
GPU peakは4Kから16Kで406MiB増えた
nvidia-smiを50ms間隔でsampleしたGPU全体のpeakです。
num_ctx 4,096 4,783 MiB
num_ctx 8,192 5,015 MiB (+232 MiB)
num_ctx 16,384 5,189 MiB (+174 MiB)
4Kから16Kで+406MiB、約8.5%増です。weightやruntimeの固定部分が大きく、context-dependent部分はその一部でした。
Ollama /api/psのsize_vramも記録しました。
4K 2.68 GiB
8K 2.82 GiB
16K 2.84 GiB
nvidia-smiとの差には、Ollamaがmodel sizeとして報告しないCUDA/runtime領域や他processなどが含まれます。2つの値は測定対象が違うため、どちらかが間違いなのではありません。
contextを大きくしても短いpromptは賢くならない
num_ctx=16384はcapacityを増やしますが、同じ短い質問への回答品質を自動で上げません。むしろmemoryを予約し、modelや実装によっては速度を下げます。
contextを増やすべき場面です。
- 論文本文と質問を同時に入れる
- 複数sourceをRAGで渡す
- 長い会話履歴を保持する
- repositoryの複数fileを読ませる
増やさなくてよい場面です。
- 1問1答の短いchat
- 数十行のcode補完
- RAGで必要箇所を十分絞れている
- VRAMへ別modelや画像処理も載せたい
「最大contextを常に設定」ではなく、input token分布の上位percentileを測って決めます。
自分のPCで再現する
cd /mnt/c/Users/user/Documents/Codex/2026-08-24/ko
python3 work/ai_lab/experiment_ollama_context_lengths.py
結果です。
work/ai_lab/results/ollama_context_lengths.json
JSONには全9runのprompt token、prompt eval duration、response、needle成否、GPU sample、/api/psを保存します。記事の表だけでなく、position別のraw dataまで追試できます。
自分のdocumentで試す場合は、synthetic logをそのまま信用せず次の段階へ進みます。
- 実PDFやcodeをtext化する
- 入力tokenをAPIで記録する
- 先頭・中央・末尾から検証可能な質問を作る
- distractorを追加する
- 複数seedまたは複数prompt表現で繰り返す
- 正答率、TTFC、VRAMを一緒に比較する
今回の限界
- Gemma 3 4B Q4_K_Mだけ
- 4K、8K、16Kだけで128K上限は未検証
- synthetic log 1形式、秘密code 1件/request
- 各contextのpositionは3 runだけ
- 単一requestで並列負荷なし
- nvidia-smiはGPU全体のmemory
- load除外TTFCはwall timeとAPI durationの差による近似
- 16Kで成功しても一般的な長文reasoning性能を示さない
まとめ
- 実promptは2,873 / 5,663 / 11,244 token
- beginning・middle・endの秘密codeを全9条件で取得
- load除外TTFC中央値は0.373 / 0.563 / 1.019秒
- promptを約3.9倍にしても最初の回答待ちは約2.7倍だった
- peak GPU usedは4,783 / 5,015 / 5,189MiB
- 4Kから16KのGPU増加は406MiB
- Gemma 3の5:1 local/global attention構造と整合するが、因果は直接分解していない
num_ctx設定値と実prompt tokenを分けて記録する必要がある
16GB GPU上のGemma 3 4Bでは16K contextも余裕を持って動きました。ただし実用性を判断するには、contextをさらに大きくするより、実際の論文やcodeを使って複数箇所を統合できるかを評価する必要があります。
