问题描述
我一直在寻找如何对这个非常简单和基本的情况执行矩阵分解的方法,但没有发现任何东西。我只找到了复杂而长久的解决方案,所以我将介绍我要解决的问题:
U x V = A
我只想知道如何在Tensorflow 2中求解该方程,即已知的稀疏矩阵 A 以及 U 和 V 两个随机初始化的矩阵。所以我想找到U和V,使它们的乘积近似等于A。
例如,具有以下变量:
# I use this function to build a toy dataset for the sparse matrix
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])
# here I create what will be the matrix 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]))
# Variables
A = build_rating_sparse_tensor(ratings)
U = tf.Variable(tf.random_normal(
[A_Sparse.shape[0],embeddings],stddev=init_stddev))
# this matrix would be transposed in the equation
V = tf.Variable(tf.random_normal(
[A_Sparse.shape[1],stddev=init_stddev))
# loss function
def sparse_mean_square_error(sparse_ratings,user_embeddings,movie_embeddings):
predictions = tf.reduce_sum(
tf.gather(user_embeddings,sparse_ratings.indices[:,0]) *
tf.gather(movie_embeddings,1]),axis=1)
loss = tf.losses.mean_squared_error(sparse_ratings.values,predictions)
return loss
是否可以使用特定的损失函数,优化程序和学习时间表来做到这一点?
非常感谢您。
解决方法
使用TensorFlow 2的天真而直接的方法
请注意,等级已转换为float32。 TensorFlow无法计算整数上的梯度,请参见https://github.com/tensorflow/tensorflow/issues/20524。
A = build_rating_sparse_tensor(ratings)
indices = ratings[["U_num","V_num"]].values
embeddings = 3000
U = tf.Variable(tf.random.normal([A.shape[0],embeddings]),dtype=tf.float32)
V = tf.Variable(tf.random.normal([embeddings,A.shape[1]]),dtype=tf.float32)
optimizer = tf.optimizers.Adam()
trainable_weights = [U,V]
for step in range(100):
with tf.GradientTape() as tape:
A_prime = tf.matmul(U,V)
# indexing the result based on the indices of A that contain a value
A_prime_sparse = tf.gather(
tf.reshape(A_prime,[-1]),indices[:,0] * tf.shape(A_prime)[1] + indices[:,1],)
loss = tf.reduce_sum(tf.metrics.mean_squared_error(A_prime_sparse,A.values))
grads = tape.gradient(loss,trainable_weights)
optimizer.apply_gradients(zip(grads,trainable_weights))
if step % 20 == 0:
print(f"Training loss at step {step}: {loss:.4f}")
我们仅通过计算A的实际值上的损失来利用A的稀疏性。但是,我们仍然必须为可训练的权重U
和V
分配两个非常大的密集张量。对于像您的示例这样的大数字,您可能会遇到一些OOM错误。
也许值得为您的数据探索另一种表示形式。