class_docstr: TCTS Model
  
  Parameters
  ----------
  d_feat : int
      input dimension for each time step
  metric: str
      the evaluation metric used in early stop
  optimizer : str
      optimizer name
  GPU : str
      the GPU ID(s) used for training
class_docstr_tok: ["TCTS","Model","Parameters","--","--","--","--","--","d_feat",":","int","input","dimension","for","each","time","step","metric",":","str","the","evaluation","metric","used","in","early","stop","optimizer",":","str","optimizer","name","GPU",":","str","the","GPU","ID","(","s",")","used","for","training"]
code: def train_epoch(self, x_train, y_train, x_valid, y_valid):
      x_train_values = x_train.values
      y_train_values = np.squeeze(y_train.values)
  
      indices = np.arange(len(x_train_values))
      np.random.shuffle(indices)
  
      task_embedding = torch.zeros([self.batch_size, self.output_dim])
      task_embedding[:, self.target_label] = 1
      task_embedding = task_embedding.to(self.device)
  
      init_fore_model = copy.deepcopy(self.fore_model)
      for p in init_fore_model.parameters():
          p.requires_grad = False
  
      self.fore_model.train()
      self.weight_model.train()
  
      for p in self.weight_model.parameters():
          p.requires_grad = False
      for p in self.fore_model.parameters():
          p.requires_grad = True
  
      for i in range(self.steps):
          for i in range(len(indices))[:: self.batch_size]:
              if len(indices) - i < self.batch_size:
                  break
  
              feature = (
                  torch.from_numpy(
                      x_train_values[indices[i : i + self.batch_size]]
                  )
                  .float()
                  .to(self.device)
              )
              label = (
                  torch.from_numpy(
                      y_train_values[indices[i : i + self.batch_size]]
                  )
                  .float()
                  .to(self.device)
              )
  
              init_pred = init_fore_model(feature)
              pred = self.fore_model(feature)
              dis = init_pred - label.transpose(0, 1)
              weight_feature = torch.cat(
                  (
                      feature,
                      dis.transpose(0, 1),
                      label,
                      init_pred.view(-1, 1),
                      task_embedding,
                  ),
                  1,
              )
              weight = self.weight_model(weight_feature)
  
              loss = self.loss_fn(pred, label, weight)
  
              self.fore_optimizer.zero_grad()
              loss.backward()
              torch.nn.utils.clip_grad_value_(
                  self.fore_model.parameters(), 3.0
              )
              self.fore_optimizer.step()
  
      x_valid_values = x_valid.values
      y_valid_values = np.squeeze(y_valid.values)
  
      indices = np.arange(len(x_valid_values))
      np.random.shuffle(indices)
      for p in self.weight_model.parameters():
          p.requires_grad = True
      for p in self.fore_model.parameters():
          p.requires_grad = False
  
      # fix forecasting model and valid weight model
      for i in range(len(indices))[:: self.batch_size]:
          if len(indices) - i < self.batch_size:
              break
  
          feature = (
              torch.from_numpy(
                  x_valid_values[indices[i : i + self.batch_size]]
              )
              .float()
              .to(self.device)
          )
          label = (
              torch.from_numpy(
                  y_valid_values[indices[i : i + self.batch_size]]
              )
              .float()
              .to(self.device)
          )
  
          pred = self.fore_model(feature)
          dis = pred - label.transpose(0, 1)
          weight_feature = torch.cat(
              (
                  feature,
                  dis.transpose(0, 1),
                  label,
                  pred.view(-1, 1),
                  task_embedding,
              ),
              1,
          )
          weight = self.weight_model(weight_feature)
          loc = torch.argmax(weight, 1)
          valid_loss = torch.mean(
              (pred - label[:, abs(self.target_label)]) ** 2
          )
          loss = torch.mean(
              valid_loss
              * torch.log(weight[np.arange(weight.shape[0]), loc])
          )
  
          self.weight_optimizer.zero_grad()
          loss.backward()
          torch.nn.utils.clip_grad_value_(
              self.weight_model.parameters(), 3.0
          )
          self.weight_optimizer.step()
  
imports: from __future__ import division
  from __future__ import print_function
  import numpy
  import pandas
  import copy
  import random
  from ...utils import get_or_create_path
  from ...log import get_module_logger
  import torch
  import torch.nn
  import torch.optim
  from ...model.base import Model
  from ...data.dataset import DatasetH
  from ...data.dataset.handler import DataHandlerLP
label_desc: Use image node_id 3 for calling the TCTS obj's underlying member method code with example usage: obj.train_epoch(x_train, y_train, x_valid, y_valid) without return types