最近、Qwenチームは QwQ-32B モデル、推論モデルである。 ベンチマーク に匹敵するショーだ。 ディープシーク-R1 システムの性能は素晴らしい。しかし、多くのユーザーが無限生成、過度の重複、トークンの問題、微調整の問題に遭遇している。この記事は、これらの問題をデバッグし、解決し、QwQ-32Bの可能性を最大限に引き出すための詳細なガイドを提供することを目的としている。
アンクロス チームによってアップロードされたモデルは、上記のバグを修正し、ファインチューニング、vLLM、トランスフォーマーといったツールやフレームワークのサポートを向上させている。以下は ラマ.cpp バックエンドエンジンとしてllama.cppを使用している方は このリンク 無限世代問題を解決するための指導を受ける。
QwQ-32B モデルをアンスロー(バグ修正):
公式推奨設定
⚙️ 公式推奨設定
Qwenの公式推奨に基づき、モデル推論のための推奨パラメータ設定を以下に示します:
- 温度:0.6
- Top_K:40(推奨範囲は20~40)
- Min_P: 0.1(任意だが、うまく機能する)
- トップ_P:0.95
- 繰り返しペナルティ: 1.0 (llama.cpp とトランスフォーマーでは、1.0 は無効を意味する)
- チャットテンプレート:
userCreate Flappy Bird game in Python.
llama.cpp 推奨設定
👍llama.cppの推奨設定
Unslothチームは、多くのユーザーが1.0より大きいバージョンの 繰り返し罰則
しかし、この方法は実際にはllama.cppのサンプリング・メカニズムを妨害する。重複ペナルティーは、生成される重複の数を減らすことを意図したものだが、実験によると、このアプローチでは期待した効果が得られないことがわかっている。
つまり、リピートペナルティを完全に無効にする(1.0に設定する)ことも選択肢の一つです。しかし、Unslothチームは、適切なリピートペナルティが無限生成の抑制に依然として効果的であることを発見した。
繰り返しペナルティーを効果的に使うには、llama.cppのサンプラーの順番を調整して 繰り返し罰則
を追加してください。これを行うには、以下のパラメータを追加する:
-サンプラー "top_k;top_p;min_p;temperature;dry;typ_p;xtc"
デフォルトでは、llama.cppは以下の順番でサンプラーを使用します:
---サンプラー "dry;top_k;typ_p;top_p;min_p;xtc;temperature"
アンスロスチームの調整した順番は、基本的に温度とドライの位置を入れ替え、min_pを前に移動させる。つまり、サンプラーは以下の順番で適用されることになる:
トップ_k=40
top_p=0.95
min_p=0.1
温度=0.6
ドライ
タイプ_p
xtc
それでも問題が解決しない場合は --リピート・ペナルティ
1.0という値は、1.2または1.3にわずかに引き上げられた。
llama.cppのサンプリング方向の問題を指摘してくれた@krist486に感謝する。
ドライ・リピート・ペナルティ
☀️ ドライ・リピート・ペナルティ
アンスロットのチームは、次のような提案をしている。 ドライペナルティ
を使用し、0.8という値を使おうとした。しかし、実験結果はドライペナルティ
特にコード生成時に構文エラーを引き起こす可能性が高くなります。それでも問題が発生する場合は ドライペナルティ
0.8に引き上げる。
を選択した場合 ドライペナルティ
調整されたサンプリング順も同様に有用である。
QwQ-32Bチュートリアル
🦙 オーラマ QwQ-32Bチュートリアルの実行
- まだインストールされていない場合
オラマ
まずはインストールしてください!
apt-get update
apt-get install pciutils -y
curl -fSSL [https://ollama.com/install.sh](https://www.google.com/url?sa=E&q=httpsollama.cominstall.sh) ||pciutils -ycurl -fSSL []() | sh
- モデルを実行する!実行に失敗した場合は、別のターミナルで実行してみてください。
オラマサーブ
Unslothチームは、すべての修正と提案されたパラメーター(温度など)をHugging Faceのアップロードモデルに含めた。パラメタ
ドキュメンテーション
ollama run hf.co/unsloth/QwQ-32B-GGUF:Q4_K_M
llama.cpp QwQ-32Bを動かすためのチュートリアル
llama.cpp QwQ-32B チュートリアルの実行
- をとおして ラマ.cpp 最新バージョンを入手する
ラマ.cpp
.以下のビルド手順を参考にビルドしてください。GPUを持っていない場合やCPU推論だけを行いたい場合は、ビルド時に-DGGML_CUDA=オン
と置き換える。-dggml_cuda=オフ
.
apt-get update
apt-get install pciutils build-essential cmake curl libcurl4-openssl-dev -y
git clone [https://github.com/ggerganov/llama.cpp](https://www.google.com/url?sa=E&q=httpsgithub.comggerganovllama.cpp)
cmake llama.cpp -B llama.cpp/build
-dbuild_shared_libs=on -dggml_cuda=on -dllama_curl=on
cmake --build llama.cpp/build --config Release -j --clean-first --target llama-quantize llama-cli llama-gguf-split
cp llama.cpp/build/bin/llama-* llama.cpp
- モデルのダウンロード(インストール中)
pip install huggingface_hub hf_transfer
(後)。Q4_K_Mまたは他の定量化バージョン(例えばBF16 full precision)を選択することができる。その他のバージョンはhttps://huggingface.co/unsloth/QwQ-32B-GGUF。
# !pip install huggingface_hub hf_transfer
インポート os
os.environ["HF_HUB_ENABLE_HF_TRANSFER"] = "1"
from huggingface_hub import snapshot_download
snapshot_download(
repo_id="unsloth/QwQ-32B-GGUF"、
local_dir="unsloth-QwQ-32B-GGUF"、
allow_patterns=[" Q4_K_M "], # For Q4_K_M
)
- Unslothが提供するFlappy Birdのテストスクリプトを実行すると、出力は以下の場所に保存される。
Q4_K_M_yes_samplers.txt
ドキュメンテーション - 実際の状況に応じてパラメータを調整する。
--スレッド 32
CPUスレッド数を設定する。--ctx-size 16384
のコンテキストの長さを設定する。--n-gpu-layers 99
GPUオフロード層の数を設定します。GPUのメモリが不足している場合は--n-gpu-layers
値を指定する。CPU推論のみを使用する場合は、このパラメータを削除する。 --repeat-penalty 1.1
歌で応える--ドライ・マルチプライヤー 0.5
はリピートペナルティとドライペナルティのパラメータで、必要に応じてユーザーが調整できる。
./llama.cpp/llama-cli
---model unsloth-QwQ-32B-GGUF/QwQ-32B-Q4_K_M.gguf
--スレッド数 32
--ctx-size 16384
--n-gpu-layers 99
--seed 3407
--プリオ 2
---temp 0.6
--repeat-penalty 1.1
-乾燥倍率 0.5
--min-p 0.1
---トップ-k 40
---top-p 0.95
--no-cnv
---サンプラー "top_k;top_p;min_p;temperature;dry;typ_p;xtc"
-prompt"userPythonでFlappy Birdゲームを作成します。 以下のものを含める必要があります。PythonでFlappy Birdのゲームを作りましょう。形は正方形、円形、三角形からランダムに選びます。 色は濃い色からランダムに選びます。 ⑬土地の色は濃い茶色か黄色からランダムに選びます。(6)右上に点数を表示し、パイプを通過し、パイプにぶつからないと点数が増えます。 (7)十分なスペースがあるパイプをランダムに作ります。負けたときはベストスコアを表示します。 画面内にテキストを表示します。qかEscを押すとゲームが終了します。 再起動はもう一度SPACEを押します。 ⑬最終的なゲームはPythonのマークダウンのセクションの中にあるはずです。nassistantn Ⅾ"
2>&1 | tee Q4_K_M_yes_samplers.txt
上記のFlappy BirdゲームのヒントはUnsloth'sから取られたものです。 DeepSeekR1-Dynamic 1.58bit ブログ.キュー・ワードの全文は以下の通り:
user
PythonでFlappy Birdゲームを作成します。 以下のものを含める必要があります: 1.
1.pygameを使うこと。
2.背景色はランダムに選び、明るい色合いとします。 水色から始めます。
3. SPACE を複数回押すと鳥が加速します。
4.鳥の形は正方形、円、三角形からランダムに選びます。 色は暗い色からランダムに選びます。 5.
5.底に、焦げ茶色または黄色に着色された土地を無作為に選んで置く。
6.右上に得点を表示し、パイプを通過し、パイプにぶつからなければ得点を増やす。 7.右上に得点を表示し、パイプを通過し、パイプにぶつからなければ得点を増やす。
7.十分な間隔をあけてパイプを作り、濃い緑や薄い茶色、濃い灰色などランダムに色をつける。 8.負けたら、右上のスコアを表示する。
8.負けたらベストスコアを表示しよう。 テキストは画面の中に書こう。 qかEscを押すとゲームが終了する。 再開はもう一度SPACEを押すこと。
The final game should be inside a markdown section in Python. The final game should be inside a markdown section in Python.
アシスタント
<考える
以下は、モデルによって生成されたPythonコードの開始部分と終了部分である(思考プロセスは削除されている):
インポート pygame
インポートランダム
インポート sys
pygame.init()
##の続き
クラス Bird.
def __init__(self).
### 続き
def main(): best_score = 0
ベストスコア = 0
現在のスコア = 0
ゲームオーバー = False
パイプ = [].
first_time = True # 最初のゲームプレイを追跡する
# 初期設定
background_color = (173, 216, 230) # 最初は水色
land_colour = random.choice(土地色)
bird = Bird()
while True: for event in pygame.
for event in pygame.event.get():: #####
###の続き
if not game_over: # 鳥とパイプを更新。
鳥とパイプを更新
bird.update()
### 続き
# 描画
### 続き
pygame.display.flip()
clock.tick(60)
if __name__ == "__main__".
clock.tick(60): if __name__ == "__main__": main().
このモデルは、フラッピーバードのゲームを正常に生成することに成功した!
次に、-samplers "top_k;top_p;min_p;temperature;dry;typ_p;xtc "パラメーターを削除し、Unslothの修正なしで同じコマンドを実行してみる。出力はQ4_K_M_no_samplers.txtファイルに保存される。
./llama.cpp/llama-cli
---model unsloth-QwQ-32B-GGUF/QwQ-32B-Q4_K_M.gguf
--スレッド数 32
--ctx-size 16384
--n-gpu-layers 99
--seed 3407
--プリオ 2
---temp 0.6
--repeat-penalty 1.1
-乾燥倍率 0.5
--min-p 0.1
---トップ-k 40
---top-p 0.95
--no-cnv
--prompt "userCreate a Flappy Bird game in Python. You must include these things:♪You must use pygame.背景色はランダムに選び、薄い色合いにします。 まずは薄い青色から始めましょう。形は正方形、円形、三角形からランダムに選びます。 色は濃い色からランダムに選びます。 ⑬土地の色は濃い茶色か黄色からランダムに選びます。(6)右上に点数を表示し、パイプを通過し、パイプにぶつからないと点数が増えます。 (7)十分なスペースがあるパイプをランダムに作ります。負けたときはベストスコアを表示します。 画面内にテキストを表示します。qかEscを押すとゲームが終了します。 再起動はもう一度SPACEを押します。 ⑬最終的なゲームはPythonのマークダウンのセクションの中にあるはずです。nassistantn"
2>&1 | tee Q4_K_M_no_samplers.txt
修正を使わないと、モデルはループのある結果を生成し、Pythonの構文エラーが横行し、その他にも様々な問題が発生します。例えば、以下のコードスニペットは正しいように見えるが、実際には正しくない!39行目 pipes.clear() ### <<< NameError: name 'pipes' is not defined. pipes'のインポートを忘れていませんか? pipes' のインポートを忘れていませんか?
インポート pygame
インポートランダム
pygame.init()
#定数
幅、高さ = 800, 600
地面の高さ = 20
重力 = 0.7
パイプの速度 = -3
バードサイズ = 45
最小ギャップ = 130
MAX_GAP = 200
パイプの色 = [(0, 96, 0), (205, 133, 63), (89, 97, 107)].
ダークブラウン = (94, 72, 4)
黄色 = (252, 228, 6)
screen = pygame.display.set_mode((WIDTH, HEIGHT))
clock = pygame.time.
def random_light_colour(): return (
return (
random.randint(180, 230), random.
random.randint(190, 300), random.randint(250, 300), random.
random.randint(250, 255)
)
def reset_game(): global bird_x, bird_y
グローバル bird_x, bird_y
グローバル pipes, score
グローバル background_colour, land_color
グローバル bird_shape, bird_color
#鳥のプロパティ
bird_x = WIDTH * 0.3
bird_y = HEIGHT // 2
bird_vel = -5 # 最初の上向きの推力
pipes.clear() ### <<< NameError: name 'pipes' is not defined.
さらに--repeat-penaltyを1.5まで上げると、状況はさらに悪化し、構文エラーが目立つようになり、コードがまったく機能しなくなる。
pygame をインポートします。
from random import randint # 色、形、位置をランダムに生成します。
pygame.init()
#定数。
幅、高さ =456 ,702 #
BACKGROUND_COLOR_LIGHTS=['lightskyblue'] #
gap_size=189 #
BIRD_RADIUS=3.
pipe_speed=- ( ) ?
class Game().
def __init__(self).
self.screen_size=( ).
def reset_game_vars(): global current_scor e
global current_scor e
#をゼロに設定、その他の初期状態。
# メインゲームループ。
while running : for event in pygame.
for event in pygame.event.get() :
if quit ... etc
pygame.quit()
print("コードは簡略化されています。 時間的制約のため、完全な動作版にはさらなる実装が必要です。")
これはQ4_K_Mの量子化バージョンだけの問題だと思うかもしれない。しかし、そうではない。BF16の全精密モデルでも、Unslothチームが提供した-samplers "top_k;top_p;min_p;temperature;dry;typ_p;xtc "の修正を適用せず、Repetition Penaltyを使用すると、生成の失敗が発生します。
トークンが表示されない?
🤔 トークン 表示されない?
一部のユーザーから、トークンがデフォルトでチャットテンプレートに追加されているため、システムによっては思考プロセスを正しく出力できないという報告がありました。ユーザーは手動でJinjaテンプレートを編集して追加する必要があります:
{%- if tools %} {{- '<|im_start|>system\n' }} {%- if messages[0]['role'] == 'system' %} {{- messages[0]['content'] }} {%- else %} {{- '' }} {%- endif %} {{- "\n\n# Tools\n\nYou may call one or more functions to assist with the user query.\n\nYou are provided with function signatures within <tools></tools> XML tags:\n<tools>" }} {%- for tool in tools %} {{- "\n" }} {{- tool | tojson }} {%- endfor %} {{- "\n</tools>\n\nFor each function call, return a json object with function name and arguments within <tool_call></tool_call> XML tags:\n<tool_call>\n{\"name\": <function-name>, \"arguments\": <args-json-object>}\n</tool_call><|im_end|>\n" }} {%- else %} {%- if messages[0]['role'] == 'system' %} {{- '<|im_start|>system\n' + messages[0]['content'] + '<|im_end|>\n' }} {%- endif %} {%- endif %} {%- for message in messages %} {%- if (message.role == "user") or (message.role == "system" and not loop.first) %} {{- '<|im_start|>' + message.role + '\n' + message.content + '<|im_end|>' + '\n' }} {%- elif message.role == "assistant" and not message.tool_calls %} {%- set content = message.content.split('</think>')[-1].lstrip('\n') %} {{- '<|im_start|>' + message.role + '\n' + content + '<|im_end|>' + '\n' }} {%- elif message.role == "assistant" %} {%- set content = message.content.split('</think>')[-1].lstrip('\n') %} {{- '<|im_start|>' + message.role }} {%- if message.content %} {{- '\n' + content }} {%- endif %} {%- for tool_call in message.tool_calls %} {%- if tool_call.function is defined %} {%- set tool_call = tool_call.function %} {%- endif %} {{- '\n<tool_call>\n{"name": "' }} {{- tool_call.name }} {{- '", "arguments": ' }} {{- tool_call.arguments | tojson }} {{- '}\n</tool_call>' }} {%- endfor %} {{- '<|im_end|>\n' }} {%- elif message.role == "tool" %} {%- if (loop.index0 == 0) or (messages[loop.index0 - 1].role != "tool") %} {{- '<|im_start|>user' }} {%- endif %} {{- '\n<tool_response>\n' }} {{- message.content }} {{- '\n</tool_response>' }} {%- if loop.last or (messages[loop.index0 + 1].role != "tool") %} {{- '<|im_end|>\n' }} {%- endif %} {%- endif %} {%- endfor %} {%- if add_generation_prompt %} {{- '<|im_start|>assistant\n<think>\n' }} {%- endif %}
を削除するように修正しました。また、DeepSeek チームは、モデルを推論モードに強制的に移行させるために、デフォルトでトークンを追加するようにすべてのモデルを修正しました。
したがって、{%- if add_generation_prompt %} {{- 'assistantn' }} {%- endif %}を{%- if add_generation_prompt %} {- 'assistantn' }} {%-endif%}に変更する。{- 'assistantn' }} {%- endif %}に変更する。
[TEL](着信音) [TEL](着信音) [TEL](着信音)
{%- if tools %} {{- '<|im_start|>system\n' }} {%- if messages[0]['role'] == 'system' %} {{- messages[0]['content'] }} {%- else %} {{- '' }} {%- endif %} {{- "\n\n# Tools\n\nYou may call one or more functions to assist with the user query.\n\nYou are provided with function signatures within <tools></tools> XML tags:\n<tools>" }} {%- for tool in tools %} {{- "\n" }} {{- tool | tojson }} {%- endfor %} {{- "\n</tools>\n\nFor each function call, return a json object with function name and arguments within <tool_call></tool_call> XML tags:\n<tool_call>\n{\"name\": <function-name>, \"arguments\": <args-json-object>}\n</tool_call><|im_end|>\n" }} {%- else %} {%- if messages[0]['role'] == 'system' %} {{- '<|im_start|>system\n' + messages[0]['content'] + '<|im_end|>\n' }} {%- endif %} {%- endif %} {%- for message in messages %} {%- if (message.role == "user") or (message.role == "system" and not loop.first) %} {{- '<|im_start|>' + message.role + '\n' + message.content + '<|im_end|>' + '\n' }} {%- elif message.role == "assistant" and not message.tool_calls %} {%- set content = message.content.split('</think>')[-1].lstrip('\n') %} {{- '<|im_start|>' + message.role + '\n' + content + '<|im_end|>' + '\n' }} {%- elif message.role == "assistant" %} {%- set content = message.content.split('</think>')[-1].lstrip('\n') %} {{- '<|im_start|>' + message.role }} {%- if message.content %} {{- '\n' + content }} {%- endif %} {%- for tool_call in message.tool_calls %} {%- if tool_call.function is defined %} {%- set tool_call = tool_call.function %} {%- endif %} {{- '\n<tool_call>\n{"name": "' }} {{- tool_call.name }} {{- '", "arguments": ' }} {{- tool_call.arguments | tojson }} {{- '}\n</tool_call>' }} {%- endfor %} {{- '<|im_end|>\n' }} {%- elif message.role == "tool" %} {%- if (loop.index0 == 0) or (messages[loop.index0 - 1].role != "tool") %} {{- '<|im_start|>user' }} {%- endif %} {{- '\n<tool_response>\n' }} {{- message.content }} {{- '\n</tool_response>' }} {%- if loop.last or (messages[loop.index0 + 1].role != "tool") %} {{- '<|im_end|>\n' }} {%- endif %} {%- endif %} {%- endfor %} {%- if add_generation_prompt %} {{- '<|im_start|>assistant\n' }} {%- endif %}
特記事項
特記事項
アンスロットのチームは当初、この問題は次のようなことが原因ではないかと推測していた:
- QwQのコンテキストの長さは、ネイティブの128Kではなく、32KにYaRN拡張を加えたものかもしれない。例えば、https://huggingface.co/Qwen/QwQ-32B の readme ファイルを参照のこと:
{
...,
"rope_scaling": {
"factor": 4.0、
"original_max_position_embeddings": 32768、
"type": "yarn"
}
}
Unslothチームはllama.cppのYaRN処理を書き直そうとしたが、問題は解決しなかった。
--override-kv qwen2.context_length=int:131072
--override-kv qwen2.rope.scaling.type=str:yarn
--override-kv qwen2.rope.scaling.factor=float:4
--override-kv qwen2.rope.scaling.original_context_length=int:32768
--override-kv qqwen2.rope.scaling.attn_factor=float:1.13862943649292 \
- アンスロスチームはまた、RMS Layernormのイプシロン値が正しくないのではないか、1e-5ではなく1e-6にすべきではないかと考えた。 たとえば、このようなことだ。 このリンク rms_norm_eps=1e-06、および このリンク Unslothチームもこの値を書き換えることを試みたが、問題はまだ解決していない:
--override-kv qwen2.attention.layer_norm_rms_epsilon=float:0.000001 \
- また、@kalomazeのおかげで、Unslothチームはllama.cppとTransformersの間のトークナイザーIDが一致するかどうかもテストしました。その結果、両者は一致しており、トークナイザーIDの不一致が問題の原因ではないことがわかった。
以下は、アンスローチームの実験結果である:
61KB file_BF16_no_samplers.txt
BF16 フル精度、サンプルリペアなし
55KBファイル_BF16_yes_samplers.txt
BF16 フル精度、サンプリング修理適用
71KB final_Q4_K_M_no_samplers.txt
Q4_K_M 精度、サンプル修正なし
65KB final_Q4_K_M_yes_samplers.txt
Q4_K_M 精度、サンプリングフィックス適用時
トーケナイザーのバグ修正
✏️ トーケナイザーのバグ修正
- Unslothチームは、微調整に影響するいくつかの特定の問題も発見しました。EOSトークンは正しいですが、PADトークンのより論理的な選択は""でしょう。Unslothチームはhttps://huggingface.co/unsloth/QwQ-32B/blob/、設定を更新しました。Unslothチームはmain/tokenizer_config.jsonの設定を更新しました。
"eos_token":""、
「pad_token": ""、
ダイナミック4ビット量子化
🛠️ ダイナミック4ビット量子化
Unslothチームは動的4ビット量子化モデルもアップロードしており、通常の4ビット量子化と比較してモデルの精度が大幅に向上している!下図は、量子化過程におけるQwQモデルの活性化値と重みのエラー解析を示しています:

Unslothチームは、ダイナミックな4ビット定量モデルをhttps://huggingface.co/unsloth/QwQ-32B-unsloth-bnb-4bit。
より ブイエルエルエム バージョン0.7.3(2024年2月20日)https://github.com/vllm-project/vllm/releases/tag/v0.7.3、vLLMはUnsloth動的4ビット定量モデルの読み込みをサポートし始めました!
GGUFフォーマットの全モデルはhttps://huggingface.co/unsloth/QwQ-32B-GGUF!