🚀 免费试用 Zilliz Cloud,完全托管的 Milvus,体验 10 倍的性能提升!立即试用>

milvus-logo
LFAI
  • Home
  • Blog
  • 使用 Milvus 搭配 PaddlePaddle 加速推荐系统中候选对象的生成

使用 Milvus 搭配 PaddlePaddle 加速推荐系统中候选对象的生成

  • Scenarios
November 26, 2021
Yunmei

如果你有开发推荐系统的经验,你很可能至少遇到过以下情况之一:

  • 由于数据集数量巨大,系统返回结果的速度极慢。
  • 无法实时处理新插入的数据以进行搜索或查询。
  • 推荐系统的部署令人望而生畏。

本文旨在通过介绍一个产品推荐系统项目,使用开源向量数据库 Milvus 搭配深度学习平台 PaddlePaddle,解决上述问题,并为大家提供一些启示。

本文首先简要介绍了推荐系统的基本工作流程。然后介绍该项目的主要组件和实施细节。

推荐系统的基本工作流程

在深入探讨项目本身之前,让我们先来看看推荐系统的基本工作流程。推荐系统可以根据用户独特的兴趣和需求返回个性化的结果。要实现这种个性化推荐,系统需要经历候选生成和排序两个阶段。

2.png 2.png

第一阶段是候选生成,返回最相关或最相似的数据,如符合用户配置文件的产品或视频。在生成候选数据的过程中,系统会将用户特征与数据库中存储的数据进行比较,并检索出相似的数据。然后在排序过程中,系统对检索到的数据进行评分和重新排序。最后,列表顶部的结果会显示给用户。

以我们的产品推荐系统为例,它首先将用户资料与库存产品的特征进行比较,筛选出符合用户需求的产品列表。然后,系统根据产品与用户资料的相似度对产品进行评分、排序,最后将前 10 种产品返回给用户。

3.png 3.png

系统架构

本项目中的产品推荐系统使用了三个组件:MIND、PaddleRec 和 Milvus。

MIND

MIND 是 "Multi-Interest Network with Dynamic Routing for Recommendation at Tmall "的缩写,是阿里巴巴集团开发的一种算法。在 MIND 提出之前,大多数盛行的人工智能推荐模型都使用单一向量来表示用户的各种兴趣。然而,单一向量远远不足以代表用户的确切兴趣。因此,MIND 算法被提出来将用户的多种兴趣转化为多个向量。

具体来说,MIND 算法在候选信息生成阶段采用动态路由的多兴趣网络来处理一个用户的多个兴趣。多兴趣网络是建立在胶囊路由机制上的一层多兴趣提取器。它可用于将用户的过往行为与其多种兴趣结合起来,从而提供准确的用户画像。

下图展示了 MIND 的网络结构。

4.png 4.png

为了表现用户的特质,MIND 将用户行为和用户兴趣作为输入,然后送入嵌入层生成用户向量,包括用户兴趣向量和用户行为向量。然后将用户行为向量输入多兴趣提取层,生成用户兴趣胶囊。将用户兴趣胶囊与用户行为嵌入连接起来,并使用多个 ReLU 层进行转换后,MIND 输出多个用户表示向量。本项目规定 MIND 最终将输出四个用户表征向量。

另一方面,产品特质经过 Embeddings 层,被转换成稀疏的项目向量。然后,每个项目向量再经过池化层,成为密集向量。

当所有数据都转换成向量后,就会引入一个额外的标签感知注意力层来指导训练过程。

PaddleRec

PaddleRec是一个用于推荐的大规模搜索模型库。它是百度PaddlePaddle生态系统的一部分。PaddleRec 旨在为开发人员提供一个集成的解决方案,使他们能以简单、快速的方式构建一个推荐系统。

5.png 5.png

正如开篇所述,开发推荐系统的工程师往往不得不面对系统可用性差、部署复杂等难题。然而,PaddleRec 可以在以下方面为开发人员提供帮助:

  • 易用性:PaddleRec 是一个开源库,它封装了业界各种流行的模型,包括候选者生成模型、排名模型、重排序模型、多任务模型等。利用 PaddleRec,您可以即时测试模型的有效性,并通过迭代提高其效率。PaddleRec 为你提供了一种为分布式系统训练模型的简便方法,而且性能卓越。它针对稀疏向量的大规模数据处理进行了优化。您可以轻松地横向扩展 PaddleRec,并加快其计算速度。因此,你可以使用 PaddleRec 在 Kubernetes 上快速构建训练环境。

  • 支持部署:PaddleRec 为其模型提供在线部署解决方案。模型在培训后可立即投入使用,具有灵活性和高可用性的特点。

Milvus

Milvus是一款以云原生架构为特色的向量数据库。它在GitHub上开源,可用于存储、索引和管理由深度神经网络和其他机器学习(ML)模型生成的海量嵌入向量。Milvus 封装了多个一流的近似近邻(ANN)搜索库,包括 Faiss、NMSLIB 和 Annoy。您还可以根据需要扩展 Milvus。Milvus 服务具有高可用性,支持统一的批处理和流处理。Milvus 致力于简化非结构化数据的管理流程,并在不同的部署环境中提供一致的用户体验。它具有以下特点:

  • 在海量数据集上进行向量搜索时具有高性能。

  • 以开发者为先的社区,提供多语言支持和工具链。

  • 云可扩展性和高可靠性,即使在中断情况下也是如此。

  • 通过将标量过滤与向量相似性搜索配对实现混合搜索。

在本项目中,Milvus 被用于向量相似性搜索和向量管理,因为它可以在保持系统稳定性的同时解决数据频繁更新的问题。

系统实施

要在本项目中建立产品推荐系统,需要经过以下步骤:

  1. 数据处理
  2. 模型训练
  3. 模型测试
  4. 生成候选产品项目
    1. 数据存储:通过训练好的模型获得项目向量,并存储在 Milvus 中。
    2. 数据搜索:将 MIND 生成的四个用户向量输入 Milvus,进行向量相似性搜索。
    3. 数据排序:四个向量中的每个向量都有自己的top_k 相似物品向量,对四组top_k 向量进行排序,返回top_k 最相似向量的最终列表。

本项目的源代码托管在百度 AI Studio平台上。下面将详细介绍本项目的源代码。

步骤 1.数据处理

原始数据集来自ComiRec 提供的亚马逊图书数据集。不过,本项目使用的是从 PaddleRec 下载并由 PaddleRec 处理的数据。更多信息请参阅 PaddleRec 项目中的AmazonBook 数据集

用于训练的数据集预计将以下列格式出现,每列代表:

  • Uid:用户 ID。
  • item_id:用户点击的产品项目 ID。
  • Time:时间戳或点击顺序。

测试数据集的格式如下,每一列代表:

  • Uid:用户 ID。

  • hist_item:历史用户点击行为中产品项目的 ID。如果有多个hist_item ,则根据时间戳排序。

  • eval_item:用户点击产品的实际顺序。

第 2 步:模型训练模型训练

模型训练使用上一步处理过的数据,并采用基于 PaddleRec 建立的候选生成模型 MIND。

1.模型 输入

dygraph_model.py 中,运行以下代码来处理数据并将其转化为模型输入。该过程会根据时间戳对原始数据中同一用户点击的项目进行排序,并将它们组合成一个序列。然后,从序列中随机选取一个item``_``id 作为target_item ,并提取target_item 之前的 10 个条目作为hist_item 作为模型输入。如果序列不够长,可以设为 0。seq_len 应该是hist_item 序列的实际长度。

def create_feeds_train(self, batch_data):
    hist_item = paddle.to_tensor(batch_data[0], dtype="int64")
    target_item = paddle.to_tensor(batch_data[1], dtype="int64")
    seq_len = paddle.to_tensor(batch_data[2], dtype="int64")
    return [hist_item, target_item, seq_len]

读取原始数据集的代码请参考脚本/home/aistudio/recommend/model/mind/mind_reader.py

2.模型联网

以下代码摘自net.pyclass Mind_Capsual_Layer 定义了建立在兴趣胶囊路由机制上的多兴趣提取层。函数label_aware_attention() 实现了 MIND 算法中的标签感知注意力技术。class MindLayer 中的函数forward() 对用户特征进行模型化,并生成相应的权重向量。

class Mind_Capsual_Layer(nn.Layer):
    def __init__(self):
        super(Mind_Capsual_Layer, self).__init__()
        self.iters = iters
        self.input_units = input_units
        self.output_units = output_units
        self.maxlen = maxlen
        self.init_std = init_std
        self.k_max = k_max
        self.batch_size = batch_size
        # B2I routing
        self.routing_logits = self.create_parameter(
            shape=[1, self.k_max, self.maxlen],
            attr=paddle.ParamAttr(
                name="routing_logits", trainable=False),
            default_initializer=nn.initializer.Normal(
                mean=0.0, std=self.init_std))
        # bilinear mapping
        self.bilinear_mapping_matrix = self.create_parameter(
            shape=[self.input_units, self.output_units],
            attr=paddle.ParamAttr(
                name="bilinear_mapping_matrix", trainable=True),
            default_initializer=nn.initializer.Normal(
                mean=0.0, std=self.init_std))
                
class MindLayer(nn.Layer):

    def label_aware_attention(self, keys, query):
        weight = paddle.sum(keys * query, axis=-1, keepdim=True)
        weight = paddle.pow(weight, self.pow_p)  # [x,k_max,1]
        weight = F.softmax(weight, axis=1)
        output = paddle.sum(keys * weight, axis=1)
        return output, weight

    def forward(self, hist_item, seqlen, labels=None):
        hit_item_emb = self.item_emb(hist_item)  # [B, seqlen, embed_dim]
        user_cap, cap_weights, cap_mask = self.capsual_layer(hit_item_emb, seqlen)
        if not self.training:
            return user_cap, cap_weights
        target_emb = self.item_emb(labels)
        user_emb, W = self.label_aware_attention(user_cap, target_emb)

        return self.sampled_softmax(
            user_emb, labels, self.item_emb.weight,
            self.embedding_bias), W, user_cap, cap_weights, cap_mask

MIND 的具体网络结构请参考脚本/home/aistudio/recommend/model/mind/net.py

3.模型优化

本项目使用Adam 算法作为模型优化器。

def create_optimizer(self, dy_model, config):
    lr = config.get("hyper_parameters.optimizer.learning_rate", 0.001)
    optimizer = paddle.optimizer.Adam(
        learning_rate=lr, parameters=dy_model.parameters())
    return optimizer

此外,PaddleRec 会在config.yaml 中写入超参数,因此只需修改该文件,就能清楚地看到两个模型的效果对比,从而提高模型效率。在训练模型时,模型效果不佳可能是由于模型欠拟合或过拟合造成的。因此可以通过修改训练轮数来改善。在本项目中,只需修改config.yaml 中的参数 epochs,就能找到完美的训练轮数。此外,您还可以更改模型优化器、optimizer.classlearning_rate 进行调试。下面显示了config.yaml 中的部分参数。

runner:
  use_gpu: True
  use_auc: False
  train_batch_size: 128
  epochs: 20
  print_interval: 10
  model_save_path: "output_model_mind"

# hyper parameters of user-defined network
hyper_parameters:
  # optimizer config
  optimizer:
    class: Adam
    learning_rate: 0.005

具体实现请参考脚本/home/aistudio/recommend/model/mind/dygraph_model.py

4.模型训练

运行以下命令开始模型训练。

python -u trainer.py -m mind/config.yaml

模型训练项目请参考/home/aistudio/recommend/model/trainer.py

步骤 3.模型测试

此步骤使用测试数据集来验证性能,如训练模型的召回率。

在模型测试过程中,所有项目向量都会从模型中加载,然后导入开源向量数据库 Milvus。通过脚本/home/aistudio/recommend/model/mind/mind_infer_reader.py 读取测试数据集。加载上一步中的模型,并将测试数据集输入模型,得到用户的四个兴趣向量。在 Milvus 中搜索与四个兴趣向量最相似的 50 个项目向量。您可以将返回的结果推荐给用户。

运行以下命令测试模型。

python -u infer.py -m mind/config.yaml -top_n 50

在模型测试过程中,系统会提供多个指标来评估模型的有效性,如 Recall@50、NDCG@50 和 HitRate@50。本文只介绍修改一个参数。不过,在您自己的应用场景中,您需要训练更多的 epoch 才能获得更好的模型效果。 您还可以通过使用不同的优化器、设置不同的学习率以及增加测试轮数来提高模型效果。建议保存多个不同效果的模型,然后选择性能最好、最适合自己应用的模型。

步骤 4.生成候选产品项目

为了构建产品候选项生成服务,本项目使用了前面步骤中训练好的模型,并与 Milvus 配对。在候选项生成过程中,使用 FASTAPI 提供接口。服务启动后,您可以通过curl 直接在终端运行命令。

运行以下命令生成初步候选。

uvicorn main:app

该服务提供四种类型的接口:

  • 插入:运行以下命令从模型中读取项向量并插入到 Milvus 中的 Collections 中。
curl -X 'POST' \
  'http://127.0.0.1:8000/rec/insert_data' \
  -H 'accept: application/json' \
  -d ''
  • 生成初步候选产品:输入用户点击产品的顺序,找出用户可能点击的下一个产品。您也可以一次为多个用户分批生成产品项目候选。以下命令中的hist_item 是一个二维向量,每一行代表用户过去点击过的产品序列。您可以定义序列的长度。返回的结果也是一组二维向量,每一行代表返回的用户的item ids。
curl -X 'POST' \
  'http://127.0.0.1:8000/rec/recall' \
  -H 'accept: application/json' \
  -H 'Content-Type: application/json' \
  -d '{
  "top_k": 50,
  "hist_item": [[43,23,65,675,3456,8654,123454,54367,234561],[675,3456,8654,123454,76543,1234,9769,5670,65443,123098,34219,234098]]
}'
  • 查询 产品项目总数运行以下命令可返回存储在 Milvus 数据库中的商品向量总数。
curl -X 'POST' \
  'http://127.0.0.1:8000/rec/count' \
  -H 'accept: application/json' \
  -d ''
  • 删除:运行以下命令删除存储在 Milvus 数据库中的所有数据。
curl -X 'POST' \
  'http://127.0.0.1:8000/qa/drop' \
  -H 'accept: application/json' \
  -d ''

如果在本地服务器上运行候选产品生成服务,也可以访问127.0.0.1:8000/docs 上的上述界面。你可以点击这四个界面并输入参数值来进行操作。然后点击 "Try it out(试试看)",即可得到推荐结果。

6.png 6.png

7.png 7.png

小结

本文主要关注建立推荐系统的第一阶段候选生成。它还提供了通过将 Milvus 与 MIND 算法和 PaddleRec 结合来加速这一过程的解决方案,因此已经解决了开篇提出的问题。

由于数据集数量巨大,系统返回结果的速度非常慢,怎么办?开源向量数据库 Milvus 专为在包含数百万、数十亿甚至数万亿向量的密集向量数据集上进行极快的相似性搜索而设计。

如果无法实时处理新插入的数据进行搜索或查询怎么办?您可以使用 Milvus,因为它支持统一的批处理和流处理,能让您实时搜索和查询新插入的数据。同时,MIND 模型能够实时转换新的用户行为,并将用户向量即时插入 Milvus。

如果复杂的部署太吓人怎么办?隶属于 PaddlePaddle 生态系统的强大库 PaddleRec 可以为您提供集成解决方案,让您轻松快速地部署推荐系统或其他应用程序。

关于作者

李云梅,Zilliz 数据工程师,毕业于华中科技大学计算机科学专业。加入Zilliz后,她一直致力于为开源项目Milvus探索解决方案,并帮助用户将Milvus应用到实际场景中。她的主要研究方向是 NLP 和推荐系统,并希望在这两个领域进一步加深研究。她喜欢独处和阅读。

寻找更多资源?

Try Managed Milvus for Free

Zilliz Cloud is hassle-free, powered by Milvus and 10x faster.

Get Started

Like the article? Spread the word

扩展阅读