batch_norm_grad输出的Output为0,导致后续出错
Created by: wangxicoding
现象
跑用户的一个模型,单机单卡、单机单卡关闭L2Decay、多机nccl2接口分布式、多机fleet接口分布式下,均出现batch_norm_grad获取的conv1_bn_offset@GRAD的shape为0,见下图log。
该错误在上述不同单机多机下的表现形式又不一样:
-
nccl2的log中,conv1_bn_offset@GRAD应该初始化了的,不过size仍然为0。且在之后的L2Decay正则化过程中,shape被_generated_var_0给重新扭回去了
-
分布式开fuse策略,一开始conv1_bn_offset@GRAD的shape正常。原因在fuse的时候直接用的给grad赋param Shape。
原因分析
- batch norm中代码问题
https://github.com/PaddlePaddle/Paddle/blob/65c8eac9fe4cfeff0b4da172125163f082bad9b2/paddle/fluid/operators/batch_norm_op.cc#L447-L451
https://github.com/PaddlePaddle/Paddle/blob/65c8eac9fe4cfeff0b4da172125163f082bad9b2/paddle/fluid/operators/batch_norm_op.cc#L466-L469
上面代码段中,当没有
framework::GradVarName("Scale")
时则不会给Bias的梯度赋Shape,恰好符合log中的情况。 - 用户代码问题
后查阅用户代码,其中有一段逻辑写的或许不太符合常理。其中scale设置为冻结参数,bias却是可学习的。
后询问用户,这个写的是有问题的,一般要么两者都可学习,要么两者都冻结。
在paddle实际计算grad norm梯度的过程也是这么处理的。
不过有个有个问题,是否用户有一个冻结一个不冻结的需求?
https://github.com/PaddlePaddle/Paddle/blob/65c8eac9fe4cfeff0b4da172125163f082bad9b2/paddle/fluid/operators/batch_norm_op.cc#L568
总结
上面的错误有很多环节都出了问题
- batch_norm_grad的Infer Shape出了问题,需要修复。另:
是否有Scale和Bias一个可训练,一个不可训练的需求
- allreduce对于shape的判断不严谨,需要有>0的判断
- WeightDecay中对于shape没有加判断,导致错误的shape也能使用,且给Infer回去了。
- fuse策略下直接给grad赋param的Shape值,这个没有问题,不过却绕过了此issue中的错误。
- nccl2接口和fleet接口,size为0的tensor,一个初始化了,一个未初始化,和fleet加的策略有关系,需查明。