定义模型
下面是线性回归的矢量计算表达式的实现,使用mm函数做矩阵乘法。
def linreg(X,w,b):
return torch.mm(X,w) + b
定义损失函数
使用平方损失来定义线型回归的损失函数。
需要把真实值y变成预测值y_hat的形状。
函数返回结果也和y_hat的形状相同。
def squared_loss(y_hat,y):
#返回值仍是向量,此外,pytorch中的MSELoss并没有除以2
return (y_hat-y.view(y_hat.size()))**2/2
定义优化算法
sgd函数实现了小批量随机梯度下降算法,通过不断迭代模型参数来优化损失函数。这里自动求梯度模块计算得来的梯度是一个批量样本的梯度和。
除以样本的大小来得到平均值。
def sgd(params,lr,batch_size):
for param in params:
param.data -= lr * param.grad/ batch_size
训练模型
训练时,迭代模型参数。每次得带,根据当前的小批量数据样本,通过调用反向函数backward计算小批量随机梯度,并用sgd算法迭代优化模型参数。
由于batch_size设为10,每个小批量的loss形状为(10,1)。
由于l不是一个标量,所以可以提前调用.sum()将其求和得到一个标量。在运行l.backward()得到该变量有关模型参数的梯度。
重点,每次更新完参数要将梯度清零。
在一个迭代周期(epoch)中,将完整遍历一遍data_iter函数,并且数据集中的所有样本都使用一次。
迭代周期个数num_epochs和虚席率lr都是超参数,分别设3和0.03.
在实践中,大多数超参数都需要通过反复是错来不断调节。
虽然迭代周期数设的越大模型可能越有效,但是训练时间可能过长。
lr = 0.03
num_epochs = 3
net = linreg
loss = squared_loss
for epoch in range(num_epochs):
#一个训练epoch个周期
#每个迭代周期会使用一次所有数据集样本
#X和y分别是小批量样本的特征和标签
for X,y in data_iter(batch_size,features,labels):
l = loss(net(X,w,b),y).sum()
l.backward()
sgd([w,b], lr, batch_size)
#重点:梯度清零
w.grad.data.zero_()
b.grad.data.zero_()
train_l = loss(net(features,w,b),labels)
print('epoch %d, loss %f'% (epoch + 1, train_l.mean().item()))
输出:
epoch 1, loss 0.032553
epoch 2, loss 0.000111
epoch 3, loss 0.000047
训练之后可以比较学到的参数和真实的参数,应该很接近。
print(true_w, '\n', w)
print(true_b, '\n', b)
输出:
[2, -3.4]
tensor([[ 2.0005],
[-3.4000]], requires_grad=True)
4.2
tensor([4.1989], requires_grad=True)
线性回归的简洁实现
使用PyTorch更方便的实现线性回归
生成数据集
num_inputs = 2
num_examples = 1000
true_w = [2,-3.4]
true_b = 4.2
features = torch.tensor(np.random.narmal(0,1,(num_examples,num_inputs)),dtype = torch.float)
labels = true_w[0] * features[:, 0] + true_w[1] * features[:, 1] + true_b
labels += torch.tensor(np.random.normal(0,0.01, size = labels.size()),dtype = torch.float)
读取数据
PyTorch提供了data包用来读取数据
由于data常用于变量名,所以将导入的data模块用Data代替。在每一次迭代中,随机读取batch_size为10的样本
import torch.utils.data as Data
batch_size = 10
#将训练数据的样本和标签结合
data = Data.TensorDataset(features,labels)
#随机读取
data_iter = Data.DataLoader(dataset, batch_size, shuffle = True)
读取并打印第一组样本
for X,y in data_iter:
print(X,y)
break
输出
tensor([[ 1.1560, 0.5133],
[-1.3982, 0.0846],
[ 0.4936, 0.7641],
[ 1.5037, -1.1534],
[ 0.5931, -0.9144],
[-0.4403, 0.8581],
[-0.3884, 1.0050],
[-1.4649, -1.4879],
[-1.1145, -0.1628],
[-0.2325, 0.1286]]) tensor([ 4.7585, 1.1172, 2.6008, 11.1254, 8.5001, 0.4031, 0.0118, 6.3202,
2.5142, 3.3013])