04 - 线性代数基础¶
学习时间: 2.5小时 重要性: ⭐⭐⭐⭐⭐ 理解神经网络和扩散模型的核心数学工具
🎯 学习目标¶
完成本章后,你将能够: - 理解向量和矩阵的基本概念 - 掌握矩阵运算及其在深度学习中的应用 - 理解特征值和特征向量的直观意义 - 掌握线性代数在扩散模型中的具体应用
1. 向量¶
1.1 什么是向量?¶
直观理解:向量是有方向和大小的量。
在深度学习中,我们通常把向量表示为: - 一维数组:[1, 2, 3, 4] - 列向量:
[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 向量加法¶
a = np.array([1, 2, 3])
b = np.array([4, 5, 6])
# 向量加法(元素对应相加)
c = a + b
print(f"向量加法: {c}") # [5, 7, 9]
1.3.2 向量点积(内积)¶
定义:两个向量对应元素相乘后求和。
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}\)$
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 什么是矩阵?¶
直观理解:矩阵是数字的二维排列。
在深度学习中,矩阵用于: - 表示图像(高×宽×通道) - 表示神经网络的权重 - 批量数据处理
2.2 矩阵的基本操作¶
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 矩阵乘法的意义¶
为什么矩阵乘法很重要?
在神经网络中,矩阵乘法实现了: - 线性变换:旋转、缩放、投影 - 信息整合:将输入特征组合成新的表示 - 批量计算:一次处理多个样本
# 示例:神经网络的一层
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\),使得:
则: - \(\lambda\) 是矩阵 \(A\) 的特征值 - \(\mathbf{v}\) 是对应的特征向量
3.2 直观理解¶
特征向量是矩阵变换后方向不变的向量,只是长度缩放了特征值倍。
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(主成分分析) - 用于白化操作 - 用于理解数据的主要变化方向
# 示例: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 图像的矩阵表示¶
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 批量数据处理的矩阵运算¶
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是扩散模型的核心架构,其中大量使用了卷积操作(特殊的线性变换):
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(奇异值分解)¶
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\) 是下三角矩阵。
# 创建正定矩阵
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 求解线性方程组¶
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:实现矩阵乘法¶
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:计算协方差矩阵¶
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 在扩散模型中的重要性¶
- 数据表示:图像作为高维向量/矩阵
- 神经网络:通过矩阵乘法实现线性变换
- UNet架构:卷积操作是特殊的矩阵乘法
- 批量处理:矩阵运算实现高效并行计算
- 优化算法:梯度计算涉及矩阵运算
7.3 学习建议¶
- 动手实践:用NumPy实现各种运算
- 可视化:用matplotlib理解几何意义
- 联系应用:思考每个概念在深度学习中的作用
- 逐步深入:从基础概念开始,逐步学习高级主题
8. 推荐资源¶
书籍¶
- 《线性代数导论》- Gilbert Strang
- 《深度学习》- 第2章:线性代数
在线课程¶
- MIT 18.06 Linear Algebra (Gilbert Strang)
- 3Blue1Brown - 线性代数的本质
编程实践¶
- NumPy官方文档
- SciPy线性代数模块
9. 自测问题¶
- 什么是向量的点积?它有什么几何意义?
- 矩阵乘法和逐元素乘法有什么区别?
- 特征值和特征向量的直观含义是什么?
- 为什么SVD分解在数据降维中很有用?
- 在深度学习中,为什么矩阵乘法比循环更高效?
下一章: 05-随机微分方程基础 - 理解连续时间扩散模型的数学基础