首页 / 资讯中心 / 文章详情

SSD目标检测实战:从原理到自制数据集训练全流程

SSD目标检测实战:从原理到自制数据集训练全流程 ★ FEATURED ARTICLE
SSDSingle Shot MultiBox Detector目标检测领域里绕不过去的一个经典模型。它把目标定位和分类统一在一个前向过程中一次推理直接输出所有候选框和类别概率不需要两阶段方法那样的先提候选区域再逐区域分类的繁琐流程。我在实际项目里用SSD做过工业零件检测、桌面场景识别、还有一些边缘设备上的轻量级检测整体感受是原理清晰、训练可控、对环境要求也不苛刻非常适合作为你上手训练自己的目标检测数据集的第一套完整方案。这篇文章我会从模型设计思路讲起再一步步带你走完环境搭建、自制数据集、训练调参、推理评估、踩坑排错的完整流程。适合有Python基础、了解基本卷积网络概念、但还没真正在自己的数据上跑通过完整目标检测流程的学习者。你不需要顶级GPU也不需要海量数据只要按着步骤来就能在自制数据集上完成SSD的端到端训练和检测。1. SSD的设计思路与核心机制拆解1.1 单阶段检测到底是什么要理解SSD得先分清目标检测的两条技术路线。两阶段检测的典型代表是Faster R-CNN系列思路是先粗筛再细查第一步用区域建议网络RPN在整张图上找出几千个可能存在目标的区域第二步再对每个区域做分类和边界框回归。好处是精度高坏处是慢两个阶段各跑一遍很难做到实时。SSD走的是另一条路一步到位。它把整张图分成多个网格每个网格点上预先放置一组不同尺寸和长宽比的默认框default box网络同时预测每个默认框里有没有目标、是什么类别、以及框的位置该往哪个方向调整多少。所有预测在一次前向过程中完成所以叫Single Shot。我经常用一个类比来解释这件事两阶段检测像你先用望远镜扫一遍整个草原发现可疑目标然后换单筒放大镜一个个仔细确认单阶段检测则是你直接站在瞭望塔上一次性用不同倍数的镜头同时扫过全场景谁是什么、在哪里一次看清。SSD属于后者速度优势非常明显。这里还有一个MultiBox的概念。它指的不是预测一个框而是预测一大批框。训练阶段会把默认框和真实标注框做匹配匹配好的默认框负责学习我该往哪里偏移、这个位置是什么目标没匹配上的默认框则负责学习这里没有目标。网络本质上是在做多任务学习一边学分类一边学框回归。1.2 多尺度特征图预测SSD的看家本领SSD最核心的设计创新是它不在单一层特征图上做预测而是在多个不同分辨率的特征图并行做预测。这个设计直接解决了一个老大难问题——小目标检测。早期的检测模型习惯只在网络最后一层特征图上接检测头但最后一层特征图经过多次池化和卷积下采样分辨率很低一个小目标可能只占据几个像素信息已经严重丢失检测效果自然差。SSD的做法是既然不同层特征图保留了不同粒度的信息那就在特征金字塔的多个层级上各接一组检测器。浅层特征图分辨率高、感受野小适合检测小目标深层特征图分辨率低、感受野大适合检测大目标。你可以把它理解成不同高度的观察者在看同一个场景站在二楼只能看到局部细节站在二十楼能看到全景轮廓SSD是让两者同时工作再汇总结果。这就是它名字里MultiBox之外的另一个关键——多尺度预测。具体到300x300输入SSD会在6层特征图上做预测38x38、19x19、10x10、5x5、3x3、1x1。每层给不同尺度的默认框尺度按线性递增公式分配s_k s_min (s_max - s_min) * (k - 1) / (m - 1)对一个m6层的网络结构s_min取0.2、s_max取0.9算出来6层的相对尺度约为0.2、0.34、0.48、0.62、0.76、0.9对应300输入就是约60、102、144、186、228、270像素。再配合多种长宽比比如1:1、1:2、2:1、1:3、3:1一个位置最多可以匹配6个不同形状的默认框。整个SSD300一张图会产生8732个候选框SSD512则是24564个。这个设计带来一个非常实际的收益检测各种尺寸的目标时模型天然具备了每个尺度都有各自专门的预测头的归纳偏置训练起来比单纯依赖最后一层特征图容易收敛得多。1.3 训练阶段不容忽视的配套机制多尺度预测是骨架但真正让SSD训练稳定的是配套的匹配策略和损失设计。先看先验框匹配。训练时每个真实标注框需要和默认框建立对应关系。匹配策略分两步第一步每个真实框优先匹配IoU交并比最高的那个默认框保证每一个真实目标都至少有一个正样本负责学习第二步对剩下的默认框只要和任意真实框的IoU大于0.5也算作正样本。这个0.5的阈值不是拍脑袋定的它保证了正样本在确实和某个目标重叠得不错的前提下尽量多缓解了正负样本比例天然悬殊的问题。再看负样本处理。一张图里大多数默认框都是背景如果全部参与损失计算负样本数量可能是正样本的几十倍模型会被背景类淹没。SSD的解决办法是难例挖掘hard negative mining按分类置信度损失从大到小排序挑选损失最高的那些负样本参与训练把正负样本比例控制在1:3左右。换句话说模型会把精力集中在那些让网络误以为有目标但实际没有的难例上而不是简单背景框上。最后是数据增强。SSD训练时的数据增强是一套组合拳随机裁剪、随机缩放、颜色抖动、水平翻转。其中随机裁剪特别重要它模拟了目标在视野中只出现局部的场景相当于无语义地制造了大量目标尺度变化和遮挡的困难样本。这也是SSD在VOC这类数据集上能和小目标斗争的关键手段之一。我现在自己训练模型时也保留了这个习惯宁可训练慢一点也要让模型见过足够多的残缺目标。2. 训练环境搭建从零把项目跑起来2.1 框架选型别在旧时代踩坑SSD最早是在Caffe框架下实现的网上大量老教程也都是Caffe版本。我不推荐你走那条路因为Caffe的环境配置至今仍是个深坑依赖库多、编译链路长、CUDA版本敏感很多老代码在新驱动上直接编译不过去。我见过不少同学把时间全耗在配置环境上模型一个epoch都没跑完。更推荐的是基于PyTorch的开源复现版本。PyTorch现在对训练、调试、可视化、模型导出的支持都更顺手处理图像数据的接口也更符合直觉。虽然Python代码跑起来的原始性能可能不如C后端硬核但对大多数个人项目和中小型业务场景来说开发效率和迭代速度远比那一点性能差异重要。你可以去代码托管平台搜SSD_PyTorch之类的仓库选一个star多、维护活跃的版本作为起点。依赖安装很直接核心就是PyTorch加上一些辅助库。我的建议是# 根据自身显卡驱动选择合适的CUDA与PyTorch版本 pip install torch torchvision pip install opencv-python numpy tqdm pip install pycocotools # 如果评估需要COCO API如果你用的是Linux环境建议直接用conda创建独立环境避免和系统Python环境打架。硬件方面我用一张12GB显存的消费级显卡训过300分辨率的SSDbatch size开到16或者32都没问题。8GB显存也能跑只要把batch size降到8左右。完全没有GPU的话小数据集也能用CPU硬扛但训练时间会长到让人怀疑人生。2.2 项目目录与数据目录规划我习惯动手之前先把目录结构规划好否则训练中途会发现乱七八糟的文件散落一地。下面是一套我验证过很多次的布局ssd_project/ ├── train.py ├── test.py ├── evaluate.py ├── data/ │ ├── datasets/ │ │ └── VOCdevkit/ │ │ └── MyDataset/ │ │ ├── Annotations/ # XML标注文件 │ │ ├── JPEGImages/ # 原始图片 │ │ └── ImageSets/ │ │ └── Main/ # train.txt, val.txt, test.txt │ └── config.py ├── checkpoints/ │ └── ssd300_epoch120.pth └── logs/这里项目名我用某自制数据集代指实际数据。为什么要用VOC格式而不是别的格式因为它结构直观、文件组织清晰标注和图片分开管理索引文件就是一行一个文件名非常容易理解。而且大多数SSD开源实现的DataLoader就是按VOC格式写的你只需要把自己的数据整理成这个结构代码基本不用大改。一个常被忽略的细节是图片名和XML文件名必须严格一一对应命名里不能有空格、中文、特殊符号。我建议统一用6位数字编号比如000001.jpg对应000001.xml。文件名不规则会导致数据加载莫名其妙报错而且定位问题时要花大量时间。2.3 预训练权重选择SSD的骨干网络默认是VGG16的前几层。为什么不自己从头训练整个VGG因为目标检测的骨干网络需要提取通用的视觉特征边缘、纹理、形状这些特征在大规模分类数据集上已经学得很好了。用预训练权重做初始化再在自己的目标检测数据上微调收敛速度会快非常多最终精度也更高。从零训练不是不行但除非你有几十万张级别的数据否则通常效果不佳。一些PyTorch复现版本会把VGG16预训练权重转换后塞进SSD结构里你只需要下载转换好的权重文件放到checkpoints目录即可。这里有一个实测过的注意事项不同复现版本对权重的组织方式略有差异下载时注意和你的代码版本对应起来否则加载权重时会出现键名不匹配的报错。万一报错也没关系检查一下状态字典的键名做一个简单的重映射就行后面我会在排错章节讲具体做法。3. 制作自己的数据集比训练更花时间的部分3.1 数据收集原则少而精不如多而杂你在训练上花一天往往能在数据上花一周。数据质量直接决定模型上限网络结构只是逼近这个上限的手段。先给个数量参考如果是单类别目标检测我建议每类至少准备300到500张原始图片多一些更好。我这里说的不是那种同一场景连拍10张的水数据而是要有足够的场景多样性。拿我自己做过的三类果蔬检测举例苹果、香蕉、橙子各400张左右但我会刻意覆盖不同光照室内灯光、自然光、不同角度俯拍、侧拍、斜拍、不同遮挡部分被其他物体遮住、堆叠摆放、不同距离近景特写、中景、远景甚至故意放进一些模糊图片做难例。模型只有在训练时见过足够多难看的姿势推理时面对真实场景才不会露怯。有一个原则特别值得强调宁可图片总数少一点也要保证所有图里有目标、目标标注无误。网上有些人为了赶进度大量下载图片后随便框一下就开训结果模型学到的全是错误的定位模式效果还不如小数据集精心标注。数据质量永远是第一位的。3.2 使用开源标注工具标注并整理标注工具我推荐开源免费、界面简单的矩形框标注工具操作逻辑是打开一张图鼠标拖拽画框填写类别名称保存后就生成VOC格式的XML文件。这些工具一般会帮你自动生成XML装在本地即可使用不需要联网配置服务。标注时有两个很容易被忽视的细节。第一标注框要尽量贴合目标边缘不要为了省事留一圈空气边。第二框得太紧也不行因为框回归的偏移量本身就包含了一定的误差空间标得太紧反而让模型学不到合理的边界。我自己通常的做法是让框的边缘比目标实际轮廓稍微收缩一到两个像素这样模型预测的框普遍更紧凑。遮挡目标的标注建议遵循一个原则只要目标还有明确的可见主体就标注它的可见部分不要试图去标一个脑补出来的完整物体。这个细节对模型非常关键它教会模型物体会被遮挡但可检测性依然存在。标注完后一定要做二次校验。最有效的办法是找一个没参与标注的同学随机抽20%的图重新过一遍看看框的位置和类别命名是否一致。我发现多人标注项目里类别命名的混乱同一个物体一会儿叫apple一会儿叫Apple是导致训练loss异常的主要元凶之一。一个统一的命名规范能省无数麻烦。3.3 划分训练集与测试集数据集做好之后第一步是把图片和XML组织进JPEGImages与Annotations目录然后划分样本索引。我建议按8:1:1划分训练、验证、测试集并且在程序里固定随机种子保证每次划分结果一致。下面给一个简单的划分脚本你可以根据自己的情况修改import os import random from pathlib import Path random.seed(42) image_dir Path(JPEGImages) names [p.stem for p in image_dir.glob(*.jpg)] random.shuffle(names) n len(names) train_names names[:int(n * 0.8)] val_names names[int(n * 0.8):int(n * 0.9)] test_names names[int(n * 0.9):] def write_txt(path, names): with open(path, w) as f: for name in names: f.write(name \n) main_dir Path(ImageSets/Main) main_dir.mkdir(parentsTrue, exist_okTrue) write_txt(main_dir / train.txt, train_names) write_txt(main_dir / val.txt, val_names) write_txt(main_dir / test.txt, test_names) write_txt(main_dir / trainval.txt, train_names val_names)这里必须提醒一个数据泄漏问题如果同一个物体的多张连拍图被同时分进训练集和测试集你的测试分数会虚高因为模型等于已经见过测试目标了。我处理这类问题的方法是先按场景分组在场景级别而不是图片级别做划分。比如同一次拍摄会话产生的图片归到同一个场景组然后以场景组为单位切分数据集。这样评估结果才可信。3.4 转成目标格式的注意事项如果你拿到的数据不是VOC格式而是像CSV、JSON或者某种私有标注格式需要写一个转换脚本。转换的核心步骤无非是把标注信息读出来重新组织成VOC XML再把图片统一命名和格式。写转换脚本时有一个细节值得注意类别名称建议统一为小写英文。虽然VOC格式本身对大小写不敏感但很多数据处理代码、数据增强模块、评估脚本都默认按名称匹配如果名称大小写不一致可能在类别统计时出现两个不同的分类导致评估时对不上号。我也遇到过因为类别名带空格导致数据加载失败的案例所以在转换时做一遍清理去空格、统一小写、替换特殊符号是一个低成本高收益的动作。另外转换完一定要抽查。随机打印几张图像的标注框信息再配合图像可视化画出框来确认坐标没有错位、类别名称没有混乱。坐标错位最常见的原因是原数据里坐标是相对坐标比如0到1的小数而转换时没有按图片宽高还原成绝对像素这个问题排查起来很费时间最好在源头就验证清楚。4. 开始训练配置、命令与节奏控制4.1 修改模型与训练配置每个参数都有讲究拿到开源代码后第一个要改的就是类别数。VOC原本是20类但你的数据集可能只有3类。SSD在计算分类损失时类别数等于实际类别数加1额外一个背景类所以num_classes需要改成实际类别数加1。如果你检测三类果蔬这个值就是4。训练尺寸的选择同样重要。SSD300表示输入300x300SSD512表示输入512x512。分辨率更高小目标检测能力更强但显存占用和训练时间会明显增加。我的建议是先在300分辨率上把流程跑通确认数据没问题后再考虑要不要换成512。我自己在做小目标密集场景时才用512普通场景300完全够用。batch size和初始学习率是一对好兄弟。参考常见的训练策略batch size调小时初始学习率也该等比降低。我推荐一个保守的起点batch size 16初始学习率0.001如果你只能开batch size 8就把学习率降到0.0005左右。优化器用SGD加动量momentum0.9配合权重衰减5e-4这是SSD训练很经典的一套配置。不要一上来就盲目上AdamSSD这类带大量锚框的模型对学习率比较敏感SGD的稳定性更适合。还有一个容易被新手忽略的参数学习率调度策略。总epoch设多少warmup要开多久学习率在哪个阶段线性衰减这些直接影响收敛质量。通常我会先跑一个100到200个epoch的大循环学习率在前几个epoch做warmup从很小的值升到目标值然后在训练后期几个阶段各衰减一次。如果你用的复现代码默认只写了VOC的120轮调度那么对自制小数据集来说epoch要适当延长模型才能充分收敛。4.2 从Debug到正式训练的完整流程我强烈建议你正式开训之前先做一个冒烟测试从每类数据中抽10张左右组成一个迷你训练集跑一个epoch。这个动作看起来简单却能帮你避开大量无效等待。冒烟测试通过的标准很简单程序不崩、loss稳定下降、每个batch都能正常反传。如果冒烟测试中loss卡住不动先别急着调学习率检查数据标签是不是有问题例如某些XML里类别名对不上配置列表、某些图里标注框是空的。一次batch里如果大部分目标都有标注问题loss会异常波动甚至不降。把数据问题排查干净模型训练才谈得上收敛。冒烟测试通过后就可以开始正式训练了。命令行跑起来时记得把日志输出到文件方便回溯。通常在训练过程中我会同时开一个tensorboard类工具实时看四个曲线总loss、分类loss、定位loss、学习率变化。这四个曲线是判断训练是否健康的核心仪表盘。训练中还有一个容易被低估的细节定期保存checkpoint。很多代码默认只保存最后一个epoch的模型但训练后期如果出现震荡或过拟合你会希望回到一个相对稳定的中间状态。我更推荐每5到20个epoch保存一次同时始终保留验证集mAP最高的那次权重作为best模型。我的习惯是checkpoint按epoch存best按指标存这样既不会丢失训练进度又总能拿最优模型出来推理。4.3 训练中的性能观察与调参建议训练过程中你观察到的曲线应该有这样的变化前20个epoch里总loss快速下降尤其是分类loss中间阶段loss下降变缓定位loss开始起作用后期loss缓慢震荡下降进入细调阶段。如果某个阶段出现了loss完全不变或者验证集mAP骤降就要警觉了。我用一个实际案例说明之前某次训练做的是三类果蔬检测1200张训练图跑SSD300VGG骨干单卡12GB显存一共训练200个epoch。前10个epoch热身后验证集上mAP已经能到0.7左右之后在0.75到0.8之间缓慢爬升最终稳定在0.83附近。整个训练过程大约几个到十几个小时完全在可接受范围。如果训练结果显示mAP只有0.3甚至更低大概率不是网络结构问题而是以下某个环节出了问题标注错位、类别不均衡、训练集划分包含重复图、学习率过大导致震荡。我建议按顺序排查先可视化一批训练样本检查标注框是否正确对齐到目标再统计每个类别的训练样本数量看是否存在严重的类别不平衡最后再回头看学习率是否合适。关于loss出现nan最常见的原因是学习率太大导致梯度爆炸数据处理时出现除零或者是输入图像中出现异常像素值。我的排查顺序是先降低学习率十倍看看nan是否消失如果还不行再检查数据增强模块里会不会产生非法边界框。诉诸于开梯度裁剪或者调小batch是最后的手段。很多同学喜欢一上来就追求花哨的新模型但我想说先把SSD用透真的足够了。SSD的训练流程覆盖了数据加载、锚框匹配、损失计算、NMS去重、评估指标等全部核心知识点如果你在一个模型上把这些环节都理解透了再迁移到任何其他检测模型都不费劲。5. 检测推理、评估与落地扩展5.1 推理管线与核心代码训练完模型后离检测自己的数据集只差最后一步推理。推理流程和训练时不一样不需要匹配真实框也不需要难例挖掘核心只有预处理、前向、解码、NMS四步。预处理的关键是把输入图片缩放到训练时的尺寸并做同样的归一化。很多推理报错都源于这里你训练时用了一张300x300的图推理时却塞进去一张原始高清大图模型当然输出不对。SSD的输入是固定尺寸的这也是它和全卷积网络的一个区别。下面是一段基于PyTorch的推理核心代码可以直接参考import torch import torch.nn.functional as F import cv2 import numpy as np def detect_one_image(model, img_path, class_names, conf_thresh0.5, nms_thresh0.45): model.eval() img cv2.imread(img_path) # 缩放并归一化 img_resized cv2.resize(img, (300, 300)).astype(np.float32) # 按训练配置做减均值、乘缩放 img_tensor torch.from_numpy(img_resized).permute(2, 0, 1).unsqueeze(0) img_tensor (img_tensor / 255.0) with torch.no_grad(): # 前向返回分类置信度和预测框偏移 confidences, locations model(img_tensor) # 解码根据默认框和偏移计算真实坐标 boxes decode(locations, default_boxes) # 由具体实现提供 # 置信度过滤 keep confidences.squeeze(0).max(dim1).values conf_thresh boxes boxes.squeeze(0)[keep] scores confidences.squeeze(0)[keep] # NMS去重 final_boxes, final_scores, final_labels nms(boxes, scores, nms_thresh) return final_boxes, final_scores, final_labels这里的decode函数做的是把网络预测的偏移量加回默认框上。SSD在训练时不是直接回归框的绝对坐标而是回归相对于默认框的编码偏移量所以推理时也必须用同样的编码方式解码。这一步很容易出错如果你的推理框位置完全对不上目标先怀疑解码逻辑有没有和数据预处理对齐。NMS非极大值抑制的目标是去掉重复检测同一目标的框。它的逻辑很直白先把所有候选框按置信度从高到低排序然后取置信度最高的框把所有和它IoU大于阈值的框都删掉再取下一个最高分的框重复直到处理完。nms_thresh一般设0.45太高会导致多个框重叠在一起太低会把同一目标的不同部位拆成多个目标。可视化推理时conf_thresh可以设0.5甚至更高减少误检框的干扰。5.2 mAP评估与结果可视化跑完测试集后你需要一个客观的量化指标来衡量模型好坏。标准做法是计算mAPmean Average Precision。具体来说对每个类别绘制精度-召回率曲线曲线下的面积就是该类别的AP所有类别AP取平均就是mAP。mAP这个数字很有用但它会掩盖一些信息。一个常见陷阱是如果某个类别的训练样本特别少它的AP会非常不稳定而mAP把这个不稳定平均掉了。所以我评估时不仅看mAP总数值还会逐个类别看AP并打印每个类别的召回率。如果发现某个类检测得特别差多半是它的样本太少或者场景和训练数据差异过大这时候优先补数据而不是调模型。除了数字指标可视化评估也必不可少。把测试图片跑一遍检测把预测框画在原图上并保存成图片然后人工扫一遍这些结果图。这一步能让你发现数字指标发现不了的问题模型是不是总在某个固定位置误检是不是对某一类特定颜色特别敏感可视化结果是和业务方沟通时最有说服力的材料也是判断模型是否真的可用的最后一关。5.3 扩展模型导出与部署思路如果你只想在自己的电脑上跑推理直接加载pth文件就行。但如果你要把它集成到服务或者另一个程序里可以导出成标准格式。PyTorch模型导出最常用的方式是ONNX导出后用ONNX Runtime推理可以明显提升部署时的加载速度和推理性能。导出前有几点要注意模型结构固定成训练时的状态输入尺寸也固定下来导出后一定要在ONNX Runtime里跑一张测试图和PyTorch的推理结果做数值对比偏差应该在极小范围。如果差异大基本可以确定是预处理环节在两边写得不一致。部署到CPU时还要注意有些在GPU上天然支持的操作在CPU上会退化为较慢的实现所以导出后实测CPU推理时间是很必要的。业务场景如果对实时性要求很高还可以考虑把SSD模型转成更轻量的版本但这已经属于优化范畴不在跑通流程的范围内。先把标准流程跑通再考虑优化是我反复强调的做事节奏。6. 常见问题、避坑实录与个人心得6.1 高频错误排查速查表下面这张表是我在多次指导和自用过程中总结出来的高频问题清单。你训练时遇到报错和异常先来这里对照一下。问题现象最常见原因解决建议loss一直不降标注错位 / 类别错乱 / 学习率太小可视化训练样本、检查标签映射、适当调大学习率loss变成nan学习率太大 / 数据增强产生非法框 / 梯度爆炸降低学习率10倍、检查增强代码、加梯度裁剪显存不足OOMbatch太大 / 输入分辨率太高减小batch、降低分辨率、使用梯度累积检测不到任何目标conf_thresh太高 / 模型欠拟合 / 解码逻辑错误调低阈值、延长训练、重点检查decode函数小目标漏检严重300分辨率信息丢失 / 小尺寸默认框偏少换512输入、检查小尺度特征图预测头预测框位置偏移解码偏移量计算错误 / 预处理不一致核对编码解码公式、统一输入归一化方式评估mAP虚高数据泄漏 / 测试集包含训练图像按场景分组划分数据集重新生成索引加载权重报错预训练权重结构不匹配比对状态字典键名做键名重映射补充一点训练环境报错时不要一上来就怀疑代码库。先看自己有没有改坏配置再看数据路径是否正确最后才考虑代码本身的bug。大部分人的问题都出在前两类。6.2 几个很少有人提醒的隐性坑有个坑是我自己踩过多次的训练集和验证集的数据增强不一致。很多代码默认训练集做全套数据增强验证集和测试集只做简单归一化。这本身没错但如果你为了省事在划分数据集时把验证集图片也扔进训练数据增强管道里验证指标就会异常波动而且你很难意识到是这里出了问题。我建议每一个需要改数据处理的环节都单独写清楚注释不弄混训练和评估两套流程。另一个隐性坑是训练集里有些图的标注框完全在图像外。出现这种情况多半是转换脚本处理坐标时出了问题或者图片被裁剪缩放后标注没跟着变。SSD的代码一般会跳过或者报错但如果你用的是那种隐式忽略的版本模型就会在不知不觉中学到错误信息。我发现这个问题的方法是统计每个图片的标注框位置看看有没有框的中心点坐标异常超出图像尺寸的情况一旦发现就回到转换脚本修正。还有一个值得养成的好习惯训练过程中每过一定轮次就抽样可视化一次验证集的检测结果保存成带有epoch编号的图片。这样你能直接看到模型从乱框到有模有样的变化过程也能及时发现模型开始过拟合的征兆比如训练loss下降但验证集AP开始下降。我把这个习惯保留到了现在每次训练都会定期翻开那些可视化图片直观感受模型学到了什么这比单纯盯loss曲线更能建立对模型行为的直觉。最后说一个我从实践里得到的总经验目标检测项目里最珍贵的东西是数据质量和数据处理的一致性而不是模型结构有多酷炫。SSD给了你一套非常成熟可靠的框架你把数据管好、把训练流程走稳效果就能超过很多数据一团糟但模型很新的项目。先用SSD跑通自己的完整流程等你对锚框、匹配、NMS、mAP这些概念都有了真实手感再去看任何更复杂的模型都会轻松很多。
阅读完成 · 觉得有帮助?
咨询建站