3.2线性回归的从零开始实现
%matplotlib inline
import random
import torch
from d2l import torch as d2l
-
%matplotlib inline
是 Jupyter Notebook 或 JupyterLab 中的一个魔术命令,用于在 Notebook 中显示 matplotlib 图形的输出。 -
import random
导入了 Python 的 random 模块,用于生成随机数。 -
import torch
导入了 PyTorch 库,用于深度学习任务。 -
from d2l import torch as d2l
导入了 d2l 模块,并将其重命名为 d2l。d2l 是 Dive into Deep Learning (D2L) 图书的一个开源教学库,用于深度学习的代码实现和示例。
3.2.1生成数据集
def synthetic_data(w, b, num_examples):
"""生成y=Xw+b+噪声"""
X = torch.normal(0, 1, (num_examples, len(w)))
y = torch.matmul(X, w) + b
y += torch.normal(0, 0.01, y.shape)
return X, y.reshape((-1, 1))
这段代码定义了一个函数 synthetic_data()
,用于生成合成数据集。
参数说明:
w
:权重张量,用于线性组合特征数据。b
:偏置项,添加到线性组合结果中。num_examples
:生成的样本数量。
函数实现:
-
X = torch.normal(0, 1, (num_examples, len(w)))
:生成一个形状为(num_examples, len(w))
的张量X
,其中的元素是从均值为 0、标准差为 1 的正态分布中随机抽取的。这个张量表示特征数据,每一行都是一个样本,每一列对应于特征的维度。 -
y = torch.matmul(X, w) + b
:通过执行矩阵乘法torch.matmul()
,将特征数据X
与权重张量w
相乘,并添加偏置项b
,得到原始的目标值y
。这里假设w
是一个列向量。 -
y += torch.normal(0, 0.01, y.shape)
:向目标值y
中添加服从均值为 0、标准差为 0.01 的正态分布噪声,以增加数据的随机性和真实性。 -
return X, y.reshape((-1, 1))
:返回特征数据X
和目标值y
。为了确保目标值y
的形状是(num_examples, 1)
,使用y.reshape((-1, 1))
对其进行形状重塑。
解释reshape
y.reshape((-1, 1))
是对张量y
进行形状重塑操作的代码。在 PyTorch 中,
reshape()
方法用于改变张量的形状。传递给reshape()
的参数是一个元组,其中包含所期望的新形状。在这里,(-1, 1)
表示将张量y
的形状调整为(n, 1)
,其中n
是根据原始张量y
的元素数量和原始形状推断得到的。为了更好地理解这个过程,让我们来看一个具体的例子:
import torch
y = torch.tensor([1, 2, 3, 4, 5, 6]) # 假设 y 的形状为 (6,)
# 对 y 进行形状重塑为 (6, 1)
y_reshaped = y.reshape((-1, 1))
print(y_reshaped)
输出结果:
tensor([[1],
[2],
[3],
[4],
[5],
[6]])
在上面的例子中,我们有一个形状为 (6,) 的张量
y
,表示具有 6 个元素的一维数组。通过调用y.reshape((-1,1))
,我们将其形状调整为 (6, 1),即一个列向量。
-1
在形状重塑中的作用是根据其他维度的大小自动计算。在这个例子中,由于我们指定了(6, 1)
,-1
表示 PyTorch会自动计算并填充所需的大小,以满足张量元素数量不变的条件。因此,y
的形状通过reshape()
操作变为(6, 1)
。重塑张量的目的可能是为了与其他张量进行运算或满足特定的形状要求。在机器学习中,常常需要将目标值调整为二维张量,以便与模型的输出进行比较和计算损失。因此,
y.reshape((-1, 1))
将一维的目标值张量y
重塑为了一个列向量,以满足这样的要求。
- 总结起来,这个函数生成了一个合成数据集,其中特征数据
X
是从正态分布中随机生成的,目标值y
是通过对特征数据和权重进行线性组合并添加噪声生成的。这种合成数据集的生成可以用于模型训练和测试中,以便进行模型的开发和评估。
true_w = torch.tensor([2, -3.4])
true_b = 4.2
features, labels = synthetic_data(true_w, true_b, 1000)
当我们运行这段代码时,它会生成一个合成数据集,其中包括特征数据和对应的标签数据。
具体解释如下:
-
true_w = torch.tensor([2, -3.4])
:我们定义了一个名为true_w
的张量,其中包含了两个元素[2, -3.4]
。这代表了真实的权重,即特征数据与标签数据之间的线性关系。 -
true_b = 4.2
:我们定义了一个标量true_b
,表示真实的偏置项,即线性关系中的常数项。 -
features, labels = synthetic_data(true_w, true_b, 1000)
:我们调用synthetic_data()
函数,并传入真实的权重true_w
、真实的偏置项true_b
和样本数量1000
。 -
在
synthetic_data()
函数内部,它会根据传入的真实权重和偏置项,生成合成的特征数据和标签数据。 -
特征数据
features
是一个形状为(1000, 2)
的张量,其中的每一行表示一个样本,每一列对应于特征的维度。特征数据是通过从均值为 0、标准差为 1 的正态分布中生成的随机数来创建的。 -
标签数据
labels
是一个形状为(1000, 1)
的张量,其中的每一行表示一个样本的标签。标签数据是通过将特征数据与真实的权重相乘并加上真实的偏置项生成的。此外,还添加了服从均值为 0、标准差为 0.01 的正态分布噪声,以增加数据的随机性和真实性。
总结起来,这段代码生成了一个合成的数据集,其中包括了特征数据 features
和对应的标签数据 labels
。这个合成数据集可以用于模型的训练和评估,以帮助我们理解和开发机器学习模型。
print('features:', features[0],'\nlabel:', labels[0])
运行这段代码将打印出第一个样本的特征数据和标签数据。
输出结果类似于:
features: tensor([0.1234, -1.5678])
label: tensor([4.5623])
在这个例子中,我们假设 features
是一个形状为 (1000, 2)
的张量,而 labels
是一个形状为 (1000, 1)
的张量。
-
features[0]
表示第一个样本的特征数据。这是一个长度为 2 的张量,它包含了第一个样本的两个特征值。在上面的示例输出中,特征值是[0.1234, -1.5678]
。 -
labels[0]
表示第一个样本的标签数据。这是一个标量(长度为 1 的张量),它包含了第一个样本的标签值。在示例输出中,标签值是4.5623
。
通过打印特征数据和标签数据,我们可以查看样本的具体值,并对数据集的结构有更好的了解。
d2l.set_figsize()
d2l.plt.scatter(features[:, 1].detach().numpy(), labels.detach().numpy(), 1)
解释如下:
-
d2l.set_figsize()
:这行代码是调用了 d2l 库中的函数set_figsize()
,它用于设置绘图的尺寸大小,以便更好地适应显示环境。如果你不提供参数,可能会使用默认的尺寸 -
d2l.plt.scatter()
:这行代码是调用了 d2l 库中的函数scatter()
,它用于绘制散点图。它接受特征数据和标签数据作为参数,并将它们绘制成散点图。 -
features[:, 1].detach().numpy()
:这部分代码表示从特征数据中选择第二个维度的数据,并将其转换为 NumPy 数组。.detach()
方法用于将张量从计算图中分离,.numpy()
方法将张量转换为 NumPy 数组。 -
labels.detach().numpy()
:这部分代码表示将标签数据转换为 NumPy 数组。
注解:
在这段代码中,
detach()
方法的作用是将张量从计算图中分离,并将其转换为 NumPy 数组。如果你将detach()
去掉,仍然可以得到类似的结果,但会有一些细微的差别。
这样做的结果是,
features[:, 1].numpy()
和labels.numpy()
会返回张量数据的 NumPy表示,而不再是分离出来的张量。主要的差异在于梯度计算和内存管理方面:
梯度计算:移除
detach()
方法后,生成的张量会保持与原始计算图相关联。如果在后续的计算过程中需要对这些张量进行梯度计算,梯度会在计算图中回传,影响梯度传播和参数更新。内存管理:移除
detach()
方法后,生成的张量会继续与原始计算图共享存储,因此可能需要更多的内存来保存梯度信息和计算历史。这可能会导致更高的内存消耗。
总之,如果你移除
detach()
方法,代码仍然可以运行并得到类似的结果。然而,保留detach()
方法可以明确指示你不需要与计算图相关的梯度信息,并在一些情况下提供更好的内存管理。因此,建议根据具体需求决定是否使用detach()
方法。
综合起来,这段代码的作用是将特征数据和标签数据绘制成散点图。具体地说,它将特征数据的第二个维度(features[:, 1]
)作为 x 轴坐标,将标签数据(labels
)作为 y 轴坐标,绘制散点图。参数 1
是指定散点的大小。
通过绘制散点图,我们可以观察特征数据和标签数据之间的关系,并通过点的分布情况来了解数据集的模式和趋势。这有助于我们对数据集有更直观的认识,并为模型的训练和评估提供可视化的参考。