code: def forward(self, x):
          
          head_outputs = [None] * self.t
  
          # Execute input layer
          if isinstance(self.input_layer, list):  # One input_module per task
              input_outputs = [mod(x) for mod, x in zip(self.input_layer, x)]
              x = torch.stack(input_outputs, dim=1)
  
              # Execute level-0 task heads from their respective input modules
              for t in self.task_map[0]:
                  head = self.heads[t]
                  head_outputs[t] = head(input_outputs[t])
          else:  # One input_module for all tasks
              x = self.input_layer(x)
  
              # Execute level-0 task heads from the single input module
              for t in self.task_map[0]:
                  head = self.heads[t]
                  head_outputs[t] = head(x)
  
          # Execute middle layers
          for i, layer in enumerate(self.middle_layers, start=1):
              x = layer(x)
  
              # Attach level-i task heads from the ith middle module
              for t in self.task_map[i]:
                  head = self.heads[t]
                  # Optionally include as input the predictions of parent tasks
                  if self.config["pass_predictions"] and bool(self.task_graph.parents[t]):
                      task_input = [x]
                      for p in self.task_graph.parents[t]:
                          task_input.append(head_outputs[p])
                      task_input = torch.stack(task_input, dim=1)
                  else:
                      task_input = x
                  head_outputs[t] = head(task_input)
          return head_outputs
docs: Returns a list of outputs for tasks 0,...t-1
  
          Args:
              x: a [batch_size, ...] batch from X