基于深度学习的混凝土马路与泥地马路识别,选题本身常见,但想做得不水、有亮点、能顺利过盲审,关键在于数据方案和模型细节,这两块也恰恰是答辩时最容易暴露问题的地方。这篇文章我会从选题拆解、数据集构建、模型改进、训练调参、部署与论文包装几个角度完整过一遍,帮你把整个项目从“会跑代码”提升到“能讲清楚、能答辩”的水平。
1. 选题价值与核心难点拆解
1.1 这个选题解决了什么实际问题
混凝土马路和泥地马路的识别,本质是道路场景下的地面材质分类。它对应着很多真实需求:农用机械在田间作业时,需要判断前方是硬化路面还是松软泥地,以决定是否调整动力输出、防止陷车;巡检机器人、清洁设备在园区或乡村环境行走时,需要根据地面类型切换行走策略与清扫力度;地形勘测、自动驾驶的非结构化道路感知,也需要从视觉上区分可通行道路与软地面。
这类识别任务有一个明显特点:两者外观差异不算小,但环境干扰因素非常多。混凝土路面可能是干燥的浅灰色、雨季的深灰色、带裂缝的旧路面;泥地可能是干裂的土黄色、湿润后的深褐色、长满杂草的松软土路。光照、阴影、季节、拍摄角度都会让同一类路面呈现截然不同的视觉特征。如果只用简单的颜色阈值或传统纹理特征,很难做到稳定区分,深度学习的优势正是在于可以从大量样本中自动学习稳健的视觉表征。
从算法角度看,这个任务既可以做成图像分类(判断一张图是混凝土路还是泥地路),也可以做成语义分割(对路面像素级分类),还可以做成目标检测(框出路面区域)。三种任务形态难度递增,适合不同基础的学生。我后面会详细对比这三条路线怎么选。
1.2 技术水平评估与难度定位
这个选题的难度属于中等偏上,适合有一定Python和深度学习基础的人,纯零基础的同学需要先补足一些前置知识才有把握完成。
技术栈涉及的主要内容包括:
- Python基础与图像处理(用OpenCV做预处理、数据增强)
- 深度学习框架(PyTorch或TensorFlow任选其一,建议PyTorch,社区资源更丰富)
- 卷积神经网络基础知识(卷积、池化、全连接、BatchNorm的基本原理)
- 图像分类或语义分割模型的训练流程(数据加载、训练循环、验证评估)
- 模型部署与可视化(可选,用Flask做Web演示或者用Gradio做交互界面)
比纯MNIST手写数字识别、CIFAR-10分类这类入门项目复杂一些,但比目标检测、实例分割这类任务简单。核心工作量集中在数据准备和训练调参两个环节,模型结构本身有大量预训练权重可以复用,不必从零训练。
1.3 三种任务形态怎么选
我在指导同学做毕设的过程中,发现很多人一开始就纠结“我该做分类还是分割”,这里给一个明确的借鉴依据:
| 任务形态 | 输出内容 | 适合人群 | 工作量 | 答辩亮点 |
|---|---|---|---|---|
| 图像分类 | 整张图片的类别 | 基础一般、时间紧张 | 较低 | 模型对比实验、可视化分析 |
| 目标检测 | 路面区域的边界框 | 有过检测经验 | 中等 | 定位能力展示 |
| 语义分割 | 像素级类别掩码 | 想挑战高水平 | 较高 | 像素级精度、边缘质量分析 |
如果追求性价比,强烈建议选图像分类作为主任务,同时附加一个简单的分割作为拓展实验。比如你用一个分类模型完成主干工作后,再用同一个数据集跑一个轻量分割模型,把两者的结果对比放在论文里,研究内容立刻丰富起来。这样做的主要原因是分类任务的评价指标清晰(准确率、精确率、召回率),容易出漂亮的结果;而分割任务对标注质量要求高,手工标注掩码的工作量非常大,如果标注不细致,训练出的效果反而拖后腿。
2. 数据集构建与预处理
2.1 数据采集的几条可行路线
混凝土和泥地路面图片,不像行人、车辆那样有成规模的开源数据集可以直接下载,主流开源数据集里几乎找不到现成可用的,只能自己采集或组合公开资源。这里有三条路线可以参考:
第一,网络爬取。用爬虫从图库网站搜索混凝土路面、水泥路、泥路、土路、乡间小路等关键词,批量下载图片。需要注意版权问题,尽量选用允许学术使用的图库,或者用搜索引擎的公开缩略图做初步实验。爬取到的图片质量参差不齐,需要逐张筛选,剔除重复图、无关图、带水印的图。
第二,实地拍摄。如果学校周边有城乡结合部、施工工地、农田区域,自己用手机拍摄是最理想的方式。你可以控制拍摄角度、光照条件、距离,并且可以主动采集一些“难例”——比如雨后半干半湿的泥路、有积水的混凝土路面、被泥土覆盖的水泥路,这些样本对模型泛化能力帮助极大。
第三,开源数据集组合。虽然缺乏现成的路面分类专用数据集,但可以通过组合多个来源来构建:从场景分类数据集中抽取包含道路的图片,从无人机航拍数据集中裁剪地面部分,甚至可以用视频关键帧提取来扩充数据量。
不管用哪条路线,一个铁律是每个类别至少需要1500张以上图片,推荐2000到3000张。太少的话,训练出的模型很容易过拟合,尤其泥地类别本身纹理变化大,样本不足根本学不到核心特征。我见过不少同学抱着六七百张图硬训,结果验证集准确率只有七十多,却不知道问题出在数据量上。
2.2 数据清洗与标注规范
采集完成后,清洗环节不能省。我的习惯是分三步走:
- 先用脚本批量检查图片尺寸、通道数,删除损坏文件和小于一定尺寸的图片。
- 人工快速浏览一遍所有图片,剔除明显跑偏的样本,比如混入的森林、天空、建筑内部等内容。
- 对保留的图片做重命名,保持统一的命名规范,便于后续管理。
分类任务的标注相对轻松,只需要在文件夹层面区分。建议结构如下:
dataset/ ├── train/ │ ├── concrete/ │ ├── mud/ ├── val/ │ ├── concrete/ │ └── mud/ └── test/ ├── concrete/ └── mud/这里有个细节容易踩坑:训练集、验证集、测试集必须在数据层面完全隔离。很多人习惯把所有图片塞进一个文件夹,然后用代码随机划分,这本身没错,但如果你的数据来源比较复杂(比如同一场景连拍了很多张相似图),不做来源隔离会导致“数据泄漏”。比如你连续拍摄的20张照片被同时分进了训练集和验证集,那么验证集里出现的实则是训练图像的高度相似副本,测试结果会虚高很多,答辩时一旦被追问就会很难堪。
2.3 数据增强策略
路面识别任务中,数据增强不是可选项,是必备流程。原因很简单:实际场景中拍摄角度、光照、天气变化剧烈,如果模型只在“好看”的图片上训练,实拍效果必然惨不忍睹。
建议的增强策略分两类:
基础增强(直接作用于原始图片):
- 随机水平翻转
- 随机旋转(-30度到30度)
- 随机裁剪与缩放
- 色彩抖动(亮度、对比度、饱和度微调)
高级增强(针对路面场景特别设计):
- 添加高斯噪声,模拟传感器噪点
- 随机遮挡(Cutout或Random Erasing),模拟树叶、水渍、阴影遮挡路面
- 模拟雨天效果(叠加半透明斜线纹理)
- 模拟阴影效果(在图片局部压暗)
这些增强操作不必全部叠加,建议在训练过程中使用在线增强,即每次迭代对batch内的图片动态做变换,增加样本多样性。PyTorch里的torchvision.transforms就能覆盖大部分需求。
2.4 分割任务的标注思路
如果选择加做语义分割拓展实验,你需要准备带像素级标注的图片。标注工具推荐用Labelme或Label Studio,手工勾勒路面区域的轮廓,导出为JSON格式,再转为掩码图。
这是一项体力活,一张中等复杂度的图片大约要花三到五分钟。建议只对部分数据做分割标注,比如400到500张,作为子实验使用,不要求所有数据都做分割。这样能控制工作量,又足以支撑论文里的对比分析。如果你用分类数据集训练分割模型,但完全没有像素级标注,还有一个偷懒方案:用弱监督方法,直接用图片级标签训练分割模型(例如CAM类方法),效果略差但是工作量小很多。这个可以作为论文里的“探索性实验”来写。
3. 模型选型与改进方案
3.1 为什么优先考虑预训练迁移学习
混凝土路面和泥地路面的识别,从视觉特征上看属于中粒度的纹理与材质分类。它既不像猫狗识别那样有明确的物体轮廓,也不像医学影像那样需要极其精细的局部特征。对这类任务,从头训练一个小型卷积网络的性价比很低,因为数据量撑不起足够深的网络,最终精度和泛化能力都不理想。
比较稳妥的做法是使用在ImageNet上预训练过的模型,然后在自己的数据集上微调。这里面的道理可以打个比方:预训练模型相当于一个已经学过大量“通用视觉知识”的学生,你只需要教它区分路面这个小任务;而从头训练相当于一个完全没见过任何图像的婴儿,你需要把基础视觉能力一起教出来,这需要的数据量和时间是完全不同数量级的。
迁移学习还有一个实际好处:预训练模型的权重文件可以直接从PyTorch官方模型库下载,省去了漫长的训练过程,基础实验基本能在半小时内跑完一轮完整训练,这对毕设的时间规划非常有利。
3.2 主干网络对比
网络选择上,主流预训练模型各有特点:
| 模型 | 参数规模 | 推理速度 | 精度表现 | 适用建议 |
|---|---|---|---|---|
| ResNet18 | 约117M | 快 | 良好 | 轻量基线,适合快速验证 |
| ResNet50 | 约255M | 中等 | 优秀 | 最常用的主干,性价比高 |
| EfficientNet-B0 | 约53M | 快 | 优秀 | 参数少,性价比高 |
| EfficientNet-B3 | 约120M | 中慢 | 更优 | 追求精度可以选择 |
| MobileNetV3 | 约25M | 极快 | 良好 | 适合移动端部署展示 |
| Swin Transformer | 约290M | 慢 | 优秀 | 适合做对比实验 |
我的建议是:核心模型用ResNet50,因为它的预训练权重最稳定,PyTorch中一行代码就能加载,训练过程中不容易出幺蛾子。然后选一个轻量模型(MobileNetV3)和一个Transformer模型(Swin Tiny或ViT)做对比实验,论文里就有“传统CNN vs 轻量CNN vs Transformer”的对比数据,内容会充实很多。很多同学问是不是模型越大越好,其实不然,你的数据集规模决定了模型的上限。两三千张的基础数据量下,ResNet50和ResNet101的精度差距往往很小,但训练时间差一倍,没必要盲目堆大模型。
3.3 针对路面场景的模型改进思路
单纯调用预训练模型微调,能拿到一个不错的基线结果,但要写进毕业论文,最好还是有一点自己的改进。这里说几个经过验证的改进方向,难度由低到高:
全局平均池化替换为池化融合。默认的分类头通常在最后一层特征图后面接全局平均池化,但路面识别的关键特征既包含整体纹理(材质粗糙度)也包含局部细节(裂缝、车辙、水渍)。建议把GAP和全局最大池化的输出拼接起来,让分类头同时利用“平均响应”和“最强响应”的特征。实现很简短,就是在forward里加几行代码:
import torch.nn as nn class DoublePoolingHead(nn.Module): def __init__(self, in_features, num_classes): super().__init__() self.avg_pool = nn.AdaptiveAvgPool2d(1) self.max_pool = nn.AdaptiveMaxPool2d(1) self.fc = nn.Linear(in_features * 2, num_classes) def forward(self, x): avg_feat = self.avg_pool(x).flatten(1) max_feat = self.max_pool(x).flatten(1) feat = torch.cat([avg_feat, max_feat], dim=1) return self.fc(feat)引入注意力模块。可以在ResNet的每个stage后面插入一个轻量的注意力模块,压缩通道维度不大,像SE模块是通道注意力,CBAM是空间与通道的混合注意力。路面图像中,模型应该更关注有纹理信息的中部区域,而不是天空或边缘杂物。加入注意力模块后,模型能自动为相关区域分配更高权重,在泥地与混凝土颜色相近的时候(比如干水泥路和干黄泥土),这个改进往往能带来2到3个百分点的准确率提升。
多尺度特征融合。路面上的车辙、裂缝、石子颗粒大小差异很大,单一尺度的特征难以同时捕获。可以在ResNet的stage3和stage4之后分别取出特征图,使用FPN式的特征融合方式合并到分类头。这能增强模型对纹理细节的感知,缺点是代码复杂度上来了,调试时间会增加。建议在核心模型上实现,时间不够就先用双池化加注意力的组合。
3.4 分割任务的模型选择
如果做分割拓展实验,有两个选择:DeepLabV3和U-Net。前者搭配ResNet骨干,分割精度高,适合复杂场景;后者结构简单,对小数据集友好,实现起来也更顺手。
分割实验的目的不是跟SOTA比指标,而是证明你理解语义分割的基本原理。所以选U-Net就足够了,主要分析它在路面边缘处的分割准确率和交并比(IoU)。在这个任务上,泥地边缘往往与杂草、碎石混在一起,分割边缘粗糙是正常现象,但在论文里可以结合数据增强来改善——训练时对分割掩码做同样的随机翻转和旋转,可以显著提升边缘预测质量。
4. 训练流程与调参经验
4.1 环境搭建要点
建议使用的环境组合:
- Python 3.8至3.10
- PyTorch 1.12以上(2.x版本也可以,只是个别API有变化)
- torchvision配套版本
- OpenCV-Python
- NumPy、Matplotlib、Scikit-learn(评估指标计算)
- CUDA(如果本机没有NVIDIA显卡,可以租用云GPU平台训练,或者退而求其次用CPU训练,但速度会慢很多,建议至少租个入门级云端GPU)
安装环节最容易出的问题是PyTorch和CUDA版本不匹配。检查CUDA版本用nvidia-smi,安装PyTorch时用官网提供的对应命令,不要自己随意指定版本。这个坑我见过太多次了,很多人花半天时间装环境还报错,最后发现是PyTorch的CUDA runtime与驱动版本不一致。
4.2 训练超参数设置
超参数设置直接决定模型能否收敛,给一份可参考的配置:
| 参数 | 推荐值 | 说明 |
|---|---|---|
| 输入尺寸 | 224×224 | 与预训练模型保持一致 |
| Batch Size | 16或32 | 根据显存调整 |
| 初始学习率 | 0.001 | 微调阶段常见配置 |
| 学习率调度 | CosineAnnealing或StepLR | 建议Cosine,收敛更平滑 |
| 优化器 | Adam或SGD | SGD+动量泛化稍好,Adam收敛快 |
| 冻结层数 | 前几层冻结或全部微调 | 数据量小就冻结更多层 |
| 训练轮数 | 20到50 | 根据验证集表现早停 |
| 损失函数 | 交叉熵 | 类别不均衡可加权 |
微调迁移学习有两种策略。策略一:特征提取模式,冻结主干全部参数,只训练分类头。收敛快、不易过拟合,但精度上限低一些。策略二:全量微调,所有层都参与训练,效果上限更高,但需要更小的学习率和更多训练轮数来避免破坏预训练权重。我的经验是:先跑策略一得到基线,然后解冻所有层用更低学习率继续训练,这样既快又稳。
这里要特别解释一下学习率的选择依据。全量微调时,因为预训练权重已经是一个很好的解,学习率不能太高,否则一步跨大了就“走出山谷”,把预训练学到的好特征破坏了。0.001是分类头初始训练的安全值,解冻主干后建议降到0.0001。SGD优化器带动量(动量系数0.9)配合权重衰减(5e-4),往往比Adam泛化性能略好,但Adam省心,不需要太多调整。
4.3 训练过程中的监控与日志
训练时不要只在终端里打印loss,推荐把每个epoch的loss、accuracy、precision、recall都记录到CSV文件或TensorBoard里。这不只是为了你自己看趋势,答辩时这些可视化图表本身就是很好的展示材料。
重点观察两个指标的组合:训练准确率和验证准确率的差距。如果训练集准确率已经到95%以上但验证集只有80%,说明过拟合严重,需要加强数据增强、增加权重衰减或提前截断网络(比如dropout)。如果两者都低,说明欠拟合,模型容量不够或训练不充分。路面识别任务中,我们踩过坑的一个现象是:模型在验证集上振荡明显,后来发现问题出在验证集划分不合理,某几类泥地样本集中在了特定光照条件下,导致验证集分布偏差。重新按来源分层划分后,振荡立刻消除了。
4.4 类别不均衡的处理
正常情况下混凝土和泥地的样本数量应该大致均衡。但如果你采集数据的时候,某类图片特别多、某类特别少,建议做两方面处理:一是简单过采样,把少类图片重复采样,让每个batch里两类比例接近1:1;二是给交叉熵损失函数加上类别权重,让少类的梯度贡献更大。
PyTorch里计算权重可以这样:
import torch.nn as nn num_class_samples = [concrete_count, mud_count] total_samples = sum(num_class_samples) weights = [total_samples / (2 * c) for c in num_class_samples] weights = torch.tensor(weights, dtype=torch.float) criterion = nn.CrossEntropyLoss(weight=weights)这个公式背后的逻辑是:让每类的损失贡献与样本数成反比,样本少的类别损失权重更大,模型就会更重视学习这类样本的特征。
5. 实验设计与结果分析
5.1 基线实验与消融实验设计
毕业论文的审阅老师最看重的是实验设计的逻辑性。不建议只提交一个“我用ResNet50跑出了92%准确率”的结果,背后没有对比、没有分析,这样的论文显得很单薄。
合理的实验安排建议分三层:
- 基线实验:ResNet50直接微调,不做任何额外改进,记录初始性能。
- 改进实验:在基线上逐步加入改进模块(双池化、注意力、多尺度融合),每加一个模块记录一次效果。
- 对比实验:用MobileNetV3、EfficientNet、Swin Transformer等做同样条件下的训练,横向对比性能。
这样设计后的结果表格,实际上就在讲一个完整的故事:我从哪里开始(基线),每步做了什么优化(消融),效果如何(指标变化),与其他方案的差距在哪里(横向对比)。
5.2 评价指标选择与计算方式
分类任务的常用指标,在答辩时每个都要能解释清楚:
- 准确率(Accuracy):所有预测正确的样本占总样本的比例。类别均衡时够用。
- 精确率(Precision):预测为“泥地”的样本中,真正是泥地的比例。精确率高说明模型报出的泥地可信度高。
- 召回率(Recall):所有真实泥地样本中,模型成功检出的比例。召回率高说明漏检少。
- F1分数:精确率和召回率的调和平均,两者兼顾。
- 混淆矩阵:最直观的工具,能看出模型是偏向把混凝土误判为泥地,还是反过来。
- ROC曲线与AUC:阈值变化时模型性能的综合表现。
对这类型任务,我们需要特别关注混淆矩阵。因为两种路面误判的后果不对等——把泥地当作混凝土路面,可能导致农机驶入松软地面陷入困境;把混凝土当作泥地,可能只是路径选择绕远。论文中如果能展示一张混淆矩阵热力图,并结合实际场景解释两类误差的限制,会非常加分。
5.3 可视化分析技巧
深度学习模型是个黑盒,可视化能帮你和答辩老师看清楚它到底学到了什么。推荐做两个可视化方向:
第一,特征图可视化。输入一张测试图片,把网络中间层的特征图提出来,看模型在哪些区域响应最强。工具可以用PyTorch Hook或者EigenCAM、Grad-CAM。路面识别任务上,Grad-CAM应该展示出模型重点关注路面纹理丰富的区域(车辙、碎石、裂缝)而不是背景天空。如果CAM热力图乱飘,说明模型学到了不该学的背景信息,需要检查数据是否有偏差。
第二,错误样本可视化。把预测错误的图片单独挑出来,排列成份整理成表格。这种分析非常体现水平,因为会揭示出模型失效的具体原因。举个例子,我们的实验中发现模型会把“刚浇筑完的深色混凝土路面”误判为泥地,原因是颜色接近湿润泥地的深褐色。基于这个发现,可以在数据增强中增加色彩归一化操作,或者在论文里分析这类错误的结构性原因,然后提出针对性解决方案。
5.4 论文中的结果呈现规范
实验结果的表格要有统一的模板,列清每一个实验的配置和对应指标。推荐一个版式:
| 实验编号 | 模型 | 改进方案 | 准确率 | 精确率 | 召回率 | F1 | 备注 |
|---|---|---|---|---|---|---|---|
| E1 | ResNet50 | 基线 | 89.2% | 88.1% | 90.4% | 0.892 | — |
| E2 | ResNet50 | +双池化 | 90.5% | 89.8% | 91.2% | 0.905 | |
| E3 | ResNet50 | +双池化+注意力 | 92.1% | 91.5% | 92.8% | 0.921 | |
| E4 | MobileNetV3 | 基线 | 86.4% | 85.2% | 87.1% | 0.861 |
表格下方补一段精炼的文字分析,说明每步提升的来源以及是否具有统计显著性。如果两个模型之间差距很小(比如0.3个百分点),要谨慎下“某某方法更优”的结论,可以说“两者性能接近,但轻量模型推理速度更快,更适合实际部署”。
6. 部署与演示系统
6.1 为什么建议加一个界面
很多毕设止步于“训练完模型,跑出一组准确率”,然后论文草草收尾。实话说,这样不是不行,但答辩观感确实差一些。如果加一个简单的Web演示界面,打开浏览器上传一张图片,模型立刻返回分类结果和置信度,配上热力图展示,这种直观的交互效果在整个答辩现场非常加分。
而且实现难度并不高,用Gradio库写一个Web界面,最快几十行代码就能搞定。
6.2 Gradio快速搭建实操
Gradio是目前做模型演示最高效的工具之一,它不需要写前端,你只要定义好输入输出函数,它自动生成页面。
import gradio as gr import torch from torchvision import transforms from PIL import Image import model_utils # 你自定义的模型结构模块 model = model_utils.build_model(num_classes=2) model.load_state_dict(torch.load("best_model.pth", map_location="cpu")) model.eval() transform = transforms.Compose([ transforms.Resize((224, 224)), transforms.ToTensor(), transforms.Normalize(mean=[0.485, 0.456, 0.406], std=[0.229, 0.224, 0.225]), ]) def predict(image): img = Image.fromarray(image).convert("RGB") img = transform(img).unsqueeze(0) with torch.no_grad(): outputs = model(img) probs = torch.softmax(outputs, dim=1).squeeze().tolist() labels = ["混凝土马路", "泥地马路"] result = {labels[i]: round(probs[i], 4) for i in range(len(labels))} return result gr.Interface(fn=predict, inputs="image", outputs="label").launch()这在本地运行后,浏览器直接打开一个交互页面,拖入图片就能测试。要注意的是:输入的预处理逻辑必须与训练时完全一致,尤其是Normalize的均值和标准差。有人图省事把预处理写错,在网页里测试时发现准确率比训练时低一大截,最后排查才知道是Resize方法不一致或Normalize参数有误。
6.3 模型保存与加载细节
训练过程中应该保留两类模型:最佳验证模型和最后一轮模型。用torch.save保存时,建议连同模型的超参数信息一起存成字典:
torch.save({ 'epoch': best_epoch, 'model_state_dict': model.state_dict(), 'optimizer_state_dict': optimizer.state_dict(), 'best_acc': best_acc, }, 'best_model.pth')加载模型时只加载权重,注意model.load_state_dict里要设置strict=True(默认),这样如果你的模型结构改过,加载时会立刻报错,能及早发现问题。另外,如果你在训练时用了DataParallel多卡训练,权重文件的键名会带module.前缀,加载到单卡模型时需要手动去掉前缀。
7. 常见问题排查与避坑指南
7.1 训练阶段高频问题速查
| 问题现象 | 可能原因 | 排查方法 |
|---|---|---|
| 训练loss不下降 | 学习率过大或过小 | 尝试学习率0.0001到0.01的网格搜索 |
| 准确率停留在50%左右 | 数据标签错乱 | 检查文件夹目录与标签对应关系 |
| 验证集在训练中剧烈震荡 | 验证集过小或分布偏 | 增大验证集,按来源分层划分 |
| 训练准确率接近100%但测试偏低 | 过拟合 | 加强数据增强、增加dropout |
| 显存不足 | Batch Size太大 | 降低Batch Size或使用梯度累积 |
| 加载预训练权重报键不匹配 | 模型结构与预训练不兼容 | 检查类别数是否改为2 |
这里特别想说一下标签错乱问题。目录结构明明写着concrete和mud,但在写数据加载代码时拼错单词、或者索引顺序反了,都会导致模型完全学不到东西。一个快速诊断方法是:在训练前,手动打印几个batch的图片和对应标签,人眼确认对应关系无误再开训。这一步花两分钟,能节省后面几小时的浪费。
7.2 分割任务中的常见坑
分割任务比分类更敏感,两个典型问题容易踩:
标签与图片尺寸不一致。数据增强时,如果翻转、缩放操作分别应用在图片和掩码上,最后掩码和图片就会错位。正确做法是:在自定义数据集类中,把图片和掩码放进同一个transform流程,使用相同的随机种子保证同步变换。
分割边界标签不准确。手工标注的掩码在物体边缘往往有一到两个像素的误差,这本身没问题。但如果在数据增强时用了过强的变形(比如随机旋转90度),掩码边缘的锯齿会变大。建议分割任务只用轻度旋转和翻转,不要用过度变形。
7.3 答辩可能被追问的问题清单
答辩前最好自己先演练以下问题,避免被问到答不上来:
- 为什么选这两个类别?实际应用场景是什么?
- 你的数据集是哪里来的,有多少张,如何划分训练、验证、测试集?
- 为什么选择这个backbone?对比过哪些模型?
- 双池化和注意力模块为什么能提升精度?原理是什么?
- 对模型进行过哪些消融实验?每步提升了多少?
- 模型在什么场景下容易误判?你如何分析原因?
- 数据增强解决了什么问题?有没有做过增强前后的对比实验?
- 你的模型训练了多久、用了什么GPU、训练效率如何?
- 如果部署到嵌入式设备,你会如何压缩模型?
这些问题都不算刁钻,但因为都是围绕项目细节,没有亲自跑过实验、每一行日志都翻过的人,现场很容易紧张。所以我的建议一直是:自己亲手把每一步跑通,不仅是训练,还要把错误样本翻出来看,把数据分布统计清楚。答辩的时候,你做过的事情都能讲出细节,这是最硬核的底气。
7.4 选题还能怎么延展
如果做完基础版本还有时间,可以考虑加一些拓展内容:把识别结果接入一个虚拟导航界面,模拟路面类型变化对规划路径的影响;或者将模型量化到TensorRT或ONNX Runtime,测试在低算力设备上的推理速度;也可以做一个对比实验,比较CNN和Transformer对路面纹理的建模差异。任何一个延展都比单纯堆砌多个模型更有价值,因为它展示的是思考深度,而不仅仅是调包能力。
最后再分享一个我在实际操作中总结出来的经验:这个选题的全部环节,从数据采集到训练完成,尽量给自己留出四周以上的完整时间。前面数据采集清洗的进度不稳,训练调参又可能反复重来。有人压缩到两周,结果数据只凑了几百张,模型效果撑不起实验分析,最后只能靠强行堆叠模块弥补,反而更耽误时间。把时间规划好,数据搞得扎实一点,这个题目能在中等偏低的投入下做出很体面的结果。