深度学习推理基础:推理与训练的区别、推理流程(前向传播)、常见推理框架

各位同学好,我是你们的老朋友。今天咱们聊聊深度学习推理的基础。说实话,很多刚入行的朋友容易把推理和训练混为一谈。我当年刚接触嵌入式部署时,也踩过这个坑。嗯,咱们今天就把这事儿彻底捋清楚。

推理 vs 训练:本质区别在哪?

训练,说白了就是让模型学会「知识」的过程。它需要海量数据、强大的GPU、来回迭代。你想想看,训练一个ResNet-50在ImageNet上,动辄几十个小时,梯度来回传,权重不断更新。

推理呢?推理是模型学会之后,拿着学到的「知识」去干活。它只需要一次前向传播,不需要反向传播,不需要更新权重。说白了,就是「用」模型,而不是「教」模型。

我给大家列个表,一目了然:

对比维度 训练 推理
计算方向 前向 + 反向 仅前向
数据需求 大量标注数据 单张/少量输入
精度要求 FP32为主 可降为FP16/INT8
延迟要求 相对宽松 毫秒级实时
硬件需求 高性能GPU集群 嵌入式GPU/边缘设备

核心要点:训练是「学习」,推理是「应用」。在嵌入式GPU上,我们只关心推理,因为设备资源有限,不可能跑训练。

推理流程:前向传播到底在做什么?

前向传播,这个名字听起来高大上。其实说白了,就是数据从输入层流到输出层的过程。我习惯把它想象成一条流水线:

  1. 输入预处理:图像缩放、归一化、通道转换。嗯,这一步经常被忽略,但我在项目中遇到过,预处理不对,后面全白搭。
  2. 逐层计算:卷积、池化、激活、全连接。每一层都在做矩阵运算。
  3. 输出后处理:Softmax、NMS(非极大值抑制)、坐标解码。

举个例子,一张224x224的图片输入ResNet-50,经过大约50层卷积,最后输出1000个类别的概率。整个过程就是矩阵乘法和非线性激活的堆叠。

我的经验:在嵌入式GPU上,前向传播的瓶颈往往不在计算,而在内存带宽。数据搬运比计算还耗时。我曾经在Jetson Nano上调试一个模型,发现80%的时间花在了数据拷贝上。后来用了CUDA Stream和Pinned Memory,才把延迟降下来。

常见推理框架:选哪个?怎么用?

市面上推理框架不少,但真正在嵌入式GPU上常用的,就三个:TensorRT、ONNX Runtime、OpenCV DNN。我一个个说。

1. TensorRT:NVIDIA的亲儿子

TensorRT是NVIDIA推出的推理优化引擎。它支持FP16、INT8量化,还能做层融合、内存复用。说白了,就是把你训练好的模型,变成能在GPU上跑得飞快的「特化版本」。

我个人的习惯是:只要用NVIDIA的GPU,首选TensorRT。它能把模型推理速度提升2-5倍,甚至更多。

// TensorRT推理示例(伪代码)
// 1. 创建Builder
IBuilder* builder = createInferBuilder(gLogger);
// 2. 构建网络
INetworkDefinition* network = builder->createNetwork();
// 3. 解析ONNX模型
parser->parse(modelFile, network);
// 4. 构建引擎
ICudaEngine* engine = builder->buildCudaEngine(*network);
// 5. 执行推理
engine->execute(batchSize, buffers);

避坑指南:我曾经在Jetson Xavier上部署一个YOLOv5模型,直接用TensorRT解析ONNX,结果报错说某些算子不支持。后来发现是ONNX导出时用了动态形状。解决办法是固定输入尺寸,或者在导出时设置opset_version为11以上。嗯,这个坑我踩了整整两天。

2. ONNX Runtime:跨平台的好选择

ONNX Runtime是微软开源的推理引擎。它支持多种硬件后端,包括CPU、GPU、甚至NPU。如果你需要在不同平台间切换,ONNX Runtime是个不错的选择。

它的优势在于:模型格式统一(ONNX),一次导出,到处运行。但说实话,在嵌入式GPU上,它的优化深度不如TensorRT。

// ONNX Runtime推理示例(Python)
import onnxruntime as ort

# 创建推理会话
session = ort.InferenceSession("model.onnx")
# 获取输入输出名称
input_name = session.get_inputs()[0].name
output_name = session.get_outputs()[0].name
# 执行推理
result = session.run([output_name], {input_name: input_data})

我的建议:如果你只是做原型验证,或者模型需要跨平台部署,用ONNX Runtime。但如果你追求极致性能,尤其是在Jetson系列上,还是老老实实用TensorRT吧。

3. OpenCV DNN:轻量级选手

OpenCV DNN是OpenCV库自带的深度学习模块。它不需要额外安装CUDA或cuDNN,直接就能跑。但它的优化能力有限,不支持量化,也不支持层融合。

我一般在什么场景用呢?快速验证模型效果,或者做一些简单的图像处理任务。比如在树莓派上跑一个人脸检测,OpenCV DNN就够用了。

// OpenCV DNN推理示例(C++)
cv::dnn::Net net = cv::dnn::readNet("model.onnx");
cv::Mat blob = cv::dnn::blobFromImage(image, 1.0, cv::Size(224, 224));
net.setInput(blob);
cv::Mat output = net.forward();

总结一下:

  • 追求极致性能 → TensorRT
  • 跨平台兼容 → ONNX Runtime
  • 快速验证/轻量任务 → OpenCV DNN

我的实战建议

说了这么多,给大家一个实际的操作路径:

  1. 先用PyTorch/TensorFlow训练模型,导出为ONNX格式。
  2. 在PC上用ONNX Runtime验证推理结果是否正确。
  3. 针对嵌入式GPU(如Jetson),用TensorRT做优化和部署。
  4. 如果资源实在紧张,考虑用OpenCV DNN做降级方案。

嗯,这套流程我用了好几年,基本没出过大问题。你想想看,每一步都有明确的目标,不会走弯路。

最后提醒一句:不要盲目追求框架的「新」和「快」。我在项目中见过有人为了用TensorRT的最新特性,把模型改得面目全非,结果精度掉了5个点。稳定性和精度,永远比那点速度提升更重要。

好了,今天的内容就到这里。下一章咱们聊聊模型量化的具体实现,包括INT8量化的原理和实战技巧。到时候我会分享一个我在Jetson Nano上做量化时遇到的「诡异」问题,保证让你大开眼界。