    def inference(self, memory, obs_and_lat, ret_has_eos=False):
        """ Decoder inference
        PARAMS
        ------
        memory: Encoder outputs
        obs_and_lat: Observed and latent attribute embeddings

        RETURNS
        -------
        mel_outputs: mel outputs from the decoder
        gate_outputs: gate outputs from the decoder
        alignments: sequence of attention weights from the decoder
        """
        decoder_input = self.get_go_frame(memory)

        self.initialize_decoder_states(memory, obs_and_lat, mask=None)

        mel_outputs, gate_outputs, alignments = [], [], []
        has_eos = False
        while True:
            decoder_input = self.prenet(decoder_input)
            mel_output, gate_output, alignment = self.decode(decoder_input)

            mel_outputs += [mel_output.squeeze(1)]
            gate_outputs += [gate_output]
            alignments += [alignment]

            if torch.sigmoid(gate_output.data) > self.gate_threshold:
                has_eos = True
                break
            elif len(mel_outputs) == self.max_decoder_steps:
                # print("Warning! Reached max decoder steps")
                break

            decoder_input = mel_output

        mel_outputs, gate_outputs, alignments = self.parse_decoder_outputs(
            mel_outputs, gate_outputs, alignments)

        if ret_has_eos:
            return mel_outputs, gate_outputs, alignments, has_eos
        else:
            return mel_outputs, gate_outputs, alignments
Decoder inference
PARAMS
------
memory: Encoder outputs
obs_and_lat: Observed and latent attribute embeddings

RETURNS
-------
mel_outputs: mel outputs from the decoder
gate_outputs: gate outputs from the decoder
alignments: sequence of attention weights from the decoder
examples/textless_nlp/gslm/unit2speech/tacotron2/model.py