@w460461339
2020-03-01T13:27:01.000000Z
字数 4893
阅读 1701
MachineLearning
模型参考:https://github.com/eriklindernoren/PyTorch-YOLOv3
钢筋数据集下载:链接:https://pan.baidu.com/s/11qJu30XHunamQjo9zRTQNA 密码:p09l
首先,这里的yolov3模型是通过coco进行训练的,它的数据和label的格式都是按照yolov3来的。
那么,为了尽可能的复用他们的结果,我们需要将我们自己的数据也变成对应的coco的格式。
比如,coco的格式为 [cls,cx,cy,dw,dh],其中cx,cy,dw,dh都是经过归一化的。(除以长or宽)
其次,不要忘记生成自己的配置文件:如类别文件等等。
最后,也需要注意划分训练(训练模型),验证(计算mAP),和测试(肉眼看效果)。
一般争取复用已有模型的dataset和dataloader。
另外需要搞清楚dataset在数据预处理阶段都做了什么,这个在之后的evaluate阶段很有用。
data-augmentation应该可以放在两个地方:
1、直接生成对应的数据和label文件。(更直观)
2、在训练时,通过预处理的方式加载。(省硬盘)
4)如何验证数据准备完毕:
将已有模型的detect.py中对应路径替换成自己的,应该能够跑起来,并产生输出。
对于darknet版本的yolov3,它的模型定义在coco.cfg中。
对于大多数任务而言,不需要修改backbone,只需要修改最终预测的类别数量即可。
那么对于yolov3而言,我们知道他会在3个scale上进行输出,找到这三个scale即可。
下面是其中一个scale。这里我们需要注意到,convolutional才是最后一个有训练参数的输出层,而下面的yolo层中是没有训练参数的,它定义的是如何计算loss的方法。而这两层都会与classes数量有关。
yolo层中,很明显,classes数量,按照自己的需求来。
convolutional层中,filters=3*(classes数量+bbox坐标+前背景flag)=3*(1+4+1)=18
[convolutional]
size=1
stride=1
pad=1
filters=18
activation=linear
[yolo]
mask = 3,4,5
anchors = 10,13, 16,30, 33,23, 30,61, 62,45, 59,119, 116,90, 156,198, 373,326
classes=1
num=9
jitter=.3
ignore_thresh = .7
truth_thresh = 1
random=1
当然,如果是其他定义模型的方法,也做相同的操作。
方法:
1、使用tensorboardX
2、使用pytorchviz
3)验证方法。
1、加载模型,若能成功加载,基本顺利
2、加载后将构造输入送入模型跑一下,如果输出的维度符合预期,说明基本顺利。
3、通过模型可视化进行观察。
0)考虑k-means重新生成anchors?
1)finetune与否,以及怎么finetune。
考虑好什么时候用与训练模型,什么时候不用,怎么用。
比如对于darknet53的yolov3而言,一般是复用74层以前的backbone,然后重新训练后面的分类器。
那么在优化的时候,前74层是freeze还是用小的lr?小的lr要多小呢?
# 加载模型,并用自定义函数weights_init_normal进行初始化
model = Darknet(opt.model_def).to(device)
model.apply(weights_init_normal)
# 加载预训练模型
if opt.pretrained_weights:
print('pre train')
if opt.pretrained_weights.endswith(".pth"):
model.load_state_dict(torch.load(opt.pretrained_weights))
else:
model.load_darknet_weights(opt.pretrained_weights)
# 将backbone和classifier层分开
pretrained_parameters = []
classifier_parameters = []
for name,layer in model.named_parameters():
print(name,layer.shape)
layer_num = name.split('.')[1]
if int(layer_num)<74:
pretrained_parameters.append(layer)
else:
classifier_parameters.append(layer)
# 对不同的层采用不同的学习率
optimizer = torch.optim.Adam([
{'params':pretrained_parameters,'lr':1e-4},
{'params':classifier_parameters,'lr':1e-3}
])
finetune的效果如何验证??
2)什么时候验证模型?什么时候保存模型?
一般是一个batch结束的时候,就跑一遍验证集,计算在验证集的loss,mAP之类的,然后保存该模型。
3)训练时可以通过visdom,tensorboadx等对训练时的情况进行查看。
1)评估参数验证,诸如mAP之类;以及一些后处理,如NMS之类的。
2)可视化。涉及输出转化等
网上的代码基本都是按照coco数据集来做的。
这里看一下coco数据集的格式。
目录结构:
1、有一个文件里面包含所有图片的名字。
2、图片名字进行一定的修改就拿到对应label文件的名字。即,图片和label是以文件的形式进行一一对应的。
重要的是label文件的形式:
1、首先,一个对象一行。
2、每一行以 label_id center_x center_y box_w box_h的方式标记,中间以空格区分
3、所有的center_x center_y box_w box_h都经过归一化处理,放锁到0~1之间。
4、具体放缩方式为,x相关的值,除以整张图片的w;y相关的值,除以整张图片的h。
另外,图片的绝对路径也要放在一个文件中。
总结一下,利用别人再coco上训练好的yolov3来finetune,要准备以下几个文件。
1)图片。
2)pics.txt,里面每一行如下:
/home/user/dir/1.jpg
/home/user/dir/2.jpg
....
3)classes.txt,里面放着类别:
cat
dog
airplane
trunk
...
代码里类别从0开始计算id
4)label文件夹,里面有存放有和图片同名的txt文件,比如1.txt,内容为:
0 0.475 0.475 0.90 0.90
3 0.44 0.332 0.896 0.96
表示这里面有一个cat,位置为(c_x/img_w,c_y/img_h,w/img_w,h/img_h);还有一个trunk,位置在...
模型定义放在config/yolov3.cfg里面,截取片段如下:
[net]
# Testing
#batch=1
#subdivisions=1
# Training
batch=16
subdivisions=1
width=416
height=416
channels=3
momentum=0.9
decay=0.0005
angle=0
saturation = 1.5
exposure = 1.5
hue=.1
learning_rate=0.001
burn_in=1000
max_batches = 500200
policy=steps
steps=400000,450000
scales=.1,.1
[convolutional]
batch_normalize=1
filters=32
size=3
stride=1
pad=1
activation=leaky
# Downsample
[convolutional]
batch_normalize=1
filters=64
size=3
stride=2
pad=1
activation=leaky
....
[upsample]
stride=2
[net]下面是模型超参数的定义(很奇怪居然没有classes的)
之后是按照顺序对模型进行定义;DarkNet里面有趣的一点是,他并没有使用maxpool来进行降采样,而是采用了stride=2的卷积,来进行降采样。
要注意,maxpoo实现几何倍数的降采样,通常也是通过stride来实现的。而maxpool和conv进行比较,同样是stride,前者无疑降低了网络的表现能力(少了需要学习参数),而conv进行stride,不仅降采样了,还增加了网络的表现力。
另外看一下这里的upsample,会发现这个upsample是不可训练的哦.
比如我们想要训练一个6类的检测器,怎么改;
回想yolov3的结构,最终会有3个不同尺度的输出;截取其中一个尺度的输出片段如下
[convolutional]
size=1
stride=1
pad=1
filters=18
activation=linear
[yolo]
mask = 3,4,5
anchors = 10,13, 16,30, 33,23, 30,61, 62,45, 59,119, 116,90, 156,198, 373,326
classes=1
num=9
jitter=.3
ignore_thresh = .7
truth_thresh = 1
random=1
[convolutional]这一层已经是模型的最后一层,[yolo]这一层其实是定义了如何解析[convlutional]这一层数据的方式,所以对于我们的6类检测器,需要修改:
1、[yolo]中的classes,变成6
2、[convlutional]中的filter变成3*(6+5)=33;3表示3个anchors,6表示6个类别,5=4+1,4表示坐标,1表示前背景。
首先注意,torch里面有几种对象:
1、nn.Module 模块层,相对高级别的层;比如Conv2D层,就不需要你在手动去实现卷积。
2、nn.Parameters(一种特殊的tensor,默认可以进行梯度计算)
named_parameters和parameters都是打印nn.Parameters类别的东西;如果自定义的module中,没有使用到类似的nn.Parameters,那么就不会出现在named_parameters()中。
https://blog.csdn.net/dz4543/article/details/90049377
finetune中关于怎么修改模型的,已经放在前面了哈。
关于加载预训练模型,我们一般只加载backbone,然后让分类层重新训练会比较好。
对于yolov3的Dark53而言,74层之后就都是分类用的了,是需要重新训练的。
可以选在下一个darknet53.conv.74,也可以自己从yolov3.weights里面拿。
另外,你会发现如果自己的classes设置的小于80(前提是cfg文档改对了),你也可以正常加载它的weights,但是这个weights是不能用的;因为在程序中,它加载weights的方式是以偏移量的形式进行加载的。所以只要的网络总大小小于它的网络参数,你随便写一个参数也是能够把它的参数加载进来的。