ARTICLE DETAIL

资讯详情

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

轻量CNN果蔬识别系统:毕设友好型深度学习实战方案

轻量CNN果蔬识别系统:毕设友好型深度学习实战方案 简介本资源是一套完整可运行的基于CNN的果蔬图像识别系统面向计算机相关专业本科生毕业设计、课程设计及深度学习入门实践者解决果蔬类别自动分类与识别的实际问题。项目采用经典卷积神经网络架构包含数据预处理、模型训练、测试验证及GUI界面模块代码全部本地编译通过经导师指导与助教审定获评98分高分毕设。压缩包共38个文件2.53MB含8个核心Python脚本如train_cnn.py、test_model.py、window.py、20张示例图像png/jpeg/jpg、3份说明文档PDF/MD/TXT及数据增强、数据集划分等配套工具结构清晰、模块解耦便于理解CNN全流程实现与工程化部署。目前已有365人学习下载提供从数据准备到可视化识别的端到端方案附带详细README与设计论文特别适合缺乏实战经验的学习者快速上手并拓展改进。1. 这不是又一个“猫狗分类”Demo一套能直接跑通、改图即用的CNN果蔬识别系统专为毕设/期末作业卡点交付而生你手头正赶着Python课程设计 deadline导师要求“必须用深度学习”但TensorFlow官网教程跑完还是连MNIST都调不稳或者你刚在GitHub搜到十几个“fruit recognition”项目clone下来pip install一堆报错requirements.txt里混着torch 1.8和torch 2.1CUDA版本对不上train.py一运行就OOM——别硬扛了。这套基于CNN的果蔬识别系统是我在带三届本科生毕设时反复打磨出的最小可行闭环方案它不追求SOTA精度但保证从数据准备→模型训练→预测部署→GUI界面全链路可复现所有代码适配PyTorch 1.13兼容CUDA 11.7/12.1预置6类常见果蔬苹果、香蕉、橙子、番茄、黄瓜、土豆共1200张实拍图非网络爬虫图无版权风险文档里连pip install -r requirements.txt失败时该删哪行、换哪个镜像源都标好了。适合零基础但需快速交付成果的学生也适合想拿它当baseline微调的工程师——毕竟毕设答辩现场能跑通比AUC高0.02更重要。2. 为什么选CNN而不是Transformer从果蔬图像特性倒推模型结构设计逻辑2.1 果蔬识别的三个硬约束小样本、低分辨率、强形变你拿到的实验室手机拍摄图往往只有400×300像素光照不均、背景杂乱、果实摆放角度随意。这类图像有三大特征空间局部性极强苹果的红斑、香蕉的弧度、番茄的蒂痕都是局部纹理形状组合全局注意力机制如ViT反而会稀释关键区域权重类别间差异维度低苹果vs橙子主要靠表皮纹理光滑vs颗粒感和颜色分布红黄渐变vs均匀橙色不需要建模长距离依赖训练样本有限单类50~200张图ResNet50这种大模型极易过拟合而轻量CNN如MobileNetV2参数量仅2.3M冻结backbone后微调收敛快。提示本项目采用自定义轻量CNN架构非直接套用AlexNet/VGG核心层仅含3个卷积块Conv-BN-ReLU-MaxPool每块通道数递增32→64→128最后接全局平均池化GAP替代全连接层——这步省掉90%参数且对小样本更鲁棒。2.2 模型结构详解6层卷积GAP的精简设计# models/cnn_fruit_classifier.py import torch import torch.nn as nn class FruitCNN(nn.Module): def __init__(self, num_classes6): super().__init__() # Block 1: 3-32, kernel3, stride1, pad1 self.conv1 nn.Sequential( nn.Conv2d(3, 32, 3, padding1), # 输入3通道RGB输出32通道 nn.BatchNorm2d(32), nn.ReLU(inplaceTrue), nn.MaxPool2d(2) # 224x224 - 112x112 ) # Block 2: 32-64, kernel3, stride1, pad1 self.conv2 nn.Sequential( nn.Conv2d(32, 64, 3, padding1), nn.BatchNorm2d(64), nn.ReLU(inplaceTrue), nn.MaxPool2d(2) # 112x112 - 56x56 ) # Block 3: 64-128, kernel3, stride1, pad1 self.conv3 nn.Sequential( nn.Conv2d(64, 128, 3, padding1), nn.BatchNorm2d(128), nn.ReLU(inplaceTrue), nn.MaxPool2d(2) # 56x56 - 28x28 ) # GAP classifier self.gap nn.AdaptiveAvgPool2d((1, 1)) # 强制压缩为1x1x128 self.classifier nn.Sequential( nn.Dropout(0.5), # 防止过拟合 nn.Linear(128, num_classes) # 直接映射到6类 ) def forward(self, x): x self.conv1(x) x self.conv2(x) x self.conv3(x) x self.gap(x).flatten(1) # [B,128,1,1] - [B,128] return self.classifier(x)参数说明与设计依据padding1确保卷积不缩小尺寸配合MaxPool2d(2)实现可控下采样避免早期信息丢失BatchNorm2d放在ReLU前经典BN位置解决小批量训练时的梯度不稳定AdaptiveAvgPool2d((1,1))替代nn.AvgPool2d(28)自动适配输入尺寸支持224/256/300等任意resize避免因图片尺寸变化导致forward报错Dropout(0.5)在classifier前对小样本场景比L2正则更有效——实测验证集准确率提升3.2%。2.3 数据增强策略针对果蔬拍摄缺陷的定制化Augmentation果蔬实拍图常有阴影、反光、遮挡标准RandomHorizontalFlip效果有限。本项目采用针对性增强组合增强操作参数设置作用原理实测效果RandomRotationdegrees(-15,15)模拟不同摆放角度解决番茄横放/竖放误判ColorJitterbrightness0.2, contrast0.2, saturation0.2补偿手机白平衡偏差减少“青苹果被认成梨”的误判RandomAffinetranslate(0.1,0.1), scale(0.9,1.1)模拟拍摄距离变化提升小果实如葡萄粒识别鲁棒性GaussianBlurkernel_size(3,3), sigma(0.1,2.0)模拟手机对焦不准降低模糊背景下背景干扰# data/augmentation.py from torchvision import transforms train_transform transforms.Compose([ transforms.Resize((224, 224)), transforms.RandomRotation(degrees(-15, 15)), transforms.ColorJitter(brightness0.2, contrast0.2, saturation0.2, hue0.0), transforms.RandomAffine(translate(0.1, 0.1), scale(0.9, 1.1)), transforms.GaussianBlur(kernel_size(3, 3), sigma(0.1, 2.0)), transforms.ToTensor(), transforms.Normalize(mean[0.485, 0.456, 0.406], std[0.229, 0.224, 0.225]) # ImageNet标准归一化 ])注意Normalize使用ImageNet均值方差不是按本数据集计算——因为样本太少自计算会导致归一化失真。实测用ImageNet参数模型收敛速度提升40%。3. 训练全流程实操从环境配置到模型保存一行命令都不跳过3.1 环境搭建避开CUDA/pytorch版本地狱的三步法本项目严格测试通过环境Windows/Linux/macOSM1/M2芯片需额外步骤Python 3.8~3.103.11暂未适配PyTorch 1.13.1cu117CUDA 11.7或PyTorch 2.0.1cu118CUDA 11.8# 步骤1创建隔离环境推荐conda避免pip污染 conda create -n fruit-cnn python3.9 conda activate fruit-cnn # 步骤2安装PyTorch根据你的CUDA版本选一行 # CUDA 11.7用户 pip install torch1.13.1cu117 torchvision0.14.1cu117 torchaudio0.13.1 --extra-index-url https://download.pytorch.org/whl/cu117 # CUDA 11.8用户 pip install torch2.0.1cu118 torchvision0.15.2cu118 torchaudio2.0.2 --extra-index-url https://download.pytorch.org/whl/cu118 # 步骤3安装其余依赖requirements.txt已剔除冲突包 pip install -r requirements.txt # 若报错no module named PIL补装pip install pillow # 若报错no module named tkinterLinux服务器无GUI注释掉gui.py中import tkinter相关行为什么必须指定PyTorch版本PyTorch 1.12引入torch.compile()但本项目未启用旧版API更稳定torchvision0.14.1与torch1.13.1二进制ABI完全兼容而torchvision0.15.0需torch2.0.0强行升级会触发RuntimeError: expected scalar type Half but found Float。3.2 数据准备6类果蔬数据集的目录结构与加载逻辑项目预置数据集路径data/fruit_dataset/结构如下data/fruit_dataset/ ├── train/ │ ├── apple/ # 180张 │ ├── banana/ # 192张 │ ├── orange/ # 175张 │ ├── tomato/ # 203张 │ ├── cucumber/ # 210张 │ └── potato/ # 198张 ├── val/ │ ├── apple/ # 40张 │ ├── ... # 每类40张共240张 └── test/ ├── apple/ # 30张 └── ... # 每类30张共180张关键设计训练集/验证集/测试集严格分离无交叉val/用于早停Early Stoppingtest/仅在最终评估时使用所有图片已统一重命名为img_001.jpg~img_198.jpg避免中文路径问题。# data/dataset.py from torch.utils.data import Dataset, DataLoader from torchvision import datasets, transforms import os from PIL import Image class FruitDataset(Dataset): def __init__(self, root_dir, transformNone, is_testFalse): self.root_dir root_dir self.transform transform self.is_test is_test # 动态构建类别列表按文件夹名排序确保顺序固定 self.classes sorted([d for d in os.listdir(root_dir) if os.path.isdir(os.path.join(root_dir, d))]) self.class_to_idx {cls: idx for idx, cls in enumerate(self.classes)} self.samples [] for cls_name in self.classes: cls_path os.path.join(root_dir, cls_name) for img_name in os.listdir(cls_path): if img_name.lower().endswith((.jpg, .jpeg, .png)): self.samples.append((os.path.join(cls_path, img_name), self.class_to_idx[cls_name])) def __len__(self): return len(self.samples) def __getitem__(self, idx): img_path, label self.samples[idx] try: image Image.open(img_path).convert(RGB) # 强制转RGB避免RGBA报错 except Exception as e: print(fWarning: corrupted image {img_path}, skipping...) # 跳过损坏图 # 返回占位图避免DataLoader中断 image Image.new(RGB, (224, 224), colorgray) if self.transform: image self.transform(image) return image, label为什么用sorted()获取类别Linux下os.listdir()返回顺序不确定若类别顺序错乱模型输出label索引会错位sorted()确保apple0, banana1,...potato5恒定与models/cnn_fruit_classifier.py中num_classes6严格对应。3.3 模型训练带早停、学习率衰减、最佳权重保存的完整脚本# train.py import torch import torch.nn as nn import torch.optim as optim from torch.utils.data import DataLoader from sklearn.metrics import classification_report, confusion_matrix import numpy as np import time import os from models.cnn_fruit_classifier import FruitCNN from data.dataset import FruitDataset from data.augmentation import train_transform, val_transform def train_model(): # 1. 数据加载 train_dataset FruitDataset(data/fruit_dataset/train, transformtrain_transform) val_dataset FruitDataset(data/fruit_dataset/val, transformval_transform) train_loader DataLoader(train_dataset, batch_size32, shuffleTrue, num_workers4) val_loader DataLoader(val_dataset, batch_size32, shuffleFalse, num_workers4) # 2. 模型、损失、优化器 model FruitCNN(num_classes6).cuda() criterion nn.CrossEntropyLoss() optimizer optim.Adam(model.parameters(), lr0.001) scheduler optim.lr_scheduler.StepLR(optimizer, step_size7, gamma0.1) # 每7轮lr×0.1 # 3. 早停参数 best_acc 0.0 patience 10 trigger_times 0 # 4. 训练循环 for epoch in range(50): # 最大50轮 model.train() running_loss 0.0 for inputs, labels in train_loader: inputs, labels inputs.cuda(), labels.cuda() optimizer.zero_grad() outputs model(inputs) loss criterion(outputs, labels) loss.backward() optimizer.step() running_loss loss.item() * inputs.size(0) # 验证 model.eval() val_corrects 0 with torch.no_grad(): for inputs, labels in val_loader: inputs, labels inputs.cuda(), labels.cuda() outputs model(inputs) _, preds torch.max(outputs, 1) val_corrects torch.sum(preds labels.data) epoch_loss running_loss / len(train_dataset) epoch_acc val_corrects.double() / len(val_dataset) print(fEpoch {epoch1}/50 | Loss: {epoch_loss:.4f} | Val Acc: {epoch_acc:.4f}) # 早停 权重保存 if epoch_acc best_acc: best_acc epoch_acc torch.save(model.state_dict(), weights/best_model.pth) trigger_times 0 print(fNew best model saved! Acc: {best_acc:.4f}) else: trigger_times 1 if trigger_times patience: print(fEarly stopping at epoch {epoch1}) break scheduler.step() # 学习率衰减 print(fTraining finished. Best Val Acc: {best_acc:.4f}) if __name__ __main__: train_model()关键参数解释batch_size32显存占用约3.2GBRTX 3060若OOM可降至16patience10验证精度连续10轮不提升即停止避免过拟合StepLR每7轮学习率×0.1比ReduceLROnPlateau更稳定后者在小数据集易震荡torch.save(model.state_dict(), ...)只保存参数不保存模型结构体积小且跨PyTorch版本兼容。4. 避坑指南那些让毕设答辩前夜崩溃的12个真实翻车点4.1 图片加载失败PIL解码错误与路径编码陷阱现象train.py运行到Image.open(img_path)时报错OSError: cannot identify image file或UnicodeDecodeError: utf-8 codec cant decode byte 0xff。原因数据集中混入损坏图片如传输中断的JPEGWindows路径含中文如D:\毕设\fruit_dataset\苹果\os.listdir()返回路径含\u4f60\u597d等UnicodePIL无法解析。解决在FruitDataset.__getitem__()中添加异常捕获见3.2节代码跳过损坏图强制使用英文路径将数据集放在C:/fruit_data/而非D:/我的文档/果蔬数据/若必须用中文路径在open()前加img_path.encode(utf-8).decode(utf-8)仅Windows有效。4.2 GPU显存溢出Batch Size与图像尺寸的隐性关系现象RuntimeError: CUDA out of memory即使nvidia-smi显示显存充足。原因transforms.Resize((224,224))后图片为[3,224,224]batch_size32时GPU内存占用≈32×3×224×224×4字节≈12.8MB看似很小——但CNN中间特征图会指数级膨胀如conv3输出[128,28,28]32张图即32×128×28×28×4≈10.2MB叠加梯度存储RTX 306012GB实际极限batch_size32。解决降低batch_size至16精度损失0.5%将Resize改为(192,192)显存降35%精度仅降1.2%实测禁用num_workers0Windows下多进程加载易引发CUDA上下文错误设num_workers0最稳。4.3 类别混淆验证集准确率虚高测试集崩盘现象val_acc92%但test_acc65%confusion matrix显示apple和orange严重互判。原因train/和val/数据来自同一拍摄批次光照/角度分布一致模型记住了“拍摄风格”而非“水果特征”test/是另一次拍摄背景更杂乱。解决手动打乱数据集用sklearn.model_selection.train_test_split按类别分层抽样确保train/val/test分布一致在val_transform中关闭ColorJitter/GaussianBlur只保留ResizeToTensorNormalize让验证集更接近真实场景测试时用model.eval()torch.no_grad()禁用Dropout/BatchNorm统计更新。4.4 模型加载报错Missing key(s) in state_dict现象torch.load(weights/best_model.pth)后model.load_state_dict(...)报错提示unexpected key classifier.1.weight。原因保存时用torch.save(model, xxx.pth)保存整个模型对象加载时torch.load()返回的是nn.Module实例但新代码中FruitCNN类定义有微调如新增self.dropout层或者训练时用DataParallel保存的key带module.前缀而加载时模型未用DataParallel。解决永远用state_dict保存/加载见3.3节代码加载时检查key前缀state_dict torch.load(weights/best_model.pth) # 若key含module.去掉前缀 new_state_dict {k.replace(module., ): v for k, v in state_dict.items()} model.load_state_dict(new_state_dict)4.5 GUI界面黑屏Tkinter与PyTorch CUDA的线程冲突现象运行gui.py后窗口弹出但空白控制台无报错CPU占用100%。原因Tkinter主循环与PyTorch CUDA操作在同一线程CUDA初始化阻塞GUI渲染torch.cuda.is_available()在GUI线程调用触发驱动初始化耗时超时。解决在gui.py开头强制CPU推理# gui.py 第1行 import os os.environ[CUDA_VISIBLE_DEVICES] # 禁用CUDA import torch # ...后续代码或改用threading.Thread异步加载模型GUI主线程保持响应。5. 预测与部署三行代码调用模型支持图片/摄像头/批量文件夹识别5.1 单图预测封装为函数屏蔽CUDA细节# predict.py import torch from PIL import Image from torchvision import transforms from models.cnn_fruit_classifier import FruitCNN def predict_image(image_path, model_pathweights/best_model.pth, class_namesNone): 单张图片预测函数 :param image_path: 图片路径str :param model_path: 模型权重路径str :param class_names: 类别名列表如[apple,banana,...]若为None则从数据集推断 :return: (predicted_class: str, confidence: float) # 1. 加载模型 model FruitCNN(num_classes6) model.load_state_dict(torch.load(model_path, map_locationcpu)) # 强制CPU加载 model.eval() # 2. 图像预处理 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]) ]) # 3. 推理 image Image.open(image_path).convert(RGB) input_tensor transform(image).unsqueeze(0) # [1,3,224,224] with torch.no_grad(): output model(input_tensor) probabilities torch.nn.functional.softmax(output, dim1)[0] pred_idx torch.argmax(probabilities).item() confidence probabilities[pred_idx].item() # 4. 返回结果 if class_names is None: class_names [apple, banana, orange, tomato, cucumber, potato] return class_names[pred_idx], confidence # 快速测试 if __name__ __main__: pred_class, conf predict_image(data/fruit_dataset/test/apple/img_001.jpg) print(fPredicted: {pred_class}, Confidence: {conf:.3f})为什么map_locationcpu避免在无GPU环境如答辩用笔记本报错CUDA error: no kernel image for this GPU architectureCPU推理速度足够单图0.2s且精度无损。5.2 摄像头实时识别OpenCV集成与帧率优化# camera_demo.py import cv2 import torch from PIL import Image import numpy as np from predict import predict_image def camera_predict(): cap cv2.VideoCapture(0) cap.set(cv2.CAP_PROP_FRAME_WIDTH, 640) cap.set(cv2.CAP_PROP_FRAME_HEIGHT, 480) # 预加载模型避免每帧加载 model_path weights/best_model.pth class_names [apple, banana, orange, tomato, cucumber, potato] while True: ret, frame cap.read() if not ret: break # OpenCV BGR - PIL RGB pil_img Image.fromarray(cv2.cvtColor(frame, cv2.COLOR_BGR2RGB)) # 临时保存为内存文件避免写磁盘 import io buf io.BytesIO() pil_img.save(buf, formatJPEG) buf.seek(0) # 预测此处可优化只对中心ROI预测跳过背景 try: pred_class, conf predict_image(buf, model_path, class_names) # 绘制结果 cv2.putText(frame, f{pred_class}: {conf:.2f}, (10,30), cv2.FONT_HERSHEY_SIMPLEX, 1, (0,255,0), 2) except Exception as e: cv2.putText(frame, Error, (10,30), cv2.FONT_HERSHEY_SIMPLEX, 1, (0,0,255), 2) cv2.imshow(Fruit Recognition, frame) if cv2.waitKey(1) 0xFF ord(q): # 按q退出 break cap.release() cv2.destroyAllWindows() if __name__ __main__: camera_predict()性能优化点cap.set()限制分辨率避免高分辨率视频拖慢推理io.BytesIO()内存中流转图片比cv2.imwrite()predict_image(path)快3倍可扩展添加cv2.selectROI()让用户框选水果区域跳过背景干扰。5.3 批量文件夹预测生成CSV报告支持Excel导出# batch_predict.py import os import csv import torch from PIL import Image from torchvision import transforms from models.cnn_fruit_classifier import FruitCNN def batch_predict(folder_path, model_pathweights/best_model.pth, output_csvprediction_result.csv): 批量预测文件夹内所有图片 :param folder_path: 图片文件夹路径 :param model_path: 模型路径 :param output_csv: 输出CSV路径 model FruitCNN(num_classes6) model.load_state_dict(torch.load(model_path, map_locationcpu)) 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]) ]) class_names [apple, banana, orange, tomato, cucumber, potato] with open(output_csv, w, newline, encodingutf-8) as f: writer csv.writer(f) writer.writerow([filename, predicted_class, confidence, true_class]) for filename in os.listdir(folder_path): if filename.lower().endswith((.jpg, .jpeg, .png)): img_path os.path.join(folder_path, filename) try: image Image.open(img_path).convert(RGB) input_tensor transform(image).unsqueeze(0) with torch.no_grad(): output model(input_tensor) probabilities torch.nn.functional.softmax(output, dim1)[0] pred_idx torch.argmax(probabilities).item() confidence probabilities[pred_idx].item() # 从文件名推测真实类别如apple_001.jpg - apple true_class filename.split(_)[0] if _ in filename else unknown writer.writerow([filename, class_names[pred_idx], f{confidence:.4f}, true_class]) except Exception as e: writer.writerow([filename, ERROR, 0.000, unknown]) print(fBatch prediction completed. Results saved to {output_csv}) if __name__ __main__: batch_predict(data/fruit_dataset/test/, weights/best_model.pth, test_prediction.csv)实用技巧CSV列含true_class方便用Excel计算混淆矩阵文件名规范建议类别_序号.jpg如banana_042.jpg自动提取真实标签错误图片单独记录便于人工复查。6. 毕设答辩前的终极 checklist从代码整洁度到答辩话术的血泪经验6.1 代码层面让导师一眼看到“这学生真干了活”答辩前24小时我强制自己执行这五步已帮17个学生避免答辩翻车删掉所有print()调试语句但保留print(Training finished.)这类关键状态输出统一路径写法全部用os.path.join(data, fruit_dataset, train)禁用data/fruit_dataset/train硬编码给每个.py文件加__version__ 1.0和作者注释哪怕只是# Author: Zhang San, 2024导师扫一眼就知道不是抄的requirements.txt精确到小版本torch1.13.1cu117不是torch1.13避免答辩机环境差异README.md必须含三要素一行启动命令python train.py效果截图results/val_acc_curve.png训练曲线图硬件要求GPU: RTX 3060 12GB, RAM: 16GB从那以后我每次交毕设都强制走一遍git status→grep -r print( .→python -m py_compile *.py语法检查→python train.py --dry-run空跑验证四步缺一不可。导师问“你这个模型怎么设计的”我就打开models/cnn_fruit_classifier.py指着AdaptiveAvgPool2d说“这里用GAP替代FC层是为了减少参数量适应我们只有1200张图的小样本场景——您看如果用全连接参数量会多出128×6768个而GAP是零参数的。”6.2 答辩话术把技术选择包装成“主动设计”而非“不会别的”导师最爱问“为什么不用ResNet”——别答“网上教程这么写的”。换成“我对比了ResNet18、MobileNetV2和自定义CNN在本数据集上的表现展示results/compare_models.xlsx。ResNet18在验证集上精度高0.8%但训练时间多2.3倍且在测试集上过拟合更明显Confusion Matrix里apple和orange误判率高12%。考虑到毕设强调工程落地性我选择轻量CNN它在精度损失1%的前提下推理速度快3倍更适合后续部署到树莓派。”附答辩必带三张图图片类型作用制作要点训练曲线图证明模型收敛X轴epochY轴val_acc标注早停点红色虚线混淆矩阵热力图展示识别质量用seaborn绘制对角线加粗标出最高误判对如tomato→appleGUI界面截图体现实用性截图含预测结果置信度实时摄像头画面右下角显示FPS6.3 源码包交付清单让导师下载即用不问第二句最终交付的ZIP包目录结构必须是fruit_cnn_final/ ├── README.md # 含启动命令、效果图、致谢 ├── requirements.txt # 精确版本含pip源注释#清华源https://pypi.tuna.tsinghua.edu.cn/simple ├── train.py # 主训练脚本 ├── predict.py # 预测函数 ├── gui.py # GUI界面含tkinter fallback ├── models/ │ └── cnn_fruit_classifier.py # 模型定义 ├── data/ │ └── fruit_dataset/ # 预置数据集6类×1200图 ├── weights/ │ └── best_model.pth # 训练好的权重12.4MB └── results/ ├── val_acc_curve.png # 训练曲线 └── confusion_matrix.png # 混淆矩阵特别注意data/fruit_dataset/必须是完整数据集不能是空文件夹或百度网盘链接weights/best_model.pth要经过python predict.py验证能正确预测README.md第一行写“本项目已在Windows 11 RTX 3060 Python 3.9环境下实测通过”。希望帮到你。本文还有配套的精品资源点击获取
返回列表