class_docstr: HardNegativeSampler is used to suppress false positive rate in classification tasks.
  During training, it selects negative samples with high prediction scores.
  
  The training workflow is described as the follows:
  1) forward network and get prediction scores (classification prob/logits) for all the samples;
  2) use hard negative sampler to choose negative samples with high prediction scores and some positive samples;
  3) compute classification loss for the selected samples;
  4) do back propagation.
  
  Args:
      batch_size_per_image: number of training samples to be randomly selected per image
      positive_fraction: percentage of positive elements in the selected samples
      min_neg: minimum number of negative samples to select if possible.
      pool_size: when we need ``num_neg`` hard negative samples, they will be randomly selected from
          ``num_neg * pool_size`` negative samples with the highest prediction scores.
          Larger ``pool_size`` gives more randomness, yet selects negative samples that are less 'hard',
          i.e., negative samples with lower prediction scores.
class_docstr_tok: ["HardNegativeSampler","is","used","to","suppress","false","positive","rate","in","classification","tasks",".","During","training",",","it","selects","negative","samples","with","high","prediction","scores",".","The","training","workflow","is","described","as","the","follows",":","1",")","forward","network","and","get","prediction","scores","(","classification","prob\/logits",")","for","all","the","samples",";","2",")","use","hard","negative","sampler","to","choose","negative","samples","with","high","prediction","scores","and","some","positive","samples",";","3",")","compute","classification","loss","for","the","selected","samples",";","4",")","do","back","propagation",".","Args",":","batch_size_per_image",":","number","of","training","samples","to","be","randomly","selected","per","image","positive_fraction",":","percentage","of","positive","elements","in","the","selected","samples","min_neg",":","minimum","number","of","negative","samples","to","select","if","possible",".","pool_size",":","when","we","need","``","num_neg","``","hard","negative","samples",",","they","will","be","randomly","selected","from","``","num_neg","*","pool_size","``","negative","samples","with","the","highest","prediction","scores",".","Larger","``","pool_size","``","gives","more","randomness",",","yet","selects","negative","samples","that","are","less","'hard","'",",","i.e.",",","negative","samples","with","lower","prediction","scores","."]
docstr: Select positives and hard negatives from samples.
  
  Args:
      labels_per_img: labels, sized (A,).
          Positive samples have positive labels, negative samples have label 0.
      fg_probs_per_img: maximum foreground probability, sized (A,)
  
  Returns:
      - binary mask for positive samples, sized (A,)
      - binary mask for negative samples, sized (A,)
  
  Example:
      .. code-block:: python
  
          sampler = HardNegativeSampler(
              batch_size_per_image=6, positive_fraction=0.5, min_neg=1, pool_size=2
          )
          # two images with different number of samples
          target_labels = torch.tensor([1,0,2,1])
          fg_probs = torch.rand(4)
          pos_idx, neg_idx = sampler.select_samples_per_img(target_labels, fg_probs)
docstr_tok: ["Select","positives","and","hard","negatives","from","samples",".","Args",":","labels_per_img",":","labels",",","sized","(","A",",",")",".","Positive","samples","have","positive","labels",",","negative","samples","have","label","0.","fg_probs_per_img",":","maximum","foreground","probability",",","sized","(","A",",",")","Returns",":","-","binary","mask","for","positive","samples",",","sized","(","A",",",")","-","binary","mask","for","negative","samples",",","sized","(","A",",",")","Example",":","..","code-block",":",":","python","sampler","=","HardNegativeSampler","(","batch_size_per_image=6",",","positive_fraction=0.5",",","min_neg=1",",","pool_size=2",")","#","two","images","with","different","number","of","samples","target_labels","=","torch.tensor","(","[","1,0,2,1","]",")","fg_probs","=","torch.rand","(","4",")","pos_idx",",","neg_idx","=","sampler.select_samples_per_img","(","target_labels",",","fg_probs",")"]
code: def select_samples_per_img(
      self, labels_per_img: Tensor, fg_probs_per_img: Tensor
  ) -> tuple[Tensor, Tensor]:
      """
      Select positives and hard negatives from samples.
  
      Args:
          labels_per_img: labels, sized (A,).
              Positive samples have positive labels, negative samples have label 0.
          fg_probs_per_img: maximum foreground probability, sized (A,)
  
      Returns:
          - binary mask for positive samples, sized (A,)
          - binary mask for negative samples, sized (A,)
  
      Example:
          .. code-block:: python
  
              sampler = HardNegativeSampler(
                  batch_size_per_image=6, positive_fraction=0.5, min_neg=1, pool_size=2
              )
              # two images with different number of samples
              target_labels = torch.tensor([1,0,2,1])
              fg_probs = torch.rand(4)
              pos_idx, neg_idx = sampler.select_samples_per_img(target_labels, fg_probs)
      """
      # for each image, find positive sample indices and negative sample indices
      if labels_per_img.numel() != fg_probs_per_img.numel():
          raise ValueError(
              "labels_per_img and fg_probs_per_img should have same number of elements."
          )
  
      positive = torch.where(labels_per_img >= 1)[0]
      negative = torch.where(labels_per_img == 0)[0]
  
      num_pos = self.get_num_pos(positive)
      pos_idx_per_image_mask = self.select_positives(
          positive, num_pos, labels_per_img
      )
  
      num_neg = self.get_num_neg(negative, num_pos)
      neg_idx_per_image_mask = self.select_negatives(
          negative, num_neg, fg_probs_per_img
      )
  
      return pos_idx_per_image_mask, neg_idx_per_image_mask
  
file_path: MONAI/monai/apps/detection/utils/hard_negative_sampler.py
imports: from __future__ import annotations
  import logging
  import torch
  from torch import Tensor
label_desc: Use image node_id 4 for calling the HardNegativeSampler obj's underlying member method code with example usage: obj.select_samples_per_img(labels_per_img, fg_probs_per_img) and returns: pos_idx_per_image_mask,  neg_idx_per_image_mask