You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何用TensorFlow 2实现稀疏矩阵的简易Matrix Factorization?

当然可以!你的代码已经为稀疏矩阵的基础矩阵分解打下了很好的基础,接下来我会帮你完善整个实现流程,让它可以直接运行,同时针对loss function、优化器和学习率调度给出具体方案。

核心思路回顾

你要实现的是经典的低秩矩阵分解:用低维度的嵌入矩阵U(用户/行侧)和V(物品/列侧)的内积去拟合稀疏矩阵A的已知元素。你的损失函数sparse_mean_square_error完全正确——只针对A中存在的非零元素计算均方误差,这是稀疏矩阵分解的标准做法,避免了处理大量零元素的冗余计算。

完整可运行实现

下面是补全后的代码,包含所有必要的组件:

1. 导入依赖库

import tensorflow as tf
import pandas as pd
import numpy as np

2. 补全变量定义与初始化

你代码里的embeddings(嵌入维度)和init_stddev(初始化标准差)需要明确赋值,这里我们选常用的参数:

# 超参数设置
embeddings = 32  # 低秩嵌入的维度,可根据数据规模调整
init_stddev = 0.1  # 初始化标准差,避免初始值过大

# 你的原有代码(补全变量逻辑)
def build_rating_sparse_tensor(ratings):
    indices = ratings[['U_num', 'V_num']].values
    values = ratings['rating'].values
    return tf.SparseTensor(
        indices=indices,
        values=values,
        dense_shape=[ratings.U_num.max()+1, ratings.V_num.max()+1])

# 创建稀疏矩阵A的玩具数据集
ratings = (pd.DataFrame({'U_num': list(range(0,10_000))*30, 'V_num': list(range(0,60_000))*5, 'rating': np.random.randint(6, size=300_000)})
          .sample(1000)
          .drop_duplicates(subset=['U_num','V_num'])
          .sort_values(['U_num','V_num'], ascending=[1,1]))

A = build_rating_sparse_tensor(ratings)
# 初始化U和V:U对应行嵌入,V对应列嵌入,形状适配后续内积计算
U = tf.Variable(tf.random.normal([A.dense_shape[0], embeddings], stddev=init_stddev))
V = tf.Variable(tf.random.normal([A.dense_shape[1], embeddings], stddev=init_stddev))

3. 损失函数(保留你的实现,可选加正则化)

为了防止过拟合,我们可以给损失函数加上L2正则化,约束U和V的嵌入范数:

def sparse_mean_square_error(sparse_ratings, user_embeddings, item_embeddings, l2_reg=1e-4):
    # 提取对应位置的嵌入向量,计算内积得到预测值
    user_embed = tf.gather(user_embeddings, sparse_ratings.indices[:, 0])
    item_embed = tf.gather(item_embeddings, sparse_ratings.indices[:, 1])
    predictions = tf.reduce_sum(user_embed * item_embed, axis=1)
    
    # 基础MSE损失
    mse_loss = tf.losses.mean_squared_error(sparse_ratings.values, predictions)
    
    # L2正则化损失(可选,防止嵌入向量过度膨胀)
    reg_loss = l2_reg * (tf.reduce_mean(tf.norm(user_embeddings, axis=1)) + tf.reduce_mean(tf.norm(item_embeddings, axis=1)))
    
    return mse_loss + reg_loss

4. 优化器与学习率调度

选择合适的优化器(Adam是最省心的选择),并搭配学习率衰减来提升训练稳定性:

# 学习率调度:指数衰减,初始学习率0.01,每1000步衰减为原来的0.96
lr_schedule = tf.keras.optimizers.schedules.ExponentialDecay(
    initial_learning_rate=0.01,
    decay_steps=1000,
    decay_rate=0.96,
    staircase=True)

# 选择优化器:Adam自适应调整学习率,适合大多数场景
optimizer = tf.keras.optimizers.Adam(learning_rate=lr_schedule)
# 如果偏好SGD也可以尝试:optimizer = tf.keras.optimizers.SGD(learning_rate=lr_schedule, momentum=0.9)

5. 训练循环

实现简单的训练流程,迭代更新U和V:

epochs = 500  # 训练轮数
for epoch in range(epochs):
    with tf.GradientTape() as tape:
        loss = sparse_mean_square_error(A, U, V)
    
    # 计算梯度并更新参数
    gradients = tape.gradient(loss, [U, V])
    optimizer.apply_gradients(zip(gradients, [U, V]))
    
    # 每50轮打印一次损失,监控训练进度
    if (epoch + 1) % 50 == 0:
        print(f"Epoch {epoch+1}, Loss: {loss.numpy():.4f}")

6. 验证训练结果

训练完成后,可以随机选取几个已知元素,对比预测值和真实值:

# 随机选5个样本验证
sample_indices = np.random.choice(len(A.indices), 5)
for idx in sample_indices:
    u_idx, v_idx = A.indices[idx]
    true_rating = A.values[idx]
    pred_rating = tf.reduce_sum(U[u_idx] * V[v_idx]).numpy()
    print(f"Row {u_idx}, Column {v_idx}: True Value={true_rating}, Predicted Value={pred_rating:.2f}")

关键组件说明

  • Loss Function:你原本的MSE损失完全适用,加上L2正则化可以有效防止过拟合(尤其是当嵌入维度较大时)。
  • Optimizer:Adam优化器自适应调整学习率,无需手动调参,适合快速上手;带动量的SGD则适合需要更精细控制收敛过程的场景。
  • Learning Rate Schedule:指数衰减的学习率能让模型在训练初期快速收敛,后期稳定调整参数,避免损失值震荡。

额外优化建议

  • 批量训练:如果你的稀疏矩阵规模极大,可以将稀疏元素分成小批量,每次只计算一个批次的损失,大幅提升训练效率。
  • 初始化策略:除了正态分布初始化,也可以尝试tf.keras.initializers.GlorotUniform()(Xavier初始化),让嵌入的初始分布更合理。
  • 早停机制:当验证集损失不再下降时提前停止训练,避免过拟合(可以拆分一部分数据作为验证集)。

内容的提问来源于stack exchange,提问作者Matias Eiletz

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.09 18:47:50