Coverage for hopwise/model/context_aware_recommender/fnn.py: 100%

33 statements  

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

1# @Time : 2020/9/15 10:57 

2# @Author : Zihan Lin 

3# @Email : linzihan.super@foxmail.com 

4# @File : fnn.py 

5 

6r"""FNN 

7################################################ 

8Reference: 

9 Weinan Zhang1 et al. "Deep Learning over Multi-field Categorical Data" in ECIR 2016 

10""" 

11 

12from torch import nn 

13from torch.nn.init import constant_, xavier_normal_ 

14 

15from hopwise.model.abstract_recommender import ContextRecommender 

16from hopwise.model.layers import MLPLayers 

17 

18 

19class FNN(ContextRecommender): 

20 """FNN which also called DNN is a basic version of CTR model that use mlp from field features to predict score. 

21 

22 Note: 

23 Based on the experiments in the paper above, This implementation incorporate 

24 Dropout instead of L2 normalization to relieve over-fitting. 

25 Our implementation of FNN is a basic version without pretrain support. 

26 If you want to pretrain the feature embedding as the original paper, 

27 we suggest you to construct a advanced FNN model and train it in two-stage 

28 process with our FM model. 

29 """ 

30 

31 def __init__(self, config, dataset): 

32 super().__init__(config, dataset) 

33 

34 # load parameters info 

35 self.mlp_hidden_size = config["mlp_hidden_size"] 

36 self.dropout_prob = config["dropout_prob"] 

37 

38 size_list = [self.embedding_size * self.num_feature_field] + self.mlp_hidden_size 

39 

40 # define layers and loss 

41 self.mlp_layers = MLPLayers( 

42 size_list, self.dropout_prob, activation="tanh", bn=False 

43 ) # use tanh as activation 

44 self.predict_layer = nn.Linear(self.mlp_hidden_size[-1], 1, bias=True) 

45 

46 self.sigmoid = nn.Sigmoid() 

47 self.loss = nn.BCEWithLogitsLoss() 

48 

49 # parameters initialization 

50 self.apply(self._init_weights) 

51 

52 def _init_weights(self, module): 

53 if isinstance(module, nn.Embedding): 

54 xavier_normal_(module.weight.data) 

55 elif isinstance(module, nn.Linear): 

56 xavier_normal_(module.weight.data) 

57 if module.bias is not None: 

58 constant_(module.bias.data, 0) 

59 

60 def forward(self, interaction): 

61 fnn_all_embeddings = self.concat_embed_input_fields(interaction) # [batch_size, num_field, embed_dim] 

62 batch_size = fnn_all_embeddings.shape[0] 

63 

64 output = self.predict_layer(self.mlp_layers(fnn_all_embeddings.view(batch_size, -1))) 

65 return output.squeeze(-1) 

66 

67 def calculate_loss(self, interaction): 

68 label = interaction[self.LABEL] 

69 output = self.forward(interaction) 

70 

71 return self.loss(output, label) 

72 

73 def predict(self, interaction): 

74 return self.sigmoid(self.forward(interaction))