class_docstr: This class computes the loss for DETR.
  The process happens in two steps:
      1) we compute hungarian assignment between ground truth boxes and the outputs
         of the model
      2) we supervise each pair of matched ground-truth / prediction (supervise class
         and box)
class_docstr_tok: ["This","class","computes","the","loss","for","DETR",".","The","process","happens","in","two","steps",":","1",")","we","compute","hungarian","assignment","between","ground","truth","boxes","and","the","outputs","of","the","model","2",")","we","supervise","each","pair","of","matched","ground-truth","\/","prediction","(","supervise","class","and","box",")"]
code: def _attribute_loss(self, attribute_logits, attributes):
      _N, _B, _C = attribute_logits.size()
      assert _C == self.attribute_class_num
      attribute_logits = attribute_logits.view(_N * _B, _C)
  
      assert attributes.size(0) == _N
      assert attributes.size(1) == _B
      assert attributes.size(2) == self.max_attribute_num
      attributes = attributes.view(_N * _B, self.max_attribute_num)
  
      # https://github.com/ronghanghu/vqa-maskrcnn-benchmark-m4c/blob/0fbccee2dfed10d652bcf014f9f8bfafd8478f51/maskrcnn_benchmark/modeling/roi_heads/box_head/loss.py#L185-L222  # NoQA
      n_boxes = attribute_logits.shape[0]
  
      # N_BOXES, N_ATTR -> N_BOXES, 1, N_ATTR
      attribute_logits = attribute_logits.unsqueeze(1)
  
      # N_BOXES, 1, N_ATTR -> N_BOXES, MAX_ATTR_PER_INST, N_ATTR
      # -> N_BOXES * MAX_ATTR_PER_INST, N_ATTR
      attribute_logits = (
          attribute_logits.expand(n_boxes, 16, self.attribute_class_num)
          .contiguous()
          .view(-1, self.attribute_class_num)
      )
  
      # Normalize each box loss by # of valid GT attributes (ie attr != -1)
      # Repeat number of valid attributes per box along the rows and take transpose
      inv_per_box_weights = (
          (attributes >= 0)
          .sum(dim=1)
          .repeat(16, 1)
          .transpose(0, 1)
          .flatten()
      )
      per_box_weights = inv_per_box_weights.float().reciprocal()
      per_box_weights[per_box_weights > 1] = 0.0
  
      attributes = attributes.view(-1)
      attribute_loss = 0.5 * F.cross_entropy(
          attribute_logits,
          attributes,
          reduction="none",
          ignore_index=-1,
      )
  
      attribute_loss = (
          (attribute_loss * per_box_weights)
          .view(n_boxes, -1)
          .sum(dim=1)
      )
  
      # Find number of boxes with atleast valid attribute
      n_valid_boxes = len(attribute_loss.nonzero())
  
      if n_valid_boxes > 0:
          attribute_loss = (attribute_loss / n_valid_boxes).sum()
      else:
          attribute_loss = (attribute_loss * 0.0).sum()
  
      return attribute_loss
  
imports: from typing import Optional
  import torch
  import torch.nn.functional
  from mmf.models.unit.backbone import build_unit_convnet_backbone
  from mmf.models.unit.matcher import HungarianMatcher
  from mmf.models.unit.misc import NestedTensor
  from mmf.models.unit.transformer import UniTTransformer
  from mmf.utils import box_ops
  from mmf.utils.distributed import get_world_size, is_dist_initialized
  from torch import nn, Tensor
label_desc: Use image node_id 10 for calling the SetCriterion obj's underlying member method code with example usage: obj._attribute_loss(attribute_logits, attributes) and returns: attribute_loss