使用最后m个item提取短期兴趣、自定义attention

一、使用最后m个item提取短期兴趣

对于短期兴趣的提取来说,我们可以使用最后m个或target item来获取

# 下面是取序列最后面的m个item
# item_seq_len是序列长度,batchsize*1
# sequence_last_m是我们定义m值
# item_seq是整个序列交互过的item,batchsize*max_seq_len
# target_item用于表明当前是否为训练阶段

# 获得m长的子序列的结束item的位置(下标+1)
sequence_last_m_interval_end = torch.squeeze(item_seq_len)

# 获得m长的子序列的开始item的位置(下标+1)
sequence_last_m_interval_start = sequence_last_m_interval_end - self.sequence_last_m

# 下面数组用于存储长度为m的子序列,batchsize*m
sequence_last_m_indexes = []

# 对batchsize里面的每个序列进行遍历
for i in range(item_seq_len.shape[0]):

	# 若获得的子序列开始位置的值大于0,证明当前序列长度大于等于m
    if sequence_last_m_interval_start[i] >= 0:
    	# 获得当前i序列的子序列
        item_index = item_seq[i, sequence_last_m_interval_start[i]:sequence_last_m_interval_end[i]]
        sequence_last_m_indexes.append(item_index)
        
    # 若获得的子序列开始位置的值小于0,证明当前序列长度小于m
    else:
    	# 我们需要将整个序列作为子序列
        item_index = item_seq[i, 0:sequence_last_m_interval_end[i]]
        # 长度不足的话在序列开始位置用0补齐,使子序列长度为m
        item_index = torch.nn.ZeroPad2d(padding=(self.sequence_last_m - sequence_last_m_interval_end[i], 0))(item_index)
        sequence_last_m_indexes.append(item_index)

# 将序列堆叠成tensor
sequence_last_m_indexes = torch.stack(sequence_last_m_indexes, dim=0)

# 将子序列padding成max_seq_len,batchsize*max_seq_len
user_short_items_indexes = torch.nn.ZeroPad2d(padding=(0, self.max_seq_length - self.sequence_last_m, 0, 0))(
    sequence_last_m_indexes)

# 若为训练阶段则使用最后的target item与子序列组成m+1的序列
if target_item is not None:
    user_short_items_indexes[:, self.sequence_last_m] = torch.squeeze(target_item)

# 获得子序列的embedding
user_short_items_emb_ori = self.item_embedding(user_short_items_indexes)

# calculate the mask
mask = torch.ones(
    user_short_items_indexes.shape, dtype=torch.float,
    device=item_seq.device) * user_short_items_indexes.gt(0)

# size = [batchSize, max_seq_len, 1]
mask = mask.unsqueeze(2)

# 使用dropout
user_short_items_emb = self.emb_dropout(user_short_items_emb_ori) * mask

# 扩大维度
user_short_items_emb = user_short_items_emb.unsqueeze(1)

二、自定义attention

这里的自定义是使用确定的query(用户兴趣)来对整个序列(用户交互系列)进行attention,最后得到维度为batchsize*2的输出和整个序列item的表示
a j = τ l ( v j ∣ ∣ q l u ∣ ∣ ( v j − q l u ) ∣ ∣ ( v j ⋅ q l u ) ) a_{j}=\tau_{l}\left(\boldsymbol{v_{j}}||\boldsymbol{q_{l}^{u}}||\left(\boldsymbol{v_{j}}-\boldsymbol{q_{l}^{u}}\right)||\left(\boldsymbol{v_{j}}\cdot\boldsymbol{q_{l}^{u}}\right)\right) aj=τl(vj∣∣qlu∣∣(vjqlu)∣∣(vjqlu))

class AttnReadout(nn.Module):
    def __init__(
            self,
            input_dim,	# 输入层维度
            hidden_dim,	# 隐藏层维度
            output_dim,	# 输出层维度
            layer_norm=True,	# 是否层归一化
            feat_drop=0.0,	# 是否dropout
    ):
        super().__init__()
        self.layer_norm = nn.LayerNorm(input_dim) if layer_norm else None
        self.feat_drop = nn.Dropout(feat_drop)

		# 将输入序列embedding维度转化,以获得key
        self.fc_key_map = nn.Linear(input_dim, hidden_dim, bias=False)
     	
     	# 将输入序列embedding维度转化,以获得value
        self.fc_value_map = nn.Linear(input_dim, hidden_dim, bias=False)

		# 将query与key相乘获得最终的batchsize*2
        self.fc_attention = nn.Linear(hidden_dim + hidden_dim + hidden_dim + 1,
                                      output_dim, bias=False)

        self.sigmoid = nn.Sigmoid()
        self.softmax = nn.Softmax(dim=1)

	# item_seq_emb:整个序列各个item的表示,batchsize*max_seq_len*feat_dim
	# user_interest_fusion_emb:query,整个序列的融合表示,batchsize*feat_dim
	# mask:该序列的mask矩阵,batchsize*max_seq_len*1
    def forward(self, item_seq_emb, user_interest_fusion_emb, mask):
        if self.layer_norm is not None:
            item_seq_emb = self.layer_norm(item_seq_emb)
        item_seq_emb = item_seq_emb * mask
        item_seq_emb = self.feat_drop(item_seq_emb)
        item_seq_emb = item_seq_emb * mask
        item_seq_emb_key = self.fc_key_map(item_seq_emb)
        item_seq_emb_key = item_seq_emb_key * mask
        
		# 将整个序列的融合表示expand成batchsize*max_seq_len*feat_dim
        user_interest_fusion_emb_expand = user_interest_fusion_emb.unsqueeze(1).expand_as(item_seq_emb)

		# 特征相减和相乘
        emb_subtract = item_seq_emb_key - user_interest_fusion_emb_expand
        emb_multiply = torch.matmul(
            item_seq_emb_key,
            user_interest_fusion_emb.unsqueeze(1).transpose(1, 2).to(torch.float))
        item_seq_two_dim_score = self.fc_attention(
            torch.cat((item_seq_emb_key, user_interest_fusion_emb_expand,
                       emb_subtract, emb_multiply), dim=-1)
        ) * mask

		# 这里的维度为batchsize*max_seq_len*2 
        score = self.sigmoid(item_seq_two_dim_score)

		# 获得整个序列经过降噪的item embedding
        denoised_items_emb = self.get_denoised_items_emb(
            item_seq_emb=item_seq_emb, score=score, mask=mask)

        return score, denoised_items_emb

    def get_denoised_items_emb(self, item_seq_emb, score, mask):
        item_seq_score = score[:, :, 0]
        item_seq_score = self.softmax(item_seq_score)
        item_seq_score = item_seq_score.unsqueeze(-1).expand_as(item_seq_emb)

		# 获得value
        item_seq_emb_value = self.fc_value_map(item_seq_emb)
        item_seq_emb_value = item_seq_emb_value * mask

		# attention scores乘value
        denoised_items_emb = item_seq_score * item_seq_emb_value
        denoised_items_emb = denoised_items_emb * mask

        return denoised_items_emb

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值