code: def _build_tf_graph(self, n_user_features, n_item_features):
      # Build placeholders
      self.tf_n_sampled_items = tf.placeholder("int64")
      self.tf_similar_items_ids = tf.placeholder("int64", [None])
      self.tf_learning_rate = tf.placeholder("float", None)
      self.tf_alpha = tf.placeholder("float", None)
  
      (
          tf_user_feature_rows,
          tf_user_feature_cols,
          tf_user_feature_values,
          tf_n_users,
          _,
      ) = self.tf_user_feature_iterator.get_next()
      (
          tf_item_feature_rows,
          tf_item_feature_cols,
          tf_item_feature_values,
          tf_n_items,
          _,
      ) = self.tf_item_feature_iterator.get_next()
      (
          tf_interaction_rows,
          tf_interaction_cols,
          tf_interaction_values,
          _,
          _,
      ) = self.tf_interaction_iterator.get_next()
  
      tf_user_feature_indices = tf.stack(
          [tf_user_feature_rows, tf_user_feature_cols], axis=1
      )
      tf_item_feature_indices = tf.stack(
          [tf_item_feature_rows, tf_item_feature_cols], axis=1
      )
      tf_interaction_indices = tf.stack(
          [tf_interaction_rows, tf_interaction_cols], axis=1
      )
  
      # Construct the features and interactions as sparse matrices
      tf_user_features = tf.SparseTensor(
          tf_user_feature_indices,
          tf_user_feature_values,
          [tf_n_users, n_user_features],
      )
      tf_item_features = tf.SparseTensor(
          tf_item_feature_indices,
          tf_item_feature_values,
          [tf_n_items, n_item_features],
      )
      tf_interactions = tf.SparseTensor(
          tf_interaction_indices,
          tf_interaction_values,
          [tf_n_users, tf_n_items],
      )
  
      # Construct the sampling py_func
      sample_items_partial = partial(
          sample_items,
          replace=self.loss_graph_factory.is_sampled_with_replacement,
      )
      self.tf_sample_indices = tf.py_func(
          func=sample_items_partial,
          inp=[tf_n_items, tf_n_users, self.tf_n_sampled_items],
          Tout=tf.int64,
      )
      self.tf_sample_indices.set_shape([None, None])
  
      # Collect the weights for regularization
      tf_weights = []
  
      # Build the item representations
      (
          self.tf_item_representation,
          item_weights,
      ) = self.item_repr_graph_factory.connect_representation_graph(
          tf_features=tf_item_features,
          n_components=self.n_components,
          n_features=n_item_features,
          node_name_ending="item",
      )
      tf_weights.extend(item_weights)
  
      tf_x_user, tf_x_item = split_sparse_tensor_indices(
          tf_sparse_tensor=tf_interactions, n_dimensions=2
      )
      tf_transposed_sample_indices = tf.transpose(
          self.tf_sample_indices
      )
      tf_x_user_sample = tf_transposed_sample_indices[0]
      tf_x_item_sample = tf_transposed_sample_indices[1]
  
      # These lists will hold the reprs and predictions for each taste
      tastes_tf_user_representations = []
      tastes_tf_predictions = []
      tastes_tf_prediction_serials = []
      tastes_tf_sample_prediction_serials = []
  
      # If this model does not use attention, Nones are used as sentinels in place of the attentions
      if self.attention_graph_factory is not None:
          tastes_tf_attentions = []
          tastes_tf_attention_serials = []
          tastes_tf_sample_attention_serials = []
          tastes_tf_attention_representations = []
      else:
          tastes_tf_attentions = None
          tastes_tf_attention_serials = None
          tastes_tf_sample_attention_serials = None
          tastes_tf_attention_representations = None
  
      # Build n_tastes user representations and predictions
      for taste in range(self.n_tastes):
          (
              tf_user_representation,
              user_weights,
          ) = self.user_repr_graph_factory.connect_representation_graph(
              tf_features=tf_user_features,
              n_components=self.n_components,
              n_features=n_user_features,
              node_name_ending="user_{}".format(taste),
          )
          tastes_tf_user_representations.append(tf_user_representation)
          tf_weights.extend(user_weights)
  
          # Connect attention, if applicable
          if self.attention_graph_factory is not None:
              (
                  tf_attention_representation,
                  attention_weights,
              ) = self.attention_graph_factory.connect_representation_graph(
                  tf_features=tf_user_features,
                  n_components=self.n_components,
                  n_features=n_user_features,
                  node_name_ending="attn_{}".format(taste),
              )
              tf_weights.extend(attention_weights)
  
              tf_attention = self.prediction_graph_factory.connect_dense_prediction_graph(
                  tf_user_representation=tf_attention_representation,
                  tf_item_representation=self.tf_item_representation,
              )
              tf_attention_serial = self.prediction_graph_factory.connect_serial_prediction_graph(
                  tf_user_representation=tf_attention_representation,
                  tf_item_representation=self.tf_item_representation,
                  tf_x_user=tf_x_user,
                  tf_x_item=tf_x_item,
              )
              tf_sample_attention_serial = self.prediction_graph_factory.connect_serial_prediction_graph(
                  tf_user_representation=tf_user_representation,
                  tf_item_representation=self.tf_item_representation,
                  tf_x_user=tf_x_user_sample,
                  tf_x_item=tf_x_item_sample,
              )
  
              tastes_tf_attentions.append(tf_attention)
              tastes_tf_attention_serials.append(tf_attention_serial)
              tastes_tf_sample_attention_serials.append(
                  tf_sample_attention_serial
              )
              tastes_tf_attention_representations.append(
                  tf_attention_representation
              )
  
          # Connect the configurable prediction graphs for each taste
          tf_prediction = self.prediction_graph_factory.connect_dense_prediction_graph(
              tf_user_representation=tf_user_representation,
              tf_item_representation=self.tf_item_representation,
          )
          tf_prediction_serial = self.prediction_graph_factory.connect_serial_prediction_graph(
              tf_user_representation=tf_user_representation,
              tf_item_representation=self.tf_item_representation,
              tf_x_user=tf_x_user,
              tf_x_item=tf_x_item,
          )
          tf_sample_predictions_serial = self.prediction_graph_factory.connect_serial_prediction_graph(
              tf_user_representation=tf_user_representation,
              tf_item_representation=self.tf_item_representation,
              tf_x_user=tf_x_user_sample,
              tf_x_item=tf_x_item_sample,
          )
  
          # Append to tastes
          tastes_tf_predictions.append(tf_prediction)
          tastes_tf_prediction_serials.append(tf_prediction_serial)
          tastes_tf_sample_prediction_serials.append(
              tf_sample_predictions_serial
          )
  
      # If attention is in the graph, build the API node
      if self.attention_graph_factory is not None:
          self.tf_user_attention_representation = tf.stack(
              tastes_tf_attention_representations
          )
  
      self.tf_user_representation = tf.stack(
          tastes_tf_user_representations
      )
      self.tf_prediction = collapse_mixture_of_tastes(
          tastes_predictions=tastes_tf_predictions,
          tastes_attentions=tastes_tf_attentions,
      )
      self.tf_prediction_serial = collapse_mixture_of_tastes(
          tastes_predictions=tastes_tf_prediction_serials,
          tastes_attentions=tastes_tf_attention_serials,
      )
      tf_sample_predictions_serial = collapse_mixture_of_tastes(
          tastes_predictions=tastes_tf_sample_prediction_serials,
          tastes_attentions=tastes_tf_sample_attention_serials,
      )
  
      # Add biases, if this is a biased estimator
      if self.biased:
          (
              tf_user_feature_biases,
              self.tf_projected_user_biases,
          ) = project_biases(
              tf_features=tf_user_features, n_features=n_user_features
          )
          (
              tf_item_feature_biases,
              self.tf_projected_item_biases,
          ) = project_biases(
              tf_features=tf_item_features, n_features=n_item_features
          )
  
          tf_weights.append(tf_user_feature_biases)
          tf_weights.append(tf_item_feature_biases)
  
          self.tf_prediction = bias_prediction_dense(
              tf_prediction=self.tf_prediction,
              tf_projected_user_biases=self.tf_projected_user_biases,
              tf_projected_item_biases=self.tf_projected_item_biases,
          )
  
          self.tf_prediction_serial = bias_prediction_serial(
              tf_prediction_serial=self.tf_prediction_serial,
              tf_projected_user_biases=self.tf_projected_user_biases,
              tf_projected_item_biases=self.tf_projected_item_biases,
              tf_x_user=tf_x_user,
              tf_x_item=tf_x_item,
          )
  
          tf_sample_predictions_serial = bias_prediction_serial(
              tf_prediction_serial=tf_sample_predictions_serial,
              tf_projected_user_biases=self.tf_projected_user_biases,
              tf_projected_item_biases=self.tf_projected_item_biases,
              tf_x_user=tf_x_user_sample,
              tf_x_item=tf_x_item_sample,
          )
  
      tf_interactions_serial = tf_interactions.values
  
      # Construct API nodes
      self.tf_rankings = rank_predictions(
          tf_prediction=self.tf_prediction
      )
      self.tf_predict_similar_items = predict_similar_items(
          prediction_graph_factory=self.prediction_graph_factory,
          tf_item_representation=self.tf_item_representation,
          tf_similar_items_ids=self.tf_similar_items_ids,
      )
      self.tf_rank_similar_items = rank_predictions(
          tf_prediction=self.tf_predict_similar_items
      )
  
      # Compose loss function args
      # This composition is for execution safety: it prevents loss functions that are incorrectly configured from
      # having visibility of certain nodes.
      loss_graph_kwargs = {
          "tf_prediction_serial": self.tf_prediction_serial,
          "tf_interactions_serial": tf_interactions_serial,
          "tf_interactions": tf_interactions,
          "tf_n_users": tf_n_users,
          "tf_n_items": tf_n_items,
      }
      if self.loss_graph_factory.is_dense:
          loss_graph_kwargs.update(
              {
                  "tf_prediction": self.tf_prediction,
                  "tf_rankings": self.tf_rankings,
              }
          )
      if self.loss_graph_factory.is_sample_based:
          tf_sample_predictions = densify_sampled_item_predictions(
              tf_sample_predictions_serial=tf_sample_predictions_serial,
              tf_n_sampled_items=self.tf_n_sampled_items,
              tf_n_users=tf_n_users,
          )
          loss_graph_kwargs.update(
              {
                  "tf_sample_predictions": tf_sample_predictions,
                  "tf_n_sampled_items": self.tf_n_sampled_items,
              }
          )
  
      # Build loss graph
      self.tf_basic_loss = self.loss_graph_factory.connect_loss_graph(
          **loss_graph_kwargs
      )
  
      self.tf_weight_reg_loss = sum(
          tf.nn.l2_loss(weights) for weights in tf_weights
      )
      self.tf_loss = self.tf_basic_loss + (
          self.tf_alpha * self.tf_weight_reg_loss
      )
      self.tf_optimizer = tf.train.AdamOptimizer(
          learning_rate=self.tf_learning_rate
      ).minimize(self.tf_loss)
  
      # Record the new node names
      self._record_graph_hook_names()
  
imports: from functools import partial
  from itertools import cycle
  import logging
  import numpy
  import os
  import pickle
  from scipy import sparse
  import tensorflow
  from .errors import ModelNotBiasedException, ModelNotFitException, ModelWithoutAttentionException, BatchNonSparseInputException, TfVersionException
  from .input_utils import create_tensorrec_iterator, get_dimensions_from_tensorrec_dataset
  from .loss_graphs import AbstractLossGraph, RMSELossGraph
  from .prediction_graphs import AbstractPredictionGraph, DotProductPredictionGraph
  from .recommendation_graphs import project_biases, split_sparse_tensor_indices, bias_prediction_dense, bias_prediction_serial, rank_predictions, densify_sampled_item_predictions, collapse_mixture_of_tastes, predict_similar_items
  from .representation_graphs import AbstractRepresentationGraph, LinearRepresentationGraph
  from .session_management import get_session
  from .util import sample_items, calculate_batched_alpha, datasets_from_raw_input
label_desc: Use image node_id 8 for calling the TensorRec obj's underlying member method code with example usage: obj._build_tf_graph(n_user_features, n_item_features) without return types