使用TensorFlow Recommenders适配自定义数据集时准确率极低求助
针对你遇到的自定义数据集准确率从0.27骤降到0.0027的问题,结合你提供的代码,从以下核心方向逐一排查:
一、数据集处理环节的关键问题
候选集重复导致指标计算失效
你主模型中FactorizedTopK的候选集用的是movies.batch(128).map(self.candidate_model),而movies是采样后所有交互记录中的电影标题(包含大量重复),这会导致候选集充斥重复的embedding,完全打乱TopK指标的计算逻辑——模型即使学到有效特征,也会因为候选集的重复项干扰,输出随机结果。
正确做法是用唯一电影标题生成候选集:# 替换原候选集代码 unique_movies = tf.data.Dataset.from_tensor_slices(unique_movie_titles) self.task = tfrs.tasks.Retrieval( metrics=tfrs.metrics.FactorizedTopK( candidates=unique_movies.batch(128).map(self.candidate_model), ), )数据集采样与分布异常
先确认采样后的数据集分布:print(combined_dataset.nunique())如果输出中
user_id或movie_title的数量极少(比如用户数1万、电影数5千),Top10的随机准确率基线约为0.002,和你的0.0027接近,说明模型完全没学到有效特征,大概率是数据分布过偏或预处理出错。
另外,检查movies_metadata的id列是否存在脏数据(比如非数值字符串、NaN),转成str后可能导致合并后的有效交互记录大幅减少,模型无足够数据学习。
二、MovieModel实现的潜在问题
TextVectorizer适配时机与逻辑
你在MovieModel的__init__中调用self.title_vectorizer.adapt(movies),这会在模型初始化时就完成适配,但如果movies是包含重复标题的数据集,vectorizer的词汇表可能冗余。另外,若验证集中存在不在unique_movie_titles中的标题,StringLookup会将其映射到OOV位置,导致embedding无效。
建议先对movies去重后再适配vectorizer:unique_movies_ds = tf.data.Dataset.from_tensor_slices(unique_movie_titles) self.title_vectorizer.adapt(unique_movies_ds)Embedding分支的有效性验证
快速验证MovieModel的输出是否合理:movie_model = MovieModel() test_input = tf.constant(["Toy Story"]) embedding_output = movie_model(test_input) print(embedding_output.numpy())如果输出全为0或随机噪声,说明某一分支(比如文本embedding)失效,可暂时去掉
title_text_embedding分支,只用title_embedding训练,看准确率是否回升——若回升,再排查文本embedding的vectorizer或池化层配置。
三、主模型与训练配置问题
QueryModel的timestamp特征处理
你在QueryModel中使用了timestamp特征,但如果直接传入原始的时间戳整数(数值极大),模型无法学到有效时序特征,导致用户表征失效。需先对timestamp做归一化处理:# 在QueryModel的call方法中添加 timestamp = tf.cast(inputs["timestamp"], tf.float32) # 转成相对时间(比如除以1e9转成秒级,或归一化到0-1区间) normalized_timestamp = timestamp / 1e9训练配置的合理性
若你修改了原教程的训练参数,会导致模型无法收敛:- 建议使用原教程的优化器配置:
tf.keras.optimizers.Adam(learning_rate=0.01) - 确保epochs设置足够(至少20-30轮),同时加入早停机制防止过拟合
- 检查训练/验证集的划分逻辑,避免验证集与训练集分布差异过大
- 建议使用原教程的优化器配置:
四、环境与代码版本问题
你提到之前成功适配过,需排查:
- 是否修改了数据集路径、采样比例或预处理逻辑?比如之前采样100万数据,现在改为10万,导致数据分布剧变
- TensorFlow或TFRS的版本是否更新?不同版本的API可能存在兼容性问题(比如
StringLookup的mask_token逻辑变化) - 是否误改了QueryModel的代码?比如用户embedding的维度设置错误、特征传入缺失等
内容的提问来源于stack exchange,提问作者Denisa Birisan

