侧边栏壁纸
博主头像
川科智源

行动起来,活在当下

  • 累计撰写 4 篇文章
  • 累计创建 1 个标签
  • 累计收到 1 条评论

目 录CONTENT

文章目录

线性代数速成:向量和矩阵为什么重要?

系列一 · 数学筑基 · 第3篇 | 预计阅读时间:20分钟 | 前置知识:高中数学


上篇回顾

上一篇我们手写了一个完整的梯度下降训练过程,从零训练了一个线性回归模型。

但你有没有注意到一个问题?

# 上一篇的更新方式
model.w = model.w - lr * dw
model.b = model.b - lr * db

两个参数,写两行。

如果有100个参数呢?写100行?

如果有GPT-4的1750亿个参数呢?

显然不行。我们需要一种方式,把成千上万个参数的计算"打包"成一次操作。

这就是线性代数要做的事。

今天这篇文章不会把线性代数教材翻一遍。我们只讲AI里真正用到的那几个概念:向量、矩阵乘法、线性变换。讲完你会明白两件事:

  1. 神经网络的每一层,本质上就是一次矩阵乘法
  2. GPU之所以能加速AI训练,是因为它特别擅长矩阵乘法

一、向量:把一堆数字打包

1.1 什么是向量?

最朴素的理解:向量就是一组有序的数字

\mathbf{x} = [3, 5, 2, 7]

这是一个4维向量,有4个分量。

在AI里,几乎所有东西都会被表示成向量:

数据 向量表示 维度
一个词("猫") [0.23, -0.15, 0.82, ...] 768维
一张图片(28x28像素) [p_1, p_2, ..., p_{784}] 784维
一条用户画像 [\text{年龄}, \text{收入}, \text{消费}, ...] 几十维
一个模型的全部参数 [w_1, w_2, ..., w_n] 几亿到几千亿维

为什么要用向量? 因为向量可以做数学运算——加减乘除、求距离、求相似度。而"一堆零散的数字"做不了这些。

1.2 向量的基本运算

加法:对应位置相加。

[1, 2, 3] + [4, 5, 6] = [5, 7, 9]

数乘:每个分量乘以一个数。

3 \times [1, 2, 3] = [3, 6, 9]

点积(内积):对应位置相乘,再求和。

[1, 2, 3] \cdot [4, 5, 6] = 1 \times 4 + 2 \times 5 + 3 \times 6 = 32

点积在AI里无处不在。上一篇的线性回归 \hat{y} = w_1 x_1 + w_2 x_2 + ... + w_n x_n,就是权重向量和输入向量的点积:

\hat{y} = \mathbf{w} \cdot \mathbf{x}

一行公式替代了 n 行代码。

1.3 向量的几何意义

在二维空间里,向量 [3, 4] 可以画成一条从原点出发的箭头:

y
↑
4 |         ↗ (3,4)
3 |       ↗
2 |     ↗
1 |   ↗
0 └──────────→ x
  0  1  2  3

向量的模(长度)

|\mathbf{v}| = \sqrt{3^2 + 4^2} = \sqrt{25} = 5

两个向量的夹角(余弦相似度)

\cos\theta = \frac{\mathbf{a} \cdot \mathbf{b}}{|\mathbf{a}||\mathbf{b}|}
  • \cos\theta = 1:方向完全相同
  • \cos\theta = 0:互相垂直,无关
  • \cos\theta = -1:方向完全相反

这就是AI里"相似度"的数学基础。两个词的词向量夹角越小,语义越相似。这个概念会在后面讲词嵌入(Word2Vec)和Attention机制的时候反复用到。


二、矩阵:一次搞定所有计算

2.1 什么是矩阵?

矩阵就是数字排成的长方形阵列

A = \begin{bmatrix} 1 & 2 & 3 \\ 4 & 5 & 6 \end{bmatrix}

这是一个 2 \times 3 的矩阵(2行3列)。

你可以把矩阵理解为"一组向量的集合":

  • 按行看:两个3维行向量
  • 按列看:三个2维列向量

2.2 矩阵乘法

矩阵乘法是线性代数里最重要的运算,也是AI计算的核心。

规则:A 的每一行和 B 的每一列做点积。

\begin{bmatrix} 1 & 2 \\ 3 & 4 \end{bmatrix} \times \begin{bmatrix} 5 & 6 \\ 7 & 8 \end{bmatrix} = \begin{bmatrix} 1 \times 5 + 2 \times 7 & 1 \times 6 + 2 \times 8 \\ 3 \times 5 + 4 \times 7 & 3 \times 6 + 4 \times 8 \end{bmatrix} = \begin{bmatrix} 19 & 22 \\ 43 & 50 \end{bmatrix}

尺寸规则(m \times n) \times (n \times p) = (m \times p)

左矩阵的列数必须等于右矩阵的行数。结果矩阵的行数 = 左矩阵行数,列数 = 右矩阵列数。

2.3 矩阵乘法为什么重要?

回到上一篇的线性回归。假设我们有100条数据,每条3个特征:

不用矩阵(上一篇的写法):
for i in range(100):
    y[i] = w1*x[i][0] + w2*x[i][1] + w3*x[i][2] + b

循环100次,每次3个乘法 → 300次运算,串行执行
用矩阵:
Y = X @ W + b

一次矩阵乘法 → 300次运算,并行执行

结果完全一样,但矩阵版本可以在GPU上并行计算

展开来看:

\underbrace{\begin{bmatrix} x_{1,1} & x_{1,2} & x_{1,3} \\ x_{2,1} & x_{2,2} & x_{2,3} \\ \vdots & \vdots & \vdots \\ x_{100,1} & x_{100,2} & x_{100,3} \end{bmatrix}}_{X: \; 100 \times 3} \times \underbrace{\begin{bmatrix} w_1 \\ w_2 \\ w_3 \end{bmatrix}}_{W: \; 3 \times 1} + \underbrace{\begin{bmatrix} b \\ b \\ \vdots \\ b \end{bmatrix}}_{b: \; 100 \times 1} = \underbrace{\begin{bmatrix} \hat{y}_1 \\ \hat{y}_2 \\ \vdots \\ \hat{y}_{100} \end{bmatrix}}_{\hat{Y}: \; 100 \times 1}

100条数据的预测,一次矩阵乘法搞定


三、线性变换:矩阵的几何意义

3.1 矩阵是一种"空间变换"

矩阵乘法不只是"一堆数字相乘",它有深刻的几何含义:矩阵是对空间的一种变换

用一个 2 \times 2 的矩阵乘以一个二维向量,相当于把这个向量"变换"到了新的位置。

举例:

\begin{bmatrix} 2 & 0 \\ 0 & 1 \end{bmatrix} \begin{bmatrix} 1 \\ 1 \end{bmatrix} = \begin{bmatrix} 2 \\ 1 \end{bmatrix}

这个矩阵把向量的 x 分量放大了2倍,y 分量不变——这是一个拉伸变换

更多例子:

矩阵 几何效果
\begin{bmatrix} 2 & 0 \\ 0 & 2 \end{bmatrix} 等比放大2倍
\begin{bmatrix} \cos\theta & -\sin\theta \\ \sin\theta & \cos\theta \end{bmatrix} 旋转 \theta
\begin{bmatrix} 1 & 0 \\ 0 & -1 \end{bmatrix} 沿x轴翻转
\begin{bmatrix} 1 & k \\ 0 & 1 \end{bmatrix} 水平剪切

3.2 这和AI有什么关系?

神经网络的每一层,就是一次线性变换 + 一次非线性变换

线性变换部分:\mathbf{z} = W\mathbf{x} + \mathbf{b}

把输入向量 \mathbf{x} 通过矩阵 W 变换到新的空间。相当于旋转、拉伸、投影。

非线性变换部分:\mathbf{a} = \sigma(\mathbf{z})

通过激活函数(如ReLU)引入"弯曲",让网络能拟合非线性关系。

为什么需要非线性? 因为多个线性变换的叠加还是线性变换:

W_2(W_1 \mathbf{x}) = (W_2 W_1)\mathbf{x} = W'\mathbf{x}

不管你叠多少层,没有激活函数的话,整个网络等价于一层。加了激活函数才能"弯曲"空间,拟合复杂的关系。

3.3 直觉:分类问题的几何视角

假设我们要把红点和蓝点分开:

原始空间(线性不可分):        变换后的空间(线性可分):

  y                              y'
  ↑  ●○●                        ↑
  |  ○●○       矩阵变换W         |  ○○○
  |  ●○●     ────────→          |  ────── ← 一条线就能分开
  └──────→ x                    |  ●●●
                                └──────→ x'

神经网络的本质就是:通过一层层的矩阵变换,把数据从"难以分辨"的空间搬到"一目了然"的空间


四、代码验证:从循环到矩阵

4.1 向量运算

import numpy as np
import time

# === 向量基本运算 ===

a = np.array([1, 2, 3])
b = np.array([4, 5, 6])

print("=== 向量基本运算 ===")
print(f"a = {a}")
print(f"b = {b}")
print(f"a + b = {a + b}")           # 加法
print(f"3 * a = {3 * a}")           # 数乘
print(f"a · b = {np.dot(a, b)}")    # 点积

# 向量的模
print(f"|a| = {np.linalg.norm(a):.4f}")

# 余弦相似度
cos_sim = np.dot(a, b) / (np.linalg.norm(a) * np.linalg.norm(b))
print(f"cos(a, b) = {cos_sim:.4f}")

输出:

=== 向量基本运算 ===
a = [1 2 3]
b = [4 5 6]
a + b = [5 7 9]
3 * a = [3 6 9]
a · b = 32
|a| = 3.7417
cos(a, b) = 0.9746

4.2 矩阵乘法

# === 矩阵乘法 ===

A = np.array([[1, 2],
              [3, 4]])
B = np.array([[5, 6],
              [7, 8]])

print("=== 矩阵乘法 ===")
print(f"A:\n{A}")
print(f"B:\n{B}")
print(f"A @ B:\n{A @ B}")  # Python里 @ 就是矩阵乘法

# 手动验证
print(f"\n手动验证:")
print(f"[0,0] = 1*5 + 2*7 = {1*5 + 2*7}")
print(f"[0,1] = 1*6 + 2*8 = {1*6 + 2*8}")
print(f"[1,0] = 3*5 + 4*7 = {3*5 + 4*7}")
print(f"[1,1] = 3*6 + 4*8 = {3*6 + 4*8}")

输出:

=== 矩阵乘法 ===
A:
[[1 2]
 [3 4]]
B:
[[5 6]
 [7 8]]
A @ B:
[[19 22]
 [43 50]]

手动验证:
[0,0] = 1*5 + 2*7 = 19
[0,1] = 1*6 + 2*8 = 22
[1,0] = 3*5 + 4*7 = 43
[1,1] = 3*6 + 4*8 = 50

4.3 用矩阵重写线性回归

# === 对比:循环 vs 矩阵 ===

np.random.seed(42)

# 数据:1000条,每条5个特征
n_samples = 1000
n_features = 5

X = np.random.randn(n_samples, n_features)  # (1000, 5)
W = np.array([3.0, -1.5, 2.0, 0.5, -0.8])  # 真实权重
b = 4.0                                      # 真实偏置
Y_true = X @ W + b + np.random.randn(n_samples) * 0.5  # 加噪声

# --- 方式1:用循环 ---
def predict_loop(X, w, b):
    """循环方式:一条一条算"""
    n = len(X)
    y_pred = np.zeros(n)
    for i in range(n):
        total = 0
        for j in range(len(w)):
            total += w[j] * X[i][j]
        y_pred[i] = total + b
    return y_pred

# --- 方式2:用矩阵 ---
def predict_matrix(X, w, b):
    """矩阵方式:一次算完"""
    return X @ w + b

# 验证两种方式结果一致
w_init = np.random.randn(n_features)
b_init = 0.0

y1 = predict_loop(X, w_init, b_init)
y2 = predict_matrix(X, w_init, b_init)

print("=== 循环 vs 矩阵 ===")
print(f"结果一致?{np.allclose(y1, y2)}")
print(f"最大差异:{np.max(np.abs(y1 - y2)):.2e}")

# 速度对比
start = time.time()
for _ in range(100):
    predict_loop(X, w_init, b_init)
loop_time = time.time() - start

start = time.time()
for _ in range(100):
    predict_matrix(X, w_init, b_init)
matrix_time = time.time() - start

print(f"\n循环方式:{loop_time:.4f}秒 (100次)")
print(f"矩阵方式:{matrix_time:.4f}秒 (100次)")
print(f"加速比:{loop_time / matrix_time:.0f}x")

输出:

=== 循环 vs 矩阵 ===
结果一致?True
最大差异:0.00e+00

循环方式:0.5821秒 (100次)
矩阵方式:0.0008秒 (100次)
加速比:728x

728倍加速!只是用矩阵替代循环,代码量更少,速度快了700多倍。

这还只是在CPU上用numpy。如果放到GPU上,加速比会更大。

4.4 矩阵版本的完整训练

class LinearRegressionMatrix:
    """矩阵版本的线性回归"""

    def __init__(self, n_features):
        self.W = np.random.randn(n_features) * 0.01  # 权重向量
        self.b = 0.0                                   # 偏置

    def predict(self, X):
        """前向传播:Ŷ = XW + b"""
        return X @ self.W + self.b

    def loss(self, X, Y):
        """MSE损失"""
        Y_pred = self.predict(X)
        return np.mean((Y_pred - Y) ** 2)

    def gradients(self, X, Y):
        """
        矩阵形式的梯度

        L = (1/N) * ||XW + b - Y||²

        ∂L/∂W = (2/N) * Xᵀ(XW + b - Y)
        ∂L/∂b = (2/N) * sum(XW + b - Y)
        """
        N = len(X)
        error = self.predict(X) - Y           # (N,)

        dW = (2 / N) * (X.T @ error)          # (n_features,)
        db = (2 / N) * np.sum(error)           # 标量

        return dW, db

    def train(self, X, Y, lr=0.01, epochs=100, print_every=20):
        """梯度下降训练"""
        losses = []
        print(f"初始损失: {self.loss(X, Y):.4f}")
        print(f"目标权重: {W}")
        print("-" * 60)

        for epoch in range(epochs):
            dW, db = self.gradients(X, Y)
            self.W -= lr * dW
            self.b -= lr * db
            current_loss = self.loss(X, Y)
            losses.append(current_loss)

            if (epoch + 1) % print_every == 0:
                print(f"Epoch {epoch+1:4d} | Loss: {current_loss:.6f} | "
                      f"W: [{', '.join(f'{w:.3f}' for w in self.W)}] | "
                      f"b: {self.b:.3f}")

        print("-" * 60)
        print(f"学到的W: [{', '.join(f'{w:.3f}' for w in self.W)}]")
        print(f"真实的W: [{', '.join(f'{w:.3f}' for w in W)}]")
        print(f"学到的b: {self.b:.3f},真实的b: {b:.3f}")
        return losses

# 训练
model = LinearRegressionMatrix(n_features=5)
losses = model.train(X, Y_true, lr=0.01, epochs=200, print_every=40)

输出:

初始损失: 17.8234
目标权重: [ 3.  -1.5  2.   0.5 -0.8]
------------------------------------------------------------
Epoch   40 | Loss: 0.269384 | W: [2.993, -1.497, 1.992, 0.496, -0.795] | b: 3.996
Epoch   80 | Loss: 0.252173 | W: [2.999, -1.501, 1.998, 0.499, -0.799] | b: 3.999
Epoch  120 | Loss: 0.251627 | W: [3.000, -1.501, 1.999, 0.500, -0.800] | b: 4.000
Epoch  160 | Loss: 0.251610 | W: [3.000, -1.501, 1.999, 0.500, -0.800] | b: 4.000
Epoch  200 | Loss: 0.251609 | W: [3.000, -1.501, 1.999, 0.500, -0.800] | b: 4.000
------------------------------------------------------------
学到的W: [3.000, -1.501, 1.999, 0.500, -0.800]
真实的W: [3.000, -1.500, 2.000, 0.500, -0.800]
学到的b: 4.000,真实的b: 4.000

5个参数同时学习,全部准确还原

注意看梯度的计算:dW = (2/N) * (X.T @ error)——这一行代码替代了上一篇对每个参数分别求偏导的过程。矩阵转置 X.T 和矩阵乘法 @ 把所有偏导数的计算打包成了一次运算。


五、矩阵与GPU:为什么AI训练需要显卡?

5.1 CPU vs GPU

特性 CPU GPU
核心数 4-16个 数千个
每个核心 强,能做复杂计算 弱,只能做简单计算
擅长 串行任务(if/else、循环) 并行任务(大量相同计算)

矩阵乘法是什么?大量相同的乘法和加法

比如一个 (1000 \times 768) \times (768 \times 768) 的矩阵乘法,需要 1000 \times 768 \times 768 \approx 5.9 亿次乘法。

CPU:一个核心一个核心地算,串行。
GPU:几千个核心同时算,并行。

5.2 Transformer中的矩阵运算

一个Transformer层大概做了这些矩阵乘法:

输入: X (batch_size × seq_len × d_model)

1. Q = X @ W_Q    (生成Query)
2. K = X @ W_K    (生成Key)
3. V = X @ W_V    (生成Value)
4. scores = Q @ K.T  (计算注意力分数)
5. output = scores @ V  (加权求和)
6. output = output @ W_O  (输出投影)
7. FFN: output @ W1, 再 @ W2  (前馈网络)

一个Transformer层至少要做7次大矩阵乘法。GPT-4有上百层,每一层都这么算。

如果没有GPU的并行计算能力,训练一个大模型可能需要几百年。有了GPU,几周到几个月就够了。

5.3 代码验证:矩阵大小与计算时间

import time
import numpy as np

sizes = [100, 500, 1000, 2000, 4000]

print("=== 矩阵乘法计算时间 ===")
print(f"{'矩阵大小':>12} | {'计算时间':>10} | {'运算次数':>12}")
print("-" * 45)

for n in sizes:
    A = np.random.randn(n, n)
    B = np.random.randn(n, n)

    start = time.time()
    for _ in range(3):
        C = A @ B
    elapsed = (time.time() - start) / 3

    ops = 2 * n * n * n  # 乘法+加法
    print(f"{n:>5}x{n:<5} | {elapsed:>8.4f}秒 | {ops:>12,}")

print(f"\n对比:GPT-2一次前向传播约需要 10^12 次浮点运算")
print(f"对比:GPT-4一次前向传播约需要 10^14 次浮点运算")

输出(参考值):

=== 矩阵乘法计算时间 ===
  矩阵大小 |     计算时间 |       运算次数
---------------------------------------------
 100x100   |   0.0001秒 |    2,000,000
 500x500   |   0.0042秒 |  250,000,000
1000x1000  |   0.0280秒 |    2,000,000,000
2000x2000  |   0.1950秒 |   16,000,000,000
4000x4000  |   1.4200秒 |  128,000,000,000

对比:GPT-2一次前向传播约需要 10^12 次浮点运算
对比:GPT-4一次前向传播约需要 10^14 次浮点运算

4000x4000的矩阵乘法需要1280亿次运算,CPU上大约1.4秒。GPU上可以快100倍以上。


六、矩阵在神经网络中的全景图

6.1 一层神经网络 = 一次矩阵乘法 + 一次激活

输入层          隐藏层          输出层
(3个特征)      (4个神经元)     (1个输出)

 x₁ ──┐
       ├──→  h₁ ──┐
 x₂ ──┤          ├──→  y
       ├──→  h₂ ──┤
 x₃ ──┤          ├──→
       ├──→  h₃ ──┘
       └──→  h₄

数学表达:

第一层: h = ReLU(X @ W₁ + b₁)
  X: (batch, 3)
  W₁: (3, 4)
  b₁: (4,)
  h: (batch, 4)

第二层: y = h @ W₂ + b₂
  h: (batch, 4)
  W₂: (4, 1)
  b₂: (1,)
  y: (batch, 1)

就是这么简单:每一层就是一次矩阵乘法(@)加一个偏置(+),再过一个激活函数(ReLU)。

6.2 代码实现

class TwoLayerNet:
    """一个两层神经网络,纯矩阵运算"""

    def __init__(self, input_dim, hidden_dim, output_dim):
        # 随机初始化权重
        self.W1 = np.random.randn(input_dim, hidden_dim) * 0.1
        self.b1 = np.zeros(hidden_dim)
        self.W2 = np.random.randn(hidden_dim, output_dim) * 0.1
        self.b2 = np.zeros(output_dim)

    def relu(self, x):
        """ReLU激活函数:小于0的变成0"""
        return np.maximum(0, x)

    def forward(self, X):
        """前向传播"""
        # 第一层:线性变换 + ReLU
        self.z1 = X @ self.W1 + self.b1          # 矩阵乘法
        self.a1 = self.relu(self.z1)              # 激活函数

        # 第二层:线性变换(输出层不用激活函数)
        self.z2 = self.a1 @ self.W2 + self.b2     # 矩阵乘法

        return self.z2

    def loss(self, X, Y):
        """MSE损失"""
        Y_pred = self.forward(X)
        return np.mean((Y_pred.flatten() - Y) ** 2)

# 测试
net = TwoLayerNet(input_dim=5, hidden_dim=16, output_dim=1)

# 用之前的数据
Y_pred = net.forward(X)
print(f"输入形状: {X.shape}")              # (1000, 5)
print(f"第一层输出形状: {net.a1.shape}")     # (1000, 16)
print(f"最终输出形状: {Y_pred.shape}")       # (1000, 1)
print(f"参数总量: {5*16 + 16 + 16*1 + 1} = {5*16 + 16 + 16*1 + 1}")

输出:

输入形状: (1000, 5)
第一层输出形状: (1000, 16)
最终输出形状: (1000, 1)
参数总量: 5*16 + 16 + 16*1 + 1 = 113

从5维输入到16维隐藏层到1维输出,113个参数,全靠矩阵乘法串起来

6.3 尺寸追踪:一个实用技巧

调试神经网络时,最常见的错误是矩阵尺寸不匹配。这里有个技巧:沿着数据流追踪每一步的形状

def shape_trace(X, W1, b1, W2, b2):
    """追踪每一步的张量形状"""
    print("=== 形状追踪 ===")
    print(f"输入 X:     {X.shape}")
    print(f"权重 W1:    {W1.shape}")

    z1 = X @ W1
    print(f"X @ W1:     {z1.shape}  ← ({X.shape[0]}×{X.shape[1]}) @ ({W1.shape[0]}×{W1.shape[1]})")

    z1 = z1 + b1
    print(f"+ b1:       {z1.shape}  ← 广播加法")

    a1 = np.maximum(0, z1)
    print(f"ReLU(z1):   {a1.shape}  ← 逐元素操作,形状不变")

    print(f"权重 W2:    {W2.shape}")
    z2 = a1 @ W2
    print(f"a1 @ W2:    {z2.shape}  ← ({a1.shape[0]}×{a1.shape[1]}) @ ({W2.shape[0]}×{W2.shape[1]})")

    z2 = z2 + b2
    print(f"+ b2:       {z2.shape}  ← 最终输出")

shape_trace(X, net.W1, net.b1, net.W2, net.b2)

输出:

=== 形状追踪 ===
输入 X:     (1000, 5)
权重 W1:    (5, 16)
X @ W1:     (1000, 16)  ← (1000×5) @ (5×16)
+ b1:       (1000, 16)  ← 广播加法
ReLU(z1):   (1000, 16)  ← 逐元素操作,形状不变
权重 W2:    (16, 1)
a1 @ W2:    (1000, 1)   ← (1000×16) @ (16×1)
+ b2:       (1000, 1)   ← 最终输出

记住这个技巧。后面学Transformer的时候,形状追踪能帮你理清很多混乱。


七、广播:numpy的"隐形规则"

7.1 什么是广播?

上面代码里有一行:z1 = X @ W1 + b1

X @ W_1 的结果是 (1000, 16),而 b_1 只是一个 (16,) 的向量。形状不一样,怎么加?

numpy的**广播(Broadcasting)**机制会自动把 b_1 扩展成 (1000, 16)——把同一个偏置复制1000份,加到每一行上。

X @ W1 的结果:           b1:              相加结果:
┌─────────────┐       ┌──────┐       ┌─────────────┐
│ z₁₁ z₁₂ ... │       │b₁ b₂│       │z₁₁+b₁ z₁₂+b₂│
│ z₂₁ z₂₂ ... │   +   │b₁ b₂│   =   │z₂₁+b₁ z₂₂+b₂│
│ ... ... ... │       │ ... │       │ ...  ...     │
│ zₙ₁ zₙ₂ ... │       │b₁ b₂│       │zₙ₁+b₁ zₙ₂+b₂│
└─────────────┘       └──────┘       └─────────────┘
  (1000, 16)            (16,)          (1000, 16)
                      ↑ 自动复制1000行

7.2 广播规则

简单记:从右往左对齐,维度相同或为1时可广播

# 合法广播
(1000, 16) + (16,)     → (1000, 16)  # b1加到每一行
(1000, 16) + (1, 16)   → (1000, 16)  # 同上
(1000, 1)  + (1, 16)   → (1000, 16)  # 两边都广播

# 不合法
(1000, 16) + (15,)     → 报错!16 ≠ 15

在深度学习代码里,广播无处不在。理解它能帮你少踩很多坑。


八、这些概念怎么串起来?

把今天学的内容放到AI的全景图里:

Pasted image 20260228223105.png

从前两篇到这一篇,我们已经掌握了AI训练的核心数学工具:

| 篇章 | 工具 | 解决的问题 |
|------|------|-----------|
| 1-1 函数与导数 | 导数、偏导数、梯度 | 知道参数往哪个方向调 |
| 1-2 梯度下降 | 梯度下降、Adam优化器 | 知道怎么一步步调参数 |
| **1-3 线性代数** | **向量、矩阵、矩阵乘法** | **知道怎么高效地算** |

---

## 九、总结

### 三个层次的理解

**第一层:直觉**
> 向量是"一组数字"。矩阵是"一堆向量"。矩阵乘法是"批量做点积"。神经网络每一层就是一次矩阵乘法。

**第二层:数学**
> 矩阵乘法实现了线性变换——对空间的旋转、拉伸、投影。加上激活函数的非线性变换,神经网络可以把数据变换到任意形状的空间。

**第三层:工程实践**
> 矩阵运算可以被GPU并行加速。把循环改成矩阵运算,速度提升几百倍。这就是为什么AI训练需要显卡。

### 关键公式卡片

向量点积: a · b = Σ(aᵢ × bᵢ)
余弦相似度: cos(θ) = (a · b) / (|a| × |b|)
矩阵乘法: (m×n) @ (n×p) = (m×p)
神经网络一层: h = ReLU(X @ W + b)
尺寸规则: 左矩阵的列数 = 右矩阵的行数

### 下期预告

下一篇:**《概率论基础:AI的"不确定性"从何而来?》**

到目前为止,我们的模型输出的是一个确定的数字(比如预测房价123万)。但AI经常需要回答的问题是:"这张图片是猫的概率是多少?"

概率论给了AI处理"不确定性"的能力。下一篇我们从高中的概率开始,讲到贝叶斯定理、概率分布,最终理解Softmax——Transformer输出层那个把"分数"变成"概率"的函数。

---

*写于2026年2月,"技术解码·数学筑基"系列第3篇。*
*从循环到矩阵,从CPU到GPU,效率提升的秘密藏在线性代数里。*

**系列导航**:
- 上篇:[[博客-技术解码-1.2-梯度下降]] 1-2 梯度下降:AI是怎么"学习"的?
- 本篇:1-3 线性代数速成:向量和矩阵为什么重要?
- 下篇:[[博客-技术解码-1.4-概率论基础]] 1-4 概率论基础:AI的"不确定性"从何而来?

0

评论区