特征交叉系列:AFM理论和实践,FM和注意力机制的结合

AFM介绍和结构简述

在上一节介绍了NFM算法[特征交叉系列:NFM原理和实践,使用交叉池化连接FM和DNN],NFM采用求和池化对两两向量的乘积做信息浓缩聚合。

AFM(Attentional Factorization Machines)整体结构和NFM类似,核心区别在于AFM采用注意力机制做池化,即采用加权求和的方式取代了NFM中的直接求和。

在FM层输出的向量乘积代表一对特征交叉的表征,可想而知,不同的特征交叉对最终预测结果的帮助大小也是不一样的,比如用户历史上感兴趣的商品类目和目标商品类目形成的交叉,肯定比用户性别和用户年龄形成的交叉效果要好,模型会给用户侧和商品侧的交互更多的倾向,而用户内部特征的交叉收益并不大。因此NFM中的求和池化并不合理,因为这相当于所有交叉结果都是相同的权重,并没有对重要的交叉做加强,对无用的交叉做衰减,压力全部给到了下游的全连接层。

AFM是NFM的升级,因此AFM也是针对FM的二阶交互层做了修改,AFM的网络结构如下

AFM网络结构

相比于NFM,AFM网络结构有两处变动

  • 1:引入了Attention Net,采用一个全连接作为Attention相似函数,具体是使用激活函数是Relu的全连接层映射到固定维度,再加一个线性层输出到标量,公式如下

Attention权重计算公式

在得到该批次下每个样本的attention权重后,和对应的特征交叉向量乘积做相乘再类和,达到加权求和的效果,注意力的输出如下

注意力输出

和NFM一样输出是一个[batch, emb_size]的二维向量。

  • 2:取消了特征交叉之后的多层感知机,而是直接以一个线性层输出为一个标量,和FM的一阶结果相加得到整个模型的输出。
注意力问题分析

这里对注意力机制有点疑问,一般注意力机制有querykeyvalue,其中query作为参照物,query和key做相似计算输出权重,再对key对应的value进行加权求和,而在AFM中显然key和value都是交叉层两两向量的乘积,而没有query,因此注意力权重可能是基于全部样本学习到的特征重要性,而此时注意力层和NFM的全连接层几乎是等同的。
换句话说哪些特征做交叉更重要是有先验知识的,AFM的注意力学习到的是类似用户侧和商品侧交叉更有意义这样的大致趋势。我个人认为由于在AFM中并没有加入query(比如召回的目标商品),因此注意力的作用不明显。


AFM在PyTorch下的实践和效果对比

本次实践的数据集和上一篇[特征交叉系列:完全理解FM因子分解机原理和代码实战]一致,采用用户的购买记录流水作为训练数据,用户侧特征是年龄,性别,会员年限等离散特征,商品侧特征采用商品的二级类目,产地,品牌三个离散特征,随机构造负样本,一共有10个特征域,全部是离散特征,对于枚举值过多的特征采用hash分箱,得到一共72个特征。
AFM的PyTorch代码实现如下

class Embedding(nn.Module):
    def __init__(self, feat_dim, emb_dim):
        super(Embedding, self).__init__()
        self.embedding = nn.Embedding(feat_dim, emb_dim)
        nn.init.xavier_normal_(self.embedding.weight.data)

    def forward(self, x):
        # [None, field_num] => [None, field_num, emb_dim]
        return self.embedding(x)


class FM(nn.Module):
    def __init__(self):
        super(FM, self).__init__()

    def forward(self, x):
        # x=[None, field_num, emb_dim]
        field_num = x.shape[1]
        p = []
        q = []
        for i in range(field_num - 1):
            for j in range(i + 1, field_num):
                p.append(i)
                q.append(j)
        pp = x[:, p]
        qq = x[:, q]
        pq = pp * qq
        return pq


class Attention(nn.Module):
    def __init__(self, emb_size, attn_size, dropout=0.1):
        super(Attention, self).__init__()
        self.w = nn.Linear(emb_size, attn_size)
        self.h = nn.Linear(attn_size, 1)
        self.fc = torch.nn.Linear(emb_size, 1)
        self.relu = nn.ReLU()
        self.dropout = nn.Dropout(dropout)
        for weight in (self.w, self.h, self.fc):
            nn.init.xavier_uniform_(weight.weight.data)

    def forward(self, x):
        # x=[None, field_num*(field_num-1)/2, emb_dim] => [None, field_num*(field_num-1)/2, 1]
        eij = torch.softmax(self.h(self.relu(self.w(x))), dim=1)
        eij = self.dropout(eij)
        attn_x = x * eij
        out = self.dropout(torch.sum(attn_x, dim=1))  # [None, emb_size]
        return self.fc(out)  # [None, 1]


class Linear(nn.Module):
    def __init__(self, feat_dim):
        super(Linear, self).__init__()
        self.embedding = nn.Embedding(feat_dim, 1)
        self.bias = nn.Parameter(torch.zeros(1))
        nn.init.xavier_normal_(self.embedding.weight.data)

    def forward(self, x):
        # [None, field_num] => [None, field_num, 1] => [None, 1]
        return self.embedding(x).sum(dim=1) + self.bias


class AFM(nn.Module):
    def __init__(self, feat_dim, emb_dim, attention_size, dropout=0.1):
        super(AFM, self).__init__()
        self.linear = Linear(feat_dim=feat_dim)
        self.embedding = Embedding(feat_dim=feat_dim, emb_dim=emb_dim)
        self.fm = FM()
        self.attention = Attention(emb_size=emb_dim, attn_size=attention_size, dropout=dropout)

    def forward(self, x):
        linear = self.linear(x)  # [None, 1]
        emb = self.embedding(x)  # [None, field_num, emb_dim]
        cross = self.fm(emb)  # [None, field_num*(field_num-1)/2, emb_dim]
        attn_cross = self.attention(cross)  # [None, 1]
        out = linear + attn_cross
        return torch.sigmoid(out).squeeze(dim=1)

其中FM+Attention子模块实现了交叉注意力池化层。
本例全部是离散分箱变量,所有有值的特征都是1,因此只要输入有值位置的索引即可,一条输入例如

>>> train_data[0]
Out[120]: (tensor([ 2, 10, 14, 18, 34, 39, 47, 51, 58, 64]), tensor(0))

采用验证集的10次AUC不上升作为早停,FM,NFM,AFM的平均验证集AUC如下

FMNFMAFM
AUC0.62740.63290.6293

结果带有注意力机制的AFM反而不如NFM,即注意力的学习可能还不如多层感知机。


AFM输出权重的业务分析

进一步看一下模型训练完成后学习到权重eij,首先基于热力图观察到几乎每一条样本的注意力权重分布都是一致的,如下图横向是所有特征交叉的案例45种,纵向是batchsize,只看了部分30条样本

每条样本的注意力权重分布

可以发现第44组特征交叉权重最大,其次是第22组,第16组,基本在8,15,22,44位置形成了三条竖线,进一步说明了AFM的注意力学习的是全局的重要性而不是个性化的。

然后将所有样本下的注意力权重求平均值,获得所有组合的注意力权重分布

整体的注意力权重分布

我们将注意力最高的组合和对应的特征业务名称对应上,结果如下

注意力权重排名组合编号特征
144商品品牌×商品产地
222会员年限×商品品牌
323会员年限×商品产地
433会员vip等级×商品品牌
534会员vip等级×商品产地

排名第一的是商品内侧的特征交叉,力压一众用户和商品的跨域交叉,不是太合理,一方面可能AFM训练出的注意力确实很糟糕,也有可能是样本中频繁出现某商品的购买记录,形成热点,导致模型给到该商品的品牌和产地,以及他们交叉项的权重很大,也说明这种基于全局样本的注意力可能会收到样本热度的影响。

最后的最后

感谢你们的阅读和喜欢,我收藏了很多技术干货,可以共享给喜欢我文章的朋友们,如果你肯花时间沉下心去学习,它们一定能帮到你。

因为这个行业不同于其他行业,知识体系实在是过于庞大,知识更新也非常快。作为一个普通人,无法全部学完,所以我们在提升技术的时候,首先需要明确一个目标,然后制定好完整的计划,同时找到好的学习方法,这样才能更快的提升自己。

这份完整版的大模型 AI 学习资料已经上传CSDN,朋友们如果需要可以微信扫描下方CSDN官方认证二维码免费领取【保证100%免费

一、全套AGI大模型学习路线

AI大模型时代的学习之旅:从基础到前沿,掌握人工智能的核心技能!

img

二、640套AI大模型报告合集

这套包含640份报告的合集,涵盖了AI大模型的理论研究、技术实现、行业应用等多个方面。无论您是科研人员、工程师,还是对AI大模型感兴趣的爱好者,这套报告合集都将为您提供宝贵的信息和启示。

img

三、AI大模型经典PDF籍

随着人工智能技术的飞速发展,AI大模型已经成为了当今科技领域的一大热点。这些大型预训练模型,如GPT-3、BERT、XLNet等,以其强大的语言理解和生成能力,正在改变我们对人工智能的认识。 那以下这些PDF籍就是非常不错的学习资源。

img

四、AI大模型商业化落地方案

img

五、面试资料

我们学习AI大模型必然是想找到高薪的工作,下面这些面试题都是总结当前最新、最热、最高频的面试题,并且每道题都有详细的答案,面试前刷完这套面试题资料,小小offer,不在话下。
在这里插入图片描述

这份完整版的大模型 AI 学习资料已经上传CSDN,朋友们如果需要可以微信扫描下方CSDN官方认证二维码免费领取【保证100%免费

AFM (Attentional Factorization Machine) 是一种用于CTR (Click-Through Rate) 预测的模型,其中的特征注意力部分对于模型的性能至关重要。在 PyTorch 中,可以通过以下方式控制特征添加注意力权重的比例: 1. 定义注意力网络 ```python import torch.nn as nn class AttentionNet(nn.Module): def __init__(self, feature_dim, attention_dim): super(AttentionNet, self).__init__() self.attention_layer = nn.Sequential( nn.Linear(feature_dim, attention_dim), nn.ReLU(inplace=True), nn.Linear(attention_dim, 1) ) def forward(self, x): """ :param x: feature tensor, shape: [batch_size, feature_dim] :return: attention weights tensor, shape: [batch_size, 1] """ attention_weights = self.attention_layer(x) return attention_weights ``` 2. 定义 AFM 模型 ```python class AFM(nn.Module): def __init__(self, feature_dim, attention_dim): super(AFM, self).__init__() self.embedding_layer = nn.Embedding(feature_dim, embedding_dim) self.attention_net = AttentionNet(embedding_dim, attention_dim) self.linear_layer = nn.Linear(embedding_dim, 1) def forward(self, x): """ :param x: input tensor, shape: [batch_size, num_features] :return: output tensor, shape: [batch_size] """ embeddings = self.embedding_layer(x) # [batch_size, num_features, embedding_dim] attention_weights = self.attention_net(embeddings) # [batch_size, num_features, 1] attention_weights = F.softmax(attention_weights.squeeze(dim=2), dim=1) # [batch_size, num_features] embeddings_weighted = embeddings * attention_weights.unsqueeze(dim=2) # [batch_size, num_features, embedding_dim] y_interactions = torch.sum(torch.sum(embeddings_weighted, dim=1), dim=1) # [batch_size, embedding_dim] y_linear = self.linear_layer(torch.mean(embeddings_weighted, dim=1)) # [batch_size, 1] y = y_interactions + y_linear.squeeze() # [batch_size] return y ``` 其中,`attention_weights` 表示特征注意力权重,通过 softmax 函数对其进行归一化,然后与特征向量相乘得到加权特征向量 `embeddings_weighted`,最终求和得到交互向量 `y_interactions`。在 `forward()` 方法中,还包含了一个线性层,用于学习偏置项。可以通过调整注意力网络的结构和超参数来控制特征注意力权重的比例。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值