跳转至

04 - 线性代数基础

学习时间: 2.5小时 重要性: ⭐⭐⭐⭐⭐ 理解神经网络和扩散模型的核心数学工具


🎯 学习目标

完成本章后,你将能够: - 理解向量和矩阵的基本概念 - 掌握矩阵运算及其在深度学习中的应用 - 理解特征值和特征向量的直观意义 - 掌握线性代数在扩散模型中的具体应用


1. 向量

1.1 什么是向量?

直观理解:向量是有方向和大小的量。

在深度学习中,我们通常把向量表示为: - 一维数组[1, 2, 3, 4] - 列向量

Text Only
  [1]
  [2]
  [3]
  ```

### 1.2 向量的维度

向量的维度就是元素的个数:

```python
import numpy as np

# 不同维度的向量
scalar = 5                # 0维(标量)
vector_1d = np.array([1, 2, 3])           # 3维向量
vector_2d = np.array([1, 2, 3, 4, 5])    # 5维向量

print(f"标量: {scalar}")
print(f"3维向量: {vector_1d}")
print(f"5维向量: {vector_2d}")

1.3 向量运算

1.3.1 向量加法

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

# 向量加法(元素对应相加)
c = a + b
print(f"向量加法: {c}")  # [5, 7, 9]

1.3.2 向量点积(内积)

定义:两个向量对应元素相乘后求和。

\[\mathbf{a} \cdot \mathbf{b} = \sum_{i=1}^{n} a_i b_i\]
Python
a = np.array([1, 2, 3])
b = np.array([4, 5, 6])

# 点积
dot_product = np.dot(a, b)  # np.dot矩阵/向量点乘
print(f"点积: {dot_product}")  # 1*4 + 2*5 + 3*6 = 32

点积的几何意义: - \(\mathbf{a} \cdot \mathbf{b} = \|\mathbf{a}\| \|\mathbf{b}\| \cos\theta\) - 可以用来计算两个向量的夹角 - 点积为0表示向量正交(垂直)

1.3.3 向量范数(长度)

L2范数(欧几里得距离): $\(\|\mathbf{x}\|_2 = \sqrt{\sum_{i=1}^{n} x_i^2}\)$

Python
a = np.array([3, 4])

# L2范数
norm = np.linalg.norm(a)  # np.linalg线性代数运算
print(f"L2范数: {norm}")  # sqrt(3^2 + 4^2) = 5

2. 矩阵

2.1 什么是矩阵?

直观理解:矩阵是数字的二维排列。

Text Only
[1  2  3]
[4  5  6]
[7  8  9]

在深度学习中,矩阵用于: - 表示图像(高×宽×通道) - 表示神经网络的权重 - 批量数据处理

2.2 矩阵的基本操作

Python
import numpy as np

# 创建矩阵
A = np.array([[1, 2],
              [3, 4]])

B = np.array([[5, 6],
              [7, 8]])

print(f"矩阵A:\n{A}")
print(f"矩阵B:\n{B}")

# 矩阵加法
C = A + B
print(f"\n矩阵加法:\n{C}")

# 矩阵乘法
D = np.dot(A, B)
print(f"\n矩阵乘法:\n{D}")

# 转置
A_T = A.T
print(f"\n矩阵A的转置:\n{A_T}")

# 矩阵的逆(如果存在)
A_inv = np.linalg.inv(A)
print(f"\n矩阵A的逆:\n{A_inv}")

# 验证 A @ A_inv = I
identity = np.dot(A, A_inv)
print(f"\nA @ A_inv (应该接近单位矩阵):\n{identity}")

2.3 矩阵乘法的意义

为什么矩阵乘法很重要?

在神经网络中,矩阵乘法实现了: - 线性变换:旋转、缩放、投影 - 信息整合:将输入特征组合成新的表示 - 批量计算:一次处理多个样本

Python
# 示例:神经网络的一层
import numpy as np

# 输入(batch_size=3, input_dim=4)
X = np.random.randn(3, 4)

# 权重矩阵(input_dim=4, output_dim=5)
W = np.random.randn(4, 5)

# 偏置(output_dim=5)
b = np.random.randn(5)

# 线性变换:Y = X @ W + b
Y = np.dot(X, W) + b

print(f"输入形状: {X.shape}")
print(f"权重形状: {W.shape}")
print(f"输出形状: {Y.shape}")

3. 特征值和特征向量

3.1 定义

对于方阵 \(A\),如果存在非零向量 \(\mathbf{v}\) 和标量 \(\lambda\),使得:

\[A\mathbf{v} = \lambda\mathbf{v}\]

则: - \(\lambda\) 是矩阵 \(A\)特征值 - \(\mathbf{v}\) 是对应的特征向量

3.2 直观理解

特征向量是矩阵变换后方向不变的向量,只是长度缩放了特征值倍。

Python
import numpy as np

A = np.array([[4, 1],
              [2, 3]])

# 计算特征值和特征向量
eigenvalues, eigenvectors = np.linalg.eig(A)

print("特征值:", eigenvalues)
print("特征向量:\n", eigenvectors)

# 验证:A @ v = lambda @ v
for i in range(len(eigenvalues)):
    v = eigenvectors[:, i]
    lambda_val = eigenvalues[i]

    Av = np.dot(A, v)
    lambda_v = lambda_val * v

    print(f"\n特征值 {i+1}: {lambda_val}")
    print(f"A @ v = {Av}")
    print(f"λ @ v = {lambda_v}")
    print(f"验证: {np.allclose(Av, lambda_v)}")

3.3 在深度学习中的应用

协方差矩阵的特征分解: - 用于PCA(主成分分析) - 用于白化操作 - 用于理解数据的主要变化方向

Python
# 示例:PCA的基本思想
import numpy as np
import matplotlib.pyplot as plt

# 生成二维数据
np.random.seed(42)
X = np.random.randn(100, 2)
X[:, 1] = 0.5 * X[:, 0] + 0.5 * X[:, 1]  # 添加相关性

# 中心化数据
X_centered = X - X.mean(axis=0)

# 计算协方差矩阵
cov_matrix = np.cov(X_centered.T)

# 特征分解
eigenvalues, eigenvectors = np.linalg.eig(cov_matrix)

print("特征值:", eigenvalues)
print("特征向量:\n", eigenvectors)

# 可视化
plt.figure(figsize=(10, 5))

plt.subplot(1, 2, 1)
plt.scatter(X[:, 0], X[:, 1], alpha=0.6)
plt.title("原始数据")
plt.xlabel("x1")
plt.ylabel("x2")
plt.grid(True, alpha=0.3)

plt.subplot(1, 2, 2)
plt.scatter(X_centered[:, 0], X_centered[:, 1], alpha=0.6)
# 绘制特征向量
for i in range(len(eigenvalues)):
    v = eigenvectors[:, i]
    plt.arrow(0, 0, v[0] * 2, v[1] * 2,
              head_width=0.1, head_length=0.1,
              fc='red', ec='red', linewidth=2,
              label=f'特征向量 {i+1}')
plt.title("中心化数据 + 特征向量")
plt.xlabel("x1")
plt.ylabel("x2")
plt.grid(True, alpha=0.3)
plt.legend()

plt.tight_layout()
plt.show()

4. 线性代数在扩散模型中的应用

4.1 图像的矩阵表示

Python
import numpy as np
import matplotlib.pyplot as plt

# 创建一个简单的图像(5x5像素)
image = np.array([
    [0, 0, 0, 0, 0],
    [0, 255, 255, 255, 0],
    [0, 255, 0, 255, 0],
    [0, 255, 255, 255, 0],
    [0, 0, 0, 0, 0]
], dtype=np.float32)

# 归一化到[0, 1]
image_normalized = image / 255.0

print(f"图像形状: {image.shape}")
print(f"图像数据类型: {image.dtype}")

# 展平为向量
image_flattened = image_normalized.flatten()
print(f"展平后的向量长度: {len(image_flattened)}")

plt.figure(figsize=(8, 4))
plt.subplot(1, 2, 1)
plt.imshow(image, cmap='gray')
plt.title("原始图像 (5×5)")
plt.axis('off')

plt.subplot(1, 2, 2)
plt.imshow(image_normalized, cmap='gray')
plt.title("归一化图像")
plt.axis('off')

plt.tight_layout()
plt.show()

4.2 批量数据处理的矩阵运算

Python
import numpy as np

# 模拟批量图像数据
batch_size = 32
height = 32
width = 32
channels = 3

# 创建一个batch的图像数据
images = np.random.randn(batch_size, height, width, channels)

print(f"批量数据形状: {images.shape}")
print(f"  - 批量大小: {batch_size}")
print(f"  - 高度: {height}")
print(f"  - 宽度: {width}")
print(f"  - 通道数: {channels}")

# 展平为矩阵(用于某些计算)
images_flattened = images.reshape(batch_size, -1)  # 重塑张量形状
print(f"\n展平后的形状: {images_flattened.shape}")
print(f"  - 每个样本的维度: {height * width * channels}")

# 计算均值(沿batch维度)
mean = images.mean(axis=0)
print(f"\n均值的形状: {mean.shape}")

# 计算方差
variance = images.var(axis=0)
print(f"方差的形状: {variance.shape}")

4.3 线性变换在UNet中的应用

UNet是扩散模型的核心架构,其中大量使用了卷积操作(特殊的线性变换):

Python
import torch
import torch.nn as nn

# 简单的卷积层示例
class SimpleConvBlock(nn.Module):  # 继承nn.Module定义网络层
    def __init__(self, in_channels, out_channels):
        super().__init__()  # super()调用父类方法
        self.conv = nn.Conv2d(in_channels, out_channels, kernel_size=3, padding=1)
        self.relu = nn.ReLU()

    def forward(self, x):
        return self.relu(self.conv(x))

# 创建测试数据
batch_size = 4
in_channels = 3
height, width = 32, 32

x = torch.randn(batch_size, in_channels, height, width)
print(f"输入形状: {x.shape}")

# 应用卷积层
conv_block = SimpleConvBlock(in_channels=3, out_channels=64)
output = conv_block(x)

print(f"输出形状: {output.shape}")
print(f"  - 通道数: 3 → 64")
print(f"  - 空间维度: 32×32 → 32×32(padding保持不变)")

# 查看卷积核的形状
kernel = conv_block.conv.weight
print(f"\n卷积核形状: {kernel.shape}")
print(f"  - 输出通道数: {kernel.shape[0]}")
print(f"  - 输入通道数: {kernel.shape[1]}")
print(f"  - 卷积核大小: {kernel.shape[2]}×{kernel.shape[3]}")

5. 常用线性代数操作

5.1 矩阵分解

5.1.1 SVD(奇异值分解)

\[A = U \Sigma V^T\]
Python
import numpy as np

A = np.random.randn(4, 5)

# SVD分解
U, S, Vt = np.linalg.svd(A)

print(f"原始矩阵形状: {A.shape}")
print(f"U形状: {U.shape}")
print(f"S形状: {S.shape}")
print(f"Vt形状: {Vt.shape}")

# 重构
A_reconstructed = U @ np.diag(S) @ Vt
print(f"\n重构误差: {np.linalg.norm(A - A_reconstructed)}")

SVD的应用: - 降维(保留主要奇异值) - 去噪 - 推荐系统

5.1.2 Cholesky分解

对于正定矩阵 \(A\): $\(A = LL^T\)$

其中 \(L\) 是下三角矩阵。

Python
# 创建正定矩阵
A = np.random.randn(3, 3)
A = A @ A.T  # 确保正定

# Cholesky分解
L = np.linalg.cholesky(A)

print("原始矩阵A:")
print(A)
print("\nCholesky分解 L:")
print(L)

# 验证
A_reconstructed = L @ L.T
print("\n验证误差:", np.linalg.norm(A - A_reconstructed))

5.2 求解线性方程组

\[Ax = b\]
Python
import numpy as np

# 创建线性方程组
A = np.array([[2, 1],
              [1, 3]])
b = np.array([5, 6])

# 方法1:使用inv
x1 = np.linalg.inv(A) @ b

# 方法2:使用solve(推荐)
x2 = np.linalg.solve(A, b)

print(f"解法1 (inv): {x1}")
print(f"解法2 (solve): {x2}")
print(f"验证: {A @ x2}")

6. 实践练习

练习1:实现矩阵乘法

Python
def matrix_multiply(A, B):
    """
    手动实现矩阵乘法
    """
    m, n = A.shape
    n2, p = B.shape

    if n != n2:
        raise ValueError("矩阵维度不匹配")

    C = np.zeros((m, p))

    for i in range(m):
        for j in range(p):
            for k in range(n):
                C[i, j] += A[i, k] * B[k, j]

    return C

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

result_custom = matrix_multiply(A, B)
result_numpy = np.dot(A, B)

print("自定义结果:")
print(result_custom)
print("\nNumPy结果:")
print(result_numpy)
print(f"\n是否一致: {np.allclose(result_custom, result_numpy)}")

练习2:计算协方差矩阵

Python
def compute_covariance_matrix(X):
    """
    计算协方差矩阵

    参数:
        X: 数据矩阵,形状为 (n_samples, n_features)

    返回:
        协方差矩阵,形状为 (n_features, n_features)
    """
    # 中心化数据
    X_centered = X - X.mean(axis=0)

    # 计算协方差矩阵
    n = X.shape[0]
    cov_matrix = (X_centered.T @ X_centered) / (n - 1)

    return cov_matrix

# 测试
np.random.seed(42)
X = np.random.randn(100, 3)

cov_custom = compute_covariance_matrix(X)
cov_numpy = np.cov(X.T)

print("自定义协方差矩阵:")
print(cov_custom)
print("\nNumPy协方差矩阵:")
print(cov_numpy)
print(f"\n是否一致: {np.allclose(cov_custom, cov_numpy)}")

7. 总结

7.1 核心概念回顾

概念 定义 应用
向量 有方向和大小的量 表示数据点、特征
矩阵 数字的二维排列 表示图像、权重、批量数据
点积 对应元素相乘求和 计算相似度、投影
矩阵乘法 线性变换 神经网络层、卷积
特征值/特征向量 变换后方向不变的向量 PCA、数据降维
SVD分解 A = UΣV^T 降维、去噪

7.2 在扩散模型中的重要性

  1. 数据表示:图像作为高维向量/矩阵
  2. 神经网络:通过矩阵乘法实现线性变换
  3. UNet架构:卷积操作是特殊的矩阵乘法
  4. 批量处理:矩阵运算实现高效并行计算
  5. 优化算法:梯度计算涉及矩阵运算

7.3 学习建议

  1. 动手实践:用NumPy实现各种运算
  2. 可视化:用matplotlib理解几何意义
  3. 联系应用:思考每个概念在深度学习中的作用
  4. 逐步深入:从基础概念开始,逐步学习高级主题

8. 推荐资源

书籍

  • 《线性代数导论》- Gilbert Strang
  • 《深度学习》- 第2章:线性代数

在线课程

  • MIT 18.06 Linear Algebra (Gilbert Strang)
  • 3Blue1Brown - 线性代数的本质

编程实践

  • NumPy官方文档
  • SciPy线性代数模块

9. 自测问题

  1. 什么是向量的点积?它有什么几何意义?
  2. 矩阵乘法和逐元素乘法有什么区别?
  3. 特征值和特征向量的直观含义是什么?
  4. 为什么SVD分解在数据降维中很有用?
  5. 在深度学习中,为什么矩阵乘法比循环更高效?

下一章: 05-随机微分方程基础 - 理解连续时间扩散模型的数学基础