You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

97 lines
3.3 KiB

This file contains ambiguous Unicode characters!

This file contains ambiguous Unicode characters that may be confused with others in your current locale. If your use case is intentional and legitimate, you can safely ignore this warning. Use the Escape button to highlight these characters.

import torch
import numpy as np
import torch.nn as nn
class AutoRec(nn.Module):
"""
基于物品的AutoRec模型
"""
def __init__(self, config):
super(AutoRec, self).__init__()
self._num_items = config['num_items']
self._hidden_units = config['hidden_units']
self._lambda_value = config['lambda']
self._config = config
# 定义编码器结构
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, input):
return self._decoder(self._encoder(input))
def loss(self, res, input, mask, optimizer):
cost = 0
temp = 0
res = res.double()
cost += ((res - input) * mask).pow(2).sum()
rmse = cost
for i in optimizer.param_groups:
# 找到权重矩阵V和W并且计算平方和用于约束项。
for j in i['params']:
if j.data.dim() == 2:
temp += torch.t(j.data).pow(2).sum()
cost += temp * self._config['lambda'] * 0.5
return cost, rmse
def recommend_user(self, r_u, N):
"""
:param r_u: 单个用户对所有物品的评分向量
:param N: 推荐的商品个数
"""
# 得到用户对所有物品的评分
predict = self.forward(torch.from_numpy(r_u).float())
predict = predict.detach().numpy()
indexs = np.argsort(-predict)[:N]
return indexs
def recommend_item(self, user, test_r, N):
"""
:param r_u: 所有用户对物品i的评分向量
:param N: 推荐的商品个数
"""
# 保存给user的推荐列表
recommends = np.array([])
for i in range(test_r.shape[1]):
predict = self.forward(test_r[:, i])
recommends.append(predict[user])
# 按照逆序对推荐列表排序得到最大的N个值的索引
indexs = np.argsot(-recommends)[:N]
# 按照用户对物品i的评分降序排序吗推荐前N个物品给到用户
return recommends[indexs]
def evaluate(self, test_r, test_mask_r, user_test_set, user_train_set, item_test_set, item_train_set):
test_r_tensor = torch.from_numpy(test_r).type(torch.FloatTensor)
test_mask_r_tensor = torch.from_numpy(test_mask_r).type(torch.FloatTensor)
res = self.forward(test_r_tensor)
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:
res[user, item] = 3
mse = ((res - 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('test RMSE : ', RMSE)
def saveModel(self):
torch.save(self.state_dict(), self._config['model_name'])
def loadModel(self, map_location):
state_dict = torch.load(self._config['model_name'], map_location=map_location)
self.load_state_dict(state_dict, strict=False)