一只小狐狸带你解锁 炼丹术&NLP 秘籍
今天介绍一下我们的一个开源项目DeepMatch,提供了若干主流的深度召回匹配算法的实现,并支持快速导出用户和物品向量进行ANN检索。非常适合同学们进行快速实验和学习,解放算法工程师的双手!
下面分别从开发背景,安装和使用方法以及贡献和交流几个方面介绍一下这个项目。文末提供了交流群感兴趣的同学不要错过,欢迎找bug和提意见~
众所周知,目前主流的推荐广告算法架构体系是一个召回排序的两阶段流程,召回模块从海量的候选池中召回多样的相关的候选物料,排序模块根据用户偏好和上下文信息给出用户最可能感兴趣的一个有序列表。
随着深度学习技术的普及,越来越多的深度学习算法被应用到了工业界中。笔者自去年毕业进入企业后,有幸参与了某新业务的推荐系统搭建以及用户体验和业务指标的优化当中,其中在召回部分也进行过一些基于向量召回的探索并取得了一些收益。
之前在读研期间出于个人兴趣开发过一个基于深度学习的点击率预测算法库DeepCTR(https://github.com/shenweichen/DeepCTR),随着时间的迭代得到了一些同学的支持和认可,自己也亲身使用到了里面的算法应用到了自己的业务当中并取得了显著的收益。
相比于排序中各种点击率预估模型,自己对于召回模块的了解还有很多欠缺,借着这个机会,抱着学习的心态,和几位热心的优秀小伙伴一起做了DeepMatch这个项目,希望它能够帮助到大家!
下面简单介绍一下如何安装和使用
通过pip安装
pip install -U deepmatch
文档
https://deepmatch.readthedocs.io/en/latest/
使用例子
下面已大家比较熟悉的YoutubeDNN为例子,给大家介绍如何使用 deepmatch进行召回模型的训练,用户和物品向量的导出,以及使用faiss进行近似最近邻搜索。
整段代码不到100行,可以是非常的方便进行学习和使用了~
import pandas as pd
from deepctr.inputs import SparseFeat, VarLenSparseFeat
from preprocess import gen_data_set, gen_model_input
from sklearn.preprocessing import LabelEncoder
from tensorflow.python.keras import backend as K
from tensorflow.python.keras.models import Model
from deepmatch.models import *
from deepmatch.utils import sampledsoftmaxloss
# 以movielens数据为例,取200条样例数据进行流程演示
data = pd.read_csvdata = pd.read_csv("./movielens_sample.txt")
sparse_features = ["movie_id", "user_id",
"gender", "age", "occupation", "zip", ]
SEQ_LEN = 50
negsample = 0
# 1. 首先对于数据中的特征进行ID化编码,然后使用 `gen_date_set` and `gen_model_input`来生成带有用户历史行为序列的特征数据
features = ['user_id', 'movie_id', 'gender', 'age', 'occupation', 'zip']
feature_max_idx = {}
for feature in features:
lbe = LabelEncoder()
data[feature] = lbe.fit_transform(data[feature]) + 1
feature_max_idx[feature] = data[feature].max() + 1
user_profile = data[["user_id", "gender", "age", "occupation", "zip"]].drop_duplicates('user_id')
item_profile = data[["movie_id"]].drop_duplicates('movie_id')
user_profile.set_index("user_id", inplace=True)
user_item_list = data.groupby("user_id")['movie_id'].apply(list)
train_set, test_set = gen_data_set(data, negsample)
train_model_input, train_label = gen_model_input(train_set, user_profile, SEQ_LEN)
test_model_input, test_label = gen_model_input(test_set, user_profile, SEQ_LEN)
# 2. 配置一下模型定义需要的特征列,主要是特征名和embedding词表的大小
embedding_dim = 16
user_feature_columns = [SparseFeat('user_id', feature_max_idx['user_id'], embedding_dim),
SparseFeat("gender", feature_max_idx['gender'], embedding_dim),
SparseFeat("age", feature_max_idx['age'], embedding_dim),
SparseFeat("occupation", feature_max_idx['occupation'], embedding_dim),
SparseFeat("zip", feature_max_idx['zip'], embedding_dim),
VarLenSparseFeat(SparseFeat('hist_movie_id', feature_max_idx['movie_id'], embedding_dim,
embedding_name="movie_id"), SEQ_LEN, 'mean', 'hist_len'),
]
item_feature_columns = [SparseFeat('movie_id', feature_max_idx['movie_id'], embedding_dim)]
# 3. 定义一个YoutubeDNN模型,分别传入用户侧特征列表`user_feature_columns`和物品侧特征列表`item_feature_columns`。然后配置优化器和损失函数,开始进行训练。
K.set_learning_phase(True)
model = YoutubeDNN(user_feature_columns, item_feature_columns, num_sampled=5, user_dnn_hidden_units=(64, 16))
# model = MIND(user_feature_columns,item_feature_columns,dynamic_k=True,p=1,k_max=2,num_sampled=5,user_dnn_hidden_units=(64,16),init_std=0.001)
model.compile(optimizer="adagrad", loss=sampledsoftmaxloss) # "binary_crossentropy")
history = model.fit(train_model_input, train_label, # train_label,
batch_size=256, epochs=1, verbose=1, validation_split=0.0, )
# 4. 训练完整后,由于在实际使用时,我们需要根据当前的用户特征实时产生用户侧向量,并对物品侧向量构建索引进行近似最近邻查找。这里由于是离线模拟,所以我们导出所有待测试用户的表示向量,和所有物品的表示向量。
test_user_model_input = test_model_input
all_item_model_input = {"movie_id": item_profile['movie_id'].values, "movie_idx": item_profile['movie_id'].values}
# 以下两行是deepmatch中的通用使用方法,分别获得用户向量模型和物品向量模型
user_embedding_model = Model(inputs=model.user_input, outputs=model.user_embedding)
item_embedding_model = Model(inputs=model.item_input, outputs=model.item_embedding)
# 输入对应的数据拿到对应的向量
user_embs = user_embedding_model.predict(test_user_model_input, batch_size=2 ** 12)
# user_embs = user_embs[:, i, :] i in [0,k_max) if MIND
item_embs = item_embedding_model.predict(all_item_model_input, batch_size=2 ** 12)
print(user_embs.shape)
print(item_embs.shape)
# 5. [可选的]如果有安装faiss库的同学,可以体验以下将上一步导出的物品向量构建索引,然后用用户向量来进行ANN查找并评估效果
test_true_label = {line[0]:[line[2]] for line in test_set}
import numpy as np
import faiss
from tqdm import tqdm
from deepmatch.utils import recall_N
index = faiss.IndexFlatIP(embedding_dim)
# faiss.normalize_L2(item_embs)
index.add(item_embs)
# faiss.normalize_L2(user_embs)
D, I = index.search(user_embs, 50)
s = []
hit = 0
for i, uid in tqdm(enumerate(test_user_model_input['user_id'])):
try:
pred = [item_profile['movie_id'].values[x] for x in I[i]]
filter_item = None
recall_score = recall_N(test_true_label[uid], pred, N=50)
s.append(recall_score)
if test_true_label[uid] in pred:
hit += 1
except:
print(i)
print("recall", np.mean(s))
print("hr", hit / len(test_user_model_input['user_id']))
完整代码见链接 https://github.com/shenweichen/DeepMatch/blob/master/examples/run_youtubednn_sampledsoftmax.py
同时我们也提供了在movielens-1M数据集上进行实验的notebook,感兴趣的同学可以运行一下试试~ https://github.com/shenweichen/DeepMatch/blob/master/examples/colab_MovieLen1M_YoutubeDNN.ipynb
一个人的力量有限,感谢一起参与开发的小伙伴们~~他们分别是:
王喆 京东广告算法工程师
blog: https://zhuanlan.zhihu.com/c_1218845039004119040
github: https://github.com/wangzhegeek
蔡庆亮 字节跳动高级广告算法工程师
blog: https://blog.csdn.net/cqlboat
github:https://github.com/LeoCai
杨婕妤,浙江大学研二找工作????,疯狂求各大公司收留
mail: [email protected]
github:https://github.com/Eleanoryuyuyu
我们也邀请了上面几位同学一起建立了DeepMatch的交流群,帮助同学们共同学习和交流。也欢迎感兴趣的同学加入我们一起进行开发!
希望大家多多支持,可以给我们来个star!
https://github.com/shenweichen/DeepMatch【点击阅读原文直达】
另外悄悄透露下:我们还有若干模型已经开发完成,等待测试好了就会公布,所以一定要关注我们呀!
本文原创首发于【浅梦的学习笔记】,想了解更多关于推荐系统的内容,欢迎扫码关注公众号。回复【加群】可以加入我们的交流群一起学习!
【浅梦的学习笔记】持续产出推荐/广告/搜索等算法相关技术干货和实践经验。关注公号后台回复口令「推荐入门」获取推荐系统入门必读的经典论文合集!
浅梦的学习笔记近期文章????
【论文笔记】谷歌最新双塔DNN召回模型——应用于YouTube大规模视频推荐场景
【论文笔记】如何刻画用户的多样兴趣——MIND阅读笔记
【视频讲解】DeepCTR中的DeepFM原理和实现
向量化召回在360信息流广告的实践
KDD19 DGL教程:Recommender System with GNN