当前位置: 首页 > news >正文

CV【5】:Layer normalization

系列文章目录

Normalization 系列方法(一):CV【4】:Batch normalization
Normalization 系列方法(二):CV【5】:Layer normalization


文章目录

  • 系列文章目录
  • 前言
  • 2. Layer normalization
    • 2.1. Motivation
    • 2.2. Method
      • 2.2.1. Standardisation
      • 2.2.2. Calculation preparation
      • 2.2.3. Calculation process
    • 2.3. Implement with PyTorch
  • 总结


前言

对于早前的 CNN 模型来说,大多使用 batch normalization 进行归一化,随着 Transformer 在计算机视觉领域掀起的热潮, layer normalization 开始被用于提升传统的 CNN 的性能,在许多工作中展现了不错的提升

本文主要是对 layer normalization 用法的总结


2. Layer normalization

2.1. Motivation

Batch Normalization 使用 mini-batch 的均值和标准差对深度神经网络的隐藏层输入进行标准化,可有效地提升训练速度

BN 的效果受制于 batch 的大小,小 batch 未必能取得预期效果

  • 对于前向神经网络可以很直接地应用 BN,因为其每一层具有固定的神经元数量,可直接地存储每层网络各神经元的均值、方差统计信息以应用于模型预测
  • RNNs 网络中,不同的 mini-batch 可能具有不同的输入序列长度(深度),比如每句话的长短都不一定相同,所有很难去使用 BN,计算统计信息比较困难,而且测试序列长度不能大于最大训练序列长度

Barch Normalization 也很难应用于在线学习模型,以及小 mini-batch 的分布式模型

Layer Normalization 是针对自然语言处理领域提出的,其计算是针对每个样本进行的, 不像 BN 那样依赖 batch 内所有样本的统计量, 可以更好地用到 RNN 和流式数据上(注意,在图像处理领域中 BNLN 是更有效的,但现在很多人将自然语言领域的模型用来处理图像,比如 Vision Transformer,此时还是会涉及到 LN,有关 Vision Transformer 的部分可以参考我的另外一篇 blog:CV-Model【6】:Vision Transformer)

2.2. Method

2.2.1. Standardisation

网络层的输出经过线性变换作为下层网络的输入,网络输出直接影响下层网络输入分布,这是一种协变量转移的现象。我们可以通过 固定网络层的输入分布(固定输入的均值和方差) 来降低协变量转移的影响

BN 对同一 mini-batch 中对不同特征进行标准化(纵向规范化:每一个特征都有自己的分布),受限于 batch size,难以处理动态神经网络中的变长序列的 mini-bach

RNNs 不同时间步共享权重参数,使得 RNNs 可以处理不同长度的序列,RNNs 使用 layer normalization 对不同时间步进行标准化(横向标准化:每一个时间步都有自己的分布),从而可以处理单一样本、变长序列,而且训练和测试处理方式一致

2.2.2. Calculation preparation

LN 是基于 BN 转化而来的

对于一个多层前向神经网络中的某一层 HiH_iHi,计算方式如下所示:
ail=wilThlhil+1=f(ail+bil)a_i^l = w_i^{l^T}h^l \\ h_i^{l+1} = f(a_i^l + b_i^l)ail=wilThlhil+1=f(ail+bil)

针对深度学习,存在 covariate shift 现象,因此需要通过 normalize 操作,使 HiH_iHi 层的输入拥有固定的均值和方差,以此削弱协方差偏移现象对深度网络的训练时的影响,加快网络收敛。

normalizeHiH_iHi 层输入进行变换,计算方式如下所示:
aˉil=gilσil(ail−μil)μil=Ex∼P(x)[ail]σil=1H∑i=1H(ail−μl)2\bar{a}_i^l = \frac{g_i^l}{\sigma_i^l}(a_i^l - \mu_i^l) \\ \mu_i^l = \mathbb{E}_{x \sim P(x)} [a_i^l] \\ \sigma_i^l = \sqrt{\frac{1}{H} \displaystyle\sum_{i=1}^H (a_i^l - \mu^l)^2}aˉil=σilgil(ailμil)μil=ExP(x)[ail]σil=H1i=1H(ailμl)2

直接使用上式进行 normalize 不现实,因为需要针对整个 trainingset 来进行计算,因此,BN 通过 mini-batch 的输入样本近似的计算 normalize 中的均值和方差,因此成为 batch normalization

2.2.3. Calculation process

BN 不同,LN 是针对深度网络的某一层的所有神经元的输入按以下公式进行 normalize 操作

如图所示。它综合考虑一层所有维度的输入,计算该层的平均输入值和输入方差,然后用同一个规范化操作来转换各个维度的输入

在这里插入图片描述
对于 RNN 的每个时间步,其输入都会包含两部分,即当前的输入 xtx^{t}xt 和上一个时刻的隐藏状态 ht−1\mathbf{h}^{t-1}ht1,记 at=Whhht−1+Wxhxt\mathbf{a}^{t}=W_{h h} h^{t-1}+W_{x h} \mathbf{x}^{t}at=Whhht1+Wxhxt,其中,WhhW_{hh}WhhWxhW_{x h}Wxh 为对应的权重矩阵,则在每一个时刻,Layer Normalization 对每一个样本都分别计算所有神经元的均值和标准差如下:

在这里插入图片描述
参数含义:

  • at\mathbf{a}^{t}at 表示输入向量(前层网络输出加权后的向量)
  • HHH 表示隐藏单元数量(RNN 层的维度)

对于标准 RNN,若当前输入为 xt\mathbf{x}^{t}xt,上一隐藏状态为 ht−1\mathbf{h}^{t-1}ht1,则加权输入向量(非线性单元的输入)为:

在这里插入图片描述
对输入向量进行层标准化,再进行缩放和平移(用于恢复非线性)得标准化后的输入 y\mathbf{y}y

在这里插入图片描述
将标准化后的输入传入非线性激活函数:

在这里插入图片描述
其中, gggbbb 为引入的自适应增益和偏置参数,其作用与 batch normalization 中的参数一样,为了保留模型的非线性能力, gggbbb 的维度均为 HHH

值得注意的是,在每个时间步,同层网络的所有隐藏单元共享均值和方差

Layer Normalizationgggbbb 的初始化不敏感,一般默认将 ggg 初始化为 1,将 bbb 初始化为 0

2.3. Implement with PyTorch

在 Pytorch 的 LayerNorm 类中有个 normalized_shape 参数,可以指定你要 Norm 的维度(注意,函数说明中 the last certain number of dimensions,指定的维度必须是从最后一维开始)。

比如我们的数据的 shape[4,2,3][4, 2, 3][4,2,3],那么 normalized_shape 可以是 [3][3][3](最后一维上进行 Norm 处理),也可以是 [2,3][2, 3][2,3]Norm 最后两个维度),也可以是 [4,2,3][4, 2, 3][4,2,3](对整个维度进行 Norm),但不能是 [2][2][2] 或者 [4,2][4, 2][4,2],否则会报以下错误(以 normalized_shape = [2] 为例):

RuntimeError: 
Given normalized_shape=[2],         
expected input with shape [*, 2],    
but got input of size[4, 2, 3]

提示我们传入的 normalized_shape = [2],接着系统根据我们传入的 normalized_shape 推理出期待的输入数据 shape 应该为 [∗,2][*, 2][,2]即最后的一个维度大小应该是 222,但我们实际传入的数据 shape[4,2,3][4, 2, 3][4,2,3] 所以报错了

接着,我们再来看个示例,分别使用官方的 LN 方法和自己实现的 LN 方法进行比较:

import torch
import torch.nn as nndef layer_norm_process(feature: torch.Tensor, beta=0., gamma=1., eps=1e-5):var_mean = torch.var_mean(feature, dim=-1, unbiased=False)# 均值mean = var_mean[1]# 方差var = var_mean[0]# layer norm processfeature = (feature - mean[..., None]) / torch.sqrt(var[..., None] + eps)feature = feature * gamma + betareturn featuredef main():t = torch.rand(4, 2, 3)print(t)# 仅在最后一个维度上做norm处理norm = nn.LayerNorm(normalized_shape=t.shape[-1], eps=1e-5)# 官方layer norm处理t1 = norm(t)# 自己实现的layer norm处理t2 = layer_norm_process(t, eps=1e-5)print("t1:\n", t1)print("t2:\n", t2)if __name__ == '__main__':main()

经测试可以发现,结果是一样的


总结

参考资料1
参考资料2

http://www.lryc.cn/news/585.html

相关文章:

  • 跳跃游戏 II 解析
  • 易基因|猪肠道组织的表观基因组功能注释增强对复杂性状和人类疾病的生物学解释:Nature子刊
  • 01- NumPy 数据库 (机器学习)
  • RapperBot僵尸网络最新进化:删除恶意软件后仍能访问主机
  • 拦截器interceptor总结
  • 轻松实现微信小程序上传多文件/图片到腾讯云对象存储COS(免费额度)
  • Golang中defer和return的执行顺序 + 相关测试题(面试常考)
  • 谁说菜鸟不会数据分析,不用Python,不用代码也轻松搞定
  • php mysql保健品购物商城系统
  • Vue3电商项目实战-首页模块6【22-首页主体-补充-vue动画、23-首页主体-面板骨架效果、4-首页主体-组件数据懒加载、25-首页主体-热门品牌】
  • linux 使用
  • 基于遗传算法的微电网调度(风、光、蓄电池、微型燃气轮机)(Matlab代码实现)
  • 方向导数与梯度下降
  • Java岗面试题--Java基础(日积月累,每日三题)
  • java基础—Volatile关键字详解
  • 内存检测工具Sanitizers
  • Triton : OpenAI 开发的用于Gpu开发语言
  • Python文件操作-代码案例
  • 活动目录(Active Directory)管理,AD自动化
  • Allegro如何使用Vertext命令修改丝印线段的形状操作指导
  • Leetcode力扣秋招刷题路-0030
  • 基于Prometheus和k8s搭建监控系统
  • 类和对象(下)
  • 达梦数据库单机部署
  • 从零到一学习Flutter——(二)状态和路由
  • TC358774XBG/TC358775XBG替代方案|CS5518替代TC358774XBG/TC358775XBG设计DSI转LVSD设计资料
  • Linux---Kernal与Shell讲解
  • Thiol-PEG-Acid,HS-PEG-COOH,巯基-聚乙二醇-羧基试剂供应
  • 数据结构与算法基础-学习-09-线性表之栈的理解、初始化顺序栈、判断顺序栈空、获取顺序栈长度的实现
  • 深入Kafka核心设计与实践原理读书笔记第二章