Sample by beam search.

        Parameters
        ----------
        F
        inputs : NDArray or Symbol
            The initial input of the decoder. Shape is (batch_size,).
        states : Object that contains NDArrays or Symbols
            The initial states of the decoder.
        Returns
        -------
        samples : NDArray or Symbol
            Samples draw by beam search. Shape (batch_size, beam_size, length). dtype is int32.
        scores : NDArray or Symbol
            Scores of the samples. Shape (batch_size, beam_size). We make sure that scores[i, :] are
            in descending order.
        valid_length : NDArray or Symbol
            The valid length of the samples. Shape (batch_size, beam_size). dtype will be int32.

def hybrid_forward(self, F, inputs, states):   # pylint: disable=arguments-differ
        """Sample by beam search.

        Parameters
        ----------
        F
        inputs : NDArray or Symbol
            The initial input of the decoder. Shape is (batch_size,).
        states : Object that contains NDArrays or Symbols
            The initial states of the decoder.
        Returns
        -------
        samples : NDArray or Symbol
            Samples draw by beam search. Shape (batch_size, beam_size, length). dtype is int32.
        scores : NDArray or Symbol
            Scores of the samples. Shape (batch_size, beam_size). We make sure that scores[i, :] are
            in descending order.
        valid_length : NDArray or Symbol
            The valid length of the samples. Shape (batch_size, beam_size). dtype will be int32.
        """
        batch_size = self._batch_size
        beam_size = self._beam_size
        vocab_size = self._vocab_size
        # Tile the states and inputs to have shape (batch_size * beam_size, ...)
        state_info = self._state_info_func(batch_size)
        step_input = _expand_to_beam_size(inputs, beam_size=beam_size,
                                          batch_size=batch_size).astype(np.int32)
        states = _expand_to_beam_size(states, beam_size=beam_size, batch_size=batch_size,
                                      state_info=state_info)
        state_structure, states = _extract_and_flatten_nested_structure(states)
        if beam_size == 1:
            init_scores = F.zeros(shape=(batch_size, 1))
        else:
            init_scores = F.concat(
                F.zeros(shape=(batch_size, 1)),
                F.full(shape=(batch_size, beam_size - 1), val=LARGE_NEGATIVE_FLOAT),
                dim=1)
        vocab_size = F.full(shape=(1,), val=vocab_size, dtype=np.int32)
        batch_shift = F.arange(0, batch_size * beam_size, beam_size, dtype=np.int32)

        def _loop_cond(_i, _samples, _indices, _step_input, _valid_length, _scores, \
            beam_alive_mask, *_states):
            return F.sum(beam_alive_mask) > 0

        def _loop_func(i, samples, indices, step_input, valid_length, scores, \
            beam_alive_mask, *states):
            outputs, new_states = self._decoder(
                step_input, _reconstruct_flattened_structure(state_structure, states))
            step = i + 1
            new_samples, new_valid_length, new_scores, \
                chosen_word_ids, new_beam_alive_mask, new_new_states = \
                self._updater(samples, valid_length, outputs, scores, step.astype(np.float32),
                              beam_alive_mask,
                              _extract_and_flatten_nested_structure(new_states)[-1],
                              vocab_size, batch_shift)
            new_step_input = F.relu(chosen_word_ids).reshape((-1,))
            # We are doing `new_indices = indices[1 : ] + indices[ : 1]`
            new_indices = F.concat(
                indices.slice_axis(axis=0, begin=1, end=None),
                indices.slice_axis(axis=0, begin=0, end=1),
                dim=0)
            return [], (step, new_samples, new_indices, new_step_input, new_valid_length, \
                   new_scores, new_beam_alive_mask) + tuple(new_new_states)

        _, pad_samples, indices, _, new_valid_length, new_scores, new_beam_alive_mask = \
            F.contrib.while_loop(
                cond=_loop_cond, func=_loop_func, max_iterations=self._max_length,
                loop_vars=(
                    F.zeros(shape=(1,), dtype=np.int32),                        # i
                    F.zeros(shape=(batch_size, beam_size, self._max_length),
                            dtype=np.int32),                                    # samples
                    F.arange(start=0, stop=self._max_length, dtype=np.int32),   # indices
                    step_input,                                                 # step_input
                    F.ones(shape=(batch_size, beam_size), dtype=np.int32),      # valid_length
                    init_scores,                                                # scores
                    F.ones(shape=(batch_size, beam_size), dtype=np.int32),      # beam_alive_mask
                ) + tuple(states)
            )[1][:7]                                                            # I hate Python 2
        samples = pad_samples.take(indices, axis=2)

        def _then_func():
            new_samples = F.concat(
                step_input.reshape((batch_size, beam_size, 1)),
                samples,
                F.full(shape=(batch_size, beam_size, 1), val=-1, dtype=np.int32),
                dim=2,
                name='concat3')
            new_new_valid_length = new_valid_length
            return new_samples, new_new_valid_length

        def _else_func():
            final_word = F.where(new_beam_alive_mask,
                                 F.full(shape=(batch_size, beam_size), val=self._eos_id,
                                        dtype=np.int32),
                                 F.full(shape=(batch_size, beam_size), val=-1, dtype=np.int32))
            new_samples = F.concat(
                step_input.reshape((batch_size, beam_size, 1)),
                samples,
                final_word.reshape((0, 0, 1)),
                dim=2)
            new_new_valid_length = new_valid_length + new_beam_alive_mask
            return new_samples, new_new_valid_length

        new_samples, new_new_valid_length = \
            F.contrib.cond(F.sum(new_beam_alive_mask) == 0, _then_func, _else_func)
        return new_samples, new_scores, new_new_valid_length