Transformer在推荐系统中的应用

7b4368d73db48bd2900cae96121f0b55.gif

本文主要介绍一下Behavior sequence transformer for e-commerce recommendation in Alibaba文章和美团基于此文章所改进的算法。

1

BST模型

Behavior sequence transformer for e-commerce recommendation in Alibaba (https://arxiv.org/pdf/1905.06874.pdf) 模型简称 BST,基于用户的历史行为挖掘用户过去行为的关联性,及对候选商品的影响。其整体的架构如下:

18f8e487860ae8a05b05b48de1ff60f3.png

从架构图中看出,主要包含4部分:

(1)输入层;

(2)Embedding层;

(3)Transformer层;

(4)MLP层和输出层;

1.1 输入层

输入的特征包含:other特征,用户行为序列特征,候选商品特征。

(1)other特征,包括:用户画像特征、商品属性特征、上下文特征和交叉特征,这些特征均属于人工基于业务经验提取出的特征,具体见下表:

9dfd86bb1aaf6f760df33ef660491627.png

(2)用户行为序列特征,包括:历史行为中的商品ID序列(item_id)和商品品类ID序列(category_id),位置信息;

(3)候选商品的特征,包括:商品ID和商品品类ID,位置信息;

1.2 Embedding层

(1)other特征Embedding

other特征通过Embedding层将所有的特征映射成固定维度的向量,然后进行 Concat 操作。

(2)用户行为序列特征Embedding

将行为序列中的每个 item(包括目标 item)通过 Embedding 层映射成低维度的向量。每个 item 通过两部分来表示:“序列 item 特征”(红色部分)和“位置特征”(深蓝色部分)。其中:

“序列 item 特征”包括:商品ID序列(item_id)和商品品类ID序列(category_id)。位置特征用来刻画用户历史行为序列中的顺序信息,文中将“位置”作为中每个 item 的另一个输入特征,然后将其投射为低维向量。第  个位置的位置特征计算方式为  。其中:  表示推荐的时间戳, 表示用户点击商品  时的时间戳。作者表示该方式的效果优于 Attention Is All You Need  论文中使用的 sin 和 cos 函数。

(3)候选商品的特征Embedding

“ item 特征”(红色部分)和“位置特征”(深蓝色部分),同(2)

1.3 Transformer layer

本文中使用的 Transformer 层仅是 Attention Is All You Need  论文中的 Encoder 部分,捕捉用户历史行为序列中的各个 item 的关联特征,与此同时,加入候选 item 来达到抽取行为序列中的商品与待推荐商品之间的相关性。

主要包含:自注意力层、前向网络层、堆积自注意力模块。此处做简单介绍,感兴趣的朋友请阅读原论文 Attention Is All You Need 

(1)自注意力层

使用多头注意力机制,将特征的 Embedding 表达分为多个头,形成多个子空间,可以让模型去关注不同方面的信息,最后再将各个方面的信息综合起来。多次 Attention 综合的结果至少能够起到增强模型的作用,也可以类比 CNN 中同时使用多个卷积核的作用,直观上讲,多头注意力有助于网络捕捉到更丰富的信息。

bfc7928c408894b38f2998490869a582.png

21ba5e4812eebce8a8d2742b20a4dd10.png

972c841c049677e370568d8f249f1712.png

(2)前向网络层

目的是增加非线性。在 Self-Attention 和 FFN 中都使用了 Dropout 和 LeakyReLU,最终 Self-Attention 和 FFN 的输出为:

a71452cc6714b20041fc7f469567df64.png

c9d320c28d0ba99cdefbea8ed84bf4b2.png

(3)堆积自注意力模块

上面的两步操作被称为一个 Self-Attention 单元,为了抽取出 item 序列中更加复杂的潜在关联特征,该模型堆叠了N层 Self-Attention 单元。

48baf3a8f7a65a6ab4c289c37ea75694.png

1.4 MLP层和输出层

将所有的 Embedding 进行拼接,输入到三层的神经网络中,并最终通过 Sigmoid 函数转换为 0-1 之间的值,代表用户点击目标商品的概率。Loss 函数如下所示:

525efc185039948fcbc30b33b91b8244.png

2

美团改进版:BST+DIN模型

美团改进版地址见:Transformer 在美团搜索排序中的实践 (https://mp.weixin.qq.com/s/Oixc46P9rQeiMDjI-0j0cw) 一文。

主要模型结构如下图所示:

68157cd2173885fcec800cd82a661663.png

可以看到较 BST 模型,增加了候选商品与 Transformer 的结果做 Attention 的环节(即DIN模型),DIN模型使用注意力机制来捕获目标商品与用户先前行为序列中商品之间的相似性。

美团实践经验:

  • Transformer 编码为什么有效?Transformer 编码层内部的自注意力机制,能够对序列内 item 的相互关系进行有效的建模来实现更好的表达,并且我们离线实验不加 Transformer 编码层的 Attention-pooling,发现离线 NDCG 下降,从实验上证明了 Transformer 编码有效。

  • Transformer 编码为什么优于 GRU ?忽略 GRU 的性能差于 Transformer;我们做过实验将行为序列长度的上限往下调,Transformer 的效果相比 GRU 的效果提升在缩小,但是整体还是行为序列的长度越大越好,所以Transformer 相比 GRU 在长距离时,特征捕获能力更强。

  • 位置编码(Pos-Encoding)的影响:我们试过加 Transformer 里面原生的正余弦以及距当前预测时间的时间间隔的位置编码都无效果,分析应该是我们在处理行为序列的时候,已经将序列切割成不同时间段,一定程度上包含了时序位置信息。为了验证这个想法,我们做了仅使用一个长序列的实验(对照组不加位置编码,实验组加位置编码,离线 NDCG 有提升),这验证了我们的猜测。

  • Transformer 编码层不需要太多,层数过多导致模型过于复杂,模型收敛慢效果不好。

  • 调节多头注意力的“头”数对效果影响不大。

3

 BST+DIN 模型实现

根据美团的 BST+DIN 算法结构,人造特征做了简单版的实现。

import tensorflow as tf
from tensorflow.keras.layers import Input, Embedding, concatenate, Flatten, Dense, Dropout

from tensorflow.keras.models import Model
from tensorflow.keras.optimizers import Adam
from tensorflow.keras.callbacks import EarlyStopping
from tensorflow.keras.utils import plot_model

from transformer import Encoder, padding_mask
from din import DinAttentionLayer, din_padding_mask

def bst_model(sparse_input_length = 1, \
    max_seq_length = 50, \
    vocab_size_dict = None, \
    embedding_dim = 512, \
    dnn_unit_list = [512, 128, 32], \
    activation = 'relu', \
    dropout_rate = 0.2, \
    n_layers = 2, \
    num_heads = 8, \
    middle_units = 1024, \
    training = False
    ):
    
    # 1. Input layer
    
    # 1.1 user
    user_id_input_layer = Input(shape=(sparse_input_length, ), name="user_id_input_layer")
    gender_input_layer = Input(shape=(sparse_input_length, ), name="gender_input_layer")
    age_input_layer = Input(shape=(sparse_input_length, ), name="age_input_layer")
    
    user_click_item_seq_input_layer = Input(shape=(max_seq_length, ), name="user_click_item_seq_input_layer")
    user_click_cate_seq_input_layer = Input(shape=(max_seq_length, ), name="user_click_cate_seq_input_layer")
    
    # 1.2 item
    item_input_layer = Input(shape=(sparse_input_length, ), name="item_input_layer")
    cate_input_layer = Input(shape=(sparse_input_length, ), name="cate_input_layer")
    
    # 2. Embedding layer
    
    # 2.1 user
    user_id_embedding_layer = Embedding(vocab_size_dict["user_id"]+1, embedding_dim, \
                                        mask_zero=True, name='user_id_embedding_layer')(user_id_input_layer)
    gender_embedding_layer = Embedding(vocab_size_dict["gender"]+1, embedding_dim, \
                                       mask_zero=True, name='gender_embedding_layer')(gender_input_layer)
    age_embedding_layer = Embedding(vocab_size_dict["age"]+1, embedding_dim, \
                                    mask_zero=True, name='age_embedding_layer')(age_input_layer)
    
    item_id_embedding = Embedding(vocab_size_dict["item_id"]+1, embedding_dim, \
                                mask_zero=True, name='item_id_embedding')
    cate_id_embedding = Embedding(vocab_size_dict["cate_id"]+1, embedding_dim, \
                                mask_zero=True, name='cate_id_embedding')
    
    user_click_item_seq_embedding_layer = item_id_embedding(user_click_item_seq_input_layer)
    user_click_cate_seq_embedding_layer = cate_id_embedding(user_click_cate_seq_input_layer)
    
    # 2.2 item
    target_item_embedding_layer = item_id_embedding(item_input_layer)
    target_cate_embedding_layer = cate_id_embedding(cate_input_layer)
    
    # 3. Concat layer
    
    # 3.1 user: other features
    other_features_concat_layer = concatenate([user_id_embedding_layer, gender_embedding_layer, \
                                               age_embedding_layer], axis=-1)
    
    # 3.1 user: sequence features
    input_transformer_layer = concatenate([user_click_item_seq_embedding_layer, \
                                           user_click_cate_seq_embedding_layer], axis=-1)

    # 3.2 item
    input_din_layer_query = concatenate([target_item_embedding_layer, \
                                         target_cate_embedding_layer], axis=-1)

    # 4. Transformer layer

    d_model = input_transformer_layer.shape[-1]
    padding_mask_list = padding_mask(user_click_item_seq_input_layer)
    
    output_tranformer_layer = Encoder(n_layers, d_model, num_heads,
             middle_units, max_seq_length, training)([input_transformer_layer, padding_mask_list])

    # 5. Din attention layer
    
    query = input_din_layer_query
    keys = output_tranformer_layer
    vecs = output_tranformer_layer
    
    din_padding_mask_list = din_padding_mask(user_click_item_seq_input_layer)

    output_din_layer = DinAttentionLayer(d_model, middle_units, dropout_rate)([query, keys, vecs, din_padding_mask_list])
    
    # 6. DNN layer
    input_dnn_layer = concatenate([other_features_concat_layer, output_din_layer], \
             axis=-1)
    
    input_dnn_layer = tf.squeeze(input=input_dnn_layer, axis=[1])

    for inx in range(len(dnn_unit_list)):
        input_dnn_layer = Dense(dnn_unit_list[inx], activation=activation, \
           name="FC_{0}".format(inx+1))(input_dnn_layer)
        
        input_dnn_layer = Dropout(dropout_rate, name="dropout_{0}".format(inx+1))(input_dnn_layer)
        
    
    output = Dense(1, activation='sigmoid', \
                   name='Sigmoid_output_layer')(input_dnn_layer)

    # Output model
    
    inputs_list = [user_id_input_layer, gender_input_layer, age_input_layer, \
      user_click_item_seq_input_layer, user_click_cate_seq_input_layer, \
                   item_input_layer, cate_input_layer]
    
    model = Model(inputs = inputs_list, outputs = output)

    return model

if __name__ == "__main__":
    vocab_size_dict = {
    "user_id": 300,
    "gender": 2,
    "age": 10,
    "item_id": 5000,
    "cate_id": 213}

    bst_model = bst_model(vocab_size_dict=vocab_size_dict)

    print(bst_model.summary())
    
    plot_model(bst_model, to_file='bst_model.png')

模型结构图如下所示:

3f2e840cbdc7f56fc9412b4548cdf49e.png

其中:Encoder 层和 DinAttentionLayer 层为自定义层。详情请参考:https://github.com/wziji/deep_ctr/tree/master/BST

d975f14a6993d2b8312fb22fe7562187.png

欢迎关注 “python科技园” 及 添加小编 进群交流。

8e9e144e740ec6f1b4bf6d73dc5eec30.png

喜欢的话请分享、点赞、在看吧~

  • 2
    点赞
  • 15
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
Transformer在印刷领域有多种应用,其之一是文本识别(OCR)。OCR是将印刷体的图像转换为可编辑的文本的过程。Transformer可以用于OCR任务的文本识别模型,以提高识别准确性和效率。 在OCRTransformer可以用于两个主要任务:文本检测和文本识别。文本检测是指在图像定位和提取出文本区域的过程,而文本识别是将提取出的文本区域转换为可编辑的文本。 对于文本检测任务,可以使用Transformer来构建一个目标检测模型,例如基于YOLO或Faster R-CNN的模型。这些模型可以检测图像的文本区域,并生成边界框来定位文本。 对于文本识别任务,可以使用Transformer来构建一个序列到序列(seq2seq)模型,例如基于Transformer的编码器-解码器架构。在这种模型,编码器将输入图像的文本区域编码为一个固定长度的向量表示,然后解码器将该向量表示转换为可编辑的文本。 Transformer在OCR应用有以下优势: 1. 处理长文本:由于Transformer的自注意力机制,它可以有效地处理长文本序列,这在OCR任务非常重要。 2. 上下文建模:Transformer可以捕捉文本序列的上下文信息,从而提高文本识别的准确性。 3. 并行计算:Transformer的自注意力机制使得可以并行计算输入序列的不同位置,从而提高了模型的训练和推理速度。 因此,Transformer在印刷领域的应用主要是用于文本识别任务,可以提高OCR系统的准确性和效率。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值