【问题标题】:Gradients vanishing despite using Kaiming initialization尽管使用了 Kaiming 初始化,但梯度消失了
【发布时间】:2021-06-25 10:50:37
【问题描述】:

我在 pytorch 中使用激活函数 (prelu) 实现了一个 conv 块。我使用 Kaiming 初始化来初始化我的所有权重并将所有偏差设置为零。然而,当我测试这些块时(通过将 100 个这样的 conv 和激活块堆叠在一起),我注意到输出我得到的值大约为 10^(-10)。这是正常的吗,考虑到我要堆叠多达 100 层。向每一层添加一个小的偏差可以解决这个问题。但在 Kaiming 初始化中,偏差应该为零。

这是转换块代码

from collections import Iterable

def convBlock(
    input_channels, output_channels, kernel_size=3, padding=None, activation="prelu"
):
    """
    Initializes a conv block using Kaiming Initialization
    """
    padding_par = 0
    if padding == "same":
        padding_par = same_padding(kernel_size)
    conv = nn.Conv2d(input_channels, output_channels, kernel_size, padding=padding_par)
    relu_negative_slope = 0.25
    act = None
    if activation == "prelu" or activation == "leaky_relu":
        nn.init.kaiming_normal_(conv.weight, a=relu_negative_slope, mode="fan_in")
        if activation == "prelu":
            act = nn.PReLU(init=relu_negative_slope)
        else:
            act = nn.LeakyReLU(negative_slope=relu_negative_slope)
    if activation == "relu":
        nn.init.kaiming_normal_(conv.weight, nonlinearity="relu")
        act = nn.ReLU()
    nn.init.constant_(conv.bias.data, 0)
    block = nn.Sequential(conv, act)
    return block


def flatten(lis):
    for item in lis:
        if isinstance(item, Iterable) and not isinstance(item, str):
            for x in flatten(item):
                yield x
        else:
            yield item


def Sequential(args):
    flattened_args = list(flatten(args))
    return nn.Sequential(*flattened_args)

这是测试代码

ls=[]
for i in range(100):
    ls.append(convBlock(3,3,3,"same"))
model=Sequential(ls)

test=np.ones((1,3,5,5))
model(torch.Tensor(test))

我得到的输出是

tensor([[[[-1.7771e-10, -3.5088e-10,  5.9369e-09,  4.2668e-09,  9.8803e-10],
          [ 1.8657e-09, -4.0271e-10,  3.1189e-09,  1.5117e-09,  6.6546e-09],
          [ 2.4237e-09, -6.2249e-10, -5.7327e-10,  4.2867e-09,  6.0034e-09],
          [-1.8757e-10,  5.5446e-09,  1.7641e-09,  5.7018e-09,  6.4347e-09],
          [ 1.2352e-09, -3.4732e-10,  4.1553e-10, -1.2996e-09,  3.8971e-09]],

         [[ 2.6607e-09,  1.7756e-09, -1.0923e-09, -1.4272e-09, -1.1840e-09],
          [ 2.0668e-10, -1.8130e-09, -2.3864e-09, -1.7061e-09, -1.7147e-10],
          [-6.7161e-10, -1.3440e-09, -6.3196e-10, -8.7677e-10, -1.4851e-09],
          [ 3.1475e-09, -1.6574e-09, -3.4180e-09, -3.5224e-09, -2.6642e-09],
          [-1.9703e-09, -3.2277e-09, -2.4733e-09, -2.3707e-09, -8.7598e-10]],

         [[ 3.5573e-09,  7.8113e-09,  6.8232e-09,  1.2285e-09, -9.3973e-10],
          [ 6.6368e-09,  8.2877e-09,  9.2108e-10,  9.7531e-10,  7.0011e-10],
          [ 6.6954e-09,  9.1019e-09,  1.5128e-08,  3.3151e-09,  2.1899e-10],
          [ 1.2152e-08,  7.7002e-09,  1.6406e-08,  1.4948e-08, -6.0882e-10],
          [ 6.9930e-09,  7.3222e-09, -7.4308e-10,  5.2505e-09,  3.4365e-09]]]],
       grad_fn=<PreluBackward>)

【问题讨论】:

    标签: pytorch gradient


    【解决方案1】:

    惊人的问题(欢迎来到 StackOverflow)! Research paper for quick reference.

    TLDR

    • 尝试更广泛的网络(64 频道)
    • 在激活后添加批量标准化(甚至在激活之前,应该没有太大区别)
    • 添加残差连接(不应该比批量规范改进太多,最后的手段)

    请按此顺序查看此内容,并发表评论,哪些(以及是否)对您的情况有效(我也很好奇)。

    你做不同的事情

    • 您的神经网络非常深,但非常狭窄81 仅限每层参数!)

    由于上述原因,由于样本太小,无法从正态分布可靠地创建这些权重。

    尝试更广泛的网络、64 频道或更多

    • 您正在尝试比他们更深的网络

    部分:比较实验

    我们对具有 14 个权重的深度但高效的模型进行了比较 层(实际上22 也与Xavier 进行了比较测试)

    这是由于本文的发布日期 (2015) 和“过去”的硬件限制(假设)

    这正常吗?

    对于这种深度的层,方法本身很奇怪,至少目前是这样;

    • 每个 conv 块通常后面跟着激活,例如 ReLU 和批量归一化(对信号进行归一化并有助于爆炸/消失信号)
    • 通常这种深度的网络(即使是你现有深度的一半)也使用残差连接(尽管这与消失/小信号没有直接关系,更多地与深度网络的退化问题有关,例如 @987654329 @层)

    【讨论】:

    • 嘿,感谢您帮助我。我只是在测试它,看看我使用 He 初始化的表现如何。测试模型不代表任何最终作品。我明白你的意思。实际上,我将使用它来处理超分辨率。我看过一些论文,他们说批量标准化不适合超分辨率任务。但是是的,有跳过连接和更多的过滤器,所以应该没问题。再次感谢您的帮助。
    • 是的,我使用了更广泛的网络,它有 10 层或 11 层深,带有跳跃连接。它工作正常。
    猜你喜欢
    • 2021-11-27
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2022-10-24
    • 2016-01-10
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多