人工智能—深度学习神经网络神经元的实现
人工智能–深度学习两层全连接神经网络搭建
我们在上一章节中已经实现了神经网络系统的结构,但作为一个成熟的预测或者分类神经网络,他还需要一定的完善。今天我们将详细介绍的就是其中的输出层中的一些优化。
我们前面提到过,神经网络是一种为了辅助深度学习的工具方法,而深度学习又是完善机器学习的一个分支,所以说本质上深度学习神经网络的覆盖问题往往都是机器学习的问题,而机器学习的问题根据结果的不同,就能分为回归问题和分类问题。那神经网络中又是如何体现这个回归或者分类的目的的呢?那肯定是要看我们的输出层的结果形式。
在上一章中,我们运行了自己的第一个神经网络系统,得出了一个结果,但在没有具体背景的情况下,那个结果其实没有什么意义,而我们要想使这个结果有意义,记得凭借我们的输出层激活函数了。
当我们的背景问题是一个回归问题的时候,我们往往选择恒等激活函数,也就是不对输出做任何改变,因为回归问题往往最后计算的结果是一个具体的权重,也是我们的最终答案,那我们当然是原封不动的输出是最好的。
当我们的背景问题是一个分类问题的时候,输出结果往往是一个概率,不同结点的值代表了是这个分类的概率大小,但由于复杂的网络关系,最后的值往往不能约束在 [ 0 , 1 ] [0,1] [0,1]范围内,为了让他更加贴切概率的概念,我们会选择使用前面提到的sigmoid函数或者今天我们要着重介绍的softmax函数
恒等函数主要用于对回归问题的激活,这种问题中往往需要我们最大程度的保护最后的输出结果,所以恒等函数简单点来说那就是什么都不做。他的定义为:
y = x y=x y=x
sigmoid函数由于其限制在 [ 0 , 1 ] [0,1] [0,1]中的特性,所以很适合用来做概率转换函数。他的定义我们已经很熟悉:
1 1 + e − x \frac{1}{1+e^{-x}} 1+e−x1
相比较sigmoid函数他比较适合于二分类问题,softmax函数能充分考虑每一个输出结点的权重影响,从而使概率的描述更加准确。他的定义式为:
e a k ∑ i = 1 n e a i \frac{e^{a_{k}}}{\sum_{i=1}^ne^{a_{i}}} ∑i=1neaieak
因为softmax中不乏指数运算,而指数运算最大的问题就是容易产生特别大的数,而当两个数特别大时,再进行其他操作就很容易出错,比如公式里的除法。让我们来看个例子具体感受一下。
def softmax(x):
return np.exp(x)/np.sum(np.exp(x))
x = np.array([1000,1010,1020])
y = softmax(x)
print(y)
输出结果为:
[nan nan nan]
Process finished with exit code 0
这种现象就是叫做计算机中的“溢出”,而我们如何避免过大的值导致的运算过程“溢出”呢?
于是我们引入了一个常量,将softmax函数改进为:
C e a k C ∑ i = 1 n e a i \frac{Ce^{a_{k}}}{C\sum_{i=1}^{n}e^{a_{i}}} C∑i=1neaiCeak
因为分式上下乘以一个常量,所以分式的值不会改变然后我们再进行变形:
C e a k C ∑ i = 1 n e a i = e a k + log c ∑ i = 1 n e a i + log c = e a k + C ′ ∑ i = 1 n e a k + C ′ \frac{Ce^{a_{k}}}{C\sum_{i=1}^{n}e^{a_{i}}}=\frac{e^{a_{k}+\log{c}}}{\sum_{i=1}^{n}e^{a_i+\log{c}}}=\frac{e^{a_k+C^{'}}}{\sum_{i=1}^ne^{a_k+C^{'}}} C∑i=1neaiCeak=∑i=1neai+logceak+logc=∑i=1neak+C′eak+C′
转换成这个形式,那就可以对 C ′ C' C′进行任意取值,因为C是任意的,所以 C ′ C' C′也相应的是,但我们引入这个 C ′ C' C′的最终目的是为了防止溢出,所以建议这个 C ′ C' C′取最大值的负数。也就是
e a k − max ( a ) ∑ i = 1 n e a i − max ( a ) \frac{e^{a_{k}-\max(a)}}{\sum_{i=1}^ne^{a_{i}-\max(a)}} ∑i=1neai−max(a)eak−max(a)
还是代入到那个例子中进行实验:
def softmax(x):
return np.exp(x-np.max(x))/np.sum(np.exp(x-np.max(x)))
x = np.array([1000,1010,1020])
y = softmax(x)
print(y)
输出结果为:
[2.06106005e-09 4.53978686e-05 9.99954600e-01]
Process finished with exit code 0
很明显我们可以看到,原来为nan的异常值已经可以被正确的计算了!
还是以我们之前实现的神经网络系统为例,我们将最后的输出层激活函数置换为我们刚刚实现的softmax函数来再看看是否能准确运行!
代码如下(示例):
def softmax(x):
return np.exp(x-np.max(x))/np.sum(np.exp(x-np.max(x)))
def forward_net(network,x):
W1 = network['W1']
b1 = network['b1']
W2 = network['W2']
b2 = network['b2']
W3 = network['W3']
b3 = network['b3']
x = np.dot(x,W1)+b1
x = ReLU(x)
x = np.dot(x,W2)+b2
x = ReLU(x)
x = np.dot(x, W3) + b3
x = softmax(x)
return x
运行结果为:
[0.00196166 0.99803834]
Process finished with exit code 0
看来我们的激活函数已经能完美运行啦。
为了能更好的带领大家投入到真实的神经网络运行实例中去,笔者准备了这一章,让大家能更好的认识一种最常用的输出层激活函数——softmax。接下来我们就可以自如的使用哦我们的网络进入到各种各样的场景中去了