深度学习入门
1.感知机
感知机算法是由美国学者 Frank Rosenblatt 在1957年提出来的。感知机算法本身非常简单,但是它是神经网络(深度学习)的起源的算法。下面,就简单介绍下这个算法。
1.1 感知机算法简介
感知机接收多个输入信号,输出一个信号。感知机的信号只有(1/0)两种取值。
下图是一个接收两个输入信号的感知机的例子。x1 和 x2是输入信号, y是输出信号,ω1、ω2 是权重。图中的 ⭕️表示神经元(或者节点)。神经元会计算传送过来的信号的总和,只有当这个总和超过了某个界限值时,才会输出1。这也称为“神经元被激活”。这里将这个界限值称为阈值,用符号 θ 表示。
那么感知机的公式就可以很容易表示出来了 :
(公式 1.1)
1.2 简单逻辑电路
简单逻辑电路实际上是感知机的一个简单的应用场景,这里定义3个概念:与门(AND gate)、 与非门(NAND gate)、或门(OR gate)、异或门(XOR gate)。
这和逻辑条件的判断相似,对于参数确定的感知机模型,x1 和 x2取相应的值时,对应的y值如下图:
针对每一个电路实例,很容易得到结论: 前3种可以有多种不同类型的感知机,不同的模型,参数不一致。
下面,是用python实现3种感知机模型(确定ω1、ω2,让它们满足与门、与非门和或门的条件):
1 def AndGate(x1,x2): 2 theata = 0.6 3 w1 = 0.5 4 w2 = 0.5 5 sum = w1*x1 + w2*x2 6 if sum <= theata: 7 return 0 8 else: return 1 9 10 def NotAndGate(x1,x2): 11 theata = -0.6 12 w1 = -0.5 13 w2 = -0.5 14 sum = w1*x1 + w2*x2 15 if sum <= theata: 16 return 0 17 else: return 1 18 19 def OrGate(x1,x2): 20 theata = 0.3 21 w1 = 0.5 22 w2 = 0.5 23 sum = w1*x1 + w2*x2 24 if sum <= theata: 25 return 0 26 else: return 1
View Code
下面,想象着对感知机的公式做一个变体,让θ = -b,那么公式就变成了:
(公式1.2)
当然,这时候问题变成了,如果确定了 b、ω1、ω2,也可以确定感知机模型,下面同样道理,我们快速写出该模型的python代码(只要让 b= -θ 即可):
1 import numpy as np 2 3 def AndGateSecond(x1,x2): 4 X = np.array([x1,x2]) 5 w1,w2 = 0.5,0.5 6 b=-0.6 7 # print (np.array([w1,w2])*X) 8 sum = b + np.sum(np.array([w1,w2])*X) 9 if sum<=0 : 10 return 0 11 else: 12 return 1 13 14 def NotAndGateSecond(x1,x2): 15 X = np.array([x1,x2]) 16 w1,w2 = -0.5,-0.5 17 b=0.6 18 # print (np.array([w1,w2])*X) 19 sum = b + np.sum(np.array([w1,w2])*X) 20 if sum<=0 : 21 return 0 22 else: 23 return 1 24 25 def OrGateSecond(x1,x2): 26 X = np.array([x1,x2]) 27 w1,w2 = 0.5, 0.5 28 b = -0.3 29 # print (np.array([w1,w2])*X) 30 sum = b + np.sum(np.array([w1,w2])*X) 31 if sum<=0 : 32 return 0 33 else: 34 return 1
View Code
1.3 感知机的局限性
异或门,不能用感知机表示,下面用图形的方式来解释原因。
y = ω1*x1 + ω2*x1 + b 可以理解为一条直线,二维空间。如果 ω1 = 1 , ω2 = 1 , b = -0.5 ,是满足或门的参数。下图是该参数的直线,将三角和圆形符号区分开了。
三角形符号: (1,0) , (0,1) , (1,1) 圆形符号:(0,0)
那么,异或门,实际上找到一条曲线,将下图中的三角和圆形符号区分开。
很明显,用直线无法将上图中三角和圆形符号区分开。 只能用曲线了:
感知机的局限性就在于它只能表示由一条直线分割的空间。而无法解决上边异或门的曲线问题。
1.4 多层感知机
上一节中,提到了感知机的局限性,无法实现异或门。也就是说,在线性空间中,感知机无法实现异或门。
但是,我们可以通过前边3个感知机的组合来实现异或门,看下边的真值表:
容易发现,我们使用与非门、或门和与门组合完成了异或门的实现。这样,python实现代码也容易完成:
1 def NotOrGate(x1,x2): 2 s1=NotAndGateSecond(x1,x2) 3 s2=OrGateSecond(x1,x2) 4 y=AndGateSecond(s1,s2) 5 return y 6 7 NotOrGate(0,0),NotOrGate(1,0),NotOrGate(0,1),NotOrGate(1,1)
View Code
叠加了多层的感知机也称为多层感知机(multi-layered perceptron)。
图形化表示异或门,如下:
2.神经网络
在上一章介绍的感知机中得到了2个结论。
好的结论是:即便对于复杂的函数,感知机也隐含着能够表示它的可能性(通过叠加多层感知机),例如上一章提到的“异或门”。
坏的结论是:设定权重的工作,即确定合适的、能符合预期的输 入与输出的权重,现在还是由人工进行的。也就是确定b、ω1、ω2的过程。
神经网络的一个重要性质是它可以自动地从数据中学习到合适的权重参数。也就是能够解决“那个坏的结论”。
2.1 从感知机到神经网路
下面,先举例说明以下神经网络,下图是一个典型的神经网络。 如下图所示,把最左边的一列称为输入层,最右边的一列称为输出层,中间的一列称为中间层。中间层有时也称为隐藏层。
上一章的公式1.2 可以做拆解为以下2个公式 :
公式(2.1)
公式(2.2)
h(x)函数会将输入信号的总和转换为输出信号,这种函数一般称为激活函数(activation function)。
对于确定的 x1 和 x2 代入到公式中,得到: a = b + ω1x1 + ω2x2 , y = h(a)
2.2 激活函数
我们看公式2.2 发现感知机的激活函数是 “阶跃函数”。如果将阶跃函数换成其他函数,就可以进入神经网络的世界了。
2.2.1 sigmod函数:
下面,首先介绍一个神经网络中最早使用的激活函数——sigmoid函数。该函数是神经网络最初使用的激活函数。
公式(2.3)
神经网络中用sigmoid函数作为激活函数,进行信号的转换,转换后的信号被传送给下一个神经元。
2.2.2 ReLU函数:
ReLU 函数在输入大于0时,直接输出该值;在输入小于等于0时,输出0。函数公式定义:
公式(2.4)
2.2.3 图形化描述激活函数:
至此,已经介绍了3种不同的激活函数,分别是:
- 感知机激活函数,公式 2.1 和 2.2 <绿色>
- sigmod激活函数, 公式2.3 <红色>
- ReLU激活函数, 公式2.4 <蓝色>
下面,用图形化的方式来看看这三个函数的分布差别:
代码 :
1 import numpy as np 2 import matplotlib.pyplot as plt 3 4 def stepFunction(x): 5 return np.array(x>0, np.int) 6 7 def sigmodFunction(x): 8 return 1/(np.exp(-x) + 1) 9 10 def reluFunction(x): 11 return np.array(np.maximum(0,x)) 12 13 x = np.arange(-5.0, 5.0, 0.1) 14 stepY = stepFunction(x) 15 sigmodY = sigmodFunction(x) 16 reluY = reluFunction(x) 17 plt.plot(x,stepY,\'g-\') 18 plt.plot(x,sigmodY,\'r--\') 19 plt.plot(x,reluY,\'b-.\') 20 plt.ylim(0,1.1) 21 plt.show()
图形化展示激活函数
2.3 Numpy实现多维数组计算
本小节整体介绍下,Numpy对于多维数组计算的支持,为了后边表达神经网络层级的计算。
首先,先介绍Numpy中支持多维数组计算的三个常用方法:
- np.ndim :获得数组的维数。
- np.shape :获得数组的形状,返回值是一个Tuple。
- np.dot :实现线性代数中,矩阵的乘法。
线性代数中,矩阵的乘法回忆:
下面是一个实例,使用Numpy多维数组来简化神经网络层级转化的计算。
上图的实例,表达的就是下面3个公式,
y1 = 1*x1 + 2*x2
y2 = 3*x1 + 4*x2
y3 = 5*x1 + 6*x2
当x1 = 1 , x2 = 2 时,输出 y1、y2、y3 。
1 X = np.array([1,2]) 2 W = np.array([[1,3,5],[2,4,6]]) 3 np.ndim(W) #2 4 W.shape #(2, 3) 5 Y = np.dot(X,W) 6 Y #array([ 5, 11, 17])
Numpy多维数组应用
代码中,输出了预期的结果:array([ 5, 11, 17]) 。
2.4 实现三层神经网络
本节将使用Numpy多维数组的知识,简洁、优雅地实现神经网络从输入到输出的(前向)处理。重点是神经网络的运算可以作为矩阵运算打包进行。
首先,介绍下权重符号的表示意义(只是本节的介绍,不具有行业一般性):
为了实现三层神经网络的(前向)处理,需要完成 输入层->第1层 ; 第1层->第2层;第2层->输出层 的三次迭代计算。
输入层 -> 第1层 信号传递。
第1层->第2层 信号传递
第2层 -> 输出层 信号传递
注意到,每一层增加了常量神经元“1” ,这个主要是为了矩阵表示偏移量 B 的。如果以输入层到第1层为例做剖析,矩阵计算公式应该是这样的:
A(1)= X*W(1)+B(1) 公式(2.5)
其中 A,X,W,B都是矩阵,表示含义如下:
这样,神经网络的前向处理就比较清晰了,如果确定了输入X,各个层级的权重W,和各个层级的偏移B,我们就可以逐层向后处理。同时,不要忘记,在中间层转化时,这里我们用sigmod激活函数做a1(1) -> z1(1) 的转换,但是在第2层 -> 输出层转换时,将不用sigmod函数,而是直接输出第2层的结果。
在本例中,第0层有2个神经元、第1层有3个神经元,第2层有2个神经元,第3层有2个神经元。所以,我们可以想象:
- W1 是2行3列矩阵,B1是1行3列矩阵
- W2是3行2列矩阵,B2是1行2列矩阵
- W3是2行2列矩阵,B2是1行2列矩阵
下面,用Python实现,3层神经网络的前向处理。下边代码中,sigmod_function()实现sigmod激活函数, identity_function()直接返回,不做任何操作。
1 def init_parameter(): 2 paras = {} 3 paras["W1"] = np.array([[0.1,0.3,0.5],[0.2,0.4,0.6]]) 4 paras["B1"] = np.array([0.1,0.2,0.3]) 5 paras["W2"] = np.array([[0.1,0.4],[0.2,0.5],[0.3,0.6]]) 6 paras["B2"] = np.array([0.1,0.2]) 7 paras["W3"] = np.array([[0.1,0.3],[0.2,0.4]]) 8 paras["B3"] = np.array([0.1,0.2]) 9 return paras 10 11 def sigmod_function(x): 12 return 1/(np.exp(-x) + 1) 13 14 def identity_function(x): 15 return x 16 17 def forward(paras,x): 18 W1,W2,W3 = paras["W1"] , paras["W2"] , paras["W3"] 19 B1,B2,B3 = paras["B1"] , paras["B2"] , paras["B3"] 20 21 A1 = np.dot(x,W1) + B1 22 Z1 = sigmod_function(A1) 23 A2 = np.dot(Z1,W2) + B2 24 Z2 = sigmod_function(A2) 25 A3 = np.dot(Z2,W3) + B3 26 Z3 = identity_function(A3) 27 return Z3 28 29 paras = init_parameter() 30 x = np.array([1.0,0.5]) 31 y = forward(paras,x) 32 y # array([0.31682708, 0.69627909])
矩阵计算实现三层神经网络
2.5 输出层设计
神经网络可以用在分类问题和回归问题上,一般而言,回归问题用恒等函数,分类问题用 softmax 函数。
2.5.1 恒等函数:
恒等函数很简单,会将输入按原样输出。上一节中,identity_function就是恒等函数,不做改变。
2.5.2 softmax函数:
softmax函数公式如下:
公式(2.6)
exp(x) 是表示 ex 的指数函数,假设输出层共有 n 个神经元,计算第 k 个神经元的输出 yk 。分析公式2.6, 我们发现yk是0~1中间的一个数(概率),同时,y1 + y2 + … + yn = 1
其中yk就可以理解成分类为第k个神经元的概率,一般取最大值的神经元,作为神经网络的分类结果。
使用公式2.6计算时,如果ak的数值过大,会导致exp(ak)的计算越界,例如ak=1000时,python无法得到预期结果。
为了处理计算越界问题,将公式2.6 做恒等变形:
(公式2.7)
其中,C是分子分母乘以的任意常数,根据ex的性质,可以最终转化为C\’常量, 下面令C\’ = – max(ak) ,可以达到减小数据的最终目标。