YOLO系列的目标检测算法发展迅速,yolov5在v4的基础上增加了一些训练的小tricks使得精度进一步提升,此次实验训练mindspore框架下的yolov5并进行简单的改进
目标检测主要解决两个问题:
1.判定图像上有哪些目标物体,解决目标物体存在性的问题;
2.判定图像中目标物体的具体位置,解决目标物体在哪里的问题。
mindspore-gpu=1.5.0
liunx操作系统
获取官方的yolov5代码 链接: https://gitee.com/mindspore/models/tree/master/official/cv/yolov5
各个领域经典算法官方都给出了复现的代码,直接通过华为modelzoo获取
数据集准备 ,数据集的格式如下:
包含:训练图像数据,验证图像,以及两个json文件,至于如何制作这样的数据集,网上教程及代码很多可以参考
在制作好数据集后,需要在default_config .yaml文件中修改数据集路径,预训练模型,yolov5的模式,类别数
修改好配置文件后执行下面命令
#run training example(1p) by python command
python train.py \
--data_dir=xxx/dataset \
--yolov5_version='yolov5s' \
--is_distributed=0 \
--lr=0.01 \
--T_max=320
--max_epoch=320 \
--warmup_epochs=4 \
--per_batch_size=32 \
--lr_scheduler=cosine_annealing > log.txt 2>&1 &
看了几篇中文核心,大抵上都是加了注意力模块,修改了损失函数等(甚至有几篇加的注意力和修改的损失都一样,离谱),那就仿照着做吧
做了以下优化:
1.yolov5的主干网络加入了SE注意力(只是用来测试,所以选择了最简单的注意力,已发表的核心主要加的是CA,ECA注意力等)
2.将giou损失修改为GIOU损失,提高边界框定位精度
SEnet的torch代码实现如下:
import torch
import torch.nn as nn
import math
class se_block(nn.Module):
def __init__(self, channel, ratio=16):
super(se_block, self).__init__()
self.avg_pool = nn.AdaptiveAvgPool2d(1)
self.fc = nn.Sequential(
nn.Linear(channel, channel // ratio, bias=False),
nn.ReLU(inplace=True),
nn.Linear(channel // ratio, channel, bias=False),
nn.Sigmoid()
)
def forward(self, x):
b, c, _, _ = x.size()
y = self.avg_pool(x).view(b, c)
y = self.fc(y).view(b, c, 1, 1)
return x * y
现在需要做的就是将torch的算子用mindspore的算子去替换
SE的代码片段短,可以挨个将算子替换
但我一开始想加入ECA注意力,算子需要修改的比较多,并且由于对ms算子不太熟悉,总是报出一些错误,如数据类型等,比如对于一个算子,我到底是用ms.Tensor里面的还是ops里面的,得查阅API
于是,我发现了一个好东西第三方框架脚本转换! MindConverter
ms支持第三方框架如pytorch、tensflow的模型脚本转换
通过MindConverter我就不用在挨个研究算子的区别了
使用:
mindconverter --in_file src/CAattention.py --output convert --report convert/report
三个参数分别为:要转换的脚本,输出路径,生成的日志路径
通过以上的命令,就将torch的SE转为了ms的SE,但是MindConverter并不能将代码全部转换,需要在根据report文件的提示来手动微调,并且有时候转换的也不太对,亲测
生成的report文件:
转换后的代码:
import mindspore.nn as nn
import mindspore.ops.operations as P
import mindspore.ops as ops
class eca_block(nn.Cell):
def __init__(self, channel, ratio=16):
super(eca_block, self).__init__()
self.avg_pool = ops.AdaptiveAvgPool2D(1)
self.fc = nn.SequentialCell([
nn.Dense(in_channels=channel, out_channels=channel // ratio, has_bias=False),
nn.ReLU(),
nn.Dense(in_channels=channel // ratio, out_channels=channel, has_bias=False),
nn.Sigmoid()
])
def construct(self, x):
b, c, _, _ = P.Shape()(x)
y = self.avg_pool(x).view(b, c)
y = self.fc(y).view(b, c, 1, 1)
return x * y
然后将边界框损失修改为CIOU loss
def ciou(boxes1,boxes2):
'''
cal CIOU of two boxes or batch boxes
:param boxes1:[xmin,ymin,xmax,ymax] or
[[xmin,ymin,xmax,ymax],[xmin,ymin,xmax,ymax],...]
:param boxes2:[xmin,ymin,xmax,ymax]
:return:
'''
#cal the box's area of boxes1 and boxess
boxes1Area = (boxes1[...,2]-boxes1[...,0])*(boxes1[...,3]-boxes1[...,1])
boxes2Area = (boxes2[..., 2] - boxes2[..., 0]) * (boxes2[..., 3] - boxes2[..., 1])
# cal Intersection
left_up = np.maximum(boxes1[...,:2],boxes2[...,:2])
right_down = np.minimum(boxes1[...,2:],boxes2[...,2:])
inter_section = np.maximum(right_down-left_up,0.0)
inter_area = inter_section[...,0] * inter_section[...,1]
union_area = boxes1Area+boxes2Area-inter_area
ious = np.maximum(1.0*inter_area/union_area,np.finfo(np.float32).eps)
# cal outer boxes
outer_left_up = np.minimum(boxes1[..., :2], boxes2[..., :2])
outer_right_down = np.maximum(boxes1[..., 2:], boxes2[..., 2:])
outer = np.maximum(outer_right_down - outer_left_up, 0.0)
outer_diagonal_line = np.square(outer[...,0]) + np.square(outer[...,1])
# cal center distance
boxes1_center = (boxes1[..., :2] + boxes1[...,2:]) * 0.5
boxes2_center = (boxes2[..., :2] + boxes2[...,2:]) * 0.5
center_dis = np.square(boxes1_center[...,0]-boxes2_center[...,0]) +\
np.square(boxes1_center[...,1]-boxes2_center[...,1])
# cal penalty term
# cal width,height
boxes1_size = np.maximum(boxes1[...,2:]-boxes1[...,:2],0.0)
boxes2_size = np.maximum(boxes2[..., 2:] - boxes2[..., :2], 0.0)
v = (4.0/np.square(np.pi)) * np.square((
np.arctan((boxes1_size[...,0]/boxes1_size[...,1])) -
np.arctan((boxes2_size[..., 0] / boxes2_size[..., 1])) ))
alpha = v / (1-ious+v)
#cal ciou
cious = ious - (center_dis / outer_diagonal_line + alpha*v)
return cious
1.yolov5的主干网络加入了SE注意力(只是用来测试,所以选择了最简单的注意力,已发表的核心主要加的是CA,ECA注意力等)
2.将giou损失修改为GIOU损失,提高边界框定位精度
3.MindConverter的使用