class_docstr: Loss function for behavioral cloning.
docstr: Calculate and return the training loss for one step (= multiple sub-steps in structured scenarios).
  
  :param policy: Structured policy to evaluate.
  :param observations: List with observations w.r.t. actor_ids.
  :param actions: List with actions w.r.t. actor_ids.
  :param action_logits: The optional action logits of the policy.
  :param actor_ids: List of actor ids.
  :param events: Events of current episode.
  :return: Total loss
docstr_tok: ["Calculate","and","return","the","training","loss","for","one","step","(","=","multiple","sub-steps","in","structured","scenarios",")",".",":","param","policy",":","Structured","policy","to","evaluate",".",":","param","observations",":","List","with","observations","w.r.t",".","actor_ids",".",":","param","actions",":","List","with","actions","w.r.t",".","actor_ids",".",":","param","action_logits",":","The","optional","action","logits","of","the","policy",".",":","param","actor_ids",":","List","of","actor","ids",".",":","param","events",":","Events","of","current","episode",".",":","return",":","Total","loss"]
code: def calculate_loss(
      self,
      policy: TorchPolicy,
      observations: List[ObservationType],
      actions: List[TorchActionType],
      action_logits: Optional[List[TorchActionType]],
      actor_ids: List[ActorID],
      events: ImitationEvents,
  ) -> torch.Tensor:
      """Calculate and return the training loss for one step (= multiple sub-steps in structured scenarios).
  
      :param policy: Structured policy to evaluate.
      :param observations: List with observations w.r.t. actor_ids.
      :param actions: List with actions w.r.t. actor_ids.
      :param action_logits: The optional action logits of the policy.
      :param actor_ids: List of actor ids.
      :param events: Events of current episode.
      :return: Total loss
      """
      losses = []
  
      # Iterate over all sub-steps
      assert len(actor_ids) == len(actions)
      assert len(actor_ids) == len(observations)
      target_dict = actions if action_logits is None else action_logits
      for (
          actor_id,
          observation,
          policy_target,
          policy_target_action,
      ) in zip(actor_ids, observations, target_dict, actions):
          policy_output = policy.compute_substep_policy_output(
              observation, actor_id=actor_id
          )
          substep_losses = self._get_substep_loss(
              actor_id,
              policy_output.action_logits,
              policy_target,
              policy_target_action,
              self.action_spaces_dict[actor_id.step_key],
              events=events,
          )
  
          losses.append(substep_losses)
  
          # Compute and report policy entropy
          entropy = policy_output.entropy.mean()
          events.policy_entropy(
              step_id=actor_id.step_key,
              agent_id=actor_id.agent_id,
              value=entropy.item(),
          )
          if self.entropy_coef > 0:
              losses.append(-self.entropy_coef * entropy)
  
      return sum(losses)
  
file_path: maze/maze/train/trainers/imitation/bc_loss.py
imports: from dataclasses import dataclass
  from typing import Dict, Union, List, Optional
  import gym
  import torch
  import torch.nn
  import torch.nn.functional
  from maze.core.agent.torch_policy import TorchPolicy
  from maze.core.env.action_conversion import TorchActionType
  from maze.core.env.observation_conversion import ObservationType
  from maze.core.env.structured_env import ActorID
  from maze.train.trainers.imitation.imitation_events import ImitationEvents
label_desc: Use image node_id 1 for calling the BCLoss obj's underlying member method code with example usage: obj.calculate_loss(policy, observations, actions, action_logits, actor_ids, events) and returns: sum