Skip to main content

Model Quantization & Deployment

This article introduces how to quantize KataGo models to reduce resource requirements, and deployment solutions for various platforms.

Quantization reduces model size and speeds up inference by lowering numerical precision: FP16 halves memory use with almost no accuracy loss, and INT8 can compress it to a quarter. Quantization comes in two forms, post-training quantization (PTQ, simple and fast) and quantization-aware training (QAT, more accurate but requires retraining), and the result is deployed to various platforms with tools such as TensorRT.


Quantization Techniques Overview​

Why Quantization?​

PrecisionSizeSpeedAccuracy Loss
FP32100%Baseline0%
FP1650%+50%~0%
INT825%+100%<1%

Quantization Types​


FP16 Half Precision​

Concept​

Convert 32-bit floating point to 16-bit:

# FP32 → FP16 conversion
model_fp16 = model.half()

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

KataGo Settings​

# config.cfg
useFP16 = true # Enable FP16 inference
useFP16Storage = true # FP16 intermediate storage

Performance Impact​

GPU SeriesFP16 Speedup
GTX 10xxNone (no Tensor Core)
RTX 20xx+30-50%
RTX 30xx+50-80%
RTX 40xx+80-100%

INT8 Quantization​

Quantization Process​

import torch.quantization as quant

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

# 2. Prepare for quantization
model_prepared = quant.prepare(model)

# 3. Calibration (use representative data)
with torch.no_grad():
for data in calibration_loader:
model_prepared(data)

# 4. Convert to quantized model
model_quantized = quant.convert(model_prepared)

Calibration Data​

def create_calibration_dataset(num_samples=1000):
"""Create calibration dataset"""
samples = []

# Sample from actual games
for game in random_games(num_samples):
position = random_position(game)
features = encode_state(position)
samples.append(features)

return samples

Notes​

  • INT8 quantization requires calibration data
  • Some layers may not be suitable for quantization
  • Need to test accuracy loss

TensorRT Deployment​

Conversion Process​

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)

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

# Set optimization options
config = builder.create_builder_config()
config.max_workspace_size = 1 << 30 # 1GB

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

# Build engine
engine = builder.build_engine(network, config)

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

Using TensorRT Engine​

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

context = engine.create_execution_context()

# Allocate memory
d_input = cuda.mem_alloc(input_data.nbytes)
d_output = cuda.mem_alloc(output_size)

# Copy input
cuda.memcpy_htod(d_input, input_data)

# Execute inference
context.execute_v2([int(d_input), int(d_output)])

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

return output

ONNX Export​

PyTorch → ONNX​

import torch.onnx

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

# Create sample input
dummy_input = torch.randn(1, 22, 19, 19)

# Export
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
)

Validate ONNX Model​

import onnx
import onnxruntime as ort

# Validate model structure
model = onnx.load("model.onnx")
onnx.checker.check_model(model)

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

Cross-Platform Deployment​

Server Deployment​

# 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

Desktop Application Integration​

# Embed KataGo in Python application
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)

Mobile Deployment​

iOS (Core ML)​

import coremltools as ct

# Convert to 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

# Convert to 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)

Embedded Systems​

Raspberry Pi​

# Use Eigen backend (CPU only)
./katago gtp -model kata-b10c128.bin.gz -config rpi.cfg
# rpi.cfg - Raspberry Pi optimized settings
numSearchThreads = 4
maxVisits = 100
nnMaxBatchSize = 1

NVIDIA Jetson​

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

Performance Comparison​

Performance by Deployment Method​

DeploymentHardwarePlayouts/sec
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

Model Size Comparison​

Formatb18c384 Size
Original (.bin.gz)~140 MB
ONNX FP32~280 MB
ONNX FP16~140 MB
TensorRT FP16~100 MB
TFLite FP16~140 MB

Deployment Checklist​

  • Select appropriate quantization precision
  • Prepare calibration data (INT8)
  • Export to target format
  • Validate acceptable accuracy loss
  • Test performance on target platform
  • Optimize memory usage
  • Set up automated deployment pipeline

Further Reading​