code: def attend_on_question(self,
                             query: torch.Tensor,
                             encoder_outputs: torch.Tensor,
                             encoder_output_mask: torch.Tensor) -> Tuple[torch.Tensor, torch.Tensor]:
          
          # (group_size, question_length)
          question_attention_weights = self._input_attention(query,
                                                             encoder_outputs,
                                                             encoder_output_mask)
          # (group_size, encoder_output_dim)
          attended_question = util.weighted_sum(encoder_outputs, question_attention_weights)
          return attended_question, question_attention_weights
docs: Given a query (which is typically the decoder hidden state), compute an attention over the
          output of the question encoder, and return a weighted sum of the question representations
          given this attention.  We also return the attention weights themselves.
  
          This is a simple computation, but we have it as a separate method so that the ``forward``
          method on the main parser module can call it on the initial hidden state, to simplify the
          logic in ``take_step``.