163种中草药数据集与源码:图像分类实战与避坑指南

发布时间:2026/10/14 4:35:50

163种中草药数据集与源码:图像分类实战与避坑指南 简介这份资源围绕Chinese-Medicine-163中草药图像数据集展开面向从事深度学习图像分类、中医药AI识别研究的开发者与高校学生帮助解决中草药识别任务中数据获取难、清洗成本高的问题。压缩包共3个文件以inscode工程配置、html说明页面和gitignore忽略规则为主整体约6KB属于轻量级说明与可运行源码包便于快速了解数据集结构与使用方式。数据集涵盖163种中药材、超过25万张图片训练集每类约1575张、测试集每类约61张来源于网络爬虫检索并经人工清洗整合质量较为可靠。目前已有251人浏览学习读者可据此获取数据集下载线索并参考配套的深度学习分类识别思路用于模型训练、算法验证与中草药自动化识别研究节省数据采集与预处理成本。1. 163种中草药数据集从图像分类到可运行源码的落地路径手里有一批中草药图像想跑分类模型却卡在数据整理这一步——这是很多做中医药信息化、植物识别或边缘端AI应用的开发者都遇到过的场景。163种中草药数据集配合可运行源码解决的正是从原始图像到模型训练之间的断层问题。它不是单纯的图片压缩包而是把类别标注、目录结构、训练脚本、推理入口打包成一条能跑通的链路。适合三类人一是做图像分类练手、需要真实多类别数据的学生和转行者二是做中药材识别App或小程序、需要快速验证模型效果的开发者三是做中医药数字化、想评估现有模型在细粒度分类上表现的研究人员。数据集覆盖163个类别属于中大规模细粒度分类任务比CIFAR-10这类通用数据集更贴近实际业务分布。2. 数据集结构与源码目录先看清文件再动手2.1 目录层级与类别映射关系拿到压缩包后别急着解压到桌面就开跑。常见做法是先看目录树确认图像是按类别分文件夹还是用CSV标注。中草药数据集通常采用ImageFolder兼容结构即每个类别一个子目录目录名就是类别标签。这种结构的好处是PyTorch的torchvision.datasets.ImageFolder可以直接读取不需要额外写解析逻辑。但要注意目录名是否包含中文、空格或特殊符号这些在跨平台时容易翻车。# 查看压缩包内目录结构不直接解压 unzip -l chinese_herbs_163.zip | head -40 # 解压到指定数据盘避免系统盘空间不足 unzip chinese_herbs_163.zip -d /data/herbs163/ # 统计每个类别的图像数量检查类别是否均衡 for d in /data/herbs163/train/*/; do echo $(basename $d): $(ls $d | wc -l) done | sort -t: -k2 -n | head -20上面三段命令分别做三件事第一段不解压只看清单确认文件数量和顶层目录第二段指定解压路径中草药图像数据集动辄几个GB放系统盘容易把根分区撑满第三段统计各类别样本数按数量排序后能快速发现长尾类别。如果发现某个类别只有十几张图而最多的有几百张训练时就需要考虑重采样或类别权重。2.2 源码入口与依赖版本可运行源码一般包含train.py、predict.py、dataset.py、requirements.txt这几个核心文件。先看requirements.txt里的版本约束这是最容易出问题的地方。常见做法是创建一个独立虚拟环境不要和系统Python混用。# dataset.py 中典型的数据增强与加载逻辑 import torch from torchvision import datasets, transforms from torch.utils.data import DataLoader, WeightedRandomSampler def build_dataloaders(data_dir, batch_size32, num_workers4): # 训练集增强随机裁剪、翻转、颜色抖动提升细粒度分类泛化 train_tf transforms.Compose([ transforms.RandomResizedCrop(224, scale(0.7, 1.0)), transforms.RandomHorizontalFlip(), transforms.ColorJitter(0.2, 0.2, 0.2), transforms.ToTensor(), transforms.Normalize([0.485, 0.456, 0.406], [0.229, 0.224, 0.225]) ]) # 验证集只做缩放和归一化保持评估一致性 val_tf transforms.Compose([ transforms.Resize(256), transforms.CenterCrop(224), transforms.ToTensor(), transforms.Normalize([0.485, 0.456, 0.406], [0.229, 0.224, 0.225]) ]) train_ds datasets.ImageFolder(f{data_dir}/train, transformtrain_tf) val_ds datasets.ImageFolder(f{data_dir}/val, transformval_tf) # 类别不均衡时用加权采样避免模型偏向多数类 targets [s[1] for s in train_ds.samples] class_count torch.bincount(torch.tensor(targets)) weights 1.0 / class_count[targets].float() sampler WeightedRandomSampler(weights, len(weights), replacementTrue) train_loader DataLoader(train_ds, batch_sizebatch_size, samplersampler, num_workersnum_workers) val_loader DataLoader(val_ds, batch_sizebatch_size, shuffleFalse, num_workersnum_workers) return train_loader, val_loader, train_ds.classes这段代码的关键参数有三个RandomResizedCrop的scale(0.7, 1.0)控制裁剪范围中草药图像主体通常居中裁剪太激进会切掉关键特征Normalize用的ImageNet均值方差如果从头训练可以改成数据集自身统计值但用预训练权重时保持一致WeightedRandomSampler的replacementTrue允许重复采样少数类缓解长尾问题。num_workers在Windows上建议设为0或2设太高容易在DataLoader处卡死。3. 训练与推理全流程从命令行到模型导出3.1 训练脚本参数与启动方式源码包里的train.py通常用argparse暴露超参数。不要直接python train.py就完事先看帮助信息确认默认值。# 查看可用参数 python train.py --help # 典型训练启动命令 python train.py \ --data-dir /data/herbs163 \ --model resnet50 \ --epochs 40 \ --batch-size 32 \ --lr 0.001 \ --pretrained \ --output-dir ./runs/herbs163_resnet50--pretrained表示加载ImageNet预训练权重163类中草药属于细粒度分类从头训练需要大量数据预训练能显著加快收敛。--lr 0.001配合Adam优化器是常见起点如果loss震荡明显就降到0.0005。--epochs 40不是固定值看验证集准确率曲线连续5个epoch不提升就可以停。输出目录建议按模型名和时间戳区分方便对比不同实验。3.2 推理与单张图像预测训练完成后predict.py负责加载权重并对单张图或整个文件夹做推理。这里容易踩的坑是预处理不一致——训练用了RandomResizedCrop推理必须用ResizeCenterCrop否则准确率会掉。# predict.py 核心推理逻辑 import torch from PIL import Image from torchvision import transforms def predict(image_path, model, class_names, devicecuda): model.eval() tf transforms.Compose([ transforms.Resize(256), transforms.CenterCrop(224), transforms.ToTensor(), transforms.Normalize([0.485, 0.456, 0.406], [0.229, 0.224, 0.225]) ]) img Image.open(image_path).convert(RGB) tensor tf(img).unsqueeze(0).to(device) with torch.no_grad(): logits model(tensor) probs torch.softmax(logits, dim1) top5 torch.topk(probs, 5) for score, idx in zip(top5.values[0], top5.indices[0]): print(f{class_names[idx]}: {score.item():.4f})model.eval()必须调用否则BatchNorm和Dropout会保持训练模式推理结果不稳定。torch.no_grad()关闭梯度计算减少显存占用。输出Top-5而不是Top-1是因为细粒度分类中有些中草药外观极其相似Top-5能给出候选供人工复核。3.3 模型导出与部署格式选择如果要把模型放到移动端或边缘设备需要导出为ONNX或TorchScript。ONNX通用性好TorchScript在PyTorch生态内更顺。# 导出ONNX python export_onnx.py \ --checkpoint ./runs/herbs163_resnet50/best.pth \ --output ./herbs163.onnx \ --opset 12 # 验证ONNX模型输出与PyTorch一致 python -c import onnxruntime as ort import numpy as np sess ort.InferenceSession(herbs163.onnx) dummy np.random.randn(1,3,224,224).astype(np.float32) out sess.run(None, {input: dummy}) print(ONNX output shape:, out[0].shape) --opset 12是兼容性较好的版本太低不支持某些算子太高部分推理引擎不认。导出后务必用ONNX Runtime跑一遍确认输出shape和数值范围与PyTorch一致这一步能提前发现算子不支持的问题。4. 避坑与排查数据、显存、精度三类翻车现场4.1 类别目录名含中文导致ImageFolder报错现象torchvision.datasets.ImageFolder读取时抛出FileNotFoundError或类别名为乱码。原因部分系统默认编码不是UTF-8中文目录名在Python读取时解码失败。解决训练前用脚本批量重命名目录为拼音或英文编号同时生成class_map.json保存映射关系。import os, json src /data/herbs163/train mapping {} for i, name in enumerate(sorted(os.listdir(src))): new_name fclass_{i:03d} mapping[new_name] name os.rename(os.path.join(src, name), os.path.join(src, new_name)) json.dump(mapping, open(class_map.json, w), ensure_asciiFalse, indent2)4.2 显存不足但batch size已经很小现象CUDA out of memory把batch size降到8仍然报错。原因num_workers过多导致每个worker都复制了一份数据到显存或者验证集没有用torch.no_grad()。解决先把num_workers设为2确认验证循环包在torch.no_grad()里再考虑用混合精度训练。from torch.cuda.amp import autocast, GradScaler scaler GradScaler() for imgs, labels in train_loader: imgs, labels imgs.cuda(), labels.cuda() with autocast(): loss criterion(model(imgs), labels) scaler.scale(loss).backward() scaler.step(optimizer) scaler.update() optimizer.zero_grad()混合精度能把显存占用降低约40%同时训练速度提升但要注意autocast只包裹前向传播反向和优化器更新由GradScaler处理。4.3 验证集准确率远高于测试集现象验证集准确率95%换一批新图测试只有60%。原因验证集和训练集来自同一批采集数据分布一致而实际测试图的光照、背景、拍摄角度不同。解决从原始数据中划出一部分做“跨域验证集”模拟真实场景或者用更强的数据增强随机背景替换、亮度对比度大幅扰动提升泛化。4.4 预训练权重加载时类别数不匹配现象--pretrained加载后报size mismatch for fc.weight。原因ImageNet是1000类中草药是163类最后一层全连接维度不同。解决加载时过滤掉最后一层只加载特征提取部分。state torch.load(resnet50_imagenet.pth) model_state model.state_dict() # 过滤掉分类层参数 filtered {k: v for k, v in state.items() if k in model_state and v.shape model_state[k].shape} model.load_state_dict(filtered, strictFalse)strictFalse允许部分参数不匹配但加载后要打印哪些层被跳过确认只是分类层。4.5 推理速度慢但GPU利用率低现象单张推理耗时超过500msnvidia-smi显示GPU利用率不到20%。原因数据预处理在CPU上串行执行成为瓶颈。解决把预处理放到GPU上做或者用DALI加速。# 将归一化放到GPU上减少CPU-GPU数据传输 mean torch.tensor([0.485, 0.456, 0.406]).cuda().view(1,3,1,1) std torch.tensor([0.229, 0.224, 0.225]).cuda().view(1,3,1,1) tensor tensor.cuda() tensor (tensor - mean) / std5. 进阶技巧用混淆矩阵定位易混类别并做定向优化跑通训练只是第一步真正让模型可用的是知道它在哪里出错。163类中草药里同科同属的植物外观差异极小比如某些伞形科药材人眼都难分。我一般会在验证集上生成混淆矩阵找出Top-10混淆对然后针对性处理。import numpy as np import matplotlib.pyplot as plt from sklearn.metrics import confusion_matrix, ConfusionMatrixDisplay def plot_confusion(model, val_loader, class_names, devicecuda): model.eval() all_preds, all_labels [], [] with torch.no_grad(): for imgs, labels in val_loader: preds model(imgs.to(device)).argmax(1).cpu().numpy() all_preds.extend(preds) all_labels.extend(labels.numpy()) cm confusion_matrix(all_labels, all_preds) # 只显示混淆最多的前20类避免163x163矩阵看不清 top_idx np.argsort(cm.sum(1))[-20:] disp ConfusionMatrixDisplay(cm[np.ix_(top_idx, top_idx)], display_labels[class_names[i] for i in top_idx]) disp.plot(xticks_rotation90, cmapBlues) plt.tight_layout() plt.savefig(confusion_top20.png, dpi150) # 输出混淆对 for i in top_idx: for j in top_idx: if i ! j and cm[i, j] 5: print(f{class_names[i]} - {class_names[j]}: {cm[i,j]}次)拿到混淆对之后三种处理方式按成本从低到高一是对混淆类别做额外数据增强比如随机旋转角度加大、加入高斯噪声二是用Focal Loss替代CrossEntropy让模型关注难分样本三是收集更多混淆类别的图像补充训练。我一般先跑混淆矩阵再决定要不要动损失函数因为改损失函数需要重新调参成本比加数据增强高。还有一个实用技巧是测试时增强TTA对同一张图做多次不同裁剪和翻转取平均概率。TTA能把准确率提升1到3个百分点代价是推理时间翻倍。如果部署环境算力允许值得加上。def predict_tta(image_path, model, class_names, n_aug5): model.eval() tf_list [ transforms.Compose([transforms.Resize(256), transforms.CenterCrop(224), transforms.ToTensor(), transforms.Normalize(mean, std)]), transforms.Compose([transforms.Resize(256), transforms.CenterCrop(224), transforms.RandomHorizontalFlip(p1.0), transforms.ToTensor(), transforms.Normalize(mean, std)]), transforms.Compose([transforms.Resize(256), transforms.CenterCrop(200), transforms.Resize(224), transforms.ToTensor(), transforms.Normalize(mean, std)]), ] img Image.open(image_path).convert(RGB) probs torch.zeros(1, len(class_names)).cuda() with torch.no_grad(): for tf in tf_list: tensor tf(img).unsqueeze(0).cuda() probs torch.softmax(model(tensor), dim1) probs / len(tf_list) return probs.argmax(1).item(), probs.max().item()从那以后我每次拿到新的细粒度分类数据集都强制先跑一遍类别分布统计和混淆矩阵再决定用不用预训练、要不要加权采样。这两个动作花不了半小时但能省掉后面反复调参的后悔药。希望帮到你。本文还有配套的精品资源点击获取
延伸阅读

更多相关文章

2026/10/14 4:35:50

逻辑回归实战:芯片质量预测的建模与落地

先说个实际场景:某条封装产线上,一批芯片做完老化测试,数据汇总到质量工程师手里,他要判断哪些芯片能出货、哪些要报废。以往靠人工定阈值,漏判和误判都时有发生,尤其是那些“边缘”芯片,参数忽…

2026/10/14 4:35:50

Unity运行时加载3D模型:TriLib插件实战与性能优化指南

简介:这份源码工程面向Unity开发者与AR/VR、游戏工具链方向的技术人员,解决运行时动态导入并预览3D模型的实际需求。工程基于TriLib 2.3.7插件,在Unity 2021.3.27与Standard Render Pipeline下实现选择模型、加载模型、场景预览的完整流程&am…

2026/10/14 8:01:24

MBA文书怎么降AI率?十款工具实测避坑指南

1. 为什么MBA圈突然都在聊"降AI率"过去一年里,我身边陆续有朋友开始准备MBA申请,本来大家讨论最多的还是选校、GMAT和推荐信。但最近几个月,话题突然变了——几乎每个人都会问一句"你的文书用AI写了吗?如果用了&am…

2026/10/14 8:01:24

NSGA-II算法在翼型多目标优化中的工程实践

1. 项目概述这个项目让我想起了十年前第一次接触气动优化的场景。当时为了优化一个小型无人机的机翼,我整整花了三个月时间反复调整参数。如今,基于NSGA-II(非主导排序遗传算法)的翼型优化已经成为工程实践中的标准方法之一&#…

2026/10/14 8:01:24

grep上下文模式详解:从-C参数到AI辅助排障的完整指南

你有没有遇到过这种情况:grep定位到一个报错关键词,但只看到孤零零的一行,前后发生了什么一概不知——报错是在什么请求里出现的?处理到第几步挂的?前面的日志里有没有前兆?你想再往上翻几十行,…

2026/10/14 8:01:24

伪代码全解析:从算法设计到代码实现的思维桥梁

1. 伪代码到底是什么:先抛开语言,谈思维干了这么多年开发,我经常在技术方案评审、算法设计、甚至给新人讲业务逻辑的时候,反复使用一种“不算代码的代码”。它不依赖任何一门具体编程语言,也不需要能跑起来&#xff0c…

2026/10/14 8:01:24

Spring Boot棋牌室茶室管理系统:计时计费与订单全流程设计

1. 项目拆解:棋牌室茶室管理系统到底做了什么很多同学看到“棋牌室茶室管理系统”这个题目,第一反应就是“又是增删改查”,这话对了一半。管理系统底子确实都是数据操作,但棋牌室茶室这种业态有个特别之处——它有“时间维度”的计…

2026/10/13 5:19:27

Python调用Gemini Structured Outputs实现工单路由门禁

客服工单最怕的不是模型“答错一句话”,而是它给出一段看起来合理的说明,程序却从中猜错优先级。通俗做法是:要求模型只交 JSON(JavaScript Object Notation,轻量数据格式),再让代码验证它。Gem…

2026/10/13 17:09:18

Spring Boot超市进销存系统毕设实战:从需求拆解到答辩通关

最近带的一个学生项目组里,有A同学跑来问我:选什么毕设题目最稳妥,既能让评审老师觉得工作量够,又不会在答辩时被问到语无伦次。我第一反应就是推荐基于Spring Boot的超市仓库管理系统——也就是超市进销存系统。这个题目乍一看平…

2026/10/14 2:32:55

Flutter StatefulWidget 生命周期核心解析

很多刚开始接触 Flutter 的朋友,在看完一堆“Hello World”和基础组件之后,大概率都会撞上同一堵墙:StatefulWidget 里那堆 initState、build、dispose 方法,到底什么时候被调用?为什么顺序是那样?在里面到…

2026/10/14 0:00:33

DFS算法解决飞机降落调度问题实战

1. 项目背景与核心思路飞机降落问题是一个经典的调度优化场景,也是算法竞赛和面试中的高频题目。这个题目要求我们合理安排多架飞机的降落顺序和时间,确保所有飞机都能安全着陆而不发生冲突。在实际航空管制中,这类问题直接关系到飞行安全和机…

2026/10/14 0:00:33

macOS/iOS高精度计时:mach_absolute_time原理与实战

1. 项目概述:为什么mach_absolute_time是 macOS/iOS 时间测量的“黄金标准”在 macOS 和 iOS 开发中,我见过太多人用CFAbsoluteTimeGetCurrent()或NSDate.timeIntervalSinceReferenceDate做性能打点,结果在高精度场景下被系统时钟跳变、NTP 同…

2026/10/14 0:00:33

SCORM课件演示与测试全解析:从API通信到自动化验证

简介:这是一套遵循SCORM标准的交互式课件演示与测试资源,面向E-Learning课程开发者、LMS平台测试人员及在线教学从业者,用于验证课件在不同学习管理系统中的识别、传递与跟踪能力。压缩包共28个文件,约12.07MB,以swf动…

还想了解更多?直接咨询顾问

免费诊断 + 免费方案 + 透明报价。

全国咨询热线400-8866-253
免费获取方案
☎咨询二维码 ☎ ↑