batch normalization

    def batchnorm(self, Ylogits, is_test, iteration, offset, convolutional=False):  
        """
        :param Ylogits:
        :param is_test:
        :param iteration:
        :param offset:
        :param convolutional:
        :return:
        """
        exp_moving_avg = tf.train.ExponentialMovingAverage(0.999, iteration)  # adding the iteration prevents from averaging across non-existing iterations
        bnepsilon = 1e-5
        if convolutional:
            mean, variance = tf.nn.moments(Ylogits, [0, 1, 2])
        else:
            mean, variance = tf.nn.moments(Ylogits, [0])
        update_moving_averages = exp_moving_avg.apply([mean, variance])  # update exp_moving_avg
        m = tf.cond(is_test, lambda: exp_moving_avg.average(mean), lambda: mean)  # 0.999*exp_moving_avg.average(mean)+(1-0.999)*exp_moving_avg
        v = tf.cond(is_test, lambda: exp_moving_avg.average(variance), lambda: variance)
        Ybn = tf.nn.batch_normalization(Ylogits, m, v, offset, None, bnepsilon)
        return Ybn, update_moving_averages

最近看程序,看到一段batchnorm的程序不是很理解,所以又学习了一下。


Internal Covariate Shift:网络训练过程中参数不断改变导致后续每一层输入的分布也发生变化,而学习的过程又要使每一层适应输入的分布,因此我们不得不降低学习率、小心地初始化。
(因为白化需要计算协方差矩阵、求逆等操作,计算量很大,此外,反向传播时,白化操作不一定可导。)
batch normalization用于减少Internal Covariate Shift,防止梯度弥散,还可加速模型的训练(激活层之前)

  • 训练时存在权重共享,把一整张特征图当做一个神经元进行处理,求所有样本所对应的一个特征图的所有神经元的平均值、方差,然后对这个特征图神经元做归一化(减少计算量)
  • 网络训练完成,参数固定不变;网络在预测时,测试样本经过中间各层时,用到的是训练好的μ、β来进行归一化处理,对于均值,直接计算batch的平均值;然后对标准差采用batch的无偏估计


第四个公式主要是变换重构,网络中间层的数据的真实分布是一个Sigmoid分布,按上式强制归一化处理后,会破坏分布,通过重构参数让网络可以学习恢复出原始网络所要学习的特征分布

随机梯度下降法对于训练深度网络简单高效,但需要人为的选择一些参数,比如学习率、参数初始化、权重衰减系数、dropout比例等。这些参数的选择对训练结果至关重要,浪费很多时间在调参上。BN算法的强大之处表现在:

  • 可以选择比较大的初始学习率,让训练速度飙涨。以前需要慢慢调整学习率,甚至在网络训练到一半时,还需要想着学习率进一步调小的比例,选择多少比较合适,现在我们可以采用初始很大的学习率,然后学习率的衰减速度也很大,因为这个算法收敛很快。当然这个算法即使你选择了较小的学习率,也比以前的收敛速度快,因为它具有快速训练收敛的特性;
  • 过拟合中dropout、L2正则项参数的选择问题,采用BN算法后,你可以移除这两项了参数,或者可以选择更小的L2正则约束参数了,因为BN具有提高网络泛化能力的特性;
  • 不需要使用局部响应归一化层,因为BN本身就是一个归一化网络层;
  • 可以把训练数据彻底打乱(防止每批训练的时候,某一个样本都经常被挑选到)。

tf.train.ExponentialMovingAverage(decay, steps)

moving average类似于卷积的操作,因此我们就可以在卷积核上做文章,最普通的卷积核就是每个数据的权重都相同,但是在实际中明显越近的数据价值越大,因此要让越近的数据权重越大,越远的数据权重越小,在这里使用的权重衰减策略就是指数衰减。具体的,
  • α控制衰减速率。
  • Yt表示时间t时的原始值
  • St表示经过EMA后的时间t的值

综上,EMA就是把一系列的离散数据点转化为更“好”的数据点,它的后面的数据点会记住前面的数据点的一些信息,离得越远记得越少。

tf.train.ExponentialMovingAverage是用来让模型不被更新的太快的一种方法,用于更新参数,就是采用滑动平均的方法更新参数。这个函数初始化需要提供一个衰减速率(decay),用于控制模型的更新速度。这个函数还会维护一个影子变量(也就是更新参数后的参数值),这个影子变量的初始值就是这个变量的初始值,影子变量值的更新方式如下:
shadow_variable = decay * shadow_variable + (1-decay) * variable
shadow_variable是影子变量,variable表示待更新的变量,也就是变量被赋予的值,decay为衰减速率。decay一般设为接近于1的数(0.99,0.999)。decay使得shadow variable具有一定的缓冲能力,不会变化太快
decay越大模型越稳定,因为decay越大,参数更新的速度就越慢,趋于稳定。
tf.train.ExponentialMovingAverage 这个函数还提供了自动更新decay的计算方式(让前期训练加快,可以计入num_update参数):
decay= min(decay,(1+steps)/(10+steps))
每次更新完以后,影子变量的值更新,varible的值就是你设定的值。如果在下一次运行这个函数的时候你不在指定新的值,那就不变,影子变量更新。如果指定,那就variable改变,影子变量也改变


mean, variance = tf.nn.moments(Ylogits, [0])

def moments(x, axes, name=None, keep_dims=False)(在某一维度上求均值方差)

  • x 可以理解为我们输出的数据,形如 [batchsize, height, width, kernels]
  • axes 表示在哪个维度上求解,是个list,例如 [0, 1, 2]
  • name 就是个名字
  • keep_dims 是否保持维度

update_moving_averages = exp_moving_avg.apply([mean, variance])  # update exp_moving_avg

返回一个op,这个op用来更新moving_average,与exp_moving_avg.average()函数不能换位置,在它之前。
执行时才对参数[mean, variance]更新


m = tf.cond(is_test, lambda: exp_moving_avg.average(mean), lambda: mean) 
v = tf.cond(is_test, lambda: exp_moving_avg.average(variance), lambda: variance)

训练和测试时的不同:训练时,均值和方差由mini-batch直接获得;测试时,均值和方差通过样本的滑动平均值获得。
exp_moving_avg.average():此op用来返回当前的moving_average,这个参数不能是list
假设有一串时间序列 {a1, a2, a3,⋯, at, at+1, ⋯}
t时刻的平均值为mv(t)=(a1 + a2 + ⋯ + at) / t
t+1时刻的平均值为mv(t+1)=(a1 + a2 + ⋯ + at + a(t+1))/(t+1) = (t * mv(t) + a(t+1)) / (t+1) = (t / (t+1)) * mv(t) + (1 / (t+1)) * a(t+1)
令decay = t / (t+1), 则mv(t+1)=decay∗mv(t)+(1−decay)∗a(t+1)

exp_moving_avg.average()函数执行时才计算公式,输出的是新的shadow_variable,在这个程序中就是0.999*exp_moving_avg.average(mean)(原来的)+(1-0.999)*updata_mean(新得到的均值)
https://blog.csdn.net/whitesilence/article/details/75667002


Ybn = tf.nn.batch_normalization(Ylogits, m, v, offset, None, bnepsilon)

def batch_normalization(x, mean, variance, offset, scale, variance_epsilon, name=None):


offset和scale需要训练

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 217,406评论 6 503
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 92,732评论 3 393
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 163,711评论 0 353
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 58,380评论 1 293
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 67,432评论 6 392
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 51,301评论 1 301
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 40,145评论 3 418
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 39,008评论 0 276
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 45,443评论 1 314
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 37,649评论 3 334
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 39,795评论 1 347
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 35,501评论 5 345
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 41,119评论 3 328
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,731评论 0 22
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,865评论 1 269
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 47,899评论 2 370
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 44,724评论 2 354

推荐阅读更多精彩内容