AI-动手学深度学习-笔记
张量
当张量的形状为 (3, 4, 4)
时,可以将其理解为一个 包含多个层的神经网络模型。让我们用 特征和权重 来比喻:
比喻解释
假设你有一个神经网络模型,输入层有 4 个特征(即 4 个特征值),并且你有 4 个权重值用于每个特征的计算。
- 3:表示神经网络中有 3 个不同的层(例如 3 个不同的神经网络中的权重矩阵)。
- 4:每个层的 输入特征有 4 个(例如每一层有 4 个特征或神经元)。
- 4:每个层的 每个特征有 4 个权重值(即每个特征都被 4 个不同的权重处理,或者每个神经元的连接数是 4)。
举个例子
假设你有一个多层感知机(MLP)神经网络模型,其中每一层的输入和输出都是 4 维的向量,而每一层的每个神经元的权重是一个 4 维的向量。张量的形状 (3, 4, 4)
就可以表示:
- 第一维
3
代表神经网络中有 3 层(或 3 个不同的权重矩阵)。 - 第二维和第三维
4
代表每个矩阵(层)的大小是 4x4,这意味着每一层有 4 个输入特征,并且每个特征有 4 个对应的权重。
具体举例
假设你有以下模型:
- 层 1:输入是 4 个特征,输出是 4 个神经元。每个神经元有 4 个权重,意味着每个神经元的计算有 4 个权重与输入特征进行相乘。
- 层 2:同样,输入是 4 个特征,输出也是 4 个神经元,每个神经元有 4 个权重。
- 层 3:依然是 4 个输入特征,4 个神经元和 4 个权重。
这样,总共有 3 个层,每层都有一个 4x4 的权重矩阵,表示每个特征在该层中如何与其他特征结合形成输出。
代码示例
1 | import torch |
解释
- 第一维
3
表示你有 3 个层,每层有一个 4x4 的权重矩阵。 - 第二维和第三维的
4
表示每个层的每个神经元的计算中使用了 4 个权重,每个权重都与输入特征相乘。
正则化
正则化(Regularization)是机器学习中用来防止模型过拟合的一种技术。过拟合是指模型在训练数据上表现很好,但在新数据(测试数据)上表现差,通常是因为模型太复杂,学习到了数据中的噪音或不重要的细节。
1. 过拟合的原因
- 模型在训练时过于“记住”了训练数据中的细节,而不是学到泛化规律(即如何处理新数据)。
- 复杂的模型(比如有很多参数)更容易过拟合。
2. 正则化的目的
正则化的目标是通过限制模型的复杂度,避免模型对训练数据的过度拟合。它通过给模型加上一些额外的约束,使得模型在学习时不能“随意”地调整参数,而是保持适度的简单性。
3. 如何实现正则化?
正则化通常通过在损失函数中加入一个额外的项来实现,这个项通常与模型的权重(参数)大小有关。常见的正则化方法有两种:
(1) L1 正则化(Lasso)
- L1 正则化在损失函数中加入一个与权重的绝对值之和成比例的项。
- 它的作用是“惩罚”大权重,迫使模型学习到的特征更加简洁。
- L1 正则化的效果:它可以将某些权重变为零,相当于自动选择特征。
公式:
$$
\text{L1 正则化} = \lambda \sum_{i=1}^{n} |w_i|
$$
- 其中,$w_i$ 是模型的权重,$\lambda$ 是正则化的强度(越大,惩罚越强)。
(2) L2 正则化(Ridge)
- L2 正则化在损失函数中加入一个与权重的平方和成比例的项。
- 它的作用是惩罚大权重,但不像 L1 那样将权重变为零,而是让权重变得更小,防止某些特征对模型的影响过大。
- L2 正则化的效果:它可以平滑模型,使模型更加稳健。
公式:
$$
\text{L2 正则化} = \lambda \sum_{i=1}^{n} w_i^2
$$
4. 如何理解正则化?
举个简单的例子:
假设你在做一个学生的成绩预测模型,输入特征有 学习时间、上课出勤率、平时作业分数 等。如果模型过于复杂,可能会学习到一些不重要的特征,比如学生每天吃的零食种类。这样,模型会在训练集上表现很好,但在实际使用时可能表现差,因为这些不重要的特征对新数据没有帮助。
通过正则化,你给模型添加了一些惩罚,强迫它只关注重要的特征,并避免关注那些噪音和不重要的细节。这样,模型会学到更有用的规律,泛化能力更强。
5. 正则化的效果
- 减少过拟合:通过限制模型复杂度,使得模型不仅能在训练数据上表现好,也能在新数据上表现好。
- 提升模型的泛化能力:正则化可以帮助模型学到更为通用的规律,而不是记住训练数据中的细节。
如何理解L1/L2正则化?
好的,我们再深入一点,详细计算一下 L1 正则化是如何惩罚权重的,以及它如何引导模型减少不重要特征的影响。
假设情境
我们使用一个非常简单的线性回归模型,有 2 个特征$x_1$ 和$x_2$,目标是预测 y。模型的公式为:
$$
y = w_1 x_1 + w_2 x_2 + b
$$
其中:
- $w_1$ 和 $w_2$ 是特征 $x_1$ 和 $x_2$ 的权重。
- $b$ 是偏置项(在这里我们忽略不讨论)。
我们要最小化的是总损失,即:
$$
\text{总损失} = \text{MSE(均方误差)} + \text{L1 正则化损失}
$$
均方误差(MSE)用来衡量模型预测值与实际值之间的误差,而 L1 正则化损失用来惩罚权重,使它们尽可能小。
1. 没有正则化的情况
假设我们没有正则化,只有 MSE 损失。对于一个简单的回归模型,损失函数可以表示为:
$$
\text{MSE} = \frac{1}{N} \sum_{i=1}^{N} (y_{\text{预测}, i} - y_{\text{实际}, i})^2
$$
其中,$y_{\text{预测}, i} = w_1 x_{1,i} + w_2 x_{2,i} + b$,是模型的预测值。
在没有正则化的情况下,模型的目标是尽量减小 MSE,但它不考虑特征权重的大小,可能会导致模型过度依赖某些特征。
2. 加入 L1 正则化
L1 正则化在损失函数中加入了对权重的惩罚项。对于每个权重,惩罚项是它的绝对值。损失函数现在变成了:
$$
\text{总损失} = \text{MSE} + \lambda \left( |w_1| + |w_2| \right)
$$
其中,$\lambda$ 是正则化系数,控制惩罚项的强度。如果 $\lambda$ 很大,惩罚就会更强,权重会被压缩得更小。
3. 例子:权重调整过程
假设我们训练了模型,得到了初始的权重:
- $w_1 = 5$
- $w_2 = 0.1$
- 正则化系数 $\lambda = 0.1$
我们还假设 MSE 损失部分的计算结果为 50(为了简化计算,不考虑具体的样本数据)。
步骤 1:计算正则化损失
L1 正则化损失是:
$$
\text{L1 正则化损失} = \lambda \left( |w_1| + |w_2| \right)
$$
代入权重值:
$$
\text{L1 正则化损失} = 0.1 \times (|5| + |0.1|) = 0.1 \times (5 + 0.1) = 0.1 \times 5.1 = 0.51
$$
步骤 2:总损失
现在,模型的总损失是:
$$
\text{总损失} = \text{MSE} + \text{L1 正则化损失}
$$
$$
\text{总损失} = 50 + 0.51 = 50.51
$$
所以,在这种情况下,L1 正则化的惩罚项增加了总损失。
步骤 3:权重更新(梯度下降)
模型通过梯度下降来最小化总损失。在梯度下降过程中,L1 正则化的惩罚项会影响梯度的计算,使得权重的更新不仅考虑误差,还考虑惩罚项。
在每次更新过程中,L1 正则化对每个权重的影响如下:
- 对于 $w_1$,L1 正则化会迫使它变小。因为 $|w_1| = 5$,所以它的梯度下降会考虑惩罚项。
- 对于 $w_2$,L1 正则化会更加显著地影响它。由于 $|w_2| = 0.1$,惩罚项在 $w_2$ 上的效果更明显,权重会逐步变小。
因为较大的权重已经对模型的预测结果产生较大的影响,L1 正则化的惩罚项只是对这个权重施加一个适度的惩罚,导致它会被逐渐减小,但不至于过多压缩。较小的权重这是因为它本身的绝对值较小,正则化的惩罚就会占据更大的比重,迫使它迅速变小甚至归零。(模型总是在选择使得损失函数变小的参数)
步骤 4:逐步更新
假设我们计算出了梯度,并在一次更新后得到以下新的权重(梯度下降步长为 0.1):
- $ w_1 = 4.8$
- $w_2 = 0.05$
这个更新过程说明了,L1 正则化会推动较小的权重变得更小,并让它们趋向于零。
4. 最终权重的变化
继续进行多次更新,L1 正则化会导致 $w_2$(那个较小的权重)逐渐减少,甚至变为零。假设经过足够多的训练步骤,最后我们得到:
- $w_1 = 4.5$
- $w_2 = 0$
此时,L1 正则化已经将不重要的特征(即 $w_2$)的权重压缩为零,表明模型已经“去除了”不重要的特征。
自注意力机制
自注意力机制 (Self-Attention Mechanism)
自注意力机制是 Transformer 模型的核心,它帮助模型捕捉输入序列中不同位置之间的依赖关系。它的目的是使每个输入元素(例如一个词)能够与其他输入元素进行交互,从而更好地理解上下文信息。自注意力机制比传统的循环神经网络(RNN)和卷积神经网络(CNN)更强大,因为它能够同时考虑整个序列的信息,而不需要按顺序逐一处理。
核心概念
输入表示:自注意力机制首先接收一个输入序列。对于文本输入,通常每个词被嵌入成一个向量,形成一个矩阵。
查询(Query)、键(Key)和值(Value):
- 查询(Q):每个输入词(或词向量)都会映射为一个查询向量,用来与其他词进行“匹配”。
- 键(K):每个输入词也会映射为一个键向量,查询会与这些键进行匹配,以确定其相关性。
- 值(V):每个输入词也会有一个值向量,最终输出是基于查询和键的匹配得分加权得到的值向量的加权和。
计算注意力得分:
自注意力机制通过计算每个查询向量与所有键向量之间的相似度(通常使用点积)。相似度得分越高,表示查询和键之间的关联越强。通常,通过Softmax对得分进行归一化,得到注意力权重。$$
\text{Attention Score} = Q \cdot K^T
$$
然后,使用 Softmax 函数将这些得分转化为概率,确保权重总和为1:$$
\text{Attention Weight} = \text{Softmax}(Q \cdot K^T)
$$加权求和值:
通过对每个值(V)向量加权求和,生成最终的输出。具体来说,注意力权重会决定各个值向量在最终输出中的贡献。$$
\text{Output} = \sum (\text{Attention Weight}_i \cdot V_i)
$$多头注意力:
Transformer 使用多头注意力机制,意味着查询、键和值向量会被拆分成多个子空间,分别计算注意力。这允许模型在不同的子空间中关注输入的不同方面。最后,多个头的结果会被拼接起来,并通过一个线性层进行变换。
自注意力机制的作用
- 捕获长距离依赖:传统的 RNN 和 CNN 主要通过局部邻域来获取信息,而自注意力机制可以通过计算所有词的相关性,捕获长距离依赖。
- 并行处理:由于不依赖于序列的顺序,自注意力机制允许模型对输入进行并行处理,效率更高。
- 灵活性:每个位置根据上下文信息调整其关注的焦点。
Transformer 中的自注意力层
Transformer 模型完全基于自注意力机制,它使用了多个自注意力层来处理序列数据。Transformer 模型中最重要的组件是 自注意力层(Self-Attention Layer)和 前馈神经网络(Feed-Forward Neural Networks)。我们来深入探讨自注意力层的工作原理。
Transformer 模型架构
Transformer 模型由多个堆叠的编码器(Encoder)和解码器(Decoder)组成。在每个编码器和解码器中,自注意力层都起着关键作用。
编码器(Encoder):
每个编码器层有两个主要部分:- 自注意力机制:编码器的每一层都包括一个自注意力层,它允许输入序列中的每个位置根据全局上下文来调整其表示。
- 前馈神经网络:每个编码器还包含一个小型的前馈神经网络(Feed-Forward Neural Network),它通过线性变换和激活函数进一步处理输入。
解码器(Decoder):
解码器的结构与编码器相似,但它在自注意力机制中加入了“遮蔽”(Masked)机制,以确保解码时每个位置仅能看到当前位置及之前的输入。此外,解码器中的每个自注意力层还会与编码器的输出交互,获取全局信息。
自注意力层的具体实现
自注意力层包括以下几个步骤:
输入嵌入和位置编码:
输入的每个词首先通过嵌入(embedding)层转换为向量,并加上位置编码,以捕捉序列的顺序信息。查询、键和值:
将输入的嵌入向量通过线性变换生成查询(Q)、键(K)和值(V)向量。计算注意力:
计算每个查询和所有键的点积,得到注意力分数,并通过 Softmax 得到归一化的权重。加权求和:
使用这些权重对值(V)向量加权求和,得到每个位置的加权表示。输出:
最后的输出通过多头注意力机制合并多个头的结果,然后通过一个线性层进行变换。
自注意力层的公式
假设我们有一个输入序列 $X = [x_1, x_2, \dots, x_n]$,每个 $x_i$ 是一个词的嵌入向量。通过训练,我们学习到查询(Q)、键(K)和值(V)矩阵,分别将输入映射为 $Q = XW_Q$、$K = XW_K$、$V = XW_V$。
- 计算注意力得分:
$$
\text{Attention Score}(Q, K) = \frac{QK^T}{\sqrt{d_k}}
$$
- 归一化注意力得分:
$$
\text{Attention Weight} = \text{Softmax}\left(\frac{QK^T}{\sqrt{d_k}}\right)
$$
- 加权求和:
$$
\text{Output} = \text{Attention Weight} \cdot V
$$
多头注意力机制
在 Transformer 中的 多头注意力(Multi-Head Attention)机制中,”拼接”(concatenation)指的是将多个注意力头的输出连接起来,以便能够捕获输入序列的更多信息。接下来,拼接后的结果会经过一个线性变换来得到最终的输出。
多头注意力机制的步骤
计算多个注意力头:
在多头注意力中,首先将输入的查询(Query)、键(Key)和值(Value)通过不同的线性变换分别映射到多个子空间,形成多个不同的查询、键和值的集合。每个头(head)对应于不同的查询、键、值子空间。假设总的嵌入维度是 $C$,而有 $h$ 个注意力头。那么,每个注意力头的维度为 $A = \frac{C}{h}$,即每个头的维度是总维度 $C$ 除以头的数量 $h$。
每个注意力头的计算:
对于每个注意力头,都会计算一个独立的自注意力输出。具体的计算过程如下:- 对每个头,使用自己的查询、键和值计算注意力得分并进行加权求和,得到该头的输出。
拼接所有头的输出:
每个头的输出维度是 $A$,所以如果有 $h$ 个头,那么拼接后的输出将是一个维度为 $h \times A = C$ 的向量。也就是说,拼接后的结果恢复了原始的输入维度 $C$。这个拼接的过程非常简单,就是将每个头的输出按顺序连接在一起,得到一个大向量。
线性变换:
将拼接后的多头注意力输出通过一个线性层(即一个权重矩阵)进行变换,得到最终的输出。
举个例子
假设输入的维度为 $C = 8$,有 $h = 2$ 个注意力头(即每个头的维度 $A = 4$)。我们来看看这个过程如何进行:
输入和映射:
输入是一个长度为 8 的向量,经过线性变换后,我们会得到两个查询(Query)、键(Key)和值(Value)的子空间,每个子空间的维度是 4。计算每个头的输出:
对于每个头(总共有 2 个头),计算它们的注意力输出(每个头的输出维度为 4)。- 头 1 的输出是一个 4 维向量。
- 头 2 的输出是另一个 4 维向量。
拼接:
将这两个头的输出拼接起来,得到一个 8 维的向量:$$
\text{Concatenated Output} = [\text{Head 1 Output}, \text{Head 2 Output}]
$$这就是拼接的过程。最终拼接结果的维度是 $C = 8$。
线性变换:
将拼接后的输出通过一个线性变换,得到最终的多头注意力层输出。
总结
- 多头注意力的拼接步骤其实是将每个注意力头计算出的输出向量沿着维度方向拼接起来,得到一个较大的向量。
- 这种拼接允许模型在不同的子空间中“并行”地学习不同类型的特征,而不是仅仅依赖于一个单一的注意力头。
- 最后,通过线性变换将拼接后的输出映射回原始维度 $C$,为后续的网络层提供输入。
这个过程使得 Transformer 模型能够从多个角度和不同的子空间捕获序列中的信息,从而提高模型的表达能力。
传统神经网络的输入和transform中的输入
1. 传统神经网络中的输入
在传统的神经网络(如前馈神经网络)中,输入通常是一个固定维度的向量或矩阵,具体内容取决于任务类型:
结构化数据:
输入是一个包含多种特征的向量。例如,在房价预测中,输入可能是房屋面积、房间数量等数值型特征。图像数据:
输入是二维或三维矩阵。例如,在图像分类任务中,输入是像素值组成的矩阵,可能还有 RGB 通道。文本数据:
输入通常是经过嵌入的向量,例如词嵌入(word embedding)或句子嵌入。
特点:
- 输入是独立的,每个样本的输入没有显式的上下文关联。
- 输入的维度固定。
- 输入数据需要提前提取和处理为数值形式。
2. Transformer 编码器中的前馈神经网络输入
在 Transformer 的编码器中,前馈神经网络(Feed-Forward Neural Network, FFN)的输入是 注意力层的输出,它是上下文相关的特征表示。以下是输入的主要特点:
来源:
输入是经过自注意力层处理后的输出,每个词(或序列位置)的表示已经包含了与其他词的上下文依赖关系。形状:
输入是一个三维张量,形状为 $[batch_size, sequence_length, embedding_dim]$。batch_size
:批量大小。sequence_length
:序列的长度(例如一个句子中的词数)。embedding_dim
:每个词的嵌入向量的维度。
内容:
每个位置的表示已经结合了该位置与其他位置之间的注意力权重(即上下文信息),所以它是 上下文相关的表示。
特点:
- 输入包含上下文依赖信息。
- 输入维度与嵌入维度一致,但输入每个位置的值已经经过注意力机制的加权。
- 输入可以表示整个序列的信息,而不是单个独立样本。
3. 传统神经网络输入与 Transformer 编码器中 FFN 输入的区别
特性 | 传统神经网络的输入 | Transformer 编码器中的 FFN 输入 |
---|---|---|
上下文依赖 | 输入数据通常是独立的,每个样本相互无关。 | 输入每个位置的表示包含上下文相关信息。 |
输入形状 | 向量或矩阵,具体形状依赖任务。 | 三维张量,形状为 ([batch_size, sequence_length, embedding_dim])。 |
维度 | 固定的输入特征维度。 | 嵌入维度通常与序列的长度和批量大小相关联。 |
表示方式 | 特征通常是直接提取的原始数据特征。 | 输入是经过嵌入层和自注意力层处理的特征表示。 |
上下文信息 | 特征是独立的,不包含其他样本的信息。 | 特征表示已经包含序列中其他位置的相关性。 |
4. 总结
- 传统神经网络:输入是独立的特征向量,通常没有上下文信息。网络依赖于层间权重来建模数据之间的关系。
- Transformer 编码器中的前馈神经网络:输入是注意力层输出的上下文相关表示,已经包含序列中各位置之间的依赖关系。FFN 的作用是在每个位置上进一步非线性地变换这些上下文相关的特征。
这种区别使得 Transformer 特别适合处理序列数据,例如自然语言处理和时间序列建模,因为其输入已经通过自注意力层捕获了序列的全局信息。