数据归一化可以将特征和标签映射到一个相对固定的范围内。
没有使用数据归一化的线性回归
import torch
import torch.nn
import torch.optim
x=torch.tensor([[1000000,0.0001],
[2000000,0.0003],
[3000000,0.0005],
[4000000,0.0002],
[5000000,0.0004]
])
y=torch.tensor([-1000.,1200.,1400.,1600.,1800.]).reshape(-1,1)
fc=torch.nn.Linear(2,1)
criterion=torch.nn.MSELoss()
optimizer=torch.optim.Adam(fc.parameters())
for step in range(10001):
if step:
optimizer.zero_grad()
loss.backward()
optimizer.step()
pred=fc(x)
loss=criterion(pred,y)
if step%1000==0:
print('step{},loss{:g}'.format(step,loss))
结果:
使用数据归一化的线性回归
import torch
import torch.nn
import torch.optim
x=torch.tensor([[1000000,0.0001],
[2000000,0.0003],
[3000000,0.0005],
[4000000,0.0002],
[5000000,0.0004]
])
y=torch.tensor([-1000.,1200.,1400.,1600.,1800.]).reshape(-1,1)
x_mean,x_std=torch.mean(x,dim=0),torch.std(x,dim=0)
x_norm=(x-x_mean)/x_std
y_mean,y_std=torch.mean(y,dim=0),torch.std(y,dim=0)
y_norm=(y-y_mean)/y_std
fc=torch.nn.Linear(2,1)
criterion=torch.nn.MSELoss()
optimizer=torch.optim.Adam(fc.parameters())
for step in range(10001):
if step:
optimizer.zero_grad()
loss_norm.backward()
optimizer.step()
pred_norm=fc(x_norm)
loss_norm=criterion(pred_norm,y_norm)
pred=pred_norm*y_std+y_mean
loss=criterion(pred,y)
if step%1000==0:
print('step{},loss{:g}'.format(step,loss))
结果:
可见,当归一化的时候,loss能够更低,下降的更加稳定。
世界人口线性回归实例
完整代码:
import torch
import torch.nn
import torch.optim
import pandas as pd
import matplotlib.pyplot as plt
# 读取数据
url=r'https://en.wikipedia.org/wiki/Estimates_of_historical_world_population#1950_to_2016'
df=pd.read_html(url,header=0,attrs={"class":"wikitable"})[2]
print(df)
years=torch.tensor(df.iloc[:,0],dtype=torch.float32)
populations=torch.tensor(df.iloc[:,1],dtype=torch.float32)
x=years.reshape(-1,1)
y=populations
x_mean,x_std=torch.mean(x),torch.std(x)
x_norm=(x-x_mean)/x_std
y_mean,y_std=torch.mean(y),torch.std(y)
y_norm=(y-y_mean)/y_std
fc=torch.nn.Linear(1,1)
criterion=torch.nn.MSELoss()
optimizer=torch.optim.Adam(fc.parameters())
weight_norm,bias_norm=fc.parameters()
for step in range(5001):
if step:
optimizer.zero_grad()
loss_norm.backward()
optimizer.step()
output_norm=fc(x_norm)#预测的输出
pred_norm=output_norm.squeeze()
loss_norm=criterion(pred_norm,y_norm)#loss值
# 通过下面两个式子,将经过Adam优化器优化得到的权重值转化为适用于原始特征和标签的权重值
weigh=y_std/x_std*weight_norm
bias=(weight_norm*(0-x_mean)/x_std+bias_norm)*y_std+y_mean
if step%1000==0:
print('第{}步:weight={},bias={}'.format(step,weigh.item(),bias.item()))
w,b=weigh.item(),bias.item()
#数据可视化
plt.plot(years,populations)
plt.xlabel('Year')
plt.ylabel('population')
y_pred=[ w*year+b for year in years]
plt.plot(years,y_pred,color='red')
plt.show()
结果: