3、多输入模型的概念:什么是多输入模型、与单输入模型的区别、常见多输入类型
在深度学习工程实践中,我们习惯将模型抽象为“输入张量 → 网络层 → 输出张量”的流水线。然而,真实世界的感知任务往往天然携带多种模态或多种来源的数据:自动驾驶汽车同时读取前视摄像头图像、毫米波雷达点云和GPS轨迹;智能座舱系统需要融合麦克风语音与驾驶员面部表情;工业预测性维护则要同步分析振动信号、温度曲线和电流波形。这些场景迫使模型架构从“单输入单输出”向“多输入多输出”演进。本章将系统梳理多输入模型的定义、与单输入模型的本质差异,以及三种最常见的多输入组合类型,为后续ONNX转换与推理引擎适配打下概念基础。
上图从模型结构视角对比了单输入模型与两种典型多输入融合策略。左侧是传统单输入模型,数据流单一;中间是特征级融合(Early Fusion / Feature-level Fusion),多个输入分支在中间层拼接或加权后共同进入后续网络;右侧是决策级融合(Late Fusion / Decision-level Fusion),每个输入独立经过一个完整模型,最后对输出概率进行投票或加权平均。理解这两种融合模式,是判断ONNX转换时输入节点数量、动态轴设置以及推理引擎调度策略的关键前提。
3.1 多输入模型的定义与核心特征
多输入模型(Multi-Input Model)是指模型在推理时接收两个或两个以上独立输入张量,且这些张量在计算图中以某种方式汇合,共同影响最终输出的神经网络结构。这里的“独立”包含两层含义:一是数据来源不同,例如图像来自摄像头、文本来自语音识别系统;二是张量形状或数据类型可能不同,例如图像为uint8的4D张量,雷达点云为float32的3D张量。
从工程实现角度看,多输入模型具有三个核心特征:
- 多输入节点(Input Nodes):ONNX计算图中存在多个
graph.input条目,每个输入节点拥有独立的名称、数据类型和形状定义。例如image_input(形状[1,3,224,224])和radar_input(形状[1,64,64,5])。 - 分支网络(Branch Networks):每个输入通常先经过独立的预处理子网络(如CNN主干、LSTM编码器),提取各自模态的特征表示。这些分支在结构上相互独立,但在训练时通过反向传播共同更新参数。
- 融合层(Fusion Layer):分支特征在某个特定深度进行合并。融合方式包括张量拼接(Concat)、逐元素相加(Add)、注意力加权(Attention)或门控机制(Gating)。融合点的位置决定了模型属于早期融合还是晚期融合。
工程视角的补充说明:在ONNX转换时,多输入模型意味着推理引擎需要同时为所有输入分配内存缓冲区,并且要处理不同输入可能具有不同批次大小(batch size)的情况。例如,图像输入批次为4,而文本输入批次可能只有2(因为某些样本文本缺失)。这种“异步批次”问题在ONNX Runtime中需要通过IOBinding或动态形状(dynamic_axes)来灵活处理。
3.2 与单输入模型的本质区别
单输入模型与多输入模型的差异不仅体现在输入节点数量上,更体现在数据流拓扑、训练策略和部署复杂度三个维度。下表从多个角度进行了系统对比:
| 对比维度 | 单输入模型 | 多输入模型 |
|---|---|---|
| 输入张量数量 | 1个 | ≥2个 |
| 数据流拓扑 | 线性流水线(输入→层→输出) | 多分支并行,存在汇合点(Merge Point) |
| 预处理复杂度 | 单一预处理管线(如Resize+Normalize) | 每个输入独立预处理,且预处理参数可能不同(如图像归一化均值不同) |
| 训练方式 | 端到端单损失函数 | 可端到端联合训练,也可分阶段训练(先预训练分支,再微调融合层) |
| ONNX转换关注点 | 输入名称、形状、动态轴 | 多个输入名称、每个输入的形状与动态轴、融合算子的兼容性(如Concat/Add) |
| 推理引擎调度 | 单输入队列,简单流水线 | 需要多输入同步机制,可能涉及多线程或异步预取 |
| 典型调试难点 | 梯度消失/爆炸、过拟合 | 模态间不平衡(某模态过强导致另一模态被忽略)、融合点梯度冲突 |
从部署角度看,单输入模型在ONNX Runtime中只需调用一次Run()并传入一个输入字典;而多输入模型需要构造包含多个键值对的输入字典,且每个键必须与ONNX图中的输入名严格匹配。此外,多输入模型对内存带宽的要求更高,因为多个输入张量需要同时驻留在显存或内存中。
3.3 常见多输入类型详解
根据实际业务场景,多输入模型可以归纳为三种典型组合。每种组合在数据特性、融合策略和ONNX转换注意事项上都有显著差异。
3.3.1 图像 + 文本(视觉-语言模型)
这种组合常见于图文检索、视觉问答(VQA)、图像描述生成等任务。图像输入通常为[batch, 3, H, W]的RGB张量,文本输入为[batch, seq_len]的 ID序列(或经过Embedding后的[batch, seq_len, embed_dim])。
融合策略上,早期方法将图像特征(如Faster R-CNN的区域特征)与文本特征(如BERT的[CLS]向量)直接拼接后送入全连接层;现代方法则采用Cross-Attention机制,让图像特征与文本特征在Transformer层中交互。ONNX转换时,文本输入通常需要额外处理tokenization和padding,且seq_len往往是动态维度,必须通过dynamic_axes声明。
# ONNX转换时动态轴设置示例(PyTorch → ONNX)
torch.onnx.export(
model,
(image_tensor, text_tensor),
"vqa_model.onnx",
input_names=["image_input", "text_input"],
output_names=["answer_logits"],
dynamic_axes={
"image_input": {0: "batch", 2: "height", 3: "width"},
"text_input": {0: "batch", 1: "seq_len"}
},
opset_version=17
)
3.3.2 雷达 + 摄像头(自动驾驶感知)
这是自动驾驶领域最典型的多传感器融合场景。摄像头提供高分辨率纹理信息(RGB图像),雷达提供精确的距离、速度和角度信息(点云或Range-Doppler谱)。两者在物理特性上互补:摄像头在光照良好时表现优异,但在夜间或逆光下失效;雷达不受光照影响,但点云稀疏且缺乏颜色信息。
工程实现上,雷达数据通常被预处理为伪图像(Pseudo-Image),例如将点云投影到鸟瞰图(BEV)或前视图(Range View),从而与摄像头图像在空间维度上对齐。融合方式包括:
- 早期融合:将雷达伪图像与摄像头图像在通道维度拼接,输入同一个CNN。优点是结构简单,但要求两种数据严格对齐(像素级对齐)。
- 中期融合:分别提取特征后,在特征图层面通过注意力机制融合。例如,利用雷达特征图生成空间注意力权重,加权摄像头特征图。
- 晚期融合:两个独立模型分别输出目标检测框,再通过NMS(非极大值抑制)或匈牙利算法进行结果级融合。
ONNX转换风险提示:雷达点云数据往往是不规则的(每帧点数不同),直接作为ONNX输入会导致形状不固定。实践中通常先将点云体素化(Voxelization)为固定尺寸的4D张量(如[batch, 10, 128, 128]),或者使用PointNet等结构将点云编码为固定长度的特征向量后再与图像特征融合。若必须处理变长点云,需在ONNX图中使用Sequence类型或自定义算子,这会显著增加转换复杂度。
3.3.3 多传感器时序数据(工业预测性维护)
在工业场景中,设备往往部署多个传感器(振动加速度计、温度探头、电流互感器),以不同采样率采集时间序列信号。例如,振动信号采样率为20kHz,温度信号为1Hz,电流信号为50Hz。多输入模型需要处理这些采样率不一致的时序数据。
典型处理流程为:
- 分段与对齐:将各传感器数据按固定时间窗口(如10秒)切分,并重采样到统一频率(如100Hz)。
- 特征提取分支:每个传感器数据经过独立的1D-CNN或LSTM分支,提取时序特征。
- 融合与分类:将各分支的最终隐藏状态拼接,输入全连接层进行故障分类。
ONNX转换时,需要注意各输入的时间步维度(time_steps)是否固定。如果使用固定窗口,则形状为[batch, time_steps, channels];如果使用变长序列,则需要借助ONNX的Scan算子或动态轴。
3.4 案例拆解:自动驾驶多传感器融合模型的ONNX转换
下面通过一个简化但完整的案例,展示多输入模型从定义到ONNX转换的完整闭环。
背景与约束:某L2级自动驾驶项目需要在前向碰撞预警(FCW)功能中融合前视摄像头和毫米波雷达数据。摄像头图像分辨率为1280×720,雷达输出为64×64的Range-Doppler地图(5个通道:R、D、R+D、速度、角度)。模型部署在车载嵌入式平台(NVIDIA Xavier),要求推理延迟小于30ms。
初始现象与目标:最初使用单输入模型(仅摄像头图像),在雨天和夜间出现大量漏检。目标是将雷达数据作为第二输入,将漏检率降低40%以上,同时保持推理延迟不超标。
关键输入数据与参数:
- 图像输入:
[1, 3, 224, 224],归一化均值[0.485, 0.456, 0.406],标准差[0.229, 0.224, 0.225]。 - 雷达输入:
[1, 64, 64, 5],数值范围[0, 1],无需额外归一化。 - 模型结构:图像分支为ResNet-18的前5层,雷达分支为3层卷积(通道数16→32→64),融合层为Concat后接2层全连接(256→128→2)。
分析判断过程:选择中期融合策略,因为早期融合要求像素级对齐,而雷达Range-Doppler图与图像视角差异大,难以直接拼接;晚期融合需要维护两个完整模型,计算量翻倍,难以满足30ms延迟约束。中期融合在特征图层面(14×14空间分辨率)进行Concat,计算量增加约15%,在可接受范围内。
实际操作步骤:
# 1. 定义PyTorch模型
class FusionModel(nn.Module):
def __init__(self):
super().__init__()
self.image_branch = nn.Sequential(*list(ResNet18(pretrained=True).children())[:5])
self.radar_branch = nn.Sequential(
nn.Conv2d(5, 16, 3, padding=1), nn.ReLU(),
nn.Conv2d(16, 32, 3, padding=1), nn.ReLU(),
nn.Conv2d(32, 64, 3, padding=1), nn.ReLU()
)
self.fc = nn.Sequential(nn.Flatten(), nn.Linear(64*14*14*2, 256), nn.ReLU(), nn.Linear(256, 2))
def forward(self, img, radar):
feat_img = self.image_branch(img) # [1, 64, 14, 14]
feat_radar = self.radar_branch(radar) # [1, 64, 14, 14]
fused = torch.cat([feat_img, feat_radar], dim=1) # [1, 128, 14, 14]
return self.fc(fused)
# 2. 导出ONNX
model = FusionModel().eval()
dummy_img = torch.randn(1, 3, 224, 224)
dummy_radar = torch.randn(1, 64, 64, 5)
torch.onnx.export(model, (dummy_img, dummy_radar), "fcw_fusion.onnx",
input_names=["image", "radar"],
output_names=["fcn_output"],
dynamic_axes={"image": {0: "batch"}, "radar": {0: "batch"}},
opset_version=17)
# 3. ONNX Runtime推理
import onnxruntime as ort
sess = ort.InferenceSession("fcw_fusion.onnx", providers=["CUDAExecutionProvider"])
result = sess.run(["fcn_output"], {"image": img_np, "radar": radar_np})
结果对比:融合模型在雨天场景的漏检率从18.2%降至9.7%,夜间场景从25.6%降至13.4%,整体漏检率下降约47%。推理延迟为22ms(TensorRT加速后),满足30ms约束。
风险与代价:雷达分支增加了约12%的参数量和15%的计算量,导致模型文件从45MB增至52MB。此外,雷达数据的质量直接影响融合效果——当雷达出现虚假回波时,融合模型可能产生误检,因此需要额外的雷达数据质量监控模块。
复盘经验:中期融合是计算量与性能提升之间的最佳平衡点;ONNX转换时务必为两个输入都设置动态批次轴,以便在推理时灵活调整batch大小;雷达输入的数值范围与图像差异大,在训练时需使用不同的数据增强策略。
3.5 常见误区与总结复盘
在多输入模型的设计与ONNX转换过程中,工程师常陷入以下误区:
误区一:忽视模态不平衡。当图像特征远强于雷达特征时,融合层可能退化为“只关注图像”,雷达分支的梯度接近零。解决方法是引入模态Dropout(训练时随机丢弃某一模态)或为不同分支设置不同的学习率。
误区二:ONNX输入顺序与训练不一致。PyTorch中forward(img, radar)与ONNX的input_names=["image", "radar"]顺序必须严格对应。若推理时传入的字典键顺序颠倒,ONNX Runtime不会报错,但会静默交换数据,导致推理结果完全错误。
误区三:所有输入都使用相同的动态轴设置。图像输入可以动态调整H和W,但雷达输入通常固定为64×64。如果为雷达输入也设置了动态H/W,会增加ONNX优化器的负担,且可能降低TensorRT的推理效率。
总结复盘:多输入模型的核心价值在于利用不同模态的互补信息提升模型鲁棒性。在ONNX转换时,应优先确认输入名称、形状、数据类型和动态轴设置。对于特征级融合,需检查Concat/Add等融合算子是否被目标推理引擎(如TensorRT、OpenVINO)完整支持;对于决策级融合,则要关注多个输出张量的后处理逻辑是否能在部署框架中高效实现。建议在转换前使用onnx.checker.check_model验证图结构,并使用onnxruntime.quantization进行量化时,特别注意多输入节点的量化参数独立设置。