class_docstr: TorchRankerAgent implementation of the biencoder.
  
  It is a standalone Agent. It might be called by the Both Encoder.
code: def score_candidates(self, batch, cand_vecs, cand_encs=None):
      # Encode contexts first
      token_idx_ctxt, segment_idx_ctxt, mask_ctxt = to_bert_input(
          batch.text_vec, self.NULL_IDX
      )
      embedding_ctxt, _ = self.model(
          token_idx_ctxt, segment_idx_ctxt, mask_ctxt, None, None, None
      )
  
      if cand_encs is not None:
          return embedding_ctxt.mm(cand_encs.t())
  
      if len(cand_vecs.size()) == 2 and cand_vecs.dtype == torch.long:
          # train time. We compare with all elements of the batch
          (
              token_idx_cands,
              segment_idx_cands,
              mask_cands,
          ) = to_bert_input(cand_vecs, self.NULL_IDX)
          _, embedding_cands = self.model(
              None,
              None,
              None,
              token_idx_cands,
              segment_idx_cands,
              mask_cands,
          )
          return embedding_ctxt.mm(embedding_cands.t())
  
      # predict time with multiple candidates
      if len(cand_vecs.size()) == 3:
          csize = cand_vecs.size()  # batchsize x ncands x sentlength
          cands_idx_reshaped = cand_vecs.view(
              csize[0] * csize[1], csize[2]
          )
          (
              token_idx_cands,
              segment_idx_cands,
              mask_cands,
          ) = to_bert_input(cands_idx_reshaped, self.NULL_IDX)
          _, embedding_cands = self.model(
              None,
              None,
              None,
              token_idx_cands,
              segment_idx_cands,
              mask_cands,
          )
          embedding_cands = embedding_cands.view(
              csize[0], csize[1], -1
          )  # batchsize x ncands x embed_size
          embedding_cands = embedding_cands.transpose(
              1, 2
          )  # batchsize x embed_size x ncands
          embedding_ctxt = embedding_ctxt.unsqueeze(
              1
          )  # batchsize x 1 x embed_size
          scores = torch.bmm(
              embedding_ctxt, embedding_cands
          )  # batchsize x 1 x ncands
          scores = scores.squeeze(1)  # batchsize x ncands
          return scores
  
      # otherwise: cand_vecs should be 2D float vector ncands x embed_size
      return embedding_ctxt.mm(cand_vecs.t())
  
imports: from typing import Optional
  from parlai.core.params import ParlaiParser
  from parlai.core.opt import Opt
  from parlai.core.torch_ranker_agent import TorchRankerAgent
  from parlai.utils.torch import padded_3d
  from parlai.zoo.bert.build import download
  from parlai.utils.io import PathManager
  from .bert_dictionary import BertDictionaryAgent
  from .helpers import BertWrapper, BertModel, add_common_args, surround, MODEL_PATH
  import os
  import torch
  from tqdm import tqdm
label_desc: Use image node_id 9 for calling the BiEncoderRankerAgent obj's underlying member method code with example usage: obj.score_candidates(batch, cand_vecs, cand_encs) and returns: embedding_ctxt, embedding_ctxt, embedding_ctxt, scores