0. 前言
前面模拟了在单层神经网络中二分类的过程,现在想清楚在单层神经网络中多分类是怎么样的。
1. softmax函数的神经网络
softmax函数是神经网络进行多分类时,默认放在输出层中处理数据的函数。
假设现在神经网络处理一个三分类的问题,样本的标签有3类(1,2,3),那么会有如下结构:
y k = e z k ∑ i = 1 K e z i y_{k}=\frac{e^{z_k}}{\sum_{i=1}^{K} e^{z_{i}}} yk=∑i=1Keziezk
在二分类的时候,只需输出正类别的概率;而在多分类的问题中,需要输出每一个类别的概率,即y1,y2,y3。
也就是多分类时,神经元的数目与标签类别的数目(若为3)是一致的,对应输出3个不同的概率。最终,样本的预测标签是输出的所有概率中(y1,y2,y3)最大的概率对应的类别。
softmax函数
g ( z ) k = e z k ∑ i = 1 K e z i g(z)_{k}=\frac{e^{z_k}}{\sum_{i=1}^{K} e^{z_{i}}} g(z)k=∑i=1Keziezk
其中,z是回归算法的结果;K表示总的标签类别数,几分类K就为几(上面三分类,K = 3);k表示标签类别(具体的某一类)。
所以,分子是某一个类别回归结果的对数,分母是所有类别回归结果的对数的总和,即softmax函数的结果表示了样本的结果为某个类别的概率。
但是,此函数是指数级增长的,所以在计算是会出现数据很大的情况,即会“溢出”。
import numpy as np
z = np.array([900, 1000, 1200])
softmax_z = np.exp(z) / np.sum(np.exp(z))
print("exp(z) =", np.exp(z))
print("softmax_z =", softmax_z)
输出结果:
exp(z) = [inf inf inf] # 无穷大的数据
softmax_z = [nan nan nan]
RuntimeWarning: invalid value encountered in true_divide # 不合法的值
softmax_z = np.exp(z) / np.sum(np.exp(z))
为了解决上面出现的问题,就需要对softmax函数式进行修改:
先分子分母同乘常数C,再通过如下变换:
y k = e z k ∑ i = 1 K e z i y_{k}=\frac{e^{z_k}}{\sum_{i=1}^{K} e^{z_{i}}} yk=∑i=1Keziezk
= C e z k C ∑ i = 1 K e z i =\frac{Ce^{z_k}}{C\sum_{i=1}^{K} e^{z_{i}}} =C∑i=1KeziCezk
= e l o g C e z k ∑ i = 1 K e l o g C e z i =\frac{e^{logC}e^{z_k}}{\sum_{i=1}^{K} e^{logC}e^{z_{i}}} =∑i=1KelogCezielogCezk
= e ( z k + l o g C ) ∑ i = 1 K e ( z i + l o g C ) =\frac{e^{(z_k+logC)}}{\sum_{i=1}^{K} e^{(z_{i}+logC)}} =∑i=1Ke(zi+logC)e(zk+logC)
= e ( z k + C ′ ) ∑ i = 1 K e ( z i + C ′ ) =\frac{e^{(z_k+C')}}{\sum_{i=1}^{K} e^{(z_{i}+C')}} =∑i=1Ke(zi+C′)e(zk+C′)
此时,只要让 C ′ C' C′为负,且其值接近 z k z_k zk中的最大值,以此控制不“溢出”。
此时,再用之前的数据进行测试,就不会报错了,即不会出现溢出的问题。
import numpy as np
z = np.array([900, 1000, 1200])
def softmax(z):
max_value = np.max(z)
exp_z = np.exp(z-max_value)
exp_z_sum = np.sum(exp_z)
res = exp_z / exp_z_sum
return res
result = softmax(z)
print(result)
输出结果:
[5.14820022e-131 1.38389653e-087 1.00000000e+000]
此时的输出不再溢出,且返回的是对应每个类别的概率,最大的是1.00000000e+000,所以预测结果是第三个类别