تكميم النموذج والنشر
يقدم هذا المقال كيفية تكميم نماذج KataGo لتقليل متطلبات الموارد، وحلول النشر على مختلف المنصات.
يقلّل التكميم حجم النموذج ويسرّع الاستدلال عبر خفض دقة الأرقام: تُوفّر دقة FP16 نصف الذاكرة بدون فقدان دقة يُذكر، بينما تضغط INT8 الحجم إلى الربع؛ ينقسم التكميم إلى التكميم بعد التدريب (PTQ، بسيط وسريع) والتدريب الواعي بالتكميم (QAT، أعلى دقة لكنه يتطلب إعادة تدريب)، ثم يُنشر على مختلف المنصات بالاستعانة بأدوات مثل TensorRT.
نظرة عامة على تقنيات التكميم
لماذا نحتاج التكميم؟
| الدقة | الحجم | السرعة | فقدان الدقة |
|---|---|---|---|
| FP32 | 100% | أساس | 0% |
| FP16 | 50% | +50% | ~0% |
| INT8 | 25% | +100% | <1% |
أنواع التكميم
التكميم بعد التدريب (PTQ)
├── بسيط وسريع
├── لا يتطلب إعادة التدريب
└── قد يكون هناك فقدان في الدقة
التدريب الواعي بالتكميم (QAT)
├── دقة أعلى
├── يتطلب إعادة التدريب
└── أكثر تعقيداً
FP16 نصف الدقة
المفهوم
تحويل أرقام الفاصلة العائمة من 32 بت إلى 16 بت:
# تحويل FP32 → FP16
model_fp16 = model.half()
# الاستدلال
with torch.cuda.amp.autocast():
output = model_fp16(input.half())
إعدادات KataGo
# config.cfg
useFP16 = true # تفعيل استدلال FP16
useFP16Storage = true # تخزين النتائج الوسيطة بـ FP16
تأثير الأداء
| سلسلة GPU | تسريع FP16 |
|---|---|
| GTX 10xx | لا يوجد (بدون Tensor Core) |
| RTX 20xx | +30-50% |
| RTX 30xx | +50-80% |
| RTX 40xx | +80-100% |
تكميم INT8
عملية التكميم
import torch.quantization as quant
# 1. إعداد النموذج
model.eval()
model.qconfig = quant.get_default_qconfig('fbgemm')
# 2. إعداد التكميم
model_prepared = quant.prepare(model)
# 3. المعايرة (باستخدام بيانات تمثيلية)
with torch.no_grad():
for data in calibration_loader:
model_prepared(data)
# 4. التحويل إلى نموذج مكمم
model_quantized = quant.convert(model_prepared)
بيانات المعايرة
def create_calibration_dataset(num_samples=1000):
"""إنشاء مجموعة بيانات المعايرة"""
samples = []
# أخذ عينات من مباريات فعلية
for game in random_games(num_samples):
position = random_position(game)
features = encode_state(position)
samples.append(features)
return samples
ملاحظات
- تكميم INT8 يتطلب بيانات معايرة
- بعض الطبقات قد لا تكون مناسبة للتكميم
- يجب اختبار فقدان الدقة
نشر TensorRT
عملية التحويل
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)
# تحليل نموذج ONNX
with open(onnx_path, 'rb') as f:
parser.parse(f.read())
# إعداد خيارات التحسين
config = builder.create_builder_config()
config.max_workspace_size = 1 << 30 # 1GB
# تفعيل FP16
config.set_flag(trt.BuilderFlag.FP16)
# بناء المحرك
engine = builder.build_engine(network, config)
# الحفظ
with open(engine_path, 'wb') as f:
f.write(engine.serialize())
استخدام محرك TensorRT
def inference_with_tensorrt(engine_path, input_data):
# تحميل المحرك
with open(engine_path, 'rb') as f:
engine = trt.Runtime(logger).deserialize_cuda_engine(f.read())
context = engine.create_execution_context()
# تخصيص الذاكرة
d_input = cuda.mem_alloc(input_data.nbytes)
d_output = cuda.mem_alloc(output_size)
# نسخ الإدخال
cuda.memcpy_htod(d_input, input_data)
# تنفيذ الاستدلال
context.execute_v2([int(d_input), int(d_output)])
# الحصول على الإخراج
output = np.empty(output_shape, dtype=np.float32)
cuda.memcpy_dtoh(output, d_output)
return output
تصدير ONNX
PyTorch → ONNX
import torch.onnx
def export_to_onnx(model, output_path):
model.eval()
# إنشاء إدخال عينة
dummy_input = torch.randn(1, 22, 19, 19)
# التصدير
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
)
التحقق من نموذج ONNX
import onnx
import onnxruntime as ort
# التحقق من هيكل النموذج
model = onnx.load("model.onnx")
onnx.checker.check_model(model)
# اختبار الاستدلال
session = ort.InferenceSession("model.onnx")
output = session.run(None, {'input': input_data})
النشر على مختلف المنصات
نشر الخوادم
# 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
تكامل تطبيقات سطح المكتب
# تضمين KataGo في تطبيق 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)
نشر الأجهزة المحمولة
iOS (Core ML)
import coremltools as ct
# التحويل إلى 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
# التحويل إلى 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)
الأنظمة المدمجة
Raspberry Pi
# استخدام واجهة Eigen (CPU فقط)
./katago gtp -model kata-b10c128.bin.gz -config rpi.cfg
# rpi.cfg - إعدادات Raspberry Pi المحسنة
numSearchThreads = 4
maxVisits = 100
nnMaxBatchSize = 1
NVIDIA Jetson
# استخدام واجهة CUDA
./katago gtp -model kata-b18c384.bin.gz -config jetson.cfg
مقارنة الأداء
أداء طرق النشر المختلفة
| طريقة النشر | الأجهزة | Playouts/ثانية |
|---|---|---|
| CUDA FP32 | RTX 3080 | ~3000 |
| CUDA FP16 | RTX 3080 | ~5000 |
| TensorRT FP16 | RTX 3080 | ~6500 |
| OpenCL | M1 Pro | ~1500 |
| Core ML | M1 Pro | ~1800 |
| TFLite | Pixel 7 | ~50 |
| Eigen | RPi 4 | ~15 |
مقارنة حجم النماذج
| التنسيق | حجم b18c384 |
|---|---|
| أصلي (.bin.gz) | ~140 MB |
| ONNX FP32 | ~280 MB |
| ONNX FP16 | ~140 MB |
| TensorRT FP16 | ~100 MB |
| TFLite FP16 | ~140 MB |
قائمة فحص النشر
- اختيار دقة التكميم المناسبة
- إعداد بيانات المعايرة (INT8)
- التصدير إلى التنسيق المستهدف
- التحقق من أن فقدان الدقة مقبول
- اختبار أداء المنصة المستهدفة
- تحسين استخدام الذاكرة
- بناء عملية نشر آلية
قراءات إضافية
- واجهات GPU والتحسين — تحسين الأداء الأساسي
- التقييم والاختبار المعياري — التحقق من الأداء بعد النشر
- التكامل مع مشروعك — أمثلة تكامل API