yolov3 05节(03)基本完成


中途帮老师搞什么新的课题,耽误了这么久,但好在yolov3之前无法检测的bug已经修复完成了,通过3-4天的非连续debug和思考,我感觉自己对yolov3的检测框架有了更加深刻的认识,包括pytorch数据的格式、darknet网络中数据的传输、检测框的实现等等,历经15多天去复现yolov3感觉还是有所收获,等后续有空可以写一篇简单的文章记录一下。

bug修复

上次跟踪到了darknet模块中,即获得的前向传播结果prediction就是错的

with torch.no_grad():
      prediction = model(batch, CUDA)  # 前向传播获得的结果

继续跟进后,在darknet的forward前向传播方法当中,第一次执行conv卷积块可以获得结果,但是进行第二次的时候,所有结果均会成为nan,包括weight权重当中的值也变成立nan;

这时候问题必然出现在load_weight方法中,因为第二次卷积紧接着第一次的结果,其中没有其他方法变量干涉,除了最开始加载的weights

反复对比结果,最后我发现自己把加载conv权重的代码,写进了加载conv偏执里去了,最终导致结果错误,还是得细心才行。

            if module_type == "convolutional":
                model = self.module_list[i]
                try:
                    batch_normalize = int(self.blocks[i + 1]["batch_normalize"])
                except:
                    batch_normalize = 0
                conv = model[0]
                if batch_normalize: # 存在bn的情况
                    bn = model[1]
                    # bn层权重数量
                    num_bn_biases = bn.bias.numel()
                    # 加载bn权重
                    bn_biases = torch.from_numpy(weights[ptr:ptr+num_bn_biases])
                    ptr+=num_bn_biases
                    bn_weights = torch.from_numpy(weights[ptr: ptr + num_bn_biases])
                    ptr += num_bn_biases
                    bn_running_mean = torch.from_numpy(weights[ptr: ptr + num_bn_biases])
                    ptr += num_bn_biases
                    bn_running_var = torch.from_numpy(weights[ptr: ptr + num_bn_biases])
                    ptr += num_bn_biases
                    # 设置权重到相同的dims
                    bn_biases = bn_biases.view_as(bn.bias.data)
                    bn_weights = bn_weights.view_as(bn.weight.data)
                    bn_running_mean = bn_running_mean.view_as(bn.running_mean)
                    bn_running_var = bn_running_var.view_as(bn.running_var)
                    # copy数据到模型
                    bn.bias.data.copy_(bn_biases)
                    bn.weight.data.copy_(bn_weights)
                    bn.running_mean.copy_(bn_running_mean)
                    bn.running_var.copy_(bn_running_var)
                else:
                    # 卷积层偏执
                    num_biases = conv.bias.numel()
                    conv_biases = torch.from_numpy(weights[ptr:ptr+num_biases])
                    ptr+=num_biases
                    conv_biases = conv_biases.view_as(conv.bias.data) # 对应维度
                    conv.bias.data.copy_(conv_biases)

                # 加载卷积层权重
                num_weights = conv.weight.numel()
                conv_weights = torch.from_numpy(weights[ptr:ptr + num_weights])
                ptr = ptr + num_weights
                conv_weights = conv_weights.view_as(conv.weight.data)
                conv.weight.data.copy_(conv_weights)

排除了这个bug后,剩下的一个大bug是位于write_result方法当中,即将prediction预测结果转为coco的80个类别部分出错了。

此处bug带来的问题是一次只能检测出一个种类,而且检测框绘制的范围也不正确,有偏差。

针对这个问题,考虑到prediction结果系正确的:

1)那么可能是在多个检测结果cat成一个大张量的过程中,后面的张量把前面的覆盖掉了,没有形成正确的cat;

2)或者是提前结束了检测过程,导致数据缺失

这样也能解释检测框位置偏差的问题。最终通过逐步debug,发现了在NMS当中,选择最佳边界框的代码出现了问题,简单且隐蔽,简单来说就是犯了(1)中的错误,但也同样产生了(2)中的后果

检测结果

完成了代码不跑几个图片玩玩怎么合适?所以我从网上随便搞了几个图片进行了测试

性能大概就是这样

很有趣,据说yolov3在 810平台?可以达到30帧/s的速度,使用c++应该会更快一些,所以对视频检测方面也可以适用,就是第一张图片检测耗时之外,后续图片就非常快了,不愧是工业上争相搭建的框架,

我都怀疑学校旁边的超市发入口的体温检测都是这个框架做的了。

当然教程中也有关于视频检测的方面,我还没有复现,后续再补上,而且训练部分都还没写呢。

作为个人第一次实现的深度学习项目,个人觉得yolov3是个非常好的入门教程,寒假有空希望自己能独立看论文复现出yolov4,好耶。