深度学习入门:基于 Python 的理论与实现 (19):神经网络 3.5.2

阅读数:48 2019 年 11 月 13 日 15:08

深度学习入门:基于Python的理论与实现(19):神经网络 3.5.2

内容简介
本书是深度学习真正意义上的入门书,深入浅出地剖析了深度学习的原理和相关技术。书中使用 Python3,尽量不依赖外部库或工具,从基本的数学知识出发,带领读者从零创建一个经典的深度学习网络,使读者在此过程中逐步理解深度学习。书中不仅介绍了深度学习和神经网络的概念、特征等基础知识,对误差反向传播法、卷积神经网络等也有深入讲解,此外还介绍了深度学习相关的实用技巧,自动驾驶、图像生成、强化学习等方面的应用,以及为什么加深层可以提高识别精度等疑难的问题。
本书适合深度学习初学者阅读,也可作为高校教材使用。

(实现 softmax 函数时的注意事项)

上面的 softmax 函数的实现虽然正确描述了式(3.10),但在计算机的运算上有一定的缺陷。这个缺陷就是溢出问题。softmax 函数的实现中要进行指数函数的运算,但是此时指数函数的值很容易变得非常大。比如,${\rm e}^{10}$ 的值会超过 20000,${\rm e}^{100}$ 会变成一个后面有 40 多个 0 的超大值,${\rm e}^{1000}$ 的结果会返回一个表示无穷大的 inf。如果在这些超大值之间进行除法运算,结果会出现“不确定”的情况。

计算机处理“数”时,数值必须在 4 字节或 8 字节的有限数据宽度内。这意味着数存在有效位数,也就是说,可以表示的数值范围是有限的。因此,会出现超大值无法表示的问题。这个问题称为溢出,在进行计算机的运算时必须(常常)注意。

softmax 函数的实现可以像式(3.11)这样进行改进。

$\begin{aligned}y_k=\frac{\exp(a_k)}{\sum^n_{i=1}\exp(a_i)}&=\frac{{\rm C}\exp(a_k)}{{\rm C}\sum^n_{i=1}\exp(a_i)}\&=\frac{\exp(a_k+\log{\rm C})}{\sum^n_{i=1}\exp(a_i+\log{\rm C})}\&=\frac{\exp(a_k+{\rm C}’)}{\sum^n_{i=1}\exp(a_i+{\rm C}’)}\end{aligned}\quad\quad\quad\quad\quad(3.11)$

首先,式(3.11)在分子和分母上都乘上 C 这个任意的常数(因为同时对分母和分子乘以相同的常数,所以计算结果不变)。然后,把这个 C 移动到指数函数(exp)中,记为 log C。最后,把 log C 替换为另一个符号 C_’_。

式(3.11)说明,在进行 softmax 的指数函数的运算时,加上(或者减去)某个常数并不会改变运算的结果。这里的 C_’_ 可以使用任何值,但是为了防止溢出,一般会使用输入信号中的最大值。我们来看一个具体的例子。

>>> a = np.array([1010, 1000, 990])
>>> np.exp(a) / np.sum(np.exp(a)) #  softmax 函数的运算
array([ nan,  nan,  nan])         #  没有被正确计算
>>>
>>> c = np.max(a) #  1010
>>> a - c
array([  0, -10, -20])
>>>
>>> np.exp(a - c) / np.sum(np.exp(a - c))
array([  9.99954600e-01,   4.53978686e-05,   2.06106005e-09])

如该例所示,通过减去输入信号中的最大值(上例中的 c),我们发现原本为 nan(not a number,不确定)的地方,现在被正确计算了。综上,我们可以像下面这样实现 softmax 函数。

def softmax(a):
    c = np.max(a)
    exp_a = np.exp(a - c) #  溢出对策
    sum_exp_a = np.sum(exp_a)
    y = exp_a / sum_exp_a

    return y

评论

发布