0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

【DGX Spark】Qwen3.8-27B に妥協して、そこから改良した記録 — TensorFold 実運用チューニング

0
Posted at

前シリーズ(構築編/不安定化の切り分け編/3モデル比較編)の続きです。
1台の DGX Spark(GB10, 128GB ユニファイドメモリ)で TensorFold + LiteLLM + opencode を運用。
前編「[Qwen3.8-Flash-Next と格闘した記録]」で Flash-Next のループに敗れ、常用を Qwen3.8-27B に妥協。
そこから 運用基盤・サンプリング・高速化を詰めて、結果的に「正解」に落ち着いた記録です。
数値は手元1台の実測。IP・ホスト名・認証情報はプレースホルダに置き換えています。


TL;DR

  • Flash-Next を諦め Qwen3.8-27B(MLX 4-bit + DFlash2) を常用に。安定・速度・素直さで正解だった。
  • サンプリングは公式準拠(thinking/non-thinkingで値が別。非thinkingは presence_penalty=1.5)。
  • 高速化で効いたのは --prefill-fp8(prefill +33%) と --checkpoint-slots+--spill-gib(prefix保持)。
  • 効かなかったのは --mtp-drafts/--drafter-bits(受入数が完全同一=投機の追加チューニングは無効)。
  • イメージは Python系 v0.6.6 が正解(ネイティブZig v1.0.x は27B未移植+Pythonより遅い)。
  • 運用の落とし穴は docker compose の profile と logs(profile配下は logs に出ない)。

1. なぜ 27B に落ち着いたか

前編の結論(Flash-Next は fast でループ)を受け、常用を 27B に切替。結果:

モデル 能力 速度 安定/使い勝手
Qwen3.8-27B(採用) 中〜高 速い ◎(枯れている)
Qwen3.8-Flash-Next 高 長文脈で健闘 △(fastループ、think前提)
  • 27B は dense 27B。MLX 4-bit + DFlash2 で単機でも実用的な速度。
  • 短文脈で decode ~148 tok/s、長文脈(150k超)で ~50 tok/s(denseは文脈長でKV読みが増える)。
  • 素直に指示に従う(ループしない)。エージェント用途では「賢さ」より「素直さ」が効く。

「妥協」と書きましたが、常用の安定性では27Bが最良のデフォルトでした。


2. 運用基盤: profile切替と docker compose logs の罠

1GPUなので「同時に1モデル」。compose の profile で切替ます。

services:
  tensorfold:            # 既定 = Qwen3.8-27B (container: tensorfold)
  tensorfold-flashnext:  # profiles: ["flashnext"]
  tensorfold2:           # profiles: ["tf36"] = Qwen3.6-35B-A3B
cd /opt/docker/TensorFold
docker compose up -d                                                    # 27B(既定)
docker compose stop tensorfold && docker compose --profile flashnext up -d tensorfold-flashnext
docker compose stop tensorfold && docker compose --profile tf36 up -d tensorfold2

落とし穴: docker compose logs -f はprofile未指定だと profile配下のサービスを出さない。

  • 稼働中モデルが profile配下だと、logs が空に見える(「起動しているのにログが出ない」)。
  • 対策: 既定サービスを常用モデルに固定し、コンテナ名を固定(tensorfold)。
    あるいは docker compose --profile <name> logs -f <svc>。

3. opencode 側のチューニング

opencode.jsonc を調整しました。

項目 変更 意図
compaction.buffer 8000 → 48000 出力トークン(32768)を含めても上限超過しないよう余白確保
limit.context サーバ窓に整合(例 240000) 宣言が実容量を超えると「too long → 圧縮」多発
small_model 停止中のホスト → 稼働中 title生成などの補助タスク失敗を解消
headerTimeout/chunkTimeout 既定(5分) → 600000/900000 ms 長い prefill でも切れにくく
  • 症状の多くは 「コンテキスト上限超過の BadRequest」 と 「停止ホスト宛の接続失敗」 でした。

4. サンプリングは「公式準拠」が最重要(前編の反省を27Bにも)

Qwen3.8(27B / Flash-Next 共通)のモデルカードの推奨値に統一します。

  • Thinking: temperature=1.0, top_p=0.95, top_k=20, min_p=0.0, presence_penalty=0.0, repetition_penalty=1.0
  • Instruct(非thinking): temperature=0.7, top_p=0.80, top_k=20, min_p=0.0, **presence_penalty=1.5**, repetition_penalty=1.0

litellm と opencode の両方を公式値に統一。

# litellm-config.yaml(非thinkingルートの例)
extra_body:
  chat_template_kwargs:
    enable_thinking: false
  temperature: 0.7
  top_p: 0.8
  top_k: 20
  min_p: 0.0
  presence_penalty: 1.5
  repetition_penalty: 1.0

教訓: 推論パラメータは体感でなく公式カードで突き合わせる。特に non-thinking の presence_penalty は見落としやすい。


5. 高速化の実測(27B)

TensorFold の27Bで各フラグを測定しました。

施策 結果
--prefill-fp8 prefill +33%(1,364 → 1,815 tok/s @30k cold)。decodeは不変
--checkpoint-slots 16+--spill-gib 32 prefix保持が向上(6会話を挟んだ後でも再送は 99.9% cached・ttft 0.12s)
--mtp-drafts 6 効果なし(受入数が完全同一)
--drafter-bits 0 効果なし(同上)
  • 効いた: prefill-fp8(プロンプト処理)と prefix保持(再prefill削減)。
  • 効かなかった: 投機デコード(DFlash2)の追加チューニング。受入数が完全に同一で、フラグが投機経路を変えていませんでした。
  • 最終構成:
tensorfold serve TensorFold/Qwen3.8-27B-MLX-4bit --name Qwen3.8-27B --host 0.0.0.0
  --parallel 8 --drafter z-lab/Qwen3.8-27B-DFlash2
  --prefill-fp8 --checkpoint-slots 16 --spill-gib 32

長文脈の decode(~50 tok/s)を直接上げるのは文脈圧縮が本命、という整理も得ました(未着手)。


6. イメージ選定: v0.6.6 が正解

  • 現行 = TensorFold v0.6.6(Python系) = Pythonラインの最新リリース。

  • 最新 = v1.0.7(ネイティブZig tensorfold-native) だが、CLI/対応モデルが別。

  • 公式リリースノート(v1.0.0)に決定的な記述:

    Qwen3.8-27B ... being ported for 1.0.x. Qwen3.8-27B passes drafted/plain equality, but remains outside 1.0.0 because its paired served decode and cold-prefill results are slower than Python 0.6.6.

  • → 27BをGB10で使うなら v0.6.6 が正解。v1.0.xへ上げても速くならず、むしろ遅い/未対応。


7. モデル/チェックポイント選定

モデル

モデル 能力 速度 安定 位置づけ
Qwen3.8-27B 中〜高 速い ◎ 安定・速度の万能デフォルト
Qwen3.8-Flash-Next 高 長文脈で健闘 △(fastループ、think前提) 品質重視
Qwen3.6-35B-A3B 中 最速 ○ 軽量枠
GLM 5.3 Flash 高 速い 要導入 対抗馬

27B のチェックポイント

チェックポイント 速度(GB10) 品質 備考
MLX 4-bit(採用) ◎最速 △〜○(難問で低下の報告) DFlash2対応
NVFP4(nvidia/RadixArk) ○(遅め) ○〜◎ 統制研究でMLXより正答率高(18/24 vs 14/24)
FP8 △(重い, ~30GB) ◎ 単機では不利
  • 速度重視(opencodeエージェント)なら MLX 4-bit。品質重視なら NVFP4 に切替えてA/B。

8. まとめ

  1. 常用は 27B が最良のデフォルト(Flash-Nextはthink前提で常用しにくい)。
  2. サンプリングは公式準拠(特に non-thinking の presence_penalty=1.5)。
  3. 高速化は prefill-fp8 と prefix保持が効く(投機の追加チューニングは効かない)。
  4. イメージは v0.6.6(Python)が正解。
  5. profile運用では docker compose logs に注意(既定サービスを常用モデルに固定)。

「妥協」から始めた 27B ですが、素直さ・安定性・速度のバランスで常用の正解でした。
前編と合わせて、単機DGX Spark でローカルLLMを常用するまでの実践記録になっています。

数値は筆者環境での実測です。ドライバ・イメージ・チェックポイント・負荷で変動します。

0
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?