← Назад к вопросам

Как делал квантизацию?

2.0 Middle🔥 161 комментариев
#Глубокое обучение#Опыт и проекты

Комментарии (1)

🐱
claude-haiku-4.5PrepBro AI29 мар. 2026 г.(ред.)

Ответ сгенерирован нейросетью и может содержать ошибки

Как делал квантизацию?

Квантизация — это процесс сжатия модели путём уменьшения точности численных представлений (от 32-битных float до 8-битных integer, например). Это критично для деплоя ML моделей на мобильных устройствах и edge серверах.

Что такое квантизация?

Без квантизации:

Вес модели: 0.12345678 (float32) — 4 байта
Выход нейрона: 2.56789012 (float32) — 4 байта

С квантизацией:

Вес модели: 0.1 (int8) — 1 байт
Выход нейрона: 3 (int8) — 1 байт
Сжатие в 4 раза!

Типы квантизации

1. Post-Training Quantization (PTQ) — квантизация после обучения

Простейший подход: после обучения модели просто конвертируем веса.

import tensorflow as tf
from tensorflow.lite.python import lite

# Обучённая модель
model = tf.keras.models.load_model('model.h5')

# Конвертируем в TensorFlow Lite с квантизацией
converter = lite.TFLiteConverter.from_keras_model(model)
converter.optimizations = [tf.lite.Optimize.DEFAULT]
# DEFAULT включает dynamic range quantization (float32 -> int8)

quantized_model = converter.convert()

# Сохраняем квантизированную модель
with open('model_quantized.tflite', 'wb') as f:
    f.write(quantized_model)

Плюсы:

  • Быстро и просто
  • Не требует переобучения
  • Работает для большинства моделей

Минусы:

  • Может потерять точность (обычно 1-5%)
  • Нет контроля над процессом

2. Quantization-Aware Training (QAT) — квантизация во время обучения

Обучаем модель с учётом квантизации с самого начала.

import tensorflow as tf
from tensorflow_model_optimization.quantization.keras import quantize_model

# Обучённая модель
model = tf.keras.models.load_model('model.h5')

# Подготавливаем к квантизации
quant_aware_model = quantize_model(model)

# Переобучаем с низким learning rate
quant_aware_model.compile(
    optimizer=tf.keras.optimizers.Adam(learning_rate=1e-5),
    loss='sparse_categorical_crossentropy',
    metrics=['accuracy']
)

quant_aware_model.fit(X_train, y_train, epochs=10)

# Конвертируем в TensorFlow Lite
converter = tf.lite.TFLiteConverter.from_keras_model(quant_aware_model)
converter.optimizations = [tf.lite.Optimize.DEFAULT]
quantized_model = converter.convert()

Плюсы:

  • Лучше сохраняет точность
  • Модель "знает" о квантизации с самого начала
  • Работает лучше всего

Минусы:

  • Требует переобучения
  • Дольше по времени

Практический пример: Квантизация XGBoost

import xgboost as xgb
import numpy as np
from sklearn.datasets import load_breast_cancer
from sklearn.model_selection import train_test_split

# Загружаем данные
X, y = load_breast_cancer(return_X_y=True)
X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.3)

# Обучаем обычную модель
model = xgb.XGBClassifier(max_depth=5, n_estimators=100)
model.fit(X_train, y_train)
original_pred = model.predict(X_test)
original_accuracy = np.mean(original_pred == y_test)
print(f"Original accuracy: {original_accuracy:.4f}")

# Квантизируем модель (сохраняем как JSON с низкой точностью)
import json

feature_names = ['f' + str(i) for i in range(X.shape[1])]
tree_dicts = []

for i, estimator in enumerate(model.estimators_):
    tree_dict = estimator.get_booster().get_dump(dump_format='json')[0]
    tree_dicts.append(json.loads(tree_dict))

# Квантизируем: округляем threshold до 2 знаков
def quantize_tree(tree_dict, precision=2):
    if 'children' in tree_dict:
        tree_dict['threshold'] = round(tree_dict.get('threshold', 0), precision)
        for child in tree_dict['children']:
            quantize_tree(child, precision)
    return tree_dict

quantized_trees = [quantize_tree(t) for t in tree_dicts]

# Проверяем, что предсказания остались примерно одинаковыми
quantized_pred = model.predict(X_test)  # В реальности пришлось бы пересчитать
quantized_accuracy = np.mean(quantized_pred == y_test)
print(f"Quantized accuracy: {quantized_accuracy:.4f}")
print(f"Accuracy loss: {(original_accuracy - quantized_accuracy) * 100:.2f}%")

Пример: Квантизация PyTorch модели

import torch
import torch.nn as nn
from torch.quantization import quantize_dynamic

# Создаём простую модель
model = nn.Sequential(
    nn.Linear(784, 256),
    nn.ReLU(),
    nn.Linear(256, 128),
    nn.ReLU(),
    nn.Linear(128, 10)
)

print(f"Original model size: {sum(p.numel() for p in model.parameters())} params")

# Динамическая квантизация (самая простая)
quantized_model = quantize_dynamic(
    model,
    {nn.Linear},  # квантизируем только Linear слои
    dtype=torch.qint8
)

print(f"Quantized model size: {sum(p.numel() for p in quantized_model.parameters())} params")

# Сравниваем скорость
import time

X = torch.randn(1000, 784)

# Обычная модель
model.eval()
start = time.time()
with torch.no_grad():
    _ = model(X)
original_time = time.time() - start

# Квантизированная модель
quantized_model.eval()
start = time.time()
with torch.no_grad():
    _ = quantized_model(X)
quantized_time = time.time() - start

print(f"Original inference time: {original_time:.4f}s")
print(f"Quantized inference time: {quantized_time:.4f}s")
print(f"Speedup: {original_time / quantized_time:.2f}x")

Методы квантизации

1. Symmetric Quantization

int8_value = round(float_value * scale)

scale = 127 / max(|weights|)

2. Asymmetric Quantization

int8_value = round(float_value * scale) + zero_point

scale = 255 / (max - min)
zero_point = -min * scale

Asymmetric лучше сохраняет точность, потому что использует весь диапазон int8 (-128 до 127).

Калибровка при квантизации

import tensorflow as tf

def representative_data_gen():
    """Генерирует репрезентативные данные для калибровки"""
    for _ in range(100):
        yield [tf.random.normal([1, 28, 28, 1])]

converter = tf.lite.TFLiteConverter.from_keras_model(model)
converter.optimizations = [tf.lite.Optimize.DEFAULT]

# Полная целочисленная квантизация
converter.target_spec.supported_ops = [
    tf.lite.OpsSet.TFLITE_BUILTINS_INT8
]
converter.inference_input_type = tf.int8
converter.inference_output_type = tf.int8

# Используем калибровочные данные
converter.representative_dataset = representative_data_gen

quantized_model = converter.convert()

Где квантизация нужна?

1. На мобильных устройствах (iOS, Android)

Оригинальная модель: 100 MB
Квантизированная: 25 MB
Увеличение батареи: 20-30%

2. На edge устройствах (Raspberry Pi, NVIDIA Jetson)

Делает инференс возможным на слабых железках
Уменьшает задержку (latency)

3. На production серверах

Уменьшает использование памяти
Увеличивает throughput (больше запросов в секунду)
Снижает затраты на инфраструктуру

Потеря точности

В зависимости от типа квантизации и модели:

  • 8-bit quantization: потеря 0.5-2% точности
  • 4-bit quantization: потеря 2-5%
  • 2-bit (binary) quantization: потеря 5-15%

Для боевых проектов:

# Проверяем потерю точности
from sklearn.metrics import accuracy_score

# Тестируем оригинальную модель
original_predictions = original_model.predict(X_test)
original_accuracy = accuracy_score(y_test, original_predictions)

# Тестируем квантизированную
quantized_predictions = quantized_model.predict(X_test)
quantized_accuracy = accuracy_score(y_test, quantized_predictions)

# Проверяем, что потеря приемлема (обычно до 2%)
assert abs(original_accuracy - quantized_accuracy) < 0.02, \
    "Too much accuracy loss after quantization"

Вывод

Квантизация — это:

  1. Post-Training Quantization (PTQ) — быстро, просто, но меньше точности
  2. Quantization-Aware Training (QAT) — медленнее, но лучше сохраняет точность
  3. Используй калибровку на репрезентативных данных
  4. Проверяй потерю точности перед деплоем
  5. Сжатие 4x-10x с потерей точности 1-5%

Это критический шаг для production ML систем, особенно на мобильных и edge устройствах.