from params import STATE_PPO_PARAMS as SPP
from params import STATE_PPO_TRAINER_PARAMS as SPTP
from params import STATE_PPO_TESTER_PARAMS as SPTEP
from params import VISUAL_PPO_TRAINER_PARAMS as VPTP
from params import VISUAL_PPO_TESTER_PARAMS as VPTEP
from models.actor import StateActor, VisualActor
from models.critic import StateCritic, VisualCritic
from utils.general_utils import AttrDict
from utils.model_utils import shuffled_indices, save_checkpoint, load_checkpoint, plot_learning_curve

import cv2
import gym
import numpy as np
import torch as T
from torch.distributions.categorical import Categorical

class PPOMemory:
    def __init__(self, batch_size):
        self.states = []
        self.probs = []
        self.values = []
        self.actions = []
        self.rewards = []
        self.dones = []

        self.batch_size = batch_size

    def generate_batches(self):
        n_states = len(self.states)
        batch_start_indices = np.arange(0, n_states, self.batch_size)
        indices = shuffled_indices(n_states)
        batches = [indices[i:i + self.batch_size] for i in batch_start_indices]
        return [np.array(self.states),
                np.array(self.actions),
                np.array(self.probs),
                np.array(self.values),
                np.array(self.rewards),
                np.array(self.dones),
                batches]

    def store_memory(self, state, action, probs, values, reward, done):
        self.states.append(state)
        self.actions.append(action)
        self.probs.append(probs)
        self.values.append(values)
        self.rewards.append(reward)
        self.dones.append(done)

    def clear_memory(self):
        self.states = []
        self.probs = []
        self.actions = []
        self.rewards = []
        self.dones = []
        self.values = []

class PPOAgent():
    def __init__(self, input_dim, task_name=SPP.TASK_NAME, num_actions=SPP.NUM_ACTIONS,
                 a_alpha=SPP.ACT_LR, c_alpha=SPP.CRIT_LR,
                 gamma=SPP.GAMMA, gae_lambda=SPP.GAE_LAMBDA, policy_clip=SPP.POL_CLIP,
                 use_encoder=SPP.USE_ENCODER, enc_output_dim=SPP.ENC_OUTPUT_DIM,
                 num_encoder_linear_layers=SPP.NUM_ENC_LIN_LAYERS, load_encoder=SPP.LOAD_ENC,
                 retrain_encoder=SPP.RETRAIN_ENC):
        if use_encoder:
            self.actor = VisualActor(input_dim, output_dim=num_actions, alpha=a_alpha, enc_output_dim=enc_output_dim,
                                     num_encoder_linear_layers=num_encoder_linear_layers,
                                     load_encoder=load_encoder, retrain_encoder=retrain_encoder)
            self.critic = VisualCritic(input_dim, alpha=c_alpha, enc_output_dim=enc_output_dim,
                                       num_encoder_linear_layers=num_encoder_linear_layers,
                                       load_encoder=load_encoder, retrain_encoder=retrain_encoder)
        else:
            self.actor = StateActor(input_dim, output_dim=num_actions, alpha=a_alpha)
            self.critic = StateCritic(input_dim, alpha=c_alpha)
        self.gamma = gamma
        self.gae_lambda = gae_lambda
        self.policy_clip = policy_clip
        self.task_name = task_name

    def save_models(self):
        print("...saving models...")
        save_checkpoint(self.actor, task_name=self.task_name)
        save_checkpoint(self.critic, task_name=self.task_name)

    def load_models(self):
        print("...loading models...")
        load_checkpoint(self.actor, task_name=self.task_name)
        load_checkpoint(self.critic, task_name=self.task_name)

    def choose_action(self, state, eps=0.2):
        value = self.critic(state)
        act_probs = self.actor(state)
        p = np.random.rand()
        if p > eps:
            action = T.argmax(act_probs)
            prob = T.log(act_probs[0, action])
        else:
            dist = Categorical(act_probs)
            action = dist.sample()
            prob = dist.log_prob(action)
        prob = T.squeeze(prob).item()
        action = T.squeeze(action).item()
        value = T.squeeze(value).item()

        return action, prob, value

class PPOTrainer():
    def __init__(self, task_name=SPTP.TASK_NAME, env_name=SPTP.ENV_NAME, state_dim=SPTP.STATE_DIM,
                 action_dict=SPTP.ACT_DICT, resolution=SPTP.RESOLUTION, max_ep_len=SPTP.MAX_EP_LEN,
                 obj_size=SPTP.OBJ_SIZE, speed=SPTP.SPEED, num_games=SPTP.NUM_GAMES, batch_size=SPTP.BATCH_SIZE,
                 epochs=SPTP.EPOCHS, learn_trigger=SPTP.LEARN_TRIGGER, avg_window=SPTP.AVG_WINDOW,
                 show_freq=SPTP.SHOW_FREQ, figure_file=SPTP.FIG_FILE, use_encoder=SPTP.USE_ENCODER,
                 enc_output_dim=SPTP.ENC_OUTPUT_DIM, num_encoder_linear_layers=SPTP.NUM_ENC_LIN_LAYERS,
                 load_encoder=SPTP.LOAD_ENC, retrain_encoder=SPTP.RETRAIN_ENC):
        self.task_name = task_name
        self.num_games = num_games
        self.batch_size = batch_size
        self.epochs = epochs
        self.learn_trigger = learn_trigger
        self.ppo_memory = PPOMemory(batch_size)
        self.action_dict = action_dict
        self.use_encoder = use_encoder
        self.ppo_agent = PPOAgent(state_dim, task_name=task_name, num_actions=len(self.action_dict),
                                  use_encoder=use_encoder, enc_output_dim=enc_output_dim,
                                  num_encoder_linear_layers=num_encoder_linear_layers,
                                  load_encoder=load_encoder, retrain_encoder=retrain_encoder)
        self.data_spec = AttrDict(
            resolution=resolution,
            max_ep_len=max_ep_len,
            max_speed=speed,  # total image range [0, 1]
            obj_size=obj_size,  # size of objects, full images is 1.0
            follow=True
        )
        self.env = gym.make(env_name)
        self.env.set_config(self.data_spec)
        self.avg_window = avg_window
        self.show_freq = show_freq
        self.figure_file = figure_file

    def learn(self):
        for _ in range(self.epochs):
            states, actions, old_probs, values, rewards, dones, batches = self.ppo_memory.generate_batches()
            advantage = np.zeros(len(rewards), dtype=np.float32)
            discount = self.ppo_agent.gamma * self.ppo_agent.gae_lambda
            for t in reversed(range(len(rewards)-1)):
                delta_t = rewards[t] + self.ppo_agent.gamma * values[t+1] * (1 - int(dones[t])) - values[t]
                advantage[t] = delta_t + discount * (1 - int(dones[t])) * advantage[t+1]
            advantage = T.tensor(advantage)
            values = T.tensor(values)

            for batch in batches:
                batch_states = T.tensor(states[batch], dtype=T.float)
                batch_old_probs = T.tensor(old_probs[batch])
                batch_actions = T.tensor(actions[batch])

                probs = self.ppo_agent.actor(batch_states)
                critic_value = self.ppo_agent.critic(batch_states)
                dist = Categorical(probs)
                critic_value = T.squeeze(critic_value)
                batch_new_probs = dist.log_prob(batch_actions)
                prob_ratio = batch_new_probs.exp() / batch_old_probs.exp()
                weighted_probs = advantage[batch] * prob_ratio
                weighted_clipped_probs = T.clamp(prob_ratio, 1 - self.ppo_agent.policy_clip,
                                                 1 + self.ppo_agent.policy_clip) * advantage[batch]
                actor_loss = -T.min(weighted_probs, weighted_clipped_probs).mean()
                returns = advantage[batch] + values[batch]
                critic_loss = (returns - critic_value) ** 2
                critic_loss = critic_loss.mean()

                total_loss = actor_loss + 0.5 * critic_loss
                self.ppo_agent.actor.optimizer.zero_grad()
                self.ppo_agent.critic.optimizer.zero_grad()
                total_loss.backward()
                self.ppo_agent.actor.optimizer.step()
                self.ppo_agent.critic.optimizer.step()
        self.ppo_memory.clear_memory()

    def train(self):
        best_score = self.env.reward_range[0]
        score_history = []
        learn_iters = 0
        avg_score = 0
        n_steps = 0

        for i in range(self.num_games):
            state = self.env.reset()
            done = False
            score = 0
            while not done:
                if self.use_encoder:
                    state = PPOTrainer._preprocess_images(state)
                    agent_input = T.tensor([state], dtype=T.float)
                else:
                    agent_input = T.tensor([state], dtype=T.float)
                action, prob, val = self.ppo_agent.choose_action(agent_input, eps=1 - (i / self.num_games))
                state_, reward, done, _, im = self.env.step(self.action_dict[action])
                if self.show_freq and (i % self.show_freq == 0):
                    cv2.imshow(self.task_name, im[:, :, None].repeat(3, axis=2).astype(np.float32) * 255.)
                    cv2.waitKey(5)
                n_steps += 1
                score += reward
                self.ppo_memory.store_memory(state, action, prob, val, reward, done)
                if n_steps % self.learn_trigger == 0:
                    self.learn()
                    learn_iters += 1
                state = state_
            score_history.append(score)
            avg_score = np.mean(score_history[-self.avg_window:])
            if avg_score > best_score:
                best_score = avg_score
                self.ppo_agent.save_models()

            print(f"episode: {i}, score: {score}, avg score: {avg_score},\
                  time_steps: {n_steps}, learning_steps: {learn_iters}")
            plot_learning_curve([i+1 for i in range(len(score_history))], score_history,
                                self.avg_window, self.figure_file)

    @staticmethod
    # Go from (H, W) of [0, 1] to (1, H, W) of [-1, 1]
    def _preprocess_images(images):
        return images[None, :, :].astype(np.float32) * 2.0 - 1.0

class PPOTester():
    def __init__(self, task_name=SPTP.TASK_NAME, env_name=SPTEP.ENV_NAME, state_dim=SPTEP.STATE_DIM,
                 action_dict=SPTEP.ACT_DICT, resolution=SPTEP.RESOLUTION, max_ep_len=SPTEP.MAX_EP_LEN,
                 obj_size=SPTEP.OBJ_SIZE, speed=SPTEP.SPEED, num_games=SPTEP.NUM_GAMES, avg_window=SPTEP.AVG_WINDOW,
                 show=SPTEP.SHOW, figure_file=SPTEP.FIG_FILE, use_encoder=SPTEP.USE_ENCODER,
                 enc_output_dim=SPTEP.ENC_OUTPUT_DIM, num_encoder_linear_layers=SPTEP.NUM_ENC_LIN_LAYERS):
        self.task_name = task_name
        self.num_games = num_games
        self.action_dict = action_dict
        self.data_spec = AttrDict(
            resolution=resolution,
            max_ep_len=max_ep_len,
            max_speed=speed,  # total image range [0, 1]
            obj_size=obj_size,  # size of objects, full images is 1.0
            follow=True
        )
        self.env = gym.make(env_name)
        self.env.set_config(self.data_spec)
        self.avg_window = avg_window
        self.figure_file = figure_file
        self.show = show

        self.use_encoder = use_encoder
        if use_encoder:
            self.actor = VisualActor(state_dim, output_dim=len(self.action_dict), enc_output_dim=enc_output_dim,
                                     num_encoder_linear_layers=num_encoder_linear_layers,
                                     load_encoder=False, retrain_encoder=False)
        else:
            self.actor = StateActor(state_dim, output_dim=len(self.action_dict))
        load_checkpoint(self.actor, task_name=self.task_name)
        self.actor.eval()

    def test(self):
        score_history = []

        for i in range(self.num_games):
            state = self.env.reset()
            done = False
            score = 0
            while not done:
                with T.no_grad():
                    if self.use_encoder:
                        state = PPOTrainer._preprocess_images(state)
                    act_probs = self.actor(T.tensor([state], dtype=T.float))
                    action = T.argmax(act_probs)
                state, reward, done, _, im = self.env.step(self.action_dict[action])
                if self.show:
                    cv2.imshow(self.task_name, im[:, :, None].repeat(3, axis=2).astype(np.float32) * 255.)
                    cv2.waitKey(10)
                score += reward
            score_history.append(score)
            avg_score = np.mean(score_history[-self.avg_window:])

            print(f"episode: {i}, score: {score}, avg score: {avg_score}")
            plot_learning_curve([i+1 for i in range(len(score_history))], score_history,
                                self.avg_window, self.figure_file)
        print(f"average score: {np.mean(score_history)}")

if __name__ == "__main__":
    print_architecture = True
    train_state_ppo = False
    test_state_ppo = True
    train_scratch_ppo = False
    test_scratch_ppo = True
    train_static_rewirl_ppo = False
    test_static_rewirl_ppo = True
    train_finetune_rewirl_ppo = False
    test_finetune_rewirl_ppo = True

    if train_state_ppo:
        spt = PPOTrainer(task_name=SPTP.TASK_NAME, env_name=SPTP.ENV_NAME, state_dim=SPTP.STATE_DIM,
                         action_dict=SPTP.ACT_DICT, resolution=SPTP.RESOLUTION, max_ep_len=SPTP.MAX_EP_LEN,
                         obj_size=SPTP.OBJ_SIZE, speed=SPTP.SPEED, num_games=SPTP.NUM_GAMES, batch_size=SPTP.BATCH_SIZE,
                         epochs=SPTP.EPOCHS, learn_trigger=SPTP.LEARN_TRIGGER, avg_window=SPTP.AVG_WINDOW,
                         show_freq=SPTP.SHOW_FREQ, figure_file=SPTP.FIG_FILE, use_encoder=SPTP.USE_ENCODER,
                         enc_output_dim=SPTP.ENC_OUTPUT_DIM, num_encoder_linear_layers=SPTP.NUM_ENC_LIN_LAYERS,
                         load_encoder=SPTP.LOAD_ENC, retrain_encoder=SPTP.RETRAIN_ENC)
        if print_architecture:
            print(spt.ppo_agent.actor)
            print(spt.ppo_agent.critic)
        spt.train()

    if test_state_ppo:
        spte = PPOTester(task_name=SPTEP.TASK_NAME, env_name=SPTEP.ENV_NAME, state_dim=SPTEP.STATE_DIM,
                         action_dict=SPTEP.ACT_DICT, resolution=SPTEP.RESOLUTION, max_ep_len=SPTEP.MAX_EP_LEN,
                         obj_size=SPTEP.OBJ_SIZE, speed=SPTEP.SPEED, num_games=SPTEP.NUM_GAMES,
                         avg_window=SPTEP.AVG_WINDOW, show=SPTEP.SHOW, figure_file=SPTEP.FIG_FILE,
                         use_encoder=SPTEP.USE_ENCODER, enc_output_dim=SPTEP.ENC_OUTPUT_DIM,
                         num_encoder_linear_layers=SPTEP.NUM_ENC_LIN_LAYERS)
        if print_architecture:
            print(spte.actor)
        spte.test()

    if train_scratch_ppo:
        srpt = PPOTrainer(task_name=f"{VPTP.TASK_NAME}_SCRATCH", env_name=VPTP.ENV_NAME, state_dim=VPTP.STATE_DIM,
                          action_dict=VPTP.ACT_DICT, resolution=VPTP.RESOLUTION, max_ep_len=VPTP.MAX_EP_LEN,
                          obj_size=VPTP.OBJ_SIZE, speed=VPTP.SPEED, num_games=VPTP.NUM_GAMES,
                          batch_size=VPTP.BATCH_SIZE, epochs=VPTP.EPOCHS, learn_trigger=VPTP.LEARN_TRIGGER,
                          avg_window=VPTP.AVG_WINDOW, show_freq=VPTP.SHOW_FREQ,
                          figure_file="plots/visual_scratch_ppo.png",
                          use_encoder=VPTP.USE_ENCODER, enc_output_dim=VPTP.ENC_OUTPUT_DIM,
                          num_encoder_linear_layers=VPTP.NUM_ENC_LIN_LAYERS, load_encoder=False,
                          retrain_encoder=True)
        if print_architecture:
            print(srpt.ppo_agent.actor)
            print(srpt.ppo_agent.critic)
        srpt.train()

    if test_scratch_ppo:
        srpte = PPOTester(task_name=f"{VPTEP.TASK_NAME}_SCRATCH", env_name=VPTEP.ENV_NAME, state_dim=VPTEP.STATE_DIM,
                          action_dict=VPTEP.ACT_DICT, resolution=VPTEP.RESOLUTION, max_ep_len=VPTEP.MAX_EP_LEN,
                          obj_size=VPTEP.OBJ_SIZE, speed=VPTEP.SPEED, num_games=VPTEP.NUM_GAMES,
                          avg_window=VPTEP.AVG_WINDOW, show=VPTEP.SHOW, figure_file="plots/visual_scratch_ppo_test.png",
                          use_encoder=VPTEP.USE_ENCODER, enc_output_dim=VPTEP.ENC_OUTPUT_DIM,
                          num_encoder_linear_layers=VPTEP.NUM_ENC_LIN_LAYERS)
        if print_architecture:
            print(srpte.actor)
        srpte.test()

    if train_static_rewirl_ppo:
        srpt = PPOTrainer(task_name=VPTP.TASK_NAME, env_name=VPTP.ENV_NAME, state_dim=VPTP.STATE_DIM,
                          action_dict=VPTP.ACT_DICT, resolution=VPTP.RESOLUTION, max_ep_len=VPTP.MAX_EP_LEN,
                          obj_size=VPTP.OBJ_SIZE, speed=VPTP.SPEED, num_games=VPTP.NUM_GAMES,
                          batch_size=VPTP.BATCH_SIZE, epochs=VPTP.EPOCHS, learn_trigger=VPTP.LEARN_TRIGGER,
                          avg_window=VPTP.AVG_WINDOW, show_freq=VPTP.SHOW_FREQ, figure_file=VPTP.FIG_FILE,
                          use_encoder=VPTP.USE_ENCODER, enc_output_dim=VPTP.ENC_OUTPUT_DIM,
                          num_encoder_linear_layers=VPTP.NUM_ENC_LIN_LAYERS, load_encoder=VPTP.LOAD_ENC,
                          retrain_encoder=VPTP.RETRAIN_ENC)
        if print_architecture:
            print(srpt.ppo_agent.actor)
            print(srpt.ppo_agent.critic)
        srpt.train()

    if test_static_rewirl_ppo:
        srpte = PPOTester(task_name=VPTEP.TASK_NAME, env_name=VPTEP.ENV_NAME, state_dim=VPTEP.STATE_DIM,
                          action_dict=VPTEP.ACT_DICT, resolution=VPTEP.RESOLUTION, max_ep_len=VPTEP.MAX_EP_LEN,
                          obj_size=VPTEP.OBJ_SIZE, speed=VPTEP.SPEED, num_games=VPTEP.NUM_GAMES,
                          avg_window=VPTEP.AVG_WINDOW, show=VPTEP.SHOW, figure_file=VPTEP.FIG_FILE,
                          use_encoder=VPTEP.USE_ENCODER, enc_output_dim=VPTEP.ENC_OUTPUT_DIM,
                          num_encoder_linear_layers=VPTEP.NUM_ENC_LIN_LAYERS)
        if print_architecture:
            print(srpte.actor)
        srpte.test()

    if train_finetune_rewirl_ppo:
        frpt = PPOTrainer(task_name=f"{VPTP.TASK_NAME}_FINETUNE", env_name=VPTP.ENV_NAME, state_dim=VPTP.STATE_DIM,
                          action_dict=VPTP.ACT_DICT, resolution=VPTP.RESOLUTION, max_ep_len=VPTP.MAX_EP_LEN,
                          obj_size=VPTP.OBJ_SIZE, speed=VPTP.SPEED, num_games=VPTP.NUM_GAMES,
                          batch_size=VPTP.BATCH_SIZE, epochs=VPTP.EPOCHS, learn_trigger=VPTP.LEARN_TRIGGER,
                          avg_window=VPTP.AVG_WINDOW, show_freq=VPTP.SHOW_FREQ,
                          figure_file="plots/visual_finetune_ppo.png",
                          use_encoder=VPTP.USE_ENCODER, enc_output_dim=VPTP.ENC_OUTPUT_DIM,
                          num_encoder_linear_layers=VPTP.NUM_ENC_LIN_LAYERS, load_encoder=VPTP.LOAD_ENC,
                          retrain_encoder=True)
        if print_architecture:
            print(frpt.ppo_agent.actor)
            print(frpt.ppo_agent.critic)
        frpt.train()

    if test_finetune_rewirl_ppo:
        frpte = PPOTester(task_name=f"{VPTEP.TASK_NAME}_FINETUNE", env_name=VPTEP.ENV_NAME, state_dim=VPTEP.STATE_DIM,
                          action_dict=VPTEP.ACT_DICT, resolution=VPTEP.RESOLUTION, max_ep_len=VPTEP.MAX_EP_LEN,
                          obj_size=VPTEP.OBJ_SIZE, speed=VPTEP.SPEED, num_games=VPTEP.NUM_GAMES,
                          avg_window=VPTEP.AVG_WINDOW, show=VPTEP.SHOW,
                          figure_file="plots/visual_finetune_ppo_test.png",
                          use_encoder=VPTEP.USE_ENCODER, enc_output_dim=VPTEP.ENC_OUTPUT_DIM,
                          num_encoder_linear_layers=VPTEP.NUM_ENC_LIN_LAYERS)
        if print_architecture:
            print(frpte.actor)
        frpte.test()


import copy
import math
import random
from typing import *

import torch
from torch import Tensor
from torch import nn
from torch.nn import functional as F
from transformers import modeling_bart as bart
from transformers.modeling_utils import BeamHypotheses, calc_banned_ngram_tokens, calc_banned_bad_words_ids, \
    top_k_top_p_filtering

def extract_backreferences(ids, num_embeddings, backpointer_idx):
    ids_mask = ids >= num_embeddings
    backreferences = ids.clone() - num_embeddings
    backreferences[~ids_mask] = 0
    backreferences += (~ids_mask).long() * torch.arange(
        ids.size(1),
        dtype=ids.dtype,
        device=ids.device)
    ids = ids.clone()
    ids[ids_mask] = backpointer_idx
    return ids, backreferences

class AMRBartEncoder(nn.Module):
    """
    Transformer encoder consisting of *config.encoder_layers* self attention layers. Each layer
    is a :class:`EncoderLayer`.

    Args:
        config: BartConfig
    """

    def __init__(self, config: bart.BartConfig, embed_tokens, backpointer_idx):
        super().__init__()

        self.backpointer_idx = backpointer_idx

        self.dropout = config.dropout
        self.layerdrop = config.encoder_layerdrop
        self.output_attentions = config.output_attentions
        self.output_hidden_states = config.output_hidden_states

        embed_dim = embed_tokens.embedding_dim
        self.embed_scale = math.sqrt(embed_dim) if config.scale_embedding else 1.0
        self.padding_idx = embed_tokens.padding_idx
        self.max_source_positions = config.max_position_embeddings

        self.embed_tokens = embed_tokens

        if config.static_position_embeddings:
            self.embed_positions = bart.SinusoidalPositionalEmbedding(
                config.max_position_embeddings, embed_dim, self.padding_idx
            )
        else:
            self.embed_positions = bart.LearnedPositionalEmbedding(
                config.max_position_embeddings, embed_dim, self.padding_idx, #config.extra_pos_embeddings,
            )

        self.layers = nn.ModuleList([bart.EncoderLayer(config) for _ in range(config.encoder_layers)])
        self.layernorm_embedding = bart.LayerNorm(embed_dim) if config.normalize_embedding else nn.Identity()
        # mbart has one extra layer_norm
        self.layer_norm = bart.LayerNorm(config.d_model) if config.normalize_before else None

    def forward(
        self, input_ids, embedded=None, attention_mask=None,
    ):
        """
        Args:
            input_ids (LongTensor): tokens in the source language of shape
                `(batch, src_len)`
            attention_mask (torch.LongTensor): indicating which indices are padding tokens.
        Returns:
            Tuple comprised of:
                - **x** (Tensor): the last encoder layer's output of
                  shape `(src_len, batch, embed_dim)`
                - **encoder_states** (List[Tensor]): all intermediate
                  hidden states of shape `(src_len, batch, embed_dim)`.
                  Only populated if *self.output_hidden_states:* is True.
                - **all_attentions** (List[Tensor]): Attention weights for each layer.
                During training might not be of length n_layers because of layer dropout.
        """
        # check attention mask and invert
        if attention_mask is not None:
            attention_mask = bart.invert_mask(attention_mask)

        input_ids, backreferences = extract_backreferences(
            input_ids, self.embed_tokens.num_embeddings, self.backpointer_idx)
        inputs_embeds = self.embed_tokens(input_ids) * self.embed_scale
        embed_pos = self.embed_positions(input_ids)
        x = inputs_embeds + embed_pos

        if embedded is not None:
            x += embedded

        x = self.layernorm_embedding(x)
        x = F.dropout(x, p=self.dropout, training=self.training)

        # B x T x C -> T x B x C
        x = x.transpose(0, 1)

        encoder_states, all_attentions = [], []
        for encoder_layer in self.layers:
            if self.output_hidden_states:
                encoder_states.append(x)
            # add LayerDrop (see https://arxiv.org/abs/1909.11556 for description)
            dropout_probability = random.uniform(0, 1)
            if self.training and (dropout_probability < self.layerdrop):  # skip the layer
                attn = None
            else:
                x, attn = encoder_layer(x, attention_mask)

            if self.output_attentions:
                all_attentions.append(attn)

        if self.layer_norm:
            x = self.layer_norm(x)
        if self.output_hidden_states:
            encoder_states.append(x)

        # T x B x C -> B x T x C
        encoder_states = [hidden_state.transpose(0, 1) for hidden_state in encoder_states]
        x = x.transpose(0, 1)

        return x, encoder_states, all_attentions

class AMRBartDecoder(nn.Module):
    """
    Transformer decoder consisting of *config.decoder_layers* layers. Each layer
    is a :class:`DecoderLayer`.
    Args:
        config: BartConfig
        embed_tokens (torch.nn.Embedding): output embedding
    """

    def __init__(self, config: bart.BartConfig, embed_tokens: nn.Embedding, backpointer_idx, amr_mode=True):
        super().__init__()
        self.output_attentions = config.output_attentions
        self.output_hidden_states = config.output_hidden_states
        self.dropout = config.dropout
        self.layerdrop = config.decoder_layerdrop
        self.padding_idx = embed_tokens.padding_idx
        self.max_target_positions = config.max_position_embeddings
        self.embed_scale = math.sqrt(config.d_model) if config.scale_embedding else 1.0
        self.backpointer_idx = backpointer_idx

        embed_dim = embed_tokens.embedding_dim

        self.embed_tokens = embed_tokens
        if config.static_position_embeddings:
            self.embed_positions = bart.SinusoidalPositionalEmbedding(
                config.max_position_embeddings, embed_dim, self.padding_idx
            )
        else:
            self.embed_positions = bart.LearnedPositionalEmbedding(
                config.max_position_embeddings, embed_dim, self.padding_idx, #config.extra_pos_embeddings,
            )

        self.layers = nn.ModuleList(
            [bart.DecoderLayer(config) for _ in range(config.decoder_layers)]
        )  # type: List[DecoderLayer]
        self.layernorm_embedding = bart.LayerNorm(config.d_model) if config.normalize_embedding else nn.Identity()
        self.layer_norm = bart.LayerNorm(config.d_model) if config.add_final_layer_norm else None

        self.pointer_k = nn.Linear(config.d_model, config.d_model)
        # self.pointer_k.weight.data = self.layers[-1].self_attn.k_proj.weight.data.clone()

        self.pointer_q = nn.Linear(config.d_model, config.d_model)
        # self.pointer_q.weight.data = self.layers[-1].self_attn.q_proj.weight.data.clone()

        # self.pointer_k = nn.Sequential(
        #     nn.Linear(config.d_model, config.decoder_ffn_dim),
        #     nn.GELU(),
        #     nn.Linear(config.decoder_ffn_dim, config.d_model),
        # )
        # self.pointer_q = nn.Sequential(
        #     nn.Linear(config.d_model, config.decoder_ffn_dim),
        #     nn.GELU(),
        #     nn.Linear(config.decoder_ffn_dim, config.d_model),
        # )

        self.amr_mode = amr_mode

    def forward(
        self,
        input_ids,
        encoder_hidden_states,
        encoder_padding_mask,
        decoder_padding_mask,
        decoder_causal_mask,
        decoder_cached_states=None,
        use_cache=False,
        **unused
    ):
        """
        Includes several features from "Jointly Learning to Align and
        Translate with Transformer Models" (Garg et al., EMNLP 2019).

        Args:
            input_ids (LongTensor): previous decoder outputs of shape
                `(batch, tgt_len)`, for teacher forcing
            encoder_hidden_states: output from the encoder, used for
                encoder-side attention
            encoder_padding_mask: for ignoring pad tokens
            decoder_cached_states (dict or None): dictionary used for storing state during generation

        Returns:
            tuple:
                - the decoder's features of shape `(batch, tgt_len, embed_dim)`
                - hidden states
                - attentions
        """

        # check attention mask and invert
        if encoder_padding_mask is not None:
            encoder_padding_mask = bart.invert_mask(encoder_padding_mask)

        input_ids, backreferences = extract_backreferences(
            input_ids,
            self.embed_tokens.num_embeddings,
            self.backpointer_idx)
        # embed positions
        embed_pos = self.embed_positions(input_ids, use_cache=use_cache)
        positions = embed_pos

        # to do this during prediction the old positions should be removed
        if use_cache:
            input_ids = input_ids[:, -1:]
            positions = positions[:, -1:]  # happens after we embed them
            # assert input_ids.ne(self.padding_idx).any()

        x = self.embed_tokens(input_ids) * self.embed_scale
        x += positions
        x = self.layernorm_embedding(x)
        x = F.dropout(x, p=self.dropout, training=self.training)

        # Convert to Bart output format: (seq_len, BS, model_dim) -> (BS, seq_len, model_dim)
        x = x.transpose(0, 1)
        encoder_hidden_states = encoder_hidden_states.transpose(0, 1)

        # decoder layers
        all_hidden_states = ()
        all_self_attns = ()
        next_decoder_cache = []
        for idx, decoder_layer in enumerate(self.layers):
            # add LayerDrop (see https://arxiv.org/abs/1909.11556 for description)
            if self.output_hidden_states:
                all_hidden_states += (x,)
            dropout_probability = random.uniform(0, 1)
            if self.training and (dropout_probability < self.layerdrop):
                continue

            layer_state = decoder_cached_states[idx] if decoder_cached_states is not None else None

            x, layer_self_attn, layer_past = decoder_layer(
                x,
                encoder_hidden_states,
                encoder_attn_mask=encoder_padding_mask,
                decoder_padding_mask=decoder_padding_mask,
                layer_state=layer_state,
                causal_mask=decoder_causal_mask,
            )

            if use_cache:
                next_decoder_cache.append(layer_past.copy())

            if self.layer_norm and (idx == len(self.layers) - 1):  # last layer of mbart
                x = self.layer_norm(x)
            if self.output_attentions:
                all_self_attns += (layer_self_attn,)

        # Convert to standard output format: (seq_len, BS, model_dim) -> (BS, seq_len, model_dim)
        all_hidden_states = [hidden_state.transpose(0, 1) for hidden_state in all_hidden_states]
        x = x.transpose(0, 1)
        encoder_hidden_states = encoder_hidden_states.transpose(0, 1)

        xq = self.pointer_q(x)
        xk = self.pointer_k(x)

        if decoder_cached_states is not None:
            if 'prev_key' in decoder_cached_states[-1].get('pointer', {}):
                last_state = decoder_cached_states[-1]['pointer']
                xk = torch.cat([last_state['prev_key'], xk], dim=1)

        next_state = {'pointer': {'prev_key': xk}}

        if use_cache:
            next_decoder_cache.append(next_state)

        if self.amr_mode:
            scores = torch.einsum('bqh,bkh->bqk', xq, xk)

            if decoder_cached_states:
                mask = torch.full_like(scores[0], float('-inf'))
                mask = mask.triu(diagonal=xk.size(1) - 1)
            else:
                mask = torch.full_like(scores[0], float('-inf'))
                mask = mask.triu()
            scores += mask.unsqueeze(0)
        else:
            scores = torch.full((xq.size(0), xq.size(1), xk.size(1)), float('-inf'), device=xq.device)

        if use_cache:
            next_cache = ((encoder_hidden_states, encoder_padding_mask), next_decoder_cache)
        else:
            next_cache = None
        return (x, scores), next_cache, all_hidden_states, list(all_self_attns)

class AMRBartModel(bart.PretrainedBartModel):
    def __init__(self, config: bart.BartConfig, backpointer_idx=None):
        super().__init__(config)
        self.output_attentions = True
        self.output_hidden_states = config.output_hidden_states

        self.padding_idx, vocab_size = config.pad_token_id, config.vocab_size
        self.shared = nn.Embedding(vocab_size, config.d_model, self.padding_idx)

        if backpointer_idx is not None:
            self.backpointer_idx = backpointer_idx
        else:
            self.backpointer_idx = self.shared.num_embeddings - 1

        self.encoder = AMRBartEncoder(config, self.shared, backpointer_idx=self.backpointer_idx)
        self.decoder = AMRBartDecoder(config, self.shared, backpointer_idx=self.backpointer_idx)

        self.init_weights()

    @property
    def sentence_mode(self):
        return self.decoder.amr_mode

    @sentence_mode.setter
    def sentence_mode(self, value):
        assert isinstance(value, bool)
        self.decoder.amr_mode = value

    def forward(
        self,
        input_ids,
        attention_mask=None,
        decoder_input_ids=None,
        encoder_outputs: Optional[Tuple] = None,
        decoder_attention_mask=None,
        decoder_cached_states=None,
        use_cache=False,
    ):

        # make masks if user doesn't supply
        if not use_cache:
            decoder_input_ids, decoder_padding_mask, causal_mask = bart._prepare_bart_decoder_inputs(
                self.config,
                input_ids,
                decoder_input_ids=decoder_input_ids,
                decoder_padding_mask=decoder_attention_mask,
                causal_mask_dtype=self.shared.weight.dtype,
            )
        else:
            decoder_padding_mask, causal_mask = None, None

        assert decoder_input_ids is not None
        if encoder_outputs is None:
            encoder_outputs = self.encoder(input_ids=input_ids, attention_mask=attention_mask)
        assert isinstance(encoder_outputs, tuple)
        # decoder outputs consists of (dec_features, layer_state, dec_hidden, dec_attn)
        decoder_outputs = self.decoder(
            decoder_input_ids,
            encoder_outputs[0],
            attention_mask,
            decoder_padding_mask,
            decoder_causal_mask=causal_mask,
            decoder_cached_states=decoder_cached_states,
            use_cache=use_cache,
        )
        # Attention and hidden_states will be [] or None if they aren't needed
        # decoder_outputs: Tuple = bart._filter_out_falsey_values(decoder_outputs)
        assert isinstance(decoder_outputs[0][0], torch.Tensor)
        assert isinstance(decoder_outputs[0][1], torch.Tensor)
        encoder_outputs: Tuple = bart._filter_out_falsey_values(encoder_outputs)
        return decoder_outputs + encoder_outputs

    def get_input_embeddings(self):
        return self.shared

    def set_input_embeddings(self, value):
        self.shared = value
        self.encoder.embed_tokens = self.shared
        self.decoder.embed_tokens = self.shared

    def get_output_embeddings(self):
        return bart._make_linear_from_emb(self.shared)  # make it on the fly

class AMRBartForConditionalGeneration(bart.PretrainedBartModel):
    base_model_prefix = "model"

    def __init__(self, config: bart.BartConfig, backpointer_idx=None):
        super().__init__(config)
        base_model = AMRBartModel(config, backpointer_idx)
        self.model = base_model
        self.pad_index = base_model.shared.padding_idx
        self.register_buffer("final_logits_bias", torch.zeros((1, self.model.shared.num_embeddings)))
        self.backpointer_idx = backpointer_idx
        self._rev = None

    def init_reverse_model(self):
        rev = AMRBartForConditionalGeneration(self.model.config, self.backpointer_idx)
        rev.model.shared = self.model.shared
        rev.model.encoder = self.model.encoder
        rev.model.decoder.embed_tokens = self.model.decoder.embed_tokens
        rev.model.decoder.embed_positions = self.model.decoder.embed_positions
        self.amr_mode = True
        rev.amr_mode = False
        self._rev = rev

    @property
    def rev(self):
        if self._rev is None:
            return self
        else:
            return self._rev

    @property
    def amr_mode(self):
        return self.model.decoder.amr_mode

    @amr_mode.setter
    def amr_mode(self, value):
        assert isinstance(value, bool)
        self.model.decoder.amr_mode = value

    def forward(
        self,
        input_ids,
        attention_mask=None,
        encoder_outputs=None,
        decoder_input_ids=None,
        decoder_attention_mask=None,
        decoder_cached_states=None,
        lm_labels=None,
        use_cache=False,
        **unused
    ):
        r"""
        lm_labels (:obj:`torch.LongTensor` of shape :obj:`(batch_size, sequence_length)`, `optional`, defaults to :obj:`None`):
            Labels for computing the masked language modeling loss.
            Indices should either be in ``[0, ..., config.vocab_size]`` or -100 (see ``input_ids`` docstring).
            Tokens with indices set to ``-100`` are ignored (masked), the loss is only computed for the tokens
            with labels
            in ``[0, ..., config.vocab_size]``.

    Returns:
        :obj:`tuple(torch.FloatTensor)` comprising various elements depending on the configuration (:class:`~transformers.RobertaConfig`) and inputs:
        masked_lm_loss (`optional`, returned when ``lm_labels`` is provided) ``torch.FloatTensor`` of shape ``(1,)``:
            Masked language modeling loss.
        prediction_scores (:obj:`torch.FloatTensor` of shape :obj:`(batch_size, sequence_length, config.vocab_size)`)
            Prediction scores of the language modeling head (scores for each vocabulary token before SoftMax).
        hidden_states (:obj:`tuple(torch.FloatTensor)`, `optional`, returned when ``config.output_hidden_states=True``):
            Tuple of :obj:`torch.FloatTensor` (one for the output of the embeddings + one for the output of each layer)
            of shape :obj:`(batch_size, sequence_length, hidden_size)`.

            Hidden-states of the model at the output of each layer plus the initial embedding outputs.
        attentions (:obj:`tuple(torch.FloatTensor)`, `optional`, returned when ``config.output_attentions=True``):
            Tuple of :obj:`torch.FloatTensor` (one for each layer) of shape
            :obj:`(batch_size, num_heads, sequence_length, sequence_length)`.

            Attentions weights after the attention softmax, used to compute the weighted average in the self-attention
            heads.

    Examples::

            # Mask filling only works for bart-large
            from transformers import BartTokenizer, BartForConditionalGeneration
            tokenizer = BartTokenizer.from_pretrained('bart-large')
            TXT = "My friends are <mask> but they eat too many carbs."
            model = BartForConditionalGeneration.from_pretrained('bart-large')
            input_ids = tokenizer.batch_encode_plus([TXT], return_tensors='pt')['input_ids']
            logits = model(input_ids)[0]
            masked_index = (input_ids[0] == tokenizer.mask_token_id).nonzero().item()
            probs = logits[0, masked_index].softmax(dim=0)
            values, predictions = probs.topk(5)
            tokenizer.decode(predictions).split()
            # ['good', 'great', 'all', 'really', 'very']
        """
        # outputs = self.model(
        #     input_ids,
        #     attention_mask=attention_mask,
        #     decoder_input_ids=decoder_input_ids,
        #     encoder_outputs=encoder_outputs,
        #     decoder_attention_mask=decoder_attention_mask,
        #     decoder_cached_states=decoder_cached_states,
        #     use_cache=use_cache,
        # )
        # lm_logits = F.linear(outputs[0][0], self.model.shared.weight, bias=self.final_logits_bias)
        # po_logits = outputs[0][1]
        # po_padding = torch.full_like(po_logits[:, :, 0:1], float('-inf'))
        # po_padding = po_padding.repeat(1, 1, 1024 - po_logits.size(-1))
        # po_logits = torch.cat([po_logits, po_padding], -1)
        # uni_logits = torch.cat([lm_logits, po_logits], -1)
        #
        # outputs = (uni_logits,) + outputs[1:]  # Add cache, hidden states and attention if they are here

        outputs = self.compute_logits(
            input_ids,
            attention_mask=attention_mask,
            decoder_input_ids=decoder_input_ids,
            encoder_outputs=encoder_outputs,
            decoder_attention_mask=decoder_attention_mask,
            decoder_cached_states=decoder_cached_states,
            use_cache=use_cache,
        )

        if lm_labels is not None:
            uni_logits = outputs[0]
            masked_lm_loss = F.nll_loss(
                uni_logits.log_softmax(-1).contiguous().view(-1, uni_logits.size(-1)),
                lm_labels.contiguous().view(-1),
                ignore_index=self.pad_index)
            outputs = (masked_lm_loss,) + outputs

        return outputs

    def compute_logits(
        self,
        input_ids,
        attention_mask=None,
        encoder_outputs=None,
        decoder_input_ids=None,
        decoder_attention_mask=None,
        decoder_cached_states=None,
        use_cache=False,
    ):
        outputs = self.model(
            input_ids,
            attention_mask=attention_mask,
            decoder_input_ids=decoder_input_ids,
            encoder_outputs=encoder_outputs,
            decoder_attention_mask=decoder_attention_mask,
            decoder_cached_states=decoder_cached_states,
            use_cache=use_cache,
        )

        lm_logits = F.linear(outputs[0][0], self.model.shared.weight, bias=self.final_logits_bias)
        po_logits = outputs[0][1]
        po_padding = torch.full_like(po_logits[:, :, 0:1], float('-inf'))
        po_padding = po_padding.repeat(1, 1, 1024 - po_logits.size(-1))
        po_logits = torch.cat([po_logits, po_padding], -1)
        uni_logits = torch.cat([lm_logits, po_logits], -1)
        outputs = (uni_logits,) + outputs[1:]  # Add cache, hidden states and attention if they are here
        return outputs

    @torch.no_grad()
    def generate(
            self,
            input_ids: Optional[torch.LongTensor] = None,
            max_length: Optional[int] = None,
            min_length: Optional[int] = None,
            do_sample: Optional[bool] = None,
            early_stopping: Optional[bool] = None,
            num_beams: Optional[int] = None,
            temperature: Optional[float] = None,
            top_k: Optional[int] = None,
            top_p: Optional[float] = None,
            repetition_penalty: Optional[float] = None,
            bad_words_ids: Optional[Iterable[int]] = None,
            bos_token_id: Optional[int] = None,
            pad_token_id: Optional[int] = None,
            eos_token_id: Optional[int] = None,
            length_penalty: Optional[float] = None,
            no_repeat_ngram_size: Optional[int] = None,
            num_return_sequences: Optional[int] = None,
            attention_mask: Optional[torch.LongTensor] = None,
            decoder_start_token_id: Optional[int] = None,
            use_cache: Optional[bool] = None,
            **model_specific_kwargs
    ) -> torch.LongTensor:
        r""" Generates sequences for models with a LM head. The method currently supports greedy decoding, beam-search decoding, sampling with temperature, sampling with top-k or nucleus sampling.

        Adapted in part from `Facebook's XLM beam search code`_.

        .. _`Facebook's XLM beam search code`:
           https://github.com/facebookresearch/XLM/blob/9e6f6814d17be4fe5b15f2e6c43eb2b2d76daeb4/src/model/transformer.py#L529

        Parameters:

            input_ids: (`optional`) `torch.LongTensor` of shape `(batch_size, sequence_length)`
                The sequence used as a prompt for the generation. If `None` the method initializes
                it as an empty `torch.LongTensor` of shape `(1,)`.

            max_length: (`optional`) int
                The max length of the sequence to be generated.  Between `min_length` and infinity. Default to 20.

            min_length: (`optional`) int
                The min length of the sequence to be generated.  Between 0 and infinity. Default to 0.

            do_sample: (`optional`) bool
                If set to `False` greedy decoding is used. Otherwise sampling is used. Defaults to `False` as defined in `configuration_utils.PretrainedConfig`.

            early_stopping: (`optional`) bool
                if set to `True` beam search is stopped when at least `num_beams` sentences finished per batch. Defaults to `False` as defined in `configuration_utils.PretrainedConfig`.

            num_beams: (`optional`) int
                Number of beams for beam search. Must be between 1 and infinity. 1 means no beam search. Default to 1.

            temperature: (`optional`) float
                The value used to module the next token probabilities. Must be strictly positive. Default to 1.0.

            top_k: (`optional`) int
                The number of highest probability vocabulary tokens to keep for top-k-filtering. Between 1 and infinity. Default to 50.

            top_p: (`optional`) float
                The cumulative probability of parameter highest probability vocabulary tokens to keep for nucleus sampling. Must be between 0 and 1. Default to 1.

            repetition_penalty: (`optional`) float
                The parameter for repetition penalty. Between 1.0 and infinity. 1.0 means no penalty. Default to 1.0.

            pad_token_id: (`optional`) int
                Padding token. Default to specicic model pad_token_id or None if it does not exist.

            bos_token_id: (`optional`) int
                BOS token. Defaults to `bos_token_id` as defined in the models config.

            eos_token_id: (`optional`) int
                EOS token. Defaults to `eos_token_id` as defined in the models config.

            length_penalty: (`optional`) float
                Exponential penalty to the length. Default to 1.

            no_repeat_ngram_size: (`optional`) int
                If set to int > 0, all ngrams of size `no_repeat_ngram_size` can only occur once.
            bad_words_ids: (`optional`) list of lists of int
                `bad_words_ids` contains tokens that are not allowed to be generated. In order to get the tokens of the words that should not appear in the generated text, use `tokenizer.encode(bad_word, add_prefix_space=True)`.

            num_return_sequences: (`optional`) int
                The number of independently computed returned sequences for each element in the batch. Default to 1.

            attention_mask (`optional`) obj: `torch.LongTensor` of same shape as `input_ids`
                Mask to avoid performing attention on padding token indices.
                Mask values selected in ``[0, 1]``:
                ``1`` for tokens that are NOT MASKED, ``0`` for MASKED tokens.
                Defaults to `None`.

                `What are attention masks? <../glossary.html#attention-mask>`__

            decoder_start_token_id=None: (`optional`) int
                If an encoder-decoder model starts decoding with a different token than BOS.
                Defaults to `None` and is changed to `BOS` later.

            use_cache: (`optional`) bool
                If `use_cache` is True, past key values are used to speed up decoding if applicable to model. Defaults to `True`.

            model_specific_kwargs: (`optional`) dict
                Additional model specific kwargs will be forwarded to the `forward` function of the model.

        Return:

            output: `torch.LongTensor` of shape `(batch_size * num_return_sequences, sequence_length)`
                sequence_length is either equal to max_length or shorter if all batches finished early due to the `eos_token_id`

        Examples::

            tokenizer = AutoTokenizer.from_pretrained('distilgpt2')   # Initialize tokenizer
            model = AutoModelWithLMHead.from_pretrained('distilgpt2')    # Download model and configuration from S3 and cache.
            outputs = model.generate(max_length=40)  # do greedy decoding
            print('Generated: {}'.format(tokenizer.decode(outputs[0], skip_special_tokens=True)))

            tokenizer = AutoTokenizer.from_pretrained('openai-gpt')   # Initialize tokenizer
            model = AutoModelWithLMHead.from_pretrained('openai-gpt')    # Download model and configuration from S3 and cache.
            input_context = 'The dog'
            input_ids = tokenizer.encode(input_context, return_tensors='pt')  # encode input context
            outputs = model.generate(input_ids=input_ids, num_beams=5, num_return_sequences=3, temperature=1.5)  # generate 3 independent sequences using beam search decoding (5 beams) with sampling from initial context 'The dog'
            for i in range(3): #  3 output sequences were generated
                print('Generated {}: {}'.format(i, tokenizer.decode(outputs[i], skip_special_tokens=True)))

            tokenizer = AutoTokenizer.from_pretrained('distilgpt2')   # Initialize tokenizer
            model = AutoModelWithLMHead.from_pretrained('distilgpt2')    # Download model and configuration from S3 and cache.
            input_context = 'The dog'
            input_ids = tokenizer.encode(input_context, return_tensors='pt')  # encode input context
            outputs = model.generate(input_ids=input_ids, max_length=40, temperature=0.7, num_return_sequences=3)  # 3 generate sequences using by sampling
            for i in range(3): #  3 output sequences were generated
                print('Generated {}: {}'.format(i, tokenizer.decode(outputs[i], skip_special_tokens=True)))

            tokenizer = AutoTokenizer.from_pretrained('ctrl')   # Initialize tokenizer
            model = AutoModelWithLMHead.from_pretrained('ctrl')    # Download model and configuration from S3 and cache.
            input_context = 'Legal My neighbor is'  # "Legal" is one of the control codes for ctrl
            input_ids = tokenizer.encode(input_context, return_tensors='pt')  # encode input context
            outputs = model.generate(input_ids=input_ids, max_length=50, temperature=0.7, repetition_penalty=1.2)  # generate sequences
            print('Generated: {}'.format(tokenizer.decode(outputs[0], skip_special_tokens=True)))

            tokenizer = AutoTokenizer.from_pretrained('gpt2')   # Initialize tokenizer
            model = AutoModelWithLMHead.from_pretrained('gpt2')    # Download model and configuration from S3 and cache.
            input_context = 'My cute dog'  # "Legal" is one of the control codes for ctrl
            bad_words_ids = [tokenizer.encode(bad_word, add_prefix_space=True) for bad_word in ['idiot', 'stupid', 'shut up']]
            input_ids = tokenizer.encode(input_context, return_tensors='pt')  # encode input context
            outputs = model.generate(input_ids=input_ids, max_length=100, do_sample=True, bad_words_ids=bad_words_ids)  # generate sequences without allowing bad_words to be generated
        """

        # We cannot generate if the model does not have a LM head
        if self.get_output_embeddings() is None:
            raise AttributeError(
                "You tried to generate sequences with a model that does not have a LM Head."
                "Please use another model class (e.g. `OpenAIGPTLMHeadModel`, `XLNetLMHeadModel`, `GPT2LMHeadModel`, `CTRLLMHeadModel`, `T5WithLMHeadModel`, `TransfoXLLMHeadModel`, `XLMWithLMHeadModel`, `BartForConditionalGeneration` )"
            )

        max_length = max_length if max_length is not None else self.config.max_length
        min_length = min_length if min_length is not None else self.config.min_length
        do_sample = do_sample if do_sample is not None else self.config.do_sample
        early_stopping = early_stopping if early_stopping is not None else self.config.early_stopping
        use_cache = use_cache if use_cache is not None else self.config.use_cache
        num_beams = num_beams if num_beams is not None else self.config.num_beams
        temperature = temperature if temperature is not None else self.config.temperature
        top_k = top_k if top_k is not None else self.config.top_k
        top_p = top_p if top_p is not None else self.config.top_p
        repetition_penalty = repetition_penalty if repetition_penalty is not None else self.config.repetition_penalty
        bos_token_id = bos_token_id if bos_token_id is not None else self.config.bos_token_id
        pad_token_id = pad_token_id if pad_token_id is not None else self.config.pad_token_id
        eos_token_id = eos_token_id if eos_token_id is not None else self.config.eos_token_id
        length_penalty = length_penalty if length_penalty is not None else self.config.length_penalty
        no_repeat_ngram_size = (
            no_repeat_ngram_size if no_repeat_ngram_size is not None else self.config.no_repeat_ngram_size
        )
        bad_words_ids = bad_words_ids if bad_words_ids is not None else self.config.bad_words_ids
        num_return_sequences = (
            num_return_sequences if num_return_sequences is not None else self.config.num_return_sequences
        )
        decoder_start_token_id = (
            decoder_start_token_id if decoder_start_token_id is not None else self.config.decoder_start_token_id
        )

        if input_ids is not None:
            batch_size = input_ids.shape[0]  # overriden by the input batch_size
        else:
            batch_size = 1

        assert isinstance(max_length, int) and max_length > 0, "`max_length` should be a strictly positive integer."
        assert isinstance(min_length, int) and min_length >= 0, "`min_length` should be a positive integer."
        assert isinstance(do_sample, bool), "`do_sample` should be a boolean."
        assert isinstance(early_stopping, bool), "`early_stopping` should be a boolean."
        assert isinstance(use_cache, bool), "`use_cache` should be a boolean."
        assert isinstance(num_beams, int) and num_beams > 0, "`num_beams` should be a strictly positive integer."
        assert temperature > 0, "`temperature` should be strictly positive."
        assert isinstance(top_k, int) and top_k >= 0, "`top_k` should be a positive integer."
        assert 0 <= top_p <= 1, "`top_p` should be between 0 and 1."
        assert repetition_penalty >= 1.0, "`repetition_penalty` should be >= 1."
        assert input_ids is not None or (
                isinstance(bos_token_id, int) and bos_token_id >= 0
        ), "If input_ids is not defined, `bos_token_id` should be a positive integer."
        assert pad_token_id is None or (
                isinstance(pad_token_id, int) and (pad_token_id >= 0)
        ), "`pad_token_id` should be a positive integer."
        assert (eos_token_id is None) or (
                isinstance(eos_token_id, int) and (eos_token_id >= 0)
        ), "`eos_token_id` should be a positive integer."
        assert length_penalty > 0, "`length_penalty` should be strictly positive."
        assert (
                isinstance(no_repeat_ngram_size, int) and no_repeat_ngram_size >= 0
        ), "`no_repeat_ngram_size` should be a positive integer."
        assert (
                isinstance(num_return_sequences, int) and num_return_sequences > 0
        ), "`num_return_sequences` should be a strictly positive integer."
        assert (
                bad_words_ids is None or isinstance(bad_words_ids, list) and isinstance(bad_words_ids[0], list)
        ), "`bad_words_ids` is either `None` or a list of lists of tokens that should not be generated"

        if input_ids is None:
            assert isinstance(bos_token_id, int) and bos_token_id >= 0, (
                "you should either supply a context to complete as `input_ids` input "
                "or a `bos_token_id` (integer >= 0) as a first token to start the generation."
            )
            input_ids = torch.full(
                (batch_size, 1), bos_token_id, dtype=torch.long, device=next(self.parameters()).device,
            )
        else:
            assert input_ids.dim() == 2, "Input prompt should be of shape (batch_size, sequence length)."

        # not allow to duplicate outputs when greedy decoding
        if do_sample is False:
            if num_beams == 1:
                # no_beam_search greedy generation conditions
                assert (
                        num_return_sequences == 1
                ), "Greedy decoding will always produce the same output for num_beams == 1 and num_return_sequences > 1. Please set num_return_sequences = 1"

            else:
                # beam_search greedy generation conditions
                assert (
                        num_beams >= num_return_sequences
                ), "Greedy beam search decoding cannot return more sequences than it has beams. Please set num_beams >= num_return_sequences"

        # create attention mask if necessary
        # TODO (PVP): this should later be handled by the forward fn() in each model in the future see PR 3140
        if (attention_mask is None) and (pad_token_id is not None) and (pad_token_id in input_ids):
            attention_mask = input_ids.ne(pad_token_id).long()
        elif attention_mask is None:
            attention_mask = input_ids.new_ones(input_ids.shape)

        # set pad_token_id to eos_token_id if not set. Important that this is done after
        # attention_mask is created
        if pad_token_id is None and eos_token_id is not None:
            logger.warning(
                "Setting `pad_token_id` to {} (first `eos_token_id`) to generate sequence".format(eos_token_id)
            )
            pad_token_id = eos_token_id

        # current position and vocab size
        if hasattr(self.config, "vocab_size"):
            vocab_size = self.config.vocab_size
        elif (
                self.config.is_encoder_decoder
                and hasattr(self.config, "decoder")
                and hasattr(self.config.decoder, "vocab_size")
        ):
            vocab_size = self.config.decoder.vocab_size

        vocab_size += 1024

        # set effective batch size and effective batch multiplier according to do_sample
        if do_sample:
            effective_batch_size = batch_size * num_return_sequences
            effective_batch_mult = num_return_sequences
        else:
            effective_batch_size = batch_size
            effective_batch_mult = 1

        if self.config.is_encoder_decoder:
            if decoder_start_token_id is None:
                decoder_start_token_id = bos_token_id

            assert (
                    decoder_start_token_id is not None
            ), "decoder_start_token_id or bos_token_id has to be defined for encoder-decoder generation"
            assert hasattr(self, "get_encoder"), "{} should have a 'get_encoder' function defined".format(self)
            assert callable(self.get_encoder), "{} should be a method".format(self.get_encoder)

            # get encoder and store encoder outputs
            encoder = self.get_encoder()

            encoder_outputs: tuple = encoder(input_ids, attention_mask=attention_mask)

        # Expand input ids if num_beams > 1 or num_return_sequences > 1
        if num_return_sequences > 1 or num_beams > 1:
            input_ids_len = input_ids.shape[-1]
            input_ids = input_ids.unsqueeze(1).expand(batch_size, effective_batch_mult * num_beams, input_ids_len)
            attention_mask = attention_mask.unsqueeze(1).expand(
                batch_size, effective_batch_mult * num_beams, input_ids_len
            )

            input_ids = input_ids.contiguous().view(
                effective_batch_size * num_beams, input_ids_len
            )  # shape: (batch_size * num_return_sequences * num_beams, cur_len)
            attention_mask = attention_mask.contiguous().view(
                effective_batch_size * num_beams, input_ids_len
            )  # shape: (batch_size * num_return_sequences * num_beams, cur_len)

        if self.config.is_encoder_decoder:
            # create empty decoder_input_ids
            input_ids = torch.full(
                (effective_batch_size * num_beams, 1),
                decoder_start_token_id,
                dtype=torch.long,
                device=next(self.parameters()).device,
            )
            cur_len = 1

            assert (
                    batch_size == encoder_outputs[0].shape[0]
            ), f"expected encoder_outputs[0] to have 1st dimension bs={batch_size}, got {encoder_outputs[0].shape[0]} "

            # expand batch_idx to assign correct encoder output for expanded input_ids (due to num_beams > 1 and num_return_sequences > 1)
            expanded_batch_idxs = (
                torch.arange(batch_size)
                    .view(-1, 1)
                    .repeat(1, num_beams * effective_batch_mult)
                    .view(-1)
                    .to(input_ids.device)
            )
            # expand encoder_outputs
            encoder_outputs = (encoder_outputs[0].index_select(0, expanded_batch_idxs), *encoder_outputs[1:])

        else:
            encoder_outputs = None
            cur_len = input_ids.shape[-1]

        if num_beams > 1:
            output = self._generate_beam_search(
                input_ids,
                cur_len=cur_len,
                max_length=max_length,
                min_length=min_length,
                do_sample=do_sample,
                early_stopping=early_stopping,
                temperature=temperature,
                top_k=top_k,
                top_p=top_p,
                repetition_penalty=repetition_penalty,
                no_repeat_ngram_size=no_repeat_ngram_size,
                bad_words_ids=bad_words_ids,
                bos_token_id=bos_token_id,
                pad_token_id=pad_token_id,
                decoder_start_token_id=decoder_start_token_id,
                eos_token_id=eos_token_id,
                batch_size=effective_batch_size,
                num_return_sequences=num_return_sequences,
                length_penalty=length_penalty,
                num_beams=num_beams,
                vocab_size=vocab_size,
                encoder_outputs=encoder_outputs,
                attention_mask=attention_mask,
                use_cache=use_cache,
                model_specific_kwargs=model_specific_kwargs,
            )
        else:
            output = self._generate_no_beam_search(
                input_ids,
                cur_len=cur_len,
                max_length=max_length,
                min_length=min_length,
                do_sample=do_sample,
                temperature=temperature,
                top_k=top_k,
                top_p=top_p,
                repetition_penalty=repetition_penalty,
                no_repeat_ngram_size=no_repeat_ngram_size,
                bad_words_ids=bad_words_ids,
                bos_token_id=bos_token_id,
                pad_token_id=pad_token_id,
                decoder_start_token_id=decoder_start_token_id,
                eos_token_id=eos_token_id,
                batch_size=effective_batch_size,
                encoder_outputs=encoder_outputs,
                attention_mask=attention_mask,
                use_cache=use_cache,
                model_specific_kwargs=model_specific_kwargs,
            )

        return output

    def _generate_beam_search(
        self,
        input_ids,
        cur_len,
        max_length,
        min_length,
        do_sample,
        early_stopping,
        temperature,
        top_k,
        top_p,
        repetition_penalty,
        no_repeat_ngram_size,
        bad_words_ids,
        bos_token_id,
        pad_token_id,
        eos_token_id,
        decoder_start_token_id,
        batch_size,
        num_return_sequences,
        length_penalty,
        num_beams,
        vocab_size,
        encoder_outputs,
        attention_mask,
        use_cache,
        model_specific_kwargs,
    ):
        """ Generate sequences for each example with beam search.
        """

        # generated hypotheses
        generated_hyps = [
            BeamHypotheses(num_beams, max_length, length_penalty, early_stopping=early_stopping)
            for _ in range(batch_size)
        ]

        # scores for each sentence in the beam
        beam_scores = torch.zeros((batch_size, num_beams), dtype=torch.float, device=input_ids.device)

        # for greedy decoding it is made sure that only tokens of the first beam are considered to avoid sampling the exact same tokens three times
        if do_sample is False:
            beam_scores[:, 1:] = -1e9
        beam_scores = beam_scores.view(-1)  # shape (batch_size * num_beams,)

        # cache compute states
        past = encoder_outputs  # defined for encoder-decoder models, None for decoder-only models

        # done sentences
        done = [False for _ in range(batch_size)]

        while cur_len < max_length:
            model_inputs = self.prepare_inputs_for_generation(
                input_ids, past=past, attention_mask=attention_mask, use_cache=use_cache, **model_specific_kwargs
            )
            outputs = self(**model_inputs)  # (batch_size * num_beams, cur_len, vocab_size)
            next_token_logits = outputs[0][:, -1, :]  # (batch_size * num_beams, vocab_size)

            # if model has past, then set the past variable to speed up decoding
            if self._use_cache(outputs, use_cache):
                past = outputs[1]

            # repetition penalty (from CTRL paper https://arxiv.org/abs/1909.05858)
            if repetition_penalty != 1.0:
                self.enforce_repetition_penalty_(
                    next_token_logits, batch_size, num_beams, input_ids, repetition_penalty,
                )

            if temperature != 1.0:
                next_token_logits = next_token_logits / temperature

            if self.config.is_encoder_decoder and do_sample is False:
                # TODO (PVP) still a bit hacky here - there might be a better solution
                next_token_logits = self.prepare_logits_for_generation(
                    next_token_logits, cur_len=cur_len, max_length=max_length
                )

            scores = F.log_softmax(next_token_logits, dim=-1)  # (batch_size * num_beams, vocab_size)

            # set eos token prob to zero if min_length is not reached
            if eos_token_id is not None and cur_len < min_length:
                scores[:, eos_token_id] = -float("inf")

            if no_repeat_ngram_size > 0:
                # calculate a list of banned tokens to prevent repetitively generating the same ngrams
                num_batch_hypotheses = batch_size * num_beams
                # from fairseq: https://github.com/pytorch/fairseq/blob/a07cb6f40480928c9e0548b737aadd36ee66ac76/fairseq/sequence_generator.py#L345
                banned_batch_tokens = calc_banned_ngram_tokens(
                    input_ids, num_batch_hypotheses, no_repeat_ngram_size, cur_len
                )
                for i, banned_tokens in enumerate(banned_batch_tokens):
                    scores[i, banned_tokens] = -float("inf")

            if bad_words_ids is not None:
                # calculate a list of banned tokens according to bad words
                banned_tokens = calc_banned_bad_words_ids(input_ids, bad_words_ids)

                for i, banned_tokens in enumerate(banned_tokens):
                    scores[i, banned_tokens] = -float("inf")

            assert scores.shape == (batch_size * num_beams, vocab_size), "Shapes of scores: {} != {}".format(
                scores.shape, (batch_size * num_beams, vocab_size)
            )

            if do_sample:
                _scores = scores + beam_scores[:, None].expand_as(scores)  # (batch_size * num_beams, vocab_size)
                # Top-p/top-k filtering
                _scores = top_k_top_p_filtering(
                    _scores, top_k=top_k, top_p=top_p, min_tokens_to_keep=2
                )  # (batch_size * num_beams, vocab_size)
                # re-organize to group the beam together to sample from all beam_idxs
                _scores = _scores.contiguous().view(
                    batch_size, num_beams * vocab_size
                )  # (batch_size, num_beams * vocab_size)

                # Sample 2 next tokens for each beam (so we have some spare tokens and match output of greedy beam search)
                probs = F.softmax(_scores, dim=-1)
                next_tokens = torch.multinomial(probs, num_samples=2 * num_beams)  # (batch_size, num_beams * 2)
                # Compute next scores
                next_scores = torch.gather(_scores, -1, next_tokens)  # (batch_size, num_beams * 2)
                # sort the sampled vector to make sure that the first num_beams samples are the best
                next_scores, next_scores_indices = torch.sort(next_scores, descending=True, dim=1)
                next_tokens = torch.gather(next_tokens, -1, next_scores_indices)  # (batch_size, num_beams * 2)

            else:
                next_scores = scores + beam_scores[:, None].expand_as(scores)  # (batch_size * num_beams, vocab_size)

                # re-organize to group the beam together (we are keeping top hypothesis accross beams)
                next_scores = next_scores.view(
                    batch_size, num_beams * vocab_size
                )  # (batch_size, num_beams * vocab_size)

                next_scores, next_tokens = torch.topk(next_scores, 2 * num_beams, dim=1, largest=True, sorted=True)

            assert next_scores.size() == next_tokens.size() == (batch_size, 2 * num_beams)

            # next batch beam content
            next_batch_beam = []

            # for each sentence
            for batch_idx in range(batch_size):

                # if we are done with this sentence
                if done[batch_idx]:
                    assert (
                        len(generated_hyps[batch_idx]) >= num_beams
                    ), "Batch can only be done if at least {} beams have been generated".format(num_beams)
                    assert (
                        eos_token_id is not None and pad_token_id is not None
                    ), "generated beams >= num_beams -> eos_token_id and pad_token have to be defined"
                    next_batch_beam.extend([(0, pad_token_id, 0)] * num_beams)  # pad the batch
                    continue

                # next sentence beam content
                next_sent_beam = []

                # next tokens for this sentence
                for beam_token_rank, (beam_token_id, beam_token_score) in enumerate(
                    zip(next_tokens[batch_idx], next_scores[batch_idx])
                ):
                    # get beam and token IDs
                    beam_id = beam_token_id // vocab_size
                    token_id = beam_token_id % vocab_size

                    effective_beam_id = batch_idx * num_beams + beam_id
                    # add to generated hypotheses if end of sentence or last iteration
                    if (eos_token_id is not None) and (token_id.item() == eos_token_id):
                        # if beam_token does not belong to top num_beams tokens, it should not be added
                        is_beam_token_worse_than_top_num_beams = beam_token_rank >= num_beams
                        if is_beam_token_worse_than_top_num_beams:
                            continue
                        generated_hyps[batch_idx].add(
                            input_ids[effective_beam_id].clone(), beam_token_score.item(),
                        )
                    else:
                        # add next predicted token if it is not eos_token
                        next_sent_beam.append((beam_token_score, token_id, effective_beam_id))

                    # the beam for next step is full
                    if len(next_sent_beam) == num_beams:
                        break

                # Check if were done so that we can save a pad step if all(done)
                done[batch_idx] = done[batch_idx] or generated_hyps[batch_idx].is_done(
                    next_scores[batch_idx].max().item(), cur_len=cur_len
                )

                # update next beam content
                assert len(next_sent_beam) == num_beams, "Beam should always be full"
                next_batch_beam.extend(next_sent_beam)
                assert len(next_batch_beam) == num_beams * (batch_idx + 1)

            # stop when we are done with each sentence
            if all(done):
                break

            # sanity check / prepare next batch
            assert len(next_batch_beam) == batch_size * num_beams
            beam_scores = beam_scores.new([x[0] for x in next_batch_beam])
            beam_tokens = input_ids.new([x[1] for x in next_batch_beam])
            beam_idx = input_ids.new([x[2] for x in next_batch_beam])

            # re-order batch and update current length
            input_ids = input_ids[beam_idx, :]
            input_ids = torch.cat([input_ids, beam_tokens.unsqueeze(1)], dim=-1)
            cur_len = cur_len + 1

            # re-order internal states
            if past is not None:
                past = self._reorder_cache(past, beam_idx)

            # extend attention_mask for new generated input if only decoder
            if self.config.is_encoder_decoder is False:
                attention_mask = torch.cat(
                    [attention_mask, attention_mask.new_ones((attention_mask.shape[0], 1))], dim=-1
                )

        # finalize all open beam hypotheses and end to generated hypotheses
        for batch_idx in range(batch_size):
            if done[batch_idx]:
                continue

            # test that beam scores match previously calculated scores if not eos and batch_idx not done
            if eos_token_id is not None and all(
                (token_id % vocab_size).item() is not eos_token_id for token_id in next_tokens[batch_idx]
            ):
                assert torch.all(
                    next_scores[batch_idx, :num_beams] == beam_scores.view(batch_size, num_beams)[batch_idx]
                ), "If batch_idx is not done, final next scores: {} have to equal to accumulated beam_scores: {}".format(
                    next_scores[:, :num_beams][batch_idx], beam_scores.view(batch_size, num_beams)[batch_idx],
                )

            # need to add best num_beams hypotheses to generated hyps
            for beam_id in range(num_beams):
                effective_beam_id = batch_idx * num_beams + beam_id
                final_score = beam_scores[effective_beam_id].item()
                final_tokens = input_ids[effective_beam_id]
                generated_hyps[batch_idx].add(final_tokens, final_score)

        # depending on whether greedy generation is wanted or not define different output_batch_size and output_num_return_sequences_per_batch
        output_batch_size = batch_size if do_sample else batch_size * num_return_sequences
        output_num_return_sequences_per_batch = 1 if do_sample else num_return_sequences

        # select the best hypotheses
        sent_lengths = input_ids.new(output_batch_size)
        best = []

        # retrieve best hypotheses
        for i, hypotheses in enumerate(generated_hyps):
            sorted_hyps = sorted(hypotheses.beams, key=lambda x: x[0])
            for j in range(output_num_return_sequences_per_batch):
                effective_batch_idx = output_num_return_sequences_per_batch * i + j
                best_hyp = sorted_hyps.pop()[1]
                sent_lengths[effective_batch_idx] = len(best_hyp)
                best.append(best_hyp)

        # shorter batches are filled with pad_token
        if sent_lengths.min().item() != sent_lengths.max().item():
            assert pad_token_id is not None, "`Pad_token_id` has to be defined"
            sent_max_len = min(sent_lengths.max().item() + 1, max_length)
            decoded = input_ids.new(output_batch_size, sent_max_len).fill_(pad_token_id)

            # fill with hypothesis and eos_token_id if necessary
            for i, hypo in enumerate(best):
                decoded[i, : sent_lengths[i]] = hypo
                if sent_lengths[i] < max_length:
                    decoded[i, sent_lengths[i]] = eos_token_id
        else:
            # none of the hypotheses have an eos_token
            assert (len(hypo) == max_length for hypo in best)
            decoded = torch.stack(best).type(torch.long).to(next(self.parameters()).device)

        return decoded

    @staticmethod
    def _reorder_cache(past: Tuple, beam_idx: Tensor) -> Tuple[Tensor]:
        return tuple(layer_past.index_select(1, beam_idx) for layer_past in past)

    def resize_token_embeddings(self, new_num_tokens: int) -> nn.Embedding:
        old_num_tokens = self.model.shared.num_embeddings
        new_embeddings = super().resize_token_embeddings(new_num_tokens)
        self.model.shared = new_embeddings
        self._resize_final_logits_bias(new_num_tokens, old_num_tokens)
        return new_embeddings

    def _resize_final_logits_bias(self, new_num_tokens: int, old_num_tokens: int) -> None:
        if new_num_tokens <= old_num_tokens:
            new_bias = self.final_logits_bias[:, :new_num_tokens]
        else:
            extra_bias = torch.zeros((1, new_num_tokens - old_num_tokens), device=self.final_logits_bias.device)
            new_bias = torch.cat([self.final_logits_bias, extra_bias], dim=1)
        self.register_buffer("final_logits_bias", new_bias)

    def prepare_inputs_for_generation(self, decoder_input_ids, past, attention_mask, use_cache, **kwargs):
        assert past is not None, "past has to be defined for encoder_outputs"

        # first step, decoder_cached_states are empty
        if not past[1]:
            encoder_outputs, decoder_cached_states = past, None
        else:
            encoder_outputs, decoder_cached_states = past
        return {
            "input_ids": None,  # encoder_outputs is defined. input_ids not needed
            "encoder_outputs": encoder_outputs,
            "decoder_cached_states": decoder_cached_states,
            "decoder_input_ids": decoder_input_ids,
            "attention_mask": attention_mask,
            "use_cache": use_cache,  # change this to avoid caching (presumably for debugging)
        }

    def prepare_logits_for_generation(self, logits, cur_len, max_length):
        #if cur_len == 1:
        #    self._force_token_ids_generation(logits, self.config.bos_token_id)
        if cur_len == max_length - 1 and self.config.eos_token_id is not None:
            self._force_token_ids_generation(logits, self.config.eos_token_id)
        return logits

    def _force_token_ids_generation(self, scores, token_ids) -> None:
        """force one of token_ids to be generated by setting prob of all other tokens to 0"""
        if isinstance(token_ids, int):
            token_ids = [token_ids]
        all_but_token_ids_mask = torch.tensor(
            [x for x in range(self.config.vocab_size) if x not in token_ids],
            dtype=torch.long,
            device=next(self.parameters()).device,
        )
        assert len(scores.shape) == 2, "scores should be of rank 2 with shape: [batch_size, vocab_size]"
        scores[:, all_but_token_ids_mask] = -float("inf")

    @staticmethod
    def _reorder_cache(past, beam_idx):
        ((enc_out, enc_mask), decoder_cached_states) = past
        reordered_past = []
        for layer_past in decoder_cached_states:
            # get the correct batch idx from decoder layer's batch dim for cross and self-attn
            layer_past_new = {
                attn_key: bart._reorder_buffer(attn_cache, beam_idx) for attn_key, attn_cache in layer_past.items()
            }
            reordered_past.append(layer_past_new)

        new_enc_out = enc_out if enc_out is None else enc_out.index_select(0, beam_idx)
        new_enc_mask = enc_mask if enc_mask is None else enc_mask.index_select(0, beam_idx)

        past = ((new_enc_out, new_enc_mask), reordered_past)
        return past

    def get_encoder(self):
        return self.model.encoder

    def get_output_embeddings(self):
        return bart._make_linear_from_emb(self.model.shared)  # make it on the fly