简介:本资源是一套面向计算机视觉初学者与YOLO系列模型实践者的罐装饮料目标检测数据集,聚焦超市货架、自动售货机等场景下的常见饮品识别任务,可支撑模型训练、算法验证与课程实验。压缩包共2000个文件,含321张高质量JPG图像(涵盖东鹏特饮、红牛、可乐、雪碧、芬达、养乐多、王老吉、AD钙奶及伊利、蒙牛等乳饮品牌)、1678个YOLOv11格式标注TXT文件(每图对应唯一标签,类别坐标规范),以及1个整合全部类别的data.yaml配置文件,总大小45.95MB,结构简洁、开箱即用。目前已有923人学习下载,适合快速构建饮料品类识别baseline、开展小样本迁移训练或拓展多类别工业质检应用。 做这个罐装饮料识别项目的初衷,其实挺生活化的。起因是有朋友在做一个智能零售柜相关的小产品,想通过摄像头自动识别货柜里还剩哪些饮料、哪些已经售罄,免去人工补货巡检的成本。所以当时就攒了这么一套数据集:一千多张从不同角度、不同光照条件下拍摄的常见包装商品图片,标注了薯片、东鹏特饮、红牛、芬达、养乐多、可乐、雪碧这七个类别,并且整套数据都按YOLOv11的标准格式整理成了txt标注文件,打包成一个zip方便分发和复用。这篇文章就把这套数据集从标注到训练再到推理部署的完整链路拆开讲一遍,包括过程中踩过的坑、调参的心得,以及zip文件处理、环境配置这些看起来很基础但实际很容易卡住的细节。
如果你也想用YOLOv11训练一个自己的商品识别或者物体检测模型,这篇文章应该能帮你省下不少摸索的时间,尤其是数据集这边怎么做才不容易坑到模型、训练时怎么判断模型是真的学好了,以及推理结果怎么正确保存,这些都是能直接照着操作的内容。
1. 项目整体设计与思路拆解
1.1 需求定位:不是科研项目,是能用就行的东西
这个项目的核心场景是货柜商品识别,所以目标非常明确:用摄像头对准货架层板拍摄,模型要能在画面中直接把每一件商品框出来,并告诉上层系统“这是红牛”“这是可乐”。相比学术性质的竞赛任务,这个场景有几个显著特点。
第一,类别数量少但混淆度高。七个类别里,可乐和雪碧是深色与浅色的关系,芬达是橙色的,东鹏特饮和红牛都是金黄色的罐体,形状高度接近。模型如果只学“颜色”和“形状”的粗特征,很容易把红牛和东鹏搞混。第二,推理设备大概率不是顶级GPU,可能是ARM架构的边缘盒子,所以模型不能太大,推理速度要快。第三,识别结果是要驱动业务动作的(比如补货提示、结算扣款),漏检的代价比误检更高,所以训练时要在召回率上稍微多留一点余量。
基于这三点,我选了YOLOv11n作为主力模型。n是nano版本,模型权重只有几兆,在CPU上也能跑到几十毫秒一帧,放在边缘设备上完全够用。而且YOLOv11的ultralytics框架对数据格式的兼容性做得很好,不管是标注文件、数据集结构还是训练脚本,几乎都是“约定优于配置”,对快速迭代非常友好。
1.2 为什么用txt标注而不是直接用标注工具的格式
很多刚入门的人会用LabelImg的XML格式,或者用Labelme的JSON格式,然后再写脚本转成YOLO格式。我的建议是:既然决定用YOLOv11训练,标注时就直接产出txt格式,一步到位,不要中间转换。
YOLO格式的标注文件是每个图片对应一个同名txt文件,每一行代表一个目标,格式是:
class_id center_x center_y width height注意这里的四个坐标值全部是归一化到0到1的小数,不是像素坐标。归一化的好处是不管你输入图片是1920×1080还是640×480,模型都能一视同仁地学习目标的位置关系。标注工具的坐标转换是自动完成的,比如LabelImg如果是YOLO模式,保存出来的就是txt,不需要自己换算。
这个数据集打包的时候,目录结构是这样的:
dataset/ ├── images/ │ ├── train/ # 约850张 │ └── val/ # 约200张 ├── labels/ │ ├── train/ # 与images/train同名对应的txt │ └── val/ # 与images/val同名对应的txt └── data.yaml # 类别定义和路径配置images和labels必须是严格同名的,后缀不同,这一点在整理数据时特别容易出错。YOLO框架会按同名规则去匹配图片和标签,如果图片叫IMG_001.jpg,那标签就一定要叫IMG_001.txt,多一个空格都不行。
2. 数据集的构建与标注实操
2.1 收集一千多张图片:质量比数量重要
同类的数据集收集方式,常见的有两种:一种是找现成的开源数据集去筛,另一种是自己拍。我们这个项目两种都用了,前期从开源数据集和网络渠道收集了一部分,后期又用手机和测试摄像头补拍了几百张,最终筛到一千多张高质量图片。
我强调“高质量”,是因为很多公开数据集里的图片存在几个问题:商品在画面里太小、被遮挡、光照极暗、或者一瓶饮料占据了大半个画面导致目标框太大。这些图片训练进去,不仅不会提升泛化能力,反而会拉低模型对尺度的鲁棒性。所以我的筛选标准是:
- 目标在画面中占比适中,最大不超过60%,最小不低于15%。
- 每个类别至少要有100张以上图片,且尽量覆盖多角度、多距离。
- 画面不过曝、不欠曝,无严重运动模糊。
- 同类商品尽量有不同摆放方向、不同数量组合。
最后我统计了一下,红牛和东鹏特饮这类常见饮料数量最多,每类大概180张;养乐多因为体型小,数量少一些,但也在130张左右。这个数据量对于YOLOv11的预训练权重微调来说,是完全够用的。重点不是你有一千张还是两千张,而是每个类别有没有覆盖到模型在真实场景里会遇到的各种变化。
2.2 标注的细节:框怎么画决定了模型怎么学
标注这件事看起来简单,一个框拖过去就完事,但实际操作中很有讲究。第一步,先在LabelImg里把图片打开,选择YOLO模式,然后按类别列表从0开始编号:0代表薯片、1代表东鹏特饮、2代表红牛、3代表芬达、4代表养乐多、5代表可乐、6代表雪碧。
框怎么画,我总结了几条经验:
- 贴合物体边缘,但不要卯着物体的外轮廓画。对于罐装饮料,我的做法是四边留出大概2到3个像素的余量,完全贴着边缘的话,训练时随机裁剪增强容易把边上的特征切掉。
- 透明包装商品要覆盖包含内容物的部分。东鹏特饮有大瓶装和小罐装,大瓶是透明塑料材质,标签只覆盖瓶身一部分。框应该包含整个瓶身,包括没贴标签但能看出液体的部分,而不是只框标签。
- 遮挡目标的处理。货柜里商品经常相互遮挡,我处理的原则是:如果遮挡面积小于30%,直接按可见部分画框;如果遮挡超过30%但还能明确判断类别,也画框;如果只露出一个角,实在看不出是什么,直接跳过不标。
- 同一类商品颜色差异大时,不要拆成多个类别。比如薯片有红色包装、绿色包装、蓝色包装,但商业需求上只关心“薯片”这个品类,那就统一归为一个类。拆太细会让类别间特征边界模糊,模型反而不容易收敛。
标注完以后,一定要检查类别id有没有标错。一个特别容易犯的错是:改掉了classes.txt里的顺序,但之前标过的txt文件里的id没改,导致类别错位。我自己踩过一次,红牛和东鹏的标签全反了,训练出来的模型把两个金罐子完全搞混。排查方法是写个小脚本扫描所有txt文件,统计每个类别id出现的次数,和图片内容做抽样比对,一旦发现某个id的数量异常多或异常少,就重点检查。
2.3 数据划分与增强:只做必要的增强
数据划分上,我用了8:2的train/val比例,没有单独留test。原因很简单:总共一千多张图,再拆出test的话,训练和验证的数据量都太紧张了。而且验证集本身就是从训练分布里分出来的,只要保证训练和验证之间没有完全相同的图片(尤其防止一张图同时出现在两个集合里),用val指标来做选模和调参就够了。
数据增强要克制。YOLOv11默认开启的mosaic增强、随机翻转、HSV扰动、平移缩放等,对这个项目基本够用。我自己额外做的一件事是:针对养乐多这种小目标,在训练时把imgsz设成了800而不是默认的640。这相当于把图片缩放得更细,让原本只有几十个像素高的小瓶子在特征图上占有更多像素点,小目标的召回率会有肉眼可见的提升。代价是训练和推理速度都会慢一些,但如果你的应用场景里小目标确实存在,这个取舍是值得的。
这里还要提一个很多人忽略的点:不要在训练前手动做大量离线数据增强(比如先把每张图翻转、裁剪、调亮度各生成一张)。YOLO训练时的在线增强是随机的,每轮epoch看到的增强结果都不一样,手动离线增强只会让数据量看起来变大,实际上模型很快就把重复的增强模式背下来了,对泛化几乎没帮助,还极大增加了训练时间。
3. YOLOv11训练全流程:环境、配置与训练实现
3.1 Anaconda环境配置与ultralytics安装
YOLOv11的训练代码是基于ultralytics这个框架的,安装方式很简单,在Anaconda的虚拟环境里执行:
conda create -n yolo python=3.10 -y conda activate yolo pip install ultralytics这里特别说明一下python版本。ultralytics框架对Python 3.8到3.12都有支持,但实测中3.10最稳,3.12在某些依赖库上还偶尔有兼容问题。如果你的机器有NVIDIA显卡,建议接着装GPU版PyTorch:
pip install torch torchvision --index-url https://download.pytorch.org/whl/cu121如果不用GPU,CPU也能跑,只是训练速度会慢很多。用CPU训练一千多张图、50个epoch,可能要跑十几个小时;而一块中端显卡(比如RTX 3060级别)大概只需要一两个小时。我个人建议,前期调试阶段就算没显卡也不要紧,先用几百张图跑几个epoch验证流程通不通,再去租带GPU的实例跑完整训练。我一贯的做法是:先在CPU上跑通代码,再上GPU,这样排错的时候不会把环境问题和代码问题混在一起。
环境配置好以后,可以跑一下版本验证:
import ultralytics ultralytics.checks()这个命令会帮你检查依赖是否齐全、GPU是否可用、torch和CUDA的匹配情况。如果输出里没有异常,说明基础环境已经就绪。
3.2 数据集配置与训练参数调优
在训练之前,需要准备一个data.yaml文件,内容如下:
path: /path/to/dataset train: images/train val: images/val names: 0: chips 1: dongpeng 2: redbull 3: fanta 4: yakult 5: cola 6: spritepath是数据集根目录的绝对路径也可以是相对路径,train和val是相对于path的图片文件夹路径。names字典里的key必须是从0开始的连续整数,不能跳号,否则训练时会直接报错。
然后是训练命令,我最终采用的组合是:
yolo train data=data.yaml model=yolo11n.pt epochs=80 imgsz=800 batch=16几个核心参数的选择逻辑:
- model=yolo11n.pt代表从官方预训练权重yolo11n.pt开始微调,而不是从头训练。COCO数据集上预训练过的模型已经学会了通用的边缘、纹理、颜色组合等低级特征,迁移到饮料识别这个小任务上,只需要在高层特征上做调整,收敛速度快且不容易过拟合。
- epochs设80是因为这个数据集不算大,训练到50轮左右val-loss就已经基本平了,再多训练容易过拟合。我会在训练结束后再看一次训练曲线,如果最后的val-loss还在明显下降,才会加10到20轮。
- batch=16取决于显卡显存。如果显存不够,优先降低batch而不是降低imgsz,因为imgsz对小目标的影响更大。batch过小时,BN层的统计量不稳定,训练容易震荡。
另外还需要明确一个通用观点:训练时不要一上来就用大模型。YOLOv11n是nano版本,参数量最小,先跑通全流程验证数据没问题,再换s、m版本看指标是否有提升。很多初学者一上来就用yolo11x,结果数据量撑不起大模型的参数量,训练完的效果反而不如nano版本。
3.3 训练过程监控与常见误判
训练启动后,ultralytics会打印每个epoch的详细信息,包括box_loss、cls_loss、dfl_loss、precision、recall、mAP50、mAP50-95这些指标。这里面重点看两个:mAP50和mAP50-95。mAP50衡量的是预测框和真实框的IoU超过0.5时算对的概率,这个指标对业务场景更友好;mAP50-95则更严格,IoU从0.5到0.95每隔0.05算一次再取平均,学术研究上更看重。
如果训练结束后mAP50在0.9以上,mAP50-95在0.7左右,对于这个七个类别的商品识别任务来说,已经是能用的水平了。但如果出现mAP50很高但mAP50-95很低的组合,说明模型定位精度不够,框的位置和大小不够准。这种情况一般是因为标注框本身画得粗糙,或者imgsz太小,建议检查标注质量,并把imgsz调大一些。
另外要注意区分“loss很小”和“模型很好”。有时候loss一直在降,但不能只看训练集的loss,因为过拟合时训练loss也会降,而val-loss反升。我的做法是训练跑完后先生成混淆矩阵:
from ultralytics import YOLO model = YOLO('runs/detect/train/weights/best.pt') model.val(data='data.yaml', plots=True)这一步会在runs/detect/train目录下生成混淆矩阵图和各类别的PR曲线。重点看红牛和东鹏这两个容易混淆的类,如果混淆矩阵里这两个类互相预测的错误率超过5%,就需要考虑加数据或者调整训练策略。
4. 推理部署、结果保存与zip文件处理
4.1 预测命令与结果保存
模型训练完成后,推理就简单了。ultralytics的predict命令可以直接对图片、视频、摄像头甚至是文件夹里的所有图片进行推理:
yolo predict model=runs/detect/train/weights/best.pt source=./test_images save=True关键参数save=True,这决定了推理结果图是否保存到本地。默认情况下,保存路径会在runs/detect/predict目录下,每次运行会生成新的predict2、predict3文件夹,不会覆盖上一次的结果。
如果是在代码里推理并保存,更灵活的方式是:
from ultralytics import YOLO model = YOLO('runs/detect/train/weights/best.pt') results = model.predict(source='./test_images', imgsz=800, conf=0.35, save=True, name='inference_result', show_labels=True)这里conf=0.35是置信度阈值。默认值0.25在背景相对干净的测试图上没问题,但在真实货柜场景里容易把一些饮料瓶上的图案误检成目标,所以我在实际部署时把阈值提到了0.35到0.4之间,漏检率上升了一点点,但误检率大幅下降。对于零售场景,把一个不存在的商品识别出来,比漏掉一个商品更让客户恼火,所以阈值取高一些更合适。
推理结果保存后,如果只是想看图片有没有识别出来,打开save出来的jpg即可;如果你要的是带坐标的结构化结果,用results[0].boxes.data可以得到一个N×6的tensor,每一行是[x1, y1, x2, y2, conf, class_id],方便后续对接业务逻辑。
4.2 Linux下解压zip文件的完整命令
整理数据集时,我习惯把最终版的标注文件和图片打包成zip,方便传给其他人或者在不同机器上同步。但zip文件在不同系统之间传递时经常出现各种问题,这里把Linux下的常用解压命令整理一下:
# 基础解压 unzip dataset_v1.zip # 解压到指定目录 unzip dataset_v1.zip -d /data/ # 查看压缩包里有什么而不解压 unzip -l dataset_v1.zip # 压缩包有中文文件名时,保留编码格式 unzip -O GBK dataset_v1.zip # 创建zip压缩文件 zip -r dataset_v1.zip dataset/ # 指定压缩级别,0不压缩,9最高压缩 zip -r -9 dataset_v1.zip dataset/其中unzip -O GBK这个参数非常实用,Windows上用中文名压缩的文件在Linux下解压经常出现乱码,指定GBK编码能解决大部分问题。另外,如果压缩包特别大,可以先列出文件列表确认结构,再决定要不要全部解压,避免一解压出来把当前目录撑爆。
4.3 常见zip问题全解:报错、损坏与加密
数据集zip在传递过程中最容易遇到的报错,按照我实际遇到的经验依次说下。
第一个是“file is not a zip file”。这个报错出现的原因可能有这么几个:一是下载不完整,文件只有几十KB但压缩包本身有几GB,基本都是下载中断导致;二是文件后缀被篡改,比如实际是个rar或者7z文件,但扩展名改成了zip;三是文件本身在传输过程中损坏。排查方法,先用file命令看真实文件类型:
file dataset_v1.zip如果输出显示是Zip archive data,那说明文件类型没问题;如果输出是数据或者gzip压缩数据,那就要检查下载源。
第二个是“invalid zip archive: could not find eocd”。EOCD是zip压缩包末尾的一个结束记录结构,如果找不到它,说明压缩包不完整或者被截断。这个报错在Windows、Linux下都常见,处理思路是重新下载,或者用修复工具尝试恢复。Linux下可以用zip -FF进行修复:
zip -FF dataset_v1.zip --out dataset_v1_fixed.zip这个命令用的是zip规范中的修复逻辑,会把损坏压缩包中还能读取的文件提取出来重新打包。实测能救回一部分覆盖了连续文件块的数据,但完全无法救回被截断的尾部文件。
第三个是zip密码相关问题。我这里想说的是:如果你给数据集压缩包加了密码,请一定用7-Zip的AES-256加密,不要用古老的ZipCrypto算法。后者安全性很低,极易被破解,而前者在暴力破解面前要稳健得多。另外,密码保护是双刃剑,如果密码忘了,基本没有官方途径恢复。所以我给数据集包加密前都会额外存一份密码到密码管理器里,而不是只记在脑子里或者聊天记录里。
第四个是分卷压缩的z01文件。有的超大压缩包会拆分成多个文件,比如dataset.z01、dataset.z02、dataset.zip。这时候必须把所有分卷放在同一个目录下,并且文件名保持完整,再用unzip命令或者7-Zip打开.zip主文件,它会自动读取分卷。如果提示找不到分卷,多半是因为文件名被改名或者放错目录了。
5. 训练过程遇到的坑与排查技巧
5.1 标注错位与类别混淆的排查
训练到中期的时候,我发现mAP50始终在0.8附近徘徊,怎么也上不去。后来仔细看混淆矩阵,发现红牛和东鹏的互相误检率高达12%,明显不正常。排查过程分为三步:第一步,随机抽了20张红牛的图片和20张东鹏的图片,人工检查标注框是否贴合、类别是否正确,发现标注本身没问题。第二步,检查训练时的数据增强,发现mosaic增强把不同类别的图片拼接在一起,偶尔会产生标注框交叉的情况,但这种情况在YOLO标准训练中是常见的,不应该导致这么高的混淆。第三步,统计了两个类别的图片环境,发现红牛的图片大多是白色背景的货架层板,而东鹏的图片很多是深色背景,模型很可能学的是背景而不是瓶子本身。
这就引出一个重要的数据策略:每个类别的图片要尽量覆盖多种背景。如果某类图片都只出现在一种环境中,模型会把背景特征与类别特征绑定。我后来专门补充了一批红牛在东鹏相同深色场景下、东鹏在红牛浅色场景下的图片,重新训练后混淆率降到了4%以下。
5.2 训练集和验证集数据泄露
一个更加隐蔽的问题:数据泄露。因为部分图片是从开源数据集收集的,我最初在处理时没有严格删除重复图片。有些图片可能在另一个数据集里被翻转或者稍微裁剪过,导致验证集里出现了跟训练集中的图片高度相似的版本。这会让val指标虚高,看似mAP50-95有0.8,实际换到真实环境中只剩0.65。
解决办法是写一个基于感知哈希的去重脚本,把所有图片计算pHash值,再比较汉明距离,距离小于阈值就把重复图片标记出来。处理后我发现大约有30多张图片是重复或近似重复的,从验证集中移除后,指标回归到了正常范围。这个过程花的时间不长,但价值极大,让我对模型的真实能力有了准确的判断。
5.3 推理阶段置信度阈值的选择
模型训练好了,推理部署时阈值设置是一个值得细调的环节。YOLO模型的默认conf阈值是0.25,但这个值在高精度要求的业务场景下偏保守。我在测试集上跑了一遍不同阈值的准确率和召回率,记录如下:
| 置信度阈值 | 精确率 | 召回率 | 适用场景 |
|---|---|---|---|
| 0.25 | 92.3% | 96.1% | 需要尽量框出所有商品,允许少量误检 |
| 0.35 | 95.7% | 94.0% | 零售控损,减少误检优先 |
| 0.50 | 97.8% | 88.2% | 只需识别高度确定的商品 |
最终我选了0.35作为默认值。对于那些本身就容易被混淆的类别,比如红牛和东鹏,我还会在业务层再加一道逻辑:如果一个框中同时出现了两个类别的置信度都超过阈值,就取置信度更高的那个,同时记录一条待人工复核日志。这个后处理逻辑成本极低,但能显著降低系统性的误检影响。
6. 从YOLOv11模型到实际落地:额外建议
6.1 模型导出与部署形态选择
训练完成之后,如果需要部署到边缘设备,建议把模型导出为ONNX或者TensorRT格式。ultralytics框架里一条命令就能完成:
yolo export model=runs/detect/train/weights/best.pt format=onnx imgsz=800 yolo export model=runs/detect/train/weights/best.pt format=engine device=0ONNX的好处是跨平台,几乎所有推理框架(OpenVINO、ONNX Runtime、TFLite)都能加载;TensorRT则是NVIDIA GPU上的性能最优解。对于CPU或者ARM设备,通常导出为ONNX后用ONNX Runtime推理即可,不用刻意追求TensorRT。
导出时有一个细节:如果你的训练是用imgsz=800完成的,导出时imgsz最好跟训练时保持一致。因为模型对输入尺寸是有一定依赖的,虽然理论上可以调整,但一旦resize到和训练不一致的尺寸,精度会有可感知的下降。我在导出ONNX之后会在测试集上跑一遍推理,对比一下pytorch模型和ONNX模型的mAP,确保导出过程没有损失精度。
6.2 扩展类别与新数据的持续学习
这个项目目前只支持七个类别,但现实场景远不止这些。如果你后续要增加类别,要格外小心“增量学习”的坑。直接把新数据加到旧数据里重新训练的话,如果旧数据没被完整保留,模型会对旧类别产生灾难性遗忘——新的类别学得越好,旧类别识别就越差。
我的做法是:保留所有原始图片和标注,每加一批新类别,就用完整的旧数据加新数据重新训练一次,而不是只拿新数据做增量。虽然训练时间变长了,但模型稳定性高得多。另外,如果新类别与旧类别外观很像(比如加一个百事可乐,跟可口可乐的红色包装很接近),建议在新类别数据里刻意混合一部分旧类别数据,专门让模型学习区分两者。
6.3 关于标注成本与数据质量的关系
最后说一个常被忽略的问题:数据标注的质量,直接影响训练效果的上限。模型结构再好、训练技巧再多,标注框画得歪七扭八,模型学到的边界就不稳定。我在这个项目里标注一千多张图片花了大概两天时间,每天只做四五个小时,因为标注这件事集中注意力做三小时以上就容易疲劳出错。
如果项目和资金允许,建议至少让两个人独立标同一批图片,然后计算标注一致性(比如IoU大于0.8的比例),不一致的图片由第三人裁决。这是工业级数据集的标准做法,能显著提升标注质量。即使是个人项目,也至少要在标注完成后做一轮抽检,尤其是对容易混淆的类别。
7. 项目复现完整清单
为了让这篇分享可以直接当“作业抄”,我把整个项目从头到尾的关键命令和配置汇总一下:
环境准备:
conda create -n yolo python=3.10 -y conda activate yolo pip install ultralytics数据集结构:
dataset/ ├── images/train/ 和 images/val/ ├── labels/train/ 和 labels/val/ └── data.yamldata.yaml内容:
path: dataset train: images/train val: images/val names: 0: chips 1: dongpeng 2: redbull 3: fanta 4: yakult 5: cola 6: sprite训练:
yolo train data=data.yaml model=yolo11n.pt epochs=80 imgsz=800 batch=16验证与绘图:
yolo val model=runs/detect/train/weights/best.pt data=data.yaml plots=True推理并保存结果:
yolo predict model=runs/detect/train/weights/best.pt source=./test_images imgsz=800 conf=0.35 save=True导出ONNX:
yolo export model=runs/detect/train/weights/best.pt format=onnx imgsz=800这套流程里,最值得花时间的是数据整理和标注环节,最开始的那次标注和清洗我花了最多精力,但换来的模型效果也是最明显的。后续调参、换模型结构这些,反而都是“锦上添花”,如果数据本身有问题,再先进的模型结构也发挥不出来。
从我个人的操作经验来看,用YOLOv11做商品识别这类垂直场景的检测任务,整个链路已经非常成熟,核心技术难点不在算法本身,而在于对数据的理解和对每个环节细节的把控。这套罐装饮料识别的项目做完之后,我又用同样的流程快速适配了另外几个零售场景的检测需求,效果都稳定在可用水平。如果你手里也有一套标注好的图标数据集,照着这篇文章的思路走一遍,大概率能少走不少弯路。
本文还有配套的精品资源,点击获取