Конвертація моделей у TensorRT
При інференсі BERT-base на T4 з batch=8 затримка в PyTorch FP32 становить ~12ms — для real-time систем це забагато. TensorRT знижує latency до 2.9ms у FP16 та 1.8ms у INT8. Розбираємося, як цього досягти на практиці.
Ми спеціалізуємося на конвертації моделей будь-якої складності: від BERT до LLaMA. Виконали 20+ проєктів. Гарантуємо сумісність і прискорення. Наші інженери сертифіковані NVIDIA. Замовте конвертацію — ми підготуємо оптимізований engine за 3–10 днів. Зв'яжіться з нами для оцінки вашого проєкту.
Як TensorRT прискорює інференс?
TensorRT оптимізує граф обчислень: ф'юзінг шарів, видалення dead-операцій, вибір оптимальних kernel-реалізацій під конкретну GPU. Додатково застосовує precision scaling (FP16, INT8) з мінімальною втратою точності. Результат — до 8x прискорення порівняно з FP32 PyTorch. NVIDIA TensorRT Documentation підтверджує ці показники.
Конвертація з ONNX у TensorRT
import tensorrt as trt TRT_LOGGER = trt.Logger(trt.Logger.WARNING) def build_engine(onnx_path: str, engine_path: str, fp16: bool = True, int8: bool = False): builder = trt.Builder(TRT_LOGGER) network = builder.create_network( 1 << int(trt.NetworkDefinitionCreationFlag.EXPLICIT_BATCH) ) parser = trt.OnnxParser(network, TRT_LOGGER) with open(onnx_path, "rb") as f: if not parser.parse(f.read()): for i in range(parser.num_errors): print(f"ONNX parse error: {parser.get_error(i)}") raise RuntimeError("Failed to parse ONNX") config = builder.create_builder_config() config.set_memory_pool_limit(trt.MemoryPoolType.WORKSPACE, 4 * 1024 ** 3) # 4 GB if fp16 and builder.platform_has_fast_fp16: config.set_flag(trt.BuilderFlag.FP16) if int8: config.set_flag(trt.BuilderFlag.INT8) # Потрібен calibrator для INT8 config.int8_calibrator = MyCalibrator(calibration_data) # Dynamic shapes — важливо для змінної довжини входу profile = builder.create_optimization_profile() profile.set_shape( "input_ids", min=(1, 1), opt=(8, 128), max=(32, 512) ) config.add_optimization_profile(profile) serialized_engine = builder.build_serialized_network(network, config) with open(engine_path, "wb") as f: f.write(serialized_engine) print(f"Engine saved to {engine_path}") Інференс з TensorRT
import tensorrt as trt import numpy as np import pycuda.driver as cuda import pycuda.autoinit class TRTInferenceSession: def __init__(self, engine_path: str): runtime = trt.Runtime(TRT_LOGGER) with open(engine_path, "rb") as f: self.engine = runtime.deserialize_cuda_engine(f.read()) self.context = self.engine.create_execution_context() self.inputs = [] self.outputs = [] self.bindings = [] for binding in self.engine: shape = self.engine.get_tensor_shape(binding) size = trt.volume(shape) * np.dtype(np.float32).itemsize device_mem = cuda.mem_alloc(size) self.bindings.append(int(device_mem)) if self.engine.get_tensor_mode(binding) == trt.TensorIOMode.INPUT: self.inputs.append({"name": binding, "mem": device_mem, "shape": shape}) else: self.outputs.append({"name": binding, "mem": device_mem, "shape": shape}) self.stream = cuda.Stream() def infer(self, inputs: dict[str, np.ndarray]) -> dict[str, np.ndarray]: for inp in self.inputs: data = inputs[inp["name"]].astype(np.float32).ravel() cuda.memcpy_htod_async(inp["mem"], data, self.stream) self.context.execute_async_v2(self.bindings, self.stream.handle) results = {} for out in self.outputs: output = np.empty(out["shape"], dtype=np.float32) cuda.memcpy_dtoh_async(output, out["mem"], self.stream) results[out["name"]] = output self.stream.synchronize() return results INT8 Calibration
INT8 потребує калібрувальних даних для визначення діапазонів значень:
class BertCalibrator(trt.IInt8EntropyCalibrator2): def __init__(self, calibration_texts: list[str], cache_file: str = "calibration.cache"): super().__init__() self.tokenizer = AutoTokenizer.from_pretrained("bert-base-uncased") self.cache_file = cache_file self.data = iter( self.tokenizer(calibration_texts, padding="max_length", truncation=True, max_length=128, return_tensors="np") ) self.device_input = cuda.mem_alloc(128 * 4) # input_ids buffer def get_batch_size(self) -> int: return 16 def get_batch(self, names: list[str]) -> list | None: try: batch = {k: next(self.data) for k in ["input_ids", "attention_mask"]} cuda.memcpy_htod(self.device_input, batch["input_ids"].astype(np.int32).ravel()) return [int(self.device_input)] except StopIteration: return None def read_calibration_cache(self) -> bytes | None: if os.path.exists(self.cache_file): with open(self.cache_file, "rb") as f: return f.read() return None def write_calibration_cache(self, cache: bytes) -> None: with open(self.cache_file, "wb") as f: f.write(cache) Використання torch-tensorrt
Більш простий шлях для PyTorch моделей:
import torch_tensorrt trt_model = torch_tensorrt.compile( model, inputs=[ torch_tensorrt.Input( min_shape=[1, 1], opt_shape=[8, 128], max_shape=[32, 512], dtype=torch.int32 ) ], enabled_precisions={torch.float16}, workspace_size=4 * 1024 ** 3, truncate_long_and_double=True ) torch.jit.save(trt_model, "bert_trt.ts") Типовий приріст продуктивності
На T4 GPU, BERT-base, batch=8, seq=128:
| Режим | Latency | Speedup |
|---|---|---|
| PyTorch FP32 | 12.3ms | 1x |
| PyTorch FP16 | 6.8ms | 1.8x |
| TensorRT FP16 | 2.9ms | 4.2x |
| TensorRT INT8 | 1.8ms | 6.8x |
Чому варто використовувати INT8 калібрування?
INT8 дає максимальний приріст швидкості (6-8x), але вимагає акуратного калібрування. Без нього точність може впасти на 2-5%. Ми використовуємо Entropy Calibrator 2, який мінімізує втрати. Якщо точність критична, залишаємо FP16 — він безпечніший і дає 4x прискорення. TensorRT INT8 також економить GPU-години: задача, що виконувалася годину на PyTorch FP32, з INT8 вирішується за 9 хвилин.
Типові помилки при конвертації
| Проблема | Причина | Рішення |
|---|---|---|
| Помилка парсингу ONNX | Непідтримувана операція (e.g., aten::view) |
Заміна на підтримувану або використання torch.onnx.export з opset_version=18 |
| Out of memory при білді | Нестача workspace | Збільшити workspace_size до 8-16 GB |
| Дроп точності INT8 > 5% | Непідходящий калібрувальний датасет | Використовувати репрезентативні дані, збільшити розмір датасету до 1000+ семплів |
| Dynamic shapes не працюють | Неправильний optimization profile | Перевірити min/opt/max, переконатися, що вхідні тензори позначені як dynamic |
| Просадка продуктивності на small batches | Домінування overhead | Використовувати фіксований batch size для real-time випадків |
Етапи конвертації: покроковий how-to
-
Експорт моделі в ONNX: Використовуйте
torch.onnx.exportзdynamic_axesдля трансформерів. -
Перевірка сумісності: Прогнати ONNX через
onnx.checkerтаonnxsim. - Збір калібрувального датасету (для INT8): 500–2000 семплів з вашої предметної області.
- Побудова engine: Вибір precision, налаштування dynamic shapes, запуск білдера.
- Валідація: Порівняти виходи TensorRT та оригінальної моделі на тестових даних.
- Інтеграція: Адаптувати пайплайн під TensorRT runtime (Python або C++).
- Профілювання: Виміряти latency p99, перевірити стабільність.
Що входить в роботу
Результат конвертації — не просто engine, а повний пакет:
- Оптимізований TensorRT engine у форматі
.plan. - Код інференс-сесії на Python або C++ з прикладами.
- Калібрувальний датасет і скрипти калібрування (при INT8).
- Інтеграція у ваш пайплайн: контейнеризація, CI/CD.
- Документація з описом конфігурацій та рекомендацій щодо масштабування.
- Підтримка після інтеграції — консультації з профілювання та тюнінгу.
Як ми працюємо
- Аналіз: Вивчаємо модель, виявляємо вузькі місця (наприклад, неефективні
view-операції). - Експорт: Конвертуємо в ONNX, усуваємо помилки сумісності.
- Калібрування: Підбираємо калібрувальні дані, налаштовуємо Entropy Calibrator 2.
- Генерація engine: Збираємо TensorRT з dynamic shapes та обраною точністю.
- Інтеграція: Вбудовуємо engine у ваш інференс-пайплайн (Python/C++).
- Документація: Передаємо конфіги, код, інструкції.
Термін виконання — від 3 до 10 днів залежно від складності моделі. Вартість розраховується індивідуально. Замовте конвертацію — ми підготуємо оптимізований engine за 3–10 днів.
Наш досвід
Багаторічний досвід в AI/ML, 20+ проєктів з оптимізації інференсу. Працювали з моделями BERT, GPT-2/3, LLaMA, YOLOv8, ResNet. Гарантуємо прискорення до заявлених значень. Звертайтеся за консультацією — оцінимо ваш проєкт.







