线性回归
利用一个简单的线性回归的例子来了解神经网络的实现逻辑。
导入需要的包
# 导入工具包
%matplotlib inline # 在plot时默认是嵌入到matplotlib里面
import random
import torch
from d2l import torch as d2l
1 线性回归-按照原理一步步实现
1.1 收集数据和整理数据
以预测房价为例子。比如说房子有很多特征(比如房子的面积,地理位置,房间的数量等等),这些特征会影响到房子的价格。
我们首先会收集数据,包括样本和标签,样本就是房子的特征信息,标签就是房子卖出的价格。
我们利用正太分布来生成一个人工的数据集:
# 构造一个简单的人造数据集
def synthetic_data(w, b, num_examples):
"""生成y=Xw+b+noise"""
X = torch.normal(0,1,(num_examples, len(w))) #均值为0,标准差为1
y = torch.matmul(X,w)+b
y += torch.normal(0,0.01, y.shape) # 添加随机噪声
return X, y.reshape((-1,1)) #将y作为一个列向量返回
true_w = torch.tensor([2,-3.4])
true_b = 4.2
features, labels = synthetic_data(true_w, true_b, 1000)
print('features:',features[0], '\nlabel',labels[0])
显示一下数据
# 显示一下数据集
d2l.set_figsize()
d2l.plt.scatter(features[:,1].detach().numpy(),
labels.detach().numpy(),1)
将数据进行分批,用于后续的批量训练
# 数据需要批量训练,构建一个提取批量数据函数
def data_iter(batch_size, features, labels):
num_examples = len(features)
indices = list(range(num_examples)) # 生成每一个数据的标号
random.shuffle(indices) # 打乱标号
for i in range(0, num_examples, batch_size):
batch_indices = torch.tensor(indices[i:min(i+batch_size, num_examples)]) # 使用min防止提取数据时超出
yield features[batch_indices], labels[batch_indices] # 使用yield不停的返回每一批数据
batch_size = 10
for X, y in data_iter(batch_size, features, labels):
print(X, '\n', y)
break
1.2 定义线性回归模型
# 定义模型,初始化参数
w = torch.normal(0, 0.01, size=(2,1), requires_grad=True)
b = torch.zeros(1, requires_grad = True) # 两个参数都需要计算梯度
# 定义线性回归模型
def linreg(X, w, b):
return torch.matmul(X, w)+b
1.3 定义损失函数和优化算法
# 定义训练过程中的损失函数-使用均方损失
def squared_loss(y_hat, y):
return (y_hat-y.reshape(y_hat.shape))**2/2 # 用reshape保持y与y_hat 维度一致
使用梯度下降算法
# 定义优化算法-小批量梯度下降
def sgd(params, lr, batch_size):
with torch.no_grad():
for param in params:
param -= lr * param.grad/batch_size # 前面定义损失函数时没有求平均,这里除以batch_size
param.grad.zero_() # pytorch的机制中梯度不会清零,这里要手动清除
1.4 设定超参数,开始训练模型,并输出损失
# 开始定义超参数和训练函数
lr = 0.03 #学习率
num_epochs = 3 #学习多少回合
net = linreg # 线性回归模型
loss = squared_loss # 均方损失函数
for epoch in range(num_epochs):
for X,y in data_iter(batch_size, features, labels):
l = loss(net(X, w, b), y) #这是一个批量的损失,l的形状是(batch_size,1)而不是一个标量
l.sum().backward() # 对l求和后再求梯度
sgd([w,b], lr, batch_size) # 使用梯度下降算法来更新参数
with torch.no_grad():
train_l = loss(net(features, w, b), labels) # 训练完成后,计算误差
print(f'epoch{epoch+1}, loss{float(train_l.mean()):f}')
结果
epoch1, loss0.045473
epoch2, loss0.000200
epoch3, loss0.000049
输出训练完成后w,b的误差
# 输出训练完成后w,b的误差
print(f'w的误差: {true_w-w.reshape(true_w.shape)}')
print(f'b的误差: {true_b-b}')
结果
w的误差: tensor([-0.0006, -0.0009])
b的误差: tensor([0.0014])
2 线性回归-利用torch中自带的方法进行简单实现
2.1 生成数据
import numpy as np
import torch
from torch.utils import data
from d2l import torch as d2l
true_w = torch.tensor([2,-3.4])
true_b = 4.2
features, labels = d2l.synthetic_data(true_w, true_b, 1000) # 用d2l中的工具生成人工数据和标签
# 将数据导入到pytorch自带的dataset集中,然后用自带的dataloader函数进行批量随机提取
def load_array(data_arrays, batch_size, is_train=True):
"""构造一个pytorch数据迭代器"""
dataset = data.TensorDataset(*data_arrays)
return data.DataLoader(dataset, batch_size, shuffle=is_train)
batch_size = 10
data_iter = load_array((features, labels), batch_size)
next(iter(data_iter))
2.2 构建线性回归模型
# 利用torch自带的方法构建神经网络模型,并初始化参数
from torch import nn
net = nn.Sequential(nn.Linear(2,1)) # 一层的线性网络
net[0].weight.data.normal_(0,0.01) # 使用正太分布函数初始化权重参数
net[0].bias.data.fill_(0)
2.3 损失函数和优化方法
# 损失函数
loss = nn.MSELoss()
# 优化方法
trainer = torch.optim.SGD(net.parameters(), lr=0.03)
2.4 训练模型
# 开始训练
num_epochs = 3
for epoch in range(num_epochs):
for X,y in data_iter:
l = loss(net(X), y)
trainer.zero_grad()
l.backward()
trainer.step()
l = loss(net(features), labels)
print(f'epoch{epoch+1}, loss{l: f}')
结果
epoch1, loss 0.000393
epoch2, loss 0.000100
epoch3, loss 0.000100