news 2026/9/28 5:33:05

眼镜图像分割数据集实战:从目录结构到PyTorch训练避坑

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
眼镜图像分割数据集实战:从目录结构到PyTorch训练避坑

简介:面部眼镜图像分割数据集包含约16000张配对图像与标签,按2类(背景与眼镜)进行像素级标注,适合用于训练和评估深度学习分割模型,特别适合人脸相关视觉项目与入门语义分割实践。资源内含清晰的训练集与测试集划分,其中训练集约11200张图片及对应mask,测试集约4800张,并附带一个Python可视化脚本,可随机抽取样本展示原始图、GT图及蒙版叠加效果,方便快速检查数据质量。压缩包共2000个文件,以PNG格式的图片和mask为主,另有类别说明txt和可视化脚本py,整体大小约849MB。该数据集已按常见分割任务格式整理,可直接用于模型训练与评估,目前已有91人学习下载,适合需要现成数据集或想熟悉分割任务流程的开发者使用。

1. 图像分割数据集:这批面部眼镜数据真能直接开训

图像分割数据集很多,但真正能直接用的不多。这批面部眼镜图像分割数据集,约16000张图片和对应mask,训练集11200张、测试集4800张,类别只有背景和眼镜两类。它解决的实际问题很明确:任何人脸眼镜区域抠图任务,比如眼镜佩戴检测、美颜特效、人脸属性编辑,都能拿它做初版训练或验证分割流程。适合正在找一份不用清洗、分好训练和测试集、还自带可视化脚本的干净二分类分割数据的人。拿到手先别急着写模型,把目录结构和mask格式摸清,后面训练会省很多麻烦。


2. 数据集目录与文件命名:从一张文件名看穿全套数据

这个数据集的组织方式对新手很友好,train/test、images/masks分得清清楚楚,但如果你只看一眼就开训,容易忽略几个关键细节。资源自带的classes文件和可视化脚本,是我觉得比一堆散图更有价值的部分。下面我从目录、文件名、mask三个角度把它拆开。

2.1 目录结构:train/test 分得清清楚楚

解压后你会看到类似下面的结构:

. ├── train │ ├── images │ │ ├── img-Glass002-414-19_cheek_blowing-1-epping_forest_02-024-sgseg.png │ │ └── ... │ └── masks │ ├── img-Glass002-414-19_cheek_blowing-1-epping_forest_02-024-sgseg.png │ └── ... ├── test │ ├── images │ │ └── ... │ └── masks │ └── ... ├── classes.txt └── visualize.py # 脚本名可能不同,以解压后为准

train 和 test 下分别有 images 和 masks,图片名和 mask 名一一对应。classes.txt里写的就是两类:背景、眼镜,用文本编辑器打开就能看到。我一般会先跑一条命令确认图片和 mask 数量是否一致:

find train/images -type f | wc -l find train/masks -type f | wc -l

如果两个数字对不上,说明有文件缺失,直接去补或过滤。正常情况train下面应该都是11200左右,test下面4800左右。我还会额外检查文件名是否完全匹配,防止少了一个扩展名或多了空格:

ls train/images | sed 's/.png$//' > /tmp/img_ids.txt ls train/masks | sed 's/.png$//' > /tmp/mask_ids.txt diff /tmp/img_ids.txt /tmp/mask_ids.txt | head

diff 无输出说明一一对应。这里有一个容易忽略的点:有些压缩包解压后会产生._开头的隐藏文件,macOS 上尤为常见。如果你的find数量比预期多,多半是混进了._img-...png这种垃圾文件,加载时一定要过滤掉。

目录结构本身没太多玄机,但建议你保留原始目录名,不要重命名成data或labels之类的。因为可视化脚本里通常写死了相对路径,你改目录名之后脚本可能报错,而且报错信息还不直观。我实际操作时就因为把train/images改成了images,导致脚本找不到文件,后来用grep翻了脚本源码才定位到路径。所以拿到手先按原结构存放,跑通再想优化。

2.2 文件名编码规则:眼镜款式、表情、场景全写在名字里

文件名的信息量非常大,比如img-Glass002-414-19_cheek_blowing-1-epping_forest_02-024-sgseg.png。拆开来大概能读出这些含义:

片段含义猜测
Glass002眼镜款式编号
414人物或姿态编号
19可能是人脸关键点编号
cheek_blowing / dimpler / grin面部动作或表情标签
1 / 0 / -3 这些表情严重程度或标签位
epping_forest_02 / autumn_ground背景场景名
024 / 170序列号
sgseg分割数据集标识

这些附加标签很有意思,但注意:它们和分割任务没有直接关系。分割任务只需要 RGB 图和对应的 mask,文件名里的表情、场景不能当监督信号。我见过有人想把cheek_blowing提取出来当多任务学习,结果发现同一个表情下的眼镜形状千差万别,反而干扰主干特征提取。所以常规做法是忽略文件名,只取图片和 mask。

不过文件名也不是完全没用。至少两个场景可以用到:一是数据去重,如果你怀疑某些图片来自同一段视频的连续帧,可以通过Glass002-414-19_cheek_blowing-1-epping_forest_02-024这种连续编号快速定位相邻序列;二是检查分布均衡性,统计每个Glass编号下的图片数量,看看是不是某一款眼镜占了半壁江山。统计命令:

ls train/images | awk -F'-' '{print $2}' | sort | uniq -c

如果发现某个款式数量特别少,训练时要在损失权重里稍微给这些稀有样本加权重,否则模型学到的眼镜形状会偏向主流款式。还有一点:cheek_blowing这类表情标签可能来自人脸属性标注,表情不同会影响脸部肌肉拉伸,导致眼镜和脸部的相对位置略有变化,但这不是分割要解决的本质问题。把注意力放在眼镜轮廓和镜片透明度上,而不是这些辅助标签。

2.3 mask 格式与可视化脚本的作用

mask 是 PNG 格式,尺寸和原图一样。但第一坑就是 mask 的像素值不一定是干净的 0 和 255。有的 mask 边缘带了抗锯齿灰度,有的甚至把镜片反光标成了半透明。所以加载时最好统一做二值化,不要直接拿 0/255 当 target。用一条 Python 命令就能检查:

from PIL import Image import numpy as np mask = np.array(Image.open('train/masks/img-Glass002-414-19_cheek_blowing-1-epping_forest_02-024-sgseg.png').convert('L')) print(np.unique(mask))

如果输出[0 255],说明是纯二值图;如果出现中间值,就得在 Dataset 里加阈值。我见过这套数据里同时存在两种编码风格,所以统一阈值处理是最稳的。

数据集附带的可视化脚本算是雪中送炭。它随机抽一张图,把原始图像、GT(Ground Truth)图像、GT 在原图上叠加的效果三张图拼在一起保存到当前目录。我在标注质量存疑时,第一件事不是写验证代码,而是跑这个脚本多看几十张,确认眼镜轮廓标得是否贴合镜框。如果你的场景是户外、阴影、侧脸,也要重点看这些图,因为分割模型最容易被边缘锯齿和遮挡带偏。

另外,这个可视化脚本的产物通常是一张横向拼接的大图,用普通图片查看器就能打开。我建议抽检时不要只看一张,而是把脚本改造成循环跑多张,或者干脆批量抽取 20 张拼成网格。下面是一个快速抽检脚本的雏形:

import matplotlib.pyplot as plt from PIL import Image import numpy as np names = ['img-Glass002-414-19_cheek_blowing-1-epping_forest_02-024-sgseg.png', 'img-Glass003-431-20_eye_closed-0-ostrich_road-170-sgseg.png'] fig, axes = plt.subplots(len(names), 3, figsize=(12, 4*len(names))) for i, name in enumerate(names): img = Image.open(f'train/images/{name}') mask = Image.open(f'train/masks/{name}').convert('L') axes[i,0].imshow(img); axes[i,0].set_title('original') axes[i,1].imshow(mask, cmap='gray'); axes[i,1].set_title('mask') axes[i,2].imshow(img); axes[i,2].imshow(mask, alpha=0.5, cmap='jet'); axes[i,2].set_title('overlay') plt.tight_layout() plt.savefig('check_overlay.png', dpi=150)

注意这里mask直接以灰度图叠加,如果 mask 有灰度值,叠加后边缘会很糊。你可以在加载时先做(mask > 0)再转 uint8。这个脚本能帮你肉眼确认图片和 mask 是否对应、mask 标注是否完整。

2.4 数据分布与划分:为什么我说别把测试集当验证集

训练集 11200 张、测试集 4800 张,这个比例大约 7:3,看起来没问题。但这里有个常见误区:测试集是用来最终评估的,不是用来调参的。如果你在训练过程中频繁拿测试集看结果,你会不自觉地根据测试集表现改超参数,最后报出来的 mIoU 会虚高。正确做法是从训练集里再切一个小验证集,比如按 9:1 切 1120 张出来,专门用来做早停和调参。

import random from pathlib import Path train_img_dir = Path('train/images') all_ids = [p.stem for p in train_img_dir.glob('*.png')] random.seed(42) random.shuffle(all_ids) val_ids = set(all_ids[:1120]) # 取约10%

然后 Dataset 初始化时传入一个ids参数,只加载指定划分。这样训练集、验证集、测试集三者完全隔离,测试集只在最终评估时碰一次。

另外,数据集的场景分布值得关注。从文件名可以看出场景名很多样,比如epping_forest_02、railway_bridges、beach_parking,说明数据采集覆盖了室外、室内、自然光、人造光等。但还是建议统计一下场景名数量,如果某些场景数量特别多,模型可能会把场景特征学进去,导致在没见过的场景上分割效果下降。用awk -F'-' '{print $(NF-1)}'这种命令提取场景段统计即可。我在实际使用中遇到过头灯、眩光等极端光照,这批数据里不一定覆盖全,所以最终上线前还是要补拍一些真实场景图。


3. 用 PyTorch 把数据集喂进分割模型:加载器、Dice 损失与训练参数

写分割训练代码,最怕的就是自定义 Dataset 写不对,训练流程跑起来之后才发现数据读取有问题。我习惯先把数据加载器写稳,再搭模型和损失函数。这一章给你一份能直接用的 PyTorch 加载、增强、训练和评估的标准做法。

3.1 自定义 Dataset:二值化 mask 是关键

我习惯用 PyTorch 写分割训练。第一步是写一个 Dataset 类,把图片读进来、mask 二值化,然后做统一的尺寸变换。下面这个代码可以直接抄:

import os import numpy as np from PIL import Image from torch.utils.data import Dataset class GlassSegDataset(Dataset): def __init__(self, images_dir, masks_dir, ids=None, transform=None): self.images_dir = images_dir self.masks_dir = masks_dir # 过滤隐藏文件和非png文件 all_ids = [ f[:-4] for f in os.listdir(images_dir) if f.endswith('.png') and not f.startswith('.') ] self.ids = ids if ids is not None else all_ids self.transform = transform def __len__(self): return len(self.ids) def __getitem__(self, idx): name = self.ids[idx] img_path = os.path.join(self.images_dir, name + '.png') mask_path = os.path.join(self.masks_dir, name + '.png') image = Image.open(img_path).convert('RGB') mask = Image.open(mask_path).convert('L') # 转 numpy 做二值化 mask = np.array(mask) # 只要像素大于0就算眼镜区域 mask = (mask > 0).astype(np.float32) return image, mask

这里最核心的是(mask > 0).astype(np.float32)。如果 mask 只有 0 和 255,这一步会把 255 变成 1;如果 mask 有灰度渐变,也能通过阈值统一。阈值设多少?我一般用 0 而不是 127,因为标注边缘即使有半透明,只要不是纯背景,就应当算作前景。某些数据集里 mask 的纯黑部分像素值也可能不是 0 而是 0 附近的小值,这种情况下用mask > 10更稳妥,但先看数据再调。另外,这个 Dataset 返回的是 PIL 图像和 numpy 数组,后面需要用 transform 把它们转成 tensor。如果你不想依赖外部库,可以用torchvision.transforms,但几何增强要自己写或者用RandomCrop保证图片和 mask 同步裁剪,稍麻烦。所以我建议直接用 albumentations。

3.2 数据增强:几何变换和颜色变换要分开对待

分割任务里,mask 必须跟着图片做同样的几何变换,但颜色增强不能作用到 mask 上。我一般用 albumentations 库,它天然对 image 和 mask 同步处理。下面是一组适合这份数据集的增强参数:

import albumentations as A from albumentations.pytorch import ToTensorV2 train_transform = A.Compose([ A.Resize(256, 256), A.HorizontalFlip(p=0.5), A.RandomBrightnessContrast(brightness_limit=0.2, contrast_limit=0.2, p=0.3), A.ShiftScaleRotate(shift_limit=0.05, scale_limit=0.1, rotate_limit=10, p=0.5), A.Normalize(mean=(0.485, 0.456, 0.406), std=(0.229, 0.224, 0.225)), ToTensorV2() ])

注意几点:Resize 用了 256,如果你的显卡显存够大,可以上 512,对眼镜这种细小目标更友好;ShfitScaleRotate 的 rotate_limit 不要超过 15 度,因为戴眼镜的人脸如果大角度旋转,眼镜可能部分超出人脸区域,导致 mask 边界被裁剪产生假标注。训练集比较充足,所以 HorizontalFlip 设为 0.5 是合理的。验证集不要加任何几何增强,只做 Resize 和 Normalize。

val_transform = A.Compose([ A.Resize(256, 256), A.Normalize(mean=(0.485, 0.456, 0.406), std=(0.229, 0.224, 0.225)), ToTensorV2() ])

RandomBrightnessContrast只影响图片,不影响 mask,albumentations 会保证 mask 原样通过。我通常会额外加一个GaussNoise,模拟弱光环境,但对这个数据集不是必须,因为样本本身已经覆盖了多种室内外场景。如果要用,把p设到 0.2 即可,太大容易把眼镜腿的细小结构破坏掉。

使用 albumentations 时,调用方式要和普通 transform 区分:

augmented = train_transform(image=np.array(image), mask=mask) image_tensor = augmented['image'] mask_tensor = augmented['mask']

这里mask必须是 numpy 数组,且形状为(H, W),不能是(H, W, 1)的二维。ToTensorV2 会自动把 mask 变成(1, H, W)的 float tensor。如果你把 mask 转成了(H, W, 1),通道维度会影响后续损失计算,所以保持单通道最省事。

3.3 损失函数:BCE 加 Dice,比单独用 BCE 稳太多

眼镜分割是典型的类别不平衡问题:背景像素占比可能超过 90%,前景(眼镜)只有一小块。单独用 BCEWithLogitsLoss 会让模型倾向全部预测背景,loss 下降很快,但 mIoU 很低。常见的做法是 BCE 加 Dice 损失。我一般这样实现:

import torch import torch.nn.functional as F def dice_loss(pred, target, smooth=1.0): # pred 是未经过 sigmoid 的 logits pred = torch.sigmoid(pred) intersection = (pred * target).sum() return 1 - (2 * intersection + smooth) / (pred.sum() + target.sum() + smooth) def combined_loss(pred, target): bce = F.binary_cross_entropy_with_logits(pred, target) dice = dice_loss(pred, target) return bce + dice

参数解读:smooth 是平滑项,防止分母为 0,一般取 1.0 即可;pred形状是[B,1,H,W],target形状一样,且已经二值化成 float32。如果你的网络输出是[B,2,H,W](两类),那就只用第一类或第二类的通道,或者改成多分类 Dice。我这里把两类问题当作单通道二分类处理,对应网络最后一层卷积输出 1 个 channel。

训练时我习惯用 Adam,初始学习率 1e-4,batch size 16(256 分辨率下 8G 显存够用)。如果 loss 长时间不降,先把学习率降到 1e-5,同时检查数据加载是不是没有 shuffle。还有一个容易忽略的点:ToTensorV2会把 float32 图像转成 0~1 范围,和Normalize的顺序不能反,否则 Normalize 的 mean/std 会对 0~255 的像素做操作,效果完全不同。我在第一次用 albumentations 时就把Normalize放在了ToTensorV2后面,结果模型训练了 10 个 epoch 都没有收敛。

3.4 评估指标:别只看 accuracy,要看 IoU

二分类分割里 accuracy 几乎没有参考价值。假设背景占 95%,模型全预测背景也能有 95% accuracy,但眼镜区域一塌糊涂。我通常在验证集上计算 mIoU,代码片段:

import numpy as np def compute_iou(pred_mask, true_mask): # pred_mask 和 true_mask 都是二值 numpy 数组 intersection = np.logical_and(pred_mask, true_mask).sum() union = np.logical_or(pred_mask, true_mask).sum() if union == 0: return 1.0 return intersection / union

对每个 batch 把 pred 用>0.5阈值转成二值,再和 true_mask 算 IoU,最后对所有样本平均。这份数据集眼镜区域相对小,如果 mIoU 能到 0.85 以上,模型基本可用。除了 mIoU,我还会看眼镜类别的 IoU,因为背景 IoU 总是很高,会被平均掩盖。用 per-class IoU 才能反映真实性能。计算时只需要单独把前景类的 intersection 和 union 拿出来代入公式,其他与 mIoU 一致。我在项目里用一个循环统计所有类别的 IoU,最后打印一个表格,这样能直观看到哪个类别拖后腿。


4. 避坑手册:这份数据集最常见的 5 个坑

这份数据集的坑不在目录结构上,而在标签编码、文件命名、跨平台兼容性这些细节里。下面是我跑完整个流程后踩过的 5 个坑,按影响程度排序。前三个坑会直接让你训练失败或指标失真,后两个坑影响你的开发效率和真实场景表现。

4.1 现象:mask 加载后像素值不是 0/255,训练 loss 震荡

第一次跑训练时,我直接用 PIL 读取 mask 并转成L模式,拿原始 0~255 的值当回归目标,结果 loss 一直不收敛,预测输出全是灰色。打印np.unique(mask)发现值有[0, 128, 255],甚至还有1这种接近 0 的像素。原因:mask 是 PNG 格式,部分样本的像素值有抗锯齿灰度,尤其眼镜腿边缘,值可能是 100、180 这类中间值;另外还有少数 mask 是 0/1 的 PNG 索引图,读进来只有 0 和 1。不同样本的标签表示不统一,模型就懵了。解决:加载时统一做mask > 0二值化,把非零值全部变成 1。最好是写进 Dataset,不要让训练循环里每步再处理。具体修改:

mask = np.array(mask) mask = (mask > 0).astype(np.uint8)

astype(np.uint8)是因为后续计算损失时,PyTorch 的binary_cross_entropy_with_logits需要 float,但这步先存成 uint8 更省内存,使用时再转 float。如果你用float32也可以,但要注意mask > 0返回 bool,直接astype(np.float32)也能行。关键在于不要保留原灰度值。这个坑属于数据质量层面的第一道防线,不解决后面所有指标都不可信。还有一点,测试集和训练集的mask格式可能也不完全一致,所以验证阶段也要做同样的二值化。

4.2 现象:文件名里的表情标签被误当成类别

我用cheek_blowing、grin这些标签想做一个多任务输出,在分割网络后面接了一个分类头,结果验证集 mIoU 暴跌到 0.5 左右,单独看分类准确率却很高。原因:这些表情标签和眼镜分割的依赖关系很弱,大笑和鼓腮时眼镜形状没有本质变化,而且数据集里表情分布不均衡,有些表情只有几百张,强制学习会引入噪声。解决:如果你真想用这些标签,最多做弱监督的辅助分类,且需要单独统计分布,不要把它和主分割分支混合在一起。我后来还是选择完全忽略文件名。辅助分支不仅在结构上增加复杂度,还让损失函数里多了一个超参数需要调,得不偿失。如果实在要统计表情分布,用一条命令:

ls train/images | awk -F- '{print $4}' | sort | uniq -c | sort -nr

这样能看到cheek_blowing有多少张、eye_closed有多少张。我统计完发现cheek_blowing数量只有grin的三分之一,这种不均衡会导致分类头学偏,进而干扰共享编码器。所以最稳妥的做法还是只做单任务分割。

4.3 现象:训练时 loss 不降,原来是数据顺序没 shuffle

我在自定义 Dataset 里没有设置 shuffle,直接把所有图片按字典序排序后的顺序传入 DataLoader,导致一个 batch 里全是同一个眼镜款式、同一个场景的图片,模型反复学同一类样本,验证 loss 几乎不下降。解决:DataLoader 里shuffle=True,或者在我自己的训练循环里手动打乱 idx。这是一个很基础但经常翻车的点,尤其在文件命名有强规律(如前缀都是 img-Glass002)时,shuffle 必须放在随机增强之前。另外,即使设置了 shuffle,如果 Dataset 的__getitem__里返回的图片路径始终不变,shuffle 仍然有效,因为它是对索引打乱。我还会在第一个 epoch 打印每个 batch 的图片名片段,确认一个 batch 内确实来自不同款式。打印代码:

for i in range(0, len(dataset), batch_size): batch_ids = dataset.ids[i:i+batch_size] print([x.split('-')[1] for x in batch_ids])

如果输出全是Glass002,说明顺序没打乱。正常情况一个 batch 里应该均衡出现几种款式。这个检查只花几秒钟,但能避免浪费一晚上的训练时间。这个坑容易在换数据集时复发,每次换数据都要重新检查。

4.4 现象:可视化脚本在 Windows 上报 FileNotFoundError

数据集附带的可视化脚本在 Linux 下没问题,但在 Windows 上跑会报错,Traceback 末尾通常是FileNotFoundError: [WinError 3] 系统找不到指定的路径。原因:脚本里可能用了/拼接路径,而 Windows 需要\,或者脚本一启动就去找某个不存在的目录。解决:用pathlib.Path重写路径拼接:

from pathlib import Path base = Path(r'你的数据集根目录') img_path = base / 'train' / 'images' / filename mask_path = base / 'train' / 'masks' / filename

注意Path的/运算符在不同操作系统上都会生成正确的分隔符。如果不想改脚本,可以手动把脚本里的所有分隔符替换成os.path.join。另外注意classes.txt路径,不同操作系统的换行符也可能导致读取到空行,最好用strip()处理。这个坑其实不是数据集的问题,是跨平台脚本的通病,但如果你在 Windows 下复现,十有八九会遇到。我自己的习惯是拿到任何项目先把os.path.join统一成pathlib.Path,一劳永逸。

4.5 现象:测试集 mIoU 很高,但是自定义图像上预测效果很差

我把训练好的模型在测试集上跑出 0.9 的 mIoU,心想稳了,结果拿手机拍了几张戴眼镜照片一测,眼镜边缘全是毛刺。原因:这个数据集的测试集和训练集来自相似的数据生成管线,场景分布接近,但真实世界有镜片反光、粗黑框、半框、金丝镜腿等多种样式,模型没见过。解决:把测试集里随机抽 100 张做人工检查,发现测试集里也大多是高清证件照风格,和手机自拍差异大。我的做法是额外收集 20~50 张不同光源下、不同拍摄角度的眼镜照片,手动标注后当验证集,用这个验证集来调阈值和做早停。同时,预测时把输出概率的阈值从 0.5 调到 0.4 或 0.3,可能让边缘更完整,但也会引入一些背景噪声,需要权衡。标注 50 张图大概两小时,但带来的可靠性提升远超训练一个晚上的成本。总的来说,自己补几张真实图,比迷信测试集指标强得多。


5. 进阶用法:用自带脚本抽检,再导成 COCO 格式

5.1 跑通可视化脚本,快速发现标注脏数据

我拿到数据第一晚就是跑这个脚本,抽了 50 张图,发现有几张眼镜边缘明显没贴住镜框,还有两张把镜片反光当成了眼镜区域。幸好有脚本一目了然,否则这种脏数据混进去,模型会被带偏。脚本运行方式一般是在命令行直接执行,比如:

python visualize.py

它会在当前目录生成三张一组的对比图。我建议你改一下脚本,让它可以指定图片编号,不要每次都随机,这样复查特定样本更快。改法很简单,把随机取样改成传参即可,具体实现不需要依赖额外库,用sys.argv接收一个文件名参数就行。

5.2 把二值 mask 导出成 COCO JSON,接上 mmdetection

如果你想用现成目标检测/分割框架,比如 mmdetection 或 Detectron2,需要把 PNG mask 转成 COCO 格式的 RLE 编码。转换代码很简单:

import numpy as np from pycocotools import mask as cocomask import json def convert_mask_to_rle(binary_mask): # 转换为 Fortran 连续数组 fortran_mask = np.asfortranarray(binary_mask.astype(np.uint8)) rle = cocomask.encode(fortran_mask) rle['counts'] = rle['counts'].decode('ascii') return rle

注意binary_mask必须是 0/1 的 uint8 数组,并且np.asfortranarray不能少,否则 RLE 编码结果会错。然后遍历所有训练集 mask,为每张图生成一个 annotation,category_id 设为 1(对应眼镜),bbox和area可以由 RLE 生成。这样导出的 JSON 可以直接被 mmdetection 的 CocoDataset 读取,省去自己写 Dataset 的功夫。如果你只需要训练分割,也可以直接用我的 Dataset,不必导 COCO。但如果你后续要接检测、实例分割、关键点等任务,这个转换就很有价值。

从那以后我每次训练前都会强制走一遍「随机抽 9 张图看叠加效果 → 打开一张 mask 看像素值是否二值化 → 再进训练」,这三个动作加起来不到五分钟,但能救下好几个小时的无效训练。希望帮到你。

本文还有配套的精品资源,点击获取

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/9/28 5:32:03

二手车交易系统实战:SpringBoot+Vue+MyBatis+MySQL

做一个二手车交易系统,其实比想象中有意思。这个项目前后端分离、带完整管理后台,涉及了 SpringBoot Vue MyBatis MySQL 这套国内中小型项目最常用的技术组合,既能作为毕业设计、面试项目,也能直接改改用在真实业务里。废话不多…

作者头像 李华
网站建设 2026/9/28 5:31:34

GitHub镜像站搭建实战:内网仓库同步与加速指南

第一次接触 GitHub 镜像站,还是因为一个很现实的问题:团队里几个人同时从 GitHub 拉代码,拉到一半 CI 红了一大片。查了半天,不是代码问题,是网络问题。后来我意识到,与其反复等网络恢复,不如自…

作者头像 李华
网站建设 2026/9/28 5:31:30

SpringBoot2+Vue3+MyBatis-Plus素材管理系统实战

接手这类“XX管理系统”的项目时,很多人第一反应是先看技术栈新不新、界面炫不炫。但真正做过一轮你就会发现,SpringBoot2 Vue3 MyBatis-Plus MySQL8.0这套组合,最值钱的地方不在于某个框架有多前沿,而在于它把“多媒体素材管理…

作者头像 李华
网站建设 2026/9/28 5:30:30

服装行业--买手

OTB(Open-to-Buy,采购限额):销售预测 - 期初库存 期末库存销售收入 客流量 转换率 客单价售罄率:卖出去的货占进货的比例。动销率:动销率 有销售的商品数 商品总数标额: 标店一天的销售额…

作者头像 李华
网站建设 2026/9/28 5:29:23

Linux进程优先级调度:renice命令实战与原理详解

日常维护Linux服务器,进程优先级调度是我几乎每天都要打交道的事情。尤其是碰上业务高峰期,CPU资源争抢严重的时候,能不能精准地让某个进程“让路”或者“加塞”,直接决定了线上服务的响应速度。今天这篇实操篇,就专门…

作者头像 李华
网站建设 2026/9/28 5:29:10

Mysql初入

mysql的进入mysql安装完毕后winR呼出后输入cmd打开命令提示符,输入mysql -u root -p-u 是以什么身份去登录-p 是登录密码quit退出mysql是一个数据库。mysql本质上是一种网络服务,是数据库服务的客户端。在磁盘或者内存是存储的特定结构的数据。一套数据库…

作者头像 李华