1.前言
1.2.关键组件
- 我们可以学习的数据(data)。
- 如何转换数据模型(model)。
- 目标函数(objective function),量化模型的有效性。
- 调整模型参数以优化目标函数的算法
2.预备知识
2.1.数据操作
2.1.1.入门
- 张量:n维数组;
- 可以使用arange创建行向量x。它们被默认创建为浮点数。除非额外指定,否则新的张量将存储在内存中,并以此为基础CPU的计算。
x = torch.arange(12) x tensor([ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11])
- shape访问张量形状的属性 (每个轴的长度)
x.shape torch.Size([12])
- 如果你只想知道张量中元素的总数,即形状中所有元素的乘积,你可以检查它的大小(size)
x.numel() 12
- 在不改变元素数量和元素值的情况下,可以调用张量的形状reshape函数。
X = x.reshape(3, 4) X tensor([[ 0, 1, 2, 3], [ 4, 5, 6, 7], [ 8, 9, 10, 11]])
不需要手动指定每个维度来改变形状。该功能可以通过放置在希望张量自动推断的维度-1来调用 6. 创建形状为(2、3、4)的张量,所有元素设置为0
torch.zeros((2, 3, 4))
创建一个形状为(2,3,4)的张量,其中所有元素都设置为1
torch.ones((2, 3, 4))
- 创建一个形状为(3,4)的张量。其中的每个元素都从均值为0、标准差为1的标准高斯(正态)分布中随机采样
torch.randn(3, 4)
tensor([[-0.9464, 0.7712, -0.0070, 1.0236],
[-2.1246, -0.7854, -1.9674, -0.1727],
[ 0.0397, -0.0477, -0.0160, -0.0113]])
8.为所需张量中的每个元素赋予确定值
torch.tensor([[2, 1, 4, 3], [1, 2, 3, 4], [4, 3, 2, 1]])
tensor([[2, 1, 4, 3],
[1, 2, 3, 4],
[4, 3, 2, 1]])
2.1.2.运算
1.计算
x = torch.tensor([1.0, 2, 4, 8])
y = torch.tensor([2, 2, 2, 2])
x + y, x - y, x * y, x / y, x ** y # **运算符是求幂运算
torch.exp(x)
2.张量连结(concatenate)
X = torch.arange(12, dtype=torch.float32).reshape((3,4))
Y = torch.tensor([[2.0, 1, 4, 3], [1, 2, 3, 4], [4, 3, 2, 1]])
torch.cat((X, Y), dim=0), torch.cat((X, Y), dim=1)
(tensor([[ 0., 1., 2., 3.],
[ 4., 5., 6., 7.],
[ 8., 9., 10., 11.],
[ 2., 1., 4., 3.],
[ 1., 2., 3., 4.],
[ 4., 3., 2., 1.]]),
tensor([[ 0., 1., 2., 3., 2., 1., 4., 3.],
[ 4., 5., 6., 7., 1., 2., 3., 4.],
[ 8., 9., 10., 11., 4., 3., 2., 1.]]))
2.二元张量
X == Y
tensor([[False, True, False, True],
[False, False, False, False],
[False, False, False, False]])
3.张量元素求和,产生只有一个元素的张量
X.sum()
tensor(66.)
2.1.3.广播机制
1.广播机制(broadcasting mechanism)
- 首先,通过适当复制元素来扩展一个或两个数组,以便在转换之后,两个张量具有相同的形状。
- 其次,对生成的数组执行按元素操作。
a = torch.arange(3).reshape((3, 1))
b = torch.arange(2).reshape((1, 2))
a, b
(tensor([[0],
[1],
[2]]),
tensor([[0, 1]]))
由于a和b分别是 3×1 和 1×2 矩阵,如果我们让它们相加,它们的形状不匹配。我们将两个矩阵广播为一个更大的 3×2 矩阵,如下所示:矩阵a将复制列,矩阵b将复制行,然后再按元素相加
a + b
tensor([[0, 1],
[1, 2],
[2, 3]])
2.1.4.索引和切片
和python一样
2.1.5.节省内存
运行一些操作可能会导致为新结果分配内存。
before = id(Y)
Y = Y + X
id(Y) == before
False
执行原地操作非常简单。我们可以使用切片表示法将操作的结果分配给先前分配的数组 zeros_like来分配一个全 0 的块
Z = torch.zeros_like(Y)
print('id(Z):', id(Z))
Z[:] = X + Y
print('id(Z):', id(Z))
id(Z): 140272150341696
id(Z): 140272150341696
也可以使用X += Y来减少操作的内存开销。
before = id(X)
X += Y
id(X) == before
True
2.1.6.转换为其他Python对象
1.转换后的结果不共享内存
A = X.numpy()
B = torch.tensor(A)
type(A), type(B)
(numpy.ndarray, torch.Tensor)
2.要将大小为1的张量转换为Python标量,我们可以调用item函数或Python的内置函数。
a = torch.tensor([3.5])
a, a.item(), float(a), int(a)
(tensor([3.5000]), 3.5, 3.5, 3)
2.2.数据预处理
2.2.1.读取数据集
2.2.2.处理缺失值
- iloc()
- fillna()
- get_dummies()
2.2.3.转换为张量格式
具体见 2.2数据预处理.py
2.3.线性代数
2.3.1.标量
2.3.2.向量
2.3.3.矩阵
A = torch.arange(20).reshape(5, 4)
A
tensor([[ 0, 1, 2, 3],
[ 4, 5, 6, 7],
[ 8, 9, 10, 11],
[12, 13, 14, 15],
[16, 17, 18, 19]])
矩阵转置 A.T
2.2.4.张量
见上文
2.3.5.张量算法的基本性质
- 给定具有相同形状的任意两个张量,任何按元素二元运算的结果都将是相同形状的张量
- 两个矩阵的按元素乘法称为哈达玛积(Hadamard product)(数学符号 ⊙)
A * B
- 将张量乘以或加上一个标量不会改变张量的形状,其中张量的每个元素都将与标量相加或相乘
2.3.6.降维
1.求和降维
A_sum_axis0 = A.sum(axis=0)
A_sum_axis0, A_sum_axis0.shape
沿着行和列对矩阵求和,等价于对矩阵的所有元素进行求和
A.sum(axis=[0, 1]) # Same as `A.sum()`
2.平均值
A.mean(), A.sum() / A.numel()
(tensor(9.5000), tensor(9.5000))
A.mean(axis=0), A.sum(axis=0) / A.shape[0]
(tensor([ 8., 9., 10., 11.]), tensor([ 8., 9., 10., 11.])
2.3.6.1.非降维求和
- 例如,由于sum_A在对每行进行求和后仍保持两个轴,我们可以通过广播将A除以sum_A。
sum_A = A.sum(axis=1, keepdims=True)
sum_A
tensor([[ 6.],
[22.],
[38.],
[54.],
[70.]])
A / sum_A
tensor([[0.0000, 0.1667, 0.3333, 0.5000],
[0.1818, 0.2273, 0.2727, 0.3182],
[0.2105, 0.2368, 0.2632, 0.2895],
[0.2222, 0.2407, 0.2593, 0.2778],
[0.2286, 0.2429, 0.2571, 0.2714]])
- 沿某个轴计算A元素的累积总和,比如axis=0(按行计算),我们可以调用cumsum函数。此函数不会沿任何轴降低输入张量的维度
A.cumsum(axis=0)
tensor([[ 0., 1., 2., 3.],
[ 4., 6., 8., 10.],
[12., 15., 18., 21.],
[24., 28., 32., 36.],
[40., 45., 50., 55.]])
2.3.7.点积
y = torch.ones(4, dtype = torch.float32)
x, y, torch.dot(x, y)
(tensor([0., 1., 2., 3.]), tensor([1., 1., 1., 1.]), tensor(6.))
2.3.8.矩阵-向量积
A.shape, x.shape, torch.mv(A, x)
(torch.Size([5, 4]), torch.Size([4]), tensor([ 14., 38., 62., 86., 110.]))
2.3.9.矩阵-矩阵乘法
B = torch.ones(4, 3)
torch.mm(A, B)
tensor([[ 6., 6., 6.],
[22., 22., 22.],
[38., 38., 38.],
[54., 54., 54.],
[70., 70., 70.]])
2.3.10.范数
- 范数:在线性代数中,向量范数是将向量映射到标量的函数 f
- 如果我们按常数因子 α 缩放向量的所有元素,其范数也会按相同常数因子的绝对值缩放
- 三角不等式
- 简单地说范数必须是非负的
- L2 范数是向量元素平方和的平方根
u = torch.tensor([3.0, -4.0])
torch.norm(u)
tensor(5.)
- L1 范数,它表示为向量元素的绝对值之和
torch.abs(u).sum()
tensor(7.)
- 矩阵 X∈Rm×n 的弗罗贝尼乌斯范数(Frobenius norm)是矩阵元素平方和的平方根
torch.norm(torch.ones((4, 9)))
tensor(6.)
2.3.10.1.范数和目标
通常,目标,或许是深度学习算法最重要的组成部分(除了数据),被表达为范数。
2.4.微分
- 拟合模型
- 优化(optimization)
- 泛化(generalization)
2.4.3梯度
- 假设x为n维向量,在微分多元函数时经常使用以下规则:
- 对于所有 A ∈ R m ∗ n A\in R^{m*n} A∈Rm∗n,都有 ▽ x A x = A T \bigtriangledown_x Ax=A^T ▽xAx=AT
- 对于所有 A ∈ R m ∗ n A\in R^{m*n} A∈Rm∗n,都有 ▽ x x T A = A \bigtriangledown_x x^T A=A ▽xxTA=A
- 对于所有 A ∈ R m ∗ n A\in R^{m*n} A∈Rm∗n,都有 ▽ x x T A x = ( A + A T ) x \bigtriangledown_x x^TAx=(A+A^T)x ▽xxTAx=(A+AT)x
- ▽ x ∥ x ∥ 2 = ▽ x x T x = 2 x \bigtriangledown_x \lVert x \rVert ^2=\bigtriangledown_x x^T x=2x ▽x∥x∥2=▽xxTx=2x 同样,对于任何矩阵X,我们都有 ▽ x ∥ x ∥ F 2 = 2 x \bigtriangledown_x \lVert x \rVert ^2_F=2x ▽x∥x∥F2=2x。
2.5.自动求导
深度学习框架通过自动计算导数,即自动求导(automatic differentiation),来加快这项工作。实际中,根据我们设计的模型, 系统会构建一个计算图(computational graph),来跟踪计算是哪些数据通过哪些操作组合起来产生输出。自动求导使系统能够随后反向传播梯度。 这里,反向传播(backpropagate)只是意味着跟踪整个计算图,填充关于每个参数的偏导数。
2.5.1.一个简单的例子
import torch
x = torch.arange(4.0)
print(x)
x.requires_grad_(True) # 等价于 `x = torch.arange(4.0, requires_grad=True)`
print(x.grad) # 默认值是None
y = 2 * torch.dot(x, x)
print(y)
y.backward()
print(x.grad)
print(x.grad == 4 * x)
2.5.2.非标量变量的反向传播
-
当
y
不是标量时,向量y
关于向量X
的导数的最自然解释是一个矩阵。对于高阶和高维的y
和x
,求导的结果可以是一个高阶张量# 对非标量调用`backward`需要传入一个`gradient`参数,该参数指定微分函数关于`self`的梯度。在我们的例子中,我们只想求偏导数的和,所以传递一个1的梯度是合适的 x.grad.zero_() y = x * x # 等价于y.backward(torch.ones(len(x))) y.sum().backward() x.grad tensor([0., 2., 4., 6.])
2.5.3.分离计算
-
希望将某些计算移动到记录的计算图之外,即视为常数,反向传播时梯度不会从此经过
x.grad.zero_() y = x * x u = y.detach() z = u * x z.sum().backward() x.grad == u tensor([True, True, True, True])
2.5.4. Python控制流的梯度计算
2.6.概率
2.7.查阅文档
help()
3.线性神经网络
3.1.线性回归
- 仿射变换的特点是通过加权和对特征进行 线性变换 (linear transformation),并通过偏置项来进行 平移 (translation)。
3.1.5.小结
- 机器学习模型中的关键要素是训练数据,损失函数,优化算法,还有模型本身。
- 矢量化使数学表达上更简洁,同时运行的更快。
- 最小化目标函数和执行最大似然估计等价。
- 线性回归模型也是神经网络。
3.3.线性回归的简洁实现
3.3.1. 生成数据集
3.3.2.读取数据集
3.3.3.定义模型
我们首先定义一个模型变量net,它是一个Sequential类的实例。Sequential类为串联在一起的多个层定义了一个容器。当给定输入数据,Sequential实例将数据传入到第一层,然后将第一层的输出作为第二层的输入,依此类推。在下面的例子中,我们的模型只包含一个层,因此实际上不需要Sequential。但是由于以后几乎所有的模型都是多层的,在这里使用Sequential会让你熟悉标准的流水线。
3.3.4.初始化模型参数
3.3.5.定义损失函数
3.3.6.定义优化算法
3.3.7.训练
在每个迭代周期里,我们将完整遍历一次数据集(rain_data
),不停地从中获取一个小批量的输入和相应的标签。对于每一个小批量,我们会进行以下步骤:
- 通过调用
net(X)
生成预测并计算损失l
(正向传播)。 - 通过进行反向传播来计算梯度。
- 通过调用优化器来更新模型参数。
3.4.softmax回归
3.4.1.分类问题
独热编码 (one-hot encoding)。独热编码是一个向量,它的分量和类别一样多。类别对应的分量设置为1,其他所有分量设置为0。
3.4.2.网络结构
全连接层:每个输出取决于全部输入。
3.4.4.softmax运算
-
在分类器输出0.5的所有样本中,我们希望这些样本有一半实际上属于预测的类。 这个属性叫做校准 (calibration)。
-
softmax函数:为了将未归一化的预测变换为非负并且总和为1,同时要求模型保持可导。我们首先对每个未归一化的预测求幂,这样可以确保输出非负。为了确保最终输出的总和为1,我们再对每个求幂后的结果除以它们的总和。 $$ \hat{y}=softmax(o) ,其中, \hat{y_j}=\frac{exp(o_j)}{\sum_k exp(o_k)}
$$
3.4.5. 小批量样本的矢量化
3.4.6. 损失函数
3.4.6.1. 对数似然
交叉熵损失 (cross-entropy loss)
3.4.7.2. 惊异
如果我们不能完全预测每一个事件,那么我们有时可能会感到惊异。当我们赋予一个事件较低的概率时,我们的惊异会更大。克劳德·香农决定用 log 1 P ( j ) = − log P ( j ) \log \frac{1}{P(j)}=-\log P(j) logP(j)1=−logP(j)来量化一个人的 惊异 (surprisal)。在观察一个事件j,并赋予它(主观)概率()。定义的熵是当分配的概率真正匹配数据生成过程时的 预期惊异 (expected surprisal)。
3.4.7.3. 重新审视交叉熵
所以,如果熵是知道真实概率的人所经历的惊异程度,那么你可能会想知道,什么是交叉熵? 交叉熵从P到Q,记为(,),是主观概率为Q的观察者在看到根据概率实际生成的数据时的预期惊异。当=时,交叉熵达到最低。在这种情况下,从到的交叉熵是 H ( P , P ) = H ( P ) H(P,P)=H(P) H(P,P)=H(P)。
简而言之,我们可以从两方面来考虑交叉熵分类目标:(i)最大化观测数据的似然;(ii)最小化传达标签所需的惊异。
3.4.9. 小结
- softmax运算获取一个向量并将其映射为概率。
- softmax回归适用于分类问题。它使用了softmax运算中输出类别的概率分布。
- 交叉熵是一个衡量两个概率分布之间差异的很好的度量。它测量给定模型编码数据所需的比特数
3.7.softmax回归的简洁实现
3.7.1.初始化模型参数
- PyTorch不会隐式地调整输入的形状。 因此,我们在线性层前定义了展平层(flatten),来调整网络输入的形状。
# PyTorch不会隐式地调整输入的形状。因此,
# 我们在线性层前定义了展平层(flatten),来调整网络输入的形状
net = nn.Sequential(nn.Flatten(), nn.Linear(784, 10))
def init_weights(m):
if type(m) == nn.Linear:
nn.init.normal_(m.weight, std=0.01)
net.apply(init_weights)
3.7.2. 重新审视Softmax的实现
- oj 是未归一化的预测 o 的第 j 个元素。如果 ok 中的一些数值非常大,那么 exp(ok) 可能大于数据类型容许的最大数字(即**上溢(overflow))**。 这将使分母或分子变为inf(无穷大),我们最后遇到的是0、inf或nan(不是数字)的 y^j 。在这些情况下,我们不能得到一个明确定义的交叉熵的返回值。
- 解决这个问题的一个技巧是,在继续softmax计算之前,先从所有 ok 中减去 max(ok) 。你可以证明每个 ok 按常数进行的移动不会改变softmax的返回值。 在减法和归一化步骤之后,可能有些 oj 具有较大的负值。由于精度受限, exp(oj) 将有接近零的值,即**下溢(underflow)**。 这些值可能会四舍五入为零,使 y^j 为零,并且使得 log(y^j) 的值为-inf。反向传播几步后,我们可能会发现自己面对一屏幕可怕的nan结果。
- 尽管我们要计算指数函数,但我们最终在计算交叉熵损失时会取它们的对数。 通过将softmax和交叉熵结合在一起,可以避免反向传播过程中可能会困扰我们的数值稳定性问题。
loss = nn.CrossEntropyLoss()
3.7.3. 优化算法
在这里,我们使用学习率为0.1的小批量随机梯度下降作为优化算法。这与我们在线性回归例子中的相同,这说明了优化器的普适性。
trainer = torch.optim.SGD(net.parameters(), lr=0.1)
3.7.4. 训练
num_epochs = 10
d2l.train_ch3(net, train_iter, test_iter, loss, num_epochs, trainer)
4.多层感知机
4.1.1.隐藏层
- 仿射变换中的线性是一个很强的假设。
4.1.1.1.线性模型可能会出错
4.1.1.2.在网络中加入隐藏层
4.1.1.3.从线性到非线性
- 上面的隐藏单元由输入的仿射函数给出,而输出(softmax操作前)只是隐藏单元的仿射函数。 仿射函数的仿射函数本身就是仿射函数。但是我们之前的线性模型已经能够表示任何仿射函数。
- 为了发挥多层结构的潜力,我们还需要一个额外的关键要素:在仿射变换之后对每个隐藏单元应用非线性的激活函数(activation function) σ 。 激活函数的输出(例如, σ(⋅) )被称为激活值(activations)。一般来说,有了激活函数,就不可能再将我们的多层感知机退化成线性模型。
- 为了构建更通用的多层感知机,我们可以继续堆叠这样的隐藏层,一层叠一层,从而产生更有表达能力的模型。
4.1.1.4.通用近似定理
- 多层感知机可以通过隐藏神经元捕捉到我们输入之间复杂的相互作用,这些神经元依赖于每个输入的值。我们可以很容易地设计隐藏节点来执行任意计算。 例如,在一对输入上进行基本逻辑操作。多层感知机是通用近似器。
- 即使是网络只有一个隐藏层,给定足够的神经元(可能非常多)和正确的权重,我们可以对任意函数建模,尽管实际中学习该函数是很困难的。
- 虽然一个单隐层网络能学习任何函数,但并不意味着应该尝试使用单隐藏层网络来解决所有问题。 事实上,通过使用更深(而不是更广)的网络,我们可以更容易地逼近许多函数。
4.1.2.激活函数
- 激活函数是将输入信号转换为输出的可微运算。大多数激活函数都是非线性的。
4.1.2.1.ReLU函数
-
线性整流单元(Rectified linear unit,ReLU)
- ReLU提供了一种非常简单的非线性变换。 给定元素 x ,ReLU函数被定义为该元素与 0 的最大值
$$ ReLU(x)=max(x,0)
$$
- ReLU函数通过将相应的激活值设为0来仅保留正元素并丢弃所有负元素
4.1.2.2.sigmoid函数
- 对于一个定义域在 R 中的输入,sigmoid函数将输入变换为区间(0, 1)上的输出。 因此,sigmoid通常称为挤压函数(squashing function):它将范围(-inf, inf)中的任意输入压缩到区间(0, 1)中的某个值:
$$ sigmoid(x)=\frac{1}{1+exp(-x)}
$$
4.1.2.3.tanh函数
- 与sigmoid函数类似,tanh(双曲正切)函数也能将其输入压缩转换到区间(-1, 1)上。tanh函数的公式如下:
$$ tanch(x)= \frac{1-exp(-2x)}{1+exp(-2x)}
$$
4.4.模型选择、欠拟合和过拟合
- 作为机器学习科学家,我们的目标是发现模式(pattern)。但是,我们如何才能确定模型是真正发现了一种泛化的模式,而不是简单地记住了数据呢?
- 更正式地来说,我们的目标是发现模式,这些模式捕捉到了我们训练集所来自的潜在总体的规律。
- 如果成功做到了这点,即使是对我们以前从未遇到过的个体,我们也可以成功地评估风险。如何发现可以泛化的模式是机器学习的根本问题。
- 将模型在训练数据上拟合得比在潜在分布中更接近的现象称为***过拟合(overfitting)***,用于对抗过拟合的技术称为***正则化(regularization)***
4.4.1.训练误差和泛化误差
- ***训练误差training error***是指,我们的模型在训练数据集上计算得到的误差。
- 是指,当我们将模型应用在同样从原始样本的分布中抽取的无限多的数据样本时,我们模型误差的期望。
4.4.1.1.统计学习理论
- 在我们目前已探讨、并将在之后继续探讨的标准的监督学习中,我们假设训练数据和测试数据都是从相同的分布中独立提取的。 这通常被称为***独立同分布假设(i.i.d. assumption)***
4.4.1.2. 模型复杂性
- 很难比较本质上不同大类的模型之间(例如,决策树与神经网络)的复杂性。 就目前而言,一条简单的经验法则相当有用:统计学家认为,能够轻松解释任意事实的模型是复杂的,而表达能力有限但仍能很好地解释数据的模型可能更有现实用途.
- 在本节中,为了给你一些直观的印象,我们将重点介绍几个倾向于影响模型泛化的因素:
- 可调整参数的数量。当可调整参数的数量(有时称为自由度)很大时,模型往往更容易过拟合。
- 参数采用的值。当权重的取值范围较大时,模型可能更容易过拟合。
- 训练样本的数量。即使你的模型很简单,也很容易过拟合只包含一两个样本的数据集。而过拟合一个有数百万个样本的数据集则需要一个极其灵活的模型。
4.4.2. 模型选择
- 在机器学习中,我们通常在评估几个候选模型后选择最终的模型。这个过程叫做***模型选择***。
4.4.2.1. 验证集
4.4.2.2. K 折交叉验证
4.4.3. 欠拟合还是过拟合?
- 训练误差和验证误差都很严重,但它们之间仅有一点差距。如果模型不能降低训练误差,这可能意味着我们的模型过于简单(即表达能力不足), 无法捕获我们试图学习的模式。此外,由于我们的训练和验证误差之间的泛化误差很小,我们有理由相信可以用一个更复杂的模型降低训练误差。 这种现象被称为***欠拟合(underfitting)***
4.4.3.1. 模型复杂性
- 高阶多项式函数比低阶多项式函数复杂得多。高阶多项式的参数较多,模型函数的选择范围较广。因此在固定训练数据集的情况下, 高阶多项式函数相对于低阶多项式的训练误差应该始终更低(最坏也是相等)。 事实上,当数据样本包含了 x 的不同值时,函数阶数等于数据样本数量的多项式函数可以完美拟合训练集。
4.4.3.2. 数据集大小
另一个需要牢记的重要因素是数据集的大小。训练数据集中的样本越少,我们就越有可能(且更严重地)遇到过拟合。 随着训练数据量的增加,泛化误差通常会减小。 此外,一般来说,更多的数据不会有什么坏处。 对于固定的任务和数据分布,模型复杂性和数据集大小之间通常存在关系。 给出更多的数据,我们可能会尝试拟合一个更复杂的模型。能够拟合更复杂的模型可能是有益的。如果没有足够的数据,简单的模型可能更有用。 对于许多任务,深度学习只有在有数千个训练样本时才优于线性模型。从一定程度上来说,深度学习目前的成功要归功于互联网公司、廉价存储、互联设备以及数字化经济带来的海量数据集。
4.4.4. 多项式回归
见4.4.多项式回归.py
4.5. 权重衰减
4.5.1. 范数与权重衰减
- L2 范数的一个原因是它对权重向量的大分量施加了巨大的惩罚。这使得我们的学习算法偏向于在大量特征上均匀分布权重的模型。 在实践中,这可能使它们对单个变量中的观测误差更为鲁棒。
- 相比之下, L1 惩罚会导致模型将其他权重清除为零而将权重集中在一小部分特征上。这称为特征选择(feature selection),这可能是其他场景下需要的。
- 根据之前章节所讲的,我们根据估计值与观测值之间的差异来更新 w 。然而,我们同时也在试图将 w 的大小缩小到零。这就是为什么这种方法有时被称为***权重衰减***
4.5.2. 高维线性回归
4.6. Dropout
- 在 4.5节 中,我们介绍了通过惩罚权重的2L2范数来正则化统计模型的经典方法。在概率角度看,我们可以通过以下论证来证明这一技术的合理性:我们已经假设了一个先验,即权重的值取自均值为0的高斯分布。更直观的是,我们可能会说,我们鼓励模型将其权重分散到许多特征中,而不是过于依赖少数潜在的虚假关联。
4.6.1. 重新审视过拟合
- 在传统说法中,泛化性和灵活性之间的这种基本权衡被描述为 偏差-方差权衡 (bias-variance tradeoff)。线性模型有很高的偏差:它们只能表示一小类函数。然而,这些模型的方差很低:它们在不同的随机数据样本上给出了相似的结果。