Skip to content

线性代数

基本知识

核心概念

线性代数的核心概念包括:

  • 标量 scalar,就是一个单独的数
  • 向量 vector,就是一列数,一般用于将一个复杂信息映射到一个连续数值空间作为特征表示,是数据的数学化身
  • 矩阵 matrix
  • 张量 tensor

Vector

在物理中,向量代表空间中的箭头;在CS中,向量大多数时候代表有序的数字列表。一个长度为2的列表,就被称为2维向量。

向量在书面表达上有两种主要的排列方式:

  • 列向量(Column Vector): 竖着写的形式,如 \(\boldsymbol{x} = \begin{pmatrix} x_1 \\ x_2 \\ \vdots \\ x_n \end{pmatrix}\)
  • 行向量(Row Vector): 横着写的形式,如 \(\boldsymbol{x} = (x_1, x_2, \dots, x_n)\)

在数学规范中,如果不加特殊说明,通常默认向量是列向量。为了节省排版空间,我们经常把原本应该竖着写的列向量横着写,并加上一个上标 \(\text{T}\) ,这就是 转置

单位向量是具有单位范数的向量。

Norm

简单来说,范数就是用来衡量向量“长度”或“大小”的一个函数。范数(Norm) 并不是两个向量相加,它是作用在 单个向量 上的一个函数,用来计算这个向量的 “长度”“大小”

要称一个函数为“范数”,它必须像我们直觉中的“长度”一样,满足三个核心性质:

  • 正定性(Positivity): 向量的长度不能是负数。只有当向量本身是零向量时,它的长度才等于 0。
  • 绝对齐次性(Homogeneity): 如果你把向量放大 \(a\) 倍,它的长度也应该相应地放大 \(|a|\) 倍。
  • 三角不等式(Triangle Inequality): 两边之和大于等于第三边。即两个向量相加后的长度,不会超过它们各自长度的和:
\[ \|\boldsymbol{x} + \boldsymbol{y}\| \leq \|\boldsymbol{x}\| + \|\boldsymbol{y}\| \]

对于一个 \(n\) 维向量 \(\boldsymbol{x}\),其 \(L_p\) 范数的通式为:

\[ \|\boldsymbol{x}\|_p = \left( \sum_{i=1}^n |x_i|^p \right)^{1/p}, \quad p \ge 1 \]

假设有一个 \(n\) 维向量 \(\boldsymbol{x} = [x_1, x_2, \dots, x_n]^\text{T}\),其各项公式如下:

\(L_1\) 范数 (Manhattan Norm)

又称“绝对值之和范数”或“曼哈顿距离”。

\[ \|\boldsymbol{x}\|_1 = \sum_{i=1}^n |x_i| = |x_1| + |x_2| + \dots + |x_n| \]

\(L_2\) 范数 (Euclidean Norm)

最常用的范数,即通常意义上的“几何长度”或“欧几里得距离”。

\[ \|\boldsymbol{x}\|_2 = \sqrt{\sum_{i=1}^n x_i^2} = \sqrt{x_1^2 + x_2^2 + \dots + x_n^2} \]

\(L_\infty\) 范数 (Maximum Norm)

又称“无穷范数”或“切比雪夫范数”,取向量分量中绝对值最大的那一个。

\[ \|\boldsymbol{x}\|_\infty = \max_{i} |x_i| = \max(|x_1|, |x_2|, \dots, |x_n|) \]

\(L_0\) 范数 (Zero Norm)

严格来说它不是数学定义的范数,但在工程中常用于表示向量的 稀疏性 。它表示向量中非零元素的个数。

\[ \|\boldsymbol{x}\|_0 = \#\{i \mid x_i \neq 0\} \]

在计算机科学(CS)和人工智能(AI)中,向量确实表现为一组有序数列,但我们计算它的“长度”(范数),本质上是在 量化某种“代价”、“差异”或“重要性” 。如果没有范数,向量就只是一堆静止的数字;有了范数,我们就能比较这些数字。以下是范数在 AI 和 CS 中的核心意义:

  • 衡量两个东西有多像,比如搜索一个商品的时候,搜索引擎可以计算搜索词向量和商品向量之间的距离,来进行搜索结果排序,并展示推荐
  • 限制模型的复杂度,训练模型的时候,如果参数(权重向量w)的数值太大,模型容易想太多(过拟合),因此可以把参数向量加入损失函数,让模型在学习规律的同时保持参数尽可能小或者尽可能稀疏

Tensor

这里的值得注意的是tensor,标量其实就是0阶(rank)张量,比如损失值、温度;向量就是1阶张量,比如一个词的embedding、一个人的特征序列等;矩阵就是2阶张量,比如权重矩阵W、灰度图;3阶张量如一张彩色照片,有高、宽、颜色通道共3个序列;4阶张量如一个批次的图片(图片张数x高x宽x通道)。

在机器学习中,一个向量就是一个样本(sample),向量的每一个数字被称为一个特征(feature),矩阵则代表一个数据集。比方说,在一个矩阵中,每一行代表一个样本(如一个房子),每一列则代表一个特征(比如房屋面积)。

在传统机器学习中张量很少出现,只有处理时序数据或者图像时才会用到3维及以上的张量。

而在深度学习中,几乎所有的数据、所有模型参数、所有中间计算结果都是张量。深度学习框架如PyTorch、TensorFlow可以看作是一个专门处理张量的加工厂。

Rank(阶)

阶(Rank) 类似于坐标轴的“轴”,比如说3维空间坐标轴有3个阶。比方来说,对于一个3阶的tensor,每个阶都是一个包含100个数字的序列,那么每一个阶就是100维。

当然,每一个rank里头的数字不一定需要一样多。比如说,一张彩色照片的tensor shape通常是:[1080, 1920, 3],这代表了一个3阶张量,其中:

  • 1080代表高度,即照片的纵向像素有1080行
  • 1920代表宽度,即照片的横向像素有1920行
  • 3代表颜色,即RGB三个颜色

对于这个3阶张量,如果我们进行可视化,它的形状将是一个长方体。

我们可以把每一个rank视作一把尺子,每一阶的长度决定了尺子有多长。

在深度学习中,有一个叫做“变形”(reshape)的动作。比方说,我们可以把一个[10, 512]的tensor(代表10个单词,每个单词被映射为512维的数列)直接揉成一个[5120]的长向量,从而让rank从2变成1。

在实际使用中,一般张量的阶从1到5不等,且要考虑到批次(batch)轴。

Broadcasting

在深度学习中,我们经常使用一种不那么常规的简写符号,允许 矩阵和向量相加 ,产生另一个矩阵。这种操作被称为广播(broadcasting)

  • \(C = A + b\),其中 \(C_{i,j} = A_{i,j} + b_j\)

在数学上,矩阵加法要求两个矩阵必须 完全一样大 。但如果我们要给 1000 个特征向量(矩阵 \(A\))都加上同一个偏移量(向量 \(b\)),手动把 \(b\) 复制 1000 遍会非常浪费内存。

当你写 \(A + b\) 时,计算机发现 \(b\) 的维度比 \(A\) 少。它会 逻辑上 (而不是真的在内存里)把 \(b\) 沿着缺失的维度拉长。

  • 例子 :矩阵 \(A\)[100, 512],向量 \(b\)[512]
  • 广播机制会让 \(b\) 像“涂抹”一样,平铺到 \(A\) 的每一行上。
  • 结果\(A\) 的第 1 行加了 \(b\),第 2 行也加了 \(b\)……直到第 100 行。

Batching

Batching(批次处理) 就是把一群孤立的向量(比如多个词、多张图)整齐地堆叠成一个更高阶张量的过程。

在深度学习中,如果不用 Batching,模型的工作效率会极低。比方说,如果你一个一个地处理向量,GPU 的强大算力就会被浪费在反复读取数据上。我们将多个 1 阶张量(向量)横向或纵向堆叠,变成一个 2 阶张量(矩阵)。GPU 就像一辆拥有几千个座位的超级大巴,而每一个神经元计算就像是一个乘客。如果你一次只送一个向量进去,大巴每次只载一个人就发车,电力和带宽都被浪费在了路上。将多个向量合并成矩阵后,原本需要做 100 次的“向量 \(\times\) 矩阵”运算,变成了 1 次高效的“ 矩阵 \(\times\) 矩阵 ”运算。这种并行计算速度要快出几十甚至上百倍。

当你把一队数据(Batch)送进模型时,我们刚才总结的那些“数学招式”就开始配合了:

  • 排队进场 :数据以 [Batch, Features] 的形式进入。
  • 统一变换 :模型里的权重矩阵 \(W\) 会一次性作用于这一整队人。
  • 广播叠加 :如果你有一个偏置项 \(b\)(比如加 5 分),广播机制会叠加到队里的每一个人身上。你不需要为 32 个人准备 32 个 \(b\),只需要一个 \(b\),广播会自动“复印”并分发。

在实践中,你会经常听到这三个词,它们描述了“排队”的不同规模:

术语 含义 形象化比喻
Batch Size 一个批次里有多少个样本(比如 32、64)。 大巴车一次载多少人。
Iteration (迭代) 完成一个 Batch 的训练过程。 大巴车跑一趟。
Epoch (轮次) 所有训练数据(全校学生)都排队过了一遍模型。 全校学生都坐过车了。

.

矩阵

一个 \(m\)\(n\) 列的矩阵 \(\boldsymbol{A}\) 通常表示为:

\[ \boldsymbol{A} = \begin{bmatrix} a_{11} & a_{12} & \cdots & a_{1n} \\ a_{21} & a_{22} & \cdots & a_{2n} \\ \vdots & \vdots & \ddots & \vdots \\ a_{m1} & a_{m2} & \cdots & a_{mn} \end{bmatrix} \]
  • 元素\(a_{ij}\) 表示第 \(i\) 行第 \(j\) 列的数字。
  • 主对角线 :指 \(a_{11}, a_{22}, \dots, a_{kk}\) 所在的线。

一般矩阵用来表示数据表,一行是一个样本,一列是一个特征。

转置是将矩阵的行和列互换的操作,记作 \(\boldsymbol{A}^\text{T}\)

  • 公式 :若 \(\boldsymbol{B} = \boldsymbol{A}^\text{T}\),则 \(b_{ij} = a_{ji}\)
  • 性质\((\boldsymbol{A}^\text{T})^\text{T} = \boldsymbol{A}\)

单位矩阵(Identity Matrix)主对角线全为 1,其余全为 0 的方阵,记作 \(\boldsymbol{I}\)

\[ \boldsymbol{I}_n = \begin{bmatrix} 1 & 0 & \cdots & 0 \\ 0 & 1 & \cdots & 0 \\ \vdots & \vdots & \ddots & \vdots \\ 0 & 0 & \cdots & 1 \end{bmatrix} \]

任何矩阵乘以单位矩阵都等于它本身(\(\boldsymbol{A}\boldsymbol{I} = \boldsymbol{A}\)),相当于数字中的 “1”。


对角矩阵(Diagonal Matrix)除了主对角线上的元素外,其余元素全部为 0 的矩阵。\(\boldsymbol{D} = \text{diag}(d_1, d_2, \dots, d_n)\),即当 \(i \neq j\) 时,\(a_{ij} = 0\)。对角矩阵常用于缩放数据特征。

矩阵的范数

矩阵也有“长度”的概念。最常用的是 Frobenius 范数 (类似于向量的 \(L_2\) 范数):

\[ \|\boldsymbol{A}\|_F = \sqrt{\sum_{i=1}^m \sum_{j=1}^n a_{ij}^2} \]
  • 直观理解 :把矩阵里所有的数都平方加起来,最后开根号。这在深度学习中用来衡量整个神经网络参数的“总量”。

矩阵加法

只要矩阵的 形状(Shape)一样 ,就可以把两个矩阵相加:

  • \(C = A + B\),即对应位置的元素分别相加:\(C_{i,j} = A_{i,j} + B_{i,j}\)

标量与矩阵相乘或相加时,只需将其与矩阵的每一个元素分别相乘或相加:

  • \(D = a \cdot B + c\),其中 \(D_{i,j} = a \cdot B_{i,j} + c\)

点积

如果矩阵 \(A\) 的形状是 \(m \times n\),矩阵 \(B\) 的形状是 \(n \times p\),那么 \(A\)列数必须等于 \(B\)行数 。乘完之后,\(C\) 的形状是 \(m \times p\)

点积与矩阵乘法的计算逻辑如下:

\[ C_{i,j} = \sum_{k} A_{i,k}B_{k,j} \]

结果矩阵中第 \(i\) 行、第 \(j\) 列的那个数字,是由 \(A\)\(i\)\(B\)\(j\)进行 点积 (对应相乘再求和)得到的。

1769281771867

这个乘法方式看起来非常奇怪。这里我们必须要理解“线性”的含义。

如果我们有几个向量 \(\vec{v}_1, \vec{v}_2, \dots, \vec{v}_n\),给它们每个都配上一个常数系数 \(c_1, c_2, \dots, c_n\),那么:

\[ c_1\vec{v}_1 + c_2\vec{v}_2 + \dots + c_n\vec{v}_n \]

这个结果就叫做这组向量的一个 线性组合 。在整个过程中,向量只发生了 伸缩 (乘常数)和 相加 (平移),没有把向量拿去平方,也没有让两个向量互相乘。这保证了在空间中,这些变换始终是“直”(线性)的。

看下面这个矩阵乘法:

\[ \begin{bmatrix} 1 & 2 \\ 3 & 4 \end{bmatrix} \times \begin{bmatrix} 5 \\ 7 \end{bmatrix} \]

如果你换个视角看,它其实是在做线性组合:

它意味着:用右边的数字作为系数,去给左边的列向量“配料”。

\[ 5 \times \begin{bmatrix} 1 \\ 3 \end{bmatrix} + 7 \times \begin{bmatrix} 2 \\ 4 \end{bmatrix} \]
  • 你拿了 5 份列向量 1。
  • 你拿了 7 份列向量 2。
  • 把它们加起来。

矩阵乘法和我们小时候学习的数字乘法规则大不相同:

  • 不满足交换律,\(AB\) 通常不等于 \(BA\)
  • 满足结合律,\(A(BC) = (AB)C\)
  • 满足分配率,\(A(B + C) = AB + AC\)
  • 乘积的转置等于转置后的矩阵以相反顺序相乘,即 \((AB)^\top = B^\top A^\top\)

对于两个一阶向量,\(x\)\(y\) 的点积可以写成 \(x^\top y\)

注意,如果你只想让两个矩阵对应位置相乘,那叫“元素对应乘积”或 Hadamard 乘积 ,记作 \(A \odot B\)

线性组合

当你用矩阵 \(A\) 乘以向量 \(\mathbf{b}\) 时:

  • 矩阵 \(A\)* 的维度是 *\(m \times n\)\(m\) 行,\(n\) )。
  • 向量 \(\mathbf{b}\)* 的维度是 *\(n \times 1\)\(n\) ,1 列)。

只有当 \(A\) 的列数 (\(n\)) 等于 \(\mathbf{b}\) 的行数 (\(n\)) 时,乘法才有意义。

假设我们有 3 个人,每个人的特征是“身高”和“体重”:

  • 矩阵 \(A\)(数据矩阵): 每一行代表一个人,每一列代表一种特征。 $$ A = \begin{bmatrix} 180 & 75 \ 160 & 50 \ 175 & 80 \end{bmatrix} \begin{matrix} \leftarrow \text{张三} \ \leftarrow \text{李四} \ \leftarrow \text{王五} \end{matrix} $$
  • 向量 \(\vec{x}\)(权重向量): 代表你对不同特征的“重视程度”。 $$ \vec{x} = \begin{bmatrix} 0.6 \ 0.4 \end{bmatrix} \begin{matrix} \leftarrow \text{身高的权重} \ \leftarrow \text{体重的权重} \end{matrix} $$
  • 结果 \(A\vec{x}\)(得分向量): 矩阵乘以向量的过程,本质上是让矩阵的每一行与向量做 点积(Dot Product) : $$ A\vec{x} = \begin{bmatrix} 180 \times 0.6 + 75 \times 0.4 \ 160 \times 0.6 + 50 \times 0.4 \ 175 \times 0.6 + 80 \times 0.4 \end{bmatrix} = \begin{bmatrix} 138 \ 116 \ 137 \end{bmatrix} \begin{matrix} \leftarrow \text{张三得分} \ \leftarrow \text{李四得分} \ \leftarrow \text{王五得分} \end{matrix} $$

你刚才描述的这个逻辑,其实就是人工神经网络(Neural Networks) 中最基础的运算单元。

  • 特征提取: 在 AI 领域,矩阵 \(A\) 就是输入数据,向量 \(\vec{x}\) 是模型学习出来的参数。
  • 降维/压缩: 你把多维的特征(身高、体重)通过加权求和,压缩成了一个一维的分数。

在之前的例子里,你只有一个权重向量(比如只算“健康分”)。但如果现在,你想根据同样的身高、体重,同时算出三个指标: 健康分、体能分、魅力分 ,该怎么办?

这时候,你就不止一个权重向量了,而是有三个权重向量。把这三个向量并排摆在一起,就成了一个 权重矩阵 \(W\)**** 。

  • 矩阵 \(A\) (数据): 还是那 3 个人的身高、体重。
  • 矩阵 \(B\) (权重集): * 第一列:健康分的权重。
    • 第二列:体能分的权重。
    • 第三列:魅力分的权重。
\[ A \times B = C (\text{结果矩阵}) \]

在结果矩阵 \(C\) 中,每一行依然代表一个人,但 每一列代表一个不同的评价指标

直观理解: 矩阵乘以矩阵,本质上是 多组权重同时作用于同一组数据 。它一次性帮你完成了所有的评价计算。

矩阵乘以矩阵,既可以看作是多个线性变换的“打包”,也可以看作是多个线性变换的“叠加”。

这取决于你从哪个角度去看。为了让你彻底理解,我们分两个视角来拆解:

视角一:横向“打包”(并行的评价系统)

这就是你刚才提到的理解方式。假设矩阵 \(A\) 是数据,矩阵 \(B\) 是由两个权重向量 \([w_1, w_2]\) 组成的。

\[ A \times [w_1, w_2] = [Aw_1, Aw_2] \]

在这个视角下,矩阵乘法就是“批量处理”

  • 你把原本需要算两次的线性变换(一次算健康分,一次算体能分),打包成了一个动作。
  • 结论: 它是 多个线性变换同时作用于同一组数据

视角二:纵向“叠加”(复合变换)

这是数学家和计算机科学家最常用的视角。如果我们考虑两个变换矩阵 \(W_1\)\(W_2\),以及一个向量 \(\vec{x}\)

当我们将它们相乘 \((W_2 \times W_1) \vec{x}\) 时:

  1. 先由 \(W_1\)\(\vec{x}\) 做一次变换(比如旋转)。
  2. 再由 \(W_2\) 对变换后的结果做第二次变换(比如拉伸)。

矩阵乘法 \(W_2 W_1\) 的结果,本身就是一个新的矩阵 \(M\) 这个 \(M\) 代表了一个“复合变换”:它直接把两次连续的动作合二为一了。

直观比喻:

  • \(W_1\) 是“把衣服洗了”。
  • \(W_2\) 是“把衣服烘干”。
  • 矩阵乘法 \(W_2 W_1\) 就是一个“洗烘一体机”。你扔进去一件脏衣服(向量 \(\vec{x}\)),它直接吐出来一件干净且干燥的衣服。你不需要关心中间经历了两个步骤,因为这个新的矩阵已经把这两个功能融合在一起了。

总结:它算线性变换吗?

算!

在线性代数中,有一个非常重要的性质:两个线性变换的复合,依然是一个线性变换。

  • 即使你连续做了 100 次矩阵乘法(\(W_{100} \dots W_2 W_1\)),只要它们都是纯粹的矩阵相乘,最终都可以简化成唯一一个巨大的矩阵 \(M\)
  • 这个 \(M\) 依然是一个单一的线性变换。

关键点拨:为什么神经网络需要“非线性”?

既然你提到了 \(y = Wx + b\),这里有个非常深刻的逻辑:

如果神经网络里只是单纯的“矩阵乘以矩阵”,那么无论你叠多少层,它最终都等同于单层矩阵运算(因为 \(W_2(W_1x) = (W_2W_1)x\))。

这就是为什么我们在神经网络的层与层之间,必须加入 激活函数 (比如 ReLU)。

它的作用就是打破这种“矩阵叠加依然是线性变换”的魔咒,让模型能理解更复杂、非线性的世界(比如判断一张照片是猫还是狗,这种逻辑不是简单的加权求和能搞定的)。


例1

比方说,我们要考虑两个因素(特征):\(x_1\) 是电影的“动作成分”,\(x_2\) 是电影的“喜剧成分”。

  • 对于 用户 A ,他很喜欢动作片,对喜剧一般。他的评分逻辑可能是: \(5 \times x_1 + 1 \times x_2 = 评分\)
  • 对于 用户 B ,他很讨厌暴力,喜欢大笑。他的评分逻辑可能是: \(0 \times x_1 + 5 \times x_2 = 评分\)

如果有成千上万个用户和电影特征,我们不可能写几万个方程。这时我们就用矩阵:

\[ \begin{bmatrix} 5 & 1 \\ 0 & 5 \end{bmatrix} \begin{bmatrix} x_1 \\ x_2 \end{bmatrix} = \begin{bmatrix} y_A \\ y_B \end{bmatrix} \]

这里:

  • 左边矩阵 (A/W) :存储了不同用户的偏好“知识”。
  • 中间向量 (x) :是当前电影的属性(比如 \(x_1=0.9, x_2=0.1\) 代表这基本是一部纯动作片)。
  • 右边向量 (b/y) :是模型一次性为所有用户计算出的预测评分。

GPU可以利用这种形式,同时并行计算几百万个神经元的输出,大大提升效率。


例2

我们来通过一个具体的例子看一下计算过程:

  • \(x\) (输入向量) :是贷款申请人的个人资料。\(x = [年龄, 收入, 信用分]^\top\)
  • \(A\) (权重矩阵) :是银行的 内部评估规则 。它决定了“年龄”占多少权重,“信用分”占多少权重。
  • \(b\) (预测结果) :是模型算出来的分值(比如大于 0 准予贷款,小于 0 拒绝)。

假设 \(x = [25, 8000, 700]^\top\)(25岁,月入8k,信用700分)。

如果此时银行的审批逻辑(矩阵 \(A\))是:

\[ A = \begin{bmatrix} -0.1 & 0.002 & 0.5 \end{bmatrix} \]

(这里年龄前的 \(-0.1\) 表示年龄越大风险越高,信用分前的 \(0.5\) 表示信用分很重要)

计算 \(Ax = b\)

\[ b = (-0.1 \times 25) + (0.002 \times 8000) + (0.5 \times 700) = -2.5 + 16 + 350 = 363.5 \]

分值很高,准予贷款。

在现实中,银行并没有这一串精确的权重数字。所谓的“训练 AI”,其实就是为了填满矩阵 \(A\) 里的那些空格。

假设我们有几百万个人作为样本,那么我们就可以训练AI:

  1. 初始状态 :刚开始,矩阵 \(A\) 里的数字是随机乱填的(比如全是 0.001)。
  2. 喂入数据 :我们把银行过去 10 年里的几百万个真实案例(每个人对应的 \(x\) 和最终还钱没还钱的标签 \(b_{true}\))喂给 AI。
  3. 发现错误
  4. AI 用当前的 \(A\) 算了一下张三,觉得张三能还钱(\(b=300\))。
  5. 但历史记录显示张三最后违约了(\(b_{true}=-100\))。
  6. 微调 \(A\)* :AI 发现自己“算错了”,它就会去调整矩阵 *\(A\) 里的数字。比如它发现张三虽然收入高但信用极低,于是它就把 \(A\) 里面对应“信用分”那个格子的权重调得更高一点。

在求解过程中,我们不能用逆矩阵法求解。这是因为,在几百万人里,很高概率有两个人的资料看起来一样,但是结果却不同(一个还了钱,一个没还钱)。这叫做方程矛盾,即不存在一个完美的A能让所有等式同时成立。而且,现实中A可能是1000x10000的规模,计算量大到无法求逆。此外,现实逻辑不是简单的加减法。为了让模型变聪明,我们会在 \(Ax\) 之后加一个“激活函数”(比如负数变 0),这一下就把公式变成了非线性的,逆矩阵那套线性规则直接失效了。

下面我们来看看训练过程。训练过程就是把这几百万人一个一个拉出来试,每错一个,就把 \(A\) 里的数字拧一拧。直到这套逻辑在大多数人身上都算得准,这个矩阵 \(A\) 就算练成了。这个过程就像是在黑盒子里调旋钮: 你不知道内部结构,你只能输入 \(x\),看输出 \(b\),如果输出不对,你就把旋钮(矩阵 \(A\) 里的元素)往左或往右转一点点。转了几百万次后,你就得到了那个最完美的旋钮组合。

这就是为什么我们在深度学习里不谈“解方程”,而谈优化(Optimization)

下面我们来看一下这个宁旋钮是怎样的过程。在拧旋钮之前,AI 必须先知道自己错得有多离谱。我们用 张三 的例子来量化这个差距:

  • AI 预测分值 (\(b\))\(300\)
  • 历史真实结果 (\(b_{true}\))\(-100\)
  • 误差 (Error)\(b - b_{true} = 300 - (-100) = 400\)

这个 \(400\) 就是我们要消灭的目标。在数学上,我们会把这个误差平方一下,称之为“损失(Loss)”。损失越大,说明矩阵 \(A\) 现在的逻辑越烂。我们的训练目标就是让损失函数最小化。

现在,我们来看一下整个训练过程大概是什么样的。

初始设定:

  • 初始权重矩阵 \(A\)* :假设随机初始化为 *\([0, 0, 0.1]\) (即:年龄权重为 0,收入权重为 0,信用分权重为 \(0.1\))。
  • 判断标准 :如果计算结果 \(b > 50\),AI 预测为“准予贷款(1)”;否则为“拒绝(0)”。
  • 微调步长(学习率) :假设每次出错,我们固定把权重调整 \(0.02\)

第一步:输入数据 1(张三):

  • 数据 \(x_1\)* :*\([25, 8000, 700]^\top\)(信用分 700)。
  • 真实结果 \(y_1\)* :*\(1\)(还钱了)。
  • 模型计算结果 \(b\)* :*\(0.1 \times 700 = 70\)
  • AI 预测\(70 > 50\),预测为 \(1\)
  • 对比与调整 :预测正确。权重 \(A\) 保持 \([0, 0, 0.1]\) 不变。

第二步:输入数据 2(李四):

  • 数据 \(x_2\)* :*\([30, 6000, 450]^\top\)(信用分 450)。
  • 真实结果 \(y_2\)* :*\(0\)(没还钱)。
  • 模型计算结果 \(b\)* :*\(0.1 \times 450 = 45\)
  • AI 预测\(45 < 50\),预测为 \(0\)
  • 对比与调整 :预测正确。权重 \(A\) 依然保持 \([0, 0, 0.1]\) 不变。

第三步:输入数据 3(王五):

  • 数据 \(x_3\)* :*\([40, 30000, 650]^\top\)(信用分 650)。
  • 真实结果 \(y_3\)* :*\(0\)(虽然信用分高,但意外违约了)。
  • 模型计算结果 \(b\)* :*\(0.1 \times 650 = 65\)
  • AI 预测\(65 > 50\),预测为 \(1\)(AI 认为他会还钱)。
  • 对比与调整预测错误! 结果应该是 \(0\)
  • AI 的纠错逻辑 :它发现现在的权重 \(0.1\) 对于高分者太宽松了。
  • 微调动作 :为了让计算结果 \(b\) 降下来,它把信用分权重减掉一个步长 \(0.02\)
  • 权重 \(A\) 变为\([0, 0, 0.08]\)

矩阵 \(A\) 的进化路径总结如下:

  • 初始状态\(A = [0, 0, 0.10]\)
  • 过完张三\(A = [0, 0, 0.10]\)(无变化)
  • 过完李四\(A = [0, 0, 0.10]\)(无变化)
  • 过完王五\(A = [0, 0, 0.08]\)(因为出错而下调)

如果你接着输入 几百万个人 ,权重 \(A\) 就会像这样不断微调:

  • 遇到“信用高且还钱”的,它会想往上调一点。
  • 遇到“信用高但违约”的,它会想往下调一点。

最终经过几百万次的拉扯,权重会停在一个“全局胜算最大”的数字上(比如 \(0.075\))。这就是为什么我们说 \(Ax=b\) 的过程是在“优化”。矩阵 \(A\) 里的数字不是解出来的,而是被这几百万人“磨”出来的。

在上面的例子中,我们把王五的信用分代入公式\(b = A \times x\),算出\(b=65\),由于 \(65 > 50\),模型给出了“准予贷款”的预测。这是信息从输入层流向输出层。然而,我们立刻发现预测结果(准予)和真实标签(违约)不符。误差 = 预测值 - 真实值。这是反向传播的“发令枪”。没有误差,就没有反向传播。

当结果出错时,AI 会问:“为了让误差变小,我该动谁?” 在你的例子里,公式只有 \(A \times 650\)链式法则(微积分核心): 数学上,误差对权重 \(A\) 的导数就是 \(650\)。这告诉 AI:“信用分 \(x\) 越大,它对最终错误结果的‘责任’就越大。”这种“把错误从后往前推,计算出每个权重该负多少责”的过程,就是 反向传播

在你的例子里只有一层矩阵 \(A\),所以“找谁负责”一眼就能看出来。但如果神经网络有 100 层:

\[ Output = A_{100} \times (A_{99} \times (\dots \times (A_1 \times x)\dots)) \]

当最后的结果错了,反向传播就像一个极其专业的审计员:

  1. 它先查第 100 层的责任。
  2. 再通过第 100 层推导出第 99 层的责任。
  3. 一路推回第 1 层。
  4. 如果没有反向传播,深层网络根本没法训练,因为你不知道该拧中间哪一层的旋钮。

在刚才的例子中:

  • 计算 \(0.1 \times 650 = 65\)**** 是前向传播。
  • 意识到“结果太大了,得减小 \(A\) 这一瞬间的逻辑推导,就是 反向传播
  • \(0.1\) 减掉 \(0.02\) 变成 \(0.08\)**** 是优化更新。

更加具体的讲解,可以参考反向传播章节。

Span

我们继续用刚才的例子来说明Span(生成空间)。

假设我们有 3 个人,每个人的特征是“身高”和“体重”:

  • 矩阵 \(A\)(数据矩阵): 每一行代表一个人,每一列代表一种特征。 $$ A = \begin{bmatrix} 180 & 75 \ 160 & 50 \ 175 & 80 \end{bmatrix} \begin{matrix} \leftarrow \text{张三} \ \leftarrow \text{李四} \ \leftarrow \text{王五} \end{matrix} $$
  • 向量 \(\vec{x}\)(权重向量): 代表你对不同特征的“重视程度”。 $$ \vec{x} = \begin{bmatrix} 0.6 \ 0.4 \end{bmatrix} \begin{matrix} \leftarrow \text{身高的权重} \ \leftarrow \text{体重的权重} \end{matrix} $$

我们现在来看A的列

  • 向量 \(v_1\) (身高列)[180, 160, 175](代表三位同学的身高分布)
  • 向量 \(v_2\) (体重列)[75, 50, 80](代表三位同学的体重分布)

这里的生成空间,就是当你随意变动身高权重 \(w_1\) 和体重权重 \(w_2\) 时,所能计算出来的 所有可能的“得分结果”向量

公式表达: 所有可能的得分向量 \(b = w_1 \cdot \text{身高向量} + w_2 \cdot \text{体重向量}\)

生成空间定义了模型的上限。由于你只有两个特征(身高、体重),你得到的“得分向量”永远只能在这个由两个向量张成的二维平面里跳动。

虽然你有 3 个同学(结果是三维向量),但因为你只有 2 个评价维度,你无法通过调整权重,让三个人得到任意你想要的组合。

  • 比如,你可能想让张三得 100 分,李四得 0 分,王五得 50 分。
  • 如果这个特定的分数组合 [100, 0, 50] 不在身高和体重的“生成空间”里,那么你的模型永远无法通过调整权重来实现这个打分目标。

列空间

列空间 = 矩阵各列的 Span。在深度学习里,这意味着一个神经层(由矩阵 \(W\) 表示)能表达的所有特征,都被锁定在这个矩阵的列空间之内。如果这个空间太“扁”(维度低),模型能学到的东西就很少。

在你的矩阵 \(A = \begin{bmatrix} 180 & 75 \\ 160 & 50 \\ 175 & 80 \end{bmatrix}\) 中:

  • 素材 :第一列(身高向量)和第二列(体重向量)。
  • Span :是你用这两列向量作为“基础方向”,通过不断改变权重(线性组合)所能到达的所有点的集合。
  • 列空间 :就是这个集合本身。它决定了你的模型 \(Ax\) 能输出什么样的结果。

特殊矩阵

逆矩阵

  • 单位矩阵 \(I_n\)* :所有沿主对角线的元素都是 *\(1\),其余位置都是 \(0\)(式 2.20)。它的作用是保持向量不变:
\[ \forall x \in \mathbb{R}^n, I_n x = x \]
  • 逆矩阵 \(A^{-1}\)* :通过矩阵逆,我们可以解析地求解 *\(Ax = b\)
  1. \(Ax = b\) 开始。
  2. 两边左乘 \(A^{-1}\)\(A^{-1}Ax = A^{-1}b\)
  3. 由于 \(A^{-1}A = I\),所以得到: \(x = A^{-1}b\)

这里要注意的是,逆矩阵虽然理论上可以求解,但是并不会在大多数软件或实际应用中被使用,这是因为计算机上只能表现出有限的精度。比如说,计算机无法存储\(\frac{1}{3}\),只能把无限的数字截断,比如变成 0.33333334。这个后果就是当你去计算一个几千行、几万行的巨大矩阵的逆时,这些微小的截断误差会不断 叠加、放大 。最后算出来的结果 \(x\) 可能会和正确答案差之毫厘,失之千里。

由于逆矩阵计算非常耗时,计算量非常大,因此我们并不在实际使用中使用。即便符号计算能够直接计算分数,其效率也非常低下,不如直接计算浮点数来得快。对于大多数现实任务(比如判断贷款、识别猫),精度达到小数点后 7 位或 15 位已经完全足够了。就像你量身高,精确到微米和精确到纳米,对买衣服没有任何区别。

事实上,在LLM开发中,人们更是在进行一场精度大倒退:从追求小数点后十几位,退步到只需要小数点后三四位,甚至更少。计算机存储浮点数(小数)有不同的“包装规格”,位数越少,占用的空间越小,算得越快:

  • FP32,单精度,占用32bit,小数点后7位,以前训练DNN的标准
  • FP16/BF16,占用16bit,小数点后3位,现在大语言模型如GPT-4就是用这个格式
  • INT8/INT4,占用8/4bit,小数点后0位(整数),目标是让手机也能跑模型

甚至有些研究认为,精度低一点反而像一种“噪音”,能防止模型死记硬背数据(过拟合),让它的泛化能力更强。神经网络由数以亿计的参数组成。某个参数的一点点截断误差,会被其他参数的调整所抵消。这就像一万个人合力拉一辆车,其中一个人稍微偏了 1 厘米,不影响车的方向。

Rank(秩)

在线性代数中,Rank一般指秩。矩阵有多少列,决定了列空间最高可能是多少维;但这个矩阵的是多少,才决定了列空间实际上是多少维。

现在很多大模型压缩技术(比如 LoRA ),本质上就是发现模型权重的矩阵虽然很大(阶很高),但其实很多列都是线性相关的,其其实很小。所以我们只需要训练一个“低秩”的小矩阵,就能达到调整大模型的目的。

在大模型(如 GPT-4)中,权重矩阵 \(W\) 可能是一个 \(10000 \times 10000\) 的庞然大物。科学家发现,尽管这个矩阵很大(阶很高),但它里面的列向量高度 线性相关 。这意味着它的秩(Rank) 其实很小。既然真正“干活”的独立维度不多,我们就不需要用 \(10000 \times 10000\) 个参数来存储它。我们把它拆解为两个长条形的小矩阵相乘:\(A \times B\)。矩阵 \(A\)\(10000 \times r\)。矩阵 \(B\)\(r \times 10000\)。这里的 \(r\) 就是我们设定的 (通常非常小,比如 \(r=8\)\(r=64\))。原本需要存储 \(10000 \times 10000 = 1 亿\) 个参数。现在只需要 \(10000 \times 8 + 8 \times 10000 = 16 万\) 个参数。计算机计算两个瘦长矩阵的乘法,比计算一个巨大的方阵快得多,这直接提升了推理速度。

在深度学习中,如果一个层的权重矩阵发生了“秩亏” (Rank Deficient),意味着:模型原本有 512 个神经元,但因为秩太低,只有 10 个神经元在干不同的活,其他的都在划水(线性相关)。你的“列空间”塌陷了,模型无法分辨复杂的输入差异。这就是为什么在大模型微调(如 LoRA )里,我们会主动选择一个 很小的秩 \(r\)**** :既然大矩阵内部本来就有很多重复(实际秩很小),那我就干脆只训练一个秩只有 8 或 16 的小矩阵。这个小矩阵虽然“阶”小,但它每一列都有“实际意义”,计算效率极高。

方阵

方阵 (Square Matrix) :必须满足 \(m = n\)(行数 = 列数),即输入维度与输出维度相等。

线性无关 :方阵的所有列向量必须彼此独立,不能存在冗余。

奇异矩阵 (Singular) :如果方阵的列向量线性相关(即“秩”不足),则称为奇异矩阵。奇异矩阵在变换过程中会丢弃信息(发生维度塌陷),导致无法通过逆矩阵 \(A^{-1}\) 找回原始输入。

对角矩阵

对称矩阵

其他概念

正交

Ian教材2.6,如果涉及到再看看

特征分解

Ian教材2.7,如果涉及到再看看

奇异值分解

Ian教材2.8,如果涉及到再看看

附:Excersize

Ex.1 线性代数练习

在上面我们已经知道线性代数在机器学习中的作用了。简单来说就是当我们有一个输入vector后,如果我们能找到一个合适的矩阵A,那么我们就能得到一个结果vector。

练习1:Prove that \(A^{T}A\) is symmetric for any \(A \in\mathbb{R}^{m \times n}\)

\(A^T\)的意思是矩阵的转置(Transpose),操作就是把一个矩阵的行和列互换,比如:

$$ A = \begin{bmatrix}

1 & 2 & 3 \

4 & 5 & 6

\end{bmatrix} $$

transpose后:

$$ A^T = \begin{bmatrix}

1 & 4 \

2 & 5 \

3 & 6

\end{bmatrix} $$

然后\(A \in \mathbb{R}^{m \times n}\)的意思是矩阵A的归属是实数(Real Numbers),然后行数x列数为\(m*n\)。组合起来就是说A是一个m行n列的矩阵,并且矩阵中的所有元素都是实数。

对于两个矩阵的乘法,计算过程就是用第一个矩阵的第一行,先和第二个矩阵的每一列相乘,得到新的矩阵的第一行;然后用第一个矩阵的第二行,再依次和第二个矩阵的每一列相乘,得到新的矩阵的第二行。也就是说新的矩阵的行数,等于第一个矩阵的行数;新的矩阵的列数,等于第二个矩阵的列数。因此矩阵的乘法是不可交换的,A x B,和B x A,是两个不同的计算过程。

我们拿上述的A和A^T来试算一下:

$$ A^T A =

\begin{bmatrix}

1 & 4 \

2 & 5 \

3 & 6

\end{bmatrix}

\begin{bmatrix}

1 & 2 & 3 \

4 & 5 & 6

\end{bmatrix} $$

计算过程:

$$ \begin{aligned}

(A^T A)_{11} &= 1\cdot1 + 4\cdot4 = 1 + 16 = 17 \

(A^T A)_{12} &= 1\cdot2 + 4\cdot5 = 2 + 20 = 22 \

(A^T A)_{13} &= 1\cdot3 + 4\cdot6 = 3 + 24 = 27 \

(A^T A)_{21} &= 2\cdot1 + 5\cdot4 = 2 + 20 = 22 \

(A^T A)_{22} &= 2\cdot2 + 5\cdot5 = 4 + 25 = 29 \

(A^T A)_{23} &= 2\cdot3 + 5\cdot6 = 6 + 30 = 36 \

(A^T A)_{31} &= 3\cdot1 + 6\cdot4 = 3 + 24 = 27 \

(A^T A)_{32} &= 3\cdot2 + 6\cdot5 = 6 + 30 = 36 \

(A^T A)_{33} &= 3\cdot3 + 6\cdot6 = 9 + 36 = 45

\end{aligned} $$

得到结果:

$$ A^T A =

\begin{bmatrix}

17 & 22 & 27 \

22 & 29 & 36 \

27 & 36 & 45

\end{bmatrix} $$

请注意观察

  • 元素(1,2) 和 元素(2,1) 都是 22。
  • 元素(1,3) 和 元素(3,1) 都是 27。
  • 元素(2,3) 和 元素(3,2) 都是 36。

这个矩阵沿着对角线是完美对称的,也就是题目中所问的symmetric。

我们现在反过来,算一下A * A^T:

$$ A A^T =

\begin{bmatrix}

1 & 2 & 3 \

4 & 5 & 6

\end{bmatrix}

\begin{bmatrix}

1 & 4 \

2 & 5 \

3 & 6

\end{bmatrix} $$

逐项计算:

$$ \begin{aligned}

(AA^T)_{11} &= 1\cdot1 + 2\cdot2 + 3\cdot3 = 1 + 4 + 9 = 14 \

(AA^T)_{12} &= 1\cdot4 + 2\cdot5 + 3\cdot6 = 4 + 10 + 18 = 32 \

(AA^T)_{21} &= 4\cdot1 + 5\cdot2 + 6\cdot3 = 4 + 10 + 18 = 32 \

(AA^T)_{22} &= 4\cdot4 + 5\cdot5 + 6\cdot6 = 16 + 25 + 36 = 77

\end{aligned} $$

最终结果:

$$ A A^T =

\begin{bmatrix}

14 & 32 \

32 & 77

\end{bmatrix} $$

这个结果也是对称的,但是结果却不同。

我们要关注两件事情:

1.结果是对称的

2.先后顺序在机器学习中的应用

首先,结果是对称的,说明两个矩阵的关系是相互的。即:

  • 矩阵 S 的元素 S[i, j] 代表了 “事物 i” 与 “事物 j” 的关系。
  • 矩阵 S 的元素 S[j, i] 代表了 “事物 j” 与 “事物 i” 的关系。

对称性 S[i, j] = S[j, i] 就意味着:

ij 的影响/关系,和 ji 的影响/关系是完全一样的。

也就是说:

  • 如果一个矩阵描述的是“城市间的飞行距离”,那它必然是对称的。纽约到波士顿的距离,等于波士顿到纽约的距离。
  • 如果一个矩阵描述的是“特征间的相关性”,那它必然是对称的。“身高”与“体重”的相关性,和“体重”与“身高”的相关性是同一个数值。

这个特性是我们用来衡量两个特征之间相关性的标准方法。

其次,假如A矩阵代表的是数据集矩阵,其每一行代表一个数据样本,比如一个病人、一栋房子、一朵花,那m行就代表我们有m个样本。然后A的每一列代表一个特征,比如房子的面积、卧室的数量,那么我们就有了n个 特征。

对于\(m*n\)的矩阵A,\(A^TA\)的含义是feature correclation matrix特征相关性矩阵,其结果是一个\(n*n\)的新矩阵,这个新矩阵衡量的是n个特征两两之间的关系。这种用法常在Linear Regression线性回归和PCA主成分分析中使用。简单来说,就是告诉我们数据集的特征之间是如何相互关联的,这是分析数据结构的基础。

而对于\(AA^T\),我们将得到一个\(m*m\)的新矩阵。这个新矩阵衡量的是样本两两之间的关系,因此视角是以样本为中心的。别忘了,我们刚才说过,m行代表的是m个样本。那么利用这种结果,我们可以找到两个样本之间特征是否相似。这个在SVMs支持向量机、Kernel Methods核方法、Clustering聚类分析中使用的比较多。

好,那现在我们理解了对称性和矩阵乘法在机器学习中的作用后,我们再来证明一下该命题。利用乘积的转置法则和转置的转置法则,我们可以得到:

\[ (A^T A)^T = A^T (A^T)^T = A^T A. \]

练习2:

考虑以下矩阵,请找出B的singular values(奇异值):

$$ B = \begin{bmatrix}

1 & 0 \

0 & 2 \

2 & 1

\end{bmatrix} $$

singular values是线性代数中极其重要的概念,这个值能快速提取出一个矩阵的重要核心信息。比如说,你喝了一杯很好喝的鸡尾酒,假设这个鸡尾酒就是上面这个B,那么你一定想要知道这个鸡尾酒的配方是什么。比如这个鸡尾酒有如下风味:

  • 风味A:香甜
  • 风味B:酸涩
  • 风味C:清凉

然后你给这些风味打分:

  • 香甜:10分
  • 酸涩:7分
  • 清凉:1分

这几个分数,就是奇异值!其中香甜是这杯鸡尾酒最大的特征,其次是酸涩和清凉。换句话说,奇异值就是一个复杂事务(如一个矩阵、一张图片、一杯鸡尾酒)中各个核心组成部分的重要性排名。

以上面的矩阵B为例,他的奇异值如下:

  • \(\sigma_{1} = \sqrt{7}\)
  • \(\sigma_{2} = \sqrt{3}\)

这两个抽象的sigma,揭示了B矩阵这个变换的核心本质。其意义包括:

  • 几何上的意义:B将二维空间 的单位圆变换成三维空间的椭圆的时候的最大和最小的 拉伸比例
  • 信息的重要性和降维:如果B是一个数据集,那么第一个奇异值将代表数据的主要变化和信息
  • 用途:按\(\sigma_1\)进行数据压缩,可以保留B矩阵最核心的特征

具体的用途在之后遇到时我们再详细讲解。

奇异值计算步骤通常是:

  1. 计算 B 的转置矩阵 BT。
  2. 计算 BT 与 B 的乘积,得到一个新的方阵 (BTB)。
  3. 计算矩阵 BTB 的特征值 (eigenvalues)。
  4. 将这些特征值取正平方根,得到的结果就是矩阵 B 的奇异值。

那么对于矩阵B,其转置矩阵与B的乘积:

$$ B^T B =

\begin{bmatrix}

1 & 0 & 2 \

0 & 2 & 1

\end{bmatrix}

\begin{bmatrix}

1 & 0 \

0 & 2 \

2 & 1

\end{bmatrix} $$

计算得到:

$$ \begin{bmatrix}

1\cdot1 + 0\cdot0 + 2\cdot2 & 1\cdot0 + 0\cdot2 + 2\cdot1 \

0\cdot1 + 2\cdot0 + 1\cdot2 & 0\cdot0 + 2\cdot2 + 1\cdot1

\end{bmatrix}

=

\begin{bmatrix}

5 & 2 \

2 & 5

\end{bmatrix} $$

用这个结果代入矩阵的characteristic polynomial特征多项式

\[ p(\lambda) = \det(A - \lambda I) \]

这里的p是polynomial多项式的首字母缩写,一般代表多项式。lambda是eigenvalue特征值,在这里作为一个变量存在。

这里的det是Determinant的缩写,中文是行列式。行列式是作用于一个行数和列数相等的矩阵的函数,他会计算出一个标量。这个标量浓缩了关于这个矩阵变换的很多重要信息。正因如此,我们才在一开始需要通过计算B转置和B的乘积,来得到一个方阵。

对于一个2x2的矩阵,det就是主对角线(从左上角到右下角)上元素的乘积,减去副对角线上元素的乘积。3x3和更大的矩阵,则需要更多不同的技巧,这里就不赘述了。我们只要记住,我们可以用det操作得到一个方阵的特征多项式并找到这个方阵的奇异值就可以了。具体的计算我们可以依赖NumPy库来完成:


import numpy as np

M = np.array([

    [4, 2, 1, 0],

    [1, 3, 2, 1],

    [0, 1, 5, 2],

    [2, 3, 1, 1]

])


# 3. 调用 np.linalg.det() 函数计算行列式

# 无论矩阵是2x2, 4x4, 还是100x100,调用的函数都是同一个

determinant_value = np.linalg.det(M)


# 4. 打印出原始矩阵和计算结果

print("创建的4x4矩阵 M:")

print(M)

print("\n计算出的行列式 det(M):")

print(determinant_value)

其中\(I\)是单位矩阵,我们现在可以得到这个特征多项式了:

$$ \det !\left(

\begin{bmatrix}

5 & 2 \

2 & 5

\end{bmatrix}

  • \lambda

\begin{bmatrix}

1 & 0 \

0 & 1

\end{bmatrix}

\right)

=

\det !\begin{bmatrix}

5 - \lambda & 2 \

2 & 5 - \lambda

\end{bmatrix} $$

\[ = (5 - \lambda)(5 - \lambda) - (2)(2) \]
\[ = (5 - \lambda)^2 - 4 \]
\[ = \lambda^2 - 10\lambda + 21 \]

得到该特征多项式后,我们可以把让该多项式等于0,即可得到特征多项式的特征值:

\[ \lambda^2 - 10\lambda + 21 = 0 \]
\[ (\lambda - 7)(\lambda - 3) = 0 \]
\[ \lambda_1 = 7, \quad \lambda_2 = 3 \]

得到两个特征值后,我们就可以得到奇异值了。奇异值是两个特征值的平方根(严格来说,奇异值是\(A^TA\)的特征值开方,而对于对称正定矩阵,\(A^TA=A^2\),所以奇异值就是特征值的正平方根),因此:

$$ \sigma_1 = \sqrt{\lambda_1} = \sqrt{7},

\quad

\sigma_2 = \sqrt{\lambda_2} = \sqrt{3} $$


Ex.2 链式法则练习

练习1: Consider the function

\[ f(x,y) = \sigma(ax + by), \]

where

$$ a, b \in\mathbb{R},

\quad

\sigma(t) = \frac{1}{1 + e^{-t}} \quad for

\quad t \in\mathbb{R}. $$

首先我们来看一下这个函数f(x, y) = σ(ax + by),这是一个接收x和y两个变量作为输入的函数。他的计算过程是两步:

  1. 先计算 ax + by。这在机器学习里叫做输入的 线性组合ab可以看作是权重)。
  2. 然后将这个结果作为输入,传递给另一个函数 σσ 在这里被称为 激活函数 (Activation Function)

然后再看一下 σ(t),这个函数有一个非常著名的名字,叫 Sigmoid 函数 ,也叫 Logistic 函数。它的作用是把任何一个实数 t(无论多大或多小)都压缩到 (0, 1) 这个区间内。因为这个特性,它经常在机器学习中被用来表示概率。

所以,整个函数 f(x,y) 的意思就是:接收输入 xy,用权重 ab 进行加权求和,然后用 Sigmoid 函数处理这个和,得到一个 0到1 之间的最终输出。

(a) Show that

\[ \frac{d\sigma}{dt} = \sigma(t)\big(1 - \sigma(t)\big) \]

解答:

$$ \frac{d}{dt}\sigma(t)

= \frac{d}{dt}\left(\frac{1}{1+e^{-t}}\right) $$

\[ = \frac{e^{-t}}{(1+e^{-t})^2} \]
\[ = \left(\frac{1}{1+e^{-t}}\right)\left(\frac{1+e^{-t}}{1+e^{-t}} - \frac{1}{1+e^{-t}}\right) \]
\[ = \sigma(t)\big(1-\sigma(t)\big) \]

这个结论在机器学习中非常有名且非常常用,因为它让求导(也就是求梯度)变得非常方便。

(b) Using the result you showed in part(a) and the chain rule, compute \(\frac{\partial f}{\partial x}\) and \(\frac{\partial f}{\partial y}\).

我们来计算函数 \(f(x, y) = \sigma(ax + by)\)\(x\)\(y\) 的偏导数。

首先计算 \(\frac{\partial f}{\partial x}\)。这是一个复合函数,为了应用链式法则,我们视内层的线性部分 \(ax + by\) 为一个整体,并记作 \(z\)。这样函数就变成了 \(f = \sigma(z)\)

根据链式法则,\(f\)\(x\) 的导数等于外层函数对 \(z\) 的导数与内层函数对 \(x\) 的导数的乘积:

$$ \frac{\partial f}{\partial x}

= \frac{d\sigma}{dz} \cdot\frac{\partial z}{\partial x} $$

我们知道第一问的结论是 \(\frac{d\sigma}{dz} = \sigma(z)\big(1 - \sigma(z)\big)\),同时,内层函数对 \(x\) 的偏导数是 \(\frac{\partial z}{\partial x} = a\)

将这两部分相乘,我们得到:

$$ \frac{\partial f}{\partial x}

= \sigma(z)\big(1 - \sigma(z)\big) \cdot a $$

最后,我们将 \(z = ax + by\) 代回,并整理成您提供的最终格式:

$$ \frac{\partial f}{\partial x}

= \boxed{a \, \sigma(ax + by)\big[1 - \sigma(ax + by)\big]} $$

计算对 \(y\) 的偏导数 \(\frac{\partial f}{\partial y}\) 的过程完全同理。链式法则的应用如下:

$$ \frac{\partial f}{\partial y}

= \frac{d\sigma}{dz} \cdot\frac{\partial z}{\partial y} $$

其中,外层函数的导数部分不变,我们只需计算内层函数对 \(y\) 的偏导数,即 \(\frac{\partial z}{\partial y} = b\)

将它们相乘得到:

$$ \frac{\partial f}{\partial y}

= \sigma(z)\big(1 - \sigma(z)\big) \cdot b $$

同样地,将 \(z = ax + by\) 代回,我们得到关于 \(y\) 的最终偏导数:

$$ \frac{\partial f}{\partial y}

= \boxed{b \, \sigma(ax + by)\big[1 - \sigma(ax + by)\big]} $$


练习2:

For

$$ \mathbf{x} =

\begin{bmatrix}

x_{1} \

\vdots \

x_{n}

\end{bmatrix}

\in\mathbb{R}^n $$

define

\[ r(\mathbf{x}) = \sum_{j=1}^{n} x_j^2 \]

Compute the partial derivative \(\frac{\partial r}{\partial x_i}\) for a generic coordinate \(i \in \{1, \ldots, n\}\)

解答:

这道题定义了一个向量x,该向量由n个分量组成。然后定义了一个函数r(x),其计算方式是将向量x的每一个分量都进行平方,然后将所有结果相加。数学表达式为:

$$ r(\mathbf{x}) = \sum_{j=1}^{n} x_j^2

= x_1^2 + x_2^2 + \cdots + x_n^2 $$

这个函数实际上计算的是向量 x 的欧几里得范数(即向量长度)的平方。

而题目要求我们来计算函数r相对于其任意一个分量\(x_i\)的偏导数(partial derivative)。

在计算偏导数\(\frac{\partial r}{\partial x_i}\)的时候,我们要将除了\(x_i\)之外的其他所有分量都当作常数来处理,因此对于上述展开的r(x),很显然,如果除了\(x_i\)之外的其他分量都被视为常数,那么这些常数在求导的过程中会变为0,也即:

$$ \frac{\partial}{\partial x_i}(x_j^2) = 0

\quad (\text{对于所有 } j \ne i) $$

那么根据幂函数的求导法则($\frac{d}{dx} x^k = k x^{k-1} $),我们可以得到

\[ \frac{\partial}{\partial x_i}(x_i^2) = 2x_i \]

由于其他项都是0,因此:

\[ \frac{\partial r}{\partial x_i} = 2x_i \]

练习3:

Let $\mathbf{w} \in\mathbb{R}^n $ be a constant vector and define the scalar function

$$ s(\mathbf{x}) = \mathbf{w}^\top\mathbf{x}

= \sum_{j=1}^{n} w_j x_j $$

Compute \(\frac{\partial s}{\partial x_i}\) for a generic coordinate \(i \in \{1, \ldots, n\}\)

解答:

这道题的意思就是给你一个固定的 n 维向量 w 和一个变量 n 维向量 x 。用这两个向量的点积定义了一个函数 s(x)。现在请你求出这个函数 s 相对于变量向量 x 的第 i 个分量 xi 的偏导数。

比如假设 n=3,那么:

*\(w=w1,w2,w3\)(三个固定的数)

  • \(x=x1,x2,x3\) (三个变量)
  • \(s(\mathbf{x}) = w_1 x_1 + w_2 x_2 + w_3 x_3\)

我们要求的就是用一个通用的表达式来代表\(\frac{\partial s}{\partial x_i}\)

那么对于这种题,其实我们把函数s(x)展开来写就很清晰了:

\[ s(\mathbf{x}) = \sum_{j=1}^{n} w_j x_j = w_1 x_1 + w_2 x_2 + \cdots + w_i x_i + \cdots + w_n x_n \]

现在对上面展开的式子求导:

\[ \frac{\partial s}{\partial x_i} = \frac{\partial}{\partial x_i} \left( w_1 x_1 + w_2 x_2 + \cdots + w_i x_i + \cdots + w_n x_n \right) \]

利用导数的加法法则,我们可以对每一项分别求导:

$$ \frac{\partial s}{\partial x_i}

= \frac{\partial}{\partial x_i}(w_1 x_1)

  • \frac{\partial}{\partial x_i}(w_2 x_2)
  • \cdots
  • \frac{\partial}{\partial x_i}(w_i x_i)
  • \cdots
  • \frac{\partial}{\partial x_i}(w_n x_n) $$

和练习2类似,当我们对wi求导的时候,非wi的项目在求导中都被视为常数,因此求导后是0.

而对于wi的目标项,可以得到:

$$ \frac{\partial}{\partial x_i}(w_i x_i)

= w_i \cdot\frac{\partial}{\partial x_i}(x_i)

= w_i \cdot1

= w_i $$

所以:

\[ \frac{\partial s}{\partial x_i} = 0 + 0 + \cdots + w_i + \cdots + 0 = w_i \]

Ex.3 概率论练习

An incoming email is spam with prior \(p(S)=0.2\) and not spam with \(p(\bar{S}) = 0.8\).

Two independent filters flag spam:

\[ p(F_{1} = 1\mid S) = 0.9, \quad p(F_{1} = 1\mid\bar{S}) = 0.1, \]
\[ p(F_{2} = 1\mid S) = 0.8, \quad p(F_{2} = 1\mid\bar{S}) = 0.05, \]

annd \(F_1, F_2\) are inndependent given the class \((S or \bar{S})\).

(a) What is the probability that both filters flag an email as spam?

首先,我们把题目给出的所有信息翻译成通俗的语言:

p(S) = 0.2: "S" 代表 "Spam" (垃圾邮件)。这句话的意思是,在没有任何其他信息的情况下,一封随机收到的邮件是 垃圾邮件的概率为20% 。这是 先验概率* 。

p(S̄) = 0.8: "S̄" 代表 "Not Spam" (非垃圾邮件)。一封邮件 不是垃圾邮件的概率为80%* 。同样是先验概率。

接下来是关于两个垃圾邮件过滤器(Filter 1 和 Filter 2)的信息:

p(F₁=1 | S) = 0.9: F₁=1 表示“过滤器1将邮件标记为垃圾邮件”。这句话的意思是:如果一封邮件确实是*垃圾邮件,那么过滤器1有90%的概率能正确地把它标记出来(这是过滤器1的“召回率”或“真阳性率”)。

p(F₁=1 | S̄) = 0.1: 如果一封邮件不是*垃圾邮件,过滤器1仍然有10%的概率会错误地把它标记为垃圾邮件(这是过滤器1的“假阳性率”)。

p(F₂=1 | S) = 0.8: 如果一封邮件确实是*垃圾邮件,过滤器2有80%的概率能正确标记它。

p(F₂=1 | S̄) = 0.05: 如果一封邮件不是*垃圾邮件,过滤器2有5%的概率会错误标记它。

最后一句关键信息:

F₁, F₂ are independent given the class (S or S̄): 这叫做 条件独立 。意思是:一旦我们确定了一封邮件的真实类别(是垃圾邮件,或不是),那么两个过滤器的判断就 互不影响* 。

  • 例如,对于一封已知的垃圾邮件,过滤器1是否标记它,和过滤器2是否标记它,是两个可以相乘的独立概率事件。

这一小问问的是:“ 两个过滤器同时把一封邮件标记为垃圾邮件的总概率是多少?

这里的关键点在于,这个问题并没有告诉你这封邮件 本身到底是不是垃圾邮件 。所以,要计算这个总概率,你必须考虑两种可能发生并导致这个结果的 互斥场景

场景一* :这封邮件 确实是垃圾邮件(S)** ,并且两个过滤器都正确地标记了它。

场景二* :这封邮件 其实不是垃圾邮件(S̄)** ,但两个过滤器都犯了错误,同时标记了它。

这道题最终想让你计算的,就是 场景一发生的概率 + 场景二发生的概率 。这背后运用的原理就是我们之前提过的 全概率公式

我们可以分别计算两个场景的概率,然后得到答案:

场景一:

邮件是垃圾邮件(S),并且两个filter都标记了它。我们计算这个特定场景发生的联合概率: \(P(A \cap S)\),根据条件概率的定义,我们知道:

\[ P(A \cap S) = P(A|S) \times P(S) \]

由于\(P(S)\)是已知的先验概率,为0.2。\(P(A \mid S)\)指的是“在一封确认为垃圾邮件的邮件中,两个filter都标记它的概率”。因为题目已经说明两个filter条件独立,所以我们可以将他们相乘:

\[ P(A|S) = P(F_{1} = 1 | S) \times P(F_{2} = 1 | S) \]

代入数值得到:

\[ P(A|S) = 0.9\times0.8 = 0.72 \]

场景一的总概率便得到了:

\[ P(A \cap S) = 0.72\times0.2 = 0.144 \]

同理,场景二的总概率\(P(A \cap \bar{S})\)也可以用同样的方法得到:

\[ P(A \cap\bar{S}) = P(A|\bar{S}) \times P(\bar{S}) \]
\[ P(A|\bar{S}) = P(F_{1} = 1 | \bar{S}) \times P(F_{2} = 1 | \bar{S}) \]
\[ P(A|\bar{S}) = 0.1\times0.05 = 0.005 \]
\[ P(A \cap\bar{S}) = 0.005\times0.8 = 0.004 \]

把两个互斥场景的概率相加,即得到总概率:

\[ P(A) = P(A \cap S) + P(A \cap\bar{S}) \]
\[ P(A) = 0.144 + 0.004 = 0.148 \]

(b) Given that both filters flag an email, what is the probability of the email being spam? (You can leave your answer as an unsimplified fraction.)

在上一问,我们算出了被两个filter同时标记为垃圾邮件的概率。而这一问问的则是,对于那些已经被两个filter同时标记的邮件,其为真垃圾邮件的比例是多少。这是一个后验概率。

回忆一下贝叶斯公式:

\[ P(Y \mid X) = \frac{P(X \mid Y) P(Y)}{P(X)} \]

在这道题中:

  • Y = 邮件真的是垃圾邮件(S)
  • X = 邮件被两个filters同时标记(我们之前称之为事件A)

所以代入到贝叶斯公式中,可以得到 :

\[ P(S \mid A) = \frac{P(A \mid S) P(S)}{P(A)} = \frac{P(A \cap S)}{P(A)} \]

翻译一下就是:

P(邮件是垃圾 | 被两个滤镜标记) = P(邮件是垃圾 并且 被两个滤镜标记) / P(被两个滤镜标记)

在第一问中,我们已经知道:

  • \(P(A) = 0.148\)
  • \(P(A \cap S)=0.144\)

代入可得:

\[ P(S \mid A) = \frac{0.144}{0.148} \approx0.973. \]

.

\[ \|\boldsymbol{A}\|_F = \sqrt{\sum_{i=1}^m \sum_{j=1}^n a_{ij}^2} \]

评论 #