-
神经网络基本概念
神经网络中最基本的成分是神经元模型,如果某神经元的电位超过了一个阈值 ,那么它就会被激活,即 “兴奋” 起来,向其他神经元发送信号。这就是一直沿用至今的 “M-P 神经元模型”。
神经元接收到来自n个其他神经元传递过来的输入信号,这些输入信号通过带权重的连接进行传递,神经元接收到的总输入值将与神经元的阈值进行比较,然后通过激活函数处理以产生神经元的输出。阶跃函数具有不连续、不光滑等不太好的性质,因此常用 Sigmoid 函数作为激活函数。 -
感知机与多层网络
更一般地,给定训练数据集,权重以及阈值可通过学习得到。阈值可看作一个固定输入为 1.0 的"哑结点" ,这样,权重和阈值的学习就可统一为权重的学习。
若两类模式是线性可分的,即存在一个线性超平面能将它们分开,则感知在fl的学习过程一定会收敛,而求得适当的权向量 ω; 否则感知机学习过程将会发生震荡。
要解决非线性可分问题,需考虑多层功能神经元。输出层与输入层之间的一 层神经元,被称为隐含层。只需包含隐层,即可称 为多层网络。 -
误差逆传播算法
误差逆传播BP 算法不仅可用于多层前馈神经网络,还可用于其他类型的神经网络,例如训练递归神经网络。通常说 “BP 网络"时,一般是指用 BP 算法训练的多层前馈神经网络.
假设一个拥有 d 个输入神经元、 l个输出神经元、 q 个隐层神经元的多层前馈网络结构,
记隐层第 h 个神经元接收到的输入为
输出 层第 j 个神经元接收到的输入为
均方误差为
参数需确定:输入层到隐层的 dxq 个权值、隐层到输出层的 q x l个权值、 q 个隐层神经元的阈值、l个输出层神经元的阈值.
BP 算法基于梯度下降策略, 以目标的负梯度方向对参数进行调整. 对误差 Ek,给定学习率 η,有
Whj为隐层到输出层的连接权值,bh为隐层对输出层的输入。
theta为输出层的阈值
Vih为输入层到隐层的连接权值,Xi为输入层对隐层的输入。
gama为隐层的阈值
具体操作步骤
上面介绍的"标准 BP 算法"每次仅针对一个训练样例更新连接权值和阈值,参数更新得非常频繁,而且对不同样例进行更新的效果可能出现"抵消"现象。累积 BP 算法直接针对累积误差最小化,它在读取整个训练集D一遍后才对参数进行更新。在很多任务中,累积误差下降到一定程度之后,进一步下降会非常缓慢,这时标准BP往往会更快获得较好解,尤其是在训练集D非常大时更明显.
如何设置隐层神经元的个数仍是个未解决的问题,实际应用中通常靠"试错法” 调整。
由于其强大的表示能力,BP神经网络经常遭遇过拟合。
有两种策略常用来缓解BP网络的过拟合。
1.将数据分成训练集和验证集,训练集用 来计算梯度、更新连接权和阈值,验证集用来估计误差,若训练集误差降低但验证集误差升高,则停止训练,同时返回具有最小验证集误差的连接权和阑值.
2.引入正则化策略的神经网络。基本思想是在误差目标函数中增加一个用于描述网络复杂度的部分,例如连接权值与阈值的平方和。
其中 λε(0,1) 用于对经验误差与网络复杂度这两项进行折中,常通过交叉验证法来估计。
关于梯度下降算法常用的Adam和SGD:
Adam 这个名字来源于adaptive moment estimation,自适应矩估计,如果一个随机变量 X 服从某个分布,X 的一阶矩是 E(X),也就是样本平均值,X 的二阶矩就是 E(X^2),也就是样本平方的平均值。Adam 算法根据损失函数对每个参数的梯度的一阶矩估计和二阶矩估计动态调整针对于每个参数的学习速率。TensorFlow提供的tf.train.AdamOptimizer可控制学习速度。Adam 也是基于梯度下降的方法,但是每次迭代参数的学习步长都有一个确定的范围,不会因为很大的梯度导致很大的学习步长,参数的值比较稳定。AdamOptimizer通过使用动量(参数的移动平均数)来改善传统梯度下降,促进超参数动态调整。
假如我们要优化一个函数 f(x) ,即找到它的最小值, 常用的方法叫做Gradient Descent (GD), 也就是最速下降法.
-
全局最小与局部最小
梯度下降法就是沿着负梯度方向搜索最优解.若当前点的梯度为零,则已达到局部极小,更新量将为0。如果误差函数仅有一个局部极小,那么此时找到的局部极小就是全局最小;然而,如果误差函数具有多个局部极小,则不能保证找到的解是全局最小。对这种情况,我们称参数寻优陷入了局部极小, 这显然不是我们所希望的。
在现实任务中,人们常采用以下策略来试图 跳出局部极小,从而进一 步接近全局最小。
1.以多组不同参数值初始化多个神经网络按标准方法训练后,取其中误差最小的解作为最终参数。
2.使用 “模拟退火”,在每一步都以一定的概率接受比当前解更差的结果,从而有助于 "跳出"局部极小. 在每步迭代过程中接受"次优解"的概率要随着时间的推移而逐渐降低,从而保证算法稳定.
3.使用随机梯度下降。与标准梯度下降法精确计算梯度不同, 随机梯度下降法在计算梯度时加入了随机因素,即便陷入局部极小点,它计算出的梯度仍可能不为零,这样就有机会跳出局部极小继续搜索。
4.遗传算法也常用来训练神经网络以更好地逼近全局最小。
需注意的是,上述用于跳出局部极小的技术大多是启发式,理论上尚缺乏保障。 -
其他神经网络
RBF(径向基函数)网络是一种单隐层前馈神经网络,它使用径向基函数作为隐层神经元激活函数,而输出层则是对隐层神经元输出的线性组合。径向基函数
通常采用两步过程来训练RBF网络:第一步,确定神经元中心Ci,常用的方式包括随机采样、聚类等; 第二步,利用 BP算法等来确定参数.
**ART网络:**是竞争型学习的重要代表。竞争型学习是神经网络中一种常用的无监督学习,在使用该策略时,网络的输出神经元相互竞争,每一时刻仅有一个竞争获胜的神经元被激活,其他神经元的状态被抑制。ART网络由比较层、识别层、识别阈值和重置模块构成.其中比较层负责接收输入样本,并将其传递给识别层神经元。识别层每个神经元对应 1个模式类,神经元数目在训练过程中动态增长以增加新的模式类。
SOM网络是一种竞争学习型的无监督神经网络。它能将高维输入数据映射到低维空间(通常为二维),同时保持输入数据在高维空间的拓扑结构。
级联相关网络有两个主要成分"级联"和"相关" 。级联是指建立连接的层级结构,在开始训练时,网络只有输入层和输出层,处于最小拓扑结 构,随着训练的进行,新的隐层神经元逐渐加入,从而创建起层级结构。当新的隐层神经元加入时,其输入端连接权值是冻结固定的。相关是指通过最大化新神经元的输出与网络误差之间的相关性来训练相 关的参数。级联相关网络无需设置网络层数、隐层神经元数目,且训练速度较快,但其在数据较小时易陷入过拟合。
Elman网络是最常用的递归神经网络之一。允许网络中出现环形结构,从而可让一些神经元的输出反馈回来作为输入信号。这样的结构与信息反馈过程,使得网络在 t 时刻的输出状态不仅与 t 时刻的输入有关,还与 t 一 1 时刻的网络状态有关,从而能处理与时间有关的动态变化。
Boltzmann机训练过程就是将每个训练样本视为一个状态向量,使其出现的概率尽可能大。标准的 Boltzmann 机是一个全连接图,训练网络的复杂度很高,这使其难以用于解决现实任务. 受限 Boltzmann 机仅保留显层与隐层之间的连接,从而将 Boltzmann 机结构由完全图简化为二部图。
6. 深度学习
典型的深度学习模型就是很深层的神经网络。
无监督逐层训练(unsupervised layer-wise training)是多隐层网络训练的有效手段,其基本思想是每次训练一层隐结点,训练时将上一层隐结点的输 出作为输入,向本层隐结点的输出作为下一层隐结点的输入,这称为"预训练" (pre-training); 在预训练全部完成后,再对整个网络进行"微调" (fine tuning)训练。如DBN。
另一种节省训练开销的策略是"权共享" 即让一组神经元使用共同的连接权,这个策略在卷积神经网络(Convolutional Neural Network,简称 CNN) 中发挥了重要作用。
# coding=utf-8
import numpy as np
def tanh(x):
return np.tanh(x)
def tanh_deriv(x):
return 1.0- np.tanh(x)*np.tanh(x)
def logistic(x):
return 1/(1+np.exp(-x))
def logistic_derivative(x):
return logistic(x)*(1-logistic(x))
class NeuralNetwork:
def __init__(self,layers,activation='tanh'):
"""
"""
if activation == 'logistic':
self.activation = logistic
self.activation_deriv = logistic_derivative
elif activation=='tanh':
self.activation = tanh
self.activation_deriv=tanh_deriv
print(layers)
self.weights=[]
self.weights.append((2*np.random.random((layers[0]+1,layers[1]))-1)*0.25)
#3*12权值矩阵
for i in range(2,len(layers)):
self.weights.append((2*np.random.random((layers[i-1],layers[i]))-1)*0.25)#12*1权值矩阵
print(self.weights)
#self.weights.append((2*np.random.random((layers[i]+1,layers[i+1]))-1)*0.25)
def fit(self,X,y,learning_rate=0.2,epochs=10000):#epochs指一次训练中迭代次数
X = np.atleast_2d(X)
# atlest_2d函数:确认X至少二维的矩阵
temp = np.ones([X.shape[0],X.shape[1]+1])
#初始化矩阵全是1(行数,列数+1是为了有B这个偏向)
temp[:,0:-1]=X
#行全选,第一列到倒数第二列
X=temp
y=np.array(y)
#数据结构转换
for k in range(epochs):
# 抽样梯度下降epochs抽样
i = np.random.randint(X.shape[0])
a = [X[i]]
for l in range(len(self.weights)):
a.append(self.activation(np.dot(a[l],self.weights[l])))
# 计算输入层的输出,得到每个节点的输出结果
error = y[i]-a[-1]
#最后一层错误率
deltas=[error*self.activation_deriv(a[-1])]#对应gj
for l in range(len(a)-2,0,-1):
deltas.append(deltas[-1].dot(self.weights[l].T)*self.activation_deriv(a[l]))
deltas.reverse()
for i in range(len(self.weights)):
layer = np.atleast_2d(a[i])
delta = np.atleast_2d(deltas[i])
self.weights[i] +=learning_rate*layer.T.dot(delta)
def predict(self,x):
x=np.array(x)
temp= np.ones(x.shape[0]+1)
temp[0:-1]=x
a = temp
for l in range(0,len(self.weights)):
a=self.activation(np.dot(a,self.weights[l]))
return(a)
if __name__ == '__main__':
nn = NeuralNetwork([2,12,1],'tanh')
x = np.array([[0,0],[0,1],[1,0],[1,1]])
y = np.array([0,1,1,0])
nn.fit(x,y)
for i in [[0,0],[0,1],[1,0],[1,1]]:
print(i,nn.predict(i))