做了快三年的深度学习视觉项目,图像识别和3D目标检测这两块我踩过的坑比看过的论文还多。很多刚入门的朋友总把这两个方向分开学,结果真到项目里才发现,实际业务根本不会给你分得那么清——智能机器人要看懂桌上有哪些物体,还得知道每个物体离自己多远、在什么角度;工业质检要在传送带上认出缺陷件,还得算出缺陷在三维空间里的位置;安防系统不仅要框出人,还得估计物体轨迹。这就是为什么深度学习图像识别与3D目标检测模型算法必须放在同一个工程里一起做。
这篇内容是我从实际项目中提炼出来的经验总结,覆盖了两个任务从数据准备、模型设计、代码实现到训练调参、问题排查的全流程。文章里有可以直接跑起来参考的核心代码思路,也有那些论文里不会写的工程细节,比如2D和3D结果对不上时怎么定位问题、损失函数莫名变NaN怎么查。无论你是刚接触视觉深度学习的学生,还是已经在做相关方向的研究者,这份整理应该都能帮你少走不少弯路。
1. 项目概述与整体思路
1.1 为什么要把图像识别和3D目标检测放在一起做
先说一个最直接的场景。我之前做一个巡检机器人项目,硬件平台上装了一个单目相机,任务是识别机房里的设备状态,同时判断设备距离机器人有多远、有没有倾斜。如果只做图像识别,模型只能告诉你"这是服务器",但服务器在哪、离你多远,完全不知道。如果只做3D检测,没有2D识别的语义信息,你又不知道检测到的那堆三维点到底是什么。两个任务单独做都不难,难的是让它们在同一个系统里协作,共享信息和计算资源。
从算法的角度看,图像识别和3D目标检测天然就有协同关系。2D检测的ROI区域可以直接作为3D检测的先验——比如先在2D图像中框出目标,再在那个区域的深度图上估计中心点深度和物体尺寸,这样3D检测的搜索范围就大大缩小了。反过来,3D几何信息也能约束2D识别,比如知道某个物体的物理尺寸在0.8到1.2米之间,就不会把远处一个2米的大卡车误分类成小轿车。两个任务放在一起做,不是简单地把两个模型串起来,而是让它们在特征层面相互增强,这才是多任务学习的核心价值。
这套方案适合什么场景?第一类是自动驾驶和移动机器人,需要同时进行交通参与者识别和障碍物空间定位。第二类是工业自动化,比如机械臂抓取,要先识别物体类别再计算抓取位姿。第三类是智慧安防,人流统计和越界检测都同时需要语义和空间信息。如果你做的是纯图片分类或者纯2D框检测,那不需要3D分支;但只要涉及空间定位、测距、抓取、避障,2D+3D协同的这套架构就绕不开。
1.2 技术方案选型与整体架构
选型是决定项目成败的第一步。我最后选定的架构是一套两阶段的深度学习方案,整体流程是:2D图像先经过骨干网络提取特征,一条分支做图像分类和2D检测框回归,另一条分支基于2D检测结果和对应深度信息做3D框回归。之所以选两阶段而不是单阶段的端到端方案,考虑的是工程稳定性和调试便利性。
骨干网络这块,我对比过多个选择,从轻量级到高性能都有涉及。最终在精度优先的项目里选了残差结构网络(ResNet-50),在实时性要求高的项目里换成了轻量化结构(MobileNetV2)。为什么不用更深的结构?在同样的数据规模下,过深的网络在小数据集上容易过拟合,而且推理帧率会明显下降,性价比不高。这里给一个直观对比:
| 骨干网络 | 参数量 | 2D分类精度 | 推理耗时 | 适合场景 |
|---|---|---|---|---|
| 轻量化网络 | 约3.5M | 中等 | 极短 | 嵌入式、实时系统 |
| 残差网络-50 | 约25M | 较高 | 中等 | 通用目标识别/检测 |
| 残差网络-101 | 约45M | 高 | 较长 | 离线分析、高精度需求 |
2D检测头是常规的分类加回归结构,输出类别置信度、2D中心点坐标和宽高。3D检测分支是这个项目的核心,输出的是三维中心点(cx, cy, cz),三维尺寸(长l、宽w、高h)和朝向角theta。这套参数刚好是三维空间里描述一个带朝向的矩形体的最小集合。深度信息的来源根据硬件条件灵活选择:有机载雷达时直接用雷达点云,没有雷达时用单目深度估计。我在项目里两种方案都验证过,后面章节会详细讲。
整体训练策略采用多任务联合训练,总损失函数等于2D分类损失、2D框回归损失和3D框回归损失的加权和。权重我常用的一组初始值是1:1:5,3D损失权重高一些,因为3D回归难度更大,刚开始训练时误差也更大,给更高权重可以加速收敛。
2. 环境搭建与数据准备
2.1 硬件配置与软件环境
先说硬件。图像识别和3D检测的模型训练对GPU有明确的门槛。显存8GB以下基本不用考虑训练深度残差网络,因为一个batch就会被显存卡死。我个人的分档建议如下:
- 入门档(显存8GB):可以跑轻量化网络加2D检测,3D分支只能做很小batch的验证
- 标准档(显存16-24GB):可以跑中等深度骨干网络,batch 32的2D训练加少量3D分支微调没问题
- 舒适档(显存32GB以上):完整训练这套方案,或者开大批次提升收敛速度
CPU方面,数据预处理和DataLoader的读取也吃性能,核数越多越好,否则训练过程CPU会成为瓶颈。内存32GB以上在这个数据集规模下是基本要求。
软件栈我选择的是PyTorch框架,原因很实际:生态成熟、调试灵活、中间层方便打印,对于需要频繁调试算法细节的任务来说效率最高。配套的CUDA版本和PyTorch版本需要匹配,一个常见的坑是装了新版CUDA但PyTorch是旧版编译的,导致GPU不可用。我建议直接用conda创建一个独立环境,指定PyTorch官方匹配的CUDA版本,不要单独手动装系统级CUDA。
环境安装的另一个实用建议是使用容器。我每次搭项目都会把基础镜像固定下来,Python版本3.8到3.10都可以,依赖项锁定版本号。这样换机器、换服务器时直接拉镜像就能复现环境,省去重新装环境的痛苦。
2.2 数据集选择与标注处理
数据是这套方案里最耗时也最决定上限的环节。图像识别的数据集采用公开的标准目标检测数据集格式,包含图像文件夹和标注文件。标注文件每行记录目标类别、2D框左上角坐标和右下角坐标,这种格式兼容性好,无论哪个框架都能直接读。数据集划分我习惯用8:1:1的比例,训练集8000多张、验证集和测试集各1000张左右,尽量保证每个类别在三个集合中都有足够样本。
3D数据的标注是另一个维度的问题。如果有雷达点云,标注工作可以在点云视图上框出三维框;如果只有图像和深度图,就需要通过相机内外参数做几何换算。换算的核心是三个坐标系的转换:图像坐标系到相机坐标系,再到世界坐标系。具体公式是:相机坐标下的三维点等于深度值乘以像素坐标的反投影,再乘以相机内参矩阵的逆。反过来,从三维框投影到2D框,只需要把三维框的8个角点通过内外参投影到图像平面,取所有投影点的外接矩形。
标注格式统一是项目里最容易埋坑的地方。我遇到过两次因标注坐标系不统一导致训练结果完全崩溃的情况。团队里有人用图像左上角为原点,有人用图像中心为原点,差一个偏移量,模型怎么训都收敛不了。所以第一件事就是定好规范:所有标注统一使用图像左上角为原点,X轴向右,Y轴向下,角度使用弧度制。这个规则要写进团队文档里,写进数据检查脚本里,自动校验。
数据增强方面,2D部分做随机翻转、随机裁剪、色彩抖动;3D部分做全局旋转、平移、缩放。特别提醒一点:3D增强必须和2D增强联动。比如图像做了水平翻转,三维框的中心点X坐标也要跟着翻转,朝向角也要对应映射,否则2D图像和3D标注就错位了。这个联动逻辑是新手最容易忽略的,一旦错位,训练时损失看似正常,实际学到的全是错误映射。
3. 图像识别模型实现与训练
3.1 骨干网络与预训练迁移
骨干网络是整个视觉模型的地基。图像分类任务和检测任务共享同一个骨干网络,所以骨干的特征提取能力直接决定两个任务的上限。我采用的方式是先加载公开的预训练权重,然后替换最后的全连接分类头,修改成自己的类别数量。这里的核心逻辑是:预训练权重已经在大规模数据集上学到了通用特征,比如边缘、纹理、形状结构,这些特征对大部分视觉任务都有效。直接用随机初始化从零训练,对数据量的要求极高,现实中很难满足。
替换分类头的代码逻辑非常简单:
import torchvision.models as models # 加载预训练的ResNet-50,修改分类头 model = models.resnet50(pretrained=True) num_ftrs = model.fc.in_features num_classes = 20 # 按实际类别数修改 model.fc = torch.nn.Linear(num_ftrs, num_classes)但这里有个细节值得展开。全连接层是随机初始化的,而骨干网络是预训练的,这会导致训练初期回传梯度严重不平衡。直接从头训,随机初始化的全连接层梯度大,会把预训练骨干权重也顺带大幅更新,可能把学好的通用特征破坏了。解决方法是骨干网络先用较小的学习率微调,新加的分类头用较大的学习率,两者分离开。PyTorch里可以按参数组设置学习率:
optimizer = torch.optim.SGD([ {'params': model.backbone.parameters(), 'lr': 1e-4}, {'params': model.head.parameters(), 'lr': 1e-3}, ], momentum=0.9, weight_decay=1e-4)另一个选择是全冻结骨干只训练分类头,这种方式适合数据量极小的迁移场景。但在这个项目里数据量中等,建议微调骨干,只把浅层参数学习率设低一点。
3.2 图像分类与检测任务协同训练
图像识别分支在这个架构里承担两件事:一是直接输出目标的语义类别,二是为3D分支提供目标级别的特征区域。因为两个任务共享骨干网络,我需要设计一个多任务头。具体结构是骨干网络输出的特征图分别经过两条并行分支,一条做分类,一条做检测框回归。
分类损失使用交叉熵损失函数,检测回归使用SmoothL1损失函数。我选SmoothL1而不是L2的原因是L2对离群点太敏感,一个标注稍微有偏差的框就会产生巨大的梯度,干扰训练。SmoothL1在误差较大时梯度有上限,训练更稳定。
协同训练时,一个关键手段是困难样本挖掘。训练初期模型容易把背景误判为目标,或者把相似类别混淆。简单样本数量太多会淹没困难样本的梯度贡献。我的做法是在每个batch内计算每个样本的损失,只对损失排在前一定比例的样本回传梯度信息,其余样本的反向传播权重置零。这样模型把能力集中在真正难分的样本上。
训练超参数参考以下这套配置,实测收敛稳定:
| 超参数 | 值 | 说明 |
|---|---|---|
| 输入尺寸 | 640x640 | 平衡精度与显存 |
| 批量大小 | 32 | 16GB显存可跑 |
| 初始学习率 | 3e-4 | 骨干微调用1e-4 |
| 权重衰减 | 1e-4 | 防过拟合 |
| 训练轮次 | 60-80 | 观察验证集收敛情况 |
| 学习率调整 | 余弦退火 | 后期平滑收敛 |
4. 3D目标检测核心实现
4.1 从2D到3D:深度估计与坐标变换
3D检测绕不开的核心问题是:一张2D图像里的一个像素点,怎么变成三维空间里的一个坐标点。
我这边有两条路线,分别对应有无雷达点云的场景。有机载雷达的项目,直接把点云投影到图像平面,为每个2D检测框内的像素建立深度值,这是最可靠的深度信息。没有雷达的项目,只能通过单目深度估计网络生成深度图。单目深度估计本质上是从一个视图推理深度,本身就有天然的不确定性——远处的物体、遮挡严重的物体、纹理缺失的平面,深度误差都会变大。我的经验是,单目方案中目标距离在15米内的深度误差还能接受,一旦超过30米,误差会迅速扩大,3D框的定位精度会明显下降。
坐标变换是实现时的重点。要把图像里的2D锚点重建为三维坐标,需要三个矩阵:相机内参矩阵K(焦距、主点)、外参矩阵(旋转R和平移t)、以及深度值Z。核心公式是三维坐标 = Z乘以K的逆再乘以像素齐次坐标。实际代码中一般以矩阵操作完成,一个batch的像素坐标并行转换。这里最容易出错的是维度错位和单位统一:图像坐标系是像素,三维坐标是米或毫米,标注和推理必须统一。
另一个跟3D检测强相关的难点是朝向角估计。同一个物体从不同方向看,2D图像可能一模一样,但朝向完全不同。比如一辆车的侧面和正面,2D结果都是"车",3D朝向可能相差90度。所以模型不能只回归3D框的位置和尺寸,还要回归朝向角。这里我采用的做法是把朝向角分成若干个离散的bin做分类,再在每个bin内做残差回归。纯回归角度会遇到周期性跳变问题,比如359度和1度实际只差2度,但如果把角度作为连续值回归,损失函数会把它们当作358度来惩罚。用离散分类加残差回归,就把这个问题绕开了。
4.2 3D检测网络结构与锚框设计
3D检测头的基础参数化方式是对锚框进行编码。一个三维锚框由七个参数组成:中心点三维坐标cx, cy, cz,三个方向尺寸l, w, h,以及朝向角theta。模型预测的不是三维坐标的绝对值,而是相对锚框的残差偏移。这样做的原因是绝对值变化范围大、回归难度高,而残差范围小、分布集中,回归更稳定。
锚框设计上,我参考了目标检测领域的经典思路。根据类别先验设置几组宽高比,比如"轿车"类的锚框尺寸设为1.8米乘0.8米乘1.5米,"行人"类设为0.6米乘0.5米乘1.7米。设置锚框后要做的是在训练阶段给每个真实三维框匹配候选锚框,匹配规则是计算真实框和锚框的三维交并比,超过设定阈值就匹配为正样本,没超过的匹配为负样本。阈值设置直接影响正负样本比例。
3D检测头的实现逻辑与2D检测框回归类似,但维度扩到7个回归值加1个类别置信度。损失函数这块我拆开讲:
- 三维中心点坐标回归:使用SmoothL1损失
- 三维尺寸回归:使用SmoothL1损失,但对长宽高分别归一化处理,避免大尺寸物体主导loss
- 朝向角:分类损失加上残差回归损失,分类用交叉熵,残差回归用SmoothL1
- 总损失 = 加权组合,初始权重按照位置:尺寸:朝向 = 1:1:2分配
为什么朝向权重更大?因为朝向角对最终三维框的投影形状影响最大。常见的一个问题场景是,检测到的三维框位置正确、尺寸正确,但朝向反了,在俯视图中看起来框错位了,这在机器人避障场景里极有可能导致碰撞。所以我把朝向损失权重提得更高,让模型优先学会角度估计。
代码层面,3D检测头的输出维度根据类别数计算。如果检测类别是20类,每个位置预测2D框4个值、3D框7个值、类别分数20个值,共用31个通道,实际实现时还要加上目标性评分。
4.3 多任务损失融合与端到端训练
把2D和3D的损失合在一起后,一个非常实际的问题是损失量纲不一致。2D框回归的值是像素级,通常在几十到几百的范围;3D框回归的值是米级,通常在0.1到10的范围;分类损失是概率,在0到1的范围。如果直接相加,量纲大的项会主导整个梯度更新。我的解决方案是对每个损失分量做标准化处理,或者调整权重。
训练初期,模型还没学到基本的结构,3D回归的损失往往很大,我遇到过初期3D部分完全淹没2D部分的情况。一个有效的技巧是逐步增大3D损失的权重,让模型先学会2D检测的基本定位,再在锚点稳定的基础上优化3D回归。具体实现是设置一个ramp函数,前N轮训练中3D损失权重从0.1线性增加到1。这个技巧在实践中非常稳,能避免早期振荡。
端到端训练还有一个细节:梯度裁剪。多任务网络比单任务更容易出现梯度爆炸,原因是多个损失的梯度方向可能不一致。我在代码中设置了最大梯度范数限制为10.0,超过即裁剪。这个操作几乎没有任何成本,但对训练的稳定性帮助很大。
5. 训练调参与优化技巧
5.1 学习率策略与优化器选择
优化器我最终选的是带动量的SGD,而不是自适应优化器如Adam。原因可能跟很多人的直觉相反,但实测结果很明确:SGD配合合适的调度方案,最终精度普遍更好,尤其适合目标检测这种高精度要求的任务。自适应优化器收敛快,但后期精度往往差一截。如果想要快速验证代码可行性,可以用自适应优化器跑通,正式训练再换回SGD。
学习率调度上,我强烈推荐warmup加余弦退火的组合。warmup的作用是训练初期学习率从很小的值逐渐升到目标值,避免初始阶段大步长导致的模型震荡。余弦退火则是训练后期学习率平滑减小,在最优解附近精细搜索。代码结构如下:
def adjust_learning_rate(optimizer, epoch, warmup_epochs, total_epochs, base_lr): if epoch < warmup_epochs: lr = base_lr * (epoch + 1) / warmup_epochs else: progress = (epoch - warmup_epochs) / (total_epochs - warmup_epochs) lr = base_lr * 0.5 * (1.0 + math.cos(math.pi * progress)) for param_group in optimizer.param_groups: param_group['lr'] = lr实际使用中我常设warmup为5轮,总轮数80轮,基础学习率按骨干网络是否冻结来定。骨干微调用低学习率,新分支用高学习率,这个在前面提到过。如果使用混合精度训练,学习率可以适当调高一些,因为FP16下的梯度更小,但要注意观察是否出现精度溢出。
5.2 数据增强与泛化能力提升
数据增强的核心目的是让模型对光照、视角、遮挡等变化不敏感。2D部分我用了随机水平翻转、随机裁剪放缩、色彩抖动,这套组合在公开数据集上的增益明显。3D部分的增强要复杂很多,因为三维框和图像是绑定的,增强时必须保持一致性。
常见的3D数据增强有几种。全局旋转增强:对整个点云或深度图施加小角度旋转,同时更新所有三维标注框的朝向角和中心点坐标,模型因此学会了旋转不变性。全局缩放增强:随机缩放所有目标,但必须同步修改三维框尺寸,同时2D框也按比例变化,这能提升模型对不同距离目标的适应能力。地面噪声点去除:针对点云数据,保留地面附近一定高度范围内的点,去除远离地面和目标的散乱点,减少噪声干扰。
特别注意一点:数据增强的强度不是越大越好。过度增强会让训练分布严重偏离真实分布,比如把目标旋转90度会让朝向角的分布变成纯噪声,模型学到的是没有意义的映射。我的经验是小角度旋转控制在正负5度以内,缩放控制在0.9到1.1倍之间。
5.3 显存优化与训练效率提升
这套多任务模型在训练时显存消耗比单任务高出很多,很多人在这一步栽跟头。我常用几招应对显存溢出问题。第一招是梯度累积,显存不足时不要盲目降低batch size,batch size过小会导致BN层统计量不稳定。做法是每隔若干个step累积一次梯度再更新参数,等效扩大batch size。第二招是混合精度训练,PyTorch自动混合精度技术在16位和32位之间切换,显存占用大约减半,训练速度还能提升。前提是显卡支持Tensor Core指令,目前主流显卡基本都有。
第三招是减少不必要的中间变量存储。比如在不需要梯度回传的前向阶段用关闭梯度模式来推理,在训练循环里避免在GPU上保存重复的特征图副本。这些小优化累积起来能省出不少显存。
多卡训练方面,如果有多张卡,可以采用同步BN操作。这个技巧在多卡场景下能显著提升训练稳定性,因为BN统计量是全局的而不是单卡上的。实验管理的角度,训练日志建议记录每轮的损失各分量、学习率、验证mAP,后续调参时这些数据特别有用。
6. 常见问题与排查技巧
6.1 训练过程中的损失异常现象
多任务模型训练时损失异常的情况比单任务多,我把最常见的几种列一下。
第一种是损失变成NaN。排查方向有三步:第一步检查学习率是不是设置过高,对于非归一化的坐标回归损失,过高的学习率很容易让损失爆掉;第二步检查数据和标注里有没有异常的极大值,比如深度值出现极大异常点、标注坐标出现负值或超界;第三步检查是否有层级梯度爆炸,在损失除以一个极小值时会出现这个情况。加一个梯度裁剪几乎能解决大部分NaN问题。
第二种是损失不下降,始终在一个水平徘徊。这时候先确认是全局不降还是某个分量不降。如果是3D回归损失不降,大概率是锚框设计方案有问题,比如锚框尺寸与目标尺寸差距过大,模型一直在预测错误的偏移量。把锚框改成聚类统计得到的尺寸分布往往会立刻见效。如果是2D分类损失不降,先检查类别平衡问题。
第三种是损失下降很快但验证集指标很差,这是典型的过拟合信号。说明模型把训练集的特征背下来了,没有学到泛化规律。应对手段有增加数据增强强度、加dropout、降低模型复杂度等。
6.2 2D与3D结果对不上的排查思路
这个问题在项目联调阶段几乎必现。明明2D检测框标得很准,投影到3D坐标却完全对不上,或者3D框投影回图像偏了几个像素。排查的思路从数据链路入手,逐步定位。
第一步检查坐标系定义。2D标注的坐标原点是左上角还是左下角?Y轴方向是向上还是向下?这一步错了,所有结果全错。第二步检查相机内参。焦距、主点坐标、像素尺寸,任何一个数值错误都会导致投影位置系统性偏移。第三步检查深度来源。深度图与2D图像是否对齐?如果是雷达点云投影到图像,投影时是否做了点云裁剪和过滤?第四步检查可视化验证。把3D框的8个角点投影回2D图像,画在原始图上,如果投影框与2D检测框在像素级别不对齐,说明内外参或深度有问题;如果对齐了说明模型输出有问题。
我自己的排查习惯是做一个单独的可视化脚本,随机选择若干张图,把标注的3D框和预测的3D框同时投影到图像上,一眼就能看出是数据问题还是模型问题。这个脚本是我项目里的标配工具。
6.3 类别不平衡与难易样本问题
图像识别和3D检测都逃不过类别不平衡。某些类别样本多、某些类别样本少是常态。最简单的处理方式是设置类别权重,样本少的类别在损失函数中乘以更高权重。但这只解决数量不平衡,不解决难易不平衡。
困难样本挖掘是更有效的方案。在每个batch内,根据样本损失值排序,只对损失最高的部分样本进行训练。这个操作在目标检测和3D检测中都有效,因为大部分背景区域和大多数易分样本对模型的提升贡献很小,难样本才是模型能力增长的关键。困难样本挖掘可以和焦点损失函数结合使用,焦点损失自动降低易分样本的权重。我用下来发现,对于3D检测这类回归任务,困难样本挖掘的作用比焦点损失更明显,因为回归问题里没有明确的概率预测用于焦点权重调整。
7. 评估指标、部署落地与经验体会
7.1 评估指标的选择与分析
2D图像识别和检测的评估指标相对成熟,主要是各类别平均精度均值mAP和各类别平均精度AP。计算时的细节是:IoU阈值选0.5还是0.75,结果差异很大。0.5相对宽松适合粗定位,0.75严格适合精细定位。比赛和论文常用0.5到0.95的平均值,但工业项目我会直接看0.75或者0.5,跟业务需求走。
3D检测的评估有层次区分。最常用的是鸟瞰图AP,只看三维框在俯视平面上的IoU;更严格的是全三维IoU的3D AP,要把高度和朝向误差也纳入考量。我的经验是,两个指标都看,因为鸟瞰图AP高不代表高度方向准,很多实际场景中高度误差会导致抓取落空或避障误判。
实际评估中的另一个重要细节是困难程度划分。公开数据集通常按简单、中等、困难三个等级评估,困难等级的样本包括小目标、遮挡严重的目标、截断的目标。我强烈建议你评估时也做这样的划分,因为平均指标容易掩盖特定场景的失败。模型整体mAP很高,但困难样本的AP可能低得离谱,这在真实部署中就是事故隐患。
7.2 模型压缩与推理优化
训练完成的模型要落地到实际环境,首先关注推理速度。原始模型直接推理往往满足不了实时性要求。我的优化路线是:先做测试找出耗时瓶颈,一般集中在骨干网络前向和3D检测头的后处理上。然后做模型裁剪或通道剪枝,把冗余通道去掉。再之后做量化,将32位浮点转为8位整数,可以大幅提升推理速度,但也需要重新评估指标损失。最后用推理加速引擎进一步优化,在硬件支持的情况下可以获得非常可观的加速比。
模型导出和转换过程中的坑也不容忽视。PyTorch模型转ONNX时,动态维度设置不对会导致推理时输入尺寸固定;某些自定义操作符无法导出,需要写等价替代操作。我建议一开始就避免自定义底层操作,尽量使用框架标准算子实现,能省去大量转换时的排错时间。
实际部署中还有一个容易被忽视的点:训练时的输入尺寸和部署时的输入尺寸必须一致,否则BN层统计量会失配。我遇到过一个人,训练用640x640,部署时为了提速改成416x416,结果精度直接掉到不可用。要改尺寸就在训练阶段改,部署阶段严格一致。
7.3 项目的扩展方向
这套端到端多任务框架只是基础模型,实际可以扩展的方向很多。最直接的扩展是增加时间维度,把单帧检测扩展成多帧跟踪检测,通过时序信息解决单帧遮挡和深度估计不稳的问题。另一个方向是无监督域适应,用源域充分训练后,在无标签的新场景上通过伪标签机制逐步适配。还有一个和业务强相关的扩展是引入语义分割分支,让每个像素都有语义类别,这对精细操作场景帮助很大。
以我个人的实际体会来说,这类视觉多任务项目最考验人的不是模型搭建能力,而是对数据的理解和对细节的把控。那个巡检机器人项目,最初3D检测的结果总在边缘情况出岔子,后来我发现问题在标注数据不统一,部分深度图与图像存在一帧的时差。修掉这个数据问题后,整个系统指标的提升比任何模型修改都大。所以我特别想强调一点:遇到问题先怀疑数据,再怀疑代码,最后才怀疑模型结构。这个排查顺序能省掉你大量精力。
最后分享一个我自己的习惯。每次跑新数据训练前,我会先把几十张图的可视化结果打印出来,检查标注框、深度图、三维框投影是否对齐。看起来麻烦,但这个环节每次都能提前发现数据问题,避免白跑几十个小时的训练。做视觉项目,眼睛永远是最好的调试工具之一。