飞桨常规赛:遥感影像地块分割 - 4月第6名方案
1.比赛介绍
1.1比赛页面传送门: 常规赛:遥感影像地块分割
1.2赛题概况
本赛题由 2020 CCF BDCI 遥感影像地块分割 初赛赛题改编而来。遥感影像地块分割, 旨在对遥感影像进行像素级内容解析,对遥感影像中感兴趣的类别进行提取和分类,在城乡规划、防汛救灾等领域具有很高的实用价值,在工业界也受到了广泛关注。现有的遥感影像地块分割数据处理方法局限于特定的场景和特定的数据来源,且精度无法满足需求。因此在实际应用中,仍然大量依赖于人工处理,需要消耗大量的人力、物力、财力。本赛题旨在衡量遥感影像地块分割模型在多个类别(如建筑、道路、林地等)上的效果,利用人工智能技术,对多来源、多场景的异构遥感影像数据进行充分挖掘,打造高效、实用的算法,提高遥感影像的分析提取能力。 赛题任务 本赛题旨在对遥感影像进行像素级内容解析,并对遥感影像中感兴趣的类别进行提取和分类,以衡量遥感影像地块分割模型在多个类别(如建筑、道路、林地等)上的效果。
1.3数据说明
本赛题提供了多个地区已脱敏的遥感影像数据,各参赛选手可以基于这些数据构建自己的地块分割模型。
1.3.1训练数据集
样例图片及其标注如下图所示:
训练数据集文件名称: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为未标注区域,表示对应区域的所属类别并不确定,在评测中也不会考虑这部分区域。
1.3.2测试数据集
测试数据集文件名称:img_test.zip,详细介绍如下:
包含4,609张分辨率为2m/pixel,尺寸为256 * 256的JPG图片,文件名称形如123.jpg。、
1.3.3数据增强工具
用什么数据增强,PaddleX自带的足矣!!!
1.4提交内容及格式
- 以zip压缩包形式提交结果文件,文件命名为 result.zip;
- zip压缩包中的图片格式必须为单通道PNG;
- PNG文件数需要与测试数据集中的文件数相同,且zip压缩包文件名需要与测试数据集中的文件名一一对应;
- 单通道PNG图片中的像素值必须介于0~3之间,像素值不能为255。如果存在未标注区域,评测系统会自动忽略对应区域的提交结果。
提交示例
提交文件命名为:result.zip,zip文件的组织方式如下所示:
主目录
├── 1.png #每个结果文件命名为:测试数据集图片名称+.png
├── 2.png
├── 3.png
├── ...
备注: 主目录中必须包含与测试数据集相同数目、名称相对应的单通道PNG图片,且每张单通道PNG图片中的像素值必须介于0~3之间,像素值不能为255。
!pip install paddlex
2.环境准备
2.1 PaddleX安装
此次比赛,先后尝试了PaddleSeg以及PaddleX,最终为了速度还是使用了PaddleX。
!pip install paddlex
2.2 import必须和显卡环境配置
# 引入必须要类库
import matplotlib
import os
import paddlex as pdx
# 设置使用0号GPU卡(如无GPU,执行此代码后仍然会使用CPU训练模型)
os.environ['CUDA_VISIBLE_DEVICES'] = '0'
3.数据准备
3.1解压数据集
解压缩数据集,使用一次即可。
- -o是为了覆盖,防止有人数据集变化重复解压提示解压不了
- -qa是为了静默,不需要日志
!unzip -oqa data/data80164/train_and_label.zip
!unzip -oqa data/data80164/img_test.zip
3.2数据增强
数据增强采用paddlex.seg.transforms自带的数据增强工具,其他第三方、手写的图像增强工具懒得看了。
- 实测Flip挺好使,提升成绩好高
- 采用数据增强的办法不是越多越好,需要和实际情况相结合
from paddlex.seg import transforms
# 定义训练和验证时的transforms
train_transforms = transforms.Compose([
# 上下、左右翻转概率默认为0.5
transforms.RandomVerticalFlip(),
transforms.RandomHorizontalFlip(),
transforms.RandomBlur(prob=0.1),
transforms.RandomRotate(rotate_range=10),
transforms.Normalize()
])
eval_transforms = transforms.Compose([
transforms.Normalize()
])
3.3数据集划分
3.3.1 获取总数据列表
import numpy as np
datas = []
image_base = 'img_train'
annos_base = 'lab_train'
ids_ = [v.split('.')[0] for v in os.listdir(image_base)]
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/work/', ''), img_pt1.replace('/home/aistudio/work/', '')))
if os.path.exists(img_pt0) and os.path.exists(img_pt1):
pass
else:
raise "path invalid!"
print('total:', len(datas))
# print(datas[0][0])
# print(datas[0][1])
data_dir = '/home/aistudio/work/'
3.3.2 train、valid数据及划分
import numpy as np
labels = ['建筑', '耕地', '林地', '其他']
with open('labels.txt', 'w') as f:
for v in labels:
f.write(v+'\n')
np.random.seed(5)
np.random.shuffle(datas)
split_num = int(0.05*len(datas))
# 划分训练集和验证集
train_data = datas[:-split_num]
valid_data = datas[-split_num:]
with open('train_list.txt', 'w') as f:
for img, lbl in train_data:
f.write(img + ' ' + lbl + '\n')
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))
3.4PaddleX数据集定义
data_dir = './'
# 定义训练和验证数据集
train_dataset = pdx.datasets.SegDataset(
data_dir=data_dir,
file_list='train_list.txt',
label_list='labels.txt',
transforms=train_transforms,
shuffle=True)
eval_dataset = pdx.datasets.SegDataset(
data_dir=data_dir,
file_list='valid_list.txt',
label_list='labels.txt',
transforms=eval_transforms)
4.模型训练
采用DeepLabv3p模型,骨干采用MobileNetV3_large_x1_0_ssld。
原因无他,速度快,不过据悉Xception65精度更高,但是会特别慢。此外使用了 resume_checkpoint 继续进行训练。
4.1 采用DeepLabv3p模型,骨干采用MobileNetV3_large_x1_0_ssld。
# num_classes分类数
num_classes = len(train_dataset.labels)
# 定义模型
model = pdx.seg.DeepLabv3p(
num_classes=num_classes,
backbone='MobileNetV3_large_x1_0_ssld',
pooling_crop_size=(256, 256))
# 开始训练
model.train(
num_epochs=100,
train_dataset=train_dataset,
# 加大batchsize
train_batch_size=300,
eval_dataset=eval_dataset,
learning_rate=0.01,
save_interval_epochs=1,
pretrain_weights='CITYSCAPES',
save_dir='output/deeplabv3p_mobilenetv3_large_ssld/pretain',
use_vdl=True)
4.2 visual dl查看训练趋势
visual dl 视图。以前的怎么搞上去的找不到了。。。。。。
5.模型评估
# 载入最好的训练模型
model = pdx.load_model('output/deeplabv3p_mobilenetv3_large_ssld/pretain/best_model')
# 模型评估
model.evaluate(eval_dataset, batch_size=160, epoch_id=None, return_details=False)
6.模型预测
from tqdm import tqdm
import cv2
test_base = 'img_testA/'
out_base = 'result/'
# 如果不存在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'])
7.打包提交
# 生成提交文件
!zip -r result.zip result/
8.其他改进
8.1 val和提交分数不一样
本版本训练iou能够达到70左右,但是交分数大概在60分左右
8.2 一定要注意保存模型
训练模型没保存,这不又得重新跑跑,看能不能达到之前的分数,然我哭一会先。偷懒了以后不跑了就没最好模型了。
8.3 显存拉满
多看看下面监控图,计算机算,200的batch size,显存利用率60%,那么333的batch size就接近100%了吧,就用300吧,做人没必要满分了。什么?你说batch size 最好2的指数?我看对计算机来说随意。随意,随意,大家随意就好。
8.4 batch size小点好 千万不要爆
batchsize=999999
8.5 中间模型一定要删掉
切记切记中间模型一定要删掉,不要动不动项目空间100Gb,打开半小时,自己都要被自己蠢哭了,还怪系统慢。。。
8.6 另外一种查看显卡状态方法
终端下运行nvidia-smi命令
8.7 图像尺寸技巧
图像要尽可能缩小尺寸,这样能节约显卡资源
8.8 来一张GPU工作图
9.其他
感谢领航团实例分割课程的各位老师、班班、助教的辛苦付出,也感谢各位同学,要不是你们,我随意跑个成绩就结束了,就不认真了。