class_docstr: SAS Rec model
  Self-Attentive Sequential Recommendation Using Transformer
  
  :Citation:
  
      Wang-Cheng Kang, Julian McAuley (2018), Self-Attentive Sequential
      Recommendation. Proceedings of IEEE International Conference on
      Data Mining (ICDM'18)
  
      Original source code from nnkkmto/SASRec-tf2,
      https://github.com/nnkkmto/SASRec-tf2
docstr: High level function for model training as well as
  evaluation on the validation and test dataset
docstr_tok: ["High","level","function","for","model","training","as","well","as","evaluation","on","the","validation","and","test","dataset"]
code: def train(self, dataset, sampler, **kwargs):
      """
      High level function for model training as well as
      evaluation on the validation and test dataset
      """
      num_epochs = kwargs.get("num_epochs", 10)
      batch_size = kwargs.get("batch_size", 128)
      lr = kwargs.get("learning_rate", 0.001)
      val_epoch = kwargs.get("val_epoch", 5)
  
      num_steps = int(len(dataset.user_train) / batch_size)
  
      optimizer = tf.keras.optimizers.Adam(
          learning_rate=lr, beta_1=0.9, beta_2=0.999, epsilon=1e-7
      )
  
      loss_function = self.loss_function
  
      train_loss = tf.keras.metrics.Mean(name="train_loss")
  
      train_step_signature = [
          {
              "users": tf.TensorSpec(shape=(None, 1), dtype=tf.int64),
              "input_seq": tf.TensorSpec(
                  shape=(None, self.seq_max_len), dtype=tf.int64
              ),
              "positive": tf.TensorSpec(
                  shape=(None, self.seq_max_len), dtype=tf.int64
              ),
              "negative": tf.TensorSpec(
                  shape=(None, self.seq_max_len), dtype=tf.int64
              ),
          },
          tf.TensorSpec(shape=(None, 1), dtype=tf.int64),
      ]
  
      @tf.function(input_signature=train_step_signature)
      def train_step(inp, tar):
          with tf.GradientTape() as tape:
              pos_logits, neg_logits, loss_mask = self(
                  inp, training=True
              )
              loss = loss_function(pos_logits, neg_logits, loss_mask)
  
          gradients = tape.gradient(loss, self.trainable_variables)
          optimizer.apply_gradients(
              zip(gradients, self.trainable_variables)
          )
  
          train_loss(loss)
          return loss
  
      T = 0.0
      t0 = Timer()
      t0.start()
  
      for epoch in range(1, num_epochs + 1):
          step_loss = []
          train_loss.reset_states()
          for step in tqdm(
              range(num_steps),
              total=num_steps,
              ncols=70,
              leave=False,
              unit="b",
          ):
              u, seq, pos, neg = sampler.next_batch()
  
              inputs, target = self.create_combined_dataset(
                  u, seq, pos, neg
              )
  
              loss = train_step(inputs, target)
              step_loss.append(loss)
  
          if epoch % val_epoch == 0:
              t0.stop()
              t1 = t0.interval
              T += t1
              print("Evaluating...")
              t_test = self.evaluate(dataset)
              t_valid = self.evaluate_valid(dataset)
              print(
                  f"\nepoch: {epoch}, time: {T}, valid (NDCG@10: {t_valid[0]}, HR@10: {t_valid[1]})"
              )
              print(
                  f"epoch: {epoch}, time: {T},  test (NDCG@10: {t_test[0]}, HR@10: {t_test[1]})"
              )
              t0.start()
  
      t_test = self.evaluate(dataset)
      print(
          f"\nepoch: {epoch}, test (NDCG@10: {t_test[0]}, HR@10: {t_test[1]})"
      )
  
      return t_test
  
imports: import random
  import numpy
  from tqdm import tqdm
  import tensorflow
  from recommenders.utils.timer import Timer
label_desc: Use image node_id 7 for calling the SASREC obj's underlying member method code with example usage: obj.train(dataset, sampler) and returns: t_test, loss