激活函数:Softmax 与 Sigmoid

Activation functions: Softmax vs Sigmoid

我一直在尝试使用 CNN 构建图像分类器。我的数据集中有 2300 张图像和两类:男性和女性。这是我使用的模型:

early_stopping = EarlyStopping(min_delta = 0.001, patience = 30, restore_best_weights = True)
model = tf.keras.Sequential()

model.add(tf.keras.layers.Conv2D(256, (3, 3), input_shape=X.shape[1:],  activation = 'relu'))

model.add(tf.keras.layers.MaxPooling2D(pool_size=(2, 2)))
model.add(tf.keras.layers.BatchNormalization())
model.add(tf.keras.layers.Conv2D(256, (3, 3), input_shape=X.shape[1:], activation = 'relu'))
model.add(tf.keras.layers.MaxPooling2D(pool_size=(2, 2)))
model.add(tf.keras.layers.BatchNormalization())
model.add(tf.keras.layers.Flatten())  # this converts our 3D feature maps to 1D feature vectors

model.add(tf.keras.layers.Dense(64))

model.add(tf.keras.layers.Dense(1, activation='softmax'))


model.compile(loss='binary_crossentropy',
              optimizer='adam',
              metrics=['accuracy'])

h= model.fit(xtrain, ytrain, validation_data=(xval, yval), batch_size=32, epochs=30, callbacks = [early_stopping], verbose = 0)

此模型的准确度为 0.501897,损失为 7.595693(模型在每个时期都停留在这些数字上)但如果我用 Sigmoid 替换 Softmax 激活,准确度约为 0.98,损失为 0.06。为什么 Softmax 会发生这种奇怪的事情?我能找到的所有信息都是这两个激活相似,softmax 更好,但我找不到任何关于这种异常的信息。如果有人能解释问题出在哪里,我会很高兴。

你的结果总结:

  • a) 具有 Softmax 激活函数的 CNN -> 精度 ~ 0.50,损失 ~ 7.60
  • b) 具有 S 形激活函数的 CNN -> 精度 ~ 0.98,损失 ~ 0.06

TLDR

更新:

现在我也看到你只使用 Softmax 的 1 个输出神经元,你将无法在二进制 class 中捕获第二个 class ]化。 使用 Softmax,您需要在输出层中定义 K 个神经元 - 其中 K 是您要预测的 classes 的数量。而对于 Sigmoid:1 个输出神经元足以进行二进制 classification。

所以简而言之,当对 2 classes 使用 softmax 时,这应该在您的代码中更改:

#use 2 neurons with softmax
model.add(tf.keras.layers.Dense(2, activation='softmax'))

另外:

当做二进制class化时,sigmoid函数更合适因为它只是与更广义的 softmax 函数(当 K>2 classes 时通常用于多 class 预测)相比,计算上更有效


进一步阅读:

所选激活函数的一些属性

如果上面的简短回答对您来说还不够,我可以与您分享一些我在研究 NN 激活函数时学到的一些东西:

首先,让我们弄清楚术语激活和激活函数

activation (alpha): is the state of a neuron. The state of neurons in hidden or output layers will be quantified by the weighted sum of input signals from a previous layer

activation function f(alpha): Is a function that transforms an activation to a neuron signal. Usually a non-linear and differentiable function as for instance the sigmoid function. Many applications & research has been applied with the sigmoid function (see Bengio & Courville, 2016, p.67 ff.). Mostly the same activation function is being used throughout the neural network, but it is possible to use multiple (e.g. different ones in different layers).

现在介绍激活函数的效果:

The choice of activation function can have an immense impact on learning of neural networks (as you have seen in your example). Historically it was common to use the sigmoid function, as it was a good function to depict a saturated neuron. Today, especially in CNNs other activation functions, also only partially linear activation functions (like relu) is being preferred over sigmoid function. There are many different functions, just to name some: sigmoid, tanh, relu, prelu, elu ,maxout, max, argmax, softmax etc.

现在我们只比较 sigmoid,relu/maxout 和 softmax:

# pseudo code / formula
sigmoid = f(alpha) = 1 / (1 + exp(-alpha))
relu = f(alpha) = max(0,alpha)
maxout = f(alpha) = max(alpha1, alpha2)
softmax = f(alpha_j) = alpha_j / sum_K(alpha_k)

乙状结肠:

  • 二进制class化优选用于输出层
  • 值可以在 [0,1] 之间,适用于概率解释 (+)
  • 饱和神经元可以消除梯度(-)
  • 不以零为中心 (-)
  • exp() 计算量大 (-)

relu:

  • 正区域没有饱和神经元 (+)
  • 计算成本更低 (+)
  • 不以零为中心 (-)
  • 负区域中的饱和神经元 (-)

最大输出:

  • relu (+) 的正属性
  • 每个神经元的参数数量加倍,通常需要更多的学习努力 (-)

softmax:

  • 可以将蜜蜂视为 sigmoid 函数的推广
  • 主要用作多class预测问题中的输出激活函数
  • 取值范围在[0,1]之间,适用于概率解释(+)
  • 由于 exp() 项 (-),计算成本更高

一些很好的进一步阅读参考资料:

您看到这些不同结果的原因是输出层的大小 - 它是 1 个神经元。

根据定义,Softmax 需要 1 个以上的输出神经元才有意义。 1个Softmax神经元永远输出1(查公式想一想)。这就是为什么你看到 ~50% 的准确度,因为你的网络总是预测 class 1.

Sigmoid 没有这个问题,可以输出任何东西,这就是它训练的原因。

如果你想测试 softmax,你必须为每个 class 制作一个输出神经元,然后“单热编码”你的 ytrain 和 yval(查看单热编码以获得更多解释)。在您的情况下,这意味着:标签 0 -> [1, 0],标签 1 -> [0, 1]。可以看到,索引的编码是class。我不确定,但在那种情况下我相信你会使用分类交叉熵。我无法从文档中得出结论,但在我看来,二元交叉熵期望 1 个输出神经元为 0 或 1(其中 Sigmoid 是要使用的正确激活),而分类交叉熵期望每个输出神经元class,其中 Softmax 有意义。您甚至可以在多输出情况下使用 Sigmoid,但这并不常见。

所以简而言之,在我看来二元熵期望 class 由 1 个神经元的值编码,而分类熵期望 class 由哪个输出神经元编码最多积极的。 (简单来说)