线性变换


文档摘要

线性变换 每一次矩阵乘法都是一次线性变换——一种在保持线性关系的同时重塑、旋转或投影向量的函数。本文件讲解旋转、反射、缩放、剪切、投影、映射的核与像,以及神经网络层如何把这些变换串联起来。 线性变换(linear transformation)(或线性映射)是一个把向量变成另一个向量的函数,同时保持加法和数乘。如果 $T$ 是线性的,那么: $T(\mathbf{u} + \mathbf{v}) = T(\mathbf{u}) + T(\mathbf{v})$ $T(c\mathbf{u}) = cT(\mathbf{u})$ 每个线性变换都可以表示成乘以一个矩阵。矩阵就是这个变换。当你把一个向量乘以一个矩阵时,你就是在对它施加一个线性变换。

线性变换

每一次矩阵乘法都是一次线性变换——一种在保持线性关系的同时重塑、旋转或投影向量的函数。本文件讲解旋转、反射、缩放、剪切、投影、映射的核与像,以及神经网络层如何把这些变换串联起来。

  • 线性变换(linear transformation)(或线性映射)是一个把向量变成另一个向量的函数,同时保持加法和数乘。如果 T 是线性的,那么:

    • T(\mathbf{u} + \mathbf{v}) = T(\mathbf{u}) + T(\mathbf{v})
    • T(c\mathbf{u}) = cT(\mathbf{u})
  • 每个线性变换都可以表示成乘以一个矩阵。矩阵就是这个变换。当你把一个向量乘以一个矩阵时,你就是在对它施加一个线性变换。

  • 2 \times 2 矩阵想象成一台机器:吃进二维向量,吐出新的二维向量。矩阵的各列告诉你标准基向量 \hat{\mathbf{i}}\hat{\mathbf{j}} 在变换后落在哪里。其他一切都由线性推导出来。

矩阵的各列显示基向量落在何处

  • 例如,如果
A = \begin{bmatrix} 2 & 1 \\ 1 & 2 \end{bmatrix}

那么 \hat{\mathbf{i}} = [1, 0]^T 落到 [2, 1]^T(第 1 列),\hat{\mathbf{j}} = [0, 1]^T 落到 [1, 2]^T(第 2 列)。其他任何向量都是这两个的组合,所以它的输出自然随之确定。

  • 两个矩阵相乘可以看作依次施加两个变换。如果 B 把向量从一个空间变换,而 A 再变换其结果,那么 AB 就是按顺序做完这两件事。在游戏引擎里,先旋转角色再向前移动,与先移动再旋转,结果完全不同——这就是为什么矩阵乘法不满足交换律。

  • **旋转(rotation)**把向量转过角度 \theta 而不改变它的长度。向量大小不变,只是指向新的方向。

旋转保持长度不变,但改变方向

  • 在二维中,旋转矩阵是:
R(\theta) = \begin{bmatrix} \cos\theta & -\sin\theta \\ \sin\theta & \cos\theta \end{bmatrix}
  • \theta = 90° 时:
R = \begin{bmatrix} 0 & -1 \\ 1 & 0 \end{bmatrix}

于是 [1, 0]^T 变成 [0, 1]^T。原本指向右的向量现在指向上。旋转矩阵是正交的,行列式永远是 1。当你在手机上旋转一张照片时,施加到每个像素坐标上的正是这个矩阵。

  • 在三维中,每个轴都有各自的旋转矩阵。机械臂的每个关节都绕着特定的轴旋转,每个关节对应一个旋转矩阵。绕 z 轴的旋转看起来就像是把二维情形嵌入到三维中:
R_z(\theta) = \begin{bmatrix} \cos\theta & -\sin\theta & 0 \\ \sin\theta & \cos\theta & 0 \\ 0 & 0 & 1 \end{bmatrix}
  • **缩放(scaling)**沿每个轴独立地拉伸或压缩向量:
S(s_x, s_y) = \begin{bmatrix} s_x & 0 \\ 0 & s_y \end{bmatrix}

缩放沿每个轴以不同因子拉伸

  • S(2, 1.5) 把 x 分量翻倍、把 y 分量乘以 1.5。沿某个轴缩放 -1 就翻转那个分量。对角矩阵永远是一种缩放变换。当你把一张图片缩小到 50% 时,你就是在对每个像素坐标施加 S(0.5, 0.5)

  • **反射(reflection)**把向量沿一条轴或直线翻转,就像照镜子。沿 x 轴反射时,x 分量保持不变,y 分量取反:

\text{Ref}_x = \begin{bmatrix} 1 & 0 \\ 0 & -1 \end{bmatrix}

沿 x 轴反射翻转 y 分量

  • 例如,[3, 2]^T 变成 [3, -2]^T。当你的手机水平翻转一张自拍好让文字变正时,它施加的就是一个反射矩阵。沿直线 y = x 反射会交换两个分量:
\text{Ref}_{y=x} = \begin{bmatrix} 0 & 1 \\ 1 & 0 \end{bmatrix}
  • 反射矩阵的行列式为 -1,证实它们会翻转朝向。

  • 旋转和反射都是刚体变换(rigid transformations):它们保持距离和角度不变。代表它们的矩阵是正交矩阵,所以正交矩阵的行列式总是 +1(旋转)或 -1(反射)。

  • **剪切(shearing)**让向量沿一个轴按与其另一个分量的比例错位。系数为 k 的水平剪切:

\text{Sh}_x(k) = \begin{bmatrix} 1 & k \\ 0 & 1 \end{bmatrix}

剪切把顶部横向滑动,底部保持不动

  • 每个点横向滑动它高度的 k 倍。当 k = 0.5 时,高度为 2 的点向右移动 1。底行不动,顶行滑动。斜体文字就是这样做的:把正立的字母剪切一下,让它们向右倾斜。

  • 上面这些(旋转、缩放、反射、剪切)都是线性变换。它们保持原点不动、保持直线。那平移(translation)(把一切都移动一个固定量)呢?

  • 平移不是线性变换,因为它会移动原点。如果你把每个点向右移 3,零向量就跑到了 [3, 0]^T,破坏了线性性。为了处理它,我们使用仿射变换(affine transformation),它把一个线性变换和一个平移结合起来:

\mathbf{y} = A\mathbf{x} + \mathbf{t}
  • 要把它表示成一次矩阵乘法,我们使用齐次坐标(homogeneous coordinates):给每个向量追加一个 1,并使用一个 (n+1) \times (n+1) 的矩阵:
\begin{bmatrix} A & \mathbf{t} \\ \mathbf{0}^T & 1 \end{bmatrix} \begin{bmatrix} \mathbf{x} \\ 1 \end{bmatrix} = \begin{bmatrix} A\mathbf{x} + \mathbf{t} \\ 1 \end{bmatrix}
  • 仿射变换保持直线和平行性,但不一定保持角度或长度。电子游戏里每个物体的位置都是用仿射变换摆放的:旋转它、缩放它、然后放到正确位置——全部编码在一个矩阵里。

  • 退化变换(degenerate transformation)(奇异矩阵)会把空间压扁到更低维度。

  • 例如,矩阵

\begin{bmatrix} 1 & 2 \\ 2 & 4 \end{bmatrix}

把每个二维向量都映射到一条直线上,因为它的两列指向同一个方向。行列式为零,信息丢失,变换无法逆转。

  • 把彩色图片(每个像素 3 个值:红、绿、蓝)转成灰度图(每个像素 1 个值)就是一个退化变换:颜色信息永久消失了。

  • 在 ML 中,线性变换是神经网络的核心,数据被表示成一个矩阵(一摞向量,代表人、飞机、文本、图像等任何东西的特征)。

  • 每一层都施加一次矩阵乘法(线性变换),细节在其他章节中讲解。我们需要解释如何组织这些数据,并恰当地引出神经网络。

  • 不过,今天最常用的技术往往几乎只把数据穿过一连串线性变换——我们把它们称为 Transformer

  • Gemini、ChatGPT、Claude、Qwen、DeepSeek,以及当今世界上表现最好的 AI,都是 Transformer!

编程练习(使用 CoLab 或 notebook)

  1. 把一个旋转矩阵作用到一个向量上,并画出原始向量和旋转后的向量。试试不同的角度。
import jax.numpy as jnp import matplotlib.pyplot as plt theta = jnp.pi / 3 R = jnp.array([[jnp.cos(theta), -jnp.sin(theta)], [jnp.sin(theta), jnp.cos(theta)]]) v = jnp.array([1.0, 0.0]) v_rot = R @ v plt.figure(figsize=(5, 5)) plt.quiver(0, 0, v[0], v[1], angles='xy', scale_units='xy', scale=1, color='red', label='original') plt.quiver(0, 0, v_rot[0], v_rot[1], angles='xy', scale_units='xy', scale=1, color='blue', label='rotated') plt.xlim(-1.5, 1.5); plt.ylim(-1.5, 1.5) plt.grid(True); plt.legend(); plt.gca().set_aspect('equal') plt.show()
  1. 对构成正方形的一组点施加剪切变换,并把变形后的形状可视化。
import jax.numpy as jnp import matplotlib.pyplot as plt square = jnp.array([[0,0],[1,0],[1,1],[0,1],[0,0]]).T k = 0.5 shear = jnp.array([[1, k], [0, 1]]) sheared = shear @ square plt.figure(figsize=(6, 4)) plt.plot(square[0], square[1], 'r-o', label='original') plt.plot(sheared[0], sheared[1], 'b-o', label='sheared') plt.grid(True); plt.legend(); plt.gca().set_aspect('equal') plt.show()

发布者: 作者: HenryNdubuaku 转发
评论区 (0)
U