news 2026/9/28 1:16:10

深度学习图像分类实战:垃圾分类识别工程从训练到部署全指南

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
深度学习图像分类实战:垃圾分类识别工程从训练到部署全指南

简介:面向Python开发者和人工智能入门学习者的垃圾分类深度学习小工程,整个项目基于ResNet50图像分类思路,覆盖数据准备、模型训练到Demo演示的完整流程,可帮助读者快速理解卷积神经网络在图像识别任务中的应用。资源压缩包共14个文件,大小约4.22MB,以6个Python脚本为核心,包含数据集生成与预处理、ResNet50模型定义、训练入口、推理演示等模块;另附2份Markdown说明、2份Word文档、1份JSON配置、1份许可证文件、示例图片及Git忽略配置,分别用于环境说明、训练信息记录和理论讲解。已有1210人学习下载,适合刚接触深度学习分类任务、希望获得可用小工程进行复现和改写的读者。通过该项目可以掌握垃圾分类场景下的数据组织方式、模型微调流程与基本调参思路。

1. 这个Python基于深度学习的垃圾分类小工程,解决的是“从零跑通到能交付”

你拿到的这个Python基于深度学习的垃圾分类小工程,本质是一个图像分类实战包:输入一张垃圾照片,模型输出它是纸板、塑料、玻璃、金属还是电池,并附上置信度。它解决的不是算法创新问题,而是把“数据整理→模型训练→单图推理”这条链路做成可以照着复现的标准答案。适合两类人:一类是有Python基础、装过深度学习环境但还没完整跑通过一个项目的新手;另一类是小团队,想用它摸清垃圾分类的图像方案到底值不值得投入。别小看这个“小”字,恰恰是它把环境、数据、训练、推理都装进了一个zip,你只需要拆开、跑通、再按自己的数据改造。它最大的坑不在模型,而在数据声明和预处理的一致性,后面我会花大篇幅讲这块。

2. 拆开zip之前:读懂垃圾分类小工程的技术选型与代码骨架

拿到zip的第一件事不是急着双击readme,而是先把整个包的结构读明白。小工程最容易让人误判的是“东西少应该很轻松”,实际上文件越精简,隐含约定越多。你在动手前花半小时搞清楚它是一个分类任务还是一个检测任务、依赖什么框架、类别从哪来,能省掉后面一整天的调试时间。

2.1 垃圾分类本质是图像分类,为什么小工程几乎都选迁移学习

先明确任务边界:这个工程要解决的是“这张图属于哪一类垃圾”,不画框、不定位,所以它属于图像分类,不是目标检测。分类网络的结构很直白:前面是卷积特征提取器,负责把图像变成特征向量;后面是一个全连接分类头,把特征映射到类别概率。卷积部分学的是边缘、纹理、反光、颜色这样的局部模式,全连接部分则负责做“综合判断”。

为什么这类小工程几乎清一色用深度学习,而不是传统图像处理?因为垃圾外观差异太大:纸箱有瓦楞纹理,塑料瓶有高光,玻璃瓶半透明,金属反光强烈。这些特征用SIFT、颜色直方图这类手工特征也能建模,但泛化性很差,换个光照、换个背景就失效。CNN能自动从数据里学这些模式,模型的内部机制对大多数人是个黑匣子,但黑匣子的输入输出规则是固定的,只要数据喂对,行为就可控。

模型选型上,这类小工程最常见的是三条路:ResNet18或ResNet34,稳定、好调、资料多,适合追求效果和复现性;MobileNetV2或MobileNetV3,参数少、CPU推理快,适合以后要部署到树莓派或小程序端;偶尔会遇到VGG16,老工程里多,特点是稳但笨重。我的习惯是先用ResNet18跑通,因为它兼容性好,torchvision直接能加载预训练权重,改分类头也简单。数据集方面,公开的垃圾分类影像集和Kaggle上的garbage classification这类数据都覆盖纸板、塑料、玻璃、金属、织物、电池等常见类别,但真实垃圾桶边拍的照片和网上数据集差异很大,训练集里看着干净的图,到现场往往会翻车。

2.2 解压后先看哪几个文件:从readme到data_loader

解压和初读我用这样一组命令:

unzip Python基于深度学习的垃圾分类小工程.zip -d garbage_sort cd garbage_sort tree -L 2 -d # 先看目录结构,别急着跑训练 cat requirements.txt # 看依赖有什么 cat config.py # 看类别数、图像尺寸、模型名

这里的参数要解释一下:-d garbage_sort是指定解压到目标目录,避免原地散落;tree -L 2 -d只显示两层目录,排除文件,让你一眼看出有没有checkpoints、dataset、models这些关键目录;cat直接读配置,比用编辑器打开更快。多数垃圾分类小工程会这样组织:train.py负责训练,predict.py负责推理,data_loader.py负责读图,models或nets.py放网络结构,config.py放超参和路径,checkpoints放训练好的权重。如果没有config.py,这些常量通常直接写在train.py顶部,注意找。

我建议的阅读顺序是:readme → config.py → data_loader.py → train.py → predict.py。很多人习惯先看train.py的训练循环,这是错的。对垃圾分类这种工程,data_loader.py才是命根子,它决定标签怎么映射、图像尺寸多大、增强怎么做。你后面所有调试都围绕它展开。看的时候重点确认三点:类别列表是不是写死在文件里、图像统一缩放到多大、返回的batch是(images, labels)还是带路径的三元组。最后先跑通predict.py再碰训练,因为权重能加载成功,说明环境和模型定义前两步已经对了。

2.3 标签、路径和编码:暗坑先打个预防针

这三个问题在垃圾分类小工程里几乎必现,先说结论。类别索引从0开始,由ImageFolder按目录名的ASCII顺序自动生成,不是按你的数据里出现的先后顺序。目录名用0_cardboard、1_plastic这种带数字前缀的命名,就是为了让排序结果和人类直觉一致。其次,中文标签在Windows控制台打印时经常乱码,因为终端默认GBK编码,而PyTorch和Python 3的字符串是UTF-8,这个不致命但很干扰判断,所以我后面所有示例都用英文标签。最后,路径别带中文,包括你的用户名目录、解压目录、数据集目录,能避开大量奇怪问题。

提示:解压路径、数据集路径全用英文。Windows下中文路径会让ImageFolder读取表现得很不稳定,这类问题排查起来最浪费时间。

3. 把深度学习环境配置跑通:从python安装检查到第一张分类结果

环境问题占了这类小工程总耗时的一半以上。常见的“代码没错但跑不起来”,十有八九是Python版本和PyTorch对不上,或者显卡驱动太老、装了CPU版torch还指望GPU跑。这一章我把从零到出结果的最小路径完整走一遍,包含环境体检、依赖安装和单图推理三个步骤。

3.1 环境体检:python版本、CUDA与PyTorch的匹配关系

我的惯例是新建一个独立环境,而不是直接往base里装东西:

conda create -n garbage python=3.9 -y conda activate garbage python --version nvidia-smi # 看显卡和驱动版本 nvcc -V # 看CUDA运行时版本 python -c "import torch; print(torch.__version__, torch.cuda.is_available())"

先解释为什么选Python 3.9:PyTorch 1.13到2.x这条主线的wheel都带3.9的包,如果你用Python 3.12装旧版torch,基本上要在编译报错上浪费一晚上。Python 3.8、3.9、3.10都是安全区,3.9最省心。nvidia-smi看的是驱动支持的CUDA版本,nvcc -V看的是本机安装的CUDA Toolkit版本,这两个不完全是一回事。只要torch.cuda.is_available()返回True,PyTorch内部自带的CUDA就能用,不要求你自己装Toolkit。如果打印出False,常见原因是装了CPU版torch、驱动版本太旧、或者torch的CUDA编译版本高于驱动支持版本。没有GPU也不用灰心,这个小工程用MobileNet在CPU上能跑推理,训练慢一点但可行。

提示:在PyCharm里新建项目时,解释器直接选刚才的garbage环境,避免命令行能跑、IDE里报错这种奇怪的不一致。

3.2 依赖安装:requirements.txt不完全可信,核心依赖自己核对

requirements.txt是作者在他自己机器上验证过的版本快照,但很多小工程的requirements.txt是网上抄来的,版本可能过老或互相矛盾。我的做法是参考它,但不盲从:

pip install -r requirements.txt -i 清华或阿里云PyPI镜像 pip install opencv-python pillow numpy tqdm scikit-learn matplotlib

PyPI镜像这个参数很有用,直接装能省不少时间。第一行把工程自带的依赖全装上,第二行补装你可能用到但requirements里没写的工具库。这里要重点核对的是torch和torchvision的版本配对,这两个库必须来自同一批Release,比如torch 2.0配torchvision 0.15,配错会在import时报“undefined symbol”之类的错。如果requirements里有个很旧的torch版本,我建议先升级:pip install -U torch torchvision,再继续装其他依赖。opencv-python负责图像增强和IO的兜底,Pillow负责读图,scikit-learn用来算评估指标,matplotlib用来画混淆矩阵,这几个都不是可选依赖。

3.3 最小推理:一张图如何变成“类别+置信度”

不管zip里自带的predict.py长什么样,我都建议先写一个最小推理脚本,把“加载权重→预处理→前向→输出类别”这四个环节彻底搞明白。下面这个脚本可以直接保存为predict_min.py:

import torch import torchvision.models as models from torchvision import transforms from PIL import Image class_names = ["cardboard", "plastic", "glass", "metal", "fabric", "battery"] def load_model(num_classes, ckpt_path): model = models.resnet18(weights=None) model.fc = torch.nn.Linear(model.fc.in_features, num_classes) state = torch.load(ckpt_path, map_location="cpu") state = {k.replace("module.", ""): v for k, v in state.items()} model.load_state_dict(state, strict=False) model.eval() return model def predict(img_path, model, device="cpu"): tf = 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]), ]) img = Image.open(img_path).convert("RGB") x = tf(img).unsqueeze(0).to(device) with torch.no_grad(): logits = model(x) probs = torch.softmax(logits, dim=1) top1 = probs.argmax(dim=1).item() top1_conf = probs[0, top1].item() return class_names[top1], top1_conf if __name__ == "__main__": model = load_model(num_classes=len(class_names), ckpt_path="./checkpoints/best.pth") cls, conf = predict("./test.jpg", model) print(f"类别: {cls} 置信度: {conf:.4f}")

这段代码有几个关键点。torch.load(..., map_location="cpu")让没有GPU的机器也能加载权重,不会因为设备名匹配不上报错。后面那行replace("module.", "")是处理DataParallel多卡训练留下的前缀,小工程里经常遇到,先写上能省一次报错。model.eval()必须调用,它会切换BN层和Dropout的行为,不调的话同一张图每次推理结果都可能不一样。预处理三件套Resize、CenterCrop、Normalize必须和训练时保持一致,尤其是Normalize的均值方差,这是ImageNet预训练权重的统计值,填错会导致颜色分布偏掉、精度骤降。运行命令是:

python predict_min.py --image ./data/test/paper_01.jpg

如果zip自带的predict.py是带argparse的,优先直接用它。我写这个最小脚本是想让你理解流程,理解之后任何变体都能看懂。

4. 把数据喂成深度学习能学的样子:目录结构、预处理与微调参数

训练阶段最耗时间的往往不是模型,而是数据准备。别一开箱就跑python train.py,那只会对着默认的dataset目录一路飞奔。先把数据组织好,把预处理和超参弄清楚,训练结果才有参考价值。和论文复现不同,这类深度学习实战项目案例更看重“改到自己的数据上还能跑”,所以数据这一环不能跳过。

4.1 用ImageFolder整理训练集:目录名就是标签,顺序就是索引

PyTorch的torchvision.datasets.ImageFolder是分类小工程的事实标准,它的规则很朴素:一级子目录名就是类别名,图片文件放在类别目录里。

dataset/train/0_cardboard/xxx.jpg dataset/train/1_plastic/xxx.jpg dataset/train/2_glass/xxx.jpg dataset/train/3_metal/xxx.jpg dataset/train/4_fabric/xxx.jpg dataset/train/5_battery/xxx.jpg dataset/val/0_cardboard/xxx.jpg dataset/val/1_plastic/xxx.jpg

用0_、1_这种前缀是刻意为之。ImageFolder会按目录名字母序排序生成class_to_idx,如果你用cardboard、plastic这样纯字母命名,虽然也能用,但排序顺序容易和推理脚本里写死的类别列表对不上。带数字前缀后,排序就和人类直觉一致,排查起来不用猜。如果原始数据是一个大目录里所有类别混着,可以写个脚本按比例切分:

import os, random, shutil random.seed(42) root = "dataset/full" for cls in os.listdir(root): imgs = os.listdir(os.path.join(root, cls)) random.shuffle(imgs) n_val = int(len(imgs) * 0.2) for i, img in enumerate(imgs): subset = "val" if i < n_val else "train" out_dir = f"dataset/{subset}/{cls}" os.makedirs(out_dir, exist_ok=True) shutil.copy(os.path.join(root, cls, img), out_dir)

这段代码里random.seed(42)保证了每次划分结果一致,这个参数很关键,不然前后两轮训练用的验证集不同,指标没法对比。n_val = int(len(imgs) * 0.2)是切出20%作为验证集,对小数据量是合理比例。要注意的是只做copy不移动,原始数据别动,这是后悔药。如果原始数据本来就有train和val目录,直接跳过这个脚本,但重点检查val目录里类别是否齐全、命名是否和train一致。

4.2 训练与推理的预处理必须一致:增强与归一化的边界

数据增强是提高泛化能力最直接的手段,但垃圾分类图有自己的特点:垃圾桶附近光线差、背景杂乱、物体可能部分被遮挡。增强要能模拟这种变化,又不能把图改得连人都认不出。我的常用transforms如下:

from torchvision import transforms train_tf = transforms.Compose([ transforms.RandomResizedCrop(224, scale=(0.7, 1.0)), transforms.RandomHorizontalFlip(p=0.5), transforms.ColorJitter(brightness=0.3, contrast=0.3), transforms.ToTensor(), transforms.Normalize(mean=[0.485, 0.456, 0.406], std=[0.229, 0.224, 0.225]), ]) eval_tf = 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, scale=(0.7, 1.0))表示裁剪后缩放到224,裁剪面积是原图的70%到100%。这个下限别设太低,垃圾物体本身就小,裁太多会把关键特征裁掉。RandomHorizontalFlip概率0.5,左右翻转对大多数垃圾是安全的,但如果你识别的是有方向性的印刷文字,这一项要关掉。ColorJitter的亮度、对比度各0.3,模拟不同光照。归一化的均值方差用的是ImageNet统计值,因为你的预训练权重是在ImageNet上训练的,输入分布必须和训练时一致,否则第一层卷积的输出就偏了。

训练端和推理端的预处理必须严格分开:训练端允许随机,推理端必须确定。推理端用Resize(256)加CenterCrop(224),这是torchvision官方推荐的稳定组合。我的习惯是把这两个transforms定义在同一个文件里并导出,两个脚本共用,而不是在train.py和predict.py各写一份,这样能从根本上杜绝不一致这个最常见的低级错误。

4.3 微调超参数设置:batch_size、lr、epochs怎么定

迁移学习不是从零训练,而是把预训练模型的通用特征拿过来用,只调整部分参数。所以超参数设置和从零训练完全不同。下表是我在垃圾分类小工程上的起点值:

参数推荐值说明
batch_size16或328G显存选16,显存充足选32
优化器Adam 或 SGDAdam收敛快,SGD更稳、泛化更好
学习率 lr1e-3(只训分类头)1e-4(解冻backbone后)
epochs20到50小工程通常在30轮内收敛
weight_decay1e-4防止全连接层过拟合
schedulerCosineAnnealingLR周期由epochs决定

先看模型改造和训练循环的最小骨架:

import torch.nn as nn from torchvision import models num_classes = len(class_names) model = models.resnet18(weights=models.ResNet18_Weights.IMAGENET1K_V1) in_features = model.fc.in_features model.fc = nn.Linear(in_features, num_classes) for name, param in model.named_parameters(): if "fc" not in name: param.requires_grad = False optimizer = torch.optim.Adam( filter(lambda p: p.requires_grad, model.parameters()), lr=1e-3) scheduler = torch.optim.lr_scheduler.CosineAnnealingLR(optimizer, T_max=epochs) criterion = nn.CrossEntropyLoss() for epoch in range(epochs): model.train() for images, labels in train_loader: images, labels = images.to(device), labels.to(device) optimizer.zero_grad() outputs = model(images) loss = criterion(outputs, labels) loss.backward() optimizer.step() scheduler.step() val_loss, val_acc = evaluate(model, val_loader)

第一段的作用是替换分类头:model.fc.in_features是预训练分类头的输入维度,ResNet18是512,替换后输出从1000类变成你的类别数。然后遍历所有参数,除了名字带fc的层之外,全部冻结。冻结的意思是requires_grad=False,Adam根本不会给这些参数分配梯度状态,显存和算力都省了。训练循环里用filter(lambda p: p.requires_grad, model.parameters())把可训练参数筛出来交给优化器,这是冻结操作能生效的关键。什么时候解冻backbone?我一般看验证集loss连续两三个epoch不下降时,把最后的layer3、layer4解冻,学习率降到1e-4,再训10轮左右。这个操作能给模型“再松一档”的机会,小数据上通常还能涨两三个点。

4.4 类别不均衡:用loss加权,不要只用整体准确率

垃圾影像数据集几乎都有类别不均衡问题,纸箱、塑料瓶这些常见类别一两千张,玻璃碎片、电池可能只有一两百张。如果不处理,模型会对多数类过度自信,少数类recall可能低到不可用。最简单的做法是给CrossEntropyLoss按类别频率反比加权:

from sklearn.utils.class_weight import compute_class_weight import numpy as np import torch.nn as nn labels = [train_dataset.targets[i] for i in range(len(train_dataset))] class_weight = compute_class_weight( "balanced", classes=np.unique(labels), y=np.array(labels)) weights = torch.tensor(class_weight, dtype=torch.float) criterion = nn.CrossEntropyLoss(weight=weights)

compute_class_weight的balanced模式计算方式是:每类权重 = 样本总数 / (类别数 × 该类样本数)。少数类因此拿到更大的loss权重,梯度更新时会被更认真地对待。用这个之后,整体accuracy可能微降,但每类recall会均衡很多。训练结束后一定要打印每个类别的recall,而不是只看总体acc,不然你根本不知道电池这类危险品被模型漏掉了多少。

5. 垃圾分类小工程避坑指南:5个高频翻车点与修复姿势

这一章写的都是我实际踩过、或者帮人排查过的坑。每个都按“现象→原因→解决”展开,建议你在改代码前先对号入座。

5.1 训练loss不降反升,或者第10轮突然爆掉

现象:前几轮loss正常下降,到第10轮突然从1.2跳到9.8,之后再也回不去;或者从一开始loss就不降,剧烈震荡。原因最常见的三个:学习率太大,模型在损失曲面震荡;数据增强过猛,图被裁得面目全非,标签失效;更隐蔽的是标签顺序错位,模型一直在学错误的映射。解决分两步。先用下面这段代码从dataloader里抽一批数据,打印出图和标签,人工确认图和类对得上:

data_iter = iter(train_loader) images, labels = next(data_iter) for i in range(min(8, len(labels))): print(i, class_names[labels[i].item()])

确认标签无误后,把学习率降到1e-4重启。如果loss曲线仍然抖动,把ColorJitter全部关掉,用最朴素的裁剪加翻转先跑一遍。这个“先极简后增强”的顺序能最快定位问题。

5.2 显存溢出或CPU慢到不可用

现象:batch_size设32,训练没两步就报CUDA out of memory;或者CPU训练一个epoch要两小时。原因通常是输入分辨率太大、batch太大、验证阶段忘了关梯度。解决路径有四条,按性价比排序:把输入统一到224或256,很多小工程默认用448或更大,显存直接翻倍;batch_size减半,从32降到16;在验证函数里加with torch.no_grad():,不然验证阶段计算图不会被释放;最后再考虑混合精度:

scaler = torch.cuda.amp.GradScaler() with torch.cuda.amp.autocast(): outputs = model(images) loss = criterion(outputs, labels) scaler.scale(loss).backward() scaler.step(optimizer) scaler.update()

混合精度对准确率影响很小,但显存和速度都有体感提升。唯一注意点是老显卡不支持AMP,设置环境变量CUDA_VISIBLE_DEVICES=""时会自动退化,不用强求。

5.3 推理结果永远是同一个类别

现象:不管输入是纸箱还是塑料瓶,输出永远是同一个标签,置信度还很高。原因有几种可能:预处理和训练不一致,比如训练用了224,推理用了320,特征分布对不上;类别顺序错位,模型输出的第3类是塑料瓶,你打印的是第3类是纸板;还有可能是softmax之后取argmax的维度写错。排查时不要只看top1,把top5打印出来:

probs = torch.softmax(logits, dim=1) top5 = torch.topk(probs, k=min(5, probs.size(1)), dim=1) for rank in range(len(top5.indices[0])): idx = top5.indices[0][rank].item() print(class_names[idx], round(top5.values[0][rank].item(), 4))

如果top5的概率分布均匀且全是同一个类别,说明模型或数据有问题;如果第二名、第三名其实是对的类别,只是被排到后面,那就是类别列表顺序写错。我遇到后者居多,因为训练脚本和推理脚本常各写一个类别数组。

5.4 加载checkpoint报missing或unexpected key

现象:load_state_dict报错,一串以module.开头的key找不到,或者fc层的权重维度对不上。原因有两个:训练时用了DataParallel,保存的权重key会多出module.前缀;或者微调时fc层输出维度不是1000,和预训练权重冲突。解决方式统一处理:

state = torch.load("best.pth", map_location="cpu") new_state = {} for k, v in state.items(): new_state[k.replace("module.", "")] = v missing, unexpected = model.load_state_dict(new_state, strict=False) print(missing, unexpected)

strict=False的意思是允许缺少部分key,先加载能匹配的,再打印缺失列表。如果你替换过fc层,那么fc.weight和fc.bias出现在unexpected里是正常的,不用管;但如果backbone层的key出现在missing里,说明网络结构定义和保存时不一致,这是错误,需要回头检查模型名。一个细节是load_state_dict返回的元组第一个元素是缺失key,第二个是多余key,千万别看反。

5.5 Windows下中文路径与中文目录名的乱码和读取失败

现象:代码在Linux好好的,Windows上一跑,读取图片报路径找不到,或者控制台打印的标签全是乱码。原因在于Windows控制台默认GBK编码,而Python 3的字符串是UTF-8,中文目录名经过ImageFolder后也可能因为文件系统编码差异对不上。解决方式最彻底的是全程英文,从项目根目录到数据集命名都不要有中文。其次,类别目录用0_cardboard而不是纸板,即使你在代码里用class_names = ["纸板"]映射中文名,目录本身也别用中文。最后,排查读取问题时用这个命令看目录里实际读到了什么:

python -c "import os; print(os.listdir('dataset/train/0_cardboard')[:5])"

如果列表为空,但资源管理器里明明有文件,多半是路径拼接问题,检查项目根目录是不是真的在当前位置,以及有没有不小心用了绝对路径却指向旧目录。

6. 把“能跑”变成“可信”:用评估脚本验收你的深度学习小工程

训练结束、推理能出图,这时最需要一份评估脚本,把所有类别的准确率、召回率、F1打印出来,再画一张混淆矩阵。只报一个整体accuracy,在垃圾类别不均衡的工程里没有说服力。评估脚本不长,核心就是下面这段:

from sklearn.metrics import classification_report, confusion_matrix # y_true 是验证集真实标签列表,y_pred 是模型预测标签列表 # 两者按同样的顺序一一对应 report = classification_report( y_true, y_pred, target_names=class_names, digits=4) print(report) cm = confusion_matrix(y_true, y_pred)

参数里target_names必须和训练时的类别列表顺序严格一致,不一致时整个报告都是错位的。digits=4是因为少数类样本量小,三位小数看不清差别。拿到结果后,重点不是看总体accuracy,而是按下面这张表的思路定位问题:

指标应该关注什么
overall accuracy初步判断模型是否可用,但不能只看这个
per-class recall哪一类被漏最多,比如电池recall只有0.4,说明模型大量漏检
confusion pair哪两类经常互相误判,比如玻璃和塑料,说明特征重叠严重

如果混淆矩阵里固定有某两类互相串,我的习惯是回到数据集里把这两类的图片调出来,观察它们到底像在哪里,然后去补充真实场景的负样本,而不是立刻换更大的模型。数据层面的缺口,靠堆网络参数是补不回来的。我自己每次接手这类深度学习小工程,第一件事永远是先跑通一次评估脚本,确认baseline可信,再动训练参数;否则后面怎么调都像在碰运气。希望帮到你。

本文还有配套的精品资源,点击获取

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/9/28 1:15:18

中兴W101D2刷机教程:晶晨S905L3A盒子变全功能电视盒子

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

作者头像 李华
网站建设 2026/9/28 1:14:52

ESP32多模块共存:用NVS命名空间实现Flash数据隔离

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

作者头像 李华
网站建设 2026/9/28 1:14:44

展锐平台SensorHub动态驱动加载与调试实战解析

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

作者头像 李华
网站建设 2026/9/28 1:14:43

VisionMaster 4.2视觉定位项目全流程实战指南

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

作者头像 李华
网站建设 2026/9/28 1:14:22

RS485乱码排查:A下拉B上拉偏置电阻设计实战

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

作者头像 李华