def train_on_batch(self, c_tokens: np.ndarray, c_chars: np.ndarray, q_tokens: np.ndarray, q_chars: np.ndarray,<EOL>y1s: Tuple[List[int], ...], y2s: Tuple[List[int], ...]) -> float:
<EOL>y1s = np.array([x[<NUM_LIT:0>] for x in y1s])<EOL>y2s = np.array([x[<NUM_LIT:0>] for x in y2s])<EOL>if self.noans_token:<EOL><INDENT>noans_mask = ((y1s != -<NUM_LIT:1>) * (y2s != -<NUM_LIT:1>))<EOL>y1s = (y1s + <NUM_LIT:1>) * noans_mask<EOL>y2s = (y2s + <NUM_LIT:1>) * noans_mask<EOL><DEDENT>feed_dict = self._build_feed_dict(c_tokens, c_chars, q_tokens, q_chars, y1s, y2s)<EOL>loss, _, lear_rate = self.sess.run([self.loss, self.train_op, self.lear_rate_ph],<EOL>feed_dict=feed_dict)<EOL>report = {'<STR_LIT>': loss, '<STR_LIT>': float(lear_rate), '<STR_LIT>': self.get_momentum()}<EOL>return report<EOL>
This method is called by trainer to make one training step on one batch.

Args:
    c_tokens: batch of tokenized contexts
    c_chars: batch of tokenized contexts, each token split on chars
    q_tokens: batch of tokenized questions
    q_chars: batch of tokenized questions, each token split on chars
    y1s: batch of ground truth answer start positions
    y2s: batch of ground truth answer end positions

Returns:
    value of loss function on batch