深度树匹配模型(TDM)
深度樹匹配模型(TDM)
算法介紹
Tree-based Deep Match(TDM)是由阿里媽媽精準定向廣告算法團隊自主研發,基于深度學習上的大規模(千萬級+)推薦系統算法框架。在大規模推薦系統的實踐中,基于商品的協同過濾算法(Item-CF)是應用較為廣泛的,而受到圖像檢索的啟發,基于內積模型的向量檢索算法也嶄露頭角,這些推薦算法產生了一定的效果,但因為受限于算法模型本身的理論限制,推薦的最終結果并不十分理想。近些年,深度學習技術逐漸興起,在包括如圖像、自然語言處理、語音等領域的應用產生了巨大的效果推動。受制于候選集合的大規模,在推薦系統里全面應用深度學習,進行計算存在效果低下的問題。TDM原創性的提出了以樹結構組織大規模候選,建立目標(興趣)的層次化依賴關系,并通過逐層樹檢索的方式進行用戶對目標(興趣)的偏好計算,從而實現用戶目標(興趣)的最終推薦。無論是在公開數據集上離線測試結果[1],還是在阿里媽媽實際業務的在線測試上,TDM都取得了非常顯著的效果提升。
基礎知識
寫在最前面
本文主要面向推薦系統的學術愛好者,實際從業者,介紹TDM系統的組成原理,TDM開源項目的使用指導,以及如何將TDM算法應用到使用者實際業務中去。下述介紹假定讀者具備一定的推薦系統/深度學習的概念了解,基本的數據結構與算法理解,以及基本編程語言(C++,Python)的掌握,如果讀者對這些技術的了解存在疑慮,可參考下述知識點進行學習。
需要的前提知識
? 基本概念
o 推薦系統:推薦技術提供用戶對某個目標(興趣)的偏好程度預測能力,基于偏好預測排序輸出用戶喜好的目標(興趣)集合。
o 深度學習:基于深度神經網絡結構的機器學習算法分支。
? 數據結構與算法
o 樹:樹是計算機科學中數據結構的經典類型,在數據組織上具有良好的效率。
o BeamSearch算法:一種啟發式的貪心搜索方法。
o Kmeans聚類算法:一種基于向量量化的無監督聚類算法。
? 語言基礎
o C++語言:通用編程語言。
o Python語言:通用腳本編程語言。
文檔內容說明
本文旨在介紹TDM以及如何使用TDM開源項目進行實際業務生產所用,閱讀完成后,可以了解到:
? TDM的基本系統組成
? TDM開源代碼的運行和使用
? 應用TDM到具體實踐的方法
受限于篇幅以及主旨,以下內容本文不涉及,或請參閱相關文檔:
? XDL訓練平臺的系統組成和使用。
? 公開數據集(UserBehavior)的下載、使用和授權。
TDM適用的范圍
TDM面向解決的是大規模推薦問題,自主提出的以樹方式組織大規模候選建立層次關系進而支撐層次檢索的框架,具有普遍的適用性和優秀的實驗效果。TDM算法具有極高的業務適用性,在包括如視頻推薦、商品推薦、新聞推薦等業務領域已經成功應用,并取得了非常可觀的業務效果。更多的業務領域TDM應用實踐正在開展中,本文后續會不斷更新TDM的業務實踐效果。
TDM框架介紹
算法原理
TDM是為大規模推薦系統設計的、能承載任意先進模型來高效檢索用戶興趣的推薦算法解決方案。TDM基于樹結構,提出了一套對用戶興趣度量進行層次化建模與檢索的方法論,使得系統能直接利高級深度學習模型,在全庫范圍內檢索用戶興趣。詳細的算法介紹,參見TDM在KDD會議上的論文,其基本原理是使用樹結構對全庫item進行索引,然后訓練深度模型以支持樹上的逐層檢索,從而將大規模推薦中全庫檢索的復雜度由O(n)(n為所有item的量級)下降至O(log n)。
系統組成
樹結構
樹在TDM框架中承擔的是索引結構的角色,即全庫item都會通過樹結構被索引起來。
樹中的每一個葉節點對應庫中的一個item;非葉節點表示item的集合。這樣的一種層次化結構,體現了粒度從粗到細的item架構。此時,推薦任務轉換成了如何從樹中檢索一系列葉節點,作為用戶最感興趣的item返回。值得一提的是,雖然圖中展示的樹結構是一個二叉樹,但在實際應用中并無此限制。
基于樹的檢索算法
在一些傳統的樹狀索引如二叉搜索樹、B-樹等結構中,檢索過程往往是使用鍵值在樹上進行逐層往下的top 1檢索,最終找到一個滿足條件的葉節點并返回。而在TDM框架中,基于樹結構進行大規模推薦的方法,是每一個用戶尋找K個最感興趣的葉節點。因此,檢索過程也做了相應的改變:在逐層往下的檢索過程中,每一層都保留K個節點并往下擴展,即經典的BeamSearch方法。這一檢索方案兼具效率與精度,剩下的問題是如何得到每層內精準的興趣判別器,來找到每層內的K個最感興趣的節點。
深度網絡模型
深度網絡在TDM框架中承擔的是用戶興趣判別器的角色,其輸出的(用戶,節點)對的興趣度,將被用于檢索過程作為尋找每層Top K的評判指標。由于TDM框架具備高效的剪枝能力,因此其能兼容任意先進的深度網絡模型來進行全庫檢索。
上述網絡結構中,在用戶特征方面僅使用了用戶歷史行為,并對歷史行為根據其發生時間,進行了時間窗口劃分。在節點特征方面,使用的是節點經過embedding后的向量作為輸入。此外,模型借助attention結構,將用戶行為中和本次判別相關的那部分篩選出來,以實現更精準的判別。
網絡與樹結構的聯合訓練
樹索引結構在TDM框架中起到了兩方面的作用,一是在訓練過程提供了上溯正采樣樣本和平層負采樣樣本;二是在檢索過程中決定了選擇與剪枝方案。因此,良好的樹結構應該能為訓練提供易于區分的上層樣本,并盡量體現真實的用戶興趣層級結構來幫助檢索。基于數據驅動的索引學習及檢索模型、索引結構聯合訓練的出發點,TDM框架進行了一種嘗試:使用學習得到的葉節點(即item)embedding向量進行層次化聚類,來生成新的樹索引結構。
檢索模型訓練、樹索引結構學習過程迭代進行,最終得到穩定的結構與模型。
評測指標
TDM主要采用召回率、準確率兩種評價指標:
? 召回率:R = size({預測集合} ∩ {真集}) / size({真集})
? 準確率:P = size({預測集合} ∩ {真集}) / size({預測集合})
TDM訓練示例
單機試驗小數據集
用戶依照以下步驟可以在隨機dummy小數據集上快速驗證流程,此dummy數據集為隨機生成,僅作快速驗證流程使用。如果需要拿到效果,試驗一個具有實際意義的數據集(例如UserBehavior數據集)
? 準備工作目錄
WORKPATH=’/your/path/work/tdm_mock’ # 自選一個工作目錄
git clone --recursive https://github.com/alibaba/x-deeplearning.git
cd x-deeplearning
git submodule update --init --recursive # 如果clone時沒有–recursive,那么需要執行本行命令
cp -r XDL-Algorithm-Solution/TDM/script/tdm_ub_att_ubuntu/ “KaTeX parse error: Expected 'EOF', got '#' at position 101: …u-mxnet1.3' #? 選擇docker鏡像地址 s…DOCKER_PATH”
下列命令啟動一個名為tdm-mock的容器,當然這個名字可以自行指定,但不能與本機上已有的容器重名
sudo docker run -it --net=host --volume HOME:HOME:HOME:HOME -w HOME‘curl?shttp://localhost:3476/docker/cli‘??nametdm?mock"HOME `curl -s http://localhost:3476/docker/cli` --name tdm-mock "HOME‘curl?shttp://localhost:3476/docker/cli‘??nametdm?mock"DOCKER_PATH"
sudo docker exec -ti tdm-mock bash # 再次進入docker使用該命令,注意tdm-mock應與上述啟動容器命令中指定的名字相同
用戶需要安裝并配置HADOOP
source /etc/profile # 設置hadoop,以及將當前路徑添加到PATH
? 編譯安裝TDM
apt-get install swig # 如果已經安裝則無需安裝
cd XDL-Algorithm-Solution/TDM/src
mkdir build
cd build
cmake …
make
cp -r …/python/store/store/ “WORKPATH"cp?r../python/disttree/disttree/"WORKPATH" cp -r ../python/dist_tree/dist_tree/ "WORKPATH"cp?r../python/distt?ree/distt?ree/"WORKPATH”
cp -r …/python/cluster/ “WORKPATH"cptdm/lib?.so"WORKPATH" cp tdm/lib*.so "WORKPATH"cptdm/lib?.so"WORKPATH”
? 分隔數據集,生成原始樣本csv
cd “KaTeX parse error: Undefined control sequence: \ at position 45: …_cutter.py \? ? --input mock.…CSV_HDFSPATH” # 確認該目錄之前不存在,若存在則刪掉或換個目錄
hadoop fs -mkdir “CSVHDFSPATH"hadoopfs?putmocktrain.csv"CSV_HDFSPATH" hadoop fs -put mock_train.csv "CSVH?DFSPATH"hadoopfs?putmockt?rain.csv"CSV_HDFSPATH”
hadoop fs -put mock_test.csv “CSVHDFSPATH"?樣本產出及樹初始化cd"CSV_HDFSPATH" ? 樣本產出及樹初始化 cd "CSVH?DFSPATH"?樣本產出及樹初始化cd"WORKPATH”
UPLOAD_HDFSPATH=‘hdfs://your/dist_tree/upload/hdfs/path/tree_data’ # 指定樣本及樹的產出目錄
hadoop fs -ls “KaTeX parse error: Expected 'EOF', got '#' at position 21: …D_HDFSPATH" #? 確認該目錄之前不存在,若存在…UPLOAD_HDFSPATH”
EMB_HDFSPATH=‘hdfs://your/emb_converted/hdfs/path’ # 指定訓練的embedding結果產出目錄
hadoop fs -ls “KaTeX parse error: Expected 'EOF', got '#' at position 21: …DFSPATH" #? 確認該目錄之前不存在,若存在…EMB_HDFSPATH”
vim data/tdm.json # train_rawdata_url 修改為 $CSV_HDFSPATH/mock_train.csv 的完整hdfs路徑
# test_rawdata_url 修改為 $CSV_HDFSPATH/mock_test.csv 的完整hdfs路徑
# upload_url 修改為 $UPLOAD_HDFSPATH 的完整hdfs路徑,此為樹及樣本生成目錄的hdfs路徑
# model_url 修改為 KaTeX parse error: Expected 'EOF', got '#' at position 112: …_mock_init' #? 指定樣本產出及樹初始化的ck…INIT_CKPT_HDFS_PATH"
hadoop fs -mkdir “KaTeX parse error: Expected 'EOF', got '#' at position 25: …_HDFS_PATH" #? 如果目錄不存在,則創建 ha…INIT_CKPT_HDFS_PATH/checkpoint” # 否則刪除其中的checkpoint目錄
vim config.tree_init.json # dependent_dirs 修改為 $WORKPATH 的完整路徑
# docker_image 修改為 $DOCKER_PATH
# checkpoint.output_dir 修改為 INITCKPTHDFSPATH/checkpointpythontreeinit.pyhadoopfs?ls"INIT_CKPT_HDFS_PATH/checkpoint python tree_init.py hadoop fs -ls "INITC?KPTH?DFSP?ATH/checkpointpythontreei?nit.pyhadoopfs?ls"UPLOAD_HDFSPATH/data"
? 訓練
cd “KaTeX parse error: Expected 'EOF', got '#' at position 74: …mock_train' #? 指定訓練的ckpt目錄 ha…TRAIN_CKPT_HDFS_PATH”
hadoop fs -mkdir “KaTeX parse error: Expected 'EOF', got '#' at position 26: …_HDFS_PATH" #? 如果目錄不存在,則創建 ha…TRAIN_CKPT_HDFS_PATH/checkpoint” # 否則刪除其中的checkpoint目錄
vim config.train.json # dependent_dirs 修改為 $WORKPATH 的完整路徑
# docker_image 修改為 $DOCKER_PATH
# checkpoint.output_dir 修改為 KaTeX parse error: Expected 'EOF', got '#' at position 53: …ata/tdm.json #? 因為是小數據集,因此參數做些…TRAIN_CKPT_HDFS_PATH/checkpoint" # 查看訓練保存的ckpt
hadoop fs -ls “KaTeX parse error: Expected 'EOF', got '#' at position 18: …B_HDFSPATH" #? 查看生成的 item_emb…WORKPATH”
CLUSTER_CKPT_HDFS_PATH=‘hdfs://your/hdfs/path/tdm_mock_cluster’ # 指定聚類的ckpt目錄
hadoop fs -ls “CLUSTERCKPTHDFSPATH"hadoopfs?mkdir"CLUSTER_CKPT_HDFS_PATH" hadoop fs -mkdir "CLUSTERC?KPTH?DFSP?ATH"hadoopfs?mkdir"CLUSTER_CKPT_HDFS_PATH” # 如果目錄不存在,則創建
hadoop fs -rm -r “$CLUSTER_CKPT_HDFS_PATH/checkpoint” # 否則刪除其中的checkpoint目錄
vim config.tree_cluster.json # dependent_dirs 修改為 $WORKPATH 的完整路徑
# docker_image 修改為 $DOCKER_PATH
# checkpoint.output_dir 修改為 CLUSTERCKPTHDFSPATH/checkpointpythontreecluster.pyhadoopfs?ls"CLUSTER_CKPT_HDFS_PATH/checkpoint python tree_cluster.py hadoop fs -ls "CLUSTERC?KPTH?DFSP?ATH/checkpointpythontreec?luster.pyhadoopfs?ls"UPLOAD_HDFSPATH/data"
? 再次訓練
同上
? 離線評測
在任意一次訓練產出ckpt后即可按需進行評測。
cd “KaTeX parse error: Expected 'EOF', got '#' at position 74: …mock_train' #? 指定訓練的ckpt目錄用于離…TRAIN_CKPT_HDFS_PATH”
vim config.predict.json # dependent_dirs 修改為 $WORKPATH 的完整路徑
# docker_image 修改為 $DOCKER_PATH
# checkpoint.output_dir 修改為 $TRAIN_CKPT_HDFS_PATH/checkpoint
vim train.py # 修改predict的代碼中DataIO的參數 namenode=“hdfs://your/namenode/hdfs/path:9000”,注意和上面train不是同一處
# 最下面修改為 is_training=False
# 因為是小數據集,因此參數做些相應調整如下:
# key_value[“pr_test_each_layer_retrieve_num”] = “40”
# key_value[“pr_test_final_layer_retrieve_num”] = “20”
python train.py --run_mode=local --config=config.predict.json
分布式試驗小數據集
? 準備任務調度目錄
可以直接使用上面單機試驗小數據集的工作目錄,額外需要做的修改都在下面給出。 注意docker應安裝并配置HADOOP。
WORKPATH=’/your/path/work/tdm_mock’
DISTPATH=’/your/path/dist/tdm_mock’
將單機運行docker中的工作目錄 $WORKPATH 拷貝至分布式任務調度機器上的目錄 $DISTPATH ,用于提任務。
cd “$DISTPATH/data”
目錄中僅保留三個文件 tdm.json、userbehavoir_fc.json、userbehavoir_stat.dat,其余文件刪除
這些其余文件是單機運行時產出的,雖然不會導致運行結果出錯,但提任務時因為要上傳整個目錄,若不刪除則會拖慢上傳速度
? 分隔數據集,生成原始樣本csv
該步驟如上單機產出即可,分布式實驗時直接使用。
? 樣本產出及樹初始化
cd “KaTeX parse error: Expected 'EOF', got '#' at position 72: …_mock_init' #? 指定樣本產出及樹初始化的ck…INIT_CKPT_HDFS_PATH”
hadoop fs -mkdir “KaTeX parse error: Expected 'EOF', got '#' at position 25: …_HDFS_PATH" #? 如果目錄不存在,則創建 ha…INIT_CKPT_HDFS_PATH/checkpoint” # 否則刪除其中的checkpoint目錄
vim config.tree_init.json # dependent_dirs 修改為 $DISTPATH 的完整路徑
# checkpoint.output_dir 修改為 INITCKPTHDFSPATH/checkpointxdlsubmit.py??configconfig.treeinit.json?訓練cd"INIT_CKPT_HDFS_PATH/checkpoint xdl_submit.py --config config.tree_init.json ? 訓練 cd "INITC?KPTH?DFSP?ATH/checkpointxdls?ubmit.py??configconfig.treei?nit.json?訓練cd"DISTPATH"
TRAIN_CKPT_HDFS_PATH=‘hdfs://your/hdfs/path/tdm_mock_train’ # 指定訓練的ckpt目錄
hadoop fs -ls “TRAINCKPTHDFSPATH"hadoopfs?mkdir"TRAIN_CKPT_HDFS_PATH" hadoop fs -mkdir "TRAINC?KPTH?DFSP?ATH"hadoopfs?mkdir"TRAIN_CKPT_HDFS_PATH” # 如果目錄不存在,則創建
hadoop fs -rm -r “$TRAIN_CKPT_HDFS_PATH/checkpoint” # 否則刪除其中的checkpoint目錄
vim data/tdm.json # 因為是小數據集,因此參數做些相應調整如下:
# train_batch_size 修改為 3000
# save_checkpoint_interval 修改為 100
vim config.train.json # dependent_dirs 修改為 $DISTPATH 的完整路徑
# checkpoint.output_dir 修改為 KaTeX parse error: Expected 'EOF', got '#' at position 57: … #? 因為是小數據集,因此計算資源…DISTPATH"
CLUSTER_CKPT_HDFS_PATH=‘hdfs://your/hdfs/path/tdm_mock_cluster’ # 指定聚類的ckpt目錄
hadoop fs -ls “CLUSTERCKPTHDFSPATH"hadoopfs?mkdir"CLUSTER_CKPT_HDFS_PATH" hadoop fs -mkdir "CLUSTERC?KPTH?DFSP?ATH"hadoopfs?mkdir"CLUSTER_CKPT_HDFS_PATH” # 如果目錄不存在,則創建
hadoop fs -rm -r “$CLUSTER_CKPT_HDFS_PATH/checkpoint” # 否則刪除其中的checkpoint目錄
vim config.tree_cluster.json # dependent_dirs 修改為 $DISTPATH 的完整路徑
# checkpoint.output_dir 修改為 CLUSTERCKPTHDFSPATH/checkpointxdlsubmit.py??configconfig.treecluster.json?再次訓練同上?離線評測在任意一次訓練產出ckpt后即可按需進行評測。cd"CLUSTER_CKPT_HDFS_PATH/checkpoint xdl_submit.py --config config.tree_cluster.json ? 再次訓練 同上 ? 離線評測 在任意一次訓練產出ckpt后即可按需進行評測。 cd "CLUSTERC?KPTH?DFSP?ATH/checkpointxdls?ubmit.py??configconfig.treec?luster.json?再次訓練同上?離線評測在任意一次訓練產出ckpt后即可按需進行評測。cd"DISTPATH"
TRAIN_CKPT_HDFS_PATH=‘hdfs://your/hdfs/path/tdm_mock_train’ # 指定訓練的ckpt目錄用于離線評測
vim config.predict.json # dependent_dirs 修改為 $DISTPATH 的完整路徑
# checkpoint.output_dir 修改為 $TRAIN_CKPT_HDFS_PATH/checkpoint
# checkpoint.output_dir 修改為 $TRAIN_CKPT_HDFS_PATH/checkpoint
# 因為是小數據集,因此計算資源申請參數做相應調整如下:
# “worker”: {
# “instance_num”: 2,
# “cpu_cores”: 8,
# “gpu_cores”: 1,
# “memory_m”: 20000
# },
# “ps”: {
# “instance_num”: 1,
# “cpu_cores”: 8,
# “gpu_cores”: 0,
# “memory_m”: 16000
# },
vim train.sh # 最下面修改為 is_training=False
xdl_submit.py --config config.predict.json
分布式試驗UB數據集
? 準備任務調度目錄
DOCKER_PATH=‘registry.cn-hangzhou.aliyuncs.com/xdl/xdl:ubuntu-gpu-mxnet1.3’ # 選擇docker鏡像地址
DISTPATH=’/your/path/dist/tdm_ub_att_ubuntu’
git clone --recursive XDL-Algorithm-Solution.git
git submodule update --init --recursive # 如果clone時沒有–recursive,那么需要執行本行命令
cp -r XDL-Algorithm-Solution/TDM/script/tdm_ub_att_ubuntu/ “DISTPATH"?分隔數據集,生成原始樣本csv該步驟見上面。?樣本產出及樹初始化cd"DISTPATH" ? 分隔數據集,生成原始樣本csv 該步驟見上面。 ? 樣本產出及樹初始化 cd "DISTPATH"?分隔數據集,生成原始樣本csv該步驟見上面。?樣本產出及樹初始化cd"DISTPATH”
UPLOAD_HDFSPATH=‘hdfs://your/dist_tree/upload/hdfs/path/tree_data’ # 指定樣本及樹的產出目錄
hadoop fs -ls “KaTeX parse error: Expected 'EOF', got '#' at position 21: …D_HDFSPATH" #? 確認該目錄之前不存在,若存在…UPLOAD_HDFSPATH”
EMB_HDFSPATH=‘hdfs://your/emb_converted/hdfs/path’ # 指定訓練的embedding結果產出目錄
hadoop fs -ls “KaTeX parse error: Expected 'EOF', got '#' at position 21: …DFSPATH" #? 確認該目錄之前不存在,若存在…EMB_HDFSPATH”
vim data/tdm.json # train_rawdata_url 修改為 $CSV_HDFSPATH/mock_train.csv 的完整hdfs路徑
# test_rawdata_url 修改為 $CSV_HDFSPATH/mock_test.csv 的完整hdfs路徑
# upload_url 修改為 $UPLOAD_HDFSPATH 的完整hdfs路徑,此為樹及樣本生成目錄的hdfs路徑
# model_url 修改為 KaTeX parse error: Expected 'EOF', got '#' at position 110: …dm_ub_init' #? 指定樣本產出及樹初始化的ck…INIT_CKPT_HDFS_PATH"
hadoop fs -mkdir “KaTeX parse error: Expected 'EOF', got '#' at position 25: …_HDFS_PATH" #? 如果目錄不存在,則創建 ha…INIT_CKPT_HDFS_PATH/checkpoint” # 否則刪除其中的checkpoint目錄
vim config.tree_init.json # dependent_dirs 修改為 $DISTPATH 的完整路徑
# docker_image 修改為 $DOCKER_PATH
# checkpoint.output_dir 修改為 KaTeX parse error: Expected 'EOF', got '#' at position 60: … #? 計算資源申請參數可根據用戶實…UPLOAD_HDFSPATH/data"
? 訓練
cd “KaTeX parse error: Expected 'EOF', got '#' at position 72: …m_ub_train' #? 指定訓練的ckpt目錄 ha…TRAIN_CKPT_HDFS_PATH”
hadoop fs -mkdir “KaTeX parse error: Expected 'EOF', got '#' at position 26: …_HDFS_PATH" #? 如果目錄不存在,則創建 ha…TRAIN_CKPT_HDFS_PATH/checkpoint” # 否則刪除其中的checkpoint目錄
vim data/tdm.json # train_epochs 設置為樣本需要訓練的輪數
vim config.train.json # dependent_dirs 修改為 $DISTPATH 的完整路徑
# docker_image 修改為 $DOCKER_PATH
# checkpoint.output_dir 修改為 KaTeX parse error: Expected 'EOF', got '#' at position 57: … #? 計算資源申請參數可根據用戶實…TRAIN_CKPT_HDFS_PATH/checkpoint" # 查看訓練保存的ckpt
hadoop fs -ls “KaTeX parse error: Expected 'EOF', got '#' at position 18: …B_HDFSPATH" #? 查看生成的 item_emb…DISTPATH”
CLUSTER_CKPT_HDFS_PATH=‘hdfs://your/hdfs/path/tdm_ub_cluster’ # 指定聚類的ckpt目錄
hadoop fs -ls “CLUSTERCKPTHDFSPATH"hadoopfs?mkdir"CLUSTER_CKPT_HDFS_PATH" hadoop fs -mkdir "CLUSTERC?KPTH?DFSP?ATH"hadoopfs?mkdir"CLUSTER_CKPT_HDFS_PATH” # 如果目錄不存在,則創建
hadoop fs -rm -r “$CLUSTER_CKPT_HDFS_PATH/checkpoint” # 否則刪除其中的checkpoint目錄
vim config.tree_cluster.json # dependent_dirs 修改為 $DISTPATH 的完整路徑
# docker_image 修改為 $DOCKER_PATH
# checkpoint.output_dir 修改為 KaTeX parse error: Expected 'EOF', got '#' at position 67: … #? 計算資源申請參數可根據用戶實…UPLOAD_HDFSPATH/data"
? 再次訓練
同上
? 離線評測
在任意一次訓練產出ckpt后即可按需進行評測。
cd “$DISTPATH”
TRAIN_CKPT_HDFS_PATH=‘hdfs://your/hdfs/path/tdm_ub_train’ # 指定訓練的ckpt目錄用于離線評測
vim config.predict.json # dependent_dirs 修改為 $DISTPATH 的完整路徑
# docker_image 修改為 $DOCKER_PATH
# checkpoint.output_dir 修改為 $TRAIN_CKPT_HDFS_PATH/checkpoint
# checkpoint.output_dir 修改為 $TRAIN_CKPT_HDFS_PATH/checkpoint
# 計算資源申請參數可根據用戶實際情況調整
vim train.py # 修改predict的代碼中DataIO的參數 namenode=“hdfs://your/namenode/hdfs/path:9000”,注意和上面train不是同一處
# 最下面修改為 is_training=False
xdl_submit.py --config config.predict.json # 該步驟耗時約5-15分鐘,與實際計算資源有關
數據處理
本小結會簡要描述數據處理階段主要完成的功能以及輸入輸出格式,主要包括生成訓練樣本、測試樣本、初始樹.
初始數據準備
在進行數據處理之前,先要準備原始訓練數據以及原始測試數據, 這兩份數據格式均為以逗號分隔的文本文件, 每行文本為一個行為記錄. 比如下面的示例數據為id為1的用戶的5條點擊行為(以逗號分隔的各字段含義為user_id, item_id, category_id, behavior_type, timestamp).
1,2268318,2520377,pv,1511544070
1,2333346,2520771,pv,1511561733
數據處理腳本
? 生成樣本格式
生成的樣本為文本文件, 每行為一個行為序列, 格式為:
sample id | group id | features | dense | label | ts
其中features為; 分隔的Key@Value序列
下面是行為序列樣本示例:
619706_13|619706_13|train_unit_id@3829251:1.0;item_55@1180190;item_53@2964905;item_54@4871;item_56@2416791;item_57@1420124;item_58@1165085;item_59@33793;item_65@917114;item_64@4080531;item_67@3915603;item_66@511224;item_61@2694865;item_60@5159307;item_63@2638297;item_62@511224;item_69@917114;item_68@1400292;item_52@629303||1.0|
239290_1|239290_1|train_unit_id@4075487:1.0;item_65@4940273;item_64@3654350;item_67@1314642;item_66@1042927;item_69@345076;item_68@2365838||1.0|
273937_1|273937_1|train_unit_id@2137809:1.0;item_65@170544;item_64@3433418;item_67@848255;item_66@2127356;item_69@3699491;item_68@2122609||1.0|
? 特征配置文件示例
{
“features”: {
“item_1”: {
“start”: 0,
“end”: 10,
“value”: 1
},
“item_2”: {
“start”: 10,
“end”: 20,
“value”: 1
}
}
此特征配置文件表示將用戶的第0個到第10個行為序列作為一個特征組,命名為item_1;將用戶的第10個到第20個行為序列作為一個特征組,命名為item_2;
? 數據處理流程
數據處理分為數據讀取, 生成訓練樣本, 生成概率統計文件, 生成測試樣本, 生成初始化樹(PB格式), 整個流程可以用下面的流程圖描述.
? 擴展及修改
數據處理階段的主要邏輯都在generator.py腳本中, 腳本按上述流程組織成模塊, 在需要時候非常易于擴展及修改, 下面簡單描述下各流程的主要邏輯及可能的修改.
Read And Parse Raw Data
該流程讀取并解析原始輸入的訓練或者測試數據, 并返回一個按列組織的字典, 及每個Key是一個列名, 對應的Value是該列所有的數據(實際存儲為一個numpy array). 這部分邏輯比較簡單, 主要就是按行讀取, 并按逗號(可以擴展為其他分隔符)分割, 并將各列Parse成指定的數據類型. 用戶實際使用時候, 可以根據自己的數據格式修改相應的讀取及解析邏輯, 比如支持其他的輔助列.Generate Train Sample
這一部分生成用戶行為序列, 并寫入樣本文件中, 樣本格式見上文. 這一部分邏輯分為兩步: 先將各用戶的行為聚合起來, 實際上就是生成一個以用戶id為Key, 用戶點擊Item Id列表為Value的字典, 注意這里會對各用戶的點擊的Item進行排序, 排序的依據是點擊行為發生的時間戳; 完成用戶行為聚合后, 再將用戶的行為按樣本序列長度切割成樣本.Generate Stat Info
該模塊的功能為統計各Item在訓練樣本中出現的概率, 并將其寫入統計文件.
Generate Test Sample
該模塊邏輯基本和Generate Train Sample相同, 略.
Init Tree
該模塊生成初始化樹, 實際是一個逐層聚類過程, 將所有的Item按其屬性不斷的進行二分聚類, 直至每個類只有單個的Item屬性, 聚類的最終效果是形成了一顆多層的二叉樹, 所有的item均屬于葉子節點, 所有的葉子結點從左到右相當于形成了一個有序的序列. 在實際的處理, 我們采用直接按Item的Category進行排序, 并在排序之后不斷二分來形成初始化樹, 樹的格式及存儲見下面樹構建部分.在用戶實際業務中用戶可根據自己的業務場景修改相應的排序邏輯以支持不同的樹初始化方式.
樹構建
樹構建階段主要完成聚類樹的生成, 該階段的輸入是根據初始樹聯合訓練生成的item的向量, 并對向量進行聚類生成新的聚類樹.
輸入數據及格式
樹構建階段的輸入是用初始樹聯合訓練產生的向量, 輸入的格式為文本格式, 每一行描述一個Item對應的id和向量, 均為數值類型, 各數值之間以逗號分隔, 下面為截選的部分輸入數據.
2515040,-0.508644402027,-0.016029631719,-0.20682746172,-0.397063672543,-0.00334448833019,-0.960261583328,0.316593915224,-0.636762738228,-0.217385306954,0.0592824667692,0.35680475831,-0.43331822753,-0.369034737349,0.351467847824,0.0969775170088,0.265370905399,0.0815298631787,-0.389724433422,-0.339153647423,0.273165374994,-0.00598054006696,-0.488672584295,0.405939608812,-0.492451280355
235900,-0.0178719386458,0.117409579456,0.0135170938447,0.208914965391,0.270535558462,-0.295207798481,-0.177082359791,-0.312212228775,0.449806898832,0.338447093964,0.0621097162366,0.327057540417,0.126456350088,0.0875944793224,0.577477931976,-0.351881921291,0.138958856463,-0.538168728352,0.329808682203,-0.239835038781,0.19346319139,0.393561393023,0.111480668187,0.317542433739
3148360,0.359621971846,-0.127544790506,-0.297782152891,-0.368366599083,0.223647251725,-0.104716196656,-0.306075185537,-0.406704396009,0.10038292408,0.712464630604,0.195787191391,-0.0189999304712,-0.146252155304,0.15387006104,-0.297544956207,0.317622750998,0.0184208322316,-0.128658607602,0.0909625515342,-0.0311253629625,0.260530024767,-0.622160255909,0.687025904655,-0.309245109558
生成樹存儲結構及格式
聚類產生的是一個編碼樹, 并以Key Value的形式存儲在任意分布式或本地Key Value存儲中。
其中Key是各個節點的編碼, Value則以PB的形式存儲各種屬性是信息, 節點存儲信息的PB描述如下.
message Node {
required int64 id = 1;
required float probality = 2;
required int32 leaf_cate_id = 3;
required bool is_leaf = 4;
repeated float embed_vec = 5;
optional bytes data = 6;
}
在Key Value存儲之上, 樹提供各種豐富的接口, 可以訪問樹的祖先, 兄弟, 孩子, 并能按層進行迭代。
總結
以上是生活随笔為你收集整理的深度树匹配模型(TDM)的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: X-Deep Learning功能模块
- 下一篇: 腾讯 angel 3.0:高效处理模型