Развертывание AI-модели для мостового крана: PyTorch до ONNX
Схема периферийного развёртывания AI-модели для мостового крана
Полный конвейер развёртывания: PyTorch ResNet-18 (FP32, 45MB, вывод на GPU 5мс) экспорт в ONNX (44MB, кросс-платформенный промежуточный формат, потеря точности <0,1%) квантование TensorRT INT8 (6MB, объём 87%, потеря точности <0,5%) периферийный вывод Jetson Orin NX (1,2мс/кадр, потребляемая мощность 15Вт). По сравнению с выводом на GPU-сервере (350Вт/5мс), потребляемая мощность Jetson снижена на 96%, скорость вывода увеличена в 4,2 раза. В статье представлены полный скрипт экспорта, метод INT8-калибровки, процедура проверки точности и архитектура многомодельного конвейера.
Как бы хорошо ни работала AI-модель для мостового крана на лабораторном GPU, без развёртывания на объекте её ценность равна нулю. Промышленные условия (вибрация, высокая температура, ограниченное пространство, отсутствие кондиционирования) не подходят для установки мощных GPU-серверов (350Вт+ требуют серверного кондиционера). Периферийное развёртывание (Edge Deployment) преобразует обученную модель PyTorch в промежуточный формат ONNX, затем с помощью квантования TensorRT INT8 оптимизирует её для работы на маломощных периферийных устройствах Jetson. В статье на примере модели ResNet-18 для обнаружения обрывов проволок каната мостового крана рассматривается полный инженерный конвейер — от экспорта до развёртывания; все шаги воспроизводимы. Экспериментальная среда: обучение NVIDIA A10 (48GB) / периферия Jetson Orin NX 16GB (15Вт) / PyTorch 2.1.0 / TensorRT 8.6 / JetPack 6.0.
Экспорт модели PyTorch в формат ONNX
ONNX (Open Neural Network Exchange) — это «универсальный язык» развёртывания моделей. Функция torch.onnx.export() преобразует динамический вычислительный граф PyTorch в статический граф ONNX. Ключевые параметры: input_names=[“input”], output_names=[“output”], dynamic_axes={“input”:{0:”batch_size”,2:”height”,3:”width”}} (поддержка входных изображений переменного размера). После экспорта точность проверяется с помощью onnxruntime: разница между FP32-выводом и PyTorch составляет <0,1% (среднее по 20 изображениям валидационного набора).
import torch, torch.onnx model = torch.load("resnet18_crane.pth") # FP32Предобученная модель типа dummy = torch.randn(1, 3, 224, 224) torch.onnx.export(model, dummy, "resnet18_crane.onnx", input_names=["input"], output_names=["output"], dynamic_axes={"input": {0: "batch", 2: "h", 3: "w"}}, opset_version=17) # Точность проверки экспорта import onnxruntime as ort sess = ort.InferenceSession("resnet18_crane.onnx") out_ort = sess.run(None, {"input": dummy.numpy()})[0] out_pt = model(dummy).detach().numpy() print(f"Max diff: {abs(out_ort - out_pt).max():.6f}") # Приложение<1e-5Квантование TensorRT INT8 для ускорения вывода
TensorRT — это оптимизированный движок вывода NVIDIA, который преобразует модель ONNX в движок TensorRT (.trt) за счёт слияния слоёв (Layer Fusion), калибровки точности (INT8 Calibration) и оптимизации памяти (Pool Allocation). Процесс INT8-квантования: веса и активации модели FP32 отображаются с 32-битных чисел с плавающей точкой на 8-битные целые (256 уровней точности). Для отображения требуется 100–500 калибровочных изображений (Calibration Dataset); используется метод энтропийной калибровки (Entropy Calibration) для поиска порога квантования с минимальной дивергенцией Кульбака–Лейблера.
Конкретная команда: trtexec –onnx=resnet18_crane.onnx –saveEngine=resnet18_int8.trt –int8 –calib=calibration_data –fp16 –workspace=4096. Пояснение ключевых параметров: –int8 включает INT8-квантование; –calib указывает каталог калибровочных изображений (500 шт.); –fp16 включает FP16-вычисления в промежуточных слоях (смешанная точность с INT8-весами); –workspace=4096 выделяет 4 ГБ рабочего пространства (Jetson Orin NX 16GB может выделить 8 ГБ). Время конвертации — около 11 минут (GPU A10), объём INT8-движка — 6,2 МБ (14% от объёма FP32 ONNX).
| Показатель | PyTorch FP32(GPU) | ONNX FP32(GPU) | TensorRT INT8(Jetson) | степень оптимизации |
|---|---|---|---|---|
| объём модели | 45MB | 44MB | 6.2MB | 86% |
| задержка вывода | 5.0ms | 4.8ms | 1.2ms | 4.2x |
| энергопотребление | 350W | 350W | 12~15W | 96% |
| стоимость оборудования | ¥80,000+ | ¥80,000+ | ¥3,500 | 96% |
| Top-1Точность | 94.0% | 93.9% | 93.6% | 0.4% |
| F1оценка | 0.93 | 0.93 | 0.92 | 0.01 |
Шаг 3: Проверка точности
После INT8-квантизации необходимо убедиться, что потеря точности находится в допустимых пределах. Процедура проверки: на тестовом наборе из 1 000 изображений последовательно запускаются PyTorch FP32 (базовый уровень) и TensorRT INT8 (проверяемый режим), сравниваются Top-1 точность, F1-мера и матрица ошибок для каждого класса. В данном эксперименте INT8 против FP32: Top-1 снизилась с 94,0% до 93,6% (Δ = 0,4%), F1 — с 0,93 до 0,92 (Δ = 0,01). Потеря точности на уровне классов сконцентрирована в категории «обрыв проволок каната» (доля пропусков выросла с 2,3% до 3,1%, Δ = +0,8%), тогда как по остальным 4 классам снижение точности не превысило 0,3%. Если потеря точности INT8 превышает 1%, рекомендуется перейти на FP16-квантизацию (объём 12 МБ, потеря точности <0,1%) как компромиссный вариант.
Шаг 4: Развёртывание на Jetson и конвейер обработки
Файл TensorRT Engine записывается непосредственно на Jetson Orin NX (JetPack 6.0 с предустановленным TensorRT 8.6). Для инференса используется Python API TensorRT (или C++ API для минимальной задержки). В многомодельном конвейере (например, YOLO-детекция + ResNet-классификация) применяется асинхронный инференс через CudaStream, при этом CPU-постобработка (NMS) перекрывается с GPU-инференсом следующей модели. Сквозная задержка конвейера составляет примерно 60% от суммы задержек отдельных моделей (в данном эксперименте YOLOv8s 3,8 мс + ResNet18 1,2 мс ≈ 5 мс сквозной задержки).
import tensorrt as trt, pycuda.driver as cuda # ЗагрузкаINT8 engine with open("resnet18_int8.trt", "rb") as f, trt.Runtime(trt.Logger()) as r: engine = r.deserialize_cuda_engine(f.read()) ctx = engine.create_execution_context() # РаспределениеGPUПамять d_input = cuda.mem_alloc(1*3*224*224*4) # FP32Вход(Практическое применениеINT8Предварительная обработка) d_output = cuda.mem_alloc(1*6*4) stream = cuda.Stream() # Цикл вывода for img in camera_stream(): cuda.memcpy_htod_async(d_input, preprocess(img), stream) ctx.execute_async_v2([int(d_input), int(d_output)], stream.handle) cuda.memcpy_dtoh_async(output, d_output, stream) stream.synchronize() result = postprocess(output) # Категория+Уверенность push_to_hmi(result) # Отправка на мостовой кранHMIОтображениеПрактический пример внедрения
В проекте AI-визуального контроля стальных канатов на 17 мостовых кранах металлургического завода (номер проекта KL-EDGE-2024-003) на каждом кране установлен один Jetson Orin NX (¥3 500/шт.). На каждом кране смонтированы 2 промышленные камеры (Basler acA2440-75um, захват изображения по всей длине каната). Jetson выполняет конвейер YOLOv8s+ResNet18 (обнаружение мест обрыва проволок + классификация класса серьёзности). Сквозная задержка инференса — 5,0 мс (двухмодельный конвейер), ежедневно обрабатывается около 14 400 изображений (2 камеры × 1 кадр каждые 5 секунд × 10 часов). За 14 месяцев непрерывной работы (январь 2025 г. — февраль 2026 г.): система зафиксировала 328 случаев обрыва проволок, ручная проверка подтвердила 307 случаев (точность 93,6%), пропущено 8 случаев (полнота 97,5%). По сравнению с ежедневным ручным осмотром (визуальная проверка каждого крана 1 раз в день, доля обнаружения обрывов около 40%), автоматическое обнаружение повышает долю выявления в 2,3 раза.
Сравнение вариантов развёртывания: GPU-сервер против периферийного инференса
Выбор варианта развёртывания зависит от ограничений, накладываемых условиями объекта. Ниже приведено сравнение преимуществ и недостатков четырёх вариантов:
| параметр сравнения | вариант решенияA:GPUсервер | вариант решенияB:ONNX Runtime CPU | вариант решенияC:TensorRT FP16 | вариант решенияD:TensorRT INT8 |
|---|---|---|---|---|
| аппаратная платформа | NVIDIA A10/RTX 4090 | промышленныйPC (i7-12700) | Jetson Orin NX 16GB | Jetson Orin NX 16GB |
| объём модели | 45MB (FP32) | 44MB (ONNX FP32) | 12MB (FP16) | 6.2MB (INT8) |
| задержка вывода | ~5ms(одиночное изображение224×224) | ~25ms | ~2.5ms | ~1.2ms |
| энергопотребление | 350W | 65W | 12~15W | 12~15W |
| Top-1Точность | 94.0% | 93.9% | 93.8% | 93.6% |
| стоимость оборудования | ¥80,000+ | ¥8,000~15,000 | ¥3,500 | ¥3,500 |
| место развёртывания | серверная(требуется кондиционирование) | помещение управления/распределительный щит | электрошкаф мостового кранавнутри | электрошкаф мостового кранавнутри |
| сложность эксплуатации | высокая(совместимость драйверов/управление средой) | средняя(операционная системаобслуживание) | низкая(готов к работе после прошивки) | низкая(готов к работе после прошивки) |
| рекомендуемый сценарий | обучение модели/пакетный офлайн-вывод | существующийпромышленный компьютери нечувствительный к задержке | Точностьприоритетное периферийное развёртывание | оптимальный выбор по соотношению цена/качество |
Условия тестирования: ResNet-18, вход 224×224, batch=1. GPU-сервер: NVIDIA A10 (48GB), CUDA 12.1, PyTorch 2.1.0. ONNX Runtime CPU: i7-12700, ONNX Runtime 1.16. Jetson: Orin NX 16GB, JetPack 6.0, TensorRT 8.6. Задержка — среднее значение по 1000 прогонам.
Частые вопросы по оптимизации моделей ИИ
В: Приемлема ли потеря точности при INT8-квантизации TensorRT?
О: В данном эксперименте Top-1 точность INT8 относительно FP32 снизилась с 94.0% до 93.6% (потеря 0.4%), F1 — с 0.93 до 0.92 (потеря 0.01). В промышленных условиях потеря точности 0.4% в обмен на сжатие объёма в 7.5 раз и ускорение инференса в 4.2 раза — вполне оправдана. Если потеря точности по какому-либо классу дефектов превышает 1% (например, обрыв проволок каната стального — с 92% до 90%), рекомендуется для данного класса использовать FP16-инференс или увеличить долю таких примеров в калибровочном наборе данных INT8.
В: Как организовать конвейер для многомодельного каскада (YOLO-детекция + ResNet-классификация) на Jetson?
О: Используйте CudaStream и CUDA Graph из TensorRT для организации конвейера. Шаги: ① создайте 2 потока CudaStream (stream1 = YOLO, stream2 = ResNet); ② YOLO выполняется в stream1, NMS (Non-Maximum Suppression, ~0.5 мс) — на CPU, затем вырезанные области подаются в ResNet в stream2; ③ синхронизация потоков через CUDA Event. Сквозная задержка составляет около 60% от суммы задержек каждой модели (за счёт перекрытия GPU-инференса и CPU-постобработки).
В: Какие типичные ошибки возникают при экспорте в ONNX?
О: Три основные проблемы: ① динамические размеры — ONNX по умолчанию фиксирует входные размеры, необходимо задать параметр dynamic_axes для поддержки переменных размеров (например, переключение между 224×224 и 416×416); ② управляющие конструкции — циклы if/for в PyTorch необходимо заменять на torch.where/torch.arange (ONNX не поддерживает Python-контроль потока); ③ пользовательские операторы — для torch.autograd.Function требуется регистрация ONNX symbolic. Рекомендуется использовать новый бэкенд torch.onnx.export(…, dynamo=True) (PyTorch 2.1+).
В: Может ли устройство Jetson стабильно работать в шкафу управления краном?
О: Да. Промышленная версия Jetson Orin NX (JetPack 6.0) поддерживает расширенный температурный диапазон от -25°C до 80°C, влажность 5–95% без конденсации, вибростойкость 50G. В реальном развёртывании используется пассивное охлаждение (алюминиевый ребристый радиатор 145×80×35 мм) + защитный кожух IP54, установленный на внутренней стенке электрошкафа. Устройства развёрнуты на 17 мостовых кранах (проект KL-EDGE-2024-003), максимальная непрерывная наработка — 14 месяцев без отказов (по состоянию на февраль 2026 г.). Температура CPU стабильноподдерживать на уровне 65–72°C (при температуре окружающей среды 35°C внутри электрошкафа).