1. 感知机
感知机是神经网络深度学习的起源的算法。用于接收多个输入信号,产生一个输出信号。
如图1.1,该感知机接收两个信号(),输出y信号,图中的〇称为神经元或者节点,
称为权重,信号从输入流向输出时会乘以对应的权重并相加,当总和超过某个界限值(称为阈值,用
表示)时,最终会输出1,此时称“神经元被激活”。这个过程用数学式子表示如下:
2. 逻辑门
2.1 用感知机实现逻辑门
可以用感知机实现逻辑门,如与门(AND gate)
用式1.1的数学式子实现满足图2.1的与门有无数种可选的权重与阈值参数,比如当时,可以满足仅当x1与x2的输入均为1时,输出y为1。
用python实现如下:
def AND(x1,x2):
w1,w2,theta = 1.0,1.0,1.0
tmp = x1*w1+x2*w2
if tmp <= theta:
return 0
else:
return 1
同理,或门(OR gate)和与非门(NAND gate)均可用感知机实现,只需要调整权重与阈值参数即可。
2.2 偏置
将式1.1的换到不等式的左边,并用字母b(称为偏置,
)来表示,则新的式子可以表示为
式子中,权重W,为控制输入信号重要性的参数,而偏置b是调整神经元被激活的容易程度的参数。
同时使用numpy库来重新实现与门的算法:
import numpy as np
def AND(x1,x2):
x = np.array([x1,x2])
w = np.array([1.0, 1.0])
b = -1.0
tmp = np.sum(w*x)+b
if tmp <= 0:
return 0
else:
return 1
2.3 用感知机实现异或门(XOR gate)
上面的与门/或门/与非门可以用图形的方式来描述问题,以或门为例,如下图所示:
对于或门的输入参数x1, x2分别取0或1时,输出y取图中四个点来表示(圆圈表示0,小三角形表示1),问题即为求解一条直线(斜率由w1,w2决定,偏移量由b决定)将输出0或者1的区域划分开,对于图2.4,有无数条满足要求的直线可以使得0位于直线的左下方,1位于直线的右上方。
当把图形换成异或门时,情况就有所不同了,异或门的真值表如下:
图形对应如下:
可以看出,对于输出的值是无法用一条直线区分开的(即无法做出一条直线将图2.6中的小圆圈和小三角划分开)。
这就是感知机的局限性,即只能用于直线划分区域,通常称为线性空间。
想要划分异或门对应的区域只能用曲线,这类区域的空间称为非线性空间。
2.4 多层感知机
单层感知机不能解决非线性问题,但是多层感知机可以做到。
如对于异或门,可以通过组合与门、或门、与非门来实现,如下图所示:
真值表如下图所示:
其算法可以如下实现(AND, NASND, OR参考2.1及2.2的实现):
def XOR(x1, x2):
s1 = NAND(x1, x2)
s2 = OR(x1, x2)
y = AND(s1, s2)
return y
与门、与非门、或门是单层感知机,异或门是多层感知机,如下图所示,第0层的两个神经元接收输入信号,并将信号发送至第1层的神经元,第1层的神经元将信号发送至第2层的神经元,第二层的神经元输出y。
3. 从感知机到神经网络
神经网络和多层感知机非常相似,下图是一个神经网络的结构:
其中每一个神经元都可以用式2.1来描述,同时为了更简便描述神经元被激活的动作,引入激活函数h(x),意义如下:
上式中激活函数的实现以某一阈值为界,一旦超过阈值就切换输出,这样的函数称为阶跃函数。
3.1 Sigmoid函数
神经网络经常使用的一个激活函数叫sigmoid函数,它的数学式子如下:
(式3.2 sigmoid函数)
阶跃函数和sigmoid函数图形如下:
sigmoid函数是一条平滑的曲线,输出随着输入产生连续性的变化,而阶跃函数的输出是跳跃性的、非连续的。它们的共同点是,两者都为非线性函数,且当输入信号为重要信息时,输出都会向1靠近或等于1,当输入信号为不重要信息时,输出都较小(向0靠近或等于0)。
神经网络的激活函数必须使用非线性函数,否则即使加深神经网络的层次,输出也只能保持第1层的输出结果。
3.2 ReLU函数
ReLU也是神经网络中使用较多的一种激活函数,当输入小于等于0时输出0,当输入大于0时输出等于输入,即如下图所示:
3.3 神经网络的内积(点积)
假定有一个简单的神经网络,其输入矩阵为 X = [x1, x2],权重矩阵为W = [ [1, 2, 3], [4, 5, 6] ],输出矩阵为Y = [y1, y2, y3],其神经网络的运算如下图所示:
用python语句示例:
import numpy as np
X = np.array([1, 2])
W = np.array([[1,3,5],[2,4,6]])
Y = np.dot(X, W)
print(Y) # [5 11 17]
3.4 三层神经网络的实现
以下图的3层神经网络为例,实现从输入到输出(在神经网络中称为前向,即forward)处理。
先将权重做如下的符号表示和说明,权重用符号表示:
从输入层到第1层的信号传递可以如下图所示:
用数学式表示的计算:
(式3.3 第1层第1个神经元的计算)
(式3.4 对上面得到的神经元使用激活函数)
若使用矩阵的乘法运算,则可以将第1层运算表示为:
(式3.5 第一层的神经元的计算)
(式3.6 使用激活函数后可作为下一层的输入神经元)
其中,
,
,
用Python语句示例如下:
import numpy as np
X = np.array([1.0,0.5])
W1 = np.array([[0.1,0.3,0.5], [0.2,0.4,0.6]])
B1 = np.array([0.1,0.2,0.3])
A1 = np.dot(X,W1) + B1
Z1 = sigmoid(A1)
print(A1) #[0.3, 0.7, 1.1]
print(Z1) #[0.57444252, 0.66818777, 0.75026011]
从第1层到第2层的信号传递类似,如下图所示,
Python语句示例如下:
W2 = np.array([[0.1,0.4],[0.2,0.5],[0.3,0.6]])
B2 = np.array([0.1,0.2])
A2 = np.dot(Z1, W2) + B2
Z2 = sigmoid(A2)
从第2层到输出层的算法仍然类似,不过一般把输出层的激活函数用表示,如下图所示:
用Python语句示例如下:
def sigma_output(x):
return x #此处直接输出结果
W3 = np.array([[0.1,0.3], [0.2,0.4]])
B3 = np.array([0.1, 0.2])
A3 = np.dot(Z2, W3) + B3
Y = sigma_output(A3) # Y = A3
将以上代码做个总结,则一个完整的3层神经网络的Python实现如下:
import numpy as np
def sigma_output(x):
return x
def init_network():
network = {}
network['W1'] = np.array([[0.1, 0.3, 0.5], [0.2, 0.4, 0.6]])
network['B1'] = np.array([0.1, 0.2, 0.3])
network['W2'] = np.array([[0.1, 0.4], [0.2, 0.5], [0.3, 0.6]])
network['B2'] = np.array([0.1, 0.2])
network['W3'] = np.array([[0.1, 0.3], [0.2, 0.4]])
network['B3'] = np.array([0.1, 0.2])
return network
def forward(network, X):
W1, W2, W3 = network['W1'], network['W2'], network['W3']
B1, B2, B3 = network['B1'], network['B2'], network['B3']
A1 = np.dot(X, W1) + B1
Z1 = sigmoid(A1)
A2 = np.dot(Z1, W2) + B2
Z2 = sigmoid(A2)
A3 = np.dot(Z2, W3) + B3
Y = sigma_output(A3)
return Y
network = init_network()
x = np.array([1.0, 0.5])
y = forward(network, x)
print(y) # [ 0.31682708 0.69627909]
3.5 关于输出层
神经网络可以用在分类问题和回归问题上,分类问题指预测离散类别的问题,回归问题指预测连续值的问题。对于回归问题,一般输出层用恒等函数作为激活函数,而分类问题则用softmax函数。
softmax函数的数学表示如下:
(式3.7 softmax函数)
使用softmax函数时,输出层的每个神经元都收到所有输入信号的影响,见下图的比较:
用Python语句表示softmax函数如下:
import numpy as np
def softmax(x):
return np.exp(x)/np.sum(np.exp(x))
上面的代码有一定的缺陷,指数的运算很容易导致np.exp(x)成为超大的数而使结果变成inf。因此可做一定的改进,由指数的性质,可将式3.7做如下改动:
(式3.8 其中C为常数)
改进后的softmax函数代码如下:
def softmax(x):
c = np.max(x)
return np.exp(x-c)/np.sum(np.exp(x-c))
由式3.7可以得出结论,softmax函数的输出是0.0到1.0之间的实数,且softmax函数的输出值的总和是1.0,因此softmax函数的输出实质上代表的是概率。
输出层的神经元数量需要根据实际待解决的问题来确定,对于分类问题,输出层的神经元数量一般设定为类别的数量。比如,对于某个数字的图片输入,需要判断图中的数字是0到9中的哪一个,可将输出层的神经元设定为10个。
求解机器学习的问题,通常有两个阶段,首先是学习阶段或者称为训练阶段,使用训练数据对权重参数进行调整;其次是推理阶段或者称为预测阶段,使用训练出来的权重参数,对输入数据进行推理(如分类)。推理的过程称为神经网络的前向传播,训练的过程称为神经网络的反向传播。