【pytorch】weight_norm和spectral_norm
- 游戏开发
- 2025-09-07 18:45:02

apply_parametrization_norm 和spectral_norm是 PyTorch 中用于对模型参数进行规范化的方法,但它们在实现和使用上有显著的区别。以下是它们的主要区别和对比:
实现方式 weight_norm:weight_norm 是一种参数重参数化技术,将权重分解为两个部分:方向(v) 和 大小(g)。 具体来说,权重 w 被重参数化为:
其中,g 是标量,表示权重的大小;v 是向量,表示权重的方向。 这种方法通过分离权重的大小和方向,使得优化过程更加稳定。
归一化后的权重向量实际上是 v 的归一化形式,即 v_normalized = v / ||v||,而 weight 的值为 g * v_normalized
spectral_norm:spectral_norm 是一种基于谱范数的规范化方法,谱范数定义为矩阵 M 的最大奇异值:
具体来说,谱范数是矩阵 M 作用在单位向量上时的最大放大因子。
作用:通过限制矩阵的最大奇异值,控制矩阵的放大能力,从而提高模型的稳定性和泛化能力
通过幂迭代法(Power Iteration)计算矩阵的最大奇异值。具体步骤如下: 初始化两个向量 u 和 v。 迭代计算:
最大奇异值
然后将权重规范化为
使用场景 weight_norm:主要用于规范化权重,特别适用于需要控制权重大小的场景。 例如,在某些生成模型或自注意力机制中,权重的大小对模型的稳定性和性能有重要影响。 weight_norm 提供了一种简单且直接的方式来实现权重的规范化。
spectral_norm:常用于生成对抗网络(GAN)中,通过限制生成器和判别器的最大奇异值,提高模型的稳定性和泛化能力。 优点:能够有效控制矩阵的放大能力,适用于需要限制模型输出范围的场景
代码样例 weight_norm: import random import torch import torch.nn as nn import torch.optim as optim import torch.nn.utils.weight_norm as weight_norm # 创建一个简单的线性层 linear_layer = nn.Linear(2, 3) # Override the weights of linear_layer linear_layer.weight.data = torch.tensor([[0, -2e-2], [0.3, 1.0], [1e-2, 0]], dtype=torch.float32) # 3x2 linear_layer.bias.data = torch.tensor([-0.3, 0, -2e-2], dtype=torch.float32) # 3x1 # Apply weight normalization linear_layer = weight_norm(linear_layer, name='weight') optimizer = optim.Adam(linear_layer.parameters(), lr=2e-3) # 打印原始权重 print("################原始权重:################") print("linear_layer.weight_v: ", linear_layer.weight_v) print("linear_layer.weight_g: ", linear_layer.weight_g) print("linear_layer.weight: ", linear_layer.weight) print("linear_layer.bias: ", linear_layer.bias) # 前向传播 for i in range(1000): input_tensor = torch.randn(10, 2) * random.random() * 10 output = linear_layer(input_tensor) loss = (1 - output.mean()) optimizer.zero_grad() loss.backward() # 反向传播,触发梯度计算 optimizer.step() # 打印规范化后的权重 print("################规范化后的权重:#################") print("linear_layer.weight_v: ", linear_layer.weight_v) print("linear_layer.weight_g: ", linear_layer.weight_g) print("linear_layer.bias: ", linear_layer.bias) # Optionally, print the effective weight print("linear_layer.weight (effective): ", linear_layer.weight) # ... existing code... # 前向传播 #input_tensor = torch.tensor([[1.0, 2.0]], dtype=torch.float32) # 1x2 for i in range(1000): input_tensor = torch.randn(10, 2)*random.random()*10 output = linear_layer(input_tensor) optimizer.zero_grad() (1-output.mean()).backward() # 反向传播,触发梯度计算 optimizer.step() # 更新权重 output = linear_layer(input_tensor) optimizer.zero_grad() (1-output.mean()).backward() # 反向传播,触发梯度计算 optimizer.step() # 更新权重 # 打印规范化后的权重 print("################规范化后的权重:#################") print("linear_layer.weight: ", linear_layer.weight) # 权重的大小 print("linear_layer.bias: ", linear_layer.bias) print("linear_layer.weight_v: ", linear_layer.weight_v) print("linear_layer.weight_g: ", linear_layer.weight_g)输出结果
################原始权重:################ linear_layer.weight_v: Parameter containing: tensor([[ 0.0000, -0.0200], [ 0.3000, 1.0000], [ 0.0100, 0.0000]], requires_grad=True) linear_layer.weight_g: Parameter containing: tensor([[0.0200], [1.0440], [0.0100]], requires_grad=True) linear_layer.weight: tensor([[ 0.0000, -0.0200], [ 0.3000, 1.0000], [ 0.0100, 0.0000]], grad_fn=<WeightNormInterfaceBackward0>) linear_layer.bias: Parameter containing: tensor([-0.3000, 0.0000, -0.0200], requires_grad=True) ################规范化后的权重:################# linear_layer.weight_v: Parameter containing: tensor([[0.0599, 0.0568], [0.4113, 0.8878], [0.0544, 0.0556]], requires_grad=True) linear_layer.weight_g: Parameter containing: tensor([[0.1038], [1.1324], [0.0897]], requires_grad=True) linear_layer.bias: Parameter containing: tensor([1.7000, 2.0000, 1.9800], requires_grad=True) linear_layer.weight (effective): tensor([[0.0751, 0.0716], [0.4758, 1.0276], [0.0625, 0.0643]], grad_fn=<WeightNormInterfaceBackward0>) spectral_norm: import torch import torch.nn as nn import torch.optim as optim import torch.nn.utils.weight_norm as spectral_norm # 创建一个简单的线性层 linear_layer = nn.Linear(2, 3) # 覆盖线性层的权重 linear_layer.weight.data = torch.tensor([[0, -2e2], [0.3, 1.0], [1e2, 0]], dtype=torch.float32) # 3x2 linear_layer.bias.data = torch.tensor([-0.3, 0, -2e2], dtype=torch.float32) # 3x1 # 应用 weight_norm linear_layer = spectral_norm(linear_layer, name='weight') # 定义优化器 optimizer = optim.Adam(linear_layer.parameters(), lr=1e-4) # 打印原始权重 print("\n################ 原始权重:################\n") print("linear_layer.weight: ", linear_layer.weight) print("linear_layer.bias: ", linear_layer.bias) # 前向传播及训练 for i in range(1000): input_tensor = torch.randn(10, 2) output = linear_layer(input_tensor) loss = (1 - output.mean()) # 损失函数 optimizer.zero_grad() loss.backward() # 反向传播 optimizer.step() # 更新权重 # 打印规范化后的权重 print("\n################ 规范化后的权重:################\n") print("linear_layer.weight: ", linear_layer.weight) # 权重的大小 print("linear_layer.bias: ", linear_layer.bias) print("linear_layer.weight_v: ", linear_layer.weight_v) print("linear_layer.weight_g: ", linear_layer.weight_g)输出结果
################ 原始权重:################ linear_layer.weight: tensor([[ 0.0000, -200.0000], [ 0.3000, 1.0000], [ 100.0000, 0.0000]], grad_fn=<WeightNormInterfaceBackward0>) linear_layer.bias: Parameter containing: tensor([ -0.3000, 0.0000, -200.0000], requires_grad=True) ################ 规范化后的权重:################ linear_layer.weight: tensor([[-1.7618e-04, -2.0000e+02], [ 2.9977e-01, 9.9956e-01], [ 1.0000e+02, -3.6516e-04]], grad_fn=<WeightNormInterfaceBackward0>) linear_layer.bias: Parameter containing: tensor([-2.0001e-01, 1.0000e-01, -1.9989e+02], requires_grad=True) linear_layer.weight_v: Parameter containing: tensor([[-2.0177e-04, -2.0001e+02], [ 2.9990e-01, 1.0001e+00], [ 1.0001e+02, -3.7132e-04]], requires_grad=True) linear_layer.weight_g: Parameter containing: tensor([[200.0006], [ 1.0435], [ 99.9998]], requires_grad=True)【pytorch】weight_norm和spectral_norm由讯客互联游戏开发栏目发布,感谢您对讯客互联的认可,以及对我们原创作品以及文章的青睐,非常欢迎各位朋友分享到个人网站或者朋友圈,但转载请说明文章出处“【pytorch】weight_norm和spectral_norm”