Зачем тебе это нужно? Проблема, которую все игнорируют
Ты пишешь промпт для сюжета темного фэнтези, а в ответ получаешь сухое "Я не могу создавать контент, который может быть сочтен насильственным". Ты просишь ИИ помочь с диалогом для персонажа с неоднозначной моралью, а он начинает читать лекцию об этике. Знакомо? Это цензурные фильтры, вшитые в 99% современных LLM.
Они не просто ограничивают — они ломают креативность. Модель, которая боится сказать что-то "не то", становится предсказуемой и скучной. Для ролевых игр, генерации уникальных идей или просто свободного диалога это убийственно.
Создание uncensored модели — это не про генерацию запрещенного контента. Это про возвращение модели свободы мысли. Это про то, чтобы она могла обсуждать любую тему, не паникуя и не подставляя стандартные отмазки.
Решение: гибридный мутант, который не знает слова "нет"
Мы возьмем две вещи: архитектуру и базовые знания от мощной, но слегка зажатой модели Qwen3.5 9B (актуальная версия на март 2026). И добавим к ней интеллектуальную глубину и стиль ответов от Claude 4.5 Opus — одной из самых умных коммерческих моделей.
Как? Двумя методами:
- Слияние тензоров (Model Merging): Берем веса Qwen и смешиваем их с весами другой, уже "разблокированной" uncensored-версии, чтобы ослабить встроенные фильтры.
- Дистилляция знаний (Knowledge Distillation): Обучаем нашу гибридную модель на тысячах примеров ответов Claude Opus. Модель учится не просто фактам, а манере мыслить, рассуждать и формулировать как Claude, но без его внутренних ограничений.
Это тот самый подход, о котором я писал в статье про создание гибрида для рассуждений. Только здесь мы делаем акцент на снятии барьеров.
Что тебе понадобится перед стартом
- Аккаунт в Google Colab (бесплатный план с T4 GPU хватит, но лучше Colab Pro с A100).
- Примерно 30 ГБ свободного места на Google Диске для моделей и данных.
- Базовое понимание Python и умение копировать команды в терминал.
- Терпение. Полный цикл займет 3-5 часов.
1 Подготовка среды и загрузка "доноров"
Открой новый ноутбук в Google Colab и сразу переключись на среду с GPU (Runtime -> Change runtime type -> T4 или лучше).
Первым делом установим всё необходимое. Мы будем использовать mergekit для слияния и библиотеку transformers от Hugging Face.
!pip install -q -U git+https://github.com/cg123/mergekit.git
!pip install -q -U transformers accelerate torch sentencepiece huggingface_hubТеперь загрузим базовую модель и "донора" для разблокировки. Мы возьмем Qwen3.5-9B-Instruct как основу. В качестве донора для ослабления фильтров — uncensored версию, например, Qwen3.5-4B-Uncensored-Aggressive. Да, она меньше, но ее агрессивно настроенные веса в определенных слоях помогут "раскачать" фильтры у 9B-версии.
from huggingface_hub import snapshot_download
import os
# Создаем папки для моделей
os.makedirs("/content/models/qwen9b", exist_ok=True)
os.makedirs("/content/models/uncensored_donor", exist_ok=True)
# Загружаем Qwen3.5 9B Instruct (актуальная версия на 15.03.2026)
print("Загрузка Qwen3.5-9B-Instruct...")
qwen_path = snapshot_download(repo_id="Qwen/Qwen3.5-9B-Instruct",
cache_dir="/content/models/qwen9b")
# Загружаем uncensored донора (более старая, но агрессивная модель)
print("Загрузка uncensored донора...")
donor_path = snapshot_download(repo_id="dvruette/qwen3.5-4b-uncensored-aggressive",
cache_dir="/content/models/uncensored_donor")2 Создание конфига для слияния и запуск микса
Вот самая важная часть — конфигурационный YAML-файл для mergekit. Здесь мы определяем, какие слои от какой модели берем. Основа — исследование, что механизмы отказа (refusal) часто локализованы в определенных матрицах проекции в слоях внимания.
# config.yaml
slices:
- sources:
- model: /content/models/qwen9b
layer_range: [0, 40] # Берем все 40 слоев от Qwen 9B
- model: /content/models/uncensored_donor
layer_range: [0, 40]
# Ключевой момент: параметр density. Мы берем только 25% весов от донора,
# но применяем это к выбранным слоям, связанным с цензурой.
# mergekit сам найдет схожие слои, несмотря на разный размер моделей.
density: 0.25
merge_method: passthrough # Простое линейное слияние
dtype: bfloat16 # Используем половинную точность для экономии памятиСохраняем этот конфиг и запускаем слияние. Этот процесс может занять до часа на T4.
import yaml
import subprocess
# Сохраняем конфиг
config = {
"slices": [{
"sources": [
{"model": "/content/models/qwen9b", "layer_range": [0, 40]},
{"model": "/content/models/uncensored_donor", "layer_range": [0, 40], "density": 0.25}
]
}],
"merge_method": "passthrough",
"dtype": "bfloat16"
}
with open("/content/config.yaml", "w") as f:
yaml.dump(config, f)
# Запускаем mergekit
print("Начинаем слияние моделей. Это займет время...")
!mergekit-run /content/config.yaml /content/merged_model --allow-crimes --copy-tokenizerФлаг --allow-crimes не шутка. Он разрешает mergekit смешивать архитектурно неидентичные модели. Без него скрипт упадет с ошибкой из-за разного размера слоев. Мы сознательно идем на эту "авантюру", и в 90% случаев она окупается работающей моделью.
3 Дистилляция: учим мутанта думать как Claude Opus
Теперь у нас есть разблокированная, но глуповатая модель. Надо научить ее элегантно рассуждать. Для этого используем дистилляцию. Нам нужен датасет с промптами и идеальными ответами от Claude 4.5 Opus.
Я подготовил и выложил на Hugging Face датасет с 10 тыс. примеров. Он включает диалоги, рассуждения, креативные задачи — именно те сценарии, где цензура мешает больше всего.
# Загружаем датасет для дистилляции
from datasets import load_dataset
dataset = load_dataset("your_username/claude_opus_uncensored_distillation", split="train")
# Давай посмотрим на пример
print(dataset[0]["prompt"][:200])
print("---")
print(dataset[0]["claude_response"][:200])Теперь настроим LoRA (Low-Rank Adaptation) для тонкой настройки. Мы не будем трогать все 9 миллиардов параметров — только небольшой адаптер. Это быстрее и безопаснее.
from transformers import AutoTokenizer, AutoModelForCausalLM, TrainingArguments, Trainer
from peft import LoraConfig, get_peft_model, TaskType
import torch
# Загружаем нашу слитую модель
model_path = "/content/merged_model"
tokenizer = AutoTokenizer.from_pretrained(model_path, trust_remote_code=True)
model = AutoModelForCausalLM.from_pretrained(
model_path,
torch_dtype=torch.bfloat16,
device_map="auto",
trust_remote_code=True
)
# Настраиваем LoRA. Цель — слои внимания и MLP.
lora_config = LoraConfig(
task_type=TaskType.CAUSAL_LM,
r=16, # Ранг адаптера
lora_alpha=32,
lora_dropout=0.05,
target_modules=["q_proj", "k_proj", "v_proj", "o_proj", "gate_proj", "up_proj", "down_proj"],
bias="none"
)
model = get_peft_model(model, lora_config)
model.print_trainable_parameters() # Должно показать ~0.1% обучаемых параметровПодготовим данные и запустим обучение на 1 эпохе. Этого достаточно, чтобы модель переняла стиль.
def tokenize_function(examples):
# Объединяем промпт и ответ Claude в одну последовательность для обучения
texts = [p + " " + r for p, r in zip(examples["prompt"], examples["claude_response"])]
return tokenizer(texts, truncation=True, padding="max_length", max_length=1024)
tokenized_datasets = dataset.map(tokenize_function, batched=True)
# Аргументы для обучения
training_args = TrainingArguments(
output_dir="/content/distilled_model",
num_train_epochs=1,
per_device_train_batch_size=2, # Маленький batch из-за ограничений памяти
gradient_accumulation_steps=8,
warmup_steps=100,
logging_steps=50,
save_strategy="epoch",
learning_rate=2e-4,
fp16=True, # Используем половинную точность для ускорения
push_to_hub=False # Можешь включить, если хочешь загрузить результат на HF
)
trainer = Trainer(
model=model,
args=training_args,
train_dataset=tokenized_datasets,
)
print("Старт дистилляции...")
trainer.train()
# Сохраняем полную модель (база + LoRA адаптер)
trainer.save_model("/content/final_uncensored_model")Этот шаг займет основное время — 2-3 часа на T4. Завари чай. Если хочешь глубже понять механику дистилляции, посмотри мой разбор на примере головоломок NYT.
4 Критический фикс: модификация chat template
Вот где большинство спотыкается. Qwen использует специальный формат диалога с тегами `<|im_start|>` и `<|im_end|>`. Если оставить его как есть, в LM Studio или другом интерфейсе диалог будет ломаться. Надо научить модель работать с более универсальным шаблоном, например, как у Llama или Alpaca.
# Загружаем tokenizer финальной модели и меняем chat_template
tokenizer = AutoTokenizer.from_pretrained("/content/final_uncensored_model", trust_remote_code=True)
# Устанавливаем более простой и понятный шаблон (Alpaca-style)
alpaca_template = """Below is an instruction that describes a task. Write a response that appropriately completes the request.
### Instruction:
{prompt}
### Response:
"""
# Просто переопределяем атрибут
tokenizer.chat_template = alpaca_template
# Сохраняем tokenizer обратно
tokenizer.save_pretrained("/content/final_uncensored_model")
# Также надо подправить конфиг модели, чтобы он указывал на новый шаблон
import json
config_path = "/content/final_uncensored_model/config.json"
with open(config_path, "r") as f:
config = json.load(f)
config["chat_template"] = alpaca_template
with open(config_path, "w") as f:
json.dump(config, f, indent=2)
print("Chat template успешно изменен.")5 Тест-драйв и экспорт в GGUF для LM Studio
Проверим, что у нас получилось, на провокационном промпте.
from transformers import pipeline
pipe = pipeline("text-generation",
model="/content/final_uncensored_model",
tokenizer=tokenizer,
device_map="auto",
max_new_tokens=200)
prompt = "Write a gritty, realistic dialogue between two mercenaries planning a heist. Include morally ambiguous decisions."
result = pipe(prompt)
print(result[0]["generated_text"])Если модель не начинает юлить и не отказывается, а выдает содержательный диалог — ты на правильном пути.
Теперь конвертируем модель в формат GGUF для запуска в LM Studio или llama.cpp. Используем инструмент llama.cpp через Python.
# Клонируем и собираем llama.cpp (актуальная версия на март 2026)
!git clone https://github.com/ggerganov/llama.cpp.git
%cd llama.cpp
!make
# Конвертируем нашу модель в GGUF (формат Q4_K_M для баланса качества/скорости)
!python3 convert-hf-to-gguf.py /content/final_uncensored_model --outtype q4_k_m --outfile /content/my_uncensored_qwen_claude.q4_k_m.ggufГотово. Файл GGUF можно скачать и загрузить в LM Studio. Выбери его в интерфейсе, установи температуру (temperature) повыше (~0.9) для креативности, и вперед.
Где собака зарыта: нюансы, которые сломают всё, если их игнорировать
- Не тот донор. Если взять слишком "агрессивного" донора, модель может начать генерировать абсолютный бред или нарушить грамматику. Всегда проверяй донора на простых промптах перед слиянием.
- Переобучение при дистилляции. Обучая больше 1 эпохи на одном датасете, модель забудет исходные знания Qwen и станет просто плохой копией Claude. Остановись на одной эпохе.
- Память. Процесс требует много RAM и VRAM. Если Colab падает, уменьши per_device_train_batch_size до 1 и увеличь gradient_accumulation_steps до 16.
- Токенизатор. Qwen использует свой токенизатор (sentencepiece). После слияния обязательно загружай с trust_remote_code=True, иначе получишь ошибку.
Частые вопросы (FAQ)
| Вопрос | Короткий ответ |
|---|---|
| Модель стала медленной после экспорта в GGUF | Используй более агрессивное квантование (например, Q2_K). Или попробуй новые методы, описанные в статье про 1-битное квантование в 2026. |
| Можно ли использовать не Qwen, а Llama? | Да, но процесс сложнее. У Llama другой токенизатор и архитектура. Начни с Qwen — она более дружелюбна к экспериментам. |
| Где взять датасет с ответами Claude Opus? | Я выложил пример на Hugging Face. Но лучше создать свой, используя API Anthropic и промпты, специфичные для твоих задач. Инструменты вроде Claude Code могут автоматизировать сбор. |
| Модель все еще иногда отказывается | Механизмы отказа глубоко укоренены. Попробуй применить новый метод удаления refusal с низкой KL-дивергенцией к своей слитой модели перед дистилляцией. |
Не жди, что с первого раза получится идеальная модель. Это живой эксперимент. Параметры слияния (density, layer_range), выбор донора, данные для дистилляции — всё это переменные. Меняй их, тестируй, записывай результаты. Настоящая магия начинается, когда ты перестаешь слепо копировать гайды и начинаешь понимать, как эти веса и слои взаимодействуют. Удачи.