说明:本文原发于“计量经济圈”公众号,在此仅展示Stata的部分。R部分请移步至本人主页的“R语言与机器学习--经济学视角”专栏,或点击下方链接卡跳转。

盲区行者:深度学习之BP神经网络--Stata和R同步实现(附R数据和代码)​zhuanlan.zhihu.com

原公众号推文标题:深度学习之BP神经网络-Stata和R同步实现(附数据和代码)


神经网络Neural Network,或Artificial Neural Network,简称NNANN)是Deep Learning深度学习(DL属于MLML属于AI)算法的代表。和SVM支持向量机类似,神经网络属于典型的black box黑箱方法。从更广泛的角度来看,神经网络可以实现几乎所有的学习算法——既可以应用于有监督学习的分类回归,也可以用于无监督学习的聚类等。

神经网络的分类有多种,从演进的角度来看,大概包括早期的单层神经网络(也叫感知器,Perceptron)和前馈神经网络(Feedforward Neural Network,FNN),到BP(Backward Propagation,反向传播)神经网络,再到现在更为复杂的卷帙(Convolutional)循环(Recurrent)深度信念(Deep Belief)生成对抗(Generative Adversarial)神经网络等等。

早期的前馈神经网络由于过于简单,应用价值不大。随后的BP算法的提出,使得神经网络的性能得到了大幅提升。在此基础之上演化出来了多种神经网络算法,大规模应用于Computer Vision计算机视觉Speech Recognition语音识别Natural Language Processing自然语言处理,以及在线广告网页搜索商品推荐等。

总的来看,BP神经网络是神经网络的典型代表,是初学者的重点学习对象。此外,Stata中目前能实现神经网络建模的的只有BP神经网络brain命令,尚无其它神经网络算法的引进,故本文在此重点介绍BP神经网络

1 神经网络介绍

1.1 神经网络原理

BP神经网络属于监督学习,由激活函数网络结构优化算法三大部分组成。对于初学者来说,我们也可以把BP神经网络模型大概当成一个庞杂的复合函数。

BP神经网络是在前馈FNN神经网络模型的基础上改进。下面的视频截图(本文中引用的视频截图全部来自吴恩达深度学习课程)展示的是单隐藏层的神经网络,便于我们大概了解FNN的原理。这里所谓前馈,是指向前传播。信息由输入变量(inputs,自变量)开始,往前经过中间的各个隐藏层向前传导,最终到达输出节点(outputs,因变量)。

上图中以房价预测为例。假设我们先知道房子的size面积、bedroom卧室的数量、zipcode邮编和当地的wealth人均收入,打算基于这4个自变量来预测房价price。这里自变量中的sizebedroom的数量,可能会通过购买者的family size来影响房价;邮编zipcode可能通过该社区的walkability便利性来影响房价;zipcode还可能和wealth一起,通过当地的school quality影响房价。这个推导过程和计量经济学中的中介变量结构化方程SEMRCT中的因果链推导原理有类似之处。

在完成前馈(正向)传播之后,信息再由输出节点反向传播。在介绍正向和反向传播具体原理之前,我们先简单了解下常见的三种激活函数。

1.2 三种常见的激活函数

Activation Function激活函数用于“在神经网络模型中加入非线性因素,以解决线性模型所不能解决的问题”。激活函数也用于反向传递中的参数修正,所以通常要求是可微的。激活函数的形式可以由用户自行定义,而常见的主要是以下三个。

(1)ReLU修正线性单元

ReLU,全称是Rectified Linear Unit,是最基础的一种激活函数。相对于后面两种激活函数,ReLU最大的优点是斜率的稳定性。不管x的取值多大,在梯度下降法中的下降斜率都保持一个较大的值,而不像Sigmoid或Tanh函数一样可能趋近于零而导致梯度算法下降较小,最终算法学习的速度会变得很慢。 ReLU的缺点也较明显,即当自变量取值小于0的时候其函数斜率恒等于0。因此,ReLU在自变量小于0的区域的斜率被改进成为了某个较小的常数,比如0.01。这种改进后的激活函数被称为Leaky ReLU泄露ReLUReLU的函数图像大致如下(来源于百度百科):

ReLULeaky ReLU通常用于卷积神经网络和循环神经网络等。

(2)Sigmoid函数

机器学习的Sigmoid函数,又被称为Logit函数,或Logistics函数,在计量中常用于结果变量是0-1等分类变量的建模。其函数形式如下:

y= 1/(1- e^(-x) )

接下来我们用Stata画出该函数的图形,让大家有个直观的了解。

. clear
. set obs 1000000
. gen x = runiform(-20, 20)
. gen y = 1/(1+exp(-x))
. line y x, sort xline(-5) xline(0) xline(5) xlabel(-20(5)20)
*在x=-5/0/5初加了3条竖线

3)Tanh双曲正切函数

Tanh函数形式如下:

y = sinhx/coshx=((e^x-e^(-x))/((e^x+e^(-x))

Tanh函数可以看成是Sigmoid函数的改进,通常只要能用Sigmoid函数的地方,Tanh函数的表现都会更优。当然,由于Sigmoid的0-1的结果可能,让它在0-1分类的算法中无可替代。在具体操作中,涉及0-1分类的神经网络通常在输出层使用Sigmoid函数,其它层使用Tanh或其它激活函数。 在此也用Stata画出Tanh函数的图像(代码省略)如下。

1.3正向传播和反向传播

先简要说明涉及到的函数和数学符号:数学标记符号中大写表示向量,如x表示某个具体的自变量,而X表示自变量矩阵;Z=WX+b,这里Wweight权重矩阵,b表示bias偏误向量;σ()g()表示激活函数,σ(Z)=AA表示activation,输出层的A=Yhat),信息正是通过Z=WX+bσ(Z)=A逐层向后传播;L(A, Y)中的L表示loss,为成本(基于损失函数)函数,确定YYhat之间的误差。

接下来分正向传播反向传播再具体介绍BP神经网络的模型算法。

(1)正向传播

Forward Propagation,也叫正向传播。如下面两个图所示,神经网络的正向传播就是样本信息向后传递的过程。由于Z是样本特征X的函数,A是Z的函数,相当于A是X的复合函数。同时,各隐藏层拥有本层的Z和A函数,隐藏层之间通过A(可以看成是某层的预测值)进行信息传递(当成下一层的X)。从信号(原始数据)传递的角度来看,正向传播将输入信号通过隐藏层后,作用于输出节点,经过非线性变换转化

正向传递中的数学算法的通用表达如下:

下图展示了更具体的前向传递向量化算法实现过程。

(2)后向传播

Backward Propagation反向传播。一次正向传播加一次反向传播,就是一次完整的iteration迭代。经过一次正向传播后,若实际输出与真实结果差距较大,则启动误差的反向传播。

如下图所示,后向传播根据前向传播计算出来的A(激活值,A=g(Z))、真实值Y和暂存的Z(Z=Wx+b),用求导的方式求出每一层参数的梯度,以调整模型参数值,进而降低成本函数的误差(梯度下降法)。和前向传播的复合函数构造过程对应,后向传播的实现包括了复合函数从外到内的链式求(偏)导过程。

通俗来说,反向传播是将输出误差反向逐层传递,算出所有层的误差估计,即将输出误差摊分给各层所有单元,并在各层算出误差信号后对各单元的参数进行调节(误差以某种形式在各网络层进行表示)。调整正向传播中输入层和隐藏层、隐藏层和输出层对应的参数,即可推动误差随梯度方向下降。经过重复的学习,确定和最小误差所对应的参数后,学习停止。  

小结:正向传播求损失,反向传播传误差,基于误差值进行参数更新;反复迭代求出最优模型。

神经网络算法的数学推导有一定的学习门槛,对于初学者来说需要一定投入才能弄懂。吴恩达在他的深度学习系列课程中提到,神经网络的反向传递的数学推断几乎是是机器学习中最复杂的,需要用到矩阵的运算、矩阵的求导和链式求导法则等数学知识。

1.4 参数和超参数

神经网络模型的参数主要包括W权重矩阵b偏误向量,前文已提到过。除了参数,神经网络模型还包括多个超参数。超参数是决定参数大小的参数,主要包括:

  • Learning Rate α 学习率α。如下图所示,学习率可以看成是权重w下降部分(成本函数Jw的导数)的系数,其取值介于0和1之间。一个好的学习率,可以让成本函数下降更快,收敛在更低的水平。不过也要注意,成本函数的下降速度过快也可能带来问题。若学习率取得过大,算法虽然收敛更快,但更容易陷入局部最优;反之若取值较小,算法的收敛速度较慢,但可以一步步逼近全局最优。
  • Training Factor训练因子。在Stata的brain命令中叫“eta”(默认值是0.25),用来指定学习率的上限和下限。
  • 隐藏层层数,the number of hidden layer。
  • Size,某个隐藏层神经元的个数。

2 神经网络的实现

2.1 神经网络与Stata实现

目前Stata 16中用于神经网络建模的是非官方命令“brain”,由Thorsten Doherr于2018年通过SSC和Github发布。该命令基于Stata的Mata矩阵编程语言,建立backward propagation向后传播型的multi-layer多层神经网络。Backwark propagation简称BP,故该算法也被称为BP神经网络。BP神经网络最早在1986年由RumelhartMcCelland发表在Nature上的论文《Learning Representations by Back-propagating Errors》提出。

Doherr对brain命令的简介:“brain”为实现反向传播神经网络算法而设计,简洁易上手。训练后的神经网络模型可以通过.brn文件保存或调用。具体模型结果以公开且可访问的矩阵的形式展示,方便老版本Stata的读取。brain命令还附带很多函数,以便于pseudo-marginal effects伪边际效应的分析;但它的主要功能还是在于预测,即倾向得分计算或者分类。和其它机器学习算法类似,边际效应的计算,是因果推断中讨论自变量对因变量影响程度的关键。

2.2 Stata神经网络建模

第一步,数据准备。同样使用的是prestige数据,但随机切割后一般会有些许差别。

clear
. set seed 1898
. use "D:Rprestige.train.dta", clear. sum prestige
. dis r(min) //14.8
. dis (r(max)-r(min)) //72.399997
. replace prestige=(prestige-r(min))/(r(max)-r(min)) //prestige归一化
. sum prestige. sum education
. dis r(min) //6.3800001
. dis r(max)-r(min) //9.5900002
. replace education=(education-r(min))/(r(max)-r(min)) //education归一化
. sum education. sum income
. dis r(min) //918
. dis r(max)-r(min) //24961
. replace income = (income-r(min)) / (r(max) - r(min)) //income归一化
. sum income           

第二步,建立BP神经网络模型。

. clear
*定义BP神经网络模型
. brain define, input(prestige education) output(income) hidden(10 10)
Defined matrices:input[4,2]output[4,1]neuron[1,23]layer[1,4]brain[1,151] *输入变量是自变量prestige和education,输出变量是income
*hidden(10 10)表示共2个隐藏层,每个各10个神经节点。和R部分一致. brain train, iter(200) eta(0.25) nosort
*iter表示迭代的次数,在此设置200次
*eta为训练因子,默认取值为0.25,表示学习率的初始值均匀分布于[-0.25, 0.25]
*nosort表示在训练前不对数据进行排序. brain save "D:RBPNNm1.brn"  //保存训练好的BP神经网络,方便后面调用进行预测

第三步,查看已经建立好的BP神经网络模型。

. matrix layer //查看各层神经节点数量layer[1,4]in  hid1  hid2   outneurons     2    10    10     1 */. matrix list input  //查看输入变量
input[4,2]prestige  educationmin          0          0norm          1          1value          0          0
signal          0          0 */. matrix list output //查看输出变量incomemin       0norm       1value       0
signal       0 . matrix list neuron //查看神经节点
neuron[1,23]in1    in2   h1n1   h1n2   h1n3   h1n4   h1n5   h1n6   h1n7   h1n8   h1n9  h1n10   h2n1
signal      0      0      0      0      0      0      0      0      0      0      0      0      0h2n2   h2n3   h2n4   h2n5   h2n6   h2n7   h2n8   h2n9  h2n10   out1
signal      0      0      0      0      0      0      0      0      0      0 . matrix list brain //查看各节点的连接权重
*只展示部分结果
brain[1,151]h1n1w1      h1n1w2       h1n1b      h1n2w1      h1n2w2       h1n2b      h1n3w1
weight   .41241582   -.4473998    .1887836   1.0385614    .4644028  -.32226553   .71407534h1n3w2       h1n3b      h1n4w1      h1n4w2       h1n4b      h1n5w1      h1n5w2
weight   .85327234  -.18876532  -.52128979  -.39156865   -.2958014   .88854821   .79453232 

第四步,查看神经网络模型中自变量的伪边际效应

.brain margin //查看边际效应incomeprestige  0.074326136
education  0.056956779
/*结果的解读:(1)职业声望每增加一单位(从0变到1),收入增加0.0743个单位(约合1855.25美元);(2)受教育程度每增加一单位,收入增加0.0570个单位(约合1421.6982美元)。*//*                   incomeprestige  14600.733767469education  -5672.844525771 */ // 未归一化的结果。education系数居然是负的!这显然和常识不符。让我们通过画图检查下数据. twoway (line income education, sort)  (lfit income education)
*从画图结果可以看出,随着受教育程度的增加,收入整体是上升的

第五步,准备测试数据。

*数据准备
. clear
. set seed 1898
. use "D:Rprestige.test.dta", clear
. sum prestige
. dis r(min) //23.200001
. dis (r(max)-r(min)) //59.100002
. replace prestige = (prestige-r(min)) / (r(max) - r(min)) //prestige归一化处理
. sum prestige. sum education
/*Variable |        Obs        Mean    Std. Dev.       Min        Max
-------------+---------------------------------------------------------education |         28    10.67536    2.965029        6.6      15.94 */. dis r(min) //6.5999999
. dis r(max)-r(min) //9.3399997
. replace education = (education-r(min)) / (r(max) - r(min)) //education归一化处理
. sum education. sum income
. dis r(min) //611
. dis r(max)-r(min) //18652
. replace income = (income-r(min)) / (r(max) - r(min)) //income归一化处理
. sum income*导入之前训练好的神经网络
. brain load "D:RBPNNm1.brn"
Loaded matrices:input[4,2]output[4,1]neuron[1,23]layer[1,4]brain[1,151] . brain think income_hat //基于预测数据进行预测,生成income_hat变量*还原income和income_hat
. sum income income_hat
. replace income = income*18652 + 611
. replace income_hat = income_hat*18652 + 611
. sum income income_hat
/*Variable |        Obs        Mean    Std. Dev.       Min        Max
-------------+---------------------------------------------------------income |         28    6668.821     3984.65        611      19263income_hat |         28    5018.372    1651.003   3066.421   8184.359 */

第六步,评价Stata BP神经网络模型预测的表现。

. gen income_se = (income_hat - income)^2
. sum income_se
. scalar income_se_mean = r(mean)
. dis sqrt(income_se_mean)  //RMSE = 3400.3261

4.3 Stata OLS建模对比

. set seed 1898
. use "D:Rprestige.train.dta", clear
. reg income prestige education //RMSE=3054.5. use "D:Rprestige.test.dta", clear
. predict income_hat
. gen income_se = (income_hat - income)^2
. sum income_se
. scalar income_se_mean = r(mean)
. dis sqrt(income_se_mean)  //RMSE = 2855.9972

3 小结

和其它一些机器学习模型一样,寻找好的神经网络模型的过程依靠的往往是经验法则,需要经过反复的参数和超参数的调整和比较。最优超参数的选择,还可能随着应用领域、数据更新和硬件技术的升级而改变。当然,短期内的模型优化方法主要还是Cross Validation交叉验证,用现有数据重复地检验模型的性能表现。 本案例中展示的是一个较为简单的BP神经网络,主要目的是介绍相关的建模过程。在掌握了基本的建模过程后,大家可以尝试从以下几个方面建立更复杂的模型:

  • 引入更多自变量和观测值。本文附带有一个名为“house_1.05m.csv”的真实房价数据拥有13个变量和约105万个观测值,可供大家进一步练习。
  • 引入因子型(分类)变量。在引入连续变量的时候需要去量纲化(0-1或者标准化),而引入因子型变量的时候处理过程稍微更复杂,需要将分类变量转换为一系列的哑变量后纳入回归模型。该转换可以通过RSNNS包的decodeClassLabels函数实现。
  • 将隐藏层参数设置为更多的层数更多的神经元数(可能需要换一台性能更好的电脑)。在此顺便向大家展示下prestige回归案例中c(50, 50, 50, 50)的神经网络长什么样。

prestige回归案例中c(50, 50, 50, 50)的神经网络视觉化(基于R语言)

Ref

1. 陈强,《高级计量经济学》,第二版。

2. 薛震,孙玉林,《R语言统计分析与机器学习》,第一版。

3. Scott V. Burger,《基于R语言的机器学习》,第一版。

4. Robert I. Kabacoff,《R in Action》,第一版。

5. Rumelhart, D., Hinton, G. & Williams, R. Learning representations by back-propagating errors. Nature 323, 533–536 (1986). https://doi.org/10.1038/323533a0.

6. Thorsten Doherr, 2018. "BRAIN: Stata module to provide neural network," Statistical Software Components S458566, Boston College Department of Economics.

7. Thorsten Doherr, codes of Stata command “brain”, https://github.com/ThorstenDoherr/brain.

8. James McCaffrey, 2015, How To Use Resilient Back Propagation To Train Neural Networks, https://visualstudiomagazine.com/articles/2015/03/01/resilient-back-propagation.asp.

9. Riedmiller M. (1994) Rprop - Description and Implementation Details. Technical Report. University of Karlsruhe.

10. Stata中“brain”命令的帮助文件。

11. 吴恩达的深度学习系列课程,在Coursera、网易云课堂和B站均可公开访问。

12. R中mlp()、nnet()和neuralnet()等函数的帮助文件。

-------全文结束-------------------------------------------------------------------------------

bp 神经网络 优点 不足_深度学习之BP神经网络--Stata和R同步实现(附Stata数据和代码)相关推荐

  1. 神经网络的输出层有哪些_深度学习的数学-神经网络、输入层、隐藏层、输出层...

    前言 前文中了解到,神经网络由多个神经单元组成,而本篇博客将会了解到深度学习由多个神经网络组成,并且分为 输入层.隐藏层和输出层,隐藏层涉及到的知识点最多,是本文的重点 正文 阶层型的神经网络主要结构 ...

  2. 为什么深层神经网络难以训练_深度学习与统计力学(III) :神经网络的误差曲面...

    谷歌和斯坦福最新合作综述报告,发表在物理学的顶级期刊"凝聚态物理年鉴"(Annual Review of Condensed Matter Physics).作者Yasaman B ...

  3. 华南理工深度学习与神经网络期末考试_深度学习基础:单层神经网络之线性回归...

    3.1 线性回归 线性回归输出是一个连续值,因此适用于回归问题.回归问题在实际中很常见,如预测房屋价格.气温.销售额等连续值的问题.与回归问题不同,分类问题中模型的最终输出是一个离散值.我们所说的图像 ...

  4. 华南理工深度学习与神经网络期末考试_深度学习算法地图

    原创声明:本文为 SIGAI 原创文章,仅供个人学习使用,未经允许,不能用于商业目的. 其它机器学习.深度学习算法的全面系统讲解可以阅读<机器学习-原理.算法与应用>,清华大学出版社,雷明 ...

  5. 神经网络算法未来_“深度学习三巨头”来了俩,Hinton、LeCun预言深度学习的未来...

    当地时间 6 月 23 日,今年的 ACM 图灵奖得主."深度学习三巨头"中的 Geoffrey Hinton.Yann LeCun 在 ACM FCRC 2019上发表演讲,分享 ...

  6. python实现胶囊网络_深度学习精要之CapsuleNets理论与实践(附Python代码)

    摘要: 本文对胶囊网络进行了非技术性的简要概括,分析了其两个重要属性,之后针对MNIST手写体数据集上验证多层感知机.卷积神经网络以及胶囊网络的性能. 神经网络于上世纪50年代提出,直到最近十年里才得 ...

  7. 神经网络 异或_深度学习入门笔记(2)线性神经网络

    在上一篇笔记中我们一起学习了单层感知器的原理,但针对于异或问题.我们的单层神经网络就束手无策了 *异或运算: 0 0 输出为0,0 1输出为1, 1 0输出为 1, 1 1输出为 0 即,针对以下四个 ...

  8. [深度学习-实践]BP神经网络的Helloworld(手写体识别和Fashion_mnist)

    前言 原理部分请看这里 [深度学习-原理]BP神经网络 Tensorflow2 实现一个简单的识别衣服的例子 数据集Fashion_mnist, 此数据集包含10类型的衣服 ('T-shirt/top ...

  9. ann人工神经网络_深度学习-人工神经网络(ANN)

    ann人工神经网络 Building your first neural network in less than 30 lines of code. 用不到30行代码构建您的第一个神经网络. 1.W ...

最新文章

  1. 每日一皮:“快准恨”的程序员叠衣法,还不快学起来?
  2. python利器手机版-将安卓手机打造成你的python全栈开发利器
  3. python threading lock_python threading之死锁和可重入锁
  4. 带你读懂Spring Bean 的生命周期,嘿,就是玩儿~
  5. 问题反馈模板_使用此模板可获得更好,更有价值的UX反馈
  6. 信息学奥赛一本通 1110:查找特定的值 | OpenJudge NOI 1.9 01
  7. 【OpenCV】OpenCV函数精讲之 -- 离散傅里叶变换原理
  8. Windows Server Failover Cluster 使用的协议和端口
  9. antlr 可以用java写吗_java – 我们可以用ANTLR定义一个非上下文语法吗?
  10. mysql mysql_real_connect 内存泄露
  11. 使用 virt-install 创建虚拟机
  12. 基于深度学习的问答系统论文
  13. Sql Server系列:数据类型转换函数
  14. opencv 摄像机标定
  15. Redis(二)Redis客户端的使用
  16. 兜兜转转躲不命运轮回---Java基础学习笔记1
  17. e站host地址_电脑网络:ip地址详解,小学生都看的懂
  18. 【LearnOpenGL】-PBR材质
  19. VS 2013的初配置
  20. 显示器颜色偏色的排查过程(偏黄、偏红、偏蓝、偏绿等)

热门文章

  1. golang学习之旅(2)- go的数据基本数据类型及变量定义方式
  2. thinkphp如何部署到宝塔面板nginx服务器
  3. 如何在README中使用图片
  4. linux系统页面缓存,Linux缓存机制之页缓存
  5. 脚本启动显示查询频繁被服务器防御_面对CC攻击,该如何进行防御
  6. 【Go】sync.RWMutex源码分析
  7. 基于MQTT协议进行应用开发
  8. getAttribute实例例java_Java ExifInterface.getAttribute方法代码示例
  9. php mysql xa事务_XA mysql php 分布式事务
  10. 衰落信道中的平均信噪比和瞬时信噪比