🚀 免費嘗試 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 最終會輸出四個使用者表徵向量。

另一方面,產品特徵會經過嵌入層,並轉換為稀疏的項目向量。然後,每個項目向量再經過匯集層,成為密集向量。

當所有資料都轉換成向量時,就會引進一個額外的標籤感知注意層來引導訓練過程。

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 來進行向量相似性搜尋與向量管理,因為 Milvus 可以解決資料頻繁更新的問題,同時維持系統的穩定性。

系統實作

要建立本專案中的商品推薦系統,需要經過以下步驟:

  1. 資料處理
  2. 模型訓練
  3. 模型測試
  4. 產生產品項目候選
    1. 資料儲存:透過訓練的模型得到項目向量,並儲存在 Milvus 中。
    2. 資料搜尋:將 MIND 產生的四個使用者向量輸入 Milvus 進行向量相似度搜尋。
    3. 資料排序:四個向量各有其top_k 相似的項目向量,並對四組top_k 向量進行排序,最後傳回top_k 最相似向量的清單。

本專案的原始碼託管於百度 AI Studio平台。以下將詳細說明本專案的原始碼。

步驟 1.資料處理

原始資料集來自ComiRec 提供的 Amazon 書籍資料集。然而,本專案使用的是由 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.py 的摘錄。class 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 會將 hyperparameters 寫入config.yaml ,因此只要修改這個檔案,就可以清楚看到兩個模型的效果比較,以提高模型效率。在訓練模型時,模型效果不佳可能是由於模型未完全擬合或過度擬合所造成。因此,您可以透過修改訓練的回合數來改善。在本專案中,您只需要修改config.yaml 中的參數 epoch,就可以找到最完美的訓練輪數。此外,您也可以變更模型最佳化器、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 的一個集合中。
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。

如果複雜的部署太嚇人怎麼辦?PaddleRec 是屬於 PaddlePaddle 生態系統的強大函式庫,可以提供您整合式的解決方案,讓您輕鬆快速地部署推薦系統或其他應用程式。

關於作者

李雲梅,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

繼續閱讀