前言
这篇文章用来记录本人在学习 《动手学深度学习》这本书时对章节( 线性回归的从零开始实现)的一些困惑、理解和解答。
任务
我们将根据带有噪声的线性模型构造一个人造数据集。
我们的任务是使用这个有限样本的数据集来恢复这个模型的参数。
1、导入相应的库函数
import torch
import random
from d2l import torch as d2l
2、生成数据集
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))
true_w = torch.tensor([2, -3.4])
true_b = 4.2
features, labels = synthetic_data(true_w, true_b, 1000)
# 打印features中的第一个二维数据样本及其对应labels中的一维标签值(一个标量)
print('features:',features[0],'\nlabel:',labels[0])
d2l.set_figsize()
d2l.plt.scatter(features[:,(1)].detach().numpy(),labels.detach().numpy(),1)
代码运行结果如下:
features:tensor([1.4632,0.5511])
label:tensor([5.2498])
代码解读
true_w :用于设置 真实的权重,是一个包含两个元素的一维张量(即向量)。
true_b:用于设置 真实的偏置,是一个标量值。
num_examples:用于设置 样本的数量,是一个标量值。
features:用来接受synthetic_data函数生成的1000个样本的特征数据,每一个样本包含了2个特征。是一个二维张量(即矩阵)。
labels:用来接受synthetic_data函数生成的1000个样本所对应的标签。是一个二维张量(即矩阵)。
X = torch.normal(0, 1, (num_examples, len(w))):生成一个形状为 (num_examples, len(w)) 的二维张量 X,其中的元素是从均值为 0,标准差为 1 的正态分布中采样得到的。
一个样本有多个特征,每一个特征要有一个权重与之对应。
这里 len(w) 的目的是确定 X 的列数,也就是特征的数量。因为在后面的代码中,我们需要用 X 和权重向量 w 进行矩阵乘法,所以 X 的列数必须和 w 的长度相同。这就是为什么我们需要 len(w) 的原因。
y = torch.matmul(X, w) + b:用于计算每个输入样本的预测值。
由于torch.matmul(X, w)是一个矩阵和一个向量进行矩阵-向量乘法运算,得到的结果是一个向量,再把这个向量加上偏置 b ,偏置b这个常数会加到这个向量的每一个元素上,这样得出的预测值y也是一个一维张量(即向量)。
y += torch.normal(0, 0.01, y.shape):给预测值y添加一些噪声,用于模拟实际应用中可能出现的观测误差或者模型误差。
这里的 += 是直接对 y 进行加法操作,所以生成的向量噪声的每一个元素会直接加到对应的向量 y 的每个元素上。
举一个简单的例子:
import torch
a = torch.tensor([0,1])
b = torch.tensor([2,3])
# 两个向量进行相加
a +=b
print(a)
代码运行结果为:
tensor([2, 4])
return X, y.reshape((-1, 1)):这里返回的X是一个矩阵,y.reshape((-1, 1))是对向量y进行重塑,得到一个单列矩阵。
一个小困惑(来自 百川大模型 的解答):
torch.normal函数
用途:用于生成正太分布(也称高斯分布)的随机数。
所需参数:torch.normal(均值, 标准差, 指定输出张量的形状)。
举一个简单的例子:
生成一个形状为 (3, 3) 的张量,其中的元素是从均值为 0,标准差为 1 的正态分布中随机抽取的,代码实现如下:
import torch
# 生成一个形状为 (3, 3) 的张量,其中的元素是从均值为 0,标准差为 1 的正态分布中随机抽取的
tensor = torch.normal(0, 1, (3, 3))
print(tensor)
由于生成的是随机数,所以每次运行上述代码时,得到的张量都会有所不同。
可能的输出结果:
tensor([[ 0.5983, -0.0891, -1.5944],
[ 0.4141, 0.5653, -0.3561],
[-0.1034, 0.2961, -0.8660]])
矩阵乘法
定义:设 A 为 m×p 的矩阵,B 为 p×n 的矩阵,那么称 m×n 的矩阵C为矩阵A与B的乘积,记作 C = A × B 。
注意事项:
1、当矩阵A的列数(column)等于矩阵B的行数(row)时,A与B可以相乘。
2、矩阵C的行数等于矩阵A的行数,C的列数等于B的列数。
3、矩阵相乘不满足交换律,即 AB ≠ BA ,除非 A 和 B 是特殊的矩阵,如单位矩阵或伴随矩阵。
举一个简单的例子:
将一个 2×3 的矩阵与一个 3×2 的矩阵相乘,得到一个 2×2 的矩阵。
矩阵-向量乘法
一个矩阵可以与一个向量相乘(矩阵的列数必须等于向量的长度),这在数学上被称为矩阵-向量乘法。
例如,如果你有一个 3×2 的矩阵和一个长度为 2 的向量,那么你可以将它们相乘,结果将是一个长度为 3 的向量。但是,如果你有一个 3×2 的矩阵和一个长度为 3 的向量,那么你不能将它们相乘,因为向量的长度 3 不等于矩阵的列数 2 。
在这种乘法中,向量被视为列数为1的特殊矩阵。相乘的结果是一个新的向量(长度为输入矩阵的行数)。
在机器学习和深度学习中,这种乘法常常用于将 输入特征矩阵 与 模型的权重向量 相乘,从而得到模型的预测输出。
torch.matmul函数和torch.mv函数
torch.matmul函数:用于执行两个张量之间的矩阵乘法。
也就是说,torch.matmul函数 可以处理 两个矩阵 的乘法,也可以处理 一个矩阵和一个向量 的乘法,甚至可以处理 两个向量 的点积,并支持广播机制。
标量,也称零维张量
向量,也称一维张量
矩阵,也称二维张量
广播机制:允许不同形状的张量(多维数组)进行数学运算。
举一个简单的例子:
import torch
# 创建一个 2x2 的矩阵和一个长度为 2 的向量
matrix = torch.tensor([[1, 2], [3, 4]])
vector = torch.tensor([1, 2])
# 使用 torch.matmul() 函数进行矩阵乘法
result = torch.matmul(matrix, vector)
print(result)
若没有指定输出的形状,PyTorch 默认返回一个行向量。
运行代码,结果如下:
tensor([ 5, 11])
由于 torch.matmul() 函数会将向量 vector 广播成一个 2x1 的矩阵,然后进行矩阵乘法。矩阵的第一行和向量的乘积是 1*1 + 2*2 = 5,矩阵的第二行和向量的乘积是 3*1 + 4*2 = 11。计算结果如下:
torch.mv函数:仅适用于一个矩阵和一个向量的乘法,并且要求矩阵的列数必须与向量的长度相等。
torch.mv 函数的参数列表如下:
torch.mv(matrix, vector) → Tensor
matrix:第一个参数,是一个二维张量,扮演矩阵的角色。
vector:第二个参数,是一个一维张量,扮演向量的角色。
举一个简单的例子:
import torch
# 创建一个 2x2 的矩阵和一个长度为 2 的向量
matrix = torch.tensor([[1, 2], [3, 4]])
vector = torch.tensor([1, 2])
# 使用 torch.mv() 函数进行矩阵-向量乘法
result = torch.mv(matrix, vector)
print(result)
运行代码,结果如下:
tensor([ 5, 11])
无论是 torch.mv 还是 torch.matmul,当它们用于执行一个矩阵和一个向量的乘法时,默认返回的都是行向量。
torch.reshape函数
torch.reshape函数:在不改变张量元素数目的情况下改变张量的形状。
torch.reshape 函数的参数列表如下:
torch.reshape(input, shape) → Tensor
input:要重塑的张量,其元素数量和元素本身不会因重塑而改变。
shape:这是一个元组,指定了输出张量的新形状。元组的每个元素表示输出张量在相应维度上的大小。
举一个简单的例子: