Предисловие
Не так давно был пост Установка SillyTavern про настройку локального чат-бота, который заставил меня погрузиться в эту кроличью нору. Если вы его не видели — настоятельно рекомендую начать с него. Этот же пост — скорее идеологическое продолжение для тех, кто хочет узнать немного больше, но не имеет достаточно времени, чтобы самостоятельно искать информацию. На этом закончим с предисловием и перейдём к теме нейроликбеза. За последние несколько дней, поигравшись с разными нейросетями, у меня появились вопросы:
1) Как и где найти модель?
2) Что значит 7B, 12B, 24B и что такое Q4 и Q8?
3) Как подобрать оптимальную модель для своего железа?
4) Можно ли заставить нейросеть работать быстрее без регистрации и СМС?
Сразу оговорюсь: я не разбираюсь в нейросетях на 100%. В посте будет самый минимум технической информации, который я постараюсь упростить. Я не буду разбирать тонкие настройки вроде температуры, Top P, Min P. Весь пост в основном про увеличение скорости ответа без сильного ухудшения качества (ну, почти). Также многие моменты я сам не до конца понял и буду рад, если в комментариях укажут на ошибки.
И я не буду давать готовые конфиги, так как всё сильно индивидуально и зависит от вашего железа и конкретной модели.
Если вас всё устраивает — прошу под кат.
Нейросети и места их обитания
Самая простая часть: идём в Google и пишем: "best storytelling llm". Всё.
Ну ладно. Сами модели в основном лежат на https://huggingface.co/. Но там нет сортировки только РП. Про конкретные названия можно спросить у тех же DeepSeek или ChatGPT (правда, у них довольно старая база по нейросетям). В сообществе таверны на Reddit народ обсуждает, какие модели лучше подходят для РП, там же часто пишут тонкие настройки для моделей.
Так как они создают новый пост каждую неделю, лучше искать по запросу:
"[Megathread] - Best Models/API discussion - Week of: site:www.reddit.com"
Для картинок можно зайти на https://civitai.com/ — там и примеры есть, и список использованных ресурсов можно посмотреть, и промпт конкретной картинки глянуть и сразу скачать всё необходимое для генерации. Генерить можно через:
Гайды от реакторчан, как это ставить (если лень читать GitHub):
Для видео:
От себя добавлю, что для SillyTavern есть SillyTavern-Launcher, который может многое упростить (на YouTube можно посмотреть его возможности). Вкратце: через него можно установить таверну и генератор картинок, и преобразование речи, если не хочется настраивать всё вручную. Так же через него можно обновлять это всё. Качаем, закидываем на SSD (где много места) и запускаем.
Выбираем Toolbox → App Installer. Дальше смотрите сами, что вам нужно.
После установки запустить можно через Toolbox → App Launcher.
Это ещё один бэкенд для запуска LLM. Особо про него говорить не буду — по настройкам он примерно такой же, как LM Studio. Он немного проще, чем LM Studio: представляет собой один EXE-файл и не требует установки. У него есть пара плюсов:
1. Есть встроенный бенчмарк, который поможет тестировать производительность (но запускать его нужно через командную строку).
2. Можно настроить и сохранить конфиг, а потом запускать одновременно Tavern и Kobold через один BAT-файл.
вот примеры его интерфейса
Немного скучной теории
С простой частью закончили — теперь пора начать погружение. Я не буду грузить вас подробным устройством LLM и расскажу только то, что важно для базового понимания.
Немного терминов:
Итак, для начала — база. Количество параметров модели измеряется в миллиардах (B — billion): те самые 7B, 12B, 24B, 70B. Грубо говоря, чем оно больше, тем модель "умнее" и способна из коробки лучше отыгрывать роли в различных сеттингах. Ну а ещё она более прожорлива в плане занимаемой памяти и вычислительных ресурсов.
Тут возникает вопрос: а **"умнее" — это насколько?** И тут всё не так однозначно. Технически, какой-нибудь *Deepseek-V3* весит ~1,5 ТБ, но в него, помимо полезной для РП литературы (фэнтези, научная фантастика и т. д.), запихали знания о программировании на куче языков, кучу юридической документации, медицинской и много чего ещё.
Не сказать, что это совсем бесполезно, но чат-ботов, которые по хардкору симулируют работу бухгалтера в "1С", я не встречал (хотя стало даже интересно посмотреть на такое). Поэтому народ пилит свои модели, обучая их на конкретных данных — и так даже 7B-модель может быть довольно неплохим собеседником **в рамках того, на что её обучили**. Хотя для ведения чего-то уровня партии в D&D лучше взять что-то посерьёзнее, например Gryphe_Pantheon-RP-1.8-24b-Small-3.1 или её новую 30B версию( это если говорить о компактности). А что тогда за IQ3_M, Q4_K_S, Q5_K_S, Q8? Всё просто — это степени квантования.
Ладно, ладно. ОЧЕНЬ грубо говоря: каждый "нейрон" в нейросети — это число. И слои выглядят примерно так:
[0.325, -1.283, 2.561, -0.679]
Квантование (quantization) — это метод сжатия нейросетевой модели путём уменьшения точности этих самых чисел ("весов").
Простыми словами:
Мы уменьшаем количество памяти для нейрона, и из:
[0.325, -1.283, 2.561, -0.679]
получаем
[0.3, -1.3, 2.6, -0.7].
Таким образом, слой будет занимать меньше памяти, а также увеличивается скорость обработки, так как процессору проще работать с менее точными значениями. Ну и, конечно же, падает качество ответов LLM: появляются ошибки, случайные слова, модель может начать отвечать сама себе.
Вообще, способов квантования несколько, но разбирать каждый довольно долго, да и актуально это только если вы решили сами квантовать модель. Вот пример квантованной сети: Mistral-7B-v0.1-ORPO-GGUF. Там есть неплохая таблица сравнений. Не стоит считать, что эта таблица верна для всех моделей, но она даёт некоторое представление о том, как квантование влияет на работу LLM. Такой вот компромисс, когда хочется мощную LLM, но железо не позволяет. От себя добавлю, что Q2 и Q3 — очень сомнительный выбор для RP. Вместо условной `12B_Q3` лучше взять `7B_Q5` или даже `7B_Q6` — по ресурсам они почти одинаковые, но качество ответов будет гораздо лучше.
Также надо бы рассказать, что такое токен. Токен — это минимальная смысловая единица текста, на которую нейросеть разбивает входные данные перед обработкой. Из них же собирается её ответ, и в них измеряется скорость генерации.
Вот как оно примерно выглядит:
(Цветами выделены отдельные токены — обратите внимание, они не всегда соответствуют буквам или словам)
P.S. Помните, как я говорил, что не буду объяснять устройство LLM? Я напиздел. Вот примерная структура LLM в вакууме.
Когда вы отправляете запрос модели, он сначала превращается в набор токенов (препроцессинг) и загружается во внутреннюю память модели — KV-Cache. На каждом шаге модель использует эти токены и информацию из кэша, чтобы предсказать следующий токен ответа.
После загрузки модель начинает высчитывать токены ответа — основа этой работы — линейная алгебра. Чтобы выполнять вычисления быстрее, используется специальная библиотека BLAS , которая ускоряет операции. Так модель шаг за шагом генерирует ответ, пока не достигнет специального сигнала «стоп» или лимита длины контекста. В конце токены снова превращаются в понятный текст (постпроцессинг).
Пара важных моментов:
1. Кэш не сохраняется между запросами — с точки зрения LLM каждый запрос для неё новый. Бывают варианты, когда модель подключена к базе данных, но, как правило, за долговременную память отвечает внешний сервис (например, LM Studio или SillyTavern).
2. Кэш и вычислительные операции требуют памяти — в зависимости от настроек это могут быть гигабайты (RAM/VRAM).
Есть две реализации кэша:
- старая: медленная, но поддерживает разделение как по слоям так и между RAM и VRAM
- новая (unified): быстрее, как видно из названия он объединённый и должен находится только в VRAM( про это ниже), не поддерживает разделение между RAM и VRAM
Если не удаётся запустить unified кэш, то используется старая реализация либо llm работает вообще без кэша.
Вообще, модель за запрос может обработать ограниченное количество токенов — так называемое окно контекста запроса. Он задаётся при старте модели и сильно влияет на размер кэша и скорость генерации ответа. Подробнее об этом — ниже.
Кратко о запуске LLM
По сути, и LM Studio, и Koboldcpp, и Oobabooga являются надстройками над llama.cpp (не путать с LLaMA - самой моделью), которые предоставляют дополнительные функции и избавляют от необходимости работать с консолью.
llama.cpp поддерживает несколько вариантов запуска:
- OpenBLAS - для CPU (Intel, AMD, ARM)
- cuBLAS - для видеокарт с поддержкой CUDA (NVIDIA, начиная с GTX 750; хотя технология появилась на 8800 GTX, актуальные версии там уже не работают)
- Vulkan - для видеокарт NVIDIA, AMD, Intel, выпущенных после 2016 года
- Metal - для компьютеров Apple
- и другие
В LM Studio эти настройки находятся в разделе Runtime, и студия вроде автоматически скачивает подходящий вариант для вашей системы.
Важно: лучше использовать видеокарту - даже топовый процессор не справится с LLM так же эффективно. Впрочем, вы можете сами проверить это - смена Runtime в LM Studio делается за четыре клика.
Это все основные моменты. Теперь можно переходить к более глубокому изучению.
Много скучной (но нужной) теории и немного про таверну
Как мы знаем, модель не имеет долговременной памяти — за неё это делает фронтенд. В нашем случае это SillyTavern.
Вообще, в рамках РП размер контекста — это один из самых важных параметров, так как от него зависит, насколько хорошо модель будет помнить историю диалога, описание сеттинга и действующих лиц. Каждый раз, когда вы отправляете запрос, к нему прикладываются:
- описание вас и бота,
- сценарий,
- история чата,
- ваши заметки,
- информация из лорбука,
- системные команды и указание формата ответа.
Кстати, у каждого ответа бота можно посмотреть статистику и текст запроса.
А что будет, если запрос таверны превысит допустимый контекст LLM? Мы получим ошибку о том, что размер запроса больше, чем модель может обработать, и всё. Поэтому желательно в таверне выставлять размер контекста такой же, как у LLM.
Так же можно на вкладке настроек подключения поставить галочку **"Derive context size from backend"**, чтобы не париться.
Какой размер контекста выбрать — зависит от личных предпочтений, но минимум — это 8192. Средний хороший бот весит ~2k+ токенов, а обычный ответ у него может занимать 300–600+ токенов. Также, как я писал выше, SillyTavern пытается оптимизировать контекст. Для хранения истории чата есть важная фича: по умолчанию после каждого 10-го сообщения она просит LLM сделать краткий пересказ чата (не больше 200 слов), и пока модель не ответит, чат блокируется ( можно отключить).
После общения с разными LLM (от 7B до 24B) я понял, что помимо качества ответа важна также скорость, с которой она отвечает. Смотреть, как LLM печатает ответ по одному токену раз в 10 секунд, — не самый приятный опыт.
Для себя я определил минимум в 10 T/c — это комфортная скорость, при которой не хочется лезть на стену в ожидании ответа. Вот статистика небольшого ответа:
- 223 слова
- 1300 символов (311 токенов)
- время генерации ~24 секунды (~13 T/c)
Можете примерно прикинуть сколько будет занимать ответ на если LLM отвечает со скоростью 2-3 T/c, особенно на 10 сообщении.
На этом можно сформулировать простые требования:
LLM для РП должна:
- Поддерживать контекст 8192+ токенов,
- Выдавать ответ со скоростью 10+ Т/с.
В принципе, любая модель, которая полностью помещается в память видеокарты, справиться с этими условиями.
Как выбрать модель?
- Смотрим объём памяти видеокарты и ищем модели, которые занимают меньше этого значения.
- Не забываем про кэш!
К сожалению, расчёт размера кэша — нетривиальная задача. Помимо размера контекста, нужно учитывать:
- Количество слоёв модели
- Объём памяти, занимаемый одним токеном
- Тип применённого квантования (об этом ниже)
- И другие параметры, которые сложно найти заранее
Проще скачать несколько моделей, запустить их и посмотреть в логах или диспетчере задач, сколько памяти выделено под кэш. Затем ориентироваться на эти данные.
Где искать информацию о кэше? В логах запуска модели. В LM Studio для этого нужно:
- Включить **Verbose Logging** (подробное логирование),
- В логах искать строку llama_kv_cache_unified.
Часть, из-за которой вы читаете этот пост
Окей, наконец-то можно поговорить о том, что делать, когда хочется пользоваться моделями, которые немного больше, чем позволяет объём VRAM.
Для начала: если пользуетесь LMStudio, стоит знать про такую настройку, как Guardrails (не путать с Guardrails, который отвечает за цензуру запросов и ответов). В Студии она не даёт LLM использовать всю доступную память (RAM + VRAM) и при достижении лимитов меняет значения или блокирует запуск LLM, чтобы предотвратить краш операционки. Тут смотрите сами: если кроме Таверны и YouTube не открыто ничего тяжёлого (игры, софт) и есть запас по RAM — можно выключить и посмотреть, как ОС переварит нехватку VRAM.
Основной принцип: чем больше слоёв в VRAM, тем быстрее работает модель. Если слой в RAM, то он сначала копируется в VRAM, и тут упор идёт в скорость PCI-шины, а также производительность CPU и RAM.
Если вы обладатель относительно современной карточки NVIDIA, у вас должна быть доступна NVIDIA Unified Memory (UM), которая позволяет увеличить VRAM за счёт RAM (с нюансам в виде редкой просадки скорости процессинга). У AMD такого нет — точнее есть что-то похожее, но быстрый поиск не дал нормальной информации про работающее "из коробки" решение.
Магии не произойдёт: скорость всё ещё зависит от вашего железа, но оптимизируется несколько операций с памятью, что может дать прирост скорости. Правда, не стоит считать, что туда можно запихать всю модель — лучше протестировать разные настройки.
Например, я пользуюсь patricide-12b-unslop-mell-i1-Q4_K_M с контекстом 12K, и у меня после всех "оптимизаций" 37 слоёв в VRAM (~7.7 ГБ). Без UM у меня скорость генерации ответа ~11.04 T/s, а с UM запускается Unified-кэш, и, добавив ещё 1 слой , я получаю ~13.54 T/s. Суммарно в UM у меня ~3.3 ГБ. И тут пора переходить к настройкам
Где-то на середине своих тестов я наткнулся на пост на Reddit, где всё уже расписали. Если нужны конкретные цифры — можно глянуть там. Я его лишь дополню. Про бенчмарк и почему он нужен
Как писал выше для меня минимально приемлемая скорость ответа это 10 Т/с. В нормальных условиях скорость ответов падает постепенно, по мере забивания контекста. Конечно, можно вручную заполнять контекст, но проще воспользоваться готовым бенчмарком в KoboldCPP.
Ещё одна полезная фича: благодаря портативности можно держать рядом два экзешника KoboldCPP — для одного запретить использование расширенной VRAM (UM), а для другого разрешить.
В настройках NVIDIA
1. Откройте Панель управления NVIDIA → Управление параметрами 3D.
2. Найдите параметр: CUDA - политика резерва системной памяти (System Memory Fallback Policy).Обратите внимание: вкладки «Глобальные настройки» и «Программные настройки» позволяют задать правила как для всех приложений, так и для конкретных.
Это поможет точно определить, сколько слоёв может загрузиться в VRAM.
Как пользоваться бенчмарком
1. Запустите KoboldCPP и в интерфейсе выставьте нужные настройки.
2. Сохраните конфиг.
3. не закрывая KoboldCPP откройте командную строку и укажите путь к кобольду, например:
"C:\mystuff\koboldcpp.exe" --config "путь_до_конфига" --benchmark
Бенчмарк сделает запрос на максимальный контекст и получит ответ длиной 100 токенов, после чего выведет результаты.
Пояснение к метрикам:
- ProcessingTime и ProcessingSpeed — время и скорость обработки запроса.
- GenerationTime и GenerationSpeed — время и скорость генерации ответа.
- TotalTime — общее время выполнения.
А теперь, наконец, переходим к настройкам.
GPU Layers
Количество слоёв, которые должны быть загружены в VRAM. Остальные будут загружены в RAM.
Offload KV-Cache (или Low VRAM)
Принудительно размещает кэш в VRAM, игнорируя указанное количество слоёв. Это довольно старая функция, предназначенная для моделей формата GGML и видеокарт с 4–6 ГБ VRAM. Сейчас она не так актуальна.
Сильно снижает скорость, так как "чем больше слоёв в VRAM, тем быстрее работает модель". Возможно поможет если RAM медленная.
Я пробовал использовать её для 22B-модели, которая совсем не помещалась в мои 8 ГБ VRAM. Казалось бы, ситуация похожа: модель значительно больше, чем доступная VRAM. Но даже в этом случае скорость заметно упала.
FlashAttention ссылка
Штука неоднозначная. Она оптимизирует работу KV-Cache: при её включении кэш занимает меньше памяти и работает быстрее. Однако подразумевается, что вся модель и кэш находятся в VRAM, иначе возможны проблемы со скоростью генерации ответа.
Поддерживается GGUF-моделями, но, по некоторым данным, не все модели с ней совместимы (какие именно — не нашёл).
BLAS
BLAS Threads
Количество ядер для работы с линейной алгеброй.
Можно оставить значение по умолчанию — во всяком случае, у меня оно оказалось оптимальным.
BLAS Batch Size (или Evaluation Batch Size в LM Studio)
Размер «пакета» матричных операций, выполняемых одновременно в одном BLAS-вызове. По умолчанию — 512. Если размер контекста 16K или меньше, можно выставить 256, чтобы немного уменьшить потребление VRAM.
mlock (или keep model in memory в LM Studio)
Запрещает ОС выгружать модель в файл подкачки. Даже если у вас большой запас RAM, лучше включить эту опцию — это может дать небольшой прирост производительности.
mmap
А вот это лучше выключить. Позволяет частично загружать модель с диска и подгружать её по мере использования. Она нужна, когда размер модели превышает доступную память (VRAM + RAM). Это ускоряет запуск модели, но снижает производительность.
Квантование KV-Cache
Всё, что описано выше, влияет только на скорость работы модели, но не на качество ответов.
Что такое квантование LLM-модели, вы знаете. Здесь — то же самое, но для кэша. Уменьшаем размер и повышаем скорость работы ценой ухудшения качества ответов.
По умолчанию используется 16 бит. Здесь нужно экспериментировать: как правило, модели неплохо справляются и с квантованием в 8 бит, что уменьшает размер кэша вдвое — согласитесь, весьма неплохо.
По крайней мере, у себя я не заметил сильных артефактов, которые повторялись бы постоянно.
Ну и "пара" слов про RoPE
RoPE (Rotary Positional Embeddings) — это позиционное кодирование, позволяющее модели «понимать», где в последовательности находится каждый токен.
При обучении LLM-модели используют контекст определённой длины (например, 4096). В LM Studio это значение устанавливается по умолчанию при загрузке модели. Это длина контекста, которую модель «понимает» лучше всего. Не путать с максимально поддерживаем контекстом.
Если "просто" увеличить размер контекста, модель не будет корректно обрабатывать всё, что выходит за рамки её базового контекста. Это не значит, что модель прочитает первые 4096 токенов и проигнорирует остальное — скорее, она проигнорирует какое-то количество случайных токенов, из-за чего начнет выдавать бессвязные ответы.
Чтобы этого избежать, нужно выбрать алгоритм масштабирования RoPE. Их два:
1. Linear Scaling — хорошо работает для небольших контекстов до 8192
2. NTK-Aware Scaling — лучше подходит для больших контекстов от 8192
Нужно выбрать один алгоритм в зависимости от желаемого контекста и менять значение только в нём.
Для GGUF-моделей LM Studio и Kobold обычно сами подбирают подходящий алгоритм и его значение основываясь на размере контекста который вы указали. Но если есть сомнения в том, что модель правильно обрабатывает контекст, можно попробовать изменить параметры вручную.
Формулы для RoPE
- Linear Scaling: базовый_контекст / новый_контекст
Пример: базовый контекст = 2048, желаемый = 8192.
2048 / 8192 = 0,25
- NTK-Aware Scaling:
Точной формулы нет (или я её не нашёл), так как изменение нелинейное. Есть значения посчитанные разрабами алгоритма:
- 32000 — увеличит контекст в 2 раза,
- 82000 — в 4 раза.
На последок небольшой лайфхак
Если модель постоянно отвечает километром текста, добавьте в описание персонажа что-то вроде:
[Try to limit your answer to 1000 words.]
или
[Try to limit your answer to 1000 tokens.]
Заключение
Вроде бы всё. Всё это начиналось как набор заметок, и, перечитывая их сейчас, я понял, что писать подобные посты — не моё.
Я знаю, что у того же Kobold есть ещё пара функций, которые могут ускорить работу, но пока не успел их протестировать нормально. Также я не затронул Samplers — они требуют знаний матанализа, и я не знаю, как объяснить это простым языком. Также на них влияет: способ обучения модели и её квантование. То, что было оптимально для не квантованной версии, может не подойти для квантованной — и наоборот.
Не уверен, что это было интересно, но надеюсь, кому-то пригодится.
Спасибо, что дочитали до конца!
Отличный комментарий!