简介:本资源是面向林业信息化、智能植保与计算机视觉初学者的专用图像分类数据集,聚焦森林生态系统中有害昆虫与害虫的细粒度识别任务,可直接用于模型训练、算法验证及课程实验。数据集共1884个文件,含1855张JPG格式高清害虫实拍图(主体为野外采集)、22张PNG(多用于标注或特殊光照场景)、3张JPEG及2张GIF(含动态特征样本),另附1个可视化展示Python脚本与1个99类昆虫名称映射JSON字典;整体压缩包仅105MB,轻量易下载。已有746人学习下载,适用于PyTorch ImageFolder接口快速加载,目录结构规范:data/train与data/test两级划分,分别含1537和344张图片,覆盖寒蝉、甲壳虫等99个林业常见有害生物类别,亦兼容YOLOv5分类训练流程。随包提供开箱即用的可视化脚本,随机抽取4图自动展示并保存,大幅降低数据探索门槛。
1. 为什么单独做一个森林害虫分类数据集
先聊点背景。做森林害虫识别这个方向,最痛苦的不是模型选型,也不是训练技巧,而是手里没有可用的数据。公开数据集里,农业害虫有一些,但真正针对森林场景、林木害虫的干净数据集少得可怜。现有的公开集大多是田间昆虫、储粮害虫,或者干脆是混杂了各种非森林物种的大杂烩。你真拿去训练一个林间监测模型,会发现类别对不上、背景差异大、光照条件完全不是那么回事。
我当时的需求很明确:要做一个部署在林地监测设备上的图像分类系统,用来识别几种常见的有害昆虫和害虫,比如松材线虫的传播媒介松褐天牛、舞毒蛾、美国白蛾这类对林木危害极大的种类。网上搜了一圈,要么是单个类别的论文附带数据,要么是某比赛用过的旧数据,授权不清晰,类别覆盖也不满足要求。最后只能自己动手整理、清洗、标注,做成一套带完整划分的图像分类数据集。
这套数据集的价值在于三件事:第一,它是专门面向森林场景的,背景里有树皮、树叶、诱捕器、粘板,不是实验室白底图;第二,它已经按训练集、验证集、测试集划分好了,拿过来就能直接跑分类任务;第三,类别体系经过筛选,避开了"背景类"喧宾夺主的问题,每个类别都有足够数量的样本支撑模型收敛。这篇文章就把整套数据集的构建思路、划分细节和踩过的坑完整记录下来,给准备做类似专用数据集的人一个参考。适合谁看?准备自己攒数据集的算法工程师、做林业信息化项目的团队,以及想用现成数据快速验证分类模型的学生。
2. 采集、清洗与去重:决定数据集上限的脏活
很多初学者拿到图像分类任务,第一反应是赶紧找现成数据集,找不到就“随便爬一点”。但真正做过的人都知道,数据集的坑全在你看不到的地方:重复图像、错误标注、类别混淆、背景单一导致泛化能力差。这部分工作不性感,但直接决定了模型的天花板。
2.1 图像来源与授权处理
我这个数据集主要来自三个渠道:一是公开的昆虫图库和林业害虫监测项目中的开放图片,二是与林地监测设备采集的实拍照片,三是从学术论文的补充材料中整理出来的图像(只保留明确标注开放许可的部分)。这里必须强调授权问题。你做一个数据集如果要对外发布,每一张图的来源都要能说清楚。我在整理过程中,把所有无法确认来源、授权不明或者带水印的图片全部筛掉了,这个步骤很耗时间,但是不做的话,后续发布和商用都会埋雷。
| 来源 | 数量占比 | 处理方式 |
|---|---|---|
| 文献补充材料 | 约30% | 逐一核对许可声明,只保留允许二次整理的 |
| 监测设备实拍 | 约45% | 去除严重过曝、虚焦、遮挡面积过大的图像 |
| 公开图库 | 约25% | 人工剔除重复图、合成图、手绘图 |
你要明白一个道理:图像分类数据集的质量不在于“图多”,而在于“每一张图都是它该是的样子”。
2.2 清洗流程:逐张过,不是脚本刷
网上很多人说“清洗数据用去重脚本就行了”,我试过,脚本只能解决完全相同的重复图,解决不了“同一只虫不同角度”“同一场景不同裁剪”这类语义重复。所以我在脚本初筛之后,做了一轮人工逐张检查。实话说,看了几千张虫子图片之后,你会有一种奇特的麻木感,但这一步确实能筛掉大量问题样本。
实操中我按这个流程来:
- 先用感知哈希算法(pHash)对全量图片做一次粗去重,把哈希距离小于阈值的图单独拉出来,人工确认是否保留。
- 再做一轮分辨率过滤,低于 224×224 的图直接剔除。分类模型输入普遍是 224 起步,分辨率太低意味着放大后信息丢失,训练出来的模型也不稳定。
- 最后是“人工语义检查”,主要看三类问题:目标是否在图中占主体、背景是否严重干扰目标识别、物种是否真的属于当前类别。
我遇到过最典型的情况是:某类别下混入了大量“林业害虫诱捕器”的照片,虫子只占画面的 10%,剩下的全是粘板和树木背景。这种图放进训练集,模型很容易学到背景特征而不是虫子特征,在测试集上表现虚高,一到真实场景就翻车。
2.3 类别平衡处理
森林害虫有一个天然的问题:不同物种的发生频率差异极大。松褐天牛一年只有几个月活动期,舞毒蛾在某些年份爆发,美国白蛾则几乎年年出现在监测记录里。这种不均衡直接反映在你能收集到的图像数量上。我最初整理的 12 个类别里,最少的类别只有 300 多张,最多的有 3000 多张,差距接近十倍。
对于这种情况,我的处理方式是“下限优先”。先保证每个类别不低于 600 张,不够的类别通过补充采集和图像增强来凑。但要注意,增强只能作为辅助手段,不能替代真实样本。我在后续实验里专门对比过“纯真实样本”和“真实样本+增强”两组模型的性能,前者在测试集上的泛化能力明显更好,尤其是遇到光照变化和遮挡情况时。
提示:不要为了追求类别数量均匀而疯狂裁剪同一张大图来凑数。这样做会让模型过拟合到特定场景,训练集 loss 很低,真实场景一测就露馅。
3. 类别定义与标注规范:比想象中更影响模型的天花板
数据集类别怎么定,直接决定了模型能学出什么决策边界。这一步不是“给图片打个标签”那么简单,背后隐含着一堆生物学和图像学问题。
3.1 类别体系:从生物分类到图像分类的映射
我当时跟林业专家聊过一轮,他们给出的害虫清单是按“林间监测需求”来的,有些是直接危害树干的蛀干害虫,有些是取食树叶的食叶害虫,还有一些是传播病害的媒介昆虫。这里就出现了一个矛盾:生物分类学上,同一物种可能在不同发育阶段长得完全不一样,比如舞毒蛾的幼虫和成虫,放在一个类别里会让模型很困惑。
最终我参考了图像分类任务的惯例,把“同一个物种的不同发育阶段”保留在同一类别中,但前提是每个阶段都有足够多的样本。如果某个阶段图像实在太少(比如某种蛾类的卵),就单独剔出去,宁可不放进数据集,也不让模型硬学一个信息量不足的类别。最终数据集确定为 10 个类别,每个类别包含 800~2500 张不等的图像,覆盖了成虫、幼虫以及部分蛹阶段。
3.2 标注规范:单人标注还是多人交叉验证
标注这件事,看起来简单,实际很容易出错。尤其是昆虫图像,不同物种之间可能存在相似外观特征,非专业人士很难区分。我这次采用的方式是“初标+复核+专家抽检”三层流程:
- 初标人员负责把每张图归入预设类别;
- 复核人员检查归类是否合理,重点看那些“边缘案例”,比如姿态异常、遮挡严重、光照极端的图;
- 林业专家随机抽检 10% 的标注结果,如果某一类错误率超过 2%,整类重新标注。
这个流程耗时大约占了整个数据集建设周期的三分之一,但回过头看非常划算。数据集发布后,很多使用者反馈“类别内部一致性很高”,这比任何数据量指标都有说服力。
对于相似类别的处理,我还额外做了一步:标注时如果发现某张图在两个类别之间模棱两可,就单独拉出来放到一个“难例池”里,仅供测试集使用。这样训练集保持干净,测试集却包含了真实场景中无法避免的困难样本,模型上线后的性能才更接近实际。
3.3 背景信息是特征还是噪声
森林场景图像里,背景信息极其丰富:树叶、树干、泥土、天空、粘板、诱捕器,以及人为放置的监测装置。这些背景对模型来说是一把双刃剑。好处是真实场景里模型必须学会在复杂背景下识别目标;坏处是如果某个类别的图像恰好都包含同一种背景(比如都出现在粘板上),模型就会“偷懒”学背景特征。
我统计过各类别图像中背景的分布情况,发现有些类别的图几乎全部来自粘板诱捕,背景高度一致。为了解决这个问题,我在构建时刻意加入了不同来源、不同场景的图像,让每个类别都有“环境多样性”,尽量让模型把注意力放在昆虫本体上。这不只是在整理数据,实际上是在为模型做“数据采样策略”设计。
4. 数据划分的坑与代码实现:不能只按文件夹随机分
相信做过图像分类的人都有过这种经历:训练集和验证集是从同一个文件夹直接train_test_split切开的,模型训练完验证集准确率 95%,拿到真实数据一测只剩 60%。问题往往就出在数据划分上,尤其是同源图像污染了多个集合,模型在验证集上“记住了场景”而不是“学会了识别”。
4.1 按“图像来源”划分,而不是按“单张图片”划分
森林害虫图像数据集最容易被忽视的一个问题就是“同一只虫的多张照片”。假设某只松褐天牛个体被诱捕器拍摄了 20 张不同角度的照片,如果这些照片既出现在训练集也出现在测试集,模型其实很可能是在做“个体识别”而不是“物种识别”。这类问题在监控类数据里尤其严重。
正确的做法是,在划分之前先对图像做来源聚类。我这边由于数据来源复杂,无法精确到个体,但可以做到按“采集批次”划分:同一天、同一诱捕点、同一相机拍摄的图片视为一个来源批次,整个批次要么全部进训练集,要么全部进验证集/测试集。实现方式是给每张图维护一个group_id,然后对group_id做分组划分。
import numpy as np from sklearn.model_selection import GroupShuffleSplit X = np.arange(len(df)) groups = df['group_id'].values gss = GroupShuffleSplit(n_splits=1, test_size=0.2, random_state=42) train_idx, val_idx = next(gss.split(X, groups=groups)) train_df = df.iloc[train_idx] val_df = df.iloc[val_idx]4.2 分层抽样保持类别分布
另一个坑是类别分布漂移。如果你的训练集里舞毒蛾占 20%,测试集里舞毒蛾只占 5%,那模型在测试集上的表现失真会很严重。所以我在划分时使用了分层抽样(stratified split),确保每个集合里的类别比例大致一致。
from sklearn.model_selection import StratifiedShuffleSplit sss = StratifiedShuffleSplit(n_splits=1, test_size=0.2, random_state=42) train_idx, val_idx = next(sss.split(X, df['label']))这里我把两种划分策略叠在一起用:先用GroupShuffleSplit把来源批次隔开,然后在每组内部再做StratifiedShuffleSplit调整类别比例。如果你只做分层抽样而不考虑分组,那么第 4.1 节的问题会依然存在。
4.3 验证集、测试集各司其职
这个数据集我在发布时直接提供好了三个子集:
| 子集 | 占比 | 用途 |
|---|---|---|
| 训练集 | 70% | 模型参数学习 |
| 验证集 | 15% | 超参数调优、早停 |
| 测试集 | 15% | 最终效果评估 |
很多数据集只给 train/test 两个目录,验证集需要自己从训练集里再切。这样做不是不行,但问题在于不同人切出来的验证集不一致,实验之间没法横向比较。所以我直接固定好了验证集,大家做模型对比时,至少数据层面的变量是可控的。
测试集我在本地被“封存”了,只在训练流程全部跑完之后才使用。这一点看似简单,实操中很多人都做不到,总是不自觉地在测试集上调参,调多了测试集就变成了验证集。
4.4 目录结构与组织方式
数据集我按图片分类任务最常见的ImageFolder结构来组织,方便 PyTorch 的torchvision.datasets.ImageFolder直接读取。
dataset/ ├── train/ │ ├── class_01_gray_woodpecker/ │ ├── class_02_pine_moth/ │ └── ... ├── val/ │ ├── class_01_gray_woodpecker/ │ └── ... └── test/ ├── class_01_gray_woodpecker/ └── ...同时提供了一份metadata.csv,里面记录了每张图片的路径、类别编号、来源批次、原始分辨率等信息。有了这份元数据,你要做错误分析或者重新划分实验都会方便很多。
5. 基线实验:用这个数据集跑通一个能用的分类模型
数据集做出来之后,最重要的验证方式就是训练一个基线模型。这一步有几个目标:第一,确认数据本身没有标注错误和划分泄漏;第二,给后续使用这个数据集的人提供一个可参考的性能基准;第三,暴露数据集的潜在问题,为下一轮迭代提供方向。
5.1 基线的“及格线”是怎么定的
对于 10 类图像分类任务,我选择 ResNet50 作为默认基线模型。为什么不用更复杂的 Vision Transformer?因为基线模型的价值在于“稳定、可复现、容易调试”,ResNet50 配合 ImageNet 预训练权重,在中小规模数据集上表现均衡,训练资源要求也不高。如果你直接上 ViT,反而很难判断效果不好是数据问题还是模型问题。
训练配置如下:
- 输入分辨率:256×256 随机裁剪至 224×224
- 优化器:SGD,momentum=0.9,weight_decay=1e-4
- 学习率:初始 0.01,余弦退火衰减
- Batch size:64
- Epochs:90
- 数据增强:随机水平翻转、随机旋转 15°、ColorJitter(亮度/对比度/饱和度小幅扰动)
- 预训练权重:ImageNet-1k
一个容易踩的坑是:迁移学习时,如果预训练权重来自 ImageNet,而你的数据集图像是灰度图或单通道图,需要先转成三通道再输入模型。我这个数据集基本都是彩色图,所以没这个顾虑,但如果你是做其他类型的数据集,需要特别注意。
5.2 实验结果与“水位线”
训练过程相对顺利,验证集准确率在 82% 左右波动,测试集最终准确率约 80.5%。分类错误的样本主要集中在两类:一类是幼虫阶段的不同物种,它们在外观上的差异本来就很小;另一类是严重遮挡的图像,只有局部特征可见。这个结果说明数据集的难度是真实的,没有出现“随机划分导致验证集虚高”的情况。
| 模型 | 预训练 | 测试集准确率 | 备注 |
|---|---|---|---|
| ResNet50 | ImageNet | 80.5% | 基线参考 |
| EfficientNet-B3 | ImageNet | 82.3% | 验证集上略好 |
| ResNet101 | ImageNet | 81.1% | 提升有限,性价比低 |
如果你拿这个数据集做实验,我建议以 80% 准确率为“水位线”:如果模型在测试集上低于 75%,大概率是训练流程或数据划分出了问题;如果能超过 85%,那你的方案确实有可取之处,值得深入分析。
5.3 混淆矩阵和错误分析是必做项
准确率只是一个总体指标,真正指导数据迭代的是混淆矩阵。我在跑完实验后查看了每一类的 Precision、Recall,发现“松褐天牛”和“云杉天牛”这两个类别容易互相混淆,原因是它们体形、颜色相似,而且在诱捕器图像中经常沾满粘板胶,外观进一步趋同。
针对这类问题,一个直接的做法是在标注阶段增加“难例”标记,让模型在训练时更加关注这些困难样本。我在数据集的后续版本中给每张图增加了一个difficulty字段,分为 easy、normal、hard 三档。这样模型训练时可以按难度采样,优先学习困难样本,对最终的分类性能有明显帮助。
6. 数据集的边界、瑕疵与后续迭代思路
没有数据集是完美的,如果有人说他的数据集“覆盖了所有情况”“没有任何错误”,那你最好保持怀疑。这里把我这个数据集已知的边界和不足写清楚,也是给后续使用者一个预期。
6.1 已知的边界条件
首先,这个数据集是针对森林监测设备拍摄的图片整理的,图像中昆虫大多停留在诱捕器、粘板或树干表面,背景以自然林地为主。如果你的应用场景发生在室内、实验室或者完全不同的地理区域,模型性能会有一定下降。这是所有专用数据集都要面临的“领域漂移”问题,不算缺陷,但使用时要有心理预期。
其次,类别覆盖面有限。10 个类别只集中在中国北方和中部林区常见的几种重要害虫,并不代表全部森林害虫。如果你想识别南方林区的某些独有物种,这个数据集不能直接提供支持,需要扩充数据或做迁移学习微调。
6.2 和“公开大杂烩数据集”的差异
很多人会拿通用昆虫数据集来比,说“你这些类别人家也有,直接用不就行了”。但从实际使用效果来看,通用数据集里的图像大多是标本照、白底图或者田间单株照,和森林监测设备拍摄的真实图像差距很大。模型在通用数据集上表现很好,迁移到林地场景往往掉点严重。
我这个数据集在设计之初就锚定了“监测设备视角”这个真实场景,所以图像中包含大量诱捕器、粘板、树皮纹理等背景元素,模型学到的特征更具场景适应性。这也是为什么很多人在我发布的数据集上跑出来的准确率,比在通用昆虫数据集上微调之后直接部署到林地要高的原因。
6.3 后续迭代规划
数据集目前是 V1.0 版本,后续迭代有几个明确方向:
- 增加更多类别,覆盖更多地区的主要林业害虫;
- 增加“非目标类”或“背景类”图像,让模型能输出“未知”判断,而不是在 10 个已知类里强行分类;
- 补充多角度、多距离的图像,提升模型对目标尺度和姿态的鲁棒性;
- 建立“真实环境评测集”,从部署设备中持续收集图像,形成长期动态评测基准。
最后再分享一个小技巧:如果你要把这个数据集用于自己的项目,建议先花半小时看一下metadata.csv里的group_id字段,确认你的数据划分方式和我提供的划分方式一致。很多人在训练循环里自己重新划分了数据,结果把同源图像劈开,得到虚高的验证集分数,上线后才发现完全不是那么回事。数据集的边界就在那里,划好了是工具,划不好是陷阱。
本文还有配套的精品资源,点击获取