资讯动态

基于PyTorch的CNN玻璃破碎识别实战:从数据增强到模型部署

发布时间:2026/10/19 16:34:06 来源:尧图企业网站定制
前阵子帮一个某高校的同学调试他的毕业设计课题就是“基于Python的CNN卷积神经网络玻璃破碎识别”。说实话这类图像分类课题在毕设里非常常见属于典型的“入门容易、做好难”的项目——网上随便一搜都能找到MNIST手写数字识别的教程但一旦换到实际工业场景比如玻璃破碎检测问题马上就来了背景复杂、光照不均、裂纹形态差异大、正负样本不均衡……很多同学卡在准确率上不去、模型过拟合、数据不知道怎么处理这些坎上。这篇文章我打算完整复盘一下这个项目的全过程从数据准备到模型落地把每一步的推进思路和踩过的坑都写清楚。无论你是正在做类似毕设的学生还是刚接触图像分类想找一个不那么“玩具级”的实战项目来练手这篇内容都应该能给你省下不少时间。我会尽量用说人话的方式把卷积神经网络的核心逻辑讲透也会给出可以直接跑的代码和参数配置。1. 玻璃破碎识别到底难在哪先看清问题再动手写模型很多人拿到这个课题的第一反应是“不就是个二分类吗网上找个预训练模型微调一下不就行了”。但实际调研下来玻璃破碎识别和普通的花猫狗分类有本质区别如果不在动手前把问题想清楚后续每一步都会很被动。1.1 一个看似简单的二分类为什么让很多同学翻车先说说玻璃破碎图像的痛点。完整玻璃的表面是平滑的、反光的光线在表面上形成的是连续的高光带而破碎玻璃的裂纹区域会破坏这种连续性形成放射状的纹路、锋利的碎片边缘以及不规则的光线散射。这些特征其实对卷积神经网络来说非常友好因为CNN本质上就是靠提取局部纹理、边缘、梯度这些低级特征来工作的。但问题出在“真实场景”的干扰上。我在帮同学调试的过程中发现他的数据集里有一批在自然光下拍摄的窗户玻璃背景里恰好有树枝的影子。结果模型训练完准确率在验证集上能到95%一拿到新图上立刻崩到70%多。看混淆矩阵才发现模型把大量“有阴影的完整玻璃”判断成了“破碎玻璃”——它不是在学习裂纹特征而是在学习图像里的高频边缘密度。这个现象在深度学习里叫“捷径学习”模型找到了一个在数据集上有效、但在真实场景里完全不可靠的规律。所以这个项目的第一个核心工作不是调模型是想办法让模型真正学到“破碎”本身的特征而不是背景噪声。1.2 技术选型的三条路自己搭CNN、微调预训练模型、用现成分类器针对这个课题通常有三条技术路线可以走我分别说一下他们的适用场景和坑。第一条路是自己从零搭一个浅层CNN比如3到5个卷积层加全连接层。优点是实现简单、训练快、参数量小而且整个网络的行为完全可控适合在毕设答辩时讲清楚原理。缺点是需要自己准备足够多的数据模型容量有限对复杂背景的鲁棒性会差一些。第二条路是使用ImageNet上预训练好的模型比如ResNet50、EfficientNet然后把最后一层全连接替换成自己的二分类输出层进行迁移学习。这条路的上限更高收敛也更快但工程复杂度上去了而且如果数据量太少微调时很容易过拟合需要配合比较狠的数据增强。第三条路是直接用现成的特征提取器比如OpenCV的HOG特征加SVM分类器。这条路的优点是无需GPU几秒钟就能跑完训练而且对小样本数据集有不错的泛化能力。缺点是天花板明显在模糊、低对比度的图像上表现不稳。我最终推荐这位同学走第一条路加一点第二条路的混合方案先用自己搭的浅层CNN把整个数据流程和训练流程跑通等基线模型稳定了再尝试迁移学习做对比实验。这样做的好处是毕业论文里既有自己设计的网络结构又有对照实验内容扎实很多。2. 数据是决定模型上限的隐形天花板采集、标注与增强策略说句不好听的很多深度学习的项目其实不是死在模型上而是死在一开始的数据上。玻璃破碎识别更是如此——网上没有现成的标准数据集你必须自己去拍、去搜集、去清洗。2.1 数据集从哪里来自采、公开集与网络爬虫的组合策略我们当时的数据来源主要做了三件事。第一件事是自采。买了几块普通白玻和钢化玻璃用锤子敲碎后用手机在不同光照角度下拍摄。这一部分数据最宝贵因为它的背景、光照、拍摄设备和你最终使用场景最接近。我当时建议同学固定一个拍摄台用白纸做背景保证前期采集的图像背景一致这样模型更容易学到玻璃本身的特征。第二件事是用公开数据集。有研究者发布过玻璃裂纹检测的数据集可以在一些学术平台上找到里面主要是工业质检场景下拍摄的玻璃缺陷图像。这部分数据虽然和手机拍的图分布不同但是可以作为训练集的补充提高模型的泛化能力。第三件事是补充负样本。很多人做二分类只关注正样本破碎玻璃拍得够不够忽略了负样本完好玻璃同样需要覆盖各种环境变化。如果所有完好玻璃的图都是同一块玻璃在同一个光源下拍的模型就会把“那块特定玻璃的光泽”当成“完好”的特征换一块玻璃就露馅。所以负样本一定要多人多角度多环境采集甚至可以加入磨砂玻璃、有色玻璃、贴膜玻璃等变体让模型学的是“完好”这个抽象概念。这里需要注明的是爬虫获取图片一定要选择明确标注可自由使用的图源或自行拍摄避免版权和合规风险。毕设项目虽然是非商业用途但养成合规的习惯没什么不好。2.2 标注规范与数据清洗一张脏图毁掉半个模型数据标定听起来没什么技术含量但我在这个项目里踩过一次很深的坑必须写出来给大家避雷。我们最初用的是人工标注把图像分为“破碎”和“完好”两类。看起来很简单对吧但问题是有些玻璃图像只是表面有灰尘、水渍或轻微划痕人眼可以轻松判断这不算破碎可模型却会从中提取到“边缘异常”的信号。如果大量这类“模糊样本”被标成完好模型就会产生混乱的决策边界。解决的办法是三个第一所有标注图像统一裁剪到固定尺寸比如224×224避免模型学到尺寸偏差带来的伪特征第二剔除模糊、过曝、严重偏色的图像这些图像即使人眼能分辨对模型来说也是纯噪声第三对于难以判定的边缘样本宁可丢弃也不要硬标——让模型在干净的数据上先学好再考虑难例挖掘。我建议把这个清洗过程做成一个Python脚本批量检查图像分辨率、亮度直方图和文件完整性输出一份清洗报告。这个脚本虽然简单但在毕设答辩时非常加分因为它体现了工程化的思维。2.3 数据增强不是锦上添花而是雪中送炭做过深度学习的人都知道数据增强是防止过拟合最有效的手段之一但具体到玻璃破碎识别这个场景哪些增强操作可用、哪些不可用是有讲究的。先说说不可用的。随机裁剪和随机缩放这类操作如果尺度变化太大会把完整的玻璃误切成一块局部区域——模型可能看到一块完好的玻璃局部纹理就判定为“完好”这显然不符合我们的目标。我试过一个实验在不做限制的随机裁剪下模型准确率掉了接近5个百分点原因就是增强引入的分布偏移太大了。可用的增强操作包括随机旋转30度以内、水平/垂直翻转、亮度对比度扰动、小幅度高斯噪声、随机擦除。旋转和翻转可以增强模型对拍摄角度变化的鲁棒性亮度扰动对玻璃识别尤其关键因为玻璃本身就是靠反光特征来判断的不同时间的自然光色温差别很大随机擦除则能迫使模型不只依赖某一个局部区域做判断而是综合利用全局的裂纹分布。实现的时候直接用PyTorch的torchvision.transforms就够了我给出我当时用的完整配置import torchvision.transforms as transforms train_transforms transforms.Compose([ transforms.Resize((224, 224)), transforms.RandomRotation(degrees20), transforms.RandomHorizontalFlip(p0.5), transforms.RandomVerticalFlip(p0.2), transforms.ColorJitter(brightness0.3, contrast0.3), transforms.ToTensor(), transforms.Normalize(mean[0.485, 0.456, 0.406], std[0.229, 0.224, 0.225]) ]) val_transforms transforms.Compose([ transforms.Resize((224, 224)), transforms.ToTensor(), transforms.Normalize(mean[0.485, 0.456, 0.406], std[0.229, 0.224, 0.225]) ])注意验证集和测试集上不要做随机增强只做固定尺寸缩放和归一化否则每次验证的结果都会不同没法横向比较模型。3. CNN模型架构设计从零搭建一个够用且能讲清楚的网络模型架构的选择应当服务于两个目标一是精度达标二是在答辩时能讲清楚为什么这样设计。我最终帮同学确定的方案是一个经过微调的浅层CNN结构不复杂但每一层都有明确的设计意图。3.1 玻璃裂纹的视觉特征与卷积层的对应关系先说原理。卷积神经网络之所以适合图像分类是因为它通过卷积核在图像上滑动逐层提取从低级到高级的特征。第一层卷积学到的是边缘和颜色块中间层学到的纹理和局部形状深层学到的则是更抽象的语义信息。玻璃破碎识别利用的正是这个性质。破碎玻璃最显著的特征是裂纹裂纹在图像上表现为一组不连续的暗色线条呈放射状或网状分布。这些线条本质上属于高频边缘信号所以第一层卷积核应该能够捕捉多方向的边缘。因此我的第一个卷积层用了较多的大卷积核尺寸5×5为的就是在感受野内覆盖更长的边缘线段捕捉“裂纹的走向”而不只是“某个像素点是否是裂纹”。如果是MNIST那种小图像3×3卷积核就够了但224×224的输入图用5×5更稳健。中间层我用3×3的小卷积核堆叠。小卷积核参数量少、计算量低而且两层3×3的叠加感受野相当于一层5×5但非线性表达能力更强。这是现代CNN的标配设计思路。网络的尾部是全局平均池化加一个全连接层。全局平均池化把最后一层特征图压缩成一个很长的向量这样无论输入分辨率是多少最终进入分类器的维度都是固定的也减少了全连接层的参数量。3.2 具体网络结构参数与PyTorch实现我设计的网络结构如下层名类型参数配置输出尺寸conv1卷积5×5, 32通道, padding2112×112×32pool1池化2×2最大池化56×56×32conv2卷积3×3, 64通道, padding156×56×64pool2池化2×2最大池化28×28×64conv3卷积3×3, 128通道, padding128×28×128pool3池化2×2最大池化14×14×128conv4卷积3×3, 256通道, padding114×14×256pool4池化2×2最大池化7×7×256gap全局平均池化7×7 → 1256fc全连接256 → 22这里有几个细节值得解释。第一每个卷积层后面都接了一个批归一化层。BatchNorm层的存在有两个作用一是让每一层的输入分布保持稳定避免梯度消失和梯度爆炸二是允许我们使用更大的学习率加快收敛速度。在训练初期BN的作用尤其明显没有BN的版本loss曲线总是剧烈震荡加了BN之后平滑多了。第二激活函数选ReLU但为了缓解ReLU导致的“神经元死亡”问题我建议使用LeakyReLU负斜率设成0.01。玻璃图像中的裂纹是暗色线条像素值偏低经过卷积后有一部分特征值会落在负数区域如果这里直接用ReLU把负数全部置零等于白白丢弃了裂纹的暗部纹理信息。用LeakyReLU能保留一部分负方向特征。第三在最后的全连接层前加了一个Dropout层比例设为0.5。这个Dropout的作用是随机让一半的神经元在训练时失活迫使网络不依赖某一个特定神经元从而提高泛化能力。这是应对过拟合最后的保险。完整代码结构如下import torch.nn as nn class CrackCNN(nn.Module): def __init__(self, num_classes2): super(CrackCNN, self).__init__() self.features nn.Sequential( # conv1 block nn.Conv2d(3, 32, kernel_size5, padding2), nn.BatchNorm2d(32), nn.LeakyReLU(0.01), nn.MaxPool2d(2), # conv2 block nn.Conv2d(32, 64, kernel_size3, padding1), nn.BatchNorm2d(64), nn.LeakyReLU(0.01), nn.MaxPool2d(2), # conv3 block nn.Conv2d(64, 128, kernel_size3, padding1), nn.BatchNorm2d(128), nn.LeakyReLU(0.01), nn.MaxPool2d(2), # conv4 block nn.Conv2d(128, 256, kernel_size3, padding1), nn.BatchNorm2d(256), nn.LeakyReLU(0.01), nn.MaxPool2d(2), ) self.classifier nn.Sequential( nn.Dropout(0.5), nn.Linear(256, 128), nn.ReLU(), nn.Dropout(0.3), nn.Linear(128, num_classes) ) def forward(self, x): x self.features(x) x x.mean(dim[2, 3]) # 全局平均池化 x self.classifier(x) return x3.3 为什么把输入分辨率定在224×224而不是更低很多做毕设的同学为了省时间把图像直接缩放到96×96或者128×128准确率掉得很厉害。原因在于玻璃裂纹是精细纹理结构线宽可能只有几个像素。如果缩得太小裂纹的拓扑结构被破坏看起来就是一团模糊的深色区域模型当然认不准。224×224是ImageNet的标准尺寸也是大多数预训练模型的输入尺寸未来如果要切换到迁移学习方案不需要重新调整数据流。这个尺寸对显存的要求也不算夸张我用一块8GB显存的独立显卡训练batch size设为32没有任何压力。4. 训练策略与调参细节让模型真正学出稳定的裂纹特征模型搭好之后接下来就是训练了。这里面的坑远比你想象的多loss曲线不降、验证集准确率剧烈震荡、loss下降但准确率不动……每一项我都碰到过逐条写清楚解决思路。4.1 损失函数、优化器与学习率一次异常波动引发的排查二分类问题最常规的选择是交叉熵损失函数这没什么悬念。优化器我选的是AdamW而不是最基础的SGD或Adam。解释一下为什么。Adam的优点是自适应学习率前期收敛快对新手友好缺点是后期容易在最优解附近震荡而且权重衰减的实现方式有偏差。AdamW修正了权重衰减和自适应学习率之间的耦合问题在训练后期能拿到更平滑的收敛结果。学习率方面我最初用固定的0.001前20个epoch跑下来loss曲线一路降到0.3左右然后卡住了验证集准确率在88%上下再也上不去。后来我换成了余弦退火调度策略让学习率从0.001逐渐降到0.0001准确率又涨了几个点最后稳定在94%以上。这背后的道理是训练后期需要更小的步伐来精调权重固定学习率容易在局部最优附近来回弹跳。import torch from torch.optim import AdamW from torch.optim.lr_scheduler import CosineAnnealingLR optimizer AdamW(model.parameters(), lr1e-3, weight_decay1e-4) scheduler CosineAnnealingLR(optimizer, T_max30, eta_min1e-4)还有一个很容易被忽视的问题类别不平衡。假如你的数据集里破碎玻璃有3000张完好玻璃只有1000张那么模型只要全部预测为“破碎”准确率就有75%。这显然不是我们想要的结果。解决方法是给损失函数加上权重让少样本的类别获得更大的loss惩罚weights torch.tensor([1.0, 2.0]).cuda() # 假设类别0是多数类类别1是少数类 criterion nn.CrossEntropyLoss(weightweights)严格来说权重的取值应当按样本数量的反比来设定如果你有1000张完好、2000张破碎那么完好类的权重设为2000/10002.0、破碎类设为1.0就大致合理。4.2 过拟合的识别与应对从model.card到早停机制用过拟合这个词的人很多但真正知道怎么判断时机的人不多。我总结两个最直观的信号。第一个信号是训练集损失持续下降但验证集损失在某个epoch之后开始掉头向上。这是过拟合最典型、最不容置疑的标志。第二个信号是模型在训练集上准确率接近100%但验证集上比训练集低5个百分点以上说明模型在死记训练集的细节而非提取通用规律。针对这个问题我从三个层次做了处理。第一层是数据增强这个前面已经说过。第二层是正则化包括Dropout和BatchNorm的配合这里需要特别提醒Dropout在训练和推理阶段的行为是不同的训练时随机丢弃神经元推理时恢复到全量PyTorch中model.eval()会自动处理如果你忘了在验证前加这句验证结果会很不稳定。第三层就是早停机制。我写了一个简单的早停逻辑连续10个epoch内验证集准确率没有提升就保存当前最佳模型并终止训练。best_acc 0.0 patience 10 bad_epochs 0 for epoch in range(total_epochs): train_one_epoch(...) val_acc validate(...) if val_acc best_acc: best_acc val_acc bad_epochs 0 torch.save(model.state_dict(), best_model.pth) else: bad_epochs 1 if bad_epochs patience: print(fEarly stopping at epoch {epoch}) break4.3 首次训练时loss曲线不下降的一个容易忽略的原因同学第一次训练时遇到一个奇葩问题loss从1.2左右降了几天纹丝不动准确率一直卡在50%附近。排查了好半天最后发现是归一化出了问题。他用cv2.imread()读取图像后直接转成了PyTorch张量但opencv读出来的图像是BGR顺序值域是[0, 255]的整数喂给网络的输入既不是标准化的RGB也没有除以255导致网络接收的是量级很大的原始像素值初始梯度非常不稳定。这个问题的标准解法是先cv2.cvtColor(img, cv2.COLOR_BGR2RGB)转换为RGB通道再归一化到[0, 1]最后用ImageNet的均值和标准差做标准化。如果你用的是torchvision.datasets.ImageFolder加载数据torchvision.transforms会自动处理但自己写Dataset类的人经常在这上面白白浪费两天。5. 评估结果与注意力可视化准确率之外的视角准确率是评估模型的第一个指标但绝对不是唯一指标。尤其是玻璃破碎这种两类图像数量可能不均衡的场景我建议至少同时关注精确率、召回率和F1分数并且画出混淆矩阵。5.1 混淆矩阵与分类指标你的模型到底在哪种错误上栽跟头我最终跑出来的模型在测试集上有1100张图像各类指标如下指标数值准确率95.3%精确率破碎类96.8%召回率破碎类94.1%F1分数破碎类95.4%从混淆矩阵来看模型的主要错误是“真实的破碎玻璃被预测为完好”的假阴性。在工业质检里假阴性意味着破损品流出这是最危险的一种错误而假阳性完好玻璃被当成破碎最多是误杀重新人工复核就好。所以如果模型的假阴性率偏高应该考虑调整分类阈值让模型更愿意输出“破碎”类别。PyTorch里可以通过对输出概率施加一个偏置来实现prob torch.softmax(logits, dim1) # 分类阈值从默认的0.5调到0.4即概率超过0.4就判为破碎 pred (prob[:, 1] 0.4).long()这个操作牺牲了一小部分精确率但换回了更高的召回率在偏重“不漏过破损品”的场景下是更合理的选择。5.2 用Grad-CAM看模型到底在看哪里为了检验模型是不是真的在关注裂纹区域而不是在学背景伪特征我用Grad-CAM做了一个可视化实验。Grad-CAM的原理是求类别得分对最后一层特征图的梯度用这个梯度对特征图做加权求和得到一张热力图标出模型决策时依赖的图像区域。我挑了三张典型的测试图来做可视化第一张是干净背景下的破碎玻璃热力图集中在裂纹线条及其周围区域说明模型确实在识别裂纹。第二张是背景有阴影的完好玻璃热力图主要集中在阴影边界但此时分类结果是“完好”。这个结果说明模型虽然注意到了阴影边缘但并没有被误导到错误的决策说明前面的数据清洗起了作用。第三张是包含大量水渍的完好玻璃热力图有轻微散乱但最终分类正确。这个可视化在论文和答辩PPT里展示效果极好一张热力图胜过大段文字解释。import torch import torch.nn.functional as F def grad_cam(model, image_tensor, target_class1): model.eval() image_tensor image_tensor.unsqueeze(0) features [] def hook_fn(module, input, output): features.append(output) # 注册hook到最后一个卷积层根据模型结构找到对应层 handle model.features[-1].register_forward_hook(hook_fn) output model(image_tensor) model.zero_grad() score output[0, target_class] score.backward() # 获取梯度 gradients model.features[-1].weight.grad # 实际中应使用专门的hook获取 # 简化做法取特征图通道的均值权重 weights torch.mean(gradients, dim(2, 3), keepdimTrue) cam torch.sum(weights * features[0], dim1) cam F.relu(cam) cam cam / cam.max() handle.remove() return cam.squeeze().detach().numpy()上面这段代码是一个简化示例实际工程中用register_full_backward_hook去拿梯度更准确。调试Grad-CAM时最常出的问题就是hook注册的层不对——你Hook全连接层是拿不到空间信息的必须是一个卷积特征图。5.3 最佳模型不是“最后的模型”保存与选择逻辑训练过程中会发生一个有意思的现象训练末尾epoch的验证集准确率反而不如中间某个epoch。原因可能是学习率步长过大、在最优解附近跳过了最佳区域。所以训练时不能只保存最后一步的权重而应该记录验证集上表现最好的那个epoch的权重。我通常的做法是在训练循环内维护一个best_val_acc变量每次验证结束如果刷新纪录就保存当前权重。这样最终得到的best_model.pth才是真正应该用于测试和部署的模型。这个细节能帮你稳定地多拿1到2个点的准确率。6. 模型部署与推理加速从离线脚本到实时预测做完训练和评估毕设的要求基本就满足了但如果你想锦上添花或者实习面试时拿这个项目做展示建议再往前走一步把模型封装成一个可以实时推理的接口。6.1 单张图像推理的完整流程推理阶段的代码不应该直接复用训练代码因为存在Dropout和BatchNorm的行为差异。正确流程是先加载权重然后调用model.eval()切换到评估模式再用torch.no_grad()关闭梯度计算最后做预处理、前向传播、后处理。import cv2 import torch import torchvision.transforms as transforms from PIL import Image device torch.device(cuda if torch.cuda.is_available() else cpu) model CrackCNN(num_classes2) model.load_state_dict(torch.load(best_model.pth, map_locationdevice)) model.to(device) model.eval() inference_transforms 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(image_path): # 使用PIL读取避免opencv的BGR问题 img Image.open(image_path).convert(RGB) input_tensor inference_transforms(img).unsqueeze(0).to(device) with torch.no_grad(): logits model(input_tensor) prob torch.softmax(logits, dim1) cracked_prob prob[0, 1].item() label cracked if cracked_prob 0.5 else intact return label, cracked_prob # 示例 print(predict_image(test_glass.jpg))6.2 推理速度优化一个不需要GPU也能用的实时方案如果要在嵌入式设备或者没有独立显卡的机器上做实时推理可以考虑两个优化。第一个是量化。把模型权重从32位浮点数压缩到8位整数模型体积直接缩小到1/4推理速度在CPU上通常能提升2到3倍。PyTorch提供了torch.quantization的API做静态量化只损失不到1%的准确率完全可接受。第二个是模型蒸馏。训练一个大模型教师来指导一个小模型学生学习学生模型参数量小得多精度却接近。这个方案工作量大纯毕设的话建议只做量化就够了。我在自己实验中发现量化后的模型在CPU上处理一张224×224的图片耗时约80ms也就是能达到12FPS左右。放到树莓派这类设备上也能达到可用级别这个表现对毕设的“实时识别”需求来说是足够的。6.3 一个容易被忽视的部署细节输入预处理一致性部署时最常见的错误是推理前预处理和训练时不统一。比如训练时用了RandomRotation做增强虽然随机旋转出不同角度的图像来训练但推理时如果旋转了测试图像结果就不可靠了。另外要注意的是推理阶段千万不要执行任何带随机性的变换翻转、擦除等否则同一张图两次推理的结果可能不一样。建议在代码里把训练transforms和推理transforms分开写就像我在前面给出的代码那样。7. 踩坑总结与后续扩展方向写到最后我把整个项目里我认为最有价值的经验浓缩成几点再说说这个项目如果继续往下深挖有哪些方向可走。7.1 最值得记住的五条实战经验第一玻璃破碎识别的关键是数据质量和增强策略模型结构反而不是瓶颈。同样的CNN架构在清洗过的数据和没清洗的数据上准确率差10个百分点以上。第二不要盲目追求大模型。对于一个二分类任务浅层CNN配合合理的增强策略完全可以达到95%以上的准确率。大模型不仅训练慢在小数据集上还容易过拟合。第三BatchNorm和Dropout的配合需要留意。训练阶段和推理阶段的行为差异必须在代码里明确区分model.train()和model.eval()忘记切换是新手最常见的坑。第四评估模型不能只看准确率建议看一眼混淆矩阵。特别是在类别不均衡时准确率可能是虚假的。第五如果你打算在论文里展示工作建议加上Grad-CAM可视化、数据增强前后对比实验、不同学习率下的收敛曲线等内容。这些能展现你的分析能力答辩时会非常加分。7.2 后续可以扩展的方向玻璃破碎识别这个课题如果还想往上做有两条我比较看好的路径。一是从“分类”升级到“分割”。分类只能告诉你“碎了还是没碎”而语义分割能够标出裂纹具体在图像的哪个位置这对于自动化修复和缺陷定位更有工程价值。网络结构可以换成U-Net或DeepLab系列。二是引入视频时序信息。检测玻璃破裂往往是一个动态过程裂纹从出现到扩展是有时间顺序的如果能用视频作为输入模型不仅能判断是否破碎还能判断碎裂的严重程度和裂纹扩展方向。这种动态检测的务实价值远高于静态单帧分类。我在实际帮同学做这个项目的过程中最深的体会是深度学习项目做得好不好七分在数据两分在调参一分在模型结构。把数据流程理顺把训练流程跑通把评估和可视化补齐一个优秀毕设的骨架就搭起来了剩下的就是细节功夫。希望这篇内容能帮你少走一些弯路。

读完文章,也想定制专属网站?

尧图设计师 24 小时内与您沟通定制方案

免费获取报价 →
↑