资讯动态

百度飞桨遥感图像智能解译:数据预处理、模型训练与部署全流程实战

发布时间:2026/9/12 10:52:25 来源:尧图企业网站定制
简介一套基于百度飞桨的遥感图像智能解译平台源自软件开发类比赛压缩包内为完整参赛源码、设计文档与配套资料可直接对应项目立项、课设或毕设场景。资源面向人工智能、通信、自动化、电子信息等专业的高校学生、教师与科研人员既可辅助比赛筹备也可作为深度学习与Web系统结合的入门范本。包内共1000个文件整体21.15MB以790个Python脚本作为后端与算法核心覆盖模型训练、推理及业务接口同时配备Vue组件、JavaScript、SVG、SCSS等前端文件呈现可视化交互界面另有SQL数据库脚本用于数据管理PDF与Markdown文档帮助理解设计思路。目前已有58人学习下载。项目代码完整且经过功能测试能够直接运行读者可依目录结构快速定位算法、接口或界面模块在现有框架上替换数据、调整模型或增加功能适合作为毕业设计、课程设计或竞赛作品的起点。1. 基于百度飞桨的遥感图像智能解译比赛里真正卡人的不是模型遥感图像智能解译赛题这几年越来越多从地物分类到海岸线提取给的原始影像通常是几万乘几万的 TIF标注却只有薄薄一张灰度图。许多队伍一上来就换网络、拼算力最后发现分数卡在 0.82 上不去问题恰恰出在数据切得不干净、类别分布没看过一眼。这篇文章按我自己打这类比赛的习惯把基于百度飞桨的遥感解译平台从数据准备、模型训练到部署演示的完整链路拆开讲每个环节给出可抄的代码和参数。适合准备参赛的队伍也适合想在业务里快速验证遥感解译可行性的工程师。飞桨生态里 PaddleRS、PaddleSeg、EISeg 这些工具已经覆盖了八成工作剩下的功课在于怎么组织数据和处理模型输出。2. 遥感图像标注与预处理让飞桨模型在原始影像上站得住2.1 标注工具选择用 EISeg 做半自动标注快速凑齐第一轮训练集比赛刚开局时最缺的是标注数据。如果完全用 LabelMe 逐像素画多边形一个 512x512 的样本要花十分钟还没开始训练先消耗大量时间。常见做法是用飞桨的 EISeg 交互式分割工具做半自动标注。EISeg 支持加载预训练模型点击前景和背景的提示点就能拉出一块区域的掩膜人工只需要修正边界。对遥感影像这类边缘清晰的地物效率比纯手动高三倍以上。EISeg 导出的标注是 PNG 灰度图背景为 0各类别从 1 开始递增。这个细节要提前定好因为后续切图和损失函数都依赖类别 ID 的连续性。我的习惯是类别 ID 保持从 0 到 N-1 连续排列背景类别放在最后而不是把背景设为 255。否则模型在计算交叉熵时容易出现维度不匹配。标注完成后第一件事是统计每类的像素占比打印出一张柱状图看一眼就知道哪些类别是少数类后续训练策略要围绕它们调。这一步很多人跳过等到训练出来才发现小类目被模型直接忽略了。提示EISeg 交互式标注时尽量固定影像的拉伸方式建议使用 2% 线性拉伸保证目视解译的色感与模型归一化后一致。2.2 大影像滑窗切块512 窗口配 stride256兼顾上下文与显存高分遥感影像动辄几万像素宽直接整图训练显存放不下模型下采样后小目标也容易丢。滑窗切块是绕不开的步骤核心参数是窗口大小和步长。窗口选 512x512 比较稳妥上下文信息足够ResNet 系列 backbone 下采样 32 倍后还有 16x16 的特征图不至于丢失大目标的全局结构。步长选窗口的一半也就是 256保证相邻窗口之间有重叠目标物体不会被一刀切成两半。import rasterio import numpy as np def sliding_window_crop(image_path, label_path, out_dir, crop_size512, stride256): with rasterio.open(image_path) as src: img src.read() # (C, H, W) with rasterio.open(label_path) as lbl_src: label lbl_src.read(1) # (H, W) h, w label.shape idx 0 for y in range(0, h - crop_size 1, stride): for x in range(0, w - crop_size 1, stride): crop_img img[:, y:ycrop_size, x:xcrop_size] crop_lbl label[y:ycrop_size, x:xcrop_size] np.save(f{out_dir}/image_{idx:06d}.npy, crop_img) np.save(f{out_dir}/label_{idx:06d}.npy, crop_lbl) idx 1这段代码把原始影像和标注同步切成固定尺寸的块保存为 npy 格式训练时用内存映射加载比每次从 TIF 上随机裁剪更快。参数上crop_size越大模型看到的上下文越完整但 batch size 和显存压力越大stride越小重叠区域越多样本量越大训练时间线性增长。对显存 24G 的显卡建议 batch size 设为 8窗口 512stride 256 的组合。如果原始影像边缘有黑边或无数据区域切图前先根据有效像素范围裁剪外接矩形。2.3 数据增强参数别照搬自然图像的配置遥感影像和自然图像的增强策略差异很大。随机裁剪、翻转、旋转可以直接用但颜色抖动要谨慎。多光谱影像中水体在近红外波段响应强烈如果对 RGB 三通道做强度不一致的颜色增强会破坏地物的光谱特征训练出来的模型在验证集上表现不错一到真实高分影像上就失效。常见做法是只做轻度的亮度扰动和 Gamma 矫正对波段间相对比例不做改动。from paddle.vision.transforms import Compose, RandomHorizontalFlip, RandomVerticalFlip from paddle.vision.transforms import RandomRotation, ColorJitter train_transforms Compose([ RandomHorizontalFlip(p0.5), RandomVerticalFlip(p0.5), RandomRotation(90), ColorJitter(brightness0.2, contrast0.2, saturation0.0, hue0.0) ])这里RandomRotation(90)限定为 90 度的整数倍是因为遥感影像地物方向随机旋转任意角度容易产生插值噪声90 度旋转不改变像素排列。ColorJitter 里 saturation 和 hue 都设 0保住地物原始色彩比例。验证集划分时按类别占比做分层抽样保证每一类的影像块都出现在验证集中否则少数类在训练过程中完全失去监督信号。这个预处理流程跑完之后把切好的样本随机打散按 8:1:1 分成训练、验证、测试三份。3. 飞桨解译模型选型与训练海岸线提取与地物分类的配置差异3.1 PaddleRS 和 PaddleSeg 的边界按任务类型选框架飞桨生态里遥感解译有两个入口PaddleRS 定位遥感影像智能解译覆盖语义分割、目标检测、场景分类、变化检测四类任务PaddleSeg 是通用分割套件模型库更丰富也支持遥感场景。我的判断标准很简单如果赛题涉及变化检测直接用 PaddleRS它内置了 BIT、SNUNet 等变化检测网络省去自己写数据处理如果只是单时相影像做地物分类或海岸线提取用 PaddleSeg 更合适模型选择多调参资料也丰富。海岸线提取是典型的边缘分割任务背景和水体占比极大岸线本身只有几个像素宽。这类任务用标准的交叉熵损失训练模型会倾向于把所有像素都预测为背景因为这样 loss 也降得下去。解决办法是换用 Dice Loss 或 Lovasz Loss它们直接优化区域重叠度对小目标更友好。PaddleSeg 的配置里可以直接指定多损失函数组合我一般让 CrossEntropyLoss 和 DiceLoss 各占一半权重前者保证收敛稳定性后者拉高边缘富集区域的精度。loss: types: - type: CrossEntropyLoss - type: DiceLoss coef: [0.5, 0.5]这段配置的意思是对 logits 同时计算交叉熵和 Dice 损失加权系数各取 0.5。如果少数类别占比低于 1%可以把 DiceLoss 的系数调到 0.7。需要说明的是Dice Loss 在小 batch 下梯度波动大batch size 低于 4 时建议先只跑交叉熵等稳定了再把这套组合损失加进来。3.2 决定名次的 5 个训练参数调好一个都能涨点从多次比赛经验看模型结构对最终分数的影响只占三成数据质量和训练细节占七成。在飞桨训练框架下有 5 个参数值得逐个调参数推荐设置影响backboneHRNet-W48 或 ResNet50前者边缘细节好后者训练快、容易收敛batch_size8单卡越小 Dice Loss 越不稳定初始学习率0.01SGD或 0.001AdamW线性缩放规则batch 翻倍学习率也翻倍学习率衰减polynomial_decaypower0.9模拟退火后期收敛更稳训练轮数120k iterations遥感数据量大时多轮训练比换模型更有效backbone 的选择更具体一点。HRNet 的特征图始终保持高分辨率对道路、岸线这类细长结构的分割精度明显更高但显存占用大。如果卡是 RTX 3090 或 A100优先用 HRNet-W48如果是消费级显卡ResNet50 做 backbone 的 DeepLabV3 是性价比选择训练时间能缩短一半。学习率上用 ImageNet 预训练权重时 SGD 初始学习率 0.01 左右poly 衰减后段学习率降到非常低模型在这个阶段会把边缘打磨得更干净。提示换 backbone 后一定要确认预训练权重的类别数。PaddleSeg 里pretrained参数加载的是 ImageNet 分类权重它只包含 backbone 部分不会影响分割头的输出维度可以放心加载。3.3 训练命令与调优路径从跑通到刷分PaddleSeg 训练入口统一配置文件用 YAML 编写训练命令只要指定 config 路径即可。下面是最小可运行的训练命令python tools/train.py \ --config configs/deeplabv3p/deeplabv3p_resnet50_os8_rs_512x512_160k.yml \ --num_workers 8 \ --use_vdl --vdl_log_dir ./vdl_log--num_workers是数据加载线程数建议和 CPU 核心数相当太少了 GPU 会空转等待数据--use_vdl开启 VisualDL 日志记录训练结束后可以用visualdl --logdir ./vdl_log启动可视化面板查看 loss 和 mIoU 曲线。训练过程中如果想在某个 checkpoint 上做评估打开另一个终端执行python tools/eval.py \ --config configs/deeplabv3p/deeplabv3p_resnet50_os8_rs_512x512_160k.yml \ --model_path output/deeplabv3p_resnet50_os8/best_model/model.pdparams第一个坑是配置文件和模型结构不匹配加载权重时报 shape 错误这时检查num_classes是否与自己的数据类别数一致。第二个坑是训练集和验证集的归一化方式不一致PaddleRS 的 dataset 配置里 image 的 mean/std 如果用了 ImageNet 默认值而切图时自己做了 [0,1] 归一化验证 mIoU 会非常难看。统一在数据集配置里指定 mean/std不要在切图阶段做归一化。调优路径上我建议让模型先跑 20k iterations 验证 loss 能降下来然后看每个类别的 IoU。少数类 IoU 极低时优先加类别权重而不是换模型。如果整体 mIoU 卡住不动打开tools/analyze.py脚本看混淆矩阵找出哪些类互相打架回到标注阶段修正边界不清晰的样本这个过程通常比调 loss 更快见效。4. 解译平台化把飞桨模型封装成可演示的智能解译服务4.1 动转静导出推理模型固定输入尺寸避免精度损失比赛交付一般要求有可视化界面单纯在命令行调模型打分拿不到演示效果。第一步把训练好的动态图参数转成静态图推理模型。PaddleSeg 提供了导出脚本tools/export.py但如果你在模型基础上做了额外后处理建议自己写一段导出代码import paddle from paddle.static import InputSpec model paddle.vision.models.segmentation.deeplabv3p_resnet50( num_classesnum_classes, pretrainedNone) model.set_dict(paddle.load(output/model.pdparams)) model.eval() spec InputSpec([1, 3, 512, 512], float32, image) model paddle.jit.to_static(model, input_spec[spec]) paddle.jit.save(model, deploy/deeplabv3p_rs)to_static把动态图模型转为可序列化的静态图InputSpec制定了输入张量的形状和数据类型。这里把 batch 维设成 1固定 512x512 分辨率推理时输入图片先缩放到这个尺寸。如果你在评估时用了多尺度推理TTA导出模型时不要保留这个逻辑TTA 逻辑写在服务端预处理里否则静态图保存的模型结构会异常复杂。导出成功后deploy目录下会生成model.pdmodel和model.pdiparams两个文件这就是后续推理引擎要加载的东西。4.2 解译后处理从掩膜到干净矢量的 5 行核心操作模型输出的概率图是 float32 类型尺寸和输入一致。直接把最大概率索引转换成标注图还是会有很多小碎块尤其是地物边界处。用连通域分析和形态学滤波能把噪音压下去import cv2 import numpy as np def postprocess(mask, min_area100): mask cv2.medianBlur(mask.astype(np.uint8), 5) num, labels, stats, _ cv2.connectedComponentsWithStats(mask) clean np.zeros_like(mask) for i in range(1, num): if stats[i, cv2.CC_STAT_AREA] min_area: clean[labels i] i - 1 return cleanmedianBlur的核大小选 5对 512x512 的预测图来说3 太弱、7 会把细长岸线断开。connectedComponentsWithStats返回每个连通域的面积统计min_area100表示面积小于 100 像素的区域直接被丢弃这个值要根据影像分辨率调整0.5 米分辨率影像上 100 像素大约对应 25 平方米。处理完的掩膜如果需要转成矢量用 GDAL 的Polygonize或者rasterio.features.shapes直接输出 GeoJSON方便在 Web 地图上叠加显示。海岸线提取场景里这一步能显著减少锯齿状边界让演示效果更专业。4.3 用 FastAPI 搭一个最小解译接口前后端联调不出幺蛾子平台化演示最常见的落地方式是 Web 服务。用户上传一张遥感影像后端调用飞桨推理引擎返回分割结果。下面是个完整的 FastAPI 端点import tempfile from fastapi import FastAPI, UploadFile import numpy as np import paddle.inference as paddle_infer config paddle_infer.Config(deploy/model.pdmodel, deploy/model.pdiparams) config.enable_memory_optim() predictor paddle_infer.create_predictor(config) input_names predictor.get_input_names() output_names predictor.get_output_names() app FastAPI() app.post(/infer) async def infer(file: UploadFile): img_data await file.read() img preprocess(img_data) # 转 RGB、缩放 512、归一化 input_handle predictor.get_input_handle(input_names[0]) input_handle.copy_from_cpu(img[None, ...]) predictor.run() output_handle predictor.get_output_handle(output_names[0]) pred output_handle.copy_to_cpu()[0].argmax(0).astype(np.uint8) mask postprocess(pred, min_area100) return {mask_base64: encode_png(mask), classes: [0, 1, 2, 3]}enable_memory_optim()让飞桨推理时共享中间内存服务端并发请求多时能省下不少显存。这里的preprocess和postprocess都是上面写好的函数接口返回 base64 编码的 PNG 掩膜前端用图片标签直接展示不涉及复杂的二进制协议。classes字段列出所有类别 ID前端根据 ID 映射颜色表。从实战角度看FastAPI 的并发能力够比赛演示用了不需要引入 Celery 之类的任务队列。如果影像很大先在后端做缩略图再进模型响应时间压在 2 秒以内才能保证演示节奏不拖沓。5. 让比赛源码和资料真正可复现工程组织与结果验证的技巧5.1 用 VisualDL 沉淀训练曲线答辩素材一步到位比赛评分时评委不会只看最终 mIoU他们更想看队伍的分析思路。飞桨的 VisualDL 可以在训练过程中记录损失、学习率、每类 IoU 的曲线训练结束后把关键图表截出来放进答辩 PPT比临时跑测试集更有说服力。visualdl --logdir ./vdl_log --port 8080启动后浏览器打开localhost:8080左侧能看到训练损失曲线和验证集指标。我习惯把前 2000 个 iteration 的图片单独截图这能说明模型在冷启动阶段的收敛行为。如果答辩时被问“为什么选这个学习率”直接把曲线中 loss 下降速率的变化讲清楚比说“试出来的”有分量得多。针对变化检测赛题或者海岸线提取赛题把模型在几组困难样本上的预测结果和标注放在一起做成三栏对比图模型边缘提取的优劣一目了然。5.2 源码目录组织让队友和评委都能快速找到关键代码软件开发比赛的源码要求可复现如果提交的项目压缩包解压后没有 README没有环境配置文件评委很难在十分钟内跑通。规范的工程目录至少要包含数据说明、配置文件、训练脚本、推理服务和实验结果五个部分缺一不可。remote_sensing_platform/ ├── README.md ├── requirements.txt ├── data/ │ ├── raw/ # 原始影像与标注 │ ├── processed/ # 切图后的 npy │ └── README.md # 类别定义与数据来源 ├── configs/ │ └── deeplabv3p_rs.yml ├── scripts/ │ ├── preprocess.py # 切图与增强 │ ├── train.sh │ └── evaluate.py ├── deploy/ │ ├── model.pdmodel │ └── server.py # FastAPI 服务 └── results/ └── metrics.csvrequirements.txt里把依赖的飞桨版本和配套库固定到具体版本号比如paddlepaddle-gpu2.5.2这样别人复现环境时不至于因为 API 变动报错。data/README.md里写清楚类别 ID 对应的地物名称、影像来源和坐标系这一步在软件开发流程里属于需求规格说明但在比赛环境中往往被忽略。固定随机种子也是复现的关键在训练脚本开头加上paddle.seed(42)和numpy.random.seed(42)确保两次训练的结果基本一致。5.3 用一个 50 行的脚本验证海岸线解译精度最后给出一段实践中验证边缘精度的技巧用形态学缓冲区法计算边界 F1。遥感解译竞赛的评测常常基于分割掩膜的 IoU但海岸线提取类任务的最终产出是矢量线线段的偏移量比掩膜重叠面积更贴近实际用途。边界 F1 通过比较预测边界和真实标签边界在缓冲区内的重合程度来计算避免了像素级 IoU 对细线结构的过度苛刻。import cv2 import numpy as np def boundary_f1(pred_mask, true_mask, tolerance3): pred_edge cv2.Canny(pred_mask.astype(np.uint8), 0, 1) true_edge cv2.Canny(true_mask.astype(np.uint8), 0, 1) kernel np.ones((2 * tolerance 1, 2 * tolerance 1), np.uint8) true_dilate cv2.dilate(true_edge, kernel) pred_dilate cv2.dilate(pred_edge, kernel) tp np.logical_and(pred_dilate 255, true_edge 255).sum() fp np.logical_and(pred_dilate 255, true_edge 0).sum() fn np.logical_and(pred_edge 255, true_dilate 0).sum() precision tp / (tp fp 1e-6) recall tp / (tp fn 1e-6) return 2 * precision * recall / (precision recall 1e-6)tolerance表示缓冲区半径数值越大对边界偏移越宽容比赛中的高分影像一般取 2 到 3 像素。把验证集中所有预测结果平均一下就得到最终的边界 F1 分数。如果分数低于 0.85说明模型预测的岸线位置系统性偏移往往是因为训练时切图导致位置信息丢失或者多光谱波段没对齐。这条脚本也是每次交付前必跑的验收脚本五分钟能拦住八成边界噪声问题。本文还有配套的精品资源点击获取

读完文章,也想定制专属网站?

尧图设计师 24 小时内与您沟通定制方案

免费获取报价