二值化神经网络(BNN)总述 - 知乎
二值化神经网络(BNN)总述 - 知乎切换形式写文章登录/注册二值化神经网络(BNN)总述Ironboy学了忘,忘了学,忘了还得学英文原文 : Simons T, Lee D J. A review of binarized neural networks[J]. Electronics, 2019, 8(6): 661.下载链接:注:本文首要是对上述英文总述论文的部分中文翻译和一些对BNN的个人了解,这篇总述的宣布日期是2019年6月份,个人感觉这篇总述写的很好,言语简练,内容详实。后续2020年3月北航宣布了一篇更新的二值化总述,但因为现已有人翻译过了,所以不再重复造轮子,原文链接贴在下面,中文翻译知乎随意一搜就能找到。闲扯淡自负四结业进入课题组以来,在模型紧缩与优化加快范畴的学习也有一年多了。曩昔的一年尽管首要是做的模型8-bit量化方面的工程实践(给硬件组当狗),可是一同也看了许多论文,陆陆续续也对整个范畴其他方面如剪枝,常识蒸馏,矩阵低秩分化等,和一些根本的轻量级网络如SqueezeNet, ShuffleNet系列,MobileNet系列,EfficientNet系列的结构规划有了必定的了解。其间,二值化神经网络(BNN)尤为引起我的爱好,因为它有着最为极点的紧缩率和极低的核算量。尽管BNN仍受限于杂乱数据集/使命上很不抱负的准确率和对特定硬件架构或软件结构的依靠,而模型紧缩范畴真实能运用于实处且算得上通用的技能依然限于通道剪枝,8bit量化和轻量级网络规划(假如能够归类为模型紧缩范畴的话),可是我依然以为BNN是模型紧缩范畴皇冠上的明珠,因为大道至简。开端正文二值化神经网络(BNN)指的是仅运用+1和-1两个值来表明weights和activations的神经网络,比较于全精度的神经网络,它能够用XNOR+popcount这样极简略的组合替代float32的乘累加来完成卷积操作,然后节约了许多的内存和核算,大大方便了模型在资源受限设备上的布置。但一同,因为二值所能表达的信息量有限,所以BNN在模型精度方面一向都是远低于全精度模型,尽管最近的研讨如MeliusNet,IRNet和ReActNet现已努力地将BNNs在ImageNet数据集上的Top-1拉到了0.70以上,与相应的全精度模型间隔拉到3个点左右,但他们一同也添加了不少核算量,而且暂时还难以有用地推行到方针检测,语义切割等杂乱使命上,所以BNN的晋级打怪之路依然道阻且长。现在有关BNN的研讨从大的方面来说便是两个:怎么提高BNN的精度和怎么有用地布置在低功耗且资源受限的平台上。 本篇总述首要从以下几个方面进行的论述: 二值化神经网络的根本介绍; 二值化神经网络的首要开展; 提高二值化神经网络精度和推理速度的技巧; 二值化神经网络在不同数据集上的精度体现; 二值化神经网络的硬件完成; 特意阐明,因为本篇总述是2019年6月宣布的,所以这个时刻点之后的相关论文的奉献并没有被总结在内,而我发现这段时刻呈现了不少优异的论文,如Bi-real Net, MeliusNet,IRNet, ReActNet等等,他们提出了许多奇妙的技能来处理现在二值化神经网络中存在的问题,所以我会将自己对这些论文的一些总结穿插在接下来的论述中,其间必然有一些了解不正确的当地,希望能够指出,咱们共同前进!根本介绍二值化神经网络的idea开端源于2016年深度学习三巨子之一Yoshua Bengio的论文《BinaryNet: Training Deep Neural Networks with Weights and Activations Constrained to +1 or -1.》,它初次提出一种办法,能够用随机梯度下降的办法练习一同运用二值化的weights和activations的神经网络。为了处理二值化weights中梯度的传递问题,作者提出在练习进程中坚持一个实值(float32)的weights,然后运用信号函数sign来取得二值化的weightsW_B = \rm{sign}(W_R) 而且针对sign函数在0处不行导,其他当地导数为0无法有用进行梯度传递的问题,规划了直通估量器STE (straight through estimator),即当梯度传递遇到sign函数时,直接越过这个函数,或许说默许sign函数输出对输入的梯度为1,即:\frac{\partial L}{\partial W_R} = \frac{\partial L}{\partial W_B} 前向和反向核算的流程如下图所示STE的可视化 运用了STE之后,实值的weights就能够运用如SGD和Adam这样常见的优化器来进行更新了,一同考虑到这个实值weights是没有设置鸿沟的,这样它就有或许会一向累加到特别大的值,然后与二值化的weights之间的量化差错越来越大,根深蒂固,所以作者对实值的weights还独自加了一个切断函数clip(x,-1,1),将其束缚在-1和+1之间,这样使得实值weights和二值化weights的间隔更近。关于activations的二值化和weights是类似的,而且在试验中作者发现,当sign函数的输入的绝对值大于1的时分,将梯度置0能够得到更好的试验成果,即:\frac{\partial L}{\partial a_R} = \frac{\partial L}{\partial a_B}*1_{|a_R|\leq1} 简略总结一下,咱们能够看到作者在练习进程中对weights和activations做了不同的设置,两个在梯度更新上都是遵循STE的准则,直接将sign函数越过,而实值weights在更新之后会裁剪到[-1,1]之间,然后减小实值weights和二值化weights之间的间隔,而activations的梯度在更新的时分,当实值activations的绝对值大于1时会将梯度置0,防止特别大的梯度向下传递使得练习时分呈现震动。 花这么大的力气来练习这个BNN,可是最终试验成果看起来与全精度比较也没有什么任何优势,必定是这个模型存在什么惊喜?我来翻译翻译,作者规划BNN的初衷仍是为了加快模型的前向推理,这儿边最大的劳绩便是用1bit数的XNOR和popcount替代了传统卷积的float32乘累加操作,用脚想也能了解这个在理论上不只能削减32倍的参数存储,还能跑的比曹操快。尽管在BNN各个数据集上的试验都是强差人意,但快不快就完事了。一同也有些亟待结业的博士研讨发现BNN在对立进犯方面有很强的鲁棒性,除了快,还稳,好家伙,直呼BNN牛逼。XNOR核算首要开展Yoshua Bengio作为BNN的开山祖师,不只给许多人指明晰山的方向 —— 更快更准更泛化,还在一路上留下了数不清的果实让后来者去逐渐摘 —— STE的优化,二值友爱结构的规划,更详尽的training tricks......,所以这个范畴开端了轰轰烈烈的刷榜比赛,以下将介绍一些在BNN开展道路上带来立异的模型,其间总述中谈到的DeReFa-Net,个人以为它首要是为低比特量化及练习规划的,将乘法用多个bitwise+shift的操作替代,梯度也能够用低比特数来表明,但假如把它的W/A的位宽设置为1/1,并没有看出许多结构上的立异,故在此处不论述。XNOR-Net 在第一篇BNN宣布不久,XNOR-Net横空出世,这篇论文其实提出了两个模型,一个是BWN(Binary Weight Networks),另一个才是XNOR-Net,BWN只运用了二值化的weights,而activation依然采纳的float32全精度,依照BNN的界说其实BWN不能算在二值化网络的范畴,但它的作用那是杠杠的,跟全精度相差不大,看来神经网络对weights的二值化还挺不灵敏的。而该文的主角XNOR-Net是正儿八经不掺水的二值化神经网络,weights和activations都采纳的二值化。它首要是在原始BNN基础上考虑了量化差错,而且提出了对实值weights每个输出通道方向上提取出一个scaling factor,用于康复二值化weights的信息,一同对activation在HW方向上每个pixel上提取一个scaling factor,用于康复二值化activations的信息,这两种scaling factor都无需学习,直接核算相应的L-1范数就能得到,且不影响二值化高效的卷积核算进程。最终的试验也比原始的BNN要好不少,而且初次展现了BNN在ImageNet这种大型数据集上的试验成果,还宣称在卷积核算上能够到达58倍的加快作用,节约32倍的内存。XNOR-Net 本文是BNN范畴一个十分重要的作业,用scaling factor康复量化差错来提高精度的思维一向被沿用至今,在各个论文中都能看到。但一同该文也有一些诟病的当地,如核算成果无法复现(我翻译的这篇英文总述说的,不是我说的),没有真实布置在硬件上实测加快作用,仅仅论述了一个理论值,究竟在前向推理进程中每层activation在HW方向每个pixel上核算scaling factor的操作是十分耗时的。ABC-Net 这是大疆立异被NIPS2017录入的论文,论文中首要针对二值化数据表达信息太弱的问题,提出运用多个二值化weights和activations线性加权求和的办法来近似表明全精度的weights和activations,如下面的公式所示。为了得到不同的二值化的bases,作者经过在sign函数中参加变量u,结合weights的均值和方差,经过改动u的值就能够取得不同的二值化tensor。而关于activations来说,运用相同的二值化操作会和XNOR-Net相同在前向推理进程中为了核算均值方差添加许多核算,所以这儿挑选在sign函数中运用N个可学习的变量u来进行二值化。其实能够看出,这篇论文的思维和DoReFa-Net仍是挺类似的,只不过DoReFa-Net是低比特量化,而ABC-Net运用的更奇妙一些,实质仍是BNN,但咱们一眼也能看出,这个ABC-Net比之前的BNN在核算量上添加了许多,适当所以用时刻和空间交换精度。论文说用5个bases能够到达十分好的试验作用,但实践上耗费的资源比W/A=2/2还多了。W \approx \alpha_1B_1+\alpha_2B_2+...+\alpha_MB_M\\ R \approx \beta_1A_1+\beta_2A_2+...+\beta_NA_N \\ \rm{Conv}(W,R) \approx Conv(\sum_{m=1}^M \alpha_mB_m, \sum_{n=1}^N \beta_nA_n)=\sum_{m=1}^M\sum_{n=1}^N \rm{Conv} (B_m, A_n)MeliusNet这是一篇BNN结构规划的论文,作者从两大经典的网络结构ResNet和DenseNet取得启示,针对在此之前的二值化feature map信息表达很弱的问题提出了两个概念:Quality(质量)和Capacity(数量),即ResNet的shortcut能够增强了每个通道的feature map的信息表达,DenseNet中的concat能够添加feature map的通道数,然后增强全体的信息表达。其实这两个主意在前作Bi-real Net和BinaryDenseNet中也别离说到了,原本计划独自讲这两篇,可是考虑到和MeliusNet思维的重合,就只独自把这一篇拎出来讲一下,但实践上述两篇论文的BNN结构上个人觉得愈加的简练,有爱好的能够下下来看一下。 论题转回来,MeliusNet依据用shotcut和concat增强Quality和Capacity的指导思维规划了两个二值友爱的模块,如下图所示,一个是Dense Block,另一个是Improvement Block,这两个模块在网络中每次都是交织呈现,在整个信息流中不断地增强二值化feature map的信息表达,然后提高精度。这篇论文除了这个中心思维之外,还提出了一个我觉得比较有意思的思路,那便是二值化网络应该有一套自己的网络结构,这种二值化友爱结构的作用要优于类似FLOPs下全精度模型二值化后的结构,而且做了相应的试验进行验证,浅显地来讲便是倡议咱们要走二值化特征社会主义道路。IR-Net这是一篇很有意思,我十分喜爱的一篇论文,它的作者便是最开端我说到另一篇总述的作者,2020年上半年也有机会在商汤的泰坦公开课中聆听了主创们对这篇论文的解读。这篇论文首要针对的是二值化在前向核算和反向梯度传达中带来的信息丢掉问题,作者别离提出了两个技能,一个是 Libra-PB(Libra Parameter Binarization),用于在前向核算中一同最小化weights的量化丢掉和信息熵丢掉,另一个是EDE(Error Decay Estimator),经过渐进近似sign函数来最小化反向传达进程中梯度的信息丢掉。 Libra-PB简略来说便是在weights被二值化之前,先对它做归一化处理,即减均值除方差,这样的话在二值化之前,就大概有一半的weights是大于0,一半的weights小于0,然后使得二值化之后的weights信息熵丢掉最小。
(二维码主动识别)而EDE则是运用k×tanh(t×x)在不同练习阶段渐进近似sign函数,并用其梯度来替代sign函数的梯度进行反向传达,然后使得整个练习进程能够愈加的滑润,然后削减信息丢掉。EDE之所以喜爱这篇论文,是因为它提出的两个技能十分的简练有用,一会儿就能让人了解,一点都不花里胡哨,然后得到的成果也十分的好。ReActNet这篇论文的一座和Bi-Real Net是同一个人——刘泽春,作者之前还在知乎上和另一个未经作者答应就直接宣布了Bi-Real Net V2的研讨人员产生了争辩,快来一同吃瓜呀! 而且从这个争辩中才了解到ReActNet这篇论文,所以急忙去下载下来,焚香沐浴,细心拜读了大佬的著作。这篇论文是连续Bi-Real Net的一篇二值化神经网络研讨的作业,作者首要运用Bi-Real Net的思路,即在原始网络中添加shortcut层来改造了MobileNetV1,然后经过许多的试验发现BNN的功能对activations的散布改变特别灵敏,即对Activations进行平移/缩放对BNN的功能影响很明显,那么作者考虑的是必定每一层的Activations都各自有一个最适合的偏移值和缩放值使得整个模型的功能最优,所以作者提出了对sign函数和PReLU函数进行改造,参加可学习的参数变量,让模型主动去学每一层最佳的偏移值和缩放值,命名为ReAct-Sign(简称RSign)和ReAct-PReLU(简称RPReLU),别的需求阐明的是这些参数都是channel-wise的,核算量其实仍是有些的哈,可是因为选的模型是MobileNetV1,参数量较小,所以比较其他的BNN模型在整个核算量上仍是少了许多,且精度还高了不少。 别的依据之前的观测成果,作者将最终一层输出经过softmax的成果与label的cross entropy 换成了与全精度模型的最终一层输出经过softmax的cross entropy,以此来学习全精度模型最终一层输出的数据散布,称之为distributional loss,有常识蒸馏那味了,而且作者着重比较于之前一些论文将二值化模型每一层输出都与全精度模型对应层输出进行匹配的做法,这个distributional loss愈加简练,且作用非也很好。以上便是个人结合本篇英文总述和自己看过的一些论文总结的二值化神经网络开展史上一些重要开展的论文。因为自己水平有限,必然不行完好,如有遗失请多多见谅!提高功能的技能总结现在来总结一下自开端的BNNs论文出来之后,为了提高功能用到的技能总结:Gain term 增益项这个首要指的是一些为了削减数据二值化丢掉而添加的一些额定的项,如XNOR-Net初次提出的在weights二值化之前核算一个channel-wise的scaling factors(一般是每个通道权重的均值)用于康复量化丢掉,这个思维被沿用至今简略有用。 还有各种在activations上添加的可学习的参数,如ReActNet说到的RSign和RPReLU,这些增益项尽管添加一点点的核算,但对模型精度却有大幅度的提高。别的要阐明的XNOR-Net里边对activations在HW方向上每个pixel核算一个scale,这个尽管能够削减二值化的信息丢掉,可是在前向进程中对推理速度的影响很严重,所以暂不列入其间,这也阐明晰一点,weights上的增益项无论是可学习的仍是在线核算的都不会对推理速度有较大影响,因为练习完毕之后能够得到固定的系数。而activations的增益项最好是用可学习的,因为在前向推理进程中,每次输入数据不同,在线核算的增益项都需求从头核算,这个对推理速度影响很大。2. 多个二值化base这个特指ABC-Net的做法,用多个二值化的base线性加权近似全精度的weights和activations,功能不错,典型的以时刻和空间交换精度的做法。3. 二值友爱的结构规划Bi-Real Net,BinaryDenseNet和MeliusNet三篇论文验证了在BNNs网络结构中参加shortcut和concat操作能够大大增强模型的Quality和Capacity,然后大大提高功能。4. 要害层的规划神经网络中要害层一般指的第一层,下采样层和最终一层,这些层相关于其他一般层对模型功能影响更大,所以需求额定留意。第一层第一层的输入是原始数据,且卷积核的参数量较少,假如第一层呈现了巨大的信息丢掉,那么后面层根本上也学不到啥了,原始BNN论文没有对输入直接二值化,因为输入的图画数据是UINT8类型,规模[0,255],二值化根本都是1了,信息丢掉殆尽,所以作者直接输入原始的数据与二值weights进行卷积核算。为了提高核算功率,作者将输入按比特位切片出来,用移位和XNOR替代乘法,如下图所示。 但这个做法不太稳当的是,输入数据尽管没有丢掉信息,可是没有做数据的归一化。在干流的模型练习中咱们能够知道,数据的normalize对成果影响还蛮大的,所以现在干流的BNNs根本上第一层都是运用全精度的卷积层,输入数据正常归一化处理后输入网络,因为一般以为这块核算量不大。可是MeliusNet在试验中发现现在许多BNNs核算中,浮点核算占了60%以上,第一层许多人运用的7×7的卷积核,核算量仍是蛮大的,所以MeliusNet用三个3×3的卷积进行了替代,节约了一半的核算。输入数据需求做normalize和二值化结构真的就无缘了吗?在FBNA论文中咱们发现,能够运用如下技巧,输入数据正常归一化之后,缩放到[-128,128]的规模并取整,然后每个pixel的值用一个长度为256的一维二值化向量表明,两者联系是这个二值化向量累加求和之后的成果除以2等于这个整数值,如下所示:下图中(a,b,c)以2Bit的数据为例再次展现了上述分化进程。输入数据假定为CIFAR10,分辨率是(32,32,3),那么经过分化之后就会变成(32,32,256,3),这个时分咱们会发现输入数据巨大无比,第一层核算量指数级添加,所以作者将原图画8bit数据的高位截掉,在分化向量中的体现便是直接去掉右侧的正负1的数,如下图所示,咱们能够发现pruning之后的图画其实依然保存了大多数的信息,且能够大大下降核算量,整个进程如下图(d)所示。FBNA下采样层下采样层的特点是图画分辨率会直接削减一半,这个进程是一个不行逆的信息丢掉的进程。前期的BNNs都倾向于运用MaxPooling来进行下采样操作,可是存在一个问题是,假如在每一层activations二值化之后进行MaxPooling,会导致梯度反传到这块的时分将梯度均匀的分给多个+1或许多个-1,可是实践上只要real-value最大的那个值真实起了作用,这样的分配是不公平的,所以比较好的做法是遇到MaxPooling操作的时分,将activations的二值化拖延,对实值的weights进行下采样,这样能够得到更好的作用。但现在的网络规划人员一般以为MaxPooling是不行学习的算子,倾向于运用stride=2的卷积层来进行下采样,这样能够保存更多的信息,所以在现在的BNNs傍边,这块一般也是运用全精度的卷积来核算,防止形成较大精度丢掉,一同能够运用组卷积+channel shuffle的办法来进一步下降浮点的核算量。输出层这一层在分类使命中一般是全衔接的结构,输出最终的猜测成果,为了防止二值化的影响,一般也是采纳全精度的核算,原本想提一下许多人对FC做的random pruning能下降核算,但又细心想了想,这中恣意剪枝办法在硬件上完成尤为费事,估量很难加快。5. 渐进式地学习如IR-Net中的EDE,用其他可微的函数来替代sign函数,而且在练习进程中不断地迫临真实的sign,使得整个练习进程梯度传递愈加的滑润。还有一些论文在练习的时分渐进地对weights和activations进行二值化,依据一些准则,一开端的时分二值化部分数据,然后在练习进程中逐渐增大二值化的份额,最终将整个模型二值化,这个进程也是相对滑润的,比直接二值化更有用,这让我想起了老本行模型量化中的INQ。6. padding战略在实值卷积神经网络中,咱们一般在输入四周padding的0,可是在BNN傍边并没有0这种数的存在,所以咱们大多数挑选全-1或许全+1。有研讨者发现这种padding战略对成果是有影响的,究竟使得整个输入数据朝着1或许-1产生了偏移,上述的ReActNet也说过activations的产生偏移对成果影响仍是很明显的,所以有人提出了Odd-Even padding的办法,即奇偶填充,1和-1间隔填充,如下图所示,而且发现这种填充办法能够到达填充0的作用。7. 其他练习技巧运用全精度模型在数据集上练习好的参数作为对应BNN的初始化参数;Batch Normlization 和输入数据的normalize是必要操作;丢掉函数添加正则项,如下图中的L-1 norm和L-2 norm,将α设为1,能够使得weights在练习进程中绝对值愈加趋近于1,有利于削减量化差错;运用较小的学习率,然后累计梯度,间隔更新的办法;8. 前向加快用INT4/INT8/FP16的卷积替代全精度卷积核算的部分;将Batch Normalization和sign函数兼并起来,将浮点核算变成符号判别和数值巨细比较;不同数据集上的精度体现因为BNN的模型实在是太多,而每一篇论文的试验成果也十分丰富,故我从两篇总述中截取出CIFAR10,ImageNet,PASCAL VOC2007和MS COCO2017最好的一些成果,如下所示:(留意:其间MS COCO2017的成果我好像没有在论文原文中找到依据,所以咱们就图个乐,不要较真)硬件完成因为我不是搞硬件的,所以这块只能简述一下。因为BNN的首要加快原因便是用XNOR+bitcount操作来替代了传统卷积中贵重的乘累加操作,而咱们运用的x86核算架构根本上都是对float32类型数据的核算做了很大程度的优化,所以直接将BNN布置在现有的x86核算平台上是很吃亏的,有或许不只没有加快作用,乃至比平等的全精度模型跑的还慢。在我的调研中,硬件布置完成有如下两种办法:ARM CPU,能够布置在手机端BMXNet结构,来自于德国的Hasso Plattner Institute,MeliusNet的作者,支撑ios和Android的布置;daBNN结构,来自京东AI研讨院,现在仅支撑Android手机上的布置;2. FPGA和ASIC比较于传统的CPU,FPGA在硬件架构规划方面很灵敏,能够支撑bitswise的高效运算,而且功耗很低,其对应的终极版的专用集成电路ASIC更是如此,能够比FPGA运算更高效,更节能。现在用FPGA规划AI加快器根本都是以Xilinx的器材和开发东西为主,而他们也为二值化神经网络专门规划了一款架构FINN,开发者能够运用高层次归纳东西(HLS),用C言语进行开发,直接将二值化模型布置到FPGA上,下图是一些比照成果。而Intel的Accelerator Architecture Lab也为BNN规划了一款layer accelerator的ASIC,不过并没有找到许多的相关数据,就不赘述。最终的总结二值化神经网络BNN因为能够完成极高的紧缩比和加快作用,所以它是推进以深度神经网络为代表的人工智能模型在资源受限和功耗受限的移动端设备,嵌入式设备上落地运用的一门十分有潜力的技能。尽管现在的BNN依然存在着许多缺乏,如模型精度依然比全精度低了不少,无法有用地泛化到更杂乱的使命上,依靠于特定的硬件架构和软件结构......,但咱们一同也能看到BNN从开端的2015年ImageNet上只要27%的Top-1准确率开展到2020年ReActNet-C的71.4%的前进,这五年时刻许多研讨人员在这条道路上不断推进着BNN朝着更准更快更稳的方向开展,所以咱们有理由信任,BNN未来可期!修改于 2020-11-01 19:01深度学习(Deep Learning)紧缩量化附和 1869 条谈论共享喜爱保藏请求
贝叶斯神经网络BNN(推导+代码完成) - 知乎
贝叶斯神经网络BNN(推导+代码完成) - 知乎首发于常见机器学习算法介绍切换形式写文章登录/注册贝叶斯神经网络BNN(推导+代码完成)来咯兔子1. 简介贝叶斯神经网络不同于一般的神经网络,其权重参数是随机变量,而非确认的值。如下图所示:也便是说,和传统的神经网络用穿插熵,mse等丢掉函数去拟合标签值相反,贝叶斯神经网络拟合后验散布。这样做的优点,便是下降过拟合。2. BNN模型BNN 不同于 DNN,能够对猜测散布进行学习,不只能够给出猜测值,而且能够给出猜测的不确认性。这关于许多问题来说十分要害,比方:机器学习中闻名的 Exploration & Exploitation (EE)的问题,在强化学习问题中,agent 是需求运用现有常识来做决议计划仍是测验一些不知道的东西;试验规划问题中,用贝叶斯优化来调超参数,挑选下一个点是依据当时模型的最优值仍是运用探究一些不确认性较高的空间。比方:反常样本检测,对立样本检测等使命,因为 BNN 具有不确认性量化才能,所以具有十分强的鲁棒性。概率建模: 在这儿,挑选似然散布的共轭散布,这样后验能够剖析核算。 比方,beta散布的先验和伯努利散布的似然,会得到遵守beta散布的后验。 因为共轭散布,需求对先验散布进行束缚。因而,咱们测验运用选用和变分揣度来近似后验散布。神经网络: 运用全衔接网络来拟合数据,适当于运用多个全衔接网络。 可是神经网络简略过拟合,泛化性差;而且对猜测的成果无法给出置信度。BNN: 把概率建模和神经网络结合起来,并能够给出猜测成果的置信度。先验用来描绘要害参数,并作为神经网络的输入。神经网络的输出用来描绘特定的概率散布的似然。经过采样或许变分揣度来核算后验散布。 一同,和神经网络不同,权重 W 不再是一个确认的值,而是一个概率散布。BNN建模如下:假定 NN 的网络参数为 W,p(W) 是参数的先验散布,给定观测数据 D={X,Y},这儿 X 是输入数据,Y 是标签数据。BNN 希望给出以下的散布:也便是咱们猜测值为:P\left(Y^{\star} | X^{\star}, D\right)=\int P\left(Y^{\star} | X^{\star}, W\right) P(W | D) d W (1) \\因为,W是随机变量,因而,咱们的猜测值也是个随机变量。其间:P(W | D)=\frac{P(W) P(D | W)}{P(D)} (2) \\这儿 P(W|D) 是后验散布,P(D|W) 是似然函数,P(D) 是边际似然。从公式(1)中能够看出,用 BNN 对数据进行概率建模并猜测的中心在于做高效近似后验揣度,而 变分揣度 VI 或许采样是一个十分适宜的办法。假如采样的话: 咱们经过采样后验散布P(W \vert \mathcal{D}) 来评价 P(W \vert \mathcal{D}) , 每个样本核算 f(X \vert w), 其间 f 是咱们的神经网络。正是咱们的输出是一个散布,而不是一个值,咱们能够估量咱们猜测的不确认度。3. 依据变分揣度的BNN练习假如直接采样后验概率 p(W|D) 来评价 p(Y|X, D)的话,存在后验散布多维的问题,而变分揣度的思维是运用简略散布去近似后验散布。表明\theta = (\mu, \sigma), 每个权重 w_i 从正态散布(\mu_i, \sigma_i) 中采样。希望 q(w \vert \theta) 和 P(w \vert \mathcal{D}) 附近,并运用 KL 散度来衡量这两个散布的间隔。 也便是优化:\theta^* = \underset{\theta}{\mathrm{argmin}} \text{ KL}\left[q(w \vert \theta) \vert \vert P(w \vert \mathcal{D})\right] \; (3) \\进一步推导:\begin{array}{l} \theta^* &= \underset{\theta}{\mathrm{argmin}} \text{ KL}\left[q(w \vert \theta) \vert \vert P(w \vert \mathcal{D})\right] & \\\\ &= \underset{\theta}{\mathrm{argmin}} \text{ }\mathbb{E}_{q(w \vert \theta)}\left[ \log\left[\frac{ q(w \vert \theta) }{P( w \vert \mathcal{D})}\right]\right] & \text{(definition of KL divegence)} \\\\ &= \underset{\theta}{\mathrm{argmin}} \text{ }\mathbb{E}_{q(w \vert \theta)}\left[ \log\left[\frac{ q(w \vert \theta)P(\mathcal{D}) }{P( \mathcal{D} \vert w)P(w)}\right]\right] & \text{(Bayes Theorem)} \\\\ &= \underset{\theta}{\mathrm{argmin}} \text{ }\mathbb{E}_{q(w \vert \theta)}\left[ \log\left[\frac{ q(w \vert \theta) }{P( \mathcal{D} \vert w)P(w)}\right]\right] & \text{(Drop }P(\mathcal{D})\text{ because it doesn't depend on } \theta) \end{array} \;(4) \\公式中, q(w|\theta) 表明给定正态散布的参数后,权重参数的散布; P(D|w) 表明给定网络参数后,观测数据的似然; P(w) 表明权重的先验,这部分能够作为模型的正则化。而且运用\mathcal{L} = - \mathbb{E}_{q(w \vert \theta)}\left[ \log\left[\frac{ q(w \vert \theta) }{P( \mathcal{D} \vert w)P(w)}\right]\right] \;(5) \\来表明变分下界ELBO, 也便是公式(4)等价于最大化ELBO: \mathcal{L} = \sum_i \log q(w_i \vert \theta_i) - \sum_i \log P(w_i) - \sum_j \log P(y_j \vert w, x_j) \;(6) \\其间,D =\{ (x, y)\}咱们需求对公式(4)中的希望进行求导,可是,这儿,咱们运用对权重进行重参数的技巧:w_i = \mu_i + \sigma_i \times \epsilon_i \; (7) \\其间, \epsilon_i \sim \mathcal{N}(0,1).所以,用 \epsilon代 替 w 后有:\frac{\partial}{\partial \theta}\mathbb{E}_{q(\epsilon)}\left[ \log\left[\frac{ q(w \vert \theta) }{P( \mathcal{D} \vert w)P(w)}\right]\right] =\mathbb{E}_{q(\epsilon)}\left[ \frac{\partial}{\partial \theta}\log\left[\frac{ q(w \vert \theta) }{P( \mathcal{D} \vert w)P(w)}\right]\right] \; (8) \\也便是说,咱们能够经过 多个不同的 \epsilon \sim \mathcal{N}(0,1) ,求取\frac{\partial}{\partial \theta}\log\left[\frac{ q(w \vert \theta) }{P( \mathcal{D} \vert w)P(w)}\right] 的平均值,来近似 KL 散度对 \theta 的求导。此外,除了对 w 进行重采样之外,为了确保 \theta 参数取值规模包括这个实轴,对 \sigma 进行重采样,能够令,\sigma = \log (1 + e^{\rho}) \;\;\; (9) \\然后,\theta = (\mu, \rho),这儿的 \theta 现已和本来界说的\theta = (\mu, \sigma) 不相同了。4. BNN实践算法:从 N(\mu, log(1+e^\rho)) 中采样,取得 w;别离核算 \log q(w|\theta)、 \log p(w)、 \log p(y|w,x). 其间,核算 \log p(y|w,x) 实践核算 \log p(y|y_{pred}), y_{pred} = w*x. 也就能够得到 \mathcal{L} = \sum_i \log q(w_i \vert \theta_i) - \sum_i \log P(w_i) - \sum_j \log P(y_j \vert w, x_j)。重复更新参数\theta’ = \theta -\alpha \nabla_\theta \mathcal{L}.Pytorch完成:import torch
import torch.nn as nn
import torch.nn.functional as F
import torch.optim as optim
from torch.distributions import Normal
import numpy as np
from scipy.stats import norm
import matplotlib.pyplot as plt
class Linear_BBB(nn.Module):
"""
Layer of our BNN.
"""
def __init__(self, input_features, output_features, prior_var=1.):
"""
Initialization of our layer : our prior is a normal distribution
centered in 0 and of variance 20.
"""
# initialize layers
super().__init__()
# set input and output dimensions
self.input_features = input_features
self.output_features = output_features
# initialize mu and rho parameters for the weights of the layer
self.w_mu = nn.Parameter(torch.zeros(output_features, input_features))
self.w_rho = nn.Parameter(torch.zeros(output_features, input_features))
#initialize mu and rho parameters for the layer's bias
self.b_mu = nn.Parameter(torch.zeros(output_features))
self.b_rho = nn.Parameter(torch.zeros(output_features))
#initialize weight samples (these will be calculated whenever the layer makes a prediction)
self.w = None
self.b = None
# initialize prior distribution for all of the weights and biases
self.prior = torch.distributions.Normal(0,prior_var)
def forward(self, input):
"""
Optimization process
"""
# sample weights
w_epsilon = Normal(0,1).sample(self.w_mu.shape)
self.w = self.w_mu + torch.log(1+torch.exp(self.w_rho)) * w_epsilon
# sample bias
b_epsilon = Normal(0,1).sample(self.b_mu.shape)
self.b = self.b_mu + torch.log(1+torch.exp(self.b_rho)) * b_epsilon
# record log prior by evaluating log pdf of prior at sampled weight and bias
w_log_prior = self.prior.log_prob(self.w)
b_log_prior = self.prior.log_prob(self.b)
self.log_prior = torch.sum(w_log_prior) + torch.sum(b_log_prior)
# record log variational posterior by evaluating log pdf of normal distribution defined by parameters with respect at the sampled values
self.w_post = Normal(self.w_mu.data, torch.log(1+torch.exp(self.w_rho)))
self.b_post = Normal(self.b_mu.data, torch.log(1+torch.exp(self.b_rho)))
self.log_post = self.w_post.log_prob(self.w).sum() + self.b_post.log_prob(self.b).sum()
return F.linear(input, self.w, self.b)
class MLP_BBB(nn.Module):
def __init__(self, hidden_units, noise_tol=.1, prior_var=1.):
# initialize the network like you would with a standard multilayer perceptron, but using the BBB layer
super().__init__()
self.hidden = Linear_BBB(1,hidden_units, prior_var=prior_var)
self.out = Linear_BBB(hidden_units, 1, prior_var=prior_var)
self.noise_tol = noise_tol # we will use the noise tolerance to calculate our likelihood
def forward(self, x):
# again, this is equivalent to a standard multilayer perceptron
x = torch.sigmoid(self.hidden(x))
x = self.out(x)
return x
def log_prior(self):
# calculate the log prior over all the layers
return self.hidden.log_prior + self.out.log_prior
def log_post(self):
# calculate the log posterior over all the layers
return self.hidden.log_post + self.out.log_post
def sample_elbo(self, input, target, samples):
# we calculate the negative elbo, which will be our loss function
#initialize tensors
outputs = torch.zeros(samples, target.shape[0])
log_priors = torch.zeros(samples)
log_posts = torch.zeros(samples)
log_likes = torch.zeros(samples)
# make predictions and calculate prior, posterior, and likelihood for a given number of samples
for i in range(samples):
outputs[i] = self(input).reshape(-1) # make predictions
log_priors[i] = self.log_prior() # get log prior
log_posts[i] = self.log_post() # get log variational posterior
log_likes[i] = Normal(outputs[i], self.noise_tol).log_prob(target.reshape(-1)).sum() # calculate the log likelihood
# calculate monte carlo estimate of prior posterior and likelihood
log_prior = log_priors.mean()
log_post = log_posts.mean()
log_like = log_likes.mean()
# calculate the negative elbo (which is our loss function)
loss = log_post - log_prior - log_like
return loss
def toy_function(x):
return -x**4 + 3*x**2 + 1
# toy dataset we can start with
x = torch.tensor([-2, -1.8, -1, 1, 1.8, 2]).reshape(-1,1)
y = toy_func
转载请注明出处:admin,如有疑问,请联系(12345678)。
本文地址:https://www.huizhoueca.com/?id=66