十年匠心定制 · 商业建站与技术教学双线并行 咨询热线:400-886-1026 service@lmnt.cn
ARTICLE DETAIL

资讯详情

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

遥感场景图像识别实战:EfficientNet复合缩放与迁移学习调参指南

遥感场景图像识别实战:EfficientNet复合缩放与迁移学习调参指南 简介面向图像分类与迁移学习实践者这是一套基于EfficientNet轻量级网络的遥感场景图像识别完整项目支持b0-b7八种模型灵活切换。资源共2000个文件含1995张jpg图像数据集、3个Python训练/评估脚本、1个readme说明与1个txt配置压缩后约297MB可直接用于25类遥感场景约1.5万张图片的一键训练。预处理与训练环节提供加载官方预训练权重、冻结特征层选项集成Adam、SGD、AdamW优化器配合交叉熵损失与cos余弦退火学习率并自动输出训练集/验证集上的loss、准确率曲线及混淆矩阵、recall、precision、F1-score、特异度等详细评估结果便于深入分析调优。项目同时支持按readme指引替换自定义数据集方便拓展新场景压缩包目录结构清晰代码注释完整便于根据需求二次开发。已有71人学习适合从入门到进阶的深度学习开发者快速复现图像分类与迁移学习流程。1. 遥感场景图像识别为什么把EfficientNet放在第一优先级遥感场景图像识别和普通 ImageNet 分类有明显区别类别之间的差异往往靠整体场景结构而不是单一物体。同样是 mountainLevel1 和 Level3 的拍摄高度不同会让纹理细节变化很大stadium 和 playground 这类人工地物则需要更抽象的上下文才能区分。迁移学习是这类任务最常见做法但如果直接搬 ResNet50参数量大、训练时间长在 15k 级别的中等规模数据上反而容易过拟合。EfficientNet 这类轻量级网络通过复合缩放同时调整深度、宽度和分辨率用不到一倍的参数换来接近极限的精度。这个项目把 EfficientNet b0-b7 全部做成可选并封装了 pretrained、freeze_layers、三种优化器和余弦退火25 类遥感场景约 15k 张数据解压后改一条命令就能跑完整训练和评估。对刚入门图像识别的开发者和需要快速验证遥感场景算法的工程师都能直接拿来做基线。2. EfficientNet 的复合缩放原理与 b0-b7 选型2.1 从 MBConv 到 NAS 搜出来的基线网络EfficientNet 不是像 VGG 那样人工堆层叠出来的而是用神经架构搜索NAS在搜索空间中找到的基线结构。基线网络的主体是 MBConv它把 MobileNetV2 的倒残差结构和 Squeeze-and-Excitation 注意力机制合在一起先用 1x1 卷积升维再走深度可分离卷积最后 SE 模块对通道重新加权再用 1x1 卷积降维并做残差连接。这样的结构让每个 block 的计算量远小于普通卷积因此基线模型已经非常轻量。遥感场景中图像分辨率普遍偏高一个 batch 塞进 GPU 显存很吃紧。MBConv 的深度可分离卷积把标准卷积分解为逐通道和逐点两步理论上计算量从 H×W×C_in×C_out×K×K 降为 H×W×C_in×(K×K C_out)。这部分省下来的算力可以留给更高输入分辨率这对遥感小目标识别很重要。常见做法是先用 torchsummary 看参数量再决定用哪一级模型。比如from efficientnet_pytorch import EfficientNet import torch import torch.nn as nn model EfficientNet.from_name(efficientnet-b0) # 把全连接层输出改成 25 类 model._fc nn.Linear(model._fc.in_features, 25) x torch.randn(1, 3, 224, 224) print(model(x).shape)这段代码直接从名称构建模型不加载任何权重。from_name和from_pretrained的区别在于后者会读取官方仓库的预训练参数到内存。遥感场景做迁移学习时一般用from_pretrained如果只想快速验证网络结构from_name更干净。全连接层替换为num_classes数量这里先用 25 类演示。2.2 复合缩放为什么同时调深度、宽度、分辨率比单独调效果好单一维度缩放会有瓶颈。深度增加会让梯度传播变难宽度增加会摊薄特征提取效率分辨率增加只带来信息量而模型容量不足时同样无法利用。EfficientNet 给出的做法是引入复合系数 φ把网络深度 d、宽度 w、输入分辨率 r 一起缩放d α^φw β^φr γ^φ并且满足 α·β²·γ² ≈ 2。当 φ 增加时计算量大约按 2^φ 增长但深度、宽度、分辨率三方面均衡提升。每一层都能在更高分辨率下提取更细的特征同时深度足够承接这些特征宽度又保证通道冗余不会成为瓶颈。实际代码里EfficientNet 系列通过这个公式预先算好了一张缩放表。b0 到 b7 就是 φ 从 0 到 7 的整数档位项目里说的“b0-b7 8 种模型”指的就是通过命令行参数直接切换网络深度和输入分辨率。2.3 b0-b7 关键参数对照与遥感选型建议模型版本输入分辨率参数量(约)ImageNet Top-1(约)遥感场景建议B02245.3M77.1%快速基线B12407.8M79.1%CPU/低显存B22609.2M80.1%中等显存B330012M81.6%精度优先B438019M82.9%GPU 较充裕B545630M83.6%高分辨率B652843M84.0%极少使用B760066M84.3%大显存实验上表数值是官方在 ImageNet 上的统计遥感任务会因场景差异略有浮动。25 类、15k 张规模下我一般建议先跑 B0 确认流程通畅再切到 B3 或 B4。注意 B7 的分辨率达到 600如果原图是项目里那种stadium_555_Level2_1.68m.jpg的遥感切片直接 resize 到 600 会丢失细节需要评估预处理是否匹配模型需求。2.4 轻量级网络的部署边界遥感图像识别的另一种痛点是在整景推图场景中模型体积不能太大。EfficientNet-B0 在 TensorRT 等加速引擎上很容易跑到毫秒级而 B7 参数量大、推理耗时明显上升。这就是“轻量级网络”在遥感场景中的实际意义不只为了训练快更是为了后续在边缘设备或 Web 服务里压 QPS。项目中预留了 freeze_layers 参数也说明从训练到部署都考虑了资源受限情形。3. 迁移学习参数解析pretrained、freeze_layers 与优化器选择3.1 pretrained 扮演的角色pretrained决定了模型初始化方式。选 True 时加载 ImageNet 预训练权重选 False 时从头训练。遥感场景图像虽然和自然图像分布不同但底层边缘、纹理、颜色特征仍然通用。加载预训练权重能显著缩短收敛时间也能在 15k 数据上稳住训练不加载权重时训练收敛慢而且小数据集上最后的准确率通常更低。本项目将 pretrained 设计为开关参数意味着可以做一组对比实验同一套数据下pretrainedTrue 和 False 各跑一遍观察验证集准确率差距。常见做法是先用 True 跑通流程再在实验记录里补第二组实验。注意如果选择 pretrainedTrue 且 freeze_layers 也打开实际被加载的只包括 backbone 部分最后的分类层是随机初始化的因为分类层数量从一个固定类别数被改成 25。3.2 freeze_layers 的可控微调freeze_layers 在代码里常见的语义是冻结所有 backbone 层只训练最后的分类层。这样做速度最快、显存占用低但适用场景是数据分布和 ImageNet 非常接近。遥感场景中高层特征仍然有一定偏移因此更好的做法往往是先冻结 backbone 训练几个 epoch再解冻全部层一起微调。如果项目实现里 freeze_layers 是布尔值那么可以在训练脚本里加一段逻辑if freeze_layers: for name, param in model.named_parameters(): if fc not in name: param.requires_grad False optimizer torch.optim.AdamW( filter(lambda p: p.requires_grad, model.parameters()), lr3e-4 )这段代码通过requires_grad控制梯度更新。分类层是fc所以只保留最后一层可训练。filter只把需要梯度的参数传给优化器避免冻结层仍然被优化器维护状态也能减少显存占用。冻结整个 backbone 时数据增强不要太强否则仅分类层很难拟合大幅形变此时验证集准确率通常会稳定在一个相对较低的平台上这是正常的。3.3 Adam、SGD、AdamW 如何选择优化器核心特点本项目中适合的场景Adam自适应学习率收敛快初期快速看效果SGD泛化能力强需要手动调 lr最终精调AdamW解耦权重衰减训练更稳推荐默认SGD 的 momentum 一般设 0.9weight_decay 设 1e-4。Adam 和 AdamW 的 lr 一般取 1e-3SGD 取 1e-2 量级。Adam 在遥感小数据集上经常遇到“训得快但泛化差”的问题AdamW 通过把 weight decay 从梯度里拆出来缓解过拟合。下面是本资源中常见的优化器构建函数按名称返回对应实例def build_optimizer(model, name, lr, weight_decay, momentum0.9): if name adam: return torch.optim.Adam(model.parameters(), lrlr, weight_decayweight_decay) elif name adamw: return torch.optim.AdamW(model.parameters(), lrlr, weight_decayweight_decay) elif name sgd: return torch.optim.SGD(model.parameters(), lrlr, momentummomentum, weight_decayweight_decay) else: raise ValueError(funknown optimizer: {name})lr 初值很敏感。用 Adam/AdamW 时 1e-3 是一个不会出错的起点如果训练过程 loss 震荡降到 3e-4。SGD 则需要更大初始学习率否则收敛极慢。遥感场景数据量不大weight_decay 建议比通用设置略高取 5e-4 到 1e-4 之间。3.4 损失函数多类交叉熵与类别不平衡的初步处理类别数是 25标准选择就是torch.nn.CrossEntropyLoss。它内部把 softmax 和负对数似然合并了输入 logits输出标量 loss。如果遥感场景里各类别图像数量不均可以为 loss 传入 weight 参数给样本少的类别更大权重class_weights torch.tensor([1.0] * num_classes) criterion nn.CrossEntropyLoss(weightclass_weights.to(device))不加 weight 时所有类别被等同对待模型会更偏向样本多的类别。计算类权重时常见做法是用N_total / (num_classes * N_c)避免权重值跨度过大。当前项目默认交叉熵如果想继续提升后续可以换成 Label Smoothing 或 Focal Loss但第一步先用交叉熵把基线跑准。4. 遥感场景识别训练实战从数据目录到一键运行4.1 数据目录结构与文件名里的隐含信息项目数据集中文件名的形式是stadium_555_Level2_1.68m.jpg拆开看是类别_编号_级别_分辨率米/像素。遥感图像常以地面采样距离GSD表示分辨率1.68m 表示每个像素覆盖地面 1.68 米。这里 Level2 和具体米数对网络来说不是标签但理解它们有助于判断同一类别在不同尺度下是否会被误判。比如 mountain 的 Level1 纹理较粗Level3 则可能出现细节丢失这种尺度变化正是遥感场景分类的核心难点。标准的数据目录组织形式是 train 和 val 两个文件夹每个文件夹下再按类别名分子目录。25 类对应 25 个子目录目录名就是标签名。训练脚本会通过torchvision.datasets.ImageFolder读取train_dataset datasets.ImageFolder(data/train, transformtrain_transform) val_dataset datasets.ImageFolder(data/val, transformval_transform)ImageFolder要求文件夹结构为根目录/类别/图片.jpg。标签按类别名字典序自动编号所以 stadium 和 railway 的索引是确定的评估 json 里也沿用这套索引。如果自己要换数据集必须保证目录名和类别一一对应不允许出现空目录否则 ImageFolder 会报警告。4.2 常用启动命令和参数解释这个项目支持用命令行参数控制训练配置。一条典型的完整命令长这样python train.py \ --model efficientnet-b0 \ --pretrained \ --freeze_layers \ --optimizer AdamW \ --lr 1e-3 \ --epochs 80 \ --batch_size 64 \ --cosine各参数的含义和作用如下参数取值示例作用--modelefficientnet-b0切换 b0-b7--pretrainedTrue/False是否加载 ImageNet 权重--freeze_layersTrue/False是否冻结 backbone 只训练分类层--optimizerAdam/AdamW/SGD选择优化器--lr1e-3初始学习率--epochs80总训练轮数--batch_size64batch 大小--cosine启用使用余弦退火调度器如果显存有限可以把 batch_size 降到 32分辨率小的 B0 在 24G 卡上可以开 128。遥感场景原图分辨率高DataLoader 里resize(224, 224)是常用设置需要保留更多细节时可以换成RandomResizedCrop让网络看到不同尺度和位置的裁剪结果。4.3 余弦退火调度器让学习率自己过山车本项目学习率优化策略采用 cos 余弦退火算法。简单说学习率按余弦曲线从初始值下降到接近 0期间会因为重启而再次上升从而逃逸局部极小点。PyTorch 中一行代码即可串在训练循环里scheduler torch.optim.lr_scheduler.CosineAnnealingLR( optimizer, T_maxepochs, eta_min1e-6 ) for epoch in range(epochs): train_one_epoch() scheduler.step()T_max设为总 epoch 数学习率会在最后一个 epoch 降到eta_min。相比固定学习率余弦退火的优势是早期学习率大快速下降后期学习率很小精细收敛。配合 AdamW 效果非常稳定。如果只训练分类层freeze_layersTrue建议把初始学习率降到 3e-4因为可训练参数少了过大的 lr 容易让最后一层在早期震荡。4.4 训练过程要盯哪些日志脚本会在每个 epoch 结束后输出训练集和验证集的 loss 与准确率并保存曲线图。常见误区是只盯训练 loss 下降就以为模型在变好验证集准确率才是能否继续训练的依据。如果验证 loss 连续 5 个 epoch 不降通常是过拟合此时要么增加数据增强要么降低训练轮数要么把 weight_decay 调大。另外遥感场景中训练集和验证集划分要避免相同场景出现在两边。如果原始数据来自同一景影像的切片直接按文件随机划分会导致空间自相关让验证准确率虚高。项目里如果是一键运行默认划分不一定考虑这一点。换自己的数据时我一般会按地理坐标或图像组划分而不是纯随机打乱。5. 评估网络混淆矩阵、PR 曲线与指标 JSON 输出5.1 评估指标的定义与读取方法项目在训练集和验证集上分别评估指标包括 loss、准确率、混淆矩阵、recall、precision、F1 score 和特异度。准确率是所有类别正确数除以总数但类别不平衡时不能单看它。recall查全率表示某类真实样本中有多少被找出precision查准率表示被分为该类的结果中有多少正确F1 是两者的调和平均。特异度是负类识别能力计算公式为 TN/(TNFP)。对遥感场景误报和漏报的代价不同比如铁路被误判为山地是漏报关键设施所以每个类别的 F1 和特异度比整体准确率更有参考价值。指标公式/含义使用场景Accuracy(TPTN)/(TPTNFPFN)类别均衡时判断整体PrecisionTP/(TPFP)关注误报时RecallTP/(TPFN)关注漏报时F12PR/(PR)不平衡数据综合能力SpecificityTN/(TNFP)负类识别能力5.2 混淆矩阵与分类报告的实现评估代码通常在每个 epoch 结束或整个训练结束后执行一次。用 sklearn 可以直接完成大部分计算from sklearn.metrics import confusion_matrix, classification_report import seaborn as sns import matplotlib.pyplot as plt cm confusion_matrix(all_labels, all_preds) report classification_report(all_labels, all_preds, target_namesclass_names, digits3) print(report) sns.heatmap(cm, annotTrue, fmtd, cmapBlues) plt.savefig(confusion_matrix.png)all_labels和all_preds来自验证集所有 batch。confusion_matrix返回 25x25 矩阵行是真实类别列是预测类别。classification_report会输出每个类别的 precision、recall、f1-score。heatmap 保存成图片方便直观查找混淆对。需要注意的是混淆矩阵数值跨度大时fmtd会不会让数字重叠如果数据超过 1 万张建议改成fmtg或只显示比例。5.3 从 JSON 文件里找最差类别项目说明中提到“具体各类别的指标在 json 文件中查看”这是评估阶段的核心产出。JSON 保存的结构通常是这样的{ overall_accuracy: 0.918, per_class: { mountain: {precision: 0.88, recall: 0.92, f1: 0.90, specificity: 0.996}, stadium: {precision: 0.78, recall: 0.71, f1: 0.74, specificity: 0.982} } }specificity在 25 类情况下往往非常高因为负样本多。F1 对不平衡数据更有区分度。查看时可以按 f1 升序排序很快找到哪几个类别在拖后腿。建议再读入混淆矩阵文档看看这些低 F1 类别主要被预测成了哪些其他类。5.4 用评估结果反推训练策略假设 stadium 和 playground 互相混淆说明两者在遥感尺度下视觉特征接近。应对方法有几种第一增加这两类的训练样本第二对局部纹理使用更高输入分辨率比如从 224 切到 300第三调整损失函数给易混淆对更大的权重。评估的作用不是训练结束后贴一张图而是定位问题再调整这也是为什么项目要把训练曲线、混淆矩阵、指标 json 同时输出。只留一个整体准确率的项目很难指导调参。6. 余弦退火中的 warmup 与换数据集时的三个调整点6.1 先 warmup 再余弦收敛更稳直接从头用余弦退火训练初期学习率太大容易把预训练权重打坏。常见做法是前 5 个 epoch 用线性 warmup 把 lr 从 0 升到初始值再用余弦下降到末尾。PyTorch 中可以用LambdaLR组合def lr_lambda(epoch): warmup_epochs 5 if epoch warmup_epochs: return (epoch 1) / warmup_epochs return 0.5 * (1 math.cos(math.pi * (epoch - warmup_epochs) / (epochs - warmup_epochs)))warmup 阶段的学习率从接近 0 缓慢增加不对预训练权重产生过大扰动。如果遥感数据已经和预训练分布很接近warmup 可以压缩到 3 个 epoch。6.2 换数据集必须改的三处第一处是num_classes。从 25 类换成自己的类别数模型最后一层要同步替换。第二处是类别权重如果数据分布不匀要按新数据集重新计算不能沿用原来的class_weights。第三处是数据增强策略遥感场景中的旋转、翻转有意义但颜色抖动要谨慎因为不同卫星传感器的波段分布并不一样。6.3 冻结层的解冻时机先用 freeze_layers 跑 10 个 epoch 后可以把requires_grad全部置为 True然后降低学习率继续训练。解冻后 backbone 前几层梯度很小可以用相对较大的 lr最后一两层特征更接近任务用小 lr。我一般会在解冻后训练 20-30 个 epoch验证集准确率通常会再涨 1-2 个百分点。本文还有配套的精品资源点击获取
返回列表