通俗话说一说各种Normalization以及用deeplearning4j实现Layer Normalization
一、Normalization是什么
Normalization一句话概括来说就是用一种办法,将一组数据压到均值为0,方差为1的正态分布上去,具体做法是数据集的每一个元素减去均值再除以标准差。公式如下:(请忽略参数g,g的问题很诡异,后面说)
这个公式说的更直白一点就是,把每一个a,经过平移和缩放,得到一个新值。而这样做的一个理由是,平移缩放并不会改变原始数据的分布情况,原来最大的还是最大,原来最小的还是最小。
Deeplearning中有很多Normalization的方法,有BN、LN、IN、GN等等,每一种Normalization公式都一样,只是沿着的轴不一样,BN就是沿着minibatch方向,LN就是沿着影藏层的output vector维方向,举个例子,对于四维张量[minibatch,depth、height、width],那就是沿着depth方向,把height、width维约简掉。
二、说说Layer Normalization
论文地址:https://arxiv.org/pdf/1607.06450.pdf
Layer Normalization对于时间序列数据有奇效,下面截一段论文的原文。这是在RNN上用Layer Normalization
简短的话说一下论文的变量含义,a表示t时刻点rnn的预输出值(还没有经过激活函数哦),h表示rnn某一个隐层t时刻点的输出。
那么,这里Normalization是哪一个维度呢?假设RNN的输入张量为[minibatch、layerSize、timesteps],这么这里Normalization的就是layerSize这一维。这样可能还是太抽象,请看下图:
这里Normalization的就是红色箭头指向的每一个维度的向量,对于一条数据的每个time step而言,就求出一个均值和方差,进行变换,下一个time step类推下去。那么多个time step就有多个均值和方差。
三、重点说说参数g和b
这里g和b的维度要和h的维度相同,也就是上图的values per time step这一维度,也就是layer size的大小,这里g和b是跟随着网络参数学出来的。开始实现时,g的所有值一般会初始化为1,b的所有值会被初始化为0,随着训练的进行,g和b就会被修改为任意值了。那么Normalization也就没有了正态分布的效果,相当于layer size维乘以了一个随机向量,注意这里是向量点积,那么就等同于给一个随机的噪声,居然也能起作用,也是一个不能解释的问题。有点没有道理,但就是这么难以置信,居然是work的。
四、deeplearning4j的自动微分实现Layer Normalization
import java.util.Map; import org.deeplearning4j.nn.conf.inputs.InputType; import org.deeplearning4j.nn.conf.layers.samediff.SDLayerParams; import org.deeplearning4j.nn.conf.layers.samediff.SameDiffLayer; import org.nd4j.autodiff.samediff.SDVariable; import org.nd4j.autodiff.samediff.SameDiff; import org.nd4j.linalg.api.ndarray.INDArray; public class LayerNormaliztion extends SameDiffLayer { // gain * standardize(x) + bias private double eps = 1e-5; private static String GAIN = "gain"; private static String BIAS = "bias"; private int nOut; private int timeStep; public LayerNormaliztion(int nOut, int timeStep) { this.timeStep = timeStep; this.nOut = nOut; } protected LayerNormaliztion() { } @Override public InputType getOutputType(int layerIndex, InputType inputType) { return InputType.recurrent(nOut); } @Override public void defineParameters(SDLayerParams params) { params.addWeightParam(GAIN, 1, nOut, 1); params.addWeightParam(BIAS, 1, nOut, 1); } @Override public SDVariable defineLayer(SameDiff sd, SDVariable layerInput, Map<String, SDVariable> paramTable, SDVariable mask) { SDVariable gain = paramTable.get(GAIN);//论文中的g SDVariable bias = paramTable.get(BIAS);//论文中的b SDVariable mean = layerInput.mean("mean", true, 1);//均值 SDVariable variance = sd.math().square(layerInput.sub(mean)).sum(true, 1).div(layerInput.getShape()[1]);//平方差 SDVariable standardDeviation = sd.math().sqrt("standardDeviation", variance.add(eps));//标准差,加上eps 防止分母为0 long[] maskShape = mask.getShape(); return gain.mul(layerInput.sub(mean).div(standardDeviation)).add(bias) .mul(mask.reshape(maskShape[0], 1, timeStep));//掩码掩掉多余长度 } @Override public void initializeParameters(Map<String, INDArray> params) { params.get(GAIN).assign(1); params.get(BIAS).assign(0); } public int getNOut() { return nOut; } public void setNOut(int nOut) { this.nOut = nOut; } public int getTimeStep() { return timeStep; } public void setTimeStep(int timeStep) { this.timeStep = timeStep; } }
五、实战的结果
就用RNN做文本分类而言,加上LN,收敛会更平稳,但准确率大大下降了。
在deeplearning的世界里,任何一种方法被提出来,只是在解当前的问题,对于每一种具体的问题,肯定是case by case。
快乐源于分享。
此博客乃作者原创, 转载请注明出处

低调大师中文资讯倾力打造互联网数据资讯、行业资源、电子商务、移动互联网、网络营销平台。
持续更新报道IT业界、互联网、市场资讯、驱动更新,是最及时权威的产业资讯及硬件资讯报道平台。
转载内容版权归作者及来源网站所有,本站原创内容转载请注明来源。
- 上一篇
vue项目实践@树洞(三)
业务开发 业务逻辑这块儿并就没有什么特别重要的东西要说,无非就是样式、兼容,再加上vue的语法。这些都是基本功,移动端没有IE,故而不会有太多让人窒息的问题。如果说有什么难点,那就是vuex,主要是它的几个核心比较难理解,理解了也不难。 目前只是一些基础的业务逻辑,故只是提一下我在这个项目中遇到的一些问题。 ## Tabbar多米诺骨牌## 使用Vant的Tabbar完成底部菜单,五个菜单项,中间项是一个创建消息的功能。类似于手机QQ空间底部菜单栏,这个功能需要功能需要登录且是一个弹窗。那么问题来了:第一,不能使用<router-link>,须根据是否已登录执行相应的逻辑;第二,页面跳转到相应的链接,这个地址再回来对应的索引必须正确;第三,弹窗关闭,对应tabbar的索引也应该进行正确的指示;第四,这个创建图标不能有指示效果,也就是说它只能有一种状态;第五,不是所有页面都有Tabbar,它相对于底部的间距需要处理。 先解决第五个问题,提取组件,所有样式、逻辑集中处理,在需要的地方引用即可。这很容易想到,那么底部菜单的间距怎么做?这也容易想得到,组件渲染完成,给body注入一...
- 下一篇
开源一文多发平台ArtiPub,让文章随处可阅
背景 很多优秀的程序员和技术人员喜欢写技术文章和技术博客,通过这样的方式分享传播知识和经验,扩大自己的知名度和影响力,吸引粉丝关注,甚至有些技术博主还通过写文章来获取广告收入,很多优秀的博主还通过这种方法获得了出版书的机会以及工作机会。因此,写技术文章是一件非常值得投入的事情,帮助了自己,也让大众受益。 但是,写技术文章通常也很耗时,特别是一些优质文章,不仅需要旁征博引、构思文章结构、照顾读者受众,还需要做很多前期工作,例如搭建环境、写demo代码、测试代码等等。一篇优质技术文章通常需要3-6个小时来完成。然而,花了很多时间来写文章,最终发布出来的文章得不到很多人的关注是一件相当令人沮丧的事情。我们认为,优质文章值得获取关注和传播,让更多的技术工作者通过阅读文章获取知识获益。 每个技术博主都有自己喜欢的技术媒体平台,例如掘金、CSDN、微信公众号等等。很多技术博主也喜欢将文章发布在不同的平台上,寻求最大的关注度,同时也防止自己辛辛苦苦写的文章被别人复制粘贴盗版过去。然而,在多个平台上发文是一件麻烦的事情:博主需要同时登陆多个媒体平台,将自己的文章复制一个一个粘贴过去;更麻烦的是,有些平...
相关文章
文章评论
共有0条评论来说两句吧...
文章二维码
点击排行
推荐阅读
最新文章
- Eclipse初始化配置,告别卡顿、闪退、编译时间过长
- CentOS7编译安装Cmake3.16.3,解决mysql等软件编译问题
- SpringBoot2全家桶,快速入门学习开发网站教程
- MySQL8.0.19开启GTID主从同步CentOS8
- Docker安装Oracle12C,快速搭建Oracle学习环境
- Docker使用Oracle官方镜像安装(12C,18C,19C)
- CentOS7安装Docker,走上虚拟化容器引擎之路
- Docker快速安装Oracle11G,搭建oracle11g学习环境
- CentOS7编译安装Gcc9.2.0,解决mysql等软件编译问题
- CentOS6,7,8上安装Nginx,支持https2.0的开启