1. 遥感图像语义分割全流程实战:从PaddleSeg训练到ONNX部署
作为一名长期从事计算机视觉开发的工程师,我最近接手了一个遥感图像分割项目。最初尝试使用YOLO-seg方案,但在实际测试中发现其对细小地物(如河流、道路)的分割效果不尽如人意。经过多轮技术选型,最终选择了PaddleSeg框架,它不仅集成了多个先进的语义分割模型,还提供了完整的数据处理、训练和部署工具链。本文将详细记录从数据标注到模型部署的完整过程,特别是关键的ONNX转换环节遇到的坑和解决方案。
遥感图像分割与常规图像分割相比有三个显著特点:一是图像尺寸通常较大(512x512起步);二是地物类别间存在严重的样本不均衡(如建筑物占比远大于河流);三是需要处理多光谱数据。这些特性使得我们在模型选择和数据处理时需要特别考虑。下面就从最基础的数据标注开始,逐步拆解整个技术流程。
2. 数据准备与预处理
2.1 使用Labelme进行遥感图像标注
在语义分割任务中,数据标注的质量直接影响模型性能。我们选择Labelme作为标注工具,主要考虑以下几点:
- 开源免费,支持多边形标注(对不规则地物如河流特别重要)
- 生成JSON格式的标注文件,便于后续处理
- 支持批量导入和快捷键操作,提升标注效率
标注时的几个实用技巧:
- 对于大尺寸遥感图像(如2048x2048),建议先裁剪为512x512的小图再标注,避免内存不足
- 复杂地物(如建筑物群)可以用多个多边形标注,后期通过形态学处理合并
- 设置合理的类别体系,我们最终确定了三类:background(背景)、build(建筑物)、river(河流)
标注完成后,文件结构应如下所示:
code复制dataset/
├── images/
│ ├── 001.jpg
│ ├── 002.jpg
│ └── ...
└── annotations/
├── 001.json
├── 002.json
└── ...
2.2 JSON标注转掩膜图像
PaddleSeg训练需要的是PNG格式的掩膜图像,每个像素值对应类别ID(如0=背景,1=建筑物,2=河流)。PaddleSeg提供了便捷的转换工具labelme2seg.py,其核心原理是:
- 解析JSON中的多边形坐标点
- 在空白画布上绘制填充多边形(使用PIL.ImageDraw)
- 根据类别名称映射为对应的像素值
转换时需要特别注意:
- 确保JSON和图像文件名一一对应(除扩展名外完全相同)
- 检查类别名称的一致性(如"build"和"building"会被视为不同类)
- 转换后的掩膜图像建议用灰度模式保存,减少存储空间
转换命令示例:
bash复制python tools/data/labelme2seg.py \
--input_dir path/to/json_dir \
--output_dir path/to/output_dir
2.3 数据集划分与索引生成
合理的训练集/验证集划分对模型评估至关重要。我们使用PaddleSeg的split_dataset_list.py脚本,其特点包括:
- 支持按比例随机划分(如70%训练,30%验证)
- 保持图像和标注的对应关系
- 生成文本索引文件而非移动文件,节省磁盘空间
关键参数说明:
python复制parser.add_argument('--split', nargs=3, type=float, default=[0.7, 0.3, 0]) # 训练/验证/测试集比例
parser.add_argument('--format', nargs=2, default=['jpg', 'png']) # 图像和标注的格式
parser.add_argument('--separator', default=" ") # 文件列表中分隔符
生成的文件列表格式如下(每行包含图像路径和标注路径,空格分隔):
code复制images/001.jpg annotations/001.png
images/002.jpg annotations/002.png
...
3. 模型训练与调优
3.1 模型选型与配置
PaddleSeg提供了丰富的预训练模型,经过对比测试,我们选择了PP-LiteSeg模型,主要基于以下考虑:
- 专为移动端设计,计算量小(仅1.5G FLOPs)
- 在遥感图像上表现优于UNet等传统结构
- 支持多种注意力机制,适合处理复杂场景
配置文件(.yml)需要调整的关键参数:
yaml复制train_dataset:
type: Dataset
dataset_root: path/to/dataset
train_path: path/to/train_list.txt
num_classes: 3 # 背景+2类
transforms:
- type: Resize
target_size: [512, 512] # 调整输入尺寸
- type: RandomHorizontalFlip
- type: Normalize
model:
type: PPLiteSeg
backbone:
type: STDC1
num_classes: 3
3.2 训练过程与技巧
启动训练的命令行示例:
bash复制python train.py \
--config configs/pp_liteseg_remote.yml \
--save_dir output \
--do_eval \
--use_vdl # 启用VisualDL日志
训练过程中的几个关键点:
- 学习率策略:采用Cosine衰减,初始lr=0.01,配合warmup
- 数据增强:除基础的翻转外,增加了随机裁剪和颜色抖动
- 损失函数:组合使用CrossEntropyLoss和DiceLoss(解决样本不均衡)
- 评估指标:重点关注mIoU和各类别的召回率
实测发现,在batch_size=8时,Tesla V100上每个epoch约需3分钟,训练100个epoch后mIoU达到78.3%
3.3 模型验证与测试
使用验证集评估模型性能时,要特别注意:
- 确保验证集具有代表性(包含各类地物的典型样本)
- 检查混淆矩阵,分析各类别的错分情况
- 对问题样本进行可视化分析
预测单张图像的示例代码:
python复制from paddleseg.core import predict
predict(
model=model,
model_path='output/best_model/model.pdparams',
transforms=val_transforms,
image_list=['test.jpg'],
save_dir='output/results'
)
常见问题及解决方案:
- 建筑物边缘分割不精确 → 增加边缘敏感损失(如EdgeAttention)
- 小河流漏检 → 在损失函数中增加小目标权重
- 类别混淆 → 检查标注一致性,或增加困难样本
4. 模型导出与ONNX转换
4.1 PaddlePaddle模型导出
PaddleSeg使用export.py脚本导出推理模型,需特别注意:
- 必须指定固定输入尺寸(与训练时一致)
- 选择正确的输出操作(argmax/softmax)
- 保存完整的部署配置(deploy.yaml)
导出命令示例:
bash复制python export.py \
--config configs/pp_liteseg_remote.yml \
--model_path output/best_model/model.pdparams \
--save_dir inference_model \
--input_shape 1 3 512 512 # 固定输入尺寸
导出的模型包含三个关键文件:
model.pdmodel:模型结构model.pdiparams:模型权重deploy.yaml:预处理配置
4.2 转换为ONNX格式
使用Paddle2ONNX工具进行转换:
bash复制paddle2onnx \
--model_dir inference_model \
--model_filename model.pdmodel \
--params_filename model.pdiparams \
--opset_version 11 \
--save_file model.onnx
转换过程中的常见问题及解决:
- 报错"Unsupported op: pool2d" → 升级paddle2onnx到最新版(>=0.6)
- 动态尺寸问题 → 导出时指定固定input_shape
- 精度下降 → 检查opset_version(建议>=11)
实测发现,在Windows平台转换时容易出现依赖冲突,推荐使用Linux环境
4.3 ONNX模型验证
转换后必须验证模型的正确性:
- 使用Netron可视化模型结构,检查输入输出
- 对比Paddle和ONNX的推理结果(余弦相似度应>0.99)
- 测试不同分辨率输入时的表现
ONNX推理示例代码:
python复制import onnxruntime as ort
sess = ort.InferenceSession("model.onnx")
input_name = sess.get_inputs()[0].name
output = sess.run(None, {input_name: input_tensor})
5. 部署优化与性能对比
5.1 ONNX运行时优化
为提高推理速度,可以:
- 启用ONNX Runtime的图优化
python复制sess_options = ort.SessionOptions()
sess_options.graph_optimization_level = ort.GraphOptimizationLevel.ORT_ENABLE_ALL
- 使用TensorRT后端(需安装onnxruntime-gpu)
- 量化模型到FP16或INT8
5.2 多平台性能测试
我们在不同硬件上测试了ONNX模型的性能(输入尺寸512x512):
| 平台 | 推理时间(ms) | 内存占用(MB) |
|---|---|---|
| Intel i7-8700K | 45 | 520 |
| NVIDIA T4 | 12 | 780 |
| Jetson Xavier NX | 28 | 650 |
| Raspberry Pi 4 | 320 | 410 |
5.3 精度对比分析
对比原始Paddle模型和ONNX模型在验证集上的表现:
| 指标 | Paddle模型 | ONNX模型 | 差异 |
|---|---|---|---|
| mIoU | 78.3% | 77.1% | -1.2% |
| 建筑物F1 | 82.5% | 81.7% | -0.8% |
| 河流F1 | 73.2% | 70.1% | -3.1% |
针对河流识别精度下降的问题,我们发现主要是由于:
- ONNX的Resize操作与Paddle实现存在细微差异
- 小目标在多次下采样中信息丢失
- 后处理的argmax操作对软预测结果的影响
解决方案包括:
- 训练时使用更大的输入尺寸(1024x1024)
- 在ONNX模型中添加自定义后处理
- 采用TTA(测试时增强)策略
6. 实际应用中的经验总结
经过完整项目实践,总结出以下几点关键经验:
- 数据层面
- 遥感图像建议先做辐射校正和几何校正
- 对不均衡类别采用过采样或加权损失
- 保留部分困难样本用于后续模型迭代
- 训练技巧
- 使用预训练backbone(在遥感数据上微调)
- 采用渐进式resize策略(先小尺寸预热,再大尺寸微调)
- 监控各类别的独立指标,避免被主导类别掩盖问题
- 部署优化
- ONNX模型在移动端部署时考虑量化
- 对实时性要求高的场景可以裁剪模型通道数
- 使用多线程流水线处理大图切片
- 持续改进
- 建立自动化测试流程监控模型性能衰减
- 定期收集bad case补充训练数据
- 探索半监督学习利用未标注数据
这套方案已经成功应用于多个遥感分析项目,包括建筑物提取、水体监测等场景。特别是在应急救灾中,ONNX格式的模型能够快速部署到边缘设备,实现实时灾害评估。后续我们计划尝试将SAM等大模型与轻量级分割模型结合,进一步提升小样本下的表现。