输出层的设计
神经网络可以处理多种问题,需要根据情况改变输出层的激活函数。一般而言,分类问题用softmax函数。
机器学习问题大致可以分为分类问题和回归问题,分类问题是数据属于哪一个类别的问题(识别),而回归问题是根据某个输入预测一个数值的问题(预测)。
恒等函数和softmax函数
恒等函数会将输入按原样输出,因此在输出层使用恒等函数,输入信号会原封不动地被输出。
分类问题使用softmax函数如下:
softmax(z)i=eak∑j=1neai
\text{softmax}(z)_i = \frac{e^{a_k}}{\sum_{j=1}^{n} e^{a_i}}
softmax(z)i=∑j=1neaieak
softmax的分子是输出信号aka_kak的指数函数,分母是输入信号aia_iai的指数函数之和。
def softmax(x):
exp_x = np.exp(x)
return exp_x / exp_x.sum()
以上是softmax函数的具体代码,需注意softmax具有溢出问题:
softmax函数的实现中要进行指数函数的运算,但是此时指数函数的值很容易变得非常大。如果在这些超大值之间进行除法运算,结果会出现“不确定”的情况。
因此要进行改进,公式如下:
yk=exp(ak)∑i=1nexp(ai)=Cexp(ak)C∑i=1nexp(ai)=exp(ak+logC)∑i=1nexp(ai+logC)=exp(ak+C′)∑i=1nexp(ai+C′) y_k = \frac{\exp(a_k)}{\sum_{i=1}^{n} \exp(a_i)} = \frac{C \exp(a_k)}{C \sum_{i=1}^{n} \exp(a_i)} = \frac{\exp(a_k + \log C)}{\sum_{i=1}^{n} \exp(a_i + \log C)}= \frac{\exp(a_k + C')}{\sum_{i=1}^{n} \exp(a_i + C')} yk=∑i=1nexp(ai)exp(ak)=C∑i=1nexp(ai)Cexp(ak)=∑i=1nexp(ai+logC)exp(ak+logC)=∑i=1nexp(ai+C′)exp(ak+C′)
这个公式通过取对数的方式来防止溢出,在分子和分母上都乘上一个任意常数,而且因为是相同的常数,所以计算结果不变。这个logC\log ClogC替换C′C'C′,为了防止溢出,一般取输入信号中的最大值。
import numpy as np
def softmax(x):
exp_x = np.exp(x)
return exp_x / exp_x.sum()
def logsoftmax(x):
x_max = np.max(x)
exp_x = np.exp(x - x_max)
sum_exp_x = np.sum(exp_x)
return exp_x / sum_exp_x
a = np.array([1010, 1000, 990])
print(softmax(a))
print(logsoftmax(a))
这个代码示例可以说明,这样的处理后,原本为nan的结果现在被正确计算了。
softmax函数的特征
softmax函数的输出是0.0~1.0之间的实数,并且输出总和是1,这是softmax函数的一个重要性质。这个性质使得可以把softmax函数的输出解释为“概率”。
即便使用softmax函数,也不会影响各个元素之间和y的各元素大小关系并没有改变。因为指数函数是单调递增函数,所以元素大小关系并没有改变。
神经网络只把输出值最大的神经元所对应的类别作为识别结果,并且即使使用softmax函数,输出值最大的神经元的位置也不会变。因此,神经网络在分类时,输出层的softmax函数可以省略。
求解机器学习问题的步骤可以分为“学习”和“推理”两个阶段
输出层的神经元数量
需要根据待解决的问题来决定。