Coverage for hopwise/model/general_recommender/multidae.py: 90%

49 statements  

« prev     ^ index     » next       coverage.py v7.16.2, created at 2026-09-30 13:25 +0000

1# @Time : 2020/12/14 

2# @Author : Yihong Guo 

3# @Email : gyihong@hotmail.com 

4 

5r"""MultiDAE 

6################################################ 

7Reference: 

8 Dawen Liang et al. "Variational Autoencoders for Collaborative Filtering." in WWW 2018. 

9 

10""" 

11 

12import torch 

13import torch.nn.functional as F 

14from torch import nn 

15 

16from hopwise.model.abstract_recommender import AutoEncoderMixin, GeneralRecommender 

17from hopwise.model.init import xavier_normal_initialization 

18from hopwise.model.layers import MLPLayers 

19from hopwise.utils import InputType 

20 

21 

22class MultiDAE(GeneralRecommender, AutoEncoderMixin): 

23 r"""MultiDAE is an item-based collaborative filtering model that simultaneously ranks all items for each user. 

24 

25 We implement the the MultiDAE model with only user dataloader. 

26 """ 

27 

28 input_type = InputType.USERWISE 

29 

30 def __init__(self, config, dataset): 

31 super().__init__(config, dataset) 

32 

33 self.layers = config["mlp_hidden_size"] 

34 self.lat_dim = config["latent_dimension"] 

35 self.drop_out = config["dropout_prob"] 

36 

37 self.build_histroy_items(dataset) 

38 

39 self.encode_layer_dims = [self.n_items] + self.layers + [self.lat_dim] 

40 self.decode_layer_dims = [self.lat_dim] + self.encode_layer_dims[::-1][1:] 

41 

42 self.encoder = MLPLayers(self.encode_layer_dims, activation="tanh") 

43 self.decoder = self.mlp_layers(self.decode_layer_dims) 

44 

45 # parameters initialization 

46 self.apply(xavier_normal_initialization) 

47 

48 def mlp_layers(self, layer_dims): 

49 mlp_modules = [] 

50 for i, (d_in, d_out) in enumerate(zip(layer_dims[:-1], layer_dims[1:])): 

51 mlp_modules.append(nn.Linear(d_in, d_out)) 

52 if i != len(layer_dims[:-1]) - 1: 

53 mlp_modules.append(nn.Tanh()) 

54 return nn.Sequential(*mlp_modules) 

55 

56 def forward(self, rating_matrix): 

57 h = F.normalize(rating_matrix) 

58 

59 h = F.dropout(h, self.drop_out, training=self.training) 

60 

61 h = self.encoder(h) 

62 return self.decoder(h) 

63 

64 def calculate_loss(self, interaction): 

65 user = interaction[self.USER_ID] 

66 

67 rating_matrix = self.get_rating_matrix(user) 

68 

69 z = self.forward(rating_matrix) 

70 

71 # CE loss 

72 ce_loss = -(F.log_softmax(z, 1) * rating_matrix).sum(1).mean() 

73 

74 return ce_loss 

75 

76 def predict(self, interaction): 

77 user = interaction[self.USER_ID] 

78 item = interaction[self.ITEM_ID] 

79 

80 rating_matrix = self.get_rating_matrix(user) 

81 

82 scores = self.forward(rating_matrix) 

83 

84 return scores[[torch.arange(len(item)).to(self.device), item]] 

85 

86 def full_sort_predict(self, interaction): 

87 user = interaction[self.USER_ID] 

88 

89 rating_matrix = self.get_rating_matrix(user) 

90 

91 scores = self.forward(rating_matrix) 

92 

93 return scores.view(-1)