1.矩阵分解
1.模型结构
1.1 模型核心原理
矩阵分解的核心思想是:每一个用户和每一个物品,都可以映射到一个低维的隐空间(Latent Space)中。
假设我们有 $m$ 个用户和 $n$ 个物品,交互矩阵为 $R \in \mathbb{R}^{m \times n}$。
由于用户不可能消费所有物品,$R$ 是极度稀疏的。我们将其分解为两个稠密的低维矩阵:
- 用户矩阵 $P \in \mathbb{R}^{m \times k}$:每一行 $p_u$ 是用户 $u$ 的隐向量。
- 物品矩阵 $Q \in \mathbb{R}^{n \times k}$:每一行 $q_i$ 是物品 $i$ 的隐向量。
预测公式:
其中 $k$ 是隐向量的维度(通常比 $m, n$ 小得多),代表了潜在的特征(如:电影的导演、风格、演员等,虽然这些特征是模型自动学习出的,并不一定具有直观语义)。
训练流程:如何学习 $P$ 和 $Q$
矩阵分解的训练本质上是一个优化问题,目标是让预测评分 $\hat{r}{ui}$ 尽可能接近真实评分 $r{ui}$。
第一步:初始化
随机初始化 $P$ 和 $Q$ 矩阵中的元素(通常服从均值为 0、方差较小的正态分布)。
第二步:定义损失函数
使用带有 L2 正则化的平方损失函数:
第三步:选择优化算法进行迭代
常用的优化方法有两种:
1. 随机梯度下降 (SGD)
- 流程: 遍历每一个已知的评分 $r{ui}$,计算误差 $e{ui} = r{ui} - \hat{r}{ui}$,然后根据梯度更新参数:
- 优点:实现简单,速度快,适合处理超大规模数据。
2. 交替最小二乘法 (ALS)
- 流程:由于 $P$ 和 $Q$ 同时变化时目标函数不是凸的,但如果固定 $Q$ 更新 $P$,或者固定 $P$ 更新 $Q$,问题就变成了线性最小二乘问题。
- 固定 $Q$,利用最小二乘法更新 $P$。
- 固定 $P$,利用最小二乘法更新 $Q$。
- 优点:适合并行化计算(Spark 默认实现),处理隐式反馈效果好。
1.2 损失函数表达式
在矩阵分解(Matrix Factorization)中,最常用的带 L2 正则化的平方损失函数为:
参数含义:
- $r_{ui}$:用户 $u$ 对物品 $i$ 的真实评分(Label)。
- $q_i^T p_u$:模型预估评分(Prediction)。
- $\lambda$:正则化系数(Hyperparameter),控制惩罚力度。
- $| \cdot |^2$:L2 范数(每个元素的平方和)。
2. 正则化项的作用
- 抑制过拟合 (Overfitting):
- 推荐数据极度稀疏,模型极易学习到噪声。
- L2 正则化通过惩罚大的参数值,降低模型复杂度,使模型不至于为了拟合个别样本而让向量波动剧烈。
- 提升数值稳定性:
- 在梯度下降过程中,防止权重更新过大导致梯度爆炸。
- 使目标函数变成严格凸函数(Strictly Convex),更容易收敛到稳定的局部最优解。
- 解决多重共线性:
- 当特征之间存在高度相关性时,正则化能有效约束参数空间。
3. L1 与 L2 正则化的对比
| 特性 | L1 正则化 (Lasso) | L2 正则化 (Ridge) |
|---|---|---|
| 惩罚项 | $\lambda \sum w_i $ | $\lambda \sum w_i^2$ |
| 效果 | 倾向于产生稀疏解(部分权重为0) | 倾向于产生稠密小值解 |
| 用途 | 特征选择(自动剔除无效特征) | 防止过拟合,保证模型稳定性 |
| 贝叶斯先验 | 拉普拉斯分布 (Laplace) | 高斯分布 (Gaussian) |
为什么是这样
从贝叶斯统计学的视角来看,正则化项本质上是我们在观测数据之前,对模型参数 $\theta$ 所抱有的先验假设 (Prior Assumption)。
1. 概率论背景:最大后验概率 (MAP)
模型学习的目标是最大化后验概率 $P(\theta|D)$。根据对数变换:
2. L2 正则化 <=> 高斯先验 (Gaussian Prior)
- 假设:每个参数 $w_i$ 独立同分布地服从 $N(0, \sigma^2)$。
- 推导: 高斯概率密度 取负对数得到
- 物理意义:高斯分布的曲线在 0 附近是平滑的。它告诉模型:参数值不应该太大,但它们可以均匀地分布在 0 附近,这导致了参数的整体缩小 (Weight Decay)。
3. L1 正则化 <=> 拉普拉斯先验 (Laplacian Prior)
- 假设:每个参数 $w_i$ 独立同分布地服从 $Laplace(0, b)$。
- 推导: 拉普拉斯概率密度 取负对数得到
- 物理意义:拉普拉斯分布在 $w=0$ 处有一个非常尖的峰(导数不连续)。这意味着模型有极高的概率预设参数就是 0,从而促使模型产生稀疏性 (Sparsity)。
4. 拓展:如何选择 $\lambda$?
- 交叉验证 (Cross-Validation):在验证集上观察不同 $\lambda$ 下的 RMSE/MAE。
- 经验法则:
- $\lambda$ 太小 $\rightarrow$ 模型依然过拟合(训练集效果好,测试集差)。
- $\lambda$ 太大 $\rightarrow$ 模型欠拟合(训练集和测试集效果都差)。
5. 工业实践演进
- Dropout:深度学习时代最常用的正则化手段,通过随机关闭神经元实现。
- Early Stopping:在验证集性能不再提升时提前停止训练。
- Embedding Normalization:在双塔模型中,对输出的向量进行 $L_2$ 归一化,使其映射到单位球面上,这可以看作是一种隐式的硬正则化。
2.FunkSVD 与传统 SVD
1. 传统 SVD 的“数学困境”
在数学定义中,奇异值分解(Singular Value Decomposition)将矩阵 $M$ 分解为 $U\Sigma V^T$。
- 硬性要求:矩阵 $M$ 必须是稠密(Dense)的。
- 推荐系统的现实:用户-物品矩阵 $R$ 极其稀疏(99% 为空)。
- 后果:为了使用传统 SVD,你必须对缺失值进行填充(Imputation),如填充 0 或均值。这会导致矩阵体积爆炸,且引入的伪造数据会严重干扰预测精度。
2. FunkSVD 的“工程智慧”
由 Simon Funk 提出,它跳出了“分解”的数学框架,转而使用“拟合”的机器学习框架。
- 核心逻辑:不再追求完美的数学分解,而是定义一个损失函数,只看已有的评分。
- 预测公式:$\hat{r}_{ui} = p_u \cdot q_i^T$
- 损失函数:
注意:求和只针对 $\text{Observed}$(已观测到的数据),这完美解决了稀疏性问题。
训练过程
FunkSVD 的训练是一个基于 SGD(随机梯度下降) 的迭代过程,主要分为以下四个步骤:
第一步:参数初始化 (Initialization)
- 随机初始化矩阵 $P$ 和 $Q$。
- 通常使用均值为 0、方差较小的正态分布(如 $N(0, 0.1)$)。初始值不宜过大,否则内积结果容易爆炸,导致模型不收敛。
第二步:定义损失函数 (Loss Function)
- 目标:让预测评分尽可能接近真实评分,同时防止过拟合。
- 公式:
核心注意点:求和符号 $\sum$ 只针对已有的(非空)评分数据进行计算。
第三步:执行随机梯度下降 (Optimization via SGD)
- 流程:遍历训练集中的每一个三元组 $(u, i, r_{ui})$。
- 计算误差:$e{ui} = r{ui} - \hat{r}_{ui}$。
- 梯度更新:根据损失函数对参数求偏导,得到更新公式: 其中 $\eta$ 是学习率(Learning Rate)。
第四步:收敛与存储
- 重复迭代(Epochs),直到损失函数不再下降或达到预设次数。
- 训练完成后,丢弃原始稀疏矩阵,只保留稠密的 $P$ 和 $Q$ 矩阵。
3.知识点讲解:随机梯度下降(SGD)优化矩阵分解
矩阵分解(MF)的训练目标是找到最优的用户隐向量 $p_u$ 和物品隐向量 $q_i$。由于目标函数通常不是简单的凸函数,我们采用随机梯度下降(SGD)这一迭代算法来寻找局部最优解。
1. 损失函数定义 (Loss Function)
为了保证模型既能拟合训练数据,又具备泛化能力,我们定义单个样本 $(u, i)$ 的损失函数如下:
其中:
- $r{ui}$ 是真实评分,$\hat{r}{ui} = p_u \cdot q_i^T$ 是模型预测评分。
- $\lambda (|p_u|^2 + |q_i|^2)$ 是 L2 正则化项,防止隐向量数值过大导致过拟合。
2. 参数更新公式推导 (Derivation)
我们需要通过求导找到损失函数下降最快的方向(负梯度方向)。
第一步:求偏导数
利用链式法则,分别对变量 $p_u$ 和 $q_i$ 求偏导:
对 $p_u$ 求偏导:
对 $q_i$ 求偏导:
第二步:参数更新
根据梯度下降公式 $\theta \leftarrow \theta - \eta \frac{\partial L}{\partial \theta}$(其中 $\eta$ 为学习率),我们将常数项 $2$ 合并到学习率中,得到最终更新公式:
- 用户向量更新:
- 物品向量更新:
3. 算法执行流程
- 初始化:随机初始化矩阵 $P$ 和 $Q$。
- 洗牌 (Shuffle):打乱训练集中三元组 $(u, i, r_{ui})$ 的顺序,防止模型产生周期性震荡。
- 迭代更新:遍历每个样本,计算误差并根据上述公式立即更新对应的 $p_u$ 和 $q_i$。
- 收敛检查:检查全量损失是否稳定或验证集指标是否下降。
4. 完整笔记与面试避坑
| 核心问题 | 关键答案 |
|---|---|
| 为什么叫“随机”? | 因为它不像批量梯度下降 (BGD) 那样计算所有样本的梯度,而是每看到一个样本就更新一次参数。 |
| 学习率 $\eta$ 的作用? | 步长。太大容易越过最优解(不收敛),太小收敛速度极慢。 |
| 正则化 $\lambda$ 的意义? | 相当于给隐向量戴上“枷锁”,强制它们不要为了拟合单一噪声而变得过大。 |
| SGD vs ALS? | SGD 在非凸问题上更灵活;ALS 在分布式场景(并行计算)下效率更高。 |
5. 拓展:工业界常见的优化变体
- Momentum (动量法):引入前一次更新的方向,帮助模型冲出“鞍点”或局部极小值。
- Adam (自适应矩估计):为每个参数动态调整学习率,是目前最常用的优化器。
- Bias-SVD:在更新公式中增加对 $b_u, b_i$(偏置项)的导数更新。