Automatic Speech Recognition
Transformers
Safetensors
PyTorch
mini_whisper
text2text-generation
custom_code
Instructions to use NeuraCraft/MiniWhisper-ASR with libraries, inference providers, notebooks, and local apps. Follow these links to get started.
- Libraries
- Transformers
How to use NeuraCraft/MiniWhisper-ASR with Transformers:
# Use a pipeline as a high-level helper from transformers import pipeline pipe = pipeline("automatic-speech-recognition", model="NeuraCraft/MiniWhisper-ASR", trust_remote_code=True)# Load model directly from transformers import AutoModelForSeq2SeqLM model = AutoModelForSeq2SeqLM.from_pretrained("NeuraCraft/MiniWhisper-ASR", trust_remote_code=True, dtype="auto") - Notebooks
- Google Colab
- Kaggle
| # modeling_mini_whisper.py | |
| import math | |
| from collections.abc import Callable | |
| import torch | |
| import torch.nn as nn | |
| from torch.nn import functional as F | |
| from transformers import PreTrainedModel, GenerationMixin | |
| from transformers.modeling_outputs import ( | |
| BaseModelOutput, | |
| BaseModelOutputWithPastAndCrossAttentions, | |
| CausalLMOutputWithCrossAttentions, | |
| Seq2SeqLMOutput, | |
| Seq2SeqModelOutput, | |
| ) | |
| from transformers.activations import ACT2FN | |
| from transformers.utils import logging | |
| from configuration_mini_whisper import MiniWhisperConfig | |
| logger = logging.get_logger(__name__) | |
| _HIDDEN_STATES_START_POSITION = 1 | |
| def sinusoids(length: int, channels: int, max_timescale: float = 10000) -> torch.Tensor: | |
| """Returns sinusoids for positional embedding""" | |
| if channels % 2 != 0: | |
| raise ValueError(f"Number of channels has to be divisible by 2, got {channels} channels.") | |
| log_timescale_increment = math.log(max_timescale) / (channels // 2 - 1) | |
| inv_timescales = torch.exp(-log_timescale_increment * torch.arange(channels // 2)) | |
| scaled_time = torch.arange(length).view(-1, 1) * inv_timescales.view(1, -1) | |
| return torch.cat([scaled_time.sin(), scaled_time.cos()], dim=1) | |
| def shift_tokens_right(input_ids: torch.Tensor, pad_token_id: int, decoder_start_token_id: int): | |
| """Shift input ids one token to the right.""" | |
| shifted_input_ids = input_ids.new_zeros(input_ids.shape) | |
| shifted_input_ids[:, 1:] = input_ids[:, :-1].clone() | |
| shifted_input_ids[:, 0] = decoder_start_token_id | |
| if pad_token_id is None: | |
| raise ValueError("pad_token_id has to be defined.") | |
| shifted_input_ids.masked_fill_(shifted_input_ids == -100, pad_token_id) | |
| return shifted_input_ids | |
| def _compute_mask_indices( | |
| shape: tuple[int, int], | |
| mask_prob: float, | |
| mask_length: int, | |
| attention_mask: torch.LongTensor | None = None, | |
| min_masks: int = 0, | |
| ): | |
| """Computes random mask spans for SpecAugment""" | |
| import numpy as np | |
| batch_size, sequence_length = shape | |
| if mask_length < 1: | |
| raise ValueError(f"mask_length has to be bigger than 0.") | |
| if mask_length > sequence_length: | |
| raise ValueError(f"mask_length has to be smaller than sequence_length.") | |
| epsilon = np.random.rand(1).item() | |
| def compute_num_masked_span(input_length): | |
| num_masked_span = int(mask_prob * input_length / mask_length + epsilon) | |
| num_masked_span = max(num_masked_span, min_masks) | |
| if num_masked_span * mask_length > sequence_length: | |
| num_masked_span = sequence_length // mask_length | |
| if input_length - (mask_length - 1) < num_masked_span: | |
| num_masked_span = max(input_length - (mask_length - 1), 0) | |
| return num_masked_span | |
| input_lengths = ( | |
| attention_mask.detach().sum(-1).tolist() | |
| if attention_mask is not None | |
| else [sequence_length for _ in range(batch_size)] | |
| ) | |
| spec_aug_mask = np.zeros((batch_size, sequence_length), dtype=bool) | |
| spec_aug_mask_idxs = [] | |
| max_num_masked_span = compute_num_masked_span(sequence_length) | |
| if max_num_masked_span == 0: | |
| return spec_aug_mask | |
| for input_length in input_lengths: | |
| num_masked_span = compute_num_masked_span(input_length) | |
| spec_aug_mask_idx = np.random.choice( | |
| np.arange(input_length - (mask_length - 1)), num_masked_span, replace=False | |
| ) | |
| if len(spec_aug_mask_idx) == 0: | |
| dummy_mask_idx = sequence_length - 1 | |
| else: | |
| dummy_mask_idx = spec_aug_mask_idx[0] | |
| spec_aug_mask_idx = np.concatenate( | |
| [spec_aug_mask_idx, np.ones(max_num_masked_span - num_masked_span, dtype=np.int32) * dummy_mask_idx] | |
| ) | |
| spec_aug_mask_idxs.append(spec_aug_mask_idx) | |
| spec_aug_mask_idxs = np.array(spec_aug_mask_idxs) | |
| spec_aug_mask_idxs = np.broadcast_to( | |
| spec_aug_mask_idxs[:, :, None], (batch_size, max_num_masked_span, mask_length) | |
| ) | |
| spec_aug_mask_idxs = spec_aug_mask_idxs.reshape(batch_size, max_num_masked_span * mask_length) | |
| offsets = np.arange(mask_length)[None, None, :] | |
| offsets = np.broadcast_to(offsets, (batch_size, max_num_masked_span, mask_length)).reshape( | |
| batch_size, max_num_masked_span * mask_length | |
| ) | |
| spec_aug_mask_idxs = spec_aug_mask_idxs + offsets | |
| if spec_aug_mask_idxs.max() > sequence_length - 1: | |
| spec_aug_mask_idxs[spec_aug_mask_idxs > sequence_length - 1] = sequence_length - 1 | |
| np.put_along_axis(spec_aug_mask, spec_aug_mask_idxs, 1, -1) | |
| return spec_aug_mask | |
| class WhisperPositionalEmbedding(nn.Module): | |
| def __init__(self, num_positions: int, embedding_dim: int, padding_idx: int | None = None): | |
| super().__init__() | |
| self.num_positions = num_positions | |
| self.embedding_dim = embedding_dim | |
| self.weight = nn.Parameter(torch.zeros(num_positions, embedding_dim)) | |
| self._init_weights() | |
| def _init_weights(self): | |
| with torch.no_grad(): | |
| self.weight.copy_(sinusoids(self.num_positions, self.embedding_dim)) | |
| def forward(self, input_ids, past_key_values_length=0, position_ids=None): | |
| if position_ids is None: | |
| return self.weight[past_key_values_length : past_key_values_length + input_ids.shape[1]] | |
| else: | |
| return self.weight[position_ids] | |
| class MiniWhisperAttention(nn.Module): | |
| """Multi-headed attention from 'Attention Is All You Need' paper""" | |
| def __init__( | |
| self, | |
| embed_dim: int, | |
| num_heads: int, | |
| dropout: float = 0.0, | |
| is_decoder: bool = False, | |
| bias: bool = True, | |
| is_causal: bool = False, | |
| layer_idx: int | None = None, | |
| config: MiniWhisperConfig | None = None, | |
| ): | |
| super().__init__() | |
| self.embed_dim = embed_dim | |
| self.num_heads = num_heads | |
| self.dropout = dropout | |
| self.head_dim = embed_dim // num_heads | |
| self.config = config | |
| if (self.head_dim * num_heads) != self.embed_dim: | |
| raise ValueError(f"embed_dim must be divisible by num_heads") | |
| self.scaling = self.head_dim ** -0.5 | |
| self.is_decoder = is_decoder | |
| self.is_causal = is_causal | |
| self.layer_idx = layer_idx | |
| self.k_proj = nn.Linear(embed_dim, embed_dim, bias=False) | |
| self.v_proj = nn.Linear(embed_dim, embed_dim, bias=bias) | |
| self.q_proj = nn.Linear(embed_dim, embed_dim, bias=bias) | |
| self.out_proj = nn.Linear(embed_dim, embed_dim, bias=bias) | |
| def forward( | |
| self, | |
| hidden_states: torch.Tensor, | |
| key_value_states: torch.Tensor | None = None, | |
| past_key_value: tuple[torch.Tensor, torch.Tensor] | None = None, | |
| attention_mask: torch.Tensor | None = None, | |
| output_attentions: bool = False, | |
| ): | |
| """Input shape: Batch x Time x Channel""" | |
| is_cross_attention = key_value_states is not None | |
| input_shape = hidden_states.shape[:-1] | |
| hidden_shape = (*input_shape, -1, self.head_dim) | |
| query_states = (self.q_proj(hidden_states) * self.scaling).view(hidden_shape).transpose(1, 2).contiguous() | |
| if past_key_value is not None and not is_cross_attention: | |
| key_states = past_key_value[0] | |
| value_states = past_key_value[1] | |
| else: | |
| current_states = key_value_states if key_value_states is not None else hidden_states | |
| kv_shape = (input_shape[0], -1, self.num_heads, self.head_dim) | |
| key_states = self.k_proj(current_states).view(kv_shape).transpose(1, 2).contiguous() | |
| value_states = self.v_proj(current_states).view(kv_shape).transpose(1, 2).contiguous() | |
| if past_key_value is not None and is_cross_attention: | |
| key_states = torch.cat([past_key_value[0], key_states], dim=2) | |
| value_states = torch.cat([past_key_value[1], value_states], dim=2) | |
| attn_weights = torch.matmul(query_states, key_states.transpose(-2, -1)) * 1.0 | |
| if attention_mask is not None: | |
| attn_weights = attn_weights + attention_mask | |
| attn_weights = F.softmax(attn_weights, dim=-1) | |
| attn_weights = F.dropout(attn_weights, p=self.dropout, training=self.training) | |
| attn_output = torch.matmul(attn_weights, value_states) | |
| attn_output = attn_output.reshape(*input_shape, -1).contiguous() | |
| attn_output = self.out_proj(attn_output) | |
| return attn_output, None | |
| class MiniWhisperEncoderLayer(nn.Module): | |
| def __init__(self, config: MiniWhisperConfig): | |
| super().__init__() | |
| self.embed_dim = config.d_model | |
| self.self_attn = MiniWhisperAttention( | |
| embed_dim=self.embed_dim, | |
| num_heads=config.encoder_attention_heads, | |
| dropout=config.attention_dropout, | |
| is_decoder=False, | |
| config=config, | |
| ) | |
| self.self_attn_layer_norm = nn.LayerNorm(self.embed_dim) | |
| self.dropout = config.dropout | |
| self.activation_fn = ACT2FN[config.activation_function] | |
| self.activation_dropout = config.activation_dropout | |
| self.fc1 = nn.Linear(self.embed_dim, config.encoder_ffn_dim) | |
| self.fc2 = nn.Linear(config.encoder_ffn_dim, self.embed_dim) | |
| self.final_layer_norm = nn.LayerNorm(self.embed_dim) | |
| def forward( | |
| self, | |
| hidden_states: torch.Tensor, | |
| attention_mask: torch.Tensor, | |
| ): | |
| residual = hidden_states | |
| hidden_states = self.self_attn_layer_norm(hidden_states) | |
| hidden_states, _ = self.self_attn( | |
| hidden_states=hidden_states, | |
| attention_mask=attention_mask, | |
| ) | |
| hidden_states = F.dropout(hidden_states, p=self.dropout, training=self.training) | |
| hidden_states = residual + hidden_states | |
| residual = hidden_states | |
| hidden_states = self.final_layer_norm(hidden_states) | |
| hidden_states = self.activation_fn(self.fc1(hidden_states)) | |
| hidden_states = F.dropout(hidden_states, p=self.activation_dropout, training=self.training) | |
| hidden_states = self.fc2(hidden_states) | |
| hidden_states = F.dropout(hidden_states, p=self.dropout, training=self.training) | |
| hidden_states = residual + hidden_states | |
| if hidden_states.dtype == torch.float16: | |
| clamp_value = torch.finfo(hidden_states.dtype).max - 1000 | |
| hidden_states = torch.clamp(hidden_states, min=-clamp_value, max=clamp_value) | |
| return hidden_states | |
| class MiniWhisperDecoderLayer(nn.Module): | |
| def __init__(self, config: MiniWhisperConfig, layer_idx: int | None = None): | |
| super().__init__() | |
| self.embed_dim = config.d_model | |
| self.self_attn = MiniWhisperAttention( | |
| embed_dim=self.embed_dim, | |
| num_heads=config.decoder_attention_heads, | |
| dropout=config.attention_dropout, | |
| is_decoder=True, | |
| is_causal=True, | |
| layer_idx=layer_idx, | |
| config=config, | |
| ) | |
| self.dropout = config.dropout | |
| self.activation_fn = ACT2FN[config.activation_function] | |
| self.activation_dropout = config.activation_dropout | |
| self.self_attn_layer_norm = nn.LayerNorm(self.embed_dim) | |
| self.encoder_attn = MiniWhisperAttention( | |
| self.embed_dim, | |
| config.decoder_attention_heads, | |
| dropout=config.attention_dropout, | |
| is_decoder=True, | |
| layer_idx=layer_idx, | |
| config=config, | |
| ) | |
| self.encoder_attn_layer_norm = nn.LayerNorm(self.embed_dim) | |
| self.fc1 = nn.Linear(self.embed_dim, config.decoder_ffn_dim) | |
| self.fc2 = nn.Linear(config.decoder_ffn_dim, self.embed_dim) | |
| self.final_layer_norm = nn.LayerNorm(self.embed_dim) | |
| def forward( | |
| self, | |
| hidden_states: torch.Tensor, | |
| attention_mask: torch.Tensor | None = None, | |
| encoder_hidden_states: torch.Tensor | None = None, | |
| encoder_attention_mask: torch.Tensor | None = None, | |
| past_key_value: tuple[tuple[torch.Tensor, torch.Tensor]] | None = None, | |
| use_cache: bool | None = True, | |
| ): | |
| residual = hidden_states | |
| hidden_states = self.self_attn_layer_norm(hidden_states) | |
| self_attn_past = past_key_value[0] if past_key_value is not None else None | |
| hidden_states, _ = self.self_attn( | |
| hidden_states, | |
| past_key_value=self_attn_past, | |
| attention_mask=attention_mask, | |
| ) | |
| hidden_states = F.dropout(hidden_states, p=self.dropout, training=self.training) | |
| hidden_states = residual + hidden_states | |
| if encoder_hidden_states is not None: | |
| residual = hidden_states | |
| hidden_states = self.encoder_attn_layer_norm(hidden_states) | |
| cross_attn_past = past_key_value[1] if past_key_value is not None else None | |
| hidden_states, _ = self.encoder_attn( | |
| hidden_states, | |
| key_value_states=encoder_hidden_states, | |
| attention_mask=encoder_attention_mask, | |
| past_key_value=cross_attn_past, | |
| ) | |
| hidden_states = F.dropout(hidden_states, p=self.dropout, training=self.training) | |
| hidden_states = residual + hidden_states | |
| residual = hidden_states | |
| hidden_states = self.final_layer_norm(hidden_states) | |
| hidden_states = self.activation_fn(self.fc1(hidden_states)) | |
| hidden_states = F.dropout(hidden_states, p=self.activation_dropout, training=self.training) | |
| hidden_states = self.fc2(hidden_states) | |
| hidden_states = F.dropout(hidden_states, p=self.dropout, training=self.training) | |
| hidden_states = residual + hidden_states | |
| return hidden_states, None | |
| class MiniWhisperEncoder(PreTrainedModel): | |
| config_class = MiniWhisperConfig | |
| main_input_name = "input_features" | |
| def __init__(self, config: MiniWhisperConfig): | |
| super().__init__(config) | |
| self.dropout = config.dropout | |
| self.layerdrop = config.encoder_layerdrop | |
| embed_dim = config.d_model | |
| self.num_mel_bins = config.num_mel_bins | |
| self.padding_idx = config.pad_token_id | |
| self.max_source_positions = config.max_source_positions | |
| self.embed_scale = math.sqrt(embed_dim) if config.scale_embedding else 1.0 | |
| self.conv1 = nn.Conv1d(self.num_mel_bins, embed_dim, kernel_size=3, padding=1) | |
| self.conv2 = nn.Conv1d(embed_dim, embed_dim, kernel_size=3, stride=2, padding=1) | |
| self.embed_positions = nn.Embedding(self.max_source_positions, embed_dim) | |
| self.embed_positions.requires_grad_(False) | |
| self.layers = nn.ModuleList([MiniWhisperEncoderLayer(config) for _ in range(config.encoder_layers)]) | |
| self.layer_norm = nn.LayerNorm(config.d_model) | |
| self.gradient_checkpointing = False | |
| self.post_init() | |
| def _init_weights(self, module): | |
| if isinstance(module, MiniWhisperEncoder): | |
| with torch.no_grad(): | |
| module.embed_positions.weight.copy_(sinusoids(*module.embed_positions.weight.shape)) | |
| def forward( | |
| self, | |
| input_features, | |
| attention_mask=None, | |
| **kwargs, | |
| ): | |
| x = F.gelu(self.conv1(input_features)) | |
| x = F.gelu(self.conv2(x)) | |
| x = x.permute(0, 2, 1) | |
| seq_len = x.shape[1] | |
| positions = torch.arange(seq_len, device=x.device) | |
| hidden_states = x + self.embed_positions(positions) | |
| hidden_states = F.dropout(hidden_states, p=self.dropout, training=self.training) | |
| for idx, encoder_layer in enumerate(self.layers): | |
| if self.training: | |
| dropout_probability = torch.rand([]) | |
| if dropout_probability < self.layerdrop: | |
| continue | |
| hidden_states = encoder_layer(hidden_states, None) | |
| hidden_states = self.layer_norm(hidden_states) | |
| return BaseModelOutput(last_hidden_state=hidden_states) | |
| def _get_feat_extract_output_lengths(self, input_lengths: torch.LongTensor): | |
| input_lengths = (input_lengths - 1) // 2 + 1 | |
| return input_lengths | |
| class MiniWhisperDecoder(PreTrainedModel): | |
| config_class = MiniWhisperConfig | |
| main_input_name = "input_ids" | |
| def __init__(self, config: MiniWhisperConfig): | |
| super().__init__(config) | |
| self.dropout = config.dropout | |
| self.layerdrop = config.decoder_layerdrop | |
| self.padding_idx = config.pad_token_id | |
| self.max_target_positions = config.max_target_positions | |
| self.max_source_positions = config.max_source_positions | |
| self.embed_scale = math.sqrt(config.d_model) if config.scale_embedding else 1.0 | |
| self.embed_tokens = nn.Embedding(config.vocab_size, config.d_model, self.padding_idx) | |
| self.embed_positions = WhisperPositionalEmbedding(self.max_target_positions, config.d_model) | |
| self.layers = nn.ModuleList( | |
| [MiniWhisperDecoderLayer(config, layer_idx) for layer_idx in range(config.decoder_layers)] | |
| ) | |
| self.layer_norm = nn.LayerNorm(config.d_model) | |
| self.gradient_checkpointing = False | |
| self.post_init() | |
| def forward( | |
| self, | |
| input_ids=None, | |
| attention_mask=None, | |
| encoder_hidden_states=None, | |
| encoder_attention_mask=None, | |
| past_key_values=None, | |
| inputs_embeds=None, | |
| position_ids=None, | |
| use_cache=None, | |
| **kwargs, | |
| ): | |
| if input_ids is not None and inputs_embeds is not None: | |
| raise ValueError("You cannot specify both decoder_input_ids and decoder_inputs_embeds at the same time") | |
| elif input_ids is not None: | |
| inputs_embeds = self.embed_tokens(input_ids) | |
| elif inputs_embeds is None: | |
| raise ValueError("You have to specify either decoder_input_ids or decoder_inputs_embeds") | |
| past_key_values_length = 0 | |
| if past_key_values is not None and len(past_key_values) > 0: | |
| if past_key_values[0] is not None and past_key_values[0][0] is not None: | |
| past_key_values_length = past_key_values[0][0].shape[2] | |
| if position_ids is None: | |
| position_ids = torch.arange(inputs_embeds.shape[1], device=inputs_embeds.device) + past_key_values_length | |
| position_ids = position_ids.unsqueeze(0).repeat(inputs_embeds.shape[0], 1) | |
| if input_ids is not None: | |
| positions = self.embed_positions(input_ids, past_key_values_length=past_key_values_length, position_ids=position_ids) | |
| else: | |
| positions = self.embed_positions(inputs_embeds, past_key_values_length=past_key_values_length, position_ids=position_ids) | |
| hidden_states = inputs_embeds + positions | |
| hidden_states = F.dropout(hidden_states, p=self.dropout, training=self.training) | |
| seq_len = inputs_embeds.shape[1] | |
| causal_mask = torch.triu( | |
| torch.ones(seq_len, seq_len, device=hidden_states.device) * float('-inf'), | |
| diagonal=1 | |
| ).unsqueeze(0).unsqueeze(0) | |
| if attention_mask is not None: | |
| padding_mask = (1 - attention_mask) * float('-inf') | |
| padding_mask = padding_mask.unsqueeze(1).unsqueeze(2) | |
| attention_mask = causal_mask + padding_mask | |
| else: | |
| attention_mask = causal_mask | |
| for idx, decoder_layer in enumerate(self.layers): | |
| if self.training: | |
| dropout_probability = torch.rand([]) | |
| if dropout_probability < self.layerdrop: | |
| continue | |
| layer_past = past_key_values[idx] if past_key_values is not None and idx < len(past_key_values) else None | |
| hidden_states, _ = decoder_layer( | |
| hidden_states, | |
| attention_mask=attention_mask, | |
| encoder_hidden_states=encoder_hidden_states, | |
| encoder_attention_mask=encoder_attention_mask, | |
| past_key_value=layer_past, | |
| use_cache=use_cache, | |
| ) | |
| hidden_states = self.layer_norm(hidden_states) | |
| return BaseModelOutputWithPastAndCrossAttentions( | |
| last_hidden_state=hidden_states, | |
| past_key_values=None, | |
| ) | |
| class MiniWhisperModel(PreTrainedModel): | |
| config_class = MiniWhisperConfig | |
| def __init__(self, config: MiniWhisperConfig): | |
| super().__init__(config) | |
| self.encoder = MiniWhisperEncoder(config) | |
| self.decoder = MiniWhisperDecoder(config) | |
| self.post_init() | |
| def get_input_embeddings(self): | |
| return self.decoder.embed_tokens | |
| def set_input_embeddings(self, value): | |
| self.decoder.embed_tokens = value | |
| def _mask_input_features( | |
| self, | |
| input_features: torch.FloatTensor, | |
| attention_mask: torch.LongTensor | None = None, | |
| ): | |
| """Apply SpecAugment""" | |
| import numpy as np | |
| if not getattr(self.config, "apply_spec_augment", True): | |
| return input_features | |
| batch_size, hidden_size, sequence_length = input_features.size() | |
| if self.config.mask_time_prob > 0 and self.training: | |
| mask_time_indices = _compute_mask_indices( | |
| (batch_size, sequence_length), | |
| mask_prob=self.config.mask_time_prob, | |
| mask_length=self.config.mask_time_length, | |
| attention_mask=attention_mask, | |
| min_masks=self.config.mask_time_min_masks, | |
| ) | |
| mask_time_indices = torch.tensor(mask_time_indices, device=input_features.device, dtype=torch.bool) | |
| mask_time_indices = mask_time_indices[:, None].expand(-1, hidden_size, -1) | |
| input_features[mask_time_indices] = 0 | |
| if self.config.mask_feature_prob > 0 and self.training: | |
| mask_feature_indices = _compute_mask_indices( | |
| (batch_size, hidden_size), | |
| mask_prob=self.config.mask_feature_prob, | |
| mask_length=self.config.mask_feature_length, | |
| min_masks=self.config.mask_feature_min_masks, | |
| ) | |
| mask_feature_indices = torch.tensor(mask_feature_indices, device=input_features.device, dtype=torch.bool) | |
| input_features[mask_feature_indices] = 0 | |
| return input_features | |
| def forward( | |
| self, | |
| input_features: torch.FloatTensor | None = None, | |
| attention_mask: torch.LongTensor | None = None, | |
| decoder_input_ids: torch.LongTensor | None = None, | |
| decoder_attention_mask: torch.LongTensor | None = None, | |
| encoder_outputs: tuple[torch.FloatTensor] | None = None, | |
| past_key_values: tuple[tuple[torch.FloatTensor]] | None = None, | |
| decoder_inputs_embeds: tuple[torch.FloatTensor] | None = None, | |
| decoder_position_ids: tuple[torch.LongTensor] | None = None, | |
| use_cache: bool | None = None, | |
| **kwargs, | |
| ): | |
| if encoder_outputs is None: | |
| input_features = self._mask_input_features(input_features, attention_mask=attention_mask) | |
| encoder_outputs = self.encoder(input_features, **kwargs) | |
| elif not isinstance(encoder_outputs, BaseModelOutput): | |
| encoder_outputs = BaseModelOutput( | |
| last_hidden_state=encoder_outputs[0], | |
| hidden_states=encoder_outputs[1] if len(encoder_outputs) > 1 else None, | |
| attentions=encoder_outputs[2] if len(encoder_outputs) > 2 else None, | |
| ) | |
| decoder_outputs = self.decoder( | |
| input_ids=decoder_input_ids, | |
| attention_mask=decoder_attention_mask, | |
| encoder_hidden_states=encoder_outputs.last_hidden_state, | |
| past_key_values=past_key_values, | |
| inputs_embeds=decoder_inputs_embeds, | |
| position_ids=decoder_position_ids, | |
| use_cache=use_cache, | |
| **kwargs, | |
| ) | |
| return Seq2SeqModelOutput( | |
| last_hidden_state=decoder_outputs.last_hidden_state, | |
| past_key_values=decoder_outputs.past_key_values, | |
| decoder_hidden_states=decoder_outputs.hidden_states, | |
| decoder_attentions=decoder_outputs.attentions, | |
| cross_attentions=decoder_outputs.cross_attentions, | |
| encoder_last_hidden_state=encoder_outputs.last_hidden_state, | |
| encoder_hidden_states=encoder_outputs.hidden_states, | |
| encoder_attentions=encoder_outputs.attentions, | |
| ) | |
| class MiniWhisperForConditionalGeneration(PreTrainedModel, GenerationMixin): | |
| config_class = MiniWhisperConfig | |
| base_model_prefix = "model" | |
| _tied_weights_keys = ["proj_out.weight"] | |
| def __init__(self, config: MiniWhisperConfig): | |
| super().__init__(config) | |
| self.model = MiniWhisperModel(config) | |
| self.proj_out = nn.Linear(config.d_model, config.vocab_size, bias=False) | |
| self.max_target_positions = config.max_target_positions | |
| self.post_init() | |
| def get_output_embeddings(self): | |
| return self.proj_out | |
| def set_output_embeddings(self, new_embeddings): | |
| self.proj_out = new_embeddings | |
| def get_input_embeddings(self): | |
| return self.model.get_input_embeddings() | |
| def forward( | |
| self, | |
| input_features: torch.FloatTensor | None = None, | |
| attention_mask: torch.LongTensor | None = None, | |
| decoder_input_ids: torch.LongTensor | None = None, | |
| decoder_attention_mask: torch.LongTensor | None = None, | |
| encoder_outputs: tuple[torch.FloatTensor] | None = None, | |
| past_key_values: tuple[tuple[torch.FloatTensor]] | None = None, | |
| decoder_inputs_embeds: tuple[torch.FloatTensor] | None = None, | |
| decoder_position_ids: tuple[torch.LongTensor] | None = None, | |
| labels: torch.LongTensor | None = None, | |
| use_cache: bool | None = None, | |
| **kwargs, | |
| ): | |
| if labels is not None: | |
| if labels.shape[1] > self.max_target_positions: | |
| raise ValueError(f"Labels' sequence length {labels.shape[1]} cannot exceed max_target_positions") | |
| if decoder_input_ids is None and decoder_inputs_embeds is None: | |
| decoder_input_ids = shift_tokens_right( | |
| labels, self.config.pad_token_id, self.config.decoder_start_token_id | |
| ) | |
| outputs = self.model( | |
| input_features, | |
| attention_mask=attention_mask, | |
| decoder_input_ids=decoder_input_ids, | |
| encoder_outputs=encoder_outputs, | |
| decoder_attention_mask=decoder_attention_mask, | |
| past_key_values=past_key_values, | |
| decoder_inputs_embeds=decoder_inputs_embeds, | |
| decoder_position_ids=decoder_position_ids, | |
| use_cache=use_cache, | |
| **kwargs, | |
| ) | |
| lm_logits = self.proj_out(outputs.last_hidden_state) | |
| loss = None | |
| if labels is not None: | |
| loss_fct = nn.CrossEntropyLoss() | |
| labels = labels.to(lm_logits.device) | |
| loss = loss_fct(lm_logits.view(-1, self.config.vocab_size), labels.view(-1)) | |
| return Seq2SeqLMOutput( | |
| loss=loss, | |
| logits=lm_logits, | |
| past_key_values=outputs.past_key_values, | |
| decoder_hidden_states=outputs.decoder_hidden_states, | |
| decoder_attentions=outputs.decoder_attentions, | |
| cross_attentions=outputs.cross_attentions, | |
| encoder_last_hidden_state=outputs.encoder_last_hidden_state, | |
| encoder_hidden_states=outputs.encoder_hidden_states, | |
| encoder_attentions=outputs.encoder_attentions, | |
| ) | |
| def generate( | |
| self, | |
| input_features, | |
| generation_config=None, | |
| max_new_tokens=50, | |
| **kwargs, | |
| ): | |
| self.eval() | |
| batch_size = input_features.shape[0] | |
| device = input_features.device | |
| decoder_input_ids = torch.full( | |
| (batch_size, 1), self.config.decoder_start_token_id, dtype=torch.long, device=device | |
| ) | |
| encoder_outputs = self.model.encoder(input_features) | |
| for _ in range(max_new_tokens): | |
| outputs = self.forward( | |
| decoder_input_ids=decoder_input_ids, | |
| encoder_outputs=encoder_outputs, | |
| use_cache=True, | |
| ) | |
| next_token_logits = outputs.logits[:, -1, :] | |
| next_token = torch.argmax(next_token_logits, dim=-1, keepdim=True) | |
| decoder_input_ids = torch.cat([decoder_input_ids, next_token], dim=1) | |
| if (next_token == self.config.eos_token_id).all(): | |
| break | |
| return decoder_input_ids | |
| def prepare_inputs_for_generation( | |
| self, | |
| decoder_input_ids, | |
| past_key_values=None, | |
| encoder_outputs=None, | |
| attention_mask=None, | |
| use_cache=None, | |
| **kwargs, | |
| ): | |
| return { | |
| "decoder_input_ids": decoder_input_ids, | |
| "past_key_values": past_key_values, | |
| "encoder_outputs": encoder_outputs, | |
| "attention_mask": attention_mask, | |
| "use_cache": use_cache, | |
| } | |
| def get_encoder(self): | |
| return self.model.get_encoder() | |
| __all__ = [ | |
| "MiniWhisperConfig", | |
| "MiniWhisperModel", | |
| "MiniWhisperForConditionalGeneration", | |
| "MiniWhisperEncoder", | |
| "MiniWhisperDecoder", | |
| "MiniWhisperEncoderLayer", | |
| "MiniWhisperDecoderLayer", | |
| "MiniWhisperAttention", | |
| "WhisperPositionalEmbedding", | |
| ] |