软件杯-目标检测功能
转自AI Studio,原文链接:【官方】第十一届 “中国软件杯”百度遥感赛项:目标检测功能 - 飞桨AI Studio第十一届 “中国软件杯”百度遥感赛项:目标检测功能1 比赛介绍“中国软件杯”大学生软件设计大赛是一项面向中国在校学生的公益性赛事,是2021年全国普通高校大学生竞赛榜单内竞赛。大赛由国家工业和信息化部、教育部、江苏省人民政府共同主办,致力于正确引导我国在校学生积极参加软件科研活动
转自AI Studio,原文链接:【官方】第十一届 “中国软件杯”百度遥感赛项:目标检测功能 - 飞桨AI Studio
第十一届 “中国软件杯”百度遥感赛项:目标检测功能
1 比赛介绍
“中国软件杯”大学生软件设计大赛是一项面向中国在校学生的公益性赛事,是2021年全国普通高校大学生竞赛榜单内竞赛。大赛由国家工业和信息化部、教育部、江苏省人民政府共同主办,致力于正确引导我国在校学生积极参加软件科研活动,切实增强自我创新能力和实际动手能力,为我国软件和信息技术服务业培养出更多高端、优秀的人才。2022年,百度飞桨承办了A组和B组两个赛道,本赛题为A组。
2 数据集介绍
本项目使用RSOD遥感影像目标检测数据集。RSOD数据集由武汉大学于2017年发布,包含4种类型的遥感地物目标(本项目仅使用其中的playground类)。影像提取自Google Earth、天地图等平台。
[1] Y. Long, Y. Gong, Z. Xiao and Q. Liu, "Accurate Object Localization in Remote Sensing Images Based on Convolutional Neural Networks," in IEEE Transactions on Geoscience and Remote Sensing, vol. 55, no. 5, pp. 2486-2498, May 2017. doi: 10.1109/TGRS.2016.2645610
[2] Z Xiao, Q Liu, G Tang, X Zhai, "Elliptic Fourier transformation-based histograms of oriented gradients for rotationally invariant object detection in remote-sensing images", International Journal of Remote Sensing, vol. 36, no. 2, 2015
3 数据预处理
In [ ]
# 解压数据集
!unzip -oq -d /home/aistudio/data/data52980/rsod/ /home/aistudio/data/data52980/RSOD-Dataset.zip
!unzip -oq -d /home/aistudio/data/data52980/rsod/ /home/aistudio/data/data52980/rsod/RSOD-Dataset/playground.zip
In [ ]
# 划分训练集/验证集/测试集,并生成文件名列表
# 所有样本从RSOD数据集的playground子集中选取
import random
import os.path as osp
from os import listdir
# 随机数生成器种子
RNG_SEED = 52980
# 调节此参数控制训练集数据的占比
TRAIN_RATIO = 0.9
# 调节此参数控制验证集数据的占比
VAL_RATIO = 0.05
# 数据集路径
DATA_DIR = '/home/aistudio/data/data52980/rsod/'
# 目标类别
CLASS = 'playground'
def write_rel_paths(phase, names, out_dir):
"""将文件相对路径存储在txt格式文件中"""
with open(osp.join(out_dir, phase+'.txt'), 'w') as f:
for name in names:
f.write(
' '.join([
osp.join(CLASS, 'JPEGImages', name),
osp.join(CLASS, 'Annotation', 'xml', name.replace('.jpg', '.xml'))
])
)
f.write('\n')
random.seed(RNG_SEED)
names = listdir(osp.join(DATA_DIR, CLASS, 'JPEGImages'))
# 对文件名进行排序,以确保多次运行结果一致
names.sort()
random.shuffle(names)
len_train = int(len(names)*TRAIN_RATIO)
len_val = int(len(names)*VAL_RATIO)
write_rel_paths('train', names[:len_train], DATA_DIR)
write_rel_paths('val', names[len_train:len_train+len_val], DATA_DIR)
write_rel_paths('test', names[len_train+len_val:], DATA_DIR)
# 写入类别信息
with open(osp.join(DATA_DIR, 'labels.txt'), 'w') as f:
f.write(CLASS+'\n')
print("数据集划分已完成。")
4 模型训练与测试
4.1 依赖安装
In [ ]
# 安装matplotlib
!pip install matplotlib==3.4 > /dev/null
# 安装PaddleRS(AI Studio上缓存的版本)
!unzip -o -d /home/aistudio/ /home/aistudio/data/data135375/PaddleRS-develop.zip > /dev/null
!mv /home/aistudio/PaddleRS-develop /home/aistudio/PaddleRS
!pip install -e /home/aistudio/PaddleRS > /dev/null
# 因为`sys.path`可能没有及时更新,这里选择手动更新
import sys
sys.path.append('/home/aistudio/PaddleRS')
4.2 模型训练
In [ ]
# 导入需要用到的库
import random
import os.path as osp
import cv2
import numpy as np
import paddle
import paddlers as pdrs
from paddlers import transforms as T
from paddlers.tasks.utils.visualize import visualize_detection
from matplotlib import pyplot as plt
from PIL import Image
In [ ]
# 定义全局变量
# 随机种子
SEED = 52980
# 数据集存放目录
DATA_DIR = '/home/aistudio/data/data52980/rsod/'
# 训练集`file_list`文件路径
TRAIN_FILE_LIST_PATH = '/home/aistudio/data/data52980/rsod/train.txt'
# 验证集`file_list`文件路径
VAL_FILE_LIST_PATH = '/home/aistudio/data/data52980/rsod/val.txt'
# 测试集`file_list`文件路径
TEST_FILE_LIST_PATH = '/home/aistudio/data/data52980/rsod/test.txt'
# 数据集类别信息文件路径
LABEL_LIST_PATH = '/home/aistudio/data/data52980/rsod/labels.txt'
# 实验目录,保存输出的模型权重和结果
EXP_DIR = '/home/aistudio/exp/'
# 目标类别
CLASS = 'playground'
# 模型验证阶段输入影像尺寸
INPUT_SIZE = 608
In [ ]
# 固定随机种子,尽可能使实验结果可复现
random.seed(SEED)
np.random.seed(SEED)
paddle.seed(SEED)
In [ ]
# 构建数据集
train_transforms = T.Compose([
# 对输入影像施加随机色彩扰动
T.RandomDistort(),
# 在影像边界进行随机padding
T.RandomExpand(),
# 随机裁剪,裁块大小在一定范围内变动
T.RandomCrop(),
# 随机水平翻转
T.RandomHorizontalFlip(),
# 对batch进行随机缩放,随机选择插值方式
T.BatchRandomResize(
target_sizes=[320, 352, 384, 416, 448, 480, 512, 544, 576, 608],
interp='RANDOM'
),
# 影像归一化
T.Normalize(
mean=[0.485, 0.456, 0.406], std=[0.229, 0.224, 0.225]
)
])
eval_transforms = T.Compose([
# 使用双三次插值将输入影像缩放到固定大小
T.Resize(
target_size=INPUT_SIZE, interp='CUBIC'
),
# 验证阶段与训练阶段的归一化方式必须相同
T.Normalize(
mean=[0.485, 0.456, 0.406], std=[0.229, 0.224, 0.225]
)
])
# 分别构建训练和验证所用的数据集
train_dataset = pdrs.datasets.VOCDetection(
data_dir=DATA_DIR,
file_list=TRAIN_FILE_LIST_PATH,
label_list=LABEL_LIST_PATH,
transforms=train_transforms,
shuffle=True
)
val_dataset = pdrs.datasets.VOCDetection(
data_dir=DATA_DIR,
file_list=VAL_FILE_LIST_PATH,
label_list=LABEL_LIST_PATH,
transforms=eval_transforms,
shuffle=False
)
In [ ]
# 构建PP-YOLO模型
model = pdrs.tasks.PPYOLO(num_classes=len(train_dataset.labels))
model.net_initialize(
pretrain_weights='COCO',
save_dir=osp.join(EXP_DIR, 'pretrain'),
resume_checkpoint=None,
is_backbone_weights=False
)
In [ ]
# 执行模型训练
model.train(
num_epochs=100,
train_dataset=train_dataset,
train_batch_size=8,
eval_dataset=val_dataset,
# 每多少个epoch存储一次检查点
save_interval_epochs=10,
# 每多少次迭代记录一次日志
log_interval_steps=10,
save_dir=EXP_DIR,
# 指定预训练权重
pretrain_weights='COCO',
# 初始学习率大小
learning_rate=0.0001,
# 学习率预热(learning rate warm-up)步数与初始值
warmup_steps=0,
warmup_start_lr=0.0,
# 是否启用VisualDL日志功能
use_vdl=True
)
4.3 模型测试
In [ ]
# 构建测试集
test_dataset = pdrs.datasets.VOCDetection(
data_dir=DATA_DIR,
file_list=TEST_FILE_LIST_PATH,
label_list=LABEL_LIST_PATH,
transforms=eval_transforms,
shuffle=False
)
# 为模型加载历史最佳权重
state_dict = paddle.load(osp.join(EXP_DIR, 'best_model/model.pdparams'))
model.net.set_state_dict(state_dict)
# 执行测试
test_result = model.evaluate(test_dataset)
print(
"测试集上指标:bbox mAP为{:.2f}".format(
test_result['bbox_map'],
)
)
4.4 预测结果可视化
In [25]
# 预测结果可视化
# 重复运行本单元可以查看不同结果
def read_rgb(path):
im = cv2.imread(path)
im = im[...,::-1]
return im
def show_images_in_row(ims, fig, title='', lut=None):
n = len(ims)
fig.suptitle(title)
axs = fig.subplots(nrows=1, ncols=n)
for idx, (im, ax) in enumerate(zip(ims, axs)):
# 去掉刻度线和边框
ax.spines['top'].set_visible(False)
ax.spines['right'].set_visible(False)
ax.spines['bottom'].set_visible(False)
ax.spines['left'].set_visible(False)
ax.get_xaxis().set_ticks([])
ax.get_yaxis().set_ticks([])
ax.imshow(im)
# 需要展示的样本个数
num_imgs_to_show = 4
# 随机抽取样本
chosen_indices = random.choices(range(len(test_dataset)), k=num_imgs_to_show)
# 参考 https://stackoverflow.com/a/68209152
fig = plt.figure(constrained_layout=True)
fig.suptitle("Test Results")
subfigs = fig.subfigures(nrows=2, ncols=1)
# 读取输入影像并显示
ims = [read_rgb(test_dataset.file_list[idx]['image']) for idx in chosen_indices]
show_images_in_row(ims, subfigs[0], title='Image')
# 绘制目标框
with paddle.no_grad():
vis_res = []
for idx, im in zip(chosen_indices, ims):
sample = test_dataset[idx]
gt = [
{
'category_id': cid[0],
'category': CLASS,
'bbox': [bbox[0], bbox[1], bbox[2]-bbox[0], bbox[3]-bbox[1]],
'score': 1.0
}
for cid, bbox in zip(sample['gt_class'], sample['gt_bbox'])
]
im = cv2.resize(im[...,::-1], (INPUT_SIZE, INPUT_SIZE), interpolation=cv2.INTER_CUBIC)
pred = model.predict(im, eval_transforms)
vis = im
# 用绿色画出预测目标框
if len(pred) > 0:
vis = visualize_detection(
np.array(vis), pred,
color=np.asarray([[0,255,0]], dtype=np.uint8),
threshold=0.2, save_dir=None
)
# 用蓝色画出真实目标框
if len(gt) > 0:
vis = visualize_detection(
np.array(vis), gt,
color=np.asarray([[0,0,255]], dtype=np.uint8),
save_dir=None
)
vis_res.append(vis)
show_images_in_row(vis_res, subfigs[1], title='Detection')
# 渲染结果
fig.canvas.draw()
Image.frombytes('RGB', fig.canvas.get_width_height(), fig.canvas.tostring_rgb())
<PIL.Image.Image image mode=RGB size=640x480 at 0x7F401CA38B10>
更多推荐
所有评论(0)