目录
[5.3 误差逆传播算法](#5.3 误差逆传播算法)
[5.4 全局最小与局部极小](#5.4 全局最小与局部极小)
[5.5 其他常见神经网络](#5.5 其他常见神经网络)
[5.6 深度学习](#5.6 深度学习)
[1. 感知机的实现](#1. 感知机的实现)
[3. BP神经网络](#3. BP神经网络)
[4. 径向基网络](#4. 径向基网络)
5.1神经元模型
"神经网络是由具有适应性的简单单元组成的广泛并行互连的网络,它的组织能够模拟生物神经系统对真实世界物体所作出的交互反应"
神经网络是一个很大的学科领域,本课程仅讨论神经网络与机器学习的交集,即"神经网络学习"亦称"连接主义(connectionism)"学习
M-P神经神经元模型:(如下图所示)
图5.1 M-P神经元模型
神经元会接收外界的n个输入信号,这些输入会与权重相结合,再通过"激活函数"对信号进行一定的修改,以得到我们自己想要的数据
**权重:**决定模型如何根据输入数据产生输出,可通过优化算法进行调整,最小化模型预测与实际结果之间的差异。
作用:
- 提高模型性能
- 加速训练过程
- 改善泛化能力
- 避免过拟合
**理想激活函数:**阶跃函数,0表示抑制神经元而1表示激活神经元
阶跃函数具有不连续、不光滑等不好的性质,常用的是 Sigmoid函数
图5.2.1 神经元激活函数
(a)函数是理想情况,对于小于0的信号直接过滤掉,(b)函数则是对小于0的信号进行过滤,而在0的信号,则为一定的值。
把许多个这样的神经元按一定的层次结构连接起来,就得到了神经网络.、
5.2感知机与多层网络
感知机:由两层神经元组成,如图5.2所示,输入层接收外界输入信号后传递给输出层,输出层是M-P神经元,亦称"阈值逻辑单元".
图5.2 感知机
更一般地,给定训练数据集,权重(i= 1,2,...,n)以及阈值可通过学习得到.
感知机的学习:
,
是学习率,若感知机对训练样例(x, y)预测正确,即,则感知机不发生变化,否则将根据错误的程度进行权重调整.
感知机只有输出层神经元进行激活函数处理,即只拥有一层功能神经元,其学习能力非常有限,只能处理线性问题,对于非线性问题,学习过程会发生振荡,w难以稳定下来,求不出解
要解决非线性可分问题,需使用多层功能神经元.
**多层神经元:**简单的两层感知机,输出层与输入层之间的一层神经元,被称为隐层或隐含层(hidden layer),隐含层和输出层神经元都是拥有激活函数的功能神经元.
图5.2.2 多层馈神经网络
**多层前馈神经网络:**常见的神经网络是形如图5.2.2所示的层级结构,每层神经元与下一层神经元全互连,神经元之间不存在同层连接,也不存在跨层连接.这样的神经网络结构通常称为"多层前馈神经网络"
多层前馈网络有强大的表示能力("万有逼近性")
仅需一个包含足够多神经元的隐层,多层前馈神经网络就能以任意精度逼近任意复杂度的连续函数
5.3 误差逆传播算法
**误差逆传播算法(BP算法):**迄今最成功、最常用的神经网络算法,可用于多种任务(不仅限于分类)
给定训练集
图5.3 BP网络及算法中的变量符号
**输入:**d维特征向量输出:l个输出值
**隐层:**假定使用q个隐层神经元
假定功能单元均使用Sigmoid函数
对于训练例,假定网络的实际输出为
则网络在上的均方误差为:
需通过学习确定的参数数目:(d+l+ 1)q+l
BP是一个迭代学习算法,在迭代的每一轮中采用广义感知机学习规则:
BP算法基于梯度下降策略,以目标的负梯度方向对参数进行调整,以为例,对误差给定学习率,有:
注意到先影响到,再影响到,然后才影响到.,有:
根据的定义,显然有
Sigmoid函数有一个很好的性质:
f' (x)= f(x)(1 - f (x)) ,
于是有
类似地,有:
其中:
学习率不能太大,也不能太小。
推导出基于累积误差最小化的更新规则,就得到了累积误差逆传播算法.
所以只需一个包含足够多神经元的隐层,多层前馈网络就能以任意精度逼近任意复杂度的连续函数.然而,如何设置隐层神经元的个数仍是个未决问题,实际应用中通常靠"试错法"(trial-by-error)调整.
正是由于其强大的表示能力,BP神经网络经常遭遇过拟合,其训练误差持续降低,但测试误差却可能上升.
缓解过拟合:
"早停":
- 若训练误差连续a轮的变化小于b,则停止训练
- 使用验证集:若训练误差降低、验证误差升高,则停止训练
正则化:
- 在误差目标函数中增加一项描述网络复杂度
5.4 全局最小与局部极小
神经网络的训练过程可看作一个参数寻优过程,即在参数空间中,寻找一组最优参数使得E最小.
"最优":
- "局部极小"(local minimum)
- "全局最小"(global minimum)
对w*和*,若存在 >0使得
局部极小解: 都有成立
全局最小解: 若对参数空间中的任意(w;)都有
**参数寻优方法:**基于梯度的搜索
从某些初始解出发,迭代寻找最优参数值.每次迭代中,我们先计算误差函数在当前点的梯度,然后根据梯度确定搜索方向.
例如,由于负梯度方向是函数值下降最快的方向,因此梯度下降法就是沿着负梯度方向搜索最优解.若误差函数在当前点的梯度为零,则已达到局部极小,更新量将为零,这意味着参数的迭代更新将在此停止.
然而,如果误差函数具有多个局部极小,则不能保证找到的解是全局最小.
可以采取以下策略解决只能找到一个"局部极小"的问题:以多组不同参数值初始化多个神经网络,按标准方法训练后,取其中误差最小的解作为最终参数.这相当于从多个不同的初始点开始搜索,这样就可能陷入不同的局部极小,从中进行选择有可能获得更接近全局最小的结果.
使用"模拟退火"(simulated annealing)技术[Aarts and Korst,1989].模拟退火在每一步都以一定的概率接受比当前解更差的结果,从而有助于"跳出"局部极小.在每步迭代过程中,接受"次优解"的概率要随着时间的推移而逐渐降低,从而保证算法稳定.
使用随机梯度下降.与标准梯度下降法精确计算梯度不同,随机梯度下降法在计算梯度时加入了随机因素.于是,即便陷入局部极小点,它计算出的梯度仍可能不为零,这样就有机会跳出局部极小继续搜索.
5.5 其他常见神经网络
- RBF网络
- ART网络
- SOM网络
- 级联相关网络
- Elman网络
- Boltzmann机
5.6 深度学习
复杂模型的训练效率低,易陷入过拟合,因此难以受到人们青睐.而"深度学习"是一种优秀的复杂模型
**深度学习模型:**深层的神经网络
通过增加隐层数量来提升模型性能,但BP算法不适用于此,不能够"收敛"
**无监督逐层训练:**多隐层网络训练的有效手段,
基本思想:"预训练+微调"
每次训练一层隐结点,训练时将上一层隐结点的输出作为输入,而本层隐结点的输出作为下一层隐结点的输入,这称为"预训练"(pre-training);在预训练全部完成后,再对整个网络进行"微调"(fine-tuning)训练.各层预训练完成后,再利用BP算法等对整个网络进行训练.
将大量参数分组,对每组先找到局部看来比较好的设置,然后再基于这些局部较优的结果联合起来进行全局寻优.这样就在利用了模型大量参数所提供的自由度的同时,有效地节省了训练开销.
**"权共享"(weight sharing):**让一组神经元使用相同的连接权,另一种节省训练开销的策略
无论是DBN还是CNN,都是通过多层处理,逐渐将初始的"低层"特征表示转化为"高层"特征表示后,用"简单模型"即可完成复杂的分类等学习任务.由此可将深度学习理解为进行"特征学习"(feature learning)或"表示学习"(representation learning).
**"特征工程":**描述样本的特征由人类专家来设计
二、实验
1. 感知机的实现
利用Python实现感知机算法的原始形式。
import numpy as np
import matplotlib.pyplot as plt
def perception(data,label,n,inter):
raw,col = np.shape(data)
w = np.random.randn(1,col)
b = np.random.randn(1)
x1 = -1
y1 = (-1/w[:,1])*(np.dot(w[:,0],x1)+b)
x2 = 2
y2 = (-1/w[:,1])*(np.dot(w[:,0],x2)+b)
plt.plot([x1,x2],[y1,y2],color='red')
plt.scatter(data[1:15,0],data[1:15,1],color='blue',marker='x')
plt.scatter(data[16:,0],data[16:,1],color='red',marker='o')
plt.show()
for times in range(inter):
for i in range(raw):
if -label[i-1]*(np.dot(w,(data[:][i-1]))+b) < 0:
w -= n*label[i-1]*data[:][i-1]
b -= n*label[i-1]
elif -label[i-1]*(np.dot(w,(data[:][i-1]))+b) == 0:
break
return w,b
if __name__ == '__main__':
data = np.array([
[-0.6508, 0.1097],[-1.4492, 0.8896],[2.0850, 0.6876],[0.2626, 1.1476],[0.6418, 1.0234],[0.2569, 0.6730],[1.1155, 0.6043],[0.0914, 0.3399],[0.0121, 0.5256],[-0.0429, 0.4660],[0.4340, 0.6870],[0.2735, 1.0287],[0.4839, 0.4851],[0.4089, -0.1267],[1.4391, 0.1614],[2.9115, 2.1973],[2.3654, 2.0475],[2.2144, 2.7515],[2.2013, 2.0014],[2.6483, 2.2183],[2.1147, 2.2242],[2.7970, 2.8795],[2.0625, 2.6366],[2.5307, 2.1285],[2.2200, 2.7777],[2.3957, 2.1076],[2.1013, 2.5989],[2.4482, 2.9455],[2.0149, 2.6192],[2.2012, 2.2611]])
label = np.array([-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1])
w,b = perception(data,label,0.5,1000)
x1 = -2
y1 = (-1/w[:,1])*(np.dot(w[:,0],x1)+b)
x2 = 3
y2 = (-1/w[:,1])*(np.dot(w[:,0],x2)+b)
plt.plot([x1,x2],[y1,y2],color='red')
plt.scatter(data[1:15,0],data[1:15,1],color='blue',marker='x')
plt.scatter(data[16:,0],data[16:,1],color='red',marker='o')
plt.show()
学习前
学习后
2.对偶形式
import numpy as np
import matplotlib.pyplot as plt
def perception_an(data,label,n,inter):
a = np.random.randn(len(data))
b = 0
Gram = np.dot(data,data.T)
for k in range(inter):
for i in range(len(data)):
tmp = 0
for j in range(len(data)):
tmp += a[j]*label[j]*Gram[i][j]
tmp += b
if (label[i]*tmp <= 0):
a[i] += n
b += n*label[i]
w = 0
for i in range(len(a)):
w += a[i]*label[i]*data[i,:]
return w,b
if __name__ == '__main__':
data = np.array([
[-0.6508, 0.1097],[-1.4492, 0.8896],[2.0850, 0.6876],[0.2626, 1.1476],[0.6418, 1.0234],[0.2569, 0.6730],[1.1155, 0.6043],[0.0914, 0.3399],[0.0121, 0.5256],[-0.0429, 0.4660],[0.4340, 0.6870],[0.2735, 1.0287],[0.4839, 0.4851],[0.4089, -0.1267],[1.4391, 0.1614],[2.9115, 2.1973],[2.3654, 2.0475],[2.2144, 2.7515],[2.2013, 2.0014],[2.6483, 2.2183],[2.1147, 2.2242],[2.7970, 2.8795],[2.0625, 2.6366],[2.5307, 2.1285],[2.2200, 2.7777],[2.3957, 2.1076],[2.1013, 2.5989],[2.4482, 2.9455],[2.0149, 2.6192],[2.2012, 2.2611]])
label = np.array([-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1])
w,b = perception_an(data,label,0.5,1)
x1 = -2
y1 = (-1/w[1])*(np.dot(w[0],x1)+b)
x2 = 3
y2 = (-1/w[1])*(np.dot(w[0],x2)+b)
plt.plot([x1,x2],[y1,y2],color='red')
plt.scatter(data[1:15,0],data[1:15,1],color='blue',marker='x')
plt.scatter(data[16:,0],data[16:,1],color='red',marker='o')
plt.show()
3. BP神经网络
# initialize parameters randomly
h = 100 # size of hidden layer
W = 0.01 * np.random.randn(D,h)
b = np.zeros((1,h))
W2 = 0.01 * np.random.randn(h,K)
b2 = np.zeros((1,K))
# some hyperparameters
step_size = 1e-0
reg = 1e-3 # regularization strength
# gradient descent loop
num_examples = X.shape[0]
for i in range(10000):
# evaluate class scores, [N x K]
hidden_layer = np.maximum(0, np.dot(X, W) + b) # note, ReLU activation
scores = np.dot(hidden_layer, W2) + b2
# compute the class probabilities
exp_scores = np.exp(scores)
probs = exp_scores / np.sum(exp_scores, axis=1, keepdims=True) # [N x K]
# compute the loss: average cross-entropy loss and regularization
corect_logprobs = -np.log(probs[range(num_examples),y])
data_loss = np.sum(corect_logprobs)/num_examples
reg_loss = 0.5 * reg * np.sum(W * W) + 0.5 * reg * np.sum(W2 * W2)
loss = data_loss + reg_loss
if i % 1000 == 0:
print("iteration %d: loss %f" % (i, loss))
# compute the gradient on scores
dscores = probs
dscores[range(num_examples),y] -= 1
dscores /= num_examples
# backpropate the gradient to the parameters
# first backprop into parameters W2 and b2
dW2 = np.dot(hidden_layer.T, dscores)
db2 = np.sum(dscores, axis=0, keepdims=True)
# next backprop into hidden layer
dhidden = np.dot(dscores, W2.T)
# backprop the ReLU non-linearity
dhidden[hidden_layer <= 0] = 0
# finally into W,b
dW = np.dot(X.T, dhidden)
db = np.sum(dhidden, axis=0, keepdims=True)
# add regularization gradient contribution
dW2 += reg * W2
dW += reg * W
# perform a parameter update
W += -step_size * dW
b += -step_size * db
W2 += -step_size * dW2
b2 += -step_size * db2
对图所示的非线性数据,迭代了10000次,最后的损失降低为0.249384,最后得到的精度为:0.98。可以说最终得到了比较理想的精确度,事实证明BP神经网络在某些情况下比单纯的线性分类器的效果要好的多
4. 径向基网络
第一步,确定神经元中心;
第二步,利用BP算法等来确定参数。
from scipy import *
from scipy.linalg import norm, pinv
from matplotlib import pyplot as plt
class RBF:
def __init__(self, indim, numCenters, outdim):
self.indim = indim
self.outdim = outdim
self.numCenters = numCenters
self.centers = [random.uniform(-1, 1, indim) for i in range(numCenters)]
self.beta = 8
self.W = random.random((self.numCenters, self.outdim))
def _basisfunc(self, c, d):
assert len(d) == self.indim
return exp(-self.beta * norm(c-d)**2)
def _calcAct(self, X):
# 计算RBFs的激活函数值
G = zeros((X.shape[0], self.numCenters), float)
for ci, c in enumerate(self.centers):
for xi, x in enumerate(X):
G[xi,ci] = self._basisfunc(c, x)
return G
def train(self, X, Y):
""" X: n x indim维的矩阵
y: n x 1维的列向量"""
# 从训练集随机选择中心向量
rnd_idx = random.permutation(X.shape[0])[:self.numCenters]
self.centers = [X[i,:] for i in rnd_idx]
print("center", self.centers)
# 计算RBFs的激活函数值
G = self._calcAct(X)
print(G)
# 计算输出层的权值
self.W = dot(pinv(G), Y)
def test(self, X):
""" X: n x indim维的矩阵 """
G = self._calcAct(X)
Y = dot(G, self.W)
return Y
if __name__ == '__main__':
n = 100
x = mgrid[-1:1:complex(0,n)].reshape(n, 1) #设置x的值
y = sin(3*(x+0.5)**3 - 1) # 设置y的值
rbf = RBF(1, 10, 1)
rbf.train(x, y)
z = rbf.test(x)
plt.figure(figsize=(12, 8))
plt.plot(x, y, 'k-')
plt.plot(x, z, 'r-', linewidth=2)
plt.plot(rbf.centers, zeros(rbf.numCenters), 'gs')
for c in rbf.centers:
cx = arange(c-0.7, c+0.7, 0.01)
cy = [rbf._basisfunc(array([cx_]), array([c])) for cx_ in cx]
plt.plot(cx, cy, '-', color='gray', linewidth=0.2)
plt.xlim(-1.2, 1.2)
plt.show()