张量的 CP 分解(CANDECOMP/PARAFAC 分解)是将一个高阶张量表示为若干个秩一张量(rank-one tensor)的和,是张量分解中最常用的一种方法,类似于矩阵的 SVD 分解。下面是详细的步骤和基本概念。
💡 CP 分解简介
对一个 $N$ 阶张量 $\mathcal{X} \in \mathbb{R}^{I_1 \times I_2 \times \dots \times I_N}$,CP 分解的目标是找到 $R$ 个秩一张量,使得:
$
\mathcal{X} \approx \sum_{r=1}^R \lambda_r \cdot a^{(1)}_r \circ a^{(2)}_r \circ \cdots \circ a^{(N)}_r
$
其中:
- $a^{(n)}_r \in \mathbb{R}^{I_n}$ 是第 $n$ 模的因子向量(component)。
- “$\circ$” 表示外积。
- $\lambda_r$ 是第 $r$ 个秩一张量的权重(有时省略)。
最终得到的因子矩阵为:
- $A^{(1)} \in \mathbb{R}^{I_1 \times R}$
- $A^{(2)} \in \mathbb{R}^{I_2 \times R}$
- …
- $A^{(N)} \in \mathbb{R}^{I_N \times R}$
🚀 CP 分解的实现方法
1. 基于 ALS(交替最小二乘法)
最常用的算法是 Alternating Least Squares (ALS),基本思想是固定其它模,只优化一个模,交替更新。
步骤如下:
- 初始化每个模的因子矩阵(通常是随机或基于 SVD)。
- 选择一个模 $n$,固定其它模,最小化误差:
$
\min_{A^{(n)}} \left| \mathcal{X}_{(n)} - A^{(n)} \left( A^{(N)} \odot \cdots \odot A^{(n+1)} \odot A^{(n-1)} \odot \cdots \odot A^{(1)} \right)^T \right|_F^2
$- 这里 $\mathcal{X}_{(n)}$ 是张量沿第 $n$ 维的展开(矩阵化)
- $\odot$ 是 Khatri-Rao 积(列式 Kronecker 积)
- 重复对每个模更新,直到收敛(如误差变化小于阈值)。
🧪 Python 示例(使用 tensorly
库)
import tensorly as tl
from tensorly.decomposition import parafac
import numpy as np
# 创建一个随机三阶张量
tensor = tl.tensor(np.random.random((30, 40, 50)))
# 设定分解秩 R
rank = 5
# 进行 CP 分解
factors = parafac(tensor, rank=rank)
# 输出分解得到的因子矩阵
for i, factor in enumerate(factors.factors):
print(f"Factor matrix {i+1}: shape = {factor.shape}")
📌 注意事项
- 选择合适的秩 $R$ 很关键,太小表示能力不足,太大容易过拟合。
- 可以使用 explained variance 或 残差分析 来选取秩。
- CP 分解不唯一:可能存在多个局部最优解。
- 对稀疏张量可使用稀疏优化版本。
如果你有具体数据、模型或者想应用在某种实际问题(如推荐系统、信号处理等),我可以帮你更具体地实现。需要的话也可以帮你用中文详细讲解各个步骤。你有想要应用 CP 分解的具体场景吗?