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

基于自定义数据的TensorFlow推荐系统推荐结果超数据集范围问题

问题描述

使用自定义数据基于TensorFlow Recommenders搭建推荐系统时,出现推荐结果超出数据集可选范围的问题:数据集仅包含item 1、2、3,但系统推荐出了1、4、6、9等不存在的item。

环境配置:

  • Google Colab
  • Python 3.7.14
  • TensorFlow 2.10.0
  • tensorflow_recommenders 0.7.2

问题原因分析

  1. 训练数据输入顺序完全错误
    构建ratings数据集时使用了df[['item_id', 'user_id']].values,每个样本结构为[item_id, user_id],但模型compute_loss方法中错误地将features[0](实际是item_id)传给用户模型,features[1](实际是user_id)传给物品模型,导致模型训练的输入完全错位,学习到的embedding不符合预期。

  2. 推荐索引未绑定原始item_id
    调用index.index_from_dataset时仅传入了经过items_model处理后的embedding,未将原始item_id与embedding对应绑定。此时BruteForce层会把模型内部的词汇表索引(而非原始item_id)作为推荐结果返回,加上IntegerLookup默认的mask token(值为0)和OOV(未知)索引,就出现了不在数据集中的数值。

  3. IntegerLookup默认配置引入无效索引
    IntegerLookup默认会添加mask token和OOV索引,导致词汇表大小大于实际item数量,这些额外索引会被当作有效item返回。

解决方案

1. 修正训练数据输入顺序

调整ratings数据集的列顺序为[user_id, item_id],并修正模型compute_loss中的特征提取逻辑:

# 修正ratings数据集列顺序
ratings = tf.data.Dataset.from_tensor_slices(df[['user_id', 'item_id']].values)

# 修正模型compute_loss方法
def compute_loss(self, features: tf.Tensor, training=False) -> tf.Tensor:
    # features形状为(batch_size, 2),[:,0]是user_id,[:,1]是item_id
    user_embeddings = self.user_model(features[:, 0])
    item_embeddings = self.item_model(features[:, 1])
    return self.task(user_embeddings, item_embeddings)

2. 构建索引时绑定原始item_id

传入包含**(物品embedding, 原始item_id)**的数据集,确保返回结果为原始item_id:

# 构建包含embedding和原始item_id的索引数据集
index_dataset = items.batch(100).map(lambda x: (items_model(x), tf.squeeze(x, axis=1)))
# 传入索引
index.index_from_dataset(index_dataset)

3. 配置IntegerLookup禁用无效索引

由于item_id是已知离散值,禁用OOV和mask token,避免引入额外无效索引:

user_id_vocabulary = tf.keras.layers.IntegerLookup(num_oov_indices=0, mask_token=None)
# 仅传入user_id列适配词汇表
user_id_vocabulary.adapt(ratings.map(lambda x: x[0]))
 
items_vocabulary = tf.keras.layers.IntegerLookup(num_oov_indices=0, mask_token=None)
items_vocabulary.adapt(items)

完整修正代码

from typing import Dict, Text

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

import tensorflow_datasets as tfds
import tensorflow_recommenders as tfrs

DATA_URL = "sample.csv"
df = pd.read_csv(DATA_URL)

# 修正训练数据集列顺序
ratings = tf.data.Dataset.from_tensor_slices(df[['user_id', 'item_id']].values)
items = tf.data.Dataset.from_tensor_slices(df[['item_id']].values)

# 配置IntegerLookup,禁用OOV和mask token
user_id_vocabulary = tf.keras.layers.IntegerLookup(num_oov_indices=0, mask_token=None)
user_id_vocabulary.adapt(ratings.map(lambda x: x[0]))
 
items_vocabulary = tf.keras.layers.IntegerLookup(num_oov_indices=0, mask_token=None)
items_vocabulary.adapt(items)

class CustomModel(tfrs.Model):
  def __init__(
      self,
      user_model: tf.keras.Model,
      item_model: tf.keras.Model,
      task: tfrs.tasks.Retrieval):
    super().__init__()
    self.user_model = user_model
    self.item_model = item_model
    self.task = task

  def compute_loss(self, features: tf.Tensor, training=False) -> tf.Tensor:
    user_embeddings = self.user_model(features[:, 0])
    item_embeddings = self.item_model(features[:, 1])
    return self.task(user_embeddings, item_embeddings)

users_model = tf.keras.Sequential([
    user_id_vocabulary, 
    tf.keras.layers.Embedding(user_id_vocabulary.vocabulary_size(),64)
])
                           
items_model = tf.keras.Sequential([
    items_vocabulary,
    tf.keras.layers.Embedding(items_vocabulary.vocabulary_size(),64)
])
 
task = tfrs.tasks.Retrieval(metrics=tfrs.metrics.FactorizedTopK(
    items.batch(128).map(lambda x: items_model(x))))

model = CustomModel(users_model, items_model, task)
model.compile(optimizer=tf.keras.optimizers.Adagrad(0.5))
model.fit(ratings.batch(8), epochs=3)

# 构建绑定原始item_id的索引数据集
index = tfrs.layers.factorized_top_k.BruteForce(model.user_model)
index_dataset = items.batch(100).map(lambda x: (items_model(x), tf.squeeze(x, axis=1)))
index.index_from_dataset(index_dataset)

# 获取推荐结果
_, titles = index(np.array([1]))
print(f"Top 3 recommendations for user 1: {titles[0, :3]}")

# 打印所有推荐结果
titlesNumpy = titles.numpy()
for i in titlesNumpy[0]:
    print(i)

内容的提问来源于stack exchange,提问作者Fian Julio

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.16 13:15:21