深度学习入门知识
什么是神经网络
一张由神经元(函数)堆砌起来的网络,将数据输入经过神经网络后会自动得出预测结果。
目前热门的机器学习指的是神经网络学习中一种机器学习——监督学习(Supervised Learning),监督学习的神经网络有四种
- 标准的神经网络(Standard Neural Net):体现了基本的神经网络原理,如ReLU(Rectified Linear Unit 修正线性单元)
- 卷积神经网络(Convolution Neural Net):一般运用于图像数据
- 循环神经网络(Recurrent Neural Net):一般运用于一维序列数据(特别是涉及了时间的数据)
- 混合神经网络(Hybrid Neural Net):应用于更加复杂的问题,如无人驾驶
而监督学习涉及的数据有两种:
- 结构化数据(Structured Data):有明确定义的数据,一般指的是数据库数据
- 非结构化数据(Unstructured Data):没有明确定义、更加自然的数据,如图像、音频、自然语言等
显然,非结构化数据更加负责处理起来更加困难,而非结构化数据处理取得巨大进展也是近几年深度学习十分火热的原因。良好的神经网络一般要求结构化和非结构化数据都能接收并计算之。
改善神经网络的因素有二:数据规模(data scale)和计算速度,从这个角度来看近年来深度学习取得巨大进展的原因有三:
- 大数据时代的到来——人们在生活中能方便快捷地使用电子设备,产生大量的数据
- 计算能力的提升——计算机硬件持续发展,能够更加快速的计算以提高神经网络运行速度
- 算法的持续创新——深度学习的算法不断创新以提高代码运行速度来完成更大规模的神经网络
算法创新中十分具有代表性的创新是激活函数有sigmoid函数发展成ReLU函数,在使用“梯度下降算法”后学习速率有逐渐接近0改进成始终以1的速率持续学习。
神经网络基础
-
二分分类:
-
将输出只分为两种情况,如有和无、黑和白、高与低等
输出表示方法:用一个特征向量包含一个样本中的所有数据,记为n=n_x
线性回归函数:y=wT*x+b,通过对样本集合x1,x2,x3,…,xn使用最小二乘的方法而得出来得的参数w,b和x之间的线性方程。但在二分分类中,输出0<=y<=1,所以为使输出结果落在(0,1)区间类,将y输入到sigmoid(y)=(1+ez)-1函数中,得出预测值y。
sigmoid函数图像 -
损失函数:得出y之后保证误差尽量小,因此需要为y设置损失函数。一般可以通过误差平方即L(Y,Y)=(Y-Y)2来反应误差大小,但这里不适合神经网络,因此使用另一个损失函数L(Y,Y)=-[YlogY+(1-Y)log(1-Y)]来反应误差。得出单个样本的误差函数,就可以得到整个训练集的误差函数J(Y^m,Ym)=1/m*(sum(L(Y^1,Yi)))=1/m*(sum(-YlogY+(1-Y)log(1-Y)))
-
损失函数L(w,b)=-[YlogY+(1-Y)log(1-Y)]分析:
- 鉴于二分分类思想,考虑Y=1时,L=-logY,为使误差尽量小,logY尽量要大,Y尽量要大,由于预测值Ysigmoid(Y)=(1+ez)-1增大趋近于1,所以Y要趋近于1
- 鉴于二分分类思想,考虑Y=0时,L=log(1-Y),为使误差尽量小,logY尽量要小,1-Y尽量要小,Y尽量要小,由于预测值Ysigmoid(Y)=(1+ez)-1减小趋近于0,所以Y^要趋近于0
因此可以反应线性函数的损失情况要求
-
在设置了损失函数之后,可以通过损失函数得到参数w和b的最佳取值使损失降到最低。观察损失函数的图像,是一个凸函数,存在全局最小值(这里也解释了为什么不使用误差平方作为损失函数看,因为误差平方损失函数的图像存在多个全局最小值,不符合二分分类思想的要求)
-
梯度下降算法:我们需要在整个最小值处求出最佳的w和b。而求出w和b可以通过梯度下降算法:分别给w和b一个初始值w0和b0和学习速率a,根据式子w_next:=w0-a(dJ(w,b)/dw)和b_next=b0-a(dJ(w,b)/db)分别逐渐逼近最小值,当dJ(w,b)/dw和dJ(w,b)/db即J在w轴和b轴的映射曲线斜率为0时到达最小值处。(注意:计算出w_next后必须代入函数J得出新的dJ(w,b)/dw和dJ(w,b)/db才能实现下降。)
-
反向传播
-
在通过梯度下降算法得出最佳w和b即参数的时候,存在一个问题:由于函数J十分复杂,并且假设在参数规模很大(即线性回归函数为:y=w1x1+w2x2+w3x3+…+wnxn+b)的时候很难计算dJ(w1,w2,…,wn,b)/dwn(或者dJ(w1,w2,…,wn,b)/db),这时需要借助微积分的链式法则(dx/dy=(dx/dv)*(dv/dy))来解决问题。使用链式法则的过程在神经网络中被称为反向传输操作。从损失函数J的推导我们可以得到这样的流程图:z=y=w1x1+w2x2+w3x3+…+wnxn+b—>a=sigmoid(z)=(1+ez)-1—>l=-[yloga+(1-y)log(1-a)],这个过程在神经网络中被称作正向传输操作。
为了得到dJ(w1,w2,…,wn,b)/dwn,可以借助链式法则反向求出这个导数,过程如下:dJ(w1,w2,…,wn,b)/dwn=dl/dw=(dl/dz)(dz/dw)=(dl/dz)x1=(dl/da)(da/dz)x1=[-y/a+(1-y)/(1-a)][a(1-a)]*x1=(a-y)*x1.
其中对于sigmoid函数的求导需要用到倒数法则,参考链接https://www.jianshu.com/p/d4301dc529d9
- 面向数据集的算法:在清楚了单个样本的梯度下降算法后,将梯度下降算法运用到样本集合m的方法也呼之欲出:在计算出m个样本的成本函数之和后,通过反向传播计算dJ(w,b)/dw得到dw_i(i),之后求平均值dw_i,也就是dw_i=1/m*(dw_i(i));接着使用梯度下降算法w_next=w0-a*dw_i逼近最小值。
伪代码如下: //梯度下降算法运用到样本集合m求最佳w和b w=[n] dw=[n];b=0; J=infinite; do J1=J; J=0; for i=0 to m //计算本次迭代的损失函数值 a^i=sigmoid(z); J+=-[yloga+(1-y)log(1-a)];//每个样本成本函数之和 //计算本次梯度下降的dw和db dz^i=a^i-y^i; for i=0 to n dw_1+=dz^i*x1; db+=dz^i; J/=m; dw_1/=m; dw_2/=m; dw_3/=m; //计算本次梯度下降后的w和b for i=0 to m w^i=w0-a*dw_i; b=b0-a*db; while J<J1
- 面向数据集的算法:在清楚了单个样本的梯度下降算法后,将梯度下降算法运用到样本集合m的方法也呼之欲出:在计算出m个样本的成本函数之和后,通过反向传播计算dJ(w,b)/dw得到dw_i(i),之后求平均值dw_i,也就是dw_i=1/m*(dw_i(i));接着使用梯度下降算法w_next=w0-a*dw_i逼近最小值。
-
向量化
到这仍存在问题,一般训练集都很大,for循环执行会特别耗时,因此需要去掉显性的for循环。在处理循环上,深度学习一般会用向量化计算来代替显性的for循环,向量化计算就是直接在特征向量层面上进行计算,而使用的向量化计算都包含在python的内置函数库中。- 注:
- ①python中内置的numpy向量化计算函数行为叫做“广播”:当在python中用一个n_xm的向量矩阵(记为X=R^(n_xm))与一个1m的向量矩阵进行运算时,由于维度不同,python会自动将1m的向量矩阵扩展“广播”为n*m的向量矩阵以便与X进行运算。
- ②在python中,声明单个行或单个列向量矩阵最好直接表明矩阵的行和列或者在进行运算前最好确定矩阵的形状,以避免出现秩为1的向量矩阵而发生很难察觉的错误。
//声明最好直接定义矩形的行和列 a=np.random.randn((5,1)) a=np.random.randn((1,5)) //声明时只定义行或列会出现秩为1的矩阵,转置操作对秩为1的矩阵不起作用,而且秩为1的矩阵参与的运算最后结果是一个常数而非矩阵 a=np.random.randn(5) print(a.shape)//输出为(5,),一个秩为1的矩阵 print((a.T).shape)//输出仍为(5,),未转置 print(np.dot(a,a.T))//输出的将是一个常数,而非矩形 a.reshape((5,1))//可以使用reshape方法重新定义矩形形状 //在进行运算之前可以使用assert语句确定a矩阵的形状 assert(a.shape=(5,1)) //测试for执行时间和向量化计算执行时间代码清单 //代码来自于《神经网络和深度学习》--吴恩达公开课课程代码 import numpy as np a=np.random.rand(1000000) b=np.random.rand(1000000) tic=time.time() c=np.dot(a,b) toc=time.time() print(c) print("Vectorized version:"+ str(1000*(toc-tic))+"ms") c=0 tic=time.time() for i in range(1000000) c+=a[i]*b[i] toc=time.time() print(c) print("for loop:"+str(1000*(toc-tic))+"ms") //一次结果如下: 250286.989866 Vectorized version:1.50275523040771484ms 250286.989866 for loop:474.29513931274414ms
可见向量化计算相比较显性for语句执行速度能提高近300倍。
-
反向传播向量化示图:
引入向量化计算后的伪代码:W[m] X[m] Y[m] B[m] J=infinite; do J1=J; J=0; //计算本次迭代的损失函数值 Z=np.dot(W*X)+b A=sigmoid(Z) J=-[np.dot(Y*log(A))+np.dot((1-Y)*log(1-A))] //计算本次梯度下降的dw和db dZ=A-Y dW=1/m*np.dot(dZ*X) dB=1/m*np.sum(dZ) //计算本次梯度下降后的w和b for i=0 to m w^i=w0-a*dw_i; b=b0-a*db; while J<J1
浅层神经网络基础
神经网络可分为三类层:输入层+隐藏层+输出层,在神经网络中,前一层的输出会成为下一层的输入
-
输入层即是数据输入的一类层,一个神经网络必须要有一个输入层
-
输出层即是输出预测结果的一类层,一个可用的神经网络必须要有一个输出层
-
隐藏层是中间实现深度学习算法的一类层,一个神经网络可有多个隐藏层,每一层隐藏层可有一个到若干个的神经元
-
样本向量化:
如图所示,每层都会包含了参数(Z,W,B,a),因此需要区分开来,在每个参数右上角标记[n]表示该参数所在层号。
如上图所示,第一层中有多个神经元,而权重也不只一个,因此向量化过程中需要使用矩阵来保存参数
假设输入神经元共有四个,而输入权重共有3个,则根据矩阵乘法,该层Z=WX+B为(4,3)(3,1)+(4,1)=(4,1)矩阵,而a=g(Z),因此a也为(4,1)矩阵;
如上图所示,当m个样本同时输入时,则输入矩阵为(3,m),因此第一层Z=WX+B为(4,3)(3,m)+(4,m)=(4,m)矩阵,而a=g(Z),因此a也为(4,m)矩阵; -
激活函数:解决线性不可分的问题(在一个三角形和圆点分界为不规则曲线的平面里,找不到一条直线可以把图中的三角形和圆点完全分开),参考链接:https://blog.csdn.net/program_developer/article/details/78704224;而在训练神经网络反向传播的时候,需要对权重W进行更新,更新时用到激活函数的导数。参考链接:https://blog.csdn.net/program_developer/article/details/78977798
- 四种激活函数:
-
sigmoid函数及其导数:使用于二分类
-
tanh函数及其导数:sigmoid函数的变形函数,适合平均值为0的情况
-
ReLU函数及其导数:最常用的函数,适合大于零的情况
-
Leaky ReLU函数及其导数:ReLU的变形函数
-
- 四种激活函数:
-
多层神经元反向传播过程:
-
多层神经元反向传播结果:
注意:在反向传播过程中应验证各变量矩阵的维度,以尽可能的减少错误。
- 参数初始化:在学习时每一层W参数不应该全为零,因为这样会导致同一层内各个神经元计算出来的a是一样的,接着会导致反向传播计算出来的dZ结果也是一样的,最后dW也一样,W矩阵的每一行都一样。
解决方法:随机参数,但需要设置随机参数系数使其足够小,否则会导致激活函数结果过大以致斜率接近零,学习速度极慢。
深层神经网络基础
深层神经网络的隐藏层层数更多,计算更加复杂,但过程还是逃不过前向传播、反向传播以实现梯度下降算法的原理。
- 为什么要使用深度神经网络?
原因有两个:-
I.现实中的问题十分复杂,有很多影响因素,如果使用神经网络来解决这些问题,就需要进行分解剖析,而分解剖析的结果往往是具有多层的,因此我们需要使用隐藏层数更多的神经网络。
图像识别需要一层层去识别关键像素并最后组合成一张结果图像
语音识别需要一层层去识别声音的关键属性 -
II.使用一层或者浅层神经网络或许可以解决问题,但会导致很多影响因素集中在同一层中,逻辑关系错综复杂,最后导致计算难度极大;而多层神经网络将问题剖析成多层,尽可能简化各个影响因素之间的逻辑关系,降低计算难度。
异或二叉树算法比一层异或算法的逻辑更加清晰,计算难度更小 -
超参数:控制实际参数的参数,如样本数量、隐藏层层数、激活函数以及学习率a等
-
参数:W和b等实际参数
-
深度神经网络前向、反向传播向量化
-
维度规律
-
神经网络中的默认记号
- (x,y)表示一个单独的样本,x表示输入,y表示输出
- M=M_train表示训练集,M_test表示测试集
- 一个样本数量为m的训练集M可以表示为{(x(1),y(1)),(x(2),y(2)),(x(3),y(3))…(x(m),y(m))},
- 该训练集中的总输入用一个n_xm的特征向量矩阵表示,记为X=R(n_x*m),总输出用一个1*m的特征向量矩阵表示,记为Y=(R(1m))
- dvar表示dJ/dvar,var指的是某一个参数