optimum/habana/transformers/generation/utils.py (3,035 lines of code) (raw):

# coding=utf-8 # Copyright 2022 The Google AI Language Team Authors, Facebook AI Research authors and The HuggingFace Inc. team. # Copyright (c) 2020, NVIDIA CORPORATION. All rights reserved. # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. # You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. import copy import inspect import math import warnings from typing import TYPE_CHECKING, Any, Callable, Dict, List, Optional, Tuple, Union import torch import torch.distributed as dist from packaging import version from transformers.cache_utils import ( Cache, DynamicCache, EncoderDecoderCache, OffloadedCache, QuantizedCacheConfig, StaticCache, ) from transformers.generation.beam_constraints import DisjunctiveConstraint, PhrasalConstraint from transformers.generation.beam_search import BeamScorer, BeamSearchScorer, ConstrainedBeamSearchScorer from transformers.generation.candidate_generator import ( AssistantVocabTranslatorCache, AssistedCandidateGeneratorDifferentTokenizers, CandidateGenerator, EarlyExitCandidateGenerator, PromptLookupCandidateGenerator, UniversalSpeculativeDecodingGenerator, _crop_past_key_values, _prepare_attention_mask, _prepare_token_type_ids, ) from transformers.generation.configuration_utils import NEED_SETUP_CACHE_CLASSES_MAPPING, QUANT_BACKEND_CLASSES_MAPPING from transformers.generation.logits_process import LogitsProcessorList from transformers.generation.stopping_criteria import ( ConfidenceCriteria, EosTokenCriteria, MaxLengthCriteria, MaxTimeCriteria, StoppingCriteriaList, StopStringCriteria, ) from transformers.generation.utils import ( ALL_CACHE_NAMES, GenerateBeamDecoderOnlyOutput, GenerateBeamEncoderDecoderOutput, GenerateBeamOutput, GenerateDecoderOnlyOutput, GenerateEncoderDecoderOutput, GenerateNonBeamOutput, GenerateOutput, GenerationMixin, GenerationMode, _split_model_outputs, stack_model_outputs, ) from transformers.integrations.deepspeed import is_deepspeed_zero3_enabled from transformers.integrations.fsdp import is_fsdp_managed_module from transformers.modeling_outputs import CausalLMOutputWithPast, Seq2SeqLMOutput from transformers.utils import ModelOutput, is_hqq_available, is_optimum_quanto_available from optimum.utils import logging from ...utils import HabanaGenerationTime, HabanaProfile from ..integrations.deepspeed import unwrap_deepspeed_model from .candidate_generator import GaudiAssistedCandidateGenerator from .configuration_utils import GaudiGenerationConfig if TYPE_CHECKING: from transformers import PreTrainedModel from transformers.generation.streamers import BaseStreamer from transformers.tokenization_utils_base import PreTrainedTokenizerBase from .candidate_generator import GaudiCandidateGenerator MODELS_OPTIMIZED_WITH_STATIC_SHAPES = [ "bloom", "gpt2", "opt", "gptj", "gpt_neo", "gpt_neox", "llama", "falcon", "codegen", "gpt_bigcode", "bart", "mpt", "t5", "mistral", "phi", "mixtral", "gemma", "gemma2", "blip_text_model", "seamless_m4t", "starcoder2", "persimmon", "qwen2", "llava", "llava_next", "llava_onevision", "stablelm", "mamba", "deci", "cohere", "qwen2_moe", "xglm", "whisper", "paligemma", "idefics2", "mllama", "video_llava", "minicpm3", "baichuan", "deepseek_v2", "deepseek_v3", "chatglm", "qwen2_vl", ] # Initial generated token index is set to 1 to accomodate SOS (start of string) token. INITIAL_TOKEN_IDX = 1 logger = logging.get_logger(__name__) def incrementor(bucket_size, prompt_len): assert bucket_size > 0 passnum = -1 while True: passnum += 1 if passnum == 0: token_idx = prompt_len allocated_space = int(math.ceil(prompt_len / bucket_size) * bucket_size) if prompt_len % bucket_size == 0: allocated_space += bucket_size need_expansion = True else: token_idx += 1 need_expansion = token_idx >= allocated_space if need_expansion: assert (allocated_space - token_idx) <= bucket_size allocated_space += bucket_size yield { "allocated_space": allocated_space, "passnum": passnum, "token_idx": token_idx, "need_expansion": need_expansion, } def get_final_stopping_criteria(x): if isinstance(x, bool): return x elif torch.is_tensor(x): return x.all() if x.dim() > 0 else x else: raise TypeError(f"The stopping criteria should be either a boolean or a torch.tensor but got {type(x)}.") class GaudiGenerationMixin(GenerationMixin): """ This class enables to perform fast generation in lazy mode and with HPU graphs. The only difference with GenerationMixin is that the various generation methods will generate sequences whose size is max_length. Having constant sizes allows to make the most of lazy mode and HPU graphs. """ def _prepare_inputs_for_generation( self, input_ids: torch.LongTensor, past_key_values: Optional[Cache] = None, attention_mask: Optional[torch.LongTensor] = None, inputs_embeds: Optional[torch.FloatTensor] = None, cache_position: Optional[torch.LongTensor] = None, **kwargs, ): """ Prepare the model inputs for generation. In includes operations like computing the 4D attention mask or slicing inputs given the existing cache. See the forward pass in the model documentation for expected arguments (different models might have different requirements for e.g. `past_key_values`). This function should work as is for most LLMs. Copied from https://github.com/huggingface/transformers/blob/v4.48.2/src/transformers/generation/utils.py#L349 Extended with custom modifications to remove keys not used in the forward method. """ # 1. Handle BC: model_inputs = {} # - some models don't have `Cache` support (which implies they don't expect `cache_position` in `forward`) if self._supports_cache_class: model_inputs["cache_position"] = cache_position # - `cache_position` was not a mandatory input in `prepare_inputs_for_generation` for those models, and this # function may be called outside of `generate`. Handle most use cases by creating `cache_position` on the fly # (this alternative is not as robust as calling `generate` and letting it create `cache_position`) elif cache_position is None: past_length = past_key_values[0][0].shape[2] if past_key_values is not None else 0 cache_position = torch.arange(past_length, input_ids.shape[1], dtype=torch.long, device=input_ids.device) # 2. Generic cache-dependent input preparation if past_key_values is not None: model_inputs["past_key_values"] = past_key_values inputs_embeds, input_ids = self._cache_dependant_input_preparation( input_ids, inputs_embeds, cache_position ) # 3. Prepare base model inputs input_ids_key = "decoder_input_ids" if self.config.is_encoder_decoder else "input_ids" # if `inputs_embeds` are passed, we only want to use them in the 1st generation step for every prompt. if not self.config.is_encoder_decoder: if inputs_embeds is not None and len(cache_position) == inputs_embeds.shape[1]: model_inputs[input_ids_key] = None model_inputs["inputs_embeds"] = inputs_embeds else: # `clone` calls in this function ensure a consistent stride. See #32227 model_inputs[input_ids_key] = input_ids.clone(memory_format=torch.contiguous_format) model_inputs["inputs_embeds"] = None else: model_inputs[input_ids_key] = input_ids.clone(memory_format=torch.contiguous_format) # 4. Create missing `position_ids` on the fly encoder_attention_mask = attention_mask if self.config.is_encoder_decoder else None attention_mask = ( kwargs.pop("decoder_attention_mask", None) if self.config.is_encoder_decoder else attention_mask ) attention_mask_key = "decoder_attention_mask" if self.config.is_encoder_decoder else "attention_mask" position_ids_key = "decoder_position_ids" if self.config.is_encoder_decoder else "position_ids" if ( attention_mask is not None and kwargs.get(position_ids_key) is None and position_ids_key in set(inspect.signature(self.forward).parameters.keys()) ): position_ids = attention_mask.long().cumsum(-1) - 1 position_ids.masked_fill_(attention_mask == 0, 1) kwargs[position_ids_key] = position_ids # placed in kwargs for further processing (see below) # 5. Slice model inputs if it's an input that should have the same length as `input_ids` for model_input_name in ["position_ids", "token_type_ids", "decoder_position_ids"]: model_input = kwargs.get(model_input_name) if model_input is not None: if past_key_values is not None: current_input_length = ( model_inputs["inputs_embeds"].shape[1] if model_inputs.get("inputs_embeds") is not None else model_inputs[input_ids_key].shape[1] ) model_input = model_input[:, -current_input_length:] model_input = model_input.clone(memory_format=torch.contiguous_format) model_inputs[model_input_name] = model_input # 6. Create 4D attention mask is we are using a `StaticCache` (important for performant compiled forward pass) if isinstance(past_key_values, StaticCache) and attention_mask.ndim == 2: if model_inputs["inputs_embeds"] is not None: batch_size, sequence_length, _ = model_inputs["inputs_embeds"].shape device = model_inputs["inputs_embeds"].device else: batch_size, sequence_length = model_inputs[input_ids_key].shape device = model_inputs[input_ids_key].device # Create the causal mask with fixed shape in advance, to reduce recompilations. If the function to create # the 4D causal mask exists, it should be present in the base model (XXXModel class). base_model = getattr(self, self.base_model_prefix, None) if base_model is None: causal_mask_creation_function = getattr( self, "_prepare_4d_causal_attention_mask_with_cache_position", None ) else: causal_mask_creation_function = getattr( base_model, "_prepare_4d_causal_attention_mask_with_cache_position", None ) if causal_mask_creation_function is None: logger.warning_once( f"{self.__class__.__name__} has no `_prepare_4d_causal_attention_mask_with_cache_position` method " "defined in its base modeling class. Compiled forward passes will be sub-optimal. If you're " "writing code, see Llama for an example implementation. If you're a user, please report this " "issue on GitHub." ) else: attention_mask = causal_mask_creation_function( attention_mask, sequence_length=sequence_length, target_length=past_key_values.get_max_cache_shape(), dtype=self.dtype, device=device, cache_position=cache_position, batch_size=batch_size, config=self.config, past_key_values=past_key_values, ) if attention_mask is not None: model_inputs[attention_mask_key] = attention_mask if encoder_attention_mask is not None: model_inputs["attention_mask"] = encoder_attention_mask # 7. Forward ALL kwargs that are uninitialized (e.g. `use_cache`). for key, value in kwargs.items(): if key not in model_inputs: model_inputs[key] = value # 8. Remove unexpected `generate` inputs (TODO @joao: fix trainer and examples) model_inputs.pop("labels", None) # 9. Custom logic to remove unused keys forward_call = self._slow_forward if torch._C._get_tracing_state() else self.forward forward_call_signature = inspect.signature(forward_call) forward_call_has_kwargs = False for param in forward_call_signature.parameters.values(): if param.kind == param.VAR_KEYWORD: forward_call_has_kwargs = True break if not forward_call_has_kwargs: forward_call_keys = set(forward_call_signature.parameters.keys()) model_inputs_keys = list(model_inputs.keys()) for key in model_inputs_keys: if key not in forward_call_keys: del model_inputs[key] return model_inputs def _get_hpu_graphs_kwargs(self, model_kwargs): hpu_graphs_kwargs = {} if model_kwargs["limit_hpu_graphs"]: hpu_graphs_kwargs.update({"bypass_hpu_graphs": False}) if "first_token" not in model_kwargs.keys(): model_kwargs["first_token"] = True hpu_graphs_kwargs.update({"bypass_hpu_graphs": True}) return hpu_graphs_kwargs def _prepare_decoder_attention_mask( self, max_steps: int, # current stopping criteria batch_size: int, device: Union[str, torch.device], dtype: torch.dtype = torch.bool, ) -> torch.Tensor: decoder_attention_mask = torch.zeros((batch_size, max_steps), device=device, dtype=dtype) index = torch.tensor(0, device=device) return decoder_attention_mask.index_fill(1, index, 1) # First position with 1 def _prepare_decoder_input_ids_for_generation( self, batch_size: int, model_input_name: str, model_kwargs: Dict[str, torch.Tensor], decoder_start_token_id: torch.Tensor, device: Optional[torch.device] = None, max_new_tokens: int = None, pad_token_id: int = None, ) -> Tuple[torch.LongTensor, Dict[str, torch.Tensor]]: """Prepares `decoder_input_ids` for generation with encoder-decoder models""" # 1. Check whether the user has defined `decoder_input_ids` manually. To facilitate in terms of input naming, # we also allow the user to pass it under `input_ids`, if the encoder does not use it as the main input. if model_kwargs is not None and "decoder_input_ids" in model_kwargs: decoder_input_ids = model_kwargs.pop("decoder_input_ids") elif "input_ids" in model_kwargs and model_input_name != "input_ids": decoder_input_ids = model_kwargs.pop("input_ids") else: decoder_input_ids = None token_idx = model_kwargs.get("token_idx", None) # 2. `decoder_start_token_id` must have shape (batch_size, 1) if device is None: device = self.device if token_idx is None: if decoder_start_token_id.ndim == 1: if decoder_start_token_id.shape[0] != batch_size: raise ValueError( f"`decoder_start_token_id` expected to have length {batch_size} but got {decoder_start_token_id.shape[0]}" ) decoder_start_token_id = decoder_start_token_id.view(-1, 1) else: decoder_start_token_id = ( torch.ones((batch_size, 1), dtype=torch.long, device=device) * decoder_start_token_id ) else: # creating padded decoder_input_ids to achieve static shapes. Later new tokens once generated are copied in to decoder_input_ids based on token_idx max_length = max_new_tokens + 1 if max_new_tokens is not None else self.generation_config.max_length decoder_start_token_id = ( torch.ones((batch_size, 1), dtype=torch.long, device=device) * decoder_start_token_id ) decoder_start_token_id = torch.nn.functional.pad( decoder_start_token_id, (0, max_length - 1), value=pad_token_id ) # 3. Encoder-decoder models expect the `decoder_input_ids` to start with a special token. Let's ensure that. # no user input -> use decoder_start_token_id as decoder_input_ids if decoder_input_ids is None: decoder_input_ids = decoder_start_token_id # exception: Donut checkpoints have task-specific decoder starts and don't expect a BOS token. Note that the # original checkpoints can't be detected through `self.__class__.__name__.lower()`, needing custom logic. # See: https://github.com/huggingface/transformers/pull/31470 elif "donut" in self.__class__.__name__.lower() or ( self.config.model_type == "vision-encoder-decoder" and "donut" in self.config.encoder.model_type.lower() ): pass # user input but doesn't start with decoder_start_token_id -> prepend decoder_start_token_id (and adjust # decoder_attention_mask if provided) elif (decoder_input_ids[:, 0] != decoder_start_token_id[:, 0]).all().item(): if token_idx is None: decoder_input_ids = torch.cat([decoder_start_token_id, decoder_input_ids], dim=-1) else: decoder_input_ids_len = decoder_input_ids.shape[-1] max_length = ( max_new_tokens + decoder_input_ids_len + 1 if max_new_tokens is not None else self.generation_config.max_length ) if max_length != decoder_start_token_id.shape[-1]: decoder_start_token_id = torch.nn.functional.pad( decoder_start_token_id, (0, max_length - decoder_start_token_id.shape[-1]), value=pad_token_id, ) decoder_start_token_id[:, 1 : 1 + decoder_input_ids_len, ...] = decoder_input_ids decoder_input_ids = decoder_start_token_id token_idx.add_(1) if "decoder_attention_mask" in model_kwargs: decoder_attention_mask = model_kwargs["decoder_attention_mask"] decoder_attention_mask = torch.cat( (torch.ones_like(decoder_attention_mask)[:, :1], decoder_attention_mask), dim=-1, ) model_kwargs["decoder_attention_mask"] = decoder_attention_mask else: if token_idx is not None: decoder_input_ids_len = decoder_input_ids.shape[-1] max_length = ( max_new_tokens + decoder_input_ids_len if max_new_tokens is not None else self.generation_config.max_length ) decoder_input_ids = torch.nn.functional.pad( decoder_input_ids, (0, max_length - decoder_input_ids_len), value=pad_token_id ) token_idx.copy_(decoder_input_ids_len) if "decoder_attention_mask" in model_kwargs: decoder_attention_mask = model_kwargs["decoder_attention_mask"] pad_len = max_length - decoder_attention_mask.shape[-1] decoder_attention_mask = torch.cat( (torch.ones_like(decoder_attention_mask)[:, :pad_len], decoder_attention_mask), dim=-1, ) model_kwargs["decoder_attention_mask"] = decoder_attention_mask return decoder_input_ids, model_kwargs @staticmethod def _expand_inputs_for_generation( expand_size: int = 1, is_encoder_decoder: bool = False, input_ids: Optional[torch.LongTensor] = None, **model_kwargs, ) -> Tuple[torch.LongTensor, Dict[str, Any]]: """ Expands tensors from [batch_size, ...] to [batch_size * expand_size, ...]. Copied from Transformers: https://github.com/huggingface/transformers/blob/527ab894e59b6582578008e3b47648a65063f73d/src/transformers/generation/utils.py#L704 The tensor `token_idx` is not expanded. """ # Do not call torch.repeat_interleave if expand_size is 1 because it clones # the input tensor and thus requires more memory although no change is applied if expand_size == 1: return input_ids, model_kwargs def _expand_dict_for_generation(dict_to_expand): for key in dict_to_expand: if ( key != "token_idx" and key != "decoder_input_ids" and key != "cache_position" and key != "inputs_embeds_offset" and dict_to_expand[key] is not None and isinstance(dict_to_expand[key], torch.Tensor) ): dict_to_expand[key] = dict_to_expand[key].repeat_interleave(expand_size, dim=0) return dict_to_expand if input_ids is not None: input_ids = input_ids.repeat_interleave(expand_size, dim=0) model_kwargs = _expand_dict_for_generation(model_kwargs) if is_encoder_decoder: if model_kwargs.get("encoder_outputs") is None: raise ValueError("If `is_encoder_decoder` is True, make sure that `encoder_outputs` is defined.") model_kwargs["encoder_outputs"] = _expand_dict_for_generation(model_kwargs["encoder_outputs"]) return input_ids, model_kwargs def _pad_past_key_values(self, model_kwargs): # Early return if no past key values to pad past_key_values = model_kwargs.get("past_key_values") if not past_key_values: return # Determine if the model is MQA or not is_mqa_model = model_kwargs.get("mqa_model", False) lazy_mode = model_kwargs.get("lazy_mode", False) pad_amount = model_kwargs.get("kv_cache_pad_len", 0) kv_cache_len = model_kwargs.get("kv_cache_len", 0) kv_cache_len_pad_amount = kv_cache_len - pad_amount # For MQA models, past_key_values is a tensor if is_mqa_model: for i, layer in enumerate(past_key_values): # Iterate over layers if torch.is_tensor(layer) and layer.shape[-2] == kv_cache_len_pad_amount: # tensor(batch_size, kv_cache_len, n_heads * head_dim * 2) k and v stacked past_key_values[i] = torch.nn.functional.pad(layer, (0, 0, 0, pad_amount)) # Mark step if lazy mode is enabled if lazy_mode: self.htcore_generation.mark_step() # For Non-MQA models, the past_key_values is a list of lists (k and v) else: for i, layer in enumerate(past_key_values): # Iterate over layers for j, k_or_v in enumerate(layer): # Iterate over k and v if torch.is_tensor(k_or_v) and k_or_v.shape[-2] == kv_cache_len_pad_amount: # tensor(batch_size, n_heads, kv_cache_len, head_dim) past_key_values[i][j] = torch.nn.functional.pad(k_or_v, (0, 0, 0, pad_amount)) # Mark step if lazy mode is enabled if lazy_mode: self.htcore_generation.mark_step() def _remove_past_key_values(self, model_kwargs): if model_kwargs["past_key_values"]: if model_kwargs.get("mqa_model", False): for i in range(len(model_kwargs["past_key_values"])): if torch.is_tensor(model_kwargs["past_key_values"][i]): t = model_kwargs["past_key_values"][i] del t model_kwargs["past_key_values"][i] = None else: for i in range(len(model_kwargs["past_key_values"])): for j in range(len(model_kwargs["past_key_values"][i])): if torch.is_tensor(model_kwargs["past_key_values"][i][j]): t = model_kwargs["past_key_values"][i][j] del t model_kwargs["past_key_values"][i][j] = None del model_kwargs["past_key_values"] model_kwargs["past_key_values"] = None def _update_model_kwargs_for_generation( self, outputs: ModelOutput, model_kwargs: Dict[str, Any], is_encoder_decoder: bool = False, num_new_tokens: int = 1, ) -> Dict[str, Any]: """ Copied from Transformers: https://github.com/huggingface/transformers/blob/527ab894e59b6582578008e3b47648a65063f73d/src/transformers/generation/utils.py#L745 Adds support for `token_idx`, which is necessary for using static shapes. """ # mark to identify starting from second token model_kwargs["first_token"] = False if not model_kwargs.get("pad_done", False): # update past_key_values keeping its naming used in model code for possible_cache_name in ALL_CACHE_NAMES: if possible_cache_name in outputs: # TODO (joao): remove output/input mismatch when these old models (xlnet, reformer) are deprecated if possible_cache_name in ("past_buckets_states", "mems"): cache_name = "past_key_values" else: cache_name = possible_cache_name model_kwargs[cache_name] = getattr(outputs, possible_cache_name) break # update token_type_ids with last value if "token_type_ids" in model_kwargs: token_type_ids = model_kwargs["token_type_ids"] model_kwargs["token_type_ids"] = torch.cat([token_type_ids, token_type_ids[:, -1].unsqueeze(-1)], dim=-1) token_idx = model_kwargs.get("token_idx", None) if not is_encoder_decoder: # update attention mask if "attention_mask" in model_kwargs: attention_mask = model_kwargs["attention_mask"] if token_idx is not None: attention_mask.index_fill_(1, token_idx, 1) else: attention_mask = torch.cat( [attention_mask, attention_mask.new_ones((attention_mask.shape[0], 1))], dim=-1 ) model_kwargs["attention_mask"] = attention_mask else: # update decoder attention mask if "decoder_attention_mask" in model_kwargs: decoder_attention_mask = model_kwargs["decoder_attention_mask"] if token_idx is not None: decoder_attention_mask.index_fill_(1, token_idx, 1) else: decoder_attention_mask = torch.cat( [ decoder_attention_mask, decoder_attention_mask.new_ones((decoder_attention_mask.shape[0], 1)), ], dim=-1, ) model_kwargs["decoder_attention_mask"] = decoder_attention_mask if token_idx is not None: token_idx.add_(1) if "token_idx_cpu" in model_kwargs: model_kwargs["token_idx_cpu"] += 1 if "cache_position" in model_kwargs and model_kwargs["cache_position"] is not None: if model_kwargs.get("use_cache", True): model_kwargs["cache_position"] = model_kwargs["cache_position"][-1:] + num_new_tokens else: past_positions = model_kwargs.pop("cache_position") new_positions = torch.arange( past_positions[-1] + 1, past_positions[-1] + num_new_tokens + 1, dtype=past_positions.dtype ).to(past_positions.device) model_kwargs["cache_position"] = torch.cat((past_positions, new_positions)) return model_kwargs @torch.no_grad() def update_model_kwargs_for_bucketing( self, params, input_ids, model_kwargs, pad_token_id, bucket_size, reduce_recompile=False ): if params["need_expansion"]: # Pad inputs to have static shapes during generation, this gives better performance than dynamic shapes on HPUs pad_amount = params["allocated_space"] - input_ids.shape[-1] input_ids = torch.nn.functional.pad(input_ids, (0, pad_amount), value=pad_token_id) if model_kwargs.get("inputs_embeds") is not None: model_kwargs["inputs_embeds"] = torch.nn.functional.pad( model_kwargs["inputs_embeds"], (0, 0, 0, pad_amount), value=pad_token_id ) if model_kwargs["attention_mask"] is not None: model_kwargs["attention_mask"] = torch.nn.functional.pad( model_kwargs["attention_mask"], (0, pad_amount), value=0 ) else: assert False, "Not tested for cases where attn_mask isn't passed" if model_kwargs.get("cross_attention_mask") is not None: model_kwargs["cross_attention_mask"] = torch.nn.functional.pad( model_kwargs["cross_attention_mask"], (0, 0, 0, 0, 0, pad_amount), value=0, ) if reduce_recompile and params["passnum"] == 0: position_ids_cpu = model_kwargs["attention_mask"].long().cumsum(-1) - 1 position_ids_cpu.masked_fill_(model_kwargs["attention_mask"] == 0, 1) input_ids = input_ids.to(self.device) model_kwargs["attention_mask"] = model_kwargs["attention_mask"].to(self.device) if "past_key_values" in model_kwargs: def create_pad_arg(pad_amount, i, j): if model_kwargs["past_key_values"][0][0].dim() == 3: assert self.config.model_type == "bloom" if j == 0: return (0, pad_amount) elif j == 1: return (0, 0, 0, pad_amount) else: assert False elif model_kwargs["past_key_values"][0][0].dim() == 4: return (0, 0, 0, pad_amount) # llama, falcon, qwen2, starcoder2, gemma else: assert False, "Unknown case, please handle, or don't use bucketing" new_kv = [None for i in range(len(model_kwargs["past_key_values"]))] if self.config.model_type == "gpt_bigcode" and model_kwargs["past_key_values"][0][0].dim() == 2: # GPT_BIGCODE's kv cache is list of tensors. new_kv = [None for i in range(len(model_kwargs["past_key_values"]))] for i in range(len(model_kwargs["past_key_values"])): pad = (0, 0, 0, pad_amount) new_kv[i] = torch.nn.functional.pad( model_kwargs["past_key_values"][i], pad, value=pad_token_id ) model_kwargs["past_key_values"] = list(new_kv) else: for i in range(len(model_kwargs["past_key_values"])): tmp_lst = [None for j in range(len(model_kwargs["past_key_values"][i]))] for j in range(len(model_kwargs["past_key_values"][i])): pad_tuple = create_pad_arg(pad_amount, i, j) # Different models might have different shapes of kv-cache # create_pad_arg handles them on a per-model basis # This is a necessary (but not sufficient) condition: what ever dimension we are padding, should be a multiple of bucket_size # This check is added in case we get a new model with a new kv-cache structure, and we attempt to pad some wrong dimension # in peft case, if there's virtual token. the model_kwargs["past_key_values"][i][j].shape[-(len(pad_tuple) // 2)] % bucket_size == num_virtual_token, no need of assert, the pad length of past_key_value should be aligned with input id and attention_mask num_virtual_tokens = model_kwargs.get("num_virtual_tokens", 0) if ( model_kwargs["past_key_values"][i][j].shape[-(len(pad_tuple) // 2)] == params["allocated_space"] - pad_amount + num_virtual_tokens ): assert ( model_kwargs["past_key_values"][i][j].shape[-(len(pad_tuple) // 2)] % bucket_size == num_virtual_tokens ) tmp_lst[j] = torch.nn.functional.pad( model_kwargs["past_key_values"][i][j], pad_tuple, value=pad_token_id ) else: tmp_lst[j] = model_kwargs["past_key_values"][i][j] new_kv[i] = tuple(tmp_lst) model_kwargs["past_key_values"] = tuple(new_kv) if "token_idx" not in model_kwargs: model_kwargs["token_idx"] = torch.tensor(params["token_idx"], device=self.device) return input_ids, model_kwargs def _get_candidate_generator( self, generation_config: GaudiGenerationConfig, input_ids: torch.LongTensor, inputs_tensor: torch.Tensor, assistant_model: "PreTrainedModel", logits_processor: LogitsProcessorList, target_tokenizer: "PreTrainedTokenizerBase", assistant_tokenizer: "PreTrainedTokenizerBase", model_kwargs: Dict, ) -> CandidateGenerator: different_tokenizers = all(v is not None for v in (assistant_model, target_tokenizer, assistant_tokenizer)) if generation_config.assistant_early_exit is not None: candidate_generator = EarlyExitCandidateGenerator( input_ids=input_ids, assistant_model=self, generation_config=generation_config, model_kwargs=model_kwargs, inputs_tensor=inputs_tensor, logits_processor=logits_processor, ) elif generation_config.prompt_lookup_num_tokens is not None: candidate_generator = PromptLookupCandidateGenerator( eos_token_id=generation_config._eos_token_tensor, num_output_tokens=generation_config.prompt_lookup_num_tokens, max_matching_ngram_size=generation_config.max_matching_ngram_size, max_length=generation_config.max_length, ) elif different_tokenizers: if generation_config.do_sample is True: atm_translator = AssistantVocabTranslatorCache.get_translator( target_tokenizer, assistant_tokenizer, self.config.vocab_size, assistant_model.device ) candidate_generator = UniversalSpeculativeDecodingGenerator( input_ids=input_ids, assistant_model=assistant_model, generation_config=generation_config, model_kwargs=model_kwargs, inputs_tensor=inputs_tensor, logits_processor=logits_processor, target_tokenizer=target_tokenizer, assistant_tokenizer=assistant_tokenizer, atm_translator=atm_translator, ) elif generation_config.do_sample is False: candidate_generator = AssistedCandidateGeneratorDifferentTokenizers( input_ids=input_ids, assistant_model=assistant_model, generation_config=generation_config, model_kwargs=model_kwargs, inputs_tensor=inputs_tensor, logits_processor=logits_processor, target_tokenizer=target_tokenizer, assistant_tokenizer=assistant_tokenizer, ) else: raise ValueError( f"Invalid value for `do_sample`: expected a boolean, got {type(generation_config.do_sample).__name__}" ) else: candidate_generator = GaudiAssistedCandidateGenerator( input_ids=input_ids, assistant_model=assistant_model, generation_config=generation_config, model_kwargs=model_kwargs, inputs_tensor=inputs_tensor, logits_processor=logits_processor, ) return candidate_generator def _get_stopping_criteria( self, generation_config: GaudiGenerationConfig, stopping_criteria: Optional[StoppingCriteriaList], tokenizer: Optional["PreTrainedTokenizerBase"] = None, **kwargs, ) -> StoppingCriteriaList: criteria = StoppingCriteriaList() if generation_config.max_length is not None: max_position_embeddings = getattr(self.config, "max_position_embeddings", None) criteria.append( MaxLengthCriteria( max_length=generation_config.max_length, max_position_embeddings=max_position_embeddings, ) ) if generation_config.max_time is not None: criteria.append(MaxTimeCriteria(max_time=generation_config.max_time)) if generation_config.stop_strings is not None: if tokenizer is None: raise ValueError( "There are one or more stop strings, either in the arguments to `generate` or in the " "model's generation config, but we could not locate a tokenizer. When generating with " "stop strings, you must pass the model's tokenizer to the `tokenizer` argument of `generate`." ) criteria.append(StopStringCriteria(stop_strings=generation_config.stop_strings, tokenizer=tokenizer)) if not generation_config.ignore_eos and generation_config._eos_token_tensor is not None: criteria.append(EosTokenCriteria(eos_token_id=generation_config._eos_token_tensor)) if ( generation_config.is_assistant and generation_config.assistant_confidence_threshold is not None and generation_config.assistant_confidence_threshold > 0 ): criteria.append( ConfidenceCriteria(assistant_confidence_threshold=generation_config.assistant_confidence_threshold) ) criteria = self._merge_criteria_processor_list(criteria, stopping_criteria) return criteria def _prepare_generated_length( self, generation_config, has_default_max_length, has_default_min_length, model_input_name, input_ids_length, inputs_tensor, has_token_idx, ): """Prepared max and min length in generation configs to avoid clashes between similar attributes""" if generation_config.max_new_tokens is not None: if not has_default_max_length and generation_config.max_length is not None: logger.warning( f"Both `max_new_tokens` (={generation_config.max_new_tokens}) and `max_length`(=" f"{generation_config.max_length}) seem to have been set. `max_new_tokens` will take precedence. " "Please refer to the documentation for more information. " "(https://huggingface.co/docs/transformers/main/en/main_classes/text_generation)" ) if has_token_idx: generation_config.max_length = input_ids_length else: generation_config.max_length = generation_config.max_new_tokens + input_ids_length # if both `inputs_embeds` and `input_ids` are passed, we do not correct the length # otherwise we need total length [inputs-embeds-len + new-tokens-len] to not go beyond indicated `max_length`` elif ( model_input_name == "inputs_embeds" and input_ids_length != inputs_tensor.shape[1] and not self.config.is_encoder_decoder ): generation_config.max_length -= inputs_tensor.shape[1] elif has_default_max_length: # by default let's always generate 20 new tokens if generation_config.max_length == GaudiGenerationConfig().max_length: generation_config.max_length = generation_config.max_length + input_ids_length max_position_embeddings = getattr(self.config, "max_position_embeddings", None) if max_position_embeddings is not None: generation_config.max_length = min(generation_config.max_length, max_position_embeddings) # same for min length if generation_config.min_new_tokens is not None: if not has_default_min_length: logger.warning( f"Both `min_new_tokens` (={generation_config.min_new_tokens}) and `min_length`(=" f"{generation_config.min_length}) seem to have been set. `min_new_tokens` will take precedence. " "Please refer to the documentation for more information. " "(https://huggingface.co/docs/transformers/main/en/main_classes/text_generation)" ) if has_token_idx: generation_config.min_length = input_ids_length else: generation_config.min_length = generation_config.min_new_tokens + input_ids_length elif ( model_input_name == "inputs_embeds" and input_ids_length != inputs_tensor.shape[1] and not self.config.is_encoder_decoder ): generation_config.min_length = max(generation_config.min_length - inputs_tensor.shape[1], 0) return generation_config def _prepare_generation_config( self, generation_config: Optional[GaudiGenerationConfig], use_model_defaults: Optional[bool] = None, **kwargs: Dict, ) -> Tuple[GaudiGenerationConfig, Dict]: """ Copied from https://github.com/huggingface/transformers/blob/v4.40.2/src/transformers/generation/utils.py#L1230 Differences: - add management of `static_shapes` and `ignore_eos` in the generation config - workaround for `token_type_ids` for Falcon """ # parameterization priority: # kwargs > non-global default values in `generation_config` > `model.generation_config` > GenerationConfig() # TODO (joao): per-model generation config classes. using_model_generation_config = False if generation_config is None: # legacy: users may modify the model configuration to control generation. To trigger this legacy behavior, # the following conditions must be met # 1) the generation config must have been created from the model config (`_from_model_config` field); # 2) the generation config must have seen no modification since its creation (the hash is the same); # 3) there are non-default generation parameters in the model config. # 4) the user must have set new generation parameters in the model config. if ( self.generation_config._from_model_config # 1) and self.generation_config._original_object_hash == hash(self.generation_config) # 2) and len(self.config._get_non_default_generation_parameters()) > 0 # 3) ): new_generation_config = GaudiGenerationConfig.from_model_config(self.config) if new_generation_config != self.generation_config: # 4) warnings.warn( "You have modified the pretrained model configuration to control generation. This is a" " deprecated strategy to control generation and will be removed in v5." " Please use and modify the model generation configuration (see" " https://huggingface.co/docs/transformers/generation_strategies#default-text-generation-configuration )", UserWarning, ) self.generation_config = new_generation_config generation_config = self.generation_config using_model_generation_config = True # `torch.export.export` usually raises an exception if it is called # with ``strict=True``. deepcopy can only be processed if ``strict=False``. generation_config = copy.deepcopy(generation_config) if not using_model_generation_config: # If `generation_config` is provided: # - `use_model_defaults`: let's fallback ALL default values to the model's generation config # - otherwise: legacy behavior, let's just make sure we have the tokens defined model_base_version = version.parse(version.parse(self.generation_config.transformers_version).base_version) if use_model_defaults is True or ( use_model_defaults is None and model_base_version >= version.parse("4.50.0") ): modified_values = {} default_generation_config = GaudiGenerationConfig() for key, default_value in default_generation_config.__dict__.items(): if key.startswith("_") or key == "transformers_version": # metadata continue custom_gen_config_value = getattr(generation_config, key) model_gen_config_value = getattr(self.generation_config, key) if custom_gen_config_value == default_value and model_gen_config_value != default_value: modified_values[key] = model_gen_config_value setattr(generation_config, key, model_gen_config_value) if len(modified_values) > 0: logger.warning_once( f"`generation_config` default values have been modified to match model-specific defaults: " f"{modified_values}. If this is not desired, please set these values explicitly." ) else: if generation_config.bos_token_id is None: generation_config.bos_token_id = self.generation_config.bos_token_id if generation_config.eos_token_id is None: generation_config.eos_token_id = self.generation_config.eos_token_id if generation_config.pad_token_id is None: generation_config.pad_token_id = self.generation_config.pad_token_id if generation_config.decoder_start_token_id is None: generation_config.decoder_start_token_id = self.generation_config.decoder_start_token_id if generation_config.static_shapes is None: generation_config.static_shapes = self.config.model_type in MODELS_OPTIMIZED_WITH_STATIC_SHAPES if self.config.model_type == "vision-encoder-decoder": generation_config.static_shapes = self.config.decoder.model_type in MODELS_OPTIMIZED_WITH_STATIC_SHAPES self.generation_config.static_shapes = generation_config.static_shapes if generation_config.ignore_eos is None: generation_config.ignore_eos = kwargs.get("ignore_eos", kwargs.get("lazy_mode", None)) self.generation_config.ignore_eos = generation_config.ignore_eos # Finally, apply any passed kwargs model_kwargs = generation_config.update(**kwargs) if self.config.model_type == "falcon" and "token_type_ids" in kwargs.keys(): for key in ["token_type_ids"]: model_kwargs.pop(key, None) return generation_config, model_kwargs def _prepare_cache_for_generation( self, generation_config: GaudiGenerationConfig, model_kwargs: Dict, assistant_model: "PreTrainedModel", batch_size: int, max_cache_length: int, device: torch.device, ) -> bool: """ Copied from: https://github.com/huggingface/transformers/blob/65bb28444849976f853063edb958b3ef3dd59d12/src/transformers/generation/utils.py#L1467 Changes: - change the default from DynamicCache to tuples """ cache_name = "past_key_values" if "mamba" not in self.__class__.__name__.lower() else "cache_params" requires_cross_attention_cache = ( self.config.is_encoder_decoder or model_kwargs.get("encoder_outputs") is not None ) # Quick escape route 1: if the user specifies a cache, we only need to: # a) check for conflicting `generate` arguments # b) convert to the new cache format (if the user passes a legacy cache and model supports it) user_defined_cache = model_kwargs.get(cache_name) if user_defined_cache is not None: if generation_config.cache_implementation is not None: raise ValueError( f"Passing both `cache_implementation` (used to initialize certain caches) and `{cache_name}` (a " "Cache object) is unsupported. Please use only one of the two." ) if isinstance(user_defined_cache, tuple) and self._supports_default_dynamic_cache(): model_kwargs[cache_name] = ( DynamicCache.from_legacy_cache(user_defined_cache) if not requires_cross_attention_cache else EncoderDecoderCache.from_legacy_cache(user_defined_cache) ) return # Quick escape route 2: if the user specifies no cache is to be used. (conflicting arguments are handled in # `generation_config.validate()`) if generation_config.use_cache is False: return # Quick escape route 3: model that only supports legacy caches = nothing to prepare if not self._supports_default_dynamic_cache(): if generation_config.cache_implementation is not None: warnings.warn( "This model does not support `Cache` instances, it only supports the legacy cache format (tuple " f"of tuples). `cache_implementation` (set to {generation_config.cache_implementation}) will be " "ignored.", UserWarning, ) return # Otherwise we NEED to prepare a cache, based on `generation_config.cache_implementation` # TODO(joao): support static caches in assisted generation. assisted generation needs to roll back caches, # which is only supported in dynamic caches atm if assistant_model is not None and generation_config.cache_implementation is not None: logger.warning_once( "An assistant model is provided, using a dynamic cache instead of a cache of type=" f"'{generation_config.cache_implementation}'." ) generation_config.cache_implementation = None # generation_config.cache_implementation = generation_config.cache_implementation or getattr( # self.config.get_text_config(), "cache_implementation", None # ) if generation_config.cache_implementation is not None: if generation_config.cache_implementation in NEED_SETUP_CACHE_CLASSES_MAPPING: if generation_config.cache_implementation == "static" and not self._supports_static_cache: raise ValueError( "This model does not support `cache_implementation='static'`. Please check the following " "issue: https://github.com/huggingface/transformers/issues/28981" ) model_kwargs[cache_name] = self._get_cache( cache_implementation=generation_config.cache_implementation, batch_size=max(generation_config.num_beams, generation_config.num_return_sequences) * batch_size, max_cache_len=max_cache_length, device=device, model_kwargs=model_kwargs, ) elif generation_config.cache_implementation == "quantized": if not self._supports_quantized_cache: raise ValueError( "This model does not support the quantized cache. If you want your model to support quantized " "cache, please open an issue and tag @zucchini-nlp." ) cache_config = ( generation_config.cache_config if generation_config.cache_config is not None else QuantizedCacheConfig() ) cache_class = QUANT_BACKEND_CLASSES_MAPPING[cache_config.backend] if cache_config.backend == "quanto" and not is_optimum_quanto_available(): raise ImportError( "You need to install optimum-quanto in order to use KV cache quantization with optimum-quanto backend. " "Please install it via with `pip install optimum-quanto`" ) elif cache_config.backend == "HQQ" and not is_hqq_available(): raise ImportError( "You need to install `HQQ` in order to use KV cache quantization with HQQ backend. " "Please install it via with `pip install hqq`" ) model_kwargs[cache_name] = cache_class(cache_config) elif generation_config.cache_implementation == "offloaded": model_kwargs[cache_name] = OffloadedCache() elif generation_config.cache_implementation == "dynamic": model_kwargs[cache_name] = DynamicCache() # Use tuples by default (.i.e. legacy format). else: return @torch.no_grad() def generate( self, inputs: Optional[torch.Tensor] = None, generation_config: Optional[GaudiGenerationConfig] = None, logits_processor: Optional[LogitsProcessorList] = None, stopping_criteria: Optional[StoppingCriteriaList] = None, prefix_allowed_tokens_fn: Optional[Callable[[int, torch.Tensor], List[int]]] = None, synced_gpus: Optional[bool] = None, assistant_model: Optional["PreTrainedModel"] = None, streamer: Optional["BaseStreamer"] = None, negative_prompt_ids: Optional[torch.Tensor] = None, negative_prompt_attention_mask: Optional[torch.Tensor] = None, use_model_defaults: Optional[bool] = None, lazy_mode: Optional[bool] = False, hpu_graphs: Optional[bool] = False, profiling_warmup_steps: Optional[int] = 0, profiling_steps: Optional[int] = 0, iteration_times: Optional[List[float]] = None, profiling_record_shapes: Optional[bool] = False, **kwargs, ) -> Union[GenerateOutput, torch.LongTensor]: r""" Generates sequences of token ids for models with a language modeling head. <Tip warning={true}> Most generation-controlling parameters are set in [`transformers.generation.generation_config`] which, if not passed, will be set to the model's default generation configuration. You can override any `generation_config` by passing the corresponding parameters to generate, e.g. `.generate(inputs, num_beams=4, do_sample=True)`. For an overview of generation strategies and code examples, check out the [following guide](../generation_strategies). </Tip> Most of these parameters are explained in more detail in [this blog post](https://huggingface.co/blog/how-to-generate). Parameters: inputs (`torch.Tensor` of varying shape depending on the modality, *optional*): The sequence used as a prompt for the generation or as model inputs to the encoder. If `None` the method initializes it with `bos_token_id` and a batch size of 1. For decoder-only models `inputs` should be in the format of `input_ids`. For encoder-decoder models *inputs* can represent any of `input_ids`, `input_values`, `input_features`, or `pixel_values`. generation_config (`transformers.generation.GenerationConfig`, *optional*): The generation configuration to be used as base parametrization for the generation call. `**kwargs` passed to generate matching the attributes of `generation_config` will override them. If `generation_config` is not provided, the default will be used, which has the following loading priority: 1) from the `generation_config.json` model file, if it exists; 2) from the model configuration. Please note that unspecified parameters will inherit [`~generation.GenerationConfig`]'s default values, whose documentation should be checked to parameterize generation. logits_processor (`LogitsProcessorList`, *optional*): Custom logits processors that complement the default logits processors built from arguments and generation config. If a logit processor is passed that is already created with the arguments or a generation config an error is thrown. This feature is intended for advanced users. stopping_criteria (`StoppingCriteriaList`, *optional*): Custom stopping criteria that complements the default stopping criteria built from arguments and a generation config. If a stopping criteria is passed that is already created with the arguments or a generation config an error is thrown. If your stopping criteria depends on the `scores` input, make sure you pass `return_dict_in_generate=True, output_scores=True` to `generate`. This feature is intended for advanced users. prefix_allowed_tokens_fn (`Callable[[int, torch.Tensor], List[int]]`, *optional*): If provided, this function constraints the beam search to allowed tokens only at each step. If not provided no constraint is applied. This function takes 2 arguments: the batch ID `batch_id` and `input_ids`. It has to return a list with the allowed tokens for the next generation step conditioned on the batch ID `batch_id` and the previously generated tokens `inputs_ids`. This argument is useful for constrained generation conditioned on the prefix, as described in [Autoregressive Entity Retrieval](https://arxiv.org/abs/2010.00904). synced_gpus (`bool`, *optional*): Whether to continue running the while loop until max_length. Unless overridden, this flag will be set to `True` if using `FullyShardedDataParallel` or DeepSpeed ZeRO Stage 3 with multiple GPUs to avoid deadlocking if one GPU finishes generating before other GPUs. Otherwise, defaults to `False`. assistant_model (`PreTrainedModel`, *optional*): An assistant model that can be used to accelerate generation. The assistant model must have the exact same tokenizer. The acceleration is achieved when forecasting candidate tokens with the assistant model is much faster than running generation with the model you're calling generate from. As such, the assistant model should be much smaller. streamer (`BaseStreamer`, *optional*): Streamer object that will be used to stream the generated sequences. Generated tokens are passed through `streamer.put(token_ids)` and the streamer is responsible for any further processing. negative_prompt_ids (`torch.LongTensor` of shape `(batch_size, sequence_length)`, *optional*): The negative prompt needed for some processors such as CFG. The batch size must match the input batch size. This is an experimental feature, subject to breaking API changes in future versions. negative_prompt_attention_mask (`torch.LongTensor` of shape `(batch_size, sequence_length)`, *optional*): Attention_mask for `negative_prompt_ids`. use_model_defaults (`bool`, *optional*): When it is `True`, unset parameters in `generation_config` will be set to the model-specific default generation configuration (`model.generation_config`), as opposed to the global defaults (`GenerationConfig()`). If unset, models saved starting from `v4.50` will consider this flag to be `True`. lazy_mode (`bool`, *optional*, defaults to `False`): Whether the run is executed in lazy mode or not (i.e. eager mode). hpu_graphs (`bool`, *optional*, defaults to `False`): Whether to use HPU graphs for inference. profiling_warmup_steps (`int`, *optional*, defaults to 0): Number of steps to ignore for profling. profiling_steps (`int`, *optional*, defaults to 0): Number of steps to be captured when enabling profiling. profiling_record_shapes (`bool`, *optional*, defaults to False): Record shapes when enabling profiling. kwargs (`Dict[str, Any]`, *optional*): Ad hoc parametrization of `generation_config` and/or additional model-specific kwargs that will be forwarded to the `forward` function of the model. If the model is an encoder-decoder model, encoder specific kwargs should not be prefixed and decoder specific kwargs should be prefixed with *decoder_*. Return: [`transformers.utils.ModelOutput`] or `torch.LongTensor`: A [`transformers.generationutils.ModelOutput`] (if `return_dict_in_generate=True` or when `config.return_dict_in_generate=True`) or a `torch.LongTensor`. If the model is *not* an encoder-decoder model (`model.config.is_encoder_decoder=False`), the possible [`transformers.generationutils.ModelOutput`] types are: - [`transformers.generation.GenerateDecoderOnlyOutput`], - [`transformers.generation.GenerateBeamDecoderOnlyOutput`] If the model is an encoder-decoder model (`model.config.is_encoder_decoder=True`), the possible [`transformers.generationutils.ModelOutput`] types are: - [`transformers.generation.GenerateEncoderDecoderOutput`], - [`transformers.generation.GenerateBeamEncoderDecoderOutput`] """ if iteration_times is not None: hb_gen_time = HabanaGenerationTime(iteration_times=iteration_times) hb_gen_time.start() else: hb_gen_time = None if synced_gpus is None: if is_deepspeed_zero3_enabled() and dist.get_world_size() > 1: synced_gpus = True else: synced_gpus = False # 1. Handle `generation_config` and kwargs that might update it, and validate the `.generate()` call self._validate_model_class() tokenizer = kwargs.pop("tokenizer", None) # Pull this out first, we only use it for stopping criteria assistant_tokenizer = kwargs.pop("assistant_tokenizer", None) # only used for assisted generation if hpu_graphs and not lazy_mode: raise ValueError( "`hpu_graphs` is True but `lazy_mode` is False. HPU graphs require `lazy_mode` to be set to True." ) num_virtual_tokens = kwargs.pop("num_virtual_tokens", 0) generation_config, model_kwargs = self._prepare_generation_config( generation_config, use_model_defaults, **kwargs ) self._validate_model_kwargs(model_kwargs.copy()) self._validate_assistant(assistant_model, tokenizer, assistant_tokenizer) # 2. Set generation parameters if not already defined if synced_gpus is None: synced_gpus = (is_deepspeed_zero3_enabled() or is_fsdp_managed_module(self)) and dist.get_world_size() > 1 logits_processor = logits_processor if logits_processor is not None else LogitsProcessorList() stopping_criteria = stopping_criteria if stopping_criteria is not None else StoppingCriteriaList() accepts_attention_mask = "attention_mask" in set(inspect.signature(self.forward).parameters.keys()) requires_attention_mask = "encoder_outputs" not in model_kwargs kwargs_has_attention_mask = model_kwargs.get("attention_mask", None) is not None # 3. Define model inputs inputs_tensor, model_input_name, model_kwargs = self._prepare_model_inputs( inputs, generation_config.bos_token_id, model_kwargs ) batch_size = inputs_tensor.shape[0] device = inputs_tensor.device self._prepare_special_tokens(generation_config, kwargs_has_attention_mask, device=device) # decoder-only models must use left-padding for batched generation. if not self.config.is_encoder_decoder: # If `input_ids` was given, check if the last id in any sequence is `pad_token_id` # Note: If using, `inputs_embeds` this check does not work, because we want to be more hands-off. if ( generation_config._pad_token_tensor is not None and batch_size > 1 and len(inputs_tensor.shape) == 2 and torch.sum(inputs_tensor[:, -1] == generation_config._pad_token_tensor) > 0 ): logger.warning( "A decoder-only architecture is being used, but right-padding was detected! For correct " "generation results, please set `padding_side='left'` when initializing the tokenizer." ) # 4. Define other model kwargs # decoder-only models with inputs_embeds forwarding must use caching (otherwise we can't detect whether we are # generating the first new token or not, and we only want to use the embeddings for the first new token) if not self.config.is_encoder_decoder and model_input_name == "inputs_embeds": generation_config.use_cache = True self.generation_config.max_length = generation_config.max_length if not kwargs_has_attention_mask and requires_attention_mask and accepts_attention_mask: model_kwargs["attention_mask"] = self._prepare_attention_mask_for_generation( inputs_tensor, generation_config, model_kwargs ) elif kwargs_has_attention_mask: # TODO (joao): generalize this check with other types of inputs if model_input_name == "input_ids" and len(model_kwargs["attention_mask"].shape) > 2: raise ValueError("`attention_mask` passed to `generate` must be 2D.") is_greedy_or_beam_and_bucket = ( not generation_config.bucket_internal and generation_config.bucket_size > 0 and generation_config.get_generation_mode(assistant_model) in [ GenerationMode.GREEDY_SEARCH, GenerationMode.SAMPLE, GenerationMode.BEAM_SEARCH, GenerationMode.BEAM_SAMPLE, GenerationMode.CONTRASTIVE_SEARCH, ] ) model_kwargs["bucket_size"] = generation_config.bucket_size if generation_config.static_shapes else -1 model_kwargs["bucket_internal"] = generation_config.bucket_internal model_kwargs["reduce_recompile"] = ( generation_config.reduce_recompile if generation_config.reduce_recompile is not None else False ) if model_kwargs["reduce_recompile"]: assert generation_config.bucket_size # Below condition checked explicitly since some models (like llama and gpt_bigcode) support bucket_internal even without reuse_cache if generation_config.bucket_internal: assert generation_config.bucket_size >= 0, "please set bucket_size to use bucket_internal" assert generation_config.use_cache, "please set use_cache flag to use bucket_internal" if generation_config.reuse_cache: assert self.config.model_type in [ "llama", "mistral", "falcon", "mixtral", "phi", "qwen2", "gptj", "starcoder2", "qwen2_moe", "gemma", "gemma2", "baichuan", "chatglm", "deepseek_v2", "deepseek_v3", ], ( "reuse_cache only supported by llama, mistral, falcon, mixtral, phi, qwen2, qwen2_moe, gemma, gemma2, starcoder2, baichuan, chatglm and deepseek_v2 at the moment" ) if not generation_config.bucket_internal: assert generation_config.bucket_size <= 0, ( "please set bucket_internal along with reuse_cache and bucket_size" ) else: assert generation_config.bucket_size >= 0, "please set valid bucket_size to use bucket_internal" if self.config.model_type == "gemma2": generation_config.cache_implementation = None if generation_config.static_shapes: # Pad inputs to have static shapes during generation, this gives better performance than dynamic shapes on HPUs # In encoder_decoder models, Inputs are already padded if not self.config.is_encoder_decoder: # only pad if bucket_size < -1. If we are bucketing (bucket_size > 0), then that is taken care in greedy_search() if not is_greedy_or_beam_and_bucket: # token_idx is the current index in the generation process, it is incremented each time a new token is generated token_idx = inputs_tensor.shape[1] if generation_config.max_new_tokens is None: generation_config.max_new_tokens = generation_config.max_length - token_idx if model_input_name == "inputs_embeds" and model_kwargs["input_ids"].numel() == 0: inputs_embeds_offset = -model_kwargs["inputs_embeds"].shape[1] model_kwargs["inputs_embeds_offset"] = torch.tensor( inputs_embeds_offset, device=inputs_tensor.device ) if ( model_input_name == "inputs_embeds" and model_kwargs.get("inputs_embeds") is not None and not model_kwargs["bucket_internal"] and not generation_config.reuse_cache ): model_kwargs["inputs_embeds"] = torch.nn.functional.pad( model_kwargs["inputs_embeds"], (0, 0, 0, generation_config.max_new_tokens), value=generation_config.pad_token_id, ) else: inputs_tensor = torch.nn.functional.pad( inputs_tensor, (0, generation_config.max_new_tokens), value=generation_config.pad_token_id ) model_kwargs["token_idx"] = torch.tensor(token_idx, device=inputs_tensor.device) model_kwargs["token_idx_cpu"] = token_idx for other_inputs in ["attention_mask", "token_type_ids"]: if model_kwargs.get(other_inputs) is not None: model_kwargs[other_inputs] = torch.nn.functional.pad( model_kwargs[other_inputs], (0, generation_config.max_new_tokens), value=0, ) if model_kwargs.get("cross_attention_mask") is not None: model_kwargs["cross_attention_mask"] = torch.nn.functional.pad( model_kwargs["cross_attention_mask"], (0, 0, 0, 0, 0, generation_config.max_new_tokens), value=0, ) else: assert generation_config.bucket_size <= 0, "Untested path for bucket>0" if model_kwargs.get("decoder_input_ids", None) is None: token_idx = INITIAL_TOKEN_IDX else: token_idx = model_kwargs["decoder_input_ids"].shape[-1] model_kwargs["token_idx"] = torch.tensor(token_idx, device=inputs_tensor.device) if model_kwargs.get("decoder_attention_mask", None) is None and generation_config.use_cache: max_length = ( generation_config.max_new_tokens + token_idx if generation_config.max_new_tokens is not None else generation_config.max_length ) model_kwargs["decoder_attention_mask"] = self._prepare_decoder_attention_mask( max_length, inputs_tensor.shape[0], inputs_tensor.device, ) if self.config.is_encoder_decoder and "encoder_outputs" not in model_kwargs: # if model is encoder decoder encoder_outputs are created and added to `model_kwargs` model_kwargs = self._prepare_encoder_decoder_kwargs_for_generation( inputs_tensor, model_kwargs, model_input_name, generation_config ) # 5. Prepare `input_ids` which will be used for auto-regressive generation if self.config.is_encoder_decoder: input_ids, model_kwargs = self._prepare_decoder_input_ids_for_generation( batch_size=batch_size, model_input_name=model_input_name, model_kwargs=model_kwargs, decoder_start_token_id=generation_config._decoder_start_token_tensor, device=inputs_tensor.device, max_new_tokens=generation_config.max_new_tokens, pad_token_id=generation_config.pad_token_id, ) else: input_ids = inputs_tensor if model_input_name == "input_ids" else model_kwargs.pop("input_ids") if model_input_name == "inputs_embeds" and generation_config.static_shapes: if not is_greedy_or_beam_and_bucket: input_ids = torch.nn.functional.pad( input_ids, (0, generation_config.max_new_tokens), value=generation_config.pad_token_id ) if generation_config.token_healing: input_ids = self.heal_tokens(input_ids, tokenizer) if streamer is not None: streamer.put(input_ids.cpu()) # 6. Prepare `max_length` depending on other stopping criteria. input_ids_length = input_ids.shape[1] has_default_max_length = kwargs.get("max_length") is None and generation_config.max_length is not None has_default_min_length = kwargs.get("min_length") is None and generation_config.min_length is not None generation_config = self._prepare_generated_length( generation_config=generation_config, has_default_max_length=has_default_max_length, has_default_min_length=has_default_min_length, model_input_name=model_input_name, inputs_tensor=inputs_tensor, input_ids_length=input_ids_length, has_token_idx="token_idx" in model_kwargs, ) # If the model supports `logits_to_keep` in forward(), set it to 1 to avoid computing the whole # logit matrix. This can save a lot of memory during the first forward pass. Note that assisted decoding # dynamically overrides this value as it can need more than the last token logits # # Use trim_logits in HPU to save memory (in replacement of the num_logits_to_keep) # if self._supports_logits_to_keep() and "logits_to_keep" not in model_kwargs: # model_kwargs["logits_to_keep"] = 1 self._validate_generated_length( generation_config, model_kwargs["token_idx"].item() if "token_idx" in model_kwargs else input_ids_length, has_default_max_length, ) # 7. Prepare the cache. # - `model_kwargs` may be updated in place with a cache as defined by the parameters in `generation_config`. # - different models have a different cache name expected by the model (default = "past_key_values") # - `max_length`, prepared above, is used to determine the maximum cache length max_cache_length = generation_config.max_length - 1 if ( inputs_tensor.shape[1] != input_ids_length and model_input_name == "inputs_embeds" and not self.config.is_encoder_decoder ): max_cache_length += inputs_tensor.shape[1] self._prepare_cache_for_generation( generation_config, model_kwargs, assistant_model, batch_size, max_cache_length, device ) # determine whether introduce trim_logits feature model_kwargs["trim_logits"] = generation_config.trim_logits # determine whether attention softmax needs to execute in lower precision model_kwargs["attn_softmax_bf16"] = generation_config.attn_softmax_bf16 # determine whether limit_hpu_graphs needs to be used model_kwargs["use_hpu_graphs"] = hpu_graphs model_kwargs["limit_hpu_graphs"] = generation_config.limit_hpu_graphs # determine whether to clear hpu graphs cache model_kwargs["clear_hpu_graphs_cache"] = generation_config.clear_hpu_graphs_cache # prepare for allocate kv cache model_kwargs["reuse_cache"] = generation_config.reuse_cache # prepare for attention batch splitting model_kwargs["attn_batch_split"] = generation_config.attn_batch_split # Keep logits in bf16 model_kwargs["logits_bf16"] = kwargs.get("logits_bf16") # determine whether flash attention needs to be used model_kwargs["use_flash_attention"] = generation_config.use_flash_attention model_kwargs["flash_attention_recompute"] = True if generation_config.flash_attention_recompute else False model_kwargs["flash_attention_causal_mask"] = True if generation_config.flash_attention_causal_mask else False model_kwargs["flash_attention_fast_softmax"] = ( True if generation_config.flash_attention_fast_softmax else False ) model_kwargs["num_virtual_tokens"] = num_virtual_tokens if generation_config.valid_sequence_lengths is not None: model_kwargs["valid_sequence_lengths"] = generation_config.valid_sequence_lengths if not self.config.is_encoder_decoder: calculated_max_length = input_ids.shape[1] + num_virtual_tokens if not generation_config.static_shapes and generation_config.max_new_tokens is not None: calculated_max_length = input_ids.shape[1] + generation_config.max_new_tokens + num_virtual_tokens if generation_config.use_cache and generation_config.reuse_cache: bs, _ = input_ids.shape if not is_greedy_or_beam_and_bucket: unwrap_deepspeed_model(self).allocate_kv_cache( bs * generation_config.num_beams, calculated_max_length, token_idx + num_virtual_tokens ) if generation_config.use_cache: model_kwargs["kv_cache_len"] = calculated_max_length model_kwargs["kv_cache_pad_len"] = generation_config.max_new_tokens if self.config.model_type in [ "llama", "falcon", "mistral", "qwen2", "gptj", "starcoder2", "gemma", "gemma2", "qwen2_moe", "baichuan", "deepseek_v2", ]: if ( hasattr(self.config, "max_position_embeddings") and self.config.max_position_embeddings < calculated_max_length ): unwrap_deepspeed_model(self).update_sincos_cache(seq_len=calculated_max_length) # 8. determine generation mode generation_mode = generation_config.get_generation_mode(assistant_model) if generation_config.bucket_size > 0: assert generation_config.static_shapes, "bucket_size > 0 can be set only when static_shapes is set" # if generation_config.bucket_size <= 0, padding is handled by the generating fn (like greedy_search) if generation_config.static_shapes and generation_config.bucket_size > 0: assert generation_mode in [ GenerationMode.GREEDY_SEARCH, GenerationMode.SAMPLE, GenerationMode.BEAM_SEARCH, GenerationMode.BEAM_SAMPLE, GenerationMode.CONTRASTIVE_SEARCH, ], "generation_config.bucket_size > 0 supported only for greedy mode" if streamer is not None and (generation_config.num_beams > 1): raise ValueError( "`streamer` cannot be used with beam search (yet!). Make sure that `num_beams` is set to 1." ) if self.device.type != input_ids.device.type: warnings.warn( ( "You are calling .generate() with the `input_ids` being on a device type different" f" than your model's device. `input_ids` is on {input_ids.device.type}, whereas the model" f" is on {self.device.type}. You may experience unexpected behaviors or slower generation." " Please make sure that you have put `input_ids` to the" f" correct device by calling for example input_ids = input_ids.to('{self.device.type}') before" " running `.generate()`." ), UserWarning, ) # 9. prepare logits processors and stopping criteria prepared_logits_processor = self._get_logits_processor( generation_config=generation_config, input_ids_seq_length=input_ids_length, encoder_input_ids=inputs_tensor, prefix_allowed_tokens_fn=prefix_allowed_tokens_fn, logits_processor=logits_processor, device=inputs_tensor.device, model_kwargs=model_kwargs, negative_prompt_ids=negative_prompt_ids, negative_prompt_attention_mask=negative_prompt_attention_mask, ) self.generation_config.generation_mode = generation_mode prepared_stopping_criteria = self._get_stopping_criteria( generation_config=generation_config, stopping_criteria=stopping_criteria, tokenizer=tokenizer, **kwargs, ) # Set model_kwargs `use_cache` so we can use it later in forward runs model_kwargs["use_cache"] = generation_config.use_cache # In lazy mode, import Habana torch to be able to add mark_step() if lazy_mode: import habana_frameworks.torch.core as htcore self.htcore_generation = htcore # 10. go into different generation modes if generation_mode == GenerationMode.ASSISTED_GENERATION: if generation_config.num_return_sequences > 1: raise ValueError( "num_return_sequences has to be 1 when doing assisted generate, " f"but is {generation_config.num_return_sequences}." ) if batch_size > 1: raise ValueError("assisted generate is only supported for batch_size = 1") if not model_kwargs["use_cache"]: raise ValueError("assisted generate requires `use_cache=True`") if generation_config.cache_implementation in ["static", "hybrid", "sliding_window"]: raise ValueError("assisted generate is not supported with Static cache classes`") if self._is_stateful: # In assisted generation we need the ability to confirm whether the model would pick certain tokens, # which is not possible with stateful models (they can't reset to a previous subset of generated text) raise ValueError( f"assisted generation is not supported with stateful models, such as {self.__class__.__name__}" ) # 11. Get the candidate generator, given the parameterization candidate_generator = self._get_candidate_generator( generation_config=generation_config, input_ids=input_ids, inputs_tensor=inputs_tensor, assistant_model=assistant_model, logits_processor=logits_processor, target_tokenizer=tokenizer, assistant_tokenizer=assistant_tokenizer, model_kwargs=model_kwargs, ) # 12. run assisted generate result = self._assisted_decoding( input_ids, candidate_generator=candidate_generator, logits_processor=prepared_logits_processor, stopping_criteria=prepared_stopping_criteria, generation_config=generation_config, synced_gpus=synced_gpus, streamer=streamer, lazy_mode=lazy_mode, ignore_eos=generation_config.ignore_eos, profiling_warmup_steps=profiling_warmup_steps, profiling_steps=profiling_steps, hb_gen_time=hb_gen_time, **model_kwargs, ) elif generation_mode == GenerationMode.DOLA_GENERATION: if self._is_stateful: # DoLa decoding was not designed for stateful models, and would require some changes raise ValueError( f"dola decoding is not supported with stateful models, such as {self.__class__.__name__}" ) result = self._dola_decoding( input_ids, dola_layers=generation_config.dola_layers, logits_processor=prepared_logits_processor, stopping_criteria=prepared_stopping_criteria, generation_config=generation_config, synced_gpus=synced_gpus, streamer=streamer, **model_kwargs, ) elif generation_mode == GenerationMode.CONTRASTIVE_SEARCH: if not model_kwargs["use_cache"]: raise ValueError("Contrastive search requires `use_cache=True`") if self._is_stateful: # Just like assisted generation, we need to be able to rollback to a previous state (see comment above) raise ValueError( f"contrastive search is not supported with stateful models, such as {self.__class__.__name__}" ) result = self._contrastive_search( input_ids, logits_processor=prepared_logits_processor, stopping_criteria=prepared_stopping_criteria, generation_config=generation_config, synced_gpus=synced_gpus, streamer=streamer, lazy_mode=lazy_mode, ignore_eos=generation_config.ignore_eos, profiling_warmup_steps=profiling_warmup_steps, profiling_steps=profiling_steps, hb_gen_time=hb_gen_time, profiling_record_shapes=profiling_record_shapes, **model_kwargs, ) elif generation_mode in (GenerationMode.SAMPLE, GenerationMode.GREEDY_SEARCH): # 11. expand input_ids with `num_return_sequences` additional sequences per batch input_ids, model_kwargs = self._expand_inputs_for_generation( input_ids=input_ids, expand_size=generation_config.num_return_sequences, is_encoder_decoder=self.config.is_encoder_decoder, **model_kwargs, ) # 12. run sample (it degenerates to greedy search when `generation_config.do_sample=False`) result = self._sample( input_ids, logits_processor=prepared_logits_processor, stopping_criteria=prepared_stopping_criteria, generation_config=generation_config, synced_gpus=synced_gpus, streamer=streamer, lazy_mode=lazy_mode, ignore_eos=generation_config.ignore_eos, profiling_warmup_steps=profiling_warmup_steps, profiling_steps=profiling_steps, hb_gen_time=hb_gen_time, profiling_record_shapes=profiling_record_shapes, **model_kwargs, ) elif generation_mode in (GenerationMode.BEAM_SAMPLE, GenerationMode.BEAM_SEARCH): # 11. prepare beam search scorer beam_scorer = BeamSearchScorer( batch_size=batch_size, num_beams=generation_config.num_beams, device=inputs_tensor.device, length_penalty=generation_config.length_penalty, do_early_stopping=generation_config.early_stopping, num_beam_hyps_to_keep=generation_config.num_return_sequences, max_length=generation_config.max_length, ) # 12. interleave input_ids with `num_beams` additional sequences per batch input_ids, model_kwargs = self._expand_inputs_for_generation( input_ids=input_ids, expand_size=generation_config.num_beams, is_encoder_decoder=self.config.is_encoder_decoder, **model_kwargs, ) # 13. run beam sample result = self._beam_search( input_ids, beam_scorer, logits_processor=prepared_logits_processor, stopping_criteria=prepared_stopping_criteria, generation_config=generation_config, synced_gpus=synced_gpus, lazy_mode=lazy_mode, profiling_warmup_steps=profiling_warmup_steps, profiling_steps=profiling_steps, hb_gen_time=hb_gen_time, profiling_record_shapes=profiling_record_shapes, **model_kwargs, ) elif generation_mode == GenerationMode.GROUP_BEAM_SEARCH: # 11. prepare beam search scorer beam_scorer = BeamSearchScorer( batch_size=batch_size, num_beams=generation_config.num_beams, device=inputs_tensor.device, length_penalty=generation_config.length_penalty, do_early_stopping=generation_config.early_stopping, num_beam_hyps_to_keep=generation_config.num_return_sequences, num_beam_groups=generation_config.num_beam_groups, max_length=generation_config.max_length, ) # 12. interleave input_ids with `num_beams` additional sequences per batch input_ids, model_kwargs = self._expand_inputs_for_generation( input_ids=input_ids, expand_size=generation_config.num_beams, is_encoder_decoder=self.config.is_encoder_decoder, **model_kwargs, ) # 13. run beam search result = self._group_beam_search( input_ids, beam_scorer, logits_processor=prepared_logits_processor, stopping_criteria=prepared_stopping_criteria, generation_config=generation_config, synced_gpus=synced_gpus, lazy_mode=lazy_mode, profiling_warmup_steps=profiling_warmup_steps, profiling_steps=profiling_steps, hb_gen_time=hb_gen_time, profiling_record_shapes=profiling_record_shapes, **model_kwargs, ) elif generation_mode == GenerationMode.CONSTRAINED_BEAM_SEARCH: final_constraints = [] if generation_config.constraints is not None: final_constraints = generation_config.constraints if generation_config.force_words_ids is not None: def typeerror(): raise ValueError( "`force_words_ids` has to either be a `List[List[List[int]]]` or `List[List[int]]` " f"of positive integers, but is {generation_config.force_words_ids}." ) if ( not isinstance(generation_config.force_words_ids, list) or len(generation_config.force_words_ids) == 0 ): typeerror() for word_ids in generation_config.force_words_ids: if isinstance(word_ids[0], list): if not isinstance(word_ids, list) or len(word_ids) == 0: typeerror() if any(not isinstance(token_ids, list) for token_ids in word_ids): typeerror() if any( any((not isinstance(token_id, int) or token_id < 0) for token_id in token_ids) for token_ids in word_ids ): typeerror() constraint = DisjunctiveConstraint(word_ids) else: if not isinstance(word_ids, list) or len(word_ids) == 0: typeerror() if any((not isinstance(token_id, int) or token_id < 0) for token_id in word_ids): typeerror() constraint = PhrasalConstraint(word_ids) final_constraints.append(constraint) # 11. prepare beam search scorer constrained_beam_scorer = ConstrainedBeamSearchScorer( constraints=final_constraints, batch_size=batch_size, num_beams=generation_config.num_beams, device=inputs_tensor.device, length_penalty=generation_config.length_penalty, do_early_stopping=generation_config.early_stopping, num_beam_hyps_to_keep=generation_config.num_return_sequences, max_length=generation_config.max_length, ) # 12. interleave input_ids with `num_beams` additional sequences per batch input_ids, model_kwargs = self._expand_inputs_for_generation( input_ids=input_ids, expand_size=generation_config.num_beams, is_encoder_decoder=self.config.is_encoder_decoder, **model_kwargs, ) # 13. run beam search result = self._constrained_beam_search( input_ids, constrained_beam_scorer=constrained_beam_scorer, logits_processor=prepared_logits_processor, stopping_criteria=prepared_stopping_criteria, generation_config=generation_config, synced_gpus=synced_gpus, lazy_mode=lazy_mode, profiling_warmup_steps=profiling_warmup_steps, profiling_steps=profiling_steps, hb_gen_time=hb_gen_time, profiling_record_shapes=profiling_record_shapes, **model_kwargs, ) # Convert to legacy cache format if requested if ( generation_config.return_legacy_cache is True and hasattr(result, "past_key_values") and getattr(result.past_key_values, "to_legacy_cache") is not None ): result.past_key_values = result.past_key_values.to_legacy_cache() return result def _dola_decoding( self, input_ids: torch.LongTensor, dola_layers: Union[str, List[int]], logits_processor: LogitsProcessorList, stopping_criteria: StoppingCriteriaList, generation_config: GaudiGenerationConfig, synced_gpus: bool, streamer: "BaseStreamer", **model_kwargs, ) -> Union[GenerateNonBeamOutput, torch.LongTensor]: r""" Generates sequences of token ids for models with a language modeling head using **dola decoding** and can be used for decoder-only text models. The method is based on the paper "DoLa: Decoding by Contrasting Layers Improves Factuality in Large Language Models" (https://arxiv.org/abs/2309.03883) in ICLR 2024. Parameters: input_ids (`torch.LongTensor` of shape `(batch_size, sequence_length)`): The sequence used as a prompt for the generation. dola_layers (`Union[str, List[int]]`): The candidate layers used in contrasting layers of DoLa. It can be either 1) 'low' or 'high', which means the lower part or higher part of the model layers, respectively, or 2) a list of layer indices to be used for candidate layers. The 0-th layer is the word embedding layer of the model. logits_processor (`LogitsProcessorList`): An instance of [`LogitsProcessorList`]. List of instances of class derived from [`LogitsProcessor`] used to modify the prediction scores of the language modeling head applied at each generation step. stopping_criteria (`StoppingCriteriaList`, *optional*): An instance of [`StoppingCriteriaList`]. List of instances of class derived from [`StoppingCriteria`] used to tell if the generation loop should stop. generation_config ([`~generation.GenerationConfig`]): The generation configuration to be used as parametrization of the decoding method. synced_gpus (`bool`): Whether to continue running the while loop until max_length (needed to avoid deadlocking with `FullyShardedDataParallel` and DeepSpeed ZeRO Stage 3). streamer (`BaseStreamer`, *optional*): Streamer object that will be used to stream the generated sequences. Generated tokens are passed through `streamer.put(token_ids)` and the streamer is responsible for any further processing. model_kwargs: Additional model specific keyword arguments will be forwarded to the `forward` function of the model. If model is an encoder-decoder model the kwargs should include `encoder_outputs`. Return: [`~generation.GenerateDecoderOnlyOutput`], [`~generation.GenerateEncoderDecoderOutput`] or `torch.LongTensor`: A `torch.LongTensor` containing the generated tokens (default behaviour) or a [`~generation.GenerateDecoderOnlyOutput`] if `model.config.is_encoder_decoder=False` and `return_dict_in_generate=True` or a [`~generation.GenerateEncoderDecoderOutput`] if `model.config.is_encoder_decoder=True`. """ raise NotImplementedError("Dola decoding is not supported by optimum-habana yet.") @torch.no_grad() def _contrastive_search( self, input_ids: torch.LongTensor, logits_processor: LogitsProcessorList, stopping_criteria: StoppingCriteriaList, generation_config: GaudiGenerationConfig, synced_gpus: bool, streamer: Optional["BaseStreamer"], lazy_mode: Optional[bool] = False, ignore_eos: Optional[bool] = False, profiling_warmup_steps: Optional[int] = 0, profiling_steps: Optional[int] = 0, hb_gen_time: Optional[HabanaGenerationTime] = None, profiling_record_shapes: Optional[bool] = False, **model_kwargs, ) -> Union[GenerateNonBeamOutput, torch.LongTensor]: r""" Generates sequences of token ids for models with a language modeling head using **contrastive search** and can be used for text-decoder, text-to-text, speech-to-text, and vision-to-text models. Adapted from: https://github.com/huggingface/transformers/blob/v4.43.3/src/transformers/generation/utils.py#L2453 The changes are: - support lazy mode and HPU graphs on Gaudi - support static shapes and bucketing Parameters: input_ids (`torch.LongTensor` of shape `(batch_size, sequence_length)`): The sequence used as a prompt for the generation. logits_processor (`LogitsProcessorList`): An instance of [`LogitsProcessorList`]. List of instances of class derived from [`LogitsProcessor`] used to modify the prediction scores of the language modeling head applied at each generation step. stopping_criteria (`StoppingCriteriaList`): An instance of [`StoppingCriteriaList`]. List of instances of class derived from [`StoppingCriteria`] used to tell if the generation loop should stop. generation_config ([`~generation.GenerationConfig`]): The generation configuration to be used as parametrization of the decoding method. synced_gpus (`bool`): Whether to continue running the while loop until max_length (needed to avoid deadlocking with `FullyShardedDataParallel` and DeepSpeed ZeRO Stage 3). streamer (`BaseStreamer`, *optional*): Streamer object that will be used to stream the generated sequences. Generated tokens are passed through `streamer.put(token_ids)` and the streamer is responsible for any further processing. lazy_mode (`bool`, *optional*, defaults to `False`): Whether the run is executed in lazy mode or not (i.e. eager mode). ignore_eos (`bool`, *optional*, defaults to `False`): Whether to ignore finished sequences (faster in lazy mode and with HPU graphs) or not (eager mode). profiling_warmup_steps (`int`, *optional*, defaults to 0): Number of steps to ignore for profling. profiling_steps (`int`, *optional*, defaults to 0): Number of steps to be captured when enabling profiling. profiling_record_shapes (`bool`, *optional*, defaults to False): Record shapes when enabling profiling. model_kwargs: Additional model specific keyword arguments will be forwarded to the `forward` function of the model. If model is an encoder-decoder model the kwargs should include `encoder_outputs`. Return: [`transformers.generation.GenerateDecoderOnlyOutput`], [`transformers.generation.GenerateEncoderDecoderOutput`] or `torch.LongTensor`: A `torch.LongTensor` containing the generated tokens (default behaviour) or a [`transformers.generation.GenerateDecoderOnlyOutput`] if `model.config.is_encoder_decoder=False` and `return_dict_in_generate=True` or a [`transformers.generation.GenerateEncoderDecoderOutput`] if `model.config.is_encoder_decoder=True`. """ # init values has_eos_stopping_criteria = any(hasattr(criteria, "eos_token_id") for criteria in stopping_criteria) top_k = generation_config.top_k penalty_alpha = generation_config.penalty_alpha pad_token_id = generation_config._pad_token_tensor output_attentions = generation_config.output_attentions output_hidden_states = generation_config.output_hidden_states output_scores = generation_config.output_scores output_logits = generation_config.output_logits return_dict_in_generate = generation_config.return_dict_in_generate sequential = generation_config.low_memory # init attention / hidden states / scores tuples raw_logits = () if (return_dict_in_generate and output_logits) else None scores = () if (return_dict_in_generate and output_scores) else None decoder_attentions = () if (return_dict_in_generate and output_attentions) else None cross_attentions = () if (return_dict_in_generate and output_attentions) else None decoder_hidden_states = () if (return_dict_in_generate and output_hidden_states) else None # if model is an encoder-decoder, retrieve encoder attention weights and hidden states if return_dict_in_generate and self.config.is_encoder_decoder: encoder_attentions = model_kwargs["encoder_outputs"].get("attentions") if output_attentions else None encoder_hidden_states = ( model_kwargs["encoder_outputs"].get("hidden_states") if output_hidden_states else None ) # keep track of which sequences are already finished batch_size, cur_len = input_ids.shape if not ignore_eos: unfinished_sequences = torch.ones(batch_size, dtype=torch.long, device=input_ids.device) model_kwargs["cache_position"] = torch.arange(cur_len, device=input_ids.device) this_peer_finished = False hb_profer = HabanaProfile( warmup=profiling_warmup_steps, active=profiling_steps, record_shapes=profiling_record_shapes ) hb_profer.start() bucket_size = model_kwargs.get("bucket_size", -1) prev_idx = -1 # avoiding calculate cache_idx when its value is not changing bucket_internal = model_kwargs.get("bucket_internal", None) reduce_recompile = model_kwargs.get("reduce_recompile", False) if not bucket_internal: if bucket_size >= 0: inc = iter(incrementor(bucket_size, cur_len)) if bucket_size > 0: assert "position_ids" not in model_kwargs, "Untested path" token_idx = model_kwargs.get("token_idx", None) top_k_ids = None if token_idx is not None: # Update cur_len in case of static shapes cur_len = (token_idx + model_kwargs.get("inputs_embeds_offset", 0)).item() time_to_first_token_done = False model_kwargs["pad_done"] = False model_kwargs["mqa_model"] = False model_kwargs["lazy_mode"] = lazy_mode batch_indices = torch.arange(batch_size, device=input_ids.device) while self._has_unfinished_sequences(this_peer_finished, synced_gpus, device=input_ids.device): if lazy_mode: self.htcore_generation.mark_step() if bucket_size > 0 and not bucket_internal: # it will not have been padded if bucket_size > 0 params = next(inc) input_ids, model_kwargs = self.update_model_kwargs_for_bucketing( params, input_ids, model_kwargs, pad_token_id, bucket_size, reduce_recompile ) # if the first step in the loop, encode all the prefix and obtain: (1) past_key_values; # (2) last_hidden_states; (3) logit_for_next_step; (4) update model kwargs for the next step if model_kwargs.get("past_key_values") is None or ( isinstance(model_kwargs["past_key_values"], (Cache, EncoderDecoderCache)) and model_kwargs["past_key_values"].get_seq_length() == 0 ): # prepare inputs model_kwargs["use_cache"] = True model_inputs = self.prepare_inputs_for_generation(input_ids, **model_kwargs) hpu_graphs_kwargs = self._get_hpu_graphs_kwargs(model_kwargs) # encode the given prefix and prepare model inputs; encoder-decoder model process the prefix and save # the `encoder_outputs` outputs = self( **model_inputs, return_dict=True, output_hidden_states=True, output_attentions=output_attentions, **hpu_graphs_kwargs, ) # last decoder hidden states will be used to compute the degeneration penalty (cosine similarity with # previous tokens) if self.config.is_encoder_decoder: last_hidden_states = outputs.decoder_hidden_states[-1] else: last_hidden_states = outputs.hidden_states[-1] # next logit for contrastive search to select top-k candidate tokens token_idx = model_kwargs.get("token_idx", None) if token_idx is not None and outputs.logits.shape[-2] > 1: last_hidden_states = last_hidden_states[:, :token_idx, :] # case1 (w/o KV caching): outputs.logits.shape: [batch_size, max_length, vocab_size] if self.config.is_encoder_decoder: logit_for_next_step = outputs.logits[:, token_idx - 1, :] else: logit_for_next_step = torch.index_select(outputs.logits, -2, token_idx - 1).squeeze(-2) else: logit_for_next_step = outputs.logits[:, -1, :] # torch.float32 is needed to retain precision for later logits manipulations logit_for_next_step = logit_for_next_step.to(copy=True, dtype=torch.float32, device=input_ids.device) model_kwargs = self._update_model_kwargs_for_generation( outputs, model_kwargs, is_encoder_decoder=self.config.is_encoder_decoder, ) if not sequential: # Expands model inputs top_k times, for batched forward passes (akin to beam search). # input_ids is required for expanding visual inputs in qwen2vl _, model_kwargs = self._expand_inputs_for_generation( input_ids=input_ids, expand_size=top_k, is_encoder_decoder=self.config.is_encoder_decoder, **model_kwargs, ) past_key_values = model_kwargs.get("past_key_values") if past_key_values is None: raise ValueError( f"{self.__class__.__name__} does not support caching and therefore **can't** be used " "for contrastive search." ) elif ( ( not isinstance(past_key_values[0], (tuple, torch.Tensor)) and not isinstance(past_key_values[0], (list, torch.Tensor)) ) # Added list type to support GaudiLlamaForCausalLM or past_key_values[0][0].shape[0] != batch_size ): raise ValueError( f"{self.__class__.__name__} does not have a standard cache format and therefore **can't** be " "used for contrastive search without further modifications." ) if lazy_mode: self.htcore_generation.mark_step() # contrastive_search main logic start: # contrastive search decoding consists of two steps: (1) candidate tokens recall; (2) candidate re-rank by # degeneration penalty if token_idx is not None and self.config.is_encoder_decoder: processed_logit_for_next_step = logits_processor(input_ids[:, :token_idx], logit_for_next_step) else: processed_logit_for_next_step = logits_processor(input_ids, logit_for_next_step) next_probs = torch.nn.functional.softmax(processed_logit_for_next_step, dim=-1) if token_idx is not None: if top_k_ids is None: top_k_ids = torch.full( (batch_size, top_k, input_ids.shape[-1]), pad_token_id, dtype=torch.int64 ).to(input_ids.device) elif bucket_size > 0 and not bucket_internal: if input_ids.shape[-1] > top_k_ids.shape[-1]: # needs expansion pad_amount = input_ids.shape[-1] - top_k_ids.shape[-1] top_k_ids = torch.nn.functional.pad(top_k_ids, (0, pad_amount), value=pad_token_id) idx = token_idx + model_kwargs.get("inputs_embeds_offset", 0) - 1 top_k_probs, top_k_prob_ids = torch.topk(next_probs, dim=-1, k=top_k) top_k_ids[:, :, idx] = top_k_prob_ids else: top_k_probs, top_k_ids = torch.topk(next_probs, dim=-1, k=top_k) # Store scores, attentions and hidden_states when required if return_dict_in_generate: if output_logits: raw_logits += (logit_for_next_step,) if output_scores: scores += (processed_logit_for_next_step,) if output_attentions: decoder_attentions += ( (outputs.decoder_attentions,) if self.config.is_encoder_decoder else (outputs.attentions,) ) if self.config.is_encoder_decoder: cross_attentions += (outputs.cross_attentions,) if output_hidden_states: decoder_hidden_states += ( (outputs.decoder_hidden_states,) if self.config.is_encoder_decoder else (outputs.hidden_states,) ) # This is needed to properly delete outputs.logits which may be very large for this first iteration # Otherwise a reference to outputs.logits is kept all along until after the next call to self.forward() del outputs if not sequential: # Replicates the new past_key_values to match the `top_k` candidates past = model_kwargs["past_key_values"] # If it is a static cache, modify it in-place layer after layer to save memory if isinstance(past, DynamicCache) or ( isinstance(past, EncoderDecoderCache) and isinstance(past.self_attention_cache, DynamicCache) ): past.batch_repeat_interleave(top_k) else: new_key_values = [] for layer in past: items = [] # item is either the key or the value matrix for item in layer: items.append(item.repeat_interleave(top_k, dim=0)) new_key_values.append(tuple(items)) past = tuple(new_key_values) model_kwargs["past_key_values"] = past if sequential: all_outputs = [] for i in range(top_k): # compute the candidate tokens by the language model and collect their hidden_states if token_idx is not None: next_model_inputs = self.prepare_inputs_for_generation( top_k_ids[:, i, :].view(-1, input_ids.shape[-1]), **model_kwargs ) else: next_model_inputs = self.prepare_inputs_for_generation( top_k_ids[:, i].view(-1, 1), **model_kwargs ) outputs = self( **next_model_inputs, return_dict=True, output_hidden_states=True, output_attentions=output_attentions, ) if isinstance(outputs["past_key_values"], DynamicCache) or ( isinstance(outputs["past_key_values"], EncoderDecoderCache) and isinstance(outputs["past_key_values"].self_attention_cache, DynamicCache) ): # Remove past K-V from output since we don't need to stack later outputs["past_key_values"] = None # Remove last token from past K-V since we don't want to append it at this point model_kwargs["past_key_values"].crop(-1) all_outputs.append(outputs) outputs = stack_model_outputs(all_outputs, self.config.get_text_config()) else: # compute the candidate tokens by the language model and collect their hidden_states # assembles top_k_ids into batch of size k if token_idx is not None: next_model_inputs = self.prepare_inputs_for_generation( top_k_ids.view(-1, input_ids.shape[-1]), **model_kwargs ) else: next_model_inputs = self.prepare_inputs_for_generation(top_k_ids.view(-1, 1), **model_kwargs) outputs = self( **next_model_inputs, return_dict=True, output_hidden_states=True, output_attentions=output_attentions, ) # This is essential to avoid having a last reference to the big past K-V and double the necessary memory # in the next loop del next_model_inputs # name is different for encoder-decoder and decoder-only models if self.config.is_encoder_decoder: next_hidden = outputs.decoder_hidden_states[-1] full_hidden_states = outputs.decoder_hidden_states else: next_hidden = outputs.hidden_states[-1] full_hidden_states = outputs.hidden_states # .float() is needed to retain precision for later logits manipulations logits = outputs.logits[:, -1, :].float() context_hidden = last_hidden_states.repeat_interleave(top_k, dim=0) # compute the degeneration penalty and re-rank the candidates based on the degeneration penalty and the # model confidence. Keeping `selected_idx` on CPU enables multi-device contrastive search and doesn't # introduce (noticeable) slowdowns on single-device runs. selected_idx = _ranking_fast(context_hidden, next_hidden, top_k_probs, penalty_alpha, top_k) # This will be used instead of the previous inneficient torch.stack(torch.split()) augmented_idx = torch.tensor( [x + i * top_k for i, x in enumerate(selected_idx)], device=selected_idx.device ) # prepare for the next step: (1) next token_id; (2) past_key_values; (3) last_hidden_states for computing # the degeneration penalty; (4) logits for selecting next top-k candidates; (5) selected tokens scores # (model confidence minus degeneration penalty); (6) decoder hidden_states top_k_indices = torch.arange(len(top_k_ids), device=input_ids.device) if token_idx is not None: idx = token_idx + model_kwargs.get("inputs_embeds_offset", 0) - 1 next_tokens = top_k_ids[top_k_indices, selected_idx, idx] else: next_tokens = top_k_ids[top_k_indices, selected_idx] next_hidden = torch.stack(torch.split(next_hidden.squeeze(dim=1), top_k)) next_hidden = next_hidden[batch_indices, selected_idx, :] last_hidden_states = torch.cat([last_hidden_states, next_hidden.unsqueeze(1)], dim=1) next_decoder_hidden_states = () for layer in full_hidden_states: layer = torch.stack(torch.split(layer, top_k))[batch_indices, selected_idx, :] next_decoder_hidden_states += (layer,) # generate past_key_values cache of only the selected token if sequential: if token_idx is not None: next_model_input = self.prepare_inputs_for_generation( top_k_ids[:, selected_idx, :].view(-1, input_ids.shape[-1]), **model_kwargs ) else: next_model_input = self.prepare_inputs_for_generation( top_k_ids[:, selected_idx].view(-1, 1), **model_kwargs ) selected_outputs = self( **next_model_input, return_dict=True, output_hidden_states=False, output_attentions=False, ) next_past_key_values = selected_outputs["past_key_values"] else: next_past_key_values = None for possible_cache_name in ALL_CACHE_NAMES: next_past_key_values = next_past_key_values or getattr(outputs, possible_cache_name, None) # Do it in-place layer per layer to save memory if isinstance(next_past_key_values, DynamicCache) or ( isinstance(next_past_key_values, EncoderDecoderCache) and isinstance(next_past_key_values.self_attention_cache, DynamicCache) ): next_past_key_values.batch_select_indices(augmented_idx) else: new_key_values = [] for layer in next_past_key_values: items = [] # item is either the key or the value matrix for item in layer: items.append(item[augmented_idx, ...]) new_key_values.append(tuple(items)) next_past_key_values = tuple(new_key_values) logit_for_next_step = torch.stack(torch.split(logits, top_k))[batch_indices, selected_idx, :] logit_for_next_step = logit_for_next_step.to(input_ids.device) # Rebuilds the relevant parts of the model output for the selected token, for use in the next iteration if self.config.is_encoder_decoder: next_step_cross_attentions = () next_step_decoder_attentions = () if output_attentions: for layer in outputs.cross_attentions: layer = torch.stack(torch.split(layer, top_k, dim=0))[batch_indices, selected_idx, ...] next_step_cross_attentions += (layer,) for layer in outputs.decoder_attentions: layer = torch.stack(torch.split(layer, top_k, dim=0))[batch_indices, selected_idx, ...] next_step_decoder_attentions += (layer,) outputs = Seq2SeqLMOutput( past_key_values=next_past_key_values, decoder_hidden_states=next_decoder_hidden_states, decoder_attentions=next_step_decoder_attentions or None, cross_attentions=next_step_cross_attentions or None, ) else: next_step_attentions = () if output_attentions: for layer in outputs.attentions: layer = torch.stack(torch.split(layer, top_k, dim=0))[batch_indices, selected_idx, ...] next_step_attentions += (layer,) outputs = CausalLMOutputWithPast( past_key_values=next_past_key_values, hidden_states=next_decoder_hidden_states, attentions=next_step_attentions or None, ) # contrastive_search main logic end if synced_gpus and this_peer_finished: continue # finished sentences should have their next token be a padding token if not ignore_eos and has_eos_stopping_criteria: next_tokens = next_tokens * unfinished_sequences + pad_token_id * (1 - unfinished_sequences) # update generated ids, model inputs, and length for next step if token_idx is not None: # Use token_idx-1 since token index is incremented twice in first iteration idx = token_idx + model_kwargs.get("inputs_embeds_offset", 0) - 1 input_ids.index_copy_(1, idx, next_tokens.unsqueeze(-1) if next_tokens.dim() == 1 else next_tokens) else: input_ids = torch.cat([input_ids, next_tokens[:, None]], dim=-1) if streamer is not None: streamer.put(next_tokens.cpu()) model_kwargs = self._update_model_kwargs_for_generation( outputs, model_kwargs, is_encoder_decoder=self.config.is_encoder_decoder, ) # increase cur_len cur_len = cur_len + 1 if bucket_size > 0 and bucket_internal: # Calculate slice idx for kv cache during the decode phase. # Breaking down the kv cache in the attention block helps to reduce computation time. if model_kwargs.get("token_idx_cpu") <= (model_kwargs["kv_cache_len"] // bucket_size) * bucket_size: idx = (model_kwargs.get("token_idx_cpu") - 1) // bucket_size if prev_idx != idx: model_kwargs["cache_idx"] = (idx + 1) * bucket_size prev_idx = idx else: model_kwargs["cache_idx"] = model_kwargs["kv_cache_len"] # stop when each sentence is finished if ignore_eos: this_peer_finished = stopping_criteria( input_ids, scores, token_idx=cur_len, ignore_eos=ignore_eos, eos_token_id=generation_config.eos_token_id, ) else: unfinished_sequences = unfinished_sequences & ~stopping_criteria( input_ids, scores, token_idx=cur_len, ignore_eos=ignore_eos, eos_token_id=generation_config.eos_token_id, ) this_peer_finished = unfinished_sequences.max() == 0 if ( not model_kwargs.get("pad_done", False) and not model_kwargs.get("reuse_cache", False) and bucket_internal ): # Pad the returned past key values tensors from prefill phase forward run to maximum length # before starting the decode phase. is_mqa_model = self.config.model_type == "gpt_bigcode" and self.config.multi_query model_kwargs["mqa_model"] = is_mqa_model if is_mqa_model: do_padding = outputs.past_key_values[0].shape[1] == model_inputs["input_ids"].shape[1] else: key_to_check = ( "input_ids" if "input_ids" in model_inputs else "inputs_embeds" if "inputs_embeds" in model_inputs else None ) do_padding = ( key_to_check is not None and outputs.past_key_values[0][0].shape[2] == model_inputs[key_to_check].shape[1] ) if do_padding: self._pad_past_key_values(model_kwargs) model_kwargs["pad_done"] = True if hb_gen_time is not None: if not time_to_first_token_done: time_to_first_token_done = True import habana_frameworks.torch.hpu as torch_hpu torch_hpu.synchronize() hb_gen_time.step() hb_profer.step() if ( model_kwargs.get("use_hpu_graphs", False) and model_kwargs.get("limit_hpu_graphs", False) and not model_kwargs.get("reuse_cache", False) and bucket_internal ): # Clear HPU graphs input tensors of the decode phase after the full generation while loop self.clear_inputs() # Delete past key value tensors self._remove_past_key_values(model_kwargs) hb_profer.stop() if streamer is not None: streamer.end() if return_dict_in_generate: # Contrastive search works by forward looking at the next token, so we need to exclude it from # `past_key_values` to be consistent with the other decoding methods if model_kwargs.get("past_key_values") is not None: if isinstance(model_kwargs["past_key_values"], DynamicCache) or ( isinstance(model_kwargs["past_key_values"], EncoderDecoderCache) and isinstance(model_kwargs["past_key_values"].self_attention_cache, DynamicCache) ): model_kwargs["past_key_values"].crop(-1) else: past_key_values = [] for layer in model_kwargs["past_key_values"]: layer_past_key_values = [] for item in layer: layer_past_key_values.append(item[..., :-1, :]) past_key_values.append(tuple(layer_past_key_values)) model_kwargs["past_key_values"] = tuple(past_key_values) if self.config.is_encoder_decoder: return GenerateEncoderDecoderOutput( sequences=input_ids, scores=scores, logits=raw_logits, encoder_attentions=encoder_attentions, encoder_hidden_states=encoder_hidden_states, decoder_attentions=decoder_attentions, cross_attentions=cross_attentions, decoder_hidden_states=decoder_hidden_states, past_key_values=model_kwargs.get("past_key_values"), ) else: return GenerateDecoderOnlyOutput( sequences=input_ids, scores=scores, logits=raw_logits, attentions=decoder_attentions, hidden_states=decoder_hidden_states, past_key_values=model_kwargs.get("past_key_values"), ) else: return input_ids def _sample( self, input_ids: torch.LongTensor, logits_processor: LogitsProcessorList, stopping_criteria: StoppingCriteriaList, generation_config: GaudiGenerationConfig, synced_gpus: bool, streamer: Optional["BaseStreamer"], lazy_mode: Optional[bool] = False, ignore_eos: Optional[bool] = False, profiling_warmup_steps: Optional[int] = 0, profiling_steps: Optional[int] = 0, hb_gen_time: Optional[HabanaGenerationTime] = None, profiling_record_shapes: Optional[bool] = False, **model_kwargs, ) -> Union[GenerateNonBeamOutput, torch.LongTensor]: r""" Generates sequences of token ids for models with a language modeling head using **multinomial sampling** and can be used for text-decoder, text-to-text, speech-to-text, and vision-to-text models. Parameters: input_ids (`torch.LongTensor` of shape `(batch_size, sequence_length)`): The sequence used as a prompt for the generation. logits_processor (`LogitsProcessorList`): An instance of [`LogitsProcessorList`]. List of instances of class derived from [`LogitsProcessor`] used to modify the prediction scores of the language modeling head applied at each generation step. stopping_criteria (`StoppingCriteriaList`): An instance of [`StoppingCriteriaList`]. List of instances of class derived from [`StoppingCriteria`] used to tell if the generation loop should stop. generation_config ([`GaudiGenerationConfig`]): The generation configuration to be used as parametrization of the decoding method. synced_gpus (`bool`): Whether to continue running the while loop until max_length (needed to avoid deadlocking with `FullyShardedDataParallel` and DeepSpeed ZeRO Stage 3). streamer (`BaseStreamer`, *optional*): Streamer object that will be used to stream the generated sequences. Generated tokens are passed through `streamer.put(token_ids)` and the streamer is responsible for any further processing. lazy_mode (`bool`, *optional*, defaults to `False`): Whether the run is executed in lazy mode or not (i.e. eager mode). ignore_eos (`bool`, *optional*, defaults to `False`): Whether to ignore finished sequences (faster in lazy mode and with HPU graphs) or not (eager mode). profiling_warmup_steps (`int`, *optional*, defaults to 0): Number of steps to ignore for profling. profiling_steps (`int`, *optional*, defaults to 0): Number of steps to be captured when enabling profiling. profiling_record_shapes (`bool`, *optional*, defaults to False): Record shapes when enabling profiling. model_kwargs: Additional model specific kwargs will be forwarded to the `forward` function of the model. If model is an encoder-decoder model the kwargs should include `encoder_outputs`. Return: [`transformers.generation.GenerateDecoderOnlyOutput`], [`transformers.generation.GenerateEncoderDecoderOutput`] or `torch.LongTensor`: A `torch.LongTensor` containing the generated tokens (default behaviour) or a [`transformers.generation.GenerateDecoderOnlyOutput`] if `model.config.is_encoder_decoder=False` and `return_dict_in_generate=True` or a [`transformers.generation.GenerateEncoderDecoderOutput`] if `model.config.is_encoder_decoder=True`. """ # init values pad_token_id = generation_config._pad_token_tensor output_attentions = generation_config.output_attentions output_hidden_states = generation_config.output_hidden_states output_scores = generation_config.output_scores output_logits = generation_config.output_logits return_dict_in_generate = generation_config.return_dict_in_generate has_eos_stopping_criteria = any(hasattr(criteria, "eos_token_id") for criteria in stopping_criteria) do_sample = generation_config.do_sample # init attention / hidden states / scores tuples scores = () if (return_dict_in_generate and output_scores) else None raw_logits = () if (return_dict_in_generate and output_logits) else None decoder_attentions = () if (return_dict_in_generate and output_attentions) else None cross_attentions = () if (return_dict_in_generate and output_attentions) else None decoder_hidden_states = () if (return_dict_in_generate and output_hidden_states) else None # if model is an encoder-decoder, retrieve encoder attention weights and hidden states if return_dict_in_generate and self.config.is_encoder_decoder: encoder_attentions = model_kwargs["encoder_outputs"].get("attentions") if output_attentions else None encoder_hidden_states = ( model_kwargs["encoder_outputs"].get("hidden_states") if output_hidden_states else None ) # keep track of which sequences are already finished batch_size, cur_len = input_ids.shape this_peer_finished = False if not ignore_eos: unfinished_sequences = torch.ones(batch_size, dtype=torch.long, device=input_ids.device) model_kwargs = self._get_initial_cache_position(input_ids, model_kwargs) bucket_size = model_kwargs.get("bucket_size", -1) prev_idx = -1 # avoiding calculate cache_idx when its value is not changing bucket_internal = model_kwargs.get("bucket_internal", None) reduce_recompile = model_kwargs.get("reduce_recompile", False) hb_profer = HabanaProfile( warmup=profiling_warmup_steps, active=profiling_steps, record_shapes=profiling_record_shapes ) hb_profer.start() if not bucket_internal: if bucket_size >= 0: inc = iter(incrementor(bucket_size, cur_len)) if bucket_size > 0: assert "position_ids" not in model_kwargs, "Untested path" token_idx = model_kwargs.get("token_idx", None) start_token_idx = cur_len if token_idx is not None: # Update cur_len in case of static shapes cur_len = (token_idx + model_kwargs.get("inputs_embeds_offset", 0)).item() start_token_idx = token_idx time_to_first_token_done = False model_kwargs["pad_done"] = False model_kwargs["mqa_model"] = False model_kwargs["lazy_mode"] = lazy_mode while self._has_unfinished_sequences(this_peer_finished, synced_gpus, device=input_ids.device): if lazy_mode: self.htcore_generation.mark_step() if bucket_size > 0 and not bucket_internal: # it will not have been padded if bucket_size > 0 params = next(inc) input_ids, model_kwargs = self.update_model_kwargs_for_bucketing( params, input_ids, model_kwargs, pad_token_id, bucket_size, reduce_recompile ) # prepare model inputs model_inputs = self.prepare_inputs_for_generation(input_ids, **model_kwargs) # prepare variable output controls (note: some models won't accept all output controls) model_inputs.update({"output_attentions": output_attentions} if output_attentions else {}) model_inputs.update({"output_hidden_states": output_hidden_states} if output_hidden_states else {}) hpu_graphs_kwargs = self._get_hpu_graphs_kwargs(model_kwargs) # forward pass to get next token outputs = self( **model_inputs, return_dict=True, **hpu_graphs_kwargs, ) # synced_gpus: don't waste resources running the code we don't need if synced_gpus and this_peer_finished: continue token_idx = model_kwargs.get("token_idx", None) if token_idx is not None and outputs.logits.shape[-2] > 1: # case1 (w/o KV caching): outputs.logits.shape: [batch_size, max_length, vocab_size] if self.config.is_encoder_decoder: next_token_logits = outputs.logits[:, token_idx - 1, :].float() next_token_logits = next_token_logits.to(input_ids.device) next_token_scores = logits_processor(input_ids[:, :token_idx], next_token_logits) else: if model_kwargs.get("num_virtual_tokens", 0) > 0: # for prompt tuning, the output logit shape > model_inputs["input_ids"].shape[-1] if model_kwargs.get("reuse_cache", False): output_idx = torch.tensor(outputs.logits.shape[-2], device=input_ids.device) else: output_idx = token_idx + outputs.logits.shape[-2] - input_ids.shape[-1] next_token_logits = torch.index_select(outputs.logits, -2, output_idx - 1).squeeze(-2).float() else: next_token_logits = torch.index_select(outputs.logits, -2, token_idx - 1).squeeze(-2).float() next_token_logits = next_token_logits.to(input_ids.device) next_token_scores = logits_processor(input_ids, next_token_logits) else: # .float() is needed to retain precision for later logits manipulations next_token_logits = outputs.logits[:, -1, :].float() next_token_logits = next_token_logits.to(input_ids.device) if token_idx is not None and self.config.is_encoder_decoder: # case2 (with KV caching): outputs.logits.shape: [batch_size, 1, vocab_size] next_token_scores = logits_processor(input_ids[:, :token_idx], next_token_logits) else: # case3 (default case): token_idx is None next_token_scores = logits_processor(input_ids, next_token_logits) # Store scores, attentions and hidden_states when required if return_dict_in_generate: if output_scores: scores += (next_token_scores,) if output_logits: raw_logits += (next_token_logits,) if output_attentions: decoder_attentions += ( (outputs.decoder_attentions,) if self.config.is_encoder_decoder else (outputs.attentions,) ) if self.config.is_encoder_decoder: cross_attentions += (outputs.cross_attentions,) if output_hidden_states: decoder_hidden_states += ( (outputs.decoder_hidden_states,) if self.config.is_encoder_decoder else (outputs.hidden_states,) ) # token selection if do_sample: # Workaround on HPU for output quality issues with torch.multinomial for lower precision models # Distribution sampled by torch.multinomial may be affected by next_token_logits upcast to float probs = torch.nn.functional.softmax(next_token_scores, dim=-1).to(outputs.logits.dtype) # TODO (joao): this OP throws "skipping cudagraphs due to ['incompatible ops']", find solution next_tokens = torch.multinomial(probs, num_samples=1).squeeze(1) else: next_tokens = torch.argmax(next_token_scores, dim=-1) # finished sentences should have their next token be a padding token # TODO: no ignore_eos check here since there is a compilation error, will add ignore_eos here if fixed if has_eos_stopping_criteria: next_tokens = next_tokens * unfinished_sequences + pad_token_id * (1 - unfinished_sequences) # update generated ids, model inputs, and length for next step if not lazy_mode: next_tokens = next_tokens.to(input_ids.dtype) if token_idx is not None: idx = token_idx + model_kwargs.get("inputs_embeds_offset", 0) input_ids.index_copy_(1, idx, next_tokens.unsqueeze(-1) if next_tokens.dim() == 1 else next_tokens) else: input_ids = torch.cat([input_ids, next_tokens[:, None]], dim=-1) if streamer is not None: streamer.put(next_tokens.cpu()) model_kwargs = self._update_model_kwargs_for_generation( outputs, model_kwargs, is_encoder_decoder=self.config.is_encoder_decoder, ) cur_len = cur_len + 1 if bucket_size > 0 and bucket_internal: # Calculate slice idx for kv cache during the decode phase. # Breaking down the kv cache in the attention block helps to reduce computation time. if model_kwargs.get("token_idx_cpu") <= (model_kwargs["kv_cache_len"] // bucket_size) * bucket_size: idx = (model_kwargs.get("token_idx_cpu") - 1) // bucket_size if prev_idx != idx: model_kwargs["cache_idx"] = (idx + 1) * bucket_size prev_idx = idx else: model_kwargs["cache_idx"] = model_kwargs["kv_cache_len"] if ignore_eos: this_peer_finished = stopping_criteria( input_ids, scores, token_idx=cur_len, ignore_eos=ignore_eos, eos_token_id=generation_config.eos_token_id, ) else: unfinished_sequences = unfinished_sequences & ~stopping_criteria( input_ids, scores, token_idx=cur_len, ignore_eos=ignore_eos, eos_token_id=generation_config.eos_token_id, ) this_peer_finished = unfinished_sequences.max() == 0 if hb_gen_time is not None: if not time_to_first_token_done: time_to_first_token_done = True import habana_frameworks.torch.hpu as torch_hpu torch_hpu.synchronize() hb_gen_time.step() hb_profer.step() if ( not model_kwargs.get("pad_done", False) and not model_kwargs.get("reuse_cache", False) and bucket_internal ): # Pad the returned past key values tensors from prefill phase forward run to maximum length # before starting the decode phase. is_mqa_model = self.config.model_type == "gpt_bigcode" and self.config.multi_query model_kwargs["mqa_model"] = is_mqa_model if is_mqa_model: do_padding = outputs.past_key_values[0].shape[1] == model_inputs["input_ids"].shape[1] else: key_to_check = ( "input_ids" if "input_ids" in model_inputs else "inputs_embeds" if "inputs_embeds" in model_inputs else None ) do_padding = ( key_to_check is not None and outputs.past_key_values[0][0].shape[2] == model_inputs[key_to_check].shape[1] ) if do_padding: self._pad_past_key_values(model_kwargs) model_kwargs["pad_done"] = True # This is needed to properly delete outputs.logits which may be very large for first iteration # Otherwise a reference to outputs is kept which keeps the logits alive in the next iteration del outputs if ( model_kwargs.get("use_hpu_graphs", False) and model_kwargs.get("limit_hpu_graphs", False) and not model_kwargs.get("reuse_cache", False) and bucket_internal ): # Clear HPU graphs cache if model_kwargs.get("clear_hpu_graphs_cache", False): self.clear_cache() # Clear HPU graphs input tensors of the decode phase after the full generation while loop else: self.clear_inputs() # Delete past key value tensors self._remove_past_key_values(model_kwargs) hb_profer.stop() if streamer is not None: streamer.end() if batch_size > 1 and has_eos_stopping_criteria: eos_token_id = generation_config.eos_token_id # Find the positions of the first eos_token_id in each sequence eos_positions = ( torch.isin(input_ids[:, start_token_idx:], torch.tensor(eos_token_id)).int().argmax(dim=1) + start_token_idx ) # Create a mask for positions greater than the first eos_token_id mask = torch.arange(generation_config.max_length, device="hpu").expand( batch_size, generation_config.max_length ) > eos_positions.unsqueeze(1) # Apply the mask to set positions greater than the first eos_token_id to pad_token_id input_ids[mask] = pad_token_id if return_dict_in_generate: if self.config.is_encoder_decoder: return GenerateEncoderDecoderOutput( sequences=input_ids, scores=scores, logits=raw_logits, encoder_attentions=encoder_attentions, encoder_hidden_states=encoder_hidden_states, decoder_attentions=decoder_attentions, cross_attentions=cross_attentions, decoder_hidden_states=decoder_hidden_states, past_key_values=model_kwargs.get("past_key_values"), ) else: return GenerateDecoderOnlyOutput( sequences=input_ids, scores=scores, logits=raw_logits, attentions=decoder_attentions, hidden_states=decoder_hidden_states, past_key_values=model_kwargs.get("past_key_values"), ) else: return input_ids def _beam_search( self, input_ids: torch.LongTensor, beam_scorer: BeamScorer, logits_processor: LogitsProcessorList, stopping_criteria: StoppingCriteriaList, generation_config: GaudiGenerationConfig, synced_gpus: bool, lazy_mode: Optional[bool] = False, profiling_warmup_steps: Optional[int] = 0, profiling_steps: Optional[int] = 0, hb_gen_time: Optional[HabanaGenerationTime] = None, profiling_record_shapes: Optional[bool] = False, **model_kwargs, ) -> Union[GenerateBeamOutput, torch.LongTensor]: r""" Generates sequences of token ids for models with a language modeling head using **beam search decoding** and can be used for text-decoder, text-to-text, speech-to-text, and vision-to-text models. If it's the first time you're diving into Beam Search, we recommend you read the following blog post: https://huggingface.co/blog/how-to-generate (especially the beam search section). You can recompute the sequence scores from the individual scores using the `compute_transition_scores` function (https://huggingface.co/docs/transformers/main_classes/text_generation#transformers.GenerationMixin.compute_transition_scores) Parameters: input_ids (`torch.LongTensor` of shape `(batch_size, sequence_length)`): The sequence used as a prompt for the generation. beam_scorer (`BeamScorer`): An derived instance of [`BeamScorer`] that defines how beam hypotheses are constructed, stored and sorted during generation. For more information, the documentation of [`BeamScorer`] should be read. logits_processor (`LogitsProcessorList`): An instance of [`LogitsProcessorList`]. List of instances of class derived from [`LogitsProcessor`] used to modify the prediction scores of the language modeling head applied at each generation step. stopping_criteria (`StoppingCriteriaList`: An instance of [`StoppingCriteriaList`]. List of instances of class derived from [`StoppingCriteria`] used to tell if the generation loop should stop. generation_config ([`GaudiGenerationConfig`]): The generation configuration to be used as parametrization of the decoding method. synced_gpus (`bool`): Whether to continue running the while loop until max_length (needed to avoid deadlocking with `FullyShardedDataParallel` and DeepSpeed ZeRO Stage 3). lazy_mode (`bool`, *optional*, defaults to `False`): Whether the run is executed in lazy mode or not (i.e. eager mode). profiling_warmup_steps (`int`, *optional*, defaults to 0): Number of steps to ignore for profling. profiling_steps (`int`, *optional*, defaults to 0): Number of steps to be captured when enabling profiling. profiling_record_shapes (`bool`, *optional*, defaults to False): Record shapes when enabling profiling. model_kwargs: Additional model specific kwargs will be forwarded to the `forward` function of the model. If model is an encoder-decoder model the kwargs should include `encoder_outputs`. Return: [`transformers.generation.utils.GenerateBeamDecoderOnlyOutput`], [`transformers.generation.GenerateBeamEncoderDecoderOutput`] or `torch.LongTensor`: A `torch.LongTensor` containing the generated tokens (default behaviour) or a [`transformers.generation.GenerateBeamDecoderOnlyOutput`] if `model.config.is_encoder_decoder=False` and `return_dict_in_generate=True` or a [`transformers.generation.GenerateBeamEncoderDecoderOutput`] if `model.config.is_encoder_decoder=True`. """ # 1. init beam_search values pad_token_id = generation_config._pad_token_tensor eos_token_id = generation_config._eos_token_tensor output_attentions = generation_config.output_attentions output_hidden_states = generation_config.output_hidden_states output_scores = generation_config.output_scores output_logits = generation_config.output_logits return_dict_in_generate = generation_config.return_dict_in_generate do_sample = generation_config.do_sample early_stopping = generation_config.early_stopping length_penalty = generation_config.length_penalty # max_length = generation_config.max_length num_beams = generation_config.num_beams # num_return_sequences = generation_config.num_return_sequences batch_size = len(beam_scorer._beam_hyps) num_beams = beam_scorer.num_beams batch_beam_size, cur_len = input_ids.shape if "inputs_embeds" in model_kwargs: cur_len = model_kwargs["inputs_embeds"].shape[1] token_idx = model_kwargs.get("token_idx", None) if token_idx is not None: # Update cur_len in case of static shapes cur_len = (token_idx + model_kwargs.get("inputs_embeds_offset", 0)).item() model_kwargs["cache_position"] = torch.arange(cur_len, device=input_ids.device) if num_beams * batch_size != batch_beam_size: raise ValueError( f"Batch dimension of `input_ids` should be {num_beams * batch_size}, but is {batch_beam_size}." ) # (joao) feature lost in the refactor. Probably won't implement, hurts readbility with minimal gains (there # are newer low-memory alternatives like the offloaded cache) sequential = generation_config.low_memory if sequential: raise ValueError( "`low_memory=True` is not supported after the beam search refactor. Please check the discussion in " "#35802 *after the PR got merged*, and add a comment there if your questions are not yet answered." ) # 2. init output tuples scores = () if (return_dict_in_generate and output_scores) else None raw_logits = () if (return_dict_in_generate and output_logits) else None beam_indices = ( tuple(() for _ in range(batch_beam_size)) if (return_dict_in_generate and output_scores) else None ) decoder_attentions = () if (return_dict_in_generate and output_attentions) else None cross_attentions = () if (return_dict_in_generate and output_attentions) else None decoder_hidden_states = () if (return_dict_in_generate and output_hidden_states) else None # if model is an encoder-decoder, retrieve encoder attention weights and hidden states if return_dict_in_generate and self.config.is_encoder_decoder: encoder_attentions = model_kwargs["encoder_outputs"].get("attentions") if output_attentions else None encoder_hidden_states = ( model_kwargs["encoder_outputs"].get("hidden_states") if output_hidden_states else None ) # initialise score of first beam with 0 and the rest with -1e9. This makes sure that only tokens # of the first beam are considered to avoid sampling the exact same tokens across all beams. beam_scores = torch.zeros((batch_size, num_beams), dtype=torch.float, device=input_ids.device) beam_scores[:, 1:] = -1e9 beam_scores = beam_scores.view((batch_size * num_beams,)) # Beam token selection: pick 1 + eos_token_id.shape[0] next tokens for each beam so we have at least 1 # non eos token per beam. n_eos_tokens = eos_token_id.shape[0] if eos_token_id is not None else 0 num_selection = max(2, 1 + n_eos_tokens) if self.generation_config.static_shapes: beam_trace_scores = torch.zeros( (input_ids.shape[1], num_selection * batch_size * num_beams), device=input_ids.device, dtype=torch.float32, ) beam_trace_indices = torch.zeros( (input_ids.shape[1], num_selection * batch_size * num_beams), device=input_ids.device, dtype=torch.int64, ) beam_trace_tokens = torch.zeros( (input_ids.shape[1], num_selection * batch_size * num_beams), device=input_ids.device, dtype=torch.int64, ) beam_trace_idx = torch.tensor(0, device=input_ids.device) num_eos_tokens = torch.zeros((1), device=input_ids.device, dtype=torch.int64) num_beams_tensor = torch.tensor(num_beams, device=input_ids.device, dtype=torch.int64) def finalize_beams(initial_ids, beam_trace, model_config, length_penalty): beam_trace_idx, beam_trace_scores, beam_trace_indices, beam_trace_tokens = beam_trace bs = initial_ids.shape[0] num_beams = beam_trace_scores.shape[1] // (num_selection * bs) beam_trace_idx = beam_trace_idx.item() beam_trace_scores = beam_trace_scores[:beam_trace_idx, :] beam_trace_indices = beam_trace_indices[:beam_trace_idx, :] beam_trace_tokens = beam_trace_tokens[:beam_trace_idx, :] # (score, parent_beam, token_id, is_finished) root = (float("-inf"), None, None, False) def resolve_beam(beam): rest = [] while beam != root: score, prev, tok, is_finished = beam rest.append(tok) beam = prev rest.reverse() return rest prev_beams = [[root] * num_beams] * bs best = [[] for _ in range(bs)] def beam_score(beam): return (beam[3], beam[0]) for step, (scores, indices, tokens) in enumerate( zip(beam_trace_scores, beam_trace_indices, beam_trace_tokens) ): cur_beams = [[] for _ in range(bs)] for idx, (s, i, t) in enumerate(zip(scores, indices, tokens)): batch = idx // (num_beams * num_selection) idx = idx % (num_beams * num_selection) b_len = 1 + step b_score = s.item() / (b_len**length_penalty) b_tok = t.item() is_finished = b_tok == model_config.eos_token_id if len(cur_beams[batch]) >= num_beams: continue beam = (b_score, prev_beams[batch][i], b_tok, is_finished) if not is_finished: cur_beams[batch].append(beam) if is_finished or (step + 1 == beam_trace_idx): if len(best[batch]) < num_beams: best[batch].append(beam) best[batch] = sorted(best[batch], key=lambda x: beam_score(x)) elif beam_score(best[batch][0]) < beam_score(beam): best[batch][0] = beam best[batch] = sorted(best[batch], key=lambda x: beam_score(x)) prev_beams = cur_beams def expand_if_needed(tensor, new_size, value, dim=-1): orig_len = tensor.shape[dim] padding_len = new_size - orig_len import torch.nn.functional as F if padding_len > 0: if dim == -1: return F.pad(tensor, (0, padding_len), value=value) elif dim == -2: return F.pad(tensor, (0, 0, 0, padding_len), value=value) else: assert False, f"Unsupported dim value: {dim}" return tensor results = [] for i, beam_hyp in enumerate(best): sorted_hyps = sorted(beam_hyp, key=lambda x: beam_score(x)) res = [] for j in range(beam_scorer.num_beam_hyps_to_keep): best_hyp_tuple = sorted_hyps.pop() resolve = resolve_beam(best_hyp_tuple) res.append(torch.cat((initial_ids[i], torch.tensor(resolve)))) results.append(res) max_length = max([n.shape[-1] for m in results for n in m]) return_res = [] for i, res in enumerate(results): for j in range(beam_scorer.num_beam_hyps_to_keep): return_res.append(expand_if_needed(res[j], max_length, model_config.pad_token_id)) input_ids = torch.stack(return_res) return input_ids hb_profer = HabanaProfile( warmup=profiling_warmup_steps, active=profiling_steps, record_shapes=profiling_record_shapes ) hb_profer.start() this_peer_finished = False bucket_size = model_kwargs.get("bucket_size", -1) prev_idx = -1 # avoiding calculate cache_idx when its value is not changing bucket_internal = model_kwargs.get("bucket_internal", None) reduce_recompile = model_kwargs.get("reduce_recompile", False) prompt_len = input_ids.shape[-1] if not bucket_internal: if bucket_size >= 0: inc = iter(incrementor(bucket_size, cur_len)) if bucket_size > 0 and "position_ids" in model_kwargs: logger.warning("Untested path for bucketing with position_ids") if self.generation_config.static_shapes: initial_ids = input_ids[::num_beams, 0:cur_len] time_to_first_token_done = False # 4. run the generation loop while self._has_unfinished_sequences(this_peer_finished, synced_gpus, device=input_ids.device): if lazy_mode: self.htcore_generation.mark_step() if bucket_size > 0 and not bucket_internal: # it will not have been padded if bucket_size > 0 params = next(inc) input_ids, model_kwargs = self.update_model_kwargs_for_bucketing( params, input_ids, model_kwargs, pad_token_id, bucket_size, reduce_recompile ) model_kwargs["lazy_mode"] = lazy_mode model_inputs = self.prepare_inputs_for_generation(input_ids, **model_kwargs) # prepare variable output controls (note: some models won't accept all output controls) model_inputs.update({"output_attentions": output_attentions} if output_attentions else {}) model_inputs.update({"output_hidden_states": output_hidden_states} if output_hidden_states else {}) hpu_graphs_kwargs = self._get_hpu_graphs_kwargs(model_kwargs) outputs = self( **model_inputs, return_dict=True, **hpu_graphs_kwargs, ) # synced_gpus: don't waste resources running the code we don't need if synced_gpus and this_peer_finished: cur_len = cur_len + 1 continue token_idx = model_kwargs.get("token_idx", None) if token_idx is not None and outputs.logits.shape[-2] > 1: if model_kwargs.get("num_virtual_tokens", 0) > 0: # for prompt tuning, the output logit shape may > model_inputs["input_ids"].shape[-1] if model_kwargs.get("reuse_cache", False): output_idx = torch.tensor(outputs.logits.shape[-2], device=input_ids.device) else: output_idx = token_idx + outputs.logits.shape[-2] - input_ids.shape[-1] next_token_logits = torch.index_select(outputs.logits, -2, output_idx - 1).squeeze(-2) else: next_token_logits = torch.index_select(outputs.logits, -2, token_idx - 1).squeeze(-2) else: next_token_logits = outputs.logits[:, -1, :].float() next_token_logits = next_token_logits.to(input_ids.device) next_token_scores = torch.nn.functional.log_softmax( next_token_logits, dim=-1 ) # (batch_size * num_beams, vocab_size) if token_idx is not None: idx = token_idx + model_kwargs.get("inputs_embeds_offset", 0) next_token_scores_processed = logits_processor(input_ids[:, :idx], next_token_scores) else: next_token_scores_processed = logits_processor(input_ids, next_token_scores) next_token_scores = next_token_scores_processed + beam_scores[:, None].expand_as( next_token_scores_processed ) # Store scores, attentions and hidden_states when required if return_dict_in_generate: if output_scores: scores += (next_token_scores_processed,) if output_logits: raw_logits += (next_token_logits,) if output_attentions: decoder_attentions += ( (outputs.decoder_attentions,) if self.config.is_encoder_decoder else (outputs.attentions,) ) if self.config.is_encoder_decoder: cross_attentions += (outputs.cross_attentions,) if output_hidden_states: decoder_hidden_states += ( (outputs.decoder_hidden_states,) if self.config.is_encoder_decoder else (outputs.hidden_states,) ) # reshape for beam search vocab_size = next_token_scores.shape[-1] next_token_scores = next_token_scores.view(batch_size, num_beams * vocab_size) n_tokens_to_keep = num_selection * num_beams if do_sample: probs = torch.nn.functional.softmax(next_token_scores, dim=-1) next_tokens = torch.multinomial(probs, num_samples=n_tokens_to_keep) next_token_scores = torch.gather(next_token_scores, -1, next_tokens) next_token_scores, _indices = torch.sort(next_token_scores, descending=True, dim=1) next_tokens = torch.gather(next_tokens, -1, _indices) else: next_token_scores, next_tokens = torch.topk( next_token_scores, n_tokens_to_keep, dim=1, largest=True, sorted=True ) next_indices = torch.div(next_tokens, vocab_size, rounding_mode="floor") if self.generation_config.static_shapes: beam_scores = next_token_scores.flatten() next_indices_flattened = next_indices.flatten() static_beam_indices = ( next_indices_flattened + torch.tensor( [[batch_idx * num_beams] * next_indices.shape[1] for batch_idx in range(batch_size)], device=next_indices.device, ).flatten() ) beam_tokens = next_tokens.remainder(vocab_size).flatten() beam_trace_scores.index_copy_(0, beam_trace_idx, beam_scores.unsqueeze(0)) beam_trace_indices.index_copy_(0, beam_trace_idx, next_indices_flattened.unsqueeze(0)) beam_trace_tokens.index_copy_(0, beam_trace_idx, beam_tokens.unsqueeze(0)) beam_trace_idx.add_(1) if early_stopping: num_eos_tokens.add_(beam_tokens[0:num_beams].eq(self.config.eos_token_id).sum()) beam_scores.add_(torch.where(beam_tokens.eq(self.config.eos_token_id), float("-inf"), 0.0)) beam_scores = beam_scores.view(batch_size, -1).unsqueeze(0) _, selected = torch.topk(beam_scores, k=num_beams, dim=-1, largest=True, sorted=True) offset = torch.arange(0, torch.numel(beam_scores), beam_scores.shape[-1]).unsqueeze(-1) selected = (selected + offset).flatten() beam_scores = beam_scores.flatten().index_select(0, selected) beam_tokens = beam_tokens.index_select(0, selected) static_beam_indices = static_beam_indices.index_select(0, selected) prev_beams = outputs.logits.shape[0] // batch_size beam_offsets = torch.arange(0, 1, prev_beams, dtype=torch.int32) beam_offsets = beam_offsets.to(device=outputs.logits.device) static_beam_indices = (static_beam_indices.view(batch_size, -1) + beam_offsets.unsqueeze(-1)).flatten() next_tokens = beam_tokens.unsqueeze(-1) beam_next_tokens = next_tokens beam_idx = static_beam_indices else: next_tokens = next_tokens % vocab_size # stateless beam_outputs = beam_scorer.process( input_ids, next_token_scores, next_tokens, next_indices, pad_token_id=pad_token_id, eos_token_id=eos_token_id, beam_indices=beam_indices, decoder_prompt_len=prompt_len, ) beam_scores = beam_outputs["next_beam_scores"] beam_next_tokens = beam_outputs["next_beam_tokens"] beam_idx = beam_outputs["next_beam_indices"] if token_idx is not None: input_ids = torch.index_select(input_ids, 0, beam_idx) idx = token_idx + model_kwargs.get("inputs_embeds_offset", 0) input_ids.index_copy_( 1, idx, beam_next_tokens.unsqueeze(-1) if beam_next_tokens.dim() == 1 else beam_next_tokens ) else: input_ids = torch.cat([input_ids[beam_idx, :], beam_next_tokens.unsqueeze(-1)], dim=-1) model_kwargs = self._update_model_kwargs_for_generation( outputs, model_kwargs, is_encoder_decoder=self.config.is_encoder_decoder, ) if model_kwargs.get("past_key_values", None) is not None: if model_kwargs["reuse_cache"]: model_kwargs["past_key_values"] = unwrap_deepspeed_model(self).reorder_kv_cache(beam_idx) else: model_kwargs["past_key_values"] = self._temporary_reorder_cache( model_kwargs["past_key_values"], beam_idx ) if return_dict_in_generate and output_scores: beam_indices = tuple((beam_indices[beam_idx[i]] + (beam_idx[i],) for i in range(len(beam_indices)))) # increase cur_len cur_len = cur_len + 1 if bucket_size > 0 and bucket_internal: # Calculate slice idx for kv cache during the decode phase. # Breaking down the kv cache in the attention block helps to reduce computation time. if model_kwargs.get("token_idx_cpu") <= (model_kwargs["kv_cache_len"] // bucket_size) * bucket_size: idx = (model_kwargs.get("token_idx_cpu") - 1) // bucket_size if prev_idx != idx: model_kwargs["cache_idx"] = (idx + 1) * bucket_size prev_idx = idx else: model_kwargs["cache_idx"] = model_kwargs["kv_cache_len"] hb_profer.step() if self.generation_config.static_shapes: is_min_length_reached = ( self.generation_config.min_length and cur_len >= self.generation_config.min_length ) if early_stopping and is_min_length_reached and num_eos_tokens >= num_beams_tensor: break elif get_final_stopping_criteria(stopping_criteria(input_ids, scores, token_idx=cur_len)): break elif get_final_stopping_criteria(stopping_criteria(input_ids, scores)) or ( beam_scorer.is_done and not lazy_mode ): this_peer_finished = True hb_profer.step() if hb_gen_time is not None: if not time_to_first_token_done: time_to_first_token_done = True import habana_frameworks.torch.hpu as torch_hpu torch_hpu.synchronize() hb_gen_time.step() if ( not model_kwargs.get("pad_done", False) and not model_kwargs.get("reuse_cache", False) and bucket_internal ): # Pad the returned past key values tensors from prefill phase forward run to maximum length # before starting the decode phase. if outputs.past_key_values[0][0].shape[2] == model_inputs["input_ids"].shape[1]: self._pad_past_key_values(model_kwargs) model_kwargs["pad_done"] = True # This is needed to properly delete outputs.logits which may be very large for first iteration # Otherwise a reference to outputs is kept which keeps the logits alive in the next iteration # IMPORTANT: Note that this should appear BEFORE the call to _reorder_cache() to save the maximum memory # (that way the memory peak does not include outputs.logits) del outputs if ( model_kwargs.get("use_hpu_graphs", False) and model_kwargs.get("limit_hpu_graphs", False) and not model_kwargs.get("reuse_cache", False) and bucket_internal ): # Clear HPU graphs input tensors of the decode phase after the full generation while loop self.clear_inputs() # Delete past key value tensors self._remove_past_key_values(model_kwargs) hb_profer.stop() if self.generation_config.static_shapes: beam_trace = (beam_trace_idx, beam_trace_scores, beam_trace_indices, beam_trace_tokens) from collections import UserDict def map_tensors(obj, fn): constructor = type(obj) if isinstance(obj, tuple): return constructor(map_tensors(v, fn) for v in obj) if isinstance(obj, list): return constructor([map_tensors(v, fn) for v in obj]) if isinstance(obj, dict) or isinstance(obj, UserDict): return constructor({k: map_tensors(v, fn) for k, v in obj.items()}) if isinstance(obj, torch.Tensor): return fn(obj) return obj def move(obj, device): return map_tensors(obj, lambda t: t.to(device)) sequence_outputs = {} sequence_outputs["sequences"] = finalize_beams( initial_ids.cpu(), move(beam_trace, "cpu"), self.config, length_penalty ) else: sequence_outputs = beam_scorer.finalize( input_ids, beam_scores, next_tokens, beam_indices, pad_token_id=pad_token_id, eos_token_id=eos_token_id, max_length=stopping_criteria.max_length, beam_indices=beam_indices, decoder_prompt_len=prompt_len, ) if return_dict_in_generate: if not output_scores: sequence_outputs["sequence_scores"] = None if self.config.is_encoder_decoder: return GenerateBeamEncoderDecoderOutput( sequences=sequence_outputs["sequences"], sequences_scores=sequence_outputs["sequence_scores"], scores=scores, logits=raw_logits, beam_indices=sequence_outputs["beam_indices"], encoder_attentions=encoder_attentions, encoder_hidden_states=encoder_hidden_states, decoder_attentions=decoder_attentions, cross_attentions=cross_attentions, decoder_hidden_states=decoder_hidden_states, past_key_values=model_kwargs.get("past_key_values"), ) else: return GenerateBeamDecoderOnlyOutput( sequences=sequence_outputs["sequences"], sequences_scores=sequence_outputs["sequence_scores"], scores=scores, logits=raw_logits, beam_indices=sequence_outputs["beam_indices"], attentions=decoder_attentions, hidden_states=decoder_hidden_states, past_key_values=model_kwargs.get("past_key_values"), ) else: return sequence_outputs["sequences"] def _group_beam_search( self, input_ids: torch.LongTensor, beam_scorer: BeamScorer, logits_processor: LogitsProcessorList, stopping_criteria: StoppingCriteriaList, generation_config: GaudiGenerationConfig, synced_gpus: bool, lazy_mode: Optional[bool] = False, profiling_warmup_steps: Optional[int] = 0, profiling_steps: Optional[int] = 0, hb_gen_time: Optional[HabanaGenerationTime] = None, profiling_record_shapes: Optional[bool] = False, **model_kwargs, ): r""" Generates sequences of token ids for models with a language modeling head using **diverse beam search decoding** and can be used for text-decoder, text-to-text, speech-to-text, and vision-to-text models. Parameters: input_ids (`torch.LongTensor` of shape `(batch_size*num_beams, sequence_length)`): The sequence used as a prompt for the generation. beam_scorer (`BeamScorer`): An derived instance of [`BeamScorer`] that defines how beam hypotheses are constructed, stored and sorted during generation. For more information, the documentation of [`BeamScorer`] should be read. logits_processor (`LogitsProcessorList`): An instance of [`LogitsProcessorList`]. List of instances of class derived from [`LogitsProcessor`] used to modify the prediction scores of the language modeling head applied at each generation step. stopping_criteria (`StoppingCriteriaList`): An instance of [`StoppingCriteriaList`]. List of instances of class derived from [`StoppingCriteria`] used to tell if the generation loop should stop. generation_config ([`GaudiGenerationConfig`]): The generation configuration to be used as parametrization of the decoding method. synced_gpus (`bool`): Whether to continue running the while loop until max_length (needed to avoid deadlocking with `FullyShardedDataParallel` and DeepSpeed ZeRO Stage 3). lazy_mode (`bool`, *optional*, defaults to `False`): Whether the run is executed in lazy mode or not (i.e. eager mode). profiling_warmup_steps (`int`, *optional*, defaults to 0): Number of steps to ignore for profling. profiling_steps (`int`, *optional*, defaults to 0): Number of steps to be captured when enabling profiling. profiling_record_shapes (`bool`, *optional*, defaults to False): Record shapes when enabling profiling. model_kwargs: Additional model specific kwargs that will be forwarded to the `forward` function of the model. If model is an encoder-decoder model the kwargs should include `encoder_outputs`. Return: [`transformers.generation.GenerateBeamDecoderOnlyOutput`], [`transformers.generation.GenerateBeamEncoderDecoderOutput`] or `torch.LongTensor`: A `torch.LongTensor` containing the generated tokens (default behaviour) or a [`transformers.generation.GenerateBeamDecoderOnlyOutput`] if [`transformers.generation.BeamSearchDecoderOnlyOutput`] if `model.config.is_encoder_decoder=False` and `return_dict_in_generate=True` or a [`transformers.generation.GenerateBeamEncoderDecoderOutput`] if `model.config.is_encoder_decoder=True`. """ raise NotImplementedError("Group beam search is not supported by optimum-habana yet.") def _constrained_beam_search( self, input_ids: torch.LongTensor, constrained_beam_scorer: ConstrainedBeamSearchScorer, logits_processor: LogitsProcessorList, stopping_criteria: StoppingCriteriaList, generation_config: GaudiGenerationConfig, synced_gpus: bool, lazy_mode: Optional[bool] = False, profiling_warmup_steps: Optional[int] = 0, profiling_steps: Optional[int] = 0, hb_gen_time: Optional[HabanaGenerationTime] = None, profiling_record_shapes: Optional[bool] = False, **model_kwargs, ) -> Union[GenerateBeamOutput, torch.LongTensor]: r""" Generates sequences of token ids for models with a language modeling head using **constrained beam search decoding** and can be used for text-decoder, text-to-text, speech-to-text, and vision-to-text models. Parameters: input_ids (`torch.LongTensor` of shape `(batch_size*num_beams, sequence_length)`): The sequence used as a prompt for the generation. constrained_beam_scorer (`ConstrainedBeamSearchScorer`): A derived instance of [`BeamScorer`] that defines how beam hypotheses are constructed, stored and sorted during generation, while satisfying a list of positive constraints. For more information, the documentation of [`ConstrainedBeamSearchScorer`] should be read. logits_processor (`LogitsProcessorList`): An instance of [`LogitsProcessorList`]. List of instances of class derived from [`LogitsProcessor`] used to modify the prediction scores of the language modeling head applied at each generation step. stopping_criteria (`StoppingCriteriaList`): An instance of [`StoppingCriteriaList`]. List of instances of class derived from [`StoppingCriteria`] used to tell if the generation loop should stop. generation_config ([`GaudiGenerationConfig`]): The generation configuration to be used as parametrization of the decoding method. synced_gpus (`bool`): Whether to continue running the while loop until max_length (needed to avoid deadlocking with `FullyShardedDataParallel` and DeepSpeed ZeRO Stage 3). lazy_mode (`bool`, *optional*, defaults to `False`): Whether the run is executed in lazy mode or not (i.e. eager mode). profiling_warmup_steps (`int`, *optional*, defaults to 0): Number of steps to ignore for profling. profiling_steps (`int`, *optional*, defaults to 0): Number of steps to be captured when enabling profiling. profiling_record_shapes (`bool`, *optional*, defaults to False): Record shapes when enabling profiling. model_kwargs: Additional model specific kwargs will be forwarded to the `forward` function of the model. If model is an encoder-decoder model the kwargs should include `encoder_outputs`. Return: [`transformers.generation.utils.GenerateBeamDecoderOnlyOutput`], [`transformers.generation.GenerateBeamEncoderDecoderOutput`] or `torch.LongTensor`: A `torch.LongTensor` containing the generated tokens (default behaviour) or a [`transformers.generation.GenerateBeamDecoderOnlyOutput`] if `model.config.is_encoder_decoder=False` and `return_dict_in_generate=True` or a [`transformers.generation.GenerateBeamEncoderDecoderOutput`] if `model.config.is_encoder_decoder=True`. """ # init values pad_token_id = generation_config._pad_token_tensor eos_token_id = generation_config._eos_token_tensor output_attentions = generation_config.output_attentions output_hidden_states = generation_config.output_hidden_states output_scores = generation_config.output_scores output_logits = generation_config.output_logits return_dict_in_generate = generation_config.return_dict_in_generate batch_size = len(constrained_beam_scorer._beam_hyps) num_beams = constrained_beam_scorer.num_beams batch_beam_size, cur_len = input_ids.shape token_idx = model_kwargs.get("token_idx", None) if token_idx is not None: # Update cur_len in case of static shapes cur_len = (token_idx + model_kwargs.get("inputs_embeds_offset", 0)).item() model_kwargs["cache_position"] = torch.arange(cur_len, device=input_ids.device) if num_beams * batch_size != batch_beam_size: raise ValueError( f"Batch dimension of `input_ids` should be {num_beams * batch_size}, but is {batch_beam_size}." ) # init attention / hidden states / scores tuples scores = () if (return_dict_in_generate and output_scores) else None raw_logits = () if (return_dict_in_generate and output_logits) else None beam_indices = ( tuple(() for _ in range(batch_beam_size)) if (return_dict_in_generate and output_scores) else None ) decoder_attentions = () if (return_dict_in_generate and output_attentions) else None cross_attentions = () if (return_dict_in_generate and output_attentions) else None decoder_hidden_states = () if (return_dict_in_generate and output_hidden_states) else None # if model is an encoder-decoder, retrieve encoder attention weights and hidden states if return_dict_in_generate and self.config.is_encoder_decoder: encoder_attentions = model_kwargs["encoder_outputs"].get("attentions") if output_attentions else None encoder_hidden_states = ( model_kwargs["encoder_outputs"].get("hidden_states") if output_hidden_states else None ) # initialise score of first beam with 0 and the rest with -1e9. This makes sure that only tokens # of the first beam are considered to avoid sampling the exact same tokens across all beams. beam_scores = torch.zeros((batch_size, num_beams), dtype=torch.float, device=input_ids.device) beam_scores[:, 1:] = -1e9 beam_scores = beam_scores.view((batch_size * num_beams,)) this_peer_finished = False # record the prompt length of decoder if token_idx is not None: decoder_prompt_len = cur_len else: decoder_prompt_len = input_ids.shape[-1] hb_profer = HabanaProfile( warmup=profiling_warmup_steps, active=profiling_steps, record_shapes=profiling_record_shapes ) hb_profer.start() time_to_first_token_done = False while self._has_unfinished_sequences(this_peer_finished, synced_gpus, device=input_ids.device): model_kwargs["lazy_mode"] = lazy_mode model_inputs = self.prepare_inputs_for_generation(input_ids, **model_kwargs) # prepare variable output controls (note: some models won't accept all output controls) model_inputs.update({"output_attentions": output_attentions} if output_attentions else {}) model_inputs.update({"output_hidden_states": output_hidden_states} if output_hidden_states else {}) hpu_graphs_kwargs = self._get_hpu_graphs_kwargs(model_kwargs) outputs = self( **model_inputs, return_dict=True, **hpu_graphs_kwargs, ) # synced_gpus: don't waste resources running the code we don't need if synced_gpus and this_peer_finished: cur_len = cur_len + 1 continue if token_idx is not None and outputs.logits.shape[-2] > 1: if model_kwargs.get("num_virtual_tokens", 0) > 0: # for prompt tuning, the output logit shape > model_inputs["input_ids"].shape[-1] if model_kwargs.get("reuse_cache", False): output_idx = torch.tensor(outputs.logits.shape[-2], device=input_ids.device) else: output_idx = token_idx + outputs.logits.shape[-2] - input_ids.shape[-1] next_token_logits = torch.index_select(outputs.logits, -2, output_idx - 1).squeeze(-2) else: next_token_logits = torch.index_select(outputs.logits, -2, token_idx - 1).squeeze(-2) else: next_token_logits = outputs.logits[:, -1, :].float() next_token_logits = next_token_logits.to(copy=True, dtype=torch.float32, device=input_ids.device) next_token_scores = torch.nn.functional.log_softmax( next_token_logits, dim=-1 ) # (batch_size * num_beams, vocab_size) next_token_scores_processed = logits_processor(input_ids, next_token_scores) next_token_scores = next_token_scores_processed + beam_scores[:, None].expand_as( next_token_scores_processed ) scores_for_all_vocab = next_token_scores.clone() # Store scores, attentions and hidden_states when required if return_dict_in_generate: if output_scores: scores += (next_token_scores,) if output_logits: raw_logits += (next_token_logits,) if output_attentions: decoder_attentions += ( (outputs.decoder_attentions,) if self.config.is_encoder_decoder else (outputs.attentions,) ) if self.config.is_encoder_decoder: cross_attentions += (outputs.cross_attentions,) if output_hidden_states: decoder_hidden_states += ( (outputs.decoder_hidden_states,) if self.config.is_encoder_decoder else (outputs.hidden_states,) ) # reshape for beam search vocab_size = next_token_scores.shape[-1] next_token_scores = next_token_scores.view(batch_size, num_beams * vocab_size) # Sample 1 + len(eos_token_id) next tokens for each beam so we have at least 1 non eos token per beam. n_eos_tokens = eos_token_id.shape[0] if eos_token_id is not None else 0 next_token_scores, next_tokens = torch.topk( next_token_scores, max(2, 1 + n_eos_tokens) * num_beams, dim=1, largest=True, sorted=True ) next_indices = (next_tokens / vocab_size).long() next_tokens = next_tokens % vocab_size # stateless beam_outputs = constrained_beam_scorer.process( input_ids[:, :cur_len], next_token_scores, next_tokens, next_indices, scores_for_all_vocab, pad_token_id=pad_token_id, eos_token_id=eos_token_id, beam_indices=beam_indices, decoder_prompt_len=decoder_prompt_len, ) beam_scores = beam_outputs["next_beam_scores"] beam_next_tokens = beam_outputs["next_beam_tokens"] beam_idx = beam_outputs["next_beam_indices"] if token_idx is not None: input_ids = input_ids[beam_idx, :] idx = token_idx + model_kwargs.get("inputs_embeds_offset", 0) input_ids.index_copy_( 1, idx, beam_next_tokens.unsqueeze(-1) if beam_next_tokens.dim() == 1 else beam_next_tokens ) else: input_ids = torch.cat([input_ids[beam_idx, :], beam_next_tokens.unsqueeze(-1)], dim=-1) model_kwargs = self._update_model_kwargs_for_generation( outputs, model_kwargs, is_encoder_decoder=self.config.is_encoder_decoder, ) # This is needed to properly delete outputs.logits which may be very large for first iteration # Otherwise a reference to outputs is kept which keeps the logits alive in the next iteration # IMPORTANT: Note that this should appear BEFORE the call to _reorder_cache() to save the maximum memory # (that way the memory peak does not include outputs.logits) del outputs if model_kwargs.get("past_key_values", None) is not None: model_kwargs["past_key_values"] = self._temporary_reorder_cache( model_kwargs["past_key_values"], beam_idx ) if return_dict_in_generate and output_scores: beam_indices = tuple((beam_indices[beam_idx[i]] + (beam_idx[i],) for i in range(len(beam_indices)))) # increase cur_len cur_len = cur_len + 1 hb_profer.step() if constrained_beam_scorer.is_done or get_final_stopping_criteria( stopping_criteria(input_ids, scores, token_idx=cur_len) ): this_peer_finished = True if hb_gen_time is not None: if not time_to_first_token_done: time_to_first_token_done = True import habana_frameworks.torch.hpu as torch_hpu torch_hpu.synchronize() hb_gen_time.step() hb_profer.stop() sequence_outputs = constrained_beam_scorer.finalize( input_ids, beam_scores, next_tokens, next_indices, pad_token_id=pad_token_id, eos_token_id=eos_token_id, max_length=stopping_criteria.max_length, beam_indices=beam_indices, decoder_prompt_len=decoder_prompt_len, ) if return_dict_in_generate: if not output_scores: sequence_outputs["sequence_scores"] = None if self.config.is_encoder_decoder: return GenerateBeamEncoderDecoderOutput( sequences=sequence_outputs["sequences"], sequences_scores=sequence_outputs["sequence_scores"], scores=scores, logits=raw_logits, beam_indices=sequence_outputs["beam_indices"], encoder_attentions=encoder_attentions, encoder_hidden_states=encoder_hidden_states, decoder_attentions=decoder_attentions, cross_attentions=cross_attentions, decoder_hidden_states=decoder_hidden_states, past_key_values=model_kwargs.get("past_key_values"), ) else: return GenerateBeamDecoderOnlyOutput( sequences=sequence_outputs["sequences"], sequences_scores=sequence_outputs["sequence_scores"], scores=scores, logits=raw_logits, beam_indices=sequence_outputs["beam_indices"], attentions=decoder_attentions, hidden_states=decoder_hidden_states, past_key_values=model_kwargs.get("past_key_values"), ) else: return sequence_outputs["sequences"] def _assisted_decoding( self, input_ids: torch.LongTensor, candidate_generator: "GaudiCandidateGenerator", logits_processor: LogitsProcessorList, stopping_criteria: StoppingCriteriaList, generation_config: GaudiGenerationConfig, synced_gpus: bool, streamer: Optional["BaseStreamer"], lazy_mode: Optional[bool] = False, ignore_eos: Optional[bool] = False, profiling_warmup_steps: Optional[int] = 0, profiling_steps: Optional[int] = 0, hb_gen_time: Optional[HabanaGenerationTime] = None, profiling_record_shapes: Optional[bool] = False, **model_kwargs, ) -> Union[GenerateNonBeamOutput, torch.LongTensor]: r""" Generates sequences of token ids for models with a language modeling head using **greedy decoding** or **sample** (depending on `do_sample`), assisted by candidate sequences. Assisted generation is an example of a candidate decoding strategy. Can be used for text-decoder, text-to-text, speech-to-text, and vision-to-text models. Parameters: input_ids (`torch.LongTensor` of shape `(batch_size, sequence_length)`): The sequence used as a prompt for the generation. candidate_generator (`CandidateGenerator`): A derived instance of [`CandidateGenerator`] that defines how candidate sequences are generated. For more information, the documentation of [`CandidateGenerator`] should be read. logits_processor (`LogitsProcessorList`): An instance of [`LogitsProcessorList`]. List of instances of class derived from [`LogitsProcessor`] used to modify the prediction scores of the language modeling head applied at each generation step. stopping_criteria (`StoppingCriteriaList`): An instance of [`StoppingCriteriaList`]. List of instances of class derived from [`StoppingCriteria`] used to tell if the generation loop should stop. generation_config ([`~generation.GenerationConfig`]): The generation configuration to be used as parametrization of the decoding method. synced_gpus (`bool`): Whether to continue running the while loop until max_length (needed to avoid deadlocking with `FullyShardedDataParallel` and DeepSpeed ZeRO Stage 3). streamer (`BaseStreamer`, *optional*): Streamer object that will be used to stream the generated sequences. Generated tokens are passed through `streamer.put(token_ids)` and the streamer is responsible for any further processing. lazy_mode (`bool`, *optional*, defaults to `False`): Whether the run is executed in lazy mode or not (i.e. eager mode). profiling_warmup_steps (`int`, *optional*, defaults to 0): Number of steps to ignore for profling. profiling_steps (`int`, *optional*, defaults to 0): Number of steps to be captured when enabling profiling. profiling_record_shapes (`bool`, *optional*, defaults to False): Record shapes when enabling profiling. model_kwargs: Additional model specific keyword arguments will be forwarded to the `forward` function of the model. If model is an encoder-decoder model the kwargs should include `encoder_outputs`. Return: [`transformers.generation.GenerateDecoderOnlyOutput`], [`transformers.generation.GenerateEncoderDecoderOutput`] or `torch.LongTensor`: A `torch.LongTensor` containing the generated tokens (default behaviour) or a [`transformers.generation.GenerateDecoderOnlyOutput`] if `model.config.is_encoder_decoder=False` and `return_dict_in_generate=True` or a [`transformers.generation.GenerateEncoderDecoderOutput`] if `model.config.is_encoder_decoder=True`. """ # init values do_sample = generation_config.do_sample output_attentions = generation_config.output_attentions output_hidden_states = generation_config.output_hidden_states output_scores = generation_config.output_scores output_logits = generation_config.output_logits return_dict_in_generate = generation_config.return_dict_in_generate # init attention / hidden states / scores tuples scores = () if (return_dict_in_generate and output_scores) else None raw_logits = () if (return_dict_in_generate and output_logits) else None decoder_attentions = () if (return_dict_in_generate and output_attentions) else None cross_attentions = () if (return_dict_in_generate and output_attentions) else None decoder_hidden_states = () if (return_dict_in_generate and output_hidden_states) else None # if model is an encoder-decoder, retrieve encoder attention weights and hidden states if return_dict_in_generate and self.config.is_encoder_decoder: encoder_attentions = model_kwargs["encoder_outputs"].get("attentions") if output_attentions else None encoder_hidden_states = ( model_kwargs["encoder_outputs"].get("hidden_states") if output_hidden_states else None ) # keep track of which sequences are already finished batch_size, cur_len = input_ids.shape if not ignore_eos: unfinished_sequences = torch.ones(batch_size, dtype=torch.long, device=input_ids.device) model_kwargs = self._get_initial_cache_position(input_ids, model_kwargs) hb_profer = HabanaProfile(warmup=profiling_warmup_steps, active=profiling_steps) hb_profer.start() this_peer_finished = False is_first_iteration = True # to preserve the same API in the output as other generation methods token_idx = model_kwargs.get("token_idx", None) time_to_first_token_done = False while self._has_unfinished_sequences(this_peer_finished, synced_gpus, device=input_ids.device): if lazy_mode: self.htcore_generation.mark_step() if token_idx is not None: # Update cur_len in case of static shapes cur_len = (token_idx + model_kwargs.get("inputs_embeds_offset", 0)).item() else: cur_len = input_ids.shape[-1] # prepare model inputs model_kwargs["lazy_mode"] = lazy_mode model_inputs = self.prepare_inputs_for_generation(input_ids, **model_kwargs) # 1. Fetch candidate sequences from a `CandidateGenerator` and move to the correct device candidate_input_ids, candidate_logits = candidate_generator.get_candidates(input_ids[:, :cur_len]) candidate_input_ids = candidate_input_ids.to(self.device) if candidate_logits is not None: candidate_logits = candidate_logits.to(self.device) if self.generation_config.static_shapes: candidate_length = candidate_input_ids.shape[1] - cur_len else: candidate_length = candidate_input_ids.shape[1] - input_ids.shape[1] is_done_candidate = stopping_criteria(candidate_input_ids, None) # 2. Use the original model to obtain the next token logits given the candidate sequence. We obtain # `candidate_length + 1` relevant logits from this process: in the event that all candidates are correct, # we use this forward pass to also pick the subsequent logits in the original model. # 2.1. Prepare the model inputs candidate_kwargs = copy.copy(model_kwargs) candidate_kwargs = _prepare_attention_mask( candidate_kwargs, candidate_input_ids.shape[1], self.config.is_encoder_decoder ) candidate_kwargs = _prepare_token_type_ids(candidate_kwargs, candidate_input_ids.shape[1]) if "cache_position" in candidate_kwargs: candidate_kwargs["cache_position"] = torch.cat( ( candidate_kwargs["cache_position"], torch.arange(cur_len, cur_len + candidate_length, device=input_ids.device, dtype=torch.long), ), dim=0, ) model_inputs = self.prepare_inputs_for_generation(candidate_input_ids, **candidate_kwargs) if "logits_to_keep" in model_inputs: model_inputs["logits_to_keep"] = candidate_length + 1 hpu_graphs_kwargs = self._get_hpu_graphs_kwargs(model_kwargs) # 2.2. Run a forward pass on the candidate sequence # prepare variable output controls (note: some models won't accept all output controls) model_inputs.update({"output_attentions": output_attentions} if output_attentions else {}) model_inputs.update({"output_hidden_states": output_hidden_states} if output_hidden_states else {}) outputs = self( **model_inputs, **hpu_graphs_kwargs, ) # 2.3. Process the new logits # .float() is needed to retain precision for later logits manipulations new_logits = outputs.logits[:, -candidate_length - 1 :].to( dtype=torch.float32, device=input_ids.device ) # excludes the input prompt if present next_token_logits = new_logits.clone() if len(logits_processor) > 0: for i in range(candidate_length + 1): new_logits[:, i, :] = logits_processor(candidate_input_ids[:, : cur_len + i], new_logits[:, i, :]) # 3. Select the accepted tokens. There are two possible cases: # Case 1: `do_sample=True` and we have logits for the candidates (originally from speculative decoding) # 👉 Apply algorithm 1 from the speculative decoding paper (https://arxiv.org/pdf/2211.17192.pdf). if do_sample and candidate_logits is not None: from transformers.generation.utils import _speculative_sampling valid_tokens, n_matches = _speculative_sampling( candidate_input_ids, candidate_logits, candidate_length, new_logits, is_done_candidate, ) # Case 2: all other cases (originally from assisted generation) 👉 Compare the tokens selected from the # original model logits with the candidate tokens. We can keep the candidate tokens until the first # mismatch, or until the max length is reached. else: if do_sample: probs = new_logits.softmax(dim=-1) selected_tokens = torch.multinomial(probs[0, :, :], num_samples=1).squeeze(1)[None, :] else: selected_tokens = new_logits.argmax(dim=-1) candidate_new_tokens = candidate_input_ids[:, cur_len:] n_matches = ((~(candidate_new_tokens == selected_tokens[:, :-1])).cumsum(dim=-1) < 1).sum() # Ensure we don't generate beyond max_len or an EOS token if is_done_candidate and n_matches == candidate_length: n_matches -= 1 valid_tokens = selected_tokens[:, : n_matches + 1] # 4. Update variables according to the number of matching assistant tokens. Remember: the token generated # by the model after the last candidate match is also valid, as it is generated from a correct sequence. # Because of this last token, assisted generation search reduces to a normal greedy search/sample if there # is no match. # 4.1. Get the valid continuation, after the matching tokens if self.generation_config.static_shapes: input_ids[:, cur_len : cur_len + n_matches + 1] = valid_tokens else: input_ids = torch.cat((input_ids, valid_tokens), dim=-1) if streamer is not None: streamer.put(valid_tokens.cpu()) new_cur_len = input_ids.shape[-1] # 4.2. Discard past key values relative to unused assistant tokens new_cache_size = new_cur_len - 1 outputs.past_key_values = _crop_past_key_values(self, outputs.past_key_values, new_cache_size) # 5. Update the candidate generation strategy if needed candidate_generator.update_candidate_strategy(input_ids, new_logits, n_matches) # Store scores, attentions and hidden_states when required # Assistant: modified to append one tuple element per token, as in the other generation methods. if return_dict_in_generate: newly_added_length = n_matches + 1 if output_scores: scores += tuple(new_logits[:, i, :] for i in range(newly_added_length)) if output_logits: raw_logits += tuple(next_token_logits[:, i, :] for i in range(newly_added_length)) newly_added_length = new_cur_len if is_first_iteration else newly_added_length if output_attentions: if self.config.is_encoder_decoder: cross_attentions = _split_model_outputs( cross_attentions, outputs.cross_attentions, cur_len, newly_added_length ) decoder_attentions = _split_model_outputs( decoder_attentions, outputs.decoder_attentions, cur_len, newly_added_length, is_decoder_attention=True, ) # some (V)LLMs have hard requirement on SDPA and thus never return attn elif outputs.attentions[0] is not None: decoder_attentions = _split_model_outputs( decoder_attentions, outputs.attentions, cur_len, newly_added_length, is_decoder_attention=True, ) if output_hidden_states: if self.config.is_encoder_decoder: decoder_hidden_states = _split_model_outputs( decoder_hidden_states, outputs.decoder_hidden_states, cur_len, newly_added_length ) else: decoder_hidden_states = _split_model_outputs( decoder_hidden_states, outputs.hidden_states, cur_len, newly_added_length ) if ignore_eos: this_peer_finished = stopping_criteria( input_ids, scores, token_idx=None, ignore_eos=ignore_eos, eos_token_id=generation_config.eos_token_id, ) else: unfinished_sequences = unfinished_sequences & ~stopping_criteria( input_ids, scores, token_idx=None, ignore_eos=ignore_eos, eos_token_id=generation_config.eos_token_id, ) this_peer_finished = unfinished_sequences.max() == 0 is_first_iteration = False if hb_gen_time is not None: if not time_to_first_token_done: time_to_first_token_done = True import habana_frameworks.torch.hpu as torch_hpu torch_hpu.synchronize() hb_gen_time.step() hb_profer.step() if this_peer_finished and not synced_gpus: break hb_profer.stop() if streamer is not None: streamer.end() if ( hasattr(candidate_generator, "assistant_model") and candidate_generator.assistant_model.generation_config.num_assistant_tokens_schedule == "heuristic" ): candidate_generator.assistant_model.generation_config.num_assistant_tokens = ( candidate_generator.num_assistant_tokens ) if return_dict_in_generate: if self.config.is_encoder_decoder: return GenerateEncoderDecoderOutput( sequences=input_ids, scores=scores, logits=raw_logits, encoder_attentions=encoder_attentions, encoder_hidden_states=encoder_hidden_states, decoder_attentions=decoder_attentions, cross_attentions=cross_attentions, decoder_hidden_states=decoder_hidden_states, past_key_values=model_kwargs.get("past_key_values"), ) else: return GenerateDecoderOnlyOutput( sequences=input_ids, scores=scores, logits=raw_logits, attentions=decoder_attentions, hidden_states=decoder_hidden_states, past_key_values=model_kwargs.get("past_key_values"), ) else: return input_ids def _ranking_fast( context_hidden: torch.FloatTensor, next_hidden: torch.FloatTensor, next_top_k_probs: torch.FloatTensor, alpha: float, beam_width: int, ) -> torch.FloatTensor: """ Reranks the top_k candidates based on a degeneration penalty (cosine similarity with previous tokens), as described in the paper "A Contrastive Framework for Neural Text Generation". Returns the index of the best candidate for each row in the batch. """ norm_context_hidden = context_hidden / context_hidden.norm(dim=2, keepdim=True) norm_next_hidden = next_hidden / next_hidden.norm(dim=2, keepdim=True) cosine_matrix = torch.matmul(norm_context_hidden, norm_next_hidden.transpose(1, 2)).squeeze(-1) # [B*K, S] degeneration_penalty, _ = torch.max(cosine_matrix, dim=-1) # [B*K] next_top_k_probs = next_top_k_probs.view(-1) # [B*K] contrastive_score = (1.0 - alpha) * next_top_k_probs - alpha * degeneration_penalty contrastive_score = torch.stack(torch.split(contrastive_score, beam_width)) # [B, K] _, selected_idx = contrastive_score.max(dim=-1) # [B] return selected_idx