☰
9000样本天气分类数据集构建与模型训练全流程实战
2026/10/16 7:39:02 网站建设 项目流程

简介:这是一份面向计算机视觉初学者与深度学习实践者的天气图像分类数据集,适用于图像识别、CNN模型训练及多类别分类任务教学与科研。数据集共9000个样本,涵盖14类典型天气现象(如cloudy、rain、snow、sunrise、fogsmog等),已按标准划分训练集(7180张)与测试集(808张),目录结构清晰(data/train_data / data/test_data),开箱即用。压缩包含2000个文件,主体为7987张JPG格式天气实拍图(命名规范,含类别前缀),辅以1个Python训练脚本和1张说明PNG图,总大小676.81MB,便于本地加载与迁移学习。已有1118人下载学习,配套CNN模型在该数据集上可达96.3%准确率,提供可复现的基线性能参考;读者可直接用于模型微调、数据增强实验、混淆矩阵分析及14细粒度天气场景识别系统开发。 天气分类数据集这件事,我算是被逼着才动手做的。当时接了一个户外场景识别的项目,需要先判断天气再走后续逻辑,翻遍了公开渠道,要么是几千张的小规模demo,要么类别只有晴天、多云、雨、雪四类,雾天和阴天基本是混在一起的。后来一咬牙,自己攒了一个9000样本的天气分类数据集,从采集、清洗到训练、部署走完了一遍全流程。这篇文章就把整个过程中的关键决策、踩过的坑、以及最终沉淀下来的方法完整记录下来,给正在做或打算做类似视觉分类任务的朋友一个可以直接参考的样本。

1. 天气分类这件事,为什么比想象中难

很多人一听“天气分类”就觉得简单,不就是给图打个标签吗。真正做了之后才发现,这是典型的“看起来容易、做起来处处是坑”的视觉任务。

1.1 天气不是一个实体,而是一组视觉特征的综合表现

先想一个本质问题:人在看到一张户外照片时,是怎么判断“今天是晴天”的?靠的是天空区域的比例和亮度、阴影是否存在且锐利、光线照射角度、地面和建筑表面的反射特性、空气中颗粒物的能见度等等。这些线索聚合在一起,才形成一个“晴天”的认知。

这就导致天气分类和猫狗分类有本质区别。猫有眼睛、耳朵、胡须这些明确的语义部件,深度学习模型可以通过提取局部纹理特征来识别;但天气没有固定的“部件”,它是一整张图的全局视觉状态。晴天和阴天的差异可能只是天空区域亮度的梯度变化,雨天和雾天都具备低能见度特征,但前者是雨丝造成的动态模糊,后者是气溶胶散射造成的均匀灰蒙。

这种全局性、模糊性的特征,对数据集构建提出了很高要求。如果采集样本时不考虑场景多样性、光照方向、拍摄设备差异、画面中是否有人为前景遮挡等因素,模型很容易学到“天空在画面顶部有多亮”这种粗暴的捷径特征,换一批真实场景就崩。

1.2 9000个样本的规模,是拍脑袋定的吗

先从需求反推。六分类任务,每类如果期望达到90%以上准确率,常规经验是每类样本量不少于数据维度承载能力的一个下限。我在实践中发现,对于ImageNet预训练模型做微调,每类1200到1500张图基本能收敛出稳定的决策边界;少于800张时,雨天和雾天这类边界模糊的类别很容易出现振荡。

9000这个数字,其实是“每类1500张 × 6类”算出来的理想值。但真实采集过程中会发现,有些类别很容易凑(晴天、阴天),有些类别极难凑到均衡(雷暴、雪天),所以最终每个类别的数量并不完全一致,整体规模定格在9000。这个数量级的另一个好处是训练时间可控,单卡环境下用ResNet50微调,20个epoch大概在一个多小时跑完,可以快速迭代验证清洗效果和数据增强策略是否有效。

2. 数据采集渠道与清洗策略:9000张图是怎么攒出来的

数据来源和清洗过程,是整条流水线里最耗时、最乏味、也最容易被低估的环节。这里直接把我的渠道配比和踩坑经历摊开讲。

2.1 三个主要采集源头与配比

我最终用的是三路来源的混合方案,不是单一渠道,原因是单一渠道会导致严重的数据偏置。比如全用网络图片搜索,模型会学到搜索引擎结果特点——大量高清、构图标准、带后期调色的图片,部署到真实监控画面时直接水土不服。

来源渠道及大致占比:

来源渠道占比说明
公开天气数据集约35%整合了多个公开数据集中的天气相关子集,但只取其中场景相对真实、不包含水印和标注框的图片
网络图片搜索引擎约40%按“晴天、阴天、雨天、雪天、雾天、雷暴”等多组关键词组合检索,覆盖不同地域和季节
实拍与街景截帧约25%用行车记录仪和手机在城市、郊区、山区、高速等场景拍摄,再从视频中截帧

为什么坚持保留实拍和街景截帧这一路?因为这是唯一能保证“设备真实感”的数据来源。网络图片大多是摄影作品,构图考究,天气特征被艺术化放大;而模型最终要部署在监控探头、车载摄像头这类常规设备上,画面可能存在偏色、噪点、镜头畸变甚至遮挡。没有真实设备画面兜底,验证集指标再高也心虚。

2.2 清洗过程中最耗费时间的细分类目

清洗是数据集中间最容易出问题的一环。9000张原始图里,能直接用的可能只有一半稍多。我逐类过了一遍,总结出几类高频废弃样本:

  • 多天气混杂:画面下半部分是雪地,上半部分却是晴空蓝天。这种样本无法给出唯一标签,直接删除。
  • 低质量强噪声:严重过曝、完全黑场、运动模糊到看不清任何场景结构。这类图连人类都无从判断,就不该进入训练集。
  • 天气特征被遮蔽:画面被大面积广告牌、建筑物墙体占满,天空占比不足5%,即使知道当天天气也无从判断。
  • 搜索引擎带水印和文字叠加:尤其是带新闻台标的画面,模型会学到“台标位置有文字”这种无关特征。

清洗是一件需要耐心但不需要太多技术含量的事情。效率最高的做法是先用一个粗筛脚本,按文件大小和基本亮度直方图剔除明显垃圾样本,再做人工逐图检查。9000张原图,我用两个晚上完成了第一轮粗筛,又用一周碎片时间做了逐类细筛。

3. 类别体系设计:分几类、边界画在哪

类别体系的设计直接决定了任务难度上限。分得太粗,模型自然容易收敛,但落地时价值低;分得太细,类别之间重叠严重,标注一致性迟早出问题。

3.1 六分类体系的判定标准

我最终采用的是“晴天、阴天、雨天、雪天、雾天、雷暴”六分类方案。这个方案参考了气象学中天气现象的基本分类,同时兼顾了视觉可分辨性。关键在于,每个类别必须有明确的视觉判定标准,而不是模糊的日常感受:

  • 晴天:天空区域存在明显亮度梯度,日照产生清晰阴影或高光反射,整体色温偏暖。
  • 阴天:天空亮度均匀且偏低,云层厚实,无明确阴影边界,光线方向不可辨识。
  • 雨天:画面中存在雨丝、雨滴或地面积水反光,能见度低于晴天但高于雾天的均匀灰蒙。
  • 雪天:地面、屋顶或植被存在积雪覆盖区域,通常伴随灰白色天空。
  • 雾天:能见度显著降低,远近物体对比度差异明显,天空区域与地面建筑边界模糊。
  • 雷暴:云层极厚且低垂,画面整体偏暗,可能包含闪电亮斑、暴雨或冰雹特征。

这个判定标准不仅是给标注者用的,也是给模型划定的决策边界。比如一张图里地面湿漉漉但天空灰亮,没有明显雨丝,这种我归入阴天而不是雨天——因为从视觉特征上讲,它不具备“雨”的直接证据,宁可让模型在阴天和雨天边界处犯一点错,也不要让内部标签自相矛盾。

3.2 容易混淆的边界样本怎么处理

最让人头疼的类别组合有两对:阴天与雨天、雾天与阴天。

阴天和雨天的混淆点很好理解:雨后地面积水反光,但天空已经亮开,此时残留的“湿”特征和“阴”特征同时存在。我的处理策略是引入“当前天气状态”的概念,即标签反映的是拍摄时刻画面呈现的最显著天气现象,而不是过去几小时发生过什么。地面有积水但无雨滴、天空泛亮,就应该标阴天。

雾天和阴天的混淆则更隐蔽。浓雾天气的天空本身也是灰白色,和阴天天空视觉差异极小。两者的判别关键在“中低空物体的清晰度”:雾天中远处楼宇、树木轮廓被大幅度模糊且边缘弥散,阴天只是光线暗,物体轮廓依然是锐利的。清洗时我会放大局部区域逐张确认,这一对类别的耗时基本上是其他类别的好几倍。

4. 预处理与数据增强:把每个样本的价值榨干

数据集的“质”来自清洗和类别设计,“量”的价值则需要预处理和数据增强来充分释放。9000张图说多不多,说少也不少,关键是让模型从有限样本里学到真正的泛化特征。

4.1 尺寸统一与归一化细节

所有图片在送入模型前统一处理为224×224分辨率,这是ResNet系列和EfficientNet系列的标准输入尺寸。处理方式上不是简单缩放,而是在缩放前先做短边对齐裁剪,避免画面比例被强行压扁导致天空区域的形态失真。

归一化参数我沿用ImageNet统计值,均值[0.485, 0.456, 0.406],标准差[0.229, 0.224, 0.225]。很多新手会忽略一个细节:如果数据集本身有明显色偏(比如监控画面偏绿偏蓝),可以在归一化之前加一个自适应白平衡或直方图均衡化步骤,但这可能同时削弱季节特征的表现力。天气分类里,色温本身就是一种天气特征,所以我强烈建议不要做重度的色彩归一化,保留原始色偏,让模型自己去利用这些线索。

数据划分上,我采用85%训练、5%验证、10%测试的比例。因为是按类别分别切分的,每个类别内部都按这个比例抽,避免出现某一类在测试集中缺失的极端情况。最终训练集约7650张,验证集450张,测试集900张。

4.2 数据增强策略的取舍

数据增强不是越多越好,每一项增强都会对特征分布产生特定影响。我实际启用的增强管线如下:

  • 随机水平翻转:概率0.5,对所有类别都安全,天空区域水平翻转不会改变天气含义。
  • 随机旋转:±10度,超过这个范围会造成地平线明显倾斜,破坏场景常识。
  • 随机亮度/对比度调整:幅度±20%,可以增强模型对曝光差异的鲁棒性,但幅度不能过大,否则晴天可能被调成阴天的亮度分布。
  • 随机色彩抖动:亮度、对比度、饱和度、色相的小幅组合扰动,帮助模型不依赖特定色温。
  • 随机裁剪缩放:0.8到1.0倍缩放后再裁剪到224×224,模拟不同拍摄距离下天气特征呈现的比例差异。

有两个增强我故意没有加:一是高斯噪声,二是随机擦除。原因是天气分类对纹理细节敏感,雨丝、雪片、闪电亮斑这些关键线索都是局部细节,加噪声或擦除会直接破坏这些微小却强判别力的特征。

实际验证下来,这套增强策略在验证集上带来了约3个百分点的提升,更重要的是增强了模型对实拍画面的适应性。测试集里我特意混入了一批没有参与训练的不同地区街景截图,准确率下降幅度在可以接受的范围内。

5. 模型选型与训练配置:为什么迁移学习是捷径

9000张图对深度学习模型来说,说多不多。如果从零训练一个ResNet50,这个数据量远不足以让底层卷积核学到足够丰富的通用视觉特征。迁移学习几乎是唯一合理的选择。

5.1 从零训练还是微调:算一笔账

从零训练的代价不仅体现在时间和算力上,更体现在收敛效果上。ImageNet预训练模型的底层特征(边缘、纹理、颜色块组合)是来自千万级图片的通用知识,这些特征和天气分类所需的基本视觉单元高度重合。微调时只需要将高层特征重新组合,形成适应天气语义的决策结构。

具体选型上我对比过ResNet50和EfficientNet-B0。ResNet50训练稳定、生态成熟、推理速度快,在1080Ti上单卡训练毫无压力;EfficientNet-B0理论精度更高,但对学习率和正则化参数更敏感,调参成本高。最终选用ResNet50,但把最后一层全连接替换为6输出的分类头,同时将分类头初始学习率设置为其他层的10倍。

5.2 超参数配置与训练结果解读

训练配置如下:

  • 优化器:AdamW,初始学习率1e-3(分类头),主干部分1e-4
  • 批次大小:32
  • 训练轮数:30个epoch
  • 学习率调度:余弦退火衰减,最低降到初始学习率的1%
  • 权重衰减:1e-4
  • 损失函数:交叉熵损失(类别不平衡不明显时不需要加权)

训练过程中我记录了每个epoch的训练损失、验证损失和验证准确率。一个值得注意的现象是第3到第5个epoch验证准确率会快速增长到88%左右,之后进入缓慢提升期,到第18个epoch稳定在93%附近,后续几乎不再有波动。如果看到验证损失在后期不再下降甚至反弹,就该及时早停,不必盲目跑满30个epoch。

最终测试集上的分类报告显示:晴天、阴天、雪天的F1分数都超过了94%,雨天和雾天在91%左右,表现最差的是雷暴,F1约87%。雷暴的短板在于数据量本身最少,且闪电亮斑在缩放到224×224后变得不显著,这是特征尺度导致的固有限制,目前靠数据规模本身难以完全解决。

6. 训练中踩过的坑:类别不均衡与样本噪声

没有哪一次训练是顺利到底的。这里把我在反复迭代中真正踩过、也真正解决了的问题记录下来。

6.1 噪声样本对收敛的影响

第一版数据集的清洗不够彻底,尤其是雪天和雷暴类混入了一些“夜晚灯光下的雨雪反光”画面。训练出来的模型在验证集上准确率尚可,但测试集误判率偏高。把误判样本拉出来逐张看,发现好几个晴天图被模型判成雪天。

原因很快定位上:部分夜间灯光画面在缩略图中呈现出白色点状高光,和雪片的视觉特征高度相似。模型学到了“大量离散白色亮点”这个特征,而这个特征在夜间城市灯光画面中同样存在。这就是典型的样本噪声引入错误偏置。

修复方式不是简单删除,而是重新审视“雪天”类别的判定标准,明确加入“环境光照充足、积雪覆盖连续区域”这一条件。夜间灯光下的动态雨雪、夜景灯光反光一律排除,能明确识别的夜晚画面在雨天、阴天类中也做了逐一排查。

6.2 混淆矩阵暴露的真实问题

训练中期,我对验证集做了一次详细的混淆矩阵分析,发现两个顽固的混淆对:一是雷暴被误判为阴天,二是雨天被误判为雾天。

雷暴被误判为阴天,根因是雷暴样本中很大一部分画面只有厚重暗云层,没有出现闪电亮斑。人眼知道这是雷暴来临前的气象,但视觉特征上它和阴天的差异确实有限。这个问题的解决思路是在类别标准上做了细化:雷暴类仅保留那些有闪电亮斑、明显强降雨、或云层结构极端低垂压迫感的样本,避免把“即将雷暴”的阴天画面硬塞进雷暴类。

雨天和雾天的混淆则是物理层面的困难:雨滴在静态帧上可能并不清晰,而雨天的低能见度和雾天在特定角度下确实视觉相近。我尝试了添加“地面湿润反射”这一人工规则,在后期处理时仍保留了一部分边界样本,允许模型对这类模糊输入给出51%对49%级别的置信度,而不是强行要求每一个测试样本都给出确定答案。对工程落地来说,知道“不确定”比知道“错答案”更有价值。

7. 评估指标与部署经验:不只是个准确率

模型训练完成只是第一步,真正让它产生价值的是评估和落地部署。这个环节的一些做法,和单纯跑模型是有明显区别的。

7.1 为什么准确率够用还不够

准确率是全局指标,但天气分类在落地时通常不是孤立模型,而是下游逻辑链中的一环。比如识别到雨天就启动雨刷、识别到雾天就提醒降低车速,这意味着不同类别的误判代价完全不同:雾天误判为晴天,代价远高于晴天误判为阴天。

因此评估时我重点看每一类的精确率和召回率,而不只盯着总体准确率。精确率低意味着模型频繁把其他天气误判成当前类,召回率低则意味着当前类大量被漏检。以雷暴为例,模型虽然整体F1只有87%,但精确率达到91%,说明“报警为雷暴”时绝大多数情况下是真的雷暴,这对安全告警场景非常关键。

另一个实用指标是置信度校准。部署时如果设定“置信度低于0.7就进入人工确认流程”,那么模型的置信度分数必须真实可靠。我测试发现ResNet50的softmax输出存在轻微过自信倾向,实际修正方法是在验证集上统计每个置信度区间内的真实准确率,然后做一个阈值映射表。这个操作耗时短,但直接提升了人机协同场景下的体验。

7.2 落地部署时的一个经验

模型最终部署时,我选择导出为ONNX格式,用ONNX Runtime做推理。相比直接用PyTorch推理,ONNX导出后推理速度提升约20%,并且可以脱离Python环境运行,方便嵌入到C++边缘设备里。

部署时有一个细节:输入图片的预处理必须和训练时保持一致。这个要求说起来简单,实际调试中很容易翻车。比如调用摄像头帧时,图片默认是BGR通道顺序,如果不做RGB转换直接送入模型,模型对颜色的理解会完全错乱,晴天和阴天这类主要靠色温和亮度区分的类别准确率会大幅跳水。我当时在这个问题上排查了小半天,最后发现就是一行通道顺序的代码写反了。

7.2.1 一个小技巧:把预处理封装成独立函数

建议把“读取图片、缩放、归一化、通道转换、维度拓展”完整封装成一个独立函数,并且用一张已知类别的图片做端到端验证。保证训练脚本和部署脚本调用同一个预处理函数,避免两份逻辑不一致。

7.2.2 关于后续扩展

这套流程跑通之后,后续遇到其他细粒度图像分类任务,比如路面状态识别、植被类型判断、建筑风格分类,基本可以直接复用。数据采集、清洗流程、类别边界定义、迁移学习微调、混淆矩阵分析、模型导出部署,这一条流水线是通用的。不同的任务只是在类别判定标准和数据来源上有所调整,核心方法论完全一致。

我实际做下来,最大的体会是:9000张图的数据集规模并不大,真正决定模型效果的不是GPU型号和数据总量,而是数据质量的控制力和对类别语义的深入理解。把这些基础工作做到位,一个不到一百行的训练脚本也能训练出可部署的实用模型。

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

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

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

立即咨询