网站百度搜索情况和反链接优化建议,视频素材网站怎么建,上海网站建设润滋,电视剧下载网站 免费糖醋蒜怎样做线性回归
线性回归基于几个简单的假设#xff1a; 首先#xff0c;假设自变量 x \mathbf{x} x和因变量 y y y之间的关系是线性的#xff0c; 即 y y y可以表示为 x \mathbf{x} x中元素的加权和#xff0c;这里通常允许包含观测值的一些噪声#xff1b; 其次#xff0c;我…线性回归
线性回归基于几个简单的假设 首先假设自变量 x \mathbf{x} x和因变量 y y y之间的关系是线性的 即 y y y可以表示为 x \mathbf{x} x中元素的加权和这里通常允许包含观测值的一些噪声 其次我们假设任何噪声都比较正常如噪声遵循正态分布。
为了解释线性回归我们举一个实际的例子 我们希望根据房屋的面积平方英尺和房龄年来估算房屋价格美元。 为了开发一个能预测房价的模型我们需要收集一个真实的数据集。 这个数据集包括了房屋的销售价格、面积和房龄。 在机器学习的术语中该数据集称为训练数据集training data set 或训练集training set。 每行数据比如一次房屋交易相对应的数据称为样本sample 也可以称为数据点data point或数据样本data instance。 我们把试图预测的目标比如预测房屋价格称为标签label或目标target。 预测所依据的自变量面积和房龄称为特征feature或协变量covariate。
通常我们使用 n n n来表示数据集中的样本数。 对索引为 i i i的样本其输入表示为 x ( i ) [ x 1 ( i ) , x 2 ( i ) ] ⊤ \mathbf{x}^{(i)} [x_1^{(i)}, x_2^{(i)}]^\top x(i)[x1(i),x2(i)]⊤ 其对应的标签是 y ( i ) y^{(i)} y(i)。
线性模型
线性假设是指目标房屋价格可以表示为特征面积和房龄的加权和如下面的式子 p r i c e w a r e a ⋅ a r e a w a g e ⋅ a g e b . \mathrm{price} w_{\mathrm{area}} \cdot \mathrm{area} w_{\mathrm{age}} \cdot \mathrm{age} b. pricewarea⋅areawage⋅ageb. :eqlabel:eq_price-area
:eqref:eq_price-area中的 w a r e a w_{\mathrm{area}} warea和 w a g e w_{\mathrm{age}} wage 称为权重weight权重决定了每个特征对我们预测值的影响。 b b b称为偏置bias、偏移量offset或截距intercept。 偏置是指当所有特征都取值为0时预测值应该为多少。 即使现实中不会有任何房子的面积是0或房龄正好是0年我们仍然需要偏置项。 如果没有偏置项我们模型的表达能力将受到限制。 严格来说 :eqref:eq_price-area是输入特征的一个 仿射变换affine transformation。 仿射变换的特点是通过加权和对特征进行线性变换linear transformation 并通过偏置项来进行平移translation。
给定一个数据集我们的目标是寻找模型的权重 w \mathbf{w} w和偏置 b b b 使得根据模型做出的预测大体符合数据里的真实价格。 输出的预测值由输入特征通过线性模型的仿射变换决定仿射变换由所选权重和偏置确定。
而在机器学习领域我们通常使用的是高维数据集建模时采用线性代数表示法会比较方便。 当我们的输入包含 d d d个特征时我们将预测结果 y ^ \hat{y} y^ 通常使用“尖角”符号表示 y y y的估计值表示为 y ^ w 1 x 1 . . . w d x d b . \hat{y} w_1 x_1 ... w_d x_d b. y^w1x1...wdxdb.
将所有特征放到向量 x ∈ R d \mathbf{x} \in \mathbb{R}^d x∈Rd中 并将所有权重放到向量 w ∈ R d \mathbf{w} \in \mathbb{R}^d w∈Rd中 我们可以用点积形式来简洁地表达模型 y ^ w ⊤ x b . \hat{y} \mathbf{w}^\top \mathbf{x} b. y^w⊤xb. :eqlabel:eq_linreg-y
在 :eqref:eq_linreg-y中 向量 x \mathbf{x} x对应于单个数据样本的特征。 用符号表示的矩阵 X ∈ R n × d \mathbf{X} \in \mathbb{R}^{n \times d} X∈Rn×d 可以很方便地引用我们整个数据集的 n n n个样本。 其中 X \mathbf{X} X的每一行是一个样本每一列是一种特征。
对于特征集合 X \mathbf{X} X预测值 y ^ ∈ R n \hat{\mathbf{y}} \in \mathbb{R}^n y^∈Rn 可以通过矩阵-向量乘法表示为 y ^ X w b {\hat{\mathbf{y}}} \mathbf{X} \mathbf{w} b y^Xwb
这个过程中的求和将使用广播机制。
解析解
线性回归刚好是一个很简单的优化问题。 与我们将在本书中所讲到的其他大部分模型不同线性回归的解可以用一个公式简单地表达出来 这类解叫作解析解analytical solution。 首先我们将偏置 b b b合并到参数 w \mathbf{w} w中合并方法是在包含所有参数的矩阵中附加一列。 我们的预测问题是最小化 ∥ y − X w ∥ 2 \|\mathbf{y} - \mathbf{X}\mathbf{w}\|^2 ∥y−Xw∥2。 这在损失平面上只有一个临界点这个临界点对应于整个区域的损失极小点。 将损失关于 w \mathbf{w} w的导数设为0得到解析解 w ∗ ( X ⊤ X ) − 1 X ⊤ y . \mathbf{w}^* (\mathbf X^\top \mathbf X)^{-1}\mathbf X^\top \mathbf{y}. w∗(X⊤X)−1X⊤y.
像线性回归这样的简单问题存在解析解但并不是所有的问题都存在解析解。 解析解可以进行很好的数学分析但解析解对问题的限制很严格导致它无法广泛应用在深度学习里。
随机梯度下降
梯度下降最简单的用法是计算损失函数数据集中所有样本的损失均值 关于模型参数的导数在这里也可以称为梯度。 但实际中的执行可能会非常慢因为在每一次更新参数之前我们必须遍历整个数据集。 因此我们通常会在每次需要计算更新的时候随机抽取一小批样本 这种变体叫做小批量随机梯度下降minibatch stochastic gradient descent。
在每次迭代中我们首先随机抽样一个小批量 B \mathcal{B} B 它是由固定数量的训练样本组成的。 然后我们计算小批量的平均损失关于模型参数的导数也可以称为梯度。 最后我们将梯度乘以一个预先确定的正数 η \eta η并从当前参数的值中减掉。
我们用下面的数学公式来表示这一更新过程 ∂ \partial ∂表示偏导数 ( w , b ) ← ( w , b ) − η ∣ B ∣ ∑ i ∈ B ∂ ( w , b ) l ( i ) ( w , b ) . (\mathbf{w},b) \leftarrow (\mathbf{w},b) - \frac{\eta}{|\mathcal{B}|} \sum_{i \in \mathcal{B}} \partial_{(\mathbf{w},b)} l^{(i)}(\mathbf{w},b). (w,b)←(w,b)−∣B∣ηi∈B∑∂(w,b)l(i)(w,b).
算法的步骤如下 1初始化模型参数的值如随机初始化 2从数据集中随机抽取小批量样本且在负梯度的方向上更新参数并不断迭代这一步骤。 对于平方损失和仿射变换我们可以明确地写成如下形式: w ← w − η ∣ B ∣ ∑ i ∈ B ∂ w l ( i ) ( w , b ) w − η ∣ B ∣ ∑ i ∈ B x ( i ) ( w ⊤ x ( i ) b − y ( i ) ) , b ← b − η ∣ B ∣ ∑ i ∈ B ∂ b l ( i ) ( w , b ) b − η ∣ B ∣ ∑ i ∈ B ( w ⊤ x ( i ) b − y ( i ) ) . \begin{aligned} \mathbf{w} \leftarrow \mathbf{w} - \frac{\eta}{|\mathcal{B}|} \sum_{i \in \mathcal{B}} \partial_{\mathbf{w}} l^{(i)}(\mathbf{w}, b) \mathbf{w} - \frac{\eta}{|\mathcal{B}|} \sum_{i \in \mathcal{B}} \mathbf{x}^{(i)} \left(\mathbf{w}^\top \mathbf{x}^{(i)} b - y^{(i)}\right),\\ b \leftarrow b - \frac{\eta}{|\mathcal{B}|} \sum_{i \in \mathcal{B}} \partial_b l^{(i)}(\mathbf{w}, b) b - \frac{\eta}{|\mathcal{B}|} \sum_{i \in \mathcal{B}} \left(\mathbf{w}^\top \mathbf{x}^{(i)} b - y^{(i)}\right). \end{aligned} wb←w−∣B∣ηi∈B∑∂wl(i)(w,b)w−∣B∣ηi∈B∑x(i)(w⊤x(i)b−y(i)),←b−∣B∣ηi∈B∑∂bl(i)(w,b)b−∣B∣ηi∈B∑(w⊤x(i)b−y(i)). :eqlabel:eq_linreg_batch_update
公式 :eqref:eq_linreg_batch_update中的 w \mathbf{w} w和 x \mathbf{x} x都是向量。 ∣ B ∣ |\mathcal{B}| ∣B∣表示每个小批量中的样本数这也称为批量大小batch size。 η \eta η表示学习率learning rate。
批量大小和学习率的值通常是手动预先指定而不是通过模型训练得到的。 这些可以调整但不在训练过程中更新的参数称为超参数hyperparameter。 调参hyperparameter tuning是选择超参数的过程。 超参数通常是我们根据训练迭代结果来调整的 而训练迭代结果是在独立的验证数据集validation dataset上评估得到的。
线性回归的从零开始实现
从零开始实现整个方法包括数据流水线、模型、损失函数和小批量随机梯度下降优化器。
%matplotlib inline
import random
import torch
from d2l import torch as d2l生成数据集
生成一个包含1000个样本的数据集 每个样本包含从标准正态分布中采样的2个特征。 我们的合成数据集是一个矩阵 X ∈ R 1000 × 2 \mathbf{X}\in \mathbb{R}^{1000 \times 2} X∈R1000×2。
我们使用线性模型参数 w [ 2 , − 3.4 ] ⊤ \mathbf{w} [2, -3.4]^\top w[2,−3.4]⊤、 b 4.2 b 4.2 b4.2 和噪声项 ϵ \epsilon ϵ生成数据集及其标签 y X w b ϵ . \mathbf{y} \mathbf{X} \mathbf{w} b \mathbf\epsilon. yXwbϵ. ϵ \epsilon ϵ可以视为模型预测和标签时的潜在观测误差。 在这里我们认为标准假设成立即 ϵ \epsilon ϵ服从均值为0的正态分布。 为了简化问题我们将标准差设为0.01。 下面的代码生成合成数据集。
def synthetic_data(w, b, num_examples): #save生成yXwb噪声X torch.normal(0, 1, (num_examples, len(w)))y torch.matmul(X, w) by 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])features: tensor([-0.4836, -0.8441])
label: tensor([6.1063])通过生成第二个特征features[:, (1)]和labels的散点图可以直观观察到两者之间的线性关系
d2l.set_figsize()
d2l.plt.scatter(features[:, (1)].detach().numpy(), labels.detach().numpy(), 1);读取数据集
定义一个data_iter函数 该函数接收批量大小、特征矩阵和标签向量作为输入生成大小为batch_size的小批量
每个小批量包含一组特征和标签。
def data_iter(batch_size, features, labels):num_examples len(features)indices list(range(num_examples))# 这些样本是随机读取的没有特定的顺序random.shuffle(indices)for i in range(0, num_examples, batch_size):batch_indices torch.tensor(indices[i: min(i batch_size, num_examples)])yield features[batch_indices], labels[batch_indices]读取第一个小批量数据样本并打印。 每个批量的特征维度显示批量大小和输入特征数。 同样的批量的标签形状与batch_size相等。
batch_size 10for X, y in data_iter(batch_size, features, labels):print(X, \n, y)breaktensor([[ 0.3747, 0.7438],[-0.9089, -1.8827],[ 1.7131, 0.8056],[ 0.8595, 1.3511],[-1.8953, -0.4136],[-0.1327, -0.5880],[ 0.6790, -0.2707],[-0.6167, -1.1107],[-0.4787, -0.1805],[-0.5738, -0.6744]]) tensor([[2.4371],[8.7851],[4.8822],[1.3283],[1.8363],[5.9220],[6.4880],[6.7299],[3.8554],[5.3370]])当我们运行迭代时我们会连续地获得不同的小批量直至遍历完整个数据集。 上面实现的迭代对教学来说很好但它的执行效率很低可能会在实际问题上陷入麻烦。 例如它要求我们将所有数据加载到内存中并执行大量的随机内存访问。 在深度学习框架中实现的内置迭代器效率要高得多 它可以处理存储在文件中的数据和数据流提供的数据。
初始化模型参数
通过从均值为0、标准差为0.01的正态分布中采样随机数来初始化权重 并将偏置初始化为0。
w torch.normal(0, 0.01, size(2, 1), requires_grad True)
b torch.zeros(1, requires_grad True)定义模型
定义模型将模型的输入和参数同模型的输出关联起来。
要计算线性模型的输出只需计算输入特征 X \mathbf{X} X和模型权重 w \mathbf{w} w的矩阵-向量乘法后加上偏置 b b b。 注意上面的 X w \mathbf{Xw} Xw是一个向量而 b b b是一个标量。
def linreg(X, w, b): #save线性回归模型return torch.matmul(X, w) b定义损失函数
因为需要计算损失函数的梯度所以我们应该先定义损失函数。 这里我们使用平方损失函数。 在实现中我们需要将真实值y的形状转换为和预测值y_hat的形状相同。
def squared_loss(y_hat, y): #save均方损失return (y_hat - y.reshape(y_hat.shape)) ** 2 / 2定义优化算法
在每一步中使用从数据集中随机抽取的一个小批量然后根据参数计算损失的梯度。 接下来朝着减少损失的方向更新我们的参数。
下面的函数实现小批量随机梯度下降更新。 该函数接受模型参数集合、学习速率和批量大小作为输入。每 一步更新的大小由学习速率lr决定。 因为我们计算的损失是一个批量样本的总和所以我们用批量大小batch_size 来规范化步长这样步长大小就不会取决于我们对批量大小的选择。
def sgd(params, lr, batch_size): #save小批量随机梯度下降with torch.no_grad():for param in params:param - lr * param.grad / batch_sizeparam.grad.zero_()训练
在每次迭代中我们读取一小批量训练样本并通过我们的模型来获得一组预测。 计算完损失后我们开始反向传播存储每个参数的梯度。 最后我们调用优化算法sgd来更新模型参数。
概括一下我们将执行以下循环
初始化参数重复以下训练直到完成 计算梯度 g ← ∂ ( w , b ) 1 ∣ B ∣ ∑ i ∈ B l ( x ( i ) , y ( i ) , w , b ) \mathbf{g} \leftarrow \partial_{(\mathbf{w},b)} \frac{1}{|\mathcal{B}|} \sum_{i \in \mathcal{B}} l(\mathbf{x}^{(i)}, y^{(i)}, \mathbf{w}, b) g←∂(w,b)∣B∣1∑i∈Bl(x(i),y(i),w,b)更新参数 ( w , b ) ← ( w , b ) − η g (\mathbf{w}, b) \leftarrow (\mathbf{w}, b) - \eta \mathbf{g} (w,b)←(w,b)−ηg
在每个迭代周期epoch中我们使用data_iter函数遍历整个数据集 并将训练数据集中所有样本都使用一次假设样本数能够被批量大小整除。 这里的迭代周期个数num_epochs和学习率lr都是超参数分别设为3和0.03。
lr 0.03
num_epochs 3
net linreg
loss squared_lossfor epoch in range(num_epochs):for X, y in data_iter(batch_size, features, labels):l loss(net(X, w, b), y) # X和y的小批量损失# 因为l形状是(batch_size,1)而不是一个标量。l中的所有元素被加到一起# 并以此计算关于[w,b]的梯度l.sum().backward()sgd([w, b], lr, batch_size) # 使用参数的梯度更新参数with torch.no_grad():train_l loss(net(features, w, b), labels)print(fepoch {epoch 1}, loss {float(train_l.mean()):f})epoch 1, loss 0.041500
epoch 2, loss 0.000147
epoch 3, loss 0.000047print(fw的估计误差: {true_w - w.reshape(true_w.shape)})
print(fb的估计误差: {true_b - b})w的估计误差: tensor([ 0.0002, -0.0003], grad_fnSubBackward0)
b的估计误差: tensor([0.0002], grad_fnRsubBackward1)线性回归的简洁实现
使用PyTorch框架来实现线性回归模型
生成数据集
import numpy as np
import torch
from torch.utils import data
from d2l import torch as d2ltrue_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表示是否希望数据迭代器对象在每个迭代周期内打乱数据。
def load_array(data_arrays, batch_size, is_trainTrue): #save构造一个PyTorch数据迭代器dataset data.TensorDataset(*data_arrays)return data.DataLoader(dataset, batch_size, shuffleis_train)batch_size 10
data_iter load_array((features, labels), batch_size)为了验证是否正常工作读取并打印第一个小批量样本。
使用iter构造Python迭代器并使用next从迭代器中获取第一项。
next(iter(data_iter))[tensor([[ 0.3532, -0.6057],[ 1.6997, -1.6114],[ 1.3135, 3.0438],[-1.0064, -1.3555],[ 1.6724, 0.7461],[ 0.3855, -1.5162],[ 0.7502, 0.5924],[ 0.8864, -0.1364],[ 2.0878, -2.4125],[ 0.4963, 1.4179]]),tensor([[ 6.9696],[13.0706],[-3.5134],[ 6.7924],[ 5.0087],[10.1182],[ 3.6684],[ 6.4485],[16.5720],[ 0.3795]])]定义模型
对于标准深度学习模型可以使用框架的预定义好的层。
首先定义一个模型变量net它是一个Sequential类的实例。
Sequential类将多个层串联在一起。当给定输入数据时Sequential实例将数据传入到第一层然后将第一层的输出作为第二层的输入以此类推。
在PyTorch中全连接层在Linear类中定义。值得注意的是我们将两个参数传递到nn.Linear中第一个指定输入特征形状即2第二个指定输出特征形状输出特征形状为单个标量因此为1。
# nn是神经网络的缩写
from torch import nnnet nn.Sequential(nn.Linear(2, 1))初始化模型参数
在使用net之前需要初始化模型参数。
深度学习框架通常有预定义的方法来初始化参数。在这里指定每个权重参数应该从均值为0、标准差为0.01的正态分布中随机采样偏置参数将初始化为零。
正如在构造nn.Linear时指定输入和输出尺寸一样现在能直接访问参数以设定它们的初始值。通过net[0]选择网络中的第一个图层然后使用weight.data和bias.data方法访问参数。还可以使用替换方法normal_和fill_来重写参数值。
net[0].weight.data.normal_(0, 0.01)
net[0].bias.data.fill_(0)tensor([0.])定义损失函数
计算均方误差使用的是MSELoss类也成为平方 L 2 L_{2} L2范数。
默认情况下它返回所有样本损失的平均值。
loss nn.MSELoss()定义优化算法
小批量随机梯度下降算法是一种优化神经网络的标准工具 PyTorch在optim模块中实现了该算法的许多变种。 当我们(实例化一个SGD实例)时我们要指定优化的参数 可通过net.parameters()从我们的模型中获得以及优化算法所需的超参数字典。 小批量随机梯度下降只需要设置lr值这里设置为0.03。
trainer torch.optim.SGD(net.parameters(), lr 0.03)训练
在每个迭代周期里将完整遍历一次数据集train_data 不停地从中获取一个小批量的输入和相应的标签。 对于每一个小批量会进行以下步骤:
通过调用net(X)生成预测并计算损失l前向传播。通过进行反向传播来计算梯度。通过调用优化器来更新模型参数。
为了更好的衡量训练效果计算每个迭代周期后的损失并打印它来监控训练过程。
num_epochs 3
for epoch in range(num_epochs):for X, y in data_iter:l loss(net(X), y)trainer.zero_grad()l.backward()trainer.step()l loss(net(features), labels)print(fepoch {epoch 1}, loss {1:f})epoch 1, loss 1.000000
epoch 2, loss 1.000000
epoch 3, loss 1.000000比较生成数据集的真实参数和通过有限数据训练获得的模型参数
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.0001, 0.0005])
b的估计误差 tensor([-0.0008])