线性回归的间接实现
虽然线性回归很简单,但当我们使用pytorch的API去实现时,非常有利于理解其工作原理,便于以后的网络构建
必要包
import numpy as np
import torch
from torch.utils import data
生成数据的函数
# 定义一个函数,输入是w和b,输出是加上噪音后的这条线的散点
# synthetic_data 假数据
def synthetic_data(w, b, num_examples): #@save
"""⽣成y=Xw+b+噪声"""
# 生成正态分布的散点矩阵,有num_examples行,每一行是一个样本
X = torch.normal(0, 1, (num_examples, len(w)))
# 生成y
y = torch.matmul(X, w) + b
# y加上噪音
y += torch.normal(0, 0.01, y.shape)
return X, y.reshape((-1, 1))
构造一个数据迭代器,每次要能去除batchsize的数据
data.TensorDataset
data.DataLoader
torch.utils.data.TensorDataset是一个数据集类,将张量(Tensor)数据和对应的标签组合成一个数据集,处理训练数据和标签之间的对应。TensorDataset的初始化参数是一系列的张量,每个张量代表一个特征或标签。它会将这些张量按照第一个维度进行对齐,即每个张量的第一个维度大小必须相同。这样,TensorDataset会将每个张量的第i个元素组合成一个样本,形成一个数据集。
torch.utils.data.DataLoader是一个数据加载器类,将数据集按照指定的批次大小进行加载和迭代。它可以方便地对数据进行批处理、随机打乱和并行加载等操作。DataLoader的初始化参数包括数据集、批次大小、是否打乱数据、是否使用多线程等。通过调用DataLoader的__iter__方法,可以获得一个可迭代的数据加载器对象,每次迭代会返回一个批次的数据和对应的标签。使用TensorDataset和DataLoader可以方便地将数据集加载到模型中进行训练。
首先,将数据和标签组合成TensorDataset对象,然后使用DataLoader对TensorDataset进行批处理和迭代,将数据输入到模型中进行训练。这样可以提高数据的处理效率和模型的训练速度。
def load_array(data_arrays, batch_size, is_train=True): #@save
"""构造⼀个PyTorch数据迭代器"""
dataset = data.TensorDataset(*data_arrays) #传入一个元组tuple
return data.DataLoader(dataset, batch_size, shuffle=is_train)
构造数据
true_w = torch.tensor([2, -3.4])
true_b = 4.2
features, labels = synthetic_data(true_w, true_b, 1000)
batch_size = 10
data_iter = load_array((features, labels), batch_size)
# 查看数据 next()迭代器下一个元素 iter()转换为可迭代对象
# next(iter(data_iter))
构造模型
这里使用pytorch中神经网络的模型,按我的经验,一般先定义一个网络net(或者称为模型model),然后定义优化器optim,把参数传到这个优化器里,设置学习率,再定义一个损失,通过损失计算梯度,通过优化器更新
from torch import nn # nn即neural network缩写
net = nn.Sequential(nn.Linear(2, 1)) # 输入特征维数为2,输入为1
net[0].weight.data.normal_(0, 0.01) # 权重
net[0].bias.data.fill_(0) # 偏置
tensor([0.])
设置损失和优化算法
loss = nn.MSELoss()
# 定义小批量随机梯度下降算法
trainer = torch.optim.SGD(net.parameters(), lr=0.03)
训练
num_epochs = 3
# 注意每个epoch遍历一整个数据集
# 每个iter遍历一个batch
for epoch in range(num_epochs):
for X, y in data_iter:
# 计算损失
l = loss(net(X) ,y)
# 清除参数之前累积的梯度
trainer.zero_grad()
# 通过损失函数,对参数进行反向传播
l.backward()
# 使用反向传播的梯度,进行参数更新
trainer.step()
# 每个epoch的损失
l = loss(net(features), labels)
print(f'epoch {epoch + 1}, loss {l:f}')
epoch 1, loss 0.000286
epoch 2, loss 0.000097
epoch 3, loss 0.000097
比较误差
w = net[0].weight.data
print('w的估计误差: ', true_w - w.reshape(true_w.shape))
b = net[0].bias.data
print('b的估计误差: ', true_b - b)
w的估计误差: tensor([-0.0003, -0.0004])
b的估计误差: tensor([0.0004])