SSD目标检测:conv4_3特征的L2Norm处理

 

正则化方式的选择:

       原生态SSD中,特征金字塔不同特征层上的特征值,有不同的尺度范围(different ranges of value),SSD采取的做法为:使用L2-Normal正则化conv4_3;FSSD使用方案更简单有效:将concate后的特征,后接一个BN层,从row2、6对比可知,新增BN层可以带来0.5%的性能提升。

(1)L2 Normalization公式及作用:

对于一行向量,其L2归一化公式入下所示,其中D为向量长度:

在深度神经网络中,偶尔会出现多个量纲不同的向量拼接在一起的情况,此时就可以使用L2归一化统一拼接后的向量的量纲,使得网络能够快速收敛。

(2)mmdetection中的vgg-ssd.py中处理方式:

class L2Norm(nn.Module):

    def __init__(self, n_dims, scale=20., eps=1e-10):
        super(L2Norm, self).__init__()
        self.n_dims = n_dims
        self.weight = nn.Parameter(torch.Tensor(self.n_dims))
        self.eps = eps
        self.scale = scale

    def forward(self, x):
        # normalization layer convert to FP32 in FP16 training
        x_float = x.float()
        norm = x_float.pow(2).sum(1, keepdim=True).sqrt() + self.eps
        return (self.weight[None, :, None, None].float().expand_as(x_float) *
                x_float / norm).type_as(x)

       转换为onnx->ncnn时,ncnn执行这一层的处理会出错,因为在ncnn中虽然支持Operation_POW处理,但是在此处保存的blobs数据只有一个,Operation_POW输入需要传入两个blobs。

若要满足ncnn的处理,需要将自定义的norm处理改为pytorch的算子,这样转换成ncnn就不会报错了:

class L2Norm(nn.Module):

    def __init__(self, n_dims, scale=20., eps=1e-10):
        super(L2Norm, self).__init__()
        self.n_dims = n_dims
        self.weight = nn.Parameter(torch.Tensor(self.n_dims))
        self.eps = eps
        self.scale = scale
        init.constant(self.weight, self.scale)

    def forward(self, x):
        norm = x.norm(p=2, dim=1, keepdim=True) + self.eps
        x = torch.div(x,norm)
        out = self.weight.unsqueeze(0).unsqueeze(2).unsqueeze(3).expand_as(x) * x
        return out

延伸阅读参考:https://blog.csdn.net/flyfish1986/article/details/105586716

你可能感兴趣的:(pytorch编程,深度学习)