输入img要修改为float()格式float32,否则跟weight不匹配报错
输入label要修改为long()格式int64,否则跟交叉熵公式不匹配报错
img = img.float()
label = label.long()
这两句要放在每个batch开始位置
为了避免遗忘,可以把这部分操作集成到自定义的to_tensor()函数中,在每次开始转tensor的时候自动转换:
if isinstance(data, torch.Tensor):
return data
elif isinstance(data, np.ndarray):
return torch.from_numpy(data)
elif isinstance(data, Sequence) and not mmcv.is_str(data):
return torch.tensor(data)
elif isinstance(data, int):
return torch.LongTensor([data])
elif isinstance(data, float):
return torch.FloatTensor([data])
如果要把在GPU中运算的数据可视化,必须先变换到cpu,然后解除grad,最后转numpy才能使用。
即:x1 = x.cpu().detach().numpy()
transform和transform_inv中涉及的数据类型变换很多种类,很容易漏掉没有做而导致输出形式不对。
对于transform_inv的变换,需要重点关注
通常会定义一个边框尺寸,比如scale = (300, 300),这是图片的最大尺寸范围。
图片首先经过transform,按比例缩放到边框尺寸,此时因为比例固定,所以每张图片尺寸都不同,但都有一条片跟边框尺寸拉平相等。
比如一个batch的图片可能尺寸会变成(300, 256),(300, 284),(240,300)这样的形式。
图片然后经过dataloader的collate_fn,对一个batch的图片取最大外沿,进行padding变成相同尺寸的图片。
由于transform时所有图片已有一条边靠近边框尺寸,所以取所有图片最大外沿结果基本都是边框尺寸,比如一个batch的图片会变成
(300,300),(300,300),(300,300)然后堆叠成(3,300,300), 所以最终进行训练的图片基本都是以边框尺寸进行训练。
经常会产生路径找不到的情况,比较合理的解决方案是:
如果有报错说部分路径无法导入,一般有2种可能性:
常见训练所采用的mean,std并不是跟训练数据集相关,而是跟基模型所训练的数据集相关,这是
因为这些训练都是在基模型的基础上进行finetunning做迁移学习来训练的。
由于pytorch的基模型基本都是在imagenet中训练的,所以这些mean, std都是imagenet的参数。
而caffe的基模型虽然也是在imagenet中训练的,但因为处理方式不同所以std取成了1(待在caffe中确认原因)
比如:
如果在一个数据集上从头训练,则需要事先计算他的mean, std。但要注意mean,std的数值顺序到底是BGR顺序还是RGB顺序。
pytorch自己的transform往往是先归一化再标准化,即:
img = (img/255 - mean) / std
所以事先准备的mean和std都是很小的值,在-1,1之间
后边看到一些其他例子,比如mmdetection里边对其他数据集的提供的mean, std值较大。
说明对数据的处理是只做了标准化,即:
img = (img - mean)/std
所以实现准备的mean和std都是比较大的数值,在0-255之间
总结一下就是:
pytorch中conv, maxpool在计算输出w,h尺寸时,默认的取整方式都是下取整(floor)。
唯一不同的是,maxpool可以手动设置成上取整即ceil mode,但conv不能手动设置,也就只能下取整。
conv, maxpool两者计算输出尺寸的公式一样
如果要在GPU训练,只需要3步
并行式GPU训练并不一定比单GPU快,相反对于一些比较小的模型,单GPU的速度远超过并行式训练的速度。
可能因为并行式训练需要让数据在GPU之间搬运造成时间损耗,同时python的并行式训练并不是真正的并行,
而是在同一时间下只有一块GPU运行的假并行,只是能利用多GPU内存而不能利用多GPU算力的假并行。
分布式训练才是真正的多GPU算力并行训练。
对常规的数据集,如果图片尺寸都是一样的,那么直接使用pytorch默认DataLoader就可以。
对数据集中img的尺寸不一样的,由于dataloader需要对img进行堆叠,此时图片尺寸不同无法直接堆叠,
则需要自定义collate_fn对img进行堆叠,同时处理那些labels/bboxes/segments是堆叠还是放入list.
pytorch默认的collate_fn设置不是None而是default_collate_fn,所以即使不用collate_fn
选项,也不要去把collate_fn设置为None,这会导致collate_fn找不到可用的函数导致错误。
(从这个角度说,pytorch的官方英文文档有问题,注明DataLoader的collate_fn默认=None,
但实际上collate_fn的默认=default_collate_fn。)
numpy和pytorch都有可能产生in_contiguous的问题。主要都是在transpose(),permute()之后会发生。
参考:https://discuss.pytorch.org/t/negative-strides-of-numpy-array-with-torch-dataloader/28769
在numpy数据下的报错形式是:ValueError: some of the strides of a given numpy array are negative.
This is currently not supported, but will be added in future releases.
在tensor数据下的报错形式是:
可通过t1.is_contiguous()查看到是否连续。
解决方案;
常规分类问题是对一张图片作为最小个体进行分类;而物体检测问题中的分类是以一张图片中的每一个bbox进行分类。
因此对于物体检测问题本质上一张图片是多个分类问题的集合。
因此常规分类问题是一张img对应一个独立label, 1个batch的数据为多张img对应多个独立label,1个batch计算一次loss,
所以需要把一个batch的label组合成一组,相当于1个batch就是一组img对应一组label。
因此分类的一个batch计算本质上相当于检测问题的一张图片计算。
但是检测分类问题是一张img有一组bbox对应一组label,1个batch的数据为多张img拥有多组bbox对应多组label,每组bbox,label完成一次loss计算。
因此检测的一个batch计算本质上相当于每张图片是一次分类batch,多张图片就要手动进行多次img循环计算,循环的主体就是常规分类问题的一个batch。
这样理解的话,就可以统一常规分类问题和检测中的分类问题了:
- 常规分类问题需要把labels组合成一组,变成一个标准计算。
- 检测分类问题需要循环计算每张img,而每张img计算相当于一次常规分类问题的batch计算。
结论:
证明:参考https://www.leiphone.com/news/201808/DB6WARlVGdm4cqgk.html
可以看到单层(也就相当于浅层)卷积核收敛以后的输出图片,类似于sobel算子,是对图片进行某个方向的边缘过滤。
也就是说明了浅层神经网络主要是学习边缘、纹理等初级信息
全连接层所占参数一般占了一个模型总参数个数的80%以上,所以为了减小模型所占内存,需要优化全连接
替换方式1:resnet/resnext的最后一部分就是这样实现。
用一个adaptiveAvgpooling(1), 先把卷积的每个通道收缩为1,即(c,h,w)->(c,1,1),再reshape后接一个简单全连接linear(c, 10)即可
变换前reshape后需要至少2个全连接(chw->256),再(256->10),参数总量256chw + 25610;
avgpool变换后reshape后只需要1个全连接(256->10),参数总量为25610, 减少了256chw个参数。