转自AI Studio,原文链接:飞桨常规赛:遥感影像地块分割 - 12月第9名方案 - 飞桨AI Studio
为了对遥感影像进行像素级内容解析,对遥感影像中感兴趣的类别进行提取和分类,考虑使用飞桨提供的PaddleX产品解决该问题(PaddleX官方参考文档),该产品在数据标注、图像处理、模型训练等方面简单实用。本项目首先安装了PaddleX以及项目中所用到的相关包。然后,进行数据处理,主要包括数据解压操作,图像数据增强操作,划分数据集操作以及数据准备操作。进而,进行模型训练,模型评估以及模型预测。最后对本项目的中的经验以及接下来的改进方向做出总结。
本赛题由 2020 CCF BDCI 遥感影像地块分割 初赛赛题改编而来。遥感影像地块分割, 旨在对遥感影像进行像素级内容解析,对遥感影像中感兴趣的类别进行提取和分类,在城乡规划、防汛救灾等领域具有很高的实用价值,在工业界也受到了广泛关注。现有的遥感影像地块分割数据处理方法局限于特定的场景和特定的数据来源,且精度无法满足需求。因此在实际应用中,仍然大量依赖于人工处理,需要消耗大量的人力、物力、财力。本赛题旨在衡量遥感影像地块分割模型在多个类别(如建筑、道路、林地等)上的效果,利用人工智能技术,对多来源、多场景的异构遥感影像数据进行充分挖掘,打造高效、实用的算法,提高遥感影像的分析提取能力。 赛题任务 本赛题旨在对遥感影像进行像素级内容解析,并对遥感影像中感兴趣的类别进行提取和分类,以衡量遥感影像地块分割模型在多个类别(如建筑、道路、林地等)上的效果。
常规赛:遥感影像地块分割
本赛题提供了多个地区已脱敏的遥感影像数据,各参赛选手可以基于这些数据构建自己的地块分割模型。
样例图片及其标注如下图所示:
训练数据集文件名称:train_and_label.zip
包含2个子文件,分别为:训练数据集(原始图片)文件、训练数据集(标注图片)文件,详细介绍如下:
训练数据集(原始图片)文件名称:img_train
包含66,653张分辨率为2m/pixel,尺寸为256 * 256的JPG图片,每张图片的名称形如T000123.jpg。
训练数据集(标注图片)文件名称:lab_train
包含66,653张分辨率为2m/pixel,尺寸为256 * 256的PNG图片,每张图片的名称形如T000123.png。
备注: 全部PNG图片共包括4种分类,像素值分别为0、1、2、3。此外,像素值255为未标注区域,表示对应区域的所属类别并不确定,在评测中也不会考虑这部分区域。
测试数据集文件名称:img_test.zip,详细介绍如下:
包含4,609张分辨率为2m/pixel,尺寸为256 * 256的JPG图片,文件名称形如123.jpg。、
PaTTA:由第三方开发者组织AgentMaker维护的Test-Time Augmentation库,可在测试时通过数据增强方式产生额外的推理结果,在此基础上进行投票即可获得更稳定的成绩表现。 https://github.com/AgentMaker/PaTTA
RIFLE:由第三方开发者对ICML 2020中的《RIFLE: Backpropagation in Depth for Deep Transfer Learning through Re-Initializing the Fully-connected LayEr》论文所提供的封装版本,其通过对输出层多次重新初始化来使得深层backbone得到更充分的更新。 https://github.com/GT-ZhangAcer/RIFLE_Module
提交文件命名为:result.zip,zip文件的组织方式如下所示:
主目录
├── 1.png #每个结果文件命名为:测试数据集图片名称+.png
├── 2.png
├── 3.png
├── ...
备注: 主目录中必须包含与测试数据集相同数目、名称相对应的单通道PNG图片,且每张单通道PNG图片中的像素值必须介于0~3之间,像素值不能为255。
本次比赛的重点是考验选手对PaddleSeg或PaddleX等工具的使用,本项目使用的是PaddleX,需要对API接口和模型库较熟练掌握。
本次比赛的难点在于数据增强的参数设定和训练时的参数优化,想要获得理想的分数,需要对参数的调整有自己的见解和方法。
In [ ]
# 安装paddlex
# 需要注意paddlex1对于版本有所要求,所以最好更新对应的包版本
!pip install "numpy<=1.19.5" -i https://mirror.baidu.com/pypi/simple
!pip install "paddlex<2.0.0" -i https://mirror.baidu.com/pypi/simple
In [ ]
!pip install imgaug
In [3]
# 设置使用0号GPU卡(如无GPU,执行此代码后仍然会使用CPU训练模型)
import matplotlib
import os
import paddlex as pdx
os.environ['CUDA_VISIBLE_DEVICES'] = '0'
In [3]
!unzip -q data/data80164/train_and_label.zip
!unzip -q data/data80164/img_test.zip
项目使用PaddleX进行数据处理和训练,详情请查看PaddleX的API说明文档
对用于分割任务的数据进行操作。可以利用paddlex.seg.transforms中的Compose类将图像预处理/增强操作进行组合。
详情请参考数据增强文档
In [7]
from paddlex.seg import transforms
import imgaug.augmenters as iaa
# 定义训练和验证时的transforms
train_transforms = transforms.Compose([
transforms.RandomHorizontalFlip(),
transforms.Resize(target_size=300),
transforms.RandomPaddingCrop(crop_size=256),
transforms.RandomBlur(prob=0.1),
transforms.RandomRotate(rotate_range=15),
# transforms.RandomDistort(brightness_range=0.5),
transforms.Normalize()
])
eval_transforms = transforms.Compose([
transforms.Resize(256),
transforms.Normalize()
])
In [ ]
import numpy as np
datas = []
image_base = 'img_train' # 训练集原图路径
annos_base = 'lab_train' # 训练集标签路径
# 读取原图文件名
ids_ = [v.split('.')[0] for v in os.listdir(image_base)]
# 将训练集的图像集和标签路径写入datas中
for id_ in ids_:
img_pt0 = os.path.join(image_base, '{}.jpg'.format(id_))
img_pt1 = os.path.join(annos_base, '{}.png'.format(id_))
datas.append((img_pt0.replace('/home/aistudio', ''), img_pt1.replace('/home/aistudio', '')))
if os.path.exists(img_pt0) and os.path.exists(img_pt1):
pass
else:
raise "path invalid!"
# 打印datas的长度和具体存储例子
print('total:', len(datas))
print(datas[0][0])
print(datas[0][1])
print(datas[10][:])
In [ ]
import numpy as np
# 四类标签,这里用处不大,比赛评测是以0、1、2、3类来对比评测的
labels = ['建筑', '耕地', '林地', '其他']
# 将labels写入标签文件
with open('labels.txt', 'w') as f:
for v in labels:
f.write(v+'\n')
# 随机打乱datas
np.random.seed(5)
np.random.shuffle(datas)
# 验证集与训练集的划分,0.05表示5%为验证集,95%为训练集
split_num = int(0.05*len(datas))
# 划分训练集和验证集
train_data = datas[:-split_num]
valid_data = datas[-split_num:]
# 写入训练集list
with open('train_list.txt', 'w') as f:
for img, lbl in train_data:
f.write(img + ' ' + lbl + '\n')
# 写入验证集list
with open('valid_list.txt', 'w') as f:
for img, lbl in valid_data:
f.write(img + ' ' + lbl + '\n')
# 打印训练集和测试集大小
print('train:', len(train_data))
print('valid:', len(valid_data))
读取语义分割任务数据集,可使用paddlex.datasets.SegDataset
paddlex.datasets.SegDataset参数说明:
In [ ]
data_dir = './'
# 定义训练和验证数据集
train_dataset = pdx.datasets.SegDataset(
data_dir=data_dir, # 数据集路径
file_list='train_list.txt', # 训练集图片文件list路径
label_list='labels.txt', # 训练集标签文件list路径
transforms=train_transforms, # train_transforms
shuffle=True) # 数据集是否打乱
eval_dataset = pdx.datasets.SegDataset(
data_dir=data_dir, # 数据集路径
file_list='valid_list.txt', # 验证集图片文件list路径
label_list='labels.txt', # 验证集标签文件list路径
transforms=eval_transforms) # eval_transforms
利用paddlex.seg.DeepLabv3p构建DeepLabv3p分割器。
paddlex.seg.DeepLabv3p参数说明:
DeepLabv3p模型的训练接口,函数内置了polynomial学习率衰减策略和momentum优化器。
train参数说明:
In [ ]
# 分割类别数
num_classes = len(train_dataset.labels)
# 构建DeepLabv3p分割器
model = pdx.seg.DeepLabv3p(
num_classes=num_classes, backbone='Xception65', use_bce_loss=False
)
# 模型训练
model.train(
num_epochs=35, # 训练迭代轮数
train_dataset=train_dataset, # 训练集读取
train_batch_size=8, # 训练时批处理图片数
eval_dataset=eval_dataset, # 验证集读取
learning_rate=0.0001, # 学习率
save_interval_epochs=1, # 保存模型间隔轮次
save_dir='output/deeplab', # 模型保存路径
log_interval_steps=200, # 日志打印间隔
pretrain_weights='output/deeplab/best_model') #加载预训练模型
In [ ]
# 加载模型
model = pdx.load_model('./output/deeplab/best_model')
# 模型评估
model.evaluate(eval_dataset, batch_size=1, epoch_id=None, return_details=False)
DeepLabv3p模型预测接口。需要注意的是,只有在训练过程中定义了eval_dataset,模型在保存时才会将预测时的图像处理流程保存在DeepLabv3p.test_transforms和DeepLabv3p.eval_transforms中。如未在训练时定义eval_dataset,那在调用预测predict接口时,用户需要再重新定义test_transforms传入给predict接口。
In [ ]
from tqdm import tqdm
import cv2
test_base = 'img_testA/' # 测试集路径
out_base = 'result/' # 预测结果保存路径
# 是否存在结果保存路径,如不存在,则创建该路径
if not os.path.exists(out_base):
os.makedirs(out_base)
# 模型预测并保存预测图片
for im in tqdm(os.listdir(test_base)):
if not im.endswith('.jpg'):
continue
pt = test_base + im
result = model.predict(pt)
cv2.imwrite(out_base+im.replace('jpg', 'png'), result['label_map'])
In [ ]
# 由预测结果生成提交文件
!zip -r result.zip result/
有一定经验的小伙伴可以从竞赛入手锻炼自己的能力,在学习中可以多查阅Paddle官方API文档或者教程,有助于快速解决问题。
另外,可以多学习他人分享的项目,从中学习一些思路和调参经验。
对于没有经验的小伙伴,可以报名飞桨训练营和相关课程,可以很好的打下基础。
总之,要多学和多练相结合可以提升自我。
常规赛:遥感影像地块分割baseline
使用 VisualDL 助力遥感影像地块分割(PaddleX 篇)