def train_on_batch(self, q_features: List[Dict],
                       c_features: List[Dict],
                       entity_tokens_pos: List[int],
                       labels: List[int]) -> float:
        """

        Args:
            q_features: batch of indices of text subwords
            c_features: batch of indices of entity description subwords
            entity_tokens_pos: list of indices of special tokens
            labels: 1 if entity is appropriate to context, 0 - otherwise

        Returns:
            the value of loss
        """
        _input = {'labels': labels}
        _input['entity_tokens_pos'] = entity_tokens_pos
        for elem in ['input_ids', 'attention_mask']:
            inp_elem = [getattr(f, elem) for f in q_features]
            _input[f"q_{elem}"] = torch.LongTensor(inp_elem).to(self.device)
        for elem in ['input_ids', 'attention_mask']:
            inp_elem = [getattr(f, elem) for f in c_features]
            _input[f"c_{elem}"] = torch.LongTensor(inp_elem).to(self.device)

        self.model.train()
        self.model.zero_grad()
        self.optimizer.zero_grad()  # zero the parameter gradients

        loss, softmax_scores = self.model(**_input)
        self._make_step(loss)

        return loss.item()


        Args:
            q_features: batch of indices of text subwords
            c_features: batch of indices of entity description subwords
            entity_tokens_pos: list of indices of special tokens
            labels: 1 if entity is appropriate to context, 0 - otherwise

        Returns:
            the value of loss
        
deeppavlov/models/torch_bert/torch_transformers_el_ranker.py