ARTICLE DETAIL

资讯详情

深耕郑州网站建设与运营推广的一线实战洞察。

卫星云图识别大作业:基于PyTorch的迁移学习实战指南

卫星云图识别大作业:基于PyTorch的迁移学习实战指南 简介一份面向计算机视觉课程设计与期末大作业的完整资源包聚焦卫星云层图像的理解与识别任务适合高校学生、初学者及需要快速完成课程项目的人群。资源包含140个文件主要有70个Python源码文件、44个编译后的pyc文件、5个CSV数据集、3个YAML配置及实验报告PDF、演示PPTX等源码含详细注释结构清晰便于理解与二次开发。压缩包大小62.35MB覆盖数据处理、模型训练、测试评估等完整流程并附带结果图片和说明文档部署简单、功能完善。已有216人学习下载是期末大作业、课程设计高分参考的实用选择。读者可直接获得完整实现方案、实验报告模板及可运行代码快速上手卫星云层图像识别项目。1. 卫星云层图像的理解与识别这门大作业到底在练什么第一次拿到“卫星云层图像的理解与识别”这个计算机视觉大作业时很多人第一反应是找现成的 python 源码跑通就收工。结果交上去分数不高因为老师要看的是你对图像识别任务的理解过程而不只是最终准确率。云图识别是一个很适合做课程项目的题目它不要求从零发明深度学习模型但足够考验数据清洗、标签设计、模型选型和实验对比。这篇笔记会把这类项目的完整落地路径拆开讲——从任务定义到训练调参再到实验报告怎么写最后把最容易被忽略的几个坑点出来。适合正在做计算机视觉大作业、想用卫星云层图像做图像识别入门项目的同学也能给需要快速复现的人留一条可走通的路。2. 先想清楚要“理解”什么云图分类任务定义与数据集准备2.1 二分类、多分类还是语义分割先做对选择题“理解”这两个字在计算机视觉大作业里非常宽泛落到可执行层面一般是三条路线二分类、多分类、语义分割。卫星云层图像的语义分割需要逐像素标注积云、层云、卷云和积雨云的轮廓手动标注一张 1024×1024 的云图要花掉的时间远超训练模型公开带掩膜的云图数据集又很少所以我不建议一上来就做分割。二分类只判断“有云”还是“无云”代码最简单但报告可写的内容太少容易让老师觉得项目工作量不够。多分类是性价比最高的选择我一般建议做四分类晴空、层云、积云、积雨云。这个类别组合既有明显的视觉差异也有容易混淆的相似纹理正好可以把图像识别算法里的特征提取、数据增强、类别不平衡这些问题全部带出来。选定类别之后下一步是搞到数据。常见做法是从气象卫星公开数据里截取云图或者直接用课程老师提供的卫星云层图像压缩包。这类数据的格式通常很不统一有的是单通道灰度图有的是三通道伪彩色图尺寸从几百乘几百到几千乘几千都有甚至有的图带经纬度水印或边框。拿到手以后不要直接丢进模型先写一个脚本把图片统一成同一个尺寸和通道数否则后面 DataLoader 会报出一堆莫名其妙的维度错误。我习惯把一个类别的图片放进一个子目录这样 torchvision 的 ImageFolder 可以直接按目录名生成标签省掉自己维护 csv 标签表的麻烦。2.2 用 Python 把卫星云图读进来目录组织与预处理代码目录结构定了之后预处理逻辑就固定了。下面的代码是 PyTorch 项目里最常见的数据加载片段先 Resize 到 224×224再转成 Tensor最后做标准化。import torch from torchvision import datasets, transforms from torch.utils.data import DataLoader transform transforms.Compose([ transforms.Resize((224, 224)), transforms.ToTensor(), transforms.Normalize(mean[0.485, 0.456, 0.406], std[0.229, 0.224, 0.225]) ]) # 目录结构 # cloud_dataset/clear/xxx.png # cloud_dataset/stratus/xxx.png # cloud_dataset/cumulus/xxx.png # cloud_dataset/cumulonimbus/xxx.png full_dataset datasets.ImageFolder(rootcloud_dataset, transformtransform) train_size int(0.8 * len(full_dataset)) val_size len(full_dataset) - train_size train_dataset, val_dataset torch.utils.data.random_split( full_dataset, [train_size, val_size]) train_loader DataLoader(train_dataset, batch_size32, shuffleTrue, num_workers4) val_loader DataLoader(val_dataset, batch_size32, shuffleFalse, num_workers4) print(类别映射:, full_dataset.classes)这段代码里有两个地方要特别说。第一个是Resize((224, 224))这个尺寸是 ResNet 的默认输入也是大部分预训练模型的常用输入。如果你最后用的是 ViT 之类的大模型224 不一定合适但对课程作业来说224 是兼顾显存和精度的保守选择。第二个是Normalize用的 mean 和 std这里复制的是 ImageNet 的统计值因为后面要加载 ImageNet 预训练权重。如果云图本身是灰度图下面章节会单独讨论通道问题不能无脑套这个标准化。2.3 数据增强要克制云图不是普通照片数据增强在云图识别里属于“能做但别做过头”的操作。随机水平翻转、小角度旋转、随机裁剪这几项对云图基本是安全的因为卫星云层图像不依赖方向性语义翻转之后仍然是一张合理的云图。但随机擦除、强色彩抖动这类增强手段我一般不用它们会把云层边缘和薄云细节洗掉反而让模型更难学习真正的纹理特征。还有一个特别容易踩的坑不要做任意角度的垂直翻转叠加。某些极地地区的云图可能因为卫星扫描方式不同南北方向的光照特征不一样垂直翻转会制造出训练阶段不存在的光照分布。增强只应该加在训练集上验证集和测试集保持固定预处理就够了。否则验证集和训练集分布不一致你会分不清准确率波动是模型问题还是数据增强把人搞晕了。下面这段增强是我的常用配置强度不高适合大多数云图数据集。import torch from torchvision import transforms train_transform transforms.Compose([ transforms.Resize((224, 224)), transforms.RandomHorizontalFlip(p0.5), transforms.RandomRotation(degrees10), transforms.ToTensor(), transforms.Normalize(mean[0.485, 0.456, 0.406], std[0.229, 0.224, 0.225]) ]) val_transform transforms.Compose([ transforms.Resize((224, 224)), transforms.ToTensor(), transforms.Normalize(mean[0.485, 0.456, 0.406], std[0.229, 0.224, 0.225]) ])注意RandomRotation(10)的旋转角度是基于图像中心转的对于正方形 Resize 后的图片不会产生黑边问题这也是我先把图 Resize 成 224 再做增强的原因之一。如果你先做大尺寸随机旋转再裁剪就很可能把大量黑边带进训练集模型会额外学习“黑边 某种云”的假相关。3. 用 PyTorch 训练一个能用的云图分类模型ResNet 迁移学习3.1 为什么选 ResNet 而不是自己造 CNN很多同学做作业时喜欢从零写一个几层卷积的 CNN理由是“代码是自己写的老师会觉得更真实”。这个想法没错但实际效果通常很差。卫星云层图像的类别差异很多时候体现在高频的边缘和局部的纹理密度上自己搭的浅层网络没有足够的感受野全靠低层特征做判断在验证集上的表现反而不如迁移学习。课程作业的评分点通常包括最终效果和实验设计不是“你有没有手写卷积层”。相比之下ResNet18 是一个非常稳的基座它结构简单、预训练权重好找、显存占用小而且残差结构让深层网络的梯度传导稳定适合小批量和短训练周期。从任务特点看ImageNet 预训练模型的低层特征——边缘、角点、颜色纹理——对云图是有迁移价值的。云层边界和自然图像里的物体边界在视觉结构上有很多共同点真正需要从数据里重新学习的是云层整体形态的组合方式这些恰好是高层特征做的事。所以我一般把 ResNet18 作为第一版模型跑通以后再考虑要不要换 ResNet34 或 EfficientNet。千万不要第一版就上 ViT 或者大模型云图数据量通常只有几千张没有足够数据把 ViT 喂饱最后很容易陷入过拟合和一通乱调。3.2 最小可跑的训练脚本下面这个训练脚本是我习惯的“最小可跑版本”重点不是炫技而是让整个流程短到能在一个晚上跑通。它包含加载预训练模型、替换全连接层、AdamW 优化器、余弦退火和训练状态保存。import torch import torch.nn as nn from torchvision import models device torch.device(cuda if torch.cuda.is_available() else cpu) model models.resnet18(pretrainedTrue) in_features model.fc.in_features model.fc nn.Linear(in_features, 4) # 四个云图类别 model model.to(device) criterion nn.CrossEntropyLoss() optimizer torch.optim.AdamW(model.parameters(), lr1e-4, weight_decay1e-4) scheduler torch.optim.lr_scheduler.CosineAnnealingLR(optimizer, T_max20) def train_one_epoch(): model.train() total_loss, correct, total 0.0, 0, 0 for images, labels in train_loader: images, labels images.to(device), labels.to(device) optimizer.zero_grad() outputs model(images) loss criterion(outputs, labels) loss.backward() optimizer.step() total_loss loss.item() * images.size(0) _, preds torch.max(outputs, 1) correct (preds labels).sum().item() total labels.size(0) return total_loss / total, correct / total for epoch in range(20): train_loss, train_acc train_one_epoch() print(fepoch {epoch1:02d} loss {train_loss:.4f} acc {train_acc:.4f}) if epoch 10: scheduler.step()这里有两个值得展开的参数。第一是lr1e-4对迁移学习来说预训练权重已经足够好学习率太高会把已经学到的底层特征破坏掉。实际调参时如果发现训练初期 loss 乱跳先把学习率降一半。第二是weight_decay1e-4这个 L2 正则能压住一些过拟合但不要设到 1e-2 这种级别否则模型在验证集上的表现会被明显压低。另外注意scheduler.step()我放在第 10 个 epoch 之后才更新因为前几个 epoch 需要让模型先把分类头拟合好太早衰减学习率反而拖慢收敛。3.3 训练完先看混淆矩阵别看总准确率训练完一轮之后第一件事不是改参数而是把验证集上的混淆矩阵打出来。云图数据集经常是不平衡的总准确率可能很高但其中某个稀有类别完全没被识别出来。只看准确率会让你误以为模型没问题等你交作业时老师随机抽几张积雨云图一看全是错分数就保不住了。混淆矩阵能看到误判方向比如层云经常被认成积云说明模型在云层厚度特征上的区分度不够如果晴空误判成积云说明模型把地表纹理和云团边界混在一起了。import numpy as np from sklearn.metrics import confusion_matrix, classification_report model.load_state_dict(torch.load(best_model.pth)) model.eval() all_preds, all_labels [], [] with torch.no_grad(): for images, labels in val_loader: images images.to(device) outputs model(images) _, preds torch.max(outputs, 1) all_preds.extend(preds.cpu().numpy()) all_labels.extend(labels.cpu().numpy()) all_preds np.array(all_preds) all_labels np.array(all_labels) print(classification_report(all_labels, all_preds)) print(confusion_matrix(all_labels, all_preds))classification_report里每个类别的 precision 和 recall 要单独看。如果某类的 recall 很低而 precision 很高说明模型很少把它预测出来一旦预测出来基本是对的这时候优先要解决召回率问题。处理手段我会在下一章讲一般从类别加权损失和数据增强入手而不是盲目加模型深度。4. 实验报告与调参分数高低从这里拉开4.1 三个最值得调的参数学习率、批次大小、输入分辨率云图识别项目里与其把十几个参数全部揉进报告不如认真做三个核心参数的对照实验。学习率决定模型能不能稳定收敛批次大小决定梯度估计的稳定性和显存占用输入分辨率决定云层细节的保留程度。这三个参数都直接影响最终准确率而且实验次数少、描述清楚老师也愿意看。参数推荐范围调参理由学习率1e-4 到 3e-4迁移学习下不宜太大否则破坏预训练卷积层批次大小16 到 64太小梯度噪声大太大显存不够且收敛变慢输入分辨率224 到 384云层细节需要足够像素支撑但过高会明显拖慢训练我一般会以 batch_size32、lr1e-4、resolution224 作为基准组然后每次只改一个变量做一个三组以内的对比。云图的分辨率尤其值得做一次对照很多公开云图原图是 2048×2048直接缩到 224 会丢掉卷云那种细丝状结构。如果显存允许建议把分辨率提到 320 或 384观察准确率提升幅度如果提升很小说明这个数据集的主要难点不在细节分辨率继续增大输入只会浪费显存。4.2 类别不平衡给损失函数加权卫星云层图像天然存在类别不平衡。晴空和层云可能出现几百张积雨云可能只有几十张。直接用普通交叉熵训练模型会把所有不确定样本都推到样本量大的类别上。常见的做法是用compute_class_weight算出每个类别的权重然后把它传给CrossEntropyLoss让少数类别在计算梯度时获得更高的信号强度。import numpy as np import torch from sklearn.utils.class_weight import compute_class_weight all_labels [sample[1] for sample in full_dataset.samples] class_names full_dataset.classes weights compute_class_weight(balanced, classesnp.unique(all_labels), yall_labels) weights_tensor torch.tensor(weights, dtypetorch.float).to(device) criterion nn.CrossEntropyLoss(weightweights_tensor)加权重之后有两种结果整体准确率略微下降因为模型不再倾向于把样本都塞到多数类里但少数类的 recall 通常会明显上升。这是合理的因为大作业评估的是模型对全部类别的识别能力而不是某一个类别的准确率。写实验报告时直接把“加权前/加权后”的各类别 precision、recall 对比放进去说明这个设计决策对分类边界的影响正好体现了你对图像识别任务的理解。4.3 高分实验报告的内容骨架实验报告不需要写成长篇小说但要能回答清楚三件事数据是什么、模型为什么这样选、结果说明了什么。我见过不少高分项目模型并不比别人的先进但报告里把每个实验决策解释得很清楚。建议按下面这个顺序组织数据集说明每类样本数量、图像来源、尺寸范围、标注方式最好附一张四类云图的样例图。任务定义和评价指标多分类任务、类别名称、总准确率之外还要列 macro-F1。基准模型ResNet18 迁移学习说明为什么选择残差结构。对照实验学习率、分辨率、类别不平衡处理附训练曲线和混淆矩阵。错误分析找出混淆最严重的一组类别结合云图形态解释原因。报告里最值钱的部分是最后的错误分析。比如“层云和积云混淆因为两者在大尺度遥感图像上都表现为连续成片的白云区域区别只在云顶高度和厚度而单张可见光图像很难反映厚度信息”。这种话比任何调参技巧都更能说明你读懂了实验结果。5. 云图识别避坑五个高频翻车现场与排查路径5.1 验证集高、新图废时间分布偏移现象随机划分训练集和验证集的时候准确率能到 93%拿另一段时间的云图来测准确率突然掉到 70%。原因你把同一颗卫星同一时间段的数据打乱混进了训练集和验证集模型可能已经记住了那个时间段的色偏、太阳高度角特征和传感器响应而不是真正的云层纹理。解决按时间划分数据比如前 80% 的时间段作为训练集后 20% 作为验证集。如果数据没有时间戳至少按文件名的拍摄顺序排序后划分不要完全随机打散。5.2 太阳耀斑和极地反光把模型带偏现象模型把海面上的太阳耀斑区域识别成积雨云或者把雪亮的极地地表识别成晴空。原因可见光云图高反射亮区在数值上看起来和厚的冷云高度相似模型只靠绝对亮度做判断没有学到云层纹理和空间连续性。解决在预处理里做标准化时必须按真实数据分布重新计算 mean 和 std而不是直接抄 ImageNet 参数如果有红外通道数据优先用红外通道它反映的是云顶温度抗太阳耀斑能力更强。另外可以故意保留一部分带高反射噪声的样本作为负样本让模型学会忽略亮度伪影。5.3 显存OOM和训练中断现象训练到第三个 epochPyTorch 报CUDA out of memory进程被杀。原因云图原图分辨率太高或者 DataLoader 里放了太多大图GPU 一次性存不下。解决把 Resize 的尺寸从 512 降到 224这是最常见也最直接的缓解方式其次把batch_size从 32 改为 16如果还不行就改成 8。另一个技巧是在脚本开头加torch.backends.cudnn.benchmark True让 cuDNN 自动选择卷积算法能稍微降低显存峰值。还想继续提升批次可以用梯度累积但课程作业阶段没必要。5.4 标签颗粒度和云图内容不匹配现象一张云图里同时有大片积云和一小块晴空空洞模型预测为积云你检查时发现标签也是积云但它把晴空空洞漏掉了。原因整图标签只能反映图像的主导内容卫星云图经常包含多种云属共存的情况模型学到的是主导区域的统计特征。解决不应该期待模型把每个局部都猜对。分析结果时按类别统计置信度分布把低置信度样本单独列出来。报告中可以诚实说明“训练标签是整图级模型无法处理像素级混合区域”这是数据条件的限制不是模型缺陷。5.5 灰度图不是简单复制成三通道就行现象模型训练 loss 不降验证集准确率一直停留在 40% 左右。原因卫星云图如果是单通道灰度图有人会直接np.stack([img, img, img])复制成三通道再送进预训练 ResNet。但这样的操作是复制同一份数据并没有增加任何信息量而且预训练模型对每个通道的独立权重会让复制后的输入产生虚假特征。解决先检查原始图像到底是不是灰度图很多伪彩色卫星云图其实是三通道只是看起来偏灰。如果确认是单通道复制成三通道之后把Normalize的 mean 和 std 改成基于该数据集的灰度统计值或者用Grayscale(num_output_channels3)做一次显式转换让整个数据流意图清晰。6. 交付一份能复现的高分项目整理脚本、环境与报告6.1 用 argparse 固定实验入口一个能复现的项目比一个准确率好看但没法重新跑通的项目更有说服力。我完成的这类作业最终会整理成三个文件train.py、evaluate.py、requirements.txt并且训练脚本支持从命令行指定关键参数。这样做有几个好处老师可以按 README 里的命令直接复现不会因为环境问题卡住你自己做过几次实验后也不会忘记当时用的学习率是多少。import argparse parser argparse.ArgumentParser() parser.add_argument(--data_dir, typestr, defaultcloud_dataset) parser.add_argument(--backbone, typestr, defaultresnet18) parser.add_argument(--epochs, typeint, default20) parser.add_argument(--batch_size, typeint, default32) parser.add_argument(--lr, typefloat, default1e-4) parser.add_argument(--resize, typeint, default224) args parser.parse_args()argparse这段代码没什么神秘感但它的价值在于让每个实验配置都明明白白。我踩过最狠的一次教训是交作业前几天发现最好的实验结果是用lr3e-4跑出来的但完全没有保存训练时的命令行参数最后只能重新花一晚上跑实验差点没赶上交作业。现在我的习惯是每一次实验都用一条python train.py --lr 3e-4 --resize 320这样的命令启动并在日志文件名里写入参数摘要。6.2 报告里最有说服力的三张图实验报告不需要堆图但下面三张图我认为是必需品。第一张是训练集和验证集的 loss 曲线能直观展示模型有没有过拟合如果 loss 曲线在验证集上持续上升报告里就要讨论正则化和数据增强第二张是混淆矩阵热力图能展示各云图类别之间最容易混淆的方向第三张是四类云图的示例图与被预测错的样本对比图这比任何文字说明都更有说服力。配置图都可以用 Matplotlib 直接保存成 PNG不要用截图工具截屏幕否则清晰度不够。最后一点是关于模型文件的命名和保存。我不建议存一个简单的best_model.pth因为跑过三次实验之后它会变成一个黑匣子。可以保存成best_resnet18_224_1e4_acc92.pth这种格式把关键参数和准确率塞进文件名这样只看文件名就能知道这个模型是从哪次实验里来的。源代码、模型文件、实验报告、数据集说明这几样东西要放在同一个项目目录下zip 压缩后再交别让老师在一个混乱的文件夹里翻找。如果你正卡在这个大作业的某个环节上我希望这篇笔记能帮你少走一点弯路。云图识别表面上是图像分类实际上是数据分布、模型假设和评估方式之间不断磨合的过程把每个决策写清楚比追求一个无敌高的准确率更值得。希望帮到你。本文还有配套的精品资源点击获取
返回列表