Saltar al contenido principal

Cuantización y despliegue de modelos

Este artículo presenta cómo cuantizar modelos KataGo para reducir los requisitos de recursos, así como soluciones de despliegue en diversas plataformas.


Visión general de técnicas de cuantización

¿Por qué se necesita cuantización?

PrecisiónTamañoVelocidadPérdida de precisión
FP32100%Base0%
FP1650%+50%~0%
INT825%+100%<1%

Tipos de cuantización

Cuantización post-entrenamiento (PTQ)
├── Simple y rápido
├── No requiere re-entrenamiento
└── Puede haber pérdida de precisión

Entrenamiento consciente de cuantización (QAT)
├── Mayor precisión
├── Requiere re-entrenamiento
└── Más complejo

FP16 Media precisión

Concepto

Convertir números de punto flotante de 32 bits a 16 bits:

# Conversión FP32 → FP16
model_fp16 = model.half()

# Inferencia
with torch.cuda.amp.autocast():
output = model_fp16(input.half())

Configuración KataGo

# config.cfg
useFP16 = true # Habilitar inferencia FP16
useFP16Storage = true # Almacenamiento de resultados intermedios en FP16

Impacto en el rendimiento

Serie GPUAceleración FP16
GTX 10xxNinguna (sin Tensor Core)
RTX 20xx+30-50%
RTX 30xx+50-80%
RTX 40xx+80-100%

Cuantización INT8

Proceso de cuantización

import torch.quantization as quant

# 1. Preparar modelo
model.eval()
model.qconfig = quant.get_default_qconfig('fbgemm')

# 2. Preparar cuantización
model_prepared = quant.prepare(model)

# 3. Calibrar (usar datos representativos)
with torch.no_grad():
for data in calibration_loader:
model_prepared(data)

# 4. Convertir a modelo cuantizado
model_quantized = quant.convert(model_prepared)

Datos de calibración

def create_calibration_dataset(num_samples=1000):
"""Crear dataset de calibración"""
samples = []

# Muestrear de partidas reales
for game in random_games(num_samples):
position = random_position(game)
features = encode_state(position)
samples.append(features)

return samples

Notas

  • La cuantización INT8 requiere datos de calibración
  • Algunas capas pueden no ser adecuadas para cuantización
  • Es necesario probar la pérdida de precisión

Despliegue TensorRT

Proceso de conversión

import tensorrt as trt

def convert_to_tensorrt(onnx_path, engine_path):
logger = trt.Logger(trt.Logger.WARNING)
builder = trt.Builder(logger)
network = builder.create_network(
1 << int(trt.NetworkDefinitionCreationFlag.EXPLICIT_BATCH)
)
parser = trt.OnnxParser(network, logger)

# Parsear modelo ONNX
with open(onnx_path, 'rb') as f:
parser.parse(f.read())

# Configurar opciones de optimización
config = builder.create_builder_config()
config.max_workspace_size = 1 << 30 # 1GB

# Habilitar FP16
config.set_flag(trt.BuilderFlag.FP16)

# Construir motor
engine = builder.build_engine(network, config)

# Guardar
with open(engine_path, 'wb') as f:
f.write(engine.serialize())

Usar motor TensorRT

def inference_with_tensorrt(engine_path, input_data):
# Cargar motor
with open(engine_path, 'rb') as f:
engine = trt.Runtime(logger).deserialize_cuda_engine(f.read())

context = engine.create_execution_context()

# Asignar memoria
d_input = cuda.mem_alloc(input_data.nbytes)
d_output = cuda.mem_alloc(output_size)

# Copiar entrada
cuda.memcpy_htod(d_input, input_data)

# Ejecutar inferencia
context.execute_v2([int(d_input), int(d_output)])

# Obtener salida
output = np.empty(output_shape, dtype=np.float32)
cuda.memcpy_dtoh(output, d_output)

return output

Exportación ONNX

PyTorch → ONNX

import torch.onnx

def export_to_onnx(model, output_path):
model.eval()

# Crear entrada de ejemplo
dummy_input = torch.randn(1, 22, 19, 19)

# Exportar
torch.onnx.export(
model,
dummy_input,
output_path,
input_names=['input'],
output_names=['policy', 'value', 'ownership'],
dynamic_axes={
'input': {0: 'batch_size'},
'policy': {0: 'batch_size'},
'value': {0: 'batch_size'},
'ownership': {0: 'batch_size'}
},
opset_version=13
)

Validar modelo ONNX

import onnx
import onnxruntime as ort

# Validar estructura del modelo
model = onnx.load("model.onnx")
onnx.checker.check_model(model)

# Probar inferencia
session = ort.InferenceSession("model.onnx")
output = session.run(None, {'input': input_data})

Despliegue multiplataforma

Despliegue en servidor

# docker-compose.yml
version: '3'
services:
katago:
image: katago/katago:latest
deploy:
resources:
reservations:
devices:
- driver: nvidia
count: 1
capabilities: [gpu]
volumes:
- ./models:/models
- ./config:/config
command: >
katago analysis
-model /models/kata-b18c384.bin.gz
-config /config/analysis.cfg

Integración en aplicación de escritorio

# Integrar KataGo en aplicación Python
import subprocess
import json

class KataGoProcess:
def __init__(self, katago_path, model_path):
self.process = subprocess.Popen(
[katago_path, 'analysis', '-model', model_path],
stdin=subprocess.PIPE,
stdout=subprocess.PIPE,
text=True
)

def analyze(self, moves):
query = {
'id': 'query1',
'moves': moves,
'rules': 'chinese',
'komi': 7.5,
'boardXSize': 19,
'boardYSize': 19
}
self.process.stdin.write(json.dumps(query) + '\n')
self.process.stdin.flush()

response = self.process.stdout.readline()
return json.loads(response)

Despliegue en dispositivos móviles

iOS (Core ML)

import coremltools as ct

# Convertir a Core ML
mlmodel = ct.convert(
model,
inputs=[ct.TensorType(shape=(1, 22, 19, 19))],
minimum_deployment_target=ct.target.iOS15
)

mlmodel.save("KataGo.mlmodel")

Android (TensorFlow Lite)

import tensorflow as tf

# Convertir a TFLite
converter = tf.lite.TFLiteConverter.from_saved_model(model_path)
converter.optimizations = [tf.lite.Optimize.DEFAULT]
converter.target_spec.supported_types = [tf.float16]

tflite_model = converter.convert()

with open('katago.tflite', 'wb') as f:
f.write(tflite_model)

Sistemas embebidos

Raspberry Pi

# Usar backend Eigen (solo CPU)
./katago gtp -model kata-b10c128.bin.gz -config rpi.cfg
# rpi.cfg - Configuración optimizada para Raspberry Pi
numSearchThreads = 4
maxVisits = 100
nnMaxBatchSize = 1

NVIDIA Jetson

# Usar backend CUDA
./katago gtp -model kata-b18c384.bin.gz -config jetson.cfg

Comparación de rendimiento

Rendimiento de diferentes métodos de despliegue

Método de despliegueHardwarePlayouts/seg
CUDA FP32RTX 3080~3000
CUDA FP16RTX 3080~5000
TensorRT FP16RTX 3080~6500
OpenCLM1 Pro~1500
Core MLM1 Pro~1800
TFLitePixel 7~50
EigenRPi 4~15

Comparación de tamaño de modelo

FormatoTamaño b18c384
Original (.bin.gz)~140 MB
ONNX FP32~280 MB
ONNX FP16~140 MB
TensorRT FP16~100 MB
TFLite FP16~140 MB

Lista de verificación de despliegue

  • Elegir la precisión de cuantización adecuada
  • Preparar datos de calibración (INT8)
  • Exportar al formato objetivo
  • Verificar que la pérdida de precisión es aceptable
  • Probar el rendimiento en la plataforma objetivo
  • Optimizar el uso de memoria
  • Establecer flujo de despliegue automatizado

Lectura adicional