ARTICLE DETAIL

资讯详情

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

高分辨率城市遥感图像水体提取:U-Net语义分割与Python工程实践

高分辨率城市遥感图像水体提取:U-Net语义分割与Python工程实践 简介这是一份基于深度学习的城市高分辨率遥感图像水体提取Python源码适合计算机、人工智能、通信工程等专业学生用于毕业设计、课程设计或项目演示。代码包含完整的模型定义、数据加载、训练评估与测试流程并提供了U-Net与注意力U-Net两种网络结构可帮助读者理解语义分割在水体提取中的实际应用。压缩包共27个文件以Python脚本为主11个py另含13张PNG图像用于展示网络结构与提取效果、1个CSV结果文件、1个MD项目介绍以及1个已训练的模型权重文件整体仅726KB轻量便捷。项目还附带了图像增强、数据预处理等实用工具配合测试脚本可直接运行验证。已有493人学习下载项目经过测试运行成功上手门槛较低适合需要快速搭建遥感图像处理方案或进行二次开发的学习者。1. 高分辨率城市遥感图像水体提取从 NDWI 失灵到语义分割的必然选择城市内涝应急、河湖岸线监测如今都要求在一两个小时之内从高分辨率遥感影像里把水体边界提出来。过去用 NDWI 指数阈值分割在空旷自然区域还能用但到了 0.5 米分辨率的城市影像里黑色沥青屋面、玻璃幕墙阴影、塑胶跑道都会和水体产生同样的光谱响应传统方法几乎不可交付。深度学习模型的主要优势不是像素级颜色判断而是懂得看形状、边缘和上下文水面总是连续、平滑、有岸线轮廓。标题里的“基于深度学习实现的高分辨率城市遥感图像的水体提取 python 源码”指向的正是这种基于语义分割的完整工程包。它适合遥感算法工程师、GIS 开发者和水利信息化实施者拿到后可以在 Python 环境里完成训练、验证、推理也能根据城市特有场景重新微调模型。2. 数据准备与模型选型U-Net 为什么能吃掉高分影像中的细碎水网水体提取项目里最耗时间的部分往往不是模型代码而是数据准备。高分辨率城市遥感影像的特点是地物碎片化河面被桥梁打断池塘边停着集装箱高层建筑阴影横跨半个水面。如果数据切分和增强策略不够稳后面模型多少都会出问题。这一章先把模型选型和输入侧的关键决策讲清楚并给出可以抄走的裁剪脚本。2.1 模型选型U-Net 是默认起点不是唯一解水体提取本质是逐像素二分类问题。FCN 可以端到端预测但连续下采样后细小河流和池塘的边界信息在解码阶段很难完全恢复。SegNet 记忆编码阶段池化位置对噪声有抵抗但对多尺度水体不够稳。DeepLabv3 的 ASPP 模块能捕捉多尺度上下文在城市大湖面场景表现很好但模型重显存占用高CPU 部署也麻烦。U-Net 之所以被多数开源水体提取项目作为默认结构核心在于跳过连接。编码器下采样得到语义特征解码器上采样恢复空间分辨率跳跃连接把浅层边缘信息直接送回到解码器边缘细节不容易丢。对高分辨率影像里几米宽的支流和碎小池塘这种结构天然更友好。常见做法是编码器用 ResNet34 或 ResNet50 预训练权重解码器保持 U-Net 对称结构如果训练数据只有几百张 patch从头训练一个更轻的 U-Net 反而比加载 ImageNet 权重更可控。从参数角度看一张 512×512 RGB patch以 ResNet34 为编码器的 U-Net 参数量约 24M单样本前向显存约 1.2G。而 DeepLabv3 在相同输入下通常要 1.8G 以上。如果只有一块 8G 显存ResNet34-U-Net 配合 batch size 4 能跑起来DeepLabv3 就很难同时保 batch 和 patch 尺寸。所以我在工程实施时第一版模型基本固定为 ResNet34-U-Net后面根据边界精度再决定是否换更强 encoder。2.2 裁剪高分影像从整景 TIFF 到 512×512 训练样本高分辨率遥感影像动辄上万像素宽整幅送进 GPU 既不现实也没必要。通常先按固定 patch 裁剪并且把标签做成同分辨率栅格。如果标签是河流或水库的 GeoJSON需要先用 rasterio.features.rasterize 转成和原图对齐的掩膜再检查投影和采样范围否则后面训练数据全是错位。常见做法是用 GDAL 或 rasterio 读取原始 TIFF直接按窗口读取减少内存压力。下面是裁剪脚本的核心部分和常见工程里的预处理脚本逻辑一致import numpy as np import rasterio from rasterio.windows import Window def make_train_patches(image_path, label_path, out_dir, patch_size512): with rasterio.open(image_path) as src_img, rasterio.open(label_path) as src_lbl: width, height src_img.width, src_img.height for i in range(0, height, patch_size): for j in range(0, width, patch_size): win Window(j, i, patch_size, patch_size) img src_img.read(windowwin, boundlessTrue, fill_value0) lbl src_lbl.read(windowwin, boundlessTrue, fill_value0) img np.transpose(img, (1, 2, 0)) lbl np.squeeze(lbl) if (lbl 1).sum() 512: continue np.savez_compressed( f{out_dir}/patch_{i}_{j}.npz, imageimg.astype(float32), labellbl.astype(uint8), )逻辑说明Window(j, i, patch_size, patch_size)的第一个参数是列起点x第二个参数才是行起点y和影像处理库的约定一致boundlessTrue允许窗口超出图像边界超出部分自动用 0 填充省去手工 pad。每个 patch 保存为 npz 而不是 tif是为了训练时 IO 更快直接用 np.load 就能拿到数组。参数说明patch_size512是我做城市高分影像的默认值分辨率为 0.5 米时约覆盖 256 米范围既能覆盖一层楼体阴影又不至于把整条大江全塞进一个 patch如果显存只有 8G 并打算用 ResNet34-U-Netpatch 降到 384 更稳。标签中水体像素少于 512 的 patch 直接跳过是为了避免大量全背景样本拖慢收敛如果任务包含大量小池塘阈值可以降到 64但要配合过采样。容易被忽视的一个细节裁剪步长不要总等于 patch 大小。我一般保留 15% 重叠让断裂在 patch 边缘的水体在相邻 patch 中仍有机会被完整看到。代码里把步长改成int(patch_size * (1 - overlap_ratio))即可。2.3 归一化与增强高分影像水体的“玄学”输入通道遥感影像的归一化不要照搬 ImageNet 的均值方差。高分影像的光谱分布和自然照片完全不同常见做法是先统计训练集每个通道的均值和标准差再把影像标准化到 0 均值和单位方差。这个统计值要保存下来推理时用同一组参数。如果统计来自全部 patch输入顺序要一致。增强策略直接影响模型对城市阴影的耐受度。我常用的增强包括随机水平翻转、垂直翻转、90 度旋转、亮度扰动、轻微高斯模糊。这里不建议随机缩放。用线性插值缩放影像不会改变语义但会改变水体边缘的硬边界标签中会出现 1-2 像素的灰色过渡区模型容易学会“模糊边缘水”推理时反而对真实锐边界不敏感。对城市阴影问题可以在增强中加一个“随机暗化”分支把整个 patch 的 RGB 乘上 0.5 到 0.8 的系数模拟部分阴影状态。这比单纯收集阴影样本成本低也能明显降低误检率。另外如果影像有近红外波段强烈建议把RGBNIR四通道作为输入并额外计算 NDWI 作为第五个通道。NDWI 对薄云和暗区有响应差异模型拿它做参考能更好地区分水体与阴影。只是这个操作必须保证训练和推理时通道顺序完全相同否则模型一上线就废。数据划分上不要按 patch 随机分训练验证因为同一景影像相邻 patch 高度相似验证 IOU 会虚高。更好的划分单位是原始影像或行政区/瓦片范围让验证集完全由未见过的区域组成。这也是我在第 5 章会再展开的一个坑。3. 用 PyTorch 训练水体提取模型训练脚本、损失函数与 3 组关键参数有了裁剪好的 patch下面进入源码包的核心训练脚本。训练脚本要解决三件事数据装载、损失计算、超参控制。这一章把训练主流程拆开并解释每个参数背后为什么这样设。3.1 训练主流程代码从 DataLoader 到反向传播训练代码并不复杂但要稳定运行还需要在细节上打磨。下面是可复现的训练循环主体也是大多数水体提取项目的骨架import torch import torch.nn as nn from torch.utils.data import DataLoader, Dataset from torch.optim import AdamW class WaterDataset(Dataset): def __init__(self, file_list, mean, std): self.file_list file_list self.mean mean self.std std def __len__(self): return len(self.file_list) def __getitem__(self, idx): data np.load(self.file_list[idx]) image data[image] label data[label] image torch.from_numpy(image).permute(2, 0, 1).float() image (image - self.mean) / (self.std 1e-8) label torch.from_numpy(label).float() return image, label model create_unet(encoderresnet34, in_channels3, out_channels1) model.cuda() optimizer AdamW(model.parameters(), lr1e-4, weight_decay1e-5) dice_loss DiceLoss() bce_loss nn.BCEWithLogitsLoss() for epoch in range(epochs): model.train() for images, labels in dataloader: images, labels images.cuda(), labels.cuda() logits model(images) loss bce_loss(logits, labels.unsqueeze(1)) dice_loss(logits, labels) optimizer.zero_grad() loss.backward() optimizer.step() torch.save({model_state: model.state_dict(), epoch: epoch}, fcheckpoints/unet_{epoch:03d}.pth)逻辑说明数据集返回的标签是(B,H,W)但模型输出是(B,1,H,W)所以要用labels.unsqueeze(1)扩展维度否则 BCELoss 会报 shape 错误。BCE 和 Dice 直接相加dice_loss内部会对 logits 做 sigmoid不需要提前归一化。每个 epoch 保存 checkpoint是为了后面做早停和多候选回退。参数说明in_channels3对应 RGB如果你按 2.3 加了 NDWI 通道要改成 4lr1e-4是 AdamW 比较稳的起点配合weight_decay1e-5避免过拟合batch size 取决于显存patch512 时 bs8 在 8-10G 显存上比较紧我通常先保 batch8不行再降 patch因为小 patch 会让模型看不到大阴影的全貌。训练循环里我还会额外加两行代码torch.nn.utils.clip_grad_norm_(model.parameters(), 5)和 AMP 混合精度scaler.scale(loss).backward()第一次跑通时可以不加。3.2 损失函数细节BCE 与 Dice 为什么不能省一个城市水体分割最大的痛点是类别不均衡。在一个 512×512 的 patch 里水体可能只占 3%纯 BCE 会让模型很自然地把所有像素预测成背景因为即使全猜错损失也能降到很低的水平。Dice 损失直接关注预测和水体掩膜的交叠程度对正样本不敏感能迫使模型去抓住那些稀疏的水体区域。但单独使用 Dice 也有问题训练早期 Dice 梯度很大容易振荡。把 BCE 和 Dice 加在一起BCE 保持像素级的稳定拟合Dice 负责拉高整体重叠度两者互补。下面是常用的 DiceLoss 实现class DiceLoss(nn.Module): def __init__(self, smooth1.0): super().__init__() self.smooth smooth def forward(self, logits, targets): probs torch.sigmoid(logits) probs probs.reshape(probs.size(0), -1) targets targets.reshape(targets.size(0), -1) intersection (probs * targets).sum(dim1) union probs.sum(dim1) targets.sum(dim1) dice (2 * intersection self.smooth) / (union self.smooth) return 1 - dice.mean()逻辑说明把每个样本的特征图拉平成(N,)向量计算每个样本的 Dice 再求平均。smooth在目标整体为 0全背景 patch时防止分母为 0。如果按 2.2 做了前景占比过滤全背景 patch 很少但也不是绝对没有。参数说明smooth一般取 1.0不需要调大太大的平滑会让损失对边界不敏感。如果使用 batch 级 Dicebatch size 不同时损失波动很大我建议按样本计算也就是代码里的dim1版本。目标是多类时DiceLoss 要拆成多类分别算但水体提取是二分类单通道输出就够了。3.3 学习率、batch size 与多尺度输入3 个参数背后的实际效应很多人把学习率当成玄学其实训练水体提取模型时它是最容易出问题的超参数。我一般先用1e-4跑 20 个 epoch如果训练 loss 一直平稳下降就继续如果 loss 在前几个 epoch 出现振荡就把学习率降到2e-5并把 weight decay 调回1e-5。若使用OneCycleLR初始峰值学习率可以给到3e-4但总 epoch 数必须足够否则后半程会欠拟合。batch size 对最终精度的影响不是单调的。较大的 batch16 或 32让梯度更平滑训练更稳定但在城市高分影像上每个 patch 间的水体形态差异很大过大 batch 会让模型学到“平均”的水体形状对细碎目标反而不利。我通常固定 batch size 为 8并用梯度累积凑等效 batch。如果显存不够不要试图把 patch 从 512 缩到 256 硬扛因为池化下采样后16 像素宽的池塘在 256 输入下只剩 8 像素模型几乎看不见。多尺度输入是一个有效但不绝对必要的技巧每个 epoch 随机把 patch 缩放 0.8、1.0、1.25 三档再剪裁回 512×512可以让模型对不同传感器的地面分辨率更鲁棒。但前面提到过缩放会让水体边缘出现过渡带如果标签二值化不干净模型会学到一条模糊边缘。我的做法是只在训练初期做多尺度最后 10 个 epoch 切回固定尺度这样模型既能泛化又保留了清晰边界输出。4. 推理与面积统计把模型输出的掩膜转成可量算的水域矢量训练后的模型用于实际影像时不能一次性把整景影像塞进显卡。推理阶段要解决三个问题如何把大图拆开预测再拼回去、如何清理预测噪声、如何把掩膜转成可统计面积的矢量。这一章给出常用脚本和参数。4.1 推理脚本滑动窗口预测与重叠融合整景高分影像通常超过 1 万像素边长显存放不下。常见做法是滑动窗口预测并在窗口重叠区域取平均。重叠比例能有效避免 patch 边缘出现接缝。推理脚本核心如下def slide_predict(model, full_img, patch_size512, overlap_ratio0.15): model.eval() h, w full_img.shape[:2] prob_map np.zeros((h, w), dtypenp.float32) count_map np.zeros((h, w), dtypenp.float32) step int(patch_size * (1 - overlap_ratio)) with torch.no_grad(): for y in range(0, h, step): for x in range(0, w, step): patch full_img[y:ypatch_size, x:xpatch_size] pad_y patch_size - patch.shape[0] pad_x patch_size - patch.shape[1] patch cv2.copyMakeBorder(patch, 0, pad_y, 0, pad_x, cv2.BORDER_CONSTANT, value0) # 这里要与训练时完全一致的mean/std归一化 patch (patch - mean) / (std 1e-8) patch_tensor torch.from_numpy(patch).permute(2, 0, 1).unsqueeze(0).float().cuda() out torch.sigmoid(model(patch_tensor)[0, 0]).cpu().numpy() # 去掉边缘填充只保留有效区域 out out[:min(patch_size, h - y), :min(patch_size, w - x)] prob_map[y:yout.shape[0], x:xout.shape[1]] out count_map[y:yout.shape[0], x:xout.shape[1]] 1 prob_map / np.maximum(count_map, 1) return prob_map逻辑说明step按重叠 15% 计算也就是从第二个窗口开始会滑动到上一个窗口内 15% 像素的位置重叠区域每个像素会有两到三次预测结果最后求平均。边缘不足时用 0 填充但填充区域不参与拼接(image - mean) / (std 1e-8)必须使用训练时保存的统计量不能重新算整幅图否则通道分布不同模型输出概率会被整体拉偏。参数说明overlap_ratio取 0.15 是速度与接缝的折中如果目标是河流、水网密集地区建议调到 0.25。推理时可以用model.half()开启 FP16速度接近翻倍但要注意如果模型里用了 BatchNorm必须保持model.eval()状态否则 BatchNorm 在 FP16 下会重新计算 batch 统计量精度可能掉得很快。如果显存足够也可以一次预测多个 patch但需要额外做 padding 到同一尺寸。4.2 后处理去掉噪声小斑块、填补水域内部空洞模型输出是连续概率图通常以 0.5 为阈值转成 0/1 掩膜。城市影像里地面噪声多直接阈值化会留下许多小斑块。常见后处理分三步连通域面积过滤、形态学闭运算、边缘平滑。以下代码可以直接放在推理脚本末尾import cv2 import numpy as np mask (prob_map 0.5).astype(np.uint8) num_labels, labels, stats, _ cv2.connectedComponentsWithStats(mask, 8) for label_id in range(1, num_labels): if stats[label_id, cv2.CC_STAT_AREA] 40: mask[labels label_id] 0 mask cv2.morphologyEx(mask, cv2.MORPH_CLOSE, np.ones((5, 5), np.uint8)) mask cv2.medianBlur(mask, 5)逻辑说明connectedComponentsWithStats会把预测结果中每个白色连通区域编号stats[label_id, cv2.CC_STAT_AREA]是该区域像素总数小于阈值的区域直接置 0能清掉道路反光形成的小碎片。MORPH_CLOSE先用膨胀补上桥体或船造成的空洞再用腐蚀恢复外部轮廓。medianBlur对边缘做中值平滑去掉孤立噪声点。顺序不能反如果先闭运算再删小斑桥墩被填掉后的小面积区域仍然会被删除影响不大但先删小斑再闭运算小水面也容易一起消失。参数说明面积阈值 40 对应 0.5 米分辨率下约 10 平方米适合中小城市池塘如果只关心大水面可以提升到 200。结构元大小 5×5 在 0.5 米影像上等效 2.5×2.5 米太小填不住桥洞太大会把细支流吞掉。如果还要做矢量边界后处理不要过于激进否则矢量化出来的岸线会比真实位置偏出好几个像素。4.3 从像素掩膜到地理坐标面积投影与比例尺换算如果只是统计“这片水面占比”可以用(mask.sum() * pixel_area)。但在地理信息系统里最终交付往往需要 GeoJSON 或 shapefile。用 rasterio 的 features.shapes 可以直接把掩膜和仿射变换转成多边形import geopandas as gpd import rasterio from rasterio.features import shapes with rasterio.open(original.tif) as src: transform src.transform geoms ( {properties: {raster_val: v}, geometry: s} for i, (s, v) in enumerate(shapes(mask, maskmask, transformtransform)) if v 1 ) gdf gpd.GeoDataFrame.from_features(geoms) # 转到当地平面坐标系计算面积 gdf gdf.to_crs(EPSG:32650) # UTM 50N示例按实际位置选 gdf[area_m2] gdf.geometry.area water_area gdf[area_m2].sum()逻辑说明shapes(mask, maskmask, transformtransform)遍历掩膜上值等于 1 的连通域生成 PolygonGeoDataFrame.from_features把几何变成 GeoDataFrame。to_crs(EPSG:32650)是 UTM 投影以米为单位投影后直接算面积才是平方米。如果原始影像不是带坐标 TIFF可以先用图像左下角坐标和像元大小构造 transform但这类操作必须非常小心坐标偏移一个像素就会导致面积偏差。参数说明UTM 带号要按城市经度选不能随便套没有 GIS 经验的话直接用原始影像的投影坐标计算风险很大。一般做法是先用src.crs读取原始投影再用 pyproj 转成当地高斯投影再求面积。5. 避坑清单城市水体提取最容易翻车的 5 个地方下面是过去做城市高分影像水体标注和训练时反复遇到的几个问题按“现象—原因—解决”记录每一条都能在工程排查时直接对照。5.1 阴影被当成水体深层原因与缓解手段现象白天阳光充足时高层建筑阴影、桥梁遮挡区域被输出成成片水体尤其集中在旧城区。原因可见光影像中阴影部分的亮度很低近红外反射也被削弱和水体的低反射率区间高度重叠模型如果只靠光谱特征很容易学到“暗像素水”这种粗糙规则。解决首要是给模型更丰富的上下文通道把 NDWI 作为额外输入因为 NDWI 对水是正值、对阴影是负值其次是增强把样本随机变暗 30%-50%让模型见过“暗但非水”的样本最后是结果后处理对高密度阴影区做连通域过滤但没法根治。实际项目中只靠后处理误检率最多下降三成必须从训练数据层面动手。排查误检位置时把预测概率图和原始影像叠加使用 GIS 点选误检区域能快速判断是阴影还是道路反光。5.2 薄云遮挡后的漏检数据增强难解决的分布漂移现象多云天气的影像上水体被漏检成碎片或概率值普遍低于 0.3。原因薄云相当于在地表反射率上叠加了一个平滑的低频偏移改变了水体在可见光波段的表现训练时如果全部来自晴空数据推理时就遇到了分布外样本。解决一种常见做法是在训练时模拟薄云给随机 patch 乘以一个 0.7 到 1.1 变化的系数并叠加高斯模糊模拟云的遮蔽效果另一种是采集目标区域的多云历史影像做微调。数据增强只能缓解想要根治需要把去云算法或相对辐射校正放进前处理但那些方法的成本和稳定性在工程里并不理想。注意做了薄云模拟后验证集最好也加入少量真实多云样本否则验证分数依旧会虚高等到了部署阶段才会暴露。5.3 小水体在损失函数里被忽略加权采样与加权损失现象训练收敛后大河大湖分割得很好但窄河、池塘边缘断裂或缺失。原因小水体像素占比太低BCE 和 Dice 都被大面积背景稀释模型认为预测成背景也足够“降低损失”。解决我一般用双重策略。第一重是 DataLoader 级加权采样按 patch 内前景像素比例排序前景占比在 1%-10% 的 patch 重复采样第二重是损失函数加权把 BCE 的前景权重设为 2 或 3或者引入 Focal Loss。需要在训练日志里记录每个 patch 的前景占比否则很难判断增强是否真的覆盖了小水体。Dice 在小目标 patch 上的值很波动不能因为某个 epoch 看到 Dice 掉到 0.7 就早停要连续观察 10 个 epoch 或 EMA 平滑后的曲线。5.4 边缘锯齿与内部空洞形态学操作的时机要放在最后现象模型输出的掩膜边缘像锯齿水体内部桥梁、船体位置出现空洞视觉上不干净。原因逐像素分类本身不具备平滑约束训练标签如果只标注水体不包含船桥模型就会把船桥位置当作背景锯齿是模型边界概率不均的结果。解决不要在模型输出前做平滑也不要一上来就膨胀。标准流程是先阈值化再连通域面积过滤然后闭运算填洞最后中值滤波。如果还要把结果交给矢量软件做“边界简化”栅格后处理越少越好否则矢量化出来的边界会偏离真实岸线好几个像素。实际项目中我会针对不同水体类型分两个后处理分支细窄河道只做小核中值滤波大湖面才做闭运算补洞。如果做多期变化监测后处理核大小必须固定否则两期之间的面积差会包含伪变化。5.5 训练和推理尺寸不一致导致精度下降固定 patch 大小现象训练用 512×512 patch推理时为了省事直接把整景影像 resize 到 512×512输出的水体边界完全糊掉河流断成一截一截。原因resize 相当于把每个水体的尺度压缩了几十倍模型从未在这个尺度下见过目标高分辨率影像中 20 米宽的池塘在 resize 后可能只剩 2 像素网络无法识别。解决必须用与训练一致尺寸的滑动窗口推理重叠区域取平均如果显卡不够缩小 batch 或 patch 尺寸但训练和推理的 patch 大小必须统一。另外如果训练时用了 BatchNorm推理时即使 patch 尺寸一致也要记得调用model.eval()确保 BN 使用 running stats而不是重新计算 batch 统计量。希望模型适应不同空间分辨率可以在训练时加入多尺度输入但推理仍然建议按原分辨率切块而不是整幅 resize。6. 验证你的模型不看测试集也能提前止损的方法训练结束后验证 IOU 不能代表真实效果。我见过太多项目训练 IOU 0.95一换城市掉到 0.6。原因出在验证方式上如果把验证集 patch 从同一景影像里随机抽出相邻 patch 高度相似空间自相关会让分数虚高。所以我的验证习惯分三步走。第一保留一个按行政区划分的“地域测试集”。训练集、验证集、测试集不共享任何一景影像测试集最好来自不同季节甚至不同城市。每训练完一个版本用跨城市验证集跑一遍推理把输出概率图和原图叠成四格图人工扫一遍。视觉扫图能快速发现系统性问题如果误检全部集中在道路或楼宇阴影就能判断需要补阴影样本而不是盲目调损失函数。第二除了 IOU还要看边界置信度。对验证集每个水体边缘取内外各 5 像素的缓冲区计算该缓冲区内预测正确的比例。城市水体提取交付时最怕边缘“糊”这个指标的下降往往比整体 IOU 更早暴露问题。实现不复杂用 Canny 提取标签边缘膨胀和腐蚀得到内外带叠加预测概率求平均。第三做轻微扰动稳定性测试对同一张输入叠加 1% 的高斯噪声连续预测 5 次统计每次输出掩膜的变化程度。如果稍微扰动就产生大面积跳变说明模型决策面距离训练数据太近进入新的城市或光照条件时很容易崩。可以把三个指标放在一张表格里作为每次版本迭代的检查项。指标计算方式什么时候看IOU预测与标签交集 / 并集整体精度边界置信度岸线内外 5 像素内预测正确率城市交付边缘质量稳定性加噪声前后掩膜变化比例上线前判断鲁棒性这里也是我自己最深的教训有一回训练 loss 降得很快验证 IOU 到了 0.92但把模型拿到另一个区域试用IOU 直接掉到 0.6。根源就是训练集全部来自夏季晴天影像而目标场景是春季多云城市。后来我把“换地域换季节”设成上线前硬指标再也不敢只盯验证集。希望帮到你。本文还有配套的精品资源点击获取
返回列表