class_docstr: Sum cross entropy loss:
  - For a single tensor, this is equivalent to the cross-entropy loss.
  - For a list of tensors, this computes the sum of the cross-entropy
  losses for each tensor in the list against the target.
  
  Can accommodate target vectors, e.g. smoothed labels.
class_docstr_tok: ["Sum","cross","entropy","loss",":","-","For","a","single","tensor",",","this","is","equivalent","to","the","cross-entropy","loss",".","-","For","a","list","of","tensors",",","this","computes","the","sum","of","the","cross-entropy","losses","for","each","tensor","in","the","list","against","the","target",".","Can","accommodate","target","vectors",",","e.g",".","smoothed","labels","."]
docstr: For each output and single target, loss is calculated.
  The returned loss value is the sum loss across all outputs.
docstr_tok: ["For","each","output","and","single","target",",","loss","is","calculated",".","The","returned","loss","value","is","the","sum","loss","across","all","outputs","."]
code: def forward(
      self,
      output: Union[torch.Tensor, List[torch.Tensor]],
      target: torch.Tensor,
  ):
      """
      For each output and single target, loss is calculated.
      The returned loss value is the sum loss across all outputs.
      """
      if isinstance(output, torch.Tensor):
          output = [output]
      assert isinstance(
          output, list
      ), "Model output should be a list of tensors. Got Type {}".format(
          type(output)
      )
      assert torch.is_tensor(
          target
      ), "Target should be a tensor. Got Type {}".format(type(target))
  
      loss = 0
      for i, pred in enumerate(output):
          if i >= len(self._losses):
              self._losses.append(self._create_loss_function())
  
          if isinstance(pred, EnsembleOutput):
              # Shape batch_size, ensemble_size, pred_size -> batch_size * ensemble_size, pred_size
              ensemble_size, batch_size, pred_size = pred.outputs.shape
              pred = torch.reshape(
                  pred.outputs, (ensemble_size * batch_size, pred_size)
              )
              local_target = (
                  target.unsqueeze(0)
                  .expand((ensemble_size, batch_size))
                  .flatten()
              )
          else:
              local_target = target
  
          assert (
              local_target.max().item() < pred.shape[1]
          ), f"pred.shape[1]={pred.shape[1]} and target.max().item()={target.max().item()}"
  
          if self._normalize_output:
              pred = nn.functional.normalize(pred, dim=1, p=2)
  
          if self._label_smoothing > 0.0:
              local_target = self.apply_label_smoothing(
                  local_target,
                  num_labels=pred.shape[1],
                  label_smoothing=self._label_smoothing,
              )
  
          loss += self._losses[i](
              pred / self._temperature, local_target
          )
      return loss
  
imports: from dataclasses import dataclass
  from typing import List, Optional, Union
  import torch
  import torch.nn.functional
  from classy_vision.generic.util import is_on_gpu
  from classy_vision.losses import ClassyLoss, register_loss
  from torch import nn, Tensor
  from vissl.config import AttrDict
label_desc: Use image node_id 2 for calling the CrossEntropyMultipleOutputSingleTargetCriterion obj's underlying member method code with example usage: obj.forward(output, target) and returns: loss