这一节中我们将用到更多 PyTorch 中的功能来更高效地实现线性回归。
本节内容可以参看莫烦教程的部分,重复的内容就不再本节赘述,害,刚入门学习的顺序有点乱。
3.3.1 生成数据集
这一部分与之前大同小异。torch 很大程度上可以替代 NumPy , 所以我把 NumPy 的一些方法也用 torch 来实现了。
# 生成数据集# 统一类型elem_type = torch.float32# 特征个数feature_size = 2# 样本数量example_size = 1000# 真实的模型参数 (w, b)true_w = torch.tensor([[2, -3.4]]).t()true_b = torch.tensor(4.2)# 输入特征features = torch.normal(0, 1, (example_size, feature_size), dtype=elem_type)# 标签, 需要加上正态分布的噪点labels = torch.mm(features, true_w) + true_blabels += torch.normal(0, 0.01, size=labels.size(), dtype=elem_type)
3.3.2 读取数据
torch_data 表示 torch.utils.data 这个模块, 这是 torch 中用于处理训练集的模块,读取数据的 data_iter 方法直接从中选取即可。
# 读取数据# 批次大小batch_size = 10# 将特征和标签组合成训练集data_set = torch_data.TensorDataset(features, labels)# 随机读取小批次样本data_iter = torch_data.DataLoader(data_set, batch_size, shuffle=True)for x, y in data_iter:print(x, '\n', y)break
运行结果
tensor([[ 0.3235, -0.6944],[-0.1412, 0.6338],[ 1.1980, -0.2269],[ 0.3041, -1.1575],[ 0.3344, 0.1352],[-0.4676, -0.3926],[-0.3720, 0.7803],[-0.0704, 0.8043],[ 0.3639, 0.2389],[-0.7440, -1.2381]])tensor([[7.2142],[1.7614],[7.3694],[8.7468],[4.4089],[4.6051],[0.8034],[1.3365],[4.1287],[6.9136]])
3.3.3 定义模型
这一次我们采用神经网络的方法来描述模型。
# 定义模型class LinearRegressionNet(torch.nn.Module):"""线性回归的神经网络模型, 只有输入层和输出层两层, 无隐藏层Attributes:output: 输出层"""def __init__(self, feature_size):"""定义神经网络的架构Args:feature_size: 输入层的特征数量Returns:无Raises:无"""super(LinearRegressionNet, self).__init__()self.output = torch.nn.Linear(feature_size, 1)def forward(self, x):"""定义前向传播的计算过程Args:x: 输入特征Returns:神经网络的输出层Raises:无"""return self.output(x)net = LinearRegressionNet(feature_size)print(net)# 查看参数for param in net.parameters():print(param)
运行结果
LinearRegressionNet((output): Linear(in_features=2, out_features=1, bias=True))Parameter containing:tensor([[0.5551, 0.5430]], requires_grad=True)Parameter containing:tensor([-0.1354], requires_grad=True)
我们可以看到网络的结构和参数。
以下提供几种快速搭建法,可以更加简洁地定义网络的架构。Sequential是一个有序的容器,网络层将按照在传入Sequential的顺序依次被添加到计算图中。
# 快递搭建网络# 方法 1net = torch.nn.Sequential(torch.nn.Linear(feature_size, 1)# 此处还可以写其他层)# 方法 2net = torch.nn.Sequential()net.add_module("output", torch.nn.Linear(feature_size, 1))# net.add_moudle() ......# 方法 3from collections import OrderedDictnet = torch.nn.Sequential(OrderedDict([("output", torch.nn.Linear(feature_size, 1))# ......]))
注意:
torch.nn仅支持输入一个batch的样本不支持单个样本输入,如果只有单个样本,可使用input.unsqueeze(0)来添加一维。
3.3.4 初始化模型参数
torch 自动对参数进行了初始化,当然我们也可以用torch.nn.init自己设定初始值。torch.nn.init 模块中不带_的方法已经弃用,使用带 _ 的。
# 初始化模型参数from torch.nn import init # 参数初始化模块init.normal_(net.output.weight, mean=0, std=0.01)init.constant_(net.output.bias, val=0)
3.3.5 选择损失函数
这次我们不用再自己定义损失函数了,从 torch 的库中挑选即可,我们依旧选择平方误差函数。
# 选择损失函数loss_func = torch.nn.MSELoss()
3.3.6 选择优化算法
# 选择随机梯度下减法optimizer = torch.optim.SGD(net.parameters(), lr=0.03)print(optimizer)
运行结果
SGD (Parameter Group 0dampening: 0lr: 0.03momentum: 0nesterov: Falseweight_decay: 0)
以下是对于学习率的一些补充,当然在这个例子中还用不上。
当我们需要更加精确的学习率时,我们可以为不同的子网络单独设置学习率
# 为不同的子网络设置不同的学习率optimizer = torch.optim.SGD([# 如果对某个参数不指定学习率,就使用最外层的默认学习率{'params': net.subnet1.parameters()}, # lr=0.03{'params': net.subnet2.parameters(), 'lr': 0.01}], lr=0.03)
有时候我们甚至需要学习率是动态变化的而非一个固定的常数,我们当然可以重新配置一个优化器(这对于使用动量的优化算法比如 Adam 存在一定风险)。也可以通过修改 param_groups 属性来实现。
# 调整学习率for param_group in optimizer.param_groups:# 学习率调整为之前的 0.1param_group["lr"] *= 0.1
3.3.7 训练模型
这一步变化不大
# 训练模型# 迭代次数iterate_num = 3for i in range(iterate_num + 1):for x, y in data_iter:output = net(x)lose = loss_func(output, y.view(output.size()))optimizer.zero_grad()lose.backward()optimizer.step()print("第{0}次迭代后的损失为{1:.7f}".format(i + 1, lose.item()))
运行结果
第1次迭代后的损失为0.0001321第2次迭代后的损失为0.0001269第3次迭代后的损失为0.0000623第4次迭代后的损失为0.0001002
最后
打印结果
print(true_w, true_b)print(net.output.weight, net.output.bias)
运行结果
tensor([[ 2.0000],[-3.4000]]) tensor(4.2000)Parameter containing:tensor([[ 1.9993, -3.3998]], requires_grad=True) Parameter containing:tensor([4.1995], requires_grad=True)
小结
整体流程是一致的,PyTorch 提供了相当多的组件,我们在搭建和训练模型时,更多得是需要选择适合问题的功能来使用。以下四个模块是常用的,注意一下它们的功能。torch.utils.data: 提供了有关数据处理的工具torch.nn: 定义了大量神经网络的层,误差函数torch.nn.init: 定义了各种初始化方法torch.optim: 提供了很多常用的优化算法。
