推荐系统fm算法

背景介绍

先介绍一下POLY2模型,POLY2是为了解决特征交叉问题而设计的模型,初期,算法工程师需要手动组合特征再通过各种手段分析特征。为了解决这种效率低下的问题,设计了特征的暴力组合。

POLY2的数学形式如下

ϕ P O L Y 2 ( w , x ) = b + ∑ i = 1 n w i x i + ∑ i = 1 n ∑ j = i + 1 n w i , j x i x j \phi POLY2(w,x)=b+\sum\limits_{i=1}^nw_ix_i+\sum\limits_{i=1}^n\sum\limits_{j=i+1}^nw_{i,j}x_ix_j ϕPOLY2(w,x)=b+i=1nwixi+i=1nj=i+1nwi,jxixj

前面 b + ∑ i = 1 n w i x i b+\sum\limits_{i=1}^nw_ix_i b+i=1nwixi是线性回归,后面部分是二阶特征交叉,暴力组合二阶特征,就是二阶特征相乘然后乘上一个系数。空间复杂度 O ( n 2 ) O(n^2) O(n2),一共 n ( n − 1 ) / 2 n(n-1)/2 n(n1)/2个。

当特征维度较高时,权重参数量很大导致训练压力巨大。而且只有当 x i , x j x_i,x_j xi,xj都不为0时,才能反向传播训练 w i , j w_{i,j} wi,j

FM针对稀疏one-hot编码,引入了稠密隐向量,减少了训练参数。

FM算法思想

对于样本 X X X每一个特征 ( x 1 , x 2 , x 3 . . . x n ) (x_1,x_2,x_3...x_n) (x1,x2,x3...xn),都有对应的隐向量 ( v 1 , v 2 , v 3 . . . v n ) (v_1,v_2,v_3...v_n) (v1,v2,v3...vn),其中隐向量维度为 k k k,其中 k ≪ n k\ll n kn,即隐向量矩阵大小 ( n , k ) (n,k) (n,k),参数总量为 n ∗ k n*k nk,使用两个隐向量点积 v i ⋅ v 2 v_i\cdot v_2 viv2得到的权值来代替POLY2算法中的枚举权重 w i , j w_{i,j} wi,j

ϕ F M ( w , x ) = b + ∑ i = 1 n w i x i + ∑ i = 1 n ∑ j = i + 1 n ⟨ v i , v j ⟩ x i x j \phi FM(w,x)=b+\sum\limits_{i=1}^nw_ix_i+\sum\limits_{i=1}^n\sum\limits_{j=i+1}^n\langle v_i,v_j\rangle x_ix_j ϕFM(w,x)=b+i=1nwixi+i=1nj=i+1nvi,vjxixj

FM公式化简

在这里插入图片描述
将计算复杂度从 O ( n 2 k ) O(n^2k) O(n2k)降为 O ( n k ) O(nk) O(nk)

pytorch代码实现

class FactorizationMachine(nn.Module):
    def __init__(self, n, k):
        """
        :param n: feature_dim
        :param k: embedding_dim
        """
        super().__init__()
        self.n = n
        self.k = k
        self.b = nn.Parameter(torch.zeros(1), requires_grad=True)
        self.W = nn.Parameter(torch.randn(n, k))
        self.linear = nn.Linear(n, 1)
        nn.init.xavier_uniform(self.W)

    def forward(self, x):
        """
        :param x: shape [batch,feature_num]
        :return:
        """
        x1 = self.linear(x)
        left = torch.mm(x, self.W) * torch.mm(x, self.W) #*是元素乘
        right = torch.mm(x * x, self.W * self.W)
        x2 = 0.5 * torch.sum(left - right, dim=-1,keepdim=True)

        return self.b + x2 + x1

参考书目:

[1].深度学习推荐系统 王喆

[2].https://blog.csdn.net/qq_38237214/article/details/121338159

Factorization Machine (FM) 是一种处理稀疏高维数据的算法,可以用于推荐系统、CTR 预估等场景。下面是使用 PyTorch 实现 FM 算法的示例代码。 首先,我们需要导入 PyTorch 和其他必要的库: ```python import torch from torch.utils.data import Dataset, DataLoader from sklearn.preprocessing import LabelEncoder ``` 然后我们定义一个自定义数据集类来加载数据: ```python class FMDataSet(Dataset): def __init__(self, X, y=None): self.X = X self.y = y def __len__(self): return len(self.X) def __getitem__(self, idx): if self.y is not None: return self.X[idx], self.y[idx] else: return self.X[idx] ``` 接着,我们定义 FM 模型的类: ```python class FM(torch.nn.Module): def __init__(self, num_features, k): super(FM, self).__init__() self.num_features = num_features self.k = k # 线性部分 self.linear = torch.nn.Linear(num_features, 1) # 交叉部分 self.V = torch.nn.Parameter(torch.randn(num_features, k)) def forward(self, x): linear_part = self.linear(x) v_part = torch.mm(x, self.V).pow(2).sum(1, keepdim=True) \ - torch.mm(x.pow(2), self.V.pow(2)).sum(1, keepdim=True) fm_part = 0.5 * v_part out = linear_part + fm_part return torch.sigmoid(out) ``` 在这个模型中,我们定义了线性部分和交叉部分。线性部分使用 PyTorch 自带的 Linear 层,而交叉部分使用了一个矩阵 V,它的形状是 (num_features, k)。我们通过矩阵乘法和张量乘法计算出交叉部分的输出。 接下来,我们可以加载数据并进行预处理。这里我们使用 MovieLens 数据集作为示例数据: ```python import pandas as pd # 加载数据 data = pd.read_csv('http://files.grouplens.org/datasets/movielens/ml-100k/u.data', sep='\t', header=None, names=['user_id', 'item_id', 'rating', 'timestamp']) # 将 user_id 和 item_id 编码成连续的整数 user_encoder = LabelEncoder() item_encoder = LabelEncoder() data['user_id'] = user_encoder.fit_transform(data['user_id']) data['item_id'] = item_encoder.fit_transform(data['item_id']) # 将数据集拆分成训练集和测试集 train_data = FMDataSet(data[['user_id', 'item_id']].values, data['rating'].values) train_loader = DataLoader(train_data, batch_size=256, shuffle=True) num_users = len(user_encoder.classes_) num_items = len(item_encoder.classes_) ``` 最后,我们可以训练模型并进行评估: ```python # 定义模型和优化器 model = FM(num_users + num_items, 20) optimizer = torch.optim.Adam(model.parameters(), lr=0.01) # 训练模型 for epoch in range(10): for x, y in train_loader: optimizer.zero_grad() y_pred = model(x) loss = torch.nn.functional.binary_cross_entropy(y_pred, y.float().unsqueeze(1)) loss.backward() optimizer.step() print('Epoch {}: loss={:.4f}'.format(epoch+1, loss.item())) # 在测试集上评估模型 test_data = FMDataSet(data[['user_id', 'item_id']].values) test_loader = DataLoader(test_data, batch_size=1024) y_pred = [] for x in test_loader: y_pred.append(model(x).detach().numpy().flatten()) y_pred = np.concatenate(y_pred) y_true = data['rating'].values rmse = np.sqrt(np.mean((y_true - y_pred)**2)) print('RMSE={:.4f}'.format(rmse)) ``` 这样就可以使用 PyTorch 实现 FM 算法了。请注意,这个示例代码只是一个简单的示例,实际的应用中可能需要进行更多的优化和调整。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值