Tensorflow:如何查找和平均每个训练实例不同数量的嵌入向量,每个小批量有多个训练实例?

数据挖掘 张量流 嵌入
2021-10-10 14:39:31

在推荐系统设置中:假设我想学习使用受Youtube 推荐系统启发的方法根据用户过去的购买来预测未来的物品购买:

在此处输入图像描述

具体来说,假设我有一个可训练的基于内容的网络,它接收一个项目作为输入,并根据其内容返回该项目的嵌入。现在,假设每个用户过去购买了可变数量的商品(一些用户可能购买了 5 件商品,其他人可能购买了 1 件,其他人可能购买了 10 件,一些异常值可能购买了 100 件,等等)。我想生成一个用户向量,一个候选项目向量,然后是一个用户项目匹配分数,如下所示:

  1. 我使用可训练的基于内容的网络将该用户购买的每个项目映射到其嵌入的项目向量
  2. 我计算所有嵌入项目向量的平均值(如图所示)
  3. 我在这个平均值之上应用了几个 ReLu 层,从而获得了一个用户向量
  4. 我使用与步骤 1 相同的可训练的基于内容的网络将候选项目(要推荐)映射到其嵌入的项目向量(这个网络的权重总是共享的,可以说是连体网络)
  5. 最后,我计算用户向量和候选项目向量之间的点积,在训练期间应用交叉熵损失等。

所以我的问题是关于如何使用 Tensorflow 实现嵌入查找和平均每个用户的可变数量嵌入项目向量的技术细节,考虑到在训练期间每个小批量可能包含许多训练实例,其中每个训练实例可能包含不同用户在过去购买了不同数量的商品。虽然上下文不同,但我的问题与这个问题非常相似,但不幸的是,到目前为止还没有人回答这个问题。

1个回答

使用tf.gather().

单例案例

在下面的示例中,我们从矩阵中选择了可变数量的嵌入向量embedding选择索引向量user可以是可变长度的。然后我们计算平均嵌入。


使用 tf.Graph().as_default():
    嵌入 = tf.placeholder(shape=[10,3], dtype=tf.float32)
    用户 = tf.placeholder(形状=无,dtype=tf.int32)
    selected = tf.gather(嵌入,用户)
    平均值 = tf.reduce_mean(选定,轴 = 0)

    使用 tf.Session() 作为 sess:
        sess.run(tf.global_variables_initializer())
        embedding_ = np.random.randn(10,3)
        user_ = [1,3,5]
        打印(sess.run(平均, feed_dict={embedding:embedding_, user:user_}))
        打印(np.mean(嵌入_[用户_],轴=0))

小批量中的多个实例

您可以手动将第一个向量指定embedding为零向量,并用 0 修补上述selection向量。例如

使用 tf.Graph().as_default():
    嵌入 = tf.placeholder(shape=[10,3], dtype=tf.float32)
    user = tf.placeholder(shape=[None, None], dtype=tf.int32)
    selected = tf.gather(嵌入,用户)
    non_zero_count = tf.cast(tf.count_nonzero(user, axis=1), tf.float32)
    embedding_sum = tf.reduce_sum(selected, axis=1)
    平均值 = embedding_sum / tf.expand_dims(non_zero_count, axis=1)

    使用 tf.Session() 作为 sess:
        sess.run(tf.global_variables_initializer())
        embedding_ = np.concatenate([np.zeros((1,3)),np.random.randn(9,3)],axis=0)
        user_ = [[3,5,7,0], [1,2,0,0]]
        打印(sess.run(平均, feed_dict={embedding:embedding_, user:user_}))
        print(np.sum([embedding_[i] for i in user_], axis=1) / np.atleast_2d(np.count_nonzero(user_, axis=1)).T)

tf.gather()即使embedding是可训练变量而不是占位符,您也可以这样使用。