class_docstr: xDeepFM model
  
  :Citation:
  
      J. Lian, X. Zhou, F. Zhang, Z. Chen, X. Xie, G. Sun, "xDeepFM: Combining Explicit
      and Implicit Feature Interactions for Recommender Systems", in Proceedings of the
      24th ACM SIGKDD International Conference on Knowledge Discovery & Data Mining,
      KDD 2018, London, 2018.
docstr: Construct the compressed interaction network.
  This component provides explicit and vector-wise higher-order feature interactions.
  
  Args:
      nn_input (object): The output of field-embedding layer. This is the input for CIN.
      res (bool): Whether use residual structure to fuse the results from each layer of CIN.
      direct (bool): If true, then all hidden units are connected to both next layer and output layer;
              otherwise, half of hidden units are connected to next layer and the other half will be connected to output layer.
      bias (bool): Whether to add bias term when calculating the feature maps.
      is_masked (bool): Controls whether to remove self-interaction in the first layer of CIN.
  
  Returns:
      object: Prediction score made by CIN.
code: def _build_CIN(
      self,
      nn_input,
      res=False,
      direct=False,
      bias=False,
      is_masked=False,
  ):
      """Construct the compressed interaction network.
      This component provides explicit and vector-wise higher-order feature interactions.
  
      Args:
          nn_input (object): The output of field-embedding layer. This is the input for CIN.
          res (bool): Whether use residual structure to fuse the results from each layer of CIN.
          direct (bool): If true, then all hidden units are connected to both next layer and output layer;
                  otherwise, half of hidden units are connected to next layer and the other half will be connected to output layer.
          bias (bool): Whether to add bias term when calculating the feature maps.
          is_masked (bool): Controls whether to remove self-interaction in the first layer of CIN.
  
      Returns:
          object: Prediction score made by CIN.
      """
      hparams = self.hparams
      hidden_nn_layers = []
      field_nums = []
      final_len = 0
      field_num = hparams.FIELD_COUNT
      nn_input = tf.reshape(
          nn_input, shape=[-1, int(field_num), hparams.dim]
      )
      field_nums.append(int(field_num))
      hidden_nn_layers.append(nn_input)
      final_result = []
      split_tensor0 = tf.split(
          hidden_nn_layers[0], hparams.dim * [1], 2
      )
      with tf.compat.v1.variable_scope(
          "exfm_part", initializer=self.initializer
      ) as scope:  # noqa: F841
          for idx, layer_size in enumerate(hparams.cross_layer_sizes):
              split_tensor = tf.split(
                  hidden_nn_layers[-1], hparams.dim * [1], 2
              )
              dot_result_m = tf.matmul(
                  split_tensor0, split_tensor, transpose_b=True
              )  # shape :  (Dim, Batch, FieldNum, HiddenNum), a.k.a (D,B,F,H)
              dot_result_o = tf.reshape(
                  dot_result_m,
                  shape=[
                      hparams.dim,
                      -1,
                      field_nums[0] * field_nums[-1],
                  ],
              )  # shape: (D,B,FH)
              dot_result = tf.transpose(
                  a=dot_result_o, perm=[1, 0, 2]
              )  # (B,D,FH)
  
              filters = tf.compat.v1.get_variable(
                  name="f_" + str(idx),
                  shape=[1, field_nums[-1] * field_nums[0], layer_size],
                  dtype=tf.float32,
              )
  
              if is_masked and idx == 0:
                  ones = tf.ones(
                      [field_nums[0], field_nums[0]], dtype=tf.float32
                  )
                  mask_matrix = tf.linalg.band_part(
                      ones, 0, -1
                  ) - tf.linalg.tensor_diag(tf.ones(field_nums[0]))
                  mask_matrix = tf.reshape(
                      mask_matrix,
                      shape=[1, field_nums[0] * field_nums[0]],
                  )
  
                  dot_result = tf.multiply(dot_result, mask_matrix) * 2
                  self.dot_result = dot_result
  
              curr_out = tf.nn.conv1d(
                  input=dot_result,
                  filters=filters,
                  stride=1,
                  padding="VALID",
              )  # shape : (B,D,H`)
  
              if bias:
                  b = tf.compat.v1.get_variable(
                      name="f_b" + str(idx),
                      shape=[layer_size],
                      dtype=tf.float32,
                      initializer=tf.compat.v1.zeros_initializer(),
                  )
                  curr_out = tf.nn.bias_add(curr_out, b)
                  self.cross_params.append(b)
  
              if hparams.enable_BN is True:
                  curr_out = tf.compat.v1.layers.batch_normalization(
                      curr_out,
                      momentum=0.95,
                      epsilon=0.0001,
                      training=self.is_train_stage,
                  )
  
              curr_out = self._activate(
                  curr_out, hparams.cross_activation
              )
  
              curr_out = tf.transpose(
                  a=curr_out, perm=[0, 2, 1]
              )  # shape : (B,H,D)
  
              if direct:
                  direct_connect = curr_out
                  next_hidden = curr_out
                  final_len += layer_size
                  field_nums.append(int(layer_size))
  
              else:
                  if idx != len(hparams.cross_layer_sizes) - 1:
                      next_hidden, direct_connect = tf.split(
                          curr_out, 2 * [int(layer_size / 2)], 1
                      )
                      final_len += int(layer_size / 2)
                  else:
                      direct_connect = curr_out
                      next_hidden = 0
                      final_len += layer_size
                  field_nums.append(int(layer_size / 2))
  
              final_result.append(direct_connect)
              hidden_nn_layers.append(next_hidden)
  
              self.cross_params.append(filters)
  
          result = tf.concat(final_result, axis=1)
          result = tf.reduce_sum(
              input_tensor=result, axis=-1
          )  # shape : (B,H)
  
          if res:
              base_score = tf.reduce_sum(
                  input_tensor=result, axis=1, keepdims=True
              )  # (B,1)
          else:
              base_score = 0
  
          w_nn_output = tf.compat.v1.get_variable(
              name="w_nn_output", shape=[final_len, 1], dtype=tf.float32
          )
          b_nn_output = tf.compat.v1.get_variable(
              name="b_nn_output",
              shape=[1],
              dtype=tf.float32,
              initializer=tf.compat.v1.zeros_initializer(),
          )
          self.layer_params.append(w_nn_output)
          self.layer_params.append(b_nn_output)
          exFM_out = base_score + tf.compat.v1.nn.xw_plus_b(
              result, w_nn_output, b_nn_output
          )
          return exFM_out
  
file_path: recommenders/recommenders/models/deeprec/models/xDeepFM.py
imports: import numpy
  import tensorflow
  from recommenders.models.deeprec.models.base_model import BaseModel
label_desc: Use image node_id 5 for calling the XDeepFMModel obj's underlying member method code with example usage: obj._build_CIN(nn_input, res, direct, bias, is_masked) and returns: exFM_out