Skip to content

Latest commit

 

History

History
191 lines (117 loc) · 14.8 KB

File metadata and controls

191 lines (117 loc) · 14.8 KB

🚀 Методы ускорения LLM: дистилляция и квантование (и зачем всё это нужно)

⚡ Как сделать модели быстрее? | Время изучения: ~50 минут | Уровень: 🏗️ Продвинутый

📋 Содержание


🎯 Краткое введение

Большие языковые модели (LLM) мощные, но «тяжёлые»: им нужна память и время. На лекции разбираются два главных подхода, как сделать модели легче и быстрее.

🧩 Что изучаем:

  • 🎓 Дистилляция — учим маленькую модель вести себя как большая
  • 🔢 Квантование — храним и считаем числа меньшей разрядности
  • ⚡ LLM-специфичные оптимизации и архитектурные решения
  • 🛠️ Практические методы для реального применения

1️⃣ Дистилляция: «большой учитель, маленький ученик»

Ключевая идея. Есть модель-учитель (большая, уже обученная) и модель-ученик (меньше и быстрее). Мы передаём ученику знания учителя — не только правильные ответы, но и распределения вероятностей по вариантам ответа (soft labels). Это даёт больше подсказок, чем «жёсткая» метка класса. Аналогия: не просто сказать «ответ — B», а показать всё ранжирование: «B — 0.6, A — 0.3, C — 0.1».

Как это оптимизируется (без боли). К обычной кросс-энтропии добавляют меру «похожести распределений» — KL-дивергенцию между предсказаниями учителя и ученика. В упрощённом виде:

🤔 Простыми словами:

Функция потерь = Учёба на правильных ответах + Копирование стиля учителя

Где:
- Первая часть: ученик должен давать правильные ответы
- Вторая часть: ученик должен быть похож на учителя по "уверенности"
- λ (лямбда): насколько сильно слушаться учителя

Головой воспринимайте так: 1) не забываем верные ответы, 2) копируем стиль уверенности учителя. Параметр лямбда регулирует, «как внимательно слушать учителя».

Живой пример — DistilBERT. Ту же архитектуру BERT упростили (меньше слоёв), получили ≈40% меньше параметров, ≈60% быстрее, при этом ~95% качества исходного BERT по GLUE. Идея: «урезать в глубину» даёт заметный выигрыш по скорости при умеренной потере точности.

Памятка.

  • Soft-лейблы хранят «нюансы» уверенности → ученик лучше имитирует учителя.

  • Хорошая инициализация и баланс между CE и KL важны для стабильности обучения.


2️⃣ Квантование: «перепакуем числа, чтобы занимали меньше места»

Ключевая идея. Храним веса/активации не в float32/float16, а, например, в int8 (8 бит) — экономим память и ускоряем вычисления. Метафора: вы переупаковали чемодан — вещей столько же, но всё компактнее. В LLM это критично: огромные модели иначе просто не помещаются в память.

2️⃣.1️⃣ Базовые виды квантования

  • Симметричное: ноль остаётся нулём; достаточно одного коэффициента масштаба ss.
    Формулы:

🤔 Простыми словами (симметричное):

1. Делим исходное число на масштаб
2. Округляем до целого
3. Чтобы восстановить: умножаем на масштаб обратно
(с обрезкой в допустимый диапазон int8). Простой и быстрый вариант.
  • Асимметричное: добавляем смещение zz (zero-point), чтобы подогнать диапазон.

🤔 Простыми словами (асимметричное):

1. Делим исходное число на масштаб + добавляем смещение
2. Округляем и обрезаем в нужный диапазон
3. Восстанавливаем: масштаб × (число - смещение)
Точнее передаёт диапазон, но вычислительно сложнее. Аналогия: не только «масштабируем» линейкой, но и «сдвигаем» начало отчёта.
  • По гранулярности:
    per-tensor (быстрее, но грубее), per-channel / по группам (точнее), вплоть до «по-токенно». Для LLM пер-тензор часто грубоват, а групповой вариант — хороший компромисс.

  • Что квантовать:
    веса — легко (статичны); активации — сложнее (зависят от входа), поэтому используют статическую (по калибровочной выборке) или динамическую калибровку на лету.

  • Когда квантовать:
    PTQ (после обучения) — быстро и дёшево по данным; QAT (во время обучения) — дороже, но точнее.

2️⃣.2️⃣ Практические тонкости: «выбросы» (outliers)

В LLM выбросы особенно часто в активациях, и просто «обрезать» их нельзя — это рушит качество. Часто выбросы концентрируются в отдельных столбцах/строках, что позволяет придумать хитрые схемы, где «трудные» части обрабатываются по-особому.

2️⃣.3️⃣ Конкретные методы из практики

  • LLM.int8 (outlier-aware): «обычные» столбцы считаем в int8, а столбцы с выбросами — во float16 и затем склеиваем результат. Так почти всё быстрее и компактнее, а «трудные» места не портят точность. Порог «что считать выбросом» берут эмпирически (например, значения больше ~6).

  • GPTQ: вместо округления каждого веса по отдельности подбираем квантованную матрицу весов W′W', чтобы ∥WX−W′X∥|WX - W'X| была минимальна на калибровочных примерах. То есть оптимизируем сразу матрицу, а не отдельные числа.

  • SmoothQuant: «перекладываем сложность» с активаций на веса. Масштабируем активации вниз, веса вверх (и наоборот), чтобы пики в активациях сгладить — квантовать становится проще, качество держится. Работает как PTQ для int8, ускоряя инференс при малых потерях точности.


3️⃣ Мини-пример квантования (на пальцах)

Пусть у нас значения слоя лежат приблизительно в [−1.0,1.0][-1.0, 1.0]. Возьмём симметричное int8: диапазон q∈[−128,127]q \in [-128, 127].
Выберем масштаб s≈1.0127≈0.00787s \approx \frac{1.0}{127} \approx 0.00787.

  • Число x=0.52x=0.52:
    q=round(0.52/0.00787)≈66q=\text{round}(0.52/0.00787)\approx 66.
    Обратное: x^=s⋅q≈0.519\hat{x}=s\cdot q\approx 0.519.

  • Число x=−0.02x=-0.02:
    q≈round(−0.02/0.00787)=−3q\approx \text{round}(-0.02/0.00787)=-3,
    x^≈−0.0236\hat{x}\approx -0.0236.

Мы слегка теряем точность, но выигрываем в памяти/скорости — особенно заметно на больших матрицах. (В активациях часто лучше идёт асимметрия с нулевой точкой zz.)


4️⃣ Когда что выбирать (быстрый ориентир)

  • Нужно резко ускорить инференс без переобучения → начните с PTQ int8 + метод против выбросов (LLM.int8, SmoothQuant).

  • Есть время дообучитьQAT поможет сохранить точность.

  • Сильно урезать модель для продакшена на слабом железе → добавьте дистилляцию (например, уменьшить глубину, как в DistilBERT).


📝 Резюме (ключевые выводы)

  • Дистилляция учит «маленького» ученика копировать распределения «большого» учителя (CE + KL), что сохраняет качество при меньшем размере и большей скорости. Пример — DistilBERT: меньше параметров, быстрее, почти прежнее качество.

  • Квантование — это компактное представление чисел (int8 и др.): симметричное/асимметричное, per-tensor vs per-channel, веса vs активации, PTQ vs QAT. Главная проблема — выбросы в активациях, их лечат методами LLM.int8, GPTQ, SmoothQuant.

  • В реальных LLM обычно комбинируют несколько подходов (например, дистилляция + PTQ + обработка выбросов) для лучшего баланса «скорость—память—качество».


❓ Вопросы для закрепления

  1. Зачем в дистилляции нужны soft-лейблы и как роль KL-дивергенции отличается от роли кросс-энтропии? (Ответ в одном-двух предложениях.)

  2. Дайте формулы прямого/обратного преобразования для асимметричного квантования и объясните простыми словами смысл параметров ss и zz.

  3. В чём идея LLM.int8 и SmoothQuant? Чем они помогают именно против выбросов?


🔗 Связанные лекции


💻 Практика: Попробуйте BitsAndBytes для QLoRA или ONNX Runtime для оптимизации вывода!

💡 Подсказка

LLM.int8: выбросы обрабатывает в float16, остальное — в int8, потом склеивает. SmoothQuant: «перекладывает сложность» — масштабирует активации вниз, веса вверх, чтобы сгладить пики.


🔗 Связанные лекции


💻 Практические ресурсы


💡 Практика: Попробуйте BitsAndBytes для QLoRA или ONNX Runtime для оптимизации вывода!