class_docstr: In the original paper, the authors proposed several architectures. We compared 3 different
  architectures:
  
      (1)  Concatenate item input and feature input and use single RNN,
  
      (2)  Concatenate outputs from two different RNNs,
  
      (3)  Weighted sum of outputs from two different RNNs.
  
  We implemented the optimal parallel version(2), which uses different RNNs to
  encode items and features respectively and concatenates the two subparts'
  outputs as the final output. The different RNN encoders are trained simultaneously.
class_docstr_tok: ["In","the","original","paper",",","the","authors","proposed","several","architectures",".","We","compared","3","different","architectures",":","(","1",")","Concatenate","item","input","and","feature","input","and","use","single","RNN",",","(","2",")","Concatenate","outputs","from","two","different","RNNs",",","(","3",")","Weighted","sum","of","outputs","from","two","different","RNNs",".","We","implemented","the","optimal","parallel","version","(","2",")",",","which","uses","different","RNNs","to","encode","items","and","features","respectively","and","concatenates","the","two","subparts'","outputs","as","the","final","output",".","The","different","RNN","encoders","are","trained","simultaneously","."]
code: def __init__(self, config, dataset):
      super(GRU4RecF, self).__init__(config, dataset)
  
      # load parameters info
      self.embedding_size = config["embedding_size"]
      self.hidden_size = config["hidden_size"]
      self.num_layers = config["num_layers"]
      self.dropout_prob = config["dropout_prob"]
  
      self.selected_features = config["selected_features"]
      self.pooling_mode = config["pooling_mode"]
      self.device = config["device"]
      self.num_feature_field = len(config["selected_features"])
  
      self.loss_type = config["loss_type"]
  
      # define layers and loss
      self.item_embedding = nn.Embedding(
          self.n_items, self.embedding_size, padding_idx=0
      )
      self.feature_embed_layer = FeatureSeqEmbLayer(
          dataset,
          self.embedding_size,
          self.selected_features,
          self.pooling_mode,
          self.device,
      )
      self.item_gru_layers = nn.GRU(
          input_size=self.embedding_size,
          hidden_size=self.hidden_size,
          num_layers=self.num_layers,
          bias=False,
          batch_first=True,
      )
      # For simplicity, we use same architecture for item_gru and feature_gru
      self.feature_gru_layers = nn.GRU(
          input_size=self.embedding_size * self.num_feature_field,
          hidden_size=self.hidden_size,
          num_layers=self.num_layers,
          bias=False,
          batch_first=True,
      )
      self.dense_layer = nn.Linear(
          self.hidden_size * 2, self.embedding_size
      )
      self.dropout = nn.Dropout(self.dropout_prob)
      if self.loss_type == "BPR":
          self.loss_fct = BPRLoss()
      elif self.loss_type == "CE":
          self.loss_fct = nn.CrossEntropyLoss()
      else:
          raise NotImplementedError(
              "Make sure 'loss_type' in ['BPR', 'CE']!"
          )
  
      # parameters initialization
      self.apply(xavier_normal_initialization)
      self.other_parameter_name = ["feature_embed_layer"]
  
file_path: RecBole/recbole/model/sequential_recommender/gru4recf.py
imports: import torch
  from torch import nn
  from recbole.model.abstract_recommender import SequentialRecommender
  from recbole.model.init import xavier_normal_initialization
  from recbole.model.layers import FeatureSeqEmbLayer
  from recbole.model.loss import BPRLoss
label_desc: Use image node_id 1 to create a new GRU4RecF object from inherited base classes: SequentialRecommender with example: obj = GRU4RecF(config, dataset)