设备端推荐的自适应框架
2021 年 4 月 29 日

发布者:Ellie Zhou、Tian Lin、Shuangfeng Li 和 Sushant Prakash

简介及动机

我们很高兴地宣布一个自适应框架,用于使用您自己的数据和高级用户建模架构构建设备端推荐 ML 解决方案。

在之前开源的 设备端推荐解决方案 之后,我们收到了社区许多关于在设备端引入推荐 AI 的兴趣。在反馈的推动和启发下,我们考虑了各种用例,并创建了一个能够生成 TensorFlow Lite 推荐模型的框架,该框架可以适应不同类型的数据、特征和架构,从而改进以前的模型。

此框架的优势

  • 灵活:自适应框架允许用户以可配置的方式创建模型。
  • 更好的模型表示:为了改进 之前的模型,我们的新推荐模型可以使用多种类型的特征,而不仅仅是一个特征。

如今,个性化推荐在数字生活中发挥着越来越重要的作用。随着越来越多的用户行为转移到边缘设备,在设备端支持推荐器成为一个重要的方向。与传统的纯服务器端推荐器相比,设备端解决方案具有独特的优势,例如保护用户隐私、快速响应设备端用户行为、利用轻量级的 TensorFlow Lite 推理以及绕过网络依赖。我们欢迎您尝试这个 框架 并在您的应用程序中创建推荐体验。

在本文中,我们将

  • 介绍改进后的模型架构和框架自适应性。
  • 逐步指导您如何使用该框架。
  • 提供基于使用公共数据集进行的研究的见解。

请在 TensorFlow 网站 上找到更多详细信息。

模型

推荐模型通常会根据用户的先前活动来预测用户的未来活动。我们的框架支持使用上下文信息来进行预测的模型,这可以用以下架构来描述

recommendation code structure
图 1:可配置推荐模型的示意图。每个模块都是根据用户定义的配置创建的。

在上下文侧,所有用户活动的表示通过编码器聚合以生成上下文嵌入。我们支持三种不同类型的编码器:1)词袋(也称为 BOW),2)一维卷积(也称为 CNN),以及 3)LSTM。 在标签侧,标签项将被编码为正向量,而词汇表中的所有其他项将被编码为负向量。上下文嵌入和标签嵌入通过点积进行组合,并馈送到 softmax 交叉熵损失函数。

在框架内,我们将 tf.keras 层封装为 ContextEncoder、LabelEncoder 和 DotProductSimilarity,作为 RecommendationModel 中的关键组件。

为了对每个用户活动进行建模,我们可以使用活动的项目 ID(称为基于 ID 的),或者项目的多个特征(称为基于特征的),或者两者结合。基于特征的模型利用多个特征来共同编码用户的行为。使用我们的框架,您可以以可配置的方式创建基于 ID 的模型或基于特征的模型。

与最后一个版本类似,在训练后将导出一个 TensorFlow Lite 模型,该模型可以直接在推荐候选集中提供前 K 个预测。

逐步操作

为了演示新的自适应框架,我们使用 MovieLens 数据集训练了一个使用多个特征的设备端电影推荐模型,并将其集成到演示应用程序中。(该模型和应用程序仅用于演示目的。)MovieLens 1M 数据集包含来自 6039 名用户对 3951 部电影的评分,每个用户只对电影的一小部分进行评分。

让我们看看如何在该 笔记本 中逐步使用该框架。

(a) 环境准备

git clone https://github.com/tensorflow/examples
cd examples/lite/examples/recommendation/ml/
pip install -r requirements.txt

(b) 准备训练数据

请参考 movielens 示例生成文件准备您的训练数据。请注意,TensorFlow Lite 输入特征应为 FixedLenFeature,请填充或截断您的特征,并在输入配置中设置特征长度。您可以使用以下命令来处理示例数据集。

python -m data.example_generation_movielens \
 --data_dir=data/raw \
 --output_dir=data/examples \
 --min_timeline_length=3 \
 --max_context_length=10 \
 --max_context_movie_genre_length=32 \
 --min_rating=2 \
 --train_data_fraction=0.9 \
 --build_vocabs=True

MovieLens 数据包含 ratings.dat(列:UserIDMovieIDRatingTimestamp)和 movies.dat(列:MovieIDTitleGenres)。示例生成脚本将同时使用这两个文件,只保留高于 2 的评分,形成用户电影交互时间线,将活动样本作为标签,并将先前的用户活动作为预测的上下文。请找到生成的 tf.Example

0 : {
  features: {
    feature: {
      key  : "context_movie_id"
      value: { int64_list: { value: [ 1124, 2240, 3251, ..., 1268 ] } }
    }
    feature: {
      key  : "context_movie_rating"
      value: { float_list: {value: [ 3.0, 3.0, 4.0, ..., 3.0 ] } }
    }
    feature: {
      key  : "context_movie_year"
      value: { int64_list: { value: [ 1981, 1980, 1985, ..., 1990 ] } }
    }
    feature: {
      key  : "context_movie_id"
      value: { int64_list: { value: [ 1124, 2240, 3251, ..., 1268 ] } }
    }
    feature: {
      key  : "context_movie_genre"
      value: { bytes_list: { value: [ "Drama", "Drama", "Mystery", ..., "UNK" ] } }
    }
    feature: {
      key  : "label_movie_id"
      value: { int64_list: { value: [ 3252 ] }  }
    }
  }
}

(c) 创建输入配置

数据准备完成后,请设置输入配置,例如,这是 movielens 电影推荐模型的一个示例配置。

activity_feature_groups {
  features {
    feature_name: "context_movie_id"
    feature_type: INT
    vocab_size: 3953
    embedding_dim: 8
    feature_length: 10
  }
  features {
    feature_name: "context_movie_rating"
    feature_type: FLOAT
    feature_length: 10
  }
  encoder_type: CNN
}
activity_feature_groups {
  features {
    feature_name: "context_movie_genre"
    feature_type: STRING
    vocab_name: "movie_genre_vocab.txt"
    vocab_size: 19
    embedding_dim: 4
    feature_length: 32
  }
  encoder_type: CNN
}
label_feature {
  feature_name: "label_movie_id"
  feature_type: INT
  vocab_size: 3953
  embedding_dim: 8
  feature_length: 1
}

(d) 训练模型

模型训练器将根据输入配置构建推荐模型,并提供简单的界面。

python -m model.recommendation_model_launcher -- \
 --training_data_filepattern "data/examples/train_movielens_1m.tfrecord" \
 --testing_data_filepattern "data/examples/test_movielens_1m.tfrecord"\
 --model_dir "model/model_dir" \
 --vocab_dir "data/examples" \
 --input_config_file "configs/sample_input_config.pbtxt" \
 --batch_size 32 \
 --learning_rate 0.01 \
 --steps_per_epoch 2 \
 --num_epochs 2 \
 --num_eval_steps 2 \
 --run_mode "train_and_eval" \
 --gradient_clip_norm 1.0 \
 --num_predictions 10 \
 --hidden_layer_dims "32,32" \
 --eval_top_k "1,5" \
 --conv_num_filter_ratios "2,4" \
 --conv_kernel_size 4 \
 --lstm_num_units 16

在推荐模型内部,核心组件被封装为 keras 层 (context_encoder.pylabel_encoder.pydotproduct_similarity.py),每个组件都可以单独使用。下图说明了代码结构

An example of model architecture using context information to predict the next movie.
图 2:使用上下文信息预测下一部电影的模型架构示例。输入是(a)电影 ID、(b)评分和(c)类型的历史记录,如上面提到的配置中指定的那样。

使用该框架,您可以使用命令直接执行模型训练启动器

python -m model.recommendation_model_launcher \
 --input_config_file "configs/sample_input_config.pbtxt" \
 --vocab_dir "data/examples" \
 --run_mode "export" \
 --checkpoint_path "model/model_dir/ckpt-1000" \
 --num_predictions 10 \
 --hidden_layer_dims "32,32" \
 --conv_num_filter_ratios "2,4" \
 --conv_kernel_size 4 \
 --lstm_num_units 16

导出到 TensorFlow Lite 后的推理代码可以在 笔记本 中找到,我们建议读者查看其中的详细信息。

框架自适应性

我们的框架提供了一个 protobuf 接口,通过该接口可以配置特征组、类型和其他信息以相应地构建模型。使用该接口,您可以配置

  • 特征

    该框架将特征一般分为三种类型:整数字符串浮点数。将为整数和字符串特征创建嵌入空间,因此需要指定嵌入维度、词汇表名称和大小。浮点数特征值将直接使用。此外,对于设备端模型,我们建议使用固定长度特征,这些特征可以直接配置。

message Feature {
  optional string feature_name = 1;

  // Supported feature types: STRING, INT, FLOAT.
  optional FeatureType feature_type = 2;

  optional string vocab_name = 3;

  optional int64 vocab_size = 4;

  optional int64 embedding_dim = 5;

  optional int64 feature_length = 6;
}
  • 特征组

    一个用户活动的一个特征可能有多个值。例如,一部电影可能属于多个类别,每部电影将具有多个类型特征值。为了处理不同的特征形状,我们引入了“特征组”来将特征组合在一起。长度相同的特征可以放在同一个特征组中,以便一起编码。在输入配置中,您可以设置全局特征组和活动特征组。

message FeatureGroup {
  repeated Feature features = 1;

  // Supported encoder types: BOW, CNN, LSTM.
  optional EncoderType encoder_type = 2;
}
  • 输入配置

    您可以使用输入配置接口将所有特征和特征组设置在一起。

message InputConfig {
  repeated FeatureGroup global_feature_groups = 1;

  repeated FeatureGroup activity_feature_groups = 2;

  optional Feature label_feature = 3;
}

输入配置被 input_pipeline.pyrecommendation_model.py 用于将训练数据处理为 tf.data.Dataset,并相应地构建模型。在 ContexEncoder 中,将为所有特征组创建 FeatureGroupEncoders,并用于从输入特征计算特征组嵌入。串联的特征组嵌入将通过顶部隐藏层馈送,以获取最终的上下文嵌入。值得注意的是,最终的上下文嵌入和标签嵌入维度应相等。

请在附录部分查看使用不同输入配置生成的不同的模型图。

实验与分析

我们借此机会分析了基于 ID 的模型和基于特征的模型在各种配置下的性能,并提供了一些经验结果。

对于基于 ID 的模型,仅使用 movie_id 作为输入特征。对于基于特征的模型,同时使用 movie_idmovie_genre 特征。这两种类型的模型都使用 3 种编码器类型(BOW/CNN/LSTM)和 3 种上下文历史长度(10/50/100)进行实验。

Comparison between ID-based and Feature-based models.
基于 ID 的模型和基于特征的模型之间的比较。我们将它们在 BOW/CNN/LSTM 编码器和上下文历史长度 10/50/100 上进行比较。

由于 MovieLens 数据集是一个实验数据集,具有约 4000 个候选电影和 19 种电影类型,因此我们在实验中缩减了嵌入维度,以模拟生产场景。对于上面的实验结果图表,ID 嵌入维度设置为 8,电影类型嵌入维度设置为 4。如果我们以 context10_cnn 为例,基于特征的模型比基于 ID 的模型高出 58.6%。此外,平均结果显示,基于特征的模型优于基于 ID 的模型 48.35%。因此,在这种情况下,基于特征的模型优于基于 ID 的模型,因为 movie_genre 特征为模型引入了额外的信息。

此外,候选项目的底层特征通常具有更小的词汇量,因此也具有更小的嵌入空间。例如,电影类型词汇量远小于电影 ID 词汇量。在这种情况下,利用底层特征可以减少模型的内存大小,使其更适合设备端使用。

鸣谢

特别感谢李聪、Josh Gordon、Khanh LeViet‎、Arun Venkatesan 和 Lawrence Chan 为这项工作提供了宝贵的建议。

下一篇文章
Adaptive Framework for On-device Recommendation

作者:周艾莉、林田、李双峰 和 Sushant Prakash介绍与动机 我们很高兴宣布一个自适应框架,利用您自己的数据和先进的用户建模架构构建设备端推荐 ML 解决方案。在之前开源的 设备端推荐解决方案 之后,我们收到了社区关于在设备端推荐中引入...