class_docstr: Modified from Partial-FC
class_docstr_tok: ["Modified","from","Partial-FC"]
code: def forward_backward(self, label, features, optimizer, feature_w):
      self._iters += 1
      total_label, norm_weight, index_positive = self.prepare(
          label, optimizer
      )
      total_features = torch.zeros(
          size=[self.batch_size * self.world_size, self.embedding_size],
          device=self.device,
      )
      dist.all_gather(
          list(total_features.chunk(self.world_size, dim=0)),
          features.data,
      )
      total_features.requires_grad = True
  
      if feature_w is not None:
          total_feature_w = torch.zeros(
              size=[
                  self.batch_size * self.world_size,
                  self.embedding_size,
              ],
              device=self.device,
          )
          dist.all_gather(
              list(total_feature_w.chunk(self.world_size, dim=0)),
              feature_w.data,
          )
  
      if self.vpl_mode >= 0:
          self.prepare_queue_lambda(total_label, self._iters)
          _lambda = self.queue_lambda.view(self.num_local, 1)
          injected_weight = (
              norm_weight * (1.0 - _lambda) + self.queue * _lambda
          )
          injected_norm_weight = normalize(injected_weight)
          logits = self.forward(total_features, injected_norm_weight)
      else:
          logits = self.forward(total_features, norm_weight)
  
      logits = self.margin_softmax(logits, total_label)
  
      with torch.no_grad():
          max_fc = torch.max(logits, dim=1, keepdim=True)[0]
          dist.all_reduce(max_fc, dist.ReduceOp.MAX)
  
          # calculate exp(logits) and all-reduce
          logits_exp = torch.exp(logits - max_fc)
          logits_sum_exp = logits_exp.sum(dim=1, keepdims=True)
          dist.all_reduce(logits_sum_exp, dist.ReduceOp.SUM)
  
          # calculate prob
          logits_exp.div_(logits_sum_exp)
  
          # get one-hot
          grad = logits_exp
          index = torch.where(total_label != -1)[0]
          one_hot = torch.zeros(
              size=[index.size()[0], grad.size()[1]], device=grad.device
          )
          one_hot.scatter_(1, total_label[index, None], 1)
  
          # calculate loss
          loss = torch.zeros(grad.size()[0], 1, device=grad.device)
          loss[index] = grad[index].gather(1, total_label[index, None])
          dist.all_reduce(loss, dist.ReduceOp.SUM)
          loss_v = loss.clamp_min_(1e-30).log_().mean() * (-1)
  
          # calculate grad
          grad[index] -= one_hot
          grad.div_(self.batch_size * self.world_size)
  
      logits.backward(grad)
      if total_features.grad is not None:
          total_features.grad.detach_()
      x_grad: torch.Tensor = torch.zeros_like(
          features, requires_grad=True
      )
      # feature gradient all-reduce
      dist.reduce_scatter(
          x_grad,
          list(total_features.grad.chunk(self.world_size, dim=0)),
      )
      x_grad = x_grad * self.world_size
      # vpl set queue
      if self.vpl_mode >= 0:
          if feature_w is None:
              self.set_queue(
                  total_features.detach(),
                  total_label,
                  index_positive,
                  self._iters,
              )
          else:
              self.set_queue(
                  total_feature_w,
                  total_label,
                  index_positive,
                  self._iters,
              )
      # backward backbone
      return x_grad, loss_v
  
file_path: insightface/recognition/vpl/vpl.py
imports: import logging
  import os
  import torch
  import torch.distributed
  from torch.nn import Module
  from torch.nn.functional import normalize, linear
  from torch.nn.parameter import Parameter
label_desc: Use image node_id 9 for calling the VPL obj's underlying member method code with example usage: obj.forward_backward(label, features, optimizer, feature_w) and returns: x_grad,  loss_v