本文仅作为个人学习笔记用,如有错误请指正,欢迎大家讨论学习。本博客内容来自动手学深度学习
一、线性回归的简洁实现
在过去的几年里,出于对深度学习强烈的兴趣, 许多公司、学者和业余爱好者开发了各种成熟的开源框架。 这些框架可以自动化基于梯度的学习算法中重复性的工作。 实际上,由于数据迭代器、损失函数、优化器和神经网络层很常用, 现代深度学习库也为我们实现了这些组件。
1.数据集
想跑代码的同学,可以先下载好Pycharm以及Anaconda,以及相应环境,可以用电脑配置允许下的较新版本。
导包
import numpy as np
import torch
from torch.utils import data
from d2l import torch as d2l
from torch import nn
创建数据集
Tensor(张量)是包含单一数据类型元素的多维数组,它是 PyTorch 中数据存储和运算的基本单元,类似于 NumPy 的numpy.ndarray
。
代码定义了两个PyTorch张量(tensors),true_w
是模型的真实权重,包含两个元素 [2, -3.4];true_b
是模型的真实偏置,值为 4.2。这些值通常用于生成或评估模型的性能。
该函数根据给定的真实权重true_w
和偏置 true_b
生成了一个包含1000个样本的数据集。数据集分为特征 features
和标签 labels
两部分。
true_w = torch.tensor([2, -3.4])
true_b = 4.2
features, labels = d2l.synthetic_data(true_w, true_b, 1000) # 库函数生成人工数据集
读取数据集
我们可以调用框架中现有的API来读取数据。 我们将features
和labels
作为API的参数传递,并通过数据迭代器指定batch_size
。 此外,布尔值is_train
表示是否希望数据迭代器对象在每个迭代周期内打乱数据。
使用data_iter
的方式是为了验证是否正常工作,让我们读取并打印第一个小批量样本。 这里我们使用iter构造Python迭代器,并使用next从迭代器中获取第一项。
def load_array(data_arrays, batch_size, is_train=True):
"""构造一个Pytorch数据迭代器"""
dataset = data.TensorDataset(*data_arrays) # dataset相当于Pytorch的Dataset。一个星号*,表示对list解开入参。
return data.DataLoader(dataset, batch_size, shuffle=is_train) # 返回的是从dataset中随机挑选出batch_size个样本出来
batch_size = 10
data_iter = load_array((features, labels), batch_size) # 返回的数据的迭代器
print(next(iter(data_iter))) # iter(data_iter) 是一个迭代器对象,next是取迭代器里面的元素
定义模型
在PyTorch中,nn.Sequential
是一个容器,它允许你将多个神经网络层按顺序堆叠起来。net = nn.Sequential(nn.Linear(2, 1))
创建了一个简单的神经网络模型 net,该模型仅包含一个线性层(也称为全连接层或密集层)。
具体来说,nn.Linear(2, 1)
定义了一个线性层,它接受输入特征的数量为2(即输入向量的维度是2),并输出一个单一的特征(即输出向量的维度是1)。这种层通常用于线性回归任务,其中你需要预测一个连续的值,但也可以作为更复杂神经网络中的一部分。
将nn.Linear(2, 1)
包裹在 nn.Sequential
中是为了方便管理模型的架构,尽管在这个例子中只包含一个层,但在构建更复杂的模型时,你可以通过简单地添加更多的层到nn.Sequential
容器中来扩展模型。
# 使用框架的预定义好的层
# nn是神经网络的缩写
net = nn.Sequential(nn.Linear(2, 1))
初始化模型参数
在使用net之前,我们需要初始化模型参数。 如在线性回归模型中的权重和偏置。 深度学习框架通常有预定义的方法来初始化参数。 在这里,我们指定每个权重参数应该从均值为0、标准差为0.01的正态分布中随机采样, 偏置参数将初始化为零。
正如我们在构造nn.Linear
时指定输入和输出尺寸一样, 现在我们能直接访问参数以设定它们的初始值。 我们通过net[0]选择网络中的第一个图层, 然后使用weight.data
和bias.data
方法访问参数。
net[0].weight.data.normal_(0, 0.01) # 使用正态分布替换掉weight变量里面的数据值
net[0].bias.data.fill_(0) # 偏差bias变量里面的值设置为0
print(net[0])
定义损失函数
计算均方误差使用的是MSELoss类,也称为平方 L 2 L_2 L2范数。 默认情况下,它返回所有样本损失的平均值。
# 计算均方误差使用的是MSELoss类,也称为平方L2范数
loss = nn.MSELoss() # L1是算术差,L2是平方差
定义优化算法
小批量随机梯度下降算法是一种优化神经网络的标准工具, PyTorch在optim模块中实现了该算法的许多变种。 当我们实例化一个SGD实例时,我们要指定优化的参数 (可通过net.parameters()
从我们的模型中获得)以及优化算法所需的超参数字典。 小批量随机梯度下降只需要设置lr值,这里设置为0.03。
# 实例化SGD实例
trainer = torch.optim.SGD(net.parameters(), lr=0.03)
训练
通过深度学习框架的高级API来实现我们的模型只需要相对较少的代码。 我们不必单独分配参数、不必定义我们的损失函数,也不必手动实现小批量随机梯度下降。 当我们需要更复杂的模型时,高级API的优势将大大增加。 当我们有了所有的基本组件,训练过程代码与我们从零开始实现时所做的非常相似。
回顾一下:在每个迭代周期里,我们将完整遍历一次数据集train_data
, 不停地从中获取一个小批量的输入和相应的标签。 对于每一个小批量,我们会进行以下步骤:
1.通过调用net(X)生成预测并计算损失 l l l(前向传播)。
2.通过进行反向传播来计算梯度。
3.通过调用优化器来更新模型参数。
为了更好的衡量训练效果,我们计算每个迭代周期后的损失,并打印它来监控训练过程。
# 训练过程代码与从零开始时所做的非常相似
num_epochs = 3
for epoch in range(num_epochs):
for X, y in data_iter: # 从DataLoader里面一次一次把所有数据拿出来
# print("X:",X)
# print("y:",y)
l = loss(net(X), y) # net(X) 为计算出来的线性回归的预测值
trainer.zero_grad() # 梯度清零
l.backward()
trainer.step() # SGD优化器优化模型
l = loss(net(features), labels)
print(f'epoch{epoch + 1},loss{l:f}')
二、所有代码及运行结果
import numpy as np
import torch
from torch.utils import data
from d2l import torch as d2l
from torch import nn
true_w = torch.tensor([2, -3.4])
true_b = 4.2
features, labels = d2l.synthetic_data(true_w, true_b, 1000) # 库函数生成人工数据集
# 调用框架现有的API来读取数据
def load_array(data_arrays, batch_size, is_train=True):
"""构造一个Pytorch数据迭代器"""
dataset = data.TensorDataset(*data_arrays) # dataset相当于Pytorch的Dataset。一个星号*,表示对list解开入参。
return data.DataLoader(dataset, batch_size, shuffle=is_train) # 返回的是从dataset中随机挑选出batch_size个样本出来
batch_size = 10
data_iter = load_array((features, labels), batch_size) # 返回的数据的迭代器
print(next(iter(data_iter))) # iter(data_iter) 是一个迭代器对象,next是取迭代器里面的元素
# 使用框架的预定义好的层
# nn是神经网络的缩写
net = nn.Sequential(nn.Linear(2, 1))
# 初始化模型参数
net[0].weight.data.normal_(0, 0.01) # 使用正态分布替换掉weight变量里面的数据值
net[0].bias.data.fill_(0) # 偏差bias变量里面的值设置为0
print(net[0])
# 计算均方误差使用的是MSELoss类,也称为平方L2范数
loss = nn.MSELoss() # L1是算术差,L2是平方差
# 实例化SGD实例
trainer = torch.optim.SGD(net.parameters(), lr=0.03)
# 训练过程代码与从零开始时所做的非常相似
num_epochs = 3
for epoch in range(num_epochs):
for X, y in data_iter: # 从DataLoader里面一次一次把所有数据拿出来
# print("X:",X)
# print("y:",y)
l = loss(net(X), y) # net(X) 为计算出来的线性回归的预测值
trainer.zero_grad() # 梯度清零
l.backward()
trainer.step() # SGD优化器优化模型
l = loss(net(features), labels)
print(f'epoch{epoch + 1},loss{l:f}')