python推介系统方法_基于AutoRec 的推荐系统介绍与python实现

本文介绍了AutoRec模型,一种融合自编码器思想和协同过滤的推荐系统。模型简单,适合初学者,通过实现在ml-1m数据集上的应用,展示其推荐过程和优缺点。
摘要由CSDN通过智能技术生成

本文要介绍的模型是2015年由澳大利亚国立大学提出的AutoRec。它将自编码器(AutoEncoder) 的思想和协同过滤结合,提出了一种但隐藏层的神经网络推荐model。因为简洁的网络结构和清晰易懂的模型原理,所以非常适合深度学习的推荐model 的入门模型来学习

本文参考了王喆大佬的新书,《深度学习推荐系统》

1.引言

协同过滤模型的目的是利用用户对商品的偏好信息来提供个性化的推荐。AutoRec是一个新型的基于自动编码器的协同过滤模型。论文作者认为AutoRec与现有的将玻尔兹曼机用于协同过滤的神经方法相比具有表征和计算上的优势,并从经验上证明了AutoRec优于当前最先进的方法

2.自编码器模型

在基于评分的协同过滤中,假设有m个用户,n个物品,并且有一个用户-物品的评分矩阵

  。每个用户向量u∈U={1.....m}可以被向量 

 表示

3.AutoRec模型的结构

下图为AutoRec的结构图,从图中可以看出,网络的输入层是物品的评分向量r,输出层是一个多分类层、蓝色的神经元代表模型的k维单隐层,其中k<

AutoRec模型的结构图

以上介绍的AutoRec输入向量是物品的评分向量,因此可称为I-AutoRec(Item based AutoRec).

4.推荐过程

基于AutoRec 模型的推荐过程并不复杂,当输入物品i 的评分向量为

 时,模型输出向量 

就是所有用户对物品i 的评分预测。那么。其中的第 u 维就是用户对物品i 的预测

  =

  。

之后通过遍历输入物品向量就可以得到用户 u 对所有物品的评分预测,进而根据评分预测排序得到推荐列表。

与 CF 一样 AutoRec 也分为 U - AutoRec 和 I - AutoRec

5.AutoRec模型的特点和局限性

AutoRec模型使用一个单隐层的AutoEncoder泛化用户或物品评分,使模型具有一定的泛化和表达能力。由于AutoRec模型的结构比较简单,使其存在一定的表达能力不足的问题。

从深度学习的角度来说,AutoRec模型的提出,拉开了使用深度学习的思想解决推荐问题的序幕,为复杂深度学习网络的构建提供了思路。

6.基于ml-1m 数据集测试

data 处理部分

import numpy as np

import argparse

import math

def get_data(path, num_users, num_items, num_total_ratings, train_ratio):

fp = open(path + "ratings.dat")

user_train_set = set()

user_test_set = set()

item_train_set = set()

item_test_set = set()

train_r = np.zeros((num_users, num_items))

test_r = np.zeros((num_users, num_items))

train_mask_r = np.zeros((num_users, num_items))

test_mask_r = np.zeros((num_users, num_items))

random_perm_idx = np.random.permutation(num_total_ratings)

train_idx = random_perm_idx[0:int(num_total_ratings * train_ratio)]

test_idx = random_perm_idx[int(num_total_ratings * train_ratio):]

lines = fp.readlines()

for itr in train_idx:

line = lines[itr]

user, item, rating, _ = line.split("::")

user_idx = int(user) - 1

item_idx = int(item) - 1

train_r[user_idx, item_idx] = int(rating)

train_mask_r[user_idx, item_idx] = 1

user_train_set.add(user_idx)

item_train_set.add(item_idx)

for itr in test_idx:

line = lines[itr]

user, item, rating, _ = line.split("::")

user_idx = int(user) - 1

item_idx = int(item) - 1

test_r[user_idx, item_idx] = int(rating)

test_mask_r[user_idx, item_idx] = 1

user_test_set.add(user_idx)

item_test_set.add(item_idx)

return train_r, train_mask_r, test_r, test_mask_r, user_train_set, item_train_set, user_test_set, item_test_set

model 部分

import torch

import torch.nn as nn

import numpy as np

from torch.autograd import variable

from recommend.auto_rec.data import get_data

import math

import time

import argparse

import torch.utils.data as Data

import torch.optim as optim

class Autorec(nn.Module):

def __init__(self, args, num_users, num_items):

super(Autorec, self).__init__()

self.args = args

self.num_users = num_users

self.num_items = num_items

self.hidden_units = args.hidden_units

self.lambda_value = args.lambda_value

self.encoder = nn.Sequential(

nn.Linear(self.num_items, self.hidden_units),

nn.Sigmoid()

)

self.decoder = nn.Sequential(

nn.Linear(self.hidden_units, self.num_items),

)

def forward(self, torch_input):

encoder = self.encoder(torch_input)

decoder = self.decoder(encoder)

return decoder

def loss(self, decoder, input, optimizer, mask_input):

cost = 0

temp2 = 0

cost += ((decoder - input) * mask_input).pow(2).sum()

rmse = cost

for i in optimizer.param_groups:

for j in i['params']:

# print(type(j.data), j.shape,j.data.dim())

if j.data.dim() == 2:

temp2 += torch.t(j.data).pow(2).sum() # 正则化项

cost += temp2 * self.lambda_value * 0.5

return cost, rmse

def train(self, epoch):

RMSE = 0

cost_all = 0

for step, (batch_x, batch_mask_x, batch_y) in enumerate(loader):

# batch_x = batch_x.type(torch.FloatTensor).cuda()

# batch_mask_x = batch_mask_x.type(torch.FloatTensor).cuda()

batch_x = batch_x.type(torch.FloatTensor)

batch_mask_x = batch_mask_x.type(torch.FloatTensor)

decoder = rec(batch_x)

loss, rmse = rec.loss(decoder=decoder, input=batch_x, optimizer=optimer, mask_input=batch_mask_x)

optimer.zero_grad()

loss.backward()

optimer.step()

cost_all += loss

RMSE += rmse

RMSE = np.sqrt(RMSE.detach().cpu().numpy() / (train_mask_r == 1).sum())

print('epoch ', epoch, ' train RMSE : ', RMSE)

def test(self, epoch):

# test_r_tensor = torch.from_numpy(test_r).type(torch.FloatTensor).cuda()

# test_mask_r_tensor = torch.from_numpy(test_mask_r).type(torch.FloatTensor).cuda()

test_r_tensor = torch.from_numpy(test_r).type(torch.FloatTensor)

test_mask_r_tensor = torch.from_numpy(test_mask_r).type(torch.FloatTensor)

decoder = rec(test_r_tensor)

# decoder = torch.from_numpy(np.clip(decoder.detach().cpu().numpy(),a_min=1,a_max=5)).cuda()

unseen_user_test_list = list(user_test_set - user_train_set) # 得到未出现在训练集中的用户列表

unseen_item_test_list = list(item_test_set - item_train_set) # 得到未出现在训练集中的电影列表

for user in unseen_user_test_list:

for item in unseen_item_test_list:

if test_mask_r[user, item] == 1: # 如果在测试集中存在这条评分记录,则进行记录decoder[user,item]=3

decoder[user, item] = 3

mse = ((decoder - test_r_tensor) * test_mask_r_tensor).pow(2).sum()

RMSE = mse.detach().cpu().numpy() / (test_mask_r == 1).sum()

RMSE = np.sqrt(RMSE)

print('epoch ', epoch, ' test RMSE : ', RMSE)

if __name__ == '__main__':

parser = argparse.ArgumentParser(description='I-AutoRec ')

parser.add_argument('--hidden_units', type=int, default=500) # 默认隐藏层单元数为500

parser.add_argument('--lambda_value', type=float, default=1)

parser.add_argument('--train_epoch', type=int, default=100) # 训练次数默认为100次

parser.add_argument('--batch_size', type=int, default=100) # batch_size 默认为100

parser.add_argument('--optimizer_method', choices=['Adam', 'RMSProp'], default='Adam') # 默认使用Adam优化

parser.add_argument('--grad_clip', type=bool, default=False)

parser.add_argument('--base_lr', type=float, default=1e-3) # 基础学习率设为1e-3

parser.add_argument('--decay_epoch_step', type=int, default=50, help="decay the learning rate for each n epochs")

parser.add_argument('--random_seed', type=int, default=1000) # 随机数种子默认设为1000

parser.add_argument('--display_step', type=int, default=1)

args = parser.parse_args()

np.random.seed(args.random_seed)

data_name = 'ml-1m'

num_users = 6040

num_items = 3952

num_total_ratings = 1000209

train_ratio = 0.9 # 90%为训练集

path = "../data/%s" % data_name + "/"

train_r, train_mask_r, test_r, test_mask_r, user_train_set, item_train_set, user_test_set, \

item_test_set = get_data(path, num_users, num_items, num_total_ratings, train_ratio)

args.cuda = False # 垃圾笔记本只能用cpu强行跑。。。

rec = Autorec(args, num_users, num_items)

# if args.cuda:

# rec.cuda()

optimer = optim.Adam(rec.parameters(), lr=args.base_lr, weight_decay=1e-4)

num_batch = int(math.ceil(num_users / args.batch_size))

torch_dataset = Data.TensorDataset(torch.from_numpy(train_r), torch.from_numpy(train_mask_r),

torch.from_numpy(train_r))

loader = Data.DataLoader(

dataset=torch_dataset,

batch_size=args.batch_size,

shuffle=True

)

for epoch in range(args.train_epoch):

rec.train(epoch=epoch)

rec.test(epoch=epoch)

引用:

王喆老师的深度学习推荐系统

原文链接:https://blog.csdn.net/zhuhongming123/article/details/106565025

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值