简介:面向面部图像理解与分割任务,这是一套包含约16000张图像及对应像素级标注的眼镜分割数据集,适合计算机视觉学习者、算法工程师及科研人员用于训练和评估眼镜区域分割模型。数据按训练集与测试集划分,训练集约11200张,测试集约4800张,每部分均含原始图像与mask模板目录,类别仅背景与眼镜两类,便于直接开展二分类语义分割实验。资源包共2000个文件,以png图像与掩码为主体,附带classes.txt类别说明及可视化脚本py,压缩后约849MB,结构清晰、即下即用。除数据外,脚本支持随机抽取样本并合成展示原图、GT及叠加结果,方便快速核对标注质量与模型效果,整体可作为语义分割入门或面部部件识别研究的优质训练样本。目前已有91人学习下载,适合需要眼镜区域标注数据或进行分割基准测试的开发者参考使用。
1. 眼镜分割数据集:约16000张标注图,能做什么、值得不值得投入
图像分割数据集里,人脸方向的不少,但专门把眼镜作为分割目标的很少。这个面部眼镜图像分割数据集,约16000张数据和标签,解决的是在人脸图像中逐像素抠出眼镜区域的任务。对做人脸识别前处理、AR 虚拟试戴、驾驶员疲劳检测的工程师来说,最耗时间的不是模型,而是标注:眼镜腿和头发挨着、镜片反光、墨镜全黑,这些边界让标注员也头疼。适合两类人:一是刚入门想跑通图像分割完整流程的新手,拿一份现成标签练手最划算;二是手头有模型但缺高质量掩码的团队,直接从这里开始清洗、训练和验证。数据本身不解决所有问题,但能帮你跳过最枯燥的几个星期。
2. 拆开数据集:标注格式、目录结构与数据体检
2.1 标注格式对比:mask 文件夹、COCO JSON 还是 RLE 压缩
拿到数据集先别急着找模型,第一步是弄清楚标签的组织方式。常见做法是两种:一种是 image 和 mask 各一个目录,mask 是 PNG 灰度图,背景 0、前景 255;另一种是 COCO 风格,所有标注汇总到一个 annotations.json 里,用多边形坐标或 RLE 编码存储。这两种格式对后续训练的路线影响很大。
| 格式 | 存储方式 | 优点 | 常见坑 |
|---|---|---|---|
| PNG mask 目录 | 每张图片对应一张灰度 PNG | 直观、可用任意分割框架 | 文件名对不齐、灰度取值不统一 |
| COCO JSON | 多边形坐标 + RLE | 适合检测/分割统一训练 | 解析复杂,多边形有孔洞时难还原 |
| RLE 单图 | 压缩编码存文本 | 省空间 | 解码麻烦,肉眼无法直接检查 |
不管标题里说约16000张,你拿到手第一件事就是确认这个数字,以及目录层级是否符合预期:
# 解压后先看两层目录结构,确认 image 和 label/mask 的存放位置 find . -maxdepth 2 -type d | head -20 # 统计图片文件总数,和标题声称的约 16000 对一下 find . -type f \( -name "*.jpg" -o -name "*.png" -o -name "*.jpeg" \) | wc -l # 查看是否有独立的 label/mask 目录,以及文件后缀 ls -la ./images | head -5 ls -la ./masks | head -5我一般会把这个输出保存下来,作为数据版本的第一条记录。注意find命令里的-o表示或,三种常见扩展名都要统计;如果实际数量与标题差的远,先看是不是有子目录嵌套,有些数据集把 train/val/test 分开,根目录下统计不全。一个容易被忽略的点是:有的数据集 mask 是 PNG 但原图是 JPG,find按后缀统计会漏掉跨格式匹配,所以后面 Python 体检时还要按文件名 stem 再对一次。
2.2 用 Python 做数据体检:图像尺寸、标签取值与文件对齐
命令行只能看数量,真正决定训练是否顺利的是标签质量。我做分割数据集的第一步永远是写一个体检脚本,跑三件事:核对文件名一一对应、统计 mask 的取值分布、记录图像尺寸范围。这三件事能挡住后续 80% 的翻车。
from pathlib import Path from PIL import Image import numpy as np import collections img_dir = Path("images") mask_dir = Path("masks") # 以文件名 stem 为 key 做对齐,忽略后缀差异 img_stems = {p.stem: p for p in img_dir.iterdir() if p.suffix.lower() in (".jpg", ".png", ".jpeg")} mask_stems = {p.stem: p for p in mask_dir.iterdir() if p.suffix.lower() in (".png", ".jpg")} print(f"原图数量: {len(img_stems)}") print(f"掩码数量: {len(mask_stems)}") print(f"有图无掩码: {len(set(img_stems) - set(mask_stems))}") print(f"有掩码无图: {len(set(mask_stems) - set(img_stems))}") # 标签取值分布,取前 300 张掩码统计 counter = collections.Counter() for stem, path in list(mask_stems.items())[:300]: arr = np.array(Image.open(path).convert("L")) counter.update(np.unique(arr).tolist()) print("掩码像素取值分布:", dict(counter))逻辑说明:convert("L")强制转灰度,避免三通道 PNG 读进来变成 (H, W, 3) 导致np.unique的结果变成数组。取值分布这一步非常关键——有的标注工具把背景导出成 255、前景导出成 0,和常见情形正好相反;有的 mask 里混入 127 这种过渡值,说明标注皮肤时开了抗锯齿。正常情况下应该只出现 0 和 255(或 0 和 1)。
参数说明:前 300 张是我常用的抽样量,能覆盖大多数脏数据模式且不会太慢。约16000张的数据全量统计也不慢,但读 PNG 非常吃磁盘 IO,抽样先看一轮更高效。发现取值里只有 0 和 1 时,训练时不用做阈值处理;发现 255 时,一定要在数据加载代码里加/255,这是训练 loss 不下降的经典隐性原因之一。
2.3 可视化抽查:叠加 mask 看边界是否可信
数值体检通过了,不代表标注没问题。眼镜分割标签有它的特殊性:镜框和眉毛、头发在灰度图上几乎融为一体,标注员稍不留神就会把眉毛画进 mask。所以必须做可视化抽查,随机抽几十张原图和 mask 叠加看。
import matplotlib.pyplot as plt def show_overlay(img_path, mask_path, alpha=0.6): img = np.array(Image.open(img_path).convert("RGB")) m = np.array(Image.open(mask_path).convert("L")) # 生成红色半透明叠加层:mask > 0 的位置标红 overlay = img.copy() overlay[m > 0] = (255, 0, 0) blended = (img * (1 - alpha) + overlay * alpha).astype(np.uint8) fig, axes = plt.subplots(1, 3, figsize=(15, 5)) axes[0].imshow(img) axes[0].set_title("原图") axes[1].imshow(m, cmap="gray") axes[1].set_title("mask") axes[2].imshow(blended) axes[2].set_title("叠加") plt.tight_layout() plt.show()逻辑说明:overlay[m > 0] = (255, 0, 0)直接把原图上对应像素改为纯红,alpha 混合让边界看得清又不遮挡细节。这里特意用m > 0而不是m == 255,就是为了兼容前一步体检发现的各种取值情况。
参数说明:alpha=0.6是我试过比较舒服的值,太高看不清原图纹理,太低红色不显眼。抽查时重点看三类问题:一是 mask 是否把眉毛、睫毛包进去了;二是眼镜腿的末端是否准确结束在脸侧,而不是一路画到耳朵;三是同一人不同角度的两张图,mask 大小是否和图中眼镜的实际尺寸一致。这一步不需要写代码自动判断,人眼扫几十张就能建立对数据集质量的直觉,后面调参才有底气。
3. 训练前的数据准备:按人划分、格式转换与增强边界
3.1 按人物身份划分训练集和验证集:避免同人串集
人脸相关的数据,翻车最多的不是网络结构,而是划分方式。约16000张图如果来自有限数量的拍摄对象,同一人的不同照片往往高度相似——光照、角度、背景接近。如果随机划分,训练集和验证集里会出现同一个人的照片,模型记住这个人就足够了,验证指标虚高;部署到真实场景,换个陌生人效果断崖式下跌。
from sklearn.model_selection import GroupShuffleSplit from pathlib import Path img_files = sorted(Path("images").glob("*.jpg")) # 假设文件名形如 person_001_002.jpg,取前两段作为人物 ID groups = [p.stem.rsplit("_", 1)[0] for p in img_files] split = GroupShuffleSplit(n_splits=1, test_size=0.15, random_state=42) train_idx, val_idx = next(split.split(img_files, groups=groups)) print(f"总人物数: {len(set(groups))}") print(f"训练集图片: {len(train_idx)}, 验证集图片: {len(val_idx)}")逻辑说明:GroupShuffleSplit和普通train_test_split的区别在于它接受groups参数,保证同一个 group 的所有样本只进训练或只进验证。关键在rsplit("_", 1)[0]怎么取人物 ID——这取决于数据集的文件名规则,有的叫face_001_01.jpg,有的叫id_001_img_02.jpg,必须先抽样打印文件名确认分隔符和字段位置。
参数说明:test_size=0.15对约16000张的数据集意味着验证集约 2400 张,足够稳定评估分割指标;如果后面要做早停或模型选择,可以提到 0.2。random_state=42固定下来,方便不同实验之间对比——这一步很多人忽略,随机种子不固定,两次实验之差还不如随机划分的开销大。
如果数据集没有提供人物 ID 信息,文件名也无法推断,还有一个近似办法:对所有人脸区域做特征向量聚类,把同一簇分到同一组。用人脸识别模型提特征、按余弦相似度聚类,虽然不是精确分组,但能有效降低串集程度。
3.2 把 PNG mask 转成 YOLO 分割格式:polygon 与归一化坐标
用 YOLOv8 训练自己的数据集已经是图像分割落地场景里的常见路线,但 yolo 系列的分割格式不是像素 mask,而是归一化多边形坐标,所以必须做格式转换。约16000张 mask,转换脚本要跑得干净、可重复,我一般这样写:
import cv2 import numpy as np def mask_to_yolo(mask_path, class_id=0): m = cv2.imread(mask_path, cv2.IMREAD_GRAYSCALE) # 统一成二值图:无论标签是 0/255 还是 0/1,都能处理 _, binary = cv2.threshold(m, 127, 255, cv2.THRESH_BINARY) binary = cv2.morphologyEx(binary, cv2.MORPH_CLOSE, np.ones((3, 3), np.uint8)) # RETR_EXTERNAL 只取最外层轮廓,避免内轮廓重复标注 contours, _ = cv2.findContours(binary, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE) h, w = binary.shape lines = [] for cnt in contours: # 点数太多会拖慢训练且 loss 波动,用多边形近似压点数 epsilon = 0.001 * cv2.arcLength(cnt, True) approx = cv2.approxPolyDP(cnt, epsilon, True) pts = approx.reshape(-1, 2).astype(np.float64) pts[:, 0] /= w pts[:, 1] /= h coords = " ".join(f"{x:.4f} {y:.4f}" for x, y in pts) lines.append(f"{class_id} {coords}") return lines逻辑说明:cv2.threshold把 mask 变成严格二值图,避免过渡值变成多边形里的锯齿。MORPH_CLOSE闭运算把细小空洞补上,对眼镜这种内部可能有镜片反光空洞的 mask 很实用。RETR_EXTERNAL只提取最外层轮廓,换成RETR_LIST会把镜框内部的孔洞也当成轮廓输出,训练时同一张图出现重叠标签。
参数说明:epsilon=0.001 * arcLength是我常用的压缩系数,换算成点数大概是每个轮廓保留 20~60 个点。眼镜腿是细长结构,epsilon 太大会把腿压成直线,太小则每个 mask 动辄几百个点,训练代码组装 batch 时会明显变慢。转完后必须抽几张图,把多边形画回原图对比,肉眼确认轮廓贴合度;这一步不能省,多边形近似造成的精度损失是可见的。
3.3 数据增强的边界:眼镜是刚性物体,翻转旋转要克制
数据增强是分割任务提升泛化能力最有效的手段之一,但人脸眼镜场景有自己的特殊约束。眼镜是刚性物体,水平翻转是合理的(镜像对称),垂直翻转则完全错误——没有人倒着戴眼镜。旋转角度也要克制,人脸检测之后接分割时,图里的人脸通常已做过对齐,旋转超过 30 度就开始偏离真实分布。
import albumentations as A train_transform = A.Compose([ A.HorizontalFlip(p=0.5), A.RandomBrightnessContrast(brightness_limit=0.2, contrast_limit=0.2, p=0.3), A.HueSaturationValue(hue_shift_limit=10, sat_shift_limit=20, p=0.3), A.Affine(scale=(0.9, 1.1), rotate=(-15, 15), translate_percent=(-0.05, 0.05), p=0.5), A.Resize(512, 512), ])逻辑说明:albumentations的分割版本会在内部自动同步原图和 mask 的变换,不需要手动把同样的随机参数传给 mask。这里没有加随机裁剪,因为眼镜在整张人脸中占比不大,随机裁剪如果切掉眼镜区域,等于喂了一批没有目标的负样本;如果一定要裁剪,应配合人脸区域约束或检测框信息。
参数说明:rotate=(-15, 15)对正视人脸是合理范围,如果数据集里有大量侧脸,可以放宽到(-25, 25)。scale=(0.9, 1.1)模拟距离变化,不要小于 0.8,否则眼镜的细节纹理被插值抹平。亮度增强对有反光的镜片尤其重要——很多实际图片里镜片白花花一片,训练时见过这种变化,推理时才不会把反光区域全部判成背景。
4. 从约16000张到可用模型:Unet 与 YOLOv8-seg 两条落地路线
4.1 Unet 路线:小显存也能跑通的最小配置
Unet 图像分割是语义分割的经典架构,在医学图像分割领域被验证过无数次,拿来做眼镜分割同样合适,尤其是想严格控制参数量和推理延迟的时候。约16000张数据对 Unet 来说不算多,用 ImageNet 预训练编码器做迁移学习是关键。习惯上我会用 segmentation_models_pytorch 这套封装,省去手写 decoder 的麻烦。
import torch import segmentation_models_pytorch as smp model = smp.Unet( encoder_name="resnet34", encoder_weights="imagenet", in_channels=3, classes=1, # 二分类:背景 + 眼镜 activation=None, # 不在模型里加 sigmoid,方便和 loss 组合 ) loss_dice = smp.losses.DiceLoss(mode="binary") loss_bce = torch.nn.BCEWithLogitsLoss() # 组合 loss:dice 对小目标稳定,bce 对梯度回传平滑 loss_fn = lambda pred, target: loss_dice(pred, target) + 0.5 * loss_bce(pred, target) optimizer = torch.optim.AdamW(model.parameters(), lr=1e-4, weight_decay=1e-5)逻辑说明:activation=None让模型输出 logits,BCEWithLogitsLoss 内部会做 sigmoid,数值上比手动 sigmoid 再接 BCELoss 更稳定,这个细节影响收敛但常被忽略。DiceLoss(mode="binary")在类别不平衡时比纯 BCE 好得多——眼镜区域在整张图中通常只占 3%~8%,纯 BCE 会让模型学会输出全背景。
参数说明:resnet34是平衡点,比 resnet18 精度好、比 resnet50 省显存,512 输入下 batch size 8 大约占 6~7G 显存。lr=1e-4是迁移学习的常见起点,配合ReduceLROnPlateau在验证 loss 停滞时降为 0.1 倍。Dice 和 BCE 的权重配比 1:0.5 是我调出来的稳健组合,如果发现边界粗糙可以调成 1:1 让 BCE 多发挥一点。
训练过程中我建议每 5 个 epoch 保存一次 checkpoint,并同时记录验证集 IoU。Unet 的训练曲线存在 loss 平了但 mask 边界还在抖的假平稳期,单看 loss 容易提前停掉。
4.2 YOLOv8-seg 路线:格式转换后的训练命令与参数
如果后续要接目标检测、跟踪或者部署到边缘设备,YOLOv8-seg 是比 Unet 更省心的选择。约16000张的数据集经过第 3 章格式转换后,组织成 yolo 要求的目录结构就能直接训练。很多人处理数据集用于 yolo 训练时,前两次都会因为 yaml 路径或类别编号问题报错,这里给出完整配置。
# glasses_seg.yaml path: ./glasses_seg # 数据集根目录,相对路径或绝对路径均可 train: images/train # 训练集图片目录 val: images/val # 验证集图片目录 names: 0: glasses # 类别编号必须和转换脚本里的 class_id 对应# 训练命令:nano 模型起步,先验证流程能不能跑通 yolo segment train \ data=glasses_seg.yaml \ model=yolov8n-seg.pt \ epochs=80 \ imgsz=640 \ batch=16 \ device=0 \ patience=15逻辑说明:yaml 里的names编号必须和 mask_to_yolo 转换脚本写入 txt 时的class_id一一对应。训练命令里model=yolov8n-seg.pt表示从官方预训练权重继续训练,比从头训练收敛快得多;patience=15表示验证集指标连续 15 个 epoch 不上升就早停,约16000张的训练量通常用不到 80 个 epoch,早停能省不少时间。
参数说明:imgsz=640是 yolo 系列的默认输入,眼镜这类细节较多的目标如果觉得分割边缘不够细,可调到 768 或 1024,显存占用大约按平方关系上涨;batch=16在 8G 显存上刚好能跑,显存不足时先降 batch 而不是降 imgsz,batch 影响梯度稳定性,imgsz 影响分割精度。patience=15不要设太小,分割任务的验证指标波动比检测大,太激进会在局部波动处停掉。
4.3 验证指标怎么组合着看:IoU、Dice 与边界误差
训练完怎么判断模型好坏?只看一个指标会被骗。约16000张的数据集,我建议至少同时记录三个指标:IoU、Dice 系数和边界平均距离误差。它们各有盲区——IoU 对小块漏检敏感,Dice 对整体重叠敏感,边界误差直接反映分割结果的可用性。
| 指标 | 计算方式 | 主要盲区 | 适用场景 |
|---|---|---|---|
| IoU | 交集/并集 | 小目标漏检时下降不明显 | 整体评估 |
| Dice | 2倍交集/(预测+真值) | 对目标形状变化不敏感 | 类别不平衡时更稳 |
| 边界距离 | 预测边界与真值边界平均像素距离 | 无法反映内部空洞 | 眼镜腿细长结构评估 |
def compute_iou(pred_mask, gt_mask, threshold=0.5): pred = (pred_mask > threshold).astype(np.uint8) gt = (gt_mask > 0).astype(np.uint8) intersection = np.logical_and(pred, gt).sum() union = np.logical_or(pred, gt).sum() return intersection / (union + 1e-6)逻辑说明:threshold=0.5是常用分割阈值,如果推理时误检偏多,可以在验证集上扫一遍 0.3~0.7 之间的阈值,找到最优点并沿用,这是分割项目通用的后处理步骤。union + 1e-6防止除零——某些极端图中没有眼镜,真值为全 0,预测也为全 0 时 IoU 定义上是 1,但多数验证脚本会跳过这种图,统计时要把规则写清楚。
参数说明:边界距离需要先用cv2.findContours提取预测边界和真值边界,再逐点算最近距离。我一般只对验证集里眼镜区域占比大于 5% 的图片计算边界误差,目标太小时该指标数值波动很大,看整体均值没有意义。
5. 眼镜分割避坑指南:5 个让人返工的细节
5.1 现象:训练 loss 降得很顺利,可视化输出却全黑或全白
原因:绝大多数情况下是训练时用了BCEWithLogitsLoss或DiceLoss,但推理时直接把模型输出当成概率,没有做 sigmoid。模型输出是 logits,正值代表前景、负值代表背景,直接阈值化时如果整体输出偏移,就会出现全黑(所有 logits 为负)或全白(所有 logits 为正)。
解决:推理前统一对输出做torch.sigmoid(pred),再与 0.5 比较。同时检查数据加载时 mask 是否做了归一化——如果标签是 0/255 而代码里没除以 255,目标值是 255,模型会拼命把 logits 往大推,最终输出全白。这类问题在拿到新数据集的第一个训练循环里最容易出现,先验证单张图的 forward 输出再跑全量,能省一晚上。
5.2 现象:眼镜腿总是断,分割结果只有镜片没有镜腿
原因:眼镜腿在整张图中只占几百个像素,是典型的细长小目标。Unet 或 yolo 的下采样会把 640 输入压到 20 或 40,眼镜腿宽度只有几个像素时,在深层特征图里已经消失;Dice loss 按像素占比加权,镜腿贡献的 loss 太小,模型倾向于放弃它。
解决:三个手段叠加。一是提高输入分辨率到 768,从根本上保住镜腿像素;二是 loss 层面把 Dice 权重调高,或换成TverskyLoss这类能对假阴性加权的 loss;三是训练后处理时对分割结果做一次形态学闭运算,cv2.morphologyEx(pred, cv2.MORPH_CLOSE, kernel)能把镜腿细小断裂补上。代价是闭运算会让边界膨胀 1~2 像素,对边缘精度要求高时,只对镜腿邻近区域做闭运算更精细。
5.3 现象:验证集 IoU 有 0.9,换到实际拍的照片效果很差
原因:这是人脸类数据集最经典的陷阱——同人串集。随机划分时同一人的多张照片同时进入训练集和验证集,模型记住的是这个人,而不是眼镜的形状。另外,数据集里如果大量是白墙背景、正面光,验证集继承这种单一分布,真实场景里的侧光、杂乱背景直接让模型失效。
解决:严格按人物 ID 分组划分,验证集里的脸绝不能出现在训练集。检查方法很简单:随机抽验证集 10 张图,看里面的人脸在训练集中能否找到同一张脸。没有人物 ID 时用 3.1 节的特征向量聚类来分组。部署前再准备一个外部陌生人人脸测试集,数量不用多,50 张就足够暴露问题。
5.4 现象:墨镜和透明镜片的标签语义混在一起
原因:约16000张数据集如果来自多个标注员,很容易出现规则不一致:有人把墨镜的深色镜片标成前景,有人把透明镜片标成背景只标镜框;有人把镜片和镜框合成一整块,有人把两者分开。训练时语义混乱,模型输出的边界就会抖动。
解决:第一步按 mask 的面积分布做离群检测——同一类目标面积应相对集中,如果分布出现明显双峰,大概率是标注规则分裂。第二步明确标签规则:面向眼镜整体分割时,把镜框和镜片合并为同一类;面向镜框追踪时,把透明镜片视为背景,只分割框体。规则定好后,用脚本剔除或改写不符合规则的 mask,再重新跑数据体检。
5.5 现象:数据集里混入低分辨率头像和漫画人脸
原因:人脸图像分割数据集通常会清洗图片来源,但 16000 张规模难免有漏网之鱼,常见的有社交软件头像缩略图、网络漫画或插画,以及分辨率低到眼镜无法辨认的图。这些样本对训练是纯噪声,模型会学到错误的纹理和边界特征。
解决:按图像尺寸和清晰度做两轮过滤。第一轮过滤尺寸小于 200×200 的图;第二轮用cv2.Laplacian算子计算方差,方差低于阈值时判定为模糊图直接剔除,阈值我常用 50~80,视数据集整体清晰度调整。过滤后重新跑第 2 章的体检脚本,再做一次可视化抽查。整个过程落成脚本,后续换数据集可以复用。
6. 让数据集增值:从二值掩码到多属性标签与边缘部署
约16000张数据加上训练好的分割模型,其实只完成了一半。眼镜分割在实际项目里很少单独使用,它往往是更大系统的前置模块。我自己的做法是把二值掩码继续往上叠加业务价值,其中一个最有用的方向是:拿到分割结果后,提取眼镜区域的最小外接矩形和长宽比,做镜框类型分类。无框眼镜的宽高比通常在 2.8~3.2 之间,墨镜通常更宽,圆形镜框的外接矩形比例接近 1.5,依靠这个特征搭配一个简单分类器就能达到实用精度,不需要重新训练一个检测模型。
另一个值得做的是把训练好的分割模型导出到端侧部署格式。Unet 转 ONNX 的代码很短,但有几步必须盯紧:
import torch model.eval() dummy = torch.randn(1, 3, 512, 512) # opset_version 11 以上才能覆盖主流边缘推理框架;dynamic_axes 支持输入尺寸动态变化 torch.onnx.export( model, dummy, "glasses_seg.onnx", input_names=["input"], output_names=["output"], dynamic_axes={"input": {0: "batch", 2: "height", 3: "width"}}, opset_version=11, )导出后我用 onnxruntime 加载 ONNX 文件,喂一张训练时没见过的图,对比 PyTorch 输出与 ONNX 输出,最大误差超过 0.01 就得排查算子兼容问题。约16000张的数据在这个阶段的优势就体现出来了:不会担心微调样本不够,可以放心地把一部分数据留给蒸馏和量化校准。INT8 量化时用 500 张有代表性的图片做校准集,眼镜分割的精度损失通常能控制在 1 个点以内。
最后我保留一个习惯:每次拿到新数据集,都先写一遍第 2 章那样的体检脚本,不管换什么分割任务都先跑一遍。这个动作帮我避开过太多次训练到半夜才发现标签问题的返工,与其在训练中段怀疑人生,不如在第一天花 20 分钟把数据看透。希望帮到你。
本文还有配套的精品资源,点击获取