class_docstr: A Bi Encoder followed by a Cross Encoder.
  
  Although it's trainable by itself, I'd recommend training the crossencoder and the
  biencoder separately which can be done in parallel or sequentially and thus
  requiring less memory on the GPU.
class_docstr_tok: ["A","Bi","Encoder","followed","by","a","Cross","Encoder",".","Although","it","'s","trainable","by","itself",",","I","'d","recommend","training","the","crossencoder","and","the","biencoder","separately","which","can","be","done","in","parallel","or","sequentially","and","thus","requiring","less","memory","on","the","GPU","."]
code: def train_step(self, batch):
      self.biencoder.train_step(batch)
      # the crossencoder requires batches that are smaller.
      # split the batch into smaller pieces
      outc = []
      step = self.crossencoder_batchsize
      for start in range(0, len(batch.text_vec), step):
          mbatch = Batch(
              text_vec=batch.text_vec[start : start + step],
              label_vec=batch.label_vec[start : start + step],
              candidate_vecs=batch.candidate_vecs[start : start + step],
              candidates=batch.candidates[start : start + step],
          )
          outc.append(self.crossencoder.train_step(mbatch))
      return Output(text=[text for out in outc for text in out.text])
  
file_path: ParlAI/parlai/agents/bert_ranker/both_encoder_ranker.py
imports: from typing import Optional
  from parlai.core.params import ParlaiParser
  from parlai.core.opt import Opt
  from .bert_dictionary import BertDictionaryAgent
  from .bi_encoder_ranker import BiEncoderRankerAgent
  from .cross_encoder_ranker import CrossEncoderRankerAgent
  from .helpers import add_common_args
  from parlai.core.torch_agent import TorchAgent, Output, Batch
label_desc: Use image node_id 4 for calling the BothEncoderRankerAgent obj's underlying member method code with example usage: obj.train_step(batch) and returns: Output