Unsloth решает проблему дублирующего вывода в квантифицированной версии QwQ-32B

Недавно команда Qwen выпустила QwQ-32B модель, модель вывода, которая используется во многих Бенчмарки Это шоу соперничает с DeepSeek-R1 Производительность системы превосходна. Однако многие пользователи сталкиваются с бесконечной генерацией, избыточным количеством дубликатов, проблемами с токенами и тонкой настройкой. Цель этой статьи - предоставить подробное руководство, которое поможет вам отладить и решить эти проблемы, а также раскрыть весь потенциал QwQ-32B.

Расстелите салфетку Выложенная командой модель исправляет вышеупомянутые ошибки и позволяет улучшить поддержку таких инструментов и фреймворков, как тонкая настройка, vLLM и Transformers. Для тех, кто использует llama.cpp и других пользователей, использующих llama.cpp в качестве бэкэнд-движка, пожалуйста, обратитесь к эта ссылка Получите руководство по устранению проблемы бесконечной генерации.

Распаковка модели QwQ-32B (исправлена ошибка):

Официальные рекомендуемые настройки

⚙️ Официальные рекомендуемые настройки

В соответствии с официальными рекомендациями Qwen, ниже приведены рекомендуемые настройки параметров для вывода модели:

  • Температура: 0,6
  • Top_K: 40 (рекомендуемый диапазон 20-40)
  • Min_P: 0.1 (необязательно, но работает хорошо)
  • Top_P: 0.95
  • Штраф за повторение: 1.0 (в llama.cpp и трансформаторах 1.0 означает отключение)
  • Шаблон чата:<|im_start|>user\nCreate a Flappy Bird game in Python.<|im_end|>\n<|im_start|>assistant\n<think>\n

llama.cpp Рекомендуемые настройки

👍 Рекомендуемые настройки llama.cpp

Команда Unsloth заметила, что многие пользователи предпочитают использовать версию выше 1.0. Repetition Penalty Однако такой подход фактически мешает механизму выборки в llama.cpp. Штраф за дубликаты был призван уменьшить количество генерируемых дубликатов, но эксперименты показали, что этот подход не дает желаемого эффекта.

Тем не менее, отключение штрафа за повтор (значение 1.0) также является одним из вариантов. Однако команда Unsloth обнаружила, что правильное наказание за повтор по-прежнему эффективно для подавления бесконечной генерации.

Чтобы эффективно использовать штраф за повтор, порядок выборок в llama.cpp должен быть изменен таким образом, чтобы при применении Repetition Penalty перед выборкой, иначе это приведет к бесконечной генерации. Для этого добавьте следующий параметр:

--samplers "top_k;top_p;min_p;temperature;dry;typ_p;xtc"

По умолчанию llama.cpp использует следующий порядок сэмплеров:

--samplers "dry;top_k;typ_p;top_p;min_p;xtc;temperature"

Скорректированный порядок команды Unsloth, по сути, меняет местами температуру и сухость, а также перемещает min_p вперед. Это означает, что сэмплер будет применяться в следующем порядке:

top_k=40 
top_p=0.95
min_p=0.1
temperature=0.6
dry
typ_p
xtc

Если проблема сохраняется, попробуйте переместить --repeat-penalty Значение 1,0 было немного увеличено до 1,2 или 1,3.

Спасибо @krist486 за предупреждение о проблеме с направлением выборки в llama.cpp.

Штраф за сухое повторение

☀️ Сухой повторный штраф

Команда Unsloth рассмотрела предложенные dry penalty использования и попытались использовать значение 0,8. Однако результаты эксперимента показали, чтоdry penalty Это с большей вероятностью приведет к синтаксическим ошибкам, особенно при генерации кода. Если пользователь все еще сталкивается с проблемами, попробуйте установить значение dry penalty Увеличьте до 0,8.

Если вы решили использовать dry penaltyНо скорректированный порядок выборки может оказаться не менее полезным.

Ollama под управлением QwQ-32B Учебные пособия

🦙 Оллама Самоучитель по работе с QwQ-32B

  1. Если они еще не установлены ollamaПожалуйста, сначала установите его!
apt-get update 
apt-get install pciutils -y
curl -fSSL [https://ollama.com/install.sh](https://www.google.com/url?sa=E&q=https%3A%2F%2Follama.com%2Finstall.sh) | sh
  1. Запустите модель! Если запуск не удался, попробуйте запустить модель в другом терминале ollama serveКоманда Unsloth включила все исправления и предложенные параметры (температура и т.д.) в модель загрузки Hugging Face. param Документация!
ollama run hf.co/unsloth/QwQ-32B-GGUF:Q4_K_M

llama.cpp Учебник для запуска QwQ-32B

📖 llama.cpp запускает QwQ-32B Tutorials

  1. через (щель) llama.cpp Получите последнюю версию llama.cpp. Вы можете обратиться к следующим инструкциям по сборке. Если у вас нет GPU или вы хотите делать выводы только на CPU, установите параметр -DGGML_CUDA=ON Заменить на -DGGML_CUDA=OFF.
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=https%3A%2F%2Fgithub.com%2Fggerganov%2Fllama.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
  1. Загрузите модель (во время установки) pip install huggingface_hub hf_transfer (после). Можно выбрать Q4_K_M или другие количественные версии (например, BF16 полной точности). Другие версии можно найти на сайте: https://huggingface.co/unsloth/QwQ-32B-GGUF.
# !pip install huggingface_hub hf_transfer
import 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
)
  1. Запустите тестовый скрипт Flappy Bird, предоставленный Unsloth, и результаты будут сохранены в файле Q4_K_M_yes_samplers.txt Документация.
  2. Настройте параметры в соответствии с реальной ситуацией.--threads 32 Установите количество потоков процессора.--ctx-size 16384 Установите длину контекста--n-gpu-layers 99 Установите количество уровней разгрузки GPU. Если GPU не хватает памяти, попробуйте отрегулировать значение --n-gpu-layers значение. Удалите этот параметр, если используется только вывод процессора.
  3. --repeat-penalty 1.1 ответить пением --dry-multiplier 0.5 параметры повторного штрафа и сухого штрафа, которые могут быть настроены пользователем по мере необходимости.
./llama.cpp/llama-cli  
--model unsloth-QwQ-32B-GGUF/QwQ-32B-Q4_K_M.gguf
--threads 32
--ctx-size 16384
--n-gpu-layers 99
--seed 3407
--prio 2
--temp 0.6
--repeat-penalty 1.1
--dry-multiplier 0.5
--min-p 0.1
--top-k 40
--top-p 0.95
-no-cnv
--samplers "top_k;top_p;min_p;temperature;dry;typ_p;xtc"
--prompt "<|im_start|>user\nCreate a Flappy Bird game in Python. You must include these things:\n1. You must use pygame.\n2. The background color should be randomly chosen and is a light shade. Start with a light blue color.\n3. Pressing SPACE multiple times will accelerate the bird.\n4. The bird's shape should be randomly chosen as a square, circle or triangle. The color should be randomly chosen as a dark color.\n5. Place on the bottom some land colored as dark brown or yellow chosen randomly.\n6. Make a score shown on the top right side. Increment if you pass pipes and don't hit them.\n7. Make randomly spaced pipes with enough space. Color them randomly as dark green or light brown or a dark gray shade.\n8. When you lose, show the best score. Make the text inside the screen. Pressing q or Esc will quit the game. Restarting is pressing SPACE again.\nThe final game should be inside a markdown section in Python. Check your code for errors and fix them before the final markdown section.<|im_end|>\n<|im_start|>assistant\n <think> \n"
2>&1 | tee Q4_K_M_yes_samplers.txt

Приведенные выше подсказки к игре Flappy Bird взяты из Unsloth's DeepSeekR1-Dynamic 1.58bit Блоги. Полный текст реплики приведен ниже:

<|im_start|>user
Create a Flappy Bird game in Python. You must include these things:
1. You must use pygame.
2. The background color should be randomly chosen and is a light shade. Start with a light blue color.
3. Pressing SPACE multiple times will accelerate the bird.
4. The bird's shape should be randomly chosen as a square, circle or triangle. The color should be randomly chosen as a dark color.
5. Place on the bottom some land colored as dark brown or yellow chosen randomly.
6. Make a score shown on the top right side. Increment if you pass pipes and don't hit them.
7. Make randomly spaced pipes with enough space. Color them randomly as dark green or light brown or a dark gray shade.
8. When you lose, show the best score. Make the text inside the screen. Pressing q or Esc will quit the game. Restarting is pressing SPACE again.
The final game should be inside a markdown section in Python. Check your code for errors and fix them before the final markdown section.<|im_end|>
<|im_start|>assistant
<think>

Вот начальная и конечная части кода на языке Python, сгенерированного моделью (с удаленным мыслительным процессом):

import pygame
import random
import sys
pygame.init()
### Continues
class Bird:
def __init__(self):
### Continues
def main():
best_score = 0
current_score = 0
game_over = False
pipes = []
first_time = True  # Track first game play
# Initial setup
background_color = (173, 216, 230)  # Light blue initially
land_color = random.choice(land_colors)
bird = Bird()
while True:
for event in pygame.event.get():
### Continues
if not game_over:
# Update bird and pipes
bird.update()
### Continues
# Drawing
### Continues
pygame.display.flip()
clock.tick(60)
if __name__ == "__main__":
main()

Модель успешно сгенерировала работающую игру Flappy Bird!

Unsloth 解决 QwQ-32B 量化版本重复推理问题

Далее попробуйте удалить параметр --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
--threads 32
--ctx-size 16384
--n-gpu-layers 99
--seed 3407
--prio 2
--temp 0.6
--repeat-penalty 1.1
--dry-multiplier 0.5
--min-p 0.1
--top-k 40
--top-p 0.95
-no-cnv
--prompt "<|im_start|>user\nCreate a Flappy Bird game in Python. You must include these things:\n1. You must use pygame.\n2. The background color should be randomly chosen and is a light shade. Start with a light blue color.\n3. Pressing SPACE multiple times will accelerate the bird.\n4. The bird's shape should be randomly chosen as a square, circle or triangle. The color should be randomly chosen as a dark color.\n5. Place on the bottom some land colored as dark brown or yellow chosen randomly.\n6. Make a score shown on the top right side. Increment if you pass pipes and don't hit them.\n7. Make randomly spaced pipes with enough space. Color them randomly as dark green or light brown or a dark gray shade.\n8. When you lose, show the best score. Make the text inside the screen. Pressing q or Esc will quit the game. Restarting is pressing SPACE again.\nThe final game should be inside a markdown section in Python. Check your code for errors and fix them before the final markdown section.<|im_end|>\n<|im_start|>assistant\n<think>\n"
2>&1 | tee Q4_K_M_no_samplers.txt

Без использования исправлений модель выдает результаты с зацикливанием, в ней часто встречаются синтаксические ошибки Python, а также множество других проблем. Например, следующий фрагмент кода кажется правильным, но на самом деле он неверен! Строка 39 pipes.clear() ### <<< NameError: name 'pipes' is not defined. Вы забыли импортировать 'pipes'? Вы забыли импортировать 'pipes'?

import pygame
import random
pygame.init()
# Constants
WIDTH, HEIGHT = 800, 600
GROUND_HEIGHT = 20
GRAVITY = 0.7
PIPE_SPEED = -3
BIRD_SIZE = 45
MIN_GAP = 130
MAX_GAP = 200
PIPE_COLORS = [(0, 96, 0), (205, 133, 63), (89, 97, 107)]
DARK_BROWN = (94, 72, 4)
YELLOW = (252, 228, 6)
screen = pygame.display.set_mode((WIDTH, HEIGHT))
clock = pygame.time.Clock()
def random_light_color():
return (
random.randint(180, 230),
random.randint(190, 300),
random.randint(250, 255)
)
def reset_game():
global bird_x, bird_y
global pipes, score
global background_color, land_color
global bird_shape, bird_color
# Bird properties
bird_x = WIDTH * 0.3
bird_y = HEIGHT // 2
bird_vel = -5  # Initial upward thrust
pipes.clear() ### <<< NameError: name 'pipes' is not defined. Did you forget to import 'pipes'?

Если еще больше увеличить --repeat-penalty до 1,5, ситуация ухудшится, синтаксические ошибки станут более очевидными, а код вообще не будет работать.

import pygame
from random import randint  # For generating colors/shapes/positions randomly 
pygame.init()
# Constants:
WIDTH, HEIGHT =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
# set to zero and other initial states.
# Main game loop:
while running :
for event in pygame.event.get() : 
if quit ... etc
pygame.quit()
print("Code is simplified. Due time constraints, full working version requires further implementation.")

Можно подумать, что это проблема только с квантованной версией Q4_K_M... Полностью точная версия BF16 должна быть в порядке, верно? Однако это не так. Даже в модели BF16 с полной точностью, если вы не примените исправление -samplers "top_k;top_p;min_p;temperature;dry;typ_p;xtc", предоставленное командой Unsloth, и не используете 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 %}

Модифицировано для удаления последнего \n. Эта модификация требует, чтобы модели вручную добавляли \n во время вывода, но это не всегда работает. Команда DeepSeek также изменила все модели, чтобы они добавляли лексемы по умолчанию, чтобы заставить модель перейти в режим вывода.

Поэтому измените {%- if add_generation_prompt %} {{- 'assistant\n\n' }} {%- endif %} на {%- if add_generation_prompt %} {{- 'assistant\n' }} {%- endif %}. {- 'assistant\n' }} {%- endif %}, т.е. удалить \n.

Полный шаблон джиндзя с удаленной частью \n.

{%- 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 %}

Дополнительные заметки

Дополнительные заметки

Команда Unsloth изначально предположила, что проблема может быть вызвана следующим:

  • Длина контекста QwQ может быть не 128K, а 32K плюс расширение YaRN. Смотрите, например, файл readme по адресу https://huggingface.co/Qwen/QwQ-32B:
{
...,
"rope_scaling": {
"factor": 4.0,
"original_max_position_embeddings": 32768,
"type": "yarn"
}
}

Команда Unsloth попыталась переписать обработку YaRN в llama.cpp, но проблема сохранилась.

--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 \
  • Команда Unsloth также подозревает, что значение эпсилон RMS Layernorm может быть неверным и, возможно, должно составлять 1e-6 вместо 1e-5. Например. По этой ссылке. в rms_norm_eps=1e-06 и По этой ссылке. в rms_norm_eps=1e-05. Команда Unsloth также пыталась переписать это значение, но проблема все еще не решена:
--override-kv qwen2.attention.layer_norm_rms_epsilon=float:0.000001 \
  • Благодаря @kalomaze команда Unsloth также проверила идентификаторы токенизаторов между llama.cpp и Transformers, чтобы проверить, совпадают ли они. Результаты показали, что они совпадают, так что несовпадение идентификаторов токенизаторов не является источником проблемы.

Вот результаты эксперимента команды Unsloth:

61KB файл_BF16_no_samplers.txt

BF16 Полная точность, без применения образцового ремонта

55KB file_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": "<|im_end|>",
"pad_token": "<|endoftext|>",

Динамическое 4-битное квантование

🛠️ Динамическая 4-битная квантизация

Команда Unsloth также загрузила динамическую 4-битную модель квантования, которая значительно повышает точность модели по сравнению с обычным 4-битным квантованием! На рисунке ниже показан анализ ошибок значений активации и весов модели QwQ в процессе квантования:

![alt text](https://docs.unsloth.ai/~gitbook/image?url=https%3A%2F%2F3215535692-files.gitbook.io%2F%7E%2Ffiles%2Fv0%2Fb%2Fgitbook-x-prod.appspot.com%2Fo%2Fspaces%252FxhOjnexMCB3dmuQFQ2Zq%252Fuploads%252F32wjrIWeUEQTMq9PhmbS%252FQwQ%2520quantization%2520errors.png%3Falt%3Dmedia%26token%3D0733fd33-9fe9-4aad-812c-75dbad00373f&width=768&dpr=4&quality=100&sign=aafe447c&sv=2)

Команда Unsloth выложила динамическую 4-битную количественную модель на сайт: https://huggingface.co/unsloth/QwQ-32B-unsloth-bnb-4bit.

с vLLM Начиная с версии 0.7.3 (20 февраля 2024) https://github.com/vllm-project/vllm/releases/tag/v0.7.3, vLLM начал поддерживать загрузку динамических 4-битных количественных моделей Unsloth!

Все модели формата GGUF можно найти на сайте https://huggingface.co/unsloth/QwQ-32B-GGUF!

© заявление об авторских правах

Похожие статьи

Нет комментариев

Вы должны войти в систему, чтобы участвовать в комментариях!
Войти сейчас
нет
Нет комментариев...