code: def _reduce_output(self, outputs, seq_lengths):
          
          batch_size = outputs.shape[0]
          reduced = []
          # Necessary to iterate over batch because of different sequence lengths
          for i in range(batch_size):
              if self.lstm_reduction == "mean":
                  # Average over all non-padding reduced
                  # Use dim=0 because first dimension disappears after indexing
                  reduced.append(outputs[i, : seq_lengths[i], :].mean(dim=0))
              elif self.lstm_reduction == "max":
                  # Max-pool over all non-padding reduced
                  # Use dim=0 because first dimension disappears after indexing
                  reduced.append(outputs[i, : seq_lengths[i], :].max(dim=0)[0])
              elif self.lstm_reduction == "last":
                  # Take the last output of the sequence (before padding starts)
                  # NOTE: maybe better to take first and last?
                  reduced.append(outputs[i, seq_lengths[i] - 1, :])
              elif self.lstm_reduction == "attention":
                  reduced.append(self._attention(outputs[i, : seq_lengths[i], :]))
              else:
                  msg = (
                      f"Did not recognize lstm kwarg 'lstm_reduction' == "
                      f"{self.lstm_reduction}"
                  )
                  raise ValueError(msg)
          return torch.stack(reduced, dim=0)
docs: Reduces the output of an LSTM step
  
          Args:
              outputs: (torch.FloatTensor) the hidden state outputs from the
                  lstm, with shape [batch_size, max_seq_length, hidden_size]