激活函数:Softmax vs Sigmoid

Posted

技术标签:

【中文标题】激活函数:Softmax vs Sigmoid【英文标题】:Activation functions: Softmax vs Sigmoid 【发布时间】:2021-03-23 06:56:35 【问题描述】:

我一直在尝试使用 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 甚至更好,但我找不到任何关于这种异常的信息。如果有人能解释问题所在,我会很高兴。

【问题讨论】:

【参考方案1】:

您的结果摘要:

a) 具有 Softmax 激活函数的 CNN -> 准确度 ~ 0.50,损失 ~ 7.60 b) 具有 Sigmoid 激活函数的 CNN -> 准确度 ~ 0.98,损失 ~ 0.06

TLDR

更新:

现在我也看到您仅使用 1 个输出神经元和 Softmax,您将无法在二元分类中捕获第二类使用 Softmax,您需要在输出层定义 K 个神经元 - 其中 K 是您要预测的类数。而使用 Sigmoid:1 个输出神经元足以进行二元分类。

所以简而言之,当您将 softmax 用于 2 个类时,这应该会在您的代码中发生变化:

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

另外:

在进行二元分类时,sigmoid 函数更适合,因为与更广义的 softmax 函数相比,它在计算上更有效(当你有 K>2 个类时,它通常用于多类预测)。


进一步阅读:

选定激活函数的一些属性

如果上面的简短回答对你来说还不够,我可以和你分享一些我从研究中学到的关于神经网络激活函数的简短知识:

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

activation (alpha):是神经元的状态。隐藏层或输出层的神经元状态将通过前一层输入信号的加权和来量化

激活函数 f(alpha):是将激活转换为神经元信号的函数。通常是非线性和可微函数,例如 sigmoid 函数。 sigmoid 函数已应用于许多应用和研究(参见 Bengio & Courville, 2016, p.67 ff.)。在整个神经网络中大多使用相同的激活函数,但也可以使用多个(例如,不同层中的不同激活函数)。

现在来看看激活函数的效果:

激活函数的选择会对神经网络的学习产生巨大影响(正如您在示例中看到的那样)。从历史上看,使用 sigmoid 函数很常见,因为它是描绘饱和神经元的好函数。今天,特别是在 CNN 的其他激活函数中,也只有部分线性激活函数(如 relu)优于 sigmoid 函数。有许多不同的函数,仅举几例:sigmoid、tanh、relu、prelu、elu、maxout、max、argmax、softmax 等。

现在我们只比较 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)

乙状结肠:

在二元分类中最好用于输出层 值的范围可以在 [0,1] 之间,适用于概率解释 (+) 饱和神经元可以消除梯度(-) 不以零为中心 (-) exp() 计算量大 (-)

relu:

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

最大输出:

relu 的积极属性 (+) 每个神经元的参数数量翻倍,通常需要增加学习努力 (-)

softmax:

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

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

http://cs231n.stanford.edu/2020/syllabus http://deeplearningbook.org(本吉奥和考特维尔) https://arxiv.org/pdf/1811.03378.pdf https://papers.nips.cc/paper/2018/file/6ecbdd6ec859d284dc13885a37ce8d81-Paper.pdf

【讨论】:

非常感谢。我现在明白我的模型出了什么问题。 @bearthum 很高兴它能帮助您理解问题。我看到你在堆栈溢出方面很新:如果一个答案解决了你的问题,请接受它,以便社区中的其他人可以看到是什么帮助你解决了问题【参考方案2】:

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

根据定义,Softmax 需要超过 1 个输出神经元才有意义。 1 Softmax 神经元总是会输出 1 (查找公式并考虑一下)。这就是为什么您会看到大约 50% 的准确率,因为您的网络总是预测第 1 类。

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

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

因此,简而言之,在我看来,二元熵期望由 1 个神经元的值编码的类,而分类熵期望由哪个输出神经元最活跃编码的类。 (简而言之)

【讨论】:

好观察!不得不承认,我没有看输出层的神经元数量:D 我同意你的解释

以上是关于激活函数:Softmax vs Sigmoid的主要内容,如果未能解决你的问题,请参考以下文章

激活函数

python 深度学习中的4种激活函数

激活函数 - 杂记

深度学习调参体验

深度学习调参体验

激活函数 Sigmoidtanh*LUsoftPlusmaxOutsoftmaxdice- 杂记