原文链接:https://arxiv.org/pdf/1606.07792.pdf
简单介绍
wide&deep顾名思义就是通过算法优化对用户进行个性化推荐(deep)和广泛推荐(wide)的算法。是谷歌公司发布于2016年的论文。比如再刷新闻的时候,软件时常会给你推荐很多种类,还会推荐你特别感兴趣的,这就和这种算法差不多。当然这个得区分热点推荐等。
main contributions:
- 帮助解决稀疏输入的通用推荐系统,用于训练带有嵌入的前馈神经网络和线性变换的线性模型。
- 这个推荐系统的实施和评估是在线实验
- 该算法在TensorFlow上有开源的数据接口,可以直接调用
Wide&Deep算法框架
在Wide&Deep算法框架上分为两个部分一个为线性模型(Wide Models)
公式为:
Y
=
W
T
X
+
b
\ Y = W^{T}X+b\,
Y=WTX+b
在个模型中我们将项目的特征作为输入也就是当做公式中的X,X = [x1, x2, x3,…xn], 公式中的W和b都是这个模型中的参数,通过训练可以得到这个模型的相关参数设置。
在上式中,就是一个做与运算的公式,只有都为true才为1,否则为0.通过这个公式,Wide Models可以捕捉了二元特征之间的相互作用,增加了广义线性模型的非线性。
上图为推荐系统在应用过程中的框架图。
Deep Models部分是一个前馈神经网络的模型,公式为:
a
(
l
+
1
)
=
f
(
W
l
a
l
+
b
l
)
\ a^{(l+1)} = f( W^{l}a^{l}+b^{l})\,
a(l+1)=f(Wlal+bl)
这个公式中的f表示的是激活函数,其中使用的是ReLu()函数,l表示的是神经网络模型的层数。
Wide&Deep连解部分
公式描述:
通过训练不同的wide和deep权重来计算wide和deep推荐的重要性,其中使用的是sigmoid激活函数。
通过计算每个项目最终得分进行排名再对项目进行推荐。
代码部分
正因为Wide侧不能发现新模式,因此我们需要根据人工经验、业务背景,将我们认为有价值的、显而易见的特征及特征组合,喂入Wide侧
Deep侧就是DNN,通过embedding的方式将categorical/id特征映射成稠密向量,让DNN学习到这些特征之间的深层交叉,以增强扩展能力。
# Wide&Deep 模型的wide部分及Deep部分的特征选择,应该根据实际的业务场景去确定哪些特征应该放在Wide部分,哪些特征应该放在Deep部分
def WideNDeep(linear_feature_columns, dnn_feature_columns):
# 构建输入层,即所有特征对应的Input()层,这里使用字典的形式返回,方便后续构建模型
dense_input_dict, sparse_input_dict = build_input_layers(linear_feature_columns + dnn_feature_columns)
# 将linear部分的特征中sparse特征筛选出来,后面用来做1维的embedding
linear_sparse_feature_columns = list(filter(lambda x: isinstance(x, SparseFeat), linear_feature_columns))
# 构建模型的输入层,模型的输入层不能是字典的形式,应该将字典的形式转换成列表的形式
# 注意:这里实际的输入与Input()层的对应,是通过模型输入时候的字典数据的key与对应name的Input层
input_layers = list(dense_input_dict.values()) + list(sparse_input_dict.values())
# Wide&Deep模型论文中Wide部分使用的特征比较简单,并且得到的特征非常的稀疏,所以使用了FTRL优化Wide部分(这里没有实现FTRL)
# 但是是根据他们业务进行选择的,我们这里将所有可能用到的特征都输入到Wide部分,具体的细节可以根据需求进行修改
linear_logits = get_linear_logits(dense_input_dict, sparse_input_dict, linear_sparse_feature_columns)
# 构建维度为k的embedding层,这里使用字典的形式返回,方便后面搭建模型
embedding_layers = build_embedding_layers(dnn_feature_columns, sparse_input_dict, is_linear=False)
dnn_sparse_feature_columns = list(filter(lambda x: isinstance(x, SparseFeat), dnn_feature_columns))
# 在Wide&Deep模型中,deep部分的输入是将dense特征和embedding特征拼在一起输入到dnn中
dnn_logits = get_dnn_logits(dense_input_dict, sparse_input_dict, dnn_sparse_feature_columns, embedding_layers)
# 将linear,dnn的logits相加作为最终的logits
output_logits = Add()([linear_logits, dnn_logits])
# 这里的激活函数使用sigmoid
output_layer = Activation("sigmoid")(output_logits)
model = Model(input_layers, output_layer)
return model
简单来说,这个模型的左边就是一个简单的线性回归模型,右边是一个DNN模型,通过这两个模型,训练出这两个模型各自所占的权重后,通过激活函数得到最终结果。当然这两个模型中DNN模型有对输入的数据进行embedding.
思考
思考题中有一个题目问道为什么deep不需要考虑数据的稀疏性的问题。我个人觉得这个可能就是embedding越来越常用,方法越来越多的原因。由于现在的数据量越来越大,如果依旧使用传统的协同过滤算法,或者简单的onehot编码等方法会存在运算量较大、数据稀疏性的问题。而使用embedding的方法,我们可以将某个项目的特征降维到,降低了运算的时间和空间复杂度的问题。同时还可以用过各种手段不断来优化项目的特征表示。这代表着我们可以通过这些手段得到更好的结果。
由于这篇文章来自于谷歌,且发表于2016年。这其实给了我们很多启发,网络模型并不是越复杂越好,层数越多越好。很多时候一些简单的算法也能取得很好的效果。