更新:增加了test.py部分的源码解析,包含mAP的计算。
更新:我的机子是pytorch0.4的,所以在训练时候踩了一些坑,把这些问题和解决方法放在yolov3网络训练踩坑纪实(pytorch)中。
yolov3-spp是yolov3的一个版本,在yolo官网中给出了cfg和weights。
本文调试源码为ultralytics/yolov3,参考博客为yolo系列之yolo v3【深度解析】
结构详解
参考yolo系列之yolo v3【深度解析】。对照这一博客中的网络结构图↓,将cfg文件print出来,分析了一下,如下图所示(注意,博客是yolov3非spp的结构,这里的输入是416x416的)。
其中,各个module的含义如下:
convolutional
:对应博客中的DBL或conv,主要是看有没有batch normalize,以及是否加了leaky rulu
shortcut
:res_unit的跨层连接
route
:重新从之前某层的输出开始forward 或 concat,主要是看'layers'
这个参数是一个参数还是两个
upsample
:上采样
yolo
:一共有三次,输出分别是13、26和52
具体参考源码中models.py
的Darknet
类的forward
train.py源码解析
调试的是Example: Train Single Image,按照步骤一步步来就可以了
数据预处理和加载
在train.py
中,将dataset装在dataloader中,并用tqdm循环。
在utils/datasets.py
中定义了datasets,在__getitem__
中返回经过了augment等预处理的image和labels。其中,label被处理为[0 class x y w h]格式(均经过归一化)。
前向传播
model = Darknet(cfg).to(device)
……
pred = model(imgs)
models.py
中,在__init__
将cfg文件中储存的网络结构,逐行读入self.module_defs
,并调用create_modules
生成对应的module,存入self.module_list
,在forward
中进行前向传播。
forward
输出的output是一个list,共包含3项,均为yolo层的输出,分别为[1,3,13,13,85],[1,3,26,26,85],[1,3,52,52,85]。(By the way,之前的yolo层,是将输入的255x13x13中的255,展开成3x85,85 = 80classes + xywh + confidence,3为每个grid对应的anchor数目)
计算loss
loss部分可以参见YOLOv3 Loss构建详解
loss, loss_items = compute_loss(pred, targets, model)
在utils/utils.py
中的compute_loss
计算loss
计算loss,主要用到了build_targets
和compute_loss
build_targets
输入:
model
targets:[0 class x y w h]格式的label
输出:
tcls, tbox, indices, av(anchor_vec),四个长度为3的list,对应3个尺度的yolo layer输出(具体的参照代码注释)
tcls[0] | tbox[0] | indices[0] | av[0] |
---|---|---|---|
torch.size([n]) | torch.size([n, 4]) | 长度为4的tuple,每个元素都是torch.size([n])的tensor | torch.size([n, 4]) |
class | gxy+gwh,即xywh(grid),且gxy减掉了整数部分 | 索引b, a, gj, gi,对应yolo_layer的输出维度 | anchor_vec |
代码注释:
def build_targets(model, targets):
# targets = [image, class, x, y, w, h]
nt = len(targets) # 一个batch中的target总数
tcls, tbox, indices, av = [], [], [], []
multi_gpu = type(model) in (nn.parallel.DataParallel, nn.parallel.DistributedDataParallel)
for i in model.yolo_layers:
# get number of grid points and anchor vec for this yolo layer
# 获取对应yolo layer的ng(grid数目,13*13或26*26或52*52)以及anchor vec
if multi_gpu:
ng, anchor_vec = model.module.module_list[i].ng, model.module.module_list[i].anchor_vec
else:
ng, anchor_vec = model.module_list[i].ng, model.module_list