Keras 神经网络:为什么可以';我不能再深入一点吗?

Keras 神经网络:为什么可以';我不能再深入一点吗?,keras,deep-learning,conv-neural-network,Keras,Deep Learning,Conv Neural Network,我使用此模型从图像中获取深度贴图: def get_model(learning_rate=0.001, channels=2): h = 128 # height of the image w = 128 # width of the image c = channels # no of channels encoding_size = 512 # encoder image = Input(shape=(c, h, w)) c

我使用此模型从图像中获取深度贴图:

def get_model(learning_rate=0.001, channels=2):
    h = 128  # height of the image
    w = 128  # width of the image
    c = channels  # no of channels

    encoding_size = 512

    # encoder
    image = Input(shape=(c, h, w))
    conv_1_1 = Conv2D(32, (3, 3), activation='relu', padding='same')(image)
    conv_1_2 = Conv2D(32, (3, 3), activation='relu', padding='same')(conv_1_1)
    pool_1_2 = MaxPooling2D((2, 2))(conv_1_2)

    conv_2_1 = Conv2D(64, (3, 3), activation='relu', padding='same')(pool_1_2)
    conv_2_2 = Conv2D(64, (3, 3), activation='relu', padding='same')(conv_2_1)
    pool_2_2 = MaxPooling2D((2, 2))(conv_2_2)

    conv_3_1 = Conv2D(128, (3, 3), activation='relu', padding='same')(pool_2_2)
    conv_3_2 = Conv2D(128, (3, 3), activation='relu', padding='same')(conv_3_1)
    # pool_3_2 = MaxPooling2D((2, 2))(conv_3_2)

    # conv_4_1 = Conv2D(256, (3, 3), activation='relu', padding='same')(pool_3_2)
    # conv_4_2 = Conv2D(256, (3, 3), activation='relu', padding='same')(conv_4_1)
    # pool_4_3 = MaxPooling2D((2, 2))(conv_4_2)

    # conv_5_1 = Conv2D(512, (3, 3), activation='relu', padding='same')(pool_4_3)
    # conv_5_2 = Conv2D(512, (3, 3), activation='relu', padding='same')(conv_5_1)
    flat_5_2 = Flatten()(conv_3_2)
    encoding = Dense(encoding_size, activation='tanh')(flat_5_2)

    # decoder
    reshaped_6_1 = Reshape((8, 8, 8))(encoding)
    conv_6_1 = Conv2D(128, (3, 3), activation='relu', padding='same')(reshaped_6_1)
    conv_6_2 = Conv2D(128, (3, 3), activation='relu', padding='same')(conv_6_1)
    upsample_6_2 = UpSampling2D((2, 2))(conv_6_2)

    conv_7_1 = Conv2D(64, (3, 3), activation='relu', padding='same')(upsample_6_2)
    conv_7_2 = Conv2D(64, (3, 3), activation='relu', padding='same')(conv_7_1)
    upsample_7_2 = UpSampling2D((2, 2))(conv_7_2)

    conv_8_1 = Conv2D(32, (3, 3), activation='relu', padding='same')(upsample_7_2)
    conv_8_2 = Conv2D(32, (3, 3), activation='relu', padding='same')(conv_8_1)
    upsample_8_2 = UpSampling2D((2, 2))(conv_8_2)

    conv_9_1 = Conv2D(16, (3, 3), activation='relu', padding='same')(upsample_8_2)
    conv_9_2 = Conv2D(16, (3, 3), activation='relu', padding='same')(conv_9_1)
    upsample_9_2 = UpSampling2D((2, 2))(conv_9_2)

    conv_10_1 = Conv2D(8, (3, 3), activation='relu', padding='same')(upsample_9_2)
    conv_10_2 = Conv2D(1, (3, 3), activation='relu', padding='same')(conv_10_1)
    output = Conv2D(1, (1, 1), activation=relu_normalized, padding='same')(conv_10_2)

    model = Model(inputs=image, outputs=output)
    model.compile(loss='mae', optimizer=Adam(learning_rate))
    return model
  • 输入:2x128x128(两个bw图像)-压缩为[0,1](预处理规范化)
  • 输出:1x128x128(深度贴图)-通过relu标准化压缩到[0,1]
注:relu_normalized只是relu,然后将值挤压到0-1,以获得正确的图像。乙状结肠似乎不符合这个标准

当我添加更多层时,损失变为常数,backprop没有正常发生,因为输出和梯度都变为零(因此改变学习速率不会改变网络中的任何内容)

因此,如果我想更深入地概括,通过取消对行的注释(当然还要将
conv_5_2
连接到
flat_5_2
),我遗漏了什么?

我的想法:

  • 使用Sigmoid会导致消失梯度问题,但我使用的是relu,这个问题还会存在吗
  • 更改网络中的任何内容,如编码大小,甚至将激活更改为
    elu
    selu
    都不会显示任何进展
当我尝试添加一个conv层,然后添加max\u pooling时,为什么我的输出越来越接近于零?


更新:

这是relu_

def relu_normalized(x):
    epsilon = 1e-6
    relu_x = relu(x)
    relu_scaled_x = relu_x / (K.max(relu_x) + epsilon)
    return relu_scaled_x

在获得范围为[0,1]的输出后,我们只需输出_image=255*输出,现在就可以将其保存为黑白图像。

如果您想更深入,您必须添加一些批处理规范化层(在Keras中)。 伊恩·古德费罗(Ian Goodfello)的书中,关于批次规范化一章:

非常深入的模型涉及多个功能或层的组合。这个 梯度告诉我们如何更新每个参数,前提是另一个参数 图层不会改变。实际上,我们同时更新所有层。 当我们进行更新时,可能会出现意外的结果,因为许多函数 使用计算的更新同时更改组合在一起 在其他函数保持不变的假设下


此外,
tanh
很容易饱和,因此仅在需要时使用:)

当学习率太高时,“relu”可能会出现问题

很有可能所有的激活都变为0,并且被卡在那里永远不会改变。(当它们为0时,其梯度也为0)

由于我不是使用“relu”详细调整参数的专家,而且我使用“relu”的结果总是不好,所以我更喜欢使用“sigmoid”或“tanh”。(这是值得一试的,尽管那里可能会有一些消失…)。我将图像的范围保持在0到1之间,并使用“二进制交叉熵”作为损失,在这种情况下,这比“mae/mse”要快得多


发生在我身上的另一件事是“显然”冻结损失函数。碰巧数值变化很小,显示的小数不足以看到变化,但经过许多时代之后,它找到了一种合理的方法来正确地下降。(可能确实是某种饱和,但对我来说,这仍然比冻结或NaN要好)

你可以引入像LSTM这样的重复层,它可以使用选通“捕捉”错误,潜在地改善情况。

你的模型越深,梯度越消失。这只是因为梯度是相乘的。Relu并不能解决每个架构的这个问题,它只是比其他激活函数更好。你确定你需要更深层的建筑吗?你有没有试着把你的tanh从编码改成其他的东西?那么人们实际上是如何绕过这个消失的梯度问题的呢?如果我想深入一点,我能做些什么吗?有什么吗?我用5幅图像和1000多个时代的输出对它进行了训练,只是想看看网络是否有能力概括这5幅输出(首先)。但结果并不令人满意。因此我得出结论,我需要更多的推广能力,才能使网络表现得更好。另外,我需要层组4和层组5,以便在max_池之前引入连接层输入的跳过连接,从而改进上采样层输出,并再次所有这些来增加网络的泛化能力。我认为,对于由5个图像组成的数据集,您无法得出任何结论。有了5张图片,它只会学到一些垃圾,这可能是你的渐变消失的原因。我确实有一个庞大的数据集来训练它,但在此之前,我认为只使用5张图片来训练和查看(使用model.predict())网络能够适应(或过适应或欠适应)这5张图片是明智的。通过这种方式,我们可以确保我们的损失函数是正确的,并且体系结构能够很好地处理这5个问题,然后我们可以考虑使其适合1000,使其更具能力,同时限制其过度拟合。如果使用“二进制交叉熵”或“分类交叉熵”,饱和不应该是一个问题。现在,“relu”和类似的词总是给我带来麻烦,从冻结丢失到nans。你是否将图像标准化为[0,1](输入时)?(我想你这样做是因为你使用的是ReLU规范化)。可能是因为它复制了行和列,所以你需要反褶积(如果你问它是什么),你可以用conv2dtranpse()@Kubaba来做,是的,我在将它传送到网络之前进行规范化。我还尝试在最大池之前跳过连接,并将其提供给上采样层以改进结果,但效果不太好。似乎在引入层组4和层组5时存在一些不正确的地方,即输出总是为零的时候。我将尝试使用deconv,并更新我的问题。谢谢:)@SaravanabalagiRamachandran:我在看relu_,我在想,你为什么需要它?如果你需要