AI-02a5a6.神经网络-与学习相关的技巧-批量归一化

批量归一化 Batch Normalization

设置合适的权重初始值,则各层的激活值分布会有适当的广度,从而可以顺利的进行学习。那么,更进一步,强制性的调整激活值的分布,是的各层拥有适当的广度呢?批量归一化(Batch Normalization)就是基于这个想法产生的。

算法介绍

有什么优点呢?

  • 可以使学习快速进行(可以增大学习率)。
  • 不那么依赖初始值(对于初始值不用那么神经质)。
  • 抑制过拟合(降低Dropout等的必要性)

向神经网络中插入对数据分布进行正规化的层,即Batch Normalization层。

式(6.7), μ B ← 1 m ∑ i = 1 m x i σ B 2 ← 1 m ∑ i = 1 m ( x i − μ B ) 2 x ^ i ← x i − μ B σ B 2 + ϵ \begin{aligned} \mu_B &\leftarrow \frac{1}{m}\sum^m_{i=1}x_i \\ \sigma_B^2 &\leftarrow \frac{1}{m}\sum^m_{i=1}(x_i-\mu_B)^2 \\ \hat{x}_i &\leftarrow \frac{x_i-\mu_B}{\sqrt{\sigma_B^2+\epsilon}} \end{aligned} μBσB2x^i←m1i=1∑mxi←m1i=1∑m(xi−μB)2←σB2+ϵ xi−μB

这里对mini-batch的 m m m个输入数据的集合 B = { x 1 , x 2 , . . . , x m } B = \{x_1, x_2, ... , x_m\} B={x1,x2,...,xm}求均值 μ B \mu_B μB和方差 σ B 2 \sigma_B^2 σB2 。然后,对输入数据进行均值为0、方差为1(合适的分布)的正规化。式(6.7)中的 ϵ \epsilon ϵ是一个微小值(比如,10e-7等),它是为了防止出现除以0的情况。

式(6.7)所做的是将mini-batch的输入数据 { x ^ 1 , x ^ 2 , . . . , x ^ m } \{\hat{x}_1, \hat{x}_2, ... , \hat{x}_m\} {x^1,x^2,...,x^m}变换为均值为0、方差为1的数据。通过将这个处理插入到激活函数的前面(或者后面),可以减小数据分布的偏向。

接着,Batch Norm层会对正规化后的数据进行缩放和平移的变换,式(6.8), y i ← γ x i ^ + β y_i \leftarrow \gamma\hat{x_i} + \beta yi←γxi^+β

这里, γ \gamma γ和 β \beta β是参数。一开始 γ = 1 , β = 0 \gamma = 1, \beta = 0 γ=1,β=0,然后再通过学习调整到合适的值。

几乎所有的情况下都是使用Batch Norm时学习进行得更快。同时也可以发现,实际上,在不使用Batch Norm的情况下,如果不赋予一个尺度好的初始值,学习将完全无法进行。

通过使用批量归一化,可以推动学习的进行。并且,对权重初始值变得健壮("对初始值健壮"表示不那么依赖初始值)。

python 复制代码
# coding: utf-8
import sys, os
sys.path.append(os.pardir)  # 为了导入父目录的文件而进行的设定
import numpy as np
import matplotlib.pyplot as plt
from dataset.mnist import load_mnist
from common.multi_layer_net_extend import MultiLayerNetExtend
from common.optimizer import SGD, Adam
  
(x_train, t_train), (x_test, t_test) = load_mnist(normalize=True)
  
# 减少学习数据
x_train = x_train[:1000]
t_train = t_train[:1000]

max_epochs = 20
train_size = x_train.shape[0]
batch_size = 100
learning_rate = 0.01

def __train(weight_init_std):
    bn_network = MultiLayerNetExtend(input_size=784, hidden_size_list=[100, 100, 100, 100, 100], output_size=10,
                                     weight_init_std=weight_init_std, use_batchnorm=True)
    network = MultiLayerNetExtend(input_size=784, hidden_size_list=[100, 100, 100, 100, 100], output_size=10,
                                  weight_init_std=weight_init_std)

    optimizer = SGD(lr=learning_rate)
    train_acc_list = []
    bn_train_acc_list = []
    iter_per_epoch = max(train_size / batch_size, 1)
    epoch_cnt = 0
    for i in range(1000000000):
        batch_mask = np.random.choice(train_size, batch_size)
        x_batch = x_train[batch_mask]
        t_batch = t_train[batch_mask]
        for _network in (bn_network, network):
            grads = _network.gradient(x_batch, t_batch)
            optimizer.update(_network.params, grads)
        if i % iter_per_epoch == 0:
            train_acc = network.accuracy(x_train, t_train)
            bn_train_acc = bn_network.accuracy(x_train, t_train)
            train_acc_list.append(train_acc)
            bn_train_acc_list.append(bn_train_acc)
            print("epoch:" + str(epoch_cnt) + " | " + str(train_acc) + " - " + str(bn_train_acc))
            epoch_cnt += 1
            if epoch_cnt >= max_epochs:
                break
    return train_acc_list, bn_train_acc_list

# 3.绘制图形==========
weight_scale_list = np.logspace(0, -4, num=16)
x = np.arange(max_epochs)

for i, w in enumerate(weight_scale_list):
    print( "============== " + str(i+1) + "/16" + " ==============")
    train_acc_list, bn_train_acc_list = __train(w)
    plt.subplot(4,4,i+1)
    plt.title("W:" + str(w))
    if i == 15:
        plt.plot(x, bn_train_acc_list, label='Batch Normalization', markevery=2)
        plt.plot(x, train_acc_list, linestyle = "--", label='Normal(without BatchNorm)', markevery=2)
    else:
        plt.plot(x, bn_train_acc_list, markevery=2)
        plt.plot(x, train_acc_list, linestyle="--", markevery=2)

    plt.ylim(0, 1.0)
    if i % 4:
        plt.yticks([])
    else:
        plt.ylabel("accuracy")
    if i < 12:
        plt.xticks([])
    else:
        plt.xlabel("epochs")
    plt.legend(loc='lower right')
plt.show()

背景

批量归一化(Batch Normalization)与层归一化(Layer Normalization)深度解析

什么是归一化 Normalization

在深度神经网络的训练过程中,随着网络深度的增加,模型的表征能力虽然有所提升,但也带来了许多训练上的难题。其中,梯度消失梯度爆炸是最具代表性的两个问题。早期的深层网络中常使用Sigmoid或tanh等饱和激活函数,一旦输入落入函数的饱和区(梯度接近0),梯度在层间传播时会迅速衰减;另一方面,如果网络层数较多或参数初始化不当,也有可能发生梯度的指数级增长,从而使参数更新呈现"发散"现象。

与此同时,随着网络在反向传播中不断更新,前几层的参数变化会连带影响后续层的输入分布,导致高层特征分布发生非平稳性,这种现象被称为内部协变量偏移(Internal Covariate Shift)。在网络很深或数据分布复杂的情况下,这种效应会被放大,导致网络难以收敛或需要极度细心地调整超参数。

归一化 (Normalization)技术正是在这样的背景下逐渐兴起的。它的核心思想是,无论网络有多深,都希望每一层的输入分布尽量稳定、可控。为此,通过对每一层的激活值进行某种形式的"标准化"处理,可以使每层输入在训练中保持较为稳定的分布,即均值和方差在较短的训练迭代内不发生剧烈波动。这种操作一方面有助于缓解梯度消失和梯度爆炸;另一方面,网络也不需要时时刻刻去适应快速变化的激活分布,从而提高了学习效率并缩短训练收敛时间。

批量归一化对批量大小的依赖

BN对批量大小较为敏感,如果批量太小(例如小于16甚至更小),当前批次的均值方差容易出现大幅波动,进而导致训练不稳定或性能下降。在一些仅能使用小批量(如显存受限或序列生成任务)的场景下,BN的效果往往不及设计专门的归一化策略(例如LN、GN等)。

优缺点

优点

  • 大幅加速收敛,允许使用更高的初始学习率。
  • 有一定正则化作用,降低对初始权重的敏感性,减少过拟合。
  • 在主流图像任务和大型批量训练的场景下表现卓越。

缺点

  • 依赖足够大的批量尺寸,否则会导致估计方差不稳定。
  • 在序列模型(如RNN、Transformer等)或者小批量场景中表现不佳。
  • 在分布式训练时,计算全局均值与方差可能比较麻烦,需要额外同步开销。
相关推荐
inputA40 分钟前
【LwIP源码学习6】UDP部分源码分析
c语言·stm32·单片机·嵌入式硬件·网络协议·学习·udp
海尔辛40 分钟前
学习黑客5 分钟读懂Linux Permissions 101
linux·学习·安全
深蓝学院1 小时前
密西根大学新作——LightEMMA:自动驾驶中轻量级端到端多模态模型
人工智能·机器学习·自动驾驶
归去_来兮1 小时前
人工神经网络(ANN)模型
人工智能·机器学习·人工神经网络
2201_754918411 小时前
深入理解卷积神经网络:从基础原理到实战应用
人工智能·神经网络·cnn
强盛小灵通专卖员2 小时前
DL00219-基于深度学习的水稻病害检测系统含源码
人工智能·深度学习·水稻病害
Luke Ewin2 小时前
CentOS7.9部署FunASR实时语音识别接口 | 部署商用级别实时语音识别接口FunASR
人工智能·语音识别·实时语音识别·商用级别实时语音识别
真的想上岸啊2 小时前
学习51单片机01(安装开发环境)
嵌入式硬件·学习·51单片机
Joern-Lee2 小时前
初探机器学习与深度学习
人工智能·深度学习·机器学习
云卓SKYDROID2 小时前
无人机数据处理与特征提取技术分析!
人工智能·科技·无人机·科普·云卓科技