class_docstr: Pseudo-Prototypical Proxy loss (PPP-loss).
  This is a contrastive loss using prototypes and representations of the
  samples in the batch to optimize the embedding space.
class_docstr_tok: ["Pseudo-Prototypical","Proxy","loss","(","PPP-loss",")",".","This","is","a","contrastive","loss","using","prototypes","and","representations","of","the","samples","in","the","batch","to","optimize","the","embedding","space","."]
docstr: The loss is calculated with one-vs-rest batches Bc and Bk,
  split into the attractor and repellor loss terms.
  We iterate over the possible batches while accumulating the losses per
  class c vs other-classes k.
docstr_tok: ["The","loss","is","calculated","with","one-vs-rest","batches","Bc","and","Bk",",","split","into","the","attractor","and","repellor","loss","terms",".","We","iterate","over","the","possible","batches","while","accumulating","the","losses","per","class","c","vs","other-classes","k","."]
code: def __call__(self, x, y):
      """
      The loss is calculated with one-vs-rest batches Bc and Bk,
      split into the attractor and repellor loss terms.
      We iterate over the possible batches while accumulating the losses per
      class c vs other-classes k.
      """
      loss = None
      bs = x.size(0)
      x = x.view(bs, -1)  # Batch x feature size
      y_unique = torch.unique(y).squeeze().view(-1)
      include_repellor = (
          len(y_unique.size()) <= 1
      )  # When at least 2 classes
  
      # All prototypes
      p_y = (
          torch.tensor([c for c in self.p_mem.keys()])
          .to(x.device)
          .detach()
      )
      p_x = (
          torch.cat([self.p_mem[c.item()] for c in p_y])
          .to(x.device)
          .detach()
      )
  
      for label_idx in range(y_unique.size(0)):  # Per-class operation
          c = y_unique[label_idx]
  
          # Make all-vs-rest batches per class (Bc=attractor, Bk=repellor set)
          Bc = x.index_select(0, torch.nonzero(y == c).squeeze(dim=1))
          Bk = x.index_select(0, torch.nonzero(y != c).squeeze(dim=1))
  
          p_idx = torch.nonzero(p_y == c).squeeze(dim=1)  # Prototypes
          pc = p_x[p_idx]  # Class proto
          pk = (
              torch.cat([p_x[:p_idx], p_x[p_idx + 1 :]])
              .clone()
              .detach()
          )
  
          # Accumulate loss for instances of class c
          sum_logLc = self.attractor(pc, pk, Bc)
          sum_logLk = (
              self.repellor(pc, pk, Bc, Bk) if include_repellor else 0
          )
          Loss_c = (
              -sum_logLc - sum_logLk
          )  # attractor + repellor for class c
          loss = (
              Loss_c if loss is None else loss + Loss_c
          )  # Update loss
      return loss / bs
  
imports: from typing import Dict
  import torch
  from torch import Tensor
  from torch.nn.functional import normalize
  from torch.nn.modules import Module
  from avalanche.training.utils import get_last_fc_layer, swap_last_fc_layer
  from avalanche.training.plugins.strategy_plugin import SupervisedPlugin
  from avalanche.training.storage_policy import ClassBalancedBuffer
  from avalanche.benchmarks.utils.data_loader import ReplayDataLoader
label_desc: Use image node_id 2 for calling the PPPloss obj's underlying member method code with example usage: obj.__call__(x, y) and returns: unknown