简介《遥感图像语义分割开发教程》是一份面向遥感、计算机视觉初学者及深度学习开发者的课程型资源系统梳理语义分割在遥感影像解译中的核心价值。文档重点介绍Swin Transformer结合UNet、Samba等前沿方法分析各自的网络结构、实验结果与优势并对比遥感影像与自然场景分割在数据集、技术挑战及评价指标上的差异同时给出Pytorch-Unet多类别分割的实现步骤综述传统与现代高分辨率影像分割方法还涉及数据预处理、模型选择、后处理技术以及土地覆盖分类、灾害评估、农业监测、城市规划等典型应用场景。压缩包内含一个Word文档大小仅16KB轻量易读便于快速掌握知识框架。资源已有224人学习适合希望快速入门或系统了解遥感图像语义分割技术脉络的学习者可作为课程笔记、技术调研或项目参考的起步材料。1. 遥感图像语义分割在解决什么问题一个像素一个类的数字化遥感图像语义分割说白了就是把一张遥感影像按像素打类别——哪块是建筑、哪块是道路、哪块是水体和农田边界要清楚到像素级。它跟遥感图像目标检测最大的不同是不画框而是输出一张与影像等大小的分类图。这类开发教程的热度这几年一直很高但真正让新人卡住的往往不是分割算法本身而是遥感影像的幅面、波段和坐标系统一套自然图像分割流程搬过来经常在数据准备阶段就翻车。下面按一套可复制的落地路径来讲数据集怎么准备、标注怎么做、模型怎么选、训练参数怎么调、坑在哪最后给一条在标注不足时的实践技巧。适合测绘与GIS背景想转算法的人也适合已经有分割基础但要面对遥感数据的工程师。2. 语义分割数据集制作从原始影像到可训练切块进入正题前先明确一件事把遥感影像直接丢给通用分割训练脚本绝大多数情况跑不通。原因不是模型而是数据形态不一样。这些差异决定了一整套预处理流程也就是语义分割数据集制作的基础工序。2.1 遥感影像和自然影像的差异波段、幅面与坐标先看两个最容易忽略的差异。第一是波段。自然图像通常是RGB三通道而遥感影像常见四波段蓝绿红近红外甚至八波段、高光谱。近红外对植被的响应和可见光完全不同所以归一化、均值方差统计、输入通道都要跟着改。很多从自然图像迁移过来的代码默认读三通道通道数改错之后标签错位、灰度拉伸奇怪的情况经常出现。第二是幅面。单张航空影像或卫星影像动辄上万乘上万像素模型不可能一次吃进去必须切块。切块带来的是边界连续性问题和标签对齐问题这也是遥感场景下自己多出来的工作量。另外还有几个容易被忽略的数据属性16bit位深、带nodata值的影像、地理参考坐标。这些属性在训练流程里偶尔会以奇怪的方式影响结果早期意识到后面少熬夜。2.2 公开数据集怎么选先看场景再看数量做遥感图像语义分割先用公开数据集把基线跑起来是常见做法。遥感图像语义分割公开数据集有这么几类航空影像代表是ISPRS Potsdam和Vaihingen分辨率高有建筑、道路、树木等多类标注适合算法验证卫星影像里LoveDA是多时相、多区域的城市—乡村场景类别包含建筑、道路、水、耕地尺度变化大适合检验泛化能力全球土地覆盖里DeepGlobe Land Cover是卫星遥感常用的土地覆盖分割数据类别偏向大类地物植被、水体、农业用地这类。选数据集不是越新越好而是看场景是否接近你的最终应用。要做城市管理Potsdam和LoveDA更容易迁移要做自然植被监测DeepGlobe更接近。另一个经验是小团队先跑小分辨率数据把流程跑通再上大影像否则在数据处理阶段就会陷入长时间的排错。还要提前想清楚类别体系公开数据集的标注类别和你的业务类别大概率不一致比如LoveDA里农作物不分种类如果业务需要分小麦、玉米就需要自行补充标注这部分工作量要算进项目成本。2.3 遥感图像标注产出矢量底稿、栅格转码与标注规范遥感图像标注和自然图像标注有一个关键区别标注格式往往先是矢量shp、geojson或dxf再转成栅格标签而不是直接在像素图上画。这样做的原因很实际——地物轮廓按矢量编辑效率高而且便于后续修正和版本管理。很多团队直接对着像素图画多边形也可以但后续要改类别时矢量底稿的价值就体现出来了。标注规范上我会约定几件事类别清单先定死并用版本管理边界争议区域定一个优先级比如“屋顶与植被重叠处按真实边界”小目标例如独立树木单独建类别或合并到背景避免类别太碎让模型难以学。另一个容易忽略的协议是层级关系一个屋顶可能同时属于建筑、太阳能板两个类别训练时做多标签还是一类优先要在开工前定好不然后期返工很麻烦。矢量转栅格是数据准备的高频操作。GDAL的RasterizeLayer是最常见的做法示例如下。import json from osgeo import gdal, ogr # 打开矢量标注文件把类别字段写入栅格 shp_path labels_buildings.shp geo_tiff image.tif # 读取影像信息确保栅格与影像严格对齐 ds gdal.Open(geo_tiff, gdal.GA_ReadOnly) geo_transform ds.GetGeoTransform() x_res, y_res ds.RasterXSize, ds.RasterYSize # 创建与影像对齐的标签栅格 driver gdal.GetDriverByName(GTiff) out_ds driver.Create(label.tif, x_res, y_res, 1, gdal.GDT_Byte) out_ds.SetGeoTransform(geo_transform) out_ds.SetProjection(ds.GetProjection()) # 栅格化把vector里的class_id字段烧录成像素值 shp_ds ogr.Open(shp_path) layer shp_ds.GetLayer() gdal.RasterizeLayer(out_ds, [1], layer, options[ATTRIBUTEclass_id]) out_ds.FlushCache()这段代码逻辑不复杂但有三个地方必须较真。SetGeoTransform写入的是影像左上角坐标和像素尺寸必须与原始影像完全一致否则标签会整体偏移SetProjection保证坐标系一致一旦坐标系不同转出来的栅格在空间上根本对不上RasterizeLayer的ATTRIBUTE指定标签取哪个字段类别必须从0开始连续编码否则训练脚本的类别索引会乱。这个操作最常见的坑是浮点精度导致边缘偏一个像素。提示转完栅格后在GIS软件里叠加上原影像并半透明显示抽查建筑轮廓是否对齐。偏差超过2个像素就要查坐标来源。2.4 裁切策略把大影像切成能训练的样子影像和标签准备好后下一个动作是裁切。切块大小和重叠率直接影响训练的类分布、模型对跨边界目标的建模能力以及推理时对大目标的连续性。我一般用512或640像素的patch重叠64到128像素。带重叠不是为了单纯增强训练数据而是为了减少目标刚好被切在块边界的情况——边界处目标被截断模型很难学到完整形状。切块时默认跳过全背景的块可以节省大量无效训练时间。import numpy as np from osgeo import gdal def crop_image_and_label(image_path, label_path, patch_size512, overlap64, out_dirpatches): # 读取影像和标签注意标签读取为0-255整数 img_ds gdal.Open(image_path) lab_ds gdal.Open(label_path) img img_ds.ReadAsArray() # shape: (bands, H, W) lab lab_ds.ReadAsArray().squeeze() # shape: (H, W) # 转成 (H, W, bands) 便于滑动 img np.transpose(img, (1, 2, 0)) h, w lab.shape step patch_size - overlap count 0 for y in range(0, h - patch_size 1, step): for x in range(0, w - patch_size 1, step): img_patch img[y:y patch_size, x:x patch_size] lab_patch lab[y:y patch_size, x:x patch_size] # 跳过完全/几乎全为背景的块节省训练时间 if (lab_patch 0).sum() patch_size * patch_size * 0.98: continue np.savez(f{out_dir}/patch_{count:05d}.npz, imgimg_patch, lablab_patch) count 1这段代码里三个关键点。step等于patch_size减overlap控制滑动步长也就是切块之间的重叠程度跳块阈值我设到98%但在类别极不平衡时不建议设太高否则小目标类别所在的块会被过早过滤掉整个类别直接消失输出落到npz格式后续配合任意深度学习框架读取都比较方便。如果你的训练框架要求jpg/png格式的图片和同名标签这里改成PIL保存即可。切块之后还要做一次一致性校验随机抽20块检查img与label的尺寸、最大值和类别数是否符合预期。滑坡的数据千万不要直接进训练这种错误一旦进数据集后面排查的代价是指数级的。3. 语义分割模型选型参数与场景匹配比追新更重要语义分割算法在遥感场景下的选型不是看论文刷榜顺序而是看数据量、显存和业务目标。下面把卷积路线和Transformer路线的差别讲透再给一套最小可跑的实现路径。3.1 卷积路线U-Net和DeepLabV3为什么依然能打U-Net是遥感语义分割绕不开的基线模型。它的编码器压缩空间分辨率提取语义解码器逐步恢复空间细节配合跳跃连接把低层纹理传给解码器。对建筑轮廓、道路边界这类细节敏感的任务跳跃连接让解码器更容易恢复出锐利边界。遥感分割项目里U-Net作为第一版跑通流程相当常见因为训练稳定、显存可控、改造空间大。DeepLabV3是另一条经典的卷积路线它用空洞卷积扩大感受野在不降低分辨率的情况下获得更大范围的上下文。遥感影像中的地物尺度变化大——一边是成片农田一边是零星房屋ASPP模块的多分支空洞卷积正好覆盖多尺度目标。空洞卷积的rate不是越大越好rate过大会让特征采样点稀疏结果在遥感边界上反而出现网格伪影通常rate取4到12这个区间效果比较稳。如果目标是快速建立闭环、验证标注质量卷积路线优先。数据量不大时卷积模型不容易过拟合收敛也更平稳。我见过不少团队一上来就用大Transformer模型结果数据量只有几百张精度反而不如一个调好参数的U-Net。3.2 Transformer路线SegFormer与Swin的空间建模差异语义分割里的Transformer模型在遥感场景经常讨论的包括SegFormer、Swin Transformer核心差异在于全局上下文空间的建模方式。SegFormer的设计相对轻量编码器输出分级特征解码器MLP逐步融合上采样对多尺度地物都友好。更重要的是SegFormer不依赖位置编码推理时换输入分辨率不需要插值位置编码对遥感大图的多尺度预测很省事。Swin Transformer的窗口注意力把自注意力限制在固定窗口内大幅降低计算量和显存占用也比全局注意力更适合高分辨率大图。遥感影像大直接用全局注意力计算量随像素数平方增长所以实际工程里窗口类Transformer更常见。Transformer在遥感数据上有天然吸引力因为很多地物类别共存于全局场景——水体环绕城市、道路连接不同区域、农田与居民区交替这种长距离依赖正是卷积的短板。但Transformer对训练数据量的要求更高数据少时容易欠拟合训练耗时长。所以不是越新的模型就一定好而是看数据预算和时间预算够不够。3.3 选型对照参数量、显存与场景匹配给一个我常用来对着选型的小表。模型参数量级别显存压力边界精度长距依赖适用场景U-Net (ResNet50)约30M低中弱小样本快速验证DeepLabV3 (ResNet50)约40M中好中多尺度地物、通用SegFormer-B2约20M低中强显存有限但需要全局上下文Swin-Unet约60M高好强高分辨率大patch、数据充足参数量级别只是参考同一个模型换不同backbone差异会很大。但遥感项目里真正决定选择的往往是两个现实约束显存和标注量。显存小又需要全局上下文SegFormer是一个好折中标注充足且追求边界精度Swin-Unet或DeepLabV3大backbone表现更稳。多尺度训练和强数据增强对模型的影响往往比换主干更大遥感分割里cutmix和随机旋转是常用的强增强后面会影响损失函数的设计。3.4 基于mmsegmentation跑通最小训练流程mmsegmentation是目前生态比较完整的一套开源工具它把数据加载、训练循环、评估指标统一成配置驱动。用它在遥感数据上快速跑基线是我最常用的方式。下面这种配置写法核心是替换数据集的pipeline和输入通道。_base_ [ mmseg::_base_/models/deeplabv3plus_r50.py, mmseg::_base_/datasets/potsdam.py, mmseg::_base_/schedules/schedule_80k.py, mmseg::_base_/default_runtime.py ] # 把输入通道改成四波段 model dict( backbonedict( in_channels4 ) ) # 优化器学习率可用默认值关键是线性调度 optim_wrapper dict( typeOptimWrapper, clip_graddict(max_norm1.0) )这是mmseg的配置对象写法不是直接执行的脚本。in_channels要按你的波段数改classes按类别数改如果影像带nodata还需要在dataset里挂一个mask训练时忽略无效像素。优化器部分我对clip_grad设置max_norm1.0防止梯度爆炸——遥感影像噪声大、边界标注不一致这个保护挺有必要。# 单卡训练把训练数据指向你的裁剪目录 python tools/train.py configs/segformer/segformer_b2_loveda.py \ --work-dir work_dirs/segformer_b2_loveda \ --seed 42上面命令假设你已经把数据整理成mmseg的目录格式img_dir放切块影像ann_dir放同名标签。如果没有用mmsegsegmentation_models_pytorchsmp是另一个快速实验选择。import segmentation_models_pytorch as smp import torch model smp.Unet( encoder_nameefficientnet-b4, encoder_weightsimagenet, in_channels4, # 四波段影像含近红外 classes6, ) optimizer torch.optim.AdamW(model.parameters(), lr3e-4)smp这套代码更轻适合验证backbone和损失函数。in_channels是遥感分割最容易漏改的参数——拿着RGB预训练权重复用过来其他都对了通道数量对不上前向直接报错。预训练权重用ImageNet的Encoder仍然是常见做法即使遥感影像分布差异大预训练编码器在纹理提取上的先验能加速收敛非RGB的波段是随机初始化的训练时先用较小学习率适应预训练层再放开全模型微调。训练时如果把输入分辨率从512改到640SegFormer的token数量会明显增加显存上涨很快所以分辨率、窗口大小和batch是三个互相拉扯的参数调整时建议一次只动一个。4. 训练参数与损失函数一张表定位大多数问题训练语义分割模型参数组合会直接影响收敛速度和最终精度。这一章给出我常用的默认值并解释每个参数背后在遥感数据上的意义。4.1 关键训练参数patch size、batch size、学习率与冻结策略参数建议值注意事项patch_size512-640与目标大小有关不追求大patch而是保证目标完整batch_size8-16受显存约束必要时用梯度累积学习率3e-4 到 1e-3AdamW配合linear或cosine调度epochs60-120遥感数据多早停比固定epoch更稳warmup5%-10% epochs避免早期大梯度冲坏预训练权重这些参数的选取逻辑首先是把patch设成能覆盖一个完整地物的大小。检测独立建筑时patch 512已足够道路需要连续性上下文patch 640是更稳妥的值。显存不够时优先减batch而不是减patch因为patch小了跨边界目标会增多模型学习到的语义完整性变差。学习率这块常见做法是AdamW初始3e-4加linear调度。遥感数据集的噪声比自然图像大——标注边界不一致、多时相光照差异学习率太大会在边界上反复震荡。warmup的作用是把学习率从接近0升到目标值前几轮训练尤其明显遥感数据里类别边界噪声多warmup能减少开始阶段的loss振荡。说实话patch size和学习率这对组合调多了你会觉得像玄学同样的512与3e-4换个城市效果就变。所以初始阶段从保守值起步再按验证集趋势调而不是凭感觉。4.2 损失函数交叉熵与Dice的组合价值交叉熵对每个像素独立计算损失忽略类别间的空间结构。遥感影像中道路、水体这类类别形状长条、连通性好纯交叉熵容易学到孤立点式的预测。Dice损失直接优化预测与标签的空间重合程度对小目标和长条目标更友好。常见组合是交叉熵加DiceL 0.6 * CE 0.4 * Dice这个比例不是固定的类别越不平衡Dice权重越高。给一个可以直接粘走的Dice实现默认忽略背景类。import torch import torch.nn as nn class DiceLoss(nn.Module): def __init__(self, smooth1.0, ignore_backgroundTrue): super().__init__() self.smooth smooth self.ignore_background ignore_background def forward(self, pred_logits, mask): # pred_logits: (B, C, H, W), mask: (B, H, W) pred torch.softmax(pred_logits, dim1).permute(0, 2, 3, 1) pred pred.reshape(-1, pred.shape[-1]) mask mask.reshape(-1) classes pred.shape[1] start_cls 1 if self.ignore_background else 0 dice_sum 0.0 valid_n 0 for cls in range(start_cls, classes): p pred[:, cls] t (mask cls).float() if t.sum() 1: continue intersect (p * t).sum() union p.sum() t.sum() dice_sum (2 * intersect self.smooth) / (union self.smooth) valid_n 1 return 1 - dice_sum / max(valid_n, 1)smooth是平滑项防止分子分母为0。ignore_background设为True时背景类不计入Dice因为背景占比很大计入会把前景类别信号稀释。如果类别不均衡特别极端建议不要对每个类别平均——可以传入类别权重权重按标签像素占比反比设定实现也不复杂手动传个list即可。4.3 评估指标mIoU、OA与类别频率的关系语义分割最常用的指标是mIoU每个类别的交并比求平均。遥感场景里类别频率差异大OA整体准确率容易被大类主导——一个只输出背景的模型OA可能很高但建筑分类是零。所以评估要以每类IoU和mIoU为主OA只做参考。如果要更贴近应用可以看FW-IoU频率加权IoU它更看重高频类别适合对总像素准确率要求高的场景。调模型时我的做法是mIoU为主FW-IoU做辅并且单独看每个类别是否出现“消失类”。计算mIoU时有一个常见坑混淆矩阵要排除nodata像素。遥感影像很多区域没有有效观测值如果不排除IoU被无效区域干扰得厉害。常见做法是给无效像素一个额外标签值并在训练和评估时都忽略。评估脚本里记得用ignore_index这类参数而不是把无效像素当成背景。4.4 训练纪律固定种子、早停与验证集划分验证集划分在遥感场景要非常小心。遥感影像的空间自相关性很强同一景影像里相邻切块是相似的甚至有重叠。如果验证集和训练集来自同一景影像的相邻块验证分数会虚高换到另一个城市就直接崩。更稳健的做法是按区域划分——城市A训练、城市B验证这样才能反映真实泛化能力。固定随机种子对训练几乎是纪律。不固定种子也能训到一个水平但对比模型或损失函数时种子波动带来的误差会掩盖真实差距。固定种子之外还要固定裁切顺序和数据打乱方式保证每次实验的数据喂入顺序一致。早停的耐心值我一般设20个epoch遥感数据集噪声大过早停会被一次意外波动骗到。5. 遥感语义分割的常见坑现象、原因与解法下面这五个坑是我在遥感分割项目里踩过或看同事踩过的按出现频率排序每一条都按现象、原因、解决三个层面说清楚。它们大多不会让程序直接崩溃而是让你花掉大把周末。5.1 切块后标签偏移几个像素预测轮廓对不上这个坑的现象是切块归档都很正常模型训练也不报错但训练到一半发现loss下不到合理水平验证集每类IoU都均匀且低。叠加上原影像一看标签整体偏移了几个像素建筑轮廓落在屋顶边缘与墙根之间。原因最常见的是矢量转栅格时没有沿用原始影像的GeoTransform用了图幅外包围盒或默认像素尺寸其次是数据从其他坐标系统重采样时没有同步更新空间参考第三是抗锯齿处理导致边缘像素归属不一致。解决上转栅格前先把影像和标签的GeoTransform与Projection打印出来逐项比对一致后再转。转完栅格用GIS软件叠加原影像半透明抽查纠偏标准是建筑轮廓偏差不超过1个像素。像素归属不一致的问题可以在栅格化时关闭抗锯齿选项或统一按“像素中心点落入哪个矢量面”作为归属规则。这块没有捷径越早抽查损失越小。5.2 训练loss崩坏为nan或异常值mIoU接近0训练刚开始正常某一步loss突然变成nan或者loss不收敛验证集mIoU接近0预测图全是一类。原因很可能是遥感影像的nodata值在作祟常见的是-9999、-32768。对整幅影像做全局均值方差归一化时异常值会把归一化分布拉到不可用范围同时标签制作时没有对无效区域做mask模型对一片没有真实信息的区域强行学习。解决上读入影像后先构建有效像素掩膜例如像素值大于0且不等于nodata只用有效像素统计均值和方差在数据pipeline里给标签同步生成mask训练时把无效像素的loss置为0。这两个操作必须在加载数据时完成不要在训练循环里临时后补。另外把归一化后的影像min和max打印出来如果出现极端值优先怀疑nodata而不是网络结构。遥感分割里这种loss崩坏的原因超过一半在数据侧。5.3 小目标类别在预测图上几乎消失训练结束后水体、农田等大类别表现不错道路、独立房屋等小目标类别在预测图上几乎消失mIoU被小类彻底拉低。原因是类别不均衡。一张512切块里背景可能占95%道路只占2%到3%交叉熵损失被大类主导小目标在梯度更新里几乎得不到有效信号。再加上道路像素本身长条形分布在切块边缘容易被裁切直接削弱。解决上损失函数层面把Dice权重提高或给小类别在交叉熵前乘一个反频率权重数据层面按小目标所在块做上采样而不是简单随机采样后处理层面道路这类连通目标用闭运算可以把断裂处接起来独立建筑用形态学膨胀可以把细碎漏分补回。后处理只能锦上添花核心还是让模型在训练时真实见过足够多的小目标样本。判断这个坑的标准是查看每类IoU如果大类高、小类接近0基本就是它。5.4 验证集表现好换到别的数据就崩验证集mIoU有65%汇报也做了把模型放到另一块待标注区域推理精度直接掉到40%以下。原因是验证集和训练集来自同一景影像的空间临近切块。遥感影像的自相关性很强相邻切块的纹理、光照、地物分布几乎一致模型在验证时等于见到了高度相似的样本分数自然虚高。还有一种情况是参数选择过程中反复看验证集验证集信息间接进入了模型选择泛化能力被高估。解决上数据划分按区域而不是按切块。一种常见做法是用一个多边形shp把研究区切成训练区与验证区或者直接把不同景影像按景分开城市A训练、城市B验证。外部测试数据必须全程隔离只在最终评估时用一次。如果数据少到没法做区域划分宁可减少训练数据量也要保住验证集独立性——这是遥感分割项目里最容易“看上去很好实际不能交付”的翻车点。5.5 大图推理时显存溢出程序被杀训练好好的推理时单张大图送入模型显卡直接OOM程序被系统kill或者推理脚本跑了一晚上没有输出。原因是遥感影像幅面巨大整图推理意味着所有中间特征图也按整幅尺寸存放显存自然不够。语义分割模型即使参数量不大特征图占用也是显存大头。解决上用滑动窗口推理。按patch推理再拼接常见做法是patch size与训练一致窗口之间保留64到128像素重叠重叠区域用加权融合而不是直接覆盖——权重按像素到patch中心的距离反比衰减这样能明显减轻拼接缝。下面是一个可用的推理框架。def sliding_window_predict(model, image, patch_size512, overlap64, num_classes6): # image: (H, W, bands) float32已经归一化 h, width image.shape[:2] step patch_size - overlap prob_map np.zeros((h, width, num_classes), dtypenp.float32) weight_map np.zeros((h, width, 1), dtypenp.float32) for y in range(0, h - patch_size 1, step): for x in range(0, width - patch_size 1, step): patch image[y:y patch_size, x:x patch_size] patch torch.from_numpy(patch).permute(2, 0, 1).unsqueeze(0).cuda() with torch.no_grad(): logit model(patch) prob torch.softmax(logit, dim1)[0].permute(1, 2, 0).cpu().numpy() # 距离权重中心高边缘低用于消除拼接缝 yy, xx np.mgrid[0:patch_size, 0:patch_size] dist np.sqrt((yy - patch_size / 2) ** 2 (xx - patch_size / 2) ** 2) weight 1.0 / (1.0 dist) weight weight[..., None] prob_map[y:y patch_size, x:x patch_size] prob * weight weight_map[y:y patch_size, x:x patch_size] weight prob_map prob_map / weight_map return prob_map.argmax(axis-1)这个函数里weight是按到patch中心的距离生成的低权重边缘目的是让相邻窗口的输出在重叠区平滑过渡。需要注意如果影像尺寸不是patch_size的整数倍边缘不满一块的区域会被丢掉常见做法是在循环外补零填充或单独处理最后一行一列。推理本身没有魔法重要的是把常用的推理函数固定成一个工具不同patch size和overlap都作为参数传入实测时才有对比依据。6. 标注不够时的一条出路半监督 置信度过滤遥感图像标注的贵做过的人都有体会——一景城市影像的精细分割标注可能消耗数周人力。如果手头只有几十张标注影像语义分割任务还要不要做一条可行路线是半监督自训练先用小标注集训练一个基础模型再让模型对大影像的无标注区域产出伪标签用置信度过滤掉低质量像素后加入训练集迭代一到两轮。具体节奏是训练完基础模型后对未标注影像按patch推理保存每个patch的softmax概率取最大概率作为置信度类别标签只有置信度高于阈值才进入下一轮训练。遥感影像的边缘通常是低置信区阈值不宜一刀切可以按类设置——建筑和道路的轮廓区阈值高大面积植被与水体的阈值可以稍低。我常用的伪标签阈值在0.85到0.95之间过低会引入噪声过高学习收益有限。有两个纪律值得守住伪标签不要一次性全量加入每轮只挑选置信度最高的那一小批切块每轮训练后重新评估验证集mIoU如果低于上一轮就回滚最多自训练两轮。伪标签噪声会随迭代放大这是半监督最容易忽略的黑匣子边界。如果只有三四十张标注图我的建议是先跑通U-Net或SegFormer小模型基线用数据增强把样本量放大到300块再叠两轮自训练通常能接近“标注量翻倍”的效果。这里面的本质是遥感影像中同类地物的像素特征相对稳定、空间先验强给自训练提供了比自然图像更好的条件。每次拿到新数据集我都会先做一次“标注量砍半”的消融测试观察mIoU掉到什么程度还能接受从而判断自训练能补回多少。这个习惯帮我避开了好几次盲目标注希望帮到你。本文还有配套的精品资源点击获取
阅读完成 · 觉得有帮助?