大白话5分钟带你走进人工智能-第40节神经网络之调优神经网络的超参数

神经网络有着灵活性,同时也是算法的主要缺点:需要有许多超参数需要去调节。比如隐藏层及神经元个数,轮次,每一轮次给多少数据,学习率,对于神经网来说,有很多超参数可以调节。层数,每层的神经元数,在每层使用的**函数,初始化权重的逻辑,等等

你怎么知道哪种组合最适合你的任务?站在机器学习角度来说,可以去使用grid search,cross validation就是交叉熵验证加上栅格搜索,但是它在深度学习里用的并不多,它特别的费时间,它要跑很多遍。

在深度学习里就是奔着过拟合去调,调过了只是说明结果已经出现过了,就是再把它存一下就可以了。

隐藏层数的调节会带来什么样的优点和缺点?

对于许多问题,你可以一开始只设置一个隐藏层,就可以获得不错的效果,比如咱们DNN里面只设置两个隐藏层,就已经获得了不错的效果。对于复杂的问题,我们可以在隐藏层上使用足够的神经元就行了。在很长一段时间内人们满足了,而且并没有去探索更深层次的神经网络。

其实就是一开始人们就用一个隐藏层,再隐藏层上加神经元,就已经可以来解决许许多的问题了。

但是深度这些网络有更高效的参数效率,神经元个数可以指数倍减少,并且训练起来更快。

比如前面mnist里面有784个输入,经过h1一个隐藏层400个神经元,最后输出有10个神经元, input到h1之间,它的w矩阵是784*400, 313600,h1到output,需要400*10,4000个,加一起需要317600个w去算。

如果两个隐藏层,输入还是784,第一个隐藏层300,第二个隐藏层100,输出10,input到h1之间784*300=235200,h1到h2之间30000,h2到输出1000,总共266200个w。

一个隐藏层变成两个隐藏层,神经元个数不变,而w个数由317600变成266200。所以随着层数的增多,要去算的w是会变少,也就是神经元的个数,会随着神经网络的加深,神经的个数会指数倍的减少。同时还有更高的参数效率,多加一个隐藏层,相当于往前推理和演绎一步,就更加抽象了一层,得到的模型效果会更好。也就是参数少了,效果甚至会更好,每个参数具有更高的效率。

2016年获得大赛第一名的模型是152层,然后在2012年的时候,当时第一名模型叫Alexnet,只有八层,所以会发现这几年间的发展,深度学习是往深了走了,网络层次越来越多了,因为它有更高的参数效率。

它就像直接画一个森林会很慢,如果我们画了一些树枝,然后复制粘贴这些树枝,可能会成大树,然后复制粘贴大树就会成森林,这样话就很快,真实的世界,通常是这种层级的结构,所以DNN就有这种优势。

这句话想表达为什么层次的加深,w的个数变少了,模型反而更准了,因为在真实的世界中,很多情况都是这种层级的结构,只用分出来一个结构,然后把它copy复制,然后堆垒,它就变成了新的结构,然后再复制粘贴,再出现一个新的结构,它在科学界里面的一个名字叫分形理论。

什么是分形?比如雪花,天空中飘下一片雪花,放在手里,看雪花是几瓣形状,然后拿显微镜再去看,它还是几瓣的形状,再放大看里面的每一个小单元还是几瓣的形状。

大白话5分钟带你走进人工智能-第40节神经网络之调优神经网络的超参数

六层之后,发现整体没有太大的变化,这就是分形。

前面的隐藏层构建低级的结构,然后组成各种各样的形状和方向的线,中间的隐藏层组合成低级的结构,譬如方块圆形,后面隐藏层输出组成比较高级的结构。比如说面部识别的一个模型,它前面的几层是在拿到像素点,再往后会生成一些带方向的线,第二层就是从点到线,接着第三层会生成一些基础的形状,然后在基础形状中间的隐藏层,可能会生成一些高级的形状,比如说方块,比如说圆形。再往后这些圆形的方块就会组成一些更高级的结构,比如说人脸,我们要的就是最后从人脸这块去识别它是哪个人的照片,这样就构成了一个神经网络。

如果站在分形角度去说,无非就是把它每层的分形抛开看,都是一个基础的形状。

这些网络不必从原始训练低层的网络,比如一个面部识别的项目和一个识别人的发型的项目,比如训练面部识别这个模型之后,我们想用模型去识别发型,前面点成线,线成基本的形状,这些不用变,只要是图像识别的模型就一定具备着一些点成线,线成基础图形的功能,只不过在最后的时候用这些形状去判断它是某人的人脸,或者使用一些形状去判别它是一些具体的发型。

这就是为什么在踩着别人肩膀来的时候,我们只会调最后的这一层的w,前面的全部w就不调了,因为前面点成线,线成基本形状都一样。

不仅这种层级的结构帮助DNN收敛很快,同时增加了复用能力到新的数据集,例如,如果你已经训练成了一个神经网络去识别面部,你现在想训练一个新的网络识别发型,你可以复制前面的几层,就不需要去随机初始化前面的weights和biases,你直接把面部识别前面几层的weights和biases拿来就可以了,可以把第一个网络里面先从权重直接付给新的网络作为初始化值,然后去训练后面的几层。

对于很多问题来说,一个、两个隐藏层其实就够用了,比如mnist手写体的识别,使用DNN的时候,用一个隐藏层就可以达到97%的准确率,使用两个隐藏层,还是学习一样的轮次,它可以达到98%的准确率,只提升了一点点。所以对于更加复杂的问题来说,可以逐渐增加隐藏层的个数,直到对于训练集来说过拟合了,就不要再去加个隐藏了。

这里过拟合怎么来理解?用两个隐藏层的时候,准确率是98%,用一个隐藏层的时候97%,如果用四个隐藏层的时候,可能是 96%,用三个隐藏层的时候,没准又回到97%了。当隐藏层个数逐渐增加的时候,测试集的准确率反而下降了。这个时候调参应该要两个隐藏层。

非常复杂的任务,比如图像识别或者语音识别是要几十层甚至上百层,但不全是全连接,为什么?隐藏层时两层的时候,全连接w就已经三十几万了,如果都是全连接,那么w太多了,每一次迭代的时候调的w就太多了,根本计算不完,所以在这个时候就不是全连接,最大的目的,就是计算量太大,只能使用卷积。

并且它们需要大量的数据,w越多需要的数据量就越大,不过,你很少需要从头来训练,很多时候我们去下载别人的模型,来调整就可以了。

输入层和输出层神经元的个数,不需要调,根据需求确定,比如每张图像上的像素点,就知道输入层是多少个神经元,你要分多少类,那么就知道输出层是多少神经元。如果要去做关键点检测,每张图片要找出五个关键点来,那这五个关键点就是五个输入的神经元,然后输出层就知道要多少个节点。

通常做法是,每个神经元的隐藏层神经元越来越少,先是奔着过拟合去调,神经元的个数很大,比如第一个隐藏层300神经元,第二个隐藏层100神经元,现在更多的是每个神经元数量一样,比如都是150个,这样超参数需要调节就少了,正如前面寻找隐藏层数量是一样的,就奔着拟合的方式去调,找到完美的数量,其实还是需要反复去尝试,需要很多的经验。

比如说有两个隐藏层,h1是300,h2是100,调每个隐藏的节点个数得分别来调,有一个黑科技就是把两个隐藏层都是150。调一个超参就行了。

假如第一层300,第二层100,那么调成第一层200,第二层50,同样的轮次准确率还是一样的话,就没有必要去用300和100了。

简单的方式是选择比你实际需要更多的层数和神经元个数,然后使用early stopping防止过拟合,还有L1,L2正则化技术,和dropout。都是一个防止过拟合的手段。

二、DropOut技术

drop是丢弃的意思,dropout就是丢掉不要,在深度学习里面最流行的正则化技术dropout,它被证明非常的成功,即使在顶尖水准的神经网络中也可以带来1%到2%的准确率提升。顶尖水准就是state-of-the-art,获得顶尖大赛123名的。

如果你的模型的准确率达到了95%,假设咱们获得2%的准确率提升,意味着95%的准确率对应错误率是5%,获得了2%,准确率就变成了97%,错误率是3%,相当于是错误率降低了40%,2/5。比如10000个,错误率5%,500个,现在预测10000个,错误率是3%,相当于还提高了200的正确率。所以在写代码上肯定用它。

在每一次训练step中,每个神经元包括输入层的神经元,但是不包括输出层的神经元,都可以使用dropout,有一个概率被临时的丢掉,dropout是把节点丢掉,比如mnist输入层784个节点,每一个节点都对应一个不带到拓扑网络里面去的概率。意思是一张图片过来,应该有784的像素点,dropout率是0.5, 50%,意味着每个节点往后传,丢掉的概率是50%,784大概一半的信息量向下传递,另一半信息量被切掉了,丢失了。

超参数p叫做dropout rate,一般设成50%,在训练之后神经元不会再被dropout。在训练训练集里面的每张数据,会用dropout,输入层或者隐藏层节点只有一半会生效,另一把节点相当于丢掉。比如输入层784,h1是300,h2是100,输出层是10,那么输入层或者隐藏层中一半节点不工作,输入层的工作节点传到隐藏层的工作节点,可以继续往下传,而输入层的工作节点传到隐藏层的不工作节点,就停了。输入层或者隐藏层都会丢失节点。

特意提到一点是使用训练集的时候,才会让整个拓扑结构一半工作一半不工作。在测试的时候,或者去使用这个模型的时候,不管是输入层还是隐藏层,里面的每个节点全部正常工作。

dropout流程,在训练的时候,会丢弃一些神经元,比如输入神经元是2个维度,如果dropout率是0.5,在这一次训练,或者在这一次迭代里面,会随机地按照这个比率丢掉神经元,输入层有两个x,我们只要一个;下一层隐藏层有四个神经元,我们只用两个,另外两个就不用了。不一定非是两个,它会有比率。神经元个数足够多的情况下,百分之五十就是保留下一半的神经元,另外一半不用。对于输出层来说都得要,因为它的结果是同样的才能去比对,才能去算loss损失。

比如一张图片好好的传给输入层,然后0.5丢失掉,相当于图片随机有一半信息没有传进去,到隐藏层,本来只有一半的信息拿过来,隐藏层还是丢掉一半信息再往下面传,相当于到输出层这个位置,比原本没有dropout时候拿到的信息量要少,说然后算一下loss损失,然后根据loss损失再反过来调图里面实线的w参数,虚线的w就不用调了,因为正向传播没有用这些虚线。

那这个地方是只训练一次吗?一次迭代就是在一个batch里面,比如传一部分图片进来,相当于是这一次迭代里面我们只用一部分神经元,在下次迭代里面,神经元又是重新随机重新选的。

下次迭代可能就把x2去掉了,x1留下来了,那么图里面的实线和虚线跟上一次迭代就不一样。

这有什么好处呢?

举个例子,公司老板每天就干一件事情,抛硬币,这家公司有一百个员工,可以理解为神经网络里面一百个神经元、一百个节点,抛硬币决定这一天哪50个员工上班,哪50个回家放假,或许带来的公司收入更高?

这家公司如果想正常运转的话,它原本需要一百个员工,但它一半员工放假回家,另外50个员工在公司上班,如果还能保证这个公司正常运转,但这50员工如果其中有任意一个员工离职请假了,有可能公司运转不起来,老板去锻炼这帮员工,一个人可以干多件事情,那么抛硬币,今天是这50个人上班,公司可以正常运转,明天是另外50个人上班,跟昨天不一定重复的50个人,这公司还能正常运转,下一次还是抛硬币,这个公司如果还能正常运转的话,那就意味着这个公司里面缺了谁这个公司都能正常运转,只要有100员工在这个公司。

如果你不锻炼它这种能力的话,如果你的公司就是一百个员工,缺了谁都不行,万一有一个请假了,有可能公司里面的很多事都堆在这,整个流程走不下去了。如果说少一个,变成99个,公司也能正常运转,那一个人的工作量就到其它人身上去,那这公司就有更好的容错能力或弹性。

在什么时候会用这种方式?  训练的过程当中,训练中的每个节点,它其实有更多的能力,把更多事情装起来。但是我们只是锻炼它这个能力,有这能力不一定非得去用,万一有一个节点丢失了,其它人可以顶它的活,因为其它人在训练的过程当中具备了这个能力。

在使用模型的时候,在用测试集测这个模型的时候,或者在使用的时候,我们就不用dropout了,所有节点全都用。

在现实生活中有点像,就是一项工作, A同学有能力去做,B同学一样有能力做,C的同学一样有能力做,因为我们在之前用dropout训练了ABC三个节点,这三个员工有这个能力。那么真正去完成这样工作的时候,它们三个都会做这项工作,它出错的可能性较低,它不是一个人来决定的事,它是好多神经元共同来决定的。有点像投票的感觉,大家都来对这项工作来进行点评,进行指导,这项工作最后出结果效果一般还不错。

所以它实际上就会使得在训练的时候,训练每个神经元,每个节点都具备更多的能力,更多的功能,在使用的时候大家一起来完成预测,这样预测准确率在一定程度上可以变得更高。

也许员工会一人多个任务,而不是未来受限于一两个员工缺席,这个员工类比到神经元。它就不会因为一个节点出错,导致最后的预测产生很大的偏差,在一定程度上防止过拟合。因为它具备了一个容错能力,这个就叫防止了过拟合

在训练的时候,让输入层、隐藏层在每一次批次迭代的时候,都要随机按照给的概率来取每一层神经元的个数。

三、Tensorflow代码封装

怎么做这件事情?真正通过代码来实现这件事情,TensorFlow有很好的封装。

Tf.placeholder相当于是每一个输入的节点,输入层就可以开始dropout了,有dropout率,is_training是一个波尔的变量,是true还是false,dropout只有在训练的时候才用,这里是true这个函数就会工作,如果给的是false,它就不会去执行dropout,是x出去还是x。

大白话5分钟带你走进人工智能-第40节神经网络之调优神经网络的超参数

第一个隐藏层,第二个隐藏层的输出结果,也可以用dropout。输出层全连接,就不用dropout了。

真正去用dropout还是超级简单的,就是导入一下。

Keep_prob是保留下来的比例,所以1-Keep_prob是dropout rate。

如果不用封装好的dropout,应该怎么来做?比如原来的数据m行n列如图,

===拓扑图======

Keep_prob是0.66,就是三条里面保留两条,没有取到数据相当于0,或者把删掉也行。最好还是设置为0,如果不是0的话,在评估的时候,真实的y那一列是m个,如果是0,数就对不上了。

所以dropout只是把数据没有随机到的置为0,x跟w矩阵该怎么算还怎么算,最后算出的输出结果再来用dropout,然后再把一些没有随到的在置为0,再往下走。

比如原来图片里是大的2,有像素点的位置就是1,没有像素点的白色就是0,如果dropout是0.5的话,这里面有很多的像素点就不要了,传给下面信息就相当于只有这张图片的一半信息量。

比如一张图片里面是2,你直接看这张图片,能识别出来它是2。如果现在要训练你具备一个0-9数字识别的能力,给你看完整的图片2万张,各种各样的形式,最后拿一张新的图片,然后能识别出来是2,很不错。

如果给你2万张图片都是随机的抹掉了一部分,如果学这个东西也认出来,这更厉害。因为拿只有一半的信息的两万张图片,来训练你,然后未来什么未来你拿一张先图片过来,没有遮挡识别出来是2,说明在训练的时候没有问题。因为在训练的时候不单单给这个图片本身的内容,还给你图片的label标签了,这张图片只看到一半,另外一半被遮挡了,让你想另外一半是什么?一张图片没法想出来,但是让你有几十万张图片,很多图片我都给你标出来,没有遮挡的应该也能识别出来,你还具备一定的容错能力。

如果未来给你一张图片遮挡了一点,也能识别出来,这就是防止过拟合,具备一定的容错能力。

人工智能非常的拟人,举现实生活的例子,比如一张图片如图

===拓扑图======

告诉你这个图片写的是2,你会觉得很蒙逼,没有关系。我不是只给你一张图片,我给你很多张label为2的另外一张图片,等等更多label为2的不同图片。

Dropout在训练的时候用,所以刚才没有画完整的图片就是训练集,我们还得拿测试集来测试,都是完整的图片,如图,都能识别出来是2,准确率还不错,那么模型就具备一定的容错能力

因为模型在学习的时候,学习的都是一些不完整的数据,然后测试不完整,有一些遮挡,也能识别出来是2,因为你训练时见过这样的2。

Dropout在数据量大的时候用,才敢说可以丢弃一些信息量,还能学到同样的东西,可以增加它的容错能力。

讲Dropout的原因是,TensorFlow代码里面有Dropout的使用,max_steps是最大迭代次数,learning_rate是学习率,data_dir是数据所存的位置,log_dir是存日志的,Dropout是丢弃的比例。

 

大白话5分钟带你走进人工智能-第40节神经网络之调优神经网络的超参数

要看它传给谁,不是谁都会传参数的,在训练的时候才传参数,如果是true才会Dropout,keep_prob保留的比例。那在测试的时候,是1.0全部都保留下来。