深度学习与全连接神经网络.docx
《深度学习与全连接神经网络.docx》由会员分享,可在线阅读,更多相关《深度学习与全连接神经网络.docx(24页珍藏版)》请在冰豆网上搜索。
深度学习与全连接神经网络
统计建模与R语言
全连接神经网络
学院航空航天学院
专业机械电子工程
年级2019级
学生学号19920191151134
学生姓名梅子阳
一、绪论
1、人工智能背景
信息技术是人类历史上的第三次工业革命,计算机、互联网、智能家居等技术的普及极大地方便了人们的日常生活。
通过编程的方式,人类可以将提前设计好的交互逻辑交给机器重复且快速地执行,从而将人类从简单枯燥的重复劳动工作中解脱出来。
但是对于需要较高智能水平的任务,如人脸识别、聊天机器人、自动驾驶等任务,很难设计明确的逻辑规则,传统的编程方式显得力不从心,而人工智能(ArtificialIntelligence,简称AI)是有望解决此问题的关键技术。
随着深度学习算法的崛起,人工智能在部分任务上取得了类人甚至超人的智力水平,如围棋上AlphaGo智能程序已经击败人类最强围棋专家之一柯洁,在Dota2游戏上OpenAIFive智能程序击败冠军队伍OG,同时人脸识别、智能语音、机器翻译等一项项实用的技术已经进入到人们的日常生活中。
现在我们的生活处处被人工智能所环绕,尽管目前能达到的智能水平离通用人工智能(ArtificialGeneralIntelligence,简称AGI)还有一段距离,但是我们仍坚定地相信人工智能的时代已经来临。
怎么实现人工智能是一个非常广袤的问题。
人工智能的发展主要经历过三个阶段,每个阶段都代表了人们从不同的角度尝试实现人工智能的探索足迹。
早期,人们试图通过总结、归纳出一些逻辑规则,并将逻辑规则以计算机程序的方式实现,来开发出智能系统。
但是这种显式的规则往往过于简单,并且很难表达复杂、抽象的概念和规则。
这一阶段被称为推理期。
1970年代,科学家们尝试通过知识库加推理的方式解决人工智能,通过建庞大复杂的专家系统来模拟人类专家的智能水平。
这些明确指定规则的方式存在一个最大的难题,就是很多复杂、抽象的概念无法用具体的代码实现。
比如人类对图片的识别、对语言的理解过程,根本无法通过既定规则模拟。
为了解决这类问题,一门通过让机器自动从数据中学习规则的研究学科诞生了,称为机器学习,并在1980年代成为人工智能中的热门学科。
在机器学习中,有一门通过神经网络来学习复杂、抽象逻辑的方向,称为神经网络。
神经网络方向的研究经历了两起两落。
2012年开始,由于效果极为显著,应用深层神经网络技术在计算机视觉、自然语言处理、机器人等领域取得了重大突破,部分任务上甚至超越了人类智能水平,开启了以深层神经网络为代表的人工智能的第三次复兴。
深层神经网络有了一个新名字:
深度学习。
一般来讲,神经网络和深度学习的本质区别并不大,深度学习特指基于深层神经网络实现的模型或算法。
2、神经网络与深度学习
将神经网络的发展历程大致分为浅层神经网络阶段和深度学习阶段,以2006年为分割点。
2006年以前,深度学习以神经网络和连接主义名义发展,历经了两次兴盛和两次寒冬;2006年,GeoffreyHinton首次将深层神经网络命名为深度学习,他发现通过逐层预训练的方式可以较好地训练多层神经网络,并在MNIST手写数字图片数据集上取得了优于SVM的错误率,开启了第三次人工智能的复兴。
在论文中,GeoffreyHinton首次提出了DeepLearning的概念,这也是(深层)神经网络被叫作深度学习的由来。
2011年,XavierGlorot提出了线性整流单元(RectifiedLinearUnit,简称ReLU)激活函数,这是现在使用最为广泛的激活函数之一。
2012年,8层的深层神经网络AlexNet发布,并在图片识别竞赛中取得了巨大的性能提升,此后数十层、数百层、甚至上千层的神经网络模型相继提出,展现出深层神经网络强大的学习能力。
一般将利用深层神经网络实现的算法称作深度学习,本质上神经网络和深度学习可认为是相同的。
二、线性模型与优化
1、神经元模型
典型生物神经元结构
1943年,心理学家WarrenMcCulloch和逻辑学家WalterPitts根据生物神经元(Neuron)结构,提出了最早的神经元数学模型,称为MP神经元模型。
该模型的输出𝑓(𝒙)=ℎ(𝑔(𝒙)),其中𝑔(𝒙)=∑𝑖𝑥𝑖,𝑥𝑖∈{0,1},模型通过𝑔(𝒙)的值来完成输出值的预测,如图所示。
如果𝑔(𝒙)≥0,输出为1;如果𝑔(𝒙)<0,输出为0。
可以看到,MP神经元模型并没有学习能力,只能完成固定逻辑的判定。
MP神经元模型
1958年,美国心理学家FrankRosenblatt提出了第一个可以自动学习权重的神经元模型,称为感知机(Perceptron),如图1.5所示,输出值𝑜与真实值之间的误差用于调整神经元的权重参数{𝑤,𝑤,…,𝑤}。
FrankRosenblatt随后基于“Mark1感知机”硬件实现感知机模型,输入为400个单元的图像传感器,输出为8个节点端子,可以成功识别一些英文字母。
一般认为1943年~1969年为人工智能发展的第一次兴盛期。
感知机模型
2、神经元的线性模型
假设神经元在传输信息的过程中,单个神经元中的输出与输入间存在线性变化,用线性方程来模拟这个过程:
𝑓(𝒙)=𝑤𝑥+b
其中w为信号的增益过程,b为信号的偏置过程;而当输入为向量形式
𝒙=[𝑥1,𝑥2,𝑥3,…,𝑥𝑛]T
时,线性方程变为:
𝑓(𝒙)=𝑤1𝑥1+𝑤2𝑥2+𝑤3𝑥3+⋯+𝑤𝑛𝑥𝑛+b
则单层神经元的线性模型如下图所示
对于已知的多组数据点(x,y),将x作为数据的输入,而将y作为数据的真实标签,建立模型,通过输入x来预测真实标签y的值,这个过程可以视为一个朴素的决策过程。
3、回归问题
从点集中找到距离所有点距离最短的直线问题,就是线性回归问题。
在R语言中,线性回归几行代码便可实现:
在神经网络中,我们常用梯度下降法来解决回归问题;梯度下降法将回归问题变为了优化问题,我们通过优化𝑓(𝒙)=𝑤𝑥+b中的参数w与参数b,使得均方函数
的取值最小,在这里我们称之为损失函数,上述过程可以记为
4、梯度下降
函数及其梯度向量
根据梯度的知识,梯度∇𝑓总是向着函数值增大的方向前进,则梯度的反方向指向函数值减少的方向,则只需要按照
=
∇𝑓
来迭代更新𝒙′,就能获得越来越小的函数值,其中𝜂用来缩放梯度向量,一般设置为某较小的值,如0.01、0.001等。
根据梯度下降算法,我们需要计算出函数在每一个点上的梯度信息:
(∂ℒ/∂𝑤,∂ℒ/∂𝑏)。
我们来推导一下梯度的表达式,首先考虑∂ℒ/∂𝑤,将均方差函数展开:
经过化简后,最终有
同理可推导出
这意味着,我们只需要计算在每一个点上面的(𝑤𝑥(𝑖)+𝑏−𝑦(𝑖))∙𝑥(𝑖)和
(𝑤𝑥(𝑖)+𝑏−𝑦(𝑖))值,平均后即可得到偏导数∂ℒ/∂𝑤和∂ℒ/∂𝑏。
最后根据之前的梯度下降方法:
来实现w和b值的不断更新,最终达到优化网络参数的目的。
在python中,可以用如下代码实现直线的梯度下降法线性回归:
importnumpyasnp
importmatplotlib.pyplotasplt
defgrad_w(xi,yi,w,b):
return2*(w*xi+b-yi)*xi
defgrad_b(xi,yi,w,b):
return2*(w*xi+b-yi)
deferro_account(points,w,b):
erros=0
foriinrange(len(points)):
erros+=(1/len(points))*(w*points[i,0]+b-points[i,1])**2
returnerros
deffinal_grad_w(points,w,b):
finalGrad_w=0
foriinrange(0,len(points)):
finalGrad_w+=(grad_w(points[i,0],points[i,1],w,b)/len(points))
returnfinalGrad_w
deffinal_grad_b(points,w,b):
finalGrad_b=0
foriinrange(0,len(points)):
finalGrad_b+=(grad_b(points[i,0],points[i,1],w,b)/len(points))
returnfinalGrad_b
defmain_runner(points,initial_w,initial_b,times_of_calc,learning_rate):
w=initial_w
b=initial_b
foriinrange(times_of_calc):
w_new=w-learning_rate*final_grad_w(points,w,b)
b_new=b-learning_rate*final_grad_b(points,w,b)
w=w_new
b=b_new
print("After{0}timesofcalc,finalw={1},b={2}".
format(times_of_calc,w,b))
return[w,b]
defvisualize(points,w,b):
x=np.linspace(0,100)
y=w*x+b
plt.figure()
plt.xlabel('valueofX')
plt.ylabel('valueofY')
plt.ylim(0,150)
plt.xlim(0,100)
plt.scatter(points[:
0],points[:
1],s=20,color='blue',label='points')
plt.plot(x,y,label='Regressionline',color='red')
plt.legend()
plt.show()
if__name__=="__main__":
points=np.genfromtxt("data.csv",delimiter=",")
answer_list=[0,0]
print('theoriginalerros={0}'.format(erro_account(points,answer_list[0],answer_list[1])))
answer_list=main_runner(points,0,0,1000,0.0001)
print('erros={0}'.format(erro_account(points,answer_list[0],answer_list[1])))
visualize(points,answer_list[0],answer_list[1])
经过1000次循环(Epoch)更新后,均方差(MSE)的大小从5565.11下降到了112.61,得到的回归线也与前文中R代码的结果基本一致。
三、神经网络
1、线性模型的表达能力
线性模型是机器学习中间最简单的数学模型之一,参数量少,计算简单,但是只能表达线性关系。
即使是简单如数字图片识别任务,它也是属于图片识别的范畴,人类目前对于复杂大脑的感知和决策的研究尚处于初步探索阶段,如果只使用一个简单的线性模型去逼近复杂的人脑图片识别模型,很显然不能胜任。
而表达能力体现为逼近复杂分布的能力。
上一章中线性模型的解决方案,相当于只使用了少量神经元组成的一层网络模型,相对于人脑中千亿级别的神经元互联结构,它的表达能力明显偏弱。
为了解决线性模型表达能力不足的问题,我们可以给线性模型嵌套非线性函数,将其转换为非线性模型。
我们把这个非线性函数称为激活函数(ActivationFunction),用σ来表示:
o=𝜎(𝑾𝒙+𝒃)
这里的σ代表某个具体的非线性激活函数,如Sigma函数、ReLU函数等。
然而,对线性函数进行激活处理后,模型表达能力仍然十分羸弱,但是通过重复堆叠多次线性模型,似乎可以增强其表达能力;
3、线性模型的堆叠:
神经网络
将第一层神经元的输出值h1作为第二层神经元模型的输入,将第二层神经元的输出h2作为第三层神经元的输入,最后一层神经元的输出作为模型的输出;
从网络结构上看,函数的嵌套表现为网络层的前后相连,每堆叠一个(非)线性环节,网络层数增加一层。
我们把输入节点𝒙所在的层叫做输入层,每一个非线性模块的输出𝒉𝑖连同它的网络层参数𝑾𝑖和𝒃𝑖称为一层网络层,特别地,对于网络中间的层,叫做隐藏层,最后一层叫做输出层。
这种由大量神经元模型连接形成的网络结构称为神经网络(NeuralNetwork)。
我们可以看到,神经网络并不难理解,神经网络的每层的节点数和神经网络的层数决定了神经网络的复杂度。
4、神经网络的优化:
反向传播
考虑复合函数𝑦=𝑓(𝑢),𝑢=𝑔(𝑥),则𝑑𝑦/𝑑𝑥可由𝑑𝑦/𝑑𝑢和𝑑𝑢/𝑑𝑥推导出:
考虑多元复合函数,𝑧=𝑓(𝑥,𝑦),其中𝑥=𝑔(𝑡),𝑦=ℎ(𝑡),那么𝑑𝑧/𝑑𝑡的导数可以由𝜕𝑧/𝜕𝑥和𝜕𝑧/𝜕𝑦等推导出,具体表达为:
神经网络的损失函数ℒ来自于各个输出节点𝑜𝑘(𝐾),其中输出节点𝑜𝑘(𝐾)又与隐藏层的输出节点𝑜j(J)相关联,因此链式法则非常适合于神经网络的梯度推导。
考虑损失函数ℒ如何应用链式法则。
小结每层参数偏导数的传播规律:
输出层:
倒数第二层:
倒数第三层:
通过链式法则,我们不需要显式计算ℒ=𝑓(𝑤𝑖j(J))的具体数学表达式,直接可以将偏导数进行分解,循环迭代计算每一层每个节点的𝛿𝑘(𝐾)、𝛿j(J)、𝛿𝑖(𝐼)等值即可求得当前层的偏导数,从而得到每层权值矩阵𝑾的梯度,再通过梯度下降算法迭代优化网络参数即可。
5、代码实战:
BP神经网络
Moons数据集是一个线性不可分的数据集,每个点包含的真实标签表示其属于分类红色还是蓝色。
尝试使用BP算法搭建简易的神经网络来实现数据集分类的算法:
#fromsklearnimport*
#fromsklearn.datasetsimport*
fromsklearn.model_selectionimport*
importmatplotlib.pyplotasplt
importnumpyasnp
classLayer:
#单层网络类
def__init__(self,n_input,n_neurons,activation=None,
weights=None,bias=None):
self.weights=weightsifweightsisnotNoneelse\
np.random.randn(n_input,n_neurons)*np.sqrt(1/n_neurons)
#numpy.random中的函数,参数为生成的随机array的shape
#其中randn()生成标准正态分布
self.bias=biasifbiasisnotNoneelse\
np.random.rand(n_neurons)*0.1
#偏置,rand()生成[0,1)间的随机分布
self.activation=activation#激活函数类型
self.after_activation=None#激活函数后的输出值
self.error=None#计算当前层的delta变量用的中间变量
self.delta=None#记录当前层的delta变量,用于梯度计算
defactivate(self,x):
#向前传播算法,实现x-->o
r=np.dot(x,self.weights)+self.bias#y=X@W+by
self.after_activation=self._apply_activation(r)#y经过激活函数变为输出o
returnself.after_activation
def_apply_activation(self,r):
ifself.activationisNone:
returnr
elifself.activation=='relu':
returnnp.maximum(r,0)#把小于0的部分限位到0
elifself.activation=='tanh':
returnnp.tanh(r)
elifself.activation=='sigmoid':
return1/(1+np.exp(-r))
else:
print('unknownactivation,donothinginapplyactivation')
returnr
defapply_activation_derivative(self,r):
#计算激活函数的导数
#无激活函数,导数为1
ifself.activationisNone:
returnnp.ones_like(r)
elifself.activation=="relu":
grad=np.array(r,copy=True)
grad[r>0]=1.
grad[r<=0]=0.
returngrad
elifself.activation=="tanh":
return1-r**2
elifself.activation=='sigmoid':
returnr*(1-r)
else:
print('unknownactivation,donothinginapplyactivationderivative')
returnr
classNeuralNetwork:
#神经网络大类
def__init__(self):
self._layers=[]
defadd_layer(self,layer):
self._layers.append(layer)
deffeed_forward(self,X):
#正向传播
forlayerinself._layers:
X=layer.activate(X)
returnX
defbackpropagation(self,X,y,learning_rate):
#实现反向传播
output=self.feed_forward(X)
foriinreversed(range(len(self._layers))):
#计算每层的delta变量,有Oi*δj=W'ij
layer=self._layers[i]
iflayer==self._layers[-1]:
#当此层为输出层时
layer.error=y-output#均方差的导数
layer.delta=layer.error*\
layer.apply_activation_derivative(output)#外导数*内导数:
导数的传递
else:
#当此层为隐藏层时
next_layer=self._layers[i+1]
layer.erro=np.dot(next_layer.weights,next_layer.delta)
layer.delta=layer.erro*\
layer.apply_activation_derivative(layer.after_activation)
foriinrange(len(self._layers)):
#更新权值w
layer=self._layers[i]#o_i为前一层网络的输出
o_i=np.atleast_2d(Xifi==0elseself._layers[i-1].after_activation)
layer.weights+=layer.delta*o_i.T*learning_rate
deftrain(self,X_train,X_test,y_train,y_test,learning_rate,
max_epochs):
y_onehot=np.zeros((y_train.shape[0],2))
y_onehot[np.arange(y_train.shape[0]),y_train]=1
y_test_onehot=np.zeros((y_test.shape[0],2))
y_test_onehot[np.arange(y_test.shape[0]),y_test]=1
mses=[[],[]]
foriinrange(max_epochs):
forjinrange(len(X_train)):
#一次训练一个样本
self.backpropagation(X_train[j],y_onehot[j],learning_rate)
ifi%10==0:
mse=np.mean(np.square(y_onehot-self.feed_forward(x_train)))
print('Epoch:
%s,MSE:
%f'%(i,float(mse)))
x_pred=self.feed_forward(X_test)#十循环测试一次模型
right_num=0
forlinesinrange(len(x_pred)):
ifx_pred[lines,0]>x_pred[lines,1]:
ify_test_onehot[lines,0]==1:
right_num+=1
e