BERT4Rec

BERT4Rec

1.简介

在BERT4Rec出现之前,推荐系统试用的算法都是用序列神经网络从左到右地顺序编码用户的历史交互信息,采用这种编码方式,只利用了单项信息。但是,自然界中很多行为没有空间顺序的限制,为了解决这个问题,BERT4Rec采用了深层的双向注意力机制(双向self-attention)来对用户行为序列进行建模。为了充分利用数据信息,采用Cloze目标进行序列推荐,通过联合item左右的上下文来预测序列中随机masked item。采用这种方式,用户历史行为中每个item都会融合左右两侧信息。

注:cloze task 是bert模型预测训练的两个任务之一,等价于完形填空任务, 即给出句子中其他的上下午token, 推测出当前位置应当是什么token.

self-attention是用于同时建立两个输入序列之间的关联以及单个序列内部的关联。

2.BERT4Rec

问题定义

我们定义,U={u1,u2,...,u∣U∣}U = \{u_1,u_2,...,u_{|U|}\}U={u1,u2,...,uU}为用户集合,V={v1,v2,...,v∣V∣}V = \{v_1,v_2,...,v_{|V|}\}V={v1,v2,...,vV}为物品集合,Su=[v1(u),...,vt(u),...,vnu(u)]S_u = [v_1^{(u)},...,v_t^{(u)},...,v_{n_u}^{(u)}]Su=[v1(u),...,vt(u),...,vnu(u)]为用户历史行为序列。我们下一个目标是预测下一时刻用户与每个候选物品交互的概率。
p(vnu+1(u)=v∣Su) p(v_{n_u+1}^{(u)} = v|S_u) p(vnu+1(u)=vSu)

模型结构

如下图BERT4Rec,每一层的transformer都会利用前一层的信息。相比于RNN,self-attention可以获得任意位置的信息。相比于CNN,可以获得整个field的信息。并且,该模型为双向传播,可以解决单向传播模型信息缺失的问题。

在这里插入图片描述

Transformer层

Multi-Head Self-attention

对于第LLL层中的Transformer,输入HLH^LHL,首先使Multi-Head Self-Attention:
MH(HL)=[head1,head2,...,headh]headi=Attention(HLWiQ,HLWiK,HLWiV)Attention(Q,K,V)=softmax(QKTd/h)V MH(H^L)=[head_1,head_2,...,head_h]\\ head_i = Attention(H^LW_i^Q,H^LW_i^K,H^LW_i^V)\\ Attention(Q,K,V)=softmax(\frac{QK^T}{\sqrt{d/h}})V MH(HL)=[head1,head2,...,headh]headi=Attention(HLWiQ,HLWiK,HLWiV)Attention(Q,K,V)=softmax(d/hQKT)V
HLH^LHL表示从embedding layer传入过来的数据

HLWiQH^LW_i^QHLWiQ表示embedding后乘上三个权重矩阵,从而获得三个向量矩阵qkv

AttentionAttentionAttention激活函数使用softmax获得多头注意力

Dropout和Add & Norm

在多注意力层之后,加入Dropout层,在这里我们设定一个概率ppp随机关闭几个神经元,避免模型的退化(过拟合,梯度爆炸或者梯度消散)

Add&NormAdd \& NormAdd&Norm分成两部分Add和Norm
LayerNorm(X+MultiHeadAttention(X)) LayerNorm(X + MultiHeadAttention(X)) LayerNorm(X+MultiHeadAttention(X))

  1. add

    在注意力机制上加上一个残差项X,加入残差项的目的和Dropout一样,为了防止训练过程中模型发生退化的问题。

    在这里插入图片描述

  2. Normalize

    归一化目的:
    1、加快训练速度
    2、提高训练的稳定性
    使用到的归一化方法是Layer Normalization。

    Layer Normalization指的是在同一个样本中,不同神经元之间进行归一化,而Batch Normalization是在同一个batch中不同样本之间的同一位置的神经元之间进行归一化。

    在这里插入图片描述

Positon-wise Feed-Forward Network位置向前传播全连接层

为了增加模型的非线性特性(softmax不是非线性特质么?),我们将每个位置的向量输入到向前神经网络,随后使用激活函数增加非线性特征
PFFN(Hl)=[FFN(h1l),...,FFN(htl)T]TFFN(x)=GELU(xW(1)+b(1))W(2)+b(2)GELU(X)=xΦ(x) PFFN(H^l) = [FFN(h_1^l),...,FFN(h_t^l)^T]^T\\ FFN(x) = GELU(xW^{(1)}+b^{(1)})W^{(2)}+b^{(2)}\\ GELU(X) = x\Phi(x) PFFN(Hl)=[FFN(h1l),...,FFN(htl)T]TFFN(x)=GELU(xW(1)+b(1))W(2)+b(2)GELU(X)=xΦ(x)
这里使用的激活函数是Gaussian Error Linear Unit(GELU),而非RELU。GELU在RELU的基础上加入了统计的特性,在论文中有较好的效果。

Embedding层

对于给定物品viv_ivi,加上位置信息pip_ipi,得到输入embedding
hi0=vi+pi h_i^0 = v_i + p_i hi0=vi+pi

Output层

经过L层的Transformer之后,我们得到所有的items最终输出HL={h1L,...,ht−1L,htL}H^L = \{h_1^L,...,h_{t-1}^L,h_{t}^L\}HL={h1L,...,ht1L,htL}

我们再第t步的时候,将物品vtv_tvt加上mask集掩盖住,随后基于htLh_t^LhtL预测物品vtv_tvt

最终使用GELU激活函数的前馈网络的最终输出为:(两层GELU?)
P(v)=softmax(GELU(htLWp+bP)ET+bO) P(v) = softmax(GELU(h_t^LW^p+b^P)E^T + b^O) P(v)=softmax(GELU(htLWp+bP)ET+bO)
这里的输出层公式是推荐场景特有的。WpW^pWp是前馈网络的权重矩阵;bPb^PbPbOb^ObO是偏置项;EEE是item集合的embedding矩阵。BERT4Rec模型再输入层和输出层用的物品embedding矩阵是相同的,即物品embedding不参与拟合,目的是减轻过拟合以及减小模型体积。

模型训练和预测

为了提升模型的泛化性,我们借鉴BERT中的Masked Language Model的训练方式,随机把输入序列的一部分掩盖变为[mask],让模型来预测该位置对应的物品。
Input:[v1,v2,v3,v4,v5]−>[v1,[mask]1,v3,[mask]4,v5]Labels:[mask]1=v2,[mask]2=v4 Input:[v_1,v_2,v_3,v_4,v_5]->[v_1,[mask]_1,v_3,[mask]_4,v_5]\\ Labels:[mask]_1=v_2,[mask]_2=v_4 Input:[v1,v2,v3,v4,v5]>[v1,[mask]1,v3,[mask]4,v5]Labels[mask]1=v2,[mask]2=v4

损失函数:
L=1∣Sum∣∑vm∈Sum−logP(vm=vm∗∣Su′) L =\frac{1}{|S_u^m|}\sum_{v_m\in S_u^m}{-logP(v_m = v_m^*|S'_u)} L=Sum1vmSumlogP(vm=vmSu)
其中

Su′S'_uSu是用户行为序列SuS_uSu的掩码版本

SumS_u^mSum是在Su′S'_uSu序列中所有的随机掩码项

vmv_mvm是掩码项的真实值

vm∗v^*_mvm是掩码项的预测值

如上所述,我们在训练过程和最终的序列预测推荐任务之间是不匹配的。因为Cloze task的目的是预测当前被masked的物品,而序列预测推荐的目的是预测未来

为了解决这个问题,在预测阶段我们将masked附加到用户行为序列的末尾,然后根据该masked的最终隐藏表示来预测下一项。

为了更好地匹配序列推荐任务(即,预测最后一项),在训练过程中我们还生成了只mask输入序列中最后一项的样本。这个工作就像对序列推荐的微调一样,可以进一步提高推荐性能。

3.参考文档

https://blog.youkuaiyun.com/u013069552/article/details/131250923
https://zhuanlan.zhihu.com/p/263014307
https://arxiv.org/pdf/1904.06690.pdf
https://arxiv.org/pdf/1904.06690.pdf

### BERT4REC 实现及其在推荐系统中的应用 #### 背景介绍 BERT4REC 是一种基于 Transformer 的序列化推荐算法,其核心思想来源于自然语言处理领域的双向编码器表示(Bidirectional Encoder Representations from Transformers)。该方法通过建模用户的交互历史来预测下一个可能的行为。它利用掩码语言模型(Masked Language Model, MLM)和因果语言模型(Causal Language Model, CLM),从而捕捉用户行为的上下文关系。 在推荐系统的背景下,BERT4REC 将用户的历史交互视为一系列 token 序列,并尝试通过对这些序列的学习来进行个性化推荐[^1]。 --- #### 技术实现要点 以下是 BERT4REC 在推荐系统中的主要实现步骤和技术细节: 1. **输入表示** 用户的历史交互被转化为一个由 item ID 组成的序列 \( S = \{i_1, i_2, ..., i_n\} \),其中每个 \( i_k \) 表示用户的一个交互项。为了适配 Transformer 结构,通常会将这些 item ID 映射到嵌入向量空间中[^3]。 2. **掩码机制** 掩码语言模型的核心在于随机遮蔽部分位置上的 items 并让模型去预测它们。具体来说,在训练过程中,某些 tokens 会被替换为特殊标记 `[MASK]` 或其他替代值。这种设计使得模型能够学习到更丰富的上下文依赖关系[^4]。 3. **Transformer 编码层** 使用多头注意力机制捕获全局范围内的关联模式。每一层都包含两个子模块:一个多头自注意网络以及一个前馈神经网络。经过若干堆叠后的隐藏状态可以用来生成最终的输出分布[^2]。 4. **目标函数** 对于给定的时间步 t 和对应的 ground truth label y_t ,交叉熵损失定义如下: ```python loss = -log(p(y_t | h_{t})) ``` 其中 p(\(y_t|h_t)\)) 表示根据当前时刻隐含表征计算得到的概率估计值。 5. **微调阶段** 预训练完成后进入下游任务特定调整期——即针对实际应用场景重新设置参数权重并优化性能指标的过程。例如,在电子商务网站上部署时可考虑加入商品类别特征作为额外辅助信息加以指导。 --- #### 示例代码片段 下面提供了一个简单的 PyTorch 版本实现概览: ```python import torch from transformers import BertTokenizer, BertForMaskedLM class BERT4RecModel(torch.nn.Module): def __init__(self, vocab_size, hidden_dim=768, num_layers=12, n_heads=12): super(BERT4RecModel, self).__init__() # 初始化 Tokenizer 及 Pre-trained model tokenizer = BertTokenizer.from_pretrained('bert-base-uncased') bert_model = BertForMaskedLM.from_pretrained('bert-base-uncased') self.embedding_layer = bert_model.bert.embeddings.word_embeddings self.transformer_encoder = torch.nn.TransformerEncoder( encoder_layer=torch.nn.TransformerEncoderLayer(d_model=hidden_dim, nhead=n_heads), num_layers=num_layers ) def forward(self, input_ids, attention_mask=None): embeddings = self.embedding_layer(input_ids) output = self.transformer_encoder(embeddings, src_key_padding_mask=~attention_mask.bool()) return output # 假设我们有一个 batch size 为 2 的样本集 input_tensor = torch.tensor([[101, 7592, 102], [101, 2054, 102]]) # Example inputs with special tokens like '[CLS]' and '[SEP]' model = BERT4RecModel(vocab_size=30522) outputs = model(input_tensor) print(outputs.shape) # 输出形状应匹配预期大小 ``` 上述代码展示了如何构建基础框架并通过加载预训练好的 BERT 来初始化 embedding 层与 transformer 架构的一部分组件。 --- #### 讨论与展望 尽管 BERT4REC 已经取得了显著成果,但仍存在一些挑战亟待解决。比如长期记忆能力不足可能导致冷启动问题恶化;另外高昂算力需求也可能成为大规模工业级落地障碍之一。 ---
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值