Python----循环神经网络(Transformer ----Layer-Normalization(层归一化))

一、Batch-Normalization

Batch Normalization的作用是将一个批次(Batch)的特征矩阵的每一个channels 计算为均值为0,方差为1的分布 规律。

一般而言,在一个神经网络输入图像之前,会将图像进行预处理,这个预处理可能是 标准化处理等手段,由于输入数据满足某一分布规律,所以会加速网络的收敛。这样 在输入第一次卷积的时候满足某一分布规律,但是在输入第二次卷积时,就不一定满 足某一分布规律了,再往后的卷积的输入就更不满足了,那么就需要一个中间商,让 上一层的输出经过它之后能够某一分布规律,Batch Normalization就是这个中间 商,它可以让输入的特征矩阵的每一个channels满足均值为0,方差为1的分布规 律。

python 复制代码
import numpy as np

def batch_normalization(BN_input, epsilon=1e-5):
    """
    对输入数据进行批量归一化(Batch Normalization)处理
    
    参数:
        BN_input: 输入数据,形状为(batch_size, channels, height, width)的4D张量
        epsilon: 用于数值稳定的小常数,防止除以零
        
    返回:
        经过批量归一化处理后的数据
    """
    
    # 1. 计算均值和方差
    # 沿batch、height、width维度计算每个channel的均值和方差
    # keepdims=True保持维度不变,便于后续广播操作
    mean = np.mean(BN_input, axis=(0, 2, 3), keepdims=True)  # 形状变为(1, C, 1, 1)
    variance = np.var(BN_input, axis=(0, 2, 3), keepdims=True)  # 形状变为(1, C, 1, 1)
    
    # 2. 归一化处理
    # 使用公式:(x - μ) / √(σ² + ε)
    normalized_data = (BN_input - mean) / np.sqrt(variance + epsilon)
    
    # 3. 缩放和平移
    # 实际应用中,gamma和beta是可学习的参数
    # 这里简化实现,gamma初始化为1,beta初始化为0
    gamma = np.ones_like(BN_input)  # 缩放参数
    beta = np.zeros_like(BN_input)  # 平移参数
    
    # 应用缩放和平移:y = γ * x_norm + β
    output_data = gamma * normalized_data + beta
    
    return output_data

# 测试数据
# 模拟卷积层输出:2个样本,2个通道,2x2的特征图
conv_output = [
    [   # 第一个样本
        [[1, 1], [1, 2]],    # 通道1
        [[-1, 1], [0, 1]],   # 通道2
    ],
    [   # 第二个样本
        [[0, -1], [2, 2]],   # 通道1
        [[0, -1], [3, 1]],   # 通道2
    ]
]

# 将列表转换为numpy数组
conv_output = np.array(conv_output)

# 进行批量归一化
normalized_output = batch_normalization(conv_output)

print("归一化后的输出:")
print(normalized_output)
python 复制代码
import torch
import torch.nn as nn

# 假设卷积后的结果如下:
# 卷积层的输出是(batch_size, channels, height, width)的四维张量
conv_output = [
    [   # 第一个样本
        [[1, 1], [1, 2]],    # 通道1
        [[-1, 1], [0, 1]],   # 通道2
    ],
    [   # 第二个样本
        [[0, -1], [2, 2]],   # 通道1
        [[0, -1], [3, 1]],   # 通道2
    ]
]

# 将列表转换为PyTorch张量,并指定数据类型为float32
embd_output = torch.tensor(conv_output, dtype=torch.float)

# 打印原始输入数据
print("Original Input:")
print(embd_output)

# 将最后三个维度(channels, height, width)合并为一个维度
# 这里使用view()进行形状变换,保持通道数不变
# -1表示自动计算batch_size
reshaped_embd_output = embd_output.view(
    -1,                      # 自动计算的batch_size
    embd_output.size(-3),     # 通道数
    embd_output.size(-2),     # 高度
    embd_output.size(-1)      # 宽度
)

# 在Batch维度上进行Batch Normalization
# 创建BatchNorm2d层,参数:
# - num_features: 输入的特征图通道数
# - affine: 是否学习缩放(gamma)和平移(beta)参数
batch_norm = nn.BatchNorm2d(
    reshaped_embd_output.size(1),  # 输入通道数
    affine=True                    # 启用可学习的gamma和beta参数
)

# 应用批量归一化
normalized_output = batch_norm(reshaped_embd_output)

# 将输出重新调整为原始形状
normalized_output = normalized_output.view(embd_output.size())

# 打印归一化后的输出
print("\nBN Normalized Output:")
print(normalized_output)

# 打印BN层的参数(训练过程中会学习这些参数)
print("\nBN层参数:")
print("gamma (weight):", batch_norm.weight)
print("beta (bias):", batch_norm.bias)
print("running_mean:", batch_norm.running_mean)
print("running_var:", batch_norm.running_var)

二、Layer Normalization

Layer Normalization由Ba, Kiros, 和Hinton于2016年提出。它主要用于解决深度神经网络训练过程中的内部协变量偏移问题。不同于Batch Normalization(批归一 化),Layer Normalization是独立于批次大小的,这使得它在处理小批次数据或循 环神经网络(RNN)时特别有用。

使用PyTorch实现图像任务的LN层

python 复制代码
import torch
import torch.nn as nn

# 假设卷积后的结果如下:
# 卷积层的输出是(batch_size, channels, height, width)的四维张量
conv_output = [
    [   # 第一个样本 (样本1)
        [[1, 1], [1, 2]],    # 通道1的2x2特征图
        [[-1, 1], [0, 1]],   # 通道2的2x2特征图
    ],
    [   # 第二个样本 (样本2)
        [[0, -1], [2, 2]],   # 通道1的2x2特征图
        [[0, -1], [3, 1]],   # 通道2的2x2特征图
    ]
]

# 将Python列表转换为PyTorch张量,并指定为float32类型
embd_output = torch.tensor(conv_output, dtype=torch.float)

# 打印原始输入数据
print("Original Input:")
print(embd_output)
print("输入形状:", embd_output.shape)  # 输出形状应为[2, 2, 2, 2] (batch, channel, height, width)

# 创建LayerNorm层
# 参数说明:
# normalized_shape: 需要规范化的维度(从最后一个维度开始)
# 这里我们传入embd_output.shape[1:4],即对每个样本的(channels, height, width)进行归一化
# 相当于对每个空间位置的特征向量进行独立归一化
layer_norm = nn.LayerNorm(embd_output.shape[1:4])  # 对每个样本的[channel, height, width]做归一化

# 应用层归一化
normalized_output = layer_norm(embd_output)

# 打印归一化后的输出
print("\nLN Normalized Output:")
print(normalized_output)
print("输出形状:", normalized_output.shape)  # 应与输入形状相同

# 打印LN层的参数(可学习的缩放和平移参数)
print("\nLayerNorm层参数:")
print("gamma (weight):", layer_norm.weight.shape)  # 形状应与normalized_shape一致
print("beta (bias):", layer_norm.bias.shape)      # 形状应与normalized_shape一致

对于输入,有样本1和样本2,即Sample1和Sample2,每个样本有四个字,即4个 token,或者叫sequence_len,每个字的Embedding有自己的维度,即embedding dimension。那么LN规则化其实就是对每个样本的每个token的embedding dimension求均值和方差,然后运算。图中相同颜色的个子就是做LN规则化的。

使用PyTorch实现NLP任务的LN层

python 复制代码
import torch
import torch.nn as nn

# 假设文字的Embedding编码如下:
# 形状为 (batch_size, sequence_length, embedding_dimension)
# 示例数据包含2个样本,每个样本4个token,每个token用2维向量表示
embd_output = [
    [   # 第一个样本 (batch=0)
        [1, -1],  # token 0
        [1, 1],   # token 1
        [1, 0],   # token 2
        [2, 1],   # token 3
    ],
    [   # 第二个样本 (batch=1)
        [0, 0],   # token 0
        [-1, -1], # token 1
        [2, 3],   # token 2
        [2, 1],   # token 3
    ]
]

# 将Python列表转换为PyTorch张量,并指定为float32类型
embd_output = torch.tensor(embd_output, dtype=torch.float)

# 打印原始输入数据
print("Original Input:")
print(embd_output)
print("输入形状:", embd_output.shape)  # 预期输出: torch.Size([2, 4, 2])

# 创建LayerNorm层
# 参数说明:
# normalized_shape: 需要规范化的维度(从最后一个维度开始)
# 这里传入embd_output.size(-1)即embedding_dimension=2,
# 表示对每个token的特征向量进行独立归一化
# eps: 防止除零的小常数(默认1e-5)
# elementwise_affine: 是否使用可学习的缩放和平移参数(默认True)
layer_norm = nn.LayerNorm(
    normalized_shape=embd_output.size(-1),  # 对embedding_dimension进行归一化
    eps=1e-5,                              # 数值稳定系数
    elementwise_affine=True                # 启用可学习的gamma和beta参数
)

# 应用层归一化
# LayerNorm的计算过程:
# 1. 对每个token的特征向量计算均值和方差
# 2. 使用 (x - mean) / sqrt(var + eps) 进行归一化
# 3. 应用缩放gamma和平移beta:y = gamma * x + beta
normalized_output = layer_norm(embd_output)

# 打印归一化后的输出
print("\nLN Normalized Output:")
print(normalized_output)
print("输出形状:", normalized_output.shape)  # 应与输入形状相同

# 打印LN层的可学习参数
print("\nLayerNorm层参数:")
print("gamma (缩放权重):", layer_norm.weight)  # 形状为[embedding_dimension]
print("beta (平移偏置):", layer_norm.bias)    # 形状为[embedding_dimension]
print("参数形状:", layer_norm.weight.shape)    # 预期输出: torch.Size([2])

三、Post-LN和Pre-LN

3.1、Post-LN(后层归一化):

Post-LN 是原始的 Transformer 架构中使用的层归一化方式。在 Post-LN 中,层归 一化是在每个子层的残差连接之后进行的。然而,Post-LN 在深度 Transformer(例 如,十层或更多层)的训练中经常变得不稳定,导致模型无法使用。

3.2、Pre-LN(前层归一化):

由于 Post-LN 的训练不稳定性,研究者们提出了 Pre-LN。在 Pre-LN 中,层归一化 是在每个子层的输入上进行的。这使得 Pre-LN 在深度 Transformer 的训练中更为稳 定。

3.3、Post-LN和Pre-LN比较:

相关推荐
测试老哥12 分钟前
软件测试之单元测试
自动化测试·软件测试·python·测试工具·职场和发展·单元测试·测试用例
张较瘦_15 分钟前
[论文阅读] 人工智能 + 软件工程 | LLM辅助软件开发:需求如何转化为代码?
论文阅读·人工智能·软件工程
whabc10029 分钟前
和鲸社区深度学习基础训练营2025年关卡3_Q1(1)
人工智能·深度学习
勤奋的知更鸟34 分钟前
标准化模型格式ONNX介绍:打通AI模型从训练到部署的环节
人工智能·语言模型
presenttttt1 小时前
用Python和OpenCV从零搭建一个完整的双目视觉系统(六 最终篇)
开发语言·python·opencv·计算机视觉
盼小辉丶1 小时前
Transoformer实战——Transformer模型性能评估
人工智能·深度学习·transformer
极限实验室1 小时前
Coco AI 实战(二):摄入MongoDB 数据
人工智能·mongodb
AIGC包拥它1 小时前
AI教学设计助手:生成好教案的Prompt技术实战(一)
人工智能·prompt
测试19982 小时前
软件测试之压力测试总结
自动化测试·软件测试·python·测试工具·职场和发展·测试用例·压力测试
SoFlu软件机器人2 小时前
Cursor、飞算JavaAI、GitHub Copilot、Gemini CLI 等热门 AI 开发工具合集
人工智能·github·copilot