使用带上下文特征的TensorFlow Recommenders模型实现预测的问题咨询
问题解答
1. 带上下文特征的TFRS预测方案
该场景完全可实现,核心要求是query模型使用Keras Functional API定义,而非Sequential模型。Sequential仅支持单张量输入,无法直接接收多特征的字典输入,这也是后续字典输入警告的根本原因。用Functional API定义接收user_id+weekday(星期几)字段的query模型,即可实现组合特征的分值预测。
2. BruteForce层的正确传参方式
'CacheDataset' object is not subscriptable错误的触发原因是直接将Dataset对象传入了BruteForce层的call方法,BruteForce层不接收Dataset类型的输入,仅支持批次化的张量/张量字典作为输入。
循环遍历Dataset批次的写法是完全可用的,警告的来源是query_model采用了Sequential定义,改为Functional API支持字典输入后警告会自动消失。
如果不想循环也可以一次性传入全量测试数据:把整个测试集的特征拼接为一个字典张量即可,示例代码:
# 合并整个测试集为一个字典 test_data = { "user_id": tf.concat([b["user_id"] for b in cached_test], axis=0), "weekday": tf.concat([b["weekday"] for b in cached_test], axis=0) } # 一次性得到所有query的top10结果 scores, titles = index(test_data, k=10)
3. model.predict的问题修正
存在的问题
- 矩阵乘法参数错误:使用
transpose_a=True时,(bs, 32)的query embedding转置为(32, bs),和(bs,32)的正例物品embedding相乘得到(32,32)的结果,完全不符合预期。输出中的160维度是测试集的batch size,和计算逻辑错误叠加才得到了异常的输出shape。 - 调用candidate_model时使用了输入中的
movie_title(即每个样本对应的正例物品)来计算embedding,只能得到每个query和对应正例的相似度,无法得到全量物品的预测分值。
正确实现
首先提前计算全量候选物品的embedding矩阵,再改写call方法计算每个query对全量物品的分值:
# 第一步:预计算全量候选物品的embedding,假设共有1425个物品 all_item_embs = tf.concat([ model.candidate_model(batch["movie_title"]) for batch in movies.batch(200) ], axis=0) # 输出shape为(1425, 32) # 第二步:改写模型call方法 def call(self, inputs): query_embeddings = self.query_model({ "user_id": inputs["user_id"], "weekday": inputs["weekday"], }) # 转置候选embedding的第二维度,得到每个query对全量物品的分值 return tf.matmul(query_embeddings, all_item_embs, transpose_b=True) # 第三步:预测得到全量分值矩阵,输出shape为(测试样本数, 1425) pred_scores = model.predict(cached_test)
调试器无法进入call方法的问题,是因为model.predict默认运行在图模式下,添加参数run_eagerly=True即可触发eager执行进入断点:model.predict(cached_test, run_eagerly=True)。
4. 方案合理性说明
两种思路都是合理的,没有方向性错误:
- 如果仅需要TopK推荐结果用于召回类指标计算,用BruteForce层效率更高;
- 如果需要全量用户-物品的预测分值来计算自定义指标,用
model.predict的方案更合适。
之前遗漏的核心逻辑只有两点:一是query模型要使用Functional API支持多特征输入,二是计算全量分值时需要预先生成全量候选物品的embedding矩阵,而非使用输入中的正例物品特征。
内容的提问来源于stack exchange,提问作者tomdalonge
相关产品推荐
相关产品推荐

