参考:
前言
在中文网络中,“字典学习”是关于这个概念最直接且最常见的翻译,但是我认为,实际上这个翻译是不合适的,我认为“稀疏编码” 才更加符合这个概念。
因为实际上人们更加关心的实际上是将原本的数据进行压缩,整个过程符合稀疏编码的概念,而字典是在整个压缩过程中所产生的产品。
第一部分:背景知识
1.1 信号处理的起源
字典学习的根源可以追溯到信号处理领域。信号处理的目标是从复杂的信号(如音频、图像、视频)中提取有意义的信息。20世纪中期,傅里叶变换(Fourier Transform)和小波变换(Wavelet Transform)成为信号分析的主流工具:
- 傅里叶变换:将信号分解为不同频率的正弦波和余弦波的组合。
- 小波变换:在傅里叶变换基础上增加了时间局部性,适合分析非平稳信号。
然而,这些方法依赖于预定义的基函数(比如正弦波、小波),对某些复杂信号的表示能力有限。比如,图像中的边缘特征或音频中的瞬态变化可能无法被这些固定基函数很好地捕捉。这就引出了一个问题:能不能从数据本身学习一组更适合的基函数?
1.2 稀疏表示的兴起
20世纪90年代,稀疏表示(Sparse Representation)开始受到关注。稀疏表示的核心思想是:许多自然信号可以用少量基向量的线性组合来表示。这种思想受到以下启发:
- 生物学:人类视觉系统(比如V1皮层)倾向于用稀疏的方式编码信息。例如,神经元对特定方向的边缘响应,而对其他方向不响应。
- 压缩感知(Compressed Sensing):Donoho 和 Candès 等人在2000年代证明,如果信号是稀疏的,可以通过少量测量精确重构信号。
稀疏表示需要一个“字典”(Dictionary),传统方法(如傅里叶基、小波基)使用固定字典,但这些字典并非对所有信号都最优。于是,研究者开始探索从数据中自适应学习字典的可能性。
1.3 机器学习与特征提取
与此同时,机器学习领域也在快速发展。20世纪末,特征提取成为模式识别和数据分析的关键问题。传统的特征提取方法(如主成分分析 PCA)虽然有效,但有局限性:
- PCA 是线性方法,假设数据服从高斯分布。
- PCA 的基向量是全局的,无法捕捉局部特征。
字典学习应运而生,它结合了稀疏表示和自适应学习的优势,成为一种强大的特征提取工具。与 PCA 不同,字典学习不要求基向量正交,且可以通过过完备字典(原子数大于数据维度)捕捉更多样化的模式。
1.4 历史里程碑
- 1996年,Olshausen 和 Field:提出了稀疏编码的概念,首次尝试从自然图像中学习字典,模拟人类视觉系统。
- 2006年,K-SVD 算法:Aharon 等人提出了 K-SVD,一种高效的字典学习算法,结合了 K-Means 和奇异值分解(SVD),成为经典方法。
- 2000年代后期,压缩感知:字典学习与压缩感知结合,推动了其在信号恢复中的应用。
- 2010年代,深度学习:卷积稀疏编码和字典学习的思想被融入深度神经网络,进一步扩展了其影响力。
第二部分:理论基础
2.1 线性代数视角
\[ X \approx D A \]- 如果 \( k = m \) 且 \( D \) 可逆,这类似于 PCA 或 ICA(独立成分分析)。
- 如果 \( k > m \),字典是过完备的(Overcomplete),允许更灵活的表示,但增加了求解难度。
2.2 稀疏性与 L1 正则化
\[ \min_a \| x - D a \|_2^2 \]\[ \min_a \| x - D a \|_2^2 + \lambda \| a \|_1 \]L1 范数(\( \| a \|_1 = \sum |a_i| \))相比 L2 范数(\( \| a \|_2^2 = \sum a_i^2 \))更倾向于产生零值解,这是稀疏性的来源。
2.3 过完备字典的优势
过完备字典(\( k > m \))相比完备字典(\( k = m \))有以下优势:
- 表达能力强:可以表示更复杂的模式。
- 鲁棒性:对噪声和数据缺失更具容忍度。
- 稀疏性:允许用更少的原子组合表示信号。
但缺点是计算复杂度增加,且优化问题变得非凸(Non-convex),需要迭代求解。
2.4 与其他方法的对比
- PCA:字典正交,重构误差最小,但不稀疏。
- NMF(非负矩阵分解):字典和系数非负,适合特定数据(如图像光谱),但不一定稀疏。
- 小波变换:固定字典,计算效率高,但缺乏自适应性。
第三部分:更详细的数学推导
3.1 目标函数
\[ \min_{D, A} \| X - D A \|_F^2 + \lambda \sum_{i=1}^n \| a_i \|_1 \]其中:
- \( \| X - D A \|_F^2 = \sum_{i,j} (X_{ij} - (D A)_{ij})^2 \) 是 Frobenius 范数。
- \( \sum_{i=1}^n \| a_i \|_1 \) 是稀疏惩罚项。
3.2 稀疏编码推导
\[ \min_{a_i} \| x_i - D a_i \|_2^2 + \lambda \| a_i \|_1 \]这是一个凸优化问题。我们可以用近端梯度下降(Proximal Gradient Descent):
- 定义损失函数 \( f(a_i) = \| x_i - D a_i \|_2^2 \) 和正则项 \( g(a_i) = \lambda \| a_i \|_1 \)。
- 梯度:\( \nabla f(a_i) = 2 D^T (D a_i - x_i) \)。
- 近端算子:对 \( g(a_i) \) 的近端映射是软阈值(Soft Thresholding): \[ \text{prox}_{\lambda}(z) = \text{sign}(z) \max(|z| - \lambda, 0) \]
- 迭代更新:\( a_i^{t+1} = \text{prox}_{\lambda} (a_i^t - \eta \nabla f(a_i^t)) \)。
3.3 字典更新推导
\[ \min_D \| X - D A \|_F^2 \]\[ \frac{\partial}{\partial D} \| X - D A \|_F^2 = -2 (X - D A) A^T \]\[ D = X A^T (A A^T)^{-1} \]但为了避免 \( D \) 的列范数过大,通常加入约束 \( \| d_j \|_2 \leq 1 \),需要投影到约束集。
3.4 K-SVD 的细节
K-SVD 改进了字典更新步骤:
- 对每个原子 \( d_j \) 和对应的系数行 \( a^j \) 单独更新。
- 计算残差 \( E_j = X - \sum_{k \neq j} d_k a^k \)。
- 对 \( E_j \) 做 SVD 分解,更新 \( d_j \) 和 \( a^j \)。
第四部分:更详细的实现(K-SVD 示例)
以下是一个手写 K-SVD 的简版实现,帮助你理解其内部机制:
import numpy as np
def omp(X, D, sparsity):
"""正交匹配追踪求稀疏系数"""
n_samples, n_features = X.shape
k = D.shape[1]
A = np.zeros((k, n_samples))
for i in range(n_samples):
x = X[i]
residual = x.copy()
support = []
for _ in range(sparsity):
scores = np.abs(D.T @ residual)
if not support:
idx = np.argmax(scores)
else:
idx = np.argmax(scores * (1 - np.array(support, dtype=int)))
support.append(idx)
D_s = D[:, support]
a_s = np.linalg.pinv(D_s) @ x
residual = x - D_s @ a_s
A[support, i] = a_s
return A
def k_svd(X, n_atoms, sparsity, n_iter):
"""K-SVD 算法"""
n_features, n_samples = X.shape
D = np.random.randn(n_features, n_atoms)
D /= np.linalg.norm(D, axis=0) # 归一化
for iteration in range(n_iter):
# 稀疏编码
A = omp(X, D, sparsity)
# 字典更新
for j in range(n_atoms):
I = A[j, :] != 0
if np.sum(I) == 0:
continue
E_j = X[:, I] - D @ A[:, I] + np.outer(D[:, j], A[j, I])
U, s, Vt = np.linalg.svd(E_j, full_matrices=False)
D[:, j] = U[:, 0]
A[j, I] = s[0] * Vt[0]
return D, A
# 测试
X = np.random.randn(20, 100) # 20维,100个样本
D, A = k_svd(X, n_atoms=30, sparsity=5, n_iter=10)
X_reconstructed = D @ A
error = np.mean((X - X_reconstructed) ** 2)
print(f"重构误差: {error:.4f}")
代码解释
- OMP:实现正交匹配追踪,逐步选择字典原子。
- K-SVD:交替进行稀疏编码和字典更新。
- 归一化:确保字典原子单位长度。
第五部分:更广泛的背景与展望
5.1 跨学科联系
- 神经科学:字典学习与大脑的稀疏编码机制有相似之处。
- 物理学:在量子信息和稀疏恢复中有潜在应用。
- 计算机视觉:用于目标检测、图像超分辨率等。
5.2 当前挑战
- 计算复杂度:大数据下的字典学习仍需优化。
- 非凸性:全局最优解难以保证。
- 可解释性:学到的字典如何与物理意义对应?
5.3 未来方向
- 与深度学习的融合(如卷积字典学习)。
- 在线学习和分布式计算的应用。
- 多模态数据的字典学习。