ARTICLE DETAIL

资讯详情

深耕郑州网站建设与运营推广的一线实战洞察。

从零实现垃圾分类系统:PyTorch迁移学习与数据增强实战

从零实现垃圾分类系统:PyTorch迁移学习与数据增强实战 简介面向机器学习课程设计场景这份Python垃圾分类系统源码是一套可运行的图像分类项目参考旨在帮助学习者掌握监督学习与计算机视觉核心环节。项目基于scikit-learn和TensorFlow 2.3覆盖数据清洗、图像预处理、特征提取、模型训练与评估的完整流程适合本科或高职学生用于完成课程作业、理解分类算法原理。资源包共32个文件以.py源码为主包含模型训练、测试与窗口演示脚本同时配有jpg/jpeg/png图像样本、xml配置文件以及记录分类结果的xls矩阵表格压缩包大小约2.26MB。已有772人学习过该资源。借助源码可直接复现MobileNet模型训练查看epoch曲线与混淆矩阵梳理从数据集标注到结果输出的实现思路对课程设计和计算机视觉入门均有较强参考价值。1. 机器学习课设选垃圾分类系统给 Python 源码一个能讲清楚的故事每到学期末机器学习的课程设计选题单里总有一席之地属于垃圾分类系统题目自带社会价值技术栈正好落在图像分类的标准范式上Python 生态从数据处理到模型推理都有现成组件。一个完整的垃圾分类课设源码包本质上就是一套图像分类工程用卷积神经网络或 ImageNet 预训练模型对垃圾图片做识别再套一个 PyQt 或 Flask 界面交付演示。这套东西适合两类人想低风险拿下课程设计学分、答辩时经得起追问的同学以及想用一个完整项目把机器学习的应用流程从头到尾走一遍的初学者。下面按我实际做过这类课设的顺序展开先选型再把数据处理成模型能吃的样子然后训练和评估最后把常见坑和答辩加分细节一次说清。2. 垃圾分类系统怎么选型四分类还是多分类用哪个预训练模型更稳先定类别再定模型最后定环境。顺序不能反因为类别数量直接决定模型分类头的输出维度模型又决定后面训练要多少算力。2.1 数据集与类别标签先定四分类还是多分类再整理图片目录垃圾分类课设的第一步不是写代码是定标签体系。常见做法有两种四分类和细分类。四分类对应生活垃圾的四大类——可回收物、厨余垃圾、有害垃圾、其他垃圾这是最稳的课设方案细分类是把可回收物继续拆成报纸、塑料瓶、易拉罐、玻璃这类具体物品公开数据集里比较常见的是四十多个细类的标准垃圾分类数据。我一般建议课设选四分类原因有三个。第一四分类每类都能凑到上千张图类别之间视觉差异大塑料瓶和剩饭从颜色到纹理都不一样模型容易学细分类里很多类长得像铝罐和铁罐、玻璃瓶和陶瓷碗混在一起模型训不上去的时候你很难跟老师解释是数据问题还是模型问题。第二四分类能直接对应小区里四种颜色的垃圾桶答辩时讲识别到厨余垃圾自动打开对应桶盖这种衍生场景非常顺。第三很多公开数据集本身已经按四分类整理过拿到就能用省掉大量清洗时间。选类别时还要留意类别分布。公开数据集里可回收物和其他垃圾往往占大头有害垃圾经常只有很少的图如果直接拿原始比例去训练模型很容易学成看到什么都猜其他垃圾。这块坑在第 5 章会专门展开这里先记住一个原则宁可每类裁到数量差不多也不要让某一类多出几倍。2.2 模型选型对比ResNet18、MobileNetV2 在课设场景的权衡分类任务定下来之后模型选择基本围绕两个成熟方案转ResNet18 和 MobileNetV2。这两个都是 ImageNet 预训练模型torchvision 里直接能用各自分类头改一下就可以。我给学生的推荐是有 GPU 用 ResNet18没 GPU 且想跑实时摄像头识别用 MobileNetV2。模型参数量CPU 单张推理耗时课设里的定位ResNet18约 11M约 80-120ms准确率更稳适合有 GPU 的机器MobileNetV2约 3.4M约 30-50ms轻量、部署方便适合 CPU 演示ResNet50约 25.5M200ms 以上对课设来说杀鸡用牛刀训得还慢选 MobileNetV2 还有一个隐藏好处就算没有显卡用 CPU 训练一个小规模四分类数据集也能在可接受的时间内跑完。比如每类八百张图、输入 224×224、batch size 16CPU 上跑一个 epoch 大约十分钟训练 10 个 epoch 也就一个半小时完全在课设时间预算内。ResNet18 在 CPU 上慢三到五倍没 GPU 的话不建议死磕。不管选哪个都要记住用预训练权重这件事。预训练权重是在 ImageNet 上训好的等于模型一出生就认识纹理、边缘、颜色这些底层特征你只负责教它区分垃圾的上层判断。这也是为什么课设里几乎没人从零训练一个 CNN——从零训又慢又容易过拟合纯属给自己挖坑。2.3 Python 环境与依赖torch、torchvision 的安装与版本对齐代码写之前先把环境弄干净。我见过的课设翻车里环境冲突占了三成多数是全局环境里装过各种包torch 和 torchvision 版本对不上模型加载时报一堆错。python -m venv .venv source .venv/bin/activate # Windows 下执行 .venv\Scripts\activate pip install torch torchvision pillow matplotlib scikit-learn flaskvenv 是 Python 自带的虚拟环境作用是让这个项目的依赖跟系统全局隔离省掉后面所有依赖打架的麻烦。pillow 负责读图片torchvision 底层会调它scikit-learn 用来算混淆矩阵和分类报告flask 是后面做 Web 演示界面用的如果打算用 PyQt5 桌面界面就把最后一项改成 pip install pyqt5。torch 和 torchvision 是核心。默认 pip 装的是 CPU 版本对课设足够如果本机有 NVIDIA 显卡且装好了 CUDA去 PyTorch 官网按操作系统选对应安装命令会带 cu118 或 cu121 这种后缀。版本对齐是这类库最容易踩的坑我的经验是尽量让 torch 和 torchvision 来自同一次安装命令不要今天装 torch 明天单独补 torchvision否则版本错位时你会花一晚上在报错信息里找答案。装完先验证一下环境再往下走这一行能帮你区分是代码问题还是环境问题python -c import torch, torchvision; print(torch.__version__, torchvision.__version__, torch.cuda.is_available())如果能看到版本号和 FalseCPU 机器说明环境就绪。下载慢的问题也很实际pip 默认源在境外几个 GB 的 torch 经常卡在下载阶段换个国内镜像源再装速度会明显不一样。3. 把垃圾分类图片处理成模型能用的数据预处理、增强与 DataLoader机器学习里的数据处理是决定模型上限的环节。对垃圾分类课设来说数据处理不是边角料而是最容易让最终分数差出一截的地方。这一章把原始图片变成训练、验证、测试三份可加载的数据。3.1 数据集目录规范化train/val/test 按类别分文件夹torchvision 的 ImageFolder 有一个硬性要求数据必须按根目录/类别名/图片文件的结构存放。所以拿到任何数据集第一步都是把图片归入下面的目录树。mkdir -p data/train/recyclable data/train/kitchen data/train/harmful data/train/other mkdir -p data/val/recyclable data/val/kitchen data/val/harmful data/val/other mkdir -p data/test/recyclable data/test/kitchen data/test/harmful data/test/other四个类别目录先建成英文后面在代码里映射成中文显示名recyclable 对应可回收物kitchen 对应厨余垃圾harmful 对应有害垃圾other 对应其他垃圾。用英文目录名不是繁琐是为了躲开 Windows 下中文路径的编码问题这个坑第 5 章会细说。如果原始数据集是别人整理好的通常已经按类别放好了但 train/val/test 没有划分。我一般用一个短脚本切分而不是手动拖文件夹import random import shutil from pathlib import Path random.seed(42) # 固定随机种子保证划分可复现 root Path(raw_images) # 原始图片目录下面每个子文件夹是一个类别 classes [recyclable, kitchen, harmful, other] split_ratio (0.8, 0.1, 0.1) # 训练 80%验证 10%测试 10% for cls in classes: files list((root / cls).iterdir()) random.shuffle(files) # 先整体打乱 n len(files) n_train int(n * split_ratio[0]) n_val int(n * split_ratio[1]) splits { train: files[:n_train], val: files[n_train:n_train n_val], test: files[n_train n_val:], } for split_name, split_files in splits.items(): dest_dir Path(data) / split_name / cls dest_dir.mkdir(parentsTrue, exist_okTrue) for f in split_files: shutil.copy2(f, dest_dir / f.name)逻辑说明先对整个文件列表做 random.shuffle再按 8:1:1 的比例切片最后把文件复制到对应的 train/val/test 目录。用 copy2 保留原始修改时间纯粹为了保险磁盘空间紧张改成 shutil.move 也行。random.seed(42) 这行是关键它保证同一份数据以后重新划分得到同样的结果模型出问题时可以回溯。要注意的是这个脚本按单个文件打乱如果某类图片是从一段视频里抽帧抽出来的相邻帧会被分到两个集合里造成数据泄漏。这种情况必须改成按来源分组切分细节见 5.2。3.2 数据增强管线RandomResizedCrop、翻转与 Normalize 参数数据进模型之前要做两类处理增强和归一化。增强是为了让模型见过更多变体比如垃圾在照片里可能偏大偏小、横着摆也可能斜着摆归一化是为了匹配预训练模型的输入习惯。from torchvision import transforms # 训练集随机缩放裁剪 水平翻转 归一化 train_transform transforms.Compose([ transforms.RandomResizedCrop(224, scale(0.6, 1.0), ratio(0.75, 1.33)), transforms.RandomHorizontalFlip(p0.5), transforms.ToTensor(), transforms.Normalize(mean[0.485, 0.456, 0.406], std[0.229, 0.224, 0.225]), ]) # 验证集/测试集等比缩放后中心裁剪不做随机增强 val_transform transforms.Compose([ transforms.Resize(256), transforms.CenterCrop(224), transforms.ToTensor(), transforms.Normalize(mean[0.485, 0.456, 0.406], std[0.229, 0.224, 0.225]), ])几个关键参数说清楚。RandomResizedCrop(224) 表示输出固定 224×224这是标准图像分类输入尺寸scale(0.6, 1.0) 表示随机裁剪区域占原图面积的 60% 到 100%ratio 控制裁剪框宽高比。这样模型每次看到的是同一张垃圾图的不同局部和不同尺度相当于免费扩充了训练集。RandomHorizontalFlip(p0.5) 是水平翻转对垃圾分类这种方向不敏感的任务是安全的增强换成文字识别这种方向敏感的任务就不能随便用。Normalize 的 mean 和 std 必须写死成 [0.485, 0.456, 0.406] 和 [0.229, 0.224, 0.225]。这是 PyTorch 各预训练模型在 ImageNet 上训练时用的标准化参数输入图像要以完全相同的方式做标准化预训练权重才能正常工作。改掉这两个值加载的预训练权重基本就废了。还有一个容易被忽略的坑公开数据集里可能混入 RGBA 或灰度图ToTensor() 会把通道数变成 4 或 1模型输入是 3 通道一到训练就报错。稳妥的做法是读取时统一转 RGBfrom PIL import Image # 在把图片放入目录之前先统一转换并清理损坏文件 for f in files: try: img Image.open(f).convert(RGB) # 可选把转换后的图重新保存回原路径 except Exception: print(损坏图片:, f) f.unlink()这种预处理不在 transform 里做而是在数据切分前跑一遍能省掉训练到一半崩溃的麻烦。3.3 ImageFolder 与 DataLoaderbatch、shuffle、workers 设置目录规整好、transform 定义好剩下就是让 DataLoader 把图片一批一批喂给模型。from torchvision import datasets from torch.utils.data import DataLoader import torch batch_size 32 if torch.cuda.is_available() else 8 train_dataset datasets.ImageFolder(rootdata/train, transformtrain_transform) val_dataset datasets.ImageFolder(rootdata/val, transformval_transform) train_loader DataLoader(train_dataset, batch_sizebatch_size, shuffleTrue, num_workers0, pin_memoryTrue) val_loader DataLoader(val_dataset, batch_sizebatch_size, shuffleFalse, num_workers0, pin_memoryTrue) print(类别映射:, train_dataset.class_to_idx) print(训练集样本数:, len(train_dataset)) print(验证集样本数:, len(val_dataset))ImageFolder 会自动把子目录名解析成类别标签class_to_idx 输出类似 {recyclable: 0, kitchen: 1, harmful: 2, other: 3}后面推理时要把索引再映射回名字。batch_size 的选法有 GPU 用 32 或 64让显存吃满一点训练更稳定CPU 用 8 甚至 4不然每个 batch 的等待时间会明显拖慢训练。shuffle 只在训练集开验证集和测试集必须关掉否则评估结果不稳定两次跑准确率不一样。num_workers0 是 Windows 上最稳的设置大于 0 时在 Windows 的 Jupyter 或 PyCharm 里经常报 DataLoader worker 崩溃还没享受多进程加速反而先踩坑课设场景不值得冒险。pin_memoryTrue 只对 GPU 训练加速有用没有 GPU 开着也无害。4. 训练一个能用的垃圾分类模型微调、损失与评估数据处理完进入课设的核心环节训练。一个完整应用流程不是把模型 fit 一下就行而是拆成加载预训练权重、设计优化器、训练、保存、评估五步每一步都有可调参数。4.1 迁移学习加载预训练权重替换分类头的两个关键行四分类任务要求模型输出 4 个类别的概率而预训练模型输出 1000 个 ImageNet 类别。迁移学习只有两件事加载预训练权重把最后一层替换成自己的分类头。import torch import torch.nn as nn import torchvision.models as models num_classes 4 # 方式一MobileNetV2 model models.mobilenet_v2(weightsmodels.MobileNet_V2_Weights.IMAGENET1K_V1) model.classifier[1] nn.Linear(model.classifier[1].in_features, num_classes) # 方式二ResNet18 # model models.resnet18(weightsmodels.ResNet18_Weights.IMAGENET1K_V1) # model.fc nn.Linear(model.fc.in_features, num_classes)注意这里的写法新版 torchvision 推荐用 weights 显式指定预训练权重老教程里的 pretrainedTrue 在新版本里会弹警告以后也会移除。model.classifier[1] 是 MobileNetV2 分类头里的最后一个全连接层in_features 从原层取就算记不住具体维度代码也能自动适配。替换掉分类头后模型其余部分仍带着 ImageNet 上学会的纹理、边缘、形状特征这是答辩时最值得讲的一句。第一次运行会自动下载几百 MB 的预训练权重保持网络畅通等待即可。提示如果下载反复失败可以先改成 weightsNone 或 pretrainedFalse 把整个流程跑通之后再补权重文件重训不要卡在下载这一步耗掉一整天。要不要冻结特征层常见做法有两种一是冻结全部特征层只训练新分类头省显存、速度快适合每类只有一两百张图的极限场景二是全部参数参与微调效果更好但要把学习率调小防止把预训练特征冲坏。课设数据每类几百到上千张我一般选第二种但用分组学习率控制见下一节。4.2 训练主循环与超参优化器、学习率、训练轮数怎么定训练代码不长参数比代码更值得讲。下面是一份能直接跑的简化训练循环from torch import nn, optim from torch.optim import lr_scheduler device torch.device(cuda if torch.cuda.is_available() else cpu) model model.to(device) criterion nn.CrossEntropyLoss() # 特征层用小学习率分类头用大学习率 optimizer optim.AdamW([ {params: model.features.parameters(), lr: 1e-4}, {params: model.classifier.parameters(), lr: 1e-3}, ], weight_decay1e-4) # 每 5 个 epoch 学习率缩小为原来的 1/10 scheduler lr_scheduler.StepLR(optimizer, step_size5, gamma0.1) num_epochs 15 best_val_acc 0.0 for epoch in range(num_epochs): model.train() running_loss 0.0 for inputs, labels in train_loader: inputs, labels inputs.to(device), labels.to(device) optimizer.zero_grad() outputs model(inputs) loss criterion(outputs, labels) loss.backward() optimizer.step() running_loss loss.item() * inputs.size(0) scheduler.step() train_loss running_loss / len(train_dataset) # 每个 epoch 结束在验证集上打分 model.eval() correct 0 total 0 with torch.no_grad(): for inputs, labels in val_loader: inputs, labels inputs.to(device), labels.to(device) outputs model(inputs) _, preds torch.max(outputs, 1) total labels.size(0) correct (preds labels).sum().item() val_acc correct / total print(fEpoch {epoch 1}/{num_epochs} | loss {train_loss:.4f} | val_acc {val_acc:.4f}) if val_acc best_val_acc: best_val_acc val_acc torch.save(model.state_dict(), best_garbage_model.pth)逻辑说明每个 epoch 先用训练集做一次完整前向和反向传播更新参数再用验证集做一次纯前向评估用 with torch.no_grad() 关掉梯度。打印的 val_acc 是模型在没见过的数据上的真实水平训练集 loss 再好看都不代表能交差。超参这几点是按课设场景调过的。AdamW 是 Adam 加了权重衰减比裸 Adam 稳定weight_decay1e-4 是图像分类的常见取值范围。分组学习率的目的features 是预训练好的特征提取器学习率大了会把已有好特征冲掉1e-4 属于微调级别classifier 是随机初始化的新层要从头学1e-3 更新得更快。StepLR(step_size5, gamma0.1) 表示每 5 个 epoch 学习率降到原来十分之一让训练后期收敛更稳。不想要这个调度器删掉相关两行也能跑但加上一般能让最终准确率高一两个点。训练轮数 15 是起点核心判断依据是验证集准确率如果 val_acc 还在稳步上升就继续训如果连续三个 epoch 不升甚至下降就停。用 if val_acc best_val_acc 保存最优权重相当于手写了一个简易早停。课程设计不需要上 EarlyStopping 三方库。4.3 测试集评估准确率、混淆矩阵与分类报告训练完不能只看 val_acc还要拿没参与过任何选择的测试集做最终评估并用混淆矩阵看到底哪两类容易搞混。import numpy as np from sklearn.metrics import confusion_matrix, classification_report model.eval() all_preds, all_labels [], [] with torch.no_grad(): for inputs, labels in test_loader: inputs inputs.to(device) outputs model(inputs) _, preds torch.max(outputs, 1) all_preds.extend(preds.cpu().numpy()) all_labels.extend(labels.numpy()) cm confusion_matrix(all_labels, all_preds) print(混淆矩阵:) print(cm) report classification_report(all_labels, all_preds, target_nameslist(train_dataset.class_to_idx.keys())) print(report)混淆矩阵的行是真实类别列是预测类别。对角线越高越可靠某个非对角线格子数字大说明这两类经常被搞混比如厨余垃圾被预测成其他垃圾。分类报告里的 precision、recall、f1-score 每个类别一行比单一准确率更能说明问题答辩时老师问模型哪里不行直接指着报告讲就很有说服力。这里有一个容易翻车的细节测试集在整个调参过程中不能被碰。如果反复用测试集调阈值和轮数测试集就变成了变相的验证集最后报出的准确率虚高。最稳的做法是验证集用于训练过程里的参数调节测试集只在最终评估时跑一次。5. 垃圾分类系统常见问题排查过拟合、数据泄漏与界面卡顿的踩坑记录这一章写的都是真实课设里反复出现的坑。每一条按现象 → 原因 → 解决来写排查问题最怕只知道现象、不知道原理。5.1 训练集准确率 99%测试集只有 70%过拟合的修法现象训练过程中 train loss 降得很漂亮最后一个 epoch 训练准确率上了 99%但 val_acc 始终在 70% 附近徘徊测试集更差。这是典型的过拟合模型把训练集的细节背下来了没有学到可泛化的规律。原因有三类训练数据量太小每类只有一两百张图数据增强太弱只写了 Resize 和 Normalize没有随机裁剪和翻转训练轮数过多模型在后期纯粹记忆训练集。对课设来说三者同时存在的概率很大。解决按优先级来。先把 RandomResizedCrop 和 RandomHorizontalFlip 加上这是成本最低的一步再把轮数从 15 减到 10或者按 4.2 的早停逻辑提前截断最后检查每类图片数量少于 300 张就考虑换更小的模型MobileNetV2 比 ResNet18 更不容易过拟合或者把数据增强的 scale 范围放宽到 (0.5, 1.0)。5.2 预测结果几乎全是同一个类别类别不平衡与模型退化现象模型训练完在测试集上预测不管是塑料瓶还是碎玻璃输出永远是可回收物看分类报告其他几个类别的 recall 全是 0 或者接近 0。这是数据分布问题不是模型坏了。原因训练集里可回收物图片占六成以上其他三类加起来不到四成。交叉熵损失在样本多的类别上梯度贡献大模型学到的最优策略就是全猜可回收物因为这样整体损失最低属于典型的类别不平衡导致的模型退化。解决第一优先做类别数量对齐把每类图片裁到接近相同的数量第二用 WeightedRandomSampler 给少数类加抽样权重让每个 batch 里各类别出现概率均衡。也可以用最简单的办法把多数类随机删掉一部分四分类各保持 500 张左右训练快且不容易出怪问题。5.3 测试集准确率高得离谱数据划分泄漏现象训练 acc 一般测试 acc 却接近 99%比验证集还高怎么看都不对。如果还记得 3.1 那个直接 shuffle 全列表的切分脚本问题多半就藏在里面原始数据集如果是连续拍摄的同一物体出现在多张连续帧里shuffle 后这些帧会同时进入训练集和测试集模型等于在考试时见过原题。原因的本质是数据泄漏训练集和测试集之间存在相同或极相似的图片。不止视频抽帧会这样同一个物体拍多张角度照片也会这样。解决切分时按来源分组。按文件名前缀把来自同一拍摄批次或同一件垃圾的图片整体放进同一个集合再在集合级别做随机划分。代码上就是先按前缀分组再打乱组列表而不是打乱单张图片列表。这条排查起来最隐蔽也是答辩时最有可能被老师追问的地方。5.4 摄像头识别像放幻灯片UI 里逐帧推理的代价现象课设演示时本地图片识别没问题换成摄像头实时识别画面明显卡顿帧率只有两三帧人走过去画面都跟不上。原因摄像头每一帧都要先做解码、缩放、归一化再跑一次模型前向。MobileNetV2 在 CPU 上一次前向平均 30 到 50 毫秒加上解码和显示刷新单帧总耗时上百毫秒自然就卡。如果用 ResNet50基本告别实时演示。解决有几个层次。最直观的是降低推理频率只对每 5 帧中的 1 帧做识别中间 4 帧直接显示上一次的结果人眼感知不到延迟其次把输入图先缩小到 224×224 再进模型不要拿整幅摄像头画面直接推理最后如果确实想要流畅体验把模型转成 ONNX 或量化到半精度CPU 推理能快一到两倍。对课设来说前两个方案足够且改动量小。5.5 中文目录名和中文标签在 Windows 下的乱码与报错现象目录用中文命名比如 data/train/厨余垃圾在 Windows 上运行时 ImageFolder 报错或者类别名显示乱码PyQt 界面里按钮上的识别也偶尔显示成方块。原因Windows 控制台默认编码是 GBKPython 字符串按 UTF-8 处理两者在打印和路径读写时对不上torchvision 的 ImageFolder 对中文路径本身支持没问题但报错信息里的中文会先乱码让人误以为是路径问题。解决目录名用英文显示层再做中英映射。训练代码里统一用 recyclable、kitchen 这类英文内部标签只有界面展示时才把 class_names 映射成可回收物厨余垃圾。PyQt 的中文显示问题通常出在字体上给控件设置支持中文的字体族比如 setFont(QFont(Microsoft YaHei, 10)) 就能解决。这条属于看不出技术含量、但能卡住你两小时的问题。6. 拿高分的小技巧用消融实验和置信度演示把课设讲清楚课程设计最后的差距往往不在模型准确率而在你能不能讲清楚自己的模型为什么这样工作。两个技巧最有效消融实验和置信度演示。消融实验不需要重新训练很多次把训练脚本里的开关分别关掉再各跑一遍记录对比即可有数据增强 vs 无数据增强、只微调分类头 vs 全部微调、MobileNetV2 vs ResNet18。三行就能出一张对比表放在报告里写我通过消融实验证明数据增强对最终准确率贡献了 X 个百分点这句话在老师听来比模型本身的值钱得多。置信度演示是我每次带课设都会让学生加的功能推理时不只打印最终类别同时打印 top-3 候选和各自概率。def topk_prediction(img_path, model, class_names, k3): img val_transform(Image.open(img_path).convert(RGB)).unsqueeze(0) model.eval() with torch.no_grad(): probs torch.softmax(model(img), dim1)[0] values, indices torch.topk(probs, k) return [(class_names[i], round(v.item(), 4)) for v, i in zip(values, indices)]演示的时候先说模型认为这张图片有 82% 的概率是厨余垃圾再补一句第二候选是可回收物15%。这句话看着简单实际上是在告诉老师你的模型不是瞎猜的它在面对模棱两可的样本时知道自己有多犹豫。老师追问这个样本为什么被分到这类时你有概率数据可以回应而不是只能说模型就是这么学的。我自己带课设这几年翻车最多的从来不是模型训不出来而是报告里放一个准确率数字、模型文件几百 MB、现场演示时因为路径问题跑不起来。把这些细节提前过一遍课设基本就稳了。最后提一句习惯所有训练脚本都固定随机种子所有模型保存都只存 state_dict这样不管调参多少次结果都能复现答辩时也经得起验证。希望帮到你。本文还有配套的精品资源点击获取
返回列表