Normalization
约 797 字大约 3 分钟
2025-10-27
import torch
device = torch.device('cuda' if torch.cuda.is_available() else 'cpu')inputs = torch.tensor([[2,1000],[3,2000],[2,500],[1,800],[4,3000]], dtype=torch.float32,device=device)
labels = torch.tensor([[i] for i in [19,31,14,15,43]], dtype=torch.float32,device=device)w = torch.randn((2,1), requires_grad=True, device=device)
b = torch.randn(1, requires_grad=True, device=device)
lr = 0.00000001 # 学习率
epoch = 1000 # 迭代次数
for i in range(epoch):
outputs = inputs @ w + b
loss = torch.mean((outputs - labels) ** 2) # 均方误差
if i % 100 == 0:
print(i, loss.item())
loss.backward() # 反向传播,计算梯度
with torch.no_grad(): # 禁用梯度计算
w -= lr * w.grad # 更新权重
b -= lr * b.grad # 更新偏置
w.grad.zero_() # 清零梯度
b.grad.zero_() # 清零梯度运行结果
0 248004.734375 100 11.363458633422852 200 10.213571548461914 300 10.213533401489258 400 10.213497161865234 500 10.213469505310059 600 10.21343994140625 700 10.213404655456543 800 10.213374137878418 900 10.213348388671875
在这个案例发现,梯度值非常大,然后后面直接掉到了nan,即使我们的学习率调小到0.0000000001,可能不会出现这种问题,但是最后loss仍然不能有效减小
这是因为输入数据的量级差异过大,所以我们不得不迁就这个大数据把这个学习率调得非常小,导致训练非常缓慢。 根本原因就是w0和w1共用一个学习率,但取值范围相差太大
所以我们需要归一化调整。
inputs = inputs / torch.tensor([4,3000], dtype=torch.float32,device=device)
w = torch.ones((2,1), requires_grad=True, device=device)
b = torch.ones(1, requires_grad=True, device=device)
lr = 0.1 # 学习率
epoch = 1000 # 迭代次数
for i in range(epoch):
outputs = inputs @ w + b
loss = torch.mean((outputs - labels) ** 2) # 均方误差
if i % 100 == 0:
print(i, loss.item())
loss.backward() # 反向传播,计算梯度
with torch.no_grad(): # 禁用梯度计算
w -= lr * w.grad # 更新权重
b -= lr * b.grad # 更新偏置
w.grad.zero_() # 清零梯度
b.grad.zero_() # 清零梯度运行结果
0 609.12255859375 100 1.6897697448730469 200 0.6992129683494568 300 0.5244799256324768 400 0.4030836522579193 500 0.31000450253486633 600 0.23842385411262512 700 0.18337129056453705 800 0.14103056490421295 900 0.10846658051013947
标准化处理
x′=σx−μ
# 实际上,我们一般使用标准化处理
# 如果使用归一化处理可能这个最大值是异常值,导致受到异常值的影响,而标准化处理能够考虑到所有数据
inputs = torch.tensor([[2,1000],[3,2000],[2,500],[1,800],[4,3000]], dtype=torch.float32,device=device)
labels = torch.tensor([[i] for i in [19,31,14,15,43]], dtype=torch.float32,device=device)
mean = torch.mean(inputs, dim=0, keepdim=True) # 按列计算均值
std = torch.std(inputs, dim=0, keepdim=True) # 按列计算标准差
inputs = (inputs - mean) / std # 标准化处理
# inputs = inputs / torch.tensor([4,3000], dtype=torch.float32,device=device)
w = torch.ones((2,1), requires_grad=True, device=device)
b = torch.ones(1, requires_grad=True, device=device)
lr = 0.1 # 学习率
epoch = 1000 # 迭代次数
for i in range(epoch):
outputs = inputs @ w + b
loss = torch.mean((outputs - labels) ** 2) # 均方误差
if i % 100 == 0:
print(i, loss.item())
loss.backward() # 反向传播,计算梯度
with torch.no_grad(): # 禁用梯度计算
w -= lr * w.grad # 更新权重
b -= lr * b.grad # 更新偏置
w.grad.zero_() # 清零梯度
b.grad.zero_() # 清零梯度运行结果
0 635.2097778320312 100 0.13335631787776947 200 0.007916293106973171 300 0.0004698981065303087 400 2.7894759114133194e-05 500 1.6545803873668774e-06 600 9.813665968749774e-08 700 6.002847108277365e-09 800 3.9308362120848983e-10 900 3.9472071444723866e-11
注意,在预测的时候,也要对输入数据做同样的归一化处理!
为什么归一化不会影响模型?
对参数进行可逆线性变换,模型理论表达能力不变,不改变数据本质关系
什么时候进行归一化?
基本上深度学习会对所有参数进行归一化
