代码之家  ›  专栏  ›  技术社区  ›  Jonathan

利用乙状结肠激活函数进行多类预测

  •  1
  • Jonathan  · 技术社区  · 6 年前

    我运行的U-net定义如下:

    inputs = Input((IMG_HEIGHT, IMG_WIDTH, IMG_CHANNELS))
    s = Lambda(lambda x: x / 255) (inputs)
    
    c1 = Conv2D(8, (3, 3), activation='relu', padding='same') (s)
    c1 = Conv2D(8, (3, 3), activation='relu', padding='same') (c1)
    p1 = MaxPooling2D((2, 2)) (c1)
    
    c2 = Conv2D(16, (3, 3), activation='relu', padding='same') (p1)
    c2 = Conv2D(16, (3, 3), activation='relu', padding='same') (c2)
    p2 = MaxPooling2D((2, 2)) (c2)
    
    c3 = Conv2D(32, (3, 3), activation='relu', padding='same') (p2)
    c3 = Conv2D(32, (3, 3), activation='relu', padding='same') (c3)
    p3 = MaxPooling2D((2, 2)) (c3)
    
    c4 = Conv2D(64, (3, 3), activation='relu', padding='same') (p3)
    c4 = Conv2D(64, (3, 3), activation='relu', padding='same') (c4)
    p4 = MaxPooling2D(pool_size=(2, 2)) (c4)
    
    c5 = Conv2D(128, (3, 3), activation='relu', padding='same') (p4)
    c5 = Conv2D(128, (3, 3), activation='relu', padding='same') (c5)
    
    u6 = Conv2DTranspose(64, (2, 2), strides=(2, 2), padding='same') (c5)
    u6 = concatenate([u6, c4])
    c6 = Conv2D(64, (3, 3), activation='relu', padding='same') (u6)
    c6 = Conv2D(64, (3, 3), activation='relu', padding='same') (c6)
    
    u7 = Conv2DTranspose(32, (2, 2), strides=(2, 2), padding='same') (c6)
    u7 = concatenate([u7, c3])
    c7 = Conv2D(32, (3, 3), activation='relu', padding='same') (u7)
    c7 = Conv2D(32, (3, 3), activation='relu', padding='same') (c7)
    
    u8 = Conv2DTranspose(16, (2, 2), strides=(2, 2), padding='same') (c7)
    u8 = concatenate([u8, c2])
    c8 = Conv2D(16, (3, 3), activation='relu', padding='same') (u8)
    c8 = Conv2D(16, (3, 3), activation='relu', padding='same') (c8)
    
    u9 = Conv2DTranspose(8, (2, 2), strides=(2, 2), padding='same') (c8)
    u9 = concatenate([u9, c1], axis=3)
    c9 = Conv2D(8, (3, 3), activation='relu', padding='same') (u9)
    c9 = Conv2D(8, (3, 3), activation='relu', padding='same') (c9)
    
    outputs = Conv2D(10, (1, 1), activation='sigmoid') (c9)
    
    model = Model(inputs=[inputs], outputs=[outputs])
    
    model.compile(optimizer='Adamax', loss = dice, metrics = [mIoU])
    

    注意,我正在对十个类进行多类预测。输入是 256x256x3 (RGB)图像和地面真相是大小的二元掩模。 256x256x10 自从 depth=num_classes=10 . 我的问题是,我不小心忘记将激活功能从 sigmoid softmax 运行网络。网络仍在运行。这怎么可能?是因为它独立处理每个二进制屏蔽吗?

    更有趣的是,网络在使用时实际上产生了更好的效果 乙状结肠 与我跑步时相反 软最大值 .

    1 回复  |  直到 6 年前
        1
  •  2
  •   pitfall    6 年前

    Q1: Why my network is still trainable with a *wrong* loss function?

    A1:因为你的网络是在梯度下降方面进行优化的,只要它是可微的,它就不关心使用哪种损耗函数。这个事实揭示了当网络不工作时调试网络的困难,因为它不是一个代码错误(例如导致内存泄漏、数字溢出等),但一些错误在科学上是不合理的(例如,回归目标是范围(0100),但您使用 sigmoid 作为最后一个致密层的活化作用)。

    Q2: How come `sigmoid` gives better performance than `softmax`?
    

    A2:首先,使用 乙状结肠 损失函数是指训练10个二进制分类器,每个类一个(即经典的一个V.S.全部或一个V.S.静止设置),因此它在技术上也是合理的。

    唯一的区别是 乙状结肠 softmax 类预测概率的和总是1 软最大值 网络,但不一定是1 乙状结肠 网络。换句话说,在测试 乙状结肠 网络。

    关于原因 乙状结肠 比…好 软最大值 这与很多方面有关,如果不仔细研究很难分析。一个可能的解释是 乙状结肠 独立处理最后一个密集层的权重矩阵中的行,而 软最大值 依赖地对待他们。因此, 乙状结肠 可以更好地处理那些梯度方向矛盾的样本。另一个想法是也许你应该尝试最近的 heated-up softmax .

    最后,如果你相信 乙状结肠 版本可以提供更好的性能,但您仍然需要 软最大值 网络,可以重用所有层,直到 乙状结肠 网络和微调新的 软最大值 分层,或者像在多任务问题中一样使用这两种损失。