zoukankan      html  css  js  c++  java
  • 初学推荐系统-05-Wide&Deep [附tensorflow的WideDeepModel代码简单实践]

    1. 点击率预估简介

    点击率预估是用来解决什么问题?

    点击率预估是对每次广告点击情况作出预测,可以输出点击或者不点击的概率 —— PClick.

    点击率模型需要做什么?

    • 其实点击率模型预估问题就是一个二分类问题
    • 逻辑回归输出的就是[0,1]的概率值
    • 因此可以使用LR的方式来学习建立模型

    点击率预估与推荐算法有什么不同?

    • 点击率预估: 需要得到某个用户对广告的点击率,然后结合报价信息用于排序(常用于AD业务)
    • 推荐算法: 常常是TopN推荐的问题,很多情况下只需要得到一个最优的推荐次序,当然,广告的点击率也是可以使用的

    2. FM与Wide&Deep的相较之下的区别

    • FM的缺点
      • 当矩阵过于稀疏并且是high-rank的时候(比如user有特殊的爱好,或item比较小众),很难非常效率的学习出低维度的表示
      • 当矩阵过于稠密(dense embedding)的时候,会导致几乎所有的query-item的预测值都为0,这就导致了推荐过渡泛化,会推荐一些不再那么相关的物品。
      • 一些异常规则(exception rules), 可以通过linear model来记住这些,具体方法:cross-product transformation(交叉产品转化法,下面再细讲)。

    3. Wide & Deep模型的“记忆能力”与“泛化能力”

    3.1 简介“记忆能力”与“泛化能力”

    image-20200910214310877
    • 记忆能力:通过用户与商品的交互信息矩阵学习规则 (更加保守,会更多推荐之前积累的经验和规则,线性模型就可以实现)
      • FM算法就是很好的泛化例子,他通过交互信息学习到一个比较短的矩阵V,其中Vi存储着每个用户特征的压缩表示(embedding:实物映射为向量),
      • 而协同过滤与SVD都是靠记住用户之前与那些物品交互,进而(加权、平均、相近)推测判断出推荐结果的
      • 我们的Wide&Deep模型就是能够融合这两种推荐结果而做出最终的推荐,得出一个比之前的推荐结果逗号的模型。
    • 泛化能力:(机器学习算法对新鲜样本的适应能力,在Rs中指的是更趋于多样化,便于提高推荐系统的多样性,多使用DNN来实现)
      • 泛化规则(又快又稳又好)
    • 组合后需要注意的点:用户需要根据自己的场景去选择哪些特征放在Wide部分。

    3.2 如何理解Wide部分有利于增强模型的“记忆能力”,Deep部分有利于增强模型的“泛化能力”?

    • Wide部分

      • 总体是一个广义的线性模型
      • 输入特征包括两个部分:原始的部分特征+原始特征的交互特征((cross-product transformation),对于交互特征可以定义为:(当两个特征同时都为1的时候,这个新的特征才能为1,否则就是0,说白了就是一个AND组合特征)

      [phi_{k}(x)=prod_{i=1}^d x_i^{c_{ki}}, c_{ki}in {0,1} ]

      • 优化器: Wide模型使用待L1正则化的FTRL算法(跟随正规化-领头算法),而L1 FTLR是非常注重模型稀疏性质的; W&D模型采用的是想让Wide部分变得更加稀疏(什么规则???), 即Wide部分的大部分参数都为0,这就大大压缩了模型权重以及特征向量的维度.
      • Wide部分模型训练完之后留下来的矩阵都是非常重要的, 这是模型的"记忆能力"就凸显了出来,得到留下的特征大多都是直接的、暴力的、显然的关联规则的能力。
      • 举个例子,Google W&D期望wide部分发现这样的规则:用户安装了应用A,此时曝光应用B,用户安装应用B的概率大。
    • DEEP部分

      • Deep部分是一个DNN模型,输入的特征主要分为两大类,一类是数值特征(可以直接输入DNN),一类是特别的特征(需要经过Embrdding映射转换之后才可以输入到DNN中),Deep部分的数学形式如下:

      [a^{(l+1)} = f(W^{l}a^{(l)} + b^{l}) ]

      • 我们知道DNN模型随着层数的增加,中间的特征就越抽象,也就提高了模型的泛化能力。
      • 对于Deep部分的DNN模型作者使用了深度学习常用的优化器AdaGrad,这也是为了使得模型可以得到更精确的解。
    • Wide部分与Deep部分的结合

      • W&D模型是将两部分输出的结果结合起来联合训练,将deep和wide部分的输出重新使用一个逻辑回归模型做最终的预测,输出概率值。联合训练的数学形式如下:

      [P(Y=1|x)=delta(w_{wide}^T[x,phi(x)] + w_{deep}^T a^{(lf)} + b) ]

    4. 操作流程

    • Retrieval(检索) :利用机器学习模型和一些人为定义的规则,来返回最匹配当前Query的一个小的items集合,这个集合就是最终的推荐列表的候选集。
    • Ranking(排名推荐TopN):
      • 收集更细致的用户特征,如:
        • User features(年龄、性别、语言、民族等)
        • Contextual features(上下文特征:设备,时间等)
        • Impression features(展示特征:app age、app的历史统计信息等)
      • 将特征分别传入Wide和Deep一起做训练。在训练的时候,根据最终的loss计算出gradient,反向传播到Wide和Deep两部分中,分别训练自己的参数(wide组件只需要填补deep组件的不足就行了,所以需要比较少的cross-product feature transformations,而不是full-size wide Model)
        • 训练方法是用mini-batch stochastic optimization。
        • Wide组件是用FTRL(Follow-the-regularized-leader) + L1正则化学习。
        • Deep组件是用AdaGrad来学习。
      • 训练完之后推荐TopN
        所以wide&deep模型尽管在模型结构上非常的简单,但是如果想要很好的使用wide&deep模型的话,还是要深入理解业务,确定wide部分使用哪部分特征,deep部分使用哪些特征,以及wide部分的交叉特征应该如何去选择

    5. tensorflow的安装

    今天网速还OK,从新开了一个conda环境,照着教程完美安装完成;刚开始在老的环境上pip倒是可以成功,但是还有些版本啥的没有对应;conda就像是docker,来个新的,照着别人的教程,一般不会再出新的环境问题。
    参考链接:

    1. Windows下安装Anaconda3(附带python3.8)以及TensorFlow
      https://blog.csdn.net/weixin_42412254/article/details/107569830

    6. 代码实战

    # -*- coding: utf-8 -*-
    # 第一步安装,调包
    from pyfm import pylibfm
    from sklearn.feature_extraction import DictVectorizer
    import numpy as np
    import tensorflow as tf
    from sklearn.metrics import mean_squared_error
    
    from tensorflow_core.python.keras.premade.linear import LinearModel
    from tensorflow_core.python.keras.premade.wide_deep import WideDeepModel
    from tensorflow import keras
    
    if __name__ == '__main__':
        # 第二步:创建训练集并转换成one-hot编码的特征形式
        train = [
            {"user": "1", "item": "5", "age": 19},
            {"user": "2", "item": "43", "age": 33},
            {"user": "3", "item": "20", "age": 55},
            {"user": "4", "item": "10", "age": 20},
        ]
        # DictVectorizer() Transforms lists of feature-value mappings to vectors.
        dv = DictVectorizer()
        X_train = dv.fit_transform(train)
        print(X_train.toarray())
    
        # 第三步:创建标签, 这里简单创建了一个全1的标签:
        y_train = np.repeat(1.0, X_train.shape[0])
    
        # 第四步:训练并预测, 就和调用sklearn的包是一样的用法:
        fm = pylibfm.FM()
        fm.fit(X_train, y_train)
        X_test = dv.transform({"user": "1", "item": "10", "age": 24})
        y_test = fm.predict(X_test)
        print(y_test)
    
        print('#' * 20)
    
        # 查看tensorflow版本
        print('tensorflow版本:', tf.__version__)
    
        # 第一部分是使用tensorflow中已经封装好的wide&deep模型
        # Tensorflow内置的WideDeepModel
        linear_model = LinearModel()
        dnn_model = keras.Sequential([keras.layers.Dense(units=64),
                                      keras.layers.Dense(units=1)])
        combined_model = WideDeepModel(linear_model, dnn_model)
        combined_model.compile(optimizer=['sgd', 'adam'], loss='mse', metrics=['mse'])
        # define dnn_inputs and linear_inputs as separate numpy arrays or
        # a single numpy array if dnn_inputs is same as linear_inputs.
    
        # 格式转换
        # [[19.  0.  0.  0.  1.  1.  0.  0.  0.]
        #  [33.  0.  0.  1.  0.  0.  1.  0.  0.]
        #  [55.  0.  1.  0.  0.  0.  0.  1.  0.]
        #  [20.  1.  0.  0.  0.  0.  0.  0.  1.]]
        # [0.99806595]
    
        linear_inputs = X_train.toarray()
        dnn_inputs = linear_inputs
        epochs = 100
        # y_train = y_train
    
        # or define a single `tf.data.Dataset` that contains a single tensor or
        # separate tensors for dnn_inputs and linear_inputs.
        # train_dataset = tf.data.Dataset.from_tensors(())
        combined_model.fit([linear_inputs, dnn_inputs], y_train, epochs)
    
        # 模型验证
        # Returns the loss value & metrics values for the model in test mode.
    
        loss_mse = combined_model.evaluate([linear_inputs, dnn_inputs], y_train, epochs)
        print('loss,mse', loss_mse)
    
        # 预测
        linear_test_inputs= X_test.toarray()
        dnn_test_inputs = linear_test_inputs
        y_test = [1]
        pre = combined_model.predict([linear_test_inputs, dnn_test_inputs])
        print(pre) 
    

    简易输出:(前半部分是FM的代码,tensorflow还需要再深度学习)

    [[19.  0.  0.  0.  1.  1.  0.  0.  0.]
     [33.  0.  0.  1.  0.  0.  1.  0.  0.]
     [55.  0.  1.  0.  0.  0.  0.  1.  0.]
     [20.  1.  0.  0.  0.  0.  0.  0.  1.]]
    Creating validation dataset of 0.01 of training for adaptive regularization
    -- Epoch 1
    Training log loss: 0.27579
    [0.98898911]
    ####################
    tensorflow版本: 2.0.0
    2020-11-22 21:42:27.116396: I tensorflow/core/platform/cpu_feature_guard.cc:142] Your CPU supports instructions that this TensorFlow binary was not compiled to use: AVX2
    Train on 4 samples
    4/4 [==============================] - 1s 217ms/sample - loss: 17.6376 - mse: 17.6376
    4/1 [========================================================================================================================] - 0s 24ms/sample - loss: 469.0519 - mse: 469.0519
    [469.0518798828125, 469.05188]
    [[-13.908051]]
    import sys; print('Python %s on %s' % (sys.version, sys.platform))
    Python 3.7.9 (default, Aug 31 2020, 17:10:11) [MSC v.1916 64 bit (AMD64)] on win32
    
    
    你不逼自己一把,你永远都不知道自己有多优秀!只有经历了一些事,你才会懂得好好珍惜眼前的时光!
  • 相关阅读:
    oracle闪回查询
    带搜索框的jQuery下拉框插件
    Eclipse、Tomcat、Spring3等使用过程的一些配置、错误等的总结记录
    局域网不能访问本机IIS网站的解决方法
    在同一台电脑部署多个Tomcat服务
    Tomcat重启脚本
    IE8下面parseInt('08')、parseInt('09')会转成0
    [转]Examining Open vSwitch Traffic Patterns
    [转]Ubuntu Precise
    [转] iptables
  • 原文地址:https://www.cnblogs.com/zhazhaacmer/p/13888400.html
Copyright © 2011-2022 走看看