Daytime-Sunny天气数据集实战:从数据预处理到语义分割训练
2026/9/10 2:50:34 网站建设 项目流程

简介:这份天气数据集Daytime-Sunny面向单域广义目标检测(Single-DGOD)研究,为计算机视觉算法工程师、科研人员及学生提供大规模白天晴朗场景下的数据基础,整体覆盖27711张白天晴天图片。压缩包内共2000个文件,其中1998个XML标注文件记录目标边界框与类别信息,2个TXT文本文件用于划分训练集与测试集,包体大小约1.84GB。目前已有133人浏览学习,数据组织规范,可直接接入YOLO、Faster R-CNN等主流检测框架进行训练与验证。该数据适合检验模型在光线充足条件下的检测精度与泛化能力,也可通过数据增强模拟阴雨、夜景等场景,支撑跨域目标检测与鲁棒性研究,在自动驾驶、视频监控、智能零售等方向均有实用价值,是算法实验与论文复现的优质基准资源。

1. 天气数据集Daytime-Sunny:27711张白天晴天图片能做什么

做自动驾驶感知或户外视觉模型的人,迟早会撞上一个尴尬问题:模型在阴天、雨天、黄昏的表现崩了,但翻遍公开数据集,发现大部分训练样本恰好是你最不缺的“白天+晴天”。Daytime-Sunny正是这类天气数据集中最常见的组合标签,它把27711张白天晴天的图片单独归为一类,看似普通,实际是训练场景理解模型的优质底料。这篇文章不谈下载渠道,只讲拿到这批图片后,怎么组织标签、怎么划分数据集、怎么调增强参数、怎么验证模型没有把“晴天”学成“过曝”。

2. 前数据准备:理解Daytime-Sunny的目录结构与标签语义

2.1 Daytime-Sunny在天气数据集里的定位:组合标签而非单标签

很多刚接触天气数据集的人会把Daytime-Sunny当成一个独立的分类标签,实际上它通常是两个维度组合后的结果:时间维度(Daytime)加上天气维度(Sunny)。在BDD100K这类大型驾驶数据集里,天气属性被拆成clear、rainy、snowy、overcast等,时间属性被拆成daytime、night、dawn/dusk,Daytime-Sunny对应的就是两个属性同时满足的子集。理解这一点很重要,因为后续做类别筛选、做迁移学习时,你要明确自己是在用“原始标注”还是“筛选后的子集”。

以这27711张图为例,它可能来自某个更大数据集的过滤结果,也可能是自行采集后人工筛选的产物。无论来源如何,文件名里往往保留着原始采集信息。常见的命名模式有两种:一种是带时间戳的,比如2019-06-15_12-30-45.jpg,另一种是带序列号的,比如sunny_day_00001.jpg。拿到数据集后的第一个动作,不是直接开训,而是先用命令行或脚本扫一遍文件名规律,搞清它是按场景分类还是按时间乱序存放。

2.2 拿到数据集后的第一件事:核对目录树与文件命名

无论数据集来自哪条渠道,第一步永远是核对物理文件是否齐全。27711张图不是小数目,网盘下载或硬盘拷贝过程中很容易出现截断文件、空文件、文件名乱码。我用一个简单的find命令配合wc -l做快速清点:

find . -type f -name "*.jpg" | wc -l find . -type f -name "*.png" | wc -l du -sh .

如果预期是27711张,但数出来少了几百张,优先检查是不是有子目录被遗漏,或者文件后缀不统一。du -sh .用来确认总体积是否在合理范围内——27711张白天晴天图片,如果平均每张几百KB到几MB,总大小应该在10GB到50GB之间,偏差过大说明可能有压缩或损坏。

文件清点通过后,我一般会随机抽20到30张图用图像查看器快速扫一遍,确认没有黑白图、没有纯色图、没有重复图。这一步花不了三分钟,但能避免后面训练时出现“loss不降但验证集很准”的假象——重复样本如果恰好同时进了训练集和验证集,评估指标会虚高到失真。

2.3 文件名里的隐藏信息:时间戳、GPS与天气标签的关系

Daytime-Sunny这27711张图里,如果文件名包含时间戳,你可以直接提取时间来验证“白天”这个标签是否站得住脚。夏季和冬季的白天时段完全不同,如果数据采集跨越了多个地区,时区的差异也会让文件名里的时间和实际光照情况对不上。常见做法是写一个脚本,从文件名里正则提取小时字段,做一个小时分布的直方图:

import re from collections import Counter from pathlib import Path img_dir = Path("./Daytime-Sunny") hours = [] for p in img_dir.glob("*.jpg"): m = re.search(r"(\d{2})[-_](\d{2})[-_](\d{2})", p.stem) if m: hours.append(int(m.group(1))) print(Counter(hours).most_common())

这段代码的核心逻辑是,用正则从文件名里抓取第一个形如“时-分-秒”或“时_分_秒”的字段,统计小时分布。如果结果里大量样本集中在上午10点到下午3点之间,说明这批数据的光照条件相当一致,模型学到的“晴天”特征会比较纯粹;如果发现有凌晨或傍晚的样本混进来,那就是标签不干净,需要单独处理。参数说明:(\d{2})匹配两位数字,[-_]允许连字符或下划线作为分隔符,p.stem取文件名去掉扩展名的部分。

3. 用Python把Daytime-Sunny读成训练样本

3.1 最小读取脚本:glob遍历与显式排序

拿到27711张图片后,最容易犯的错误是直接依赖glob的返回顺序。文件系统对glob.glob的返回顺序在不同操作系统上不保证一致,Windows下可能是按文件名排序,Linux下则不确定。这会导致每次运行脚本时训练集和验证集的划分结果不同,模型结果无法复现。

我一般用pathlib.Path.glob配合显式的sorted()来固定顺序:

from pathlib import Path import random img_dir = Path("./Daytime-Sunny") all_images = sorted(img_dir.glob("*.jpg")) print(f"总图片数: {len(all_images)}") random.seed(42) indices = list(range(len(all_images))) random.shuffle(indices) train_idx = indices[: int(len(all_images) * 0.8)] val_idx = indices[int(len(all_images) * 0.8) :] train_files = [all_images[i] for i in train_idx] val_files = [all_images[i] for i in val_idx] print(f"训练集: {len(train_files)}, 验证集: {len(val_files)}")

逻辑说明:先对路径列表做sorted(),保证在多台机器、多次运行下顺序一致;再用random.seed(42)固定随机种子,确保划分结果可复现。这里的关键参数是0.8,即80%数据用于训练、20%用于验证,27711张图对应约22168张训练图和5543张验证图。如果你的下游任务是目标检测或语义分割,建议把比例调成0.85/0.15,因为检测任务对验证集的多样性要求更高。

3.2 从图片路径到训练/验证划分的内存管理细节

27711张图片的路径列表本身不占多少内存,但如果你打算把所有图片一次性读入内存做预处理,8GB内存的机器大概率会扛不住。假设每张图解码成RGB数组后平均占用约1.5MB(以720p分辨率估算),27711张图的裸数据就是40GB以上。常见做法是只保存路径列表,在训练循环里按需读取。

用PyTorch的Dataset类封装时,注意不要在__init__里做图片解码,只存路径:

from torch.utils.data import Dataset from PIL import Image class SunnyDataset(Dataset): def __init__(self, file_list, transform=None): self.file_list = file_list self.transform = transform def __len__(self): return len(self.file_list) def __getitem__(self, idx): img = Image.open(self.file_list[idx]).convert("RGB") if self.transform: img = self.transform(img) return img

把图片读取延迟到__getitem__里是性能关键。Image.open本身是惰性操作,只有真正调用.load().convert()时才会把像素数据读进内存。这样每个batch只占当前批量的内存,而不是一次性把27711张图全部装进去。如果训练时发现磁盘I/O成为瓶颈,优先用--num-workers调高DataLoader的进程数,而不是提前把所有图读进内存。

3.3 边界情况检查:空文件、坏图、重复样本

27711张图里混进几张坏图是常见情况,训练中突然报OSError: image file is truncated是典型症状。常见做法是用Pillow在训练前做一次全量损坏扫描:

from PIL import Image from pathlib import Path import io bad_files = [] for p in sorted(Path("./Daytime-Sunny").glob("*.jpg")): try: with Image.open(p) as img: img.load() except Exception: bad_files.append(str(p)) print(f"损坏文件数量: {len(bad_files)}") for f in bad_files[:5]: print(f)

img.load()会强制完成像素数据的读取,任何截断或格式错误都会在这里抛出异常。参数说明:with Image.open(p) as img确保文件句柄及时释放,避免文件数过多时耗尽文件描述符。如果扫描出损坏文件,建议直接移出数据集目录而不是原地修改,因为修复后的图片可能和原图光照条件不一致,混进训练集会引入噪声。

重复样本的检测则用文件哈希更快:计算每个文件的MD5,比对哈希值是否重复。27711张图做一次全量MD5大概需要几分钟,但能避免训练集和验证集之间存在同源图片。

4. 白昼晴天场景下的增强策略与类别不均衡处理

4.1 晴天数据做增强容易“增强过头”

Daytime-Sunny这27711张图的共同特征是光照充足、阴影锐利、天空区域多为蓝色或白色。直接用随机亮度抖动、随机色彩抖动这类通用增强,很容易制造出“假阴天”或“假黄昏”样本——但这恰恰是问题所在:你的任务是晴天下游任务时,过度增强会抹掉晴天特有的对比度和阴影特征,导致模型在真实晴天场景上表现反而变差。

以albumentations库为例,如果做语义分割或检测任务,我一般只用以下增强组合:

import albumentations as A train_transform = A.Compose([ A.HorizontalFlip(p=0.5), A.RandomBrightnessContrast(brightness_limit=0.05, contrast_limit=0.05, p=0.3), A.RandomGamma(gamma_limit=(90, 110), p=0.2), A.Resize(height=512, width=512), ])

参数说明至关重要:brightness_limit=0.05意味着亮度只做±5%的扰动,对晴天高光区域来说,超过10%的扰动就会让天空区域过曝到失去纹理;gamma_limit=(90, 110)对应Gamma校正的上下界,这个范围保持了晴天强烈的明暗对比。相比阴天或雨天数据集常用的RandomBrightnessContrast(0.3),这里刻意调低了扰动强度,核心思路是:晴天数据的核心特征是“高对比+锐利阴影”,增强的目标是增加样本多样性,而不是把晴天变成其他天气。

4.2 类别不均衡的三种常规解法

虽然整个数据集都是Daytime-Sunny,但在目标检测或语义分割任务里,内部样本之间仍然存在类别不均衡。例如行人、交通标志这类小目标在晴天场景下可能只占少数样本,而路面和天空占据大部分像素。三种常规解法各有适用场景。

第一种是类别重采样,对样本量少的类别对应的图片做重复采样,优点是不改图片内容,缺点是可能过拟合少样本类别。第二种是损失函数加权,在交叉熵损失里给少样本类别更高的权重,做法是在torch.nn.CrossEntropyLoss里传入weight参数:

import torch.nn as nn class_weights = torch.tensor([1.0, 2.0, 0.5]) # 按实际类别频次设定 criterion = nn.CrossEntropyLoss(weight=class_weights)

class_weights的取值逻辑是,类别出现频率越低,权重越高。比如行人像素占比只有路面的十分之一,权重可以设成路面类别的10倍。第三种是数据合成,对包含小目标的图片做粘贴增强,把行人或车辆贴到其他晴天背景图上,这个方案效果最好但成本最高。

4.3 显存有限时的批大小与分辨率取舍

27711张图片的Daytime-Sunny数据集中,如果做语义分割,输入分辨率直接决定显存消耗和训练时间。一个常见的取舍是,用512×512输入配合batch size 8,在11GB显存的GPU上跑ResNet50编码器的分割模型是可行的;如果提升到1024×1024,batch size必须降到2或3,训练时间则翻倍以上。

我建议用混合精度训练来节省显存,PyTorch自带的torch.cuda.amp可以在几乎不掉精度的情况下把显存占用降到原来的60%左右。使用方式简单:

from torch.cuda.amp import autocast, GradScaler scaler = GradScaler() for images, labels in dataloader: with autocast(): outputs = model(images) loss = criterion(outputs, labels) scaler.scale(loss).backward() scaler.step(optimizer) scaler.update()

autocast()自动将模型计算中的float32运算切换为float16,只保留必要的精度敏感操作(如损失计算)在float32下执行;GradScaler防止梯度下溢到0。参数说明:scaler.scale(loss)把损失放大若干倍,避免float16表示不了过小的梯度值,scaler.step(optimizer)在调用优化器前把梯度缩小回原始尺度。这样设置后,原本batch size 4才能跑得动的1024×1024输入,现在可以稳稳用到batch size 8。

5. 训练一条晴天语义分割基线的验证清单

5.1 用预训练权重做迁移的最小命令

如果你在Daytime-Sunny上训练语义分割模型,直接用随机初始化的编码器从头训练会非常慢,收敛效果也差。常见做法是利用ImageNet或Cityscapes预训练的权重做迁移学习。以MMSegmentation框架为例,最小训练命令长这样:

python tools/train.py configs/pspnet/pspnet_r50-d8_4xb2-40k_cityscapes-512x1024.py \ --work-dir ./work_dirs/daytime_sunny \ --load-from /path/to/pretrained_weights.pth

--load-from指定加载预训练权重的路径,模型会保留编码器部分的权重,只重新初始化解码器;--work-dir指定日志和checkpoint的输出目录。前提是你的数据集结构能被MMSegmentation的CustomDataset类正确读取,通常要求图片和标签各放在一个目录下,且文件名一一对应。

如果没有现成的标注文件,只是在做图像分类或自监督预训练,可以用torchvision.models加载ImageNet权重:

import torchvision.models as models model = models.resnet50(weights=models.ResNet50_Weights.IMAGENET1K_V1) num_classes = 10 model.fc = torch.nn.Linear(model.fc.in_features, num_classes)

weights=models.ResNet50_Weights.IMAGENET1K_V1是PyTorch官方推荐的加载方式,比直接传pretrained=True更明确;替换最后一层全连接为自定义类别数是分类任务的常规操作。

5.2 三个必看的验证指标与计算方式

训练收敛后,不要只看一个mIoU或准确率就收工。针对Daytime-Sunny这类白天晴天数据集,我会额外盯三个指标。

第一个是mIoU,语义分割的标准指标,主要反映整体分割质量;第二个是晴天高光区域的IoU,单独算天空、白色车辆、反光路面这三类的IoU,能暴露模型是否把高光区域错误地归为“未知”类别;第三个是类别混淆矩阵中对“阴影”和“晴天路面”的错分率,这两个类别在正午阳光下区别很小。

计算天空区域单独IoU的方法是在验证脚本里过滤预测和标签都只保留天空类别的像素:

import numpy as np def class_iou(pred, label, class_id): pred_mask = (pred == class_id) label_mask = (label == class_id) intersection = np.logical_and(pred_mask, label_mask).sum() union = np.logical_or(pred_mask, label_mask).sum() return intersection / (union + 1e-6)

1e-6是平滑项,避免union为零时出现除零错误。这个函数的逻辑是:先为指定类别生成布尔掩码,再分别计算交集和并集像素数,最终得到该类别单独的交并比。

验证指标计算方式晴天场景下的正常范围
天空类IoU预测与标签的天空像素交并比0.85以上
阴影类别召回率真实阴影像素中被正确识别的比例0.60-0.75
晴天路面误检率非路面像素被预测为路面的比例低于0.10

5.3 边界场景测试:晴天样本里故意混入阴天

验证模型是否真的学会了“晴天”特征,一个有效方法是把晴天测试集和少量阴天图片混合在一起做鲁棒性测试。具体做法是:取500张Daytime-Sunny验证图,再找500张阴天图片,混合后分别计算模型在两组样本上的表现差异。如果模型在晴天样本上的mIoU是0.75,在阴天样本上掉到0.30,说明模型对天气高度敏感,这不一定是坏事;但如果你的目标是一个通用的驾驶感知模型,就需要对训练策略重新审视,比如额外加入阴天样本做域适应,或者调整增强策略中的颜色扰动幅度来提升跨天气泛化能力。

另外一个容易被忽略的验证技巧是检查模型是否过度依赖天空区域的蓝色通道做决策。做法是在验证图上把天空区域替换为灰色,再跑一次推理,观察下游目标的检测置信度变化。置信度暴跌说明模型学到的“晴天”特征高度依赖天空色彩,而缺乏对地面目标纹理的理解。这个测试不需要额外标注,用一个掩码把天空区域像素值拉平就能做,值得在Daytime-Sunny这27711张图上落地。

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

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询