Add files using upload-large-folder tool
Browse filesThis view is limited to 50 files because it contains too many changes. See raw diff
- third_party/transformers/src/transformers/models/cohere2/modeling_cohere2.py +509 -0
- third_party/transformers/src/transformers/models/cohere2/modular_cohere2.py +325 -0
- third_party/transformers/src/transformers/models/conditional_detr/__init__.py +29 -0
- third_party/transformers/src/transformers/models/conditional_detr/configuration_conditional_detr.py +119 -0
- third_party/transformers/src/transformers/models/conditional_detr/convert_conditional_detr_original_pytorch_checkpoint_to_pytorch.py +363 -0
- third_party/transformers/src/transformers/models/conditional_detr/image_processing_conditional_detr.py +1083 -0
- third_party/transformers/src/transformers/models/conditional_detr/image_processing_pil_conditional_detr.py +1136 -0
- third_party/transformers/src/transformers/models/conditional_detr/modeling_conditional_detr.py +1827 -0
- third_party/transformers/src/transformers/models/conditional_detr/modular_conditional_detr.py +1109 -0
- third_party/transformers/src/transformers/models/donut/__init__.py +30 -0
- third_party/transformers/src/transformers/models/donut/configuration_donut_swin.py +76 -0
- third_party/transformers/src/transformers/models/donut/convert_donut_to_pytorch.py +233 -0
- third_party/transformers/src/transformers/models/donut/image_processing_donut.py +206 -0
- third_party/transformers/src/transformers/models/donut/image_processing_pil_donut.py +212 -0
- third_party/transformers/src/transformers/models/donut/modeling_donut_swin.py +967 -0
- third_party/transformers/src/transformers/models/donut/processing_donut.py +135 -0
- third_party/transformers/src/transformers/models/ibert/__init__.py +27 -0
- third_party/transformers/src/transformers/models/ibert/configuration_ibert.py +61 -0
- third_party/transformers/src/transformers/models/ibert/modeling_ibert.py +1201 -0
- third_party/transformers/src/transformers/models/ibert/quant_modules.py +819 -0
- third_party/transformers/src/transformers/models/layoutlm/__init__.py +29 -0
- third_party/transformers/src/transformers/models/layoutlm/configuration_layoutlm.py +67 -0
- third_party/transformers/src/transformers/models/layoutlm/modeling_layoutlm.py +1012 -0
- third_party/transformers/src/transformers/models/led/__init__.py +28 -0
- third_party/transformers/src/transformers/models/led/configuration_led.py +86 -0
- third_party/transformers/src/transformers/models/led/modeling_led.py +0 -0
- third_party/transformers/src/transformers/models/lfm2_moe/__init__.py +28 -0
- third_party/transformers/src/transformers/models/lfm2_moe/configuration_lfm2_moe.py +84 -0
- third_party/transformers/src/transformers/models/lfm2_moe/modeling_lfm2_moe.py +704 -0
- third_party/transformers/src/transformers/models/lfm2_moe/modular_lfm2_moe.py +214 -0
- third_party/transformers/src/transformers/models/lfm2_vl/__init__.py +29 -0
- third_party/transformers/src/transformers/models/lfm2_vl/configuration_lfm2_vl.py +63 -0
- third_party/transformers/src/transformers/models/lfm2_vl/image_processing_lfm2_vl.py +561 -0
- third_party/transformers/src/transformers/models/lfm2_vl/modeling_lfm2_vl.py +482 -0
- third_party/transformers/src/transformers/models/lfm2_vl/modular_lfm2_vl.py +359 -0
- third_party/transformers/src/transformers/models/lfm2_vl/processing_lfm2_vl.py +272 -0
- third_party/transformers/src/transformers/models/minimax_m2/__init__.py +28 -0
- third_party/transformers/src/transformers/models/minimax_m2/configuration_minimax_m2.py +94 -0
- third_party/transformers/src/transformers/models/minimax_m2/modeling_minimax_m2.py +691 -0
- third_party/transformers/src/transformers/models/minimax_m2/modular_minimax_m2.py +246 -0
- third_party/transformers/src/transformers/models/mixtral/__init__.py +27 -0
- third_party/transformers/src/transformers/models/mixtral/configuration_mixtral.py +93 -0
- third_party/transformers/src/transformers/models/mixtral/convert_mixtral_weights_to_hf.py +243 -0
- third_party/transformers/src/transformers/models/mixtral/modeling_mixtral.py +702 -0
- third_party/transformers/src/transformers/models/mixtral/modular_mixtral.py +448 -0
- third_party/transformers/src/transformers/models/mra/__init__.py +27 -0
- third_party/transformers/src/transformers/models/mra/configuration_mra.py +76 -0
- third_party/transformers/src/transformers/models/mra/convert_mra_pytorch_to_pytorch.py +109 -0
- third_party/transformers/src/transformers/models/mra/modeling_mra.py +1332 -0
- third_party/transformers/src/transformers/models/nemotron_h/__init__.py +27 -0
third_party/transformers/src/transformers/models/cohere2/modeling_cohere2.py
ADDED
|
@@ -0,0 +1,509 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
# 🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨
|
| 2 |
+
# This file was automatically generated from src/transformers/models/cohere2/modular_cohere2.py.
|
| 3 |
+
# Do NOT edit this file manually as any edits will be overwritten by the generation of
|
| 4 |
+
# the file from the modular. If any change should be done, please apply the change to the
|
| 5 |
+
# modular_cohere2.py file directly. One of our CI enforces this.
|
| 6 |
+
# 🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨
|
| 7 |
+
# Copyright 2024 Cohere Inc. HuggingFace Inc. team. All rights reserved.
|
| 8 |
+
#
|
| 9 |
+
#
|
| 10 |
+
# Licensed under the Apache License, Version 2.0 (the "License");
|
| 11 |
+
# you may not use this file except in compliance with the License.
|
| 12 |
+
# You may obtain a copy of the License at
|
| 13 |
+
#
|
| 14 |
+
# http://www.apache.org/licenses/LICENSE-2.0
|
| 15 |
+
#
|
| 16 |
+
# Unless required by applicable law or agreed to in writing, software
|
| 17 |
+
# distributed under the License is distributed on an "AS IS" BASIS,
|
| 18 |
+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
| 19 |
+
# See the License for the specific language governing permissions and
|
| 20 |
+
# limitations under the License.
|
| 21 |
+
from collections.abc import Callable
|
| 22 |
+
from typing import Optional
|
| 23 |
+
|
| 24 |
+
import torch
|
| 25 |
+
import torch.nn as nn
|
| 26 |
+
|
| 27 |
+
from ...activations import ACT2FN
|
| 28 |
+
from ...cache_utils import Cache, DynamicCache
|
| 29 |
+
from ...generation import GenerationMixin
|
| 30 |
+
from ...integrations import use_kernelized_func
|
| 31 |
+
from ...masking_utils import create_causal_mask, create_sliding_window_causal_mask
|
| 32 |
+
from ...modeling_layers import GradientCheckpointingLayer
|
| 33 |
+
from ...modeling_outputs import BaseModelOutputWithPast, CausalLMOutputWithPast
|
| 34 |
+
from ...modeling_rope_utils import ROPE_INIT_FUNCTIONS, dynamic_rope_update
|
| 35 |
+
from ...modeling_utils import ALL_ATTENTION_FUNCTIONS, PreTrainedModel
|
| 36 |
+
from ...processing_utils import Unpack
|
| 37 |
+
from ...utils import TransformersKwargs, auto_docstring, can_return_tuple
|
| 38 |
+
from ...utils.generic import maybe_autocast, merge_with_config_defaults
|
| 39 |
+
from ...utils.output_capturing import capture_outputs
|
| 40 |
+
from .configuration_cohere2 import Cohere2Config
|
| 41 |
+
|
| 42 |
+
|
| 43 |
+
class Cohere2RotaryEmbedding(nn.Module):
|
| 44 |
+
inv_freq: torch.Tensor # fix linting for `register_buffer`
|
| 45 |
+
|
| 46 |
+
def __init__(self, config: Cohere2Config, device=None):
|
| 47 |
+
super().__init__()
|
| 48 |
+
self.max_seq_len_cached = config.max_position_embeddings
|
| 49 |
+
self.original_max_seq_len = config.max_position_embeddings
|
| 50 |
+
|
| 51 |
+
self.config = config
|
| 52 |
+
|
| 53 |
+
self.rope_type = self.config.rope_parameters["rope_type"]
|
| 54 |
+
rope_init_fn: Callable = self.compute_default_rope_parameters
|
| 55 |
+
if self.rope_type != "default":
|
| 56 |
+
rope_init_fn = ROPE_INIT_FUNCTIONS[self.rope_type]
|
| 57 |
+
inv_freq, self.attention_scaling = rope_init_fn(self.config, device)
|
| 58 |
+
|
| 59 |
+
self.register_buffer("inv_freq", inv_freq, persistent=False)
|
| 60 |
+
self.register_buffer("original_inv_freq", inv_freq.clone(), persistent=False)
|
| 61 |
+
|
| 62 |
+
@staticmethod
|
| 63 |
+
def compute_default_rope_parameters(
|
| 64 |
+
config: Cohere2Config | None = None,
|
| 65 |
+
device: Optional["torch.device"] = None,
|
| 66 |
+
seq_len: int | None = None,
|
| 67 |
+
) -> tuple["torch.Tensor", float]:
|
| 68 |
+
"""
|
| 69 |
+
Computes the inverse frequencies according to the original RoPE implementation
|
| 70 |
+
Args:
|
| 71 |
+
config ([`~transformers.PreTrainedConfig`]):
|
| 72 |
+
The model configuration.
|
| 73 |
+
device (`torch.device`):
|
| 74 |
+
The device to use for initialization of the inverse frequencies.
|
| 75 |
+
seq_len (`int`, *optional*):
|
| 76 |
+
The current sequence length. Unused for this type of RoPE.
|
| 77 |
+
Returns:
|
| 78 |
+
Tuple of (`torch.Tensor`, `float`), containing the inverse frequencies for the RoPE embeddings and the
|
| 79 |
+
post-processing scaling factor applied to the computed cos/sin (unused in this type of RoPE).
|
| 80 |
+
"""
|
| 81 |
+
base = config.rope_parameters["rope_theta"]
|
| 82 |
+
dim = getattr(config, "head_dim", None) or config.hidden_size // config.num_attention_heads
|
| 83 |
+
|
| 84 |
+
attention_factor = 1.0 # Unused in this type of RoPE
|
| 85 |
+
|
| 86 |
+
# Compute the inverse frequencies
|
| 87 |
+
inv_freq = 1.0 / (
|
| 88 |
+
base ** (torch.arange(0, dim, 2, dtype=torch.int64).to(device=device, dtype=torch.float) / dim)
|
| 89 |
+
)
|
| 90 |
+
return inv_freq, attention_factor
|
| 91 |
+
|
| 92 |
+
@torch.no_grad()
|
| 93 |
+
@dynamic_rope_update # power user: used with advanced RoPE types (e.g. dynamic rope)
|
| 94 |
+
def forward(self, x, position_ids):
|
| 95 |
+
inv_freq_expanded = self.inv_freq[None, :, None].float().expand(position_ids.shape[0], -1, 1)
|
| 96 |
+
position_ids_expanded = position_ids[:, None, :].float()
|
| 97 |
+
|
| 98 |
+
device_type = x.device.type if isinstance(x.device.type, str) and x.device.type != "mps" else "cpu"
|
| 99 |
+
with maybe_autocast(device_type=device_type, enabled=False): # Force float32
|
| 100 |
+
freqs = (inv_freq_expanded.float() @ position_ids_expanded.float()).transpose(1, 2)
|
| 101 |
+
emb = torch.repeat_interleave(freqs, 2, dim=-1) # diff from Llama: we interleave() instead of cat()
|
| 102 |
+
cos = emb.cos() * self.attention_scaling
|
| 103 |
+
sin = emb.sin() * self.attention_scaling
|
| 104 |
+
|
| 105 |
+
return cos.to(dtype=x.dtype), sin.to(dtype=x.dtype)
|
| 106 |
+
|
| 107 |
+
|
| 108 |
+
class Cohere2LayerNorm(nn.Module):
|
| 109 |
+
def __init__(self, hidden_size=None, eps=1e-5, bias=False):
|
| 110 |
+
"""The hidden size can be a tuple or an int. The tuple is used for QKNorm to normalize across head_dim"""
|
| 111 |
+
super().__init__()
|
| 112 |
+
self.weight = nn.Parameter(torch.ones(hidden_size))
|
| 113 |
+
self.variance_epsilon = eps
|
| 114 |
+
|
| 115 |
+
def forward(self, hidden_states):
|
| 116 |
+
input_dtype = hidden_states.dtype
|
| 117 |
+
hidden_states = hidden_states.to(torch.float32)
|
| 118 |
+
mean = hidden_states.mean(-1, keepdim=True)
|
| 119 |
+
variance = (hidden_states - mean).pow(2).mean(-1, keepdim=True)
|
| 120 |
+
hidden_states = (hidden_states - mean) * torch.rsqrt(variance + self.variance_epsilon)
|
| 121 |
+
hidden_states = self.weight.to(torch.float32) * hidden_states
|
| 122 |
+
return hidden_states.to(input_dtype)
|
| 123 |
+
|
| 124 |
+
|
| 125 |
+
def repeat_kv(hidden_states: torch.Tensor, n_rep: int) -> torch.Tensor:
|
| 126 |
+
"""
|
| 127 |
+
This is the equivalent of torch.repeat_interleave(x, dim=1, repeats=n_rep). The hidden states go from (batch,
|
| 128 |
+
num_key_value_heads, seqlen, head_dim) to (batch, num_attention_heads, seqlen, head_dim)
|
| 129 |
+
"""
|
| 130 |
+
batch, num_key_value_heads, slen, head_dim = hidden_states.shape
|
| 131 |
+
if n_rep == 1:
|
| 132 |
+
return hidden_states
|
| 133 |
+
hidden_states = hidden_states[:, :, None, :, :].expand(batch, num_key_value_heads, n_rep, slen, head_dim)
|
| 134 |
+
return hidden_states.reshape(batch, num_key_value_heads * n_rep, slen, head_dim)
|
| 135 |
+
|
| 136 |
+
|
| 137 |
+
def eager_attention_forward(
|
| 138 |
+
module: nn.Module,
|
| 139 |
+
query: torch.Tensor,
|
| 140 |
+
key: torch.Tensor,
|
| 141 |
+
value: torch.Tensor,
|
| 142 |
+
attention_mask: torch.Tensor | None,
|
| 143 |
+
scaling: float,
|
| 144 |
+
dropout: float = 0.0,
|
| 145 |
+
**kwargs: Unpack[TransformersKwargs],
|
| 146 |
+
):
|
| 147 |
+
key_states = repeat_kv(key, module.num_key_value_groups)
|
| 148 |
+
value_states = repeat_kv(value, module.num_key_value_groups)
|
| 149 |
+
|
| 150 |
+
attn_weights = torch.matmul(query, key_states.transpose(2, 3)) * scaling
|
| 151 |
+
if attention_mask is not None:
|
| 152 |
+
attn_weights = attn_weights + attention_mask
|
| 153 |
+
|
| 154 |
+
attn_weights = nn.functional.softmax(attn_weights, dim=-1, dtype=torch.float32).to(query.dtype)
|
| 155 |
+
attn_weights = nn.functional.dropout(attn_weights, p=dropout, training=module.training)
|
| 156 |
+
attn_output = torch.matmul(attn_weights, value_states)
|
| 157 |
+
attn_output = attn_output.transpose(1, 2).contiguous()
|
| 158 |
+
|
| 159 |
+
return attn_output, attn_weights
|
| 160 |
+
|
| 161 |
+
|
| 162 |
+
def rotate_half(x):
|
| 163 |
+
# Split and rotate. Note that this function is different from e.g. Llama.
|
| 164 |
+
x1 = x[..., ::2]
|
| 165 |
+
x2 = x[..., 1::2]
|
| 166 |
+
rot_x = torch.stack([-x2, x1], dim=-1).flatten(-2)
|
| 167 |
+
return rot_x
|
| 168 |
+
|
| 169 |
+
|
| 170 |
+
def apply_rotary_pos_emb(q, k, cos, sin, unsqueeze_dim=1):
|
| 171 |
+
"""Applies Rotary Position Embedding to the query and key tensors.
|
| 172 |
+
|
| 173 |
+
Args:
|
| 174 |
+
q (`torch.Tensor`): The query tensor.
|
| 175 |
+
k (`torch.Tensor`): The key tensor.
|
| 176 |
+
cos (`torch.Tensor`): The cosine part of the rotary embedding.
|
| 177 |
+
sin (`torch.Tensor`): The sine part of the rotary embedding.
|
| 178 |
+
unsqueeze_dim (`int`, *optional*, defaults to 1):
|
| 179 |
+
The 'unsqueeze_dim' argument specifies the dimension along which to unsqueeze cos[position_ids] and
|
| 180 |
+
sin[position_ids] so that they can be properly broadcasted to the dimensions of q and k. For example, note
|
| 181 |
+
that cos[position_ids] and sin[position_ids] have the shape [batch_size, seq_len, head_dim]. Then, if q and
|
| 182 |
+
k have the shape [batch_size, heads, seq_len, head_dim], then setting unsqueeze_dim=1 makes
|
| 183 |
+
cos[position_ids] and sin[position_ids] broadcastable to the shapes of q and k. Similarly, if q and k have
|
| 184 |
+
the shape [batch_size, seq_len, heads, head_dim], then set unsqueeze_dim=2.
|
| 185 |
+
Returns:
|
| 186 |
+
`tuple(torch.Tensor)` comprising of the query and key tensors rotated using the Rotary Position Embedding.
|
| 187 |
+
"""
|
| 188 |
+
dtype = q.dtype
|
| 189 |
+
q = q.float()
|
| 190 |
+
k = k.float()
|
| 191 |
+
cos = cos.unsqueeze(unsqueeze_dim)
|
| 192 |
+
sin = sin.unsqueeze(unsqueeze_dim)
|
| 193 |
+
q_embed = (q * cos) + (rotate_half(q) * sin)
|
| 194 |
+
k_embed = (k * cos) + (rotate_half(k) * sin)
|
| 195 |
+
return q_embed.to(dtype=dtype), k_embed.to(dtype=dtype)
|
| 196 |
+
|
| 197 |
+
|
| 198 |
+
@use_kernelized_func(apply_rotary_pos_emb)
|
| 199 |
+
class Cohere2Attention(nn.Module):
|
| 200 |
+
"""Multi-headed attention from 'Attention Is All You Need' paper"""
|
| 201 |
+
|
| 202 |
+
def __init__(self, config: Cohere2Config, layer_idx: int | None = None):
|
| 203 |
+
super().__init__()
|
| 204 |
+
self.config = config
|
| 205 |
+
self.layer_idx = layer_idx
|
| 206 |
+
self.head_dim = getattr(config, "head_dim", config.hidden_size // config.num_attention_heads)
|
| 207 |
+
self.num_key_value_groups = config.num_attention_heads // config.num_key_value_heads
|
| 208 |
+
self.scaling = self.head_dim**-0.5
|
| 209 |
+
self.attention_dropout = config.attention_dropout
|
| 210 |
+
self.is_causal = True
|
| 211 |
+
layer_type = config.layer_types[layer_idx] if hasattr(config, "layer_types") else None
|
| 212 |
+
self.sliding_window = config.sliding_window if layer_type == "sliding_attention" else None
|
| 213 |
+
|
| 214 |
+
self.q_proj = nn.Linear(
|
| 215 |
+
config.hidden_size, config.num_attention_heads * self.head_dim, bias=config.attention_bias
|
| 216 |
+
)
|
| 217 |
+
self.k_proj = nn.Linear(
|
| 218 |
+
config.hidden_size, config.num_key_value_heads * self.head_dim, bias=config.attention_bias
|
| 219 |
+
)
|
| 220 |
+
self.v_proj = nn.Linear(
|
| 221 |
+
config.hidden_size, config.num_key_value_heads * self.head_dim, bias=config.attention_bias
|
| 222 |
+
)
|
| 223 |
+
self.o_proj = nn.Linear(
|
| 224 |
+
config.num_attention_heads * self.head_dim, config.hidden_size, bias=config.attention_bias
|
| 225 |
+
)
|
| 226 |
+
|
| 227 |
+
def forward(
|
| 228 |
+
self,
|
| 229 |
+
hidden_states: torch.Tensor,
|
| 230 |
+
position_embeddings: tuple[torch.Tensor, torch.Tensor],
|
| 231 |
+
attention_mask: torch.Tensor | None,
|
| 232 |
+
past_key_values: Cache | None = None,
|
| 233 |
+
**kwargs: Unpack[TransformersKwargs],
|
| 234 |
+
) -> tuple[torch.Tensor, torch.Tensor | None, tuple[torch.Tensor] | None]:
|
| 235 |
+
input_shape = hidden_states.shape[:-1]
|
| 236 |
+
hidden_shape = (*input_shape, -1, self.head_dim)
|
| 237 |
+
|
| 238 |
+
query_states = self.q_proj(hidden_states).view(hidden_shape).transpose(1, 2)
|
| 239 |
+
key_states = self.k_proj(hidden_states).view(hidden_shape).transpose(1, 2)
|
| 240 |
+
value_states = self.v_proj(hidden_states).view(hidden_shape).transpose(1, 2)
|
| 241 |
+
|
| 242 |
+
cos, sin = position_embeddings
|
| 243 |
+
if self.sliding_window is not None:
|
| 244 |
+
query_states, key_states = apply_rotary_pos_emb(query_states, key_states, cos, sin)
|
| 245 |
+
|
| 246 |
+
if past_key_values is not None:
|
| 247 |
+
key_states, value_states = past_key_values.update(key_states, value_states, self.layer_idx)
|
| 248 |
+
|
| 249 |
+
attention_interface: Callable = ALL_ATTENTION_FUNCTIONS.get_interface(
|
| 250 |
+
self.config._attn_implementation, eager_attention_forward
|
| 251 |
+
)
|
| 252 |
+
|
| 253 |
+
attn_output, attn_weights = attention_interface(
|
| 254 |
+
self,
|
| 255 |
+
query_states,
|
| 256 |
+
key_states,
|
| 257 |
+
value_states,
|
| 258 |
+
attention_mask,
|
| 259 |
+
dropout=0.0 if not self.training else self.attention_dropout,
|
| 260 |
+
scaling=self.scaling,
|
| 261 |
+
sliding_window=self.sliding_window,
|
| 262 |
+
**kwargs,
|
| 263 |
+
)
|
| 264 |
+
|
| 265 |
+
attn_output = attn_output.reshape(*input_shape, -1).contiguous()
|
| 266 |
+
attn_output = self.o_proj(attn_output)
|
| 267 |
+
return attn_output, attn_weights
|
| 268 |
+
|
| 269 |
+
|
| 270 |
+
class Cohere2MLP(nn.Module):
|
| 271 |
+
def __init__(self, config):
|
| 272 |
+
super().__init__()
|
| 273 |
+
self.config = config
|
| 274 |
+
self.hidden_size = config.hidden_size
|
| 275 |
+
self.intermediate_size = config.intermediate_size
|
| 276 |
+
self.gate_proj = nn.Linear(self.hidden_size, self.intermediate_size, bias=False)
|
| 277 |
+
self.up_proj = nn.Linear(self.hidden_size, self.intermediate_size, bias=False)
|
| 278 |
+
self.down_proj = nn.Linear(self.intermediate_size, self.hidden_size, bias=False)
|
| 279 |
+
self.act_fn = ACT2FN[config.hidden_act]
|
| 280 |
+
|
| 281 |
+
def forward(self, x):
|
| 282 |
+
down_proj = self.down_proj(self.act_fn(self.gate_proj(x)) * self.up_proj(x))
|
| 283 |
+
return down_proj
|
| 284 |
+
|
| 285 |
+
|
| 286 |
+
class Cohere2DecoderLayer(GradientCheckpointingLayer):
|
| 287 |
+
def __init__(self, config: Cohere2Config, layer_idx: int):
|
| 288 |
+
super().__init__()
|
| 289 |
+
self.hidden_size = config.hidden_size
|
| 290 |
+
self.self_attn = Cohere2Attention(config=config, layer_idx=layer_idx)
|
| 291 |
+
self.mlp = Cohere2MLP(config)
|
| 292 |
+
self.input_layernorm = Cohere2LayerNorm(hidden_size=(config.hidden_size), eps=config.layer_norm_eps)
|
| 293 |
+
|
| 294 |
+
def forward(
|
| 295 |
+
self,
|
| 296 |
+
hidden_states: torch.Tensor,
|
| 297 |
+
position_embeddings: tuple[torch.Tensor, torch.Tensor] | None = None,
|
| 298 |
+
attention_mask: torch.Tensor | None = None,
|
| 299 |
+
past_key_values: Cache | None = None,
|
| 300 |
+
use_cache: bool | None = False,
|
| 301 |
+
**kwargs: Unpack[TransformersKwargs],
|
| 302 |
+
) -> tuple[torch.FloatTensor, tuple[torch.FloatTensor, torch.FloatTensor] | None]:
|
| 303 |
+
"""
|
| 304 |
+
Args:
|
| 305 |
+
hidden_states (`torch.FloatTensor`): input to the layer of shape `(batch, seq_len, embed_dim)`
|
| 306 |
+
attention_mask (`torch.FloatTensor`, *optional*):
|
| 307 |
+
attention mask of size `(batch_size, sequence_length)` if flash attention is used or `(batch_size, 1,
|
| 308 |
+
query_sequence_length, key_sequence_length)` if default attention is used.
|
| 309 |
+
past_key_values (`Cache`, *optional*): cached past key and value projection states
|
| 310 |
+
output_attentions (`bool`, *optional*):
|
| 311 |
+
Whether or not to return the attentions tensors of all attention layers. See `attentions` under
|
| 312 |
+
returned tensors for more detail.
|
| 313 |
+
use_cache (`bool`, *optional*):
|
| 314 |
+
If set to `True`, `past_key_values` key value states are returned and can be used to speed up decoding
|
| 315 |
+
(see `past_key_values`).
|
| 316 |
+
position_embeddings (`tuple[torch.FloatTensor, torch.FloatTensor]`, *optional*):
|
| 317 |
+
Tuple containing the cosine and sine positional embeddings of shape `(batch_size, seq_len, head_dim)`,
|
| 318 |
+
with `head_dim` being the embedding dimension of each attention head.
|
| 319 |
+
"""
|
| 320 |
+
residual = hidden_states
|
| 321 |
+
hidden_states = self.input_layernorm(hidden_states)
|
| 322 |
+
hidden_states_attention, _ = self.self_attn(
|
| 323 |
+
hidden_states=hidden_states,
|
| 324 |
+
position_embeddings=position_embeddings,
|
| 325 |
+
attention_mask=attention_mask,
|
| 326 |
+
past_key_values=past_key_values,
|
| 327 |
+
use_cache=use_cache,
|
| 328 |
+
**kwargs,
|
| 329 |
+
)
|
| 330 |
+
|
| 331 |
+
hidden_states_mlp = self.mlp(hidden_states)
|
| 332 |
+
hidden_states = residual + hidden_states_attention + hidden_states_mlp
|
| 333 |
+
return hidden_states
|
| 334 |
+
|
| 335 |
+
|
| 336 |
+
@auto_docstring
|
| 337 |
+
class Cohere2PreTrainedModel(PreTrainedModel):
|
| 338 |
+
config: Cohere2Config
|
| 339 |
+
base_model_prefix = "model"
|
| 340 |
+
supports_gradient_checkpointing = True
|
| 341 |
+
_no_split_modules = ["Cohere2DecoderLayer"]
|
| 342 |
+
_skip_keys_device_placement = ["past_key_values"]
|
| 343 |
+
_supports_flash_attn = True
|
| 344 |
+
_supports_sdpa = True
|
| 345 |
+
_supports_flex_attn = True
|
| 346 |
+
|
| 347 |
+
_can_compile_fullgraph = True
|
| 348 |
+
_supports_attention_backend = True
|
| 349 |
+
_can_record_outputs = {
|
| 350 |
+
"hidden_states": Cohere2DecoderLayer,
|
| 351 |
+
"attentions": Cohere2Attention,
|
| 352 |
+
}
|
| 353 |
+
|
| 354 |
+
|
| 355 |
+
@auto_docstring
|
| 356 |
+
class Cohere2Model(Cohere2PreTrainedModel):
|
| 357 |
+
def __init__(self, config: Cohere2Config):
|
| 358 |
+
super().__init__(config)
|
| 359 |
+
self.padding_idx = config.pad_token_id
|
| 360 |
+
self.vocab_size = config.vocab_size
|
| 361 |
+
self.embed_tokens = nn.Embedding(config.vocab_size, config.hidden_size, self.padding_idx)
|
| 362 |
+
self.layers = nn.ModuleList(
|
| 363 |
+
[Cohere2DecoderLayer(config, layer_idx) for layer_idx in range(config.num_hidden_layers)]
|
| 364 |
+
)
|
| 365 |
+
self.norm = Cohere2LayerNorm(hidden_size=(config.hidden_size), eps=config.layer_norm_eps)
|
| 366 |
+
self.rotary_emb = Cohere2RotaryEmbedding(config)
|
| 367 |
+
self.gradient_checkpointing = False
|
| 368 |
+
|
| 369 |
+
# Initialize weights and apply final processing
|
| 370 |
+
self.post_init()
|
| 371 |
+
|
| 372 |
+
@merge_with_config_defaults
|
| 373 |
+
@capture_outputs
|
| 374 |
+
@auto_docstring
|
| 375 |
+
def forward(
|
| 376 |
+
self,
|
| 377 |
+
input_ids: torch.LongTensor | None = None,
|
| 378 |
+
attention_mask: torch.Tensor | None = None,
|
| 379 |
+
position_ids: torch.LongTensor | None = None,
|
| 380 |
+
past_key_values: Cache | None = None,
|
| 381 |
+
inputs_embeds: torch.FloatTensor | None = None,
|
| 382 |
+
use_cache: bool | None = None,
|
| 383 |
+
**kwargs: Unpack[TransformersKwargs],
|
| 384 |
+
) -> BaseModelOutputWithPast:
|
| 385 |
+
if (input_ids is None) ^ (inputs_embeds is not None):
|
| 386 |
+
raise ValueError("You must specify exactly one of input_ids or inputs_embeds")
|
| 387 |
+
|
| 388 |
+
if inputs_embeds is None:
|
| 389 |
+
inputs_embeds = self.embed_tokens(input_ids)
|
| 390 |
+
|
| 391 |
+
if use_cache and past_key_values is None:
|
| 392 |
+
past_key_values = DynamicCache(config=self.config)
|
| 393 |
+
|
| 394 |
+
if position_ids is None:
|
| 395 |
+
past_seen_tokens = past_key_values.get_seq_length() if past_key_values is not None else 0
|
| 396 |
+
position_ids = torch.arange(inputs_embeds.shape[1], device=inputs_embeds.device) + past_seen_tokens
|
| 397 |
+
position_ids = position_ids.unsqueeze(0)
|
| 398 |
+
|
| 399 |
+
if not isinstance(causal_mask_mapping := attention_mask, dict):
|
| 400 |
+
mask_kwargs = {
|
| 401 |
+
"config": self.config,
|
| 402 |
+
"inputs_embeds": inputs_embeds,
|
| 403 |
+
"attention_mask": attention_mask,
|
| 404 |
+
"past_key_values": past_key_values,
|
| 405 |
+
"position_ids": position_ids,
|
| 406 |
+
}
|
| 407 |
+
causal_mask_mapping = {
|
| 408 |
+
"full_attention": create_causal_mask(**mask_kwargs),
|
| 409 |
+
"sliding_attention": create_sliding_window_causal_mask(**mask_kwargs),
|
| 410 |
+
}
|
| 411 |
+
|
| 412 |
+
hidden_states = inputs_embeds
|
| 413 |
+
position_embeddings = self.rotary_emb(hidden_states, position_ids)
|
| 414 |
+
|
| 415 |
+
for i, decoder_layer in enumerate(self.layers):
|
| 416 |
+
hidden_states = decoder_layer(
|
| 417 |
+
hidden_states,
|
| 418 |
+
attention_mask=causal_mask_mapping[self.config.layer_types[i]],
|
| 419 |
+
position_embeddings=position_embeddings,
|
| 420 |
+
past_key_values=past_key_values,
|
| 421 |
+
use_cache=use_cache,
|
| 422 |
+
position_ids=position_ids,
|
| 423 |
+
**kwargs,
|
| 424 |
+
)
|
| 425 |
+
|
| 426 |
+
hidden_states = self.norm(hidden_states)
|
| 427 |
+
return BaseModelOutputWithPast(
|
| 428 |
+
last_hidden_state=hidden_states,
|
| 429 |
+
past_key_values=past_key_values,
|
| 430 |
+
)
|
| 431 |
+
|
| 432 |
+
|
| 433 |
+
@auto_docstring
|
| 434 |
+
class Cohere2ForCausalLM(Cohere2PreTrainedModel, GenerationMixin):
|
| 435 |
+
_tied_weights_keys = {"lm_head.weight": "model.embed_tokens.weight"}
|
| 436 |
+
_tp_plan = {"lm_head": "colwise_gather_output"}
|
| 437 |
+
_pp_plan = {"lm_head": (["hidden_states"], ["logits"])}
|
| 438 |
+
|
| 439 |
+
def __init__(self, config):
|
| 440 |
+
super().__init__(config)
|
| 441 |
+
self.model = Cohere2Model(config)
|
| 442 |
+
self.vocab_size = config.vocab_size
|
| 443 |
+
self.lm_head = nn.Linear(config.hidden_size, config.vocab_size, bias=False)
|
| 444 |
+
self.logit_scale = config.logit_scale
|
| 445 |
+
self.tie_word_embeddings = config.tie_word_embeddings
|
| 446 |
+
|
| 447 |
+
# Initialize weights and apply final processing
|
| 448 |
+
self.post_init()
|
| 449 |
+
|
| 450 |
+
@can_return_tuple
|
| 451 |
+
@auto_docstring
|
| 452 |
+
def forward(
|
| 453 |
+
self,
|
| 454 |
+
input_ids: torch.LongTensor | None = None,
|
| 455 |
+
attention_mask: torch.Tensor | None = None,
|
| 456 |
+
position_ids: torch.LongTensor | None = None,
|
| 457 |
+
past_key_values: Cache | None = None,
|
| 458 |
+
inputs_embeds: torch.FloatTensor | None = None,
|
| 459 |
+
labels: torch.LongTensor | None = None,
|
| 460 |
+
use_cache: bool | None = None,
|
| 461 |
+
logits_to_keep: int | torch.Tensor = 0,
|
| 462 |
+
**kwargs: Unpack[TransformersKwargs],
|
| 463 |
+
) -> CausalLMOutputWithPast:
|
| 464 |
+
r"""
|
| 465 |
+
Example:
|
| 466 |
+
|
| 467 |
+
```python
|
| 468 |
+
>> from transformers import AutoTokenizer, Cohere2ForCausalLM
|
| 469 |
+
|
| 470 |
+
>> model = Cohere2ForCausalLM.from_pretrained("Cohere2ForAI/c4ai-command-r-v01")
|
| 471 |
+
>> tokenizer = AutoTokenizer.from_pretrained("Cohere2ForAI/c4ai-command-r-v01")
|
| 472 |
+
|
| 473 |
+
>> prompt = "Hey, are you conscious? Can you talk to me?"
|
| 474 |
+
>> inputs = tokenizer(prompt, return_tensors="pt")
|
| 475 |
+
|
| 476 |
+
>> # Generate
|
| 477 |
+
>> generate_ids = model.generate(inputs.input_ids, max_length=30)
|
| 478 |
+
>> tokenizer.batch_decode(generate_ids, skip_special_tokens=True, clean_up_tokenization_spaces=False)[0]
|
| 479 |
+
"Hey, are you conscious? Can you talk to me?\nI'm not conscious, but I can talk to you."
|
| 480 |
+
```"""
|
| 481 |
+
outputs: BaseModelOutputWithPast = self.model(
|
| 482 |
+
input_ids=input_ids,
|
| 483 |
+
attention_mask=attention_mask,
|
| 484 |
+
position_ids=position_ids,
|
| 485 |
+
past_key_values=past_key_values,
|
| 486 |
+
inputs_embeds=inputs_embeds,
|
| 487 |
+
use_cache=use_cache,
|
| 488 |
+
**kwargs,
|
| 489 |
+
)
|
| 490 |
+
|
| 491 |
+
hidden_states = outputs.last_hidden_state
|
| 492 |
+
slice_indices = slice(-logits_to_keep, None) if isinstance(logits_to_keep, int) else logits_to_keep
|
| 493 |
+
logits = self.lm_head(hidden_states[:, slice_indices, :])
|
| 494 |
+
logits = logits * self.logit_scale # main diff from Llama
|
| 495 |
+
|
| 496 |
+
loss = None
|
| 497 |
+
if labels is not None:
|
| 498 |
+
loss = self.loss_function(logits=logits, labels=labels, vocab_size=self.config.vocab_size, **kwargs)
|
| 499 |
+
|
| 500 |
+
return CausalLMOutputWithPast(
|
| 501 |
+
loss=loss,
|
| 502 |
+
logits=logits,
|
| 503 |
+
past_key_values=outputs.past_key_values,
|
| 504 |
+
hidden_states=outputs.hidden_states,
|
| 505 |
+
attentions=outputs.attentions,
|
| 506 |
+
)
|
| 507 |
+
|
| 508 |
+
|
| 509 |
+
__all__ = ["Cohere2ForCausalLM", "Cohere2Model", "Cohere2PreTrainedModel"]
|
third_party/transformers/src/transformers/models/cohere2/modular_cohere2.py
ADDED
|
@@ -0,0 +1,325 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
# Copyright 2024 Cohere Inc. HuggingFace Inc. team. All rights reserved.
|
| 2 |
+
#
|
| 3 |
+
#
|
| 4 |
+
# Licensed under the Apache License, Version 2.0 (the "License");
|
| 5 |
+
# you may not use this file except in compliance with the License.
|
| 6 |
+
# You may obtain a copy of the License at
|
| 7 |
+
#
|
| 8 |
+
# http://www.apache.org/licenses/LICENSE-2.0
|
| 9 |
+
#
|
| 10 |
+
# Unless required by applicable law or agreed to in writing, software
|
| 11 |
+
# distributed under the License is distributed on an "AS IS" BASIS,
|
| 12 |
+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
| 13 |
+
# See the License for the specific language governing permissions and
|
| 14 |
+
# limitations under the License.
|
| 15 |
+
from collections.abc import Callable
|
| 16 |
+
|
| 17 |
+
import torch
|
| 18 |
+
import torch.nn as nn
|
| 19 |
+
from huggingface_hub.dataclasses import strict
|
| 20 |
+
|
| 21 |
+
from ...cache_utils import Cache, DynamicCache
|
| 22 |
+
from ...configuration_utils import PreTrainedConfig
|
| 23 |
+
from ...masking_utils import create_causal_mask, create_sliding_window_causal_mask
|
| 24 |
+
from ...modeling_outputs import BaseModelOutputWithPast
|
| 25 |
+
from ...modeling_rope_utils import (
|
| 26 |
+
RopeParameters,
|
| 27 |
+
dynamic_rope_update,
|
| 28 |
+
)
|
| 29 |
+
from ...modeling_utils import ALL_ATTENTION_FUNCTIONS
|
| 30 |
+
from ...processing_utils import Unpack
|
| 31 |
+
from ...utils import TransformersKwargs, auto_docstring, logging
|
| 32 |
+
from ...utils.generic import maybe_autocast
|
| 33 |
+
from ..cohere.modeling_cohere import (
|
| 34 |
+
CohereAttention,
|
| 35 |
+
CohereDecoderLayer,
|
| 36 |
+
CohereForCausalLM,
|
| 37 |
+
CohereLayerNorm,
|
| 38 |
+
CoherePreTrainedModel,
|
| 39 |
+
CohereRotaryEmbedding,
|
| 40 |
+
apply_rotary_pos_emb,
|
| 41 |
+
eager_attention_forward,
|
| 42 |
+
)
|
| 43 |
+
from ..gemma2.modeling_gemma2 import Gemma2Model
|
| 44 |
+
|
| 45 |
+
|
| 46 |
+
logger = logging.get_logger(__name__)
|
| 47 |
+
|
| 48 |
+
|
| 49 |
+
@auto_docstring(checkpoint="CohereForAI/c4ai-command-r-v01")
|
| 50 |
+
@strict
|
| 51 |
+
class Cohere2Config(PreTrainedConfig):
|
| 52 |
+
r"""
|
| 53 |
+
logit_scale (`float`, *optional*, defaults to 0.0625):
|
| 54 |
+
The scaling factor for the output logits.
|
| 55 |
+
|
| 56 |
+
```python
|
| 57 |
+
>>> from transformers import Cohere2Model, Cohere2Config
|
| 58 |
+
|
| 59 |
+
>>> # Initializing a Cohere Nextmodel configuration
|
| 60 |
+
>>> configuration = Cohere2Config()
|
| 61 |
+
|
| 62 |
+
>>> # Initializing a model from the Cohere2 configuration
|
| 63 |
+
>>> model = Cohere2Model(configuration) # doctest: +SKIP
|
| 64 |
+
|
| 65 |
+
>>> # Accessing the model configuration
|
| 66 |
+
>>> configuration = model.config # doctest: +SKIP
|
| 67 |
+
```
|
| 68 |
+
"""
|
| 69 |
+
|
| 70 |
+
model_type = "cohere2"
|
| 71 |
+
keys_to_ignore_at_inference = ["past_key_values"]
|
| 72 |
+
base_model_tp_plan = {
|
| 73 |
+
"layers.*.self_attn.q_proj": "colwise",
|
| 74 |
+
"layers.*.self_attn.k_proj": "colwise",
|
| 75 |
+
"layers.*.self_attn.v_proj": "colwise",
|
| 76 |
+
"layers.*.self_attn.o_proj": "rowwise",
|
| 77 |
+
"layers.*.mlp.gate_proj": "colwise",
|
| 78 |
+
"layers.*.mlp.up_proj": "colwise",
|
| 79 |
+
"layers.*.mlp.down_proj": "rowwise",
|
| 80 |
+
}
|
| 81 |
+
base_model_pp_plan = {
|
| 82 |
+
"embed_tokens": (["input_ids"], ["inputs_embeds"]),
|
| 83 |
+
"layers": (["hidden_states", "attention_mask"], ["hidden_states"]),
|
| 84 |
+
"norm": (["hidden_states"], ["hidden_states"]),
|
| 85 |
+
}
|
| 86 |
+
|
| 87 |
+
vocab_size: int = 256000
|
| 88 |
+
hidden_size: int = 8192
|
| 89 |
+
intermediate_size: int = 22528
|
| 90 |
+
logit_scale: float = 0.0625
|
| 91 |
+
num_hidden_layers: int = 40
|
| 92 |
+
num_attention_heads: int = 64
|
| 93 |
+
num_key_value_heads: int | None = None
|
| 94 |
+
hidden_act: str = "silu"
|
| 95 |
+
max_position_embeddings: int = 8192
|
| 96 |
+
initializer_range: float = 0.02
|
| 97 |
+
layer_norm_eps: float = 1e-5
|
| 98 |
+
use_cache: bool = True
|
| 99 |
+
pad_token_id: int | None = 0
|
| 100 |
+
bos_token_id: int | None = 5
|
| 101 |
+
eos_token_id: int | list[int] | None = 255001
|
| 102 |
+
tie_word_embeddings: bool = True
|
| 103 |
+
rope_parameters: RopeParameters | dict | None = None
|
| 104 |
+
attention_bias: bool = False
|
| 105 |
+
attention_dropout: float | int = 0.0
|
| 106 |
+
sliding_window: int | None = 4096
|
| 107 |
+
layer_types: list[str] | None = None
|
| 108 |
+
|
| 109 |
+
def __post_init__(self, **kwargs):
|
| 110 |
+
if self.num_key_value_heads is None:
|
| 111 |
+
self.num_key_value_heads = self.num_attention_heads
|
| 112 |
+
|
| 113 |
+
# Need to specify head_dim in the config so it can be used in the attention forward functions
|
| 114 |
+
self.head_dim = self.hidden_size // self.num_attention_heads
|
| 115 |
+
|
| 116 |
+
# BC -> the pattern used to be a simple int, and it's still present in configs on the Hub
|
| 117 |
+
if self.layer_types is None:
|
| 118 |
+
# BC -> the pattern used to be a simple int, and it's still present in configs on the Hub
|
| 119 |
+
_sliding_window_pattern = kwargs.pop("sliding_window_pattern", 4)
|
| 120 |
+
self.layer_types = [
|
| 121 |
+
"sliding_attention" if bool((i + 1) % _sliding_window_pattern) else "full_attention"
|
| 122 |
+
for i in range(self.num_hidden_layers)
|
| 123 |
+
]
|
| 124 |
+
|
| 125 |
+
super().__post_init__(**kwargs)
|
| 126 |
+
|
| 127 |
+
|
| 128 |
+
class Cohere2RotaryEmbedding(CohereRotaryEmbedding):
|
| 129 |
+
@torch.no_grad()
|
| 130 |
+
@dynamic_rope_update # power user: used with advanced RoPE types (e.g. dynamic rope)
|
| 131 |
+
def forward(self, x, position_ids):
|
| 132 |
+
inv_freq_expanded = self.inv_freq[None, :, None].float().expand(position_ids.shape[0], -1, 1)
|
| 133 |
+
position_ids_expanded = position_ids[:, None, :].float()
|
| 134 |
+
|
| 135 |
+
device_type = x.device.type if isinstance(x.device.type, str) and x.device.type != "mps" else "cpu"
|
| 136 |
+
with maybe_autocast(device_type=device_type, enabled=False): # Force float32
|
| 137 |
+
freqs = (inv_freq_expanded.float() @ position_ids_expanded.float()).transpose(1, 2)
|
| 138 |
+
emb = torch.repeat_interleave(freqs, 2, dim=-1) # diff from Llama: we interleave() instead of cat()
|
| 139 |
+
cos = emb.cos() * self.attention_scaling
|
| 140 |
+
sin = emb.sin() * self.attention_scaling
|
| 141 |
+
|
| 142 |
+
return cos.to(dtype=x.dtype), sin.to(dtype=x.dtype)
|
| 143 |
+
|
| 144 |
+
|
| 145 |
+
class Cohere2LayerNorm(CohereLayerNorm):
|
| 146 |
+
pass
|
| 147 |
+
|
| 148 |
+
|
| 149 |
+
class Cohere2Attention(CohereAttention):
|
| 150 |
+
"""Multi-headed attention from 'Attention Is All You Need' paper"""
|
| 151 |
+
|
| 152 |
+
def __init__(self, config: Cohere2Config, layer_idx: int | None = None):
|
| 153 |
+
nn.Module.__init__(self)
|
| 154 |
+
self.config = config
|
| 155 |
+
self.layer_idx = layer_idx
|
| 156 |
+
self.head_dim = getattr(config, "head_dim", config.hidden_size // config.num_attention_heads)
|
| 157 |
+
self.num_key_value_groups = config.num_attention_heads // config.num_key_value_heads
|
| 158 |
+
self.scaling = self.head_dim**-0.5
|
| 159 |
+
self.attention_dropout = config.attention_dropout
|
| 160 |
+
self.is_causal = True
|
| 161 |
+
layer_type = config.layer_types[layer_idx] if hasattr(config, "layer_types") else None
|
| 162 |
+
self.sliding_window = config.sliding_window if layer_type == "sliding_attention" else None
|
| 163 |
+
|
| 164 |
+
self.q_proj = nn.Linear(
|
| 165 |
+
config.hidden_size, config.num_attention_heads * self.head_dim, bias=config.attention_bias
|
| 166 |
+
)
|
| 167 |
+
self.k_proj = nn.Linear(
|
| 168 |
+
config.hidden_size, config.num_key_value_heads * self.head_dim, bias=config.attention_bias
|
| 169 |
+
)
|
| 170 |
+
self.v_proj = nn.Linear(
|
| 171 |
+
config.hidden_size, config.num_key_value_heads * self.head_dim, bias=config.attention_bias
|
| 172 |
+
)
|
| 173 |
+
self.o_proj = nn.Linear(
|
| 174 |
+
config.num_attention_heads * self.head_dim, config.hidden_size, bias=config.attention_bias
|
| 175 |
+
)
|
| 176 |
+
|
| 177 |
+
def forward(
|
| 178 |
+
self,
|
| 179 |
+
hidden_states: torch.Tensor,
|
| 180 |
+
position_embeddings: tuple[torch.Tensor, torch.Tensor],
|
| 181 |
+
attention_mask: torch.Tensor | None,
|
| 182 |
+
past_key_values: Cache | None = None,
|
| 183 |
+
**kwargs: Unpack[TransformersKwargs],
|
| 184 |
+
) -> tuple[torch.Tensor, torch.Tensor | None, tuple[torch.Tensor] | None]:
|
| 185 |
+
input_shape = hidden_states.shape[:-1]
|
| 186 |
+
hidden_shape = (*input_shape, -1, self.head_dim)
|
| 187 |
+
|
| 188 |
+
query_states = self.q_proj(hidden_states).view(hidden_shape).transpose(1, 2)
|
| 189 |
+
key_states = self.k_proj(hidden_states).view(hidden_shape).transpose(1, 2)
|
| 190 |
+
value_states = self.v_proj(hidden_states).view(hidden_shape).transpose(1, 2)
|
| 191 |
+
|
| 192 |
+
cos, sin = position_embeddings
|
| 193 |
+
if self.sliding_window is not None:
|
| 194 |
+
query_states, key_states = apply_rotary_pos_emb(query_states, key_states, cos, sin)
|
| 195 |
+
|
| 196 |
+
if past_key_values is not None:
|
| 197 |
+
key_states, value_states = past_key_values.update(key_states, value_states, self.layer_idx)
|
| 198 |
+
|
| 199 |
+
attention_interface: Callable = ALL_ATTENTION_FUNCTIONS.get_interface(
|
| 200 |
+
self.config._attn_implementation, eager_attention_forward
|
| 201 |
+
)
|
| 202 |
+
|
| 203 |
+
attn_output, attn_weights = attention_interface(
|
| 204 |
+
self,
|
| 205 |
+
query_states,
|
| 206 |
+
key_states,
|
| 207 |
+
value_states,
|
| 208 |
+
attention_mask,
|
| 209 |
+
dropout=0.0 if not self.training else self.attention_dropout,
|
| 210 |
+
scaling=self.scaling,
|
| 211 |
+
sliding_window=self.sliding_window,
|
| 212 |
+
**kwargs,
|
| 213 |
+
)
|
| 214 |
+
|
| 215 |
+
attn_output = attn_output.reshape(*input_shape, -1).contiguous()
|
| 216 |
+
attn_output = self.o_proj(attn_output)
|
| 217 |
+
return attn_output, attn_weights
|
| 218 |
+
|
| 219 |
+
|
| 220 |
+
class Cohere2DecoderLayer(CohereDecoderLayer):
|
| 221 |
+
def __init__(self, config: Cohere2Config, layer_idx: int):
|
| 222 |
+
super().__init__(config, layer_idx)
|
| 223 |
+
|
| 224 |
+
def forward(
|
| 225 |
+
self,
|
| 226 |
+
hidden_states: torch.Tensor,
|
| 227 |
+
position_embeddings: tuple[torch.Tensor, torch.Tensor] | None = None,
|
| 228 |
+
attention_mask: torch.Tensor | None = None,
|
| 229 |
+
past_key_values: Cache | None = None,
|
| 230 |
+
use_cache: bool | None = False,
|
| 231 |
+
**kwargs: Unpack[TransformersKwargs],
|
| 232 |
+
) -> tuple[torch.FloatTensor, tuple[torch.FloatTensor, torch.FloatTensor] | None]:
|
| 233 |
+
residual = hidden_states
|
| 234 |
+
hidden_states = self.input_layernorm(hidden_states)
|
| 235 |
+
hidden_states_attention, _ = self.self_attn(
|
| 236 |
+
hidden_states=hidden_states,
|
| 237 |
+
position_embeddings=position_embeddings,
|
| 238 |
+
attention_mask=attention_mask,
|
| 239 |
+
past_key_values=past_key_values,
|
| 240 |
+
use_cache=use_cache,
|
| 241 |
+
**kwargs,
|
| 242 |
+
)
|
| 243 |
+
|
| 244 |
+
hidden_states_mlp = self.mlp(hidden_states)
|
| 245 |
+
hidden_states = residual + hidden_states_attention + hidden_states_mlp
|
| 246 |
+
return hidden_states
|
| 247 |
+
|
| 248 |
+
|
| 249 |
+
class Cohere2PreTrainedModel(CoherePreTrainedModel):
|
| 250 |
+
config: Cohere2Config
|
| 251 |
+
_can_record_outputs = {
|
| 252 |
+
"hidden_states": Cohere2DecoderLayer,
|
| 253 |
+
"attentions": Cohere2Attention,
|
| 254 |
+
}
|
| 255 |
+
|
| 256 |
+
|
| 257 |
+
class Cohere2Model(Gemma2Model):
|
| 258 |
+
def __init__(self, config: Cohere2Config):
|
| 259 |
+
super().__init__(config)
|
| 260 |
+
self.norm = Cohere2LayerNorm(hidden_size=(config.hidden_size), eps=config.layer_norm_eps)
|
| 261 |
+
self.embed_tokens = nn.Embedding(config.vocab_size, config.hidden_size, self.padding_idx)
|
| 262 |
+
|
| 263 |
+
def forward(
|
| 264 |
+
self,
|
| 265 |
+
input_ids: torch.LongTensor | None = None,
|
| 266 |
+
attention_mask: torch.Tensor | None = None,
|
| 267 |
+
position_ids: torch.LongTensor | None = None,
|
| 268 |
+
past_key_values: Cache | None = None,
|
| 269 |
+
inputs_embeds: torch.FloatTensor | None = None,
|
| 270 |
+
use_cache: bool | None = None,
|
| 271 |
+
**kwargs: Unpack[TransformersKwargs],
|
| 272 |
+
) -> BaseModelOutputWithPast:
|
| 273 |
+
if (input_ids is None) ^ (inputs_embeds is not None):
|
| 274 |
+
raise ValueError("You must specify exactly one of input_ids or inputs_embeds")
|
| 275 |
+
|
| 276 |
+
if inputs_embeds is None:
|
| 277 |
+
inputs_embeds = self.embed_tokens(input_ids)
|
| 278 |
+
|
| 279 |
+
if use_cache and past_key_values is None:
|
| 280 |
+
past_key_values = DynamicCache(config=self.config)
|
| 281 |
+
|
| 282 |
+
if position_ids is None:
|
| 283 |
+
past_seen_tokens = past_key_values.get_seq_length() if past_key_values is not None else 0
|
| 284 |
+
position_ids = torch.arange(inputs_embeds.shape[1], device=inputs_embeds.device) + past_seen_tokens
|
| 285 |
+
position_ids = position_ids.unsqueeze(0)
|
| 286 |
+
|
| 287 |
+
if not isinstance(causal_mask_mapping := attention_mask, dict):
|
| 288 |
+
mask_kwargs = {
|
| 289 |
+
"config": self.config,
|
| 290 |
+
"inputs_embeds": inputs_embeds,
|
| 291 |
+
"attention_mask": attention_mask,
|
| 292 |
+
"past_key_values": past_key_values,
|
| 293 |
+
"position_ids": position_ids,
|
| 294 |
+
}
|
| 295 |
+
causal_mask_mapping = {
|
| 296 |
+
"full_attention": create_causal_mask(**mask_kwargs),
|
| 297 |
+
"sliding_attention": create_sliding_window_causal_mask(**mask_kwargs),
|
| 298 |
+
}
|
| 299 |
+
|
| 300 |
+
hidden_states = inputs_embeds
|
| 301 |
+
position_embeddings = self.rotary_emb(hidden_states, position_ids)
|
| 302 |
+
|
| 303 |
+
for i, decoder_layer in enumerate(self.layers):
|
| 304 |
+
hidden_states = decoder_layer(
|
| 305 |
+
hidden_states,
|
| 306 |
+
attention_mask=causal_mask_mapping[self.config.layer_types[i]],
|
| 307 |
+
position_embeddings=position_embeddings,
|
| 308 |
+
past_key_values=past_key_values,
|
| 309 |
+
use_cache=use_cache,
|
| 310 |
+
position_ids=position_ids,
|
| 311 |
+
**kwargs,
|
| 312 |
+
)
|
| 313 |
+
|
| 314 |
+
hidden_states = self.norm(hidden_states)
|
| 315 |
+
return BaseModelOutputWithPast(
|
| 316 |
+
last_hidden_state=hidden_states,
|
| 317 |
+
past_key_values=past_key_values,
|
| 318 |
+
)
|
| 319 |
+
|
| 320 |
+
|
| 321 |
+
class Cohere2ForCausalLM(CohereForCausalLM):
|
| 322 |
+
pass
|
| 323 |
+
|
| 324 |
+
|
| 325 |
+
__all__ = ["Cohere2Config", "Cohere2ForCausalLM", "Cohere2Model", "Cohere2PreTrainedModel"]
|
third_party/transformers/src/transformers/models/conditional_detr/__init__.py
ADDED
|
@@ -0,0 +1,29 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
# Copyright 2024 The HuggingFace Team. All rights reserved.
|
| 2 |
+
#
|
| 3 |
+
# Licensed under the Apache License, Version 2.0 (the "License");
|
| 4 |
+
# you may not use this file except in compliance with the License.
|
| 5 |
+
# You may obtain a copy of the License at
|
| 6 |
+
#
|
| 7 |
+
# http://www.apache.org/licenses/LICENSE-2.0
|
| 8 |
+
#
|
| 9 |
+
# Unless required by applicable law or agreed to in writing, software
|
| 10 |
+
# distributed under the License is distributed on an "AS IS" BASIS,
|
| 11 |
+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
| 12 |
+
# See the License for the specific language governing permissions and
|
| 13 |
+
# limitations under the License.
|
| 14 |
+
from typing import TYPE_CHECKING
|
| 15 |
+
|
| 16 |
+
from ...utils import _LazyModule
|
| 17 |
+
from ...utils.import_utils import define_import_structure
|
| 18 |
+
|
| 19 |
+
|
| 20 |
+
if TYPE_CHECKING:
|
| 21 |
+
from .configuration_conditional_detr import *
|
| 22 |
+
from .image_processing_conditional_detr import *
|
| 23 |
+
from .image_processing_pil_conditional_detr import *
|
| 24 |
+
from .modeling_conditional_detr import *
|
| 25 |
+
else:
|
| 26 |
+
import sys
|
| 27 |
+
|
| 28 |
+
_file = globals()["__file__"]
|
| 29 |
+
sys.modules[__name__] = _LazyModule(__name__, _file, define_import_structure(_file), module_spec=__spec__)
|
third_party/transformers/src/transformers/models/conditional_detr/configuration_conditional_detr.py
ADDED
|
@@ -0,0 +1,119 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
# Copyright 2022 The HuggingFace Inc. team. All rights reserved.
|
| 2 |
+
#
|
| 3 |
+
# Licensed under the Apache License, Version 2.0 (the "License");
|
| 4 |
+
# you may not use this file except in compliance with the License.
|
| 5 |
+
# You may obtain a copy of the License at
|
| 6 |
+
#
|
| 7 |
+
# http://www.apache.org/licenses/LICENSE-2.0
|
| 8 |
+
#
|
| 9 |
+
# Unless required by applicable law or agreed to in writing, software
|
| 10 |
+
# distributed under the License is distributed on an "AS IS" BASIS,
|
| 11 |
+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
| 12 |
+
# See the License for the specific language governing permissions and
|
| 13 |
+
# limitations under the License.
|
| 14 |
+
"""Conditional DETR model configuration"""
|
| 15 |
+
|
| 16 |
+
from huggingface_hub.dataclasses import strict
|
| 17 |
+
|
| 18 |
+
from ...backbone_utils import consolidate_backbone_kwargs_to_config
|
| 19 |
+
from ...configuration_utils import PreTrainedConfig
|
| 20 |
+
from ...utils import auto_docstring
|
| 21 |
+
from ..auto import AutoConfig
|
| 22 |
+
|
| 23 |
+
|
| 24 |
+
@auto_docstring(checkpoint="microsoft/conditional-detr-resnet-50")
|
| 25 |
+
@strict
|
| 26 |
+
class ConditionalDetrConfig(PreTrainedConfig):
|
| 27 |
+
r"""
|
| 28 |
+
num_queries (`int`, *optional*, defaults to 100):
|
| 29 |
+
Number of object queries, i.e. detection slots. This is the maximal number of objects
|
| 30 |
+
[`ConditionalDetrModel`] can detect in a single image. For COCO, we recommend 100 queries.
|
| 31 |
+
auxiliary_loss (`bool`, *optional*, defaults to `False`):
|
| 32 |
+
Whether auxiliary decoding losses (loss at each decoder layer) are to be used.
|
| 33 |
+
position_embedding_type (`str`, *optional*, defaults to `"sine"`):
|
| 34 |
+
Type of position embeddings to be used on top of the image features. One of `"sine"` or `"learned"`.
|
| 35 |
+
dilation (`bool`, *optional*, defaults to `False`):
|
| 36 |
+
Whether to replace stride with dilation in the last convolutional block (DC5). Only supported when
|
| 37 |
+
`use_timm_backbone` = `True`.
|
| 38 |
+
|
| 39 |
+
Examples:
|
| 40 |
+
|
| 41 |
+
```python
|
| 42 |
+
>>> from transformers import ConditionalDetrConfig, ConditionalDetrModel
|
| 43 |
+
|
| 44 |
+
>>> # Initializing a Conditional DETR microsoft/conditional-detr-resnet-50 style configuration
|
| 45 |
+
>>> configuration = ConditionalDetrConfig()
|
| 46 |
+
|
| 47 |
+
>>> # Initializing a model (with random weights) from the microsoft/conditional-detr-resnet-50 style configuration
|
| 48 |
+
>>> model = ConditionalDetrModel(configuration)
|
| 49 |
+
|
| 50 |
+
>>> # Accessing the model configuration
|
| 51 |
+
>>> configuration = model.config
|
| 52 |
+
```"""
|
| 53 |
+
|
| 54 |
+
model_type = "conditional_detr"
|
| 55 |
+
sub_configs = {"backbone_config": AutoConfig}
|
| 56 |
+
keys_to_ignore_at_inference = ["past_key_values"]
|
| 57 |
+
attribute_map = {
|
| 58 |
+
"hidden_size": "d_model",
|
| 59 |
+
"num_attention_heads": "encoder_attention_heads",
|
| 60 |
+
"num_hidden_layers": "encoder_layers",
|
| 61 |
+
}
|
| 62 |
+
|
| 63 |
+
backbone_config: dict | PreTrainedConfig | None = None
|
| 64 |
+
num_channels: int = 3
|
| 65 |
+
num_queries: int = 300
|
| 66 |
+
encoder_layers: int = 6
|
| 67 |
+
encoder_ffn_dim: int = 2048
|
| 68 |
+
encoder_attention_heads: int = 8
|
| 69 |
+
decoder_layers: int = 6
|
| 70 |
+
decoder_ffn_dim: int = 2048
|
| 71 |
+
decoder_attention_heads: int = 8
|
| 72 |
+
encoder_layerdrop: float | int = 0.0
|
| 73 |
+
decoder_layerdrop: float | int = 0.0
|
| 74 |
+
is_encoder_decoder: bool = True
|
| 75 |
+
activation_function: str = "relu"
|
| 76 |
+
d_model: int = 256
|
| 77 |
+
dropout: float | int = 0.1
|
| 78 |
+
attention_dropout: float | int = 0.0
|
| 79 |
+
activation_dropout: float | int = 0.0
|
| 80 |
+
init_std: float = 0.02
|
| 81 |
+
init_xavier_std: float = 1.0
|
| 82 |
+
auxiliary_loss: bool = False
|
| 83 |
+
position_embedding_type: str = "sine"
|
| 84 |
+
dilation: bool = False
|
| 85 |
+
class_cost: int = 2
|
| 86 |
+
bbox_cost: int = 5
|
| 87 |
+
giou_cost: int = 2
|
| 88 |
+
mask_loss_coefficient: int = 1
|
| 89 |
+
dice_loss_coefficient: int = 1
|
| 90 |
+
cls_loss_coefficient: int = 2
|
| 91 |
+
bbox_loss_coefficient: int = 5
|
| 92 |
+
giou_loss_coefficient: int = 2
|
| 93 |
+
focal_alpha: float = 0.25
|
| 94 |
+
|
| 95 |
+
def __post_init__(self, **kwargs):
|
| 96 |
+
# Init timm backbone with hardcoded values for BC
|
| 97 |
+
backbone_kwargs = kwargs.get("backbone_kwargs", {})
|
| 98 |
+
timm_default_kwargs = {
|
| 99 |
+
"num_channels": backbone_kwargs.get("num_channels", self.num_channels),
|
| 100 |
+
"features_only": True,
|
| 101 |
+
"use_pretrained_backbone": False,
|
| 102 |
+
"out_indices": backbone_kwargs.get("out_indices", [1, 2, 3, 4]),
|
| 103 |
+
}
|
| 104 |
+
if self.dilation:
|
| 105 |
+
timm_default_kwargs["output_stride"] = backbone_kwargs.get("output_stride", 16)
|
| 106 |
+
|
| 107 |
+
self.backbone_config, kwargs = consolidate_backbone_kwargs_to_config(
|
| 108 |
+
backbone_config=self.backbone_config,
|
| 109 |
+
default_backbone="resnet50",
|
| 110 |
+
default_config_type="resnet",
|
| 111 |
+
default_config_kwargs={"out_features": ["stage4"]},
|
| 112 |
+
timm_default_kwargs=timm_default_kwargs,
|
| 113 |
+
**kwargs,
|
| 114 |
+
)
|
| 115 |
+
|
| 116 |
+
super().__post_init__(**kwargs)
|
| 117 |
+
|
| 118 |
+
|
| 119 |
+
__all__ = ["ConditionalDetrConfig"]
|
third_party/transformers/src/transformers/models/conditional_detr/convert_conditional_detr_original_pytorch_checkpoint_to_pytorch.py
ADDED
|
@@ -0,0 +1,363 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
# Copyright 2022 The HuggingFace Inc. team.
|
| 2 |
+
#
|
| 3 |
+
# Licensed under the Apache License, Version 2.0 (the "License");
|
| 4 |
+
# you may not use this file except in compliance with the License.
|
| 5 |
+
# You may obtain a copy of the License at
|
| 6 |
+
#
|
| 7 |
+
# http://www.apache.org/licenses/LICENSE-2.0
|
| 8 |
+
#
|
| 9 |
+
# Unless required by applicable law or agreed to in writing, software
|
| 10 |
+
# distributed under the License is distributed on an "AS IS" BASIS,
|
| 11 |
+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
| 12 |
+
# See the License for the specific language governing permissions and
|
| 13 |
+
# limitations under the License.
|
| 14 |
+
"""Convert Conditional DETR checkpoints."""
|
| 15 |
+
|
| 16 |
+
import argparse
|
| 17 |
+
import json
|
| 18 |
+
from collections import OrderedDict
|
| 19 |
+
from io import BytesIO
|
| 20 |
+
from pathlib import Path
|
| 21 |
+
|
| 22 |
+
import httpx
|
| 23 |
+
import torch
|
| 24 |
+
from huggingface_hub import hf_hub_download
|
| 25 |
+
from PIL import Image
|
| 26 |
+
|
| 27 |
+
from transformers import (
|
| 28 |
+
ConditionalDetrConfig,
|
| 29 |
+
ConditionalDetrForObjectDetection,
|
| 30 |
+
ConditionalDetrForSegmentation,
|
| 31 |
+
ConditionalDetrImageProcessor,
|
| 32 |
+
)
|
| 33 |
+
from transformers.utils import logging
|
| 34 |
+
|
| 35 |
+
|
| 36 |
+
logging.set_verbosity_info()
|
| 37 |
+
logger = logging.get_logger(__name__)
|
| 38 |
+
|
| 39 |
+
# here we list all keys to be renamed (original name on the left, our name on the right)
|
| 40 |
+
rename_keys = []
|
| 41 |
+
for i in range(6):
|
| 42 |
+
# encoder layers: output projection, 2 feedforward neural networks and 2 layernorms
|
| 43 |
+
rename_keys.append(
|
| 44 |
+
(f"transformer.encoder.layers.{i}.self_attn.out_proj.weight", f"encoder.layers.{i}.self_attn.out_proj.weight")
|
| 45 |
+
)
|
| 46 |
+
rename_keys.append(
|
| 47 |
+
(f"transformer.encoder.layers.{i}.self_attn.out_proj.bias", f"encoder.layers.{i}.self_attn.out_proj.bias")
|
| 48 |
+
)
|
| 49 |
+
rename_keys.append((f"transformer.encoder.layers.{i}.linear1.weight", f"encoder.layers.{i}.fc1.weight"))
|
| 50 |
+
rename_keys.append((f"transformer.encoder.layers.{i}.linear1.bias", f"encoder.layers.{i}.fc1.bias"))
|
| 51 |
+
rename_keys.append((f"transformer.encoder.layers.{i}.linear2.weight", f"encoder.layers.{i}.fc2.weight"))
|
| 52 |
+
rename_keys.append((f"transformer.encoder.layers.{i}.linear2.bias", f"encoder.layers.{i}.fc2.bias"))
|
| 53 |
+
rename_keys.append(
|
| 54 |
+
(f"transformer.encoder.layers.{i}.norm1.weight", f"encoder.layers.{i}.self_attn_layer_norm.weight")
|
| 55 |
+
)
|
| 56 |
+
rename_keys.append((f"transformer.encoder.layers.{i}.norm1.bias", f"encoder.layers.{i}.self_attn_layer_norm.bias"))
|
| 57 |
+
rename_keys.append((f"transformer.encoder.layers.{i}.norm2.weight", f"encoder.layers.{i}.final_layer_norm.weight"))
|
| 58 |
+
rename_keys.append((f"transformer.encoder.layers.{i}.norm2.bias", f"encoder.layers.{i}.final_layer_norm.bias"))
|
| 59 |
+
# decoder layers: 2 times output projection, 2 feedforward neural networks and 3 layernorms
|
| 60 |
+
rename_keys.append(
|
| 61 |
+
(f"transformer.decoder.layers.{i}.self_attn.out_proj.weight", f"decoder.layers.{i}.self_attn.out_proj.weight")
|
| 62 |
+
)
|
| 63 |
+
rename_keys.append(
|
| 64 |
+
(f"transformer.decoder.layers.{i}.self_attn.out_proj.bias", f"decoder.layers.{i}.self_attn.out_proj.bias")
|
| 65 |
+
)
|
| 66 |
+
rename_keys.append(
|
| 67 |
+
(
|
| 68 |
+
f"transformer.decoder.layers.{i}.cross_attn.out_proj.weight",
|
| 69 |
+
f"decoder.layers.{i}.encoder_attn.out_proj.weight",
|
| 70 |
+
)
|
| 71 |
+
)
|
| 72 |
+
rename_keys.append(
|
| 73 |
+
(
|
| 74 |
+
f"transformer.decoder.layers.{i}.cross_attn.out_proj.bias",
|
| 75 |
+
f"decoder.layers.{i}.encoder_attn.out_proj.bias",
|
| 76 |
+
)
|
| 77 |
+
)
|
| 78 |
+
rename_keys.append((f"transformer.decoder.layers.{i}.linear1.weight", f"decoder.layers.{i}.fc1.weight"))
|
| 79 |
+
rename_keys.append((f"transformer.decoder.layers.{i}.linear1.bias", f"decoder.layers.{i}.fc1.bias"))
|
| 80 |
+
rename_keys.append((f"transformer.decoder.layers.{i}.linear2.weight", f"decoder.layers.{i}.fc2.weight"))
|
| 81 |
+
rename_keys.append((f"transformer.decoder.layers.{i}.linear2.bias", f"decoder.layers.{i}.fc2.bias"))
|
| 82 |
+
rename_keys.append(
|
| 83 |
+
(f"transformer.decoder.layers.{i}.norm1.weight", f"decoder.layers.{i}.self_attn_layer_norm.weight")
|
| 84 |
+
)
|
| 85 |
+
rename_keys.append((f"transformer.decoder.layers.{i}.norm1.bias", f"decoder.layers.{i}.self_attn_layer_norm.bias"))
|
| 86 |
+
rename_keys.append(
|
| 87 |
+
(f"transformer.decoder.layers.{i}.norm2.weight", f"decoder.layers.{i}.encoder_attn_layer_norm.weight")
|
| 88 |
+
)
|
| 89 |
+
rename_keys.append(
|
| 90 |
+
(f"transformer.decoder.layers.{i}.norm2.bias", f"decoder.layers.{i}.encoder_attn_layer_norm.bias")
|
| 91 |
+
)
|
| 92 |
+
rename_keys.append((f"transformer.decoder.layers.{i}.norm3.weight", f"decoder.layers.{i}.final_layer_norm.weight"))
|
| 93 |
+
rename_keys.append((f"transformer.decoder.layers.{i}.norm3.bias", f"decoder.layers.{i}.final_layer_norm.bias"))
|
| 94 |
+
|
| 95 |
+
# q, k, v projections in self/cross-attention in decoder for conditional DETR
|
| 96 |
+
# Self-attention projections moved into self_attn module
|
| 97 |
+
rename_keys.append(
|
| 98 |
+
(
|
| 99 |
+
f"transformer.decoder.layers.{i}.sa_qcontent_proj.weight",
|
| 100 |
+
f"decoder.layers.{i}.self_attn.q_content_proj.weight",
|
| 101 |
+
)
|
| 102 |
+
)
|
| 103 |
+
rename_keys.append(
|
| 104 |
+
(
|
| 105 |
+
f"transformer.decoder.layers.{i}.sa_kcontent_proj.weight",
|
| 106 |
+
f"decoder.layers.{i}.self_attn.k_content_proj.weight",
|
| 107 |
+
)
|
| 108 |
+
)
|
| 109 |
+
rename_keys.append(
|
| 110 |
+
(f"transformer.decoder.layers.{i}.sa_qpos_proj.weight", f"decoder.layers.{i}.self_attn.q_pos_proj.weight")
|
| 111 |
+
)
|
| 112 |
+
rename_keys.append(
|
| 113 |
+
(f"transformer.decoder.layers.{i}.sa_kpos_proj.weight", f"decoder.layers.{i}.self_attn.k_pos_proj.weight")
|
| 114 |
+
)
|
| 115 |
+
rename_keys.append(
|
| 116 |
+
(f"transformer.decoder.layers.{i}.sa_v_proj.weight", f"decoder.layers.{i}.self_attn.v_proj.weight")
|
| 117 |
+
)
|
| 118 |
+
# Cross-attention projections moved into encoder_attn module
|
| 119 |
+
rename_keys.append(
|
| 120 |
+
(
|
| 121 |
+
f"transformer.decoder.layers.{i}.ca_qcontent_proj.weight",
|
| 122 |
+
f"decoder.layers.{i}.encoder_attn.q_content_proj.weight",
|
| 123 |
+
)
|
| 124 |
+
)
|
| 125 |
+
# rename_keys.append((f"transformer.decoder.layers.{i}.ca_qpos_proj.weight", f"decoder.layers.{i}.encoder_attn.q_pos_proj.weight"))
|
| 126 |
+
rename_keys.append(
|
| 127 |
+
(
|
| 128 |
+
f"transformer.decoder.layers.{i}.ca_kcontent_proj.weight",
|
| 129 |
+
f"decoder.layers.{i}.encoder_attn.k_content_proj.weight",
|
| 130 |
+
)
|
| 131 |
+
)
|
| 132 |
+
rename_keys.append(
|
| 133 |
+
(f"transformer.decoder.layers.{i}.ca_kpos_proj.weight", f"decoder.layers.{i}.encoder_attn.k_pos_proj.weight")
|
| 134 |
+
)
|
| 135 |
+
rename_keys.append(
|
| 136 |
+
(f"transformer.decoder.layers.{i}.ca_v_proj.weight", f"decoder.layers.{i}.encoder_attn.v_proj.weight")
|
| 137 |
+
)
|
| 138 |
+
rename_keys.append(
|
| 139 |
+
(
|
| 140 |
+
f"transformer.decoder.layers.{i}.ca_qpos_sine_proj.weight",
|
| 141 |
+
f"decoder.layers.{i}.encoder_attn.q_pos_sine_proj.weight",
|
| 142 |
+
)
|
| 143 |
+
)
|
| 144 |
+
|
| 145 |
+
rename_keys.append(
|
| 146 |
+
(f"transformer.decoder.layers.{i}.sa_qcontent_proj.bias", f"decoder.layers.{i}.self_attn.q_content_proj.bias")
|
| 147 |
+
)
|
| 148 |
+
rename_keys.append(
|
| 149 |
+
(f"transformer.decoder.layers.{i}.sa_kcontent_proj.bias", f"decoder.layers.{i}.self_attn.k_content_proj.bias")
|
| 150 |
+
)
|
| 151 |
+
rename_keys.append(
|
| 152 |
+
(f"transformer.decoder.layers.{i}.sa_qpos_proj.bias", f"decoder.layers.{i}.self_attn.q_pos_proj.bias")
|
| 153 |
+
)
|
| 154 |
+
rename_keys.append(
|
| 155 |
+
(f"transformer.decoder.layers.{i}.sa_kpos_proj.bias", f"decoder.layers.{i}.self_attn.k_pos_proj.bias")
|
| 156 |
+
)
|
| 157 |
+
rename_keys.append((f"transformer.decoder.layers.{i}.sa_v_proj.bias", f"decoder.layers.{i}.self_attn.v_proj.bias"))
|
| 158 |
+
rename_keys.append(
|
| 159 |
+
(
|
| 160 |
+
f"transformer.decoder.layers.{i}.ca_qcontent_proj.bias",
|
| 161 |
+
f"decoder.layers.{i}.encoder_attn.q_content_proj.bias",
|
| 162 |
+
)
|
| 163 |
+
)
|
| 164 |
+
# rename_keys.append((f"transformer.decoder.layers.{i}.ca_qpos_proj.bias", f"decoder.layers.{i}.encoder_attn.q_pos_proj.bias"))
|
| 165 |
+
rename_keys.append(
|
| 166 |
+
(
|
| 167 |
+
f"transformer.decoder.layers.{i}.ca_kcontent_proj.bias",
|
| 168 |
+
f"decoder.layers.{i}.encoder_attn.k_content_proj.bias",
|
| 169 |
+
)
|
| 170 |
+
)
|
| 171 |
+
rename_keys.append(
|
| 172 |
+
(f"transformer.decoder.layers.{i}.ca_kpos_proj.bias", f"decoder.layers.{i}.encoder_attn.k_pos_proj.bias")
|
| 173 |
+
)
|
| 174 |
+
rename_keys.append(
|
| 175 |
+
(f"transformer.decoder.layers.{i}.ca_v_proj.bias", f"decoder.layers.{i}.encoder_attn.v_proj.bias")
|
| 176 |
+
)
|
| 177 |
+
rename_keys.append(
|
| 178 |
+
(
|
| 179 |
+
f"transformer.decoder.layers.{i}.ca_qpos_sine_proj.bias",
|
| 180 |
+
f"decoder.layers.{i}.encoder_attn.q_pos_sine_proj.bias",
|
| 181 |
+
)
|
| 182 |
+
)
|
| 183 |
+
|
| 184 |
+
# convolutional projection + query embeddings + layernorm of decoder + class and bounding box heads
|
| 185 |
+
# for conditional DETR, also convert reference point head and query scale MLP
|
| 186 |
+
rename_keys.extend(
|
| 187 |
+
[
|
| 188 |
+
("input_proj.weight", "input_projection.weight"),
|
| 189 |
+
("input_proj.bias", "input_projection.bias"),
|
| 190 |
+
("query_embed.weight", "query_position_embeddings.weight"),
|
| 191 |
+
("transformer.decoder.norm.weight", "decoder.layernorm.weight"),
|
| 192 |
+
("transformer.decoder.norm.bias", "decoder.layernorm.bias"),
|
| 193 |
+
("class_embed.weight", "class_labels_classifier.weight"),
|
| 194 |
+
("class_embed.bias", "class_labels_classifier.bias"),
|
| 195 |
+
("bbox_embed.layers.0.weight", "bbox_predictor.layers.0.weight"),
|
| 196 |
+
("bbox_embed.layers.0.bias", "bbox_predictor.layers.0.bias"),
|
| 197 |
+
("bbox_embed.layers.1.weight", "bbox_predictor.layers.1.weight"),
|
| 198 |
+
("bbox_embed.layers.1.bias", "bbox_predictor.layers.1.bias"),
|
| 199 |
+
("bbox_embed.layers.2.weight", "bbox_predictor.layers.2.weight"),
|
| 200 |
+
("bbox_embed.layers.2.bias", "bbox_predictor.layers.2.bias"),
|
| 201 |
+
("transformer.decoder.ref_point_head.layers.0.weight", "decoder.ref_point_head.layers.0.weight"),
|
| 202 |
+
("transformer.decoder.ref_point_head.layers.0.bias", "decoder.ref_point_head.layers.0.bias"),
|
| 203 |
+
("transformer.decoder.ref_point_head.layers.1.weight", "decoder.ref_point_head.layers.1.weight"),
|
| 204 |
+
("transformer.decoder.ref_point_head.layers.1.bias", "decoder.ref_point_head.layers.1.bias"),
|
| 205 |
+
("transformer.decoder.query_scale.layers.0.weight", "decoder.query_scale.layers.0.weight"),
|
| 206 |
+
("transformer.decoder.query_scale.layers.0.bias", "decoder.query_scale.layers.0.bias"),
|
| 207 |
+
("transformer.decoder.query_scale.layers.1.weight", "decoder.query_scale.layers.1.weight"),
|
| 208 |
+
("transformer.decoder.query_scale.layers.1.bias", "decoder.query_scale.layers.1.bias"),
|
| 209 |
+
("transformer.decoder.layers.0.ca_qpos_proj.weight", "decoder.layers.0.encoder_attn.q_pos_proj.weight"),
|
| 210 |
+
("transformer.decoder.layers.0.ca_qpos_proj.bias", "decoder.layers.0.encoder_attn.q_pos_proj.bias"),
|
| 211 |
+
]
|
| 212 |
+
)
|
| 213 |
+
|
| 214 |
+
|
| 215 |
+
def rename_key(state_dict, old, new):
|
| 216 |
+
val = state_dict.pop(old)
|
| 217 |
+
state_dict[new] = val
|
| 218 |
+
|
| 219 |
+
|
| 220 |
+
def rename_backbone_keys(state_dict):
|
| 221 |
+
new_state_dict = OrderedDict()
|
| 222 |
+
for key, value in state_dict.items():
|
| 223 |
+
if "backbone.0.body" in key:
|
| 224 |
+
new_key = key.replace("backbone.0.body", "backbone.conv_encoder.model")
|
| 225 |
+
new_state_dict[new_key] = value
|
| 226 |
+
else:
|
| 227 |
+
new_state_dict[key] = value
|
| 228 |
+
|
| 229 |
+
return new_state_dict
|
| 230 |
+
|
| 231 |
+
|
| 232 |
+
def read_in_q_k_v(state_dict, is_panoptic=False):
|
| 233 |
+
prefix = ""
|
| 234 |
+
if is_panoptic:
|
| 235 |
+
prefix = "conditional_detr."
|
| 236 |
+
|
| 237 |
+
# first: transformer encoder
|
| 238 |
+
for i in range(6):
|
| 239 |
+
# read in weights + bias of input projection layer (in PyTorch's MultiHeadAttention, this is a single matrix + bias)
|
| 240 |
+
in_proj_weight = state_dict.pop(f"{prefix}transformer.encoder.layers.{i}.self_attn.in_proj_weight")
|
| 241 |
+
in_proj_bias = state_dict.pop(f"{prefix}transformer.encoder.layers.{i}.self_attn.in_proj_bias")
|
| 242 |
+
# next, add query, keys and values (in that order) to the state dict
|
| 243 |
+
state_dict[f"encoder.layers.{i}.self_attn.q_proj.weight"] = in_proj_weight[:256, :]
|
| 244 |
+
state_dict[f"encoder.layers.{i}.self_attn.q_proj.bias"] = in_proj_bias[:256]
|
| 245 |
+
state_dict[f"encoder.layers.{i}.self_attn.k_proj.weight"] = in_proj_weight[256:512, :]
|
| 246 |
+
state_dict[f"encoder.layers.{i}.self_attn.k_proj.bias"] = in_proj_bias[256:512]
|
| 247 |
+
state_dict[f"encoder.layers.{i}.self_attn.v_proj.weight"] = in_proj_weight[-256:, :]
|
| 248 |
+
state_dict[f"encoder.layers.{i}.self_attn.v_proj.bias"] = in_proj_bias[-256:]
|
| 249 |
+
|
| 250 |
+
|
| 251 |
+
# We will verify our results on an image of cute cats
|
| 252 |
+
def prepare_img():
|
| 253 |
+
url = "http://images.cocodataset.org/val2017/000000039769.jpg"
|
| 254 |
+
with httpx.stream("GET", url) as response:
|
| 255 |
+
image = Image.open(BytesIO(response.read()))
|
| 256 |
+
|
| 257 |
+
return image
|
| 258 |
+
|
| 259 |
+
|
| 260 |
+
@torch.no_grad()
|
| 261 |
+
def convert_conditional_detr_checkpoint(model_name, pytorch_dump_folder_path):
|
| 262 |
+
"""
|
| 263 |
+
Copy/paste/tweak model's weights to our CONDITIONAL_DETR structure.
|
| 264 |
+
"""
|
| 265 |
+
|
| 266 |
+
# load default config
|
| 267 |
+
config = ConditionalDetrConfig()
|
| 268 |
+
# set backbone and dilation attributes
|
| 269 |
+
if "resnet101" in model_name:
|
| 270 |
+
config.backbone = "resnet101"
|
| 271 |
+
if "dc5" in model_name:
|
| 272 |
+
config.dilation = True
|
| 273 |
+
is_panoptic = "panoptic" in model_name
|
| 274 |
+
if is_panoptic:
|
| 275 |
+
config.num_labels = 250
|
| 276 |
+
else:
|
| 277 |
+
config.num_labels = 91
|
| 278 |
+
repo_id = "huggingface/label-files"
|
| 279 |
+
filename = "coco-detection-id2label.json"
|
| 280 |
+
id2label = json.load(open(hf_hub_download(repo_id, filename, repo_type="dataset"), "r"))
|
| 281 |
+
id2label = {int(k): v for k, v in id2label.items()}
|
| 282 |
+
config.id2label = id2label
|
| 283 |
+
config.label2id = {v: k for k, v in id2label.items()}
|
| 284 |
+
|
| 285 |
+
# load image processor
|
| 286 |
+
format = "coco_panoptic" if is_panoptic else "coco_detection"
|
| 287 |
+
image_processor = ConditionalDetrImageProcessor(format=format)
|
| 288 |
+
|
| 289 |
+
# prepare image
|
| 290 |
+
img = prepare_img()
|
| 291 |
+
encoding = image_processor(images=img, return_tensors="pt")
|
| 292 |
+
pixel_values = encoding["pixel_values"]
|
| 293 |
+
|
| 294 |
+
logger.info(f"Converting model {model_name}...")
|
| 295 |
+
|
| 296 |
+
# load original model from torch hub
|
| 297 |
+
conditional_detr = torch.hub.load("DeppMeng/ConditionalDETR", model_name, pretrained=True).eval()
|
| 298 |
+
state_dict = conditional_detr.state_dict()
|
| 299 |
+
# rename keys
|
| 300 |
+
for src, dest in rename_keys:
|
| 301 |
+
if is_panoptic:
|
| 302 |
+
src = "conditional_detr." + src
|
| 303 |
+
rename_key(state_dict, src, dest)
|
| 304 |
+
state_dict = rename_backbone_keys(state_dict)
|
| 305 |
+
# query, key and value matrices need special treatment
|
| 306 |
+
read_in_q_k_v(state_dict, is_panoptic=is_panoptic)
|
| 307 |
+
# important: we need to prepend a prefix to each of the base model keys as the head models use different attributes for them
|
| 308 |
+
prefix = "conditional_detr.model." if is_panoptic else "model."
|
| 309 |
+
for key in state_dict.copy():
|
| 310 |
+
if is_panoptic:
|
| 311 |
+
if (
|
| 312 |
+
key.startswith("conditional_detr")
|
| 313 |
+
and not key.startswith("class_labels_classifier")
|
| 314 |
+
and not key.startswith("bbox_predictor")
|
| 315 |
+
):
|
| 316 |
+
val = state_dict.pop(key)
|
| 317 |
+
state_dict["conditional_detr.model" + key[4:]] = val
|
| 318 |
+
elif "class_labels_classifier" in key or "bbox_predictor" in key:
|
| 319 |
+
val = state_dict.pop(key)
|
| 320 |
+
state_dict["conditional_detr." + key] = val
|
| 321 |
+
elif key.startswith("bbox_attention") or key.startswith("mask_head"):
|
| 322 |
+
continue
|
| 323 |
+
else:
|
| 324 |
+
val = state_dict.pop(key)
|
| 325 |
+
state_dict[prefix + key] = val
|
| 326 |
+
else:
|
| 327 |
+
if not key.startswith("class_labels_classifier") and not key.startswith("bbox_predictor"):
|
| 328 |
+
val = state_dict.pop(key)
|
| 329 |
+
state_dict[prefix + key] = val
|
| 330 |
+
# finally, create HuggingFace model and load state dict
|
| 331 |
+
model = ConditionalDetrForSegmentation(config) if is_panoptic else ConditionalDetrForObjectDetection(config)
|
| 332 |
+
model.load_state_dict(state_dict)
|
| 333 |
+
model.eval()
|
| 334 |
+
model.push_to_hub(repo_id=f"DepuMeng/{model_name}", commit_message="Add model")
|
| 335 |
+
# verify our conversion
|
| 336 |
+
original_outputs = conditional_detr(pixel_values)
|
| 337 |
+
outputs = model(pixel_values)
|
| 338 |
+
assert torch.allclose(outputs.logits, original_outputs["pred_logits"], atol=1e-4)
|
| 339 |
+
assert torch.allclose(outputs.pred_boxes, original_outputs["pred_boxes"], atol=1e-4)
|
| 340 |
+
if is_panoptic:
|
| 341 |
+
assert torch.allclose(outputs.pred_masks, original_outputs["pred_masks"], atol=1e-4)
|
| 342 |
+
|
| 343 |
+
# Save model and image processor
|
| 344 |
+
logger.info(f"Saving PyTorch model and image processor to {pytorch_dump_folder_path}...")
|
| 345 |
+
Path(pytorch_dump_folder_path).mkdir(exist_ok=True)
|
| 346 |
+
model.save_pretrained(pytorch_dump_folder_path)
|
| 347 |
+
image_processor.save_pretrained(pytorch_dump_folder_path)
|
| 348 |
+
|
| 349 |
+
|
| 350 |
+
if __name__ == "__main__":
|
| 351 |
+
parser = argparse.ArgumentParser()
|
| 352 |
+
|
| 353 |
+
parser.add_argument(
|
| 354 |
+
"--model_name",
|
| 355 |
+
default="conditional_detr_resnet50",
|
| 356 |
+
type=str,
|
| 357 |
+
help="Name of the CONDITIONAL_DETR model you'd like to convert.",
|
| 358 |
+
)
|
| 359 |
+
parser.add_argument(
|
| 360 |
+
"--pytorch_dump_folder_path", default=None, type=str, help="Path to the folder to output PyTorch model."
|
| 361 |
+
)
|
| 362 |
+
args = parser.parse_args()
|
| 363 |
+
convert_conditional_detr_checkpoint(args.model_name, args.pytorch_dump_folder_path)
|
third_party/transformers/src/transformers/models/conditional_detr/image_processing_conditional_detr.py
ADDED
|
@@ -0,0 +1,1083 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
# 🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨
|
| 2 |
+
# This file was automatically generated from src/transformers/models/conditional_detr/modular_conditional_detr.py.
|
| 3 |
+
# Do NOT edit this file manually as any edits will be overwritten by the generation of
|
| 4 |
+
# the file from the modular. If any change should be done, please apply the change to the
|
| 5 |
+
# modular_conditional_detr.py file directly. One of our CI enforces this.
|
| 6 |
+
# 🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨
|
| 7 |
+
# Copyright 2022 Microsoft Research Asia and The HuggingFace Inc. team. All rights reserved.
|
| 8 |
+
#
|
| 9 |
+
# Licensed under the Apache License, Version 2.0 (the "License");
|
| 10 |
+
# you may not use this file except in compliance with the License.
|
| 11 |
+
# You may obtain a copy of the License at
|
| 12 |
+
#
|
| 13 |
+
# http://www.apache.org/licenses/LICENSE-2.0
|
| 14 |
+
#
|
| 15 |
+
# Unless required by applicable law or agreed to in writing, software
|
| 16 |
+
# distributed under the License is distributed on an "AS IS" BASIS,
|
| 17 |
+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
| 18 |
+
# See the License for the specific language governing permissions and
|
| 19 |
+
# limitations under the License.
|
| 20 |
+
|
| 21 |
+
import pathlib
|
| 22 |
+
from typing import Any, Optional
|
| 23 |
+
|
| 24 |
+
import numpy as np
|
| 25 |
+
import torch
|
| 26 |
+
from torch import nn
|
| 27 |
+
from torchvision.io import read_image
|
| 28 |
+
from torchvision.transforms.v2 import functional as tvF
|
| 29 |
+
|
| 30 |
+
from ...image_processing_backends import TorchvisionBackend
|
| 31 |
+
from ...image_processing_utils import BatchFeature, get_size_dict
|
| 32 |
+
from ...image_transforms import (
|
| 33 |
+
center_to_corners_format,
|
| 34 |
+
corners_to_center_format,
|
| 35 |
+
get_size_with_aspect_ratio,
|
| 36 |
+
safe_squeeze,
|
| 37 |
+
)
|
| 38 |
+
from ...image_utils import (
|
| 39 |
+
IMAGENET_DEFAULT_MEAN,
|
| 40 |
+
IMAGENET_DEFAULT_STD,
|
| 41 |
+
AnnotationFormat,
|
| 42 |
+
AnnotationType,
|
| 43 |
+
ChannelDimension,
|
| 44 |
+
ImageInput,
|
| 45 |
+
PILImageResampling,
|
| 46 |
+
SizeDict,
|
| 47 |
+
get_image_size,
|
| 48 |
+
get_image_size_for_max_height_width,
|
| 49 |
+
get_max_height_width,
|
| 50 |
+
validate_annotations,
|
| 51 |
+
)
|
| 52 |
+
from ...processing_utils import ImagesKwargs, Unpack
|
| 53 |
+
from ...utils import TensorType, auto_docstring, logging
|
| 54 |
+
|
| 55 |
+
|
| 56 |
+
logger = logging.get_logger(__name__)
|
| 57 |
+
|
| 58 |
+
|
| 59 |
+
class ConditionalDetrImageProcessorKwargs(ImagesKwargs, total=False):
|
| 60 |
+
r"""
|
| 61 |
+
format (`str`, *optional*, defaults to `AnnotationFormat.COCO_DETECTION`):
|
| 62 |
+
Data format of the annotations. One of "coco_detection" or "coco_panoptic".
|
| 63 |
+
do_convert_annotations (`bool`, *optional*, defaults to `True`):
|
| 64 |
+
Controls whether to convert the annotations to the format expected by the CONDITIONAL_DETR model. Converts the
|
| 65 |
+
bounding boxes to the format `(center_x, center_y, width, height)` and in the range `[0, 1]`.
|
| 66 |
+
Can be overridden by the `do_convert_annotations` parameter in the `preprocess` method.
|
| 67 |
+
"""
|
| 68 |
+
|
| 69 |
+
format: str | AnnotationFormat
|
| 70 |
+
do_convert_annotations: bool
|
| 71 |
+
|
| 72 |
+
|
| 73 |
+
SUPPORTED_ANNOTATION_FORMATS = (AnnotationFormat.COCO_DETECTION, AnnotationFormat.COCO_PANOPTIC)
|
| 74 |
+
|
| 75 |
+
|
| 76 |
+
def binary_mask_to_rle(mask):
|
| 77 |
+
"""
|
| 78 |
+
Converts given binary mask of shape `(height, width)` to the run-length encoding (RLE) format.
|
| 79 |
+
|
| 80 |
+
Args:
|
| 81 |
+
mask (`torch.Tensor` or `numpy.array`):
|
| 82 |
+
A binary mask tensor of shape `(height, width)` where 0 denotes background and 1 denotes the target
|
| 83 |
+
segment_id or class_id.
|
| 84 |
+
Returns:
|
| 85 |
+
`List`: Run-length encoded list of the binary mask. Refer to COCO API for more information about the RLE
|
| 86 |
+
format.
|
| 87 |
+
"""
|
| 88 |
+
from ...utils import is_torch_tensor
|
| 89 |
+
|
| 90 |
+
if is_torch_tensor(mask):
|
| 91 |
+
mask = mask.numpy()
|
| 92 |
+
|
| 93 |
+
pixels = mask.flatten()
|
| 94 |
+
pixels = np.concatenate([[0], pixels, [0]])
|
| 95 |
+
runs = np.where(pixels[1:] != pixels[:-1])[0] + 1
|
| 96 |
+
runs[1::2] -= runs[::2]
|
| 97 |
+
return list(runs)
|
| 98 |
+
|
| 99 |
+
|
| 100 |
+
def convert_segmentation_to_rle(segmentation):
|
| 101 |
+
"""
|
| 102 |
+
Converts given segmentation map of shape `(height, width)` to the run-length encoding (RLE) format.
|
| 103 |
+
|
| 104 |
+
Args:
|
| 105 |
+
segmentation (`torch.Tensor` or `numpy.array`):
|
| 106 |
+
A segmentation map of shape `(height, width)` where each value denotes a segment or class id.
|
| 107 |
+
Returns:
|
| 108 |
+
`list[List]`: A list of lists, where each list is the run-length encoding of a segment / class id.
|
| 109 |
+
"""
|
| 110 |
+
segment_ids = torch.unique(segmentation)
|
| 111 |
+
|
| 112 |
+
run_length_encodings = []
|
| 113 |
+
for idx in segment_ids:
|
| 114 |
+
mask = torch.where(segmentation == idx, 1, 0)
|
| 115 |
+
rle = binary_mask_to_rle(mask)
|
| 116 |
+
run_length_encodings.append(rle)
|
| 117 |
+
|
| 118 |
+
return run_length_encodings
|
| 119 |
+
|
| 120 |
+
|
| 121 |
+
def remove_low_and_no_objects(masks, scores, labels, object_mask_threshold, num_labels):
|
| 122 |
+
"""
|
| 123 |
+
Binarize the given masks using `object_mask_threshold`, it returns the associated values of `masks`, `scores` and
|
| 124 |
+
`labels`.
|
| 125 |
+
|
| 126 |
+
Args:
|
| 127 |
+
masks (`torch.Tensor`):
|
| 128 |
+
A tensor of shape `(num_queries, height, width)`.
|
| 129 |
+
scores (`torch.Tensor`):
|
| 130 |
+
A tensor of shape `(num_queries)`.
|
| 131 |
+
labels (`torch.Tensor`):
|
| 132 |
+
A tensor of shape `(num_queries)`.
|
| 133 |
+
object_mask_threshold (`float`):
|
| 134 |
+
A number between 0 and 1 used to binarize the masks.
|
| 135 |
+
Raises:
|
| 136 |
+
`ValueError`: Raised when the first dimension doesn't match in all input tensors.
|
| 137 |
+
Returns:
|
| 138 |
+
`tuple[`torch.Tensor`, `torch.Tensor`, `torch.Tensor`]`: The `masks`, `scores` and `labels` without the region
|
| 139 |
+
< `object_mask_threshold`.
|
| 140 |
+
"""
|
| 141 |
+
if not (masks.shape[0] == scores.shape[0] == labels.shape[0]):
|
| 142 |
+
raise ValueError("mask, scores and labels must have the same shape!")
|
| 143 |
+
|
| 144 |
+
to_keep = labels.ne(num_labels) & (scores > object_mask_threshold)
|
| 145 |
+
|
| 146 |
+
return masks[to_keep], scores[to_keep], labels[to_keep]
|
| 147 |
+
|
| 148 |
+
|
| 149 |
+
def check_segment_validity(mask_labels, mask_probs, k, mask_threshold=0.5, overlap_mask_area_threshold=0.8):
|
| 150 |
+
# Get the mask associated with the k class
|
| 151 |
+
mask_k = mask_labels == k
|
| 152 |
+
mask_k_area = mask_k.sum()
|
| 153 |
+
|
| 154 |
+
# Compute the area of all the stuff in query k
|
| 155 |
+
original_area = (mask_probs[k] >= mask_threshold).sum()
|
| 156 |
+
mask_exists = mask_k_area > 0 and original_area > 0
|
| 157 |
+
|
| 158 |
+
# Eliminate disconnected tiny segments
|
| 159 |
+
if mask_exists:
|
| 160 |
+
area_ratio = mask_k_area / original_area
|
| 161 |
+
if not area_ratio.item() > overlap_mask_area_threshold:
|
| 162 |
+
mask_exists = False
|
| 163 |
+
|
| 164 |
+
return mask_exists, mask_k
|
| 165 |
+
|
| 166 |
+
|
| 167 |
+
def compute_segments(
|
| 168 |
+
mask_probs,
|
| 169 |
+
pred_scores,
|
| 170 |
+
pred_labels,
|
| 171 |
+
mask_threshold: float = 0.5,
|
| 172 |
+
overlap_mask_area_threshold: float = 0.8,
|
| 173 |
+
label_ids_to_fuse: set[int] | None = None,
|
| 174 |
+
target_size: tuple[int, int] | None = None,
|
| 175 |
+
):
|
| 176 |
+
height = mask_probs.shape[1] if target_size is None else target_size[0]
|
| 177 |
+
width = mask_probs.shape[2] if target_size is None else target_size[1]
|
| 178 |
+
|
| 179 |
+
segmentation = torch.zeros((height, width), dtype=torch.int32, device=mask_probs.device)
|
| 180 |
+
segments: list[dict] = []
|
| 181 |
+
|
| 182 |
+
if target_size is not None:
|
| 183 |
+
mask_probs = nn.functional.interpolate(
|
| 184 |
+
mask_probs.unsqueeze(0), size=target_size, mode="bilinear", align_corners=False
|
| 185 |
+
)[0]
|
| 186 |
+
|
| 187 |
+
current_segment_id = 0
|
| 188 |
+
|
| 189 |
+
# Weigh each mask by its prediction score
|
| 190 |
+
mask_probs *= pred_scores.view(-1, 1, 1)
|
| 191 |
+
mask_labels = mask_probs.argmax(0) # [height, width]
|
| 192 |
+
|
| 193 |
+
# Keep track of instances of each class
|
| 194 |
+
stuff_memory_list: dict[str, int] = {}
|
| 195 |
+
for k in range(pred_labels.shape[0]):
|
| 196 |
+
pred_class = pred_labels[k].item()
|
| 197 |
+
should_fuse = pred_class in label_ids_to_fuse
|
| 198 |
+
|
| 199 |
+
# Check if mask exists and large enough to be a segment
|
| 200 |
+
mask_exists, mask_k = check_segment_validity(
|
| 201 |
+
mask_labels, mask_probs, k, mask_threshold, overlap_mask_area_threshold
|
| 202 |
+
)
|
| 203 |
+
|
| 204 |
+
if mask_exists:
|
| 205 |
+
if pred_class in stuff_memory_list:
|
| 206 |
+
current_segment_id = stuff_memory_list[pred_class]
|
| 207 |
+
else:
|
| 208 |
+
current_segment_id += 1
|
| 209 |
+
|
| 210 |
+
# Add current object segment to final segmentation map
|
| 211 |
+
segmentation[mask_k] = current_segment_id
|
| 212 |
+
segment_score = round(pred_scores[k].item(), 6)
|
| 213 |
+
segments.append(
|
| 214 |
+
{
|
| 215 |
+
"id": current_segment_id,
|
| 216 |
+
"label_id": pred_class,
|
| 217 |
+
"was_fused": should_fuse,
|
| 218 |
+
"score": segment_score,
|
| 219 |
+
}
|
| 220 |
+
)
|
| 221 |
+
if should_fuse:
|
| 222 |
+
stuff_memory_list[pred_class] = current_segment_id
|
| 223 |
+
|
| 224 |
+
return segmentation, segments
|
| 225 |
+
|
| 226 |
+
|
| 227 |
+
# inspired by https://github.com/facebookresearch/conditional_detr/blob/master/datasets/coco.py#L33
|
| 228 |
+
def convert_coco_poly_to_mask(segmentations, height: int, width: int, device: torch.device) -> torch.Tensor:
|
| 229 |
+
"""
|
| 230 |
+
Convert a COCO polygon annotation to a mask.
|
| 231 |
+
|
| 232 |
+
Args:
|
| 233 |
+
segmentations (`list[list[float]]`):
|
| 234 |
+
List of polygons, each polygon represented by a list of x-y coordinates.
|
| 235 |
+
height (`int`):
|
| 236 |
+
Height of the mask.
|
| 237 |
+
width (`int`):
|
| 238 |
+
Width of the mask.
|
| 239 |
+
"""
|
| 240 |
+
try:
|
| 241 |
+
from pycocotools import mask as coco_mask
|
| 242 |
+
except ImportError:
|
| 243 |
+
raise ImportError("Pycocotools is not installed in your environment.")
|
| 244 |
+
|
| 245 |
+
masks = []
|
| 246 |
+
for polygons in segmentations:
|
| 247 |
+
rles = coco_mask.frPyObjects(polygons, height, width)
|
| 248 |
+
mask = coco_mask.decode(rles)
|
| 249 |
+
if len(mask.shape) < 3:
|
| 250 |
+
mask = mask[..., None]
|
| 251 |
+
mask = torch.as_tensor(mask, dtype=torch.uint8, device=device)
|
| 252 |
+
mask = torch.any(mask, axis=2)
|
| 253 |
+
masks.append(mask)
|
| 254 |
+
if masks:
|
| 255 |
+
masks = torch.stack(masks, axis=0)
|
| 256 |
+
else:
|
| 257 |
+
masks = torch.zeros((0, height, width), dtype=torch.uint8, device=device)
|
| 258 |
+
|
| 259 |
+
return masks
|
| 260 |
+
|
| 261 |
+
|
| 262 |
+
# inspired by https://github.com/facebookresearch/conditional_detr/blob/master/datasets/coco.py#L50
|
| 263 |
+
def prepare_coco_detection_annotation(
|
| 264 |
+
image,
|
| 265 |
+
target,
|
| 266 |
+
return_segmentation_masks: bool = False,
|
| 267 |
+
input_data_format: ChannelDimension | str | None = None,
|
| 268 |
+
):
|
| 269 |
+
"""
|
| 270 |
+
Convert the target in COCO format into the format expected by CONDITIONAL_DETR.
|
| 271 |
+
"""
|
| 272 |
+
image_height, image_width = image.size()[-2:]
|
| 273 |
+
|
| 274 |
+
image_id = target["image_id"]
|
| 275 |
+
image_id = torch.as_tensor([image_id], dtype=torch.int64, device=image.device)
|
| 276 |
+
|
| 277 |
+
# Get all COCO annotations for the given image.
|
| 278 |
+
annotations = target["annotations"]
|
| 279 |
+
classes = []
|
| 280 |
+
area = []
|
| 281 |
+
boxes = []
|
| 282 |
+
keypoints = []
|
| 283 |
+
for obj in annotations:
|
| 284 |
+
if "iscrowd" not in obj or obj["iscrowd"] == 0:
|
| 285 |
+
classes.append(obj["category_id"])
|
| 286 |
+
area.append(obj["area"])
|
| 287 |
+
boxes.append(obj["bbox"])
|
| 288 |
+
if "keypoints" in obj:
|
| 289 |
+
keypoints.append(obj["keypoints"])
|
| 290 |
+
|
| 291 |
+
classes = torch.as_tensor(classes, dtype=torch.int64, device=image.device)
|
| 292 |
+
area = torch.as_tensor(area, dtype=torch.float32, device=image.device)
|
| 293 |
+
iscrowd = torch.zeros_like(classes, dtype=torch.int64, device=image.device)
|
| 294 |
+
# guard against no boxes via resizing
|
| 295 |
+
boxes = torch.as_tensor(boxes, dtype=torch.float32, device=image.device).reshape(-1, 4)
|
| 296 |
+
boxes[:, 2:] += boxes[:, :2]
|
| 297 |
+
boxes[:, 0::2] = boxes[:, 0::2].clip(min=0, max=image_width)
|
| 298 |
+
boxes[:, 1::2] = boxes[:, 1::2].clip(min=0, max=image_height)
|
| 299 |
+
|
| 300 |
+
keep = (boxes[:, 3] > boxes[:, 1]) & (boxes[:, 2] > boxes[:, 0])
|
| 301 |
+
|
| 302 |
+
new_target = {
|
| 303 |
+
"image_id": image_id,
|
| 304 |
+
"class_labels": classes[keep],
|
| 305 |
+
"boxes": boxes[keep],
|
| 306 |
+
"area": area[keep],
|
| 307 |
+
"iscrowd": iscrowd[keep],
|
| 308 |
+
"orig_size": torch.as_tensor([int(image_height), int(image_width)], dtype=torch.int64, device=image.device),
|
| 309 |
+
}
|
| 310 |
+
|
| 311 |
+
if keypoints:
|
| 312 |
+
keypoints = torch.as_tensor(keypoints, dtype=torch.float32, device=image.device)
|
| 313 |
+
# Apply the keep mask here to filter the relevant annotations
|
| 314 |
+
keypoints = keypoints[keep]
|
| 315 |
+
num_keypoints = keypoints.shape[0]
|
| 316 |
+
keypoints = keypoints.reshape((-1, 3)) if num_keypoints else keypoints
|
| 317 |
+
new_target["keypoints"] = keypoints
|
| 318 |
+
|
| 319 |
+
if return_segmentation_masks:
|
| 320 |
+
segmentation_masks = [obj["segmentation"] for obj in annotations]
|
| 321 |
+
masks = convert_coco_poly_to_mask(segmentation_masks, image_height, image_width, device=image.device)
|
| 322 |
+
new_target["masks"] = masks[keep]
|
| 323 |
+
|
| 324 |
+
return new_target
|
| 325 |
+
|
| 326 |
+
|
| 327 |
+
def masks_to_boxes(masks: torch.Tensor) -> torch.Tensor:
|
| 328 |
+
"""
|
| 329 |
+
Compute the bounding boxes around the provided panoptic segmentation masks.
|
| 330 |
+
|
| 331 |
+
Args:
|
| 332 |
+
masks: masks in format `[number_masks, height, width]` where N is the number of masks
|
| 333 |
+
|
| 334 |
+
Returns:
|
| 335 |
+
boxes: bounding boxes in format `[number_masks, 4]` in xyxy format
|
| 336 |
+
"""
|
| 337 |
+
if masks.numel() == 0:
|
| 338 |
+
return torch.zeros((0, 4), device=masks.device)
|
| 339 |
+
|
| 340 |
+
h, w = masks.shape[-2:]
|
| 341 |
+
y = torch.arange(0, h, dtype=torch.float32, device=masks.device)
|
| 342 |
+
x = torch.arange(0, w, dtype=torch.float32, device=masks.device)
|
| 343 |
+
# see https://github.com/pytorch/pytorch/issues/50276
|
| 344 |
+
y, x = torch.meshgrid(y, x, indexing="ij")
|
| 345 |
+
|
| 346 |
+
x_mask = masks * torch.unsqueeze(x, 0)
|
| 347 |
+
x_max = x_mask.view(x_mask.shape[0], -1).max(-1)[0]
|
| 348 |
+
x_min = (
|
| 349 |
+
torch.where(masks, x.unsqueeze(0), torch.tensor(1e8, device=masks.device)).view(masks.shape[0], -1).min(-1)[0]
|
| 350 |
+
)
|
| 351 |
+
|
| 352 |
+
y_mask = masks * torch.unsqueeze(y, 0)
|
| 353 |
+
y_max = y_mask.view(y_mask.shape[0], -1).max(-1)[0]
|
| 354 |
+
y_min = (
|
| 355 |
+
torch.where(masks, y.unsqueeze(0), torch.tensor(1e8, device=masks.device)).view(masks.shape[0], -1).min(-1)[0]
|
| 356 |
+
)
|
| 357 |
+
|
| 358 |
+
return torch.stack([x_min, y_min, x_max, y_max], 1)
|
| 359 |
+
|
| 360 |
+
|
| 361 |
+
# 2 functions below adapted from https://github.com/cocodataset/panopticapi/blob/master/panopticapi/utils.py
|
| 362 |
+
# Copyright (c) 2018, Alexander Kirillov
|
| 363 |
+
# All rights reserved.
|
| 364 |
+
def rgb_to_id(color):
|
| 365 |
+
"""
|
| 366 |
+
Converts RGB color to unique ID.
|
| 367 |
+
"""
|
| 368 |
+
if isinstance(color, torch.Tensor) and len(color.shape) == 3:
|
| 369 |
+
if color.dtype == torch.uint8:
|
| 370 |
+
color = color.to(torch.int32)
|
| 371 |
+
return color[:, :, 0] + 256 * color[:, :, 1] + 256 * 256 * color[:, :, 2]
|
| 372 |
+
return int(color[0] + 256 * color[1] + 256 * 256 * color[2])
|
| 373 |
+
|
| 374 |
+
|
| 375 |
+
def prepare_coco_panoptic_annotation(
|
| 376 |
+
image: torch.Tensor,
|
| 377 |
+
target: dict,
|
| 378 |
+
masks_path: str | pathlib.Path,
|
| 379 |
+
return_masks: bool = True,
|
| 380 |
+
input_data_format: ChannelDimension | str = None,
|
| 381 |
+
) -> dict:
|
| 382 |
+
"""
|
| 383 |
+
Prepare a coco panoptic annotation for CONDITIONAL_DETR.
|
| 384 |
+
"""
|
| 385 |
+
image_height, image_width = get_image_size(image, channel_dim=input_data_format)
|
| 386 |
+
annotation_path = pathlib.Path(masks_path) / target["file_name"]
|
| 387 |
+
|
| 388 |
+
new_target = {}
|
| 389 |
+
new_target["image_id"] = torch.as_tensor(
|
| 390 |
+
[target["image_id"] if "image_id" in target else target["id"]], dtype=torch.int64, device=image.device
|
| 391 |
+
)
|
| 392 |
+
new_target["size"] = torch.as_tensor([image_height, image_width], dtype=torch.int64, device=image.device)
|
| 393 |
+
new_target["orig_size"] = torch.as_tensor([image_height, image_width], dtype=torch.int64, device=image.device)
|
| 394 |
+
|
| 395 |
+
if "segments_info" in target:
|
| 396 |
+
masks = read_image(annotation_path).permute(1, 2, 0).to(dtype=torch.int32, device=image.device)
|
| 397 |
+
masks = rgb_to_id(masks)
|
| 398 |
+
|
| 399 |
+
ids = torch.as_tensor([segment_info["id"] for segment_info in target["segments_info"]], device=image.device)
|
| 400 |
+
masks = masks == ids[:, None, None]
|
| 401 |
+
masks = masks.to(torch.bool)
|
| 402 |
+
if return_masks:
|
| 403 |
+
new_target["masks"] = masks
|
| 404 |
+
new_target["boxes"] = masks_to_boxes(masks)
|
| 405 |
+
new_target["class_labels"] = torch.as_tensor(
|
| 406 |
+
[segment_info["category_id"] for segment_info in target["segments_info"]],
|
| 407 |
+
dtype=torch.int64,
|
| 408 |
+
device=image.device,
|
| 409 |
+
)
|
| 410 |
+
new_target["iscrowd"] = torch.as_tensor(
|
| 411 |
+
[segment_info["iscrowd"] for segment_info in target["segments_info"]],
|
| 412 |
+
dtype=torch.int64,
|
| 413 |
+
device=image.device,
|
| 414 |
+
)
|
| 415 |
+
new_target["area"] = torch.as_tensor(
|
| 416 |
+
[segment_info["area"] for segment_info in target["segments_info"]],
|
| 417 |
+
dtype=torch.float32,
|
| 418 |
+
device=image.device,
|
| 419 |
+
)
|
| 420 |
+
|
| 421 |
+
return new_target
|
| 422 |
+
|
| 423 |
+
|
| 424 |
+
@auto_docstring
|
| 425 |
+
class ConditionalDetrImageProcessor(TorchvisionBackend):
|
| 426 |
+
valid_kwargs = ConditionalDetrImageProcessorKwargs
|
| 427 |
+
resample = PILImageResampling.BILINEAR
|
| 428 |
+
image_mean = IMAGENET_DEFAULT_MEAN
|
| 429 |
+
image_std = IMAGENET_DEFAULT_STD
|
| 430 |
+
format = AnnotationFormat.COCO_DETECTION
|
| 431 |
+
do_resize = True
|
| 432 |
+
do_rescale = True
|
| 433 |
+
do_normalize = True
|
| 434 |
+
do_pad = True
|
| 435 |
+
size = {"shortest_edge": 800, "longest_edge": 1333}
|
| 436 |
+
default_to_square = False
|
| 437 |
+
model_input_names = ["pixel_values", "pixel_mask"]
|
| 438 |
+
|
| 439 |
+
def __init__(self, **kwargs: Unpack[ConditionalDetrImageProcessorKwargs]) -> None:
|
| 440 |
+
kwargs.setdefault("do_pad", kwargs.pop("pad_and_return_pixel_mask", self.do_pad))
|
| 441 |
+
|
| 442 |
+
size = kwargs.pop("size", None)
|
| 443 |
+
max_size = None if size is None else kwargs.pop("max_size", 1333)
|
| 444 |
+
size = size if size is not None else {"shortest_edge": 800, "longest_edge": 1333}
|
| 445 |
+
# Convert size dict for backwards compat with max_size parameter
|
| 446 |
+
kwargs["size"] = get_size_dict(size, max_size=max_size, default_to_square=False)
|
| 447 |
+
|
| 448 |
+
# Backwards compatibility
|
| 449 |
+
do_convert_annotations = kwargs.get("do_convert_annotations")
|
| 450 |
+
do_normalize = kwargs.get("do_normalize")
|
| 451 |
+
if do_convert_annotations is None and getattr(self, "do_convert_annotations", None) is None:
|
| 452 |
+
self.do_convert_annotations = do_normalize if do_normalize is not None else self.do_normalize
|
| 453 |
+
|
| 454 |
+
super().__init__(**kwargs)
|
| 455 |
+
|
| 456 |
+
def prepare_annotation(
|
| 457 |
+
self,
|
| 458 |
+
image: torch.Tensor,
|
| 459 |
+
target: dict,
|
| 460 |
+
format: AnnotationFormat | None = None,
|
| 461 |
+
return_segmentation_masks: bool | None = None,
|
| 462 |
+
masks_path: str | pathlib.Path | None = None,
|
| 463 |
+
input_data_format: str | ChannelDimension | None = None,
|
| 464 |
+
) -> dict:
|
| 465 |
+
"""
|
| 466 |
+
Prepare an annotation for feeding into CONDITIONAL_DETR model.
|
| 467 |
+
"""
|
| 468 |
+
format = format if format is not None else self.format
|
| 469 |
+
|
| 470 |
+
if format == AnnotationFormat.COCO_DETECTION:
|
| 471 |
+
return_segmentation_masks = False if return_segmentation_masks is None else return_segmentation_masks
|
| 472 |
+
target = prepare_coco_detection_annotation(
|
| 473 |
+
image, target, return_segmentation_masks, input_data_format=input_data_format
|
| 474 |
+
)
|
| 475 |
+
elif format == AnnotationFormat.COCO_PANOPTIC:
|
| 476 |
+
return_segmentation_masks = True if return_segmentation_masks is None else return_segmentation_masks
|
| 477 |
+
target = prepare_coco_panoptic_annotation(
|
| 478 |
+
image,
|
| 479 |
+
target,
|
| 480 |
+
masks_path=masks_path,
|
| 481 |
+
return_masks=return_segmentation_masks,
|
| 482 |
+
input_data_format=input_data_format,
|
| 483 |
+
)
|
| 484 |
+
else:
|
| 485 |
+
raise ValueError(f"Format {format} is not supported.")
|
| 486 |
+
return target
|
| 487 |
+
|
| 488 |
+
def resize(
|
| 489 |
+
self,
|
| 490 |
+
image: torch.Tensor,
|
| 491 |
+
size: SizeDict,
|
| 492 |
+
resample: Optional["PILImageResampling | tvF.InterpolationMode | int"] = None,
|
| 493 |
+
**kwargs,
|
| 494 |
+
) -> torch.Tensor:
|
| 495 |
+
"""
|
| 496 |
+
Resize the image to the given size. Size can be `min_size` (scalar) or `(height, width)` tuple. If size is an
|
| 497 |
+
int, smaller edge of the image will be matched to this number.
|
| 498 |
+
|
| 499 |
+
Args:
|
| 500 |
+
image (`torch.Tensor`):
|
| 501 |
+
Image to resize.
|
| 502 |
+
size (`SizeDict`):
|
| 503 |
+
Size of the image's `(height, width)` dimensions after resizing. Available options are:
|
| 504 |
+
- `{"height": int, "width": int}`: The image will be resized to the exact size `(height, width)`.
|
| 505 |
+
Do NOT keep the aspect ratio.
|
| 506 |
+
- `{"shortest_edge": int, "longest_edge": int}`: The image will be resized to a maximum size respecting
|
| 507 |
+
the aspect ratio and keeping the shortest edge less or equal to `shortest_edge` and the longest edge
|
| 508 |
+
less or equal to `longest_edge`.
|
| 509 |
+
- `{"max_height": int, "max_width": int}`: The image will be resized to the maximum size respecting the
|
| 510 |
+
aspect ratio and keeping the height less or equal to `max_height` and the width less or equal to
|
| 511 |
+
`max_width`.
|
| 512 |
+
resample (`PILImageResampling | tvF.InterpolationMode | int`, *optional*, defaults to `PILImageResampling.BILINEAR`):
|
| 513 |
+
Resampling filter to use if resizing the image.
|
| 514 |
+
"""
|
| 515 |
+
if size.shortest_edge and size.longest_edge:
|
| 516 |
+
# Resize the image so that the shortest edge or the longest edge is of the given size
|
| 517 |
+
# while maintaining the aspect ratio of the original image.
|
| 518 |
+
new_size = get_size_with_aspect_ratio(image.shape[-2:], size.shortest_edge, size.longest_edge)
|
| 519 |
+
elif size.max_height and size.max_width:
|
| 520 |
+
new_size = get_image_size_for_max_height_width(image.shape[-2:], size.max_height, size.max_width)
|
| 521 |
+
elif size.height and size.width:
|
| 522 |
+
new_size = (size.height, size.width)
|
| 523 |
+
else:
|
| 524 |
+
raise ValueError(
|
| 525 |
+
f"Size must contain 'height' and 'width' keys or 'shortest_edge' and 'longest_edge' keys. Got {size}."
|
| 526 |
+
)
|
| 527 |
+
|
| 528 |
+
image = super().resize(
|
| 529 |
+
image, size=SizeDict(height=new_size[0], width=new_size[1]), resample=resample, **kwargs
|
| 530 |
+
)
|
| 531 |
+
return image
|
| 532 |
+
|
| 533 |
+
def resize_annotation(
|
| 534 |
+
self,
|
| 535 |
+
annotation: dict[str, Any],
|
| 536 |
+
orig_size: tuple[int, int],
|
| 537 |
+
target_size: tuple[int, int],
|
| 538 |
+
threshold: float = 0.5,
|
| 539 |
+
resample: Optional["PILImageResampling | tvF.InterpolationMode | int"] = PILImageResampling.NEAREST,
|
| 540 |
+
):
|
| 541 |
+
"""
|
| 542 |
+
Resizes an annotation to a target size.
|
| 543 |
+
|
| 544 |
+
Args:
|
| 545 |
+
annotation (`dict[str, Any]`):
|
| 546 |
+
The annotation dictionary.
|
| 547 |
+
orig_size (`tuple[int, int]`):
|
| 548 |
+
The original size of the input image.
|
| 549 |
+
target_size (`tuple[int, int]`):
|
| 550 |
+
The target size of the image, as returned by the preprocessing `resize` step.
|
| 551 |
+
threshold (`float`, *optional*, defaults to 0.5):
|
| 552 |
+
The threshold used to binarize the segmentation masks.
|
| 553 |
+
resample (`PILImageResampling | tvF.InterpolationMode | int`, defaults to `tvF.InterpolationMode.NEAREST_EXACT`):
|
| 554 |
+
The resampling filter to use when resizing the masks.
|
| 555 |
+
"""
|
| 556 |
+
ratio_height, ratio_width = [target / orig for target, orig in zip(target_size, orig_size)]
|
| 557 |
+
|
| 558 |
+
new_annotation = {}
|
| 559 |
+
new_annotation["size"] = target_size
|
| 560 |
+
|
| 561 |
+
for key, value in annotation.items():
|
| 562 |
+
if key == "boxes":
|
| 563 |
+
boxes = value
|
| 564 |
+
scaled_boxes = boxes * torch.as_tensor(
|
| 565 |
+
[ratio_width, ratio_height, ratio_width, ratio_height], dtype=torch.float32, device=boxes.device
|
| 566 |
+
)
|
| 567 |
+
new_annotation["boxes"] = scaled_boxes
|
| 568 |
+
elif key == "area":
|
| 569 |
+
area = value
|
| 570 |
+
scaled_area = area * (ratio_width * ratio_height)
|
| 571 |
+
new_annotation["area"] = scaled_area
|
| 572 |
+
elif key == "masks":
|
| 573 |
+
masks = value[:, None]
|
| 574 |
+
masks = [
|
| 575 |
+
super(ConditionalDetrImageProcessor, self).resize(
|
| 576 |
+
mask, size=SizeDict(height=target_size[0], width=target_size[1]), resample=resample
|
| 577 |
+
)
|
| 578 |
+
for mask in masks
|
| 579 |
+
]
|
| 580 |
+
masks = torch.stack(masks).to(torch.float32)
|
| 581 |
+
masks = masks[:, 0] > threshold
|
| 582 |
+
new_annotation["masks"] = masks
|
| 583 |
+
elif key == "size":
|
| 584 |
+
new_annotation["size"] = target_size
|
| 585 |
+
else:
|
| 586 |
+
new_annotation[key] = value
|
| 587 |
+
|
| 588 |
+
return new_annotation
|
| 589 |
+
|
| 590 |
+
def normalize_annotation(self, annotation: dict, image_size: tuple[int, int]) -> dict:
|
| 591 |
+
image_height, image_width = image_size
|
| 592 |
+
norm_annotation = {}
|
| 593 |
+
for key, value in annotation.items():
|
| 594 |
+
if key == "boxes":
|
| 595 |
+
boxes = value
|
| 596 |
+
boxes = corners_to_center_format(boxes)
|
| 597 |
+
boxes /= torch.as_tensor(
|
| 598 |
+
[image_width, image_height, image_width, image_height], dtype=torch.float32, device=boxes.device
|
| 599 |
+
)
|
| 600 |
+
norm_annotation[key] = boxes
|
| 601 |
+
else:
|
| 602 |
+
norm_annotation[key] = value
|
| 603 |
+
return norm_annotation
|
| 604 |
+
|
| 605 |
+
def _update_annotation_for_padded_image(
|
| 606 |
+
self,
|
| 607 |
+
annotation: dict,
|
| 608 |
+
input_image_size: tuple[int, int],
|
| 609 |
+
output_image_size: tuple[int, int],
|
| 610 |
+
padding,
|
| 611 |
+
update_bboxes,
|
| 612 |
+
) -> dict:
|
| 613 |
+
"""
|
| 614 |
+
Update the annotation for a padded image.
|
| 615 |
+
"""
|
| 616 |
+
new_annotation = {}
|
| 617 |
+
new_annotation["size"] = output_image_size
|
| 618 |
+
ratio_height, ratio_width = (input / output for output, input in zip(output_image_size, input_image_size))
|
| 619 |
+
|
| 620 |
+
for key, value in annotation.items():
|
| 621 |
+
if key == "masks":
|
| 622 |
+
masks = value
|
| 623 |
+
masks = tvF.pad(
|
| 624 |
+
masks,
|
| 625 |
+
padding,
|
| 626 |
+
fill=0,
|
| 627 |
+
)
|
| 628 |
+
masks = safe_squeeze(masks, 1)
|
| 629 |
+
new_annotation["masks"] = masks
|
| 630 |
+
elif key == "boxes" and update_bboxes:
|
| 631 |
+
boxes = value
|
| 632 |
+
boxes *= torch.as_tensor([ratio_width, ratio_height, ratio_width, ratio_height], device=boxes.device)
|
| 633 |
+
new_annotation["boxes"] = boxes
|
| 634 |
+
elif key == "size":
|
| 635 |
+
new_annotation["size"] = output_image_size
|
| 636 |
+
else:
|
| 637 |
+
new_annotation[key] = value
|
| 638 |
+
return new_annotation
|
| 639 |
+
|
| 640 |
+
def pad(
|
| 641 |
+
self,
|
| 642 |
+
image: torch.Tensor,
|
| 643 |
+
padded_size: tuple[int, int],
|
| 644 |
+
annotation: dict[str, Any] | None = None,
|
| 645 |
+
update_bboxes: bool = True,
|
| 646 |
+
fill: int = 0,
|
| 647 |
+
):
|
| 648 |
+
original_size = image.size()[-2:]
|
| 649 |
+
padding_bottom = padded_size[0] - original_size[0]
|
| 650 |
+
padding_right = padded_size[1] - original_size[1]
|
| 651 |
+
if padding_bottom < 0 or padding_right < 0:
|
| 652 |
+
raise ValueError(
|
| 653 |
+
f"Padding dimensions are negative. Please make sure that the padded size is larger than the "
|
| 654 |
+
f"original size. Got padded size: {padded_size}, original size: {original_size}."
|
| 655 |
+
)
|
| 656 |
+
if original_size != padded_size:
|
| 657 |
+
padding = [0, 0, padding_right, padding_bottom]
|
| 658 |
+
image = tvF.pad(image, padding, fill=fill)
|
| 659 |
+
if annotation is not None:
|
| 660 |
+
annotation = self._update_annotation_for_padded_image(
|
| 661 |
+
annotation, original_size, padded_size, padding, update_bboxes
|
| 662 |
+
)
|
| 663 |
+
|
| 664 |
+
# Make a pixel mask for the image, where 1 indicates a valid pixel and 0 indicates padding.
|
| 665 |
+
pixel_mask = torch.zeros(padded_size, dtype=torch.int64, device=image.device)
|
| 666 |
+
pixel_mask[: original_size[0], : original_size[1]] = 1
|
| 667 |
+
|
| 668 |
+
return image, pixel_mask, annotation
|
| 669 |
+
|
| 670 |
+
@auto_docstring
|
| 671 |
+
def preprocess(
|
| 672 |
+
self,
|
| 673 |
+
images: ImageInput,
|
| 674 |
+
annotations: AnnotationType | list[AnnotationType] | None = None,
|
| 675 |
+
return_segmentation_masks: bool | None = None,
|
| 676 |
+
masks_path: str | pathlib.Path | None = None,
|
| 677 |
+
**kwargs: Unpack[ConditionalDetrImageProcessorKwargs],
|
| 678 |
+
) -> BatchFeature:
|
| 679 |
+
r"""
|
| 680 |
+
annotations (`AnnotationType` or `list[AnnotationType]`, *optional*):
|
| 681 |
+
Annotations to transform according to the padding that is applied to the images.
|
| 682 |
+
return_segmentation_masks (`bool`, *optional*, defaults to `self.return_segmentation_masks`):
|
| 683 |
+
Whether to return segmentation masks.
|
| 684 |
+
masks_path (`str` or `pathlib.Path`, *optional*):
|
| 685 |
+
Path to the directory containing the segmentation masks.
|
| 686 |
+
"""
|
| 687 |
+
return super().preprocess(images, annotations, return_segmentation_masks, masks_path, **kwargs)
|
| 688 |
+
|
| 689 |
+
def _preprocess(
|
| 690 |
+
self,
|
| 691 |
+
images: list["torch.Tensor"],
|
| 692 |
+
annotations: AnnotationType | list[AnnotationType] | None,
|
| 693 |
+
return_segmentation_masks: bool,
|
| 694 |
+
masks_path: str | pathlib.Path | None,
|
| 695 |
+
do_resize: bool,
|
| 696 |
+
size: SizeDict,
|
| 697 |
+
resample: "PILImageResampling | tvF.InterpolationMode | int | None",
|
| 698 |
+
do_rescale: bool,
|
| 699 |
+
rescale_factor: float,
|
| 700 |
+
do_normalize: bool,
|
| 701 |
+
do_convert_annotations: bool,
|
| 702 |
+
image_mean: float | list[float] | None,
|
| 703 |
+
image_std: float | list[float] | None,
|
| 704 |
+
do_pad: bool,
|
| 705 |
+
pad_size: SizeDict | None,
|
| 706 |
+
format: str | AnnotationFormat | None,
|
| 707 |
+
return_tensors: str | TensorType | None,
|
| 708 |
+
**kwargs,
|
| 709 |
+
) -> BatchFeature:
|
| 710 |
+
"""
|
| 711 |
+
Preprocess an image or a batch of images so that it can be used by the model.
|
| 712 |
+
"""
|
| 713 |
+
if annotations is not None and isinstance(annotations, dict):
|
| 714 |
+
annotations = [annotations]
|
| 715 |
+
|
| 716 |
+
if annotations is not None and len(images) != len(annotations):
|
| 717 |
+
raise ValueError(
|
| 718 |
+
f"The number of images ({len(images)}) and annotations ({len(annotations)}) do not match."
|
| 719 |
+
)
|
| 720 |
+
|
| 721 |
+
format = AnnotationFormat(format)
|
| 722 |
+
if annotations is not None:
|
| 723 |
+
validate_annotations(format, SUPPORTED_ANNOTATION_FORMATS, annotations)
|
| 724 |
+
|
| 725 |
+
if (
|
| 726 |
+
masks_path is not None
|
| 727 |
+
and format == AnnotationFormat.COCO_PANOPTIC
|
| 728 |
+
and not isinstance(masks_path, (pathlib.Path, str))
|
| 729 |
+
):
|
| 730 |
+
raise ValueError(
|
| 731 |
+
"The path to the directory containing the mask PNG files should be provided as a"
|
| 732 |
+
f" `pathlib.Path` or string object, but is {type(masks_path)} instead."
|
| 733 |
+
)
|
| 734 |
+
|
| 735 |
+
data = {}
|
| 736 |
+
|
| 737 |
+
processed_images = []
|
| 738 |
+
processed_annotations = []
|
| 739 |
+
pixel_masks = [] # Initialize pixel_masks here
|
| 740 |
+
for image, annotation in zip(images, annotations if annotations is not None else [None] * len(images)):
|
| 741 |
+
# prepare (COCO annotations as a list of Dict -> CONDITIONAL_DETR target as a single Dict per image)
|
| 742 |
+
if annotations is not None:
|
| 743 |
+
annotation = self.prepare_annotation(
|
| 744 |
+
image,
|
| 745 |
+
annotation,
|
| 746 |
+
format,
|
| 747 |
+
return_segmentation_masks=return_segmentation_masks,
|
| 748 |
+
masks_path=masks_path,
|
| 749 |
+
input_data_format=ChannelDimension.FIRST,
|
| 750 |
+
)
|
| 751 |
+
|
| 752 |
+
if do_resize:
|
| 753 |
+
resized_image = self.resize(image, size=size, resample=resample)
|
| 754 |
+
if annotations is not None:
|
| 755 |
+
annotation = self.resize_annotation(
|
| 756 |
+
annotation,
|
| 757 |
+
orig_size=image.size()[-2:],
|
| 758 |
+
target_size=resized_image.size()[-2:],
|
| 759 |
+
)
|
| 760 |
+
image = resized_image
|
| 761 |
+
# Fused rescale and normalize
|
| 762 |
+
image = self.rescale_and_normalize(image, do_rescale, rescale_factor, do_normalize, image_mean, image_std)
|
| 763 |
+
if do_convert_annotations and annotations is not None:
|
| 764 |
+
annotation = self.normalize_annotation(annotation, get_image_size(image, ChannelDimension.FIRST))
|
| 765 |
+
|
| 766 |
+
processed_images.append(image)
|
| 767 |
+
processed_annotations.append(annotation)
|
| 768 |
+
images = processed_images
|
| 769 |
+
annotations = processed_annotations if annotations is not None else None
|
| 770 |
+
|
| 771 |
+
if do_pad:
|
| 772 |
+
# depends on all resized image shapes so we need another loop
|
| 773 |
+
if pad_size is not None:
|
| 774 |
+
padded_size = (pad_size.height, pad_size.width)
|
| 775 |
+
else:
|
| 776 |
+
padded_size = get_max_height_width(images)
|
| 777 |
+
|
| 778 |
+
padded_images = []
|
| 779 |
+
padded_annotations = []
|
| 780 |
+
for image, annotation in zip(images, annotations if annotations is not None else [None] * len(images)):
|
| 781 |
+
# Pads images and returns their mask: {'pixel_values': ..., 'pixel_mask': ...}
|
| 782 |
+
if padded_size == image.size()[-2:]:
|
| 783 |
+
padded_images.append(image)
|
| 784 |
+
pixel_masks.append(torch.ones(padded_size, dtype=torch.int64, device=image.device))
|
| 785 |
+
padded_annotations.append(annotation)
|
| 786 |
+
continue
|
| 787 |
+
image, pixel_mask, annotation = self.pad(
|
| 788 |
+
image, padded_size, annotation=annotation, update_bboxes=do_convert_annotations
|
| 789 |
+
)
|
| 790 |
+
padded_images.append(image)
|
| 791 |
+
padded_annotations.append(annotation)
|
| 792 |
+
pixel_masks.append(pixel_mask)
|
| 793 |
+
images = padded_images
|
| 794 |
+
annotations = padded_annotations if annotations is not None else None
|
| 795 |
+
data.update({"pixel_mask": torch.stack(pixel_masks, dim=0)})
|
| 796 |
+
|
| 797 |
+
data.update({"pixel_values": torch.stack(images, dim=0)})
|
| 798 |
+
encoded_inputs = BatchFeature(data, tensor_type=return_tensors)
|
| 799 |
+
if annotations is not None:
|
| 800 |
+
encoded_inputs["labels"] = [
|
| 801 |
+
BatchFeature(annotation, tensor_type=return_tensors) for annotation in annotations
|
| 802 |
+
]
|
| 803 |
+
return encoded_inputs
|
| 804 |
+
|
| 805 |
+
def post_process_object_detection(
|
| 806 |
+
self, outputs, threshold: float = 0.5, target_sizes: TensorType | list[tuple] = None, top_k: int = 100
|
| 807 |
+
):
|
| 808 |
+
"""
|
| 809 |
+
Converts the raw output of [`ConditionalDetrForObjectDetection`] into final bounding boxes in (top_left_x,
|
| 810 |
+
top_left_y, bottom_right_x, bottom_right_y) format. Only supports PyTorch.
|
| 811 |
+
|
| 812 |
+
Args:
|
| 813 |
+
outputs ([`ConditionalDetrObjectDetectionOutput`]):
|
| 814 |
+
Raw outputs of the model.
|
| 815 |
+
threshold (`float`, *optional*):
|
| 816 |
+
Score threshold to keep object detection predictions.
|
| 817 |
+
target_sizes (`torch.Tensor` or `list[tuple[int, int]]`, *optional*):
|
| 818 |
+
Tensor of shape `(batch_size, 2)` or list of tuples (`tuple[int, int]`) containing the target size
|
| 819 |
+
(height, width) of each image in the batch. If left to None, predictions will not be resized.
|
| 820 |
+
top_k (`int`, *optional*, defaults to 100):
|
| 821 |
+
Keep only top k bounding boxes before filtering by thresholding.
|
| 822 |
+
|
| 823 |
+
Returns:
|
| 824 |
+
`list[Dict]`: A list of dictionaries, each dictionary containing the scores, labels and boxes for an image
|
| 825 |
+
in the batch as predicted by the model.
|
| 826 |
+
"""
|
| 827 |
+
out_logits, out_bbox = outputs.logits, outputs.pred_boxes
|
| 828 |
+
|
| 829 |
+
if target_sizes is not None:
|
| 830 |
+
if len(out_logits) != len(target_sizes):
|
| 831 |
+
raise ValueError(
|
| 832 |
+
"Make sure that you pass in as many target sizes as the batch dimension of the logits"
|
| 833 |
+
)
|
| 834 |
+
|
| 835 |
+
prob = out_logits.sigmoid()
|
| 836 |
+
prob = prob.view(out_logits.shape[0], -1)
|
| 837 |
+
k_value = min(top_k, prob.size(1))
|
| 838 |
+
topk_values, topk_indexes = torch.topk(prob, k_value, dim=1)
|
| 839 |
+
scores = topk_values
|
| 840 |
+
topk_boxes = torch.div(topk_indexes, out_logits.shape[2], rounding_mode="floor")
|
| 841 |
+
labels = topk_indexes % out_logits.shape[2]
|
| 842 |
+
boxes = center_to_corners_format(out_bbox)
|
| 843 |
+
boxes = torch.gather(boxes, 1, topk_boxes.unsqueeze(-1).repeat(1, 1, 4))
|
| 844 |
+
|
| 845 |
+
# and from relative [0, 1] to absolute [0, height] coordinates
|
| 846 |
+
if target_sizes is not None:
|
| 847 |
+
if isinstance(target_sizes, list):
|
| 848 |
+
img_h = torch.Tensor([i[0] for i in target_sizes])
|
| 849 |
+
img_w = torch.Tensor([i[1] for i in target_sizes])
|
| 850 |
+
else:
|
| 851 |
+
img_h, img_w = target_sizes.unbind(1)
|
| 852 |
+
scale_fct = torch.stack([img_w, img_h, img_w, img_h], dim=1).to(boxes.device)
|
| 853 |
+
boxes = boxes * scale_fct[:, None, :]
|
| 854 |
+
|
| 855 |
+
results = []
|
| 856 |
+
for s, l, b in zip(scores, labels, boxes):
|
| 857 |
+
score = s[s > threshold]
|
| 858 |
+
label = l[s > threshold]
|
| 859 |
+
box = b[s > threshold]
|
| 860 |
+
results.append({"scores": score, "labels": label, "boxes": box})
|
| 861 |
+
|
| 862 |
+
return results
|
| 863 |
+
|
| 864 |
+
def post_process_semantic_segmentation(self, outputs, target_sizes: list[tuple[int, int]] | None = None):
|
| 865 |
+
"""
|
| 866 |
+
Converts the output of [`ConditionalDetrForSegmentation`] into semantic segmentation maps. Only supports PyTorch.
|
| 867 |
+
|
| 868 |
+
Args:
|
| 869 |
+
outputs ([`ConditionalDetrForSegmentation`]):
|
| 870 |
+
Raw outputs of the model.
|
| 871 |
+
target_sizes (`list[tuple[int, int]]`, *optional*):
|
| 872 |
+
A list of tuples (`tuple[int, int]`) containing the target size (height, width) of each image in the
|
| 873 |
+
batch. If unset, predictions will not be resized.
|
| 874 |
+
Returns:
|
| 875 |
+
`list[torch.Tensor]`:
|
| 876 |
+
A list of length `batch_size`, where each item is a semantic segmentation map of shape (height, width)
|
| 877 |
+
corresponding to the target_sizes entry (if `target_sizes` is specified). Each entry of each
|
| 878 |
+
`torch.Tensor` correspond to a semantic class id.
|
| 879 |
+
"""
|
| 880 |
+
class_queries_logits = outputs.logits # [batch_size, num_queries, num_classes]
|
| 881 |
+
masks_queries_logits = outputs.pred_masks # [batch_size, num_queries, height, width]
|
| 882 |
+
|
| 883 |
+
# Conditional DETR does not have a null class, so we use all classes
|
| 884 |
+
masks_classes = class_queries_logits.softmax(dim=-1)
|
| 885 |
+
masks_probs = masks_queries_logits.sigmoid() # [batch_size, num_queries, height, width]
|
| 886 |
+
|
| 887 |
+
# Semantic segmentation logits of shape (batch_size, num_classes, height, width)
|
| 888 |
+
segmentation = torch.einsum("bqc, bqhw -> bchw", masks_classes, masks_probs)
|
| 889 |
+
batch_size = class_queries_logits.shape[0]
|
| 890 |
+
|
| 891 |
+
# Resize logits and compute semantic segmentation maps
|
| 892 |
+
if target_sizes is not None:
|
| 893 |
+
if batch_size != len(target_sizes):
|
| 894 |
+
raise ValueError(
|
| 895 |
+
"Make sure that you pass in as many target sizes as the batch dimension of the logits"
|
| 896 |
+
)
|
| 897 |
+
|
| 898 |
+
semantic_segmentation = []
|
| 899 |
+
for idx in range(batch_size):
|
| 900 |
+
resized_logits = nn.functional.interpolate(
|
| 901 |
+
segmentation[idx].unsqueeze(dim=0), size=target_sizes[idx], mode="bilinear", align_corners=False
|
| 902 |
+
)
|
| 903 |
+
semantic_map = resized_logits[0].argmax(dim=0)
|
| 904 |
+
semantic_segmentation.append(semantic_map)
|
| 905 |
+
else:
|
| 906 |
+
semantic_segmentation = segmentation.argmax(dim=1)
|
| 907 |
+
semantic_segmentation = [semantic_segmentation[i] for i in range(semantic_segmentation.shape[0])]
|
| 908 |
+
|
| 909 |
+
return semantic_segmentation
|
| 910 |
+
|
| 911 |
+
def post_process_instance_segmentation(
|
| 912 |
+
self,
|
| 913 |
+
outputs,
|
| 914 |
+
threshold: float = 0.5,
|
| 915 |
+
mask_threshold: float = 0.5,
|
| 916 |
+
overlap_mask_area_threshold: float = 0.8,
|
| 917 |
+
target_sizes: list[tuple[int, int]] | None = None,
|
| 918 |
+
return_coco_annotation: bool | None = False,
|
| 919 |
+
) -> list[dict]:
|
| 920 |
+
"""
|
| 921 |
+
Converts the output of [`ConditionalDetrForSegmentation`] into instance segmentation predictions. Only supports PyTorch.
|
| 922 |
+
|
| 923 |
+
Args:
|
| 924 |
+
outputs ([`ConditionalDetrForSegmentation`]):
|
| 925 |
+
Raw outputs of the model.
|
| 926 |
+
threshold (`float`, *optional*, defaults to 0.5):
|
| 927 |
+
The probability score threshold to keep predicted instance masks.
|
| 928 |
+
mask_threshold (`float`, *optional*, defaults to 0.5):
|
| 929 |
+
Threshold to use when turning the predicted masks into binary values.
|
| 930 |
+
overlap_mask_area_threshold (`float`, *optional*, defaults to 0.8):
|
| 931 |
+
The overlap mask area threshold to merge or discard small disconnected parts within each binary
|
| 932 |
+
instance mask.
|
| 933 |
+
target_sizes (`list[Tuple]`, *optional*):
|
| 934 |
+
List of length (batch_size), where each list item (`tuple[int, int]]`) corresponds to the requested
|
| 935 |
+
final size (height, width) of each prediction. If unset, predictions will not be resized.
|
| 936 |
+
return_coco_annotation (`bool`, *optional*):
|
| 937 |
+
Defaults to `False`. If set to `True`, segmentation maps are returned in COCO run-length encoding (RLE)
|
| 938 |
+
format.
|
| 939 |
+
Returns:
|
| 940 |
+
`list[Dict]`: A list of dictionaries, one per image, each dictionary containing two keys:
|
| 941 |
+
- **segmentation** -- A tensor of shape `(height, width)` where each pixel represents a `segment_id` or
|
| 942 |
+
`list[List]` run-length encoding (RLE) of the segmentation map if return_coco_annotation is set to
|
| 943 |
+
`True`. Set to `None` if no mask if found above `threshold`.
|
| 944 |
+
- **segments_info** -- A dictionary that contains additional information on each segment.
|
| 945 |
+
- **id** -- An integer representing the `segment_id`.
|
| 946 |
+
- **label_id** -- An integer representing the label / semantic class id corresponding to `segment_id`.
|
| 947 |
+
- **score** -- Prediction score of segment with `segment_id`.
|
| 948 |
+
"""
|
| 949 |
+
class_queries_logits = outputs.logits # [batch_size, num_queries, num_classes+1]
|
| 950 |
+
masks_queries_logits = outputs.pred_masks # [batch_size, num_queries, height, width]
|
| 951 |
+
|
| 952 |
+
batch_size = class_queries_logits.shape[0]
|
| 953 |
+
num_labels = class_queries_logits.shape[-1] - 1
|
| 954 |
+
|
| 955 |
+
mask_probs = masks_queries_logits.sigmoid() # [batch_size, num_queries, height, width]
|
| 956 |
+
|
| 957 |
+
# Predicted label and score of each query (batch_size, num_queries)
|
| 958 |
+
pred_scores, pred_labels = nn.functional.softmax(class_queries_logits, dim=-1).max(-1)
|
| 959 |
+
|
| 960 |
+
# Loop over items in batch size
|
| 961 |
+
results: list[dict[str, TensorType]] = []
|
| 962 |
+
|
| 963 |
+
for i in range(batch_size):
|
| 964 |
+
mask_probs_item, pred_scores_item, pred_labels_item = remove_low_and_no_objects(
|
| 965 |
+
mask_probs[i], pred_scores[i], pred_labels[i], threshold, num_labels
|
| 966 |
+
)
|
| 967 |
+
|
| 968 |
+
# No mask found
|
| 969 |
+
if mask_probs_item.shape[0] <= 0:
|
| 970 |
+
height, width = target_sizes[i] if target_sizes is not None else mask_probs_item.shape[1:]
|
| 971 |
+
segmentation = torch.zeros((height, width)) - 1
|
| 972 |
+
results.append({"segmentation": segmentation, "segments_info": []})
|
| 973 |
+
continue
|
| 974 |
+
|
| 975 |
+
# Get segmentation map and segment information of batch item
|
| 976 |
+
target_size = target_sizes[i] if target_sizes is not None else None
|
| 977 |
+
segmentation, segments = compute_segments(
|
| 978 |
+
mask_probs=mask_probs_item,
|
| 979 |
+
pred_scores=pred_scores_item,
|
| 980 |
+
pred_labels=pred_labels_item,
|
| 981 |
+
mask_threshold=mask_threshold,
|
| 982 |
+
overlap_mask_area_threshold=overlap_mask_area_threshold,
|
| 983 |
+
label_ids_to_fuse=[],
|
| 984 |
+
target_size=target_size,
|
| 985 |
+
)
|
| 986 |
+
|
| 987 |
+
# Return segmentation map in run-length encoding (RLE) format
|
| 988 |
+
if return_coco_annotation:
|
| 989 |
+
segmentation = convert_segmentation_to_rle(segmentation)
|
| 990 |
+
|
| 991 |
+
results.append({"segmentation": segmentation, "segments_info": segments})
|
| 992 |
+
return results
|
| 993 |
+
|
| 994 |
+
def post_process_panoptic_segmentation(
|
| 995 |
+
self,
|
| 996 |
+
outputs,
|
| 997 |
+
threshold: float = 0.5,
|
| 998 |
+
mask_threshold: float = 0.5,
|
| 999 |
+
overlap_mask_area_threshold: float = 0.8,
|
| 1000 |
+
label_ids_to_fuse: set[int] | None = None,
|
| 1001 |
+
target_sizes: list[tuple[int, int]] | None = None,
|
| 1002 |
+
) -> list[dict]:
|
| 1003 |
+
"""
|
| 1004 |
+
Converts the output of [`ConditionalDetrForSegmentation`] into image panoptic segmentation predictions. Only supports
|
| 1005 |
+
PyTorch.
|
| 1006 |
+
|
| 1007 |
+
Args:
|
| 1008 |
+
outputs ([`ConditionalDetrForSegmentation`]):
|
| 1009 |
+
The outputs from [`ConditionalDetrForSegmentation`].
|
| 1010 |
+
threshold (`float`, *optional*, defaults to 0.5):
|
| 1011 |
+
The probability score threshold to keep predicted instance masks.
|
| 1012 |
+
mask_threshold (`float`, *optional*, defaults to 0.5):
|
| 1013 |
+
Threshold to use when turning the predicted masks into binary values.
|
| 1014 |
+
overlap_mask_area_threshold (`float`, *optional*, defaults to 0.8):
|
| 1015 |
+
The overlap mask area threshold to merge or discard small disconnected parts within each binary
|
| 1016 |
+
instance mask.
|
| 1017 |
+
label_ids_to_fuse (`Set[int]`, *optional*):
|
| 1018 |
+
The labels in this state will have all their instances be fused together. For instance we could say
|
| 1019 |
+
there can only be one sky in an image, but several persons, so the label ID for sky would be in that
|
| 1020 |
+
set, but not the one for person.
|
| 1021 |
+
target_sizes (`list[Tuple]`, *optional*):
|
| 1022 |
+
List of length (batch_size), where each list item (`tuple[int, int]]`) corresponds to the requested
|
| 1023 |
+
final size (height, width) of each prediction in batch. If unset, predictions will not be resized.
|
| 1024 |
+
Returns:
|
| 1025 |
+
`list[Dict]`: A list of dictionaries, one per image, each dictionary containing two keys:
|
| 1026 |
+
- **segmentation** -- a tensor of shape `(height, width)` where each pixel represents a `segment_id` or
|
| 1027 |
+
`None` if no mask if found above `threshold`. If `target_sizes` is specified, segmentation is resized to
|
| 1028 |
+
the corresponding `target_sizes` entry.
|
| 1029 |
+
- **segments_info** -- A dictionary that contains additional information on each segment.
|
| 1030 |
+
- **id** -- an integer representing the `segment_id`.
|
| 1031 |
+
- **label_id** -- An integer representing the label / semantic class id corresponding to `segment_id`.
|
| 1032 |
+
- **was_fused** -- a boolean, `True` if `label_id` was in `label_ids_to_fuse`, `False` otherwise.
|
| 1033 |
+
Multiple instances of the same class / label were fused and assigned a single `segment_id`.
|
| 1034 |
+
- **score** -- Prediction score of segment with `segment_id`.
|
| 1035 |
+
"""
|
| 1036 |
+
|
| 1037 |
+
if label_ids_to_fuse is None:
|
| 1038 |
+
logger.warning_once("`label_ids_to_fuse` unset. No instance will be fused.")
|
| 1039 |
+
label_ids_to_fuse = set()
|
| 1040 |
+
|
| 1041 |
+
class_queries_logits = outputs.logits # [batch_size, num_queries, num_classes+1]
|
| 1042 |
+
masks_queries_logits = outputs.pred_masks # [batch_size, num_queries, height, width]
|
| 1043 |
+
|
| 1044 |
+
batch_size = class_queries_logits.shape[0]
|
| 1045 |
+
num_labels = class_queries_logits.shape[-1] - 1
|
| 1046 |
+
|
| 1047 |
+
mask_probs = masks_queries_logits.sigmoid() # [batch_size, num_queries, height, width]
|
| 1048 |
+
|
| 1049 |
+
# Predicted label and score of each query (batch_size, num_queries)
|
| 1050 |
+
pred_scores, pred_labels = nn.functional.softmax(class_queries_logits, dim=-1).max(-1)
|
| 1051 |
+
|
| 1052 |
+
# Loop over items in batch size
|
| 1053 |
+
results: list[dict[str, TensorType]] = []
|
| 1054 |
+
|
| 1055 |
+
for i in range(batch_size):
|
| 1056 |
+
mask_probs_item, pred_scores_item, pred_labels_item = remove_low_and_no_objects(
|
| 1057 |
+
mask_probs[i], pred_scores[i], pred_labels[i], threshold, num_labels
|
| 1058 |
+
)
|
| 1059 |
+
|
| 1060 |
+
# No mask found
|
| 1061 |
+
if mask_probs_item.shape[0] <= 0:
|
| 1062 |
+
height, width = target_sizes[i] if target_sizes is not None else mask_probs_item.shape[1:]
|
| 1063 |
+
segmentation = torch.zeros((height, width)) - 1
|
| 1064 |
+
results.append({"segmentation": segmentation, "segments_info": []})
|
| 1065 |
+
continue
|
| 1066 |
+
|
| 1067 |
+
# Get segmentation map and segment information of batch item
|
| 1068 |
+
target_size = target_sizes[i] if target_sizes is not None else None
|
| 1069 |
+
segmentation, segments = compute_segments(
|
| 1070 |
+
mask_probs=mask_probs_item,
|
| 1071 |
+
pred_scores=pred_scores_item,
|
| 1072 |
+
pred_labels=pred_labels_item,
|
| 1073 |
+
mask_threshold=mask_threshold,
|
| 1074 |
+
overlap_mask_area_threshold=overlap_mask_area_threshold,
|
| 1075 |
+
label_ids_to_fuse=label_ids_to_fuse,
|
| 1076 |
+
target_size=target_size,
|
| 1077 |
+
)
|
| 1078 |
+
|
| 1079 |
+
results.append({"segmentation": segmentation, "segments_info": segments})
|
| 1080 |
+
return results
|
| 1081 |
+
|
| 1082 |
+
|
| 1083 |
+
__all__ = ["ConditionalDetrImageProcessor"]
|
third_party/transformers/src/transformers/models/conditional_detr/image_processing_pil_conditional_detr.py
ADDED
|
@@ -0,0 +1,1136 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
# 🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨
|
| 2 |
+
# This file was automatically generated from src/transformers/models/conditional_detr/modular_conditional_detr.py.
|
| 3 |
+
# Do NOT edit this file manually as any edits will be overwritten by the generation of
|
| 4 |
+
# the file from the modular. If any change should be done, please apply the change to the
|
| 5 |
+
# modular_conditional_detr.py file directly. One of our CI enforces this.
|
| 6 |
+
# 🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨
|
| 7 |
+
# Copyright 2022 Microsoft Research Asia and The HuggingFace Inc. team. All rights reserved.
|
| 8 |
+
#
|
| 9 |
+
# Licensed under the Apache License, Version 2.0 (the "License");
|
| 10 |
+
# you may not use this file except in compliance with the License.
|
| 11 |
+
# You may obtain a copy of the License at
|
| 12 |
+
#
|
| 13 |
+
# http://www.apache.org/licenses/LICENSE-2.0
|
| 14 |
+
#
|
| 15 |
+
# Unless required by applicable law or agreed to in writing, software
|
| 16 |
+
# distributed under the License is distributed on an "AS IS" BASIS,
|
| 17 |
+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
| 18 |
+
# See the License for the specific language governing permissions and
|
| 19 |
+
# limitations under the License.
|
| 20 |
+
|
| 21 |
+
import pathlib
|
| 22 |
+
from typing import Any, Optional
|
| 23 |
+
|
| 24 |
+
import numpy as np
|
| 25 |
+
|
| 26 |
+
from ...image_processing_backends import PilBackend
|
| 27 |
+
from ...image_processing_utils import BatchFeature
|
| 28 |
+
from ...image_transforms import (
|
| 29 |
+
PaddingMode,
|
| 30 |
+
center_to_corners_format,
|
| 31 |
+
corners_to_center_format,
|
| 32 |
+
get_size_with_aspect_ratio,
|
| 33 |
+
pad,
|
| 34 |
+
resize,
|
| 35 |
+
safe_squeeze,
|
| 36 |
+
)
|
| 37 |
+
from ...image_utils import (
|
| 38 |
+
IMAGENET_DEFAULT_MEAN,
|
| 39 |
+
IMAGENET_DEFAULT_STD,
|
| 40 |
+
AnnotationFormat,
|
| 41 |
+
AnnotationType,
|
| 42 |
+
ChannelDimension,
|
| 43 |
+
ImageInput,
|
| 44 |
+
PILImageResampling,
|
| 45 |
+
SizeDict,
|
| 46 |
+
get_image_size,
|
| 47 |
+
get_image_size_for_max_height_width,
|
| 48 |
+
get_max_height_width,
|
| 49 |
+
validate_annotations,
|
| 50 |
+
)
|
| 51 |
+
from ...processing_utils import ImagesKwargs, Unpack
|
| 52 |
+
from ...utils import TensorType, auto_docstring, is_torch_available, is_vision_available, logging, requires_backends
|
| 53 |
+
from ...utils.import_utils import requires
|
| 54 |
+
|
| 55 |
+
|
| 56 |
+
if is_vision_available():
|
| 57 |
+
import PIL.Image
|
| 58 |
+
if is_torch_available():
|
| 59 |
+
import torch
|
| 60 |
+
from torch import nn
|
| 61 |
+
|
| 62 |
+
logger = logging.get_logger(__name__)
|
| 63 |
+
|
| 64 |
+
|
| 65 |
+
class ConditionalDetrImageProcessorKwargs(ImagesKwargs, total=False):
|
| 66 |
+
r"""
|
| 67 |
+
format (`str`, *optional*, defaults to `AnnotationFormat.COCO_DETECTION`):
|
| 68 |
+
Data format of the annotations. One of "coco_detection" or "coco_panoptic".
|
| 69 |
+
do_convert_annotations (`bool`, *optional*, defaults to `True`):
|
| 70 |
+
Controls whether to convert the annotations to the format expected by the CONDITIONAL_DETR model. Converts the
|
| 71 |
+
bounding boxes to the format `(center_x, center_y, width, height)` and in the range `[0, 1]`.
|
| 72 |
+
Can be overridden by the `do_convert_annotations` parameter in the `preprocess` method.
|
| 73 |
+
"""
|
| 74 |
+
|
| 75 |
+
format: str | AnnotationFormat
|
| 76 |
+
do_convert_annotations: bool
|
| 77 |
+
|
| 78 |
+
|
| 79 |
+
SUPPORTED_ANNOTATION_FORMATS = (AnnotationFormat.COCO_DETECTION, AnnotationFormat.COCO_PANOPTIC)
|
| 80 |
+
|
| 81 |
+
|
| 82 |
+
# inspired by https://github.com/facebookresearch/conditional_detr/blob/master/datasets/coco.py#L33
|
| 83 |
+
def convert_coco_poly_to_mask(segmentations, height: int, width: int) -> np.ndarray:
|
| 84 |
+
"""
|
| 85 |
+
Convert a COCO polygon annotation to a mask.
|
| 86 |
+
|
| 87 |
+
Args:
|
| 88 |
+
segmentations (`list[list[float]]`):
|
| 89 |
+
List of polygons, each polygon represented by a list of x-y coordinates.
|
| 90 |
+
height (`int`):
|
| 91 |
+
Height of the mask.
|
| 92 |
+
width (`int`):
|
| 93 |
+
Width of the mask.
|
| 94 |
+
"""
|
| 95 |
+
try:
|
| 96 |
+
from pycocotools import mask as coco_mask
|
| 97 |
+
except ImportError:
|
| 98 |
+
raise ImportError("Pycocotools is not installed in your environment.")
|
| 99 |
+
|
| 100 |
+
masks = []
|
| 101 |
+
for polygons in segmentations:
|
| 102 |
+
rles = coco_mask.frPyObjects(polygons, height, width)
|
| 103 |
+
mask = coco_mask.decode(rles)
|
| 104 |
+
if len(mask.shape) < 3:
|
| 105 |
+
mask = mask[..., None]
|
| 106 |
+
mask = np.asarray(mask, dtype=np.uint8)
|
| 107 |
+
mask = np.any(mask, axis=2)
|
| 108 |
+
masks.append(mask)
|
| 109 |
+
if masks:
|
| 110 |
+
masks = np.stack(masks, axis=0)
|
| 111 |
+
else:
|
| 112 |
+
masks = np.zeros((0, height, width), dtype=np.uint8)
|
| 113 |
+
|
| 114 |
+
return masks
|
| 115 |
+
|
| 116 |
+
|
| 117 |
+
# inspired by https://github.com/facebookresearch/conditional_detr/blob/master/datasets/coco.py#L50
|
| 118 |
+
def prepare_coco_detection_annotation(
|
| 119 |
+
image,
|
| 120 |
+
target,
|
| 121 |
+
return_segmentation_masks: bool = False,
|
| 122 |
+
input_data_format: ChannelDimension | str | None = None,
|
| 123 |
+
):
|
| 124 |
+
"""
|
| 125 |
+
Convert the target in COCO format into the format expected by CONDITIONAL_DETR.
|
| 126 |
+
"""
|
| 127 |
+
image_height, image_width = get_image_size(image, channel_dim=input_data_format)
|
| 128 |
+
|
| 129 |
+
image_id = target["image_id"]
|
| 130 |
+
image_id = np.asarray([image_id], dtype=np.int64)
|
| 131 |
+
|
| 132 |
+
# Get all COCO annotations for the given image.
|
| 133 |
+
annotations = target["annotations"]
|
| 134 |
+
annotations = [obj for obj in annotations if "iscrowd" not in obj or obj["iscrowd"] == 0]
|
| 135 |
+
|
| 136 |
+
classes = [obj["category_id"] for obj in annotations]
|
| 137 |
+
classes = np.asarray(classes, dtype=np.int64)
|
| 138 |
+
|
| 139 |
+
# for conversion to coco api
|
| 140 |
+
area = np.asarray([obj["area"] for obj in annotations], dtype=np.float32)
|
| 141 |
+
iscrowd = np.asarray([obj.get("iscrowd", 0) for obj in annotations], dtype=np.int64)
|
| 142 |
+
|
| 143 |
+
boxes = [obj["bbox"] for obj in annotations]
|
| 144 |
+
# guard against no boxes via resizing
|
| 145 |
+
boxes = np.asarray(boxes, dtype=np.float32).reshape(-1, 4)
|
| 146 |
+
boxes[:, 2:] += boxes[:, :2]
|
| 147 |
+
boxes[:, 0::2] = boxes[:, 0::2].clip(min=0, max=image_width)
|
| 148 |
+
boxes[:, 1::2] = boxes[:, 1::2].clip(min=0, max=image_height)
|
| 149 |
+
|
| 150 |
+
keep = (boxes[:, 3] > boxes[:, 1]) & (boxes[:, 2] > boxes[:, 0])
|
| 151 |
+
|
| 152 |
+
new_target = {}
|
| 153 |
+
new_target["image_id"] = image_id
|
| 154 |
+
new_target["class_labels"] = classes[keep]
|
| 155 |
+
new_target["boxes"] = boxes[keep]
|
| 156 |
+
new_target["area"] = area[keep]
|
| 157 |
+
new_target["iscrowd"] = iscrowd[keep]
|
| 158 |
+
new_target["orig_size"] = np.asarray([int(image_height), int(image_width)], dtype=np.int64)
|
| 159 |
+
|
| 160 |
+
if annotations and "keypoints" in annotations[0]:
|
| 161 |
+
keypoints = [obj["keypoints"] for obj in annotations]
|
| 162 |
+
# Converting the filtered keypoints list to a numpy array
|
| 163 |
+
keypoints = np.asarray(keypoints, dtype=np.float32)
|
| 164 |
+
# Apply the keep mask here to filter the relevant annotations
|
| 165 |
+
keypoints = keypoints[keep]
|
| 166 |
+
num_keypoints = keypoints.shape[0]
|
| 167 |
+
keypoints = keypoints.reshape((-1, 3)) if num_keypoints else keypoints
|
| 168 |
+
new_target["keypoints"] = keypoints
|
| 169 |
+
|
| 170 |
+
if return_segmentation_masks:
|
| 171 |
+
segmentation_masks = [obj["segmentation"] for obj in annotations]
|
| 172 |
+
masks = convert_coco_poly_to_mask(segmentation_masks, image_height, image_width)
|
| 173 |
+
new_target["masks"] = masks[keep]
|
| 174 |
+
|
| 175 |
+
return new_target
|
| 176 |
+
|
| 177 |
+
|
| 178 |
+
def masks_to_boxes(masks: np.ndarray) -> np.ndarray:
|
| 179 |
+
"""
|
| 180 |
+
Compute the bounding boxes around the provided panoptic segmentation masks.
|
| 181 |
+
|
| 182 |
+
Args:
|
| 183 |
+
masks: masks in format `[number_masks, height, width]` where N is the number of masks
|
| 184 |
+
|
| 185 |
+
Returns:
|
| 186 |
+
boxes: bounding boxes in format `[number_masks, 4]` in xyxy format
|
| 187 |
+
"""
|
| 188 |
+
if masks.size == 0:
|
| 189 |
+
return np.zeros((0, 4))
|
| 190 |
+
|
| 191 |
+
h, w = masks.shape[-2:]
|
| 192 |
+
y = np.arange(0, h, dtype=np.float32)
|
| 193 |
+
x = np.arange(0, w, dtype=np.float32)
|
| 194 |
+
# see https://github.com/pytorch/pytorch/issues/50276
|
| 195 |
+
y, x = np.meshgrid(y, x, indexing="ij")
|
| 196 |
+
|
| 197 |
+
x_mask = masks * np.expand_dims(x, axis=0)
|
| 198 |
+
x_max = x_mask.reshape(x_mask.shape[0], -1).max(-1)
|
| 199 |
+
x = np.ma.array(x_mask, mask=~(np.array(masks, dtype=bool)))
|
| 200 |
+
x_min = x.filled(fill_value=1e8)
|
| 201 |
+
x_min = x_min.reshape(x_min.shape[0], -1).min(-1)
|
| 202 |
+
|
| 203 |
+
y_mask = masks * np.expand_dims(y, axis=0)
|
| 204 |
+
y_max = y_mask.reshape(x_mask.shape[0], -1).max(-1)
|
| 205 |
+
y = np.ma.array(y_mask, mask=~(np.array(masks, dtype=bool)))
|
| 206 |
+
y_min = y.filled(fill_value=1e8)
|
| 207 |
+
y_min = y_min.reshape(y_min.shape[0], -1).min(-1)
|
| 208 |
+
|
| 209 |
+
return np.stack([x_min, y_min, x_max, y_max], 1)
|
| 210 |
+
|
| 211 |
+
|
| 212 |
+
# 2 functions below adapted from https://github.com/cocodataset/panopticapi/blob/master/panopticapi/utils.py
|
| 213 |
+
# Copyright (c) 2018, Alexander Kirillov
|
| 214 |
+
# All rights reserved.
|
| 215 |
+
def rgb_to_id(color):
|
| 216 |
+
"""
|
| 217 |
+
Converts RGB color to unique ID.
|
| 218 |
+
"""
|
| 219 |
+
if isinstance(color, np.ndarray) and len(color.shape) == 3:
|
| 220 |
+
if color.dtype == np.uint8:
|
| 221 |
+
color = color.astype(np.int32)
|
| 222 |
+
return color[:, :, 0] + 256 * color[:, :, 1] + 256 * 256 * color[:, :, 2]
|
| 223 |
+
return int(color[0] + 256 * color[1] + 256 * 256 * color[2])
|
| 224 |
+
|
| 225 |
+
|
| 226 |
+
def prepare_coco_panoptic_annotation(
|
| 227 |
+
image: np.ndarray,
|
| 228 |
+
target: dict,
|
| 229 |
+
masks_path: str | pathlib.Path,
|
| 230 |
+
return_masks: bool = True,
|
| 231 |
+
input_data_format: ChannelDimension | str = None,
|
| 232 |
+
) -> dict:
|
| 233 |
+
"""
|
| 234 |
+
Prepare a coco panoptic annotation for CONDITIONAL_DETR.
|
| 235 |
+
"""
|
| 236 |
+
image_height, image_width = get_image_size(image, channel_dim=input_data_format)
|
| 237 |
+
annotation_path = pathlib.Path(masks_path) / target["file_name"]
|
| 238 |
+
|
| 239 |
+
new_target = {}
|
| 240 |
+
new_target["image_id"] = np.asarray([target["image_id"] if "image_id" in target else target["id"]], dtype=np.int64)
|
| 241 |
+
new_target["size"] = np.asarray([image_height, image_width], dtype=np.int64)
|
| 242 |
+
new_target["orig_size"] = np.asarray([image_height, image_width], dtype=np.int64)
|
| 243 |
+
|
| 244 |
+
if "segments_info" in target:
|
| 245 |
+
masks = np.asarray(PIL.Image.open(annotation_path), dtype=np.uint32)
|
| 246 |
+
masks = rgb_to_id(masks)
|
| 247 |
+
|
| 248 |
+
ids = np.array([segment_info["id"] for segment_info in target["segments_info"]])
|
| 249 |
+
masks = masks == ids[:, None, None]
|
| 250 |
+
masks = masks.astype(np.uint8)
|
| 251 |
+
if return_masks:
|
| 252 |
+
new_target["masks"] = masks
|
| 253 |
+
new_target["boxes"] = masks_to_boxes(masks)
|
| 254 |
+
new_target["class_labels"] = np.array(
|
| 255 |
+
[segment_info["category_id"] for segment_info in target["segments_info"]], dtype=np.int64
|
| 256 |
+
)
|
| 257 |
+
new_target["iscrowd"] = np.asarray(
|
| 258 |
+
[segment_info["iscrowd"] for segment_info in target["segments_info"]], dtype=np.int64
|
| 259 |
+
)
|
| 260 |
+
new_target["area"] = np.asarray(
|
| 261 |
+
[segment_info["area"] for segment_info in target["segments_info"]], dtype=np.float32
|
| 262 |
+
)
|
| 263 |
+
|
| 264 |
+
return new_target
|
| 265 |
+
|
| 266 |
+
|
| 267 |
+
# Adapted from transformers.models.conditional_detr.image_processing_conditional_detr.binary_mask_to_rle
|
| 268 |
+
def binary_mask_to_rle(mask):
|
| 269 |
+
"""
|
| 270 |
+
Converts given binary mask of shape `(height, width)` to the run-length encoding (RLE) format.
|
| 271 |
+
|
| 272 |
+
Args:
|
| 273 |
+
mask (`torch.Tensor` or `numpy.array`):
|
| 274 |
+
A binary mask tensor of shape `(height, width)` where 0 denotes background and 1 denotes the target
|
| 275 |
+
segment_id or class_id.
|
| 276 |
+
Returns:
|
| 277 |
+
`List`: Run-length encoded list of the binary mask. Refer to COCO API for more information about the RLE
|
| 278 |
+
format.
|
| 279 |
+
"""
|
| 280 |
+
from ...utils import is_torch_tensor
|
| 281 |
+
|
| 282 |
+
if is_torch_tensor(mask):
|
| 283 |
+
mask = mask.numpy()
|
| 284 |
+
|
| 285 |
+
pixels = mask.flatten()
|
| 286 |
+
pixels = np.concatenate([[0], pixels, [0]])
|
| 287 |
+
runs = np.where(pixels[1:] != pixels[:-1])[0] + 1
|
| 288 |
+
runs[1::2] -= runs[::2]
|
| 289 |
+
return list(runs)
|
| 290 |
+
|
| 291 |
+
|
| 292 |
+
# Adapted from transformers.models.conditional_detr.image_processing_conditional_detr.check_segment_validity
|
| 293 |
+
def check_segment_validity(mask_labels, mask_probs, k, mask_threshold=0.5, overlap_mask_area_threshold=0.8):
|
| 294 |
+
# Get the mask associated with the k class
|
| 295 |
+
mask_k = mask_labels == k
|
| 296 |
+
mask_k_area = mask_k.sum()
|
| 297 |
+
|
| 298 |
+
# Compute the area of all the stuff in query k
|
| 299 |
+
original_area = (mask_probs[k] >= mask_threshold).sum()
|
| 300 |
+
mask_exists = mask_k_area > 0 and original_area > 0
|
| 301 |
+
|
| 302 |
+
# Eliminate disconnected tiny segments
|
| 303 |
+
if mask_exists:
|
| 304 |
+
area_ratio = mask_k_area / original_area
|
| 305 |
+
if not area_ratio.item() > overlap_mask_area_threshold:
|
| 306 |
+
mask_exists = False
|
| 307 |
+
|
| 308 |
+
return mask_exists, mask_k
|
| 309 |
+
|
| 310 |
+
|
| 311 |
+
# Adapted from transformers.models.conditional_detr.image_processing_conditional_detr.compute_segments
|
| 312 |
+
def compute_segments(
|
| 313 |
+
mask_probs,
|
| 314 |
+
pred_scores,
|
| 315 |
+
pred_labels,
|
| 316 |
+
mask_threshold: float = 0.5,
|
| 317 |
+
overlap_mask_area_threshold: float = 0.8,
|
| 318 |
+
label_ids_to_fuse: set[int] | None = None,
|
| 319 |
+
target_size: tuple[int, int] | None = None,
|
| 320 |
+
):
|
| 321 |
+
import torch
|
| 322 |
+
from torch import nn
|
| 323 |
+
|
| 324 |
+
height = mask_probs.shape[1] if target_size is None else target_size[0]
|
| 325 |
+
width = mask_probs.shape[2] if target_size is None else target_size[1]
|
| 326 |
+
|
| 327 |
+
segmentation = torch.zeros((height, width), dtype=torch.int32, device=mask_probs.device)
|
| 328 |
+
segments: list[dict] = []
|
| 329 |
+
|
| 330 |
+
if target_size is not None:
|
| 331 |
+
mask_probs = nn.functional.interpolate(
|
| 332 |
+
mask_probs.unsqueeze(0), size=target_size, mode="bilinear", align_corners=False
|
| 333 |
+
)[0]
|
| 334 |
+
|
| 335 |
+
current_segment_id = 0
|
| 336 |
+
|
| 337 |
+
# Weigh each mask by its prediction score
|
| 338 |
+
mask_probs *= pred_scores.view(-1, 1, 1)
|
| 339 |
+
mask_labels = mask_probs.argmax(0) # [height, width]
|
| 340 |
+
|
| 341 |
+
# Keep track of instances of each class
|
| 342 |
+
stuff_memory_list: dict[str, int] = {}
|
| 343 |
+
for k in range(pred_labels.shape[0]):
|
| 344 |
+
pred_class = pred_labels[k].item()
|
| 345 |
+
should_fuse = pred_class in label_ids_to_fuse
|
| 346 |
+
|
| 347 |
+
# Check if mask exists and large enough to be a segment
|
| 348 |
+
mask_exists, mask_k = check_segment_validity(
|
| 349 |
+
mask_labels, mask_probs, k, mask_threshold, overlap_mask_area_threshold
|
| 350 |
+
)
|
| 351 |
+
|
| 352 |
+
if mask_exists:
|
| 353 |
+
if pred_class in stuff_memory_list:
|
| 354 |
+
current_segment_id = stuff_memory_list[pred_class]
|
| 355 |
+
else:
|
| 356 |
+
current_segment_id += 1
|
| 357 |
+
|
| 358 |
+
# Add current object segment to final segmentation map
|
| 359 |
+
segmentation[mask_k] = current_segment_id
|
| 360 |
+
segment_score = round(pred_scores[k].item(), 6)
|
| 361 |
+
segments.append(
|
| 362 |
+
{
|
| 363 |
+
"id": current_segment_id,
|
| 364 |
+
"label_id": pred_class,
|
| 365 |
+
"was_fused": should_fuse,
|
| 366 |
+
"score": segment_score,
|
| 367 |
+
}
|
| 368 |
+
)
|
| 369 |
+
if should_fuse:
|
| 370 |
+
stuff_memory_list[pred_class] = current_segment_id
|
| 371 |
+
|
| 372 |
+
return segmentation, segments
|
| 373 |
+
|
| 374 |
+
|
| 375 |
+
# Adapted from transformers.models.conditional_detr.image_processing_conditional_detr.convert_segmentation_to_rle
|
| 376 |
+
def convert_segmentation_to_rle(segmentation):
|
| 377 |
+
"""
|
| 378 |
+
Converts given segmentation map of shape `(height, width)` to the run-length encoding (RLE) format.
|
| 379 |
+
|
| 380 |
+
Args:
|
| 381 |
+
segmentation (`torch.Tensor` or `numpy.array`):
|
| 382 |
+
A segmentation map of shape `(height, width)` where each value denotes a segment or class id.
|
| 383 |
+
Returns:
|
| 384 |
+
`list[List]`: A list of lists, where each list is the run-length encoding of a segment / class id.
|
| 385 |
+
"""
|
| 386 |
+
import torch
|
| 387 |
+
|
| 388 |
+
segment_ids = torch.unique(segmentation)
|
| 389 |
+
|
| 390 |
+
run_length_encodings = []
|
| 391 |
+
for idx in segment_ids:
|
| 392 |
+
mask = torch.where(segmentation == idx, 1, 0)
|
| 393 |
+
rle = binary_mask_to_rle(mask)
|
| 394 |
+
run_length_encodings.append(rle)
|
| 395 |
+
|
| 396 |
+
return run_length_encodings
|
| 397 |
+
|
| 398 |
+
|
| 399 |
+
# Adapted from transformers.models.conditional_detr.image_processing_conditional_detr.remove_low_and_no_objects
|
| 400 |
+
def remove_low_and_no_objects(masks, scores, labels, object_mask_threshold, num_labels):
|
| 401 |
+
"""
|
| 402 |
+
Binarize the given masks using `object_mask_threshold`, it returns the associated values of `masks`, `scores` and
|
| 403 |
+
`labels`.
|
| 404 |
+
|
| 405 |
+
Args:
|
| 406 |
+
masks (`torch.Tensor`):
|
| 407 |
+
A tensor of shape `(num_queries, height, width)`.
|
| 408 |
+
scores (`torch.Tensor`):
|
| 409 |
+
A tensor of shape `(num_queries)`.
|
| 410 |
+
labels (`torch.Tensor`):
|
| 411 |
+
A tensor of shape `(num_queries)`.
|
| 412 |
+
object_mask_threshold (`float`):
|
| 413 |
+
A number between 0 and 1 used to binarize the masks.
|
| 414 |
+
Raises:
|
| 415 |
+
`ValueError`: Raised when the first dimension doesn't match in all input tensors.
|
| 416 |
+
Returns:
|
| 417 |
+
`tuple[`torch.Tensor`, `torch.Tensor`, `torch.Tensor`]`: The `masks`, `scores` and `labels` without the region
|
| 418 |
+
< `object_mask_threshold`.
|
| 419 |
+
"""
|
| 420 |
+
if not (masks.shape[0] == scores.shape[0] == labels.shape[0]):
|
| 421 |
+
raise ValueError("mask, scores and labels must have the same shape!")
|
| 422 |
+
|
| 423 |
+
to_keep = labels.ne(num_labels) & (scores > object_mask_threshold)
|
| 424 |
+
|
| 425 |
+
return masks[to_keep], scores[to_keep], labels[to_keep]
|
| 426 |
+
|
| 427 |
+
|
| 428 |
+
@auto_docstring
|
| 429 |
+
class ConditionalDetrImageProcessorPil(PilBackend):
|
| 430 |
+
resample = PILImageResampling.BILINEAR
|
| 431 |
+
image_mean = IMAGENET_DEFAULT_MEAN
|
| 432 |
+
image_std = IMAGENET_DEFAULT_STD
|
| 433 |
+
format = AnnotationFormat.COCO_DETECTION
|
| 434 |
+
do_resize = True
|
| 435 |
+
do_rescale = True
|
| 436 |
+
do_normalize = True
|
| 437 |
+
do_pad = True
|
| 438 |
+
size = {"shortest_edge": 800, "longest_edge": 1333}
|
| 439 |
+
default_to_square = False
|
| 440 |
+
model_input_names = ["pixel_values", "pixel_mask"]
|
| 441 |
+
valid_kwargs = ConditionalDetrImageProcessorKwargs
|
| 442 |
+
|
| 443 |
+
def __init__(self, **kwargs: Unpack[ConditionalDetrImageProcessorKwargs]) -> None:
|
| 444 |
+
kwargs.setdefault("do_pad", kwargs.pop("pad_and_return_pixel_mask", self.do_pad))
|
| 445 |
+
|
| 446 |
+
size = kwargs.pop("size", None)
|
| 447 |
+
max_size = None if size is None else kwargs.pop("max_size", 1333)
|
| 448 |
+
size = size if size is not None else {"shortest_edge": 800, "longest_edge": 1333}
|
| 449 |
+
# Convert size dict for backwards compat with max_size parameter
|
| 450 |
+
if size is not None:
|
| 451 |
+
from ...image_processing_utils import get_size_dict
|
| 452 |
+
|
| 453 |
+
kwargs["size"] = get_size_dict(size, max_size=max_size, default_to_square=False)
|
| 454 |
+
|
| 455 |
+
# Backwards compatibility
|
| 456 |
+
do_convert_annotations = kwargs.get("do_convert_annotations")
|
| 457 |
+
do_normalize = kwargs.get("do_normalize")
|
| 458 |
+
if do_convert_annotations is None and getattr(self, "do_convert_annotations", None) is None:
|
| 459 |
+
self.do_convert_annotations = do_normalize if do_normalize is not None else self.do_normalize
|
| 460 |
+
|
| 461 |
+
super().__init__(**kwargs)
|
| 462 |
+
|
| 463 |
+
def prepare_annotation(
|
| 464 |
+
self,
|
| 465 |
+
image: np.ndarray,
|
| 466 |
+
target: dict,
|
| 467 |
+
format: AnnotationFormat | None = None,
|
| 468 |
+
return_segmentation_masks: bool | None = None,
|
| 469 |
+
masks_path: str | pathlib.Path | None = None,
|
| 470 |
+
input_data_format: str | ChannelDimension | None = None,
|
| 471 |
+
) -> dict:
|
| 472 |
+
"""
|
| 473 |
+
Prepare an annotation for feeding into CONDITIONAL_DETR model.
|
| 474 |
+
"""
|
| 475 |
+
format = format if format is not None else self.format
|
| 476 |
+
|
| 477 |
+
if format == AnnotationFormat.COCO_DETECTION:
|
| 478 |
+
return_segmentation_masks = False if return_segmentation_masks is None else return_segmentation_masks
|
| 479 |
+
target = prepare_coco_detection_annotation(
|
| 480 |
+
image, target, return_segmentation_masks, input_data_format=input_data_format
|
| 481 |
+
)
|
| 482 |
+
elif format == AnnotationFormat.COCO_PANOPTIC:
|
| 483 |
+
return_segmentation_masks = True if return_segmentation_masks is None else return_segmentation_masks
|
| 484 |
+
target = prepare_coco_panoptic_annotation(
|
| 485 |
+
image,
|
| 486 |
+
target,
|
| 487 |
+
masks_path=masks_path,
|
| 488 |
+
return_masks=return_segmentation_masks,
|
| 489 |
+
input_data_format=input_data_format,
|
| 490 |
+
)
|
| 491 |
+
else:
|
| 492 |
+
raise ValueError(f"Format {format} is not supported.")
|
| 493 |
+
return target
|
| 494 |
+
|
| 495 |
+
def resize(
|
| 496 |
+
self,
|
| 497 |
+
image: np.ndarray,
|
| 498 |
+
size: SizeDict,
|
| 499 |
+
resample: Optional["PILImageResampling"] = None,
|
| 500 |
+
**kwargs,
|
| 501 |
+
) -> np.ndarray:
|
| 502 |
+
"""
|
| 503 |
+
Resize the image to the given size. Size can be `min_size` (scalar) or `(height, width)` tuple. If size is an
|
| 504 |
+
int, smaller edge of the image will be matched to this number.
|
| 505 |
+
|
| 506 |
+
Args:
|
| 507 |
+
image (`np.ndarray`):
|
| 508 |
+
Image to resize.
|
| 509 |
+
size (`SizeDict`):
|
| 510 |
+
Size of the image's `(height, width)` dimensions after resizing. Available options are:
|
| 511 |
+
- `{"height": int, "width": int}`: The image will be resized to the exact size `(height, width)`.
|
| 512 |
+
Do NOT keep the aspect ratio.
|
| 513 |
+
- `{"shortest_edge": int, "longest_edge": int}`: The image will be resized to a maximum size respecting
|
| 514 |
+
the aspect ratio and keeping the shortest edge less or equal to `shortest_edge` and the longest edge
|
| 515 |
+
less or equal to `longest_edge`.
|
| 516 |
+
- `{"max_height": int, "max_width": int}`: The image will be resized to the maximum size respecting the
|
| 517 |
+
aspect ratio and keeping the height less or equal to `max_height` and the width less or equal to
|
| 518 |
+
`max_width`.
|
| 519 |
+
resample (`PILImageResampling`, *optional*, defaults to `PILImageResampling.BILINEAR`):
|
| 520 |
+
Resampling filter to use if resizing the image.
|
| 521 |
+
"""
|
| 522 |
+
resample = resample if resample is not None else self.resample
|
| 523 |
+
|
| 524 |
+
if size.shortest_edge and size.longest_edge:
|
| 525 |
+
# Resize the image so that the shortest edge or the longest edge is of the given size
|
| 526 |
+
# while maintaining the aspect ratio of the original image.
|
| 527 |
+
new_size = get_size_with_aspect_ratio(
|
| 528 |
+
image.shape[-2:],
|
| 529 |
+
size.shortest_edge,
|
| 530 |
+
size.longest_edge or size.shortest_edge,
|
| 531 |
+
)
|
| 532 |
+
elif size.max_height and size.max_width:
|
| 533 |
+
new_size = get_image_size_for_max_height_width(image.shape[-2:], size.max_height, size.max_width)
|
| 534 |
+
elif size.height and size.width:
|
| 535 |
+
new_size = (size.height, size.width)
|
| 536 |
+
else:
|
| 537 |
+
raise ValueError(
|
| 538 |
+
f"Size must contain 'height' and 'width' keys or 'shortest_edge' and 'longest_edge' keys. Got {size}."
|
| 539 |
+
)
|
| 540 |
+
|
| 541 |
+
image = super().resize(
|
| 542 |
+
image,
|
| 543 |
+
size=SizeDict(height=new_size[0], width=new_size[1]),
|
| 544 |
+
resample=resample,
|
| 545 |
+
**kwargs,
|
| 546 |
+
)
|
| 547 |
+
return image
|
| 548 |
+
|
| 549 |
+
def resize_annotation(
|
| 550 |
+
self,
|
| 551 |
+
annotation: dict[str, Any],
|
| 552 |
+
orig_size: tuple[int, int],
|
| 553 |
+
target_size: tuple[int, int],
|
| 554 |
+
threshold: float = 0.5,
|
| 555 |
+
resample: Optional["PILImageResampling"] = PILImageResampling.NEAREST,
|
| 556 |
+
):
|
| 557 |
+
"""
|
| 558 |
+
Resizes an annotation to a target size.
|
| 559 |
+
|
| 560 |
+
Args:
|
| 561 |
+
annotation (`dict[str, Any]`):
|
| 562 |
+
The annotation dictionary.
|
| 563 |
+
orig_size (`tuple[int, int]`):
|
| 564 |
+
The original size of the input image.
|
| 565 |
+
target_size (`tuple[int, int]`):
|
| 566 |
+
The target size of the image, as returned by the preprocessing `resize` step.
|
| 567 |
+
threshold (`float`, *optional*, defaults to 0.5):
|
| 568 |
+
The threshold used to binarize the segmentation masks.
|
| 569 |
+
resample (`PILImageResampling`, defaults to `PILImageResampling.NEAREST`):
|
| 570 |
+
The resampling filter to use when resizing the masks.
|
| 571 |
+
"""
|
| 572 |
+
ratios = tuple(float(s) / float(s_orig) for s, s_orig in zip(target_size, orig_size))
|
| 573 |
+
ratio_height, ratio_width = ratios
|
| 574 |
+
|
| 575 |
+
new_annotation = {}
|
| 576 |
+
new_annotation["size"] = target_size
|
| 577 |
+
|
| 578 |
+
for key, value in annotation.items():
|
| 579 |
+
if key == "boxes":
|
| 580 |
+
boxes = value
|
| 581 |
+
scaled_boxes = boxes * np.asarray(
|
| 582 |
+
[ratio_width, ratio_height, ratio_width, ratio_height], dtype=np.float32
|
| 583 |
+
)
|
| 584 |
+
new_annotation["boxes"] = scaled_boxes
|
| 585 |
+
elif key == "area":
|
| 586 |
+
area = value
|
| 587 |
+
scaled_area = area * (ratio_width * ratio_height)
|
| 588 |
+
new_annotation["area"] = scaled_area
|
| 589 |
+
elif key == "masks":
|
| 590 |
+
masks = value[:, None]
|
| 591 |
+
masks = np.array([resize(mask, target_size, resample=resample) for mask in masks])
|
| 592 |
+
masks = masks.astype(np.float32)
|
| 593 |
+
masks = masks[:, 0] > threshold
|
| 594 |
+
new_annotation["masks"] = masks
|
| 595 |
+
elif key == "size":
|
| 596 |
+
new_annotation["size"] = target_size
|
| 597 |
+
else:
|
| 598 |
+
new_annotation[key] = value
|
| 599 |
+
|
| 600 |
+
return new_annotation
|
| 601 |
+
|
| 602 |
+
def normalize_annotation(self, annotation: dict, image_size: tuple[int, int]) -> dict:
|
| 603 |
+
image_height, image_width = image_size
|
| 604 |
+
norm_annotation = {}
|
| 605 |
+
for key, value in annotation.items():
|
| 606 |
+
if key == "boxes":
|
| 607 |
+
boxes = value
|
| 608 |
+
boxes = corners_to_center_format(boxes)
|
| 609 |
+
boxes /= np.asarray([image_width, image_height, image_width, image_height], dtype=np.float32)
|
| 610 |
+
norm_annotation[key] = boxes
|
| 611 |
+
else:
|
| 612 |
+
norm_annotation[key] = value
|
| 613 |
+
return norm_annotation
|
| 614 |
+
|
| 615 |
+
def _update_annotation_for_padded_image(
|
| 616 |
+
self,
|
| 617 |
+
annotation: dict,
|
| 618 |
+
input_image_size: tuple[int, int],
|
| 619 |
+
output_image_size: tuple[int, int],
|
| 620 |
+
padding,
|
| 621 |
+
update_bboxes,
|
| 622 |
+
) -> dict:
|
| 623 |
+
"""
|
| 624 |
+
Update the annotation for a padded image.
|
| 625 |
+
"""
|
| 626 |
+
new_annotation = {}
|
| 627 |
+
new_annotation["size"] = output_image_size
|
| 628 |
+
ratio_height, ratio_width = (input / output for output, input in zip(output_image_size, input_image_size))
|
| 629 |
+
|
| 630 |
+
for key, value in annotation.items():
|
| 631 |
+
if key == "masks":
|
| 632 |
+
masks = value
|
| 633 |
+
masks = pad(
|
| 634 |
+
masks,
|
| 635 |
+
padding,
|
| 636 |
+
mode=PaddingMode.CONSTANT,
|
| 637 |
+
constant_values=0,
|
| 638 |
+
input_data_format=ChannelDimension.FIRST,
|
| 639 |
+
)
|
| 640 |
+
masks = safe_squeeze(masks, 1)
|
| 641 |
+
new_annotation["masks"] = masks
|
| 642 |
+
elif key == "boxes" and update_bboxes:
|
| 643 |
+
boxes = value
|
| 644 |
+
boxes *= np.asarray(
|
| 645 |
+
[
|
| 646 |
+
input_image_size[1] / output_image_size[1],
|
| 647 |
+
input_image_size[0] / output_image_size[0],
|
| 648 |
+
input_image_size[1] / output_image_size[1],
|
| 649 |
+
input_image_size[0] / output_image_size[0],
|
| 650 |
+
]
|
| 651 |
+
)
|
| 652 |
+
new_annotation["boxes"] = boxes
|
| 653 |
+
elif key == "size":
|
| 654 |
+
new_annotation["size"] = output_image_size
|
| 655 |
+
else:
|
| 656 |
+
new_annotation[key] = value
|
| 657 |
+
return new_annotation
|
| 658 |
+
|
| 659 |
+
def pad(
|
| 660 |
+
self,
|
| 661 |
+
image: np.ndarray,
|
| 662 |
+
padded_size: tuple[int, int],
|
| 663 |
+
annotation: dict[str, Any] | None = None,
|
| 664 |
+
update_bboxes: bool = True,
|
| 665 |
+
fill: int = 0,
|
| 666 |
+
):
|
| 667 |
+
input_height, input_width = get_image_size(image, channel_dim=ChannelDimension.FIRST)
|
| 668 |
+
output_height, output_width = padded_size
|
| 669 |
+
padding_bottom = output_height - input_height
|
| 670 |
+
padding_right = output_width - input_width
|
| 671 |
+
if padding_bottom < 0 or padding_right < 0:
|
| 672 |
+
raise ValueError(
|
| 673 |
+
f"Padding dimensions are negative. Please make sure that the padded size is larger than the "
|
| 674 |
+
f"original size. Got padded size: {padded_size}, original size: {(input_height, input_width)}."
|
| 675 |
+
)
|
| 676 |
+
if (input_height, input_width) != padded_size:
|
| 677 |
+
padding = ((0, padding_bottom), (0, padding_right))
|
| 678 |
+
image = pad(
|
| 679 |
+
image,
|
| 680 |
+
padding,
|
| 681 |
+
mode=PaddingMode.CONSTANT,
|
| 682 |
+
constant_values=fill,
|
| 683 |
+
data_format=ChannelDimension.FIRST,
|
| 684 |
+
input_data_format=ChannelDimension.FIRST,
|
| 685 |
+
)
|
| 686 |
+
if annotation is not None:
|
| 687 |
+
annotation = self._update_annotation_for_padded_image(
|
| 688 |
+
annotation, (input_height, input_width), (output_height, output_width), padding, update_bboxes
|
| 689 |
+
)
|
| 690 |
+
|
| 691 |
+
# Make a pixel mask for the image, where 1 indicates a valid pixel and 0 indicates padding.
|
| 692 |
+
pixel_mask = np.zeros(padded_size, dtype=np.int64)
|
| 693 |
+
pixel_mask[:input_height, :input_width] = 1
|
| 694 |
+
|
| 695 |
+
return image, pixel_mask, annotation
|
| 696 |
+
|
| 697 |
+
@auto_docstring
|
| 698 |
+
def preprocess(
|
| 699 |
+
self,
|
| 700 |
+
images: ImageInput,
|
| 701 |
+
annotations: AnnotationType | list[AnnotationType] | None = None,
|
| 702 |
+
return_segmentation_masks: bool | None = None,
|
| 703 |
+
masks_path: str | pathlib.Path | None = None,
|
| 704 |
+
**kwargs: Unpack[ConditionalDetrImageProcessorKwargs],
|
| 705 |
+
) -> BatchFeature:
|
| 706 |
+
r"""
|
| 707 |
+
annotations (`AnnotationType` or `list[AnnotationType]`, *optional*):
|
| 708 |
+
Annotations to transform according to the padding that is applied to the images.
|
| 709 |
+
return_segmentation_masks (`bool`, *optional*, defaults to `self.return_segmentation_masks`):
|
| 710 |
+
Whether to return segmentation masks.
|
| 711 |
+
masks_path (`str` or `pathlib.Path`, *optional*):
|
| 712 |
+
Path to the directory containing the segmentation masks.
|
| 713 |
+
"""
|
| 714 |
+
return super().preprocess(images, annotations, return_segmentation_masks, masks_path, **kwargs)
|
| 715 |
+
|
| 716 |
+
def _preprocess(
|
| 717 |
+
self,
|
| 718 |
+
images: list[np.ndarray],
|
| 719 |
+
annotations: AnnotationType | list[AnnotationType] | None,
|
| 720 |
+
return_segmentation_masks: bool,
|
| 721 |
+
masks_path: str | pathlib.Path | None,
|
| 722 |
+
do_resize: bool,
|
| 723 |
+
size: SizeDict,
|
| 724 |
+
resample: "PILImageResampling | None",
|
| 725 |
+
do_rescale: bool,
|
| 726 |
+
rescale_factor: float,
|
| 727 |
+
do_normalize: bool,
|
| 728 |
+
do_convert_annotations: bool,
|
| 729 |
+
image_mean: float | list[float] | None,
|
| 730 |
+
image_std: float | list[float] | None,
|
| 731 |
+
do_pad: bool,
|
| 732 |
+
pad_size: SizeDict | None,
|
| 733 |
+
format: str | AnnotationFormat | None,
|
| 734 |
+
return_tensors: str | TensorType | None,
|
| 735 |
+
**kwargs,
|
| 736 |
+
) -> BatchFeature:
|
| 737 |
+
"""
|
| 738 |
+
Preprocess an image or a batch of images so that it can be used by the model.
|
| 739 |
+
"""
|
| 740 |
+
if annotations is not None and isinstance(annotations, dict):
|
| 741 |
+
annotations = [annotations]
|
| 742 |
+
|
| 743 |
+
if annotations is not None and len(images) != len(annotations):
|
| 744 |
+
raise ValueError(
|
| 745 |
+
f"The number of images ({len(images)}) and annotations ({len(annotations)}) do not match."
|
| 746 |
+
)
|
| 747 |
+
|
| 748 |
+
format = AnnotationFormat(format)
|
| 749 |
+
if annotations is not None:
|
| 750 |
+
validate_annotations(format, SUPPORTED_ANNOTATION_FORMATS, annotations)
|
| 751 |
+
|
| 752 |
+
if (
|
| 753 |
+
masks_path is not None
|
| 754 |
+
and format == AnnotationFormat.COCO_PANOPTIC
|
| 755 |
+
and not isinstance(masks_path, (pathlib.Path, str))
|
| 756 |
+
):
|
| 757 |
+
raise ValueError(
|
| 758 |
+
"The path to the directory containing the mask PNG files should be provided as a"
|
| 759 |
+
f" `pathlib.Path` or string object, but is {type(masks_path)} instead."
|
| 760 |
+
)
|
| 761 |
+
|
| 762 |
+
data = {}
|
| 763 |
+
|
| 764 |
+
# Import torch if needed for tensor conversion
|
| 765 |
+
if return_tensors == "pt":
|
| 766 |
+
if not is_torch_available():
|
| 767 |
+
raise ImportError("PyTorch is required for tensor conversion.")
|
| 768 |
+
|
| 769 |
+
processed_images = []
|
| 770 |
+
processed_annotations = []
|
| 771 |
+
pixel_masks = [] # Initialize pixel_masks here
|
| 772 |
+
for image, annotation in zip(images, annotations if annotations is not None else [None] * len(images)):
|
| 773 |
+
# prepare (COCO annotations as a list of Dict -> CONDITIONAL_DETR target as a single Dict per image)
|
| 774 |
+
if annotations is not None:
|
| 775 |
+
annotation = self.prepare_annotation(
|
| 776 |
+
image,
|
| 777 |
+
annotation,
|
| 778 |
+
format,
|
| 779 |
+
return_segmentation_masks=return_segmentation_masks,
|
| 780 |
+
masks_path=masks_path,
|
| 781 |
+
input_data_format=ChannelDimension.FIRST,
|
| 782 |
+
)
|
| 783 |
+
|
| 784 |
+
if do_resize:
|
| 785 |
+
resized_image = self.resize(image, size=size, resample=resample)
|
| 786 |
+
if annotations is not None:
|
| 787 |
+
annotation = self.resize_annotation(
|
| 788 |
+
annotation,
|
| 789 |
+
orig_size=get_image_size(image, channel_dim=ChannelDimension.FIRST),
|
| 790 |
+
target_size=get_image_size(resized_image, channel_dim=ChannelDimension.FIRST),
|
| 791 |
+
)
|
| 792 |
+
image = resized_image
|
| 793 |
+
|
| 794 |
+
if do_rescale:
|
| 795 |
+
image = self.rescale(image, rescale_factor)
|
| 796 |
+
if do_normalize:
|
| 797 |
+
image = self.normalize(image, image_mean, image_std)
|
| 798 |
+
|
| 799 |
+
if do_convert_annotations and annotations is not None:
|
| 800 |
+
annotation = self.normalize_annotation(annotation, get_image_size(image, ChannelDimension.FIRST))
|
| 801 |
+
|
| 802 |
+
processed_images.append(image)
|
| 803 |
+
processed_annotations.append(annotation)
|
| 804 |
+
images = processed_images
|
| 805 |
+
annotations = processed_annotations if annotations is not None else None
|
| 806 |
+
|
| 807 |
+
if do_pad:
|
| 808 |
+
# depends on all resized image shapes so we need another loop
|
| 809 |
+
if pad_size is not None:
|
| 810 |
+
padded_size = (pad_size.height, pad_size.width)
|
| 811 |
+
else:
|
| 812 |
+
padded_size = get_max_height_width(images, input_data_format=ChannelDimension.FIRST)
|
| 813 |
+
|
| 814 |
+
padded_images = []
|
| 815 |
+
padded_annotations = []
|
| 816 |
+
for image, annotation in zip(images, annotations if annotations is not None else [None] * len(images)):
|
| 817 |
+
# Pads images and returns their mask: {'pixel_values': ..., 'pixel_mask': ...}
|
| 818 |
+
image_height, image_width = get_image_size(image, channel_dim=ChannelDimension.FIRST)
|
| 819 |
+
if padded_size == (image_height, image_width):
|
| 820 |
+
padded_images.append(image)
|
| 821 |
+
pixel_masks.append(np.ones(padded_size, dtype=np.int64))
|
| 822 |
+
padded_annotations.append(annotation)
|
| 823 |
+
continue
|
| 824 |
+
image, pixel_mask, annotation = self.pad(
|
| 825 |
+
image, padded_size, annotation=annotation, update_bboxes=do_convert_annotations
|
| 826 |
+
)
|
| 827 |
+
padded_images.append(image)
|
| 828 |
+
padded_annotations.append(annotation)
|
| 829 |
+
pixel_masks.append(pixel_mask)
|
| 830 |
+
images = padded_images
|
| 831 |
+
annotations = padded_annotations if annotations is not None else None
|
| 832 |
+
data.update({"pixel_mask": pixel_masks})
|
| 833 |
+
|
| 834 |
+
data.update({"pixel_values": images})
|
| 835 |
+
encoded_inputs = BatchFeature(data, tensor_type=return_tensors)
|
| 836 |
+
if annotations is not None:
|
| 837 |
+
encoded_inputs["labels"] = [
|
| 838 |
+
BatchFeature(annotation, tensor_type=return_tensors) for annotation in annotations
|
| 839 |
+
]
|
| 840 |
+
return encoded_inputs
|
| 841 |
+
|
| 842 |
+
@requires(backends=("torch",))
|
| 843 |
+
def post_process_object_detection(
|
| 844 |
+
self, outputs, threshold: float = 0.5, target_sizes: TensorType | list[tuple] = None, top_k: int = 100
|
| 845 |
+
):
|
| 846 |
+
"""
|
| 847 |
+
Converts the raw output of [`ConditionalDetrForObjectDetection`] into final bounding boxes in (top_left_x,
|
| 848 |
+
top_left_y, bottom_right_x, bottom_right_y) format. Only supports PyTorch.
|
| 849 |
+
|
| 850 |
+
Args:
|
| 851 |
+
outputs ([`ConditionalDetrObjectDetectionOutput`]):
|
| 852 |
+
Raw outputs of the model.
|
| 853 |
+
threshold (`float`, *optional*):
|
| 854 |
+
Score threshold to keep object detection predictions.
|
| 855 |
+
target_sizes (`torch.Tensor` or `list[tuple[int, int]]`, *optional*):
|
| 856 |
+
Tensor of shape `(batch_size, 2)` or list of tuples (`tuple[int, int]`) containing the target size
|
| 857 |
+
(height, width) of each image in the batch. If left to None, predictions will not be resized.
|
| 858 |
+
top_k (`int`, *optional*, defaults to 100):
|
| 859 |
+
Keep only top k bounding boxes before filtering by thresholding.
|
| 860 |
+
|
| 861 |
+
Returns:
|
| 862 |
+
`list[Dict]`: A list of dictionaries, each dictionary containing the scores, labels and boxes for an image
|
| 863 |
+
in the batch as predicted by the model.
|
| 864 |
+
"""
|
| 865 |
+
requires_backends(self, ["torch"])
|
| 866 |
+
out_logits, out_bbox = outputs.logits, outputs.pred_boxes
|
| 867 |
+
|
| 868 |
+
if target_sizes is not None:
|
| 869 |
+
if len(out_logits) != len(target_sizes):
|
| 870 |
+
raise ValueError(
|
| 871 |
+
"Make sure that you pass in as many target sizes as the batch dimension of the logits"
|
| 872 |
+
)
|
| 873 |
+
|
| 874 |
+
prob = out_logits.sigmoid()
|
| 875 |
+
prob = prob.view(out_logits.shape[0], -1)
|
| 876 |
+
k_value = min(top_k, prob.size(1))
|
| 877 |
+
topk_values, topk_indexes = torch.topk(prob, k_value, dim=1)
|
| 878 |
+
scores = topk_values
|
| 879 |
+
topk_boxes = torch.div(topk_indexes, out_logits.shape[2], rounding_mode="floor")
|
| 880 |
+
labels = topk_indexes % out_logits.shape[2]
|
| 881 |
+
boxes = center_to_corners_format(out_bbox)
|
| 882 |
+
boxes = torch.gather(boxes, 1, topk_boxes.unsqueeze(-1).repeat(1, 1, 4))
|
| 883 |
+
|
| 884 |
+
# and from relative [0, 1] to absolute [0, height] coordinates
|
| 885 |
+
if target_sizes is not None:
|
| 886 |
+
if isinstance(target_sizes, list):
|
| 887 |
+
img_h = torch.Tensor([i[0] for i in target_sizes])
|
| 888 |
+
img_w = torch.Tensor([i[1] for i in target_sizes])
|
| 889 |
+
else:
|
| 890 |
+
img_h, img_w = target_sizes.unbind(1)
|
| 891 |
+
scale_fct = torch.stack([img_w, img_h, img_w, img_h], dim=1).to(boxes.device)
|
| 892 |
+
boxes = boxes * scale_fct[:, None, :]
|
| 893 |
+
|
| 894 |
+
results = []
|
| 895 |
+
for s, l, b in zip(scores, labels, boxes):
|
| 896 |
+
score = s[s > threshold]
|
| 897 |
+
label = l[s > threshold]
|
| 898 |
+
box = b[s > threshold]
|
| 899 |
+
results.append({"scores": score, "labels": label, "boxes": box})
|
| 900 |
+
|
| 901 |
+
return results
|
| 902 |
+
|
| 903 |
+
@requires(backends=("torch",))
|
| 904 |
+
def post_process_semantic_segmentation(self, outputs, target_sizes: list[tuple[int, int]] | None = None):
|
| 905 |
+
"""
|
| 906 |
+
Converts the output of [`ConditionalDetrForSegmentation`] into semantic segmentation maps. Only supports PyTorch.
|
| 907 |
+
|
| 908 |
+
Args:
|
| 909 |
+
outputs ([`ConditionalDetrForSegmentation`]):
|
| 910 |
+
Raw outputs of the model.
|
| 911 |
+
target_sizes (`list[tuple[int, int]]`, *optional*):
|
| 912 |
+
A list of tuples (`tuple[int, int]`) containing the target size (height, width) of each image in the
|
| 913 |
+
batch. If unset, predictions will not be resized.
|
| 914 |
+
Returns:
|
| 915 |
+
`list[torch.Tensor]`:
|
| 916 |
+
A list of length `batch_size`, where each item is a semantic segmentation map of shape (height, width)
|
| 917 |
+
corresponding to the target_sizes entry (if `target_sizes` is specified). Each entry of each
|
| 918 |
+
`torch.Tensor` correspond to a semantic class id.
|
| 919 |
+
"""
|
| 920 |
+
requires_backends(self, ["torch"])
|
| 921 |
+
class_queries_logits = outputs.logits # [batch_size, num_queries, num_classes]
|
| 922 |
+
masks_queries_logits = outputs.pred_masks # [batch_size, num_queries, height, width]
|
| 923 |
+
|
| 924 |
+
# Conditional DETR does not have a null class, so we use all classes
|
| 925 |
+
masks_classes = class_queries_logits.softmax(dim=-1)
|
| 926 |
+
masks_probs = masks_queries_logits.sigmoid() # [batch_size, num_queries, height, width]
|
| 927 |
+
|
| 928 |
+
# Semantic segmentation logits of shape (batch_size, num_classes, height, width)
|
| 929 |
+
segmentation = torch.einsum("bqc, bqhw -> bchw", masks_classes, masks_probs)
|
| 930 |
+
batch_size = class_queries_logits.shape[0]
|
| 931 |
+
|
| 932 |
+
# Resize logits and compute semantic segmentation maps
|
| 933 |
+
if target_sizes is not None:
|
| 934 |
+
if batch_size != len(target_sizes):
|
| 935 |
+
raise ValueError(
|
| 936 |
+
"Make sure that you pass in as many target sizes as the batch dimension of the logits"
|
| 937 |
+
)
|
| 938 |
+
|
| 939 |
+
semantic_segmentation = []
|
| 940 |
+
for idx in range(batch_size):
|
| 941 |
+
resized_logits = nn.functional.interpolate(
|
| 942 |
+
segmentation[idx].unsqueeze(dim=0), size=target_sizes[idx], mode="bilinear", align_corners=False
|
| 943 |
+
)
|
| 944 |
+
semantic_map = resized_logits[0].argmax(dim=0)
|
| 945 |
+
semantic_segmentation.append(semantic_map)
|
| 946 |
+
else:
|
| 947 |
+
semantic_segmentation = segmentation.argmax(dim=1)
|
| 948 |
+
semantic_segmentation = [semantic_segmentation[i] for i in range(semantic_segmentation.shape[0])]
|
| 949 |
+
|
| 950 |
+
return semantic_segmentation
|
| 951 |
+
|
| 952 |
+
@requires(backends=("torch",))
|
| 953 |
+
def post_process_instance_segmentation(
|
| 954 |
+
self,
|
| 955 |
+
outputs,
|
| 956 |
+
threshold: float = 0.5,
|
| 957 |
+
mask_threshold: float = 0.5,
|
| 958 |
+
overlap_mask_area_threshold: float = 0.8,
|
| 959 |
+
target_sizes: list[tuple[int, int]] | None = None,
|
| 960 |
+
return_coco_annotation: bool | None = False,
|
| 961 |
+
) -> list[dict]:
|
| 962 |
+
"""
|
| 963 |
+
Converts the output of [`ConditionalDetrForSegmentation`] into instance segmentation predictions. Only supports PyTorch.
|
| 964 |
+
|
| 965 |
+
Args:
|
| 966 |
+
outputs ([`ConditionalDetrForSegmentation`]):
|
| 967 |
+
Raw outputs of the model.
|
| 968 |
+
threshold (`float`, *optional*, defaults to 0.5):
|
| 969 |
+
The probability score threshold to keep predicted instance masks.
|
| 970 |
+
mask_threshold (`float`, *optional*, defaults to 0.5):
|
| 971 |
+
Threshold to use when turning the predicted masks into binary values.
|
| 972 |
+
overlap_mask_area_threshold (`float`, *optional*, defaults to 0.8):
|
| 973 |
+
The overlap mask area threshold to merge or discard small disconnected parts within each binary
|
| 974 |
+
instance mask.
|
| 975 |
+
target_sizes (`list[Tuple]`, *optional*):
|
| 976 |
+
List of length (batch_size), where each list item (`tuple[int, int]]`) corresponds to the requested
|
| 977 |
+
final size (height, width) of each prediction. If unset, predictions will not be resized.
|
| 978 |
+
return_coco_annotation (`bool`, *optional*):
|
| 979 |
+
Defaults to `False`. If set to `True`, segmentation maps are returned in COCO run-length encoding (RLE)
|
| 980 |
+
format.
|
| 981 |
+
Returns:
|
| 982 |
+
`list[Dict]`: A list of dictionaries, one per image, each dictionary containing two keys:
|
| 983 |
+
- **segmentation** -- A tensor of shape `(height, width)` where each pixel represents a `segment_id` or
|
| 984 |
+
`list[List]` run-length encoding (RLE) of the segmentation map if return_coco_annotation is set to
|
| 985 |
+
`True`. Set to `None` if no mask if found above `threshold`.
|
| 986 |
+
- **segments_info** -- A dictionary that contains additional information on each segment.
|
| 987 |
+
- **id** -- An integer representing the `segment_id`.
|
| 988 |
+
- **label_id** -- An integer representing the label / semantic class id corresponding to `segment_id`.
|
| 989 |
+
- **score** -- Prediction score of segment with `segment_id`.
|
| 990 |
+
"""
|
| 991 |
+
if not is_torch_available():
|
| 992 |
+
raise ImportError("PyTorch is required for post-processing.")
|
| 993 |
+
import torch
|
| 994 |
+
from torch import nn
|
| 995 |
+
|
| 996 |
+
class_queries_logits = outputs.logits # [batch_size, num_queries, num_classes+1]
|
| 997 |
+
masks_queries_logits = outputs.pred_masks # [batch_size, num_queries, height, width]
|
| 998 |
+
|
| 999 |
+
batch_size = class_queries_logits.shape[0]
|
| 1000 |
+
num_labels = class_queries_logits.shape[-1] - 1
|
| 1001 |
+
|
| 1002 |
+
mask_probs = masks_queries_logits.sigmoid() # [batch_size, num_queries, height, width]
|
| 1003 |
+
|
| 1004 |
+
# Predicted label and score of each query (batch_size, num_queries)
|
| 1005 |
+
pred_scores, pred_labels = nn.functional.softmax(class_queries_logits, dim=-1).max(-1)
|
| 1006 |
+
|
| 1007 |
+
# Loop over items in batch size
|
| 1008 |
+
results: list[dict[str, TensorType]] = []
|
| 1009 |
+
|
| 1010 |
+
for i in range(batch_size):
|
| 1011 |
+
mask_probs_item, pred_scores_item, pred_labels_item = remove_low_and_no_objects(
|
| 1012 |
+
mask_probs[i], pred_scores[i], pred_labels[i], threshold, num_labels
|
| 1013 |
+
)
|
| 1014 |
+
|
| 1015 |
+
# No mask found
|
| 1016 |
+
if mask_probs_item.shape[0] <= 0:
|
| 1017 |
+
height, width = target_sizes[i] if target_sizes is not None else mask_probs_item.shape[1:]
|
| 1018 |
+
segmentation = torch.zeros((height, width)) - 1
|
| 1019 |
+
results.append({"segmentation": segmentation, "segments_info": []})
|
| 1020 |
+
continue
|
| 1021 |
+
|
| 1022 |
+
# Get segmentation map and segment information of batch item
|
| 1023 |
+
target_size = target_sizes[i] if target_sizes is not None else None
|
| 1024 |
+
segmentation, segments = compute_segments(
|
| 1025 |
+
mask_probs=mask_probs_item,
|
| 1026 |
+
pred_scores=pred_scores_item,
|
| 1027 |
+
pred_labels=pred_labels_item,
|
| 1028 |
+
mask_threshold=mask_threshold,
|
| 1029 |
+
overlap_mask_area_threshold=overlap_mask_area_threshold,
|
| 1030 |
+
label_ids_to_fuse=[],
|
| 1031 |
+
target_size=target_size,
|
| 1032 |
+
)
|
| 1033 |
+
|
| 1034 |
+
# Return segmentation map in run-length encoding (RLE) format
|
| 1035 |
+
if return_coco_annotation:
|
| 1036 |
+
segmentation = convert_segmentation_to_rle(segmentation)
|
| 1037 |
+
|
| 1038 |
+
results.append({"segmentation": segmentation, "segments_info": segments})
|
| 1039 |
+
return results
|
| 1040 |
+
|
| 1041 |
+
@requires(backends=("torch",))
|
| 1042 |
+
def post_process_panoptic_segmentation(
|
| 1043 |
+
self,
|
| 1044 |
+
outputs,
|
| 1045 |
+
threshold: float = 0.5,
|
| 1046 |
+
mask_threshold: float = 0.5,
|
| 1047 |
+
overlap_mask_area_threshold: float = 0.8,
|
| 1048 |
+
label_ids_to_fuse: set[int] | None = None,
|
| 1049 |
+
target_sizes: list[tuple[int, int]] | None = None,
|
| 1050 |
+
) -> list[dict]:
|
| 1051 |
+
"""
|
| 1052 |
+
Converts the output of [`ConditionalDetrForSegmentation`] into image panoptic segmentation predictions. Only supports
|
| 1053 |
+
PyTorch.
|
| 1054 |
+
|
| 1055 |
+
Args:
|
| 1056 |
+
outputs ([`ConditionalDetrForSegmentation`]):
|
| 1057 |
+
The outputs from [`ConditionalDetrForSegmentation`].
|
| 1058 |
+
threshold (`float`, *optional*, defaults to 0.5):
|
| 1059 |
+
The probability score threshold to keep predicted instance masks.
|
| 1060 |
+
mask_threshold (`float`, *optional*, defaults to 0.5):
|
| 1061 |
+
Threshold to use when turning the predicted masks into binary values.
|
| 1062 |
+
overlap_mask_area_threshold (`float`, *optional*, defaults to 0.8):
|
| 1063 |
+
The overlap mask area threshold to merge or discard small disconnected parts within each binary
|
| 1064 |
+
instance mask.
|
| 1065 |
+
label_ids_to_fuse (`Set[int]`, *optional*):
|
| 1066 |
+
The labels in this state will have all their instances be fused together. For instance we could say
|
| 1067 |
+
there can only be one sky in an image, but several persons, so the label ID for sky would be in that
|
| 1068 |
+
set, but not the one for person.
|
| 1069 |
+
target_sizes (`list[Tuple]`, *optional*):
|
| 1070 |
+
List of length (batch_size), where each list item (`tuple[int, int]]`) corresponds to the requested
|
| 1071 |
+
final size (height, width) of each prediction in batch. If unset, predictions will not be resized.
|
| 1072 |
+
Returns:
|
| 1073 |
+
`list[Dict]`: A list of dictionaries, one per image, each dictionary containing two keys:
|
| 1074 |
+
- **segmentation** -- a tensor of shape `(height, width)` where each pixel represents a `segment_id` or
|
| 1075 |
+
`None` if no mask if found above `threshold`. If `target_sizes` is specified, segmentation is resized to
|
| 1076 |
+
the corresponding `target_sizes` entry.
|
| 1077 |
+
- **segments_info** -- A dictionary that contains additional information on each segment.
|
| 1078 |
+
- **id** -- an integer representing the `segment_id`.
|
| 1079 |
+
- **label_id** -- An integer representing the label / semantic class id corresponding to `segment_id`.
|
| 1080 |
+
- **was_fused** -- a boolean, `True` if `label_id` was in `label_ids_to_fuse`, `False` otherwise.
|
| 1081 |
+
Multiple instances of the same class / label were fused and assigned a single `segment_id`.
|
| 1082 |
+
- **score** -- Prediction score of segment with `segment_id`.
|
| 1083 |
+
"""
|
| 1084 |
+
|
| 1085 |
+
if label_ids_to_fuse is None:
|
| 1086 |
+
logger.warning_once("`label_ids_to_fuse` unset. No instance will be fused.")
|
| 1087 |
+
label_ids_to_fuse = set()
|
| 1088 |
+
|
| 1089 |
+
if not is_torch_available():
|
| 1090 |
+
raise ImportError("PyTorch is required for post-processing.")
|
| 1091 |
+
import torch
|
| 1092 |
+
from torch import nn
|
| 1093 |
+
|
| 1094 |
+
class_queries_logits = outputs.logits # [batch_size, num_queries, num_classes+1]
|
| 1095 |
+
masks_queries_logits = outputs.pred_masks # [batch_size, num_queries, height, width]
|
| 1096 |
+
|
| 1097 |
+
batch_size = class_queries_logits.shape[0]
|
| 1098 |
+
num_labels = class_queries_logits.shape[-1] - 1
|
| 1099 |
+
|
| 1100 |
+
mask_probs = masks_queries_logits.sigmoid() # [batch_size, num_queries, height, width]
|
| 1101 |
+
|
| 1102 |
+
# Predicted label and score of each query (batch_size, num_queries)
|
| 1103 |
+
pred_scores, pred_labels = nn.functional.softmax(class_queries_logits, dim=-1).max(-1)
|
| 1104 |
+
|
| 1105 |
+
# Loop over items in batch size
|
| 1106 |
+
results: list[dict[str, TensorType]] = []
|
| 1107 |
+
|
| 1108 |
+
for i in range(batch_size):
|
| 1109 |
+
mask_probs_item, pred_scores_item, pred_labels_item = remove_low_and_no_objects(
|
| 1110 |
+
mask_probs[i], pred_scores[i], pred_labels[i], threshold, num_labels
|
| 1111 |
+
)
|
| 1112 |
+
|
| 1113 |
+
# No mask found
|
| 1114 |
+
if mask_probs_item.shape[0] <= 0:
|
| 1115 |
+
height, width = target_sizes[i] if target_sizes is not None else mask_probs_item.shape[1:]
|
| 1116 |
+
segmentation = torch.zeros((height, width)) - 1
|
| 1117 |
+
results.append({"segmentation": segmentation, "segments_info": []})
|
| 1118 |
+
continue
|
| 1119 |
+
|
| 1120 |
+
# Get segmentation map and segment information of batch item
|
| 1121 |
+
target_size = target_sizes[i] if target_sizes is not None else None
|
| 1122 |
+
segmentation, segments = compute_segments(
|
| 1123 |
+
mask_probs=mask_probs_item,
|
| 1124 |
+
pred_scores=pred_scores_item,
|
| 1125 |
+
pred_labels=pred_labels_item,
|
| 1126 |
+
mask_threshold=mask_threshold,
|
| 1127 |
+
overlap_mask_area_threshold=overlap_mask_area_threshold,
|
| 1128 |
+
label_ids_to_fuse=label_ids_to_fuse,
|
| 1129 |
+
target_size=target_size,
|
| 1130 |
+
)
|
| 1131 |
+
|
| 1132 |
+
results.append({"segmentation": segmentation, "segments_info": segments})
|
| 1133 |
+
return results
|
| 1134 |
+
|
| 1135 |
+
|
| 1136 |
+
__all__ = ["ConditionalDetrImageProcessorPil"]
|
third_party/transformers/src/transformers/models/conditional_detr/modeling_conditional_detr.py
ADDED
|
@@ -0,0 +1,1827 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
# 🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨
|
| 2 |
+
# This file was automatically generated from src/transformers/models/conditional_detr/modular_conditional_detr.py.
|
| 3 |
+
# Do NOT edit this file manually as any edits will be overwritten by the generation of
|
| 4 |
+
# the file from the modular. If any change should be done, please apply the change to the
|
| 5 |
+
# modular_conditional_detr.py file directly. One of our CI enforces this.
|
| 6 |
+
# 🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨
|
| 7 |
+
# Copyright 2022 Microsoft Research Asia and The HuggingFace Inc. team. All rights reserved.
|
| 8 |
+
#
|
| 9 |
+
# Licensed under the Apache License, Version 2.0 (the "License");
|
| 10 |
+
# you may not use this file except in compliance with the License.
|
| 11 |
+
# You may obtain a copy of the License at
|
| 12 |
+
#
|
| 13 |
+
# http://www.apache.org/licenses/LICENSE-2.0
|
| 14 |
+
#
|
| 15 |
+
# Unless required by applicable law or agreed to in writing, software
|
| 16 |
+
# distributed under the License is distributed on an "AS IS" BASIS,
|
| 17 |
+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
| 18 |
+
# See the License for the specific language governing permissions and
|
| 19 |
+
# limitations under the License.
|
| 20 |
+
import math
|
| 21 |
+
from collections.abc import Callable
|
| 22 |
+
from dataclasses import dataclass
|
| 23 |
+
|
| 24 |
+
import torch
|
| 25 |
+
from torch import nn
|
| 26 |
+
|
| 27 |
+
from ... import initialization as init
|
| 28 |
+
from ...activations import ACT2FN
|
| 29 |
+
from ...backbone_utils import load_backbone
|
| 30 |
+
from ...masking_utils import create_bidirectional_mask
|
| 31 |
+
from ...modeling_layers import GradientCheckpointingLayer
|
| 32 |
+
from ...modeling_outputs import BaseModelOutput, BaseModelOutputWithCrossAttentions, Seq2SeqModelOutput
|
| 33 |
+
from ...modeling_utils import ALL_ATTENTION_FUNCTIONS, PreTrainedModel
|
| 34 |
+
from ...processing_utils import Unpack
|
| 35 |
+
from ...pytorch_utils import compile_compatible_method_lru_cache
|
| 36 |
+
from ...utils import ModelOutput, TransformersKwargs, auto_docstring
|
| 37 |
+
from ...utils.generic import can_return_tuple, merge_with_config_defaults
|
| 38 |
+
from ...utils.output_capturing import OutputRecorder, capture_outputs
|
| 39 |
+
from .configuration_conditional_detr import ConditionalDetrConfig
|
| 40 |
+
|
| 41 |
+
|
| 42 |
+
@dataclass
|
| 43 |
+
@auto_docstring(
|
| 44 |
+
custom_intro="""
|
| 45 |
+
Base class for outputs of the CONDITIONAL_DETR decoder. This class adds one attribute to BaseModelOutputWithCrossAttentions,
|
| 46 |
+
namely an optional stack of intermediate decoder activations, i.e. the output of each decoder layer, each of them
|
| 47 |
+
gone through a layernorm. This is useful when training the model with auxiliary decoding losses.
|
| 48 |
+
"""
|
| 49 |
+
)
|
| 50 |
+
class ConditionalDetrDecoderOutput(BaseModelOutputWithCrossAttentions):
|
| 51 |
+
r"""
|
| 52 |
+
cross_attentions (`tuple(torch.FloatTensor)`, *optional*, returned when `output_attentions=True` and `config.add_cross_attention=True` is passed or when `config.output_attentions=True`):
|
| 53 |
+
Tuple of `torch.FloatTensor` (one for each layer) of shape `(batch_size, num_heads, sequence_length,
|
| 54 |
+
sequence_length)`. Attentions weights of the decoder's cross-attention layer, after the attention softmax,
|
| 55 |
+
used to compute the weighted average in the cross-attention heads.
|
| 56 |
+
intermediate_hidden_states (`torch.FloatTensor` of shape `(config.decoder_layers, batch_size, num_queries, hidden_size)`, *optional*, returned when `config.auxiliary_loss=True`):
|
| 57 |
+
Intermediate decoder activations, i.e. the output of each decoder layer, each of them gone through a
|
| 58 |
+
layernorm.
|
| 59 |
+
reference_points (`torch.FloatTensor` of shape `(config.decoder_layers, batch_size, num_queries, 2 (anchor points))`):
|
| 60 |
+
Reference points (reference points of each layer of the decoder).
|
| 61 |
+
"""
|
| 62 |
+
|
| 63 |
+
intermediate_hidden_states: torch.FloatTensor | None = None
|
| 64 |
+
|
| 65 |
+
reference_points: tuple[torch.FloatTensor] | None = None
|
| 66 |
+
|
| 67 |
+
|
| 68 |
+
@dataclass
|
| 69 |
+
@auto_docstring(
|
| 70 |
+
custom_intro="""
|
| 71 |
+
Base class for outputs of the CONDITIONAL_DETR encoder-decoder model. This class adds one attribute to Seq2SeqModelOutput,
|
| 72 |
+
namely an optional stack of intermediate decoder activations, i.e. the output of each decoder layer, each of them
|
| 73 |
+
gone through a layernorm. This is useful when training the model with auxiliary decoding losses.
|
| 74 |
+
"""
|
| 75 |
+
)
|
| 76 |
+
class ConditionalDetrModelOutput(Seq2SeqModelOutput):
|
| 77 |
+
r"""
|
| 78 |
+
last_hidden_state (`torch.FloatTensor` of shape `(batch_size, sequence_length, hidden_size)`):
|
| 79 |
+
Sequence of hidden-states at the output of the last layer of the decoder of the model.
|
| 80 |
+
intermediate_hidden_states (`torch.FloatTensor` of shape `(config.decoder_layers, batch_size, sequence_length, hidden_size)`, *optional*, returned when `config.auxiliary_loss=True`):
|
| 81 |
+
Intermediate decoder activations, i.e. the output of each decoder layer, each of them gone through a
|
| 82 |
+
layernorm.
|
| 83 |
+
reference_points (`torch.FloatTensor` of shape `(config.decoder_layers, batch_size, num_queries, 2 (anchor points))`):
|
| 84 |
+
Reference points (reference points of each layer of the decoder).
|
| 85 |
+
"""
|
| 86 |
+
|
| 87 |
+
intermediate_hidden_states: torch.FloatTensor | None = None
|
| 88 |
+
|
| 89 |
+
reference_points: tuple[torch.FloatTensor] | None = None
|
| 90 |
+
|
| 91 |
+
|
| 92 |
+
@dataclass
|
| 93 |
+
@auto_docstring(
|
| 94 |
+
custom_intro="""
|
| 95 |
+
Output type of [`ConditionalDetrForObjectDetection`].
|
| 96 |
+
"""
|
| 97 |
+
)
|
| 98 |
+
class ConditionalDetrObjectDetectionOutput(ModelOutput):
|
| 99 |
+
r"""
|
| 100 |
+
loss (`torch.FloatTensor` of shape `(1,)`, *optional*, returned when `labels` are provided)):
|
| 101 |
+
Total loss as a linear combination of a negative log-likehood (cross-entropy) for class prediction and a
|
| 102 |
+
bounding box loss. The latter is defined as a linear combination of the L1 loss and the generalized
|
| 103 |
+
scale-invariant IoU loss.
|
| 104 |
+
loss_dict (`Dict`, *optional*):
|
| 105 |
+
A dictionary containing the individual losses. Useful for logging.
|
| 106 |
+
logits (`torch.FloatTensor` of shape `(batch_size, num_queries, num_classes + 1)`):
|
| 107 |
+
Classification logits (including no-object) for all queries.
|
| 108 |
+
pred_boxes (`torch.FloatTensor` of shape `(batch_size, num_queries, 4)`):
|
| 109 |
+
Normalized boxes coordinates for all queries, represented as (center_x, center_y, width, height). These
|
| 110 |
+
values are normalized in [0, 1], relative to the size of each individual image in the batch (disregarding
|
| 111 |
+
possible padding). You can use [`~ConditionalDetrImageProcessor.post_process_object_detection`] to retrieve the
|
| 112 |
+
unnormalized bounding boxes.
|
| 113 |
+
auxiliary_outputs (`list[Dict]`, *optional*):
|
| 114 |
+
Optional, only returned when auxiliary losses are activated (i.e. `config.auxiliary_loss` is set to `True`)
|
| 115 |
+
and labels are provided. It is a list of dictionaries containing the two above keys (`logits` and
|
| 116 |
+
`pred_boxes`) for each decoder layer.
|
| 117 |
+
last_hidden_state (`torch.FloatTensor` of shape `(batch_size, sequence_length, hidden_size)`, *optional*):
|
| 118 |
+
Sequence of hidden-states at the output of the last layer of the decoder of the model.
|
| 119 |
+
"""
|
| 120 |
+
|
| 121 |
+
loss: torch.FloatTensor | None = None
|
| 122 |
+
loss_dict: dict | None = None
|
| 123 |
+
logits: torch.FloatTensor | None = None
|
| 124 |
+
pred_boxes: torch.FloatTensor | None = None
|
| 125 |
+
auxiliary_outputs: list[dict] | None = None
|
| 126 |
+
last_hidden_state: torch.FloatTensor | None = None
|
| 127 |
+
decoder_hidden_states: tuple[torch.FloatTensor] | None = None
|
| 128 |
+
decoder_attentions: tuple[torch.FloatTensor] | None = None
|
| 129 |
+
cross_attentions: tuple[torch.FloatTensor] | None = None
|
| 130 |
+
encoder_last_hidden_state: torch.FloatTensor | None = None
|
| 131 |
+
encoder_hidden_states: tuple[torch.FloatTensor] | None = None
|
| 132 |
+
encoder_attentions: tuple[torch.FloatTensor] | None = None
|
| 133 |
+
|
| 134 |
+
|
| 135 |
+
@dataclass
|
| 136 |
+
@auto_docstring(
|
| 137 |
+
custom_intro="""
|
| 138 |
+
Output type of [`ConditionalDetrForSegmentation`].
|
| 139 |
+
"""
|
| 140 |
+
)
|
| 141 |
+
class ConditionalDetrSegmentationOutput(ModelOutput):
|
| 142 |
+
r"""
|
| 143 |
+
loss (`torch.FloatTensor` of shape `(1,)`, *optional*, returned when `labels` are provided)):
|
| 144 |
+
Total loss as a linear combination of a negative log-likehood (cross-entropy) for class prediction and a
|
| 145 |
+
bounding box loss. The latter is defined as a linear combination of the L1 loss and the generalized
|
| 146 |
+
scale-invariant IoU loss.
|
| 147 |
+
loss_dict (`Dict`, *optional*):
|
| 148 |
+
A dictionary containing the individual losses. Useful for logging.
|
| 149 |
+
logits (`torch.FloatTensor` of shape `(batch_size, num_queries, num_classes + 1)`):
|
| 150 |
+
Classification logits (including no-object) for all queries.
|
| 151 |
+
pred_boxes (`torch.FloatTensor` of shape `(batch_size, num_queries, 4)`):
|
| 152 |
+
Normalized boxes coordinates for all queries, represented as (center_x, center_y, width, height). These
|
| 153 |
+
values are normalized in [0, 1], relative to the size of each individual image in the batch (disregarding
|
| 154 |
+
possible padding). You can use [`~ConditionalDetrImageProcessor.post_process_object_detection`] to retrieve the
|
| 155 |
+
unnormalized bounding boxes.
|
| 156 |
+
pred_masks (`torch.FloatTensor` of shape `(batch_size, num_queries, height/4, width/4)`):
|
| 157 |
+
Segmentation masks logits for all queries. See also
|
| 158 |
+
[`~ConditionalDetrImageProcessor.post_process_semantic_segmentation`] or
|
| 159 |
+
[`~ConditionalDetrImageProcessor.post_process_instance_segmentation`]
|
| 160 |
+
[`~ConditionalDetrImageProcessor.post_process_panoptic_segmentation`] to evaluate semantic, instance and panoptic
|
| 161 |
+
segmentation masks respectively.
|
| 162 |
+
auxiliary_outputs (`list[Dict]`, *optional*):
|
| 163 |
+
Optional, only returned when auxiliary losses are activated (i.e. `config.auxiliary_loss` is set to `True`)
|
| 164 |
+
and labels are provided. It is a list of dictionaries containing the two above keys (`logits` and
|
| 165 |
+
`pred_boxes`) for each decoder layer.
|
| 166 |
+
last_hidden_state (`torch.FloatTensor` of shape `(batch_size, sequence_length, hidden_size)`, *optional*):
|
| 167 |
+
Sequence of hidden-states at the output of the last layer of the decoder of the model.
|
| 168 |
+
"""
|
| 169 |
+
|
| 170 |
+
loss: torch.FloatTensor | None = None
|
| 171 |
+
loss_dict: dict | None = None
|
| 172 |
+
logits: torch.FloatTensor | None = None
|
| 173 |
+
pred_boxes: torch.FloatTensor | None = None
|
| 174 |
+
pred_masks: torch.FloatTensor | None = None
|
| 175 |
+
auxiliary_outputs: list[dict] | None = None
|
| 176 |
+
last_hidden_state: torch.FloatTensor | None = None
|
| 177 |
+
decoder_hidden_states: tuple[torch.FloatTensor] | None = None
|
| 178 |
+
decoder_attentions: tuple[torch.FloatTensor] | None = None
|
| 179 |
+
cross_attentions: tuple[torch.FloatTensor] | None = None
|
| 180 |
+
encoder_last_hidden_state: torch.FloatTensor | None = None
|
| 181 |
+
encoder_hidden_states: tuple[torch.FloatTensor] | None = None
|
| 182 |
+
encoder_attentions: tuple[torch.FloatTensor] | None = None
|
| 183 |
+
|
| 184 |
+
|
| 185 |
+
class ConditionalDetrFrozenBatchNorm2d(nn.Module):
|
| 186 |
+
"""
|
| 187 |
+
BatchNorm2d where the batch statistics and the affine parameters are fixed.
|
| 188 |
+
|
| 189 |
+
Copy-paste from torchvision.misc.ops with added eps before rqsrt, without which any other models than
|
| 190 |
+
torchvision.models.resnet[18,34,50,101] produce nans.
|
| 191 |
+
"""
|
| 192 |
+
|
| 193 |
+
def __init__(self, n):
|
| 194 |
+
super().__init__()
|
| 195 |
+
self.register_buffer("weight", torch.ones(n))
|
| 196 |
+
self.register_buffer("bias", torch.zeros(n))
|
| 197 |
+
self.register_buffer("running_mean", torch.zeros(n))
|
| 198 |
+
self.register_buffer("running_var", torch.ones(n))
|
| 199 |
+
|
| 200 |
+
def _load_from_state_dict(
|
| 201 |
+
self, state_dict, prefix, local_metadata, strict, missing_keys, unexpected_keys, error_msgs
|
| 202 |
+
):
|
| 203 |
+
num_batches_tracked_key = prefix + "num_batches_tracked"
|
| 204 |
+
if num_batches_tracked_key in state_dict:
|
| 205 |
+
del state_dict[num_batches_tracked_key]
|
| 206 |
+
|
| 207 |
+
super()._load_from_state_dict(
|
| 208 |
+
state_dict, prefix, local_metadata, strict, missing_keys, unexpected_keys, error_msgs
|
| 209 |
+
)
|
| 210 |
+
|
| 211 |
+
def forward(self, x):
|
| 212 |
+
# move reshapes to the beginning
|
| 213 |
+
# to make it user-friendly
|
| 214 |
+
weight = self.weight.reshape(1, -1, 1, 1)
|
| 215 |
+
bias = self.bias.reshape(1, -1, 1, 1)
|
| 216 |
+
running_var = self.running_var.reshape(1, -1, 1, 1)
|
| 217 |
+
running_mean = self.running_mean.reshape(1, -1, 1, 1)
|
| 218 |
+
epsilon = 1e-5
|
| 219 |
+
scale = weight * (running_var + epsilon).rsqrt()
|
| 220 |
+
bias = bias - running_mean * scale
|
| 221 |
+
return x * scale + bias
|
| 222 |
+
|
| 223 |
+
|
| 224 |
+
def replace_batch_norm(model):
|
| 225 |
+
r"""
|
| 226 |
+
Recursively replace all `torch.nn.BatchNorm2d` with `ConditionalDetrFrozenBatchNorm2d`.
|
| 227 |
+
|
| 228 |
+
Args:
|
| 229 |
+
model (torch.nn.Module):
|
| 230 |
+
input model
|
| 231 |
+
"""
|
| 232 |
+
for name, module in model.named_children():
|
| 233 |
+
if isinstance(module, nn.BatchNorm2d):
|
| 234 |
+
new_module = ConditionalDetrFrozenBatchNorm2d(module.num_features)
|
| 235 |
+
|
| 236 |
+
if module.weight.device != torch.device("meta"):
|
| 237 |
+
new_module.weight.copy_(module.weight)
|
| 238 |
+
new_module.bias.copy_(module.bias)
|
| 239 |
+
new_module.running_mean.copy_(module.running_mean)
|
| 240 |
+
new_module.running_var.copy_(module.running_var)
|
| 241 |
+
|
| 242 |
+
model._modules[name] = new_module
|
| 243 |
+
|
| 244 |
+
if len(list(module.children())) > 0:
|
| 245 |
+
replace_batch_norm(module)
|
| 246 |
+
|
| 247 |
+
|
| 248 |
+
class ConditionalDetrConvEncoder(nn.Module):
|
| 249 |
+
"""
|
| 250 |
+
Convolutional backbone, using either the AutoBackbone API or one from the timm library.
|
| 251 |
+
|
| 252 |
+
nn.BatchNorm2d layers are replaced by ConditionalDetrFrozenBatchNorm2d as defined above.
|
| 253 |
+
|
| 254 |
+
"""
|
| 255 |
+
|
| 256 |
+
def __init__(self, config):
|
| 257 |
+
super().__init__()
|
| 258 |
+
|
| 259 |
+
self.config = config
|
| 260 |
+
|
| 261 |
+
backbone = load_backbone(config)
|
| 262 |
+
self.intermediate_channel_sizes = backbone.channels
|
| 263 |
+
|
| 264 |
+
# replace batch norm by frozen batch norm
|
| 265 |
+
with torch.no_grad():
|
| 266 |
+
replace_batch_norm(backbone)
|
| 267 |
+
|
| 268 |
+
# We used to load with timm library directly instead of the AutoBackbone API
|
| 269 |
+
# so we need to unwrap the `backbone._backbone` module to load weights without mismatch
|
| 270 |
+
is_timm_model = False
|
| 271 |
+
if hasattr(backbone, "_backbone"):
|
| 272 |
+
backbone = backbone._backbone
|
| 273 |
+
is_timm_model = True
|
| 274 |
+
self.model = backbone
|
| 275 |
+
|
| 276 |
+
backbone_model_type = config.backbone_config.model_type
|
| 277 |
+
if "resnet" in backbone_model_type:
|
| 278 |
+
for name, parameter in self.model.named_parameters():
|
| 279 |
+
if is_timm_model:
|
| 280 |
+
if "layer2" not in name and "layer3" not in name and "layer4" not in name:
|
| 281 |
+
parameter.requires_grad_(False)
|
| 282 |
+
else:
|
| 283 |
+
if "stage.1" not in name and "stage.2" not in name and "stage.3" not in name:
|
| 284 |
+
parameter.requires_grad_(False)
|
| 285 |
+
|
| 286 |
+
def forward(self, pixel_values: torch.Tensor, pixel_mask: torch.Tensor):
|
| 287 |
+
# send pixel_values through the model to get list of feature maps
|
| 288 |
+
features = self.model(pixel_values)
|
| 289 |
+
if isinstance(features, dict):
|
| 290 |
+
features = features.feature_maps
|
| 291 |
+
|
| 292 |
+
out = []
|
| 293 |
+
for feature_map in features:
|
| 294 |
+
# downsample pixel_mask to match shape of corresponding feature_map
|
| 295 |
+
mask = nn.functional.interpolate(pixel_mask[None].float(), size=feature_map.shape[-2:]).to(torch.bool)[0]
|
| 296 |
+
out.append((feature_map, mask))
|
| 297 |
+
return out
|
| 298 |
+
|
| 299 |
+
|
| 300 |
+
class ConditionalDetrSinePositionEmbedding(nn.Module):
|
| 301 |
+
"""
|
| 302 |
+
This is a more standard version of the position embedding, very similar to the one used by the Attention is all you
|
| 303 |
+
need paper, generalized to work on images.
|
| 304 |
+
"""
|
| 305 |
+
|
| 306 |
+
def __init__(
|
| 307 |
+
self,
|
| 308 |
+
num_position_features: int = 64,
|
| 309 |
+
temperature: int = 10000,
|
| 310 |
+
normalize: bool = False,
|
| 311 |
+
scale: float | None = None,
|
| 312 |
+
):
|
| 313 |
+
super().__init__()
|
| 314 |
+
if scale is not None and normalize is False:
|
| 315 |
+
raise ValueError("normalize should be True if scale is passed")
|
| 316 |
+
self.num_position_features = num_position_features
|
| 317 |
+
self.temperature = temperature
|
| 318 |
+
self.normalize = normalize
|
| 319 |
+
self.scale = 2 * math.pi if scale is None else scale
|
| 320 |
+
|
| 321 |
+
@compile_compatible_method_lru_cache(maxsize=1)
|
| 322 |
+
def forward(
|
| 323 |
+
self,
|
| 324 |
+
shape: torch.Size,
|
| 325 |
+
device: torch.device | str,
|
| 326 |
+
dtype: torch.dtype,
|
| 327 |
+
mask: torch.Tensor | None = None,
|
| 328 |
+
) -> torch.Tensor:
|
| 329 |
+
if mask is None:
|
| 330 |
+
mask = torch.zeros((shape[0], shape[2], shape[3]), device=device, dtype=torch.bool)
|
| 331 |
+
y_embed = mask.cumsum(1, dtype=dtype)
|
| 332 |
+
x_embed = mask.cumsum(2, dtype=dtype)
|
| 333 |
+
if self.normalize:
|
| 334 |
+
eps = 1e-6
|
| 335 |
+
y_embed = y_embed / (y_embed[:, -1:, :] + eps) * self.scale
|
| 336 |
+
x_embed = x_embed / (x_embed[:, :, -1:] + eps) * self.scale
|
| 337 |
+
|
| 338 |
+
dim_t = torch.arange(self.num_position_features, dtype=torch.int64, device=device).to(dtype)
|
| 339 |
+
dim_t = self.temperature ** (2 * torch.div(dim_t, 2, rounding_mode="floor") / self.num_position_features)
|
| 340 |
+
|
| 341 |
+
pos_x = x_embed[:, :, :, None] / dim_t
|
| 342 |
+
pos_y = y_embed[:, :, :, None] / dim_t
|
| 343 |
+
pos_x = torch.stack((pos_x[:, :, :, 0::2].sin(), pos_x[:, :, :, 1::2].cos()), dim=4).flatten(3)
|
| 344 |
+
pos_y = torch.stack((pos_y[:, :, :, 0::2].sin(), pos_y[:, :, :, 1::2].cos()), dim=4).flatten(3)
|
| 345 |
+
pos = torch.cat((pos_y, pos_x), dim=3).permute(0, 3, 1, 2)
|
| 346 |
+
# Flatten spatial dimensions and permute to (batch_size, sequence_length, hidden_size) format
|
| 347 |
+
# expected by the encoder
|
| 348 |
+
pos = pos.flatten(2).permute(0, 2, 1)
|
| 349 |
+
return pos
|
| 350 |
+
|
| 351 |
+
|
| 352 |
+
class ConditionalDetrLearnedPositionEmbedding(nn.Module):
|
| 353 |
+
"""
|
| 354 |
+
This module learns positional embeddings up to a fixed maximum size.
|
| 355 |
+
"""
|
| 356 |
+
|
| 357 |
+
def __init__(self, embedding_dim=256):
|
| 358 |
+
super().__init__()
|
| 359 |
+
self.row_embeddings = nn.Embedding(50, embedding_dim)
|
| 360 |
+
self.column_embeddings = nn.Embedding(50, embedding_dim)
|
| 361 |
+
|
| 362 |
+
@compile_compatible_method_lru_cache(maxsize=1)
|
| 363 |
+
def forward(
|
| 364 |
+
self,
|
| 365 |
+
shape: torch.Size,
|
| 366 |
+
device: torch.device | str,
|
| 367 |
+
dtype: torch.dtype,
|
| 368 |
+
mask: torch.Tensor | None = None,
|
| 369 |
+
):
|
| 370 |
+
height, width = shape[-2:]
|
| 371 |
+
width_values = torch.arange(width, device=device)
|
| 372 |
+
height_values = torch.arange(height, device=device)
|
| 373 |
+
x_emb = self.column_embeddings(width_values)
|
| 374 |
+
y_emb = self.row_embeddings(height_values)
|
| 375 |
+
pos = torch.cat([x_emb.unsqueeze(0).repeat(height, 1, 1), y_emb.unsqueeze(1).repeat(1, width, 1)], dim=-1)
|
| 376 |
+
pos = pos.permute(2, 0, 1)
|
| 377 |
+
pos = pos.unsqueeze(0)
|
| 378 |
+
pos = pos.repeat(shape[0], 1, 1, 1)
|
| 379 |
+
# Flatten spatial dimensions and permute to (batch_size, sequence_length, hidden_size) format
|
| 380 |
+
# expected by the encoder
|
| 381 |
+
pos = pos.flatten(2).permute(0, 2, 1)
|
| 382 |
+
return pos
|
| 383 |
+
|
| 384 |
+
|
| 385 |
+
def eager_attention_forward(
|
| 386 |
+
module: nn.Module,
|
| 387 |
+
query: torch.Tensor,
|
| 388 |
+
key: torch.Tensor,
|
| 389 |
+
value: torch.Tensor,
|
| 390 |
+
attention_mask: torch.Tensor | None,
|
| 391 |
+
scaling: float | None = None,
|
| 392 |
+
dropout: float = 0.0,
|
| 393 |
+
**kwargs: Unpack[TransformersKwargs],
|
| 394 |
+
):
|
| 395 |
+
if scaling is None:
|
| 396 |
+
scaling = query.size(-1) ** -0.5
|
| 397 |
+
|
| 398 |
+
# Take the dot product between "query" and "key" to get the raw attention scores.
|
| 399 |
+
attn_weights = torch.matmul(query, key.transpose(2, 3)) * scaling
|
| 400 |
+
|
| 401 |
+
if attention_mask is not None:
|
| 402 |
+
attn_weights = attn_weights + attention_mask
|
| 403 |
+
|
| 404 |
+
attn_weights = nn.functional.softmax(attn_weights, dim=-1)
|
| 405 |
+
attn_weights = nn.functional.dropout(attn_weights, p=dropout, training=module.training)
|
| 406 |
+
|
| 407 |
+
attn_output = torch.matmul(attn_weights, value)
|
| 408 |
+
attn_output = attn_output.transpose(1, 2).contiguous()
|
| 409 |
+
|
| 410 |
+
return attn_output, attn_weights
|
| 411 |
+
|
| 412 |
+
|
| 413 |
+
class ConditionalDetrSelfAttention(nn.Module):
|
| 414 |
+
"""
|
| 415 |
+
Multi-headed self-attention from 'Attention Is All You Need' paper.
|
| 416 |
+
|
| 417 |
+
In CONDITIONAL_DETR, position embeddings are added to both queries and keys (but not values) in self-attention.
|
| 418 |
+
"""
|
| 419 |
+
|
| 420 |
+
def __init__(
|
| 421 |
+
self,
|
| 422 |
+
config: ConditionalDetrConfig,
|
| 423 |
+
hidden_size: int,
|
| 424 |
+
num_attention_heads: int,
|
| 425 |
+
dropout: float = 0.0,
|
| 426 |
+
bias: bool = True,
|
| 427 |
+
):
|
| 428 |
+
super().__init__()
|
| 429 |
+
self.config = config
|
| 430 |
+
self.head_dim = hidden_size // num_attention_heads
|
| 431 |
+
self.scaling = self.head_dim**-0.5
|
| 432 |
+
self.attention_dropout = dropout
|
| 433 |
+
self.is_causal = False
|
| 434 |
+
|
| 435 |
+
self.k_proj = nn.Linear(hidden_size, hidden_size, bias=bias)
|
| 436 |
+
self.v_proj = nn.Linear(hidden_size, hidden_size, bias=bias)
|
| 437 |
+
self.q_proj = nn.Linear(hidden_size, hidden_size, bias=bias)
|
| 438 |
+
self.o_proj = nn.Linear(hidden_size, hidden_size, bias=bias)
|
| 439 |
+
|
| 440 |
+
def forward(
|
| 441 |
+
self,
|
| 442 |
+
hidden_states: torch.Tensor,
|
| 443 |
+
attention_mask: torch.Tensor | None = None,
|
| 444 |
+
position_embeddings: torch.Tensor | None = None,
|
| 445 |
+
**kwargs: Unpack[TransformersKwargs],
|
| 446 |
+
) -> tuple[torch.Tensor, torch.Tensor]:
|
| 447 |
+
"""
|
| 448 |
+
Position embeddings are added to both queries and keys (but not values).
|
| 449 |
+
"""
|
| 450 |
+
input_shape = hidden_states.shape[:-1]
|
| 451 |
+
hidden_shape = (*input_shape, -1, self.head_dim)
|
| 452 |
+
|
| 453 |
+
query_key_input = hidden_states + position_embeddings if position_embeddings is not None else hidden_states
|
| 454 |
+
|
| 455 |
+
query_states = self.q_proj(query_key_input).view(hidden_shape).transpose(1, 2)
|
| 456 |
+
key_states = self.k_proj(query_key_input).view(hidden_shape).transpose(1, 2)
|
| 457 |
+
value_states = self.v_proj(hidden_states).view(hidden_shape).transpose(1, 2)
|
| 458 |
+
|
| 459 |
+
attention_interface: Callable = ALL_ATTENTION_FUNCTIONS.get_interface(
|
| 460 |
+
self.config._attn_implementation, eager_attention_forward
|
| 461 |
+
)
|
| 462 |
+
|
| 463 |
+
attn_output, attn_weights = attention_interface(
|
| 464 |
+
self,
|
| 465 |
+
query_states,
|
| 466 |
+
key_states,
|
| 467 |
+
value_states,
|
| 468 |
+
attention_mask,
|
| 469 |
+
dropout=0.0 if not self.training else self.attention_dropout,
|
| 470 |
+
scaling=self.scaling,
|
| 471 |
+
**kwargs,
|
| 472 |
+
)
|
| 473 |
+
|
| 474 |
+
attn_output = attn_output.reshape(*input_shape, -1).contiguous()
|
| 475 |
+
attn_output = self.o_proj(attn_output)
|
| 476 |
+
return attn_output, attn_weights
|
| 477 |
+
|
| 478 |
+
|
| 479 |
+
class ConditionalDetrDecoderSelfAttention(nn.Module):
|
| 480 |
+
"""
|
| 481 |
+
Multi-headed self-attention for Conditional DETR decoder layers.
|
| 482 |
+
|
| 483 |
+
This attention module handles separate content and position projections, which are then combined
|
| 484 |
+
before applying standard self-attention. Position embeddings are added to both queries and keys.
|
| 485 |
+
"""
|
| 486 |
+
|
| 487 |
+
def __init__(
|
| 488 |
+
self,
|
| 489 |
+
config: ConditionalDetrConfig,
|
| 490 |
+
hidden_size: int,
|
| 491 |
+
num_attention_heads: int,
|
| 492 |
+
dropout: float | int = 0.0,
|
| 493 |
+
):
|
| 494 |
+
super().__init__()
|
| 495 |
+
self.config = config
|
| 496 |
+
self.hidden_size = hidden_size
|
| 497 |
+
self.head_dim = hidden_size // num_attention_heads
|
| 498 |
+
self.scaling = self.head_dim**-0.5
|
| 499 |
+
self.attention_dropout = dropout
|
| 500 |
+
self.is_causal = False
|
| 501 |
+
|
| 502 |
+
# Content and position projections
|
| 503 |
+
self.q_content_proj = nn.Linear(hidden_size, hidden_size)
|
| 504 |
+
self.q_pos_proj = nn.Linear(hidden_size, hidden_size)
|
| 505 |
+
self.k_content_proj = nn.Linear(hidden_size, hidden_size)
|
| 506 |
+
self.k_pos_proj = nn.Linear(hidden_size, hidden_size)
|
| 507 |
+
self.v_proj = nn.Linear(hidden_size, hidden_size)
|
| 508 |
+
self.o_proj = nn.Linear(hidden_size, hidden_size)
|
| 509 |
+
|
| 510 |
+
def forward(
|
| 511 |
+
self,
|
| 512 |
+
hidden_states: torch.Tensor,
|
| 513 |
+
query_position_embeddings: torch.Tensor,
|
| 514 |
+
attention_mask: torch.Tensor | None = None,
|
| 515 |
+
**kwargs: Unpack[TransformersKwargs],
|
| 516 |
+
) -> tuple[torch.Tensor, torch.Tensor]:
|
| 517 |
+
"""
|
| 518 |
+
Args:
|
| 519 |
+
hidden_states (`torch.Tensor` of shape `(batch_size, num_queries, hidden_size)`):
|
| 520 |
+
Input hidden states from the decoder layer.
|
| 521 |
+
query_position_embeddings (`torch.Tensor` of shape `(batch_size, num_queries, hidden_size)`):
|
| 522 |
+
Position embeddings for queries and keys. Required (unlike standard attention). Processed through
|
| 523 |
+
separate position projections (`q_pos_proj`, `k_pos_proj`) and added to content projections.
|
| 524 |
+
attention_mask (`torch.Tensor` of shape `(batch_size, 1, num_queries, num_queries)`, *optional*):
|
| 525 |
+
Attention mask to avoid attending to padding tokens.
|
| 526 |
+
"""
|
| 527 |
+
input_shape = hidden_states.shape[:-1]
|
| 528 |
+
hidden_shape = (*input_shape, -1, self.head_dim)
|
| 529 |
+
|
| 530 |
+
query_states = (
|
| 531 |
+
(self.q_content_proj(hidden_states) + self.q_pos_proj(query_position_embeddings))
|
| 532 |
+
.view(hidden_shape)
|
| 533 |
+
.transpose(1, 2)
|
| 534 |
+
)
|
| 535 |
+
key_states = (
|
| 536 |
+
(self.k_content_proj(hidden_states) + self.k_pos_proj(query_position_embeddings))
|
| 537 |
+
.view(hidden_shape)
|
| 538 |
+
.transpose(1, 2)
|
| 539 |
+
)
|
| 540 |
+
value_states = self.v_proj(hidden_states).view(hidden_shape).transpose(1, 2)
|
| 541 |
+
|
| 542 |
+
attention_interface: Callable = ALL_ATTENTION_FUNCTIONS.get_interface(
|
| 543 |
+
self.config._attn_implementation, eager_attention_forward
|
| 544 |
+
)
|
| 545 |
+
|
| 546 |
+
attn_output, attn_weights = attention_interface(
|
| 547 |
+
self,
|
| 548 |
+
query_states,
|
| 549 |
+
key_states,
|
| 550 |
+
value_states,
|
| 551 |
+
attention_mask,
|
| 552 |
+
dropout=0.0 if not self.training else self.attention_dropout,
|
| 553 |
+
scaling=self.scaling,
|
| 554 |
+
**kwargs,
|
| 555 |
+
)
|
| 556 |
+
|
| 557 |
+
attn_output = attn_output.reshape(*input_shape, -1).contiguous()
|
| 558 |
+
attn_output = self.o_proj(attn_output)
|
| 559 |
+
return attn_output, attn_weights
|
| 560 |
+
|
| 561 |
+
|
| 562 |
+
class ConditionalDetrDecoderCrossAttention(nn.Module):
|
| 563 |
+
"""
|
| 564 |
+
Multi-headed cross-attention for Conditional DETR decoder layers.
|
| 565 |
+
|
| 566 |
+
This attention module handles the special cross-attention logic in Conditional DETR:
|
| 567 |
+
- Separate content and position projections for queries and keys
|
| 568 |
+
- Concatenation of query sine embeddings with queries (doubling query dimension)
|
| 569 |
+
- Concatenation of key position embeddings with keys (doubling key dimension)
|
| 570 |
+
- Output dimension remains hidden_size despite doubled input dimensions
|
| 571 |
+
"""
|
| 572 |
+
|
| 573 |
+
def __init__(
|
| 574 |
+
self,
|
| 575 |
+
config: ConditionalDetrConfig,
|
| 576 |
+
hidden_size: int,
|
| 577 |
+
num_attention_heads: int,
|
| 578 |
+
dropout: float | int = 0.0,
|
| 579 |
+
):
|
| 580 |
+
super().__init__()
|
| 581 |
+
self.config = config
|
| 582 |
+
self.hidden_size = hidden_size
|
| 583 |
+
self.num_attention_heads = num_attention_heads
|
| 584 |
+
self.head_dim = hidden_size // num_attention_heads
|
| 585 |
+
self.attention_dropout = dropout
|
| 586 |
+
self.is_causal = False
|
| 587 |
+
|
| 588 |
+
# Content and position projections
|
| 589 |
+
self.q_content_proj = nn.Linear(hidden_size, hidden_size)
|
| 590 |
+
self.q_pos_proj = nn.Linear(hidden_size, hidden_size)
|
| 591 |
+
self.k_content_proj = nn.Linear(hidden_size, hidden_size)
|
| 592 |
+
self.k_pos_proj = nn.Linear(hidden_size, hidden_size)
|
| 593 |
+
self.v_proj = nn.Linear(hidden_size, hidden_size)
|
| 594 |
+
self.q_pos_sine_proj = nn.Linear(hidden_size, hidden_size)
|
| 595 |
+
|
| 596 |
+
# Output projection: input is hidden_size * 2 (from concatenated q/k), output is hidden_size
|
| 597 |
+
self.o_proj = nn.Linear(hidden_size, hidden_size)
|
| 598 |
+
|
| 599 |
+
# Compute scaling for expanded head_dim (q and k have doubled dimensions after concatenation)
|
| 600 |
+
# This matches the original Conditional DETR implementation where embed_dim * 2 is used
|
| 601 |
+
expanded_head_dim = (hidden_size * 2) // num_attention_heads
|
| 602 |
+
self.scaling = expanded_head_dim**-0.5
|
| 603 |
+
|
| 604 |
+
def forward(
|
| 605 |
+
self,
|
| 606 |
+
hidden_states: torch.Tensor,
|
| 607 |
+
encoder_hidden_states: torch.Tensor,
|
| 608 |
+
query_sine_embed: torch.Tensor,
|
| 609 |
+
encoder_position_embeddings: torch.Tensor,
|
| 610 |
+
query_position_embeddings: torch.Tensor | None = None,
|
| 611 |
+
attention_mask: torch.Tensor | None = None,
|
| 612 |
+
**kwargs: Unpack[TransformersKwargs],
|
| 613 |
+
) -> tuple[torch.Tensor, torch.Tensor]:
|
| 614 |
+
"""
|
| 615 |
+
Args:
|
| 616 |
+
hidden_states (`torch.Tensor` of shape `(batch_size, num_queries, hidden_size)`):
|
| 617 |
+
Decoder hidden states (queries).
|
| 618 |
+
encoder_hidden_states (`torch.Tensor` of shape `(batch_size, encoder_seq_len, hidden_size)`):
|
| 619 |
+
Encoder output hidden states (keys and values).
|
| 620 |
+
query_sine_embed (`torch.Tensor` of shape `(batch_size, num_queries, hidden_size)`):
|
| 621 |
+
Sine position embeddings for queries. **Concatenated** (not added) with query content,
|
| 622 |
+
doubling the query dimension.
|
| 623 |
+
encoder_position_embeddings (`torch.Tensor` of shape `(batch_size, encoder_seq_len, hidden_size)`):
|
| 624 |
+
Position embeddings for keys. **Concatenated** (not added) with key content, doubling the key dimension.
|
| 625 |
+
query_position_embeddings (`torch.Tensor` of shape `(batch_size, num_queries, hidden_size)`, *optional*):
|
| 626 |
+
Additional position embeddings. When provided (first layer only), **added** to query content
|
| 627 |
+
before concatenation with `query_sine_embed`. Also causes `encoder_position_embeddings` to be
|
| 628 |
+
added to key content before concatenation.
|
| 629 |
+
attention_mask (`torch.Tensor` of shape `(batch_size, 1, num_queries, encoder_seq_len)`, *optional*):
|
| 630 |
+
Attention mask to avoid attending to padding tokens.
|
| 631 |
+
"""
|
| 632 |
+
query_input_shape = hidden_states.shape[:-1]
|
| 633 |
+
kv_input_shape = encoder_hidden_states.shape[:-1]
|
| 634 |
+
query_hidden_shape = (*query_input_shape, self.num_attention_heads, self.head_dim)
|
| 635 |
+
kv_hidden_shape = (*kv_input_shape, self.num_attention_heads, self.head_dim)
|
| 636 |
+
|
| 637 |
+
# Apply content and position projections
|
| 638 |
+
query_input = self.q_content_proj(hidden_states)
|
| 639 |
+
key_input = self.k_content_proj(encoder_hidden_states)
|
| 640 |
+
value_states = self.v_proj(encoder_hidden_states)
|
| 641 |
+
key_pos = self.k_pos_proj(encoder_position_embeddings)
|
| 642 |
+
|
| 643 |
+
# Combine content and position embeddings
|
| 644 |
+
if query_position_embeddings is not None:
|
| 645 |
+
query_input = query_input + self.q_pos_proj(query_position_embeddings)
|
| 646 |
+
key_input = key_input + key_pos
|
| 647 |
+
|
| 648 |
+
# Reshape and concatenate position embeddings (doubling head_dim)
|
| 649 |
+
query_input = query_input.view(query_hidden_shape)
|
| 650 |
+
key_input = key_input.view(kv_hidden_shape)
|
| 651 |
+
query_sine_embed = self.q_pos_sine_proj(query_sine_embed).view(query_hidden_shape)
|
| 652 |
+
key_pos = key_pos.view(kv_hidden_shape)
|
| 653 |
+
|
| 654 |
+
query_states = torch.cat([query_input, query_sine_embed], dim=-1).view(*query_input_shape, -1)
|
| 655 |
+
key_states = torch.cat([key_input, key_pos], dim=-1).view(*kv_input_shape, -1)
|
| 656 |
+
|
| 657 |
+
# Reshape for attention computation
|
| 658 |
+
expanded_head_dim = query_states.shape[-1] // self.num_attention_heads
|
| 659 |
+
query_states = query_states.view(*query_input_shape, self.num_attention_heads, expanded_head_dim).transpose(
|
| 660 |
+
1, 2
|
| 661 |
+
)
|
| 662 |
+
key_states = key_states.view(*kv_input_shape, self.num_attention_heads, expanded_head_dim).transpose(1, 2)
|
| 663 |
+
value_states = value_states.view(kv_hidden_shape).transpose(1, 2)
|
| 664 |
+
|
| 665 |
+
attention_interface: Callable = ALL_ATTENTION_FUNCTIONS.get_interface(
|
| 666 |
+
self.config._attn_implementation, eager_attention_forward
|
| 667 |
+
)
|
| 668 |
+
|
| 669 |
+
attn_output, attn_weights = attention_interface(
|
| 670 |
+
self,
|
| 671 |
+
query_states,
|
| 672 |
+
key_states,
|
| 673 |
+
value_states,
|
| 674 |
+
attention_mask,
|
| 675 |
+
dropout=0.0 if not self.training else self.attention_dropout,
|
| 676 |
+
scaling=self.scaling,
|
| 677 |
+
**kwargs,
|
| 678 |
+
)
|
| 679 |
+
|
| 680 |
+
attn_output = attn_output.reshape(*query_input_shape, -1).contiguous()
|
| 681 |
+
attn_output = self.o_proj(attn_output)
|
| 682 |
+
return attn_output, attn_weights
|
| 683 |
+
|
| 684 |
+
|
| 685 |
+
class ConditionalDetrMLP(nn.Module):
|
| 686 |
+
def __init__(self, config: ConditionalDetrConfig, hidden_size: int, intermediate_size: int):
|
| 687 |
+
super().__init__()
|
| 688 |
+
self.fc1 = nn.Linear(hidden_size, intermediate_size)
|
| 689 |
+
self.fc2 = nn.Linear(intermediate_size, hidden_size)
|
| 690 |
+
self.activation_fn = ACT2FN[config.activation_function]
|
| 691 |
+
self.activation_dropout = config.activation_dropout
|
| 692 |
+
self.dropout = config.dropout
|
| 693 |
+
|
| 694 |
+
def forward(self, hidden_states: torch.Tensor) -> torch.Tensor:
|
| 695 |
+
hidden_states = self.activation_fn(self.fc1(hidden_states))
|
| 696 |
+
hidden_states = nn.functional.dropout(hidden_states, p=self.activation_dropout, training=self.training)
|
| 697 |
+
hidden_states = self.fc2(hidden_states)
|
| 698 |
+
hidden_states = nn.functional.dropout(hidden_states, p=self.dropout, training=self.training)
|
| 699 |
+
return hidden_states
|
| 700 |
+
|
| 701 |
+
|
| 702 |
+
class ConditionalDetrEncoderLayer(GradientCheckpointingLayer):
|
| 703 |
+
def __init__(self, config: ConditionalDetrConfig):
|
| 704 |
+
super().__init__()
|
| 705 |
+
self.hidden_size = config.d_model
|
| 706 |
+
self.self_attn = ConditionalDetrSelfAttention(
|
| 707 |
+
config=config,
|
| 708 |
+
hidden_size=self.hidden_size,
|
| 709 |
+
num_attention_heads=config.encoder_attention_heads,
|
| 710 |
+
dropout=config.attention_dropout,
|
| 711 |
+
)
|
| 712 |
+
self.self_attn_layer_norm = nn.LayerNorm(self.hidden_size)
|
| 713 |
+
self.dropout = config.dropout
|
| 714 |
+
self.mlp = ConditionalDetrMLP(config, self.hidden_size, config.encoder_ffn_dim)
|
| 715 |
+
self.final_layer_norm = nn.LayerNorm(self.hidden_size)
|
| 716 |
+
|
| 717 |
+
def forward(
|
| 718 |
+
self,
|
| 719 |
+
hidden_states: torch.Tensor,
|
| 720 |
+
attention_mask: torch.Tensor,
|
| 721 |
+
spatial_position_embeddings: torch.Tensor | None = None,
|
| 722 |
+
**kwargs: Unpack[TransformersKwargs],
|
| 723 |
+
) -> torch.Tensor:
|
| 724 |
+
"""
|
| 725 |
+
Args:
|
| 726 |
+
hidden_states (`torch.FloatTensor`): input to the layer of shape `(batch, seq_len, hidden_size)`
|
| 727 |
+
attention_mask (`torch.FloatTensor`): attention mask of size
|
| 728 |
+
`(batch, 1, target_len, source_len)` where padding elements are indicated by very large negative
|
| 729 |
+
values.
|
| 730 |
+
spatial_position_embeddings (`torch.FloatTensor`, *optional*):
|
| 731 |
+
Spatial position embeddings (2D positional encodings of image locations), to be added to both
|
| 732 |
+
the queries and keys in self-attention (but not to values).
|
| 733 |
+
"""
|
| 734 |
+
residual = hidden_states
|
| 735 |
+
hidden_states, _ = self.self_attn(
|
| 736 |
+
hidden_states=hidden_states,
|
| 737 |
+
attention_mask=attention_mask,
|
| 738 |
+
position_embeddings=spatial_position_embeddings,
|
| 739 |
+
**kwargs,
|
| 740 |
+
)
|
| 741 |
+
|
| 742 |
+
hidden_states = nn.functional.dropout(hidden_states, p=self.dropout, training=self.training)
|
| 743 |
+
hidden_states = residual + hidden_states
|
| 744 |
+
hidden_states = self.self_attn_layer_norm(hidden_states)
|
| 745 |
+
|
| 746 |
+
residual = hidden_states
|
| 747 |
+
hidden_states = self.mlp(hidden_states)
|
| 748 |
+
hidden_states = residual + hidden_states
|
| 749 |
+
hidden_states = self.final_layer_norm(hidden_states)
|
| 750 |
+
|
| 751 |
+
if self.training:
|
| 752 |
+
if not torch.isfinite(hidden_states).all():
|
| 753 |
+
clamp_value = torch.finfo(hidden_states.dtype).max - 1000
|
| 754 |
+
hidden_states = torch.clamp(hidden_states, min=-clamp_value, max=clamp_value)
|
| 755 |
+
|
| 756 |
+
return hidden_states
|
| 757 |
+
|
| 758 |
+
|
| 759 |
+
class ConditionalDetrDecoderLayer(GradientCheckpointingLayer):
|
| 760 |
+
def __init__(self, config: ConditionalDetrConfig):
|
| 761 |
+
super().__init__()
|
| 762 |
+
self.hidden_size = config.d_model
|
| 763 |
+
self.self_attn = ConditionalDetrDecoderSelfAttention(
|
| 764 |
+
config=config,
|
| 765 |
+
hidden_size=self.hidden_size,
|
| 766 |
+
num_attention_heads=config.decoder_attention_heads,
|
| 767 |
+
dropout=config.attention_dropout,
|
| 768 |
+
)
|
| 769 |
+
self.dropout = config.dropout
|
| 770 |
+
|
| 771 |
+
self.self_attn_layer_norm = nn.LayerNorm(self.hidden_size)
|
| 772 |
+
self.encoder_attn = ConditionalDetrDecoderCrossAttention(
|
| 773 |
+
config=config,
|
| 774 |
+
hidden_size=self.hidden_size,
|
| 775 |
+
num_attention_heads=config.decoder_attention_heads,
|
| 776 |
+
dropout=config.attention_dropout,
|
| 777 |
+
)
|
| 778 |
+
self.encoder_attn_layer_norm = nn.LayerNorm(self.hidden_size)
|
| 779 |
+
self.mlp = ConditionalDetrMLP(config, self.hidden_size, config.decoder_ffn_dim)
|
| 780 |
+
self.final_layer_norm = nn.LayerNorm(self.hidden_size)
|
| 781 |
+
|
| 782 |
+
def forward(
|
| 783 |
+
self,
|
| 784 |
+
hidden_states: torch.Tensor,
|
| 785 |
+
attention_mask: torch.Tensor | None = None,
|
| 786 |
+
spatial_position_embeddings: torch.Tensor | None = None,
|
| 787 |
+
query_position_embeddings: torch.Tensor | None = None,
|
| 788 |
+
query_sine_embed: torch.Tensor | None = None,
|
| 789 |
+
encoder_hidden_states: torch.Tensor | None = None,
|
| 790 |
+
encoder_attention_mask: torch.Tensor | None = None,
|
| 791 |
+
is_first: bool | None = False,
|
| 792 |
+
**kwargs: Unpack[TransformersKwargs],
|
| 793 |
+
) -> torch.Tensor:
|
| 794 |
+
"""
|
| 795 |
+
Args:
|
| 796 |
+
hidden_states (`torch.FloatTensor`): input to the layer of shape `(seq_len, batch, embed_dim)`
|
| 797 |
+
attention_mask (`torch.FloatTensor`): attention mask of size
|
| 798 |
+
`(batch, 1, target_len, source_len)` where padding elements are indicated by very large negative
|
| 799 |
+
values.
|
| 800 |
+
spatial_position_embeddings (`torch.FloatTensor` of shape `(batch_size, sequence_length, hidden_size)`):
|
| 801 |
+
Spatial position embeddings (2D positional encodings) that are added to the queries and keys in each self-attention layer.
|
| 802 |
+
query_position_embeddings (`torch.FloatTensor`, *optional*):
|
| 803 |
+
object_queries that are added to the queries and keys
|
| 804 |
+
in the self-attention layer.
|
| 805 |
+
encoder_hidden_states (`torch.FloatTensor`):
|
| 806 |
+
cross attention input to the layer of shape `(seq_len, batch, embed_dim)`
|
| 807 |
+
encoder_attention_mask (`torch.FloatTensor`): encoder attention mask of size
|
| 808 |
+
`(batch, 1, target_len, source_len)` where padding elements are indicated by very large negative
|
| 809 |
+
values.
|
| 810 |
+
output_attentions (`bool`, *optional*):
|
| 811 |
+
Whether or not to return the attentions tensors of all attention layers. See `attentions` under
|
| 812 |
+
returned tensors for more detail.
|
| 813 |
+
"""
|
| 814 |
+
residual = hidden_states
|
| 815 |
+
|
| 816 |
+
hidden_states, _ = self.self_attn(
|
| 817 |
+
hidden_states=hidden_states,
|
| 818 |
+
query_position_embeddings=query_position_embeddings,
|
| 819 |
+
attention_mask=attention_mask,
|
| 820 |
+
**kwargs,
|
| 821 |
+
)
|
| 822 |
+
|
| 823 |
+
hidden_states = nn.functional.dropout(hidden_states, p=self.dropout, training=self.training)
|
| 824 |
+
hidden_states = residual + hidden_states
|
| 825 |
+
hidden_states = self.self_attn_layer_norm(hidden_states)
|
| 826 |
+
|
| 827 |
+
if encoder_hidden_states is not None:
|
| 828 |
+
residual = hidden_states
|
| 829 |
+
|
| 830 |
+
hidden_states, _ = self.encoder_attn(
|
| 831 |
+
hidden_states=hidden_states,
|
| 832 |
+
encoder_hidden_states=encoder_hidden_states,
|
| 833 |
+
attention_mask=encoder_attention_mask,
|
| 834 |
+
query_sine_embed=query_sine_embed,
|
| 835 |
+
encoder_position_embeddings=spatial_position_embeddings,
|
| 836 |
+
# Only pass query_position_embeddings for the first layer
|
| 837 |
+
query_position_embeddings=query_position_embeddings if is_first else None,
|
| 838 |
+
**kwargs,
|
| 839 |
+
)
|
| 840 |
+
|
| 841 |
+
hidden_states = nn.functional.dropout(hidden_states, p=self.dropout, training=self.training)
|
| 842 |
+
hidden_states = residual + hidden_states
|
| 843 |
+
hidden_states = self.encoder_attn_layer_norm(hidden_states)
|
| 844 |
+
|
| 845 |
+
# Fully Connected
|
| 846 |
+
residual = hidden_states
|
| 847 |
+
hidden_states = self.mlp(hidden_states)
|
| 848 |
+
hidden_states = residual + hidden_states
|
| 849 |
+
hidden_states = self.final_layer_norm(hidden_states)
|
| 850 |
+
|
| 851 |
+
return hidden_states
|
| 852 |
+
|
| 853 |
+
|
| 854 |
+
class ConditionalDetrMLPPredictionHead(nn.Module):
|
| 855 |
+
"""
|
| 856 |
+
Very simple multi-layer perceptron (MLP, also called FFN), used to predict the normalized center coordinates,
|
| 857 |
+
height and width of a bounding box w.r.t. an image.
|
| 858 |
+
|
| 859 |
+
"""
|
| 860 |
+
|
| 861 |
+
def __init__(self, input_dim, hidden_dim, output_dim, num_layers):
|
| 862 |
+
super().__init__()
|
| 863 |
+
self.num_layers = num_layers
|
| 864 |
+
h = [hidden_dim] * (num_layers - 1)
|
| 865 |
+
self.layers = nn.ModuleList(nn.Linear(n, k) for n, k in zip([input_dim] + h, h + [output_dim]))
|
| 866 |
+
|
| 867 |
+
def forward(self, x):
|
| 868 |
+
for i, layer in enumerate(self.layers):
|
| 869 |
+
x = nn.functional.relu(layer(x)) if i < self.num_layers - 1 else layer(x)
|
| 870 |
+
return x
|
| 871 |
+
|
| 872 |
+
|
| 873 |
+
class ConditionalDetrConvBlock(nn.Module):
|
| 874 |
+
"""Basic conv block: Conv3x3 -> GroupNorm -> Activation."""
|
| 875 |
+
|
| 876 |
+
def __init__(self, in_channels: int, out_channels: int, activation: str = "relu"):
|
| 877 |
+
super().__init__()
|
| 878 |
+
self.conv = nn.Conv2d(in_channels, out_channels, kernel_size=3, padding=1)
|
| 879 |
+
self.norm = nn.GroupNorm(min(8, out_channels), out_channels)
|
| 880 |
+
self.activation = ACT2FN[activation]
|
| 881 |
+
|
| 882 |
+
def forward(self, x: torch.Tensor) -> torch.Tensor:
|
| 883 |
+
return self.activation(self.norm(self.conv(x)))
|
| 884 |
+
|
| 885 |
+
|
| 886 |
+
class ConditionalDetrFPNFusionStage(nn.Module):
|
| 887 |
+
"""Single FPN fusion stage combining low-resolution features with high-resolution FPN features."""
|
| 888 |
+
|
| 889 |
+
def __init__(self, fpn_channels: int, current_channels: int, output_channels: int, activation: str = "relu"):
|
| 890 |
+
super().__init__()
|
| 891 |
+
self.fpn_adapter = nn.Conv2d(fpn_channels, current_channels, kernel_size=1)
|
| 892 |
+
self.refine = ConditionalDetrConvBlock(current_channels, output_channels, activation)
|
| 893 |
+
|
| 894 |
+
def forward(self, features: torch.Tensor, fpn_features: torch.Tensor) -> torch.Tensor:
|
| 895 |
+
"""
|
| 896 |
+
Args:
|
| 897 |
+
features: Current features to upsample, shape (B*Q, current_channels, H_in, W_in)
|
| 898 |
+
fpn_features: FPN features at target resolution, shape (B*Q, fpn_channels, H_out, W_out)
|
| 899 |
+
|
| 900 |
+
Returns:
|
| 901 |
+
Fused and refined features, shape (B*Q, output_channels, H_out, W_out)
|
| 902 |
+
"""
|
| 903 |
+
fpn_features = self.fpn_adapter(fpn_features)
|
| 904 |
+
features = nn.functional.interpolate(features, size=fpn_features.shape[-2:], mode="nearest")
|
| 905 |
+
return self.refine(fpn_features + features)
|
| 906 |
+
|
| 907 |
+
|
| 908 |
+
class ConditionalDetrMaskHeadSmallConv(nn.Module):
|
| 909 |
+
"""
|
| 910 |
+
Segmentation mask head that generates per-query masks using FPN-based progressive upsampling.
|
| 911 |
+
|
| 912 |
+
Combines attention maps (spatial localization) with encoder features (semantics) and progressively
|
| 913 |
+
upsamples through multiple scales, fusing with FPN features for high-resolution detail.
|
| 914 |
+
"""
|
| 915 |
+
|
| 916 |
+
def __init__(
|
| 917 |
+
self,
|
| 918 |
+
input_channels: int,
|
| 919 |
+
fpn_channels: list[int],
|
| 920 |
+
hidden_size: int,
|
| 921 |
+
activation_function: str = "relu",
|
| 922 |
+
):
|
| 923 |
+
super().__init__()
|
| 924 |
+
if input_channels % 8 != 0:
|
| 925 |
+
raise ValueError(f"input_channels must be divisible by 8, got {input_channels}")
|
| 926 |
+
|
| 927 |
+
self.conv1 = ConditionalDetrConvBlock(input_channels, input_channels, activation_function)
|
| 928 |
+
self.conv2 = ConditionalDetrConvBlock(input_channels, hidden_size // 2, activation_function)
|
| 929 |
+
|
| 930 |
+
# Progressive channel reduction: /2 -> /4 -> /8 -> /16
|
| 931 |
+
self.fpn_stages = nn.ModuleList(
|
| 932 |
+
[
|
| 933 |
+
ConditionalDetrFPNFusionStage(
|
| 934 |
+
fpn_channels[0], hidden_size // 2, hidden_size // 4, activation_function
|
| 935 |
+
),
|
| 936 |
+
ConditionalDetrFPNFusionStage(
|
| 937 |
+
fpn_channels[1], hidden_size // 4, hidden_size // 8, activation_function
|
| 938 |
+
),
|
| 939 |
+
ConditionalDetrFPNFusionStage(
|
| 940 |
+
fpn_channels[2], hidden_size // 8, hidden_size // 16, activation_function
|
| 941 |
+
),
|
| 942 |
+
]
|
| 943 |
+
)
|
| 944 |
+
|
| 945 |
+
self.output_conv = nn.Conv2d(hidden_size // 16, 1, kernel_size=3, padding=1)
|
| 946 |
+
|
| 947 |
+
def forward(
|
| 948 |
+
self,
|
| 949 |
+
features: torch.Tensor,
|
| 950 |
+
attention_masks: torch.Tensor,
|
| 951 |
+
fpn_features: list[torch.Tensor],
|
| 952 |
+
) -> torch.Tensor:
|
| 953 |
+
"""
|
| 954 |
+
Args:
|
| 955 |
+
features: Encoder output features, shape (batch_size, hidden_size, H, W)
|
| 956 |
+
attention_masks: Cross-attention maps from decoder, shape (batch_size, num_queries, num_heads, H, W)
|
| 957 |
+
fpn_features: List of 3 FPN features from low to high resolution, each (batch_size, C, H, W)
|
| 958 |
+
|
| 959 |
+
Returns:
|
| 960 |
+
Predicted masks, shape (batch_size * num_queries, 1, output_H, output_W)
|
| 961 |
+
"""
|
| 962 |
+
num_queries = attention_masks.shape[1]
|
| 963 |
+
|
| 964 |
+
# Expand to (batch_size * num_queries) dimension
|
| 965 |
+
features = features.unsqueeze(1).expand(-1, num_queries, -1, -1, -1).flatten(0, 1)
|
| 966 |
+
attention_masks = attention_masks.flatten(0, 1)
|
| 967 |
+
fpn_features = [
|
| 968 |
+
fpn_feat.unsqueeze(1).expand(-1, num_queries, -1, -1, -1).flatten(0, 1) for fpn_feat in fpn_features
|
| 969 |
+
]
|
| 970 |
+
|
| 971 |
+
hidden_states = torch.cat([features, attention_masks], dim=1)
|
| 972 |
+
hidden_states = self.conv1(hidden_states)
|
| 973 |
+
hidden_states = self.conv2(hidden_states)
|
| 974 |
+
|
| 975 |
+
for fpn_stage, fpn_feat in zip(self.fpn_stages, fpn_features):
|
| 976 |
+
hidden_states = fpn_stage(hidden_states, fpn_feat)
|
| 977 |
+
|
| 978 |
+
return self.output_conv(hidden_states)
|
| 979 |
+
|
| 980 |
+
|
| 981 |
+
class ConditionalDetrMHAttentionMap(nn.Module):
|
| 982 |
+
"""This is a 2D attention module, which only returns the attention softmax (no multiplication by value)"""
|
| 983 |
+
|
| 984 |
+
def __init__(
|
| 985 |
+
self,
|
| 986 |
+
hidden_size: int,
|
| 987 |
+
num_attention_heads: int,
|
| 988 |
+
dropout: float = 0.0,
|
| 989 |
+
bias: bool = True,
|
| 990 |
+
):
|
| 991 |
+
super().__init__()
|
| 992 |
+
self.head_dim = hidden_size // num_attention_heads
|
| 993 |
+
self.scaling = self.head_dim**-0.5
|
| 994 |
+
self.attention_dropout = dropout
|
| 995 |
+
|
| 996 |
+
self.q_proj = nn.Linear(hidden_size, hidden_size, bias=bias)
|
| 997 |
+
self.k_proj = nn.Linear(hidden_size, hidden_size, bias=bias)
|
| 998 |
+
|
| 999 |
+
def forward(
|
| 1000 |
+
self, query_states: torch.Tensor, key_states: torch.Tensor, attention_mask: torch.Tensor | None = None
|
| 1001 |
+
):
|
| 1002 |
+
query_hidden_shape = (*query_states.shape[:-1], -1, self.head_dim)
|
| 1003 |
+
key_hidden_shape = (key_states.shape[0], -1, self.head_dim, *key_states.shape[-2:])
|
| 1004 |
+
|
| 1005 |
+
query_states = self.q_proj(query_states).view(query_hidden_shape)
|
| 1006 |
+
key_states = nn.functional.conv2d(
|
| 1007 |
+
key_states, self.k_proj.weight.unsqueeze(-1).unsqueeze(-1), self.k_proj.bias
|
| 1008 |
+
).view(key_hidden_shape)
|
| 1009 |
+
|
| 1010 |
+
batch_size, num_queries, num_heads, head_dim = query_states.shape
|
| 1011 |
+
_, _, _, height, width = key_states.shape
|
| 1012 |
+
query_shape = (batch_size * num_heads, num_queries, head_dim)
|
| 1013 |
+
key_shape = (batch_size * num_heads, height * width, head_dim)
|
| 1014 |
+
attn_weights_shape = (batch_size, num_heads, num_queries, height, width)
|
| 1015 |
+
|
| 1016 |
+
query = query_states.transpose(1, 2).contiguous().view(query_shape)
|
| 1017 |
+
key = key_states.permute(0, 1, 3, 4, 2).contiguous().view(key_shape)
|
| 1018 |
+
|
| 1019 |
+
attn_weights = (
|
| 1020 |
+
(torch.matmul(query * self.scaling, key.transpose(1, 2))).view(attn_weights_shape).transpose(1, 2)
|
| 1021 |
+
)
|
| 1022 |
+
|
| 1023 |
+
if attention_mask is not None:
|
| 1024 |
+
attn_weights = attn_weights + attention_mask
|
| 1025 |
+
|
| 1026 |
+
attn_weights = nn.functional.softmax(attn_weights.flatten(2), dim=-1).view(attn_weights.size())
|
| 1027 |
+
attn_weights = nn.functional.dropout(attn_weights, p=self.attention_dropout, training=self.training)
|
| 1028 |
+
|
| 1029 |
+
return attn_weights
|
| 1030 |
+
|
| 1031 |
+
|
| 1032 |
+
@auto_docstring
|
| 1033 |
+
class ConditionalDetrPreTrainedModel(PreTrainedModel):
|
| 1034 |
+
config: ConditionalDetrConfig
|
| 1035 |
+
base_model_prefix = "model"
|
| 1036 |
+
main_input_name = "pixel_values"
|
| 1037 |
+
input_modalities = ("image",)
|
| 1038 |
+
_no_split_modules = [r"ConditionalDetrConvEncoder", r"ConditionalDetrEncoderLayer", r"ConditionalDetrDecoderLayer"]
|
| 1039 |
+
supports_gradient_checkpointing = True
|
| 1040 |
+
_supports_sdpa = True
|
| 1041 |
+
_supports_flash_attn = True
|
| 1042 |
+
_supports_attention_backend = True
|
| 1043 |
+
_supports_flex_attn = True # Uses create_bidirectional_masks for attention masking
|
| 1044 |
+
_keys_to_ignore_on_load_unexpected = [
|
| 1045 |
+
r"detr\.model\.backbone\.model\.layer\d+\.0\.downsample\.1\.num_batches_tracked"
|
| 1046 |
+
]
|
| 1047 |
+
|
| 1048 |
+
@torch.no_grad()
|
| 1049 |
+
def _init_weights(self, module):
|
| 1050 |
+
std = self.config.init_std
|
| 1051 |
+
xavier_std = self.config.init_xavier_std
|
| 1052 |
+
|
| 1053 |
+
if isinstance(module, ConditionalDetrMaskHeadSmallConv):
|
| 1054 |
+
# ConditionalDetrMaskHeadSmallConv uses kaiming initialization for all its Conv2d layers
|
| 1055 |
+
for m in module.modules():
|
| 1056 |
+
if isinstance(m, nn.Conv2d):
|
| 1057 |
+
init.kaiming_uniform_(m.weight, a=1)
|
| 1058 |
+
if m.bias is not None:
|
| 1059 |
+
init.constant_(m.bias, 0)
|
| 1060 |
+
elif isinstance(module, ConditionalDetrMHAttentionMap):
|
| 1061 |
+
init.zeros_(module.k_proj.bias)
|
| 1062 |
+
init.zeros_(module.q_proj.bias)
|
| 1063 |
+
init.xavier_uniform_(module.k_proj.weight, gain=xavier_std)
|
| 1064 |
+
init.xavier_uniform_(module.q_proj.weight, gain=xavier_std)
|
| 1065 |
+
elif isinstance(module, ConditionalDetrLearnedPositionEmbedding):
|
| 1066 |
+
init.uniform_(module.row_embeddings.weight)
|
| 1067 |
+
init.uniform_(module.column_embeddings.weight)
|
| 1068 |
+
elif isinstance(module, (nn.Linear, nn.Conv2d)):
|
| 1069 |
+
init.normal_(module.weight, mean=0.0, std=std)
|
| 1070 |
+
if module.bias is not None:
|
| 1071 |
+
init.zeros_(module.bias)
|
| 1072 |
+
elif isinstance(module, nn.Embedding):
|
| 1073 |
+
init.normal_(module.weight, mean=0.0, std=std)
|
| 1074 |
+
# Here we need the check explicitly, as we slice the weight in the `zeros_` call, so it looses the flag
|
| 1075 |
+
if module.padding_idx is not None and not getattr(module.weight, "_is_hf_initialized", False):
|
| 1076 |
+
init.zeros_(module.weight[module.padding_idx])
|
| 1077 |
+
elif isinstance(module, (nn.LayerNorm, nn.GroupNorm)):
|
| 1078 |
+
init.ones_(module.weight)
|
| 1079 |
+
init.zeros_(module.bias)
|
| 1080 |
+
|
| 1081 |
+
|
| 1082 |
+
class ConditionalDetrEncoder(ConditionalDetrPreTrainedModel):
|
| 1083 |
+
"""
|
| 1084 |
+
Transformer encoder that processes a flattened feature map from a vision backbone, composed of a stack of
|
| 1085 |
+
[`ConditionalDetrEncoderLayer`] modules.
|
| 1086 |
+
|
| 1087 |
+
Args:
|
| 1088 |
+
config (`ConditionalDetrConfig`): Model configuration object.
|
| 1089 |
+
"""
|
| 1090 |
+
|
| 1091 |
+
_can_record_outputs = {"hidden_states": ConditionalDetrEncoderLayer, "attentions": ConditionalDetrSelfAttention}
|
| 1092 |
+
|
| 1093 |
+
def __init__(self, config: ConditionalDetrConfig):
|
| 1094 |
+
super().__init__(config)
|
| 1095 |
+
|
| 1096 |
+
self.dropout = config.dropout
|
| 1097 |
+
self.layers = nn.ModuleList([ConditionalDetrEncoderLayer(config) for _ in range(config.encoder_layers)])
|
| 1098 |
+
|
| 1099 |
+
# Initialize weights and apply final processing
|
| 1100 |
+
self.post_init()
|
| 1101 |
+
|
| 1102 |
+
@merge_with_config_defaults
|
| 1103 |
+
@capture_outputs
|
| 1104 |
+
def forward(
|
| 1105 |
+
self,
|
| 1106 |
+
inputs_embeds=None,
|
| 1107 |
+
attention_mask=None,
|
| 1108 |
+
spatial_position_embeddings=None,
|
| 1109 |
+
**kwargs: Unpack[TransformersKwargs],
|
| 1110 |
+
) -> BaseModelOutput:
|
| 1111 |
+
r"""
|
| 1112 |
+
Args:
|
| 1113 |
+
inputs_embeds (`torch.FloatTensor` of shape `(batch_size, sequence_length, hidden_size)`):
|
| 1114 |
+
Flattened feature map (output of the backbone + projection layer) that is passed to the encoder.
|
| 1115 |
+
attention_mask (`torch.Tensor` of shape `(batch_size, sequence_length)`, *optional*):
|
| 1116 |
+
Mask to avoid performing attention on padding pixel features. Mask values selected in `[0, 1]`:
|
| 1117 |
+
|
| 1118 |
+
- 1 for pixel features that are real (i.e. **not masked**),
|
| 1119 |
+
- 0 for pixel features that are padding (i.e. **masked**).
|
| 1120 |
+
|
| 1121 |
+
[What are attention masks?](../glossary#attention-mask)
|
| 1122 |
+
spatial_position_embeddings (`torch.FloatTensor` of shape `(batch_size, sequence_length, hidden_size)`):
|
| 1123 |
+
Spatial position embeddings (2D positional encodings) that are added to the queries and keys in each self-attention layer.
|
| 1124 |
+
"""
|
| 1125 |
+
hidden_states = inputs_embeds
|
| 1126 |
+
hidden_states = nn.functional.dropout(hidden_states, p=self.dropout, training=self.training)
|
| 1127 |
+
|
| 1128 |
+
attention_mask = create_bidirectional_mask(
|
| 1129 |
+
config=self.config,
|
| 1130 |
+
inputs_embeds=inputs_embeds,
|
| 1131 |
+
attention_mask=attention_mask,
|
| 1132 |
+
)
|
| 1133 |
+
|
| 1134 |
+
for encoder_layer in self.layers:
|
| 1135 |
+
# we add spatial_position_embeddings as extra input to the encoder_layer
|
| 1136 |
+
hidden_states = encoder_layer(
|
| 1137 |
+
hidden_states, attention_mask, spatial_position_embeddings=spatial_position_embeddings, **kwargs
|
| 1138 |
+
)
|
| 1139 |
+
|
| 1140 |
+
return BaseModelOutput(last_hidden_state=hidden_states)
|
| 1141 |
+
|
| 1142 |
+
|
| 1143 |
+
# function to generate sine positional embedding for 2d coordinates
|
| 1144 |
+
def gen_sine_position_embeddings(pos_tensor, d_model):
|
| 1145 |
+
scale = 2 * math.pi
|
| 1146 |
+
dim = d_model // 2
|
| 1147 |
+
dim_t = torch.arange(dim, dtype=torch.float32, device=pos_tensor.device)
|
| 1148 |
+
dim_t = 10000 ** (2 * torch.div(dim_t, 2, rounding_mode="floor") / dim)
|
| 1149 |
+
x_embed = pos_tensor[:, :, 0] * scale
|
| 1150 |
+
y_embed = pos_tensor[:, :, 1] * scale
|
| 1151 |
+
pos_x = x_embed[:, :, None] / dim_t
|
| 1152 |
+
pos_y = y_embed[:, :, None] / dim_t
|
| 1153 |
+
pos_x = torch.stack((pos_x[:, :, 0::2].sin(), pos_x[:, :, 1::2].cos()), dim=3).flatten(2)
|
| 1154 |
+
pos_y = torch.stack((pos_y[:, :, 0::2].sin(), pos_y[:, :, 1::2].cos()), dim=3).flatten(2)
|
| 1155 |
+
pos = torch.cat((pos_y, pos_x), dim=2)
|
| 1156 |
+
return pos.to(pos_tensor.dtype)
|
| 1157 |
+
|
| 1158 |
+
|
| 1159 |
+
class ConditionalDetrDecoder(ConditionalDetrPreTrainedModel):
|
| 1160 |
+
"""
|
| 1161 |
+
Transformer decoder consisting of *config.decoder_layers* layers. Each layer is a [`ConditionalDetrDecoderLayer`].
|
| 1162 |
+
|
| 1163 |
+
The decoder updates the query embeddings through multiple self-attention and cross-attention layers.
|
| 1164 |
+
|
| 1165 |
+
Some small tweaks for Conditional DETR:
|
| 1166 |
+
|
| 1167 |
+
- object_queries and query_position_embeddings are added to the forward pass.
|
| 1168 |
+
- if self.config.auxiliary_loss is set to True, also returns a stack of activations from all decoding layers.
|
| 1169 |
+
|
| 1170 |
+
Args:
|
| 1171 |
+
config: ConditionalDetrConfig
|
| 1172 |
+
"""
|
| 1173 |
+
|
| 1174 |
+
_can_record_outputs = {
|
| 1175 |
+
"hidden_states": ConditionalDetrDecoderLayer,
|
| 1176 |
+
"attentions": OutputRecorder(ConditionalDetrDecoderSelfAttention, layer_name="self_attn", index=1),
|
| 1177 |
+
"cross_attentions": OutputRecorder(ConditionalDetrDecoderCrossAttention, layer_name="encoder_attn", index=1),
|
| 1178 |
+
}
|
| 1179 |
+
|
| 1180 |
+
def __init__(self, config: ConditionalDetrConfig):
|
| 1181 |
+
super().__init__(config)
|
| 1182 |
+
self.hidden_size = config.d_model
|
| 1183 |
+
|
| 1184 |
+
self.dropout = config.dropout
|
| 1185 |
+
self.layerdrop = config.decoder_layerdrop
|
| 1186 |
+
|
| 1187 |
+
self.layers = nn.ModuleList([ConditionalDetrDecoderLayer(config) for _ in range(config.decoder_layers)])
|
| 1188 |
+
# in Conditional DETR, the decoder uses layernorm after the last decoder layer output
|
| 1189 |
+
self.layernorm = nn.LayerNorm(config.d_model)
|
| 1190 |
+
|
| 1191 |
+
# query_scale is the FFN applied on f to generate transformation T
|
| 1192 |
+
self.query_scale = ConditionalDetrMLPPredictionHead(self.hidden_size, self.hidden_size, self.hidden_size, 2)
|
| 1193 |
+
self.ref_point_head = ConditionalDetrMLPPredictionHead(self.hidden_size, self.hidden_size, 2, 2)
|
| 1194 |
+
for layer_id in range(config.decoder_layers - 1):
|
| 1195 |
+
# Set q_pos_proj to None for layers after the first (only first layer uses query position embeddings)
|
| 1196 |
+
self.layers[layer_id + 1].encoder_attn.q_pos_proj = None
|
| 1197 |
+
|
| 1198 |
+
# Initialize weights and apply final processing
|
| 1199 |
+
self.post_init()
|
| 1200 |
+
|
| 1201 |
+
@merge_with_config_defaults
|
| 1202 |
+
@capture_outputs
|
| 1203 |
+
def forward(
|
| 1204 |
+
self,
|
| 1205 |
+
inputs_embeds=None,
|
| 1206 |
+
attention_mask=None,
|
| 1207 |
+
encoder_hidden_states=None,
|
| 1208 |
+
encoder_attention_mask=None,
|
| 1209 |
+
spatial_position_embeddings=None,
|
| 1210 |
+
object_queries_position_embeddings=None,
|
| 1211 |
+
**kwargs: Unpack[TransformersKwargs],
|
| 1212 |
+
) -> ConditionalDetrDecoderOutput:
|
| 1213 |
+
r"""
|
| 1214 |
+
Args:
|
| 1215 |
+
inputs_embeds (`torch.FloatTensor` of shape `(batch_size, sequence_length, hidden_size)`):
|
| 1216 |
+
The query embeddings that are passed into the decoder.
|
| 1217 |
+
|
| 1218 |
+
attention_mask (`torch.Tensor` of shape `(batch_size, sequence_length)`, *optional*):
|
| 1219 |
+
Mask to avoid performing attention on certain queries. Mask values selected in `[0, 1]`:
|
| 1220 |
+
|
| 1221 |
+
- 1 for queries that are **not masked**,
|
| 1222 |
+
- 0 for queries that are **masked**.
|
| 1223 |
+
|
| 1224 |
+
[What are attention masks?](../glossary#attention-mask)
|
| 1225 |
+
encoder_hidden_states (`torch.FloatTensor` of shape `(batch_size, encoder_sequence_length, hidden_size)`, *optional*):
|
| 1226 |
+
Sequence of hidden-states at the output of the last layer of the encoder. Used in the cross-attention
|
| 1227 |
+
of the decoder.
|
| 1228 |
+
encoder_attention_mask (`torch.LongTensor` of shape `(batch_size, encoder_sequence_length)`, *optional*):
|
| 1229 |
+
Mask to avoid performing cross-attention on padding pixel_values of the encoder. Mask values selected
|
| 1230 |
+
in `[0, 1]`:
|
| 1231 |
+
|
| 1232 |
+
- 1 for pixels that are real (i.e. **not masked**),
|
| 1233 |
+
- 0 for pixels that are padding (i.e. **masked**).
|
| 1234 |
+
|
| 1235 |
+
spatial_position_embeddings (`torch.FloatTensor` of shape `(batch_size, sequence_length, hidden_size)`, *optional*):
|
| 1236 |
+
Spatial position embeddings that are added to the queries and keys in each cross-attention layer.
|
| 1237 |
+
object_queries_position_embeddings (`torch.FloatTensor` of shape `(batch_size, num_queries, hidden_size)`):
|
| 1238 |
+
, *optional*): Position embeddings that are added to the queries and keys in each self-attention layer.
|
| 1239 |
+
"""
|
| 1240 |
+
if inputs_embeds is not None:
|
| 1241 |
+
hidden_states = inputs_embeds
|
| 1242 |
+
|
| 1243 |
+
# expand encoder attention mask
|
| 1244 |
+
if encoder_hidden_states is not None and encoder_attention_mask is not None:
|
| 1245 |
+
# [batch_size, seq_len] -> [batch_size, 1, target_seq_len, source_seq_len]
|
| 1246 |
+
encoder_attention_mask = create_bidirectional_mask(
|
| 1247 |
+
self.config,
|
| 1248 |
+
inputs_embeds,
|
| 1249 |
+
encoder_attention_mask,
|
| 1250 |
+
)
|
| 1251 |
+
|
| 1252 |
+
# optional intermediate hidden states
|
| 1253 |
+
intermediate = () if self.config.auxiliary_loss else None
|
| 1254 |
+
|
| 1255 |
+
reference_points_before_sigmoid = self.ref_point_head(
|
| 1256 |
+
object_queries_position_embeddings
|
| 1257 |
+
) # [num_queries, batch_size, 2]
|
| 1258 |
+
reference_points = reference_points_before_sigmoid.sigmoid().transpose(0, 1)
|
| 1259 |
+
obj_center = reference_points[..., :2].transpose(0, 1)
|
| 1260 |
+
# get sine embedding for the query vector
|
| 1261 |
+
query_sine_embed_before_transformation = gen_sine_position_embeddings(obj_center, self.config.d_model)
|
| 1262 |
+
|
| 1263 |
+
for idx, decoder_layer in enumerate(self.layers):
|
| 1264 |
+
if self.training:
|
| 1265 |
+
dropout_probability = torch.rand([])
|
| 1266 |
+
if dropout_probability < self.layerdrop:
|
| 1267 |
+
continue
|
| 1268 |
+
if idx == 0:
|
| 1269 |
+
pos_transformation = 1
|
| 1270 |
+
else:
|
| 1271 |
+
pos_transformation = self.query_scale(hidden_states)
|
| 1272 |
+
# apply transformation
|
| 1273 |
+
query_sine_embed = query_sine_embed_before_transformation * pos_transformation
|
| 1274 |
+
|
| 1275 |
+
hidden_states = decoder_layer(
|
| 1276 |
+
hidden_states,
|
| 1277 |
+
None,
|
| 1278 |
+
spatial_position_embeddings,
|
| 1279 |
+
object_queries_position_embeddings,
|
| 1280 |
+
query_sine_embed,
|
| 1281 |
+
encoder_hidden_states, # as a positional argument for gradient checkpointing
|
| 1282 |
+
encoder_attention_mask=encoder_attention_mask,
|
| 1283 |
+
is_first=(idx == 0),
|
| 1284 |
+
**kwargs,
|
| 1285 |
+
)
|
| 1286 |
+
|
| 1287 |
+
if self.config.auxiliary_loss:
|
| 1288 |
+
hidden_states = self.layernorm(hidden_states)
|
| 1289 |
+
intermediate += (hidden_states,)
|
| 1290 |
+
|
| 1291 |
+
# finally, apply layernorm
|
| 1292 |
+
hidden_states = self.layernorm(hidden_states)
|
| 1293 |
+
|
| 1294 |
+
# stack intermediate decoder activations
|
| 1295 |
+
if self.config.auxiliary_loss:
|
| 1296 |
+
intermediate = torch.stack(intermediate)
|
| 1297 |
+
|
| 1298 |
+
return ConditionalDetrDecoderOutput(
|
| 1299 |
+
last_hidden_state=hidden_states,
|
| 1300 |
+
intermediate_hidden_states=intermediate,
|
| 1301 |
+
reference_points=reference_points,
|
| 1302 |
+
)
|
| 1303 |
+
|
| 1304 |
+
|
| 1305 |
+
@auto_docstring(
|
| 1306 |
+
custom_intro="""
|
| 1307 |
+
The bare CONDITIONAL_DETR Model (consisting of a backbone and encoder-decoder Transformer) outputting raw hidden-states without
|
| 1308 |
+
any specific head on top.
|
| 1309 |
+
"""
|
| 1310 |
+
)
|
| 1311 |
+
class ConditionalDetrModel(ConditionalDetrPreTrainedModel):
|
| 1312 |
+
def __init__(self, config: ConditionalDetrConfig):
|
| 1313 |
+
super().__init__(config)
|
| 1314 |
+
|
| 1315 |
+
self.backbone = ConditionalDetrConvEncoder(config)
|
| 1316 |
+
|
| 1317 |
+
if config.position_embedding_type == "sine":
|
| 1318 |
+
self.position_embedding = ConditionalDetrSinePositionEmbedding(config.d_model // 2, normalize=True)
|
| 1319 |
+
elif config.position_embedding_type == "learned":
|
| 1320 |
+
self.position_embedding = ConditionalDetrLearnedPositionEmbedding(config.d_model // 2)
|
| 1321 |
+
else:
|
| 1322 |
+
raise ValueError(f"Not supported {config.position_embedding_type}")
|
| 1323 |
+
self.query_position_embeddings = nn.Embedding(config.num_queries, config.d_model)
|
| 1324 |
+
self.input_projection = nn.Conv2d(self.backbone.intermediate_channel_sizes[-1], config.d_model, kernel_size=1)
|
| 1325 |
+
|
| 1326 |
+
self.encoder = ConditionalDetrEncoder(config)
|
| 1327 |
+
self.decoder = ConditionalDetrDecoder(config)
|
| 1328 |
+
|
| 1329 |
+
# Initialize weights and apply final processing
|
| 1330 |
+
self.post_init()
|
| 1331 |
+
|
| 1332 |
+
def freeze_backbone(self):
|
| 1333 |
+
for _, param in self.backbone.model.named_parameters():
|
| 1334 |
+
param.requires_grad_(False)
|
| 1335 |
+
|
| 1336 |
+
def unfreeze_backbone(self):
|
| 1337 |
+
for _, param in self.backbone.model.named_parameters():
|
| 1338 |
+
param.requires_grad_(True)
|
| 1339 |
+
|
| 1340 |
+
@auto_docstring
|
| 1341 |
+
@can_return_tuple
|
| 1342 |
+
def forward(
|
| 1343 |
+
self,
|
| 1344 |
+
pixel_values: torch.FloatTensor,
|
| 1345 |
+
pixel_mask: torch.LongTensor | None = None,
|
| 1346 |
+
decoder_attention_mask: torch.LongTensor | None = None,
|
| 1347 |
+
encoder_outputs: torch.FloatTensor | None = None,
|
| 1348 |
+
inputs_embeds: torch.FloatTensor | None = None,
|
| 1349 |
+
decoder_inputs_embeds: torch.FloatTensor | None = None,
|
| 1350 |
+
**kwargs: Unpack[TransformersKwargs],
|
| 1351 |
+
) -> ConditionalDetrModelOutput:
|
| 1352 |
+
r"""
|
| 1353 |
+
decoder_attention_mask (`torch.FloatTensor` of shape `(batch_size, num_queries)`, *optional*):
|
| 1354 |
+
Not used by default. Can be used to mask object queries.
|
| 1355 |
+
inputs_embeds (`torch.FloatTensor` of shape `(batch_size, sequence_length, hidden_size)`, *optional*):
|
| 1356 |
+
Optionally, instead of passing the flattened feature map (output of the backbone + projection layer), you
|
| 1357 |
+
can choose to directly pass a flattened representation of an image.
|
| 1358 |
+
decoder_inputs_embeds (`torch.FloatTensor` of shape `(batch_size, num_queries, hidden_size)`, *optional*):
|
| 1359 |
+
Optionally, instead of initializing the queries with a tensor of zeros, you can choose to directly pass an
|
| 1360 |
+
embedded representation.
|
| 1361 |
+
|
| 1362 |
+
Examples:
|
| 1363 |
+
|
| 1364 |
+
```python
|
| 1365 |
+
>>> from transformers import AutoImageProcessor, AutoModel
|
| 1366 |
+
>>> from PIL import Image
|
| 1367 |
+
>>> import requests
|
| 1368 |
+
|
| 1369 |
+
>>> url = "http://images.cocodataset.org/val2017/000000039769.jpg"
|
| 1370 |
+
>>> image = Image.open(requests.get(url, stream=True).raw)
|
| 1371 |
+
|
| 1372 |
+
>>> image_processor = AutoImageProcessor.from_pretrained("microsoft/conditional-detr-resnet-50")
|
| 1373 |
+
>>> model = AutoModel.from_pretrained("microsoft/conditional-detr-resnet-50")
|
| 1374 |
+
|
| 1375 |
+
>>> # prepare image for the model
|
| 1376 |
+
>>> inputs = image_processor(images=image, return_tensors="pt")
|
| 1377 |
+
|
| 1378 |
+
>>> # forward pass
|
| 1379 |
+
>>> outputs = model(**inputs)
|
| 1380 |
+
|
| 1381 |
+
>>> # the last hidden states are the final query embeddings of the Transformer decoder
|
| 1382 |
+
>>> # these are of shape (batch_size, num_queries, hidden_size)
|
| 1383 |
+
>>> last_hidden_states = outputs.last_hidden_state
|
| 1384 |
+
>>> list(last_hidden_states.shape)
|
| 1385 |
+
[1, 300, 256]
|
| 1386 |
+
```"""
|
| 1387 |
+
batch_size, num_channels, height, width = pixel_values.shape
|
| 1388 |
+
device = pixel_values.device
|
| 1389 |
+
|
| 1390 |
+
if pixel_mask is None:
|
| 1391 |
+
pixel_mask = torch.ones(((batch_size, height, width)), device=device)
|
| 1392 |
+
|
| 1393 |
+
# First, sent pixel_values + pixel_mask through Backbone to obtain the features
|
| 1394 |
+
# pixel_values should be of shape (batch_size, num_channels, height, width)
|
| 1395 |
+
# pixel_mask should be of shape (batch_size, height, width)
|
| 1396 |
+
features = self.backbone(pixel_values, pixel_mask)
|
| 1397 |
+
|
| 1398 |
+
# get final feature map and downsampled mask
|
| 1399 |
+
feature_map, mask = features[-1]
|
| 1400 |
+
|
| 1401 |
+
if mask is None:
|
| 1402 |
+
raise ValueError("Backbone does not return downsampled pixel mask")
|
| 1403 |
+
|
| 1404 |
+
# Second, apply 1x1 convolution to reduce the channel dimension to d_model (256 by default)
|
| 1405 |
+
projected_feature_map = self.input_projection(feature_map)
|
| 1406 |
+
|
| 1407 |
+
# Generate position embeddings
|
| 1408 |
+
spatial_position_embeddings = self.position_embedding(
|
| 1409 |
+
shape=feature_map.shape, device=device, dtype=pixel_values.dtype, mask=mask
|
| 1410 |
+
)
|
| 1411 |
+
|
| 1412 |
+
# Third, flatten the feature map of shape NxCxHxW to NxCxHW, and permute it to NxHWxC
|
| 1413 |
+
# In other words, turn their shape into (batch_size, sequence_length, hidden_size)
|
| 1414 |
+
flattened_features = projected_feature_map.flatten(2).permute(0, 2, 1)
|
| 1415 |
+
|
| 1416 |
+
flattened_mask = mask.flatten(1)
|
| 1417 |
+
|
| 1418 |
+
# Fourth, sent flattened_features + flattened_mask + spatial_position_embeddings through encoder
|
| 1419 |
+
# flattened_features is a Tensor of shape (batch_size, height*width, hidden_size)
|
| 1420 |
+
# flattened_mask is a Tensor of shape (batch_size, height*width)
|
| 1421 |
+
if encoder_outputs is None:
|
| 1422 |
+
encoder_outputs = self.encoder(
|
| 1423 |
+
inputs_embeds=flattened_features,
|
| 1424 |
+
attention_mask=flattened_mask,
|
| 1425 |
+
spatial_position_embeddings=spatial_position_embeddings,
|
| 1426 |
+
**kwargs,
|
| 1427 |
+
)
|
| 1428 |
+
# If the user passed a tuple for encoder_outputs, we wrap it in a BaseModelOutput
|
| 1429 |
+
elif not isinstance(encoder_outputs, BaseModelOutput):
|
| 1430 |
+
encoder_outputs = BaseModelOutput(
|
| 1431 |
+
last_hidden_state=encoder_outputs[0],
|
| 1432 |
+
hidden_states=encoder_outputs[1] if len(encoder_outputs) > 1 else None,
|
| 1433 |
+
attentions=encoder_outputs[2] if len(encoder_outputs) > 2 else None,
|
| 1434 |
+
)
|
| 1435 |
+
|
| 1436 |
+
# Fifth, sent query embeddings through the decoder (which is conditioned on the encoder output)
|
| 1437 |
+
object_queries_position_embeddings = self.query_position_embeddings.weight.unsqueeze(0).repeat(
|
| 1438 |
+
batch_size, 1, 1
|
| 1439 |
+
)
|
| 1440 |
+
queries = torch.zeros_like(object_queries_position_embeddings)
|
| 1441 |
+
|
| 1442 |
+
# decoder outputs consists of (dec_features, dec_hidden, dec_attn)
|
| 1443 |
+
decoder_outputs = self.decoder(
|
| 1444 |
+
inputs_embeds=queries,
|
| 1445 |
+
attention_mask=None,
|
| 1446 |
+
spatial_position_embeddings=spatial_position_embeddings,
|
| 1447 |
+
object_queries_position_embeddings=object_queries_position_embeddings,
|
| 1448 |
+
encoder_hidden_states=encoder_outputs.last_hidden_state,
|
| 1449 |
+
encoder_attention_mask=flattened_mask,
|
| 1450 |
+
**kwargs,
|
| 1451 |
+
)
|
| 1452 |
+
|
| 1453 |
+
return ConditionalDetrModelOutput(
|
| 1454 |
+
last_hidden_state=decoder_outputs.last_hidden_state,
|
| 1455 |
+
decoder_hidden_states=decoder_outputs.hidden_states,
|
| 1456 |
+
decoder_attentions=decoder_outputs.attentions,
|
| 1457 |
+
cross_attentions=decoder_outputs.cross_attentions,
|
| 1458 |
+
encoder_last_hidden_state=encoder_outputs.last_hidden_state,
|
| 1459 |
+
encoder_hidden_states=encoder_outputs.hidden_states,
|
| 1460 |
+
encoder_attentions=encoder_outputs.attentions,
|
| 1461 |
+
intermediate_hidden_states=decoder_outputs.intermediate_hidden_states,
|
| 1462 |
+
reference_points=decoder_outputs.reference_points,
|
| 1463 |
+
)
|
| 1464 |
+
|
| 1465 |
+
|
| 1466 |
+
def inverse_sigmoid(x, eps=1e-5):
|
| 1467 |
+
x = x.clamp(min=0, max=1)
|
| 1468 |
+
x1 = x.clamp(min=eps)
|
| 1469 |
+
x2 = (1 - x).clamp(min=eps)
|
| 1470 |
+
return torch.log(x1 / x2)
|
| 1471 |
+
|
| 1472 |
+
|
| 1473 |
+
@auto_docstring(
|
| 1474 |
+
custom_intro="""
|
| 1475 |
+
CONDITIONAL_DETR Model (consisting of a backbone and encoder-decoder Transformer) with object detection heads on top, for tasks
|
| 1476 |
+
such as COCO detection.
|
| 1477 |
+
"""
|
| 1478 |
+
)
|
| 1479 |
+
class ConditionalDetrForObjectDetection(ConditionalDetrPreTrainedModel):
|
| 1480 |
+
def __init__(self, config: ConditionalDetrConfig):
|
| 1481 |
+
super().__init__(config)
|
| 1482 |
+
|
| 1483 |
+
# CONDITIONAL_DETR encoder-decoder model
|
| 1484 |
+
self.model = ConditionalDetrModel(config)
|
| 1485 |
+
self.class_labels_classifier = nn.Linear(config.d_model, config.num_labels)
|
| 1486 |
+
self.bbox_predictor = ConditionalDetrMLPPredictionHead(
|
| 1487 |
+
input_dim=config.d_model, hidden_dim=config.d_model, output_dim=4, num_layers=3
|
| 1488 |
+
)
|
| 1489 |
+
|
| 1490 |
+
# Initialize weights and apply final processing
|
| 1491 |
+
self.post_init()
|
| 1492 |
+
|
| 1493 |
+
@auto_docstring
|
| 1494 |
+
@can_return_tuple
|
| 1495 |
+
def forward(
|
| 1496 |
+
self,
|
| 1497 |
+
pixel_values: torch.FloatTensor,
|
| 1498 |
+
pixel_mask: torch.LongTensor | None = None,
|
| 1499 |
+
decoder_attention_mask: torch.LongTensor | None = None,
|
| 1500 |
+
encoder_outputs: torch.FloatTensor | None = None,
|
| 1501 |
+
inputs_embeds: torch.FloatTensor | None = None,
|
| 1502 |
+
decoder_inputs_embeds: torch.FloatTensor | None = None,
|
| 1503 |
+
labels: list[dict] | None = None,
|
| 1504 |
+
**kwargs: Unpack[TransformersKwargs],
|
| 1505 |
+
) -> ConditionalDetrObjectDetectionOutput:
|
| 1506 |
+
r"""
|
| 1507 |
+
decoder_attention_mask (`torch.FloatTensor` of shape `(batch_size, num_queries)`, *optional*):
|
| 1508 |
+
Not used by default. Can be used to mask object queries.
|
| 1509 |
+
inputs_embeds (`torch.FloatTensor` of shape `(batch_size, sequence_length, hidden_size)`, *optional*):
|
| 1510 |
+
Optionally, instead of passing the flattened feature map (output of the backbone + projection layer), you
|
| 1511 |
+
can choose to directly pass a flattened representation of an image.
|
| 1512 |
+
decoder_inputs_embeds (`torch.FloatTensor` of shape `(batch_size, num_queries, hidden_size)`, *optional*):
|
| 1513 |
+
Optionally, instead of initializing the queries with a tensor of zeros, you can choose to directly pass an
|
| 1514 |
+
embedded representation.
|
| 1515 |
+
labels (`list[Dict]` of len `(batch_size,)`, *optional*):
|
| 1516 |
+
Labels for computing the bipartite matching loss. List of dicts, each dictionary containing at least the
|
| 1517 |
+
following 2 keys: 'class_labels' and 'boxes' (the class labels and bounding boxes of an image in the batch
|
| 1518 |
+
respectively). The class labels themselves should be a `torch.LongTensor` of len `(number of bounding boxes
|
| 1519 |
+
in the image,)` and the boxes a `torch.FloatTensor` of shape `(number of bounding boxes in the image, 4)`.
|
| 1520 |
+
|
| 1521 |
+
Examples:
|
| 1522 |
+
|
| 1523 |
+
```python
|
| 1524 |
+
>>> from transformers import AutoImageProcessor, AutoModelForObjectDetection
|
| 1525 |
+
>>> from PIL import Image
|
| 1526 |
+
>>> import requests
|
| 1527 |
+
|
| 1528 |
+
>>> url = "http://images.cocodataset.org/val2017/000000039769.jpg"
|
| 1529 |
+
>>> image = Image.open(requests.get(url, stream=True).raw)
|
| 1530 |
+
|
| 1531 |
+
>>> image_processor = AutoImageProcessor.from_pretrained("microsoft/conditional-detr-resnet-50")
|
| 1532 |
+
>>> model = AutoModelForObjectDetection.from_pretrained("microsoft/conditional-detr-resnet-50")
|
| 1533 |
+
|
| 1534 |
+
>>> inputs = image_processor(images=image, return_tensors="pt")
|
| 1535 |
+
|
| 1536 |
+
>>> outputs = model(**inputs)
|
| 1537 |
+
|
| 1538 |
+
>>> # convert outputs (bounding boxes and class logits) to Pascal VOC format (xmin, ymin, xmax, ymax)
|
| 1539 |
+
>>> target_sizes = torch.tensor([image.size[::-1]])
|
| 1540 |
+
>>> results = image_processor.post_process_object_detection(outputs, threshold=0.5, target_sizes=target_sizes)[
|
| 1541 |
+
... 0
|
| 1542 |
+
... ]
|
| 1543 |
+
>>> for score, label, box in zip(results["scores"], results["labels"], results["boxes"]):
|
| 1544 |
+
... box = [round(i, 2) for i in box.tolist()]
|
| 1545 |
+
... print(
|
| 1546 |
+
... f"Detected {model.config.id2label[label.item()]} with confidence "
|
| 1547 |
+
... f"{round(score.item(), 3)} at location {box}"
|
| 1548 |
+
... )
|
| 1549 |
+
Detected remote with confidence 0.833 at location [38.31, 72.1, 177.63, 118.45]
|
| 1550 |
+
Detected cat with confidence 0.831 at location [9.2, 51.38, 321.13, 469.0]
|
| 1551 |
+
Detected cat with confidence 0.804 at location [340.3, 16.85, 642.93, 370.95]
|
| 1552 |
+
Detected remote with confidence 0.683 at location [334.48, 73.49, 366.37, 190.01]
|
| 1553 |
+
Detected couch with confidence 0.535 at location [0.52, 1.19, 640.35, 475.1]
|
| 1554 |
+
```"""
|
| 1555 |
+
# First, sent images through CONDITIONAL_DETR base model to obtain encoder + decoder outputs
|
| 1556 |
+
outputs = self.model(
|
| 1557 |
+
pixel_values,
|
| 1558 |
+
pixel_mask=pixel_mask,
|
| 1559 |
+
decoder_attention_mask=decoder_attention_mask,
|
| 1560 |
+
encoder_outputs=encoder_outputs,
|
| 1561 |
+
inputs_embeds=inputs_embeds,
|
| 1562 |
+
decoder_inputs_embeds=decoder_inputs_embeds,
|
| 1563 |
+
**kwargs,
|
| 1564 |
+
)
|
| 1565 |
+
|
| 1566 |
+
sequence_output = outputs[0]
|
| 1567 |
+
|
| 1568 |
+
# class logits + predicted bounding boxes
|
| 1569 |
+
logits = self.class_labels_classifier(sequence_output)
|
| 1570 |
+
|
| 1571 |
+
reference = outputs.reference_points
|
| 1572 |
+
reference_before_sigmoid = inverse_sigmoid(reference).transpose(0, 1)
|
| 1573 |
+
|
| 1574 |
+
hs = sequence_output
|
| 1575 |
+
tmp = self.bbox_predictor(hs)
|
| 1576 |
+
tmp[..., :2] += reference_before_sigmoid
|
| 1577 |
+
pred_boxes = tmp.sigmoid()
|
| 1578 |
+
# pred_boxes = self.bbox_predictor(sequence_output).sigmoid()
|
| 1579 |
+
|
| 1580 |
+
loss, loss_dict, auxiliary_outputs = None, None, None
|
| 1581 |
+
if labels is not None:
|
| 1582 |
+
outputs_class, outputs_coord = None, None
|
| 1583 |
+
if self.config.auxiliary_loss:
|
| 1584 |
+
outputs_coords = []
|
| 1585 |
+
intermediate = outputs.intermediate_hidden_states
|
| 1586 |
+
outputs_class = self.class_labels_classifier(intermediate)
|
| 1587 |
+
for lvl in range(intermediate.shape[0]):
|
| 1588 |
+
tmp = self.bbox_predictor(intermediate[lvl])
|
| 1589 |
+
tmp[..., :2] += reference_before_sigmoid
|
| 1590 |
+
outputs_coord = tmp.sigmoid()
|
| 1591 |
+
outputs_coords.append(outputs_coord)
|
| 1592 |
+
outputs_coord = torch.stack(outputs_coords)
|
| 1593 |
+
loss, loss_dict, auxiliary_outputs = self.loss_function(
|
| 1594 |
+
logits, labels, self.device, pred_boxes, self.config, outputs_class, outputs_coord
|
| 1595 |
+
)
|
| 1596 |
+
|
| 1597 |
+
return ConditionalDetrObjectDetectionOutput(
|
| 1598 |
+
loss=loss,
|
| 1599 |
+
loss_dict=loss_dict,
|
| 1600 |
+
logits=logits,
|
| 1601 |
+
pred_boxes=pred_boxes,
|
| 1602 |
+
auxiliary_outputs=auxiliary_outputs,
|
| 1603 |
+
last_hidden_state=outputs.last_hidden_state,
|
| 1604 |
+
decoder_hidden_states=outputs.decoder_hidden_states,
|
| 1605 |
+
decoder_attentions=outputs.decoder_attentions,
|
| 1606 |
+
cross_attentions=outputs.cross_attentions,
|
| 1607 |
+
encoder_last_hidden_state=outputs.encoder_last_hidden_state,
|
| 1608 |
+
encoder_hidden_states=outputs.encoder_hidden_states,
|
| 1609 |
+
encoder_attentions=outputs.encoder_attentions,
|
| 1610 |
+
)
|
| 1611 |
+
|
| 1612 |
+
# taken from https://github.com/Atten4Vis/conditionalDETR/blob/master/models/conditional_detr.py
|
| 1613 |
+
def _set_aux_loss(self, outputs_class, outputs_coord):
|
| 1614 |
+
return [{"logits": a, "pred_boxes": b} for a, b in zip(outputs_class[:-1], outputs_coord[:-1])]
|
| 1615 |
+
|
| 1616 |
+
|
| 1617 |
+
@auto_docstring(
|
| 1618 |
+
custom_intro="""
|
| 1619 |
+
CONDITIONAL_DETR Model (consisting of a backbone and encoder-decoder Transformer) with a segmentation head on top, for tasks
|
| 1620 |
+
such as COCO panoptic.
|
| 1621 |
+
"""
|
| 1622 |
+
)
|
| 1623 |
+
class ConditionalDetrForSegmentation(ConditionalDetrPreTrainedModel):
|
| 1624 |
+
def __init__(self, config: ConditionalDetrConfig):
|
| 1625 |
+
super().__init__(config)
|
| 1626 |
+
|
| 1627 |
+
# object detection model
|
| 1628 |
+
self.conditional_detr = ConditionalDetrForObjectDetection(config)
|
| 1629 |
+
|
| 1630 |
+
# segmentation head
|
| 1631 |
+
hidden_size, number_of_heads = config.d_model, config.encoder_attention_heads
|
| 1632 |
+
intermediate_channel_sizes = self.conditional_detr.model.backbone.intermediate_channel_sizes
|
| 1633 |
+
|
| 1634 |
+
self.mask_head = ConditionalDetrMaskHeadSmallConv(
|
| 1635 |
+
input_channels=hidden_size + number_of_heads,
|
| 1636 |
+
fpn_channels=intermediate_channel_sizes[::-1][-3:],
|
| 1637 |
+
hidden_size=hidden_size,
|
| 1638 |
+
activation_function=config.activation_function,
|
| 1639 |
+
)
|
| 1640 |
+
|
| 1641 |
+
self.bbox_attention = ConditionalDetrMHAttentionMap(hidden_size, number_of_heads, dropout=0.0)
|
| 1642 |
+
# Initialize weights and apply final processing
|
| 1643 |
+
self.post_init()
|
| 1644 |
+
|
| 1645 |
+
@auto_docstring
|
| 1646 |
+
@can_return_tuple
|
| 1647 |
+
def forward(
|
| 1648 |
+
self,
|
| 1649 |
+
pixel_values: torch.FloatTensor,
|
| 1650 |
+
pixel_mask: torch.LongTensor | None = None,
|
| 1651 |
+
decoder_attention_mask: torch.FloatTensor | None = None,
|
| 1652 |
+
encoder_outputs: torch.FloatTensor | None = None,
|
| 1653 |
+
inputs_embeds: torch.FloatTensor | None = None,
|
| 1654 |
+
decoder_inputs_embeds: torch.FloatTensor | None = None,
|
| 1655 |
+
labels: list[dict] | None = None,
|
| 1656 |
+
**kwargs: Unpack[TransformersKwargs],
|
| 1657 |
+
) -> tuple[torch.FloatTensor] | ConditionalDetrSegmentationOutput:
|
| 1658 |
+
r"""
|
| 1659 |
+
decoder_attention_mask (`torch.FloatTensor` of shape `(batch_size, num_queries)`, *optional*):
|
| 1660 |
+
Mask to avoid performing attention on certain object queries in the decoder. Mask values selected in `[0, 1]`:
|
| 1661 |
+
|
| 1662 |
+
- 1 for queries that are **not masked**,
|
| 1663 |
+
- 0 for queries that are **masked**.
|
| 1664 |
+
inputs_embeds (`torch.FloatTensor` of shape `(batch_size, sequence_length, hidden_size)`, *optional*):
|
| 1665 |
+
Kept for backward compatibility, but cannot be used for segmentation, as segmentation requires
|
| 1666 |
+
multi-scale features from the backbone that are not available when bypassing it with inputs_embeds.
|
| 1667 |
+
decoder_inputs_embeds (`torch.FloatTensor` of shape `(batch_size, num_queries, hidden_size)`, *optional*):
|
| 1668 |
+
Optionally, instead of initializing the queries with a tensor of zeros, you can choose to directly pass an
|
| 1669 |
+
embedded representation. Useful for tasks that require custom query initialization.
|
| 1670 |
+
labels (`list[Dict]` of len `(batch_size,)`, *optional*):
|
| 1671 |
+
Labels for computing the bipartite matching loss, DICE/F-1 loss and Focal loss. List of dicts, each
|
| 1672 |
+
dictionary containing at least the following 3 keys: 'class_labels', 'boxes' and 'masks' (the class labels,
|
| 1673 |
+
bounding boxes and segmentation masks of an image in the batch respectively). The class labels themselves
|
| 1674 |
+
should be a `torch.LongTensor` of len `(number of bounding boxes in the image,)`, the boxes a
|
| 1675 |
+
`torch.FloatTensor` of shape `(number of bounding boxes in the image, 4)` and the masks a
|
| 1676 |
+
`torch.FloatTensor` of shape `(number of bounding boxes in the image, height, width)`.
|
| 1677 |
+
|
| 1678 |
+
Examples:
|
| 1679 |
+
|
| 1680 |
+
```python
|
| 1681 |
+
>>> import io
|
| 1682 |
+
>>> import httpx
|
| 1683 |
+
>>> from io import BytesIO
|
| 1684 |
+
>>> from PIL import Image
|
| 1685 |
+
>>> import torch
|
| 1686 |
+
>>> import numpy
|
| 1687 |
+
|
| 1688 |
+
>>> from transformers import AutoImageProcessor, ConditionalDetrForSegmentation
|
| 1689 |
+
>>> from transformers.image_transforms import rgb_to_id
|
| 1690 |
+
|
| 1691 |
+
>>> url = "http://images.cocodataset.org/val2017/000000039769.jpg"
|
| 1692 |
+
>>> with httpx.stream("GET", url) as response:
|
| 1693 |
+
... image = Image.open(BytesIO(response.read()))
|
| 1694 |
+
|
| 1695 |
+
>>> image_processor = AutoImageProcessor.from_pretrained("facebook/conditional_detr-resnet-50-panoptic")
|
| 1696 |
+
>>> model = ConditionalDetrForSegmentation.from_pretrained("facebook/conditional_detr-resnet-50-panoptic")
|
| 1697 |
+
|
| 1698 |
+
>>> # prepare image for the model
|
| 1699 |
+
>>> inputs = image_processor(images=image, return_tensors="pt")
|
| 1700 |
+
|
| 1701 |
+
>>> # forward pass
|
| 1702 |
+
>>> outputs = model(**inputs)
|
| 1703 |
+
|
| 1704 |
+
>>> # Use the `post_process_panoptic_segmentation` method of the `image_processor` to retrieve post-processed panoptic segmentation maps
|
| 1705 |
+
>>> # Segmentation results are returned as a list of dictionaries
|
| 1706 |
+
>>> result = image_processor.post_process_panoptic_segmentation(outputs, target_sizes=[(300, 500)])
|
| 1707 |
+
|
| 1708 |
+
>>> # A tensor of shape (height, width) where each value denotes a segment id, filled with -1 if no segment is found
|
| 1709 |
+
>>> panoptic_seg = result[0]["segmentation"]
|
| 1710 |
+
>>> panoptic_seg.shape
|
| 1711 |
+
torch.Size([300, 500])
|
| 1712 |
+
>>> # Get prediction score and segment_id to class_id mapping of each segment
|
| 1713 |
+
>>> panoptic_segments_info = result[0]["segments_info"]
|
| 1714 |
+
>>> len(panoptic_segments_info)
|
| 1715 |
+
5
|
| 1716 |
+
```"""
|
| 1717 |
+
|
| 1718 |
+
batch_size, num_channels, height, width = pixel_values.shape
|
| 1719 |
+
device = pixel_values.device
|
| 1720 |
+
|
| 1721 |
+
if pixel_mask is None:
|
| 1722 |
+
pixel_mask = torch.ones((batch_size, height, width), device=device)
|
| 1723 |
+
|
| 1724 |
+
vision_features = self.conditional_detr.model.backbone(pixel_values, pixel_mask)
|
| 1725 |
+
feature_map, mask = vision_features[-1]
|
| 1726 |
+
|
| 1727 |
+
# Apply 1x1 conv to map (batch_size, C, H, W) -> (batch_size, hidden_size, H, W), then flatten to (batch_size, HW, hidden_size)
|
| 1728 |
+
projected_feature_map = self.conditional_detr.model.input_projection(feature_map)
|
| 1729 |
+
flattened_features = projected_feature_map.flatten(2).permute(0, 2, 1)
|
| 1730 |
+
spatial_position_embeddings = self.conditional_detr.model.position_embedding(
|
| 1731 |
+
shape=feature_map.shape, device=device, dtype=pixel_values.dtype, mask=mask
|
| 1732 |
+
)
|
| 1733 |
+
flattened_mask = mask.flatten(1)
|
| 1734 |
+
|
| 1735 |
+
if encoder_outputs is None:
|
| 1736 |
+
encoder_outputs = self.conditional_detr.model.encoder(
|
| 1737 |
+
inputs_embeds=flattened_features,
|
| 1738 |
+
attention_mask=flattened_mask,
|
| 1739 |
+
spatial_position_embeddings=spatial_position_embeddings,
|
| 1740 |
+
**kwargs,
|
| 1741 |
+
)
|
| 1742 |
+
|
| 1743 |
+
object_queries_position_embeddings = self.conditional_detr.model.query_position_embeddings.weight.unsqueeze(
|
| 1744 |
+
0
|
| 1745 |
+
).repeat(batch_size, 1, 1)
|
| 1746 |
+
|
| 1747 |
+
# Use decoder_inputs_embeds as queries if provided, otherwise initialize with zeros
|
| 1748 |
+
if decoder_inputs_embeds is not None:
|
| 1749 |
+
queries = decoder_inputs_embeds
|
| 1750 |
+
else:
|
| 1751 |
+
queries = torch.zeros_like(object_queries_position_embeddings)
|
| 1752 |
+
|
| 1753 |
+
decoder_outputs = self.conditional_detr.model.decoder(
|
| 1754 |
+
inputs_embeds=queries,
|
| 1755 |
+
attention_mask=decoder_attention_mask,
|
| 1756 |
+
spatial_position_embeddings=spatial_position_embeddings,
|
| 1757 |
+
object_queries_position_embeddings=object_queries_position_embeddings,
|
| 1758 |
+
encoder_hidden_states=encoder_outputs.last_hidden_state,
|
| 1759 |
+
encoder_attention_mask=flattened_mask,
|
| 1760 |
+
**kwargs,
|
| 1761 |
+
)
|
| 1762 |
+
|
| 1763 |
+
sequence_output = decoder_outputs[0]
|
| 1764 |
+
|
| 1765 |
+
logits = self.conditional_detr.class_labels_classifier(sequence_output)
|
| 1766 |
+
pred_boxes = self.conditional_detr.bbox_predictor(sequence_output).sigmoid()
|
| 1767 |
+
|
| 1768 |
+
height, width = feature_map.shape[-2:]
|
| 1769 |
+
memory = encoder_outputs.last_hidden_state.permute(0, 2, 1).view(
|
| 1770 |
+
batch_size, self.config.d_model, height, width
|
| 1771 |
+
)
|
| 1772 |
+
attention_mask = flattened_mask.view(batch_size, height, width)
|
| 1773 |
+
|
| 1774 |
+
if attention_mask is not None:
|
| 1775 |
+
min_dtype = torch.finfo(memory.dtype).min
|
| 1776 |
+
attention_mask = torch.where(
|
| 1777 |
+
attention_mask.unsqueeze(1).unsqueeze(1),
|
| 1778 |
+
torch.tensor(0.0, device=memory.device, dtype=memory.dtype),
|
| 1779 |
+
min_dtype,
|
| 1780 |
+
)
|
| 1781 |
+
|
| 1782 |
+
bbox_mask = self.bbox_attention(sequence_output, memory, attention_mask=attention_mask)
|
| 1783 |
+
|
| 1784 |
+
seg_masks = self.mask_head(
|
| 1785 |
+
features=projected_feature_map,
|
| 1786 |
+
attention_masks=bbox_mask,
|
| 1787 |
+
fpn_features=[vision_features[2][0], vision_features[1][0], vision_features[0][0]],
|
| 1788 |
+
)
|
| 1789 |
+
|
| 1790 |
+
pred_masks = seg_masks.view(
|
| 1791 |
+
batch_size, self.conditional_detr.config.num_queries, seg_masks.shape[-2], seg_masks.shape[-1]
|
| 1792 |
+
)
|
| 1793 |
+
|
| 1794 |
+
loss, loss_dict, auxiliary_outputs = None, None, None
|
| 1795 |
+
if labels is not None:
|
| 1796 |
+
outputs_class, outputs_coord = None, None
|
| 1797 |
+
if self.config.auxiliary_loss:
|
| 1798 |
+
intermediate = decoder_outputs.intermediate_hidden_states
|
| 1799 |
+
outputs_class = self.conditional_detr.class_labels_classifier(intermediate)
|
| 1800 |
+
outputs_coord = self.conditional_detr.bbox_predictor(intermediate).sigmoid()
|
| 1801 |
+
loss, loss_dict, auxiliary_outputs = self.loss_function(
|
| 1802 |
+
logits, labels, device, pred_boxes, pred_masks, self.config, outputs_class, outputs_coord
|
| 1803 |
+
)
|
| 1804 |
+
|
| 1805 |
+
return ConditionalDetrSegmentationOutput(
|
| 1806 |
+
loss=loss,
|
| 1807 |
+
loss_dict=loss_dict,
|
| 1808 |
+
logits=logits,
|
| 1809 |
+
pred_boxes=pred_boxes,
|
| 1810 |
+
pred_masks=pred_masks,
|
| 1811 |
+
auxiliary_outputs=auxiliary_outputs,
|
| 1812 |
+
last_hidden_state=decoder_outputs.last_hidden_state,
|
| 1813 |
+
decoder_hidden_states=decoder_outputs.hidden_states,
|
| 1814 |
+
decoder_attentions=decoder_outputs.attentions,
|
| 1815 |
+
cross_attentions=decoder_outputs.cross_attentions,
|
| 1816 |
+
encoder_last_hidden_state=encoder_outputs.last_hidden_state,
|
| 1817 |
+
encoder_hidden_states=encoder_outputs.hidden_states,
|
| 1818 |
+
encoder_attentions=encoder_outputs.attentions,
|
| 1819 |
+
)
|
| 1820 |
+
|
| 1821 |
+
|
| 1822 |
+
__all__ = [
|
| 1823 |
+
"ConditionalDetrForObjectDetection",
|
| 1824 |
+
"ConditionalDetrForSegmentation",
|
| 1825 |
+
"ConditionalDetrModel",
|
| 1826 |
+
"ConditionalDetrPreTrainedModel",
|
| 1827 |
+
]
|
third_party/transformers/src/transformers/models/conditional_detr/modular_conditional_detr.py
ADDED
|
@@ -0,0 +1,1109 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
# Copyright 2022 Microsoft Research Asia and The HuggingFace Inc. team. All rights reserved.
|
| 2 |
+
#
|
| 3 |
+
# Licensed under the Apache License, Version 2.0 (the "License");
|
| 4 |
+
# you may not use this file except in compliance with the License.
|
| 5 |
+
# You may obtain a copy of the License at
|
| 6 |
+
#
|
| 7 |
+
# http://www.apache.org/licenses/LICENSE-2.0
|
| 8 |
+
#
|
| 9 |
+
# Unless required by applicable law or agreed to in writing, software
|
| 10 |
+
# distributed under the License is distributed on an "AS IS" BASIS,
|
| 11 |
+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
| 12 |
+
# See the License for the specific language governing permissions and
|
| 13 |
+
# limitations under the License.
|
| 14 |
+
import math
|
| 15 |
+
from collections.abc import Callable
|
| 16 |
+
|
| 17 |
+
import torch
|
| 18 |
+
from torch import nn
|
| 19 |
+
|
| 20 |
+
from ...image_transforms import (
|
| 21 |
+
center_to_corners_format,
|
| 22 |
+
)
|
| 23 |
+
from ...image_utils import AnnotationFormat
|
| 24 |
+
from ...masking_utils import create_bidirectional_mask
|
| 25 |
+
from ...modeling_outputs import (
|
| 26 |
+
BaseModelOutput,
|
| 27 |
+
)
|
| 28 |
+
from ...modeling_utils import ALL_ATTENTION_FUNCTIONS
|
| 29 |
+
from ...processing_utils import ImagesKwargs, Unpack
|
| 30 |
+
from ...utils import (
|
| 31 |
+
TensorType,
|
| 32 |
+
TransformersKwargs,
|
| 33 |
+
auto_docstring,
|
| 34 |
+
logging,
|
| 35 |
+
requires_backends,
|
| 36 |
+
)
|
| 37 |
+
from ...utils.generic import can_return_tuple, merge_with_config_defaults
|
| 38 |
+
from ...utils.import_utils import requires
|
| 39 |
+
from ...utils.output_capturing import OutputRecorder, capture_outputs
|
| 40 |
+
from ..deformable_detr.modeling_deformable_detr import inverse_sigmoid
|
| 41 |
+
from ..detr.image_processing_detr import DetrImageProcessor
|
| 42 |
+
from ..detr.image_processing_pil_detr import DetrImageProcessorPil
|
| 43 |
+
from ..detr.modeling_detr import (
|
| 44 |
+
DetrConvEncoder,
|
| 45 |
+
DetrDecoderLayer,
|
| 46 |
+
DetrDecoderOutput,
|
| 47 |
+
DetrEncoder,
|
| 48 |
+
DetrEncoderLayer,
|
| 49 |
+
DetrForObjectDetection,
|
| 50 |
+
DetrForSegmentation,
|
| 51 |
+
DetrLearnedPositionEmbedding,
|
| 52 |
+
DetrMLP,
|
| 53 |
+
DetrMLPPredictionHead,
|
| 54 |
+
DetrModel,
|
| 55 |
+
DetrModelOutput,
|
| 56 |
+
DetrObjectDetectionOutput,
|
| 57 |
+
DetrPreTrainedModel,
|
| 58 |
+
DetrSegmentationOutput,
|
| 59 |
+
DetrSelfAttention,
|
| 60 |
+
DetrSinePositionEmbedding,
|
| 61 |
+
eager_attention_forward,
|
| 62 |
+
)
|
| 63 |
+
from .configuration_conditional_detr import ConditionalDetrConfig
|
| 64 |
+
|
| 65 |
+
|
| 66 |
+
logger = logging.get_logger(__name__)
|
| 67 |
+
|
| 68 |
+
|
| 69 |
+
class ConditionalDetrImageProcessorKwargs(ImagesKwargs, total=False):
|
| 70 |
+
r"""
|
| 71 |
+
format (`str`, *optional*, defaults to `AnnotationFormat.COCO_DETECTION`):
|
| 72 |
+
Data format of the annotations. One of "coco_detection" or "coco_panoptic".
|
| 73 |
+
do_convert_annotations (`bool`, *optional*, defaults to `True`):
|
| 74 |
+
Controls whether to convert the annotations to the format expected by the CONDITIONAL_DETR model. Converts the
|
| 75 |
+
bounding boxes to the format `(center_x, center_y, width, height)` and in the range `[0, 1]`.
|
| 76 |
+
Can be overridden by the `do_convert_annotations` parameter in the `preprocess` method.
|
| 77 |
+
"""
|
| 78 |
+
|
| 79 |
+
format: str | AnnotationFormat
|
| 80 |
+
do_convert_annotations: bool
|
| 81 |
+
|
| 82 |
+
|
| 83 |
+
class ConditionalDetrImageProcessor(DetrImageProcessor):
|
| 84 |
+
def post_process_object_detection(
|
| 85 |
+
self, outputs, threshold: float = 0.5, target_sizes: TensorType | list[tuple] = None, top_k: int = 100
|
| 86 |
+
):
|
| 87 |
+
"""
|
| 88 |
+
Converts the raw output of [`ConditionalDetrForObjectDetection`] into final bounding boxes in (top_left_x,
|
| 89 |
+
top_left_y, bottom_right_x, bottom_right_y) format. Only supports PyTorch.
|
| 90 |
+
|
| 91 |
+
Args:
|
| 92 |
+
outputs ([`ConditionalDetrObjectDetectionOutput`]):
|
| 93 |
+
Raw outputs of the model.
|
| 94 |
+
threshold (`float`, *optional*):
|
| 95 |
+
Score threshold to keep object detection predictions.
|
| 96 |
+
target_sizes (`torch.Tensor` or `list[tuple[int, int]]`, *optional*):
|
| 97 |
+
Tensor of shape `(batch_size, 2)` or list of tuples (`tuple[int, int]`) containing the target size
|
| 98 |
+
(height, width) of each image in the batch. If left to None, predictions will not be resized.
|
| 99 |
+
top_k (`int`, *optional*, defaults to 100):
|
| 100 |
+
Keep only top k bounding boxes before filtering by thresholding.
|
| 101 |
+
|
| 102 |
+
Returns:
|
| 103 |
+
`list[Dict]`: A list of dictionaries, each dictionary containing the scores, labels and boxes for an image
|
| 104 |
+
in the batch as predicted by the model.
|
| 105 |
+
"""
|
| 106 |
+
out_logits, out_bbox = outputs.logits, outputs.pred_boxes
|
| 107 |
+
|
| 108 |
+
if target_sizes is not None:
|
| 109 |
+
if len(out_logits) != len(target_sizes):
|
| 110 |
+
raise ValueError(
|
| 111 |
+
"Make sure that you pass in as many target sizes as the batch dimension of the logits"
|
| 112 |
+
)
|
| 113 |
+
|
| 114 |
+
prob = out_logits.sigmoid()
|
| 115 |
+
prob = prob.view(out_logits.shape[0], -1)
|
| 116 |
+
k_value = min(top_k, prob.size(1))
|
| 117 |
+
topk_values, topk_indexes = torch.topk(prob, k_value, dim=1)
|
| 118 |
+
scores = topk_values
|
| 119 |
+
topk_boxes = torch.div(topk_indexes, out_logits.shape[2], rounding_mode="floor")
|
| 120 |
+
labels = topk_indexes % out_logits.shape[2]
|
| 121 |
+
boxes = center_to_corners_format(out_bbox)
|
| 122 |
+
boxes = torch.gather(boxes, 1, topk_boxes.unsqueeze(-1).repeat(1, 1, 4))
|
| 123 |
+
|
| 124 |
+
# and from relative [0, 1] to absolute [0, height] coordinates
|
| 125 |
+
if target_sizes is not None:
|
| 126 |
+
if isinstance(target_sizes, list):
|
| 127 |
+
img_h = torch.Tensor([i[0] for i in target_sizes])
|
| 128 |
+
img_w = torch.Tensor([i[1] for i in target_sizes])
|
| 129 |
+
else:
|
| 130 |
+
img_h, img_w = target_sizes.unbind(1)
|
| 131 |
+
scale_fct = torch.stack([img_w, img_h, img_w, img_h], dim=1).to(boxes.device)
|
| 132 |
+
boxes = boxes * scale_fct[:, None, :]
|
| 133 |
+
|
| 134 |
+
results = []
|
| 135 |
+
for s, l, b in zip(scores, labels, boxes):
|
| 136 |
+
score = s[s > threshold]
|
| 137 |
+
label = l[s > threshold]
|
| 138 |
+
box = b[s > threshold]
|
| 139 |
+
results.append({"scores": score, "labels": label, "boxes": box})
|
| 140 |
+
|
| 141 |
+
return results
|
| 142 |
+
|
| 143 |
+
def post_process_semantic_segmentation(self, outputs, target_sizes: list[tuple[int, int]] | None = None):
|
| 144 |
+
"""
|
| 145 |
+
Converts the output of [`ConditionalDetrForSegmentation`] into semantic segmentation maps. Only supports PyTorch.
|
| 146 |
+
|
| 147 |
+
Args:
|
| 148 |
+
outputs ([`ConditionalDetrForSegmentation`]):
|
| 149 |
+
Raw outputs of the model.
|
| 150 |
+
target_sizes (`list[tuple[int, int]]`, *optional*):
|
| 151 |
+
A list of tuples (`tuple[int, int]`) containing the target size (height, width) of each image in the
|
| 152 |
+
batch. If unset, predictions will not be resized.
|
| 153 |
+
Returns:
|
| 154 |
+
`list[torch.Tensor]`:
|
| 155 |
+
A list of length `batch_size`, where each item is a semantic segmentation map of shape (height, width)
|
| 156 |
+
corresponding to the target_sizes entry (if `target_sizes` is specified). Each entry of each
|
| 157 |
+
`torch.Tensor` correspond to a semantic class id.
|
| 158 |
+
"""
|
| 159 |
+
class_queries_logits = outputs.logits # [batch_size, num_queries, num_classes]
|
| 160 |
+
masks_queries_logits = outputs.pred_masks # [batch_size, num_queries, height, width]
|
| 161 |
+
|
| 162 |
+
# Conditional DETR does not have a null class, so we use all classes
|
| 163 |
+
masks_classes = class_queries_logits.softmax(dim=-1)
|
| 164 |
+
masks_probs = masks_queries_logits.sigmoid() # [batch_size, num_queries, height, width]
|
| 165 |
+
|
| 166 |
+
# Semantic segmentation logits of shape (batch_size, num_classes, height, width)
|
| 167 |
+
segmentation = torch.einsum("bqc, bqhw -> bchw", masks_classes, masks_probs)
|
| 168 |
+
batch_size = class_queries_logits.shape[0]
|
| 169 |
+
|
| 170 |
+
# Resize logits and compute semantic segmentation maps
|
| 171 |
+
if target_sizes is not None:
|
| 172 |
+
if batch_size != len(target_sizes):
|
| 173 |
+
raise ValueError(
|
| 174 |
+
"Make sure that you pass in as many target sizes as the batch dimension of the logits"
|
| 175 |
+
)
|
| 176 |
+
|
| 177 |
+
semantic_segmentation = []
|
| 178 |
+
for idx in range(batch_size):
|
| 179 |
+
resized_logits = nn.functional.interpolate(
|
| 180 |
+
segmentation[idx].unsqueeze(dim=0), size=target_sizes[idx], mode="bilinear", align_corners=False
|
| 181 |
+
)
|
| 182 |
+
semantic_map = resized_logits[0].argmax(dim=0)
|
| 183 |
+
semantic_segmentation.append(semantic_map)
|
| 184 |
+
else:
|
| 185 |
+
semantic_segmentation = segmentation.argmax(dim=1)
|
| 186 |
+
semantic_segmentation = [semantic_segmentation[i] for i in range(semantic_segmentation.shape[0])]
|
| 187 |
+
|
| 188 |
+
return semantic_segmentation
|
| 189 |
+
|
| 190 |
+
|
| 191 |
+
class ConditionalDetrImageProcessorPil(DetrImageProcessorPil):
|
| 192 |
+
@requires(backends=("torch",))
|
| 193 |
+
def post_process_object_detection(
|
| 194 |
+
self, outputs, threshold: float = 0.5, target_sizes: TensorType | list[tuple] = None, top_k: int = 100
|
| 195 |
+
):
|
| 196 |
+
"""
|
| 197 |
+
Converts the raw output of [`ConditionalDetrForObjectDetection`] into final bounding boxes in (top_left_x,
|
| 198 |
+
top_left_y, bottom_right_x, bottom_right_y) format. Only supports PyTorch.
|
| 199 |
+
|
| 200 |
+
Args:
|
| 201 |
+
outputs ([`ConditionalDetrObjectDetectionOutput`]):
|
| 202 |
+
Raw outputs of the model.
|
| 203 |
+
threshold (`float`, *optional*):
|
| 204 |
+
Score threshold to keep object detection predictions.
|
| 205 |
+
target_sizes (`torch.Tensor` or `list[tuple[int, int]]`, *optional*):
|
| 206 |
+
Tensor of shape `(batch_size, 2)` or list of tuples (`tuple[int, int]`) containing the target size
|
| 207 |
+
(height, width) of each image in the batch. If left to None, predictions will not be resized.
|
| 208 |
+
top_k (`int`, *optional*, defaults to 100):
|
| 209 |
+
Keep only top k bounding boxes before filtering by thresholding.
|
| 210 |
+
|
| 211 |
+
Returns:
|
| 212 |
+
`list[Dict]`: A list of dictionaries, each dictionary containing the scores, labels and boxes for an image
|
| 213 |
+
in the batch as predicted by the model.
|
| 214 |
+
"""
|
| 215 |
+
requires_backends(self, ["torch"])
|
| 216 |
+
out_logits, out_bbox = outputs.logits, outputs.pred_boxes
|
| 217 |
+
|
| 218 |
+
if target_sizes is not None:
|
| 219 |
+
if len(out_logits) != len(target_sizes):
|
| 220 |
+
raise ValueError(
|
| 221 |
+
"Make sure that you pass in as many target sizes as the batch dimension of the logits"
|
| 222 |
+
)
|
| 223 |
+
|
| 224 |
+
prob = out_logits.sigmoid()
|
| 225 |
+
prob = prob.view(out_logits.shape[0], -1)
|
| 226 |
+
k_value = min(top_k, prob.size(1))
|
| 227 |
+
topk_values, topk_indexes = torch.topk(prob, k_value, dim=1)
|
| 228 |
+
scores = topk_values
|
| 229 |
+
topk_boxes = torch.div(topk_indexes, out_logits.shape[2], rounding_mode="floor")
|
| 230 |
+
labels = topk_indexes % out_logits.shape[2]
|
| 231 |
+
boxes = center_to_corners_format(out_bbox)
|
| 232 |
+
boxes = torch.gather(boxes, 1, topk_boxes.unsqueeze(-1).repeat(1, 1, 4))
|
| 233 |
+
|
| 234 |
+
# and from relative [0, 1] to absolute [0, height] coordinates
|
| 235 |
+
if target_sizes is not None:
|
| 236 |
+
if isinstance(target_sizes, list):
|
| 237 |
+
img_h = torch.Tensor([i[0] for i in target_sizes])
|
| 238 |
+
img_w = torch.Tensor([i[1] for i in target_sizes])
|
| 239 |
+
else:
|
| 240 |
+
img_h, img_w = target_sizes.unbind(1)
|
| 241 |
+
scale_fct = torch.stack([img_w, img_h, img_w, img_h], dim=1).to(boxes.device)
|
| 242 |
+
boxes = boxes * scale_fct[:, None, :]
|
| 243 |
+
|
| 244 |
+
results = []
|
| 245 |
+
for s, l, b in zip(scores, labels, boxes):
|
| 246 |
+
score = s[s > threshold]
|
| 247 |
+
label = l[s > threshold]
|
| 248 |
+
box = b[s > threshold]
|
| 249 |
+
results.append({"scores": score, "labels": label, "boxes": box})
|
| 250 |
+
|
| 251 |
+
return results
|
| 252 |
+
|
| 253 |
+
@requires(backends=("torch",))
|
| 254 |
+
def post_process_semantic_segmentation(self, outputs, target_sizes: list[tuple[int, int]] | None = None):
|
| 255 |
+
"""
|
| 256 |
+
Converts the output of [`ConditionalDetrForSegmentation`] into semantic segmentation maps. Only supports PyTorch.
|
| 257 |
+
|
| 258 |
+
Args:
|
| 259 |
+
outputs ([`ConditionalDetrForSegmentation`]):
|
| 260 |
+
Raw outputs of the model.
|
| 261 |
+
target_sizes (`list[tuple[int, int]]`, *optional*):
|
| 262 |
+
A list of tuples (`tuple[int, int]`) containing the target size (height, width) of each image in the
|
| 263 |
+
batch. If unset, predictions will not be resized.
|
| 264 |
+
Returns:
|
| 265 |
+
`list[torch.Tensor]`:
|
| 266 |
+
A list of length `batch_size`, where each item is a semantic segmentation map of shape (height, width)
|
| 267 |
+
corresponding to the target_sizes entry (if `target_sizes` is specified). Each entry of each
|
| 268 |
+
`torch.Tensor` correspond to a semantic class id.
|
| 269 |
+
"""
|
| 270 |
+
requires_backends(self, ["torch"])
|
| 271 |
+
class_queries_logits = outputs.logits # [batch_size, num_queries, num_classes]
|
| 272 |
+
masks_queries_logits = outputs.pred_masks # [batch_size, num_queries, height, width]
|
| 273 |
+
|
| 274 |
+
# Conditional DETR does not have a null class, so we use all classes
|
| 275 |
+
masks_classes = class_queries_logits.softmax(dim=-1)
|
| 276 |
+
masks_probs = masks_queries_logits.sigmoid() # [batch_size, num_queries, height, width]
|
| 277 |
+
|
| 278 |
+
# Semantic segmentation logits of shape (batch_size, num_classes, height, width)
|
| 279 |
+
segmentation = torch.einsum("bqc, bqhw -> bchw", masks_classes, masks_probs)
|
| 280 |
+
batch_size = class_queries_logits.shape[0]
|
| 281 |
+
|
| 282 |
+
# Resize logits and compute semantic segmentation maps
|
| 283 |
+
if target_sizes is not None:
|
| 284 |
+
if batch_size != len(target_sizes):
|
| 285 |
+
raise ValueError(
|
| 286 |
+
"Make sure that you pass in as many target sizes as the batch dimension of the logits"
|
| 287 |
+
)
|
| 288 |
+
|
| 289 |
+
semantic_segmentation = []
|
| 290 |
+
for idx in range(batch_size):
|
| 291 |
+
resized_logits = nn.functional.interpolate(
|
| 292 |
+
segmentation[idx].unsqueeze(dim=0), size=target_sizes[idx], mode="bilinear", align_corners=False
|
| 293 |
+
)
|
| 294 |
+
semantic_map = resized_logits[0].argmax(dim=0)
|
| 295 |
+
semantic_segmentation.append(semantic_map)
|
| 296 |
+
else:
|
| 297 |
+
semantic_segmentation = segmentation.argmax(dim=1)
|
| 298 |
+
semantic_segmentation = [semantic_segmentation[i] for i in range(semantic_segmentation.shape[0])]
|
| 299 |
+
|
| 300 |
+
return semantic_segmentation
|
| 301 |
+
|
| 302 |
+
|
| 303 |
+
class ConditionalDetrDecoderOutput(DetrDecoderOutput):
|
| 304 |
+
r"""
|
| 305 |
+
cross_attentions (`tuple(torch.FloatTensor)`, *optional*, returned when `output_attentions=True` and `config.add_cross_attention=True` is passed or when `config.output_attentions=True`):
|
| 306 |
+
Tuple of `torch.FloatTensor` (one for each layer) of shape `(batch_size, num_heads, sequence_length,
|
| 307 |
+
sequence_length)`. Attentions weights of the decoder's cross-attention layer, after the attention softmax,
|
| 308 |
+
used to compute the weighted average in the cross-attention heads.
|
| 309 |
+
intermediate_hidden_states (`torch.FloatTensor` of shape `(config.decoder_layers, batch_size, num_queries, hidden_size)`, *optional*, returned when `config.auxiliary_loss=True`):
|
| 310 |
+
Intermediate decoder activations, i.e. the output of each decoder layer, each of them gone through a
|
| 311 |
+
layernorm.
|
| 312 |
+
reference_points (`torch.FloatTensor` of shape `(config.decoder_layers, batch_size, num_queries, 2 (anchor points))`):
|
| 313 |
+
Reference points (reference points of each layer of the decoder).
|
| 314 |
+
"""
|
| 315 |
+
|
| 316 |
+
reference_points: tuple[torch.FloatTensor] | None = None
|
| 317 |
+
|
| 318 |
+
|
| 319 |
+
class ConditionalDetrModelOutput(DetrModelOutput):
|
| 320 |
+
r"""
|
| 321 |
+
last_hidden_state (`torch.FloatTensor` of shape `(batch_size, sequence_length, hidden_size)`):
|
| 322 |
+
Sequence of hidden-states at the output of the last layer of the decoder of the model.
|
| 323 |
+
intermediate_hidden_states (`torch.FloatTensor` of shape `(config.decoder_layers, batch_size, sequence_length, hidden_size)`, *optional*, returned when `config.auxiliary_loss=True`):
|
| 324 |
+
Intermediate decoder activations, i.e. the output of each decoder layer, each of them gone through a
|
| 325 |
+
layernorm.
|
| 326 |
+
reference_points (`torch.FloatTensor` of shape `(config.decoder_layers, batch_size, num_queries, 2 (anchor points))`):
|
| 327 |
+
Reference points (reference points of each layer of the decoder).
|
| 328 |
+
"""
|
| 329 |
+
|
| 330 |
+
reference_points: tuple[torch.FloatTensor] | None = None
|
| 331 |
+
|
| 332 |
+
|
| 333 |
+
# function to generate sine positional embedding for 2d coordinates
|
| 334 |
+
def gen_sine_position_embeddings(pos_tensor, d_model):
|
| 335 |
+
scale = 2 * math.pi
|
| 336 |
+
dim = d_model // 2
|
| 337 |
+
dim_t = torch.arange(dim, dtype=torch.float32, device=pos_tensor.device)
|
| 338 |
+
dim_t = 10000 ** (2 * torch.div(dim_t, 2, rounding_mode="floor") / dim)
|
| 339 |
+
x_embed = pos_tensor[:, :, 0] * scale
|
| 340 |
+
y_embed = pos_tensor[:, :, 1] * scale
|
| 341 |
+
pos_x = x_embed[:, :, None] / dim_t
|
| 342 |
+
pos_y = y_embed[:, :, None] / dim_t
|
| 343 |
+
pos_x = torch.stack((pos_x[:, :, 0::2].sin(), pos_x[:, :, 1::2].cos()), dim=3).flatten(2)
|
| 344 |
+
pos_y = torch.stack((pos_y[:, :, 0::2].sin(), pos_y[:, :, 1::2].cos()), dim=3).flatten(2)
|
| 345 |
+
pos = torch.cat((pos_y, pos_x), dim=2)
|
| 346 |
+
return pos.to(pos_tensor.dtype)
|
| 347 |
+
|
| 348 |
+
|
| 349 |
+
class ConditionalDetrObjectDetectionOutput(DetrObjectDetectionOutput):
|
| 350 |
+
pass
|
| 351 |
+
|
| 352 |
+
|
| 353 |
+
class ConditionalDetrSegmentationOutput(DetrSegmentationOutput):
|
| 354 |
+
pass
|
| 355 |
+
|
| 356 |
+
|
| 357 |
+
class ConditionalDetrConvEncoder(DetrConvEncoder):
|
| 358 |
+
pass
|
| 359 |
+
|
| 360 |
+
|
| 361 |
+
class ConditionalDetrSinePositionEmbedding(DetrSinePositionEmbedding):
|
| 362 |
+
pass
|
| 363 |
+
|
| 364 |
+
|
| 365 |
+
class ConditionalDetrLearnedPositionEmbedding(DetrLearnedPositionEmbedding):
|
| 366 |
+
pass
|
| 367 |
+
|
| 368 |
+
|
| 369 |
+
class ConditionalDetrSelfAttention(DetrSelfAttention):
|
| 370 |
+
pass
|
| 371 |
+
|
| 372 |
+
|
| 373 |
+
class ConditionalDetrDecoderSelfAttention(nn.Module):
|
| 374 |
+
"""
|
| 375 |
+
Multi-headed self-attention for Conditional DETR decoder layers.
|
| 376 |
+
|
| 377 |
+
This attention module handles separate content and position projections, which are then combined
|
| 378 |
+
before applying standard self-attention. Position embeddings are added to both queries and keys.
|
| 379 |
+
"""
|
| 380 |
+
|
| 381 |
+
def __init__(
|
| 382 |
+
self,
|
| 383 |
+
config: ConditionalDetrConfig,
|
| 384 |
+
hidden_size: int,
|
| 385 |
+
num_attention_heads: int,
|
| 386 |
+
dropout: float | int = 0.0,
|
| 387 |
+
):
|
| 388 |
+
super().__init__()
|
| 389 |
+
self.config = config
|
| 390 |
+
self.hidden_size = hidden_size
|
| 391 |
+
self.head_dim = hidden_size // num_attention_heads
|
| 392 |
+
self.scaling = self.head_dim**-0.5
|
| 393 |
+
self.attention_dropout = dropout
|
| 394 |
+
self.is_causal = False
|
| 395 |
+
|
| 396 |
+
# Content and position projections
|
| 397 |
+
self.q_content_proj = nn.Linear(hidden_size, hidden_size)
|
| 398 |
+
self.q_pos_proj = nn.Linear(hidden_size, hidden_size)
|
| 399 |
+
self.k_content_proj = nn.Linear(hidden_size, hidden_size)
|
| 400 |
+
self.k_pos_proj = nn.Linear(hidden_size, hidden_size)
|
| 401 |
+
self.v_proj = nn.Linear(hidden_size, hidden_size)
|
| 402 |
+
self.o_proj = nn.Linear(hidden_size, hidden_size)
|
| 403 |
+
|
| 404 |
+
def forward(
|
| 405 |
+
self,
|
| 406 |
+
hidden_states: torch.Tensor,
|
| 407 |
+
query_position_embeddings: torch.Tensor,
|
| 408 |
+
attention_mask: torch.Tensor | None = None,
|
| 409 |
+
**kwargs: Unpack[TransformersKwargs],
|
| 410 |
+
) -> tuple[torch.Tensor, torch.Tensor]:
|
| 411 |
+
"""
|
| 412 |
+
Args:
|
| 413 |
+
hidden_states (`torch.Tensor` of shape `(batch_size, num_queries, hidden_size)`):
|
| 414 |
+
Input hidden states from the decoder layer.
|
| 415 |
+
query_position_embeddings (`torch.Tensor` of shape `(batch_size, num_queries, hidden_size)`):
|
| 416 |
+
Position embeddings for queries and keys. Required (unlike standard attention). Processed through
|
| 417 |
+
separate position projections (`q_pos_proj`, `k_pos_proj`) and added to content projections.
|
| 418 |
+
attention_mask (`torch.Tensor` of shape `(batch_size, 1, num_queries, num_queries)`, *optional*):
|
| 419 |
+
Attention mask to avoid attending to padding tokens.
|
| 420 |
+
"""
|
| 421 |
+
input_shape = hidden_states.shape[:-1]
|
| 422 |
+
hidden_shape = (*input_shape, -1, self.head_dim)
|
| 423 |
+
|
| 424 |
+
query_states = (
|
| 425 |
+
(self.q_content_proj(hidden_states) + self.q_pos_proj(query_position_embeddings))
|
| 426 |
+
.view(hidden_shape)
|
| 427 |
+
.transpose(1, 2)
|
| 428 |
+
)
|
| 429 |
+
key_states = (
|
| 430 |
+
(self.k_content_proj(hidden_states) + self.k_pos_proj(query_position_embeddings))
|
| 431 |
+
.view(hidden_shape)
|
| 432 |
+
.transpose(1, 2)
|
| 433 |
+
)
|
| 434 |
+
value_states = self.v_proj(hidden_states).view(hidden_shape).transpose(1, 2)
|
| 435 |
+
|
| 436 |
+
attention_interface: Callable = ALL_ATTENTION_FUNCTIONS.get_interface(
|
| 437 |
+
self.config._attn_implementation, eager_attention_forward
|
| 438 |
+
)
|
| 439 |
+
|
| 440 |
+
attn_output, attn_weights = attention_interface(
|
| 441 |
+
self,
|
| 442 |
+
query_states,
|
| 443 |
+
key_states,
|
| 444 |
+
value_states,
|
| 445 |
+
attention_mask,
|
| 446 |
+
dropout=0.0 if not self.training else self.attention_dropout,
|
| 447 |
+
scaling=self.scaling,
|
| 448 |
+
**kwargs,
|
| 449 |
+
)
|
| 450 |
+
|
| 451 |
+
attn_output = attn_output.reshape(*input_shape, -1).contiguous()
|
| 452 |
+
attn_output = self.o_proj(attn_output)
|
| 453 |
+
return attn_output, attn_weights
|
| 454 |
+
|
| 455 |
+
|
| 456 |
+
class ConditionalDetrDecoderCrossAttention(nn.Module):
|
| 457 |
+
"""
|
| 458 |
+
Multi-headed cross-attention for Conditional DETR decoder layers.
|
| 459 |
+
|
| 460 |
+
This attention module handles the special cross-attention logic in Conditional DETR:
|
| 461 |
+
- Separate content and position projections for queries and keys
|
| 462 |
+
- Concatenation of query sine embeddings with queries (doubling query dimension)
|
| 463 |
+
- Concatenation of key position embeddings with keys (doubling key dimension)
|
| 464 |
+
- Output dimension remains hidden_size despite doubled input dimensions
|
| 465 |
+
"""
|
| 466 |
+
|
| 467 |
+
def __init__(
|
| 468 |
+
self,
|
| 469 |
+
config: ConditionalDetrConfig,
|
| 470 |
+
hidden_size: int,
|
| 471 |
+
num_attention_heads: int,
|
| 472 |
+
dropout: float | int = 0.0,
|
| 473 |
+
):
|
| 474 |
+
super().__init__()
|
| 475 |
+
self.config = config
|
| 476 |
+
self.hidden_size = hidden_size
|
| 477 |
+
self.num_attention_heads = num_attention_heads
|
| 478 |
+
self.head_dim = hidden_size // num_attention_heads
|
| 479 |
+
self.attention_dropout = dropout
|
| 480 |
+
self.is_causal = False
|
| 481 |
+
|
| 482 |
+
# Content and position projections
|
| 483 |
+
self.q_content_proj = nn.Linear(hidden_size, hidden_size)
|
| 484 |
+
self.q_pos_proj = nn.Linear(hidden_size, hidden_size)
|
| 485 |
+
self.k_content_proj = nn.Linear(hidden_size, hidden_size)
|
| 486 |
+
self.k_pos_proj = nn.Linear(hidden_size, hidden_size)
|
| 487 |
+
self.v_proj = nn.Linear(hidden_size, hidden_size)
|
| 488 |
+
self.q_pos_sine_proj = nn.Linear(hidden_size, hidden_size)
|
| 489 |
+
|
| 490 |
+
# Output projection: input is hidden_size * 2 (from concatenated q/k), output is hidden_size
|
| 491 |
+
self.o_proj = nn.Linear(hidden_size, hidden_size)
|
| 492 |
+
|
| 493 |
+
# Compute scaling for expanded head_dim (q and k have doubled dimensions after concatenation)
|
| 494 |
+
# This matches the original Conditional DETR implementation where embed_dim * 2 is used
|
| 495 |
+
expanded_head_dim = (hidden_size * 2) // num_attention_heads
|
| 496 |
+
self.scaling = expanded_head_dim**-0.5
|
| 497 |
+
|
| 498 |
+
def forward(
|
| 499 |
+
self,
|
| 500 |
+
hidden_states: torch.Tensor,
|
| 501 |
+
encoder_hidden_states: torch.Tensor,
|
| 502 |
+
query_sine_embed: torch.Tensor,
|
| 503 |
+
encoder_position_embeddings: torch.Tensor,
|
| 504 |
+
query_position_embeddings: torch.Tensor | None = None,
|
| 505 |
+
attention_mask: torch.Tensor | None = None,
|
| 506 |
+
**kwargs: Unpack[TransformersKwargs],
|
| 507 |
+
) -> tuple[torch.Tensor, torch.Tensor]:
|
| 508 |
+
"""
|
| 509 |
+
Args:
|
| 510 |
+
hidden_states (`torch.Tensor` of shape `(batch_size, num_queries, hidden_size)`):
|
| 511 |
+
Decoder hidden states (queries).
|
| 512 |
+
encoder_hidden_states (`torch.Tensor` of shape `(batch_size, encoder_seq_len, hidden_size)`):
|
| 513 |
+
Encoder output hidden states (keys and values).
|
| 514 |
+
query_sine_embed (`torch.Tensor` of shape `(batch_size, num_queries, hidden_size)`):
|
| 515 |
+
Sine position embeddings for queries. **Concatenated** (not added) with query content,
|
| 516 |
+
doubling the query dimension.
|
| 517 |
+
encoder_position_embeddings (`torch.Tensor` of shape `(batch_size, encoder_seq_len, hidden_size)`):
|
| 518 |
+
Position embeddings for keys. **Concatenated** (not added) with key content, doubling the key dimension.
|
| 519 |
+
query_position_embeddings (`torch.Tensor` of shape `(batch_size, num_queries, hidden_size)`, *optional*):
|
| 520 |
+
Additional position embeddings. When provided (first layer only), **added** to query content
|
| 521 |
+
before concatenation with `query_sine_embed`. Also causes `encoder_position_embeddings` to be
|
| 522 |
+
added to key content before concatenation.
|
| 523 |
+
attention_mask (`torch.Tensor` of shape `(batch_size, 1, num_queries, encoder_seq_len)`, *optional*):
|
| 524 |
+
Attention mask to avoid attending to padding tokens.
|
| 525 |
+
"""
|
| 526 |
+
query_input_shape = hidden_states.shape[:-1]
|
| 527 |
+
kv_input_shape = encoder_hidden_states.shape[:-1]
|
| 528 |
+
query_hidden_shape = (*query_input_shape, self.num_attention_heads, self.head_dim)
|
| 529 |
+
kv_hidden_shape = (*kv_input_shape, self.num_attention_heads, self.head_dim)
|
| 530 |
+
|
| 531 |
+
# Apply content and position projections
|
| 532 |
+
query_input = self.q_content_proj(hidden_states)
|
| 533 |
+
key_input = self.k_content_proj(encoder_hidden_states)
|
| 534 |
+
value_states = self.v_proj(encoder_hidden_states)
|
| 535 |
+
key_pos = self.k_pos_proj(encoder_position_embeddings)
|
| 536 |
+
|
| 537 |
+
# Combine content and position embeddings
|
| 538 |
+
if query_position_embeddings is not None:
|
| 539 |
+
query_input = query_input + self.q_pos_proj(query_position_embeddings)
|
| 540 |
+
key_input = key_input + key_pos
|
| 541 |
+
|
| 542 |
+
# Reshape and concatenate position embeddings (doubling head_dim)
|
| 543 |
+
query_input = query_input.view(query_hidden_shape)
|
| 544 |
+
key_input = key_input.view(kv_hidden_shape)
|
| 545 |
+
query_sine_embed = self.q_pos_sine_proj(query_sine_embed).view(query_hidden_shape)
|
| 546 |
+
key_pos = key_pos.view(kv_hidden_shape)
|
| 547 |
+
|
| 548 |
+
query_states = torch.cat([query_input, query_sine_embed], dim=-1).view(*query_input_shape, -1)
|
| 549 |
+
key_states = torch.cat([key_input, key_pos], dim=-1).view(*kv_input_shape, -1)
|
| 550 |
+
|
| 551 |
+
# Reshape for attention computation
|
| 552 |
+
expanded_head_dim = query_states.shape[-1] // self.num_attention_heads
|
| 553 |
+
query_states = query_states.view(*query_input_shape, self.num_attention_heads, expanded_head_dim).transpose(
|
| 554 |
+
1, 2
|
| 555 |
+
)
|
| 556 |
+
key_states = key_states.view(*kv_input_shape, self.num_attention_heads, expanded_head_dim).transpose(1, 2)
|
| 557 |
+
value_states = value_states.view(kv_hidden_shape).transpose(1, 2)
|
| 558 |
+
|
| 559 |
+
attention_interface: Callable = ALL_ATTENTION_FUNCTIONS.get_interface(
|
| 560 |
+
self.config._attn_implementation, eager_attention_forward
|
| 561 |
+
)
|
| 562 |
+
|
| 563 |
+
attn_output, attn_weights = attention_interface(
|
| 564 |
+
self,
|
| 565 |
+
query_states,
|
| 566 |
+
key_states,
|
| 567 |
+
value_states,
|
| 568 |
+
attention_mask,
|
| 569 |
+
dropout=0.0 if not self.training else self.attention_dropout,
|
| 570 |
+
scaling=self.scaling,
|
| 571 |
+
**kwargs,
|
| 572 |
+
)
|
| 573 |
+
|
| 574 |
+
attn_output = attn_output.reshape(*query_input_shape, -1).contiguous()
|
| 575 |
+
attn_output = self.o_proj(attn_output)
|
| 576 |
+
return attn_output, attn_weights
|
| 577 |
+
|
| 578 |
+
|
| 579 |
+
class ConditionalDetrMLP(DetrMLP):
|
| 580 |
+
pass
|
| 581 |
+
|
| 582 |
+
|
| 583 |
+
class ConditionalDetrEncoderLayer(DetrEncoderLayer):
|
| 584 |
+
pass
|
| 585 |
+
|
| 586 |
+
|
| 587 |
+
class ConditionalDetrDecoderLayer(DetrDecoderLayer):
|
| 588 |
+
def __init__(self, config: ConditionalDetrConfig):
|
| 589 |
+
super().__init__()
|
| 590 |
+
self.self_attn = ConditionalDetrDecoderSelfAttention(
|
| 591 |
+
config=config,
|
| 592 |
+
hidden_size=self.hidden_size,
|
| 593 |
+
num_attention_heads=config.decoder_attention_heads,
|
| 594 |
+
dropout=config.attention_dropout,
|
| 595 |
+
)
|
| 596 |
+
self.encoder_attn = ConditionalDetrDecoderCrossAttention(
|
| 597 |
+
config=config,
|
| 598 |
+
hidden_size=self.hidden_size,
|
| 599 |
+
num_attention_heads=config.decoder_attention_heads,
|
| 600 |
+
dropout=config.attention_dropout,
|
| 601 |
+
)
|
| 602 |
+
|
| 603 |
+
def forward(
|
| 604 |
+
self,
|
| 605 |
+
hidden_states: torch.Tensor,
|
| 606 |
+
attention_mask: torch.Tensor | None = None,
|
| 607 |
+
spatial_position_embeddings: torch.Tensor | None = None,
|
| 608 |
+
query_position_embeddings: torch.Tensor | None = None,
|
| 609 |
+
query_sine_embed: torch.Tensor | None = None,
|
| 610 |
+
encoder_hidden_states: torch.Tensor | None = None,
|
| 611 |
+
encoder_attention_mask: torch.Tensor | None = None,
|
| 612 |
+
is_first: bool | None = False,
|
| 613 |
+
**kwargs: Unpack[TransformersKwargs],
|
| 614 |
+
) -> torch.Tensor:
|
| 615 |
+
"""
|
| 616 |
+
Args:
|
| 617 |
+
hidden_states (`torch.FloatTensor`): input to the layer of shape `(seq_len, batch, embed_dim)`
|
| 618 |
+
attention_mask (`torch.FloatTensor`): attention mask of size
|
| 619 |
+
`(batch, 1, target_len, source_len)` where padding elements are indicated by very large negative
|
| 620 |
+
values.
|
| 621 |
+
spatial_position_embeddings (`torch.FloatTensor` of shape `(batch_size, sequence_length, hidden_size)`):
|
| 622 |
+
Spatial position embeddings (2D positional encodings) that are added to the queries and keys in each self-attention layer.
|
| 623 |
+
query_position_embeddings (`torch.FloatTensor`, *optional*):
|
| 624 |
+
object_queries that are added to the queries and keys
|
| 625 |
+
in the self-attention layer.
|
| 626 |
+
encoder_hidden_states (`torch.FloatTensor`):
|
| 627 |
+
cross attention input to the layer of shape `(seq_len, batch, embed_dim)`
|
| 628 |
+
encoder_attention_mask (`torch.FloatTensor`): encoder attention mask of size
|
| 629 |
+
`(batch, 1, target_len, source_len)` where padding elements are indicated by very large negative
|
| 630 |
+
values.
|
| 631 |
+
output_attentions (`bool`, *optional*):
|
| 632 |
+
Whether or not to return the attentions tensors of all attention layers. See `attentions` under
|
| 633 |
+
returned tensors for more detail.
|
| 634 |
+
"""
|
| 635 |
+
residual = hidden_states
|
| 636 |
+
|
| 637 |
+
hidden_states, _ = self.self_attn(
|
| 638 |
+
hidden_states=hidden_states,
|
| 639 |
+
query_position_embeddings=query_position_embeddings,
|
| 640 |
+
attention_mask=attention_mask,
|
| 641 |
+
**kwargs,
|
| 642 |
+
)
|
| 643 |
+
|
| 644 |
+
hidden_states = nn.functional.dropout(hidden_states, p=self.dropout, training=self.training)
|
| 645 |
+
hidden_states = residual + hidden_states
|
| 646 |
+
hidden_states = self.self_attn_layer_norm(hidden_states)
|
| 647 |
+
|
| 648 |
+
if encoder_hidden_states is not None:
|
| 649 |
+
residual = hidden_states
|
| 650 |
+
|
| 651 |
+
hidden_states, _ = self.encoder_attn(
|
| 652 |
+
hidden_states=hidden_states,
|
| 653 |
+
encoder_hidden_states=encoder_hidden_states,
|
| 654 |
+
attention_mask=encoder_attention_mask,
|
| 655 |
+
query_sine_embed=query_sine_embed,
|
| 656 |
+
encoder_position_embeddings=spatial_position_embeddings,
|
| 657 |
+
# Only pass query_position_embeddings for the first layer
|
| 658 |
+
query_position_embeddings=query_position_embeddings if is_first else None,
|
| 659 |
+
**kwargs,
|
| 660 |
+
)
|
| 661 |
+
|
| 662 |
+
hidden_states = nn.functional.dropout(hidden_states, p=self.dropout, training=self.training)
|
| 663 |
+
hidden_states = residual + hidden_states
|
| 664 |
+
hidden_states = self.encoder_attn_layer_norm(hidden_states)
|
| 665 |
+
|
| 666 |
+
# Fully Connected
|
| 667 |
+
residual = hidden_states
|
| 668 |
+
hidden_states = self.mlp(hidden_states)
|
| 669 |
+
hidden_states = residual + hidden_states
|
| 670 |
+
hidden_states = self.final_layer_norm(hidden_states)
|
| 671 |
+
|
| 672 |
+
return hidden_states
|
| 673 |
+
|
| 674 |
+
|
| 675 |
+
class ConditionalDetrMLPPredictionHead(DetrMLPPredictionHead):
|
| 676 |
+
pass
|
| 677 |
+
|
| 678 |
+
|
| 679 |
+
class ConditionalDetrPreTrainedModel(DetrPreTrainedModel):
|
| 680 |
+
_keys_to_ignore_on_load_unexpected = [
|
| 681 |
+
r"detr\.model\.backbone\.model\.layer\d+\.0\.downsample\.1\.num_batches_tracked"
|
| 682 |
+
]
|
| 683 |
+
|
| 684 |
+
|
| 685 |
+
class ConditionalDetrEncoder(DetrEncoder):
|
| 686 |
+
pass
|
| 687 |
+
|
| 688 |
+
|
| 689 |
+
class ConditionalDetrDecoder(ConditionalDetrPreTrainedModel):
|
| 690 |
+
"""
|
| 691 |
+
Transformer decoder consisting of *config.decoder_layers* layers. Each layer is a [`ConditionalDetrDecoderLayer`].
|
| 692 |
+
|
| 693 |
+
The decoder updates the query embeddings through multiple self-attention and cross-attention layers.
|
| 694 |
+
|
| 695 |
+
Some small tweaks for Conditional DETR:
|
| 696 |
+
|
| 697 |
+
- object_queries and query_position_embeddings are added to the forward pass.
|
| 698 |
+
- if self.config.auxiliary_loss is set to True, also returns a stack of activations from all decoding layers.
|
| 699 |
+
|
| 700 |
+
Args:
|
| 701 |
+
config: ConditionalDetrConfig
|
| 702 |
+
"""
|
| 703 |
+
|
| 704 |
+
_can_record_outputs = {
|
| 705 |
+
"hidden_states": ConditionalDetrDecoderLayer,
|
| 706 |
+
"attentions": OutputRecorder(ConditionalDetrDecoderSelfAttention, layer_name="self_attn", index=1),
|
| 707 |
+
"cross_attentions": OutputRecorder(ConditionalDetrDecoderCrossAttention, layer_name="encoder_attn", index=1),
|
| 708 |
+
}
|
| 709 |
+
|
| 710 |
+
def __init__(self, config: ConditionalDetrConfig):
|
| 711 |
+
super().__init__(config)
|
| 712 |
+
self.hidden_size = config.d_model
|
| 713 |
+
|
| 714 |
+
self.dropout = config.dropout
|
| 715 |
+
self.layerdrop = config.decoder_layerdrop
|
| 716 |
+
|
| 717 |
+
self.layers = nn.ModuleList([ConditionalDetrDecoderLayer(config) for _ in range(config.decoder_layers)])
|
| 718 |
+
# in Conditional DETR, the decoder uses layernorm after the last decoder layer output
|
| 719 |
+
self.layernorm = nn.LayerNorm(config.d_model)
|
| 720 |
+
|
| 721 |
+
# query_scale is the FFN applied on f to generate transformation T
|
| 722 |
+
self.query_scale = ConditionalDetrMLPPredictionHead(self.hidden_size, self.hidden_size, self.hidden_size, 2)
|
| 723 |
+
self.ref_point_head = ConditionalDetrMLPPredictionHead(self.hidden_size, self.hidden_size, 2, 2)
|
| 724 |
+
for layer_id in range(config.decoder_layers - 1):
|
| 725 |
+
# Set q_pos_proj to None for layers after the first (only first layer uses query position embeddings)
|
| 726 |
+
self.layers[layer_id + 1].encoder_attn.q_pos_proj = None
|
| 727 |
+
|
| 728 |
+
# Initialize weights and apply final processing
|
| 729 |
+
self.post_init()
|
| 730 |
+
|
| 731 |
+
@merge_with_config_defaults
|
| 732 |
+
@capture_outputs
|
| 733 |
+
def forward(
|
| 734 |
+
self,
|
| 735 |
+
inputs_embeds=None,
|
| 736 |
+
attention_mask=None,
|
| 737 |
+
encoder_hidden_states=None,
|
| 738 |
+
encoder_attention_mask=None,
|
| 739 |
+
spatial_position_embeddings=None,
|
| 740 |
+
object_queries_position_embeddings=None,
|
| 741 |
+
**kwargs: Unpack[TransformersKwargs],
|
| 742 |
+
) -> ConditionalDetrDecoderOutput:
|
| 743 |
+
r"""
|
| 744 |
+
Args:
|
| 745 |
+
inputs_embeds (`torch.FloatTensor` of shape `(batch_size, sequence_length, hidden_size)`):
|
| 746 |
+
The query embeddings that are passed into the decoder.
|
| 747 |
+
|
| 748 |
+
attention_mask (`torch.Tensor` of shape `(batch_size, sequence_length)`, *optional*):
|
| 749 |
+
Mask to avoid performing attention on certain queries. Mask values selected in `[0, 1]`:
|
| 750 |
+
|
| 751 |
+
- 1 for queries that are **not masked**,
|
| 752 |
+
- 0 for queries that are **masked**.
|
| 753 |
+
|
| 754 |
+
[What are attention masks?](../glossary#attention-mask)
|
| 755 |
+
encoder_hidden_states (`torch.FloatTensor` of shape `(batch_size, encoder_sequence_length, hidden_size)`, *optional*):
|
| 756 |
+
Sequence of hidden-states at the output of the last layer of the encoder. Used in the cross-attention
|
| 757 |
+
of the decoder.
|
| 758 |
+
encoder_attention_mask (`torch.LongTensor` of shape `(batch_size, encoder_sequence_length)`, *optional*):
|
| 759 |
+
Mask to avoid performing cross-attention on padding pixel_values of the encoder. Mask values selected
|
| 760 |
+
in `[0, 1]`:
|
| 761 |
+
|
| 762 |
+
- 1 for pixels that are real (i.e. **not masked**),
|
| 763 |
+
- 0 for pixels that are padding (i.e. **masked**).
|
| 764 |
+
|
| 765 |
+
spatial_position_embeddings (`torch.FloatTensor` of shape `(batch_size, sequence_length, hidden_size)`, *optional*):
|
| 766 |
+
Spatial position embeddings that are added to the queries and keys in each cross-attention layer.
|
| 767 |
+
object_queries_position_embeddings (`torch.FloatTensor` of shape `(batch_size, num_queries, hidden_size)`):
|
| 768 |
+
, *optional*): Position embeddings that are added to the queries and keys in each self-attention layer.
|
| 769 |
+
"""
|
| 770 |
+
if inputs_embeds is not None:
|
| 771 |
+
hidden_states = inputs_embeds
|
| 772 |
+
|
| 773 |
+
# expand encoder attention mask
|
| 774 |
+
if encoder_hidden_states is not None and encoder_attention_mask is not None:
|
| 775 |
+
# [batch_size, seq_len] -> [batch_size, 1, target_seq_len, source_seq_len]
|
| 776 |
+
encoder_attention_mask = create_bidirectional_mask(
|
| 777 |
+
self.config,
|
| 778 |
+
inputs_embeds,
|
| 779 |
+
encoder_attention_mask,
|
| 780 |
+
)
|
| 781 |
+
|
| 782 |
+
# optional intermediate hidden states
|
| 783 |
+
intermediate = () if self.config.auxiliary_loss else None
|
| 784 |
+
|
| 785 |
+
reference_points_before_sigmoid = self.ref_point_head(
|
| 786 |
+
object_queries_position_embeddings
|
| 787 |
+
) # [num_queries, batch_size, 2]
|
| 788 |
+
reference_points = reference_points_before_sigmoid.sigmoid().transpose(0, 1)
|
| 789 |
+
obj_center = reference_points[..., :2].transpose(0, 1)
|
| 790 |
+
# get sine embedding for the query vector
|
| 791 |
+
query_sine_embed_before_transformation = gen_sine_position_embeddings(obj_center, self.config.d_model)
|
| 792 |
+
|
| 793 |
+
for idx, decoder_layer in enumerate(self.layers):
|
| 794 |
+
if self.training:
|
| 795 |
+
dropout_probability = torch.rand([])
|
| 796 |
+
if dropout_probability < self.layerdrop:
|
| 797 |
+
continue
|
| 798 |
+
if idx == 0:
|
| 799 |
+
pos_transformation = 1
|
| 800 |
+
else:
|
| 801 |
+
pos_transformation = self.query_scale(hidden_states)
|
| 802 |
+
# apply transformation
|
| 803 |
+
query_sine_embed = query_sine_embed_before_transformation * pos_transformation
|
| 804 |
+
|
| 805 |
+
hidden_states = decoder_layer(
|
| 806 |
+
hidden_states,
|
| 807 |
+
None,
|
| 808 |
+
spatial_position_embeddings,
|
| 809 |
+
object_queries_position_embeddings,
|
| 810 |
+
query_sine_embed,
|
| 811 |
+
encoder_hidden_states, # as a positional argument for gradient checkpointing
|
| 812 |
+
encoder_attention_mask=encoder_attention_mask,
|
| 813 |
+
is_first=(idx == 0),
|
| 814 |
+
**kwargs,
|
| 815 |
+
)
|
| 816 |
+
|
| 817 |
+
if self.config.auxiliary_loss:
|
| 818 |
+
hidden_states = self.layernorm(hidden_states)
|
| 819 |
+
intermediate += (hidden_states,)
|
| 820 |
+
|
| 821 |
+
# finally, apply layernorm
|
| 822 |
+
hidden_states = self.layernorm(hidden_states)
|
| 823 |
+
|
| 824 |
+
# stack intermediate decoder activations
|
| 825 |
+
if self.config.auxiliary_loss:
|
| 826 |
+
intermediate = torch.stack(intermediate)
|
| 827 |
+
|
| 828 |
+
return ConditionalDetrDecoderOutput(
|
| 829 |
+
last_hidden_state=hidden_states,
|
| 830 |
+
intermediate_hidden_states=intermediate,
|
| 831 |
+
reference_points=reference_points,
|
| 832 |
+
)
|
| 833 |
+
|
| 834 |
+
|
| 835 |
+
class ConditionalDetrModel(DetrModel):
|
| 836 |
+
def __init__(self, config: ConditionalDetrConfig):
|
| 837 |
+
super().__init__(config)
|
| 838 |
+
self.query_position_embeddings = nn.Embedding(config.num_queries, config.d_model)
|
| 839 |
+
|
| 840 |
+
# Initialize weights and apply final processing
|
| 841 |
+
self.post_init()
|
| 842 |
+
|
| 843 |
+
@auto_docstring
|
| 844 |
+
@can_return_tuple
|
| 845 |
+
def forward(
|
| 846 |
+
self,
|
| 847 |
+
pixel_values: torch.FloatTensor,
|
| 848 |
+
pixel_mask: torch.LongTensor | None = None,
|
| 849 |
+
decoder_attention_mask: torch.LongTensor | None = None,
|
| 850 |
+
encoder_outputs: torch.FloatTensor | None = None,
|
| 851 |
+
inputs_embeds: torch.FloatTensor | None = None,
|
| 852 |
+
decoder_inputs_embeds: torch.FloatTensor | None = None,
|
| 853 |
+
**kwargs: Unpack[TransformersKwargs],
|
| 854 |
+
) -> ConditionalDetrModelOutput:
|
| 855 |
+
r"""
|
| 856 |
+
decoder_attention_mask (`torch.FloatTensor` of shape `(batch_size, num_queries)`, *optional*):
|
| 857 |
+
Not used by default. Can be used to mask object queries.
|
| 858 |
+
inputs_embeds (`torch.FloatTensor` of shape `(batch_size, sequence_length, hidden_size)`, *optional*):
|
| 859 |
+
Optionally, instead of passing the flattened feature map (output of the backbone + projection layer), you
|
| 860 |
+
can choose to directly pass a flattened representation of an image.
|
| 861 |
+
decoder_inputs_embeds (`torch.FloatTensor` of shape `(batch_size, num_queries, hidden_size)`, *optional*):
|
| 862 |
+
Optionally, instead of initializing the queries with a tensor of zeros, you can choose to directly pass an
|
| 863 |
+
embedded representation.
|
| 864 |
+
|
| 865 |
+
Examples:
|
| 866 |
+
|
| 867 |
+
```python
|
| 868 |
+
>>> from transformers import AutoImageProcessor, AutoModel
|
| 869 |
+
>>> from PIL import Image
|
| 870 |
+
>>> import requests
|
| 871 |
+
|
| 872 |
+
>>> url = "http://images.cocodataset.org/val2017/000000039769.jpg"
|
| 873 |
+
>>> image = Image.open(requests.get(url, stream=True).raw)
|
| 874 |
+
|
| 875 |
+
>>> image_processor = AutoImageProcessor.from_pretrained("microsoft/conditional-detr-resnet-50")
|
| 876 |
+
>>> model = AutoModel.from_pretrained("microsoft/conditional-detr-resnet-50")
|
| 877 |
+
|
| 878 |
+
>>> # prepare image for the model
|
| 879 |
+
>>> inputs = image_processor(images=image, return_tensors="pt")
|
| 880 |
+
|
| 881 |
+
>>> # forward pass
|
| 882 |
+
>>> outputs = model(**inputs)
|
| 883 |
+
|
| 884 |
+
>>> # the last hidden states are the final query embeddings of the Transformer decoder
|
| 885 |
+
>>> # these are of shape (batch_size, num_queries, hidden_size)
|
| 886 |
+
>>> last_hidden_states = outputs.last_hidden_state
|
| 887 |
+
>>> list(last_hidden_states.shape)
|
| 888 |
+
[1, 300, 256]
|
| 889 |
+
```"""
|
| 890 |
+
batch_size, num_channels, height, width = pixel_values.shape
|
| 891 |
+
device = pixel_values.device
|
| 892 |
+
|
| 893 |
+
if pixel_mask is None:
|
| 894 |
+
pixel_mask = torch.ones(((batch_size, height, width)), device=device)
|
| 895 |
+
|
| 896 |
+
# First, sent pixel_values + pixel_mask through Backbone to obtain the features
|
| 897 |
+
# pixel_values should be of shape (batch_size, num_channels, height, width)
|
| 898 |
+
# pixel_mask should be of shape (batch_size, height, width)
|
| 899 |
+
features = self.backbone(pixel_values, pixel_mask)
|
| 900 |
+
|
| 901 |
+
# get final feature map and downsampled mask
|
| 902 |
+
feature_map, mask = features[-1]
|
| 903 |
+
|
| 904 |
+
if mask is None:
|
| 905 |
+
raise ValueError("Backbone does not return downsampled pixel mask")
|
| 906 |
+
|
| 907 |
+
# Second, apply 1x1 convolution to reduce the channel dimension to d_model (256 by default)
|
| 908 |
+
projected_feature_map = self.input_projection(feature_map)
|
| 909 |
+
|
| 910 |
+
# Generate position embeddings
|
| 911 |
+
spatial_position_embeddings = self.position_embedding(
|
| 912 |
+
shape=feature_map.shape, device=device, dtype=pixel_values.dtype, mask=mask
|
| 913 |
+
)
|
| 914 |
+
|
| 915 |
+
# Third, flatten the feature map of shape NxCxHxW to NxCxHW, and permute it to NxHWxC
|
| 916 |
+
# In other words, turn their shape into (batch_size, sequence_length, hidden_size)
|
| 917 |
+
flattened_features = projected_feature_map.flatten(2).permute(0, 2, 1)
|
| 918 |
+
|
| 919 |
+
flattened_mask = mask.flatten(1)
|
| 920 |
+
|
| 921 |
+
# Fourth, sent flattened_features + flattened_mask + spatial_position_embeddings through encoder
|
| 922 |
+
# flattened_features is a Tensor of shape (batch_size, height*width, hidden_size)
|
| 923 |
+
# flattened_mask is a Tensor of shape (batch_size, height*width)
|
| 924 |
+
if encoder_outputs is None:
|
| 925 |
+
encoder_outputs = self.encoder(
|
| 926 |
+
inputs_embeds=flattened_features,
|
| 927 |
+
attention_mask=flattened_mask,
|
| 928 |
+
spatial_position_embeddings=spatial_position_embeddings,
|
| 929 |
+
**kwargs,
|
| 930 |
+
)
|
| 931 |
+
# If the user passed a tuple for encoder_outputs, we wrap it in a BaseModelOutput
|
| 932 |
+
elif not isinstance(encoder_outputs, BaseModelOutput):
|
| 933 |
+
encoder_outputs = BaseModelOutput(
|
| 934 |
+
last_hidden_state=encoder_outputs[0],
|
| 935 |
+
hidden_states=encoder_outputs[1] if len(encoder_outputs) > 1 else None,
|
| 936 |
+
attentions=encoder_outputs[2] if len(encoder_outputs) > 2 else None,
|
| 937 |
+
)
|
| 938 |
+
|
| 939 |
+
# Fifth, sent query embeddings through the decoder (which is conditioned on the encoder output)
|
| 940 |
+
object_queries_position_embeddings = self.query_position_embeddings.weight.unsqueeze(0).repeat(
|
| 941 |
+
batch_size, 1, 1
|
| 942 |
+
)
|
| 943 |
+
queries = torch.zeros_like(object_queries_position_embeddings)
|
| 944 |
+
|
| 945 |
+
# decoder outputs consists of (dec_features, dec_hidden, dec_attn)
|
| 946 |
+
decoder_outputs = self.decoder(
|
| 947 |
+
inputs_embeds=queries,
|
| 948 |
+
attention_mask=None,
|
| 949 |
+
spatial_position_embeddings=spatial_position_embeddings,
|
| 950 |
+
object_queries_position_embeddings=object_queries_position_embeddings,
|
| 951 |
+
encoder_hidden_states=encoder_outputs.last_hidden_state,
|
| 952 |
+
encoder_attention_mask=flattened_mask,
|
| 953 |
+
**kwargs,
|
| 954 |
+
)
|
| 955 |
+
|
| 956 |
+
return ConditionalDetrModelOutput(
|
| 957 |
+
last_hidden_state=decoder_outputs.last_hidden_state,
|
| 958 |
+
decoder_hidden_states=decoder_outputs.hidden_states,
|
| 959 |
+
decoder_attentions=decoder_outputs.attentions,
|
| 960 |
+
cross_attentions=decoder_outputs.cross_attentions,
|
| 961 |
+
encoder_last_hidden_state=encoder_outputs.last_hidden_state,
|
| 962 |
+
encoder_hidden_states=encoder_outputs.hidden_states,
|
| 963 |
+
encoder_attentions=encoder_outputs.attentions,
|
| 964 |
+
intermediate_hidden_states=decoder_outputs.intermediate_hidden_states,
|
| 965 |
+
reference_points=decoder_outputs.reference_points,
|
| 966 |
+
)
|
| 967 |
+
|
| 968 |
+
|
| 969 |
+
class ConditionalDetrForObjectDetection(DetrForObjectDetection):
|
| 970 |
+
def __init__(self, config: ConditionalDetrConfig):
|
| 971 |
+
super().__init__(config)
|
| 972 |
+
self.class_labels_classifier = nn.Linear(config.d_model, config.num_labels)
|
| 973 |
+
|
| 974 |
+
# taken from https://github.com/Atten4Vis/conditionalDETR/blob/master/models/conditional_detr.py
|
| 975 |
+
def _set_aux_loss(self, outputs_class, outputs_coord):
|
| 976 |
+
return [{"logits": a, "pred_boxes": b} for a, b in zip(outputs_class[:-1], outputs_coord[:-1])]
|
| 977 |
+
|
| 978 |
+
@auto_docstring
|
| 979 |
+
@can_return_tuple
|
| 980 |
+
def forward(
|
| 981 |
+
self,
|
| 982 |
+
pixel_values: torch.FloatTensor,
|
| 983 |
+
pixel_mask: torch.LongTensor | None = None,
|
| 984 |
+
decoder_attention_mask: torch.LongTensor | None = None,
|
| 985 |
+
encoder_outputs: torch.FloatTensor | None = None,
|
| 986 |
+
inputs_embeds: torch.FloatTensor | None = None,
|
| 987 |
+
decoder_inputs_embeds: torch.FloatTensor | None = None,
|
| 988 |
+
labels: list[dict] | None = None,
|
| 989 |
+
**kwargs: Unpack[TransformersKwargs],
|
| 990 |
+
) -> ConditionalDetrObjectDetectionOutput:
|
| 991 |
+
r"""
|
| 992 |
+
decoder_attention_mask (`torch.FloatTensor` of shape `(batch_size, num_queries)`, *optional*):
|
| 993 |
+
Not used by default. Can be used to mask object queries.
|
| 994 |
+
inputs_embeds (`torch.FloatTensor` of shape `(batch_size, sequence_length, hidden_size)`, *optional*):
|
| 995 |
+
Optionally, instead of passing the flattened feature map (output of the backbone + projection layer), you
|
| 996 |
+
can choose to directly pass a flattened representation of an image.
|
| 997 |
+
decoder_inputs_embeds (`torch.FloatTensor` of shape `(batch_size, num_queries, hidden_size)`, *optional*):
|
| 998 |
+
Optionally, instead of initializing the queries with a tensor of zeros, you can choose to directly pass an
|
| 999 |
+
embedded representation.
|
| 1000 |
+
labels (`list[Dict]` of len `(batch_size,)`, *optional*):
|
| 1001 |
+
Labels for computing the bipartite matching loss. List of dicts, each dictionary containing at least the
|
| 1002 |
+
following 2 keys: 'class_labels' and 'boxes' (the class labels and bounding boxes of an image in the batch
|
| 1003 |
+
respectively). The class labels themselves should be a `torch.LongTensor` of len `(number of bounding boxes
|
| 1004 |
+
in the image,)` and the boxes a `torch.FloatTensor` of shape `(number of bounding boxes in the image, 4)`.
|
| 1005 |
+
|
| 1006 |
+
Examples:
|
| 1007 |
+
|
| 1008 |
+
```python
|
| 1009 |
+
>>> from transformers import AutoImageProcessor, AutoModelForObjectDetection
|
| 1010 |
+
>>> from PIL import Image
|
| 1011 |
+
>>> import requests
|
| 1012 |
+
|
| 1013 |
+
>>> url = "http://images.cocodataset.org/val2017/000000039769.jpg"
|
| 1014 |
+
>>> image = Image.open(requests.get(url, stream=True).raw)
|
| 1015 |
+
|
| 1016 |
+
>>> image_processor = AutoImageProcessor.from_pretrained("microsoft/conditional-detr-resnet-50")
|
| 1017 |
+
>>> model = AutoModelForObjectDetection.from_pretrained("microsoft/conditional-detr-resnet-50")
|
| 1018 |
+
|
| 1019 |
+
>>> inputs = image_processor(images=image, return_tensors="pt")
|
| 1020 |
+
|
| 1021 |
+
>>> outputs = model(**inputs)
|
| 1022 |
+
|
| 1023 |
+
>>> # convert outputs (bounding boxes and class logits) to Pascal VOC format (xmin, ymin, xmax, ymax)
|
| 1024 |
+
>>> target_sizes = torch.tensor([image.size[::-1]])
|
| 1025 |
+
>>> results = image_processor.post_process_object_detection(outputs, threshold=0.5, target_sizes=target_sizes)[
|
| 1026 |
+
... 0
|
| 1027 |
+
... ]
|
| 1028 |
+
>>> for score, label, box in zip(results["scores"], results["labels"], results["boxes"]):
|
| 1029 |
+
... box = [round(i, 2) for i in box.tolist()]
|
| 1030 |
+
... print(
|
| 1031 |
+
... f"Detected {model.config.id2label[label.item()]} with confidence "
|
| 1032 |
+
... f"{round(score.item(), 3)} at location {box}"
|
| 1033 |
+
... )
|
| 1034 |
+
Detected remote with confidence 0.833 at location [38.31, 72.1, 177.63, 118.45]
|
| 1035 |
+
Detected cat with confidence 0.831 at location [9.2, 51.38, 321.13, 469.0]
|
| 1036 |
+
Detected cat with confidence 0.804 at location [340.3, 16.85, 642.93, 370.95]
|
| 1037 |
+
Detected remote with confidence 0.683 at location [334.48, 73.49, 366.37, 190.01]
|
| 1038 |
+
Detected couch with confidence 0.535 at location [0.52, 1.19, 640.35, 475.1]
|
| 1039 |
+
```"""
|
| 1040 |
+
# First, sent images through CONDITIONAL_DETR base model to obtain encoder + decoder outputs
|
| 1041 |
+
outputs = self.model(
|
| 1042 |
+
pixel_values,
|
| 1043 |
+
pixel_mask=pixel_mask,
|
| 1044 |
+
decoder_attention_mask=decoder_attention_mask,
|
| 1045 |
+
encoder_outputs=encoder_outputs,
|
| 1046 |
+
inputs_embeds=inputs_embeds,
|
| 1047 |
+
decoder_inputs_embeds=decoder_inputs_embeds,
|
| 1048 |
+
**kwargs,
|
| 1049 |
+
)
|
| 1050 |
+
|
| 1051 |
+
sequence_output = outputs[0]
|
| 1052 |
+
|
| 1053 |
+
# class logits + predicted bounding boxes
|
| 1054 |
+
logits = self.class_labels_classifier(sequence_output)
|
| 1055 |
+
|
| 1056 |
+
reference = outputs.reference_points
|
| 1057 |
+
reference_before_sigmoid = inverse_sigmoid(reference).transpose(0, 1)
|
| 1058 |
+
|
| 1059 |
+
hs = sequence_output
|
| 1060 |
+
tmp = self.bbox_predictor(hs)
|
| 1061 |
+
tmp[..., :2] += reference_before_sigmoid
|
| 1062 |
+
pred_boxes = tmp.sigmoid()
|
| 1063 |
+
# pred_boxes = self.bbox_predictor(sequence_output).sigmoid()
|
| 1064 |
+
|
| 1065 |
+
loss, loss_dict, auxiliary_outputs = None, None, None
|
| 1066 |
+
if labels is not None:
|
| 1067 |
+
outputs_class, outputs_coord = None, None
|
| 1068 |
+
if self.config.auxiliary_loss:
|
| 1069 |
+
outputs_coords = []
|
| 1070 |
+
intermediate = outputs.intermediate_hidden_states
|
| 1071 |
+
outputs_class = self.class_labels_classifier(intermediate)
|
| 1072 |
+
for lvl in range(intermediate.shape[0]):
|
| 1073 |
+
tmp = self.bbox_predictor(intermediate[lvl])
|
| 1074 |
+
tmp[..., :2] += reference_before_sigmoid
|
| 1075 |
+
outputs_coord = tmp.sigmoid()
|
| 1076 |
+
outputs_coords.append(outputs_coord)
|
| 1077 |
+
outputs_coord = torch.stack(outputs_coords)
|
| 1078 |
+
loss, loss_dict, auxiliary_outputs = self.loss_function(
|
| 1079 |
+
logits, labels, self.device, pred_boxes, self.config, outputs_class, outputs_coord
|
| 1080 |
+
)
|
| 1081 |
+
|
| 1082 |
+
return ConditionalDetrObjectDetectionOutput(
|
| 1083 |
+
loss=loss,
|
| 1084 |
+
loss_dict=loss_dict,
|
| 1085 |
+
logits=logits,
|
| 1086 |
+
pred_boxes=pred_boxes,
|
| 1087 |
+
auxiliary_outputs=auxiliary_outputs,
|
| 1088 |
+
last_hidden_state=outputs.last_hidden_state,
|
| 1089 |
+
decoder_hidden_states=outputs.decoder_hidden_states,
|
| 1090 |
+
decoder_attentions=outputs.decoder_attentions,
|
| 1091 |
+
cross_attentions=outputs.cross_attentions,
|
| 1092 |
+
encoder_last_hidden_state=outputs.encoder_last_hidden_state,
|
| 1093 |
+
encoder_hidden_states=outputs.encoder_hidden_states,
|
| 1094 |
+
encoder_attentions=outputs.encoder_attentions,
|
| 1095 |
+
)
|
| 1096 |
+
|
| 1097 |
+
|
| 1098 |
+
class ConditionalDetrForSegmentation(DetrForSegmentation):
|
| 1099 |
+
pass
|
| 1100 |
+
|
| 1101 |
+
|
| 1102 |
+
__all__ = [
|
| 1103 |
+
"ConditionalDetrImageProcessor",
|
| 1104 |
+
"ConditionalDetrImageProcessorPil",
|
| 1105 |
+
"ConditionalDetrForObjectDetection",
|
| 1106 |
+
"ConditionalDetrForSegmentation",
|
| 1107 |
+
"ConditionalDetrModel",
|
| 1108 |
+
"ConditionalDetrPreTrainedModel",
|
| 1109 |
+
]
|
third_party/transformers/src/transformers/models/donut/__init__.py
ADDED
|
@@ -0,0 +1,30 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
# Copyright 2024 The HuggingFace Team. All rights reserved.
|
| 2 |
+
#
|
| 3 |
+
# Licensed under the Apache License, Version 2.0 (the "License");
|
| 4 |
+
# you may not use this file except in compliance with the License.
|
| 5 |
+
# You may obtain a copy of the License at
|
| 6 |
+
#
|
| 7 |
+
# http://www.apache.org/licenses/LICENSE-2.0
|
| 8 |
+
#
|
| 9 |
+
# Unless required by applicable law or agreed to in writing, software
|
| 10 |
+
# distributed under the License is distributed on an "AS IS" BASIS,
|
| 11 |
+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
| 12 |
+
# See the License for the specific language governing permissions and
|
| 13 |
+
# limitations under the License.
|
| 14 |
+
from typing import TYPE_CHECKING
|
| 15 |
+
|
| 16 |
+
from ...utils import _LazyModule
|
| 17 |
+
from ...utils.import_utils import define_import_structure
|
| 18 |
+
|
| 19 |
+
|
| 20 |
+
if TYPE_CHECKING:
|
| 21 |
+
from .configuration_donut_swin import *
|
| 22 |
+
from .image_processing_donut import *
|
| 23 |
+
from .image_processing_pil_donut import *
|
| 24 |
+
from .modeling_donut_swin import *
|
| 25 |
+
from .processing_donut import *
|
| 26 |
+
else:
|
| 27 |
+
import sys
|
| 28 |
+
|
| 29 |
+
_file = globals()["__file__"]
|
| 30 |
+
sys.modules[__name__] = _LazyModule(__name__, _file, define_import_structure(_file), module_spec=__spec__)
|
third_party/transformers/src/transformers/models/donut/configuration_donut_swin.py
ADDED
|
@@ -0,0 +1,76 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
# Copyright 2022 The HuggingFace Inc. team. All rights reserved.
|
| 2 |
+
#
|
| 3 |
+
# Licensed under the Apache License, Version 2.0 (the "License");
|
| 4 |
+
# you may not use this file except in compliance with the License.
|
| 5 |
+
# You may obtain a copy of the License at
|
| 6 |
+
#
|
| 7 |
+
# http://www.apache.org/licenses/LICENSE-2.0
|
| 8 |
+
#
|
| 9 |
+
# Unless required by applicable law or agreed to in writing, software
|
| 10 |
+
# distributed under the License is distributed on an "AS IS" BASIS,
|
| 11 |
+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
| 12 |
+
# See the License for the specific language governing permissions and
|
| 13 |
+
# limitations under the License.
|
| 14 |
+
"""Donut Swin Transformer model configuration"""
|
| 15 |
+
|
| 16 |
+
from huggingface_hub.dataclasses import strict
|
| 17 |
+
|
| 18 |
+
from ...configuration_utils import PreTrainedConfig
|
| 19 |
+
from ...utils import auto_docstring
|
| 20 |
+
|
| 21 |
+
|
| 22 |
+
@auto_docstring(checkpoint="naver-clova-ix/donut-base")
|
| 23 |
+
@strict
|
| 24 |
+
class DonutSwinConfig(PreTrainedConfig):
|
| 25 |
+
r"""
|
| 26 |
+
window_size (`int`, *optional*, defaults to 7):
|
| 27 |
+
Size of windows.
|
| 28 |
+
|
| 29 |
+
Example:
|
| 30 |
+
|
| 31 |
+
```python
|
| 32 |
+
>>> from transformers import DonutSwinConfig, DonutSwinModel
|
| 33 |
+
|
| 34 |
+
>>> # Initializing a Donut naver-clova-ix/donut-base style configuration
|
| 35 |
+
>>> configuration = DonutSwinConfig()
|
| 36 |
+
|
| 37 |
+
>>> # Randomly initializing a model from the naver-clova-ix/donut-base style configuration
|
| 38 |
+
>>> model = DonutSwinModel(configuration)
|
| 39 |
+
|
| 40 |
+
>>> # Accessing the model configuration
|
| 41 |
+
>>> configuration = model.config
|
| 42 |
+
```"""
|
| 43 |
+
|
| 44 |
+
model_type = "donut-swin"
|
| 45 |
+
|
| 46 |
+
attribute_map = {
|
| 47 |
+
"num_attention_heads": "num_heads",
|
| 48 |
+
"num_hidden_layers": "num_layers",
|
| 49 |
+
}
|
| 50 |
+
|
| 51 |
+
image_size: int | list[int] | tuple[int, int] = 224
|
| 52 |
+
patch_size: int | list[int] | tuple[int, int] = 4
|
| 53 |
+
num_channels: int = 3
|
| 54 |
+
embed_dim: int = 96
|
| 55 |
+
depths: list[int] | tuple[int, ...] = (2, 2, 6, 2)
|
| 56 |
+
num_heads: list[int] | tuple[int, ...] = (3, 6, 12, 24)
|
| 57 |
+
window_size: int = 7
|
| 58 |
+
mlp_ratio: float = 4.0
|
| 59 |
+
qkv_bias: bool = True
|
| 60 |
+
hidden_dropout_prob: float | int = 0.0
|
| 61 |
+
attention_probs_dropout_prob: float | int = 0.0
|
| 62 |
+
drop_path_rate: float | int = 0.1
|
| 63 |
+
hidden_act: str = "gelu"
|
| 64 |
+
use_absolute_embeddings: bool = False
|
| 65 |
+
initializer_range: float = 0.02
|
| 66 |
+
layer_norm_eps: float = 1e-5
|
| 67 |
+
|
| 68 |
+
def __post_init__(self, **kwargs):
|
| 69 |
+
self.num_layers = len(self.depths)
|
| 70 |
+
# we set the hidden_size attribute in order to make Swin work with VisionEncoderDecoderModel
|
| 71 |
+
# this indicates the channel dimension after the last stage of the model
|
| 72 |
+
self.hidden_size = int(self.embed_dim * 2 ** (len(self.depths) - 1))
|
| 73 |
+
super().__post_init__(**kwargs)
|
| 74 |
+
|
| 75 |
+
|
| 76 |
+
__all__ = ["DonutSwinConfig"]
|
third_party/transformers/src/transformers/models/donut/convert_donut_to_pytorch.py
ADDED
|
@@ -0,0 +1,233 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
# Copyright 2022 The HuggingFace Inc. team.
|
| 2 |
+
#
|
| 3 |
+
# Licensed under the Apache License, Version 2.0 (the "License");
|
| 4 |
+
# you may not use this file except in compliance with the License.
|
| 5 |
+
# You may obtain a copy of the License at
|
| 6 |
+
#
|
| 7 |
+
# http://www.apache.org/licenses/LICENSE-2.0
|
| 8 |
+
#
|
| 9 |
+
# Unless required by applicable law or agreed to in writing, software
|
| 10 |
+
# distributed under the License is distributed on an "AS IS" BASIS,
|
| 11 |
+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
| 12 |
+
# See the License for the specific language governing permissions and
|
| 13 |
+
# limitations under the License.
|
| 14 |
+
"""Convert Donut checkpoints using the original `donut-python` library. URL: https://github.com/clovaai/donut"""
|
| 15 |
+
|
| 16 |
+
import argparse
|
| 17 |
+
|
| 18 |
+
import torch
|
| 19 |
+
from datasets import load_dataset
|
| 20 |
+
from donut import DonutModel
|
| 21 |
+
|
| 22 |
+
from transformers import (
|
| 23 |
+
DonutImageProcessor,
|
| 24 |
+
DonutProcessor,
|
| 25 |
+
DonutSwinConfig,
|
| 26 |
+
DonutSwinModel,
|
| 27 |
+
MBartConfig,
|
| 28 |
+
MBartForCausalLM,
|
| 29 |
+
VisionEncoderDecoderModel,
|
| 30 |
+
XLMRobertaTokenizerFast,
|
| 31 |
+
)
|
| 32 |
+
|
| 33 |
+
|
| 34 |
+
def get_configs(model):
|
| 35 |
+
original_config = model.config
|
| 36 |
+
|
| 37 |
+
encoder_config = DonutSwinConfig(
|
| 38 |
+
image_size=original_config.input_size,
|
| 39 |
+
patch_size=4,
|
| 40 |
+
depths=original_config.encoder_layer,
|
| 41 |
+
num_heads=[4, 8, 16, 32],
|
| 42 |
+
window_size=original_config.window_size,
|
| 43 |
+
embed_dim=128,
|
| 44 |
+
)
|
| 45 |
+
decoder_config = MBartConfig(
|
| 46 |
+
is_decoder=True,
|
| 47 |
+
is_encoder_decoder=False,
|
| 48 |
+
add_cross_attention=True,
|
| 49 |
+
decoder_layers=original_config.decoder_layer,
|
| 50 |
+
max_position_embeddings=original_config.max_position_embeddings,
|
| 51 |
+
vocab_size=len(
|
| 52 |
+
model.decoder.tokenizer
|
| 53 |
+
), # several special tokens are added to the vocab of XLMRobertaTokenizer, see repo on the hub (added_tokens.json)
|
| 54 |
+
scale_embedding=True,
|
| 55 |
+
add_final_layer_norm=True,
|
| 56 |
+
)
|
| 57 |
+
|
| 58 |
+
return encoder_config, decoder_config
|
| 59 |
+
|
| 60 |
+
|
| 61 |
+
def rename_key(name):
|
| 62 |
+
if "encoder.model" in name:
|
| 63 |
+
name = name.replace("encoder.model", "encoder")
|
| 64 |
+
if "decoder.model" in name:
|
| 65 |
+
name = name.replace("decoder.model", "decoder")
|
| 66 |
+
if "patch_embed.proj" in name:
|
| 67 |
+
name = name.replace("patch_embed.proj", "embeddings.patch_embeddings.projection")
|
| 68 |
+
if "patch_embed.norm" in name:
|
| 69 |
+
name = name.replace("patch_embed.norm", "embeddings.norm")
|
| 70 |
+
if name.startswith("encoder"):
|
| 71 |
+
if "layers" in name:
|
| 72 |
+
name = "encoder." + name
|
| 73 |
+
if "attn.proj" in name:
|
| 74 |
+
name = name.replace("attn.proj", "attention.output.dense")
|
| 75 |
+
if "attn" in name and "mask" not in name:
|
| 76 |
+
name = name.replace("attn", "attention.self")
|
| 77 |
+
if "norm1" in name:
|
| 78 |
+
name = name.replace("norm1", "layernorm_before")
|
| 79 |
+
if "norm2" in name:
|
| 80 |
+
name = name.replace("norm2", "layernorm_after")
|
| 81 |
+
if "mlp.fc1" in name:
|
| 82 |
+
name = name.replace("mlp.fc1", "intermediate.dense")
|
| 83 |
+
if "mlp.fc2" in name:
|
| 84 |
+
name = name.replace("mlp.fc2", "output.dense")
|
| 85 |
+
|
| 86 |
+
if name == "encoder.norm.weight":
|
| 87 |
+
name = "encoder.layernorm.weight"
|
| 88 |
+
if name == "encoder.norm.bias":
|
| 89 |
+
name = "encoder.layernorm.bias"
|
| 90 |
+
|
| 91 |
+
return name
|
| 92 |
+
|
| 93 |
+
|
| 94 |
+
def convert_state_dict(orig_state_dict, model):
|
| 95 |
+
for key in orig_state_dict.copy():
|
| 96 |
+
val = orig_state_dict.pop(key)
|
| 97 |
+
|
| 98 |
+
if "qkv" in key:
|
| 99 |
+
key_split = key.split(".")
|
| 100 |
+
layer_num = int(key_split[3])
|
| 101 |
+
block_num = int(key_split[5])
|
| 102 |
+
dim = model.encoder.encoder.layers[layer_num].blocks[block_num].attention.self.all_head_size
|
| 103 |
+
|
| 104 |
+
if "weight" in key:
|
| 105 |
+
orig_state_dict[
|
| 106 |
+
f"encoder.encoder.layers.{layer_num}.blocks.{block_num}.attention.self.query.weight"
|
| 107 |
+
] = val[:dim, :]
|
| 108 |
+
orig_state_dict[f"encoder.encoder.layers.{layer_num}.blocks.{block_num}.attention.self.key.weight"] = (
|
| 109 |
+
val[dim : dim * 2, :]
|
| 110 |
+
)
|
| 111 |
+
orig_state_dict[
|
| 112 |
+
f"encoder.encoder.layers.{layer_num}.blocks.{block_num}.attention.self.value.weight"
|
| 113 |
+
] = val[-dim:, :]
|
| 114 |
+
else:
|
| 115 |
+
orig_state_dict[f"encoder.encoder.layers.{layer_num}.blocks.{block_num}.attention.self.query.bias"] = (
|
| 116 |
+
val[:dim]
|
| 117 |
+
)
|
| 118 |
+
orig_state_dict[f"encoder.encoder.layers.{layer_num}.blocks.{block_num}.attention.self.key.bias"] = (
|
| 119 |
+
val[dim : dim * 2]
|
| 120 |
+
)
|
| 121 |
+
orig_state_dict[f"encoder.encoder.layers.{layer_num}.blocks.{block_num}.attention.self.value.bias"] = (
|
| 122 |
+
val[-dim:]
|
| 123 |
+
)
|
| 124 |
+
elif "attn_mask" in key or key in ["encoder.model.norm.weight", "encoder.model.norm.bias"]:
|
| 125 |
+
# HuggingFace implementation doesn't use attn_mask buffer
|
| 126 |
+
# and model doesn't use final LayerNorms for the encoder
|
| 127 |
+
pass
|
| 128 |
+
else:
|
| 129 |
+
orig_state_dict[rename_key(key)] = val
|
| 130 |
+
|
| 131 |
+
return orig_state_dict
|
| 132 |
+
|
| 133 |
+
|
| 134 |
+
def convert_donut_checkpoint(model_name, pytorch_dump_folder_path=None, push_to_hub=False):
|
| 135 |
+
# load original model
|
| 136 |
+
original_model = DonutModel.from_pretrained(model_name).eval()
|
| 137 |
+
|
| 138 |
+
# load HuggingFace model
|
| 139 |
+
encoder_config, decoder_config = get_configs(original_model)
|
| 140 |
+
encoder = DonutSwinModel(encoder_config)
|
| 141 |
+
decoder = MBartForCausalLM(decoder_config)
|
| 142 |
+
model = VisionEncoderDecoderModel(encoder=encoder, decoder=decoder)
|
| 143 |
+
model.eval()
|
| 144 |
+
|
| 145 |
+
state_dict = original_model.state_dict()
|
| 146 |
+
new_state_dict = convert_state_dict(state_dict, model)
|
| 147 |
+
model.load_state_dict(new_state_dict)
|
| 148 |
+
|
| 149 |
+
# verify results on scanned document
|
| 150 |
+
dataset = load_dataset("hf-internal-testing/example-documents") # no-script
|
| 151 |
+
image = dataset["test"][0]["image"].convert("RGB")
|
| 152 |
+
|
| 153 |
+
tokenizer = XLMRobertaTokenizerFast.from_pretrained(model_name, from_slow=True)
|
| 154 |
+
image_processor = DonutImageProcessor(
|
| 155 |
+
do_align_long_axis=original_model.config.align_long_axis, size=original_model.config.input_size[::-1]
|
| 156 |
+
)
|
| 157 |
+
processor = DonutProcessor(image_processor, tokenizer)
|
| 158 |
+
pixel_values = processor(image, return_tensors="pt").pixel_values
|
| 159 |
+
|
| 160 |
+
if model_name == "naver-clova-ix/donut-base-finetuned-docvqa":
|
| 161 |
+
task_prompt = "<s_docvqa><s_question>{user_input}</s_question><s_answer>"
|
| 162 |
+
question = "When is the coffee break?"
|
| 163 |
+
task_prompt = task_prompt.replace("{user_input}", question)
|
| 164 |
+
elif model_name == "naver-clova-ix/donut-base-finetuned-rvlcdip":
|
| 165 |
+
task_prompt = "<s_rvlcdip>"
|
| 166 |
+
elif model_name in [
|
| 167 |
+
"naver-clova-ix/donut-base-finetuned-cord-v1",
|
| 168 |
+
"naver-clova-ix/donut-base-finetuned-cord-v1-2560",
|
| 169 |
+
]:
|
| 170 |
+
task_prompt = "<s_cord>"
|
| 171 |
+
elif model_name == "naver-clova-ix/donut-base-finetuned-cord-v2":
|
| 172 |
+
task_prompt = "s_cord-v2>"
|
| 173 |
+
elif model_name == "naver-clova-ix/donut-base-finetuned-zhtrainticket":
|
| 174 |
+
task_prompt = "<s_zhtrainticket>"
|
| 175 |
+
elif model_name in ["naver-clova-ix/donut-proto", "naver-clova-ix/donut-base"]:
|
| 176 |
+
# use a random prompt
|
| 177 |
+
task_prompt = "hello world"
|
| 178 |
+
else:
|
| 179 |
+
raise ValueError("Model name not supported")
|
| 180 |
+
prompt_tensors = original_model.decoder.tokenizer(task_prompt, add_special_tokens=False, return_tensors="pt")[
|
| 181 |
+
"input_ids"
|
| 182 |
+
]
|
| 183 |
+
|
| 184 |
+
original_patch_embed = original_model.encoder.model.patch_embed(pixel_values)
|
| 185 |
+
patch_embeddings, _ = model.encoder.embeddings(pixel_values)
|
| 186 |
+
assert torch.allclose(original_patch_embed, patch_embeddings, atol=1e-3)
|
| 187 |
+
|
| 188 |
+
# verify encoder hidden states
|
| 189 |
+
original_last_hidden_state = original_model.encoder(pixel_values)
|
| 190 |
+
last_hidden_state = model.encoder(pixel_values).last_hidden_state
|
| 191 |
+
assert torch.allclose(original_last_hidden_state, last_hidden_state, atol=1e-2)
|
| 192 |
+
|
| 193 |
+
# verify decoder hidden states
|
| 194 |
+
original_logits = original_model(pixel_values, prompt_tensors, None).logits
|
| 195 |
+
logits = model(pixel_values, decoder_input_ids=prompt_tensors).logits
|
| 196 |
+
assert torch.allclose(original_logits, logits, atol=1e-3)
|
| 197 |
+
print("Looks ok!")
|
| 198 |
+
|
| 199 |
+
if pytorch_dump_folder_path is not None:
|
| 200 |
+
print(f"Saving model and processor to {pytorch_dump_folder_path}")
|
| 201 |
+
model.save_pretrained(pytorch_dump_folder_path)
|
| 202 |
+
processor.save_pretrained(pytorch_dump_folder_path)
|
| 203 |
+
|
| 204 |
+
if push_to_hub:
|
| 205 |
+
model.push_to_hub("nielsr/" + model_name.split("/")[-1], commit_message="Update model")
|
| 206 |
+
processor.push_to_hub("nielsr/" + model_name.split("/")[-1], commit_message="Update model")
|
| 207 |
+
|
| 208 |
+
|
| 209 |
+
if __name__ == "__main__":
|
| 210 |
+
parser = argparse.ArgumentParser()
|
| 211 |
+
# Required parameters
|
| 212 |
+
parser.add_argument(
|
| 213 |
+
"--model_name",
|
| 214 |
+
default="naver-clova-ix/donut-base-finetuned-docvqa",
|
| 215 |
+
required=False,
|
| 216 |
+
type=str,
|
| 217 |
+
help="Name of the original model you'd like to convert.",
|
| 218 |
+
)
|
| 219 |
+
parser.add_argument(
|
| 220 |
+
"--pytorch_dump_folder_path",
|
| 221 |
+
default=None,
|
| 222 |
+
required=False,
|
| 223 |
+
type=str,
|
| 224 |
+
help="Path to the output PyTorch model directory.",
|
| 225 |
+
)
|
| 226 |
+
parser.add_argument(
|
| 227 |
+
"--push_to_hub",
|
| 228 |
+
action="store_true",
|
| 229 |
+
help="Whether or not to push the converted model and processor to the Hugging Face hub.",
|
| 230 |
+
)
|
| 231 |
+
|
| 232 |
+
args = parser.parse_args()
|
| 233 |
+
convert_donut_checkpoint(args.model_name, args.pytorch_dump_folder_path, args.push_to_hub)
|
third_party/transformers/src/transformers/models/donut/image_processing_donut.py
ADDED
|
@@ -0,0 +1,206 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
# Copyright 2024 The HuggingFace Inc. team. All rights reserved.
|
| 2 |
+
#
|
| 3 |
+
# Licensed under the Apache License, Version 2.0 (the "License");
|
| 4 |
+
# you may not use this file except in compliance with the License.
|
| 5 |
+
# You may obtain a copy of the License at
|
| 6 |
+
#
|
| 7 |
+
# http://www.apache.org/licenses/LICENSE-2.0
|
| 8 |
+
#
|
| 9 |
+
# Unless required by applicable law or agreed to in writing, software
|
| 10 |
+
# distributed under the License is distributed on an "AS IS" BASIS,
|
| 11 |
+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
| 12 |
+
# See the License for the specific language governing permissions and
|
| 13 |
+
# limitations under the License.
|
| 14 |
+
"""Image processor class for Donut."""
|
| 15 |
+
|
| 16 |
+
import torch
|
| 17 |
+
from torchvision.transforms.v2 import functional as tvF
|
| 18 |
+
|
| 19 |
+
from ...image_processing_backends import TorchvisionBackend
|
| 20 |
+
from ...image_processing_utils import BatchFeature
|
| 21 |
+
from ...image_transforms import group_images_by_shape, reorder_images
|
| 22 |
+
from ...image_utils import (
|
| 23 |
+
IMAGENET_STANDARD_MEAN,
|
| 24 |
+
IMAGENET_STANDARD_STD,
|
| 25 |
+
ImageInput,
|
| 26 |
+
PILImageResampling,
|
| 27 |
+
SizeDict,
|
| 28 |
+
)
|
| 29 |
+
from ...processing_utils import ImagesKwargs, Unpack
|
| 30 |
+
from ...utils import TensorType, auto_docstring
|
| 31 |
+
|
| 32 |
+
|
| 33 |
+
class DonutImageProcessorKwargs(ImagesKwargs, total=False):
|
| 34 |
+
r"""
|
| 35 |
+
do_thumbnail (`bool`, *optional*, defaults to `self.do_thumbnail`):
|
| 36 |
+
Whether to resize the image using thumbnail method.
|
| 37 |
+
do_align_long_axis (`bool`, *optional*, defaults to `self.do_align_long_axis`):
|
| 38 |
+
Whether to align the long axis of the image with the long axis of `size` by rotating by 90 degrees.
|
| 39 |
+
"""
|
| 40 |
+
|
| 41 |
+
do_thumbnail: bool
|
| 42 |
+
do_align_long_axis: bool
|
| 43 |
+
|
| 44 |
+
|
| 45 |
+
@auto_docstring
|
| 46 |
+
class DonutImageProcessor(TorchvisionBackend):
|
| 47 |
+
"""Torchvision backend for Donut with align_long_axis, thumbnail, and pad_image."""
|
| 48 |
+
|
| 49 |
+
valid_kwargs = DonutImageProcessorKwargs
|
| 50 |
+
|
| 51 |
+
resample = PILImageResampling.BILINEAR
|
| 52 |
+
image_mean = IMAGENET_STANDARD_MEAN
|
| 53 |
+
image_std = IMAGENET_STANDARD_STD
|
| 54 |
+
size = {"height": 2560, "width": 1920}
|
| 55 |
+
do_resize = True
|
| 56 |
+
do_rescale = True
|
| 57 |
+
do_normalize = True
|
| 58 |
+
do_thumbnail = True
|
| 59 |
+
do_align_long_axis = False
|
| 60 |
+
do_pad = True
|
| 61 |
+
|
| 62 |
+
def __init__(self, **kwargs: Unpack[DonutImageProcessorKwargs]):
|
| 63 |
+
size = kwargs.pop("size", None)
|
| 64 |
+
if isinstance(size, (tuple, list)):
|
| 65 |
+
size = size[::-1]
|
| 66 |
+
if size is not None:
|
| 67 |
+
kwargs["size"] = size
|
| 68 |
+
super().__init__(**kwargs)
|
| 69 |
+
|
| 70 |
+
@auto_docstring
|
| 71 |
+
def preprocess(
|
| 72 |
+
self,
|
| 73 |
+
images: ImageInput,
|
| 74 |
+
**kwargs: Unpack[DonutImageProcessorKwargs],
|
| 75 |
+
) -> BatchFeature:
|
| 76 |
+
kwargs = dict(kwargs)
|
| 77 |
+
if "size" in kwargs:
|
| 78 |
+
size = kwargs["size"]
|
| 79 |
+
if isinstance(size, (tuple, list)):
|
| 80 |
+
kwargs["size"] = size[::-1]
|
| 81 |
+
return super().preprocess(images, **kwargs)
|
| 82 |
+
|
| 83 |
+
def align_long_axis(
|
| 84 |
+
self,
|
| 85 |
+
image: "torch.Tensor",
|
| 86 |
+
size: SizeDict,
|
| 87 |
+
) -> "torch.Tensor":
|
| 88 |
+
"""Align the long axis of the image to the longest axis of the specified size."""
|
| 89 |
+
input_height, input_width = image.shape[-2:]
|
| 90 |
+
output_height, output_width = size.height, size.width
|
| 91 |
+
|
| 92 |
+
if (output_width < output_height and input_width > input_height) or (
|
| 93 |
+
output_width > output_height and input_width < input_height
|
| 94 |
+
):
|
| 95 |
+
height_dim, width_dim = image.dim() - 2, image.dim() - 1
|
| 96 |
+
image = torch.rot90(image, 3, dims=[height_dim, width_dim])
|
| 97 |
+
|
| 98 |
+
return image
|
| 99 |
+
|
| 100 |
+
def pad_image(
|
| 101 |
+
self,
|
| 102 |
+
image: "torch.Tensor",
|
| 103 |
+
size: SizeDict,
|
| 104 |
+
random_padding: bool = False,
|
| 105 |
+
) -> "torch.Tensor":
|
| 106 |
+
"""Pad the image to the specified size."""
|
| 107 |
+
output_height, output_width = size.height, size.width
|
| 108 |
+
input_height, input_width = image.shape[-2:]
|
| 109 |
+
|
| 110 |
+
delta_width = output_width - input_width
|
| 111 |
+
delta_height = output_height - input_height
|
| 112 |
+
|
| 113 |
+
if random_padding:
|
| 114 |
+
pad_top = torch.randint(0, delta_height + 1, ()).item()
|
| 115 |
+
pad_left = torch.randint(0, delta_width + 1, ()).item()
|
| 116 |
+
else:
|
| 117 |
+
pad_top = delta_height // 2
|
| 118 |
+
pad_left = delta_width // 2
|
| 119 |
+
|
| 120 |
+
pad_bottom = delta_height - pad_top
|
| 121 |
+
pad_right = delta_width - pad_left
|
| 122 |
+
|
| 123 |
+
padding = (pad_left, pad_top, pad_right, pad_bottom)
|
| 124 |
+
return tvF.pad(image, padding)
|
| 125 |
+
|
| 126 |
+
def thumbnail(
|
| 127 |
+
self,
|
| 128 |
+
image: "torch.Tensor",
|
| 129 |
+
size: SizeDict,
|
| 130 |
+
resample: "PILImageResampling | tvF.InterpolationMode | int | None" = None,
|
| 131 |
+
**kwargs,
|
| 132 |
+
) -> "torch.Tensor":
|
| 133 |
+
"""Resize the image to make a thumbnail."""
|
| 134 |
+
input_height, input_width = image.shape[-2:]
|
| 135 |
+
output_height, output_width = size.height, size.width
|
| 136 |
+
|
| 137 |
+
height = min(input_height, output_height)
|
| 138 |
+
width = min(input_width, output_width)
|
| 139 |
+
|
| 140 |
+
if height == input_height and width == input_width:
|
| 141 |
+
return image
|
| 142 |
+
|
| 143 |
+
if input_height > input_width:
|
| 144 |
+
width = int(input_width * height / input_height)
|
| 145 |
+
elif input_width > input_height:
|
| 146 |
+
height = int(input_height * width / input_width)
|
| 147 |
+
|
| 148 |
+
return super().resize(
|
| 149 |
+
image,
|
| 150 |
+
size=SizeDict(width=width, height=height),
|
| 151 |
+
resample=resample,
|
| 152 |
+
**kwargs,
|
| 153 |
+
)
|
| 154 |
+
|
| 155 |
+
def _preprocess(
|
| 156 |
+
self,
|
| 157 |
+
images: list["torch.Tensor"],
|
| 158 |
+
do_resize: bool,
|
| 159 |
+
size: SizeDict,
|
| 160 |
+
resample: "PILImageResampling | tvF.InterpolationMode | int | None",
|
| 161 |
+
do_center_crop: bool,
|
| 162 |
+
crop_size: SizeDict,
|
| 163 |
+
do_rescale: bool,
|
| 164 |
+
rescale_factor: float,
|
| 165 |
+
do_normalize: bool,
|
| 166 |
+
image_mean: float | list[float] | None,
|
| 167 |
+
image_std: float | list[float] | None,
|
| 168 |
+
do_pad: bool | None,
|
| 169 |
+
pad_size: SizeDict | None,
|
| 170 |
+
disable_grouping: bool | None,
|
| 171 |
+
return_tensors: str | TensorType | None,
|
| 172 |
+
do_thumbnail: bool = True,
|
| 173 |
+
do_align_long_axis: bool = False,
|
| 174 |
+
**kwargs,
|
| 175 |
+
) -> BatchFeature:
|
| 176 |
+
"""Custom preprocessing for Donut."""
|
| 177 |
+
grouped_images, grouped_images_index = group_images_by_shape(images, disable_grouping=disable_grouping)
|
| 178 |
+
resized_images_grouped = {}
|
| 179 |
+
for shape, stacked_images in grouped_images.items():
|
| 180 |
+
if do_align_long_axis:
|
| 181 |
+
stacked_images = self.align_long_axis(stacked_images, size)
|
| 182 |
+
if do_resize:
|
| 183 |
+
shortest_edge = min(size.height, size.width)
|
| 184 |
+
stacked_images = self.resize(stacked_images, SizeDict(shortest_edge=shortest_edge), resample)
|
| 185 |
+
if do_thumbnail:
|
| 186 |
+
stacked_images = self.thumbnail(stacked_images, size, resample)
|
| 187 |
+
if do_pad:
|
| 188 |
+
stacked_images = self.pad_image(stacked_images, size, random_padding=False)
|
| 189 |
+
resized_images_grouped[shape] = stacked_images
|
| 190 |
+
resized_images = reorder_images(resized_images_grouped, grouped_images_index)
|
| 191 |
+
|
| 192 |
+
grouped_images, grouped_images_index = group_images_by_shape(resized_images, disable_grouping=disable_grouping)
|
| 193 |
+
processed_images_grouped = {}
|
| 194 |
+
for shape, stacked_images in grouped_images.items():
|
| 195 |
+
if do_center_crop:
|
| 196 |
+
stacked_images = self.center_crop(stacked_images, crop_size)
|
| 197 |
+
stacked_images = self.rescale_and_normalize(
|
| 198 |
+
stacked_images, do_rescale, rescale_factor, do_normalize, image_mean, image_std
|
| 199 |
+
)
|
| 200 |
+
processed_images_grouped[shape] = stacked_images
|
| 201 |
+
|
| 202 |
+
processed_images = reorder_images(processed_images_grouped, grouped_images_index)
|
| 203 |
+
return BatchFeature(data={"pixel_values": processed_images}, tensor_type=return_tensors)
|
| 204 |
+
|
| 205 |
+
|
| 206 |
+
__all__ = ["DonutImageProcessor"]
|
third_party/transformers/src/transformers/models/donut/image_processing_pil_donut.py
ADDED
|
@@ -0,0 +1,212 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
# Copyright 2024 The HuggingFace Inc. team. All rights reserved.
|
| 2 |
+
#
|
| 3 |
+
# Licensed under the Apache License, Version 2.0 (the "License");
|
| 4 |
+
# you may not use this file except in compliance with the License.
|
| 5 |
+
# You may obtain a copy of the License at
|
| 6 |
+
#
|
| 7 |
+
# http://www.apache.org/licenses/LICENSE-2.0
|
| 8 |
+
#
|
| 9 |
+
# Unless required by applicable law or agreed to in writing, software
|
| 10 |
+
# distributed under the License is distributed on an "AS IS" BASIS,
|
| 11 |
+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
| 12 |
+
# See the License for the specific language governing permissions and
|
| 13 |
+
# limitations under the License.
|
| 14 |
+
"""Image processor class for Donut."""
|
| 15 |
+
|
| 16 |
+
import numpy as np
|
| 17 |
+
|
| 18 |
+
from ...image_processing_backends import PilBackend
|
| 19 |
+
from ...image_processing_utils import BatchFeature
|
| 20 |
+
from ...image_utils import (
|
| 21 |
+
IMAGENET_STANDARD_MEAN,
|
| 22 |
+
IMAGENET_STANDARD_STD,
|
| 23 |
+
ImageInput,
|
| 24 |
+
PILImageResampling,
|
| 25 |
+
SizeDict,
|
| 26 |
+
get_image_size,
|
| 27 |
+
)
|
| 28 |
+
from ...processing_utils import ImagesKwargs, Unpack
|
| 29 |
+
from ...utils import TensorType, auto_docstring
|
| 30 |
+
|
| 31 |
+
|
| 32 |
+
# Adapted from transformers.models.donut.image_processing_donut.DonutImageProcessorKwargs
|
| 33 |
+
class DonutImageProcessorKwargs(ImagesKwargs, total=False):
|
| 34 |
+
r"""
|
| 35 |
+
do_thumbnail (`bool`, *optional*, defaults to `self.do_thumbnail`):
|
| 36 |
+
Whether to resize the image using thumbnail method.
|
| 37 |
+
do_align_long_axis (`bool`, *optional*, defaults to `self.do_align_long_axis`):
|
| 38 |
+
Whether to align the long axis of the image with the long axis of `size` by rotating by 90 degrees.
|
| 39 |
+
"""
|
| 40 |
+
|
| 41 |
+
do_thumbnail: bool
|
| 42 |
+
do_align_long_axis: bool
|
| 43 |
+
|
| 44 |
+
|
| 45 |
+
@auto_docstring
|
| 46 |
+
class DonutImageProcessorPil(PilBackend):
|
| 47 |
+
"""PIL backend for Donut with align_long_axis, thumbnail, and pad_image."""
|
| 48 |
+
|
| 49 |
+
valid_kwargs = DonutImageProcessorKwargs
|
| 50 |
+
|
| 51 |
+
resample = PILImageResampling.BILINEAR
|
| 52 |
+
image_mean = IMAGENET_STANDARD_MEAN
|
| 53 |
+
image_std = IMAGENET_STANDARD_STD
|
| 54 |
+
size = {"height": 2560, "width": 1920}
|
| 55 |
+
do_resize = True
|
| 56 |
+
do_rescale = True
|
| 57 |
+
do_normalize = True
|
| 58 |
+
do_thumbnail = True
|
| 59 |
+
do_align_long_axis = False
|
| 60 |
+
do_pad = True
|
| 61 |
+
|
| 62 |
+
def __init__(self, **kwargs: Unpack[DonutImageProcessorKwargs]):
|
| 63 |
+
size = kwargs.pop("size", None)
|
| 64 |
+
if isinstance(size, (tuple, list)):
|
| 65 |
+
size = size[::-1]
|
| 66 |
+
if size is not None:
|
| 67 |
+
kwargs["size"] = size
|
| 68 |
+
super().__init__(**kwargs)
|
| 69 |
+
|
| 70 |
+
@auto_docstring
|
| 71 |
+
def preprocess(
|
| 72 |
+
self,
|
| 73 |
+
images: ImageInput,
|
| 74 |
+
**kwargs: Unpack[DonutImageProcessorKwargs],
|
| 75 |
+
) -> BatchFeature:
|
| 76 |
+
kwargs = dict(kwargs)
|
| 77 |
+
if "size" in kwargs:
|
| 78 |
+
size = kwargs["size"]
|
| 79 |
+
if isinstance(size, (tuple, list)):
|
| 80 |
+
kwargs["size"] = size[::-1]
|
| 81 |
+
return super().preprocess(images, **kwargs)
|
| 82 |
+
|
| 83 |
+
def align_long_axis(
|
| 84 |
+
self,
|
| 85 |
+
image: np.ndarray,
|
| 86 |
+
size: SizeDict,
|
| 87 |
+
) -> np.ndarray:
|
| 88 |
+
"""Align the long axis of the image to the longest axis of the specified size."""
|
| 89 |
+
from ...image_utils import ChannelDimension
|
| 90 |
+
|
| 91 |
+
input_height, input_width = get_image_size(image, channel_dim=ChannelDimension.FIRST)
|
| 92 |
+
output_height, output_width = size.height, size.width
|
| 93 |
+
|
| 94 |
+
if (output_width < output_height and input_width > input_height) or (
|
| 95 |
+
output_width > output_height and input_width < input_height
|
| 96 |
+
):
|
| 97 |
+
image = np.rot90(image, 3, axes=(1, 2))
|
| 98 |
+
|
| 99 |
+
return image
|
| 100 |
+
|
| 101 |
+
def pad_image(
|
| 102 |
+
self,
|
| 103 |
+
image: np.ndarray,
|
| 104 |
+
size: SizeDict,
|
| 105 |
+
random_padding: bool = False,
|
| 106 |
+
) -> np.ndarray:
|
| 107 |
+
"""Pad the image to the specified size."""
|
| 108 |
+
from ...image_transforms import PaddingMode
|
| 109 |
+
from ...image_transforms import pad as np_pad
|
| 110 |
+
from ...image_utils import ChannelDimension
|
| 111 |
+
|
| 112 |
+
output_height, output_width = size.height, size.width
|
| 113 |
+
input_height, input_width = get_image_size(image, channel_dim=ChannelDimension.FIRST)
|
| 114 |
+
|
| 115 |
+
delta_width = output_width - input_width
|
| 116 |
+
delta_height = output_height - input_height
|
| 117 |
+
|
| 118 |
+
if random_padding:
|
| 119 |
+
pad_top = int(np.random.randint(low=0, high=delta_height + 1))
|
| 120 |
+
pad_left = int(np.random.randint(low=0, high=delta_width + 1))
|
| 121 |
+
else:
|
| 122 |
+
pad_top = delta_height // 2
|
| 123 |
+
pad_left = delta_width // 2
|
| 124 |
+
|
| 125 |
+
pad_bottom = delta_height - pad_top
|
| 126 |
+
pad_right = delta_width - pad_left
|
| 127 |
+
|
| 128 |
+
# pad() expects (height_pad, width_pad) and adds channel dimension
|
| 129 |
+
padding = ((pad_top, pad_bottom), (pad_left, pad_right))
|
| 130 |
+
return np_pad(
|
| 131 |
+
image,
|
| 132 |
+
padding,
|
| 133 |
+
mode=PaddingMode.CONSTANT,
|
| 134 |
+
constant_values=0,
|
| 135 |
+
data_format=ChannelDimension.FIRST,
|
| 136 |
+
input_data_format=ChannelDimension.FIRST,
|
| 137 |
+
)
|
| 138 |
+
|
| 139 |
+
def thumbnail(
|
| 140 |
+
self,
|
| 141 |
+
image: np.ndarray,
|
| 142 |
+
size: SizeDict,
|
| 143 |
+
resample: "PILImageResampling | None" = None,
|
| 144 |
+
**kwargs,
|
| 145 |
+
) -> np.ndarray:
|
| 146 |
+
"""Resize the image to make a thumbnail."""
|
| 147 |
+
from ...image_utils import ChannelDimension
|
| 148 |
+
|
| 149 |
+
input_height, input_width = get_image_size(image, channel_dim=ChannelDimension.FIRST)
|
| 150 |
+
output_height, output_width = size.height, size.width
|
| 151 |
+
|
| 152 |
+
height = min(input_height, output_height)
|
| 153 |
+
width = min(input_width, output_width)
|
| 154 |
+
|
| 155 |
+
if height == input_height and width == input_width:
|
| 156 |
+
return image
|
| 157 |
+
|
| 158 |
+
if input_height > input_width:
|
| 159 |
+
width = int(input_width * height / input_height)
|
| 160 |
+
elif input_width > input_height:
|
| 161 |
+
height = int(input_height * width / input_width)
|
| 162 |
+
|
| 163 |
+
return self.resize(
|
| 164 |
+
image,
|
| 165 |
+
size=SizeDict(width=width, height=height),
|
| 166 |
+
resample=resample or PILImageResampling.BICUBIC,
|
| 167 |
+
)
|
| 168 |
+
|
| 169 |
+
def _preprocess(
|
| 170 |
+
self,
|
| 171 |
+
images: list[np.ndarray],
|
| 172 |
+
do_resize: bool,
|
| 173 |
+
size: SizeDict,
|
| 174 |
+
resample: "PILImageResampling | None",
|
| 175 |
+
do_center_crop: bool,
|
| 176 |
+
crop_size: SizeDict,
|
| 177 |
+
do_rescale: bool,
|
| 178 |
+
rescale_factor: float,
|
| 179 |
+
do_normalize: bool,
|
| 180 |
+
image_mean: float | list[float] | None,
|
| 181 |
+
image_std: float | list[float] | None,
|
| 182 |
+
do_pad: bool | None,
|
| 183 |
+
pad_size: SizeDict | None,
|
| 184 |
+
return_tensors: str | TensorType | None,
|
| 185 |
+
do_thumbnail: bool = True,
|
| 186 |
+
do_align_long_axis: bool = False,
|
| 187 |
+
**kwargs,
|
| 188 |
+
) -> BatchFeature:
|
| 189 |
+
"""Custom preprocessing for Donut."""
|
| 190 |
+
processed_images = []
|
| 191 |
+
for image in images:
|
| 192 |
+
if do_align_long_axis:
|
| 193 |
+
image = self.align_long_axis(image, size)
|
| 194 |
+
if do_resize:
|
| 195 |
+
shortest_edge = min(size.height, size.width)
|
| 196 |
+
image = self.resize(image, SizeDict(shortest_edge=shortest_edge), resample)
|
| 197 |
+
if do_thumbnail:
|
| 198 |
+
image = self.thumbnail(image, size, resample)
|
| 199 |
+
if do_pad:
|
| 200 |
+
image = self.pad_image(image, size, random_padding=False)
|
| 201 |
+
if do_center_crop:
|
| 202 |
+
image = self.center_crop(image, crop_size)
|
| 203 |
+
if do_rescale:
|
| 204 |
+
image = self.rescale(image, rescale_factor)
|
| 205 |
+
if do_normalize:
|
| 206 |
+
image = self.normalize(image, image_mean, image_std)
|
| 207 |
+
processed_images.append(image)
|
| 208 |
+
|
| 209 |
+
return BatchFeature(data={"pixel_values": processed_images}, tensor_type=return_tensors)
|
| 210 |
+
|
| 211 |
+
|
| 212 |
+
__all__ = ["DonutImageProcessorPil"]
|
third_party/transformers/src/transformers/models/donut/modeling_donut_swin.py
ADDED
|
@@ -0,0 +1,967 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
# Copyright 2022 The HuggingFace Inc. team. All rights reserved.
|
| 2 |
+
#
|
| 3 |
+
# Licensed under the Apache License, Version 2.0 (the "License");
|
| 4 |
+
# you may not use this file except in compliance with the License.
|
| 5 |
+
# You may obtain a copy of the License at
|
| 6 |
+
#
|
| 7 |
+
# http://www.apache.org/licenses/LICENSE-2.0
|
| 8 |
+
#
|
| 9 |
+
# Unless required by applicable law or agreed to in writing, software
|
| 10 |
+
# distributed under the License is distributed on an "AS IS" BASIS,
|
| 11 |
+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
| 12 |
+
# See the License for the specific language governing permissions and
|
| 13 |
+
# limitations under the License.
|
| 14 |
+
"""PyTorch Donut Swin Transformer model.
|
| 15 |
+
|
| 16 |
+
This implementation is identical to a regular Swin Transformer, without final layer norm on top of the final hidden
|
| 17 |
+
states."""
|
| 18 |
+
|
| 19 |
+
import collections.abc
|
| 20 |
+
import math
|
| 21 |
+
from dataclasses import dataclass
|
| 22 |
+
|
| 23 |
+
import torch
|
| 24 |
+
from torch import nn
|
| 25 |
+
|
| 26 |
+
from ... import initialization as init
|
| 27 |
+
from ...activations import ACT2FN
|
| 28 |
+
from ...modeling_layers import GradientCheckpointingLayer
|
| 29 |
+
from ...modeling_utils import PreTrainedModel
|
| 30 |
+
from ...utils import ModelOutput, auto_docstring, logging, torch_int
|
| 31 |
+
from .configuration_donut_swin import DonutSwinConfig
|
| 32 |
+
|
| 33 |
+
|
| 34 |
+
logger = logging.get_logger(__name__)
|
| 35 |
+
|
| 36 |
+
|
| 37 |
+
@dataclass
|
| 38 |
+
@auto_docstring(
|
| 39 |
+
custom_intro="""
|
| 40 |
+
DonutSwin encoder's outputs, with potential hidden states and attentions.
|
| 41 |
+
"""
|
| 42 |
+
)
|
| 43 |
+
# Copied from transformers.models.swin.modeling_swin.SwinEncoderOutput with Swin->DonutSwin
|
| 44 |
+
class DonutSwinEncoderOutput(ModelOutput):
|
| 45 |
+
r"""
|
| 46 |
+
reshaped_hidden_states (`tuple(torch.FloatTensor)`, *optional*, returned when `output_hidden_states=True` is passed or when `config.output_hidden_states=True`):
|
| 47 |
+
Tuple of `torch.FloatTensor` (one for the output of the embeddings + one for the output of each stage) of
|
| 48 |
+
shape `(batch_size, hidden_size, height, width)`.
|
| 49 |
+
|
| 50 |
+
Hidden-states of the model at the output of each layer plus the initial embedding outputs reshaped to
|
| 51 |
+
include the spatial dimensions.
|
| 52 |
+
"""
|
| 53 |
+
|
| 54 |
+
last_hidden_state: torch.FloatTensor | None = None
|
| 55 |
+
hidden_states: tuple[torch.FloatTensor, ...] | None = None
|
| 56 |
+
attentions: tuple[torch.FloatTensor, ...] | None = None
|
| 57 |
+
reshaped_hidden_states: tuple[torch.FloatTensor, ...] | None = None
|
| 58 |
+
|
| 59 |
+
|
| 60 |
+
@dataclass
|
| 61 |
+
@auto_docstring(
|
| 62 |
+
custom_intro="""
|
| 63 |
+
DonutSwin model's outputs that also contains a pooling of the last hidden states.
|
| 64 |
+
"""
|
| 65 |
+
)
|
| 66 |
+
# Copied from transformers.models.swin.modeling_swin.SwinModelOutput with Swin->DonutSwin
|
| 67 |
+
class DonutSwinModelOutput(ModelOutput):
|
| 68 |
+
r"""
|
| 69 |
+
pooler_output (`torch.FloatTensor` of shape `(batch_size, hidden_size)`, *optional*, returned when `add_pooling_layer=True` is passed):
|
| 70 |
+
Average pooling of the last layer hidden-state.
|
| 71 |
+
reshaped_hidden_states (`tuple(torch.FloatTensor)`, *optional*, returned when `output_hidden_states=True` is passed or when `config.output_hidden_states=True`):
|
| 72 |
+
Tuple of `torch.FloatTensor` (one for the output of the embeddings + one for the output of each stage) of
|
| 73 |
+
shape `(batch_size, hidden_size, height, width)`.
|
| 74 |
+
|
| 75 |
+
Hidden-states of the model at the output of each layer plus the initial embedding outputs reshaped to
|
| 76 |
+
include the spatial dimensions.
|
| 77 |
+
"""
|
| 78 |
+
|
| 79 |
+
last_hidden_state: torch.FloatTensor | None = None
|
| 80 |
+
pooler_output: torch.FloatTensor | None = None
|
| 81 |
+
hidden_states: tuple[torch.FloatTensor, ...] | None = None
|
| 82 |
+
attentions: tuple[torch.FloatTensor, ...] | None = None
|
| 83 |
+
reshaped_hidden_states: tuple[torch.FloatTensor, ...] | None = None
|
| 84 |
+
|
| 85 |
+
|
| 86 |
+
@dataclass
|
| 87 |
+
@auto_docstring(
|
| 88 |
+
custom_intro="""
|
| 89 |
+
DonutSwin outputs for image classification.
|
| 90 |
+
"""
|
| 91 |
+
)
|
| 92 |
+
# Copied from transformers.models.swin.modeling_swin.SwinImageClassifierOutput with Swin->DonutSwin
|
| 93 |
+
class DonutSwinImageClassifierOutput(ModelOutput):
|
| 94 |
+
r"""
|
| 95 |
+
loss (`torch.FloatTensor` of shape `(1,)`, *optional*, returned when `labels` is provided):
|
| 96 |
+
Classification (or regression if config.num_labels==1) loss.
|
| 97 |
+
logits (`torch.FloatTensor` of shape `(batch_size, config.num_labels)`):
|
| 98 |
+
Classification (or regression if config.num_labels==1) scores (before SoftMax).
|
| 99 |
+
reshaped_hidden_states (`tuple(torch.FloatTensor)`, *optional*, returned when `output_hidden_states=True` is passed or when `config.output_hidden_states=True`):
|
| 100 |
+
Tuple of `torch.FloatTensor` (one for the output of the embeddings + one for the output of each stage) of
|
| 101 |
+
shape `(batch_size, hidden_size, height, width)`.
|
| 102 |
+
|
| 103 |
+
Hidden-states of the model at the output of each layer plus the initial embedding outputs reshaped to
|
| 104 |
+
include the spatial dimensions.
|
| 105 |
+
"""
|
| 106 |
+
|
| 107 |
+
loss: torch.FloatTensor | None = None
|
| 108 |
+
logits: torch.FloatTensor | None = None
|
| 109 |
+
hidden_states: tuple[torch.FloatTensor, ...] | None = None
|
| 110 |
+
attentions: tuple[torch.FloatTensor, ...] | None = None
|
| 111 |
+
reshaped_hidden_states: tuple[torch.FloatTensor, ...] | None = None
|
| 112 |
+
|
| 113 |
+
|
| 114 |
+
# Copied from transformers.models.swin.modeling_swin.window_partition
|
| 115 |
+
def window_partition(input_feature, window_size):
|
| 116 |
+
"""
|
| 117 |
+
Partitions the given input into windows.
|
| 118 |
+
"""
|
| 119 |
+
batch_size, height, width, num_channels = input_feature.shape
|
| 120 |
+
input_feature = input_feature.view(
|
| 121 |
+
batch_size, height // window_size, window_size, width // window_size, window_size, num_channels
|
| 122 |
+
)
|
| 123 |
+
windows = input_feature.permute(0, 1, 3, 2, 4, 5).contiguous().view(-1, window_size, window_size, num_channels)
|
| 124 |
+
return windows
|
| 125 |
+
|
| 126 |
+
|
| 127 |
+
# Copied from transformers.models.swin.modeling_swin.window_reverse
|
| 128 |
+
def window_reverse(windows, window_size, height, width):
|
| 129 |
+
"""
|
| 130 |
+
Merges windows to produce higher resolution features.
|
| 131 |
+
"""
|
| 132 |
+
num_channels = windows.shape[-1]
|
| 133 |
+
windows = windows.view(-1, height // window_size, width // window_size, window_size, window_size, num_channels)
|
| 134 |
+
windows = windows.permute(0, 1, 3, 2, 4, 5).contiguous().view(-1, height, width, num_channels)
|
| 135 |
+
return windows
|
| 136 |
+
|
| 137 |
+
|
| 138 |
+
# Copied from transformers.models.swin.modeling_swin.SwinEmbeddings with Swin->DonutSwin
|
| 139 |
+
class DonutSwinEmbeddings(nn.Module):
|
| 140 |
+
"""
|
| 141 |
+
Construct the patch and position embeddings. Optionally, also the mask token.
|
| 142 |
+
"""
|
| 143 |
+
|
| 144 |
+
def __init__(self, config, use_mask_token=False):
|
| 145 |
+
super().__init__()
|
| 146 |
+
|
| 147 |
+
self.patch_embeddings = DonutSwinPatchEmbeddings(config)
|
| 148 |
+
num_patches = self.patch_embeddings.num_patches
|
| 149 |
+
self.patch_grid = self.patch_embeddings.grid_size
|
| 150 |
+
self.mask_token = nn.Parameter(torch.zeros(1, 1, config.embed_dim)) if use_mask_token else None
|
| 151 |
+
|
| 152 |
+
if config.use_absolute_embeddings:
|
| 153 |
+
self.position_embeddings = nn.Parameter(torch.zeros(1, num_patches + 1, config.embed_dim))
|
| 154 |
+
else:
|
| 155 |
+
self.position_embeddings = None
|
| 156 |
+
|
| 157 |
+
self.norm = nn.LayerNorm(config.embed_dim)
|
| 158 |
+
self.dropout = nn.Dropout(config.hidden_dropout_prob)
|
| 159 |
+
self.patch_size = config.patch_size
|
| 160 |
+
self.config = config
|
| 161 |
+
|
| 162 |
+
# Copied from transformers.models.vit.modeling_vit.ViTEmbeddings.interpolate_pos_encoding
|
| 163 |
+
def interpolate_pos_encoding(self, embeddings: torch.Tensor, height: int, width: int) -> torch.Tensor:
|
| 164 |
+
"""
|
| 165 |
+
This method allows to interpolate the pre-trained position encodings, to be able to use the model on higher resolution
|
| 166 |
+
images. This method is also adapted to support torch.jit tracing.
|
| 167 |
+
|
| 168 |
+
Adapted from:
|
| 169 |
+
- https://github.com/facebookresearch/dino/blob/de9ee3df6cf39fac952ab558447af1fa1365362a/vision_transformer.py#L174-L194, and
|
| 170 |
+
- https://github.com/facebookresearch/dinov2/blob/e1277af2ba9496fbadf7aec6eba56e8d882d1e35/dinov2/models/vision_transformer.py#L179-L211
|
| 171 |
+
"""
|
| 172 |
+
|
| 173 |
+
num_patches = embeddings.shape[1] - 1
|
| 174 |
+
num_positions = self.position_embeddings.shape[1] - 1
|
| 175 |
+
|
| 176 |
+
# always interpolate when tracing to ensure the exported model works for dynamic input shapes
|
| 177 |
+
if not torch.jit.is_tracing() and num_patches == num_positions and height == width:
|
| 178 |
+
return self.position_embeddings
|
| 179 |
+
|
| 180 |
+
class_pos_embed = self.position_embeddings[:, :1]
|
| 181 |
+
patch_pos_embed = self.position_embeddings[:, 1:]
|
| 182 |
+
|
| 183 |
+
dim = embeddings.shape[-1]
|
| 184 |
+
|
| 185 |
+
new_height = height // self.patch_size
|
| 186 |
+
new_width = width // self.patch_size
|
| 187 |
+
|
| 188 |
+
sqrt_num_positions = torch_int(num_positions**0.5)
|
| 189 |
+
patch_pos_embed = patch_pos_embed.reshape(1, sqrt_num_positions, sqrt_num_positions, dim)
|
| 190 |
+
patch_pos_embed = patch_pos_embed.permute(0, 3, 1, 2)
|
| 191 |
+
|
| 192 |
+
patch_pos_embed = nn.functional.interpolate(
|
| 193 |
+
patch_pos_embed,
|
| 194 |
+
size=(new_height, new_width),
|
| 195 |
+
mode="bicubic",
|
| 196 |
+
align_corners=False,
|
| 197 |
+
)
|
| 198 |
+
|
| 199 |
+
patch_pos_embed = patch_pos_embed.permute(0, 2, 3, 1).view(1, -1, dim)
|
| 200 |
+
|
| 201 |
+
return torch.cat((class_pos_embed, patch_pos_embed), dim=1)
|
| 202 |
+
|
| 203 |
+
def forward(
|
| 204 |
+
self,
|
| 205 |
+
pixel_values: torch.FloatTensor | None,
|
| 206 |
+
bool_masked_pos: torch.BoolTensor | None = None,
|
| 207 |
+
interpolate_pos_encoding: bool = False,
|
| 208 |
+
) -> tuple[torch.Tensor]:
|
| 209 |
+
_, num_channels, height, width = pixel_values.shape
|
| 210 |
+
embeddings, output_dimensions = self.patch_embeddings(pixel_values)
|
| 211 |
+
embeddings = self.norm(embeddings)
|
| 212 |
+
batch_size, seq_len, _ = embeddings.size()
|
| 213 |
+
|
| 214 |
+
if bool_masked_pos is not None:
|
| 215 |
+
mask_tokens = self.mask_token.expand(batch_size, seq_len, -1)
|
| 216 |
+
# replace the masked visual tokens by mask_tokens
|
| 217 |
+
mask = bool_masked_pos.unsqueeze(-1).type_as(mask_tokens)
|
| 218 |
+
embeddings = embeddings * (1.0 - mask) + mask_tokens * mask
|
| 219 |
+
|
| 220 |
+
if self.position_embeddings is not None:
|
| 221 |
+
if interpolate_pos_encoding:
|
| 222 |
+
embeddings = embeddings + self.interpolate_pos_encoding(embeddings, height, width)
|
| 223 |
+
else:
|
| 224 |
+
embeddings = embeddings + self.position_embeddings
|
| 225 |
+
|
| 226 |
+
embeddings = self.dropout(embeddings)
|
| 227 |
+
|
| 228 |
+
return embeddings, output_dimensions
|
| 229 |
+
|
| 230 |
+
|
| 231 |
+
# Copied from transformers.models.swin.modeling_swin.SwinPatchEmbeddings with Swin->DonutSwin
|
| 232 |
+
class DonutSwinPatchEmbeddings(nn.Module):
|
| 233 |
+
"""
|
| 234 |
+
This class turns `pixel_values` of shape `(batch_size, num_channels, height, width)` into the initial
|
| 235 |
+
`hidden_states` (patch embeddings) of shape `(batch_size, seq_length, hidden_size)` to be consumed by a
|
| 236 |
+
Transformer.
|
| 237 |
+
"""
|
| 238 |
+
|
| 239 |
+
def __init__(self, config):
|
| 240 |
+
super().__init__()
|
| 241 |
+
image_size, patch_size = config.image_size, config.patch_size
|
| 242 |
+
num_channels, hidden_size = config.num_channels, config.embed_dim
|
| 243 |
+
image_size = image_size if isinstance(image_size, collections.abc.Iterable) else (image_size, image_size)
|
| 244 |
+
patch_size = patch_size if isinstance(patch_size, collections.abc.Iterable) else (patch_size, patch_size)
|
| 245 |
+
num_patches = (image_size[1] // patch_size[1]) * (image_size[0] // patch_size[0])
|
| 246 |
+
self.image_size = image_size
|
| 247 |
+
self.patch_size = patch_size
|
| 248 |
+
self.num_channels = num_channels
|
| 249 |
+
self.num_patches = num_patches
|
| 250 |
+
self.grid_size = (image_size[0] // patch_size[0], image_size[1] // patch_size[1])
|
| 251 |
+
|
| 252 |
+
self.projection = nn.Conv2d(num_channels, hidden_size, kernel_size=patch_size, stride=patch_size)
|
| 253 |
+
|
| 254 |
+
def maybe_pad(self, pixel_values, height, width):
|
| 255 |
+
if width % self.patch_size[1] != 0:
|
| 256 |
+
pad_values = (0, self.patch_size[1] - width % self.patch_size[1])
|
| 257 |
+
pixel_values = nn.functional.pad(pixel_values, pad_values)
|
| 258 |
+
if height % self.patch_size[0] != 0:
|
| 259 |
+
pad_values = (0, 0, 0, self.patch_size[0] - height % self.patch_size[0])
|
| 260 |
+
pixel_values = nn.functional.pad(pixel_values, pad_values)
|
| 261 |
+
return pixel_values
|
| 262 |
+
|
| 263 |
+
def forward(self, pixel_values: torch.FloatTensor | None) -> tuple[torch.Tensor, tuple[int]]:
|
| 264 |
+
_, num_channels, height, width = pixel_values.shape
|
| 265 |
+
# pad the input to be divisible by self.patch_size, if needed
|
| 266 |
+
pixel_values = self.maybe_pad(pixel_values, height, width)
|
| 267 |
+
embeddings = self.projection(pixel_values)
|
| 268 |
+
_, _, height, width = embeddings.shape
|
| 269 |
+
output_dimensions = (height, width)
|
| 270 |
+
embeddings = embeddings.flatten(2).transpose(1, 2)
|
| 271 |
+
|
| 272 |
+
return embeddings, output_dimensions
|
| 273 |
+
|
| 274 |
+
|
| 275 |
+
# Copied from transformers.models.swin.modeling_swin.SwinPatchMerging
|
| 276 |
+
class DonutSwinPatchMerging(nn.Module):
|
| 277 |
+
"""
|
| 278 |
+
Patch Merging Layer.
|
| 279 |
+
|
| 280 |
+
Args:
|
| 281 |
+
input_resolution (`tuple[int]`):
|
| 282 |
+
Resolution of input feature.
|
| 283 |
+
dim (`int`):
|
| 284 |
+
Number of input channels.
|
| 285 |
+
norm_layer (`nn.Module`, *optional*, defaults to `nn.LayerNorm`):
|
| 286 |
+
Normalization layer class.
|
| 287 |
+
"""
|
| 288 |
+
|
| 289 |
+
def __init__(self, input_resolution: tuple[int], dim: int, norm_layer: nn.Module = nn.LayerNorm) -> None:
|
| 290 |
+
super().__init__()
|
| 291 |
+
self.input_resolution = input_resolution
|
| 292 |
+
self.dim = dim
|
| 293 |
+
self.reduction = nn.Linear(4 * dim, 2 * dim, bias=False)
|
| 294 |
+
self.norm = norm_layer(4 * dim)
|
| 295 |
+
|
| 296 |
+
def maybe_pad(self, input_feature, height, width):
|
| 297 |
+
should_pad = (height % 2 == 1) or (width % 2 == 1)
|
| 298 |
+
if should_pad:
|
| 299 |
+
pad_values = (0, 0, 0, width % 2, 0, height % 2)
|
| 300 |
+
input_feature = nn.functional.pad(input_feature, pad_values)
|
| 301 |
+
|
| 302 |
+
return input_feature
|
| 303 |
+
|
| 304 |
+
def forward(self, input_feature: torch.Tensor, input_dimensions: tuple[int, int]) -> torch.Tensor:
|
| 305 |
+
height, width = input_dimensions
|
| 306 |
+
# `dim` is height * width
|
| 307 |
+
batch_size, dim, num_channels = input_feature.shape
|
| 308 |
+
|
| 309 |
+
input_feature = input_feature.view(batch_size, height, width, num_channels)
|
| 310 |
+
# pad input to be divisible by width and height, if needed
|
| 311 |
+
input_feature = self.maybe_pad(input_feature, height, width)
|
| 312 |
+
# [batch_size, height/2, width/2, num_channels]
|
| 313 |
+
input_feature_0 = input_feature[:, 0::2, 0::2, :]
|
| 314 |
+
# [batch_size, height/2, width/2, num_channels]
|
| 315 |
+
input_feature_1 = input_feature[:, 1::2, 0::2, :]
|
| 316 |
+
# [batch_size, height/2, width/2, num_channels]
|
| 317 |
+
input_feature_2 = input_feature[:, 0::2, 1::2, :]
|
| 318 |
+
# [batch_size, height/2, width/2, num_channels]
|
| 319 |
+
input_feature_3 = input_feature[:, 1::2, 1::2, :]
|
| 320 |
+
# batch_size height/2 width/2 4*num_channels
|
| 321 |
+
input_feature = torch.cat([input_feature_0, input_feature_1, input_feature_2, input_feature_3], -1)
|
| 322 |
+
input_feature = input_feature.view(batch_size, -1, 4 * num_channels) # batch_size height/2*width/2 4*C
|
| 323 |
+
|
| 324 |
+
input_feature = self.norm(input_feature)
|
| 325 |
+
input_feature = self.reduction(input_feature)
|
| 326 |
+
|
| 327 |
+
return input_feature
|
| 328 |
+
|
| 329 |
+
|
| 330 |
+
# Copied from transformers.models.beit.modeling_beit.drop_path
|
| 331 |
+
def drop_path(input: torch.Tensor, drop_prob: float = 0.0, training: bool = False) -> torch.Tensor:
|
| 332 |
+
"""
|
| 333 |
+
Drop paths (Stochastic Depth) per sample (when applied in main path of residual blocks).
|
| 334 |
+
|
| 335 |
+
"""
|
| 336 |
+
if drop_prob == 0.0 or not training:
|
| 337 |
+
return input
|
| 338 |
+
keep_prob = 1 - drop_prob
|
| 339 |
+
shape = (input.shape[0],) + (1,) * (input.ndim - 1) # work with diff dim tensors, not just 2D ConvNets
|
| 340 |
+
random_tensor = keep_prob + torch.rand(shape, dtype=input.dtype, device=input.device)
|
| 341 |
+
random_tensor.floor_() # binarize
|
| 342 |
+
output = input.div(keep_prob) * random_tensor
|
| 343 |
+
return output
|
| 344 |
+
|
| 345 |
+
|
| 346 |
+
# Copied from transformers.models.swin.modeling_swin.SwinDropPath
|
| 347 |
+
class DonutSwinDropPath(nn.Module):
|
| 348 |
+
"""Drop paths (Stochastic Depth) per sample (when applied in main path of residual blocks)."""
|
| 349 |
+
|
| 350 |
+
def __init__(self, drop_prob: float | None = None) -> None:
|
| 351 |
+
super().__init__()
|
| 352 |
+
self.drop_prob = drop_prob
|
| 353 |
+
|
| 354 |
+
def forward(self, hidden_states: torch.Tensor) -> torch.Tensor:
|
| 355 |
+
return drop_path(hidden_states, self.drop_prob, self.training)
|
| 356 |
+
|
| 357 |
+
def extra_repr(self) -> str:
|
| 358 |
+
return f"p={self.drop_prob}"
|
| 359 |
+
|
| 360 |
+
|
| 361 |
+
# Copied from transformers.models.swin.modeling_swin.SwinSelfAttention with Swin->DonutSwin
|
| 362 |
+
class DonutSwinSelfAttention(nn.Module):
|
| 363 |
+
def __init__(self, config, dim, num_heads, window_size):
|
| 364 |
+
super().__init__()
|
| 365 |
+
if dim % num_heads != 0:
|
| 366 |
+
raise ValueError(
|
| 367 |
+
f"The hidden size ({dim}) is not a multiple of the number of attention heads ({num_heads})"
|
| 368 |
+
)
|
| 369 |
+
|
| 370 |
+
self.num_attention_heads = num_heads
|
| 371 |
+
self.attention_head_size = int(dim / num_heads)
|
| 372 |
+
self.all_head_size = self.num_attention_heads * self.attention_head_size
|
| 373 |
+
self.window_size = (
|
| 374 |
+
window_size if isinstance(window_size, collections.abc.Iterable) else (window_size, window_size)
|
| 375 |
+
)
|
| 376 |
+
|
| 377 |
+
self.relative_position_bias_table = nn.Parameter(
|
| 378 |
+
torch.zeros((2 * self.window_size[0] - 1) * (2 * self.window_size[1] - 1), num_heads)
|
| 379 |
+
)
|
| 380 |
+
|
| 381 |
+
self.register_buffer("relative_position_index", self.create_relative_position_index())
|
| 382 |
+
|
| 383 |
+
self.query = nn.Linear(self.all_head_size, self.all_head_size, bias=config.qkv_bias)
|
| 384 |
+
self.key = nn.Linear(self.all_head_size, self.all_head_size, bias=config.qkv_bias)
|
| 385 |
+
self.value = nn.Linear(self.all_head_size, self.all_head_size, bias=config.qkv_bias)
|
| 386 |
+
|
| 387 |
+
self.dropout = nn.Dropout(config.attention_probs_dropout_prob)
|
| 388 |
+
|
| 389 |
+
def forward(
|
| 390 |
+
self,
|
| 391 |
+
hidden_states: torch.Tensor,
|
| 392 |
+
attention_mask: torch.FloatTensor | None = None,
|
| 393 |
+
output_attentions: bool | None = False,
|
| 394 |
+
) -> tuple[torch.Tensor]:
|
| 395 |
+
batch_size, dim, num_channels = hidden_states.shape
|
| 396 |
+
hidden_shape = (batch_size, dim, -1, self.attention_head_size)
|
| 397 |
+
|
| 398 |
+
query_layer = self.query(hidden_states).view(hidden_shape).transpose(1, 2)
|
| 399 |
+
key_layer = self.key(hidden_states).view(hidden_shape).transpose(1, 2)
|
| 400 |
+
value_layer = self.value(hidden_states).view(hidden_shape).transpose(1, 2)
|
| 401 |
+
|
| 402 |
+
# Take the dot product between "query" and "key" to get the raw attention scores.
|
| 403 |
+
attention_scores = torch.matmul(query_layer, key_layer.transpose(-1, -2))
|
| 404 |
+
|
| 405 |
+
attention_scores = attention_scores / math.sqrt(self.attention_head_size)
|
| 406 |
+
|
| 407 |
+
relative_position_bias = self.relative_position_bias_table[self.relative_position_index.view(-1)]
|
| 408 |
+
relative_position_bias = relative_position_bias.view(
|
| 409 |
+
self.window_size[0] * self.window_size[1], self.window_size[0] * self.window_size[1], -1
|
| 410 |
+
)
|
| 411 |
+
|
| 412 |
+
relative_position_bias = relative_position_bias.permute(2, 0, 1).contiguous()
|
| 413 |
+
attention_scores = attention_scores + relative_position_bias.unsqueeze(0)
|
| 414 |
+
|
| 415 |
+
if attention_mask is not None:
|
| 416 |
+
# Apply the attention mask is (precomputed for all layers in DonutSwinModel forward() function)
|
| 417 |
+
mask_shape = attention_mask.shape[0]
|
| 418 |
+
attention_scores = attention_scores.view(
|
| 419 |
+
batch_size // mask_shape, mask_shape, self.num_attention_heads, dim, dim
|
| 420 |
+
)
|
| 421 |
+
attention_scores = attention_scores + attention_mask.unsqueeze(1).unsqueeze(0)
|
| 422 |
+
attention_scores = attention_scores.view(-1, self.num_attention_heads, dim, dim)
|
| 423 |
+
|
| 424 |
+
# Normalize the attention scores to probabilities.
|
| 425 |
+
attention_probs = nn.functional.softmax(attention_scores, dim=-1)
|
| 426 |
+
|
| 427 |
+
# This is actually dropping out entire tokens to attend to, which might
|
| 428 |
+
# seem a bit unusual, but is taken from the original Transformer paper.
|
| 429 |
+
attention_probs = self.dropout(attention_probs)
|
| 430 |
+
|
| 431 |
+
context_layer = torch.matmul(attention_probs, value_layer)
|
| 432 |
+
context_layer = context_layer.permute(0, 2, 1, 3).contiguous()
|
| 433 |
+
new_context_layer_shape = context_layer.size()[:-2] + (self.all_head_size,)
|
| 434 |
+
context_layer = context_layer.view(new_context_layer_shape)
|
| 435 |
+
|
| 436 |
+
outputs = (context_layer, attention_probs) if output_attentions else (context_layer,)
|
| 437 |
+
|
| 438 |
+
return outputs
|
| 439 |
+
|
| 440 |
+
def create_relative_position_index(self):
|
| 441 |
+
# get pair-wise relative position index for each token inside the window
|
| 442 |
+
coords_h = torch.arange(self.window_size[0])
|
| 443 |
+
coords_w = torch.arange(self.window_size[1])
|
| 444 |
+
coords = torch.stack(torch.meshgrid([coords_h, coords_w], indexing="ij"))
|
| 445 |
+
coords_flatten = torch.flatten(coords, 1)
|
| 446 |
+
relative_coords = coords_flatten[:, :, None] - coords_flatten[:, None, :]
|
| 447 |
+
relative_coords = relative_coords.permute(1, 2, 0).contiguous()
|
| 448 |
+
relative_coords[:, :, 0] += self.window_size[0] - 1
|
| 449 |
+
relative_coords[:, :, 1] += self.window_size[1] - 1
|
| 450 |
+
relative_coords[:, :, 0] *= 2 * self.window_size[1] - 1
|
| 451 |
+
relative_position_index = relative_coords.sum(-1)
|
| 452 |
+
return relative_position_index
|
| 453 |
+
|
| 454 |
+
|
| 455 |
+
# Copied from transformers.models.swin.modeling_swin.SwinSelfOutput
|
| 456 |
+
class DonutSwinSelfOutput(nn.Module):
|
| 457 |
+
def __init__(self, config, dim):
|
| 458 |
+
super().__init__()
|
| 459 |
+
self.dense = nn.Linear(dim, dim)
|
| 460 |
+
self.dropout = nn.Dropout(config.attention_probs_dropout_prob)
|
| 461 |
+
|
| 462 |
+
def forward(self, hidden_states: torch.Tensor, input_tensor: torch.Tensor) -> torch.Tensor:
|
| 463 |
+
hidden_states = self.dense(hidden_states)
|
| 464 |
+
hidden_states = self.dropout(hidden_states)
|
| 465 |
+
|
| 466 |
+
return hidden_states
|
| 467 |
+
|
| 468 |
+
|
| 469 |
+
# Copied from transformers.models.swin.modeling_swin.SwinAttention with Swin->DonutSwin
|
| 470 |
+
class DonutSwinAttention(nn.Module):
|
| 471 |
+
def __init__(self, config, dim, num_heads, window_size):
|
| 472 |
+
super().__init__()
|
| 473 |
+
self.self = DonutSwinSelfAttention(config, dim, num_heads, window_size)
|
| 474 |
+
self.output = DonutSwinSelfOutput(config, dim)
|
| 475 |
+
|
| 476 |
+
def forward(
|
| 477 |
+
self,
|
| 478 |
+
hidden_states: torch.Tensor,
|
| 479 |
+
attention_mask: torch.FloatTensor | None = None,
|
| 480 |
+
output_attentions: bool | None = False,
|
| 481 |
+
) -> tuple[torch.Tensor]:
|
| 482 |
+
self_outputs = self.self(hidden_states, attention_mask, output_attentions)
|
| 483 |
+
attention_output = self.output(self_outputs[0], hidden_states)
|
| 484 |
+
outputs = (attention_output,) + self_outputs[1:] # add attentions if we output them
|
| 485 |
+
return outputs
|
| 486 |
+
|
| 487 |
+
|
| 488 |
+
# Copied from transformers.models.swin.modeling_swin.SwinIntermediate
|
| 489 |
+
class DonutSwinIntermediate(nn.Module):
|
| 490 |
+
def __init__(self, config, dim):
|
| 491 |
+
super().__init__()
|
| 492 |
+
self.dense = nn.Linear(dim, int(config.mlp_ratio * dim))
|
| 493 |
+
if isinstance(config.hidden_act, str):
|
| 494 |
+
self.intermediate_act_fn = ACT2FN[config.hidden_act]
|
| 495 |
+
else:
|
| 496 |
+
self.intermediate_act_fn = config.hidden_act
|
| 497 |
+
|
| 498 |
+
def forward(self, hidden_states: torch.Tensor) -> torch.Tensor:
|
| 499 |
+
hidden_states = self.dense(hidden_states)
|
| 500 |
+
hidden_states = self.intermediate_act_fn(hidden_states)
|
| 501 |
+
return hidden_states
|
| 502 |
+
|
| 503 |
+
|
| 504 |
+
# Copied from transformers.models.swin.modeling_swin.SwinOutput
|
| 505 |
+
class DonutSwinOutput(nn.Module):
|
| 506 |
+
def __init__(self, config, dim):
|
| 507 |
+
super().__init__()
|
| 508 |
+
self.dense = nn.Linear(int(config.mlp_ratio * dim), dim)
|
| 509 |
+
self.dropout = nn.Dropout(config.hidden_dropout_prob)
|
| 510 |
+
|
| 511 |
+
def forward(self, hidden_states: torch.Tensor) -> torch.Tensor:
|
| 512 |
+
hidden_states = self.dense(hidden_states)
|
| 513 |
+
hidden_states = self.dropout(hidden_states)
|
| 514 |
+
return hidden_states
|
| 515 |
+
|
| 516 |
+
|
| 517 |
+
# Copied from transformers.models.swin.modeling_swin.SwinLayer with Swin->DonutSwin
|
| 518 |
+
class DonutSwinLayer(nn.Module):
|
| 519 |
+
def __init__(self, config, dim, input_resolution, num_heads, drop_path_rate=0.0, shift_size=0):
|
| 520 |
+
super().__init__()
|
| 521 |
+
self.chunk_size_feed_forward = config.chunk_size_feed_forward
|
| 522 |
+
self.shift_size = shift_size
|
| 523 |
+
self.window_size = config.window_size
|
| 524 |
+
self.input_resolution = input_resolution
|
| 525 |
+
self.layernorm_before = nn.LayerNorm(dim, eps=config.layer_norm_eps)
|
| 526 |
+
self.attention = DonutSwinAttention(config, dim, num_heads, window_size=self.window_size)
|
| 527 |
+
self.drop_path = DonutSwinDropPath(drop_path_rate) if drop_path_rate > 0.0 else nn.Identity()
|
| 528 |
+
self.layernorm_after = nn.LayerNorm(dim, eps=config.layer_norm_eps)
|
| 529 |
+
self.intermediate = DonutSwinIntermediate(config, dim)
|
| 530 |
+
self.output = DonutSwinOutput(config, dim)
|
| 531 |
+
|
| 532 |
+
def set_shift_and_window_size(self, input_resolution):
|
| 533 |
+
if min(input_resolution) <= self.window_size:
|
| 534 |
+
# if window size is larger than input resolution, we don't partition windows
|
| 535 |
+
self.shift_size = torch_int(0)
|
| 536 |
+
self.window_size = (
|
| 537 |
+
torch.min(torch.tensor(input_resolution)) if torch.jit.is_tracing() else min(input_resolution)
|
| 538 |
+
)
|
| 539 |
+
|
| 540 |
+
def get_attn_mask(self, height, width, dtype, device):
|
| 541 |
+
if self.shift_size > 0:
|
| 542 |
+
# calculate attention mask for SW-MSA
|
| 543 |
+
img_mask = torch.zeros((1, height, width, 1), dtype=dtype, device=device)
|
| 544 |
+
height_slices = (
|
| 545 |
+
slice(0, -self.window_size),
|
| 546 |
+
slice(-self.window_size, -self.shift_size),
|
| 547 |
+
slice(-self.shift_size, None),
|
| 548 |
+
)
|
| 549 |
+
width_slices = (
|
| 550 |
+
slice(0, -self.window_size),
|
| 551 |
+
slice(-self.window_size, -self.shift_size),
|
| 552 |
+
slice(-self.shift_size, None),
|
| 553 |
+
)
|
| 554 |
+
count = 0
|
| 555 |
+
for height_slice in height_slices:
|
| 556 |
+
for width_slice in width_slices:
|
| 557 |
+
img_mask[:, height_slice, width_slice, :] = count
|
| 558 |
+
count += 1
|
| 559 |
+
|
| 560 |
+
mask_windows = window_partition(img_mask, self.window_size)
|
| 561 |
+
mask_windows = mask_windows.view(-1, self.window_size * self.window_size)
|
| 562 |
+
attn_mask = mask_windows.unsqueeze(1) - mask_windows.unsqueeze(2)
|
| 563 |
+
attn_mask = attn_mask.masked_fill(attn_mask != 0, -100.0).masked_fill(attn_mask == 0, 0.0)
|
| 564 |
+
else:
|
| 565 |
+
attn_mask = None
|
| 566 |
+
return attn_mask
|
| 567 |
+
|
| 568 |
+
def maybe_pad(self, hidden_states, height, width):
|
| 569 |
+
pad_right = (self.window_size - width % self.window_size) % self.window_size
|
| 570 |
+
pad_bottom = (self.window_size - height % self.window_size) % self.window_size
|
| 571 |
+
pad_values = (0, 0, 0, pad_right, 0, pad_bottom)
|
| 572 |
+
hidden_states = nn.functional.pad(hidden_states, pad_values)
|
| 573 |
+
return hidden_states, pad_values
|
| 574 |
+
|
| 575 |
+
def forward(
|
| 576 |
+
self,
|
| 577 |
+
hidden_states: torch.Tensor,
|
| 578 |
+
input_dimensions: tuple[int, int],
|
| 579 |
+
output_attentions: bool | None = False,
|
| 580 |
+
always_partition: bool | None = False,
|
| 581 |
+
) -> tuple[torch.Tensor, torch.Tensor]:
|
| 582 |
+
if not always_partition:
|
| 583 |
+
self.set_shift_and_window_size(input_dimensions)
|
| 584 |
+
else:
|
| 585 |
+
pass
|
| 586 |
+
height, width = input_dimensions
|
| 587 |
+
batch_size, _, channels = hidden_states.size()
|
| 588 |
+
shortcut = hidden_states
|
| 589 |
+
|
| 590 |
+
hidden_states = self.layernorm_before(hidden_states)
|
| 591 |
+
|
| 592 |
+
hidden_states = hidden_states.view(batch_size, height, width, channels)
|
| 593 |
+
|
| 594 |
+
# pad hidden_states to multiples of window size
|
| 595 |
+
hidden_states, pad_values = self.maybe_pad(hidden_states, height, width)
|
| 596 |
+
|
| 597 |
+
_, height_pad, width_pad, _ = hidden_states.shape
|
| 598 |
+
# cyclic shift
|
| 599 |
+
if self.shift_size > 0:
|
| 600 |
+
shifted_hidden_states = torch.roll(hidden_states, shifts=(-self.shift_size, -self.shift_size), dims=(1, 2))
|
| 601 |
+
else:
|
| 602 |
+
shifted_hidden_states = hidden_states
|
| 603 |
+
|
| 604 |
+
# partition windows
|
| 605 |
+
hidden_states_windows = window_partition(shifted_hidden_states, self.window_size)
|
| 606 |
+
hidden_states_windows = hidden_states_windows.view(-1, self.window_size * self.window_size, channels)
|
| 607 |
+
attn_mask = self.get_attn_mask(
|
| 608 |
+
height_pad, width_pad, dtype=hidden_states.dtype, device=hidden_states_windows.device
|
| 609 |
+
)
|
| 610 |
+
|
| 611 |
+
attention_outputs = self.attention(hidden_states_windows, attn_mask, output_attentions=output_attentions)
|
| 612 |
+
|
| 613 |
+
attention_output = attention_outputs[0]
|
| 614 |
+
|
| 615 |
+
attention_windows = attention_output.view(-1, self.window_size, self.window_size, channels)
|
| 616 |
+
shifted_windows = window_reverse(attention_windows, self.window_size, height_pad, width_pad)
|
| 617 |
+
|
| 618 |
+
# reverse cyclic shift
|
| 619 |
+
if self.shift_size > 0:
|
| 620 |
+
attention_windows = torch.roll(shifted_windows, shifts=(self.shift_size, self.shift_size), dims=(1, 2))
|
| 621 |
+
else:
|
| 622 |
+
attention_windows = shifted_windows
|
| 623 |
+
|
| 624 |
+
was_padded = pad_values[3] > 0 or pad_values[5] > 0
|
| 625 |
+
if was_padded:
|
| 626 |
+
attention_windows = attention_windows[:, :height, :width, :].contiguous()
|
| 627 |
+
|
| 628 |
+
attention_windows = attention_windows.view(batch_size, height * width, channels)
|
| 629 |
+
|
| 630 |
+
hidden_states = shortcut + self.drop_path(attention_windows)
|
| 631 |
+
|
| 632 |
+
layer_output = self.layernorm_after(hidden_states)
|
| 633 |
+
layer_output = self.intermediate(layer_output)
|
| 634 |
+
layer_output = hidden_states + self.output(layer_output)
|
| 635 |
+
|
| 636 |
+
layer_outputs = (layer_output, attention_outputs[1]) if output_attentions else (layer_output,)
|
| 637 |
+
return layer_outputs
|
| 638 |
+
|
| 639 |
+
|
| 640 |
+
# Copied from transformers.models.swin.modeling_swin.SwinStage with Swin->DonutSwin
|
| 641 |
+
class DonutSwinStage(GradientCheckpointingLayer):
|
| 642 |
+
def __init__(self, config, dim, input_resolution, depth, num_heads, drop_path, downsample):
|
| 643 |
+
super().__init__()
|
| 644 |
+
self.config = config
|
| 645 |
+
self.dim = dim
|
| 646 |
+
self.blocks = nn.ModuleList(
|
| 647 |
+
[
|
| 648 |
+
DonutSwinLayer(
|
| 649 |
+
config=config,
|
| 650 |
+
dim=dim,
|
| 651 |
+
input_resolution=input_resolution,
|
| 652 |
+
num_heads=num_heads,
|
| 653 |
+
drop_path_rate=drop_path[i],
|
| 654 |
+
shift_size=0 if (i % 2 == 0) else config.window_size // 2,
|
| 655 |
+
)
|
| 656 |
+
for i in range(depth)
|
| 657 |
+
]
|
| 658 |
+
)
|
| 659 |
+
|
| 660 |
+
# patch merging layer
|
| 661 |
+
if downsample is not None:
|
| 662 |
+
self.downsample = downsample(input_resolution, dim=dim, norm_layer=nn.LayerNorm)
|
| 663 |
+
else:
|
| 664 |
+
self.downsample = None
|
| 665 |
+
|
| 666 |
+
self.pointing = False
|
| 667 |
+
|
| 668 |
+
def forward(
|
| 669 |
+
self,
|
| 670 |
+
hidden_states: torch.Tensor,
|
| 671 |
+
input_dimensions: tuple[int, int],
|
| 672 |
+
output_attentions: bool | None = False,
|
| 673 |
+
always_partition: bool | None = False,
|
| 674 |
+
) -> tuple[torch.Tensor]:
|
| 675 |
+
height, width = input_dimensions
|
| 676 |
+
for i, layer_module in enumerate(self.blocks):
|
| 677 |
+
layer_outputs = layer_module(hidden_states, input_dimensions, output_attentions, always_partition)
|
| 678 |
+
|
| 679 |
+
hidden_states = layer_outputs[0]
|
| 680 |
+
|
| 681 |
+
hidden_states_before_downsampling = hidden_states
|
| 682 |
+
if self.downsample is not None:
|
| 683 |
+
height_downsampled, width_downsampled = (height + 1) // 2, (width + 1) // 2
|
| 684 |
+
output_dimensions = (height, width, height_downsampled, width_downsampled)
|
| 685 |
+
hidden_states = self.downsample(hidden_states_before_downsampling, input_dimensions)
|
| 686 |
+
else:
|
| 687 |
+
output_dimensions = (height, width, height, width)
|
| 688 |
+
|
| 689 |
+
stage_outputs = (hidden_states, hidden_states_before_downsampling, output_dimensions)
|
| 690 |
+
|
| 691 |
+
if output_attentions:
|
| 692 |
+
stage_outputs += layer_outputs[1:]
|
| 693 |
+
return stage_outputs
|
| 694 |
+
|
| 695 |
+
|
| 696 |
+
# Copied from transformers.models.swin.modeling_swin.SwinEncoder with Swin->DonutSwin
|
| 697 |
+
class DonutSwinEncoder(nn.Module):
|
| 698 |
+
def __init__(self, config, grid_size):
|
| 699 |
+
super().__init__()
|
| 700 |
+
self.num_layers = len(config.depths)
|
| 701 |
+
self.config = config
|
| 702 |
+
dpr = [x.item() for x in torch.linspace(0, config.drop_path_rate, sum(config.depths), device="cpu")]
|
| 703 |
+
self.layers = nn.ModuleList(
|
| 704 |
+
[
|
| 705 |
+
DonutSwinStage(
|
| 706 |
+
config=config,
|
| 707 |
+
dim=int(config.embed_dim * 2**i_layer),
|
| 708 |
+
input_resolution=(grid_size[0] // (2**i_layer), grid_size[1] // (2**i_layer)),
|
| 709 |
+
depth=config.depths[i_layer],
|
| 710 |
+
num_heads=config.num_heads[i_layer],
|
| 711 |
+
drop_path=dpr[sum(config.depths[:i_layer]) : sum(config.depths[: i_layer + 1])],
|
| 712 |
+
downsample=DonutSwinPatchMerging if (i_layer < self.num_layers - 1) else None,
|
| 713 |
+
)
|
| 714 |
+
for i_layer in range(self.num_layers)
|
| 715 |
+
]
|
| 716 |
+
)
|
| 717 |
+
|
| 718 |
+
self.gradient_checkpointing = False
|
| 719 |
+
|
| 720 |
+
def forward(
|
| 721 |
+
self,
|
| 722 |
+
hidden_states: torch.Tensor,
|
| 723 |
+
input_dimensions: tuple[int, int],
|
| 724 |
+
output_attentions: bool | None = False,
|
| 725 |
+
output_hidden_states: bool | None = False,
|
| 726 |
+
output_hidden_states_before_downsampling: bool | None = False,
|
| 727 |
+
always_partition: bool | None = False,
|
| 728 |
+
return_dict: bool | None = True,
|
| 729 |
+
) -> tuple | DonutSwinEncoderOutput:
|
| 730 |
+
all_hidden_states = () if output_hidden_states else None
|
| 731 |
+
all_reshaped_hidden_states = () if output_hidden_states else None
|
| 732 |
+
all_self_attentions = () if output_attentions else None
|
| 733 |
+
|
| 734 |
+
if output_hidden_states:
|
| 735 |
+
batch_size, _, hidden_size = hidden_states.shape
|
| 736 |
+
# rearrange b (h w) c -> b c h w
|
| 737 |
+
reshaped_hidden_state = hidden_states.view(batch_size, *input_dimensions, hidden_size)
|
| 738 |
+
reshaped_hidden_state = reshaped_hidden_state.permute(0, 3, 1, 2)
|
| 739 |
+
all_hidden_states += (hidden_states,)
|
| 740 |
+
all_reshaped_hidden_states += (reshaped_hidden_state,)
|
| 741 |
+
|
| 742 |
+
for i, layer_module in enumerate(self.layers):
|
| 743 |
+
layer_outputs = layer_module(hidden_states, input_dimensions, output_attentions, always_partition)
|
| 744 |
+
|
| 745 |
+
hidden_states = layer_outputs[0]
|
| 746 |
+
hidden_states_before_downsampling = layer_outputs[1]
|
| 747 |
+
output_dimensions = layer_outputs[2]
|
| 748 |
+
|
| 749 |
+
input_dimensions = (output_dimensions[-2], output_dimensions[-1])
|
| 750 |
+
|
| 751 |
+
if output_hidden_states and output_hidden_states_before_downsampling:
|
| 752 |
+
batch_size, _, hidden_size = hidden_states_before_downsampling.shape
|
| 753 |
+
# rearrange b (h w) c -> b c h w
|
| 754 |
+
# here we use the original (not downsampled) height and width
|
| 755 |
+
reshaped_hidden_state = hidden_states_before_downsampling.view(
|
| 756 |
+
batch_size, *(output_dimensions[0], output_dimensions[1]), hidden_size
|
| 757 |
+
)
|
| 758 |
+
reshaped_hidden_state = reshaped_hidden_state.permute(0, 3, 1, 2)
|
| 759 |
+
all_hidden_states += (hidden_states_before_downsampling,)
|
| 760 |
+
all_reshaped_hidden_states += (reshaped_hidden_state,)
|
| 761 |
+
elif output_hidden_states and not output_hidden_states_before_downsampling:
|
| 762 |
+
batch_size, _, hidden_size = hidden_states.shape
|
| 763 |
+
# rearrange b (h w) c -> b c h w
|
| 764 |
+
reshaped_hidden_state = hidden_states.view(batch_size, *input_dimensions, hidden_size)
|
| 765 |
+
reshaped_hidden_state = reshaped_hidden_state.permute(0, 3, 1, 2)
|
| 766 |
+
all_hidden_states += (hidden_states,)
|
| 767 |
+
all_reshaped_hidden_states += (reshaped_hidden_state,)
|
| 768 |
+
|
| 769 |
+
if output_attentions:
|
| 770 |
+
all_self_attentions += layer_outputs[3:]
|
| 771 |
+
|
| 772 |
+
if not return_dict:
|
| 773 |
+
return tuple(v for v in [hidden_states, all_hidden_states, all_self_attentions] if v is not None)
|
| 774 |
+
|
| 775 |
+
return DonutSwinEncoderOutput(
|
| 776 |
+
last_hidden_state=hidden_states,
|
| 777 |
+
hidden_states=all_hidden_states,
|
| 778 |
+
attentions=all_self_attentions,
|
| 779 |
+
reshaped_hidden_states=all_reshaped_hidden_states,
|
| 780 |
+
)
|
| 781 |
+
|
| 782 |
+
|
| 783 |
+
@auto_docstring
|
| 784 |
+
# Copied from transformers.models.swin.modeling_swin.SwinPreTrainedModel with Swin->DonutSwin,swin->donut
|
| 785 |
+
class DonutSwinPreTrainedModel(PreTrainedModel):
|
| 786 |
+
config: DonutSwinConfig
|
| 787 |
+
base_model_prefix = "donut"
|
| 788 |
+
main_input_name = "pixel_values"
|
| 789 |
+
input_modalities = ("image",)
|
| 790 |
+
supports_gradient_checkpointing = True
|
| 791 |
+
_no_split_modules = ["DonutSwinStage"]
|
| 792 |
+
|
| 793 |
+
@torch.no_grad()
|
| 794 |
+
def _init_weights(self, module):
|
| 795 |
+
"""Initialize the weights"""
|
| 796 |
+
super()._init_weights(module)
|
| 797 |
+
if isinstance(module, DonutSwinEmbeddings):
|
| 798 |
+
if module.mask_token is not None:
|
| 799 |
+
init.zeros_(module.mask_token)
|
| 800 |
+
if module.position_embeddings is not None:
|
| 801 |
+
init.zeros_(module.position_embeddings)
|
| 802 |
+
elif isinstance(module, DonutSwinSelfAttention):
|
| 803 |
+
init.zeros_(module.relative_position_bias_table)
|
| 804 |
+
init.copy_(module.relative_position_index, module.create_relative_position_index())
|
| 805 |
+
|
| 806 |
+
|
| 807 |
+
@auto_docstring
|
| 808 |
+
class DonutSwinModel(DonutSwinPreTrainedModel):
|
| 809 |
+
def __init__(self, config, add_pooling_layer=True, use_mask_token=False):
|
| 810 |
+
r"""
|
| 811 |
+
add_pooling_layer (bool, *optional*, defaults to `True`):
|
| 812 |
+
Whether to add a pooling layer
|
| 813 |
+
use_mask_token (`bool`, *optional*, defaults to `False`):
|
| 814 |
+
Whether to use a mask token for masked image modeling.
|
| 815 |
+
"""
|
| 816 |
+
super().__init__(config)
|
| 817 |
+
self.config = config
|
| 818 |
+
self.num_layers = len(config.depths)
|
| 819 |
+
self.num_features = int(config.embed_dim * 2 ** (self.num_layers - 1))
|
| 820 |
+
|
| 821 |
+
self.embeddings = DonutSwinEmbeddings(config, use_mask_token=use_mask_token)
|
| 822 |
+
self.encoder = DonutSwinEncoder(config, self.embeddings.patch_grid)
|
| 823 |
+
|
| 824 |
+
self.pooler = nn.AdaptiveAvgPool1d(1) if add_pooling_layer else None
|
| 825 |
+
|
| 826 |
+
# Initialize weights and apply final processing
|
| 827 |
+
self.post_init()
|
| 828 |
+
|
| 829 |
+
def get_input_embeddings(self):
|
| 830 |
+
return self.embeddings.patch_embeddings
|
| 831 |
+
|
| 832 |
+
@auto_docstring
|
| 833 |
+
def forward(
|
| 834 |
+
self,
|
| 835 |
+
pixel_values: torch.FloatTensor | None = None,
|
| 836 |
+
bool_masked_pos: torch.BoolTensor | None = None,
|
| 837 |
+
output_attentions: bool | None = None,
|
| 838 |
+
output_hidden_states: bool | None = None,
|
| 839 |
+
interpolate_pos_encoding: bool = False,
|
| 840 |
+
return_dict: bool | None = None,
|
| 841 |
+
**kwargs,
|
| 842 |
+
) -> tuple | DonutSwinModelOutput:
|
| 843 |
+
r"""
|
| 844 |
+
bool_masked_pos (`torch.BoolTensor` of shape `(batch_size, num_patches)`):
|
| 845 |
+
Boolean masked positions. Indicates which patches are masked (1) and which aren't (0).
|
| 846 |
+
"""
|
| 847 |
+
output_attentions = output_attentions if output_attentions is not None else self.config.output_attentions
|
| 848 |
+
output_hidden_states = (
|
| 849 |
+
output_hidden_states if output_hidden_states is not None else self.config.output_hidden_states
|
| 850 |
+
)
|
| 851 |
+
return_dict = return_dict if return_dict is not None else self.config.return_dict
|
| 852 |
+
|
| 853 |
+
if pixel_values is None:
|
| 854 |
+
raise ValueError("You have to specify pixel_values")
|
| 855 |
+
|
| 856 |
+
embedding_output, input_dimensions = self.embeddings(
|
| 857 |
+
pixel_values, bool_masked_pos=bool_masked_pos, interpolate_pos_encoding=interpolate_pos_encoding
|
| 858 |
+
)
|
| 859 |
+
|
| 860 |
+
encoder_outputs = self.encoder(
|
| 861 |
+
embedding_output,
|
| 862 |
+
input_dimensions,
|
| 863 |
+
output_attentions=output_attentions,
|
| 864 |
+
output_hidden_states=output_hidden_states,
|
| 865 |
+
return_dict=return_dict,
|
| 866 |
+
)
|
| 867 |
+
|
| 868 |
+
sequence_output = encoder_outputs[0]
|
| 869 |
+
|
| 870 |
+
pooled_output = None
|
| 871 |
+
if self.pooler is not None:
|
| 872 |
+
pooled_output = self.pooler(sequence_output.transpose(1, 2))
|
| 873 |
+
pooled_output = torch.flatten(pooled_output, 1)
|
| 874 |
+
|
| 875 |
+
if not return_dict:
|
| 876 |
+
output = (sequence_output, pooled_output) + encoder_outputs[1:]
|
| 877 |
+
|
| 878 |
+
return output
|
| 879 |
+
|
| 880 |
+
return DonutSwinModelOutput(
|
| 881 |
+
last_hidden_state=sequence_output,
|
| 882 |
+
pooler_output=pooled_output,
|
| 883 |
+
hidden_states=encoder_outputs.hidden_states,
|
| 884 |
+
attentions=encoder_outputs.attentions,
|
| 885 |
+
reshaped_hidden_states=encoder_outputs.reshaped_hidden_states,
|
| 886 |
+
)
|
| 887 |
+
|
| 888 |
+
|
| 889 |
+
@auto_docstring(
|
| 890 |
+
custom_intro="""
|
| 891 |
+
DonutSwin Model transformer with an image classification head on top (a linear layer on top of the final hidden state of
|
| 892 |
+
the [CLS] token) e.g. for ImageNet.
|
| 893 |
+
|
| 894 |
+
<Tip>
|
| 895 |
+
|
| 896 |
+
Note that it's possible to fine-tune DonutSwin on higher resolution images than the ones it has been trained on, by
|
| 897 |
+
setting `interpolate_pos_encoding` to `True` in the forward of the model. This will interpolate the pre-trained
|
| 898 |
+
position embeddings to the higher resolution.
|
| 899 |
+
|
| 900 |
+
</Tip>
|
| 901 |
+
"""
|
| 902 |
+
)
|
| 903 |
+
# Copied from transformers.models.swin.modeling_swin.SwinForImageClassification with Swin->DonutSwin,swin->donut
|
| 904 |
+
class DonutSwinForImageClassification(DonutSwinPreTrainedModel):
|
| 905 |
+
def __init__(self, config):
|
| 906 |
+
super().__init__(config)
|
| 907 |
+
|
| 908 |
+
self.num_labels = config.num_labels
|
| 909 |
+
self.donut = DonutSwinModel(config)
|
| 910 |
+
|
| 911 |
+
# Classifier head
|
| 912 |
+
self.classifier = (
|
| 913 |
+
nn.Linear(self.donut.num_features, config.num_labels) if config.num_labels > 0 else nn.Identity()
|
| 914 |
+
)
|
| 915 |
+
|
| 916 |
+
# Initialize weights and apply final processing
|
| 917 |
+
self.post_init()
|
| 918 |
+
|
| 919 |
+
@auto_docstring
|
| 920 |
+
def forward(
|
| 921 |
+
self,
|
| 922 |
+
pixel_values: torch.FloatTensor | None = None,
|
| 923 |
+
labels: torch.LongTensor | None = None,
|
| 924 |
+
output_attentions: bool | None = None,
|
| 925 |
+
output_hidden_states: bool | None = None,
|
| 926 |
+
interpolate_pos_encoding: bool = False,
|
| 927 |
+
return_dict: bool | None = None,
|
| 928 |
+
**kwargs,
|
| 929 |
+
) -> tuple | DonutSwinImageClassifierOutput:
|
| 930 |
+
r"""
|
| 931 |
+
labels (`torch.LongTensor` of shape `(batch_size,)`, *optional*):
|
| 932 |
+
Labels for computing the image classification/regression loss. Indices should be in `[0, ...,
|
| 933 |
+
config.num_labels - 1]`. If `config.num_labels == 1` a regression loss is computed (Mean-Square loss), If
|
| 934 |
+
`config.num_labels > 1` a classification loss is computed (Cross-Entropy).
|
| 935 |
+
"""
|
| 936 |
+
return_dict = return_dict if return_dict is not None else self.config.return_dict
|
| 937 |
+
|
| 938 |
+
outputs = self.donut(
|
| 939 |
+
pixel_values,
|
| 940 |
+
output_attentions=output_attentions,
|
| 941 |
+
output_hidden_states=output_hidden_states,
|
| 942 |
+
interpolate_pos_encoding=interpolate_pos_encoding,
|
| 943 |
+
return_dict=return_dict,
|
| 944 |
+
)
|
| 945 |
+
|
| 946 |
+
pooled_output = outputs[1]
|
| 947 |
+
|
| 948 |
+
logits = self.classifier(pooled_output)
|
| 949 |
+
|
| 950 |
+
loss = None
|
| 951 |
+
if labels is not None:
|
| 952 |
+
loss = self.loss_function(labels, logits, self.config)
|
| 953 |
+
|
| 954 |
+
if not return_dict:
|
| 955 |
+
output = (logits,) + outputs[2:]
|
| 956 |
+
return ((loss,) + output) if loss is not None else output
|
| 957 |
+
|
| 958 |
+
return DonutSwinImageClassifierOutput(
|
| 959 |
+
loss=loss,
|
| 960 |
+
logits=logits,
|
| 961 |
+
hidden_states=outputs.hidden_states,
|
| 962 |
+
attentions=outputs.attentions,
|
| 963 |
+
reshaped_hidden_states=outputs.reshaped_hidden_states,
|
| 964 |
+
)
|
| 965 |
+
|
| 966 |
+
|
| 967 |
+
__all__ = ["DonutSwinModel", "DonutSwinPreTrainedModel", "DonutSwinForImageClassification"]
|
third_party/transformers/src/transformers/models/donut/processing_donut.py
ADDED
|
@@ -0,0 +1,135 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
# Copyright 2022 The HuggingFace Inc. team.
|
| 2 |
+
#
|
| 3 |
+
# Licensed under the Apache License, Version 2.0 (the "License");
|
| 4 |
+
# you may not use this file except in compliance with the License.
|
| 5 |
+
# You may obtain a copy of the License at
|
| 6 |
+
#
|
| 7 |
+
# http://www.apache.org/licenses/LICENSE-2.0
|
| 8 |
+
#
|
| 9 |
+
# Unless required by applicable law or agreed to in writing, software
|
| 10 |
+
# distributed under the License is distributed on an "AS IS" BASIS,
|
| 11 |
+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
| 12 |
+
# See the License for the specific language governing permissions and
|
| 13 |
+
# limitations under the License.
|
| 14 |
+
"""
|
| 15 |
+
Processor class for Donut.
|
| 16 |
+
"""
|
| 17 |
+
|
| 18 |
+
import re
|
| 19 |
+
|
| 20 |
+
from ...image_utils import ImageInput
|
| 21 |
+
from ...processing_utils import ProcessingKwargs, ProcessorMixin, Unpack
|
| 22 |
+
from ...tokenization_utils_base import PreTokenizedInput, TextInput
|
| 23 |
+
from ...utils import auto_docstring, logging
|
| 24 |
+
|
| 25 |
+
|
| 26 |
+
class DonutProcessorKwargs(ProcessingKwargs, total=False):
|
| 27 |
+
_defaults = {}
|
| 28 |
+
|
| 29 |
+
|
| 30 |
+
logger = logging.get_logger(__name__)
|
| 31 |
+
|
| 32 |
+
|
| 33 |
+
@auto_docstring
|
| 34 |
+
class DonutProcessor(ProcessorMixin):
|
| 35 |
+
def __init__(self, image_processor=None, tokenizer=None, **kwargs):
|
| 36 |
+
super().__init__(image_processor, tokenizer)
|
| 37 |
+
|
| 38 |
+
@auto_docstring
|
| 39 |
+
def __call__(
|
| 40 |
+
self,
|
| 41 |
+
images: ImageInput | None = None,
|
| 42 |
+
text: str | list[str] | TextInput | PreTokenizedInput | None = None,
|
| 43 |
+
**kwargs: Unpack[DonutProcessorKwargs],
|
| 44 |
+
):
|
| 45 |
+
if images is None and text is None:
|
| 46 |
+
raise ValueError("You need to specify either an `images` or `text` input to process.")
|
| 47 |
+
|
| 48 |
+
output_kwargs = self._merge_kwargs(
|
| 49 |
+
DonutProcessorKwargs,
|
| 50 |
+
tokenizer_init_kwargs=self.tokenizer.init_kwargs,
|
| 51 |
+
**kwargs,
|
| 52 |
+
)
|
| 53 |
+
|
| 54 |
+
if images is not None:
|
| 55 |
+
inputs = self.image_processor(images, **output_kwargs["images_kwargs"])
|
| 56 |
+
if text is not None:
|
| 57 |
+
if images is not None:
|
| 58 |
+
output_kwargs["text_kwargs"].setdefault("add_special_tokens", False)
|
| 59 |
+
encodings = self.tokenizer(text, **output_kwargs["text_kwargs"])
|
| 60 |
+
|
| 61 |
+
if text is None:
|
| 62 |
+
return inputs
|
| 63 |
+
elif images is None:
|
| 64 |
+
return encodings
|
| 65 |
+
else:
|
| 66 |
+
inputs["labels"] = encodings["input_ids"] # for BC
|
| 67 |
+
inputs["input_ids"] = encodings["input_ids"]
|
| 68 |
+
return inputs
|
| 69 |
+
|
| 70 |
+
@property
|
| 71 |
+
def model_input_names(self):
|
| 72 |
+
image_processor_input_names = self.image_processor.model_input_names
|
| 73 |
+
|
| 74 |
+
return list(image_processor_input_names + ["input_ids", "labels"])
|
| 75 |
+
|
| 76 |
+
def token2json(self, tokens, is_inner_value=False, added_vocab=None):
|
| 77 |
+
"""
|
| 78 |
+
Convert a (generated) token sequence into an ordered JSON format.
|
| 79 |
+
"""
|
| 80 |
+
if added_vocab is None:
|
| 81 |
+
added_vocab = self.tokenizer.get_added_vocab()
|
| 82 |
+
|
| 83 |
+
output = {}
|
| 84 |
+
|
| 85 |
+
while tokens:
|
| 86 |
+
# We want r"<s_(.*?)>" but without ReDOS risk, so do it manually in two parts
|
| 87 |
+
potential_start = re.search(r"<s_", tokens, re.IGNORECASE)
|
| 88 |
+
if potential_start is None:
|
| 89 |
+
break
|
| 90 |
+
start_token = tokens[potential_start.start() :]
|
| 91 |
+
if ">" not in start_token:
|
| 92 |
+
break
|
| 93 |
+
start_token = start_token[: start_token.index(">") + 1]
|
| 94 |
+
key = start_token[len("<s_") : -len(">")]
|
| 95 |
+
key_escaped = re.escape(key)
|
| 96 |
+
|
| 97 |
+
end_token = re.search(rf"</s_{key_escaped}>", tokens, re.IGNORECASE)
|
| 98 |
+
if end_token is None:
|
| 99 |
+
tokens = tokens.replace(start_token, "")
|
| 100 |
+
else:
|
| 101 |
+
end_token = end_token.group()
|
| 102 |
+
start_token_escaped = re.escape(start_token)
|
| 103 |
+
end_token_escaped = re.escape(end_token)
|
| 104 |
+
content = re.search(
|
| 105 |
+
f"{start_token_escaped}(.*?){end_token_escaped}", tokens, re.IGNORECASE | re.DOTALL
|
| 106 |
+
)
|
| 107 |
+
if content is not None:
|
| 108 |
+
content = content.group(1).strip()
|
| 109 |
+
if r"<s_" in content and r"</s_" in content: # non-leaf node
|
| 110 |
+
value = self.token2json(content, is_inner_value=True, added_vocab=added_vocab)
|
| 111 |
+
if value:
|
| 112 |
+
if len(value) == 1:
|
| 113 |
+
value = value[0]
|
| 114 |
+
output[key] = value
|
| 115 |
+
else: # leaf nodes
|
| 116 |
+
output[key] = []
|
| 117 |
+
for leaf in content.split(r"<sep/>"):
|
| 118 |
+
leaf = leaf.strip()
|
| 119 |
+
if leaf in added_vocab and leaf[0] == "<" and leaf[-2:] == "/>":
|
| 120 |
+
leaf = leaf[1:-2] # for categorical special tokens
|
| 121 |
+
output[key].append(leaf)
|
| 122 |
+
if len(output[key]) == 1:
|
| 123 |
+
output[key] = output[key][0]
|
| 124 |
+
|
| 125 |
+
tokens = tokens[tokens.find(end_token) + len(end_token) :].strip()
|
| 126 |
+
if tokens[:6] == r"<sep/>": # non-leaf nodes
|
| 127 |
+
return [output] + self.token2json(tokens[6:], is_inner_value=True, added_vocab=added_vocab)
|
| 128 |
+
|
| 129 |
+
if output:
|
| 130 |
+
return [output] if is_inner_value else output
|
| 131 |
+
else:
|
| 132 |
+
return [] if is_inner_value else {"text_sequence": tokens}
|
| 133 |
+
|
| 134 |
+
|
| 135 |
+
__all__ = ["DonutProcessor"]
|
third_party/transformers/src/transformers/models/ibert/__init__.py
ADDED
|
@@ -0,0 +1,27 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
# Copyright 2024 The HuggingFace Team. All rights reserved.
|
| 2 |
+
#
|
| 3 |
+
# Licensed under the Apache License, Version 2.0 (the "License");
|
| 4 |
+
# you may not use this file except in compliance with the License.
|
| 5 |
+
# You may obtain a copy of the License at
|
| 6 |
+
#
|
| 7 |
+
# http://www.apache.org/licenses/LICENSE-2.0
|
| 8 |
+
#
|
| 9 |
+
# Unless required by applicable law or agreed to in writing, software
|
| 10 |
+
# distributed under the License is distributed on an "AS IS" BASIS,
|
| 11 |
+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
| 12 |
+
# See the License for the specific language governing permissions and
|
| 13 |
+
# limitations under the License.
|
| 14 |
+
from typing import TYPE_CHECKING
|
| 15 |
+
|
| 16 |
+
from ...utils import _LazyModule
|
| 17 |
+
from ...utils.import_utils import define_import_structure
|
| 18 |
+
|
| 19 |
+
|
| 20 |
+
if TYPE_CHECKING:
|
| 21 |
+
from .configuration_ibert import *
|
| 22 |
+
from .modeling_ibert import *
|
| 23 |
+
else:
|
| 24 |
+
import sys
|
| 25 |
+
|
| 26 |
+
_file = globals()["__file__"]
|
| 27 |
+
sys.modules[__name__] = _LazyModule(__name__, _file, define_import_structure(_file), module_spec=__spec__)
|
third_party/transformers/src/transformers/models/ibert/configuration_ibert.py
ADDED
|
@@ -0,0 +1,61 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
# Copyright 2021 The I-BERT Authors (Sehoon Kim, Amir Gholami, Zhewei Yao,
|
| 2 |
+
# Michael Mahoney, Kurt Keutzer - UC Berkeley) and The HuggingFace Inc. team.
|
| 3 |
+
# Copyright (c) 20121, NVIDIA CORPORATION. All rights reserved.
|
| 4 |
+
#
|
| 5 |
+
# Licensed under the Apache License, Version 2.0 (the "License");
|
| 6 |
+
# you may not use this file except in compliance with the License.
|
| 7 |
+
# You may obtain a copy of the License at
|
| 8 |
+
#
|
| 9 |
+
# http://www.apache.org/licenses/LICENSE-2.0
|
| 10 |
+
#
|
| 11 |
+
# Unless required by applicable law or agreed to in writing, software
|
| 12 |
+
# distributed under the License is distributed on an "AS IS" BASIS,
|
| 13 |
+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
| 14 |
+
# See the License for the specific language governing permissions and
|
| 15 |
+
# limitations under the License.
|
| 16 |
+
"""I-BERT configuration"""
|
| 17 |
+
|
| 18 |
+
from huggingface_hub.dataclasses import strict
|
| 19 |
+
|
| 20 |
+
from ...configuration_utils import PreTrainedConfig
|
| 21 |
+
from ...utils import auto_docstring
|
| 22 |
+
|
| 23 |
+
|
| 24 |
+
@auto_docstring(checkpoint="kssteven/ibert-roberta-base")
|
| 25 |
+
@strict
|
| 26 |
+
class IBertConfig(PreTrainedConfig):
|
| 27 |
+
r"""
|
| 28 |
+
type_vocab_size (`int`, *optional*, defaults to 2):
|
| 29 |
+
The vocabulary size of the `token_type_ids` passed when calling [`IBertModel`]
|
| 30 |
+
quant_mode (`bool`, *optional*, defaults to `False`):
|
| 31 |
+
Whether to quantize the model or not.
|
| 32 |
+
force_dequant (`str`, *optional*, defaults to `"none"`):
|
| 33 |
+
Force dequantize specific nonlinear layer. Dequantized layers are then executed with full precision.
|
| 34 |
+
`"none"`, `"gelu"`, `"softmax"`, `"layernorm"` and `"nonlinear"` are supported. As default, it is set as
|
| 35 |
+
`"none"`, which does not dequantize any layers. Please specify `"gelu"`, `"softmax"`, or `"layernorm"` to
|
| 36 |
+
dequantize GELU, Softmax, or LayerNorm, respectively. `"nonlinear"` will dequantize all nonlinear layers,
|
| 37 |
+
i.e., GELU, Softmax, and LayerNorm.
|
| 38 |
+
"""
|
| 39 |
+
|
| 40 |
+
model_type = "ibert"
|
| 41 |
+
|
| 42 |
+
vocab_size: int = 30522
|
| 43 |
+
hidden_size: int = 768
|
| 44 |
+
num_hidden_layers: int = 12
|
| 45 |
+
num_attention_heads: int = 12
|
| 46 |
+
intermediate_size: int = 3072
|
| 47 |
+
hidden_act: str = "gelu"
|
| 48 |
+
hidden_dropout_prob: float | int = 0.1
|
| 49 |
+
attention_probs_dropout_prob: float | int = 0.1
|
| 50 |
+
max_position_embeddings: int = 512
|
| 51 |
+
type_vocab_size: int = 2
|
| 52 |
+
initializer_range: float = 0.02
|
| 53 |
+
layer_norm_eps: float = 1e-12
|
| 54 |
+
pad_token_id: int | None = 1
|
| 55 |
+
bos_token_id: int | None = 0
|
| 56 |
+
eos_token_id: int | list[int] | None = 2
|
| 57 |
+
quant_mode: bool = False
|
| 58 |
+
force_dequant: str = "none"
|
| 59 |
+
|
| 60 |
+
|
| 61 |
+
__all__ = ["IBertConfig"]
|
third_party/transformers/src/transformers/models/ibert/modeling_ibert.py
ADDED
|
@@ -0,0 +1,1201 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
# Copyright 2021 The I-BERT Authors (Sehoon Kim, Amir Gholami, Zhewei Yao,
|
| 2 |
+
# Michael Mahoney, Kurt Keutzer - UC Berkeley) and The HuggingFace Inc. team.
|
| 3 |
+
# Copyright (c) 20121, NVIDIA CORPORATION. All rights reserved.
|
| 4 |
+
#
|
| 5 |
+
# Licensed under the Apache License, Version 2.0 (the "License");
|
| 6 |
+
# you may not use this file except in compliance with the License.
|
| 7 |
+
# You may obtain a copy of the License at
|
| 8 |
+
#
|
| 9 |
+
# http://www.apache.org/licenses/LICENSE-2.0
|
| 10 |
+
#
|
| 11 |
+
# Unless required by applicable law or agreed to in writing, software
|
| 12 |
+
# distributed under the License is distributed on an "AS IS" BASIS,
|
| 13 |
+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
| 14 |
+
# See the License for the specific language governing permissions and
|
| 15 |
+
# limitations under the License.
|
| 16 |
+
|
| 17 |
+
"""PyTorch I-BERT model."""
|
| 18 |
+
|
| 19 |
+
import math
|
| 20 |
+
|
| 21 |
+
import torch
|
| 22 |
+
from torch import nn
|
| 23 |
+
from torch.nn import BCEWithLogitsLoss, CrossEntropyLoss, MSELoss
|
| 24 |
+
|
| 25 |
+
from ... import initialization as init
|
| 26 |
+
from ...activations import gelu
|
| 27 |
+
from ...modeling_outputs import (
|
| 28 |
+
BaseModelOutputWithPastAndCrossAttentions,
|
| 29 |
+
BaseModelOutputWithPoolingAndCrossAttentions,
|
| 30 |
+
MaskedLMOutput,
|
| 31 |
+
MultipleChoiceModelOutput,
|
| 32 |
+
QuestionAnsweringModelOutput,
|
| 33 |
+
SequenceClassifierOutput,
|
| 34 |
+
TokenClassifierOutput,
|
| 35 |
+
)
|
| 36 |
+
from ...modeling_utils import PreTrainedModel
|
| 37 |
+
from ...utils import auto_docstring, logging
|
| 38 |
+
from .configuration_ibert import IBertConfig
|
| 39 |
+
from .quant_modules import IntGELU, IntLayerNorm, IntSoftmax, QuantAct, QuantEmbedding, QuantLinear
|
| 40 |
+
|
| 41 |
+
|
| 42 |
+
logger = logging.get_logger(__name__)
|
| 43 |
+
|
| 44 |
+
|
| 45 |
+
class IBertEmbeddings(nn.Module):
|
| 46 |
+
"""
|
| 47 |
+
Same as BertEmbeddings with a tiny tweak for positional embeddings indexing.
|
| 48 |
+
"""
|
| 49 |
+
|
| 50 |
+
def __init__(self, config):
|
| 51 |
+
super().__init__()
|
| 52 |
+
self.quant_mode = config.quant_mode
|
| 53 |
+
self.embedding_bit = 8
|
| 54 |
+
self.embedding_act_bit = 16
|
| 55 |
+
self.act_bit = 8
|
| 56 |
+
self.ln_input_bit = 22
|
| 57 |
+
self.ln_output_bit = 32
|
| 58 |
+
|
| 59 |
+
self.word_embeddings = QuantEmbedding(
|
| 60 |
+
config.vocab_size,
|
| 61 |
+
config.hidden_size,
|
| 62 |
+
padding_idx=config.pad_token_id,
|
| 63 |
+
weight_bit=self.embedding_bit,
|
| 64 |
+
quant_mode=self.quant_mode,
|
| 65 |
+
)
|
| 66 |
+
self.token_type_embeddings = QuantEmbedding(
|
| 67 |
+
config.type_vocab_size, config.hidden_size, weight_bit=self.embedding_bit, quant_mode=self.quant_mode
|
| 68 |
+
)
|
| 69 |
+
|
| 70 |
+
# position_ids (1, len position emb) is contiguous in memory and exported when serialized
|
| 71 |
+
self.register_buffer(
|
| 72 |
+
"position_ids", torch.arange(config.max_position_embeddings).expand((1, -1)), persistent=False
|
| 73 |
+
)
|
| 74 |
+
|
| 75 |
+
# End copy
|
| 76 |
+
self.padding_idx = config.pad_token_id
|
| 77 |
+
self.position_embeddings = QuantEmbedding(
|
| 78 |
+
config.max_position_embeddings,
|
| 79 |
+
config.hidden_size,
|
| 80 |
+
padding_idx=self.padding_idx,
|
| 81 |
+
weight_bit=self.embedding_bit,
|
| 82 |
+
quant_mode=self.quant_mode,
|
| 83 |
+
)
|
| 84 |
+
|
| 85 |
+
# Integer-only addition between embeddings
|
| 86 |
+
self.embeddings_act1 = QuantAct(self.embedding_act_bit, quant_mode=self.quant_mode)
|
| 87 |
+
self.embeddings_act2 = QuantAct(self.embedding_act_bit, quant_mode=self.quant_mode)
|
| 88 |
+
|
| 89 |
+
self.LayerNorm = IntLayerNorm(
|
| 90 |
+
config.hidden_size,
|
| 91 |
+
eps=config.layer_norm_eps,
|
| 92 |
+
output_bit=self.ln_output_bit,
|
| 93 |
+
quant_mode=self.quant_mode,
|
| 94 |
+
force_dequant=config.force_dequant,
|
| 95 |
+
)
|
| 96 |
+
self.output_activation = QuantAct(self.act_bit, quant_mode=self.quant_mode)
|
| 97 |
+
self.dropout = nn.Dropout(config.hidden_dropout_prob)
|
| 98 |
+
|
| 99 |
+
def forward(
|
| 100 |
+
self, input_ids=None, token_type_ids=None, position_ids=None, inputs_embeds=None, past_key_values_length=0
|
| 101 |
+
):
|
| 102 |
+
if position_ids is None:
|
| 103 |
+
if input_ids is not None:
|
| 104 |
+
# Create the position ids from the input token ids. Any padded tokens remain padded.
|
| 105 |
+
position_ids = create_position_ids_from_input_ids(
|
| 106 |
+
input_ids, self.padding_idx, past_key_values_length
|
| 107 |
+
).to(input_ids.device)
|
| 108 |
+
else:
|
| 109 |
+
position_ids = self.create_position_ids_from_inputs_embeds(inputs_embeds)
|
| 110 |
+
|
| 111 |
+
if input_ids is not None:
|
| 112 |
+
input_shape = input_ids.size()
|
| 113 |
+
else:
|
| 114 |
+
input_shape = inputs_embeds.size()[:-1]
|
| 115 |
+
|
| 116 |
+
if token_type_ids is None:
|
| 117 |
+
token_type_ids = torch.zeros(input_shape, dtype=torch.long, device=self.position_ids.device)
|
| 118 |
+
|
| 119 |
+
if inputs_embeds is None:
|
| 120 |
+
inputs_embeds, inputs_embeds_scaling_factor = self.word_embeddings(input_ids)
|
| 121 |
+
else:
|
| 122 |
+
inputs_embeds_scaling_factor = None
|
| 123 |
+
token_type_embeddings, token_type_embeddings_scaling_factor = self.token_type_embeddings(token_type_ids)
|
| 124 |
+
|
| 125 |
+
embeddings, embeddings_scaling_factor = self.embeddings_act1(
|
| 126 |
+
inputs_embeds,
|
| 127 |
+
inputs_embeds_scaling_factor,
|
| 128 |
+
identity=token_type_embeddings,
|
| 129 |
+
identity_scaling_factor=token_type_embeddings_scaling_factor,
|
| 130 |
+
)
|
| 131 |
+
|
| 132 |
+
position_embeddings, position_embeddings_scaling_factor = self.position_embeddings(position_ids)
|
| 133 |
+
embeddings, embeddings_scaling_factor = self.embeddings_act1(
|
| 134 |
+
embeddings,
|
| 135 |
+
embeddings_scaling_factor,
|
| 136 |
+
identity=position_embeddings,
|
| 137 |
+
identity_scaling_factor=position_embeddings_scaling_factor,
|
| 138 |
+
)
|
| 139 |
+
|
| 140 |
+
embeddings, embeddings_scaling_factor = self.LayerNorm(embeddings, embeddings_scaling_factor)
|
| 141 |
+
embeddings = self.dropout(embeddings)
|
| 142 |
+
embeddings, embeddings_scaling_factor = self.output_activation(embeddings, embeddings_scaling_factor)
|
| 143 |
+
return embeddings, embeddings_scaling_factor
|
| 144 |
+
|
| 145 |
+
def create_position_ids_from_inputs_embeds(self, inputs_embeds):
|
| 146 |
+
"""
|
| 147 |
+
We are provided embeddings directly. We cannot infer which are padded so just generate sequential position ids.
|
| 148 |
+
|
| 149 |
+
Args:
|
| 150 |
+
inputs_embeds: torch.Tensor
|
| 151 |
+
|
| 152 |
+
Returns: torch.Tensor
|
| 153 |
+
"""
|
| 154 |
+
input_shape = inputs_embeds.size()[:-1]
|
| 155 |
+
sequence_length = input_shape[1]
|
| 156 |
+
|
| 157 |
+
position_ids = torch.arange(
|
| 158 |
+
self.padding_idx + 1, sequence_length + self.padding_idx + 1, dtype=torch.long, device=inputs_embeds.device
|
| 159 |
+
)
|
| 160 |
+
return position_ids.unsqueeze(0).expand(input_shape)
|
| 161 |
+
|
| 162 |
+
|
| 163 |
+
class IBertSelfAttention(nn.Module):
|
| 164 |
+
def __init__(self, config):
|
| 165 |
+
super().__init__()
|
| 166 |
+
if config.hidden_size % config.num_attention_heads != 0 and not hasattr(config, "embedding_size"):
|
| 167 |
+
raise ValueError(
|
| 168 |
+
f"The hidden size ({config.hidden_size}) is not a multiple of the number of attention "
|
| 169 |
+
f"heads ({config.num_attention_heads})"
|
| 170 |
+
)
|
| 171 |
+
self.quant_mode = config.quant_mode
|
| 172 |
+
self.weight_bit = 8
|
| 173 |
+
self.bias_bit = 32
|
| 174 |
+
self.act_bit = 8
|
| 175 |
+
|
| 176 |
+
self.num_attention_heads = config.num_attention_heads
|
| 177 |
+
self.attention_head_size = int(config.hidden_size / config.num_attention_heads)
|
| 178 |
+
self.all_head_size = self.num_attention_heads * self.attention_head_size
|
| 179 |
+
|
| 180 |
+
# Q, K, V Linear layers
|
| 181 |
+
self.query = QuantLinear(
|
| 182 |
+
config.hidden_size,
|
| 183 |
+
self.all_head_size,
|
| 184 |
+
bias=True,
|
| 185 |
+
weight_bit=self.weight_bit,
|
| 186 |
+
bias_bit=self.bias_bit,
|
| 187 |
+
quant_mode=self.quant_mode,
|
| 188 |
+
per_channel=True,
|
| 189 |
+
)
|
| 190 |
+
self.key = QuantLinear(
|
| 191 |
+
config.hidden_size,
|
| 192 |
+
self.all_head_size,
|
| 193 |
+
bias=True,
|
| 194 |
+
weight_bit=self.weight_bit,
|
| 195 |
+
bias_bit=self.bias_bit,
|
| 196 |
+
quant_mode=self.quant_mode,
|
| 197 |
+
per_channel=True,
|
| 198 |
+
)
|
| 199 |
+
self.value = QuantLinear(
|
| 200 |
+
config.hidden_size,
|
| 201 |
+
self.all_head_size,
|
| 202 |
+
bias=True,
|
| 203 |
+
weight_bit=self.weight_bit,
|
| 204 |
+
bias_bit=self.bias_bit,
|
| 205 |
+
quant_mode=self.quant_mode,
|
| 206 |
+
per_channel=True,
|
| 207 |
+
)
|
| 208 |
+
|
| 209 |
+
# Requantization (32bit -> 8bit) for Q, K, V activations
|
| 210 |
+
self.query_activation = QuantAct(self.act_bit, quant_mode=self.quant_mode)
|
| 211 |
+
self.key_activation = QuantAct(self.act_bit, quant_mode=self.quant_mode)
|
| 212 |
+
self.value_activation = QuantAct(self.act_bit, quant_mode=self.quant_mode)
|
| 213 |
+
self.output_activation = QuantAct(self.act_bit, quant_mode=self.quant_mode)
|
| 214 |
+
|
| 215 |
+
self.dropout = nn.Dropout(config.attention_probs_dropout_prob)
|
| 216 |
+
|
| 217 |
+
self.softmax = IntSoftmax(self.act_bit, quant_mode=self.quant_mode, force_dequant=config.force_dequant)
|
| 218 |
+
|
| 219 |
+
def forward(
|
| 220 |
+
self,
|
| 221 |
+
hidden_states,
|
| 222 |
+
hidden_states_scaling_factor,
|
| 223 |
+
attention_mask=None,
|
| 224 |
+
output_attentions=False,
|
| 225 |
+
):
|
| 226 |
+
# Projection
|
| 227 |
+
mixed_query_layer, mixed_query_layer_scaling_factor = self.query(hidden_states, hidden_states_scaling_factor)
|
| 228 |
+
mixed_key_layer, mixed_key_layer_scaling_factor = self.key(hidden_states, hidden_states_scaling_factor)
|
| 229 |
+
mixed_value_layer, mixed_value_layer_scaling_factor = self.value(hidden_states, hidden_states_scaling_factor)
|
| 230 |
+
|
| 231 |
+
# Requantization
|
| 232 |
+
query_layer, query_layer_scaling_factor = self.query_activation(
|
| 233 |
+
mixed_query_layer, mixed_query_layer_scaling_factor
|
| 234 |
+
)
|
| 235 |
+
key_layer, key_layer_scaling_factor = self.key_activation(mixed_key_layer, mixed_key_layer_scaling_factor)
|
| 236 |
+
value_layer, value_layer_scaling_factor = self.value_activation(
|
| 237 |
+
mixed_value_layer, mixed_value_layer_scaling_factor
|
| 238 |
+
)
|
| 239 |
+
|
| 240 |
+
# Transpose
|
| 241 |
+
batch_size, seq_length, _ = hidden_states.shape
|
| 242 |
+
query_layer = query_layer.view(batch_size, -1, self.num_attention_heads, self.attention_head_size).transpose(
|
| 243 |
+
1, 2
|
| 244 |
+
)
|
| 245 |
+
key_layer = key_layer.view(batch_size, -1, self.num_attention_heads, self.attention_head_size).transpose(1, 2)
|
| 246 |
+
value_layer = value_layer.view(batch_size, -1, self.num_attention_heads, self.attention_head_size).transpose(
|
| 247 |
+
1, 2
|
| 248 |
+
)
|
| 249 |
+
|
| 250 |
+
# Take the dot product between "query" and "key" to get the raw attention scores.
|
| 251 |
+
attention_scores = torch.matmul(query_layer, key_layer.transpose(-1, -2))
|
| 252 |
+
scale = math.sqrt(self.attention_head_size)
|
| 253 |
+
attention_scores = attention_scores / scale
|
| 254 |
+
if self.quant_mode:
|
| 255 |
+
attention_scores_scaling_factor = query_layer_scaling_factor * key_layer_scaling_factor / scale
|
| 256 |
+
else:
|
| 257 |
+
attention_scores_scaling_factor = None
|
| 258 |
+
|
| 259 |
+
if attention_mask is not None:
|
| 260 |
+
# Apply the attention mask is (precomputed for all layers in IBertModel forward() function)
|
| 261 |
+
attention_scores = attention_scores + attention_mask
|
| 262 |
+
|
| 263 |
+
# Normalize the attention scores to probabilities.
|
| 264 |
+
attention_probs, attention_probs_scaling_factor = self.softmax(
|
| 265 |
+
attention_scores, attention_scores_scaling_factor
|
| 266 |
+
)
|
| 267 |
+
|
| 268 |
+
# This is actually dropping out entire tokens to attend to, which might
|
| 269 |
+
# seem a bit unusual, but is taken from the original Transformer paper.
|
| 270 |
+
attention_probs = self.dropout(attention_probs)
|
| 271 |
+
|
| 272 |
+
context_layer = torch.matmul(attention_probs, value_layer)
|
| 273 |
+
if attention_probs_scaling_factor is not None:
|
| 274 |
+
context_layer_scaling_factor = attention_probs_scaling_factor * value_layer_scaling_factor
|
| 275 |
+
else:
|
| 276 |
+
context_layer_scaling_factor = None
|
| 277 |
+
|
| 278 |
+
context_layer = context_layer.permute(0, 2, 1, 3).contiguous()
|
| 279 |
+
new_context_layer_shape = context_layer.size()[:-2] + (self.all_head_size,)
|
| 280 |
+
context_layer = context_layer.view(*new_context_layer_shape)
|
| 281 |
+
|
| 282 |
+
# requantization: 32-bit -> 8-bit
|
| 283 |
+
context_layer, context_layer_scaling_factor = self.output_activation(
|
| 284 |
+
context_layer, context_layer_scaling_factor
|
| 285 |
+
)
|
| 286 |
+
|
| 287 |
+
outputs = (context_layer, attention_probs) if output_attentions else (context_layer,)
|
| 288 |
+
output_scaling_factor = (
|
| 289 |
+
(context_layer_scaling_factor, attention_probs_scaling_factor)
|
| 290 |
+
if output_attentions
|
| 291 |
+
else (context_layer_scaling_factor,)
|
| 292 |
+
)
|
| 293 |
+
|
| 294 |
+
return outputs, output_scaling_factor
|
| 295 |
+
|
| 296 |
+
|
| 297 |
+
class IBertSelfOutput(nn.Module):
|
| 298 |
+
def __init__(self, config):
|
| 299 |
+
super().__init__()
|
| 300 |
+
self.quant_mode = config.quant_mode
|
| 301 |
+
self.act_bit = 8
|
| 302 |
+
self.weight_bit = 8
|
| 303 |
+
self.bias_bit = 32
|
| 304 |
+
self.ln_input_bit = 22
|
| 305 |
+
self.ln_output_bit = 32
|
| 306 |
+
|
| 307 |
+
self.dense = QuantLinear(
|
| 308 |
+
config.hidden_size,
|
| 309 |
+
config.hidden_size,
|
| 310 |
+
bias=True,
|
| 311 |
+
weight_bit=self.weight_bit,
|
| 312 |
+
bias_bit=self.bias_bit,
|
| 313 |
+
quant_mode=self.quant_mode,
|
| 314 |
+
per_channel=True,
|
| 315 |
+
)
|
| 316 |
+
self.ln_input_act = QuantAct(self.ln_input_bit, quant_mode=self.quant_mode)
|
| 317 |
+
self.LayerNorm = IntLayerNorm(
|
| 318 |
+
config.hidden_size,
|
| 319 |
+
eps=config.layer_norm_eps,
|
| 320 |
+
output_bit=self.ln_output_bit,
|
| 321 |
+
quant_mode=self.quant_mode,
|
| 322 |
+
force_dequant=config.force_dequant,
|
| 323 |
+
)
|
| 324 |
+
self.output_activation = QuantAct(self.act_bit, quant_mode=self.quant_mode)
|
| 325 |
+
self.dropout = nn.Dropout(config.hidden_dropout_prob)
|
| 326 |
+
|
| 327 |
+
def forward(self, hidden_states, hidden_states_scaling_factor, input_tensor, input_tensor_scaling_factor):
|
| 328 |
+
hidden_states, hidden_states_scaling_factor = self.dense(hidden_states, hidden_states_scaling_factor)
|
| 329 |
+
hidden_states = self.dropout(hidden_states)
|
| 330 |
+
hidden_states, hidden_states_scaling_factor = self.ln_input_act(
|
| 331 |
+
hidden_states,
|
| 332 |
+
hidden_states_scaling_factor,
|
| 333 |
+
identity=input_tensor,
|
| 334 |
+
identity_scaling_factor=input_tensor_scaling_factor,
|
| 335 |
+
)
|
| 336 |
+
hidden_states, hidden_states_scaling_factor = self.LayerNorm(hidden_states, hidden_states_scaling_factor)
|
| 337 |
+
|
| 338 |
+
hidden_states, hidden_states_scaling_factor = self.output_activation(
|
| 339 |
+
hidden_states, hidden_states_scaling_factor
|
| 340 |
+
)
|
| 341 |
+
return hidden_states, hidden_states_scaling_factor
|
| 342 |
+
|
| 343 |
+
|
| 344 |
+
class IBertAttention(nn.Module):
|
| 345 |
+
def __init__(self, config):
|
| 346 |
+
super().__init__()
|
| 347 |
+
self.quant_mode = config.quant_mode
|
| 348 |
+
self.self = IBertSelfAttention(config)
|
| 349 |
+
self.output = IBertSelfOutput(config)
|
| 350 |
+
|
| 351 |
+
def forward(
|
| 352 |
+
self,
|
| 353 |
+
hidden_states,
|
| 354 |
+
hidden_states_scaling_factor,
|
| 355 |
+
attention_mask=None,
|
| 356 |
+
output_attentions=False,
|
| 357 |
+
):
|
| 358 |
+
self_outputs, self_outputs_scaling_factor = self.self(
|
| 359 |
+
hidden_states,
|
| 360 |
+
hidden_states_scaling_factor,
|
| 361 |
+
attention_mask,
|
| 362 |
+
output_attentions,
|
| 363 |
+
)
|
| 364 |
+
attention_output, attention_output_scaling_factor = self.output(
|
| 365 |
+
self_outputs[0], self_outputs_scaling_factor[0], hidden_states, hidden_states_scaling_factor
|
| 366 |
+
)
|
| 367 |
+
outputs = (attention_output,) + self_outputs[1:] # add attentions if we output them
|
| 368 |
+
outputs_scaling_factor = (attention_output_scaling_factor,) + self_outputs_scaling_factor[1:]
|
| 369 |
+
return outputs, outputs_scaling_factor
|
| 370 |
+
|
| 371 |
+
|
| 372 |
+
class IBertIntermediate(nn.Module):
|
| 373 |
+
def __init__(self, config):
|
| 374 |
+
super().__init__()
|
| 375 |
+
self.quant_mode = config.quant_mode
|
| 376 |
+
self.act_bit = 8
|
| 377 |
+
self.weight_bit = 8
|
| 378 |
+
self.bias_bit = 32
|
| 379 |
+
self.dense = QuantLinear(
|
| 380 |
+
config.hidden_size,
|
| 381 |
+
config.intermediate_size,
|
| 382 |
+
bias=True,
|
| 383 |
+
weight_bit=self.weight_bit,
|
| 384 |
+
bias_bit=self.bias_bit,
|
| 385 |
+
quant_mode=self.quant_mode,
|
| 386 |
+
per_channel=True,
|
| 387 |
+
)
|
| 388 |
+
if config.hidden_act != "gelu":
|
| 389 |
+
raise ValueError("I-BERT only supports 'gelu' for `config.hidden_act`")
|
| 390 |
+
self.intermediate_act_fn = IntGELU(quant_mode=self.quant_mode, force_dequant=config.force_dequant)
|
| 391 |
+
self.output_activation = QuantAct(self.act_bit, quant_mode=self.quant_mode)
|
| 392 |
+
|
| 393 |
+
def forward(self, hidden_states, hidden_states_scaling_factor):
|
| 394 |
+
hidden_states, hidden_states_scaling_factor = self.dense(hidden_states, hidden_states_scaling_factor)
|
| 395 |
+
hidden_states, hidden_states_scaling_factor = self.intermediate_act_fn(
|
| 396 |
+
hidden_states, hidden_states_scaling_factor
|
| 397 |
+
)
|
| 398 |
+
|
| 399 |
+
# Requantization: 32bit -> 8-bit
|
| 400 |
+
hidden_states, hidden_states_scaling_factor = self.output_activation(
|
| 401 |
+
hidden_states, hidden_states_scaling_factor
|
| 402 |
+
)
|
| 403 |
+
return hidden_states, hidden_states_scaling_factor
|
| 404 |
+
|
| 405 |
+
|
| 406 |
+
class IBertOutput(nn.Module):
|
| 407 |
+
def __init__(self, config):
|
| 408 |
+
super().__init__()
|
| 409 |
+
self.quant_mode = config.quant_mode
|
| 410 |
+
self.act_bit = 8
|
| 411 |
+
self.weight_bit = 8
|
| 412 |
+
self.bias_bit = 32
|
| 413 |
+
self.ln_input_bit = 22
|
| 414 |
+
self.ln_output_bit = 32
|
| 415 |
+
|
| 416 |
+
self.dense = QuantLinear(
|
| 417 |
+
config.intermediate_size,
|
| 418 |
+
config.hidden_size,
|
| 419 |
+
bias=True,
|
| 420 |
+
weight_bit=self.weight_bit,
|
| 421 |
+
bias_bit=self.bias_bit,
|
| 422 |
+
quant_mode=self.quant_mode,
|
| 423 |
+
per_channel=True,
|
| 424 |
+
)
|
| 425 |
+
self.ln_input_act = QuantAct(self.ln_input_bit, quant_mode=self.quant_mode)
|
| 426 |
+
self.LayerNorm = IntLayerNorm(
|
| 427 |
+
config.hidden_size,
|
| 428 |
+
eps=config.layer_norm_eps,
|
| 429 |
+
output_bit=self.ln_output_bit,
|
| 430 |
+
quant_mode=self.quant_mode,
|
| 431 |
+
force_dequant=config.force_dequant,
|
| 432 |
+
)
|
| 433 |
+
self.output_activation = QuantAct(self.act_bit, quant_mode=self.quant_mode)
|
| 434 |
+
self.dropout = nn.Dropout(config.hidden_dropout_prob)
|
| 435 |
+
|
| 436 |
+
def forward(self, hidden_states, hidden_states_scaling_factor, input_tensor, input_tensor_scaling_factor):
|
| 437 |
+
hidden_states, hidden_states_scaling_factor = self.dense(hidden_states, hidden_states_scaling_factor)
|
| 438 |
+
hidden_states = self.dropout(hidden_states)
|
| 439 |
+
hidden_states, hidden_states_scaling_factor = self.ln_input_act(
|
| 440 |
+
hidden_states,
|
| 441 |
+
hidden_states_scaling_factor,
|
| 442 |
+
identity=input_tensor,
|
| 443 |
+
identity_scaling_factor=input_tensor_scaling_factor,
|
| 444 |
+
)
|
| 445 |
+
hidden_states, hidden_states_scaling_factor = self.LayerNorm(hidden_states, hidden_states_scaling_factor)
|
| 446 |
+
|
| 447 |
+
hidden_states, hidden_states_scaling_factor = self.output_activation(
|
| 448 |
+
hidden_states, hidden_states_scaling_factor
|
| 449 |
+
)
|
| 450 |
+
return hidden_states, hidden_states_scaling_factor
|
| 451 |
+
|
| 452 |
+
|
| 453 |
+
class IBertLayer(nn.Module):
|
| 454 |
+
def __init__(self, config):
|
| 455 |
+
super().__init__()
|
| 456 |
+
self.quant_mode = config.quant_mode
|
| 457 |
+
self.act_bit = 8
|
| 458 |
+
|
| 459 |
+
self.seq_len_dim = 1
|
| 460 |
+
self.attention = IBertAttention(config)
|
| 461 |
+
self.intermediate = IBertIntermediate(config)
|
| 462 |
+
self.output = IBertOutput(config)
|
| 463 |
+
|
| 464 |
+
self.pre_intermediate_act = QuantAct(self.act_bit, quant_mode=self.quant_mode)
|
| 465 |
+
self.pre_output_act = QuantAct(self.act_bit, quant_mode=self.quant_mode)
|
| 466 |
+
|
| 467 |
+
def forward(
|
| 468 |
+
self,
|
| 469 |
+
hidden_states,
|
| 470 |
+
hidden_states_scaling_factor,
|
| 471 |
+
attention_mask=None,
|
| 472 |
+
output_attentions=False,
|
| 473 |
+
):
|
| 474 |
+
self_attention_outputs, self_attention_outputs_scaling_factor = self.attention(
|
| 475 |
+
hidden_states,
|
| 476 |
+
hidden_states_scaling_factor,
|
| 477 |
+
attention_mask,
|
| 478 |
+
output_attentions=output_attentions,
|
| 479 |
+
)
|
| 480 |
+
attention_output = self_attention_outputs[0]
|
| 481 |
+
attention_output_scaling_factor = self_attention_outputs_scaling_factor[0]
|
| 482 |
+
|
| 483 |
+
outputs = self_attention_outputs[1:] # add self attentions if we output attention weights
|
| 484 |
+
|
| 485 |
+
layer_output, layer_output_scaling_factor = self.feed_forward_chunk(
|
| 486 |
+
attention_output, attention_output_scaling_factor
|
| 487 |
+
)
|
| 488 |
+
outputs = (layer_output,) + outputs
|
| 489 |
+
|
| 490 |
+
return outputs
|
| 491 |
+
|
| 492 |
+
def feed_forward_chunk(self, attention_output, attention_output_scaling_factor):
|
| 493 |
+
attention_output, attention_output_scaling_factor = self.pre_intermediate_act(
|
| 494 |
+
attention_output, attention_output_scaling_factor
|
| 495 |
+
)
|
| 496 |
+
intermediate_output, intermediate_output_scaling_factor = self.intermediate(
|
| 497 |
+
attention_output, attention_output_scaling_factor
|
| 498 |
+
)
|
| 499 |
+
|
| 500 |
+
intermediate_output, intermediate_output_scaling_factor = self.pre_output_act(
|
| 501 |
+
intermediate_output, intermediate_output_scaling_factor
|
| 502 |
+
)
|
| 503 |
+
layer_output, layer_output_scaling_factor = self.output(
|
| 504 |
+
intermediate_output, intermediate_output_scaling_factor, attention_output, attention_output_scaling_factor
|
| 505 |
+
)
|
| 506 |
+
return layer_output, layer_output_scaling_factor
|
| 507 |
+
|
| 508 |
+
|
| 509 |
+
class IBertEncoder(nn.Module):
|
| 510 |
+
def __init__(self, config):
|
| 511 |
+
super().__init__()
|
| 512 |
+
self.config = config
|
| 513 |
+
self.quant_mode = config.quant_mode
|
| 514 |
+
self.layer = nn.ModuleList([IBertLayer(config) for _ in range(config.num_hidden_layers)])
|
| 515 |
+
|
| 516 |
+
def forward(
|
| 517 |
+
self,
|
| 518 |
+
hidden_states,
|
| 519 |
+
hidden_states_scaling_factor,
|
| 520 |
+
attention_mask=None,
|
| 521 |
+
output_attentions=False,
|
| 522 |
+
output_hidden_states=False,
|
| 523 |
+
return_dict=True,
|
| 524 |
+
):
|
| 525 |
+
all_hidden_states = () if output_hidden_states else None
|
| 526 |
+
all_self_attentions = () if output_attentions else None
|
| 527 |
+
all_cross_attentions = None # `config.add_cross_attention` is not supported
|
| 528 |
+
|
| 529 |
+
for i, layer_module in enumerate(self.layer):
|
| 530 |
+
if output_hidden_states:
|
| 531 |
+
all_hidden_states = all_hidden_states + (hidden_states,)
|
| 532 |
+
|
| 533 |
+
layer_outputs = layer_module(
|
| 534 |
+
hidden_states,
|
| 535 |
+
hidden_states_scaling_factor,
|
| 536 |
+
attention_mask,
|
| 537 |
+
output_attentions,
|
| 538 |
+
)
|
| 539 |
+
|
| 540 |
+
hidden_states = layer_outputs[0]
|
| 541 |
+
if output_attentions:
|
| 542 |
+
all_self_attentions = all_self_attentions + (layer_outputs[1],)
|
| 543 |
+
|
| 544 |
+
if output_hidden_states:
|
| 545 |
+
all_hidden_states = all_hidden_states + (hidden_states,)
|
| 546 |
+
|
| 547 |
+
if not return_dict:
|
| 548 |
+
return tuple(
|
| 549 |
+
v
|
| 550 |
+
for v in [
|
| 551 |
+
hidden_states,
|
| 552 |
+
all_hidden_states,
|
| 553 |
+
all_self_attentions,
|
| 554 |
+
all_cross_attentions,
|
| 555 |
+
]
|
| 556 |
+
if v is not None
|
| 557 |
+
)
|
| 558 |
+
return BaseModelOutputWithPastAndCrossAttentions(
|
| 559 |
+
last_hidden_state=hidden_states,
|
| 560 |
+
hidden_states=all_hidden_states,
|
| 561 |
+
attentions=all_self_attentions,
|
| 562 |
+
cross_attentions=all_cross_attentions,
|
| 563 |
+
)
|
| 564 |
+
|
| 565 |
+
|
| 566 |
+
class IBertPooler(nn.Module):
|
| 567 |
+
def __init__(self, config):
|
| 568 |
+
super().__init__()
|
| 569 |
+
self.quant_mode = config.quant_mode
|
| 570 |
+
self.dense = nn.Linear(config.hidden_size, config.hidden_size)
|
| 571 |
+
self.activation = nn.Tanh()
|
| 572 |
+
|
| 573 |
+
def forward(self, hidden_states):
|
| 574 |
+
# We "pool" the model by simply taking the hidden state corresponding
|
| 575 |
+
# to the first token.
|
| 576 |
+
first_token_tensor = hidden_states[:, 0]
|
| 577 |
+
pooled_output = self.dense(first_token_tensor)
|
| 578 |
+
pooled_output = self.activation(pooled_output)
|
| 579 |
+
return pooled_output
|
| 580 |
+
|
| 581 |
+
|
| 582 |
+
@auto_docstring
|
| 583 |
+
class IBertPreTrainedModel(PreTrainedModel):
|
| 584 |
+
config: IBertConfig
|
| 585 |
+
base_model_prefix = "ibert"
|
| 586 |
+
|
| 587 |
+
@torch.no_grad()
|
| 588 |
+
def _init_weights(self, module):
|
| 589 |
+
"""Initialize the weights"""
|
| 590 |
+
if isinstance(module, (QuantLinear, nn.Linear)):
|
| 591 |
+
init.normal_(module.weight, mean=0.0, std=self.config.initializer_range)
|
| 592 |
+
if module.bias is not None:
|
| 593 |
+
init.zeros_(module.bias)
|
| 594 |
+
if getattr(module, "weight_integer", None) is not None:
|
| 595 |
+
init.zeros_(module.weight_integer)
|
| 596 |
+
init.zeros_(module.fc_scaling_factor)
|
| 597 |
+
if getattr(module, "bias_integer", None) is not None:
|
| 598 |
+
init.zeros_(module.bias_integer)
|
| 599 |
+
elif isinstance(module, (QuantEmbedding, nn.Embedding)):
|
| 600 |
+
init.normal_(module.weight, mean=0.0, std=self.config.initializer_range)
|
| 601 |
+
# Here we need the check explicitly, as we slice the weight in the `zeros_` call, so it looses the flag
|
| 602 |
+
if module.padding_idx is not None and not getattr(module.weight, "_is_hf_initialized", False):
|
| 603 |
+
init.zeros_(module.weight[module.padding_idx])
|
| 604 |
+
if getattr(module, "weight_scaling_factor", None) is not None:
|
| 605 |
+
init.zeros_(module.weight_scaling_factor)
|
| 606 |
+
init.zeros_(module.weight_integer)
|
| 607 |
+
elif isinstance(module, (IntLayerNorm, nn.LayerNorm)):
|
| 608 |
+
init.zeros_(module.bias)
|
| 609 |
+
init.ones_(module.weight)
|
| 610 |
+
if getattr(module, "shift", None) is not None:
|
| 611 |
+
init.zeros_(module.shift)
|
| 612 |
+
elif isinstance(module, IBertLMHead):
|
| 613 |
+
init.zeros_(module.bias)
|
| 614 |
+
elif isinstance(module, IBertEmbeddings):
|
| 615 |
+
init.copy_(module.position_ids, torch.arange(module.position_ids.shape[-1]).expand((1, -1)))
|
| 616 |
+
elif isinstance(module, QuantAct):
|
| 617 |
+
init.constant_(module.x_min, -1e-5)
|
| 618 |
+
init.constant_(module.x_max, 1e-5)
|
| 619 |
+
init.zeros_(module.act_scaling_factor)
|
| 620 |
+
|
| 621 |
+
def resize_token_embeddings(self, new_num_tokens=None):
|
| 622 |
+
raise NotImplementedError("`resize_token_embeddings` is not supported for I-BERT.")
|
| 623 |
+
|
| 624 |
+
|
| 625 |
+
@auto_docstring
|
| 626 |
+
class IBertModel(IBertPreTrainedModel):
|
| 627 |
+
"""
|
| 628 |
+
|
| 629 |
+
The model can behave as an encoder (with only self-attention) as well as a decoder, in which case a layer of
|
| 630 |
+
cross-attention is added between the self-attention layers, following the architecture described in [Attention is
|
| 631 |
+
all you need](https://huggingface.co/papers/1706.03762) by Ashish Vaswani, Noam Shazeer, Niki Parmar, Jakob Uszkoreit,
|
| 632 |
+
Llion Jones, Aidan N. Gomez, Lukasz Kaiser and Illia Polosukhin.
|
| 633 |
+
|
| 634 |
+
"""
|
| 635 |
+
|
| 636 |
+
def __init__(self, config, add_pooling_layer=True):
|
| 637 |
+
r"""
|
| 638 |
+
add_pooling_layer (bool, *optional*, defaults to `True`):
|
| 639 |
+
Whether to add a pooling layer
|
| 640 |
+
"""
|
| 641 |
+
super().__init__(config)
|
| 642 |
+
self.config = config
|
| 643 |
+
self.quant_mode = config.quant_mode
|
| 644 |
+
|
| 645 |
+
self.embeddings = IBertEmbeddings(config)
|
| 646 |
+
self.encoder = IBertEncoder(config)
|
| 647 |
+
|
| 648 |
+
self.pooler = IBertPooler(config) if add_pooling_layer else None
|
| 649 |
+
|
| 650 |
+
# Initialize weights and apply final processing
|
| 651 |
+
self.post_init()
|
| 652 |
+
|
| 653 |
+
def get_input_embeddings(self):
|
| 654 |
+
return self.embeddings.word_embeddings
|
| 655 |
+
|
| 656 |
+
def set_input_embeddings(self, value):
|
| 657 |
+
self.embeddings.word_embeddings = value
|
| 658 |
+
|
| 659 |
+
@auto_docstring
|
| 660 |
+
def forward(
|
| 661 |
+
self,
|
| 662 |
+
input_ids: torch.LongTensor | None = None,
|
| 663 |
+
attention_mask: torch.FloatTensor | None = None,
|
| 664 |
+
token_type_ids: torch.LongTensor | None = None,
|
| 665 |
+
position_ids: torch.LongTensor | None = None,
|
| 666 |
+
inputs_embeds: torch.FloatTensor | None = None,
|
| 667 |
+
output_attentions: bool | None = None,
|
| 668 |
+
output_hidden_states: bool | None = None,
|
| 669 |
+
return_dict: bool | None = None,
|
| 670 |
+
**kwargs,
|
| 671 |
+
) -> BaseModelOutputWithPoolingAndCrossAttentions | tuple[torch.FloatTensor]:
|
| 672 |
+
output_attentions = output_attentions if output_attentions is not None else self.config.output_attentions
|
| 673 |
+
output_hidden_states = (
|
| 674 |
+
output_hidden_states if output_hidden_states is not None else self.config.output_hidden_states
|
| 675 |
+
)
|
| 676 |
+
return_dict = return_dict if return_dict is not None else self.config.return_dict
|
| 677 |
+
|
| 678 |
+
if input_ids is not None and inputs_embeds is not None:
|
| 679 |
+
raise ValueError("You cannot specify both input_ids and inputs_embeds at the same time")
|
| 680 |
+
elif input_ids is not None:
|
| 681 |
+
self.warn_if_padding_and_no_attention_mask(input_ids, attention_mask)
|
| 682 |
+
input_shape = input_ids.size()
|
| 683 |
+
elif inputs_embeds is not None:
|
| 684 |
+
input_shape = inputs_embeds.size()[:-1]
|
| 685 |
+
else:
|
| 686 |
+
raise ValueError("You have to specify either input_ids or inputs_embeds")
|
| 687 |
+
|
| 688 |
+
batch_size, seq_length = input_shape
|
| 689 |
+
device = input_ids.device if input_ids is not None else inputs_embeds.device
|
| 690 |
+
|
| 691 |
+
if attention_mask is None:
|
| 692 |
+
attention_mask = torch.ones(((batch_size, seq_length)), device=device)
|
| 693 |
+
if token_type_ids is None:
|
| 694 |
+
token_type_ids = torch.zeros(input_shape, dtype=torch.long, device=device)
|
| 695 |
+
|
| 696 |
+
# We can provide a self-attention mask of dimensions [batch_size, from_seq_length, to_seq_length]
|
| 697 |
+
# ourselves in which case we just need to make it broadcastable to all heads.
|
| 698 |
+
extended_attention_mask: torch.Tensor = self.get_extended_attention_mask(attention_mask, input_shape)
|
| 699 |
+
|
| 700 |
+
embedding_output, embedding_output_scaling_factor = self.embeddings(
|
| 701 |
+
input_ids=input_ids,
|
| 702 |
+
position_ids=position_ids,
|
| 703 |
+
token_type_ids=token_type_ids,
|
| 704 |
+
inputs_embeds=inputs_embeds,
|
| 705 |
+
)
|
| 706 |
+
encoder_outputs = self.encoder(
|
| 707 |
+
embedding_output,
|
| 708 |
+
embedding_output_scaling_factor,
|
| 709 |
+
attention_mask=extended_attention_mask,
|
| 710 |
+
output_attentions=output_attentions,
|
| 711 |
+
output_hidden_states=output_hidden_states,
|
| 712 |
+
return_dict=return_dict,
|
| 713 |
+
)
|
| 714 |
+
sequence_output = encoder_outputs[0]
|
| 715 |
+
pooled_output = self.pooler(sequence_output) if self.pooler is not None else None
|
| 716 |
+
|
| 717 |
+
if not return_dict:
|
| 718 |
+
return (sequence_output, pooled_output) + encoder_outputs[1:]
|
| 719 |
+
|
| 720 |
+
return BaseModelOutputWithPoolingAndCrossAttentions(
|
| 721 |
+
last_hidden_state=sequence_output,
|
| 722 |
+
pooler_output=pooled_output,
|
| 723 |
+
hidden_states=encoder_outputs.hidden_states,
|
| 724 |
+
attentions=encoder_outputs.attentions,
|
| 725 |
+
cross_attentions=encoder_outputs.cross_attentions,
|
| 726 |
+
)
|
| 727 |
+
|
| 728 |
+
|
| 729 |
+
@auto_docstring
|
| 730 |
+
class IBertForMaskedLM(IBertPreTrainedModel):
|
| 731 |
+
_tied_weights_keys = {
|
| 732 |
+
"lm_head.decoder.weight": "ibert.embeddings.word_embeddings.weight$",
|
| 733 |
+
"lm_head.decoder.bias": "lm_head.bias",
|
| 734 |
+
}
|
| 735 |
+
|
| 736 |
+
def __init__(self, config):
|
| 737 |
+
super().__init__(config)
|
| 738 |
+
|
| 739 |
+
self.ibert = IBertModel(config, add_pooling_layer=False)
|
| 740 |
+
self.lm_head = IBertLMHead(config)
|
| 741 |
+
|
| 742 |
+
# Initialize weights and apply final processing
|
| 743 |
+
self.post_init()
|
| 744 |
+
|
| 745 |
+
def get_output_embeddings(self):
|
| 746 |
+
return self.lm_head.decoder
|
| 747 |
+
|
| 748 |
+
def set_output_embeddings(self, new_embeddings):
|
| 749 |
+
self.lm_head.decoder = new_embeddings
|
| 750 |
+
self.lm_head.bias = new_embeddings.bias
|
| 751 |
+
|
| 752 |
+
@auto_docstring
|
| 753 |
+
def forward(
|
| 754 |
+
self,
|
| 755 |
+
input_ids: torch.LongTensor | None = None,
|
| 756 |
+
attention_mask: torch.FloatTensor | None = None,
|
| 757 |
+
token_type_ids: torch.LongTensor | None = None,
|
| 758 |
+
position_ids: torch.LongTensor | None = None,
|
| 759 |
+
inputs_embeds: torch.FloatTensor | None = None,
|
| 760 |
+
labels: torch.LongTensor | None = None,
|
| 761 |
+
output_attentions: bool | None = None,
|
| 762 |
+
output_hidden_states: bool | None = None,
|
| 763 |
+
return_dict: bool | None = None,
|
| 764 |
+
**kwargs,
|
| 765 |
+
) -> MaskedLMOutput | tuple[torch.FloatTensor]:
|
| 766 |
+
r"""
|
| 767 |
+
labels (`torch.LongTensor` of shape `(batch_size, sequence_length)`, *optional*):
|
| 768 |
+
Labels for computing the masked language modeling loss. Indices should be in `[-100, 0, ...,
|
| 769 |
+
config.vocab_size]` (see `input_ids` docstring) Tokens with indices set to `-100` are ignored (masked), the
|
| 770 |
+
loss is only computed for the tokens with labels in `[0, ..., config.vocab_size]`
|
| 771 |
+
"""
|
| 772 |
+
return_dict = return_dict if return_dict is not None else self.config.return_dict
|
| 773 |
+
|
| 774 |
+
outputs = self.ibert(
|
| 775 |
+
input_ids,
|
| 776 |
+
attention_mask=attention_mask,
|
| 777 |
+
token_type_ids=token_type_ids,
|
| 778 |
+
position_ids=position_ids,
|
| 779 |
+
inputs_embeds=inputs_embeds,
|
| 780 |
+
output_attentions=output_attentions,
|
| 781 |
+
output_hidden_states=output_hidden_states,
|
| 782 |
+
return_dict=return_dict,
|
| 783 |
+
)
|
| 784 |
+
sequence_output = outputs[0]
|
| 785 |
+
prediction_scores = self.lm_head(sequence_output)
|
| 786 |
+
|
| 787 |
+
masked_lm_loss = None
|
| 788 |
+
if labels is not None:
|
| 789 |
+
loss_fct = CrossEntropyLoss()
|
| 790 |
+
masked_lm_loss = loss_fct(prediction_scores.view(-1, self.config.vocab_size), labels.view(-1))
|
| 791 |
+
|
| 792 |
+
if not return_dict:
|
| 793 |
+
output = (prediction_scores,) + outputs[2:]
|
| 794 |
+
return ((masked_lm_loss,) + output) if masked_lm_loss is not None else output
|
| 795 |
+
|
| 796 |
+
return MaskedLMOutput(
|
| 797 |
+
loss=masked_lm_loss,
|
| 798 |
+
logits=prediction_scores,
|
| 799 |
+
hidden_states=outputs.hidden_states,
|
| 800 |
+
attentions=outputs.attentions,
|
| 801 |
+
)
|
| 802 |
+
|
| 803 |
+
|
| 804 |
+
class IBertLMHead(nn.Module):
|
| 805 |
+
"""I-BERT Head for masked language modeling."""
|
| 806 |
+
|
| 807 |
+
def __init__(self, config):
|
| 808 |
+
super().__init__()
|
| 809 |
+
self.dense = nn.Linear(config.hidden_size, config.hidden_size)
|
| 810 |
+
self.layer_norm = nn.LayerNorm(config.hidden_size, eps=config.layer_norm_eps)
|
| 811 |
+
|
| 812 |
+
self.decoder = nn.Linear(config.hidden_size, config.vocab_size)
|
| 813 |
+
self.bias = nn.Parameter(torch.zeros(config.vocab_size))
|
| 814 |
+
|
| 815 |
+
def forward(self, features, **kwargs):
|
| 816 |
+
x = self.dense(features)
|
| 817 |
+
x = gelu(x)
|
| 818 |
+
x = self.layer_norm(x)
|
| 819 |
+
|
| 820 |
+
# project back to size of vocabulary with bias
|
| 821 |
+
x = self.decoder(x)
|
| 822 |
+
|
| 823 |
+
return x
|
| 824 |
+
|
| 825 |
+
|
| 826 |
+
@auto_docstring(
|
| 827 |
+
custom_intro="""
|
| 828 |
+
I-BERT Model transformer with a sequence classification/regression head on top (a linear layer on top of the pooled
|
| 829 |
+
output) e.g. for GLUE tasks.
|
| 830 |
+
"""
|
| 831 |
+
)
|
| 832 |
+
class IBertForSequenceClassification(IBertPreTrainedModel):
|
| 833 |
+
def __init__(self, config):
|
| 834 |
+
super().__init__(config)
|
| 835 |
+
self.num_labels = config.num_labels
|
| 836 |
+
|
| 837 |
+
self.ibert = IBertModel(config, add_pooling_layer=False)
|
| 838 |
+
self.classifier = IBertClassificationHead(config)
|
| 839 |
+
|
| 840 |
+
# Initialize weights and apply final processing
|
| 841 |
+
self.post_init()
|
| 842 |
+
|
| 843 |
+
@auto_docstring
|
| 844 |
+
def forward(
|
| 845 |
+
self,
|
| 846 |
+
input_ids: torch.LongTensor | None = None,
|
| 847 |
+
attention_mask: torch.FloatTensor | None = None,
|
| 848 |
+
token_type_ids: torch.LongTensor | None = None,
|
| 849 |
+
position_ids: torch.LongTensor | None = None,
|
| 850 |
+
inputs_embeds: torch.FloatTensor | None = None,
|
| 851 |
+
labels: torch.LongTensor | None = None,
|
| 852 |
+
output_attentions: bool | None = None,
|
| 853 |
+
output_hidden_states: bool | None = None,
|
| 854 |
+
return_dict: bool | None = None,
|
| 855 |
+
**kwargs,
|
| 856 |
+
) -> SequenceClassifierOutput | tuple[torch.FloatTensor]:
|
| 857 |
+
r"""
|
| 858 |
+
labels (`torch.LongTensor` of shape `(batch_size,)`, *optional*):
|
| 859 |
+
Labels for computing the sequence classification/regression loss. Indices should be in `[0, ...,
|
| 860 |
+
config.num_labels - 1]`. If `config.num_labels == 1` a regression loss is computed (Mean-Square loss), If
|
| 861 |
+
`config.num_labels > 1` a classification loss is computed (Cross-Entropy).
|
| 862 |
+
"""
|
| 863 |
+
return_dict = return_dict if return_dict is not None else self.config.return_dict
|
| 864 |
+
|
| 865 |
+
outputs = self.ibert(
|
| 866 |
+
input_ids,
|
| 867 |
+
attention_mask=attention_mask,
|
| 868 |
+
token_type_ids=token_type_ids,
|
| 869 |
+
position_ids=position_ids,
|
| 870 |
+
inputs_embeds=inputs_embeds,
|
| 871 |
+
output_attentions=output_attentions,
|
| 872 |
+
output_hidden_states=output_hidden_states,
|
| 873 |
+
return_dict=return_dict,
|
| 874 |
+
)
|
| 875 |
+
sequence_output = outputs[0]
|
| 876 |
+
logits = self.classifier(sequence_output)
|
| 877 |
+
|
| 878 |
+
loss = None
|
| 879 |
+
if labels is not None:
|
| 880 |
+
if self.config.problem_type is None:
|
| 881 |
+
if self.num_labels == 1:
|
| 882 |
+
self.config.problem_type = "regression"
|
| 883 |
+
elif self.num_labels > 1 and (labels.dtype == torch.long or labels.dtype == torch.int):
|
| 884 |
+
self.config.problem_type = "single_label_classification"
|
| 885 |
+
else:
|
| 886 |
+
self.config.problem_type = "multi_label_classification"
|
| 887 |
+
|
| 888 |
+
if self.config.problem_type == "regression":
|
| 889 |
+
loss_fct = MSELoss()
|
| 890 |
+
if self.num_labels == 1:
|
| 891 |
+
loss = loss_fct(logits.squeeze(), labels.squeeze())
|
| 892 |
+
else:
|
| 893 |
+
loss = loss_fct(logits, labels)
|
| 894 |
+
elif self.config.problem_type == "single_label_classification":
|
| 895 |
+
loss_fct = CrossEntropyLoss()
|
| 896 |
+
loss = loss_fct(logits.view(-1, self.num_labels), labels.view(-1))
|
| 897 |
+
elif self.config.problem_type == "multi_label_classification":
|
| 898 |
+
loss_fct = BCEWithLogitsLoss()
|
| 899 |
+
loss = loss_fct(logits, labels)
|
| 900 |
+
if not return_dict:
|
| 901 |
+
output = (logits,) + outputs[2:]
|
| 902 |
+
return ((loss,) + output) if loss is not None else output
|
| 903 |
+
|
| 904 |
+
return SequenceClassifierOutput(
|
| 905 |
+
loss=loss,
|
| 906 |
+
logits=logits,
|
| 907 |
+
hidden_states=outputs.hidden_states,
|
| 908 |
+
attentions=outputs.attentions,
|
| 909 |
+
)
|
| 910 |
+
|
| 911 |
+
|
| 912 |
+
@auto_docstring
|
| 913 |
+
class IBertForMultipleChoice(IBertPreTrainedModel):
|
| 914 |
+
def __init__(self, config):
|
| 915 |
+
super().__init__(config)
|
| 916 |
+
|
| 917 |
+
self.ibert = IBertModel(config)
|
| 918 |
+
self.dropout = nn.Dropout(config.hidden_dropout_prob)
|
| 919 |
+
self.classifier = nn.Linear(config.hidden_size, 1)
|
| 920 |
+
|
| 921 |
+
# Initialize weights and apply final processing
|
| 922 |
+
self.post_init()
|
| 923 |
+
|
| 924 |
+
@auto_docstring
|
| 925 |
+
def forward(
|
| 926 |
+
self,
|
| 927 |
+
input_ids: torch.LongTensor | None = None,
|
| 928 |
+
token_type_ids: torch.LongTensor | None = None,
|
| 929 |
+
attention_mask: torch.FloatTensor | None = None,
|
| 930 |
+
labels: torch.LongTensor | None = None,
|
| 931 |
+
position_ids: torch.LongTensor | None = None,
|
| 932 |
+
inputs_embeds: torch.FloatTensor | None = None,
|
| 933 |
+
output_attentions: bool | None = None,
|
| 934 |
+
output_hidden_states: bool | None = None,
|
| 935 |
+
return_dict: bool | None = None,
|
| 936 |
+
**kwargs,
|
| 937 |
+
) -> MultipleChoiceModelOutput | tuple[torch.FloatTensor]:
|
| 938 |
+
r"""
|
| 939 |
+
input_ids (`torch.LongTensor` of shape `(batch_size, num_choices, sequence_length)`):
|
| 940 |
+
Indices of input sequence tokens in the vocabulary.
|
| 941 |
+
|
| 942 |
+
Indices can be obtained using [`AutoTokenizer`]. See [`PreTrainedTokenizer.encode`] and
|
| 943 |
+
[`PreTrainedTokenizer.__call__`] for details.
|
| 944 |
+
|
| 945 |
+
[What are input IDs?](../glossary#input-ids)
|
| 946 |
+
token_type_ids (`torch.LongTensor` of shape `(batch_size, num_choices, sequence_length)`, *optional*):
|
| 947 |
+
Segment token indices to indicate first and second portions of the inputs. Indices are selected in `[0,
|
| 948 |
+
1]`:
|
| 949 |
+
|
| 950 |
+
- 0 corresponds to a *sentence A* token,
|
| 951 |
+
- 1 corresponds to a *sentence B* token.
|
| 952 |
+
|
| 953 |
+
[What are token type IDs?](../glossary#token-type-ids)
|
| 954 |
+
labels (`torch.LongTensor` of shape `(batch_size,)`, *optional*):
|
| 955 |
+
Labels for computing the multiple choice classification loss. Indices should be in `[0, ...,
|
| 956 |
+
num_choices-1]` where `num_choices` is the size of the second dimension of the input tensors. (See
|
| 957 |
+
`input_ids` above)
|
| 958 |
+
position_ids (`torch.LongTensor` of shape `(batch_size, num_choices, sequence_length)`, *optional*):
|
| 959 |
+
Indices of positions of each input sequence tokens in the position embeddings. Selected in the range `[0,
|
| 960 |
+
config.max_position_embeddings - 1]`.
|
| 961 |
+
|
| 962 |
+
[What are position IDs?](../glossary#position-ids)
|
| 963 |
+
inputs_embeds (`torch.FloatTensor` of shape `(batch_size, num_choices, sequence_length, hidden_size)`, *optional*):
|
| 964 |
+
Optionally, instead of passing `input_ids` you can choose to directly pass an embedded representation. This
|
| 965 |
+
is useful if you want more control over how to convert `input_ids` indices into associated vectors than the
|
| 966 |
+
model's internal embedding lookup matrix.
|
| 967 |
+
"""
|
| 968 |
+
return_dict = return_dict if return_dict is not None else self.config.return_dict
|
| 969 |
+
num_choices = input_ids.shape[1] if input_ids is not None else inputs_embeds.shape[1]
|
| 970 |
+
|
| 971 |
+
flat_input_ids = input_ids.view(-1, input_ids.size(-1)) if input_ids is not None else None
|
| 972 |
+
flat_position_ids = position_ids.view(-1, position_ids.size(-1)) if position_ids is not None else None
|
| 973 |
+
flat_token_type_ids = token_type_ids.view(-1, token_type_ids.size(-1)) if token_type_ids is not None else None
|
| 974 |
+
flat_attention_mask = attention_mask.view(-1, attention_mask.size(-1)) if attention_mask is not None else None
|
| 975 |
+
flat_inputs_embeds = (
|
| 976 |
+
inputs_embeds.view(-1, inputs_embeds.size(-2), inputs_embeds.size(-1))
|
| 977 |
+
if inputs_embeds is not None
|
| 978 |
+
else None
|
| 979 |
+
)
|
| 980 |
+
|
| 981 |
+
outputs = self.ibert(
|
| 982 |
+
flat_input_ids,
|
| 983 |
+
position_ids=flat_position_ids,
|
| 984 |
+
token_type_ids=flat_token_type_ids,
|
| 985 |
+
attention_mask=flat_attention_mask,
|
| 986 |
+
inputs_embeds=flat_inputs_embeds,
|
| 987 |
+
output_attentions=output_attentions,
|
| 988 |
+
output_hidden_states=output_hidden_states,
|
| 989 |
+
return_dict=return_dict,
|
| 990 |
+
)
|
| 991 |
+
pooled_output = outputs[1]
|
| 992 |
+
|
| 993 |
+
pooled_output = self.dropout(pooled_output)
|
| 994 |
+
logits = self.classifier(pooled_output)
|
| 995 |
+
reshaped_logits = logits.view(-1, num_choices)
|
| 996 |
+
|
| 997 |
+
loss = None
|
| 998 |
+
if labels is not None:
|
| 999 |
+
loss_fct = CrossEntropyLoss()
|
| 1000 |
+
loss = loss_fct(reshaped_logits, labels)
|
| 1001 |
+
|
| 1002 |
+
if not return_dict:
|
| 1003 |
+
output = (reshaped_logits,) + outputs[2:]
|
| 1004 |
+
return ((loss,) + output) if loss is not None else output
|
| 1005 |
+
|
| 1006 |
+
return MultipleChoiceModelOutput(
|
| 1007 |
+
loss=loss,
|
| 1008 |
+
logits=reshaped_logits,
|
| 1009 |
+
hidden_states=outputs.hidden_states,
|
| 1010 |
+
attentions=outputs.attentions,
|
| 1011 |
+
)
|
| 1012 |
+
|
| 1013 |
+
|
| 1014 |
+
@auto_docstring
|
| 1015 |
+
class IBertForTokenClassification(IBertPreTrainedModel):
|
| 1016 |
+
def __init__(self, config):
|
| 1017 |
+
super().__init__(config)
|
| 1018 |
+
self.num_labels = config.num_labels
|
| 1019 |
+
|
| 1020 |
+
self.ibert = IBertModel(config, add_pooling_layer=False)
|
| 1021 |
+
self.dropout = nn.Dropout(config.hidden_dropout_prob)
|
| 1022 |
+
self.classifier = nn.Linear(config.hidden_size, config.num_labels)
|
| 1023 |
+
|
| 1024 |
+
# Initialize weights and apply final processing
|
| 1025 |
+
self.post_init()
|
| 1026 |
+
|
| 1027 |
+
@auto_docstring
|
| 1028 |
+
def forward(
|
| 1029 |
+
self,
|
| 1030 |
+
input_ids: torch.LongTensor | None = None,
|
| 1031 |
+
attention_mask: torch.FloatTensor | None = None,
|
| 1032 |
+
token_type_ids: torch.LongTensor | None = None,
|
| 1033 |
+
position_ids: torch.LongTensor | None = None,
|
| 1034 |
+
inputs_embeds: torch.FloatTensor | None = None,
|
| 1035 |
+
labels: torch.LongTensor | None = None,
|
| 1036 |
+
output_attentions: bool | None = None,
|
| 1037 |
+
output_hidden_states: bool | None = None,
|
| 1038 |
+
return_dict: bool | None = None,
|
| 1039 |
+
**kwargs,
|
| 1040 |
+
) -> TokenClassifierOutput | tuple[torch.FloatTensor]:
|
| 1041 |
+
r"""
|
| 1042 |
+
labels (`torch.LongTensor` of shape `(batch_size, sequence_length)`, *optional*):
|
| 1043 |
+
Labels for computing the token classification loss. Indices should be in `[0, ..., config.num_labels - 1]`.
|
| 1044 |
+
"""
|
| 1045 |
+
return_dict = return_dict if return_dict is not None else self.config.return_dict
|
| 1046 |
+
|
| 1047 |
+
outputs = self.ibert(
|
| 1048 |
+
input_ids,
|
| 1049 |
+
attention_mask=attention_mask,
|
| 1050 |
+
token_type_ids=token_type_ids,
|
| 1051 |
+
position_ids=position_ids,
|
| 1052 |
+
inputs_embeds=inputs_embeds,
|
| 1053 |
+
output_attentions=output_attentions,
|
| 1054 |
+
output_hidden_states=output_hidden_states,
|
| 1055 |
+
return_dict=return_dict,
|
| 1056 |
+
)
|
| 1057 |
+
|
| 1058 |
+
sequence_output = outputs[0]
|
| 1059 |
+
|
| 1060 |
+
sequence_output = self.dropout(sequence_output)
|
| 1061 |
+
logits = self.classifier(sequence_output)
|
| 1062 |
+
|
| 1063 |
+
loss = None
|
| 1064 |
+
if labels is not None:
|
| 1065 |
+
loss_fct = CrossEntropyLoss()
|
| 1066 |
+
loss = loss_fct(logits.view(-1, self.num_labels), labels.view(-1))
|
| 1067 |
+
|
| 1068 |
+
if not return_dict:
|
| 1069 |
+
output = (logits,) + outputs[2:]
|
| 1070 |
+
return ((loss,) + output) if loss is not None else output
|
| 1071 |
+
|
| 1072 |
+
return TokenClassifierOutput(
|
| 1073 |
+
loss=loss,
|
| 1074 |
+
logits=logits,
|
| 1075 |
+
hidden_states=outputs.hidden_states,
|
| 1076 |
+
attentions=outputs.attentions,
|
| 1077 |
+
)
|
| 1078 |
+
|
| 1079 |
+
|
| 1080 |
+
class IBertClassificationHead(nn.Module):
|
| 1081 |
+
"""Head for sentence-level classification tasks."""
|
| 1082 |
+
|
| 1083 |
+
def __init__(self, config):
|
| 1084 |
+
super().__init__()
|
| 1085 |
+
self.dense = nn.Linear(config.hidden_size, config.hidden_size)
|
| 1086 |
+
self.dropout = nn.Dropout(config.hidden_dropout_prob)
|
| 1087 |
+
self.out_proj = nn.Linear(config.hidden_size, config.num_labels)
|
| 1088 |
+
|
| 1089 |
+
def forward(self, features, **kwargs):
|
| 1090 |
+
hidden_states = features[:, 0, :] # take <s> token (equiv. to [CLS])
|
| 1091 |
+
hidden_states = self.dropout(hidden_states)
|
| 1092 |
+
hidden_states = self.dense(hidden_states)
|
| 1093 |
+
hidden_states = torch.tanh(hidden_states)
|
| 1094 |
+
hidden_states = self.dropout(hidden_states)
|
| 1095 |
+
hidden_states = self.out_proj(hidden_states)
|
| 1096 |
+
return hidden_states
|
| 1097 |
+
|
| 1098 |
+
|
| 1099 |
+
@auto_docstring
|
| 1100 |
+
class IBertForQuestionAnswering(IBertPreTrainedModel):
|
| 1101 |
+
def __init__(self, config):
|
| 1102 |
+
super().__init__(config)
|
| 1103 |
+
self.num_labels = config.num_labels
|
| 1104 |
+
|
| 1105 |
+
self.ibert = IBertModel(config, add_pooling_layer=False)
|
| 1106 |
+
self.qa_outputs = nn.Linear(config.hidden_size, config.num_labels)
|
| 1107 |
+
|
| 1108 |
+
# Initialize weights and apply final processing
|
| 1109 |
+
self.post_init()
|
| 1110 |
+
|
| 1111 |
+
@auto_docstring
|
| 1112 |
+
def forward(
|
| 1113 |
+
self,
|
| 1114 |
+
input_ids: torch.LongTensor | None = None,
|
| 1115 |
+
attention_mask: torch.FloatTensor | None = None,
|
| 1116 |
+
token_type_ids: torch.LongTensor | None = None,
|
| 1117 |
+
position_ids: torch.LongTensor | None = None,
|
| 1118 |
+
inputs_embeds: torch.FloatTensor | None = None,
|
| 1119 |
+
start_positions: torch.LongTensor | None = None,
|
| 1120 |
+
end_positions: torch.LongTensor | None = None,
|
| 1121 |
+
output_attentions: bool | None = None,
|
| 1122 |
+
output_hidden_states: bool | None = None,
|
| 1123 |
+
return_dict: bool | None = None,
|
| 1124 |
+
**kwargs,
|
| 1125 |
+
) -> QuestionAnsweringModelOutput | tuple[torch.FloatTensor]:
|
| 1126 |
+
return_dict = return_dict if return_dict is not None else self.config.return_dict
|
| 1127 |
+
|
| 1128 |
+
outputs = self.ibert(
|
| 1129 |
+
input_ids,
|
| 1130 |
+
attention_mask=attention_mask,
|
| 1131 |
+
token_type_ids=token_type_ids,
|
| 1132 |
+
position_ids=position_ids,
|
| 1133 |
+
inputs_embeds=inputs_embeds,
|
| 1134 |
+
output_attentions=output_attentions,
|
| 1135 |
+
output_hidden_states=output_hidden_states,
|
| 1136 |
+
return_dict=return_dict,
|
| 1137 |
+
)
|
| 1138 |
+
|
| 1139 |
+
sequence_output = outputs[0]
|
| 1140 |
+
|
| 1141 |
+
logits = self.qa_outputs(sequence_output)
|
| 1142 |
+
start_logits, end_logits = logits.split(1, dim=-1)
|
| 1143 |
+
start_logits = start_logits.squeeze(-1).contiguous()
|
| 1144 |
+
end_logits = end_logits.squeeze(-1).contiguous()
|
| 1145 |
+
|
| 1146 |
+
total_loss = None
|
| 1147 |
+
if start_positions is not None and end_positions is not None:
|
| 1148 |
+
# If we are on multi-GPU, split add a dimension
|
| 1149 |
+
if len(start_positions.size()) > 1:
|
| 1150 |
+
start_positions = start_positions.squeeze(-1)
|
| 1151 |
+
if len(end_positions.size()) > 1:
|
| 1152 |
+
end_positions = end_positions.squeeze(-1)
|
| 1153 |
+
# sometimes the start/end positions are outside our model inputs, we ignore these terms
|
| 1154 |
+
ignored_index = start_logits.size(1)
|
| 1155 |
+
start_positions = start_positions.clamp(0, ignored_index)
|
| 1156 |
+
end_positions = end_positions.clamp(0, ignored_index)
|
| 1157 |
+
|
| 1158 |
+
loss_fct = CrossEntropyLoss(ignore_index=ignored_index)
|
| 1159 |
+
start_loss = loss_fct(start_logits, start_positions)
|
| 1160 |
+
end_loss = loss_fct(end_logits, end_positions)
|
| 1161 |
+
total_loss = (start_loss + end_loss) / 2
|
| 1162 |
+
|
| 1163 |
+
if not return_dict:
|
| 1164 |
+
output = (start_logits, end_logits) + outputs[2:]
|
| 1165 |
+
return ((total_loss,) + output) if total_loss is not None else output
|
| 1166 |
+
|
| 1167 |
+
return QuestionAnsweringModelOutput(
|
| 1168 |
+
loss=total_loss,
|
| 1169 |
+
start_logits=start_logits,
|
| 1170 |
+
end_logits=end_logits,
|
| 1171 |
+
hidden_states=outputs.hidden_states,
|
| 1172 |
+
attentions=outputs.attentions,
|
| 1173 |
+
)
|
| 1174 |
+
|
| 1175 |
+
|
| 1176 |
+
def create_position_ids_from_input_ids(input_ids, padding_idx, past_key_values_length=0):
|
| 1177 |
+
"""
|
| 1178 |
+
Replace non-padding symbols with their position numbers. Position numbers begin at padding_idx+1. Padding symbols
|
| 1179 |
+
are ignored. This is modified from fairseq's *utils.make_positions*.
|
| 1180 |
+
|
| 1181 |
+
Args:
|
| 1182 |
+
input_ids (`torch.LongTensor`):
|
| 1183 |
+
Indices of input sequence tokens in the vocabulary.
|
| 1184 |
+
|
| 1185 |
+
Returns: torch.Tensor
|
| 1186 |
+
"""
|
| 1187 |
+
# The series of casts and type-conversions here are carefully balanced to both work with ONNX export and XLA.
|
| 1188 |
+
mask = input_ids.ne(padding_idx).int()
|
| 1189 |
+
incremental_indices = (torch.cumsum(mask, dim=1).type_as(mask) + past_key_values_length) * mask
|
| 1190 |
+
return incremental_indices.long() + padding_idx
|
| 1191 |
+
|
| 1192 |
+
|
| 1193 |
+
__all__ = [
|
| 1194 |
+
"IBertForMaskedLM",
|
| 1195 |
+
"IBertForMultipleChoice",
|
| 1196 |
+
"IBertForQuestionAnswering",
|
| 1197 |
+
"IBertForSequenceClassification",
|
| 1198 |
+
"IBertForTokenClassification",
|
| 1199 |
+
"IBertModel",
|
| 1200 |
+
"IBertPreTrainedModel",
|
| 1201 |
+
]
|
third_party/transformers/src/transformers/models/ibert/quant_modules.py
ADDED
|
@@ -0,0 +1,819 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
# Copyright 2021 The I-BERT Authors (Sehoon Kim, Amir Gholami, Zhewei Yao,
|
| 2 |
+
# Michael Mahoney, Kurt Keutzer - UC Berkeley) and The HuggingFace Inc. team.
|
| 3 |
+
# Copyright (c) 20121, NVIDIA CORPORATION. All rights reserved.
|
| 4 |
+
#
|
| 5 |
+
# Licensed under the Apache License, Version 2.0 (the "License");
|
| 6 |
+
# you may not use this file except in compliance with the License.
|
| 7 |
+
# You may obtain a copy of the License at
|
| 8 |
+
#
|
| 9 |
+
# http://www.apache.org/licenses/LICENSE-2.0
|
| 10 |
+
#
|
| 11 |
+
# Unless required by applicable law or agreed to in writing, software
|
| 12 |
+
# distributed under the License is distributed on an "AS IS" BASIS,
|
| 13 |
+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
| 14 |
+
# See the License for the specific language governing permissions and
|
| 15 |
+
# limitations under the License.
|
| 16 |
+
|
| 17 |
+
import decimal
|
| 18 |
+
|
| 19 |
+
import numpy as np
|
| 20 |
+
import torch
|
| 21 |
+
from torch import nn
|
| 22 |
+
from torch.autograd import Function
|
| 23 |
+
|
| 24 |
+
from ...utils import logging
|
| 25 |
+
|
| 26 |
+
|
| 27 |
+
logger = logging.get_logger(__name__)
|
| 28 |
+
|
| 29 |
+
|
| 30 |
+
class QuantEmbedding(nn.Module):
|
| 31 |
+
"""
|
| 32 |
+
Quantized version of `torch.nn.Embedding`. Adds quantization-specific arguments on top of `torch.nn.Embedding`.
|
| 33 |
+
|
| 34 |
+
Args:
|
| 35 |
+
weight_bit (`int`, *optional*, defaults to `8`):
|
| 36 |
+
Bitwidth for the quantized weight.
|
| 37 |
+
momentum (`float`, *optional*, defaults to `0.95`):
|
| 38 |
+
Momentum for updating the activation quantization range.
|
| 39 |
+
quant_mode (`bool`, *optional*, defaults to `False`):
|
| 40 |
+
Whether or not the layer is quantized.
|
| 41 |
+
"""
|
| 42 |
+
|
| 43 |
+
def __init__(
|
| 44 |
+
self,
|
| 45 |
+
num_embeddings,
|
| 46 |
+
embedding_dim,
|
| 47 |
+
padding_idx=None,
|
| 48 |
+
max_norm=None,
|
| 49 |
+
norm_type=2.0,
|
| 50 |
+
scale_grad_by_freq=False,
|
| 51 |
+
sparse=False,
|
| 52 |
+
_weight=None,
|
| 53 |
+
weight_bit=8,
|
| 54 |
+
momentum=0.95,
|
| 55 |
+
quant_mode=False,
|
| 56 |
+
):
|
| 57 |
+
super().__init__()
|
| 58 |
+
self.num_ = num_embeddings
|
| 59 |
+
self.dim = embedding_dim
|
| 60 |
+
self.padding_idx = padding_idx
|
| 61 |
+
self.max_norm = max_norm
|
| 62 |
+
self.norm_type = norm_type
|
| 63 |
+
self.scale_grad_by_freq = scale_grad_by_freq
|
| 64 |
+
self.sparse = sparse
|
| 65 |
+
|
| 66 |
+
self.weight = nn.Parameter(torch.zeros([num_embeddings, embedding_dim]))
|
| 67 |
+
self.register_buffer("weight_scaling_factor", torch.zeros(1))
|
| 68 |
+
self.register_buffer("weight_integer", torch.zeros_like(self.weight))
|
| 69 |
+
|
| 70 |
+
self.weight_bit = weight_bit
|
| 71 |
+
self.momentum = momentum
|
| 72 |
+
self.quant_mode = quant_mode
|
| 73 |
+
self.percentile_mode = False
|
| 74 |
+
self.weight_function = SymmetricQuantFunction.apply
|
| 75 |
+
|
| 76 |
+
def forward(self, x, positions=None, incremental_state=None):
|
| 77 |
+
if not self.quant_mode:
|
| 78 |
+
return (
|
| 79 |
+
nn.functional.embedding(
|
| 80 |
+
x,
|
| 81 |
+
self.weight,
|
| 82 |
+
self.padding_idx,
|
| 83 |
+
self.max_norm,
|
| 84 |
+
self.norm_type,
|
| 85 |
+
self.scale_grad_by_freq,
|
| 86 |
+
self.sparse,
|
| 87 |
+
),
|
| 88 |
+
None,
|
| 89 |
+
)
|
| 90 |
+
|
| 91 |
+
w = self.weight
|
| 92 |
+
w_transform = w.data.detach()
|
| 93 |
+
w_min = w_transform.min().expand(1)
|
| 94 |
+
w_max = w_transform.max().expand(1)
|
| 95 |
+
|
| 96 |
+
self.weight_scaling_factor = symmetric_linear_quantization_params(self.weight_bit, w_min, w_max, False)
|
| 97 |
+
self.weight_integer = self.weight_function(
|
| 98 |
+
self.weight, self.weight_bit, self.percentile_mode, self.weight_scaling_factor
|
| 99 |
+
)
|
| 100 |
+
|
| 101 |
+
emb_int = nn.functional.embedding(
|
| 102 |
+
x,
|
| 103 |
+
self.weight_integer,
|
| 104 |
+
self.padding_idx,
|
| 105 |
+
self.max_norm,
|
| 106 |
+
self.norm_type,
|
| 107 |
+
self.scale_grad_by_freq,
|
| 108 |
+
self.sparse,
|
| 109 |
+
)
|
| 110 |
+
return emb_int * self.weight_scaling_factor, self.weight_scaling_factor
|
| 111 |
+
|
| 112 |
+
|
| 113 |
+
class QuantAct(nn.Module):
|
| 114 |
+
"""
|
| 115 |
+
Quantizes the given activation.
|
| 116 |
+
|
| 117 |
+
Args:
|
| 118 |
+
activation_bit (`int`):
|
| 119 |
+
Bitwidth for the quantized activation.
|
| 120 |
+
act_range_momentum (`float`, *optional*, defaults to `0.95`):
|
| 121 |
+
Momentum for updating the activation quantization range.
|
| 122 |
+
per_channel (`bool`, *optional*, defaults to `False`):
|
| 123 |
+
Whether to or not use channel-wise quantization.
|
| 124 |
+
channel_len (`int`, *optional*):
|
| 125 |
+
Specify the channel length when set the *per_channel* True.
|
| 126 |
+
quant_mode (`bool`, *optional*, defaults to `False`):
|
| 127 |
+
Whether or not the layer is quantized.
|
| 128 |
+
"""
|
| 129 |
+
|
| 130 |
+
def __init__(self, activation_bit, act_range_momentum=0.95, per_channel=False, channel_len=None, quant_mode=False):
|
| 131 |
+
super().__init__()
|
| 132 |
+
|
| 133 |
+
self.activation_bit = activation_bit
|
| 134 |
+
self.act_range_momentum = act_range_momentum
|
| 135 |
+
self.quant_mode = quant_mode
|
| 136 |
+
self.per_channel = per_channel
|
| 137 |
+
self.percentile = False
|
| 138 |
+
self.act_function = SymmetricQuantFunction.apply
|
| 139 |
+
|
| 140 |
+
if not self.per_channel:
|
| 141 |
+
self.register_buffer("x_min", torch.zeros(1))
|
| 142 |
+
self.register_buffer("x_max", torch.zeros(1))
|
| 143 |
+
self.register_buffer("act_scaling_factor", torch.zeros(1))
|
| 144 |
+
self.x_min -= 1e-5
|
| 145 |
+
self.x_max += 1e-5
|
| 146 |
+
else:
|
| 147 |
+
raise NotImplementedError("per-channel mode is not currently supported for activation.")
|
| 148 |
+
|
| 149 |
+
def __repr__(self):
|
| 150 |
+
return (
|
| 151 |
+
f"{self.__class__.__name__}(activation_bit={self.activation_bit}, "
|
| 152 |
+
f"quant_mode: {self.quant_mode}, Act_min: {self.x_min.item():.2f}, "
|
| 153 |
+
f"Act_max: {self.x_max.item():.2f})"
|
| 154 |
+
)
|
| 155 |
+
|
| 156 |
+
def forward(
|
| 157 |
+
self,
|
| 158 |
+
x,
|
| 159 |
+
pre_act_scaling_factor=None,
|
| 160 |
+
identity=None,
|
| 161 |
+
identity_scaling_factor=None,
|
| 162 |
+
specified_min=None,
|
| 163 |
+
specified_max=None,
|
| 164 |
+
):
|
| 165 |
+
x_act = x if identity is None else identity + x
|
| 166 |
+
# collect running stats if training
|
| 167 |
+
if self.training:
|
| 168 |
+
assert not self.percentile, "percentile mode is not currently supported for activation."
|
| 169 |
+
assert not self.per_channel, "per-channel mode is not currently supported for activation."
|
| 170 |
+
x_min = x_act.data.min()
|
| 171 |
+
x_max = x_act.data.max()
|
| 172 |
+
|
| 173 |
+
assert x_max.isnan().sum() == 0 and x_min.isnan().sum() == 0, (
|
| 174 |
+
"NaN detected when computing min/max of the activation"
|
| 175 |
+
)
|
| 176 |
+
|
| 177 |
+
# Initialization
|
| 178 |
+
if self.x_min.min() > -1.1e-5 and self.x_max.max() < 1.1e-5:
|
| 179 |
+
self.x_min = self.x_min + x_min
|
| 180 |
+
self.x_max = self.x_max + x_max
|
| 181 |
+
|
| 182 |
+
# exponential moving average (EMA)
|
| 183 |
+
# use momentum to prevent the quantized values change greatly every iteration
|
| 184 |
+
elif self.act_range_momentum == -1:
|
| 185 |
+
self.x_min = torch.min(self.x_min, x_min)
|
| 186 |
+
self.x_max = torch.max(self.x_max, x_max)
|
| 187 |
+
else:
|
| 188 |
+
self.x_min = self.x_min * self.act_range_momentum + x_min * (1 - self.act_range_momentum)
|
| 189 |
+
self.x_max = self.x_max * self.act_range_momentum + x_max * (1 - self.act_range_momentum)
|
| 190 |
+
|
| 191 |
+
if not self.quant_mode:
|
| 192 |
+
return x_act, None
|
| 193 |
+
|
| 194 |
+
x_min = self.x_min if specified_min is None else specified_min
|
| 195 |
+
x_max = self.x_max if specified_max is None else specified_max
|
| 196 |
+
|
| 197 |
+
self.act_scaling_factor = symmetric_linear_quantization_params(
|
| 198 |
+
self.activation_bit, x_min, x_max, per_channel=self.per_channel
|
| 199 |
+
)
|
| 200 |
+
|
| 201 |
+
if pre_act_scaling_factor is None:
|
| 202 |
+
# this is for the input quantization
|
| 203 |
+
quant_act_int = self.act_function(x, self.activation_bit, self.percentile, self.act_scaling_factor)
|
| 204 |
+
else:
|
| 205 |
+
quant_act_int = FixedPointMul.apply(
|
| 206 |
+
x,
|
| 207 |
+
pre_act_scaling_factor,
|
| 208 |
+
self.activation_bit,
|
| 209 |
+
self.act_scaling_factor,
|
| 210 |
+
identity,
|
| 211 |
+
identity_scaling_factor,
|
| 212 |
+
)
|
| 213 |
+
|
| 214 |
+
correct_output_scale = self.act_scaling_factor.view(-1)
|
| 215 |
+
|
| 216 |
+
return quant_act_int * correct_output_scale, self.act_scaling_factor
|
| 217 |
+
|
| 218 |
+
|
| 219 |
+
class QuantLinear(nn.Module):
|
| 220 |
+
"""
|
| 221 |
+
Quantized version of `torch.nn.Linear`. Adds quantization-specific arguments on top of `torch.nn.Linear`.
|
| 222 |
+
|
| 223 |
+
Args:
|
| 224 |
+
weight_bit (`int`, *optional*, defaults to `8`):
|
| 225 |
+
Bitwidth for the quantized weight.
|
| 226 |
+
bias_bit (`int`, *optional*, defaults to `32`):
|
| 227 |
+
Bitwidth for the quantized bias.
|
| 228 |
+
per_channel (`bool`, *optional*, defaults to `False`):
|
| 229 |
+
Whether or not to use channel-wise quantization.
|
| 230 |
+
quant_mode (`bool`, *optional*, defaults to `False`):
|
| 231 |
+
Whether or not the layer is quantized.
|
| 232 |
+
"""
|
| 233 |
+
|
| 234 |
+
def __init__(
|
| 235 |
+
self, in_features, out_features, bias=True, weight_bit=8, bias_bit=32, per_channel=False, quant_mode=False
|
| 236 |
+
):
|
| 237 |
+
super().__init__()
|
| 238 |
+
self.in_features = in_features
|
| 239 |
+
self.out_features = out_features
|
| 240 |
+
|
| 241 |
+
self.weight = nn.Parameter(torch.zeros([out_features, in_features]))
|
| 242 |
+
self.register_buffer("weight_integer", torch.zeros_like(self.weight))
|
| 243 |
+
self.register_buffer("fc_scaling_factor", torch.zeros(self.out_features))
|
| 244 |
+
if bias:
|
| 245 |
+
self.bias = nn.Parameter(torch.zeros(out_features))
|
| 246 |
+
self.register_buffer("bias_integer", torch.zeros_like(self.bias))
|
| 247 |
+
|
| 248 |
+
self.weight_bit = weight_bit
|
| 249 |
+
self.quant_mode = quant_mode
|
| 250 |
+
self.per_channel = per_channel
|
| 251 |
+
self.bias_bit = bias_bit
|
| 252 |
+
self.quant_mode = quant_mode
|
| 253 |
+
self.percentile_mode = False
|
| 254 |
+
self.weight_function = SymmetricQuantFunction.apply
|
| 255 |
+
|
| 256 |
+
def __repr__(self):
|
| 257 |
+
s = super().__repr__()
|
| 258 |
+
s = f"({s} weight_bit={self.weight_bit}, quant_mode={self.quant_mode})"
|
| 259 |
+
return s
|
| 260 |
+
|
| 261 |
+
def forward(self, x, prev_act_scaling_factor=None):
|
| 262 |
+
if not self.quant_mode:
|
| 263 |
+
return nn.functional.linear(x, weight=self.weight, bias=self.bias), None
|
| 264 |
+
|
| 265 |
+
# assert that prev_act_scaling_factor is a scalar tensor
|
| 266 |
+
assert prev_act_scaling_factor is not None and prev_act_scaling_factor.shape == (1,), (
|
| 267 |
+
"Input activation to the QuantLinear layer should be globally (non-channel-wise) quantized. "
|
| 268 |
+
"Please add a QuantAct layer with `per_channel = True` before this QuantAct layer"
|
| 269 |
+
)
|
| 270 |
+
|
| 271 |
+
w = self.weight
|
| 272 |
+
w_transform = w.data.detach()
|
| 273 |
+
if self.per_channel:
|
| 274 |
+
w_min, _ = torch.min(w_transform, dim=1, out=None)
|
| 275 |
+
w_max, _ = torch.max(w_transform, dim=1, out=None)
|
| 276 |
+
else:
|
| 277 |
+
w_min = w_transform.min().expand(1)
|
| 278 |
+
w_max = w_transform.max().expand(1)
|
| 279 |
+
|
| 280 |
+
self.fc_scaling_factor = symmetric_linear_quantization_params(self.weight_bit, w_min, w_max, self.per_channel)
|
| 281 |
+
self.weight_integer = self.weight_function(
|
| 282 |
+
self.weight, self.weight_bit, self.percentile_mode, self.fc_scaling_factor
|
| 283 |
+
)
|
| 284 |
+
|
| 285 |
+
bias_scaling_factor = self.fc_scaling_factor * prev_act_scaling_factor
|
| 286 |
+
|
| 287 |
+
if self.bias is not None:
|
| 288 |
+
self.bias_integer = self.weight_function(self.bias, self.bias_bit, False, bias_scaling_factor)
|
| 289 |
+
|
| 290 |
+
prev_act_scaling_factor = prev_act_scaling_factor.view(1, -1)
|
| 291 |
+
x_int = x / prev_act_scaling_factor
|
| 292 |
+
|
| 293 |
+
return (
|
| 294 |
+
nn.functional.linear(x_int, weight=self.weight_integer, bias=self.bias_integer) * bias_scaling_factor,
|
| 295 |
+
bias_scaling_factor,
|
| 296 |
+
)
|
| 297 |
+
|
| 298 |
+
|
| 299 |
+
class IntGELU(nn.Module):
|
| 300 |
+
"""
|
| 301 |
+
Quantized version of `torch.nn.GELU`. Adds quantization-specific arguments on top of `torch.nn.GELU`.
|
| 302 |
+
|
| 303 |
+
Args:
|
| 304 |
+
quant_mode (`bool`, *optional*, defaults to `False`):
|
| 305 |
+
Whether or not the layer is quantized.
|
| 306 |
+
force_dequant (`str`, *optional*, defaults to `"none"`):
|
| 307 |
+
Force dequantize the layer if either "gelu" or "nonlinear" is given.
|
| 308 |
+
"""
|
| 309 |
+
|
| 310 |
+
def __init__(self, quant_mode=True, force_dequant="none"):
|
| 311 |
+
super().__init__()
|
| 312 |
+
self.quant_mode = quant_mode
|
| 313 |
+
|
| 314 |
+
if force_dequant in ["nonlinear", "gelu"]:
|
| 315 |
+
logger.info("Force dequantize gelu")
|
| 316 |
+
self.quant_mode = False
|
| 317 |
+
|
| 318 |
+
if not self.quant_mode:
|
| 319 |
+
self.activation_fn = nn.GELU()
|
| 320 |
+
|
| 321 |
+
self.k = 1.4142
|
| 322 |
+
self.const = 14 # dummy integer constant
|
| 323 |
+
self.coeff = [-0.2888, -1.769, 1] # a(x+b)**2 + c
|
| 324 |
+
self.coeff[2] /= self.coeff[0]
|
| 325 |
+
|
| 326 |
+
def int_erf(self, x_int, scaling_factor):
|
| 327 |
+
b_int = torch.floor(self.coeff[1] / scaling_factor)
|
| 328 |
+
c_int = torch.floor(self.coeff[2] / scaling_factor**2)
|
| 329 |
+
sign = torch.sign(x_int)
|
| 330 |
+
|
| 331 |
+
abs_int = torch.min(torch.abs(x_int), -b_int)
|
| 332 |
+
y_int = sign * ((abs_int + b_int) ** 2 + c_int)
|
| 333 |
+
scaling_factor = scaling_factor**2 * self.coeff[0]
|
| 334 |
+
|
| 335 |
+
# avoid overflow
|
| 336 |
+
y_int = floor_ste.apply(y_int / 2**self.const)
|
| 337 |
+
scaling_factor = scaling_factor * 2**self.const
|
| 338 |
+
|
| 339 |
+
return y_int, scaling_factor
|
| 340 |
+
|
| 341 |
+
def forward(self, x, scaling_factor=None):
|
| 342 |
+
if not self.quant_mode:
|
| 343 |
+
return self.activation_fn(x), None
|
| 344 |
+
|
| 345 |
+
x_int = x / scaling_factor
|
| 346 |
+
sigmoid_int, sigmoid_scaling_factor = self.int_erf(x_int, scaling_factor / self.k)
|
| 347 |
+
|
| 348 |
+
shift_int = 1.0 // sigmoid_scaling_factor
|
| 349 |
+
|
| 350 |
+
x_int = x_int * (sigmoid_int + shift_int)
|
| 351 |
+
scaling_factor = scaling_factor * sigmoid_scaling_factor / 2
|
| 352 |
+
|
| 353 |
+
return x_int * scaling_factor, scaling_factor
|
| 354 |
+
|
| 355 |
+
|
| 356 |
+
class IntSoftmax(nn.Module):
|
| 357 |
+
"""
|
| 358 |
+
Quantized version of `torch.nn.Softmax`. Adds quantization-specific arguments on top of `torch.nn.Softmax`.
|
| 359 |
+
|
| 360 |
+
Args:
|
| 361 |
+
output_bit (`int`):
|
| 362 |
+
Bitwidth for the layer output activation.
|
| 363 |
+
quant_mode (`bool`, *optional*, defaults to `False`):
|
| 364 |
+
Whether or not the layer is quantized.
|
| 365 |
+
force_dequant (`str`, *optional*, defaults to `"none"`):
|
| 366 |
+
Force dequantize the layer if either "softmax" or "nonlinear" is given.
|
| 367 |
+
"""
|
| 368 |
+
|
| 369 |
+
def __init__(self, output_bit, quant_mode=False, force_dequant="none"):
|
| 370 |
+
super().__init__()
|
| 371 |
+
self.output_bit = output_bit
|
| 372 |
+
self.max_bit = 32
|
| 373 |
+
self.quant_mode = quant_mode
|
| 374 |
+
|
| 375 |
+
if force_dequant in ["nonlinear", "softmax"]:
|
| 376 |
+
logger.info("Force dequantize softmax")
|
| 377 |
+
self.quant_mode = False
|
| 378 |
+
|
| 379 |
+
self.act = QuantAct(16, quant_mode=self.quant_mode)
|
| 380 |
+
self.x0 = -0.6931 # -ln2
|
| 381 |
+
self.const = 30 # dummy integer constant
|
| 382 |
+
self.coef = [0.35815147, 0.96963238, 1.0] # ax**2 + bx + c
|
| 383 |
+
self.coef[1] /= self.coef[0]
|
| 384 |
+
self.coef[2] /= self.coef[0]
|
| 385 |
+
|
| 386 |
+
def int_polynomial(self, x_int, scaling_factor):
|
| 387 |
+
with torch.no_grad():
|
| 388 |
+
b_int = torch.floor(self.coef[1] / scaling_factor)
|
| 389 |
+
c_int = torch.floor(self.coef[2] / scaling_factor**2)
|
| 390 |
+
z = (x_int + b_int) * x_int + c_int
|
| 391 |
+
scaling_factor = self.coef[0] * scaling_factor**2
|
| 392 |
+
return z, scaling_factor
|
| 393 |
+
|
| 394 |
+
def int_exp(self, x_int, scaling_factor):
|
| 395 |
+
with torch.no_grad():
|
| 396 |
+
x0_int = torch.floor(self.x0 / scaling_factor)
|
| 397 |
+
x_int = torch.max(x_int, self.const * x0_int)
|
| 398 |
+
|
| 399 |
+
q = floor_ste.apply(x_int / x0_int)
|
| 400 |
+
r = x_int - x0_int * q
|
| 401 |
+
exp_int, exp_scaling_factor = self.int_polynomial(r, scaling_factor)
|
| 402 |
+
exp_int = torch.clamp(floor_ste.apply(exp_int * 2 ** (self.const - q)), min=0)
|
| 403 |
+
scaling_factor = exp_scaling_factor / 2**self.const
|
| 404 |
+
return exp_int, scaling_factor
|
| 405 |
+
|
| 406 |
+
def forward(self, x, scaling_factor):
|
| 407 |
+
if not self.quant_mode:
|
| 408 |
+
return nn.functional.softmax(x, dim=-1), None
|
| 409 |
+
|
| 410 |
+
x_int = x / scaling_factor
|
| 411 |
+
|
| 412 |
+
x_int_max, _ = x_int.max(dim=-1, keepdim=True)
|
| 413 |
+
x_int = x_int - x_int_max
|
| 414 |
+
exp_int, exp_scaling_factor = self.int_exp(x_int, scaling_factor)
|
| 415 |
+
|
| 416 |
+
# Avoid overflow
|
| 417 |
+
exp, exp_scaling_factor = self.act(exp_int, exp_scaling_factor)
|
| 418 |
+
exp_int = exp / exp_scaling_factor
|
| 419 |
+
|
| 420 |
+
exp_int_sum = exp_int.sum(dim=-1, keepdim=True)
|
| 421 |
+
factor = floor_ste.apply(2**self.max_bit / exp_int_sum)
|
| 422 |
+
exp_int = floor_ste.apply(exp_int * factor / 2 ** (self.max_bit - self.output_bit))
|
| 423 |
+
scaling_factor = 1 / 2**self.output_bit
|
| 424 |
+
return exp_int * scaling_factor, scaling_factor
|
| 425 |
+
|
| 426 |
+
|
| 427 |
+
class IntLayerNorm(nn.Module):
|
| 428 |
+
"""
|
| 429 |
+
Quantized version of `torch.nn.LayerNorm`. Adds quantization-specific arguments on top of `torch.nn.LayerNorm`.
|
| 430 |
+
|
| 431 |
+
Args:
|
| 432 |
+
output_bit (`int`, *optional*, defaults to `8`):
|
| 433 |
+
Bitwidth for the layer output activation.
|
| 434 |
+
quant_mode (`bool`, *optional*, defaults to `False`):
|
| 435 |
+
Whether or not the layer is quantized.
|
| 436 |
+
force_dequant (`str`, *optional*, defaults to `"none"`):
|
| 437 |
+
Force dequantize the layer if either "layernorm" or "nonlinear" is given.
|
| 438 |
+
"""
|
| 439 |
+
|
| 440 |
+
def __init__(self, normalized_shape, eps, output_bit=8, quant_mode=False, force_dequant="none"):
|
| 441 |
+
super().__init__()
|
| 442 |
+
self.normalized_shape = normalized_shape
|
| 443 |
+
self.eps = eps
|
| 444 |
+
|
| 445 |
+
self.weight = nn.Parameter(torch.zeros(normalized_shape))
|
| 446 |
+
self.bias = nn.Parameter(torch.zeros(normalized_shape))
|
| 447 |
+
|
| 448 |
+
self.quant_mode = quant_mode
|
| 449 |
+
if force_dequant in ["nonlinear", "layernorm"]:
|
| 450 |
+
logger.info("Force dequantize layernorm")
|
| 451 |
+
self.quant_mode = False
|
| 452 |
+
|
| 453 |
+
self.register_buffer("shift", torch.zeros(1))
|
| 454 |
+
self.output_bit = output_bit
|
| 455 |
+
self.max_bit = 32
|
| 456 |
+
self.dim_sqrt = None
|
| 457 |
+
self.activation = QuantAct(self.output_bit, quant_mode=self.quant_mode)
|
| 458 |
+
|
| 459 |
+
def set_shift(self, y_int):
|
| 460 |
+
with torch.no_grad():
|
| 461 |
+
y_sq_int = y_int**2
|
| 462 |
+
var_int = torch.sum(y_sq_int, axis=2, keepdim=True)
|
| 463 |
+
shift = (torch.log2(torch.sqrt(var_int / 2**self.max_bit)).ceil()).max()
|
| 464 |
+
shift_old = self.shift
|
| 465 |
+
self.shift = torch.max(self.shift, shift)
|
| 466 |
+
logger.info(f"Dynamic shift adjustment: {int(shift_old)} -> {int(self.shift)}")
|
| 467 |
+
|
| 468 |
+
def overflow_fallback(self, y_int):
|
| 469 |
+
"""
|
| 470 |
+
This fallback function is called when overflow is detected during training time, and adjusts the `self.shift`
|
| 471 |
+
to avoid overflow in the subsequent runs.
|
| 472 |
+
"""
|
| 473 |
+
self.set_shift(y_int) # adjusts `self.shift`
|
| 474 |
+
y_int_shifted = floor_ste.apply(y_int / 2**self.shift)
|
| 475 |
+
y_sq_int = y_int_shifted**2
|
| 476 |
+
var_int = torch.sum(y_sq_int, axis=2, keepdim=True)
|
| 477 |
+
return var_int
|
| 478 |
+
|
| 479 |
+
def forward(self, x, scaling_factor=None):
|
| 480 |
+
if not self.quant_mode:
|
| 481 |
+
mean = x.mean(axis=2, keepdim=True)
|
| 482 |
+
y = x - mean
|
| 483 |
+
var = torch.mean(y**2, axis=2, keepdim=True)
|
| 484 |
+
x = y / torch.sqrt(self.eps + var)
|
| 485 |
+
x = x * self.weight + self.bias
|
| 486 |
+
return x, None
|
| 487 |
+
|
| 488 |
+
# compute sqrt of the feature dimension if it is the first run
|
| 489 |
+
if self.dim_sqrt is None:
|
| 490 |
+
n = torch.tensor(x.shape[2], dtype=torch.float)
|
| 491 |
+
self.dim_sqrt = torch.sqrt(n).to(x.device)
|
| 492 |
+
|
| 493 |
+
# Normalization: computes mean and variance(std)
|
| 494 |
+
x_int = x / scaling_factor
|
| 495 |
+
mean_int = round_ste.apply(x_int.mean(axis=2, keepdim=True))
|
| 496 |
+
y_int = x_int - mean_int
|
| 497 |
+
y_int_shifted = floor_ste.apply(y_int / 2**self.shift)
|
| 498 |
+
y_sq_int = y_int_shifted**2
|
| 499 |
+
var_int = torch.sum(y_sq_int, axis=2, keepdim=True)
|
| 500 |
+
|
| 501 |
+
# overflow handling in training time
|
| 502 |
+
if self.training:
|
| 503 |
+
# if overflow is detected
|
| 504 |
+
if var_int.max() >= 2**self.max_bit:
|
| 505 |
+
var_int = self.overflow_fallback(y_int)
|
| 506 |
+
assert var_int.max() < 2**self.max_bit + 0.1, (
|
| 507 |
+
"Error detected in overflow handling: "
|
| 508 |
+
"`var_int` exceeds `self.max_bit` (the maximum possible bit width)"
|
| 509 |
+
)
|
| 510 |
+
|
| 511 |
+
# To be replaced with integer-sqrt kernel that produces the same output
|
| 512 |
+
std_int = floor_ste.apply(torch.sqrt(var_int)) * 2**self.shift
|
| 513 |
+
factor = floor_ste.apply(2**31 / std_int)
|
| 514 |
+
y_int = floor_ste.apply(y_int * factor / 2)
|
| 515 |
+
scaling_factor = self.dim_sqrt / 2**30
|
| 516 |
+
|
| 517 |
+
# scaling and shifting
|
| 518 |
+
bias = self.bias.data.detach() / (self.weight.data.detach())
|
| 519 |
+
bias_int = floor_ste.apply(bias / scaling_factor)
|
| 520 |
+
|
| 521 |
+
y_int = y_int + bias_int
|
| 522 |
+
scaling_factor = scaling_factor * self.weight
|
| 523 |
+
x = y_int * scaling_factor
|
| 524 |
+
|
| 525 |
+
return x, scaling_factor
|
| 526 |
+
|
| 527 |
+
|
| 528 |
+
def get_percentile_min_max(input, lower_percentile, upper_percentile, output_tensor=False):
|
| 529 |
+
"""
|
| 530 |
+
Calculate the percentile max and min values in a given tensor
|
| 531 |
+
|
| 532 |
+
Args:
|
| 533 |
+
input (`torch.Tensor`):
|
| 534 |
+
The target tensor to calculate percentile max and min.
|
| 535 |
+
lower_percentile (`float`):
|
| 536 |
+
If 0.1, means we return the value of the smallest 0.1% value in the tensor as percentile min.
|
| 537 |
+
upper_percentile (`float`):
|
| 538 |
+
If 99.9, means we return the value of the largest 0.1% value in the tensor as percentile max.
|
| 539 |
+
output_tensor (`bool`, *optional*, defaults to `False`):
|
| 540 |
+
If True, this function returns tensors, otherwise it returns values.
|
| 541 |
+
|
| 542 |
+
Returns:
|
| 543 |
+
`Tuple(torch.Tensor, torch.Tensor)`: Percentile min and max value of *input*
|
| 544 |
+
"""
|
| 545 |
+
input_length = input.shape[0]
|
| 546 |
+
|
| 547 |
+
lower_index = round(input_length * (1 - lower_percentile * 0.01))
|
| 548 |
+
upper_index = round(input_length * upper_percentile * 0.01)
|
| 549 |
+
|
| 550 |
+
upper_bound = torch.kthvalue(input, k=upper_index).values
|
| 551 |
+
|
| 552 |
+
if lower_percentile == 0:
|
| 553 |
+
lower_bound = upper_bound * 0
|
| 554 |
+
# lower_index += 1
|
| 555 |
+
else:
|
| 556 |
+
lower_bound = -torch.kthvalue(-input, k=lower_index).values
|
| 557 |
+
|
| 558 |
+
if not output_tensor:
|
| 559 |
+
lower_bound = lower_bound.item()
|
| 560 |
+
upper_bound = upper_bound.item()
|
| 561 |
+
return lower_bound, upper_bound
|
| 562 |
+
|
| 563 |
+
|
| 564 |
+
def linear_quantize(input, scale, zero_point, inplace=False):
|
| 565 |
+
"""
|
| 566 |
+
Quantize single-precision input tensor to integers with the given scaling factor and zeropoint.
|
| 567 |
+
|
| 568 |
+
Args:
|
| 569 |
+
input (`torch.Tensor`):
|
| 570 |
+
Single-precision input tensor to be quantized.
|
| 571 |
+
scale (`torch.Tensor`):
|
| 572 |
+
Scaling factor for quantization.
|
| 573 |
+
zero_pint (`torch.Tensor`):
|
| 574 |
+
Shift for quantization.
|
| 575 |
+
inplace (`bool`, *optional*, defaults to `False`):
|
| 576 |
+
Whether to compute inplace or not.
|
| 577 |
+
|
| 578 |
+
Returns:
|
| 579 |
+
`torch.Tensor`: Linearly quantized value of *input* according to *scale* and *zero_point*.
|
| 580 |
+
"""
|
| 581 |
+
# reshape scale and zeropoint for convolutional weights and activation
|
| 582 |
+
if len(input.shape) == 4:
|
| 583 |
+
scale = scale.view(-1, 1, 1, 1)
|
| 584 |
+
zero_point = zero_point.view(-1, 1, 1, 1)
|
| 585 |
+
# reshape scale and zeropoint for linear weights
|
| 586 |
+
elif len(input.shape) == 2:
|
| 587 |
+
scale = scale.view(-1, 1)
|
| 588 |
+
zero_point = zero_point.view(-1, 1)
|
| 589 |
+
else:
|
| 590 |
+
scale = scale.view(-1)
|
| 591 |
+
zero_point = zero_point.view(-1)
|
| 592 |
+
# quantized = float / scale + zero_point
|
| 593 |
+
if inplace:
|
| 594 |
+
input.mul_(1.0 / scale).add_(zero_point).round_()
|
| 595 |
+
return input
|
| 596 |
+
return torch.round(1.0 / scale * input + zero_point)
|
| 597 |
+
|
| 598 |
+
|
| 599 |
+
def symmetric_linear_quantization_params(num_bits, saturation_min, saturation_max, per_channel=False):
|
| 600 |
+
"""
|
| 601 |
+
Compute the scaling factor with the given quantization range for symmetric quantization.
|
| 602 |
+
|
| 603 |
+
Args:
|
| 604 |
+
saturation_min (`torch.Tensor`):
|
| 605 |
+
Lower bound for quantization range.
|
| 606 |
+
saturation_max (`torch.Tensor`):
|
| 607 |
+
Upper bound for quantization range.
|
| 608 |
+
per_channel (`bool`, *optional*, defaults to `False`):
|
| 609 |
+
Whether to or not use channel-wise quantization.
|
| 610 |
+
|
| 611 |
+
Returns:
|
| 612 |
+
`torch.Tensor`: Scaling factor that linearly quantizes the given range between *saturation_min* and
|
| 613 |
+
*saturation_max*.
|
| 614 |
+
"""
|
| 615 |
+
# in this part, we do not need any gradient computation,
|
| 616 |
+
# in order to enforce this, we put torch.no_grad()
|
| 617 |
+
with torch.no_grad():
|
| 618 |
+
n = 2 ** (num_bits - 1) - 1
|
| 619 |
+
|
| 620 |
+
if per_channel:
|
| 621 |
+
scale, _ = torch.max(torch.stack([saturation_min.abs(), saturation_max.abs()], dim=1), dim=1)
|
| 622 |
+
scale = torch.clamp(scale, min=1e-8) / n
|
| 623 |
+
|
| 624 |
+
else:
|
| 625 |
+
scale = max(saturation_min.abs(), saturation_max.abs())
|
| 626 |
+
scale = torch.clamp(scale, min=1e-8) / n
|
| 627 |
+
|
| 628 |
+
return scale
|
| 629 |
+
|
| 630 |
+
|
| 631 |
+
class SymmetricQuantFunction(Function):
|
| 632 |
+
"""
|
| 633 |
+
Class to quantize the given floating-point values using symmetric quantization with given range and bitwidth.
|
| 634 |
+
"""
|
| 635 |
+
|
| 636 |
+
@staticmethod
|
| 637 |
+
def forward(ctx, x, k, percentile_mode, scale):
|
| 638 |
+
"""
|
| 639 |
+
Args:
|
| 640 |
+
x (`torch.Tensor`):
|
| 641 |
+
Floating point tensor to be quantized.
|
| 642 |
+
k (`int`):
|
| 643 |
+
Quantization bitwidth.
|
| 644 |
+
percentile_mode (`bool`):
|
| 645 |
+
Whether or not to use percentile calibration.
|
| 646 |
+
scale (`torch.Tensor`):
|
| 647 |
+
Pre-calculated scaling factor for *x*. Note that the current implementation of SymmetricQuantFunction
|
| 648 |
+
requires pre-calculated scaling factor.
|
| 649 |
+
|
| 650 |
+
Returns:
|
| 651 |
+
`torch.Tensor`: Symmetric-quantized value of *input*.
|
| 652 |
+
"""
|
| 653 |
+
zero_point = torch.tensor(0.0, device=scale.device)
|
| 654 |
+
|
| 655 |
+
n = 2 ** (k - 1) - 1
|
| 656 |
+
new_quant_x = linear_quantize(x, scale, zero_point, inplace=False)
|
| 657 |
+
new_quant_x = torch.clamp(new_quant_x, -n, n - 1)
|
| 658 |
+
|
| 659 |
+
ctx.scale = scale
|
| 660 |
+
return new_quant_x
|
| 661 |
+
|
| 662 |
+
@staticmethod
|
| 663 |
+
def backward(ctx, grad_output):
|
| 664 |
+
scale = ctx.scale
|
| 665 |
+
if len(grad_output.shape) == 4:
|
| 666 |
+
scale = scale.view(-1, 1, 1, 1)
|
| 667 |
+
# reshape scale and zeropoint for linear weights
|
| 668 |
+
elif len(grad_output.shape) == 2:
|
| 669 |
+
scale = scale.view(-1, 1)
|
| 670 |
+
else:
|
| 671 |
+
scale = scale.view(-1)
|
| 672 |
+
|
| 673 |
+
return grad_output.clone() / scale, None, None, None, None
|
| 674 |
+
|
| 675 |
+
|
| 676 |
+
class floor_ste(Function):
|
| 677 |
+
"""
|
| 678 |
+
Straight-through Estimator(STE) for torch.floor()
|
| 679 |
+
"""
|
| 680 |
+
|
| 681 |
+
@staticmethod
|
| 682 |
+
def forward(ctx, x):
|
| 683 |
+
return torch.floor(x)
|
| 684 |
+
|
| 685 |
+
@staticmethod
|
| 686 |
+
def backward(ctx, grad_output):
|
| 687 |
+
return grad_output.clone()
|
| 688 |
+
|
| 689 |
+
|
| 690 |
+
class round_ste(Function):
|
| 691 |
+
"""
|
| 692 |
+
Straight-through Estimator(STE) for torch.round()
|
| 693 |
+
"""
|
| 694 |
+
|
| 695 |
+
@staticmethod
|
| 696 |
+
def forward(ctx, x):
|
| 697 |
+
return torch.round(x)
|
| 698 |
+
|
| 699 |
+
@staticmethod
|
| 700 |
+
def backward(ctx, grad_output):
|
| 701 |
+
return grad_output.clone()
|
| 702 |
+
|
| 703 |
+
|
| 704 |
+
def batch_frexp(inputs, max_bit=31):
|
| 705 |
+
"""
|
| 706 |
+
Decompose the scaling factor into mantissa and twos exponent.
|
| 707 |
+
|
| 708 |
+
Args:
|
| 709 |
+
scaling_factor (`torch.Tensor`):
|
| 710 |
+
Target scaling factor to decompose.
|
| 711 |
+
|
| 712 |
+
Returns:
|
| 713 |
+
``Tuple(torch.Tensor, torch.Tensor)`: mantisa and exponent
|
| 714 |
+
"""
|
| 715 |
+
|
| 716 |
+
shape_of_input = inputs.size()
|
| 717 |
+
|
| 718 |
+
# trans the input to be a 1-d tensor
|
| 719 |
+
inputs = inputs.view(-1)
|
| 720 |
+
|
| 721 |
+
output_m, output_e = np.frexp(inputs.cpu().numpy())
|
| 722 |
+
tmp_m = []
|
| 723 |
+
for m in output_m:
|
| 724 |
+
int_m_shifted = int(
|
| 725 |
+
decimal.Decimal(m * (2**max_bit)).quantize(decimal.Decimal(1), rounding=decimal.ROUND_HALF_UP)
|
| 726 |
+
)
|
| 727 |
+
tmp_m.append(int_m_shifted)
|
| 728 |
+
output_m = np.array(tmp_m)
|
| 729 |
+
|
| 730 |
+
output_e = float(max_bit) - output_e
|
| 731 |
+
|
| 732 |
+
return (
|
| 733 |
+
torch.from_numpy(output_m).to(inputs.device).view(shape_of_input),
|
| 734 |
+
torch.from_numpy(output_e).to(inputs.device).view(shape_of_input),
|
| 735 |
+
)
|
| 736 |
+
|
| 737 |
+
|
| 738 |
+
class FixedPointMul(Function):
|
| 739 |
+
"""
|
| 740 |
+
Function to perform fixed-point arithmetic that can match integer arithmetic on hardware.
|
| 741 |
+
|
| 742 |
+
Args:
|
| 743 |
+
pre_act (`torch.Tensor`):
|
| 744 |
+
Input tensor.
|
| 745 |
+
pre_act_scaling_factor (`torch.Tensor`):
|
| 746 |
+
Scaling factor of the input tensor *pre_act*.
|
| 747 |
+
bit_num (`int`):
|
| 748 |
+
Quantization bitwidth.
|
| 749 |
+
z_scaling_factor (`torch.Tensor`):
|
| 750 |
+
Scaling factor of the output tensor.
|
| 751 |
+
identity (`torch.Tensor`, *optional*):
|
| 752 |
+
Identity tensor, if exists.
|
| 753 |
+
identity_scaling_factor (`torch.Tensor`, *optional*):
|
| 754 |
+
Scaling factor of the identity tensor *identity*, if exists.
|
| 755 |
+
|
| 756 |
+
Returns:
|
| 757 |
+
`torch.Tensor`: Output tensor(*pre_act* if *identity* is not given, otherwise the addition of *pre_act* and
|
| 758 |
+
*identity*), whose scale is rescaled to *z_scaling_factor*.
|
| 759 |
+
"""
|
| 760 |
+
|
| 761 |
+
@staticmethod
|
| 762 |
+
def forward(
|
| 763 |
+
ctx,
|
| 764 |
+
pre_act,
|
| 765 |
+
pre_act_scaling_factor,
|
| 766 |
+
bit_num,
|
| 767 |
+
z_scaling_factor,
|
| 768 |
+
identity=None,
|
| 769 |
+
identity_scaling_factor=None,
|
| 770 |
+
):
|
| 771 |
+
if len(pre_act_scaling_factor.shape) == 3:
|
| 772 |
+
reshape = lambda x: x # noqa: E731
|
| 773 |
+
else:
|
| 774 |
+
reshape = lambda x: x.view(1, 1, -1) # noqa: E731
|
| 775 |
+
ctx.identity = identity
|
| 776 |
+
|
| 777 |
+
n = 2 ** (bit_num - 1) - 1
|
| 778 |
+
|
| 779 |
+
with torch.no_grad():
|
| 780 |
+
pre_act_scaling_factor = reshape(pre_act_scaling_factor)
|
| 781 |
+
if identity is not None:
|
| 782 |
+
identity_scaling_factor = reshape(identity_scaling_factor)
|
| 783 |
+
|
| 784 |
+
ctx.z_scaling_factor = z_scaling_factor
|
| 785 |
+
|
| 786 |
+
z_int = torch.round(pre_act / pre_act_scaling_factor)
|
| 787 |
+
_A = pre_act_scaling_factor.type(torch.double)
|
| 788 |
+
_B = (z_scaling_factor.type(torch.float)).type(torch.double)
|
| 789 |
+
new_scale = _A / _B
|
| 790 |
+
new_scale = reshape(new_scale)
|
| 791 |
+
|
| 792 |
+
m, e = batch_frexp(new_scale)
|
| 793 |
+
|
| 794 |
+
output = z_int.type(torch.double) * m.type(torch.double)
|
| 795 |
+
output = torch.round(output / (2.0**e))
|
| 796 |
+
|
| 797 |
+
if identity is not None:
|
| 798 |
+
# needs addition of identity activation
|
| 799 |
+
wx_int = torch.round(identity / identity_scaling_factor)
|
| 800 |
+
|
| 801 |
+
_A = identity_scaling_factor.type(torch.double)
|
| 802 |
+
_B = (z_scaling_factor.type(torch.float)).type(torch.double)
|
| 803 |
+
new_scale = _A / _B
|
| 804 |
+
new_scale = reshape(new_scale)
|
| 805 |
+
|
| 806 |
+
m1, e1 = batch_frexp(new_scale)
|
| 807 |
+
output1 = wx_int.type(torch.double) * m1.type(torch.double)
|
| 808 |
+
output1 = torch.round(output1 / (2.0**e1))
|
| 809 |
+
|
| 810 |
+
output = output1 + output
|
| 811 |
+
|
| 812 |
+
return torch.clamp(output.type(torch.float), -n - 1, n)
|
| 813 |
+
|
| 814 |
+
@staticmethod
|
| 815 |
+
def backward(ctx, grad_output):
|
| 816 |
+
identity_grad = None
|
| 817 |
+
if ctx.identity is not None:
|
| 818 |
+
identity_grad = grad_output.clone() / ctx.z_scaling_factor
|
| 819 |
+
return grad_output.clone() / ctx.z_scaling_factor, None, None, None, None, identity_grad, None
|
third_party/transformers/src/transformers/models/layoutlm/__init__.py
ADDED
|
@@ -0,0 +1,29 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
# Copyright 2024 The HuggingFace Team. All rights reserved.
|
| 2 |
+
#
|
| 3 |
+
# Licensed under the Apache License, Version 2.0 (the "License");
|
| 4 |
+
# you may not use this file except in compliance with the License.
|
| 5 |
+
# You may obtain a copy of the License at
|
| 6 |
+
#
|
| 7 |
+
# http://www.apache.org/licenses/LICENSE-2.0
|
| 8 |
+
#
|
| 9 |
+
# Unless required by applicable law or agreed to in writing, software
|
| 10 |
+
# distributed under the License is distributed on an "AS IS" BASIS,
|
| 11 |
+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
| 12 |
+
# See the License for the specific language governing permissions and
|
| 13 |
+
# limitations under the License.
|
| 14 |
+
from typing import TYPE_CHECKING
|
| 15 |
+
|
| 16 |
+
from ...utils import _LazyModule
|
| 17 |
+
from ...utils.import_utils import define_import_structure
|
| 18 |
+
|
| 19 |
+
|
| 20 |
+
if TYPE_CHECKING:
|
| 21 |
+
from ..bert.tokenization_bert import BertTokenizer as LayoutLMTokenizer
|
| 22 |
+
from ..bert.tokenization_bert import BertTokenizer as LayoutLMTokenizerFast
|
| 23 |
+
from .configuration_layoutlm import *
|
| 24 |
+
from .modeling_layoutlm import *
|
| 25 |
+
else:
|
| 26 |
+
import sys
|
| 27 |
+
|
| 28 |
+
_file = globals()["__file__"]
|
| 29 |
+
sys.modules[__name__] = _LazyModule(__name__, _file, define_import_structure(_file), module_spec=__spec__)
|
third_party/transformers/src/transformers/models/layoutlm/configuration_layoutlm.py
ADDED
|
@@ -0,0 +1,67 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
# Copyright 2010, The Microsoft Research Asia LayoutLM Team authors
|
| 2 |
+
#
|
| 3 |
+
# Licensed under the Apache License, Version 2.0 (the "License");
|
| 4 |
+
# you may not use this file except in compliance with the License.
|
| 5 |
+
# You may obtain a copy of the License at
|
| 6 |
+
#
|
| 7 |
+
# http://www.apache.org/licenses/LICENSE-2.0
|
| 8 |
+
#
|
| 9 |
+
# Unless required by applicable law or agreed to in writing, software
|
| 10 |
+
# distributed under the License is distributed on an "AS IS" BASIS,
|
| 11 |
+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
| 12 |
+
# See the License for the specific language governing permissions and
|
| 13 |
+
# limitations under the License.
|
| 14 |
+
"""LayoutLM model configuration"""
|
| 15 |
+
|
| 16 |
+
from huggingface_hub.dataclasses import strict
|
| 17 |
+
|
| 18 |
+
from ... import PreTrainedConfig
|
| 19 |
+
from ...utils import auto_docstring
|
| 20 |
+
|
| 21 |
+
|
| 22 |
+
@auto_docstring(checkpoint="microsoft/layoutlm-base-uncased")
|
| 23 |
+
@strict
|
| 24 |
+
class LayoutLMConfig(PreTrainedConfig):
|
| 25 |
+
r"""
|
| 26 |
+
max_2d_position_embeddings (`int`, *optional*, defaults to 1024):
|
| 27 |
+
The maximum value that the 2D position embedding might ever used. Typically set this to something large
|
| 28 |
+
just in case (e.g., 1024).
|
| 29 |
+
|
| 30 |
+
Examples:
|
| 31 |
+
|
| 32 |
+
```python
|
| 33 |
+
>>> from transformers import LayoutLMConfig, LayoutLMModel
|
| 34 |
+
|
| 35 |
+
>>> # Initializing a LayoutLM configuration
|
| 36 |
+
>>> configuration = LayoutLMConfig()
|
| 37 |
+
|
| 38 |
+
>>> # Initializing a model (with random weights) from the configuration
|
| 39 |
+
>>> model = LayoutLMModel(configuration)
|
| 40 |
+
|
| 41 |
+
>>> # Accessing the model configuration
|
| 42 |
+
>>> configuration = model.config
|
| 43 |
+
```"""
|
| 44 |
+
|
| 45 |
+
model_type = "layoutlm"
|
| 46 |
+
|
| 47 |
+
vocab_size: int = 30522
|
| 48 |
+
hidden_size: int = 768
|
| 49 |
+
num_hidden_layers: int = 12
|
| 50 |
+
num_attention_heads: int = 12
|
| 51 |
+
intermediate_size: int = 3072
|
| 52 |
+
hidden_act: str = "gelu"
|
| 53 |
+
hidden_dropout_prob: float | int = 0.1
|
| 54 |
+
attention_probs_dropout_prob: float | int = 0.1
|
| 55 |
+
max_position_embeddings: int = 512
|
| 56 |
+
type_vocab_size: int = 2
|
| 57 |
+
initializer_range: float = 0.02
|
| 58 |
+
layer_norm_eps: float = 1e-12
|
| 59 |
+
pad_token_id: int | None = 0
|
| 60 |
+
eos_token_id: int | list[int] | None = None
|
| 61 |
+
bos_token_id: int | None = None
|
| 62 |
+
use_cache: bool = True
|
| 63 |
+
max_2d_position_embeddings: int = 1024
|
| 64 |
+
tie_word_embeddings: bool = True
|
| 65 |
+
|
| 66 |
+
|
| 67 |
+
__all__ = ["LayoutLMConfig"]
|
third_party/transformers/src/transformers/models/layoutlm/modeling_layoutlm.py
ADDED
|
@@ -0,0 +1,1012 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
# Copyright 2018 The Microsoft Research Asia LayoutLM Team Authors and the HuggingFace Inc. team.
|
| 2 |
+
#
|
| 3 |
+
# Licensed under the Apache License, Version 2.0 (the "License");
|
| 4 |
+
# you may not use this file except in compliance with the License.
|
| 5 |
+
# You may obtain a copy of the License at
|
| 6 |
+
#
|
| 7 |
+
# http://www.apache.org/licenses/LICENSE-2.0
|
| 8 |
+
#
|
| 9 |
+
# Unless required by applicable law or agreed to in writing, software
|
| 10 |
+
# distributed under the License is distributed on an "AS IS" BASIS,
|
| 11 |
+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
| 12 |
+
# See the License for the specific language governing permissions and
|
| 13 |
+
# limitations under the License.
|
| 14 |
+
"""PyTorch LayoutLM model."""
|
| 15 |
+
|
| 16 |
+
from collections.abc import Callable
|
| 17 |
+
|
| 18 |
+
import torch
|
| 19 |
+
from torch import nn
|
| 20 |
+
from torch.nn import BCEWithLogitsLoss, CrossEntropyLoss, MSELoss
|
| 21 |
+
|
| 22 |
+
from ... import initialization as init
|
| 23 |
+
from ...activations import ACT2FN
|
| 24 |
+
from ...modeling_layers import GradientCheckpointingLayer
|
| 25 |
+
from ...modeling_outputs import (
|
| 26 |
+
BaseModelOutput,
|
| 27 |
+
BaseModelOutputWithPooling,
|
| 28 |
+
MaskedLMOutput,
|
| 29 |
+
QuestionAnsweringModelOutput,
|
| 30 |
+
SequenceClassifierOutput,
|
| 31 |
+
TokenClassifierOutput,
|
| 32 |
+
)
|
| 33 |
+
from ...modeling_utils import ALL_ATTENTION_FUNCTIONS, PreTrainedModel
|
| 34 |
+
from ...processing_utils import Unpack
|
| 35 |
+
from ...pytorch_utils import apply_chunking_to_forward
|
| 36 |
+
from ...utils import TransformersKwargs, auto_docstring, can_return_tuple, logging
|
| 37 |
+
from ...utils.generic import merge_with_config_defaults
|
| 38 |
+
from ...utils.output_capturing import capture_outputs
|
| 39 |
+
from .configuration_layoutlm import LayoutLMConfig
|
| 40 |
+
|
| 41 |
+
|
| 42 |
+
logger = logging.get_logger(__name__)
|
| 43 |
+
|
| 44 |
+
|
| 45 |
+
LayoutLMLayerNorm = nn.LayerNorm
|
| 46 |
+
|
| 47 |
+
|
| 48 |
+
class LayoutLMEmbeddings(nn.Module):
|
| 49 |
+
"""Construct the embeddings from word, position and token_type embeddings."""
|
| 50 |
+
|
| 51 |
+
def __init__(self, config):
|
| 52 |
+
super().__init__()
|
| 53 |
+
self.word_embeddings = nn.Embedding(config.vocab_size, config.hidden_size, padding_idx=config.pad_token_id)
|
| 54 |
+
self.position_embeddings = nn.Embedding(config.max_position_embeddings, config.hidden_size)
|
| 55 |
+
self.x_position_embeddings = nn.Embedding(config.max_2d_position_embeddings, config.hidden_size)
|
| 56 |
+
self.y_position_embeddings = nn.Embedding(config.max_2d_position_embeddings, config.hidden_size)
|
| 57 |
+
self.h_position_embeddings = nn.Embedding(config.max_2d_position_embeddings, config.hidden_size)
|
| 58 |
+
self.w_position_embeddings = nn.Embedding(config.max_2d_position_embeddings, config.hidden_size)
|
| 59 |
+
self.token_type_embeddings = nn.Embedding(config.type_vocab_size, config.hidden_size)
|
| 60 |
+
|
| 61 |
+
self.LayerNorm = LayoutLMLayerNorm(config.hidden_size, eps=config.layer_norm_eps)
|
| 62 |
+
self.dropout = nn.Dropout(config.hidden_dropout_prob)
|
| 63 |
+
|
| 64 |
+
self.register_buffer(
|
| 65 |
+
"position_ids", torch.arange(config.max_position_embeddings).expand((1, -1)), persistent=False
|
| 66 |
+
)
|
| 67 |
+
|
| 68 |
+
def forward(
|
| 69 |
+
self,
|
| 70 |
+
input_ids=None,
|
| 71 |
+
bbox=None,
|
| 72 |
+
token_type_ids=None,
|
| 73 |
+
position_ids=None,
|
| 74 |
+
inputs_embeds=None,
|
| 75 |
+
):
|
| 76 |
+
if input_ids is not None:
|
| 77 |
+
input_shape = input_ids.size()
|
| 78 |
+
else:
|
| 79 |
+
input_shape = inputs_embeds.size()[:-1]
|
| 80 |
+
|
| 81 |
+
seq_length = input_shape[1]
|
| 82 |
+
|
| 83 |
+
device = input_ids.device if input_ids is not None else inputs_embeds.device
|
| 84 |
+
|
| 85 |
+
if position_ids is None:
|
| 86 |
+
position_ids = self.position_ids[:, :seq_length]
|
| 87 |
+
|
| 88 |
+
if token_type_ids is None:
|
| 89 |
+
token_type_ids = torch.zeros(input_shape, dtype=torch.long, device=device)
|
| 90 |
+
|
| 91 |
+
if inputs_embeds is None:
|
| 92 |
+
inputs_embeds = self.word_embeddings(input_ids)
|
| 93 |
+
|
| 94 |
+
words_embeddings = inputs_embeds
|
| 95 |
+
position_embeddings = self.position_embeddings(position_ids)
|
| 96 |
+
try:
|
| 97 |
+
left_position_embeddings = self.x_position_embeddings(bbox[:, :, 0])
|
| 98 |
+
upper_position_embeddings = self.y_position_embeddings(bbox[:, :, 1])
|
| 99 |
+
right_position_embeddings = self.x_position_embeddings(bbox[:, :, 2])
|
| 100 |
+
lower_position_embeddings = self.y_position_embeddings(bbox[:, :, 3])
|
| 101 |
+
except IndexError as e:
|
| 102 |
+
raise IndexError("The `bbox`coordinate values should be within 0-1000 range.") from e
|
| 103 |
+
|
| 104 |
+
h_position_embeddings = self.h_position_embeddings(bbox[:, :, 3] - bbox[:, :, 1])
|
| 105 |
+
w_position_embeddings = self.w_position_embeddings(bbox[:, :, 2] - bbox[:, :, 0])
|
| 106 |
+
token_type_embeddings = self.token_type_embeddings(token_type_ids)
|
| 107 |
+
|
| 108 |
+
embeddings = (
|
| 109 |
+
words_embeddings
|
| 110 |
+
+ position_embeddings
|
| 111 |
+
+ left_position_embeddings
|
| 112 |
+
+ upper_position_embeddings
|
| 113 |
+
+ right_position_embeddings
|
| 114 |
+
+ lower_position_embeddings
|
| 115 |
+
+ h_position_embeddings
|
| 116 |
+
+ w_position_embeddings
|
| 117 |
+
+ token_type_embeddings
|
| 118 |
+
)
|
| 119 |
+
embeddings = self.LayerNorm(embeddings)
|
| 120 |
+
embeddings = self.dropout(embeddings)
|
| 121 |
+
return embeddings
|
| 122 |
+
|
| 123 |
+
|
| 124 |
+
# Copied from transformers.models.align.modeling_align.eager_attention_forward
|
| 125 |
+
def eager_attention_forward(
|
| 126 |
+
module: nn.Module,
|
| 127 |
+
query: torch.Tensor,
|
| 128 |
+
key: torch.Tensor,
|
| 129 |
+
value: torch.Tensor,
|
| 130 |
+
attention_mask: torch.Tensor | None,
|
| 131 |
+
scaling: float,
|
| 132 |
+
dropout: float = 0.0,
|
| 133 |
+
**kwargs,
|
| 134 |
+
):
|
| 135 |
+
attn_weights = torch.matmul(query, key.transpose(2, 3)) * scaling
|
| 136 |
+
if attention_mask is not None:
|
| 137 |
+
attn_weights = attn_weights + attention_mask
|
| 138 |
+
|
| 139 |
+
attn_weights = nn.functional.softmax(attn_weights, dim=-1, dtype=torch.float32).to(query.dtype)
|
| 140 |
+
attn_weights = nn.functional.dropout(attn_weights, p=dropout, training=module.training)
|
| 141 |
+
|
| 142 |
+
attn_output = torch.matmul(attn_weights, value)
|
| 143 |
+
attn_output = attn_output.transpose(1, 2).contiguous()
|
| 144 |
+
return attn_output, attn_weights
|
| 145 |
+
|
| 146 |
+
|
| 147 |
+
# Copied from transformers.models.align.modeling_align.AlignTextSelfAttention with AlignText->LayoutLM
|
| 148 |
+
class LayoutLMSelfAttention(nn.Module):
|
| 149 |
+
def __init__(self, config):
|
| 150 |
+
super().__init__()
|
| 151 |
+
if config.hidden_size % config.num_attention_heads != 0 and not hasattr(config, "embedding_size"):
|
| 152 |
+
raise ValueError(
|
| 153 |
+
f"The hidden size ({config.hidden_size}) is not a multiple of the number of attention "
|
| 154 |
+
f"heads ({config.num_attention_heads})"
|
| 155 |
+
)
|
| 156 |
+
|
| 157 |
+
self.config = config
|
| 158 |
+
self.num_attention_heads = config.num_attention_heads
|
| 159 |
+
self.attention_head_size = int(config.hidden_size / config.num_attention_heads)
|
| 160 |
+
self.all_head_size = self.num_attention_heads * self.attention_head_size
|
| 161 |
+
|
| 162 |
+
self.query = nn.Linear(config.hidden_size, self.all_head_size)
|
| 163 |
+
self.key = nn.Linear(config.hidden_size, self.all_head_size)
|
| 164 |
+
self.value = nn.Linear(config.hidden_size, self.all_head_size)
|
| 165 |
+
|
| 166 |
+
self.dropout = nn.Dropout(config.attention_probs_dropout_prob)
|
| 167 |
+
self.attention_dropout = config.attention_probs_dropout_prob
|
| 168 |
+
self.scaling = self.attention_head_size**-0.5
|
| 169 |
+
|
| 170 |
+
def forward(
|
| 171 |
+
self,
|
| 172 |
+
hidden_states: torch.Tensor,
|
| 173 |
+
attention_mask: torch.FloatTensor | None = None,
|
| 174 |
+
**kwargs: Unpack[TransformersKwargs],
|
| 175 |
+
) -> tuple[torch.Tensor, torch.Tensor | None]:
|
| 176 |
+
input_shape = hidden_states.shape[:-1]
|
| 177 |
+
hidden_shape = (*input_shape, -1, self.attention_head_size)
|
| 178 |
+
|
| 179 |
+
query_states = self.query(hidden_states).view(hidden_shape).transpose(1, 2)
|
| 180 |
+
key_states = self.key(hidden_states).view(hidden_shape).transpose(1, 2)
|
| 181 |
+
value_states = self.value(hidden_states).view(hidden_shape).transpose(1, 2)
|
| 182 |
+
|
| 183 |
+
attention_interface: Callable = ALL_ATTENTION_FUNCTIONS.get_interface(
|
| 184 |
+
self.config._attn_implementation, eager_attention_forward
|
| 185 |
+
)
|
| 186 |
+
|
| 187 |
+
attn_output, attn_weights = attention_interface(
|
| 188 |
+
self,
|
| 189 |
+
query_states,
|
| 190 |
+
key_states,
|
| 191 |
+
value_states,
|
| 192 |
+
attention_mask,
|
| 193 |
+
dropout=0.0 if not self.training else self.attention_dropout,
|
| 194 |
+
scaling=self.scaling,
|
| 195 |
+
**kwargs,
|
| 196 |
+
)
|
| 197 |
+
|
| 198 |
+
attn_output = attn_output.reshape(*input_shape, -1).contiguous()
|
| 199 |
+
return attn_output, attn_weights
|
| 200 |
+
|
| 201 |
+
|
| 202 |
+
# Copied from transformers.models.bert.modeling_bert.BertSelfOutput with Bert->LayoutLM
|
| 203 |
+
class LayoutLMSelfOutput(nn.Module):
|
| 204 |
+
def __init__(self, config):
|
| 205 |
+
super().__init__()
|
| 206 |
+
self.dense = nn.Linear(config.hidden_size, config.hidden_size)
|
| 207 |
+
self.LayerNorm = nn.LayerNorm(config.hidden_size, eps=config.layer_norm_eps)
|
| 208 |
+
self.dropout = nn.Dropout(config.hidden_dropout_prob)
|
| 209 |
+
|
| 210 |
+
def forward(self, hidden_states: torch.Tensor, input_tensor: torch.Tensor) -> torch.Tensor:
|
| 211 |
+
hidden_states = self.dense(hidden_states)
|
| 212 |
+
hidden_states = self.dropout(hidden_states)
|
| 213 |
+
hidden_states = self.LayerNorm(hidden_states + input_tensor)
|
| 214 |
+
return hidden_states
|
| 215 |
+
|
| 216 |
+
|
| 217 |
+
# Copied from transformers.models.align.modeling_align.AlignTextAttention with AlignText->LayoutLM
|
| 218 |
+
class LayoutLMAttention(nn.Module):
|
| 219 |
+
def __init__(self, config):
|
| 220 |
+
super().__init__()
|
| 221 |
+
self.self = LayoutLMSelfAttention(config)
|
| 222 |
+
self.output = LayoutLMSelfOutput(config)
|
| 223 |
+
|
| 224 |
+
def forward(
|
| 225 |
+
self,
|
| 226 |
+
hidden_states: torch.Tensor,
|
| 227 |
+
attention_mask: torch.FloatTensor | None = None,
|
| 228 |
+
**kwargs: Unpack[TransformersKwargs],
|
| 229 |
+
) -> torch.Tensor:
|
| 230 |
+
residual = hidden_states
|
| 231 |
+
hidden_states, _ = self.self(
|
| 232 |
+
hidden_states,
|
| 233 |
+
attention_mask=attention_mask,
|
| 234 |
+
**kwargs,
|
| 235 |
+
)
|
| 236 |
+
hidden_states = self.output(hidden_states, residual)
|
| 237 |
+
return hidden_states
|
| 238 |
+
|
| 239 |
+
|
| 240 |
+
# Copied from transformers.models.bert.modeling_bert.BertIntermediate
|
| 241 |
+
class LayoutLMIntermediate(nn.Module):
|
| 242 |
+
def __init__(self, config):
|
| 243 |
+
super().__init__()
|
| 244 |
+
self.dense = nn.Linear(config.hidden_size, config.intermediate_size)
|
| 245 |
+
if isinstance(config.hidden_act, str):
|
| 246 |
+
self.intermediate_act_fn = ACT2FN[config.hidden_act]
|
| 247 |
+
else:
|
| 248 |
+
self.intermediate_act_fn = config.hidden_act
|
| 249 |
+
|
| 250 |
+
def forward(self, hidden_states: torch.Tensor) -> torch.Tensor:
|
| 251 |
+
hidden_states = self.dense(hidden_states)
|
| 252 |
+
hidden_states = self.intermediate_act_fn(hidden_states)
|
| 253 |
+
return hidden_states
|
| 254 |
+
|
| 255 |
+
|
| 256 |
+
# Copied from transformers.models.bert.modeling_bert.BertOutput with Bert->LayoutLM
|
| 257 |
+
class LayoutLMOutput(nn.Module):
|
| 258 |
+
def __init__(self, config):
|
| 259 |
+
super().__init__()
|
| 260 |
+
self.dense = nn.Linear(config.intermediate_size, config.hidden_size)
|
| 261 |
+
self.LayerNorm = nn.LayerNorm(config.hidden_size, eps=config.layer_norm_eps)
|
| 262 |
+
self.dropout = nn.Dropout(config.hidden_dropout_prob)
|
| 263 |
+
|
| 264 |
+
def forward(self, hidden_states: torch.Tensor, input_tensor: torch.Tensor) -> torch.Tensor:
|
| 265 |
+
hidden_states = self.dense(hidden_states)
|
| 266 |
+
hidden_states = self.dropout(hidden_states)
|
| 267 |
+
hidden_states = self.LayerNorm(hidden_states + input_tensor)
|
| 268 |
+
return hidden_states
|
| 269 |
+
|
| 270 |
+
|
| 271 |
+
# Copied from transformers.models.align.modeling_align.AlignTextLayer with AlignText->LayoutLM
|
| 272 |
+
class LayoutLMLayer(GradientCheckpointingLayer):
|
| 273 |
+
def __init__(self, config):
|
| 274 |
+
super().__init__()
|
| 275 |
+
self.chunk_size_feed_forward = config.chunk_size_feed_forward
|
| 276 |
+
self.seq_len_dim = 1
|
| 277 |
+
self.attention = LayoutLMAttention(config)
|
| 278 |
+
self.intermediate = LayoutLMIntermediate(config)
|
| 279 |
+
self.output = LayoutLMOutput(config)
|
| 280 |
+
|
| 281 |
+
def forward(
|
| 282 |
+
self,
|
| 283 |
+
hidden_states: torch.Tensor,
|
| 284 |
+
attention_mask: torch.FloatTensor | None = None,
|
| 285 |
+
**kwargs: Unpack[TransformersKwargs],
|
| 286 |
+
) -> torch.Tensor:
|
| 287 |
+
hidden_states = self.attention(
|
| 288 |
+
hidden_states,
|
| 289 |
+
attention_mask=attention_mask,
|
| 290 |
+
**kwargs,
|
| 291 |
+
)
|
| 292 |
+
|
| 293 |
+
hidden_states = apply_chunking_to_forward(
|
| 294 |
+
self.feed_forward_chunk, self.chunk_size_feed_forward, self.seq_len_dim, hidden_states
|
| 295 |
+
)
|
| 296 |
+
|
| 297 |
+
return hidden_states
|
| 298 |
+
|
| 299 |
+
def feed_forward_chunk(self, attention_output):
|
| 300 |
+
intermediate_output = self.intermediate(attention_output)
|
| 301 |
+
layer_output = self.output(intermediate_output, attention_output)
|
| 302 |
+
return layer_output
|
| 303 |
+
|
| 304 |
+
|
| 305 |
+
# Copied from transformers.models.align.modeling_align.AlignTextEncoder with AlignText->LayoutLM
|
| 306 |
+
class LayoutLMEncoder(nn.Module):
|
| 307 |
+
def __init__(self, config):
|
| 308 |
+
super().__init__()
|
| 309 |
+
self.config = config
|
| 310 |
+
self.layer = nn.ModuleList([LayoutLMLayer(config) for i in range(config.num_hidden_layers)])
|
| 311 |
+
self.gradient_checkpointing = False
|
| 312 |
+
|
| 313 |
+
def forward(
|
| 314 |
+
self,
|
| 315 |
+
hidden_states: torch.Tensor,
|
| 316 |
+
attention_mask: torch.FloatTensor | None = None,
|
| 317 |
+
**kwargs: Unpack[TransformersKwargs],
|
| 318 |
+
) -> BaseModelOutput:
|
| 319 |
+
for layer_module in self.layer:
|
| 320 |
+
hidden_states = layer_module(
|
| 321 |
+
hidden_states,
|
| 322 |
+
attention_mask,
|
| 323 |
+
**kwargs,
|
| 324 |
+
)
|
| 325 |
+
|
| 326 |
+
return BaseModelOutput(
|
| 327 |
+
last_hidden_state=hidden_states,
|
| 328 |
+
)
|
| 329 |
+
|
| 330 |
+
|
| 331 |
+
# Copied from transformers.models.bert.modeling_bert.BertPooler
|
| 332 |
+
class LayoutLMPooler(nn.Module):
|
| 333 |
+
def __init__(self, config):
|
| 334 |
+
super().__init__()
|
| 335 |
+
self.dense = nn.Linear(config.hidden_size, config.hidden_size)
|
| 336 |
+
self.activation = nn.Tanh()
|
| 337 |
+
|
| 338 |
+
def forward(self, hidden_states: torch.Tensor) -> torch.Tensor:
|
| 339 |
+
# We "pool" the model by simply taking the hidden state corresponding
|
| 340 |
+
# to the first token.
|
| 341 |
+
first_token_tensor = hidden_states[:, 0]
|
| 342 |
+
pooled_output = self.dense(first_token_tensor)
|
| 343 |
+
pooled_output = self.activation(pooled_output)
|
| 344 |
+
return pooled_output
|
| 345 |
+
|
| 346 |
+
|
| 347 |
+
# Copied from transformers.models.bert.modeling_bert.BertPredictionHeadTransform with Bert->LayoutLM
|
| 348 |
+
class LayoutLMPredictionHeadTransform(nn.Module):
|
| 349 |
+
def __init__(self, config):
|
| 350 |
+
super().__init__()
|
| 351 |
+
self.dense = nn.Linear(config.hidden_size, config.hidden_size)
|
| 352 |
+
if isinstance(config.hidden_act, str):
|
| 353 |
+
self.transform_act_fn = ACT2FN[config.hidden_act]
|
| 354 |
+
else:
|
| 355 |
+
self.transform_act_fn = config.hidden_act
|
| 356 |
+
self.LayerNorm = nn.LayerNorm(config.hidden_size, eps=config.layer_norm_eps)
|
| 357 |
+
|
| 358 |
+
def forward(self, hidden_states: torch.Tensor) -> torch.Tensor:
|
| 359 |
+
hidden_states = self.dense(hidden_states)
|
| 360 |
+
hidden_states = self.transform_act_fn(hidden_states)
|
| 361 |
+
hidden_states = self.LayerNorm(hidden_states)
|
| 362 |
+
return hidden_states
|
| 363 |
+
|
| 364 |
+
|
| 365 |
+
# Copied from transformers.models.bert.modeling_bert.BertLMPredictionHead with Bert->LayoutLM
|
| 366 |
+
class LayoutLMLMPredictionHead(nn.Module):
|
| 367 |
+
def __init__(self, config):
|
| 368 |
+
super().__init__()
|
| 369 |
+
self.transform = LayoutLMPredictionHeadTransform(config)
|
| 370 |
+
|
| 371 |
+
# The output weights are the same as the input embeddings, but there is
|
| 372 |
+
# an output-only bias for each token.
|
| 373 |
+
self.decoder = nn.Linear(config.hidden_size, config.vocab_size, bias=True)
|
| 374 |
+
self.bias = nn.Parameter(torch.zeros(config.vocab_size))
|
| 375 |
+
|
| 376 |
+
def forward(self, hidden_states):
|
| 377 |
+
hidden_states = self.transform(hidden_states)
|
| 378 |
+
hidden_states = self.decoder(hidden_states)
|
| 379 |
+
return hidden_states
|
| 380 |
+
|
| 381 |
+
|
| 382 |
+
# Copied from transformers.models.bert.modeling_bert.BertOnlyMLMHead with Bert->LayoutLM
|
| 383 |
+
class LayoutLMOnlyMLMHead(nn.Module):
|
| 384 |
+
def __init__(self, config):
|
| 385 |
+
super().__init__()
|
| 386 |
+
self.predictions = LayoutLMLMPredictionHead(config)
|
| 387 |
+
|
| 388 |
+
def forward(self, sequence_output: torch.Tensor) -> torch.Tensor:
|
| 389 |
+
prediction_scores = self.predictions(sequence_output)
|
| 390 |
+
return prediction_scores
|
| 391 |
+
|
| 392 |
+
|
| 393 |
+
@auto_docstring
|
| 394 |
+
class LayoutLMPreTrainedModel(PreTrainedModel):
|
| 395 |
+
config: LayoutLMConfig
|
| 396 |
+
base_model_prefix = "layoutlm"
|
| 397 |
+
supports_gradient_checkpointing = True
|
| 398 |
+
_can_record_outputs = {
|
| 399 |
+
"hidden_states": LayoutLMLayer,
|
| 400 |
+
"attentions": LayoutLMSelfAttention,
|
| 401 |
+
}
|
| 402 |
+
|
| 403 |
+
@torch.no_grad()
|
| 404 |
+
def _init_weights(self, module):
|
| 405 |
+
"""Initialize the weights"""
|
| 406 |
+
super()._init_weights(module)
|
| 407 |
+
if isinstance(module, LayoutLMLMPredictionHead):
|
| 408 |
+
init.zeros_(module.bias)
|
| 409 |
+
elif isinstance(module, LayoutLMEmbeddings):
|
| 410 |
+
init.copy_(module.position_ids, torch.arange(module.position_ids.shape[-1]).expand((1, -1)))
|
| 411 |
+
|
| 412 |
+
|
| 413 |
+
@auto_docstring
|
| 414 |
+
class LayoutLMModel(LayoutLMPreTrainedModel):
|
| 415 |
+
def __init__(self, config):
|
| 416 |
+
super().__init__(config)
|
| 417 |
+
self.config = config
|
| 418 |
+
|
| 419 |
+
self.embeddings = LayoutLMEmbeddings(config)
|
| 420 |
+
self.encoder = LayoutLMEncoder(config)
|
| 421 |
+
self.pooler = LayoutLMPooler(config)
|
| 422 |
+
|
| 423 |
+
# Initialize weights and apply final processing
|
| 424 |
+
self.post_init()
|
| 425 |
+
|
| 426 |
+
def get_input_embeddings(self):
|
| 427 |
+
return self.embeddings.word_embeddings
|
| 428 |
+
|
| 429 |
+
def set_input_embeddings(self, value):
|
| 430 |
+
self.embeddings.word_embeddings = value
|
| 431 |
+
|
| 432 |
+
@merge_with_config_defaults
|
| 433 |
+
@capture_outputs
|
| 434 |
+
@auto_docstring
|
| 435 |
+
def forward(
|
| 436 |
+
self,
|
| 437 |
+
input_ids: torch.LongTensor | None = None,
|
| 438 |
+
bbox: torch.LongTensor | None = None,
|
| 439 |
+
attention_mask: torch.FloatTensor | None = None,
|
| 440 |
+
token_type_ids: torch.LongTensor | None = None,
|
| 441 |
+
position_ids: torch.LongTensor | None = None,
|
| 442 |
+
inputs_embeds: torch.FloatTensor | None = None,
|
| 443 |
+
**kwargs: Unpack[TransformersKwargs],
|
| 444 |
+
) -> tuple | BaseModelOutputWithPooling:
|
| 445 |
+
r"""
|
| 446 |
+
bbox (`torch.LongTensor` of shape `(batch_size, sequence_length, 4)`, *optional*):
|
| 447 |
+
Bounding boxes of each input sequence tokens. Selected in the range `[0,
|
| 448 |
+
config.max_2d_position_embeddings-1]`. Each bounding box should be a normalized version in (x0, y0, x1, y1)
|
| 449 |
+
format, where (x0, y0) corresponds to the position of the upper left corner in the bounding box, and (x1,
|
| 450 |
+
y1) represents the position of the lower right corner. See [Overview](#Overview) for normalization.
|
| 451 |
+
|
| 452 |
+
Examples:
|
| 453 |
+
|
| 454 |
+
```python
|
| 455 |
+
>>> from transformers import AutoTokenizer, LayoutLMModel
|
| 456 |
+
>>> import torch
|
| 457 |
+
|
| 458 |
+
>>> tokenizer = AutoTokenizer.from_pretrained("microsoft/layoutlm-base-uncased")
|
| 459 |
+
>>> model = LayoutLMModel.from_pretrained("microsoft/layoutlm-base-uncased")
|
| 460 |
+
|
| 461 |
+
>>> words = ["Hello", "world"]
|
| 462 |
+
>>> normalized_word_boxes = [637, 773, 693, 782], [698, 773, 733, 782]
|
| 463 |
+
|
| 464 |
+
>>> token_boxes = []
|
| 465 |
+
>>> for word, box in zip(words, normalized_word_boxes):
|
| 466 |
+
... word_tokens = tokenizer.tokenize(word)
|
| 467 |
+
... token_boxes.extend([box] * len(word_tokens))
|
| 468 |
+
>>> # add bounding boxes of cls + sep tokens
|
| 469 |
+
>>> token_boxes = [[0, 0, 0, 0]] + token_boxes + [[1000, 1000, 1000, 1000]]
|
| 470 |
+
|
| 471 |
+
>>> encoding = tokenizer(" ".join(words), return_tensors="pt")
|
| 472 |
+
>>> input_ids = encoding["input_ids"]
|
| 473 |
+
>>> attention_mask = encoding["attention_mask"]
|
| 474 |
+
>>> token_type_ids = encoding["token_type_ids"]
|
| 475 |
+
>>> bbox = torch.tensor([token_boxes])
|
| 476 |
+
|
| 477 |
+
>>> outputs = model(
|
| 478 |
+
... input_ids=input_ids, bbox=bbox, attention_mask=attention_mask, token_type_ids=token_type_ids
|
| 479 |
+
... )
|
| 480 |
+
|
| 481 |
+
>>> last_hidden_states = outputs.last_hidden_state
|
| 482 |
+
```"""
|
| 483 |
+
if input_ids is not None and inputs_embeds is not None:
|
| 484 |
+
raise ValueError("You cannot specify both input_ids and inputs_embeds at the same time")
|
| 485 |
+
elif input_ids is not None:
|
| 486 |
+
self.warn_if_padding_and_no_attention_mask(input_ids, attention_mask)
|
| 487 |
+
input_shape = input_ids.size()
|
| 488 |
+
elif inputs_embeds is not None:
|
| 489 |
+
input_shape = inputs_embeds.size()[:-1]
|
| 490 |
+
else:
|
| 491 |
+
raise ValueError("You have to specify either input_ids or inputs_embeds")
|
| 492 |
+
|
| 493 |
+
device = input_ids.device if input_ids is not None else inputs_embeds.device
|
| 494 |
+
|
| 495 |
+
if attention_mask is None:
|
| 496 |
+
attention_mask = torch.ones(input_shape, device=device)
|
| 497 |
+
if token_type_ids is None:
|
| 498 |
+
token_type_ids = torch.zeros(input_shape, dtype=torch.long, device=device)
|
| 499 |
+
|
| 500 |
+
if bbox is None:
|
| 501 |
+
bbox = torch.zeros(input_shape + (4,), dtype=torch.long, device=device)
|
| 502 |
+
|
| 503 |
+
extended_attention_mask = attention_mask.unsqueeze(1).unsqueeze(2)
|
| 504 |
+
|
| 505 |
+
extended_attention_mask = extended_attention_mask.to(dtype=self.dtype)
|
| 506 |
+
extended_attention_mask = (1.0 - extended_attention_mask) * torch.finfo(self.dtype).min
|
| 507 |
+
|
| 508 |
+
embedding_output = self.embeddings(
|
| 509 |
+
input_ids=input_ids,
|
| 510 |
+
bbox=bbox,
|
| 511 |
+
position_ids=position_ids,
|
| 512 |
+
token_type_ids=token_type_ids,
|
| 513 |
+
inputs_embeds=inputs_embeds,
|
| 514 |
+
)
|
| 515 |
+
encoder_outputs = self.encoder(
|
| 516 |
+
embedding_output,
|
| 517 |
+
extended_attention_mask,
|
| 518 |
+
**kwargs,
|
| 519 |
+
)
|
| 520 |
+
sequence_output = encoder_outputs[0]
|
| 521 |
+
pooled_output = self.pooler(sequence_output)
|
| 522 |
+
|
| 523 |
+
return BaseModelOutputWithPooling(
|
| 524 |
+
last_hidden_state=sequence_output,
|
| 525 |
+
pooler_output=pooled_output,
|
| 526 |
+
)
|
| 527 |
+
|
| 528 |
+
|
| 529 |
+
@auto_docstring
|
| 530 |
+
class LayoutLMForMaskedLM(LayoutLMPreTrainedModel):
|
| 531 |
+
_tied_weights_keys = {
|
| 532 |
+
"cls.predictions.decoder.bias": "cls.predictions.bias",
|
| 533 |
+
"cls.predictions.decoder.weight": "layoutlm.embeddings.word_embeddings.weight",
|
| 534 |
+
}
|
| 535 |
+
|
| 536 |
+
def __init__(self, config):
|
| 537 |
+
super().__init__(config)
|
| 538 |
+
|
| 539 |
+
self.layoutlm = LayoutLMModel(config)
|
| 540 |
+
self.cls = LayoutLMOnlyMLMHead(config)
|
| 541 |
+
|
| 542 |
+
# Initialize weights and apply final processing
|
| 543 |
+
self.post_init()
|
| 544 |
+
|
| 545 |
+
def get_input_embeddings(self):
|
| 546 |
+
return self.layoutlm.embeddings.word_embeddings
|
| 547 |
+
|
| 548 |
+
def get_output_embeddings(self):
|
| 549 |
+
return self.cls.predictions.decoder
|
| 550 |
+
|
| 551 |
+
def set_output_embeddings(self, new_embeddings):
|
| 552 |
+
self.cls.predictions.decoder = new_embeddings
|
| 553 |
+
self.cls.predictions.bias = new_embeddings.bias
|
| 554 |
+
|
| 555 |
+
@can_return_tuple
|
| 556 |
+
@auto_docstring
|
| 557 |
+
def forward(
|
| 558 |
+
self,
|
| 559 |
+
input_ids: torch.LongTensor | None = None,
|
| 560 |
+
bbox: torch.LongTensor | None = None,
|
| 561 |
+
attention_mask: torch.FloatTensor | None = None,
|
| 562 |
+
token_type_ids: torch.LongTensor | None = None,
|
| 563 |
+
position_ids: torch.LongTensor | None = None,
|
| 564 |
+
inputs_embeds: torch.FloatTensor | None = None,
|
| 565 |
+
labels: torch.LongTensor | None = None,
|
| 566 |
+
**kwargs: Unpack[TransformersKwargs],
|
| 567 |
+
) -> tuple | MaskedLMOutput:
|
| 568 |
+
r"""
|
| 569 |
+
bbox (`torch.LongTensor` of shape `(batch_size, sequence_length, 4)`, *optional*):
|
| 570 |
+
Bounding boxes of each input sequence tokens. Selected in the range `[0,
|
| 571 |
+
config.max_2d_position_embeddings-1]`. Each bounding box should be a normalized version in (x0, y0, x1, y1)
|
| 572 |
+
format, where (x0, y0) corresponds to the position of the upper left corner in the bounding box, and (x1,
|
| 573 |
+
y1) represents the position of the lower right corner. See [Overview](#Overview) for normalization.
|
| 574 |
+
labels (`torch.LongTensor` of shape `(batch_size, sequence_length)`, *optional*):
|
| 575 |
+
Labels for computing the masked language modeling loss. Indices should be in `[-100, 0, ...,
|
| 576 |
+
config.vocab_size]` (see `input_ids` docstring) Tokens with indices set to `-100` are ignored (masked), the
|
| 577 |
+
loss is only computed for the tokens with labels in `[0, ..., config.vocab_size]`
|
| 578 |
+
|
| 579 |
+
Examples:
|
| 580 |
+
|
| 581 |
+
```python
|
| 582 |
+
>>> from transformers import AutoTokenizer, LayoutLMForMaskedLM
|
| 583 |
+
>>> import torch
|
| 584 |
+
|
| 585 |
+
>>> tokenizer = AutoTokenizer.from_pretrained("microsoft/layoutlm-base-uncased")
|
| 586 |
+
>>> model = LayoutLMForMaskedLM.from_pretrained("microsoft/layoutlm-base-uncased")
|
| 587 |
+
|
| 588 |
+
>>> words = ["Hello", "[MASK]"]
|
| 589 |
+
>>> normalized_word_boxes = [637, 773, 693, 782], [698, 773, 733, 782]
|
| 590 |
+
|
| 591 |
+
>>> token_boxes = []
|
| 592 |
+
>>> for word, box in zip(words, normalized_word_boxes):
|
| 593 |
+
... word_tokens = tokenizer.tokenize(word)
|
| 594 |
+
... token_boxes.extend([box] * len(word_tokens))
|
| 595 |
+
>>> # add bounding boxes of cls + sep tokens
|
| 596 |
+
>>> token_boxes = [[0, 0, 0, 0]] + token_boxes + [[1000, 1000, 1000, 1000]]
|
| 597 |
+
|
| 598 |
+
>>> encoding = tokenizer(" ".join(words), return_tensors="pt")
|
| 599 |
+
>>> input_ids = encoding["input_ids"]
|
| 600 |
+
>>> attention_mask = encoding["attention_mask"]
|
| 601 |
+
>>> token_type_ids = encoding["token_type_ids"]
|
| 602 |
+
>>> bbox = torch.tensor([token_boxes])
|
| 603 |
+
|
| 604 |
+
>>> labels = tokenizer("Hello world", return_tensors="pt")["input_ids"]
|
| 605 |
+
|
| 606 |
+
>>> outputs = model(
|
| 607 |
+
... input_ids=input_ids,
|
| 608 |
+
... bbox=bbox,
|
| 609 |
+
... attention_mask=attention_mask,
|
| 610 |
+
... token_type_ids=token_type_ids,
|
| 611 |
+
... labels=labels,
|
| 612 |
+
... )
|
| 613 |
+
|
| 614 |
+
>>> loss = outputs.loss
|
| 615 |
+
```"""
|
| 616 |
+
outputs = self.layoutlm(
|
| 617 |
+
input_ids,
|
| 618 |
+
bbox,
|
| 619 |
+
attention_mask=attention_mask,
|
| 620 |
+
token_type_ids=token_type_ids,
|
| 621 |
+
position_ids=position_ids,
|
| 622 |
+
inputs_embeds=inputs_embeds,
|
| 623 |
+
**kwargs,
|
| 624 |
+
)
|
| 625 |
+
|
| 626 |
+
sequence_output = outputs[0]
|
| 627 |
+
prediction_scores = self.cls(sequence_output)
|
| 628 |
+
|
| 629 |
+
masked_lm_loss = None
|
| 630 |
+
if labels is not None:
|
| 631 |
+
loss_fct = CrossEntropyLoss()
|
| 632 |
+
masked_lm_loss = loss_fct(
|
| 633 |
+
prediction_scores.view(-1, self.config.vocab_size),
|
| 634 |
+
labels.view(-1),
|
| 635 |
+
)
|
| 636 |
+
|
| 637 |
+
return MaskedLMOutput(
|
| 638 |
+
loss=masked_lm_loss,
|
| 639 |
+
logits=prediction_scores,
|
| 640 |
+
hidden_states=outputs.hidden_states,
|
| 641 |
+
attentions=outputs.attentions,
|
| 642 |
+
)
|
| 643 |
+
|
| 644 |
+
|
| 645 |
+
@auto_docstring(
|
| 646 |
+
custom_intro="""
|
| 647 |
+
LayoutLM Model with a sequence classification head on top (a linear layer on top of the pooled output) e.g. for
|
| 648 |
+
document image classification tasks such as the [RVL-CDIP](https://www.cs.cmu.edu/~aharley/rvl-cdip/) dataset.
|
| 649 |
+
"""
|
| 650 |
+
)
|
| 651 |
+
class LayoutLMForSequenceClassification(LayoutLMPreTrainedModel):
|
| 652 |
+
def __init__(self, config):
|
| 653 |
+
super().__init__(config)
|
| 654 |
+
self.num_labels = config.num_labels
|
| 655 |
+
self.layoutlm = LayoutLMModel(config)
|
| 656 |
+
self.dropout = nn.Dropout(config.hidden_dropout_prob)
|
| 657 |
+
self.classifier = nn.Linear(config.hidden_size, config.num_labels)
|
| 658 |
+
|
| 659 |
+
# Initialize weights and apply final processing
|
| 660 |
+
self.post_init()
|
| 661 |
+
|
| 662 |
+
def get_input_embeddings(self):
|
| 663 |
+
return self.layoutlm.embeddings.word_embeddings
|
| 664 |
+
|
| 665 |
+
@can_return_tuple
|
| 666 |
+
@auto_docstring
|
| 667 |
+
def forward(
|
| 668 |
+
self,
|
| 669 |
+
input_ids: torch.LongTensor | None = None,
|
| 670 |
+
bbox: torch.LongTensor | None = None,
|
| 671 |
+
attention_mask: torch.FloatTensor | None = None,
|
| 672 |
+
token_type_ids: torch.LongTensor | None = None,
|
| 673 |
+
position_ids: torch.LongTensor | None = None,
|
| 674 |
+
inputs_embeds: torch.FloatTensor | None = None,
|
| 675 |
+
labels: torch.LongTensor | None = None,
|
| 676 |
+
**kwargs: Unpack[TransformersKwargs],
|
| 677 |
+
) -> tuple | SequenceClassifierOutput:
|
| 678 |
+
r"""
|
| 679 |
+
bbox (`torch.LongTensor` of shape `(batch_size, sequence_length, 4)`, *optional*):
|
| 680 |
+
Bounding boxes of each input sequence tokens. Selected in the range `[0,
|
| 681 |
+
config.max_2d_position_embeddings-1]`. Each bounding box should be a normalized version in (x0, y0, x1, y1)
|
| 682 |
+
format, where (x0, y0) corresponds to the position of the upper left corner in the bounding box, and (x1,
|
| 683 |
+
y1) represents the position of the lower right corner. See [Overview](#Overview) for normalization.
|
| 684 |
+
labels (`torch.LongTensor` of shape `(batch_size,)`, *optional*):
|
| 685 |
+
Labels for computing the sequence classification/regression loss. Indices should be in `[0, ...,
|
| 686 |
+
config.num_labels - 1]`. If `config.num_labels == 1` a regression loss is computed (Mean-Square loss), If
|
| 687 |
+
`config.num_labels > 1` a classification loss is computed (Cross-Entropy).
|
| 688 |
+
|
| 689 |
+
Examples:
|
| 690 |
+
|
| 691 |
+
```python
|
| 692 |
+
>>> from transformers import AutoTokenizer, LayoutLMForSequenceClassification
|
| 693 |
+
>>> import torch
|
| 694 |
+
|
| 695 |
+
>>> tokenizer = AutoTokenizer.from_pretrained("microsoft/layoutlm-base-uncased")
|
| 696 |
+
>>> model = LayoutLMForSequenceClassification.from_pretrained("microsoft/layoutlm-base-uncased")
|
| 697 |
+
|
| 698 |
+
>>> words = ["Hello", "world"]
|
| 699 |
+
>>> normalized_word_boxes = [637, 773, 693, 782], [698, 773, 733, 782]
|
| 700 |
+
|
| 701 |
+
>>> token_boxes = []
|
| 702 |
+
>>> for word, box in zip(words, normalized_word_boxes):
|
| 703 |
+
... word_tokens = tokenizer.tokenize(word)
|
| 704 |
+
... token_boxes.extend([box] * len(word_tokens))
|
| 705 |
+
>>> # add bounding boxes of cls + sep tokens
|
| 706 |
+
>>> token_boxes = [[0, 0, 0, 0]] + token_boxes + [[1000, 1000, 1000, 1000]]
|
| 707 |
+
|
| 708 |
+
>>> encoding = tokenizer(" ".join(words), return_tensors="pt")
|
| 709 |
+
>>> input_ids = encoding["input_ids"]
|
| 710 |
+
>>> attention_mask = encoding["attention_mask"]
|
| 711 |
+
>>> token_type_ids = encoding["token_type_ids"]
|
| 712 |
+
>>> bbox = torch.tensor([token_boxes])
|
| 713 |
+
>>> sequence_label = torch.tensor([1])
|
| 714 |
+
|
| 715 |
+
>>> outputs = model(
|
| 716 |
+
... input_ids=input_ids,
|
| 717 |
+
... bbox=bbox,
|
| 718 |
+
... attention_mask=attention_mask,
|
| 719 |
+
... token_type_ids=token_type_ids,
|
| 720 |
+
... labels=sequence_label,
|
| 721 |
+
... )
|
| 722 |
+
|
| 723 |
+
>>> loss = outputs.loss
|
| 724 |
+
>>> logits = outputs.logits
|
| 725 |
+
```"""
|
| 726 |
+
outputs = self.layoutlm(
|
| 727 |
+
input_ids=input_ids,
|
| 728 |
+
bbox=bbox,
|
| 729 |
+
attention_mask=attention_mask,
|
| 730 |
+
token_type_ids=token_type_ids,
|
| 731 |
+
position_ids=position_ids,
|
| 732 |
+
inputs_embeds=inputs_embeds,
|
| 733 |
+
**kwargs,
|
| 734 |
+
)
|
| 735 |
+
|
| 736 |
+
pooled_output = outputs[1]
|
| 737 |
+
|
| 738 |
+
pooled_output = self.dropout(pooled_output)
|
| 739 |
+
logits = self.classifier(pooled_output)
|
| 740 |
+
|
| 741 |
+
loss = None
|
| 742 |
+
if labels is not None:
|
| 743 |
+
if self.config.problem_type is None:
|
| 744 |
+
if self.num_labels == 1:
|
| 745 |
+
self.config.problem_type = "regression"
|
| 746 |
+
elif self.num_labels > 1 and (labels.dtype == torch.long or labels.dtype == torch.int):
|
| 747 |
+
self.config.problem_type = "single_label_classification"
|
| 748 |
+
else:
|
| 749 |
+
self.config.problem_type = "multi_label_classification"
|
| 750 |
+
|
| 751 |
+
if self.config.problem_type == "regression":
|
| 752 |
+
loss_fct = MSELoss()
|
| 753 |
+
if self.num_labels == 1:
|
| 754 |
+
loss = loss_fct(logits.squeeze(), labels.squeeze())
|
| 755 |
+
else:
|
| 756 |
+
loss = loss_fct(logits, labels)
|
| 757 |
+
elif self.config.problem_type == "single_label_classification":
|
| 758 |
+
loss_fct = CrossEntropyLoss()
|
| 759 |
+
loss = loss_fct(logits.view(-1, self.num_labels), labels.view(-1))
|
| 760 |
+
elif self.config.problem_type == "multi_label_classification":
|
| 761 |
+
loss_fct = BCEWithLogitsLoss()
|
| 762 |
+
loss = loss_fct(logits, labels)
|
| 763 |
+
|
| 764 |
+
return SequenceClassifierOutput(
|
| 765 |
+
loss=loss,
|
| 766 |
+
logits=logits,
|
| 767 |
+
hidden_states=outputs.hidden_states,
|
| 768 |
+
attentions=outputs.attentions,
|
| 769 |
+
)
|
| 770 |
+
|
| 771 |
+
|
| 772 |
+
@auto_docstring(
|
| 773 |
+
custom_intro="""
|
| 774 |
+
LayoutLM Model with a token classification head on top (a linear layer on top of the hidden-states output) e.g. for
|
| 775 |
+
sequence labeling (information extraction) tasks such as the [FUNSD](https://guillaumejaume.github.io/FUNSD/)
|
| 776 |
+
dataset and the [SROIE](https://rrc.cvc.uab.es/?ch=13) dataset.
|
| 777 |
+
"""
|
| 778 |
+
)
|
| 779 |
+
class LayoutLMForTokenClassification(LayoutLMPreTrainedModel):
|
| 780 |
+
def __init__(self, config):
|
| 781 |
+
super().__init__(config)
|
| 782 |
+
self.num_labels = config.num_labels
|
| 783 |
+
self.layoutlm = LayoutLMModel(config)
|
| 784 |
+
self.dropout = nn.Dropout(config.hidden_dropout_prob)
|
| 785 |
+
self.classifier = nn.Linear(config.hidden_size, config.num_labels)
|
| 786 |
+
|
| 787 |
+
# Initialize weights and apply final processing
|
| 788 |
+
self.post_init()
|
| 789 |
+
|
| 790 |
+
def get_input_embeddings(self):
|
| 791 |
+
return self.layoutlm.embeddings.word_embeddings
|
| 792 |
+
|
| 793 |
+
@can_return_tuple
|
| 794 |
+
@auto_docstring
|
| 795 |
+
def forward(
|
| 796 |
+
self,
|
| 797 |
+
input_ids: torch.LongTensor | None = None,
|
| 798 |
+
bbox: torch.LongTensor | None = None,
|
| 799 |
+
attention_mask: torch.FloatTensor | None = None,
|
| 800 |
+
token_type_ids: torch.LongTensor | None = None,
|
| 801 |
+
position_ids: torch.LongTensor | None = None,
|
| 802 |
+
inputs_embeds: torch.FloatTensor | None = None,
|
| 803 |
+
labels: torch.LongTensor | None = None,
|
| 804 |
+
**kwargs: Unpack[TransformersKwargs],
|
| 805 |
+
) -> tuple | TokenClassifierOutput:
|
| 806 |
+
r"""
|
| 807 |
+
bbox (`torch.LongTensor` of shape `(batch_size, sequence_length, 4)`, *optional*):
|
| 808 |
+
Bounding boxes of each input sequence tokens. Selected in the range `[0,
|
| 809 |
+
config.max_2d_position_embeddings-1]`. Each bounding box should be a normalized version in (x0, y0, x1, y1)
|
| 810 |
+
format, where (x0, y0) corresponds to the position of the upper left corner in the bounding box, and (x1,
|
| 811 |
+
y1) represents the position of the lower right corner. See [Overview](#Overview) for normalization.
|
| 812 |
+
labels (`torch.LongTensor` of shape `(batch_size, sequence_length)`, *optional*):
|
| 813 |
+
Labels for computing the token classification loss. Indices should be in `[0, ..., config.num_labels - 1]`.
|
| 814 |
+
|
| 815 |
+
Examples:
|
| 816 |
+
|
| 817 |
+
```python
|
| 818 |
+
>>> from transformers import AutoTokenizer, LayoutLMForTokenClassification
|
| 819 |
+
>>> import torch
|
| 820 |
+
|
| 821 |
+
>>> tokenizer = AutoTokenizer.from_pretrained("microsoft/layoutlm-base-uncased")
|
| 822 |
+
>>> model = LayoutLMForTokenClassification.from_pretrained("microsoft/layoutlm-base-uncased")
|
| 823 |
+
|
| 824 |
+
>>> words = ["Hello", "world"]
|
| 825 |
+
>>> normalized_word_boxes = [637, 773, 693, 782], [698, 773, 733, 782]
|
| 826 |
+
|
| 827 |
+
>>> token_boxes = []
|
| 828 |
+
>>> for word, box in zip(words, normalized_word_boxes):
|
| 829 |
+
... word_tokens = tokenizer.tokenize(word)
|
| 830 |
+
... token_boxes.extend([box] * len(word_tokens))
|
| 831 |
+
>>> # add bounding boxes of cls + sep tokens
|
| 832 |
+
>>> token_boxes = [[0, 0, 0, 0]] + token_boxes + [[1000, 1000, 1000, 1000]]
|
| 833 |
+
|
| 834 |
+
>>> encoding = tokenizer(" ".join(words), return_tensors="pt")
|
| 835 |
+
>>> input_ids = encoding["input_ids"]
|
| 836 |
+
>>> attention_mask = encoding["attention_mask"]
|
| 837 |
+
>>> token_type_ids = encoding["token_type_ids"]
|
| 838 |
+
>>> bbox = torch.tensor([token_boxes])
|
| 839 |
+
>>> token_labels = torch.tensor([1, 1, 0, 0]).unsqueeze(0) # batch size of 1
|
| 840 |
+
|
| 841 |
+
>>> outputs = model(
|
| 842 |
+
... input_ids=input_ids,
|
| 843 |
+
... bbox=bbox,
|
| 844 |
+
... attention_mask=attention_mask,
|
| 845 |
+
... token_type_ids=token_type_ids,
|
| 846 |
+
... labels=token_labels,
|
| 847 |
+
... )
|
| 848 |
+
|
| 849 |
+
>>> loss = outputs.loss
|
| 850 |
+
>>> logits = outputs.logits
|
| 851 |
+
```"""
|
| 852 |
+
outputs = self.layoutlm(
|
| 853 |
+
input_ids=input_ids,
|
| 854 |
+
bbox=bbox,
|
| 855 |
+
attention_mask=attention_mask,
|
| 856 |
+
token_type_ids=token_type_ids,
|
| 857 |
+
position_ids=position_ids,
|
| 858 |
+
inputs_embeds=inputs_embeds,
|
| 859 |
+
**kwargs,
|
| 860 |
+
)
|
| 861 |
+
|
| 862 |
+
sequence_output = outputs[0]
|
| 863 |
+
|
| 864 |
+
sequence_output = self.dropout(sequence_output)
|
| 865 |
+
logits = self.classifier(sequence_output)
|
| 866 |
+
|
| 867 |
+
loss = None
|
| 868 |
+
if labels is not None:
|
| 869 |
+
loss_fct = CrossEntropyLoss()
|
| 870 |
+
loss = loss_fct(logits.view(-1, self.num_labels), labels.view(-1))
|
| 871 |
+
|
| 872 |
+
return TokenClassifierOutput(
|
| 873 |
+
loss=loss,
|
| 874 |
+
logits=logits,
|
| 875 |
+
hidden_states=outputs.hidden_states,
|
| 876 |
+
attentions=outputs.attentions,
|
| 877 |
+
)
|
| 878 |
+
|
| 879 |
+
|
| 880 |
+
@auto_docstring
|
| 881 |
+
class LayoutLMForQuestionAnswering(LayoutLMPreTrainedModel):
|
| 882 |
+
def __init__(self, config, has_visual_segment_embedding=True):
|
| 883 |
+
r"""
|
| 884 |
+
has_visual_segment_embedding (`bool`, *optional*, defaults to `True`):
|
| 885 |
+
Whether or not to add visual segment embeddings.
|
| 886 |
+
"""
|
| 887 |
+
super().__init__(config)
|
| 888 |
+
self.num_labels = config.num_labels
|
| 889 |
+
|
| 890 |
+
self.layoutlm = LayoutLMModel(config)
|
| 891 |
+
self.qa_outputs = nn.Linear(config.hidden_size, config.num_labels)
|
| 892 |
+
|
| 893 |
+
# Initialize weights and apply final processing
|
| 894 |
+
self.post_init()
|
| 895 |
+
|
| 896 |
+
def get_input_embeddings(self):
|
| 897 |
+
return self.layoutlm.embeddings.word_embeddings
|
| 898 |
+
|
| 899 |
+
@can_return_tuple
|
| 900 |
+
@auto_docstring
|
| 901 |
+
def forward(
|
| 902 |
+
self,
|
| 903 |
+
input_ids: torch.LongTensor | None = None,
|
| 904 |
+
bbox: torch.LongTensor | None = None,
|
| 905 |
+
attention_mask: torch.FloatTensor | None = None,
|
| 906 |
+
token_type_ids: torch.LongTensor | None = None,
|
| 907 |
+
position_ids: torch.LongTensor | None = None,
|
| 908 |
+
inputs_embeds: torch.FloatTensor | None = None,
|
| 909 |
+
start_positions: torch.LongTensor | None = None,
|
| 910 |
+
end_positions: torch.LongTensor | None = None,
|
| 911 |
+
**kwargs: Unpack[TransformersKwargs],
|
| 912 |
+
) -> tuple | QuestionAnsweringModelOutput:
|
| 913 |
+
r"""
|
| 914 |
+
bbox (`torch.LongTensor` of shape `(batch_size, sequence_length, 4)`, *optional*):
|
| 915 |
+
Bounding boxes of each input sequence tokens. Selected in the range `[0,
|
| 916 |
+
config.max_2d_position_embeddings-1]`. Each bounding box should be a normalized version in (x0, y0, x1, y1)
|
| 917 |
+
format, where (x0, y0) corresponds to the position of the upper left corner in the bounding box, and (x1,
|
| 918 |
+
y1) represents the position of the lower right corner. See [Overview](#Overview) for normalization.
|
| 919 |
+
|
| 920 |
+
Example:
|
| 921 |
+
|
| 922 |
+
In the example below, we prepare a question + context pair for the LayoutLM model. It will give us a prediction
|
| 923 |
+
of what it thinks the answer is (the span of the answer within the texts parsed from the image).
|
| 924 |
+
|
| 925 |
+
```python
|
| 926 |
+
>>> from transformers import AutoTokenizer, LayoutLMForQuestionAnswering
|
| 927 |
+
>>> from datasets import load_dataset
|
| 928 |
+
>>> import torch
|
| 929 |
+
|
| 930 |
+
>>> tokenizer = AutoTokenizer.from_pretrained("impira/layoutlm-document-qa", add_prefix_space=True)
|
| 931 |
+
>>> model = LayoutLMForQuestionAnswering.from_pretrained("impira/layoutlm-document-qa", revision="1e3ebac")
|
| 932 |
+
|
| 933 |
+
>>> dataset = load_dataset("nielsr/funsd", split="train")
|
| 934 |
+
>>> example = dataset[0]
|
| 935 |
+
>>> question = "what's his name?"
|
| 936 |
+
>>> words = example["words"]
|
| 937 |
+
>>> boxes = example["bboxes"]
|
| 938 |
+
|
| 939 |
+
>>> encoding = tokenizer(
|
| 940 |
+
... question.split(), words, is_split_into_words=True, return_token_type_ids=True, return_tensors="pt"
|
| 941 |
+
... )
|
| 942 |
+
>>> bbox = []
|
| 943 |
+
>>> for i, s, w in zip(encoding.input_ids[0], encoding.sequence_ids(0), encoding.word_ids(0)):
|
| 944 |
+
... if s == 1:
|
| 945 |
+
... bbox.append(boxes[w])
|
| 946 |
+
... elif i == tokenizer.sep_token_id:
|
| 947 |
+
... bbox.append([1000] * 4)
|
| 948 |
+
... else:
|
| 949 |
+
... bbox.append([0] * 4)
|
| 950 |
+
>>> encoding["bbox"] = torch.tensor([bbox])
|
| 951 |
+
|
| 952 |
+
>>> word_ids = encoding.word_ids(0)
|
| 953 |
+
>>> outputs = model(**encoding)
|
| 954 |
+
>>> loss = outputs.loss
|
| 955 |
+
>>> start_scores = outputs.start_logits
|
| 956 |
+
>>> end_scores = outputs.end_logits
|
| 957 |
+
>>> start, end = word_ids[start_scores.argmax(-1)], word_ids[end_scores.argmax(-1)]
|
| 958 |
+
>>> print(" ".join(words[start : end + 1]))
|
| 959 |
+
M. Hamann P. Harper, P. Martinez
|
| 960 |
+
```"""
|
| 961 |
+
|
| 962 |
+
outputs = self.layoutlm(
|
| 963 |
+
input_ids=input_ids,
|
| 964 |
+
bbox=bbox,
|
| 965 |
+
attention_mask=attention_mask,
|
| 966 |
+
token_type_ids=token_type_ids,
|
| 967 |
+
position_ids=position_ids,
|
| 968 |
+
inputs_embeds=inputs_embeds,
|
| 969 |
+
**kwargs,
|
| 970 |
+
)
|
| 971 |
+
|
| 972 |
+
sequence_output = outputs[0]
|
| 973 |
+
|
| 974 |
+
logits = self.qa_outputs(sequence_output)
|
| 975 |
+
start_logits, end_logits = logits.split(1, dim=-1)
|
| 976 |
+
start_logits = start_logits.squeeze(-1).contiguous()
|
| 977 |
+
end_logits = end_logits.squeeze(-1).contiguous()
|
| 978 |
+
|
| 979 |
+
total_loss = None
|
| 980 |
+
if start_positions is not None and end_positions is not None:
|
| 981 |
+
# If we are on multi-GPU, split add a dimension
|
| 982 |
+
if len(start_positions.size()) > 1:
|
| 983 |
+
start_positions = start_positions.squeeze(-1)
|
| 984 |
+
if len(end_positions.size()) > 1:
|
| 985 |
+
end_positions = end_positions.squeeze(-1)
|
| 986 |
+
# sometimes the start/end positions are outside our model inputs, we ignore these terms
|
| 987 |
+
ignored_index = start_logits.size(1)
|
| 988 |
+
start_positions = start_positions.clamp(0, ignored_index)
|
| 989 |
+
end_positions = end_positions.clamp(0, ignored_index)
|
| 990 |
+
|
| 991 |
+
loss_fct = CrossEntropyLoss(ignore_index=ignored_index)
|
| 992 |
+
start_loss = loss_fct(start_logits, start_positions)
|
| 993 |
+
end_loss = loss_fct(end_logits, end_positions)
|
| 994 |
+
total_loss = (start_loss + end_loss) / 2
|
| 995 |
+
|
| 996 |
+
return QuestionAnsweringModelOutput(
|
| 997 |
+
loss=total_loss,
|
| 998 |
+
start_logits=start_logits,
|
| 999 |
+
end_logits=end_logits,
|
| 1000 |
+
hidden_states=outputs.hidden_states,
|
| 1001 |
+
attentions=outputs.attentions,
|
| 1002 |
+
)
|
| 1003 |
+
|
| 1004 |
+
|
| 1005 |
+
__all__ = [
|
| 1006 |
+
"LayoutLMForMaskedLM",
|
| 1007 |
+
"LayoutLMForSequenceClassification",
|
| 1008 |
+
"LayoutLMForTokenClassification",
|
| 1009 |
+
"LayoutLMForQuestionAnswering",
|
| 1010 |
+
"LayoutLMModel",
|
| 1011 |
+
"LayoutLMPreTrainedModel",
|
| 1012 |
+
]
|
third_party/transformers/src/transformers/models/led/__init__.py
ADDED
|
@@ -0,0 +1,28 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
# Copyright 2024 The HuggingFace Team. All rights reserved.
|
| 2 |
+
#
|
| 3 |
+
# Licensed under the Apache License, Version 2.0 (the "License");
|
| 4 |
+
# you may not use this file except in compliance with the License.
|
| 5 |
+
# You may obtain a copy of the License at
|
| 6 |
+
#
|
| 7 |
+
# http://www.apache.org/licenses/LICENSE-2.0
|
| 8 |
+
#
|
| 9 |
+
# Unless required by applicable law or agreed to in writing, software
|
| 10 |
+
# distributed under the License is distributed on an "AS IS" BASIS,
|
| 11 |
+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
| 12 |
+
# See the License for the specific language governing permissions and
|
| 13 |
+
# limitations under the License.
|
| 14 |
+
from typing import TYPE_CHECKING
|
| 15 |
+
|
| 16 |
+
from ...utils import _LazyModule
|
| 17 |
+
from ...utils.import_utils import define_import_structure
|
| 18 |
+
|
| 19 |
+
|
| 20 |
+
if TYPE_CHECKING:
|
| 21 |
+
from ..roberta.tokenization_roberta import RobertaTokenizer as LEDTokenizer
|
| 22 |
+
from .configuration_led import *
|
| 23 |
+
from .modeling_led import *
|
| 24 |
+
else:
|
| 25 |
+
import sys
|
| 26 |
+
|
| 27 |
+
_file = globals()["__file__"]
|
| 28 |
+
sys.modules[__name__] = _LazyModule(__name__, _file, define_import_structure(_file), module_spec=__spec__)
|
third_party/transformers/src/transformers/models/led/configuration_led.py
ADDED
|
@@ -0,0 +1,86 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
# Copyright 2021 Iz Beltagy, Matthew E. Peters, Arman Cohan and The HuggingFace Inc. team. All rights reserved.
|
| 2 |
+
#
|
| 3 |
+
# Licensed under the Apache License, Version 2.0 (the "License");
|
| 4 |
+
# you may not use this file except in compliance with the License.
|
| 5 |
+
# You may obtain a copy of the License at
|
| 6 |
+
#
|
| 7 |
+
# http://www.apache.org/licenses/LICENSE-2.0
|
| 8 |
+
#
|
| 9 |
+
# Unless required by applicable law or agreed to in writing, software
|
| 10 |
+
# distributed under the License is distributed on an "AS IS" BASIS,
|
| 11 |
+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
| 12 |
+
# See the License for the specific language governing permissions and
|
| 13 |
+
# limitations under the License.
|
| 14 |
+
"""LED model configuration"""
|
| 15 |
+
|
| 16 |
+
from huggingface_hub.dataclasses import strict
|
| 17 |
+
|
| 18 |
+
from ...configuration_utils import PreTrainedConfig
|
| 19 |
+
from ...utils import auto_docstring
|
| 20 |
+
|
| 21 |
+
|
| 22 |
+
@auto_docstring(checkpoint="allenai/led-base-16384")
|
| 23 |
+
@strict
|
| 24 |
+
class LEDConfig(PreTrainedConfig):
|
| 25 |
+
r"""
|
| 26 |
+
max_encoder_position_embeddings (`int`, *optional*, defaults to 16384):
|
| 27 |
+
The maximum sequence length that the encoder might ever be used with.
|
| 28 |
+
max_decoder_position_embeddings (`int`, *optional*, defaults to 16384):
|
| 29 |
+
The maximum sequence length that the decoder might ever be used with.
|
| 30 |
+
attention_window (`int` or `list[int]`, *optional*, defaults to 512):
|
| 31 |
+
Size of an attention window around each token. If an `int`, use the same size for all layers. To specify a
|
| 32 |
+
different window size for each layer, use a `list[int]` where `len(attention_window) == num_hidden_layers`.
|
| 33 |
+
|
| 34 |
+
Example:
|
| 35 |
+
|
| 36 |
+
```python
|
| 37 |
+
>>> from transformers import LEDModel, LEDConfig
|
| 38 |
+
|
| 39 |
+
>>> # Initializing a LED allenai/led-base-16384 style configuration
|
| 40 |
+
>>> configuration = LEDConfig()
|
| 41 |
+
|
| 42 |
+
>>> # Initializing a model from the allenai/led-base-16384 style configuration
|
| 43 |
+
>>> model = LEDModel(configuration)
|
| 44 |
+
|
| 45 |
+
>>> # Accessing the model configuration
|
| 46 |
+
>>> configuration = model.config
|
| 47 |
+
```"""
|
| 48 |
+
|
| 49 |
+
model_type = "led"
|
| 50 |
+
attribute_map = {
|
| 51 |
+
"num_attention_heads": "encoder_attention_heads",
|
| 52 |
+
"hidden_size": "d_model",
|
| 53 |
+
"attention_probs_dropout_prob": "attention_dropout",
|
| 54 |
+
"initializer_range": "init_std",
|
| 55 |
+
"num_hidden_layers": "encoder_layers",
|
| 56 |
+
}
|
| 57 |
+
|
| 58 |
+
vocab_size: int = 50265
|
| 59 |
+
max_encoder_position_embeddings: int = 16384
|
| 60 |
+
max_decoder_position_embeddings: int = 1024
|
| 61 |
+
encoder_layers: int = 12
|
| 62 |
+
encoder_ffn_dim: int = 4096
|
| 63 |
+
encoder_attention_heads: int = 16
|
| 64 |
+
decoder_layers: int = 12
|
| 65 |
+
decoder_ffn_dim: int = 4096
|
| 66 |
+
decoder_attention_heads: int = 16
|
| 67 |
+
encoder_layerdrop: float | int = 0.0
|
| 68 |
+
decoder_layerdrop: float | int = 0.0
|
| 69 |
+
use_cache: bool = True
|
| 70 |
+
is_encoder_decoder: bool = True
|
| 71 |
+
activation_function: str = "gelu"
|
| 72 |
+
d_model: int = 1024
|
| 73 |
+
dropout: float | int = 0.1
|
| 74 |
+
attention_dropout: float | int = 0.0
|
| 75 |
+
activation_dropout: float | int = 0.0
|
| 76 |
+
init_std: float = 0.02
|
| 77 |
+
decoder_start_token_id: int = 2
|
| 78 |
+
classifier_dropout: float | int = 0.0
|
| 79 |
+
pad_token_id: int | None = 1
|
| 80 |
+
bos_token_id: int | None = 0
|
| 81 |
+
eos_token_id: int | list[int] | None = 2
|
| 82 |
+
attention_window: list[int] | int = 512
|
| 83 |
+
tie_word_embeddings: bool = True
|
| 84 |
+
|
| 85 |
+
|
| 86 |
+
__all__ = ["LEDConfig"]
|
third_party/transformers/src/transformers/models/led/modeling_led.py
ADDED
|
The diff for this file is too large to render.
See raw diff
|
|
|
third_party/transformers/src/transformers/models/lfm2_moe/__init__.py
ADDED
|
@@ -0,0 +1,28 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
# Copyright 2025 the HuggingFace Team. All rights reserved.
|
| 2 |
+
#
|
| 3 |
+
# Licensed under the Apache License, Version 2.0 (the "License");
|
| 4 |
+
# you may not use this file except in compliance with the License.
|
| 5 |
+
# You may obtain a copy of the License at
|
| 6 |
+
#
|
| 7 |
+
# http://www.apache.org/licenses/LICENSE-2.0
|
| 8 |
+
#
|
| 9 |
+
# Unless required by applicable law or agreed to in writing, software
|
| 10 |
+
# distributed under the License is distributed on an "AS IS" BASIS,
|
| 11 |
+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
| 12 |
+
# See the License for the specific language governing permissions and
|
| 13 |
+
# limitations under the License.
|
| 14 |
+
|
| 15 |
+
from typing import TYPE_CHECKING
|
| 16 |
+
|
| 17 |
+
from ...utils import _LazyModule
|
| 18 |
+
from ...utils.import_utils import define_import_structure
|
| 19 |
+
|
| 20 |
+
|
| 21 |
+
if TYPE_CHECKING:
|
| 22 |
+
from .configuration_lfm2_moe import *
|
| 23 |
+
from .modeling_lfm2_moe import *
|
| 24 |
+
else:
|
| 25 |
+
import sys
|
| 26 |
+
|
| 27 |
+
_file = globals()["__file__"]
|
| 28 |
+
sys.modules[__name__] = _LazyModule(__name__, _file, define_import_structure(_file), module_spec=__spec__)
|
third_party/transformers/src/transformers/models/lfm2_moe/configuration_lfm2_moe.py
ADDED
|
@@ -0,0 +1,84 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
# Copyright 2025 The HuggingFace Team. All rights reserved.
|
| 2 |
+
#
|
| 3 |
+
# Licensed under the Apache License, Version 2.0 (the "License");
|
| 4 |
+
# you may not use this file except in compliance with the License.
|
| 5 |
+
# You may obtain a copy of the License at
|
| 6 |
+
#
|
| 7 |
+
# http://www.apache.org/licenses/LICENSE-2.0
|
| 8 |
+
#
|
| 9 |
+
# Unless required by applicable law or agreed to in writing, software
|
| 10 |
+
# distributed under the License is distributed on an "AS IS" BASIS,
|
| 11 |
+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
| 12 |
+
# See the License for the specific language governing permissions and
|
| 13 |
+
# limitations under the License.
|
| 14 |
+
|
| 15 |
+
|
| 16 |
+
from huggingface_hub.dataclasses import strict
|
| 17 |
+
|
| 18 |
+
from ...configuration_utils import PreTrainedConfig
|
| 19 |
+
from ...utils import auto_docstring
|
| 20 |
+
|
| 21 |
+
|
| 22 |
+
@auto_docstring(checkpoint="LiquidAI/LFM2-8B-A1B")
|
| 23 |
+
@strict
|
| 24 |
+
class Lfm2MoeConfig(PreTrainedConfig):
|
| 25 |
+
r"""
|
| 26 |
+
conv_bias (`bool`, *optional*, defaults to `False`):
|
| 27 |
+
Whether to use bias in the conv layers.
|
| 28 |
+
conv_L_cache (`int`, *optional*, defaults to 3):
|
| 29 |
+
L_cache dim in the conv layers.
|
| 30 |
+
num_dense_layers (`int`, *optional*, defaults to 2):
|
| 31 |
+
Number of dense Lfm2MoeMLP layers in shallow layers(embed->dense->dense->...->dense->moe->moe...->lm_head).
|
| 32 |
+
use_expert_bias (`bool`, *optional*, defaults to `True`):
|
| 33 |
+
Whether to use the expert bias on the routing weights.
|
| 34 |
+
|
| 35 |
+
```python
|
| 36 |
+
>>> from transformers import Lfm2MoeModel, Lfm2MoeConfig
|
| 37 |
+
|
| 38 |
+
>>> # Initializing a LFM2 Moe model
|
| 39 |
+
>>> configuration = Lfm2MoeConfig()
|
| 40 |
+
|
| 41 |
+
>>> # Initializing a model from the LFM2-8B-A1B style configuration
|
| 42 |
+
>>> model = Lfm2MoeModel(configuration)
|
| 43 |
+
|
| 44 |
+
>>> # Accessing the model configuration
|
| 45 |
+
>>> configuration = model.config
|
| 46 |
+
```
|
| 47 |
+
"""
|
| 48 |
+
|
| 49 |
+
model_type = "lfm2_moe"
|
| 50 |
+
keys_to_ignore_at_inference = ["past_key_values"]
|
| 51 |
+
default_theta = 1000000.0
|
| 52 |
+
|
| 53 |
+
vocab_size: int = 65536
|
| 54 |
+
hidden_size: int = 2048
|
| 55 |
+
intermediate_size: int = 7168
|
| 56 |
+
moe_intermediate_size: int = 1792
|
| 57 |
+
num_hidden_layers: int = 32
|
| 58 |
+
pad_token_id: int | None = 0
|
| 59 |
+
bos_token_id: int | None = 1
|
| 60 |
+
eos_token_id: int | list[int] | None = 2
|
| 61 |
+
tie_word_embeddings: bool = True
|
| 62 |
+
rope_parameters: dict | None = None
|
| 63 |
+
max_position_embeddings: int = 128_000
|
| 64 |
+
initializer_range: float = 0.02
|
| 65 |
+
use_cache: bool = True
|
| 66 |
+
norm_eps: float = 0.00001
|
| 67 |
+
num_attention_heads: int = 32
|
| 68 |
+
num_key_value_heads: int = 8
|
| 69 |
+
conv_bias: bool = False
|
| 70 |
+
conv_L_cache: int = 3
|
| 71 |
+
num_dense_layers: int = 2
|
| 72 |
+
num_experts_per_tok: int = 4
|
| 73 |
+
num_experts: int = 32
|
| 74 |
+
use_expert_bias: bool = True
|
| 75 |
+
routed_scaling_factor: float = 1.0
|
| 76 |
+
norm_topk_prob: bool = True
|
| 77 |
+
layer_types: list[str] | None = None
|
| 78 |
+
|
| 79 |
+
def __post_init__(self, **kwargs):
|
| 80 |
+
self.tie_word_embeddings = kwargs.pop("tie_embedding", self.tie_word_embeddings)
|
| 81 |
+
super().__post_init__(**kwargs)
|
| 82 |
+
|
| 83 |
+
|
| 84 |
+
__all__ = ["Lfm2MoeConfig"]
|
third_party/transformers/src/transformers/models/lfm2_moe/modeling_lfm2_moe.py
ADDED
|
@@ -0,0 +1,704 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
# 🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨
|
| 2 |
+
# This file was automatically generated from src/transformers/models/lfm2_moe/modular_lfm2_moe.py.
|
| 3 |
+
# Do NOT edit this file manually as any edits will be overwritten by the generation of
|
| 4 |
+
# the file from the modular. If any change should be done, please apply the change to the
|
| 5 |
+
# modular_lfm2_moe.py file directly. One of our CI enforces this.
|
| 6 |
+
# 🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨
|
| 7 |
+
# Copyright 2025 The HuggingFace Team. All rights reserved.
|
| 8 |
+
#
|
| 9 |
+
# Licensed under the Apache License, Version 2.0 (the "License");
|
| 10 |
+
# you may not use this file except in compliance with the License.
|
| 11 |
+
# You may obtain a copy of the License at
|
| 12 |
+
#
|
| 13 |
+
# http://www.apache.org/licenses/LICENSE-2.0
|
| 14 |
+
#
|
| 15 |
+
# Unless required by applicable law or agreed to in writing, software
|
| 16 |
+
# distributed under the License is distributed on an "AS IS" BASIS,
|
| 17 |
+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
| 18 |
+
# See the License for the specific language governing permissions and
|
| 19 |
+
# limitations under the License.
|
| 20 |
+
|
| 21 |
+
from collections.abc import Callable
|
| 22 |
+
from typing import Optional
|
| 23 |
+
|
| 24 |
+
import torch
|
| 25 |
+
import torch.nn.functional as F
|
| 26 |
+
from torch import nn
|
| 27 |
+
|
| 28 |
+
from ... import initialization as init
|
| 29 |
+
from ...cache_utils import Cache, DynamicCache
|
| 30 |
+
from ...generation import GenerationMixin
|
| 31 |
+
from ...integrations import (
|
| 32 |
+
use_experts_implementation,
|
| 33 |
+
use_kernel_forward_from_hub,
|
| 34 |
+
use_kernel_func_from_hub,
|
| 35 |
+
use_kernelized_func,
|
| 36 |
+
)
|
| 37 |
+
from ...masking_utils import create_causal_mask
|
| 38 |
+
from ...modeling_layers import GradientCheckpointingLayer
|
| 39 |
+
from ...modeling_outputs import BaseModelOutputWithPast, CausalLMOutputWithPast, MoeModelOutputWithPast
|
| 40 |
+
from ...modeling_rope_utils import ROPE_INIT_FUNCTIONS, dynamic_rope_update
|
| 41 |
+
from ...modeling_utils import ALL_ATTENTION_FUNCTIONS, PreTrainedModel
|
| 42 |
+
from ...processing_utils import Unpack
|
| 43 |
+
from ...utils import TransformersKwargs, auto_docstring, can_return_tuple
|
| 44 |
+
from ...utils.generic import maybe_autocast, merge_with_config_defaults
|
| 45 |
+
from ...utils.import_utils import is_causal_conv1d_available, is_torchdynamo_compiling
|
| 46 |
+
from ...utils.output_capturing import capture_outputs
|
| 47 |
+
from .configuration_lfm2_moe import Lfm2MoeConfig
|
| 48 |
+
|
| 49 |
+
|
| 50 |
+
if is_causal_conv1d_available():
|
| 51 |
+
from causal_conv1d import causal_conv1d_fn, causal_conv1d_update
|
| 52 |
+
else:
|
| 53 |
+
causal_conv1d_fn, causal_conv1d_update = None, None
|
| 54 |
+
|
| 55 |
+
|
| 56 |
+
@use_kernel_forward_from_hub("RMSNorm")
|
| 57 |
+
class Lfm2MoeRMSNorm(nn.Module):
|
| 58 |
+
def __init__(self, hidden_size, eps: float = 1e-6) -> None:
|
| 59 |
+
"""
|
| 60 |
+
Lfm2MoeRMSNorm is equivalent to T5LayerNorm
|
| 61 |
+
"""
|
| 62 |
+
super().__init__()
|
| 63 |
+
self.weight = nn.Parameter(torch.ones(hidden_size))
|
| 64 |
+
self.variance_epsilon = eps
|
| 65 |
+
|
| 66 |
+
def forward(self, hidden_states: torch.Tensor) -> torch.Tensor:
|
| 67 |
+
input_dtype = hidden_states.dtype
|
| 68 |
+
hidden_states = hidden_states.to(torch.float32)
|
| 69 |
+
variance = hidden_states.pow(2).mean(-1, keepdim=True)
|
| 70 |
+
hidden_states = hidden_states * torch.rsqrt(variance + self.variance_epsilon)
|
| 71 |
+
return self.weight * hidden_states.to(input_dtype)
|
| 72 |
+
|
| 73 |
+
def extra_repr(self):
|
| 74 |
+
return f"{tuple(self.weight.shape)}, eps={self.variance_epsilon}"
|
| 75 |
+
|
| 76 |
+
|
| 77 |
+
class Lfm2MoeRotaryEmbedding(nn.Module):
|
| 78 |
+
inv_freq: torch.Tensor # fix linting for `register_buffer`
|
| 79 |
+
|
| 80 |
+
def __init__(self, config: Lfm2MoeConfig, device=None):
|
| 81 |
+
super().__init__()
|
| 82 |
+
self.max_seq_len_cached = config.max_position_embeddings
|
| 83 |
+
self.original_max_seq_len = config.max_position_embeddings
|
| 84 |
+
|
| 85 |
+
self.config = config
|
| 86 |
+
|
| 87 |
+
self.rope_type = self.config.rope_parameters["rope_type"]
|
| 88 |
+
rope_init_fn: Callable = self.compute_default_rope_parameters
|
| 89 |
+
if self.rope_type != "default":
|
| 90 |
+
rope_init_fn = ROPE_INIT_FUNCTIONS[self.rope_type]
|
| 91 |
+
inv_freq, self.attention_scaling = rope_init_fn(self.config, device)
|
| 92 |
+
|
| 93 |
+
self.register_buffer("inv_freq", inv_freq, persistent=False)
|
| 94 |
+
self.register_buffer("original_inv_freq", inv_freq.clone(), persistent=False)
|
| 95 |
+
|
| 96 |
+
@staticmethod
|
| 97 |
+
def compute_default_rope_parameters(
|
| 98 |
+
config: Lfm2MoeConfig | None = None,
|
| 99 |
+
device: Optional["torch.device"] = None,
|
| 100 |
+
seq_len: int | None = None,
|
| 101 |
+
) -> tuple["torch.Tensor", float]:
|
| 102 |
+
"""
|
| 103 |
+
Computes the inverse frequencies according to the original RoPE implementation
|
| 104 |
+
Args:
|
| 105 |
+
config ([`~transformers.PreTrainedConfig`]):
|
| 106 |
+
The model configuration.
|
| 107 |
+
device (`torch.device`):
|
| 108 |
+
The device to use for initialization of the inverse frequencies.
|
| 109 |
+
seq_len (`int`, *optional*):
|
| 110 |
+
The current sequence length. Unused for this type of RoPE.
|
| 111 |
+
Returns:
|
| 112 |
+
Tuple of (`torch.Tensor`, `float`), containing the inverse frequencies for the RoPE embeddings and the
|
| 113 |
+
post-processing scaling factor applied to the computed cos/sin (unused in this type of RoPE).
|
| 114 |
+
"""
|
| 115 |
+
base = config.rope_parameters["rope_theta"]
|
| 116 |
+
dim = getattr(config, "head_dim", None) or config.hidden_size // config.num_attention_heads
|
| 117 |
+
|
| 118 |
+
attention_factor = 1.0 # Unused in this type of RoPE
|
| 119 |
+
|
| 120 |
+
# Compute the inverse frequencies
|
| 121 |
+
inv_freq = 1.0 / (
|
| 122 |
+
base ** (torch.arange(0, dim, 2, dtype=torch.int64).to(device=device, dtype=torch.float) / dim)
|
| 123 |
+
)
|
| 124 |
+
return inv_freq, attention_factor
|
| 125 |
+
|
| 126 |
+
@torch.no_grad()
|
| 127 |
+
@dynamic_rope_update # power user: used with advanced RoPE types (e.g. dynamic rope)
|
| 128 |
+
def forward(self, x, position_ids):
|
| 129 |
+
inv_freq_expanded = self.inv_freq[None, :, None].float().expand(position_ids.shape[0], -1, 1).to(x.device)
|
| 130 |
+
position_ids_expanded = position_ids[:, None, :].float()
|
| 131 |
+
|
| 132 |
+
device_type = x.device.type if isinstance(x.device.type, str) and x.device.type != "mps" else "cpu"
|
| 133 |
+
with maybe_autocast(device_type=device_type, enabled=False): # Force float32
|
| 134 |
+
freqs = (inv_freq_expanded.float() @ position_ids_expanded.float()).transpose(1, 2)
|
| 135 |
+
emb = torch.cat((freqs, freqs), dim=-1)
|
| 136 |
+
cos = emb.cos() * self.attention_scaling
|
| 137 |
+
sin = emb.sin() * self.attention_scaling
|
| 138 |
+
|
| 139 |
+
return cos.to(dtype=x.dtype), sin.to(dtype=x.dtype)
|
| 140 |
+
|
| 141 |
+
|
| 142 |
+
class Lfm2MoeMLP(nn.Module):
|
| 143 |
+
def __init__(self, config: Lfm2MoeConfig, intermediate_size: int | None = None):
|
| 144 |
+
super().__init__()
|
| 145 |
+
self.hidden_size = config.hidden_size
|
| 146 |
+
self.intermediate_size = config.intermediate_size if intermediate_size is None else intermediate_size
|
| 147 |
+
self.w1 = nn.Linear(self.hidden_size, self.intermediate_size, bias=False)
|
| 148 |
+
self.w3 = nn.Linear(self.hidden_size, self.intermediate_size, bias=False)
|
| 149 |
+
self.w2 = nn.Linear(self.intermediate_size, self.hidden_size, bias=False)
|
| 150 |
+
|
| 151 |
+
def forward(self, x):
|
| 152 |
+
return self.w2(F.silu(self.w1(x)) * self.w3(x))
|
| 153 |
+
|
| 154 |
+
|
| 155 |
+
@use_experts_implementation
|
| 156 |
+
class Lfm2MoeExperts(nn.Module):
|
| 157 |
+
"""Collection of expert weights stored as 3D tensors."""
|
| 158 |
+
|
| 159 |
+
def __init__(self, config):
|
| 160 |
+
super().__init__()
|
| 161 |
+
self.num_experts = config.num_experts
|
| 162 |
+
self.hidden_dim = config.hidden_size
|
| 163 |
+
self.intermediate_dim = config.moe_intermediate_size
|
| 164 |
+
self.gate_up_proj = nn.Parameter(torch.empty(self.num_experts, 2 * self.intermediate_dim, self.hidden_dim))
|
| 165 |
+
self.down_proj = nn.Parameter(torch.empty(self.num_experts, self.hidden_dim, self.intermediate_dim))
|
| 166 |
+
self.act_fn = F.silu
|
| 167 |
+
|
| 168 |
+
def forward(
|
| 169 |
+
self,
|
| 170 |
+
hidden_states: torch.Tensor,
|
| 171 |
+
top_k_index: torch.Tensor,
|
| 172 |
+
top_k_weights: torch.Tensor,
|
| 173 |
+
) -> torch.Tensor:
|
| 174 |
+
final_hidden_states = torch.zeros_like(hidden_states)
|
| 175 |
+
with torch.no_grad():
|
| 176 |
+
expert_mask = torch.nn.functional.one_hot(top_k_index, num_classes=self.num_experts)
|
| 177 |
+
expert_mask = expert_mask.permute(2, 1, 0)
|
| 178 |
+
expert_hit = torch.greater(expert_mask.sum(dim=(-1, -2)), 0).nonzero()
|
| 179 |
+
|
| 180 |
+
for expert_idx in expert_hit:
|
| 181 |
+
expert_idx = expert_idx[0]
|
| 182 |
+
if expert_idx == self.num_experts:
|
| 183 |
+
continue
|
| 184 |
+
top_k_pos, token_idx = torch.where(expert_mask[expert_idx])
|
| 185 |
+
current_state = hidden_states[token_idx]
|
| 186 |
+
gate, up = nn.functional.linear(current_state, self.gate_up_proj[expert_idx]).chunk(2, dim=-1)
|
| 187 |
+
current_hidden_states = self.act_fn(gate) * up
|
| 188 |
+
current_hidden_states = nn.functional.linear(current_hidden_states, self.down_proj[expert_idx])
|
| 189 |
+
current_hidden_states = current_hidden_states * top_k_weights[token_idx, top_k_pos, None]
|
| 190 |
+
final_hidden_states.index_add_(0, token_idx, current_hidden_states.to(final_hidden_states.dtype))
|
| 191 |
+
|
| 192 |
+
return final_hidden_states
|
| 193 |
+
|
| 194 |
+
|
| 195 |
+
class Lfm2MoeSparseMoeBlock(nn.Module):
|
| 196 |
+
def __init__(self, config):
|
| 197 |
+
super().__init__()
|
| 198 |
+
self.top_k = config.num_experts_per_tok
|
| 199 |
+
self.routed_scaling_factor = config.routed_scaling_factor
|
| 200 |
+
self.norm_topk_prob = config.norm_topk_prob
|
| 201 |
+
self.use_expert_bias = config.use_expert_bias
|
| 202 |
+
|
| 203 |
+
self.gate = nn.Linear(config.hidden_size, config.num_experts, bias=False)
|
| 204 |
+
self.experts = Lfm2MoeExperts(config)
|
| 205 |
+
if self.use_expert_bias:
|
| 206 |
+
self.register_buffer("expert_bias", torch.zeros(config.num_experts, dtype=torch.float32))
|
| 207 |
+
|
| 208 |
+
def route_tokens_to_experts(self, router_logits):
|
| 209 |
+
routing_weights = router_logits.sigmoid()
|
| 210 |
+
if self.use_expert_bias:
|
| 211 |
+
scores_for_routing = routing_weights + self.expert_bias
|
| 212 |
+
_, selected_experts = torch.topk(scores_for_routing, k=self.top_k, dim=-1)
|
| 213 |
+
routing_weights = torch.gather(routing_weights, dim=1, index=selected_experts).type_as(router_logits)
|
| 214 |
+
else:
|
| 215 |
+
routing_weights, selected_experts = torch.topk(routing_weights, k=self.top_k, dim=-1)
|
| 216 |
+
|
| 217 |
+
if self.norm_topk_prob:
|
| 218 |
+
routing_weights = routing_weights / (routing_weights.sum(dim=-1, keepdim=True) + 1e-6)
|
| 219 |
+
routing_weights = routing_weights * self.routed_scaling_factor
|
| 220 |
+
return selected_experts, routing_weights
|
| 221 |
+
|
| 222 |
+
def forward(self, hidden_states: torch.Tensor) -> tuple[torch.Tensor, torch.Tensor]:
|
| 223 |
+
batch_size, sequence_length, hidden_dim = hidden_states.shape
|
| 224 |
+
hidden_states_reshaped = hidden_states.view(-1, hidden_dim)
|
| 225 |
+
router_logits = self.gate(hidden_states_reshaped)
|
| 226 |
+
selected_experts, routing_weights = self.route_tokens_to_experts(router_logits)
|
| 227 |
+
final_hidden_states = self.experts(hidden_states_reshaped, selected_experts, routing_weights)
|
| 228 |
+
return final_hidden_states.reshape(batch_size, sequence_length, hidden_dim)
|
| 229 |
+
|
| 230 |
+
|
| 231 |
+
def rotate_half(x):
|
| 232 |
+
"""Rotates half the hidden dims of the input."""
|
| 233 |
+
x1 = x[..., : x.shape[-1] // 2]
|
| 234 |
+
x2 = x[..., x.shape[-1] // 2 :]
|
| 235 |
+
return torch.cat((-x2, x1), dim=-1)
|
| 236 |
+
|
| 237 |
+
|
| 238 |
+
@use_kernel_func_from_hub("rotary_pos_emb")
|
| 239 |
+
def apply_rotary_pos_emb(q, k, cos, sin, unsqueeze_dim=1):
|
| 240 |
+
"""Applies Rotary Position Embedding to the query and key tensors.
|
| 241 |
+
|
| 242 |
+
Args:
|
| 243 |
+
q (`torch.Tensor`): The query tensor.
|
| 244 |
+
k (`torch.Tensor`): The key tensor.
|
| 245 |
+
cos (`torch.Tensor`): The cosine part of the rotary embedding.
|
| 246 |
+
sin (`torch.Tensor`): The sine part of the rotary embedding.
|
| 247 |
+
unsqueeze_dim (`int`, *optional*, defaults to 1):
|
| 248 |
+
The 'unsqueeze_dim' argument specifies the dimension along which to unsqueeze cos[position_ids] and
|
| 249 |
+
sin[position_ids] so that they can be properly broadcasted to the dimensions of q and k. For example, note
|
| 250 |
+
that cos[position_ids] and sin[position_ids] have the shape [batch_size, seq_len, head_dim]. Then, if q and
|
| 251 |
+
k have the shape [batch_size, heads, seq_len, head_dim], then setting unsqueeze_dim=1 makes
|
| 252 |
+
cos[position_ids] and sin[position_ids] broadcastable to the shapes of q and k. Similarly, if q and k have
|
| 253 |
+
the shape [batch_size, seq_len, heads, head_dim], then set unsqueeze_dim=2.
|
| 254 |
+
Returns:
|
| 255 |
+
`tuple(torch.Tensor)` comprising of the query and key tensors rotated using the Rotary Position Embedding.
|
| 256 |
+
"""
|
| 257 |
+
cos = cos.unsqueeze(unsqueeze_dim)
|
| 258 |
+
sin = sin.unsqueeze(unsqueeze_dim)
|
| 259 |
+
q_embed = (q * cos) + (rotate_half(q) * sin)
|
| 260 |
+
k_embed = (k * cos) + (rotate_half(k) * sin)
|
| 261 |
+
return q_embed, k_embed
|
| 262 |
+
|
| 263 |
+
|
| 264 |
+
def repeat_kv(hidden_states: torch.Tensor, n_rep: int) -> torch.Tensor:
|
| 265 |
+
"""
|
| 266 |
+
This is the equivalent of torch.repeat_interleave(x, dim=1, repeats=n_rep). The hidden states go from (batch,
|
| 267 |
+
num_key_value_heads, seqlen, head_dim) to (batch, num_attention_heads, seqlen, head_dim)
|
| 268 |
+
"""
|
| 269 |
+
batch, num_key_value_heads, slen, head_dim = hidden_states.shape
|
| 270 |
+
if n_rep == 1:
|
| 271 |
+
return hidden_states
|
| 272 |
+
hidden_states = hidden_states[:, :, None, :, :].expand(batch, num_key_value_heads, n_rep, slen, head_dim)
|
| 273 |
+
return hidden_states.reshape(batch, num_key_value_heads * n_rep, slen, head_dim)
|
| 274 |
+
|
| 275 |
+
|
| 276 |
+
def eager_attention_forward(
|
| 277 |
+
module: nn.Module,
|
| 278 |
+
query: torch.Tensor,
|
| 279 |
+
key: torch.Tensor,
|
| 280 |
+
value: torch.Tensor,
|
| 281 |
+
attention_mask: torch.Tensor | None,
|
| 282 |
+
scaling: float,
|
| 283 |
+
dropout: float = 0.0,
|
| 284 |
+
**kwargs: Unpack[TransformersKwargs],
|
| 285 |
+
):
|
| 286 |
+
key_states = repeat_kv(key, module.num_key_value_groups)
|
| 287 |
+
value_states = repeat_kv(value, module.num_key_value_groups)
|
| 288 |
+
|
| 289 |
+
attn_weights = torch.matmul(query, key_states.transpose(2, 3)) * scaling
|
| 290 |
+
if attention_mask is not None:
|
| 291 |
+
attn_weights = attn_weights + attention_mask
|
| 292 |
+
|
| 293 |
+
attn_weights = nn.functional.softmax(attn_weights, dim=-1, dtype=torch.float32).to(query.dtype)
|
| 294 |
+
attn_weights = nn.functional.dropout(attn_weights, p=dropout, training=module.training)
|
| 295 |
+
attn_output = torch.matmul(attn_weights, value_states)
|
| 296 |
+
attn_output = attn_output.transpose(1, 2).contiguous()
|
| 297 |
+
|
| 298 |
+
return attn_output, attn_weights
|
| 299 |
+
|
| 300 |
+
|
| 301 |
+
@use_kernelized_func(apply_rotary_pos_emb)
|
| 302 |
+
class Lfm2MoeAttention(nn.Module):
|
| 303 |
+
"""Multi-headed attention from 'Attention Is All You Need' paper"""
|
| 304 |
+
|
| 305 |
+
def __init__(self, config: Lfm2MoeConfig, layer_idx: int):
|
| 306 |
+
super().__init__()
|
| 307 |
+
self.config = config
|
| 308 |
+
self.layer_idx = layer_idx
|
| 309 |
+
self.head_dim = getattr(config, "head_dim", config.hidden_size // config.num_attention_heads)
|
| 310 |
+
self.num_key_value_groups = config.num_attention_heads // config.num_key_value_heads
|
| 311 |
+
self.scaling = self.head_dim**-0.5
|
| 312 |
+
self.is_causal = True
|
| 313 |
+
self.q_proj = nn.Linear(config.hidden_size, config.num_attention_heads * self.head_dim, bias=False)
|
| 314 |
+
self.k_proj = nn.Linear(config.hidden_size, config.num_key_value_heads * self.head_dim, bias=False)
|
| 315 |
+
self.v_proj = nn.Linear(config.hidden_size, config.num_key_value_heads * self.head_dim, bias=False)
|
| 316 |
+
self.out_proj = nn.Linear(config.num_attention_heads * self.head_dim, config.hidden_size, bias=False)
|
| 317 |
+
self.q_layernorm = Lfm2MoeRMSNorm(self.head_dim, eps=config.norm_eps)
|
| 318 |
+
self.k_layernorm = Lfm2MoeRMSNorm(self.head_dim, eps=config.norm_eps)
|
| 319 |
+
|
| 320 |
+
def forward(
|
| 321 |
+
self,
|
| 322 |
+
hidden_states: torch.Tensor,
|
| 323 |
+
position_embeddings: tuple[torch.Tensor, torch.Tensor],
|
| 324 |
+
attention_mask: torch.Tensor | None,
|
| 325 |
+
past_key_values: Cache | None = None,
|
| 326 |
+
**kwargs,
|
| 327 |
+
) -> tuple[torch.Tensor, torch.Tensor | None]:
|
| 328 |
+
input_shape = hidden_states.shape[:-1]
|
| 329 |
+
hidden_shape = (*input_shape, -1, self.head_dim)
|
| 330 |
+
|
| 331 |
+
query_states = self.q_layernorm(self.q_proj(hidden_states).view(*hidden_shape)).transpose(1, 2)
|
| 332 |
+
key_states = self.k_layernorm(self.k_proj(hidden_states).view(*hidden_shape)).transpose(1, 2)
|
| 333 |
+
value_states = self.v_proj(hidden_states).view(*hidden_shape).transpose(1, 2)
|
| 334 |
+
|
| 335 |
+
cos, sin = position_embeddings
|
| 336 |
+
query_states, key_states = apply_rotary_pos_emb(query_states, key_states, cos, sin)
|
| 337 |
+
|
| 338 |
+
if past_key_values is not None:
|
| 339 |
+
key_states, value_states = past_key_values.update(key_states, value_states, self.layer_idx)
|
| 340 |
+
|
| 341 |
+
attention_interface: Callable = ALL_ATTENTION_FUNCTIONS.get_interface(
|
| 342 |
+
self.config._attn_implementation, eager_attention_forward
|
| 343 |
+
)
|
| 344 |
+
|
| 345 |
+
attn_output, attn_weights = attention_interface(
|
| 346 |
+
self,
|
| 347 |
+
query_states,
|
| 348 |
+
key_states,
|
| 349 |
+
value_states,
|
| 350 |
+
attention_mask,
|
| 351 |
+
dropout=0.0,
|
| 352 |
+
scaling=self.scaling,
|
| 353 |
+
**kwargs,
|
| 354 |
+
)
|
| 355 |
+
attn_output = attn_output.reshape(*input_shape, -1).contiguous()
|
| 356 |
+
output = self.out_proj(attn_output)
|
| 357 |
+
return output, attn_weights
|
| 358 |
+
|
| 359 |
+
|
| 360 |
+
def apply_mask_to_padding_states(hidden_states, attention_mask):
|
| 361 |
+
"""
|
| 362 |
+
Tunes out the hidden states for padding tokens, see https://github.com/state-spaces/mamba/issues/66
|
| 363 |
+
"""
|
| 364 |
+
# NOTE: attention mask is a 2D boolean tensor
|
| 365 |
+
if attention_mask is not None and attention_mask.shape[1] > 1 and attention_mask.shape[0] > 1:
|
| 366 |
+
dtype = hidden_states.dtype
|
| 367 |
+
hidden_states = (hidden_states * attention_mask[:, :, None]).to(dtype)
|
| 368 |
+
|
| 369 |
+
return hidden_states
|
| 370 |
+
|
| 371 |
+
|
| 372 |
+
kernel_modules = (causal_conv1d_fn, causal_conv1d_update)
|
| 373 |
+
is_fast_path_available = all(kernel_modules)
|
| 374 |
+
|
| 375 |
+
|
| 376 |
+
class Lfm2MoeShortConv(nn.Module):
|
| 377 |
+
def __init__(
|
| 378 |
+
self,
|
| 379 |
+
config: Lfm2MoeConfig,
|
| 380 |
+
layer_idx: int,
|
| 381 |
+
):
|
| 382 |
+
super().__init__()
|
| 383 |
+
self.config = config
|
| 384 |
+
self.layer_idx = layer_idx
|
| 385 |
+
self.L_cache = config.conv_L_cache
|
| 386 |
+
self.bias = config.conv_bias
|
| 387 |
+
|
| 388 |
+
self.conv = nn.Conv1d(
|
| 389 |
+
in_channels=config.hidden_size,
|
| 390 |
+
out_channels=config.hidden_size,
|
| 391 |
+
kernel_size=self.L_cache,
|
| 392 |
+
groups=config.hidden_size,
|
| 393 |
+
bias=self.bias,
|
| 394 |
+
padding=self.L_cache - 1,
|
| 395 |
+
)
|
| 396 |
+
self.in_proj = nn.Linear(config.hidden_size, 3 * config.hidden_size, bias=self.bias)
|
| 397 |
+
self.out_proj = nn.Linear(config.hidden_size, config.hidden_size, bias=self.bias)
|
| 398 |
+
|
| 399 |
+
def cuda_kernels_forward(
|
| 400 |
+
self,
|
| 401 |
+
x: torch.Tensor,
|
| 402 |
+
past_key_values: Cache | None = None,
|
| 403 |
+
attention_mask: torch.Tensor | None = None,
|
| 404 |
+
):
|
| 405 |
+
x = apply_mask_to_padding_states(x, attention_mask)
|
| 406 |
+
BCx = self.in_proj(x).transpose(-1, -2)
|
| 407 |
+
B, C, x = BCx.chunk(3, dim=-2)
|
| 408 |
+
|
| 409 |
+
Bx = B * x
|
| 410 |
+
|
| 411 |
+
conv_weights = self.conv.weight.view(self.conv.weight.size(0), self.conv.weight.size(2))
|
| 412 |
+
if past_key_values is not None and past_key_values.has_previous_state(self.layer_idx):
|
| 413 |
+
conv_out = causal_conv1d_update(
|
| 414 |
+
Bx.squeeze(-1),
|
| 415 |
+
past_key_values.layers[self.layer_idx].conv_states,
|
| 416 |
+
conv_weights,
|
| 417 |
+
self.conv.bias,
|
| 418 |
+
None,
|
| 419 |
+
)
|
| 420 |
+
conv_out = conv_out.unsqueeze(-1)
|
| 421 |
+
else:
|
| 422 |
+
if past_key_values is not None:
|
| 423 |
+
conv_state = nn.functional.pad(Bx, (self.L_cache - Bx.shape[-1], 0))
|
| 424 |
+
conv_state = past_key_values.update_conv_state(conv_state, self.layer_idx)
|
| 425 |
+
|
| 426 |
+
conv_out = causal_conv1d_fn(Bx, conv_weights, self.conv.bias, activation=None)
|
| 427 |
+
|
| 428 |
+
y = C * conv_out
|
| 429 |
+
y = self.out_proj(y.transpose(-1, -2).contiguous())
|
| 430 |
+
return y
|
| 431 |
+
|
| 432 |
+
def slow_forward(
|
| 433 |
+
self,
|
| 434 |
+
x: torch.Tensor,
|
| 435 |
+
past_key_values: Cache | None = None,
|
| 436 |
+
attention_mask: torch.Tensor | None = None,
|
| 437 |
+
):
|
| 438 |
+
seqlen = x.shape[1]
|
| 439 |
+
|
| 440 |
+
x = apply_mask_to_padding_states(x, attention_mask)
|
| 441 |
+
BCx = self.in_proj(x).transpose(-1, -2)
|
| 442 |
+
B, C, x = BCx.chunk(3, dim=-2)
|
| 443 |
+
|
| 444 |
+
Bx = B * x
|
| 445 |
+
|
| 446 |
+
if past_key_values is not None and past_key_values.has_previous_state(self.layer_idx):
|
| 447 |
+
conv_state = past_key_values.update_conv_state(Bx, self.layer_idx)
|
| 448 |
+
conv_out = torch.sum(conv_state.to(Bx.device) * self.conv.weight[:, 0, :], dim=-1)
|
| 449 |
+
if self.bias:
|
| 450 |
+
conv_out += self.conv.bias
|
| 451 |
+
|
| 452 |
+
conv_out = conv_out.unsqueeze(-1)
|
| 453 |
+
else:
|
| 454 |
+
if past_key_values is not None:
|
| 455 |
+
conv_state = nn.functional.pad(Bx, (self.L_cache - Bx.shape[-1], 0))
|
| 456 |
+
conv_state = past_key_values.update_conv_state(conv_state, self.layer_idx)
|
| 457 |
+
|
| 458 |
+
conv_out = self.conv(Bx)[..., :seqlen]
|
| 459 |
+
|
| 460 |
+
y = C * conv_out
|
| 461 |
+
y = y.transpose(-1, -2).contiguous()
|
| 462 |
+
y = self.out_proj(y)
|
| 463 |
+
return y
|
| 464 |
+
|
| 465 |
+
def forward(
|
| 466 |
+
self,
|
| 467 |
+
hidden_states: torch.Tensor,
|
| 468 |
+
past_key_values: Cache | None = None,
|
| 469 |
+
attention_mask: torch.Tensor | None = None,
|
| 470 |
+
):
|
| 471 |
+
if is_fast_path_available and "cuda" in hidden_states.device.type and not is_torchdynamo_compiling():
|
| 472 |
+
return self.cuda_kernels_forward(hidden_states, past_key_values, attention_mask)
|
| 473 |
+
return self.slow_forward(hidden_states, past_key_values, attention_mask)
|
| 474 |
+
|
| 475 |
+
|
| 476 |
+
class Lfm2MoeDecoderLayer(GradientCheckpointingLayer):
|
| 477 |
+
def __init__(self, config: Lfm2MoeConfig, layer_idx: int):
|
| 478 |
+
super().__init__()
|
| 479 |
+
self.is_attention_layer = config.layer_types[layer_idx] == "full_attention"
|
| 480 |
+
|
| 481 |
+
if self.is_attention_layer:
|
| 482 |
+
self.self_attn = Lfm2MoeAttention(config, layer_idx)
|
| 483 |
+
else:
|
| 484 |
+
self.conv = Lfm2MoeShortConv(config, layer_idx)
|
| 485 |
+
self.feed_forward = (
|
| 486 |
+
Lfm2MoeMLP(config, intermediate_size=config.intermediate_size)
|
| 487 |
+
if layer_idx < config.num_dense_layers
|
| 488 |
+
else Lfm2MoeSparseMoeBlock(config)
|
| 489 |
+
)
|
| 490 |
+
self.operator_norm = Lfm2MoeRMSNorm(config.hidden_size, eps=config.norm_eps)
|
| 491 |
+
self.ffn_norm = Lfm2MoeRMSNorm(config.hidden_size, eps=config.norm_eps)
|
| 492 |
+
|
| 493 |
+
def forward(
|
| 494 |
+
self,
|
| 495 |
+
hidden_states: torch.Tensor,
|
| 496 |
+
position_embeddings: tuple[torch.Tensor, torch.Tensor] | None = None,
|
| 497 |
+
attention_mask: torch.Tensor | None = None,
|
| 498 |
+
position_ids: torch.LongTensor | None = None,
|
| 499 |
+
past_key_values: Cache | None = None,
|
| 500 |
+
**kwargs,
|
| 501 |
+
) -> torch.Tensor:
|
| 502 |
+
residual = hidden_states
|
| 503 |
+
if self.is_attention_layer:
|
| 504 |
+
hidden_states, _ = self.self_attn(
|
| 505 |
+
hidden_states=self.operator_norm(hidden_states),
|
| 506 |
+
position_embeddings=position_embeddings,
|
| 507 |
+
attention_mask=attention_mask,
|
| 508 |
+
position_ids=position_ids,
|
| 509 |
+
past_key_values=past_key_values,
|
| 510 |
+
**kwargs,
|
| 511 |
+
)
|
| 512 |
+
else:
|
| 513 |
+
hidden_states = self.conv(
|
| 514 |
+
hidden_states=self.operator_norm(hidden_states),
|
| 515 |
+
past_key_values=past_key_values,
|
| 516 |
+
attention_mask=attention_mask,
|
| 517 |
+
)
|
| 518 |
+
hidden_states = hidden_states + residual
|
| 519 |
+
hidden_states = hidden_states + self.feed_forward(self.ffn_norm(hidden_states))
|
| 520 |
+
|
| 521 |
+
return hidden_states
|
| 522 |
+
|
| 523 |
+
|
| 524 |
+
@auto_docstring
|
| 525 |
+
class Lfm2MoePreTrainedModel(PreTrainedModel):
|
| 526 |
+
config: Lfm2MoeConfig
|
| 527 |
+
base_model_prefix = "model"
|
| 528 |
+
supports_gradient_checkpointing = True
|
| 529 |
+
_no_split_modules = ["Lfm2MoeDecoderLayer"]
|
| 530 |
+
_skip_keys_device_placement = ["past_key_values"]
|
| 531 |
+
_supports_flash_attn = True
|
| 532 |
+
_supports_sdpa = True
|
| 533 |
+
_supports_flex_attn = True
|
| 534 |
+
_can_compile_fullgraph = False # uses a non-compilable cache class
|
| 535 |
+
_supports_attention_backend = True
|
| 536 |
+
_can_record_outputs = {
|
| 537 |
+
"hidden_states": Lfm2MoeDecoderLayer,
|
| 538 |
+
"attentions": Lfm2MoeAttention,
|
| 539 |
+
}
|
| 540 |
+
|
| 541 |
+
@torch.no_grad()
|
| 542 |
+
def _init_weights(self, module):
|
| 543 |
+
super()._init_weights(module)
|
| 544 |
+
if isinstance(module, Lfm2MoeExperts):
|
| 545 |
+
init.normal_(module.gate_up_proj, mean=0.0, std=self.config.initializer_range)
|
| 546 |
+
init.normal_(module.down_proj, mean=0.0, std=self.config.initializer_range)
|
| 547 |
+
elif isinstance(module, Lfm2MoeSparseMoeBlock):
|
| 548 |
+
if module.use_expert_bias:
|
| 549 |
+
init.zeros_(module.expert_bias)
|
| 550 |
+
|
| 551 |
+
|
| 552 |
+
@auto_docstring
|
| 553 |
+
class Lfm2MoeModel(Lfm2MoePreTrainedModel):
|
| 554 |
+
def __init__(self, config: Lfm2MoeConfig):
|
| 555 |
+
super().__init__(config)
|
| 556 |
+
self.padding_idx = config.pad_token_id
|
| 557 |
+
self.vocab_size = config.vocab_size
|
| 558 |
+
|
| 559 |
+
self.embed_tokens = nn.Embedding(config.vocab_size, config.hidden_size, self.padding_idx)
|
| 560 |
+
self.layers = nn.ModuleList(
|
| 561 |
+
[Lfm2MoeDecoderLayer(config, layer_idx) for layer_idx in range(config.num_hidden_layers)]
|
| 562 |
+
)
|
| 563 |
+
self.gradient_checkpointing = False
|
| 564 |
+
self.pos_emb = Lfm2MoeRotaryEmbedding(config)
|
| 565 |
+
self.embedding_norm = Lfm2MoeRMSNorm(config.hidden_size, eps=config.norm_eps)
|
| 566 |
+
|
| 567 |
+
# Initialize weights and apply final processing
|
| 568 |
+
self.post_init()
|
| 569 |
+
|
| 570 |
+
@merge_with_config_defaults
|
| 571 |
+
@capture_outputs
|
| 572 |
+
@auto_docstring
|
| 573 |
+
def forward(
|
| 574 |
+
self,
|
| 575 |
+
input_ids: torch.LongTensor | None = None,
|
| 576 |
+
attention_mask: torch.Tensor | None = None,
|
| 577 |
+
position_ids: torch.LongTensor | None = None,
|
| 578 |
+
past_key_values: Cache | None = None,
|
| 579 |
+
inputs_embeds: torch.FloatTensor | None = None,
|
| 580 |
+
use_cache: bool | None = None,
|
| 581 |
+
**kwargs: Unpack[TransformersKwargs],
|
| 582 |
+
) -> MoeModelOutputWithPast:
|
| 583 |
+
if (input_ids is None) ^ (inputs_embeds is not None):
|
| 584 |
+
raise ValueError("You must specify exactly one of input_ids or inputs_embeds")
|
| 585 |
+
|
| 586 |
+
if inputs_embeds is None:
|
| 587 |
+
inputs_embeds = self.embed_tokens(input_ids)
|
| 588 |
+
|
| 589 |
+
if use_cache and past_key_values is None:
|
| 590 |
+
past_key_values = DynamicCache(config=self.config)
|
| 591 |
+
|
| 592 |
+
if position_ids is None:
|
| 593 |
+
past_seen_tokens = past_key_values.get_seq_length() if past_key_values is not None else 0
|
| 594 |
+
position_ids = torch.arange(inputs_embeds.shape[1], device=inputs_embeds.device) + past_seen_tokens
|
| 595 |
+
position_ids = position_ids.unsqueeze(0)
|
| 596 |
+
|
| 597 |
+
causal_mask = create_causal_mask(
|
| 598 |
+
config=self.config,
|
| 599 |
+
inputs_embeds=inputs_embeds,
|
| 600 |
+
attention_mask=attention_mask,
|
| 601 |
+
past_key_values=past_key_values,
|
| 602 |
+
position_ids=position_ids,
|
| 603 |
+
)
|
| 604 |
+
# Skip masking for decoding stage. We check shape here to be compile-friendly
|
| 605 |
+
linear_attention = attention_mask if inputs_embeds.shape[1] != 1 else None
|
| 606 |
+
|
| 607 |
+
hidden_states = inputs_embeds
|
| 608 |
+
position_embeddings = self.pos_emb(hidden_states, position_ids=position_ids)
|
| 609 |
+
|
| 610 |
+
# decoder layers
|
| 611 |
+
for i, decoder_layer in enumerate(self.layers[: self.config.num_hidden_layers]):
|
| 612 |
+
layer_mask = causal_mask if self.config.layer_types[i] == "full_attention" else linear_attention
|
| 613 |
+
hidden_states = decoder_layer(
|
| 614 |
+
hidden_states,
|
| 615 |
+
attention_mask=layer_mask,
|
| 616 |
+
position_ids=position_ids,
|
| 617 |
+
past_key_values=past_key_values,
|
| 618 |
+
position_embeddings=position_embeddings,
|
| 619 |
+
**kwargs,
|
| 620 |
+
)
|
| 621 |
+
|
| 622 |
+
hidden_states = self.embedding_norm(hidden_states)
|
| 623 |
+
|
| 624 |
+
return MoeModelOutputWithPast(
|
| 625 |
+
last_hidden_state=hidden_states,
|
| 626 |
+
past_key_values=past_key_values,
|
| 627 |
+
)
|
| 628 |
+
|
| 629 |
+
|
| 630 |
+
@auto_docstring
|
| 631 |
+
class Lfm2MoeForCausalLM(Lfm2MoePreTrainedModel, GenerationMixin):
|
| 632 |
+
_tied_weights_keys = {"lm_head.weight": "model.embed_tokens.weight"}
|
| 633 |
+
_tp_plan = {"lm_head": "colwise_gather_output"}
|
| 634 |
+
_pp_plan = {"lm_head": (["hidden_states"], ["logits"])}
|
| 635 |
+
|
| 636 |
+
def __init__(self, config):
|
| 637 |
+
super().__init__(config)
|
| 638 |
+
self.model = Lfm2MoeModel(config)
|
| 639 |
+
self.vocab_size = config.vocab_size
|
| 640 |
+
self.lm_head = nn.Linear(config.hidden_size, config.vocab_size, bias=False)
|
| 641 |
+
|
| 642 |
+
# Initialize weights and apply final processing
|
| 643 |
+
self.post_init()
|
| 644 |
+
|
| 645 |
+
@can_return_tuple
|
| 646 |
+
@auto_docstring
|
| 647 |
+
def forward(
|
| 648 |
+
self,
|
| 649 |
+
input_ids: torch.LongTensor | None = None,
|
| 650 |
+
attention_mask: torch.Tensor | None = None,
|
| 651 |
+
position_ids: torch.LongTensor | None = None,
|
| 652 |
+
past_key_values: Cache | None = None,
|
| 653 |
+
inputs_embeds: torch.FloatTensor | None = None,
|
| 654 |
+
labels: torch.LongTensor | None = None,
|
| 655 |
+
use_cache: bool | None = None,
|
| 656 |
+
logits_to_keep: int | torch.Tensor = 0,
|
| 657 |
+
**kwargs: Unpack[TransformersKwargs],
|
| 658 |
+
) -> CausalLMOutputWithPast:
|
| 659 |
+
r"""
|
| 660 |
+
Example:
|
| 661 |
+
|
| 662 |
+
```python
|
| 663 |
+
>>> from transformers import AutoTokenizer, Lfm2MoeForCausalLM
|
| 664 |
+
|
| 665 |
+
>>> model = Lfm2MoeForCausalLM.from_pretrained("meta-lfm2_moe/Lfm2Moe-2-7b-hf")
|
| 666 |
+
>>> tokenizer = AutoTokenizer.from_pretrained("meta-lfm2_moe/Lfm2Moe-2-7b-hf")
|
| 667 |
+
|
| 668 |
+
>>> prompt = "Hey, are you conscious? Can you talk to me?"
|
| 669 |
+
>>> inputs = tokenizer(prompt, return_tensors="pt")
|
| 670 |
+
|
| 671 |
+
>>> # Generate
|
| 672 |
+
>>> generate_ids = model.generate(inputs.input_ids, max_length=30)
|
| 673 |
+
>>> tokenizer.batch_decode(generate_ids, skip_special_tokens=True, clean_up_tokenization_spaces=False)[0]
|
| 674 |
+
"Hey, are you conscious? Can you talk to me?\nI'm not conscious, but I can talk to you."
|
| 675 |
+
```"""
|
| 676 |
+
outputs: BaseModelOutputWithPast = self.model(
|
| 677 |
+
input_ids=input_ids,
|
| 678 |
+
attention_mask=attention_mask,
|
| 679 |
+
position_ids=position_ids,
|
| 680 |
+
past_key_values=past_key_values,
|
| 681 |
+
inputs_embeds=inputs_embeds,
|
| 682 |
+
use_cache=use_cache,
|
| 683 |
+
**kwargs,
|
| 684 |
+
)
|
| 685 |
+
|
| 686 |
+
hidden_states = outputs.last_hidden_state
|
| 687 |
+
# Only compute necessary logits, and do not upcast them to float if we are not computing the loss
|
| 688 |
+
slice_indices = slice(-logits_to_keep, None) if isinstance(logits_to_keep, int) else logits_to_keep
|
| 689 |
+
logits = self.lm_head(hidden_states[:, slice_indices, :])
|
| 690 |
+
|
| 691 |
+
loss = None
|
| 692 |
+
if labels is not None:
|
| 693 |
+
loss = self.loss_function(logits=logits, labels=labels, vocab_size=self.config.vocab_size, **kwargs)
|
| 694 |
+
|
| 695 |
+
return CausalLMOutputWithPast(
|
| 696 |
+
loss=loss,
|
| 697 |
+
logits=logits,
|
| 698 |
+
past_key_values=outputs.past_key_values,
|
| 699 |
+
hidden_states=outputs.hidden_states,
|
| 700 |
+
attentions=outputs.attentions,
|
| 701 |
+
)
|
| 702 |
+
|
| 703 |
+
|
| 704 |
+
__all__ = ["Lfm2MoeForCausalLM", "Lfm2MoeModel", "Lfm2MoePreTrainedModel"]
|
third_party/transformers/src/transformers/models/lfm2_moe/modular_lfm2_moe.py
ADDED
|
@@ -0,0 +1,214 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
# Copyright 2025 The HuggingFace Team. All rights reserved.
|
| 2 |
+
#
|
| 3 |
+
# Licensed under the Apache License, Version 2.0 (the "License");
|
| 4 |
+
# you may not use this file except in compliance with the License.
|
| 5 |
+
# You may obtain a copy of the License at
|
| 6 |
+
#
|
| 7 |
+
# http://www.apache.org/licenses/LICENSE-2.0
|
| 8 |
+
#
|
| 9 |
+
# Unless required by applicable law or agreed to in writing, software
|
| 10 |
+
# distributed under the License is distributed on an "AS IS" BASIS,
|
| 11 |
+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
| 12 |
+
# See the License for the specific language governing permissions and
|
| 13 |
+
# limitations under the License.
|
| 14 |
+
|
| 15 |
+
import torch
|
| 16 |
+
import torch.nn.functional as F
|
| 17 |
+
from torch import nn
|
| 18 |
+
|
| 19 |
+
from ... import initialization as init
|
| 20 |
+
from ...cache_utils import Cache, DynamicCache
|
| 21 |
+
from ...masking_utils import create_causal_mask
|
| 22 |
+
from ...modeling_outputs import MoeModelOutputWithPast
|
| 23 |
+
from ...modeling_utils import PreTrainedModel
|
| 24 |
+
from ...processing_utils import Unpack
|
| 25 |
+
from ...utils import TransformersKwargs, logging
|
| 26 |
+
from ...utils.import_utils import is_causal_conv1d_available
|
| 27 |
+
from ..lfm2.modeling_lfm2 import (
|
| 28 |
+
Lfm2Attention,
|
| 29 |
+
Lfm2DecoderLayer,
|
| 30 |
+
Lfm2MLP,
|
| 31 |
+
Lfm2RotaryEmbedding,
|
| 32 |
+
Lfm2ShortConv,
|
| 33 |
+
)
|
| 34 |
+
from ..llama.modeling_llama import LlamaForCausalLM, LlamaPreTrainedModel, LlamaRMSNorm
|
| 35 |
+
from ..mixtral.modeling_mixtral import MixtralModel
|
| 36 |
+
from ..qwen2_moe.modeling_qwen2_moe import Qwen2MoeExperts
|
| 37 |
+
from .configuration_lfm2_moe import Lfm2MoeConfig
|
| 38 |
+
|
| 39 |
+
|
| 40 |
+
if is_causal_conv1d_available():
|
| 41 |
+
from causal_conv1d import causal_conv1d_fn, causal_conv1d_update
|
| 42 |
+
else:
|
| 43 |
+
causal_conv1d_fn, causal_conv1d_update = None, None
|
| 44 |
+
|
| 45 |
+
|
| 46 |
+
kernel_modules = (causal_conv1d_fn, causal_conv1d_update)
|
| 47 |
+
is_fast_path_available = all(kernel_modules)
|
| 48 |
+
|
| 49 |
+
|
| 50 |
+
logger = logging.get_logger(__name__)
|
| 51 |
+
|
| 52 |
+
|
| 53 |
+
class Lfm2MoeRMSNorm(LlamaRMSNorm):
|
| 54 |
+
pass
|
| 55 |
+
|
| 56 |
+
|
| 57 |
+
class Lfm2MoeRotaryEmbedding(Lfm2RotaryEmbedding):
|
| 58 |
+
pass
|
| 59 |
+
|
| 60 |
+
|
| 61 |
+
class Lfm2MoeMLP(Lfm2MLP):
|
| 62 |
+
def __init__(self, config: Lfm2MoeConfig, intermediate_size: int | None = None):
|
| 63 |
+
nn.Module.__init__(self)
|
| 64 |
+
self.hidden_size = config.hidden_size
|
| 65 |
+
self.intermediate_size = config.intermediate_size if intermediate_size is None else intermediate_size
|
| 66 |
+
self.w1 = nn.Linear(self.hidden_size, self.intermediate_size, bias=False)
|
| 67 |
+
self.w3 = nn.Linear(self.hidden_size, self.intermediate_size, bias=False)
|
| 68 |
+
self.w2 = nn.Linear(self.intermediate_size, self.hidden_size, bias=False)
|
| 69 |
+
|
| 70 |
+
|
| 71 |
+
class Lfm2MoeExperts(Qwen2MoeExperts):
|
| 72 |
+
def __init__(self, config):
|
| 73 |
+
super().__init__(config)
|
| 74 |
+
self.act_fn = F.silu
|
| 75 |
+
|
| 76 |
+
|
| 77 |
+
class Lfm2MoeSparseMoeBlock(nn.Module):
|
| 78 |
+
def __init__(self, config):
|
| 79 |
+
super().__init__()
|
| 80 |
+
self.top_k = config.num_experts_per_tok
|
| 81 |
+
self.routed_scaling_factor = config.routed_scaling_factor
|
| 82 |
+
self.norm_topk_prob = config.norm_topk_prob
|
| 83 |
+
self.use_expert_bias = config.use_expert_bias
|
| 84 |
+
|
| 85 |
+
self.gate = nn.Linear(config.hidden_size, config.num_experts, bias=False)
|
| 86 |
+
self.experts = Lfm2MoeExperts(config)
|
| 87 |
+
if self.use_expert_bias:
|
| 88 |
+
self.register_buffer("expert_bias", torch.zeros(config.num_experts, dtype=torch.float32))
|
| 89 |
+
|
| 90 |
+
def route_tokens_to_experts(self, router_logits):
|
| 91 |
+
routing_weights = router_logits.sigmoid()
|
| 92 |
+
if self.use_expert_bias:
|
| 93 |
+
scores_for_routing = routing_weights + self.expert_bias
|
| 94 |
+
_, selected_experts = torch.topk(scores_for_routing, k=self.top_k, dim=-1)
|
| 95 |
+
routing_weights = torch.gather(routing_weights, dim=1, index=selected_experts).type_as(router_logits)
|
| 96 |
+
else:
|
| 97 |
+
routing_weights, selected_experts = torch.topk(routing_weights, k=self.top_k, dim=-1)
|
| 98 |
+
|
| 99 |
+
if self.norm_topk_prob:
|
| 100 |
+
routing_weights = routing_weights / (routing_weights.sum(dim=-1, keepdim=True) + 1e-6)
|
| 101 |
+
routing_weights = routing_weights * self.routed_scaling_factor
|
| 102 |
+
return selected_experts, routing_weights
|
| 103 |
+
|
| 104 |
+
def forward(self, hidden_states: torch.Tensor) -> tuple[torch.Tensor, torch.Tensor]:
|
| 105 |
+
batch_size, sequence_length, hidden_dim = hidden_states.shape
|
| 106 |
+
hidden_states_reshaped = hidden_states.view(-1, hidden_dim)
|
| 107 |
+
router_logits = self.gate(hidden_states_reshaped)
|
| 108 |
+
selected_experts, routing_weights = self.route_tokens_to_experts(router_logits)
|
| 109 |
+
final_hidden_states = self.experts(hidden_states_reshaped, selected_experts, routing_weights)
|
| 110 |
+
return final_hidden_states.reshape(batch_size, sequence_length, hidden_dim)
|
| 111 |
+
|
| 112 |
+
|
| 113 |
+
class Lfm2MoeAttention(Lfm2Attention):
|
| 114 |
+
pass
|
| 115 |
+
|
| 116 |
+
|
| 117 |
+
class Lfm2MoeShortConv(Lfm2ShortConv):
|
| 118 |
+
pass
|
| 119 |
+
|
| 120 |
+
|
| 121 |
+
class Lfm2MoeDecoderLayer(Lfm2DecoderLayer):
|
| 122 |
+
def __init__(self, config: Lfm2MoeConfig, layer_idx: int):
|
| 123 |
+
super().__init__(config, layer_idx)
|
| 124 |
+
self.feed_forward = (
|
| 125 |
+
Lfm2MoeMLP(config, intermediate_size=config.intermediate_size)
|
| 126 |
+
if layer_idx < config.num_dense_layers
|
| 127 |
+
else Lfm2MoeSparseMoeBlock(config)
|
| 128 |
+
)
|
| 129 |
+
|
| 130 |
+
|
| 131 |
+
class Lfm2MoePreTrainedModel(LlamaPreTrainedModel):
|
| 132 |
+
_can_compile_fullgraph = False # uses a non-compilable cache class
|
| 133 |
+
|
| 134 |
+
@torch.no_grad()
|
| 135 |
+
def _init_weights(self, module):
|
| 136 |
+
PreTrainedModel._init_weights(self, module)
|
| 137 |
+
if isinstance(module, Lfm2MoeExperts):
|
| 138 |
+
init.normal_(module.gate_up_proj, mean=0.0, std=self.config.initializer_range)
|
| 139 |
+
init.normal_(module.down_proj, mean=0.0, std=self.config.initializer_range)
|
| 140 |
+
elif isinstance(module, Lfm2MoeSparseMoeBlock):
|
| 141 |
+
if module.use_expert_bias:
|
| 142 |
+
init.zeros_(module.expert_bias)
|
| 143 |
+
|
| 144 |
+
|
| 145 |
+
class Lfm2MoeModel(MixtralModel):
|
| 146 |
+
def __init__(self, config: Lfm2MoeConfig):
|
| 147 |
+
super().__init__(config)
|
| 148 |
+
self.pos_emb = Lfm2MoeRotaryEmbedding(config)
|
| 149 |
+
self.embedding_norm = Lfm2MoeRMSNorm(config.hidden_size, eps=config.norm_eps)
|
| 150 |
+
del self.norm
|
| 151 |
+
del self.rotary_emb
|
| 152 |
+
|
| 153 |
+
def forward(
|
| 154 |
+
self,
|
| 155 |
+
input_ids: torch.LongTensor | None = None,
|
| 156 |
+
attention_mask: torch.Tensor | None = None,
|
| 157 |
+
position_ids: torch.LongTensor | None = None,
|
| 158 |
+
past_key_values: Cache | None = None,
|
| 159 |
+
inputs_embeds: torch.FloatTensor | None = None,
|
| 160 |
+
use_cache: bool | None = None,
|
| 161 |
+
**kwargs: Unpack[TransformersKwargs],
|
| 162 |
+
) -> MoeModelOutputWithPast:
|
| 163 |
+
if (input_ids is None) ^ (inputs_embeds is not None):
|
| 164 |
+
raise ValueError("You must specify exactly one of input_ids or inputs_embeds")
|
| 165 |
+
|
| 166 |
+
if inputs_embeds is None:
|
| 167 |
+
inputs_embeds = self.embed_tokens(input_ids)
|
| 168 |
+
|
| 169 |
+
if use_cache and past_key_values is None:
|
| 170 |
+
past_key_values = DynamicCache(config=self.config)
|
| 171 |
+
|
| 172 |
+
if position_ids is None:
|
| 173 |
+
past_seen_tokens = past_key_values.get_seq_length() if past_key_values is not None else 0
|
| 174 |
+
position_ids = torch.arange(inputs_embeds.shape[1], device=inputs_embeds.device) + past_seen_tokens
|
| 175 |
+
position_ids = position_ids.unsqueeze(0)
|
| 176 |
+
|
| 177 |
+
causal_mask = create_causal_mask(
|
| 178 |
+
config=self.config,
|
| 179 |
+
inputs_embeds=inputs_embeds,
|
| 180 |
+
attention_mask=attention_mask,
|
| 181 |
+
past_key_values=past_key_values,
|
| 182 |
+
position_ids=position_ids,
|
| 183 |
+
)
|
| 184 |
+
# Skip masking for decoding stage. We check shape here to be compile-friendly
|
| 185 |
+
linear_attention = attention_mask if inputs_embeds.shape[1] != 1 else None
|
| 186 |
+
|
| 187 |
+
hidden_states = inputs_embeds
|
| 188 |
+
position_embeddings = self.pos_emb(hidden_states, position_ids=position_ids)
|
| 189 |
+
|
| 190 |
+
# decoder layers
|
| 191 |
+
for i, decoder_layer in enumerate(self.layers[: self.config.num_hidden_layers]):
|
| 192 |
+
layer_mask = causal_mask if self.config.layer_types[i] == "full_attention" else linear_attention
|
| 193 |
+
hidden_states = decoder_layer(
|
| 194 |
+
hidden_states,
|
| 195 |
+
attention_mask=layer_mask,
|
| 196 |
+
position_ids=position_ids,
|
| 197 |
+
past_key_values=past_key_values,
|
| 198 |
+
position_embeddings=position_embeddings,
|
| 199 |
+
**kwargs,
|
| 200 |
+
)
|
| 201 |
+
|
| 202 |
+
hidden_states = self.embedding_norm(hidden_states)
|
| 203 |
+
|
| 204 |
+
return MoeModelOutputWithPast(
|
| 205 |
+
last_hidden_state=hidden_states,
|
| 206 |
+
past_key_values=past_key_values,
|
| 207 |
+
)
|
| 208 |
+
|
| 209 |
+
|
| 210 |
+
class Lfm2MoeForCausalLM(LlamaForCausalLM):
|
| 211 |
+
pass
|
| 212 |
+
|
| 213 |
+
|
| 214 |
+
__all__ = ["Lfm2MoeForCausalLM", "Lfm2MoeModel", "Lfm2MoePreTrainedModel"]
|
third_party/transformers/src/transformers/models/lfm2_vl/__init__.py
ADDED
|
@@ -0,0 +1,29 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
# Copyright 2025 The HuggingFace Team. All rights reserved.
|
| 2 |
+
#
|
| 3 |
+
# Licensed under the Apache License, Version 2.0 (the "License");
|
| 4 |
+
# you may not use this file except in compliance with the License.
|
| 5 |
+
# You may obtain a copy of the License at
|
| 6 |
+
#
|
| 7 |
+
# http://www.apache.org/licenses/LICENSE-2.0
|
| 8 |
+
#
|
| 9 |
+
# Unless required by applicable law or agreed to in writing, software
|
| 10 |
+
# distributed under the License is distributed on an "AS IS" BASIS,
|
| 11 |
+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
| 12 |
+
# See the License for the specific language governing permissions and
|
| 13 |
+
# limitations under the License.
|
| 14 |
+
from typing import TYPE_CHECKING
|
| 15 |
+
|
| 16 |
+
from ...utils import _LazyModule
|
| 17 |
+
from ...utils.import_utils import define_import_structure
|
| 18 |
+
|
| 19 |
+
|
| 20 |
+
if TYPE_CHECKING:
|
| 21 |
+
from .configuration_lfm2_vl import *
|
| 22 |
+
from .image_processing_lfm2_vl import *
|
| 23 |
+
from .modeling_lfm2_vl import *
|
| 24 |
+
from .processing_lfm2_vl import *
|
| 25 |
+
else:
|
| 26 |
+
import sys
|
| 27 |
+
|
| 28 |
+
_file = globals()["__file__"]
|
| 29 |
+
sys.modules[__name__] = _LazyModule(__name__, _file, define_import_structure(_file), module_spec=__spec__)
|
third_party/transformers/src/transformers/models/lfm2_vl/configuration_lfm2_vl.py
ADDED
|
@@ -0,0 +1,63 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
# Copyright 2025 the HuggingFace Inc. team. All rights reserved.
|
| 2 |
+
#
|
| 3 |
+
# Licensed under the Apache License, Version 2.0 (the "License");
|
| 4 |
+
# you may not use this file except in compliance with the License.
|
| 5 |
+
# You may obtain a copy of the License at
|
| 6 |
+
#
|
| 7 |
+
# http://www.apache.org/licenses/LICENSE-2.0
|
| 8 |
+
#
|
| 9 |
+
# Unless required by applicable law or agreed to in writing, software
|
| 10 |
+
# distributed under the License is distributed on an "AS IS" BASIS,
|
| 11 |
+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
| 12 |
+
# See the License for the specific language governing permissions and
|
| 13 |
+
# limitations under the License.
|
| 14 |
+
"""PyTorch LFM2-VL model."""
|
| 15 |
+
|
| 16 |
+
from huggingface_hub.dataclasses import strict
|
| 17 |
+
|
| 18 |
+
from ...configuration_utils import PreTrainedConfig
|
| 19 |
+
from ...utils import auto_docstring
|
| 20 |
+
from ..auto import CONFIG_MAPPING, AutoConfig
|
| 21 |
+
|
| 22 |
+
|
| 23 |
+
@auto_docstring(checkpoint="LiquidAI/LFM2-VL-1.6B")
|
| 24 |
+
@strict
|
| 25 |
+
class Lfm2VlConfig(PreTrainedConfig):
|
| 26 |
+
r"""
|
| 27 |
+
projector_use_layernorm (`bool`, *optional*, defaults to `True`):
|
| 28 |
+
Whether to use layernorm in the multimodal projector.
|
| 29 |
+
downsample_factor (`int`, *optional*, defaults to 2):
|
| 30 |
+
The downsample_factor factor of the vision backbone.
|
| 31 |
+
"""
|
| 32 |
+
|
| 33 |
+
model_type = "lfm2_vl"
|
| 34 |
+
sub_configs = {"text_config": AutoConfig, "vision_config": AutoConfig}
|
| 35 |
+
|
| 36 |
+
vision_config: dict | PreTrainedConfig | None = None
|
| 37 |
+
text_config: dict | PreTrainedConfig | None = None
|
| 38 |
+
image_token_id: int = 396
|
| 39 |
+
projector_hidden_act: str = "gelu"
|
| 40 |
+
projector_hidden_size: int = 2560
|
| 41 |
+
projector_bias: bool = True
|
| 42 |
+
projector_use_layernorm: bool = True
|
| 43 |
+
downsample_factor: int = 2
|
| 44 |
+
tie_word_embeddings: bool = True
|
| 45 |
+
|
| 46 |
+
def __post_init__(self, **kwargs):
|
| 47 |
+
if isinstance(self.vision_config, dict):
|
| 48 |
+
self.vision_config["model_type"] = self.vision_config.get("model_type", "siglip2_vision_model")
|
| 49 |
+
self.vision_config = CONFIG_MAPPING[self.vision_config["model_type"]](**self.vision_config)
|
| 50 |
+
elif self.vision_config is None:
|
| 51 |
+
self.vision_config = CONFIG_MAPPING["siglip2_vision_model"]()
|
| 52 |
+
|
| 53 |
+
if isinstance(self.text_config, dict):
|
| 54 |
+
self.text_config["model_type"] = self.text_config.get("model_type", "lfm2")
|
| 55 |
+
self.text_config = CONFIG_MAPPING[self.text_config["model_type"]](**self.text_config)
|
| 56 |
+
elif self.text_config is None:
|
| 57 |
+
self.text_config = CONFIG_MAPPING["lfm2"]()
|
| 58 |
+
|
| 59 |
+
self.tie_word_embeddings = kwargs.pop("tie_embedding", self.tie_word_embeddings)
|
| 60 |
+
super().__post_init__(**kwargs)
|
| 61 |
+
|
| 62 |
+
|
| 63 |
+
__all__ = ["Lfm2VlConfig"]
|
third_party/transformers/src/transformers/models/lfm2_vl/image_processing_lfm2_vl.py
ADDED
|
@@ -0,0 +1,561 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
# Copyright 2025 the HuggingFace Inc. team. All rights reserved.
|
| 2 |
+
#
|
| 3 |
+
# Licensed under the Apache License, Version 2.0 (the "License");
|
| 4 |
+
# you may not use this file except in compliance with the License.
|
| 5 |
+
# You may obtain a copy of the License at
|
| 6 |
+
#
|
| 7 |
+
# http://www.apache.org/licenses/LICENSE-2.0
|
| 8 |
+
#
|
| 9 |
+
# Unless required by applicable law or agreed to in writing, software
|
| 10 |
+
# distributed under the License is distributed on an "AS IS" BASIS,
|
| 11 |
+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
| 12 |
+
# See the License for the specific language governing permissions and
|
| 13 |
+
# limitations under the License.
|
| 14 |
+
import math
|
| 15 |
+
from functools import lru_cache
|
| 16 |
+
|
| 17 |
+
import torch
|
| 18 |
+
from torchvision.transforms.v2 import functional as tvF
|
| 19 |
+
|
| 20 |
+
from ...image_processing_backends import TorchvisionBackend
|
| 21 |
+
from ...image_processing_utils import BatchFeature
|
| 22 |
+
from ...image_transforms import group_images_by_shape, reorder_images, split_to_tiles
|
| 23 |
+
from ...image_utils import (
|
| 24 |
+
IMAGENET_STANDARD_MEAN,
|
| 25 |
+
IMAGENET_STANDARD_STD,
|
| 26 |
+
PILImageResampling,
|
| 27 |
+
SizeDict,
|
| 28 |
+
)
|
| 29 |
+
from ...processing_utils import ImagesKwargs, Unpack
|
| 30 |
+
from ...utils import (
|
| 31 |
+
TensorType,
|
| 32 |
+
auto_docstring,
|
| 33 |
+
logging,
|
| 34 |
+
)
|
| 35 |
+
|
| 36 |
+
|
| 37 |
+
logger = logging.get_logger(__name__)
|
| 38 |
+
|
| 39 |
+
|
| 40 |
+
def round_by_factor(number: float, factor: int) -> int:
|
| 41 |
+
"""Returns the closest integer to 'number' that is divisible by 'factor'."""
|
| 42 |
+
return round(number / factor) * factor
|
| 43 |
+
|
| 44 |
+
|
| 45 |
+
def find_closest_aspect_ratio(
|
| 46 |
+
aspect_ratio: float,
|
| 47 |
+
target_ratios: list[tuple[int, int]],
|
| 48 |
+
width: int,
|
| 49 |
+
height: int,
|
| 50 |
+
image_size: int,
|
| 51 |
+
) -> tuple[int, int]:
|
| 52 |
+
"""Find the closest aspect ratio from target_ratios to match the input aspect ratio.
|
| 53 |
+
|
| 54 |
+
Args:
|
| 55 |
+
aspect_ratio: The aspect ratio to match (width/height).
|
| 56 |
+
target_ratios: List of possible aspect ratios as tuples of (width, height) integers.
|
| 57 |
+
width: Original image width in pixels.
|
| 58 |
+
height: Original image height in pixels.
|
| 59 |
+
image_size: Base size for calculating target area.
|
| 60 |
+
|
| 61 |
+
Returns:
|
| 62 |
+
tuple[int, int]: The best matching ratio as (width, height) integers.
|
| 63 |
+
"""
|
| 64 |
+
best_ratio_diff = float("inf")
|
| 65 |
+
best_ratio = (1, 1)
|
| 66 |
+
area = width * height
|
| 67 |
+
|
| 68 |
+
for ratio in target_ratios:
|
| 69 |
+
target_aspect_ratio = ratio[0] / ratio[1]
|
| 70 |
+
ratio_diff = abs(aspect_ratio - target_aspect_ratio)
|
| 71 |
+
|
| 72 |
+
# update best ratio if we found a closer match
|
| 73 |
+
if ratio_diff < best_ratio_diff:
|
| 74 |
+
best_ratio_diff = ratio_diff
|
| 75 |
+
best_ratio = ratio
|
| 76 |
+
# if equally close, prefer the ratio that better matches the original image area
|
| 77 |
+
elif ratio_diff == best_ratio_diff:
|
| 78 |
+
target_area = image_size * image_size * ratio[0] * ratio[1]
|
| 79 |
+
if area > 0.5 * target_area:
|
| 80 |
+
best_ratio = ratio
|
| 81 |
+
|
| 82 |
+
return best_ratio
|
| 83 |
+
|
| 84 |
+
|
| 85 |
+
# copied from Siglip2ImageProcessor
|
| 86 |
+
@lru_cache(maxsize=256)
|
| 87 |
+
def get_image_size_for_max_num_patches(
|
| 88 |
+
image_height: int, image_width: int, patch_size: int, max_num_patches: int, eps: float = 1e-5
|
| 89 |
+
) -> tuple[int, int]:
|
| 90 |
+
"""
|
| 91 |
+
Determine image size based on max number of patches, ensure dimensions are divisible by patch size and image is at least 1 patch.
|
| 92 |
+
|
| 93 |
+
Args:
|
| 94 |
+
image_height (`int`):
|
| 95 |
+
Original image height.
|
| 96 |
+
image_width (`int`):
|
| 97 |
+
Original image width.
|
| 98 |
+
patch_size (`int`):
|
| 99 |
+
Patch size for processing.
|
| 100 |
+
max_num_patches (`int`):
|
| 101 |
+
Maximum number of patches.
|
| 102 |
+
eps (`float`):
|
| 103 |
+
Small threshold for binary search.
|
| 104 |
+
|
| 105 |
+
Returns:
|
| 106 |
+
Tuple: (target_height, target_width)
|
| 107 |
+
"""
|
| 108 |
+
|
| 109 |
+
def get_scaled_image_size(scale: float, size: int, patch_size: int) -> int:
|
| 110 |
+
scaled_size = size * scale
|
| 111 |
+
scaled_size = math.ceil(scaled_size / patch_size) * patch_size # make divisible by patch_size
|
| 112 |
+
scaled_size = max(patch_size, scaled_size) # ensure at least 1 patch
|
| 113 |
+
return int(scaled_size)
|
| 114 |
+
|
| 115 |
+
# Binary search for optimal scale
|
| 116 |
+
scale_min, scale_max = eps / 10, 100.0
|
| 117 |
+
while (scale_max - scale_min) >= eps:
|
| 118 |
+
scale = (scale_min + scale_max) / 2
|
| 119 |
+
target_height = get_scaled_image_size(scale, image_height, patch_size)
|
| 120 |
+
target_width = get_scaled_image_size(scale, image_width, patch_size)
|
| 121 |
+
num_patches = (target_height / patch_size) * (target_width / patch_size)
|
| 122 |
+
|
| 123 |
+
if num_patches <= max_num_patches:
|
| 124 |
+
scale_min = scale
|
| 125 |
+
else:
|
| 126 |
+
scale_max = scale
|
| 127 |
+
|
| 128 |
+
scale = scale_min
|
| 129 |
+
target_height = get_scaled_image_size(scale, image_height, patch_size)
|
| 130 |
+
target_width = get_scaled_image_size(scale, image_width, patch_size)
|
| 131 |
+
return target_height, target_width
|
| 132 |
+
|
| 133 |
+
|
| 134 |
+
def convert_image_to_patches(images: "torch.Tensor", patch_size: int) -> "torch.Tensor":
|
| 135 |
+
"""
|
| 136 |
+
Convert 3D array image of shape (image_height, image_width, num_channels) into 2D array of patches of shape
|
| 137 |
+
(num_patches_height * num_patches_width, patch_size * patch_size * num_channels).
|
| 138 |
+
"""
|
| 139 |
+
batch_size, num_channels, image_height, image_width = images.shape
|
| 140 |
+
num_patches_height = image_height // patch_size
|
| 141 |
+
num_patches_width = image_width // patch_size
|
| 142 |
+
patched_image = images.reshape(
|
| 143 |
+
batch_size, num_channels, num_patches_height, patch_size, num_patches_width, patch_size
|
| 144 |
+
)
|
| 145 |
+
patched_image = patched_image.permute(0, 2, 4, 3, 5, 1)
|
| 146 |
+
patched_image = patched_image.reshape(batch_size, num_patches_height * num_patches_width, -1)
|
| 147 |
+
return patched_image
|
| 148 |
+
|
| 149 |
+
|
| 150 |
+
def pad_along_first_dim(
|
| 151 |
+
images: "torch.Tensor", target_length: int, pad_value: int = 0
|
| 152 |
+
) -> tuple["torch.Tensor", "torch.Tensor"]:
|
| 153 |
+
"""
|
| 154 |
+
Pad the array along the first dimension.
|
| 155 |
+
"""
|
| 156 |
+
current_length = images.shape[1]
|
| 157 |
+
padding_length = target_length - current_length
|
| 158 |
+
pixel_mask = torch.ones((target_length,), dtype=torch.int32)
|
| 159 |
+
if padding_length > 0:
|
| 160 |
+
paddings = (0, 0, 0, padding_length, 0, 0)
|
| 161 |
+
images = torch.nn.functional.pad(images, paddings, mode="constant", value=pad_value)
|
| 162 |
+
pixel_mask[-padding_length:] = 0
|
| 163 |
+
return images, pixel_mask
|
| 164 |
+
|
| 165 |
+
|
| 166 |
+
class Lfm2VlImageProcessorKwargs(ImagesKwargs, total=False):
|
| 167 |
+
"""
|
| 168 |
+
downsample_factor (`int`, *optional*, defaults to `2`):
|
| 169 |
+
The downsampling factor for images used when resizing the image.
|
| 170 |
+
do_image_splitting (`bool`, *optional*, defaults to `True`):
|
| 171 |
+
Whether to split large images into a grid of smaller tiles. When enabled, images exceeding the maximum token
|
| 172 |
+
limit are divided into multiple tiles based on `min_tiles` and `max_tiles` constraints.
|
| 173 |
+
min_tiles (`int`, *optional*, defaults to `2`):
|
| 174 |
+
Minimum number of tiles (width × height) to use when splitting an image into a grid. The grid configuration
|
| 175 |
+
is chosen to maintain the original aspect ratio while staying within the `min_tiles` and `max_tiles` range.
|
| 176 |
+
max_tiles (`int`, *optional*, defaults to `10`):
|
| 177 |
+
Maximum number of tiles (width × height) to use when splitting an image into a grid. The grid configuration
|
| 178 |
+
is chosen to maintain the original aspect ratio while staying within the `min_tiles` and `max_tiles` range.
|
| 179 |
+
use_thumbnail (`bool`, *optional*, defaults to `True`):
|
| 180 |
+
Whether to include a thumbnail version of the image when splitting into tiles. The thumbnail provides a
|
| 181 |
+
low-resolution overview of the entire image and is added as an additional patch when the grid has more than
|
| 182 |
+
one tile.
|
| 183 |
+
min_image_tokens (`int`, *optional*, defaults to `64`):
|
| 184 |
+
Minimum number of image tokens (patches) to generate for an image. Images smaller than this threshold will
|
| 185 |
+
be upscaled to meet the minimum token requirement.
|
| 186 |
+
max_image_tokens (`int`, *optional*, defaults to `256`):
|
| 187 |
+
Maximum number of image tokens (patches) allowed for a single image. Images exceeding this limit will be
|
| 188 |
+
split into multiple tiles or downscaled accordingly.
|
| 189 |
+
encoder_patch_size (`int`, *optional*, defaults to `16`):
|
| 190 |
+
The patch size used by the vision encoder. Images are divided into patches of this size, and both height
|
| 191 |
+
and width must be divisible by this value (after accounting for the downsampling factor).
|
| 192 |
+
tile_size (`int`, *optional*, defaults to `512`):
|
| 193 |
+
The size of each tile when splitting large images into a grid. Each tile will be resized to this dimension
|
| 194 |
+
before being processed into patches.
|
| 195 |
+
max_pixels_tolerance (`float`, *optional*, defaults to `2.0`):
|
| 196 |
+
Tolerance factor for determining if an image is too large. An image is considered too large if its pixel
|
| 197 |
+
count exceeds `max_image_tokens * encoder_patch_size^2 * downsample_factor^2 * max_pixels_tolerance`.
|
| 198 |
+
return_row_col_info (`bool`, *optional*, defaults to `False`):
|
| 199 |
+
Whether to return row and column information for each image in the batch. When enabled, the output includes
|
| 200 |
+
`image_rows`, `image_cols`, and `image_sizes` fields indicating the grid layout and dimensions of processed images.
|
| 201 |
+
"""
|
| 202 |
+
|
| 203 |
+
downsample_factor: int
|
| 204 |
+
do_image_splitting: bool
|
| 205 |
+
min_tiles: int
|
| 206 |
+
max_tiles: int
|
| 207 |
+
use_thumbnail: bool
|
| 208 |
+
min_image_tokens: int
|
| 209 |
+
max_image_tokens: int
|
| 210 |
+
encoder_patch_size: int
|
| 211 |
+
tile_size: int
|
| 212 |
+
max_pixels_tolerance: float
|
| 213 |
+
do_pad: bool
|
| 214 |
+
return_row_col_info: bool
|
| 215 |
+
|
| 216 |
+
|
| 217 |
+
@auto_docstring
|
| 218 |
+
class Lfm2VlImageProcessor(TorchvisionBackend):
|
| 219 |
+
downsample_factor = 2
|
| 220 |
+
do_image_splitting = True
|
| 221 |
+
min_tiles = 2
|
| 222 |
+
max_tiles = 10
|
| 223 |
+
use_thumbnail = True
|
| 224 |
+
min_image_tokens = 64
|
| 225 |
+
max_image_tokens = 256
|
| 226 |
+
encoder_patch_size = 16
|
| 227 |
+
tile_size = 512
|
| 228 |
+
max_pixels_tolerance = 2.0
|
| 229 |
+
do_resize = True
|
| 230 |
+
size = {"height": 512, "width": 512}
|
| 231 |
+
resample = PILImageResampling.BILINEAR
|
| 232 |
+
do_rescale = True
|
| 233 |
+
rescale_factor = 1 / 255
|
| 234 |
+
do_normalize = True
|
| 235 |
+
do_pad = True
|
| 236 |
+
return_row_col_info = False
|
| 237 |
+
image_mean = IMAGENET_STANDARD_MEAN
|
| 238 |
+
image_std = IMAGENET_STANDARD_STD
|
| 239 |
+
valid_kwargs = Lfm2VlImageProcessorKwargs
|
| 240 |
+
model_input_names = ["pixel_values", "pixel_attention_mask", "spatial_shapes"]
|
| 241 |
+
|
| 242 |
+
def __init__(self, **kwargs: Unpack[Lfm2VlImageProcessorKwargs]):
|
| 243 |
+
super().__init__(**kwargs)
|
| 244 |
+
|
| 245 |
+
max_thumbnail_image_patches = self.max_image_tokens * self.downsample_factor**2
|
| 246 |
+
tile_size_patches = (self.tile_size // self.encoder_patch_size) ** 2 if self.do_image_splitting else 0
|
| 247 |
+
self.max_num_patches = max(
|
| 248 |
+
max_thumbnail_image_patches,
|
| 249 |
+
tile_size_patches,
|
| 250 |
+
)
|
| 251 |
+
|
| 252 |
+
@lru_cache(maxsize=256)
|
| 253 |
+
def _target_ratios(self, min_tiles: int, max_tiles: int) -> list[tuple[int, int]]:
|
| 254 |
+
ratios = [
|
| 255 |
+
(w, h)
|
| 256 |
+
for n in range(min_tiles, max_tiles + 1)
|
| 257 |
+
for w in range(1, n + 1)
|
| 258 |
+
for h in range(1, n + 1)
|
| 259 |
+
if min_tiles <= w * h <= max_tiles
|
| 260 |
+
]
|
| 261 |
+
return sorted(set(ratios), key=lambda x: x[0] * x[1])
|
| 262 |
+
|
| 263 |
+
def _get_grid_layout(
|
| 264 |
+
self,
|
| 265 |
+
height: int,
|
| 266 |
+
width: int,
|
| 267 |
+
min_tiles: int,
|
| 268 |
+
max_tiles: int,
|
| 269 |
+
tile_size: int,
|
| 270 |
+
) -> tuple[int, int]:
|
| 271 |
+
aspect_ratio = width / height
|
| 272 |
+
target_ratios = self._target_ratios(min_tiles, max_tiles)
|
| 273 |
+
|
| 274 |
+
# find best matching grid configuration
|
| 275 |
+
grid_width, grid_height = find_closest_aspect_ratio(aspect_ratio, target_ratios, width, height, tile_size)
|
| 276 |
+
|
| 277 |
+
target_width = tile_size * grid_width
|
| 278 |
+
target_height = tile_size * grid_height
|
| 279 |
+
total_patches = grid_width * grid_height
|
| 280 |
+
|
| 281 |
+
return grid_width, grid_height, target_width, target_height, total_patches
|
| 282 |
+
|
| 283 |
+
def crop_image_to_patches(
|
| 284 |
+
self,
|
| 285 |
+
image: "torch.Tensor",
|
| 286 |
+
min_tiles: int,
|
| 287 |
+
max_tiles: int,
|
| 288 |
+
tile_size: int,
|
| 289 |
+
use_thumbnail: bool,
|
| 290 |
+
thumbnail_size: tuple[int],
|
| 291 |
+
resample: "PILImageResampling | tvF.InterpolationMode | int | None" = None,
|
| 292 |
+
antialias: bool = True,
|
| 293 |
+
**kwargs,
|
| 294 |
+
) -> "torch.Tensor":
|
| 295 |
+
"""
|
| 296 |
+
Processes a high resolution image into patches.
|
| 297 |
+
This method splits a high resolution image into a grid of smaller patches while trying to maintain
|
| 298 |
+
the original aspect ratio. It finds the optimal grid configuration within the specified tile constraints.
|
| 299 |
+
"""
|
| 300 |
+
batch_size, num_channels, height, width = image.shape
|
| 301 |
+
grid_width, grid_height, target_width, target_height, total_patches = self._get_grid_layout(
|
| 302 |
+
height, width, min_tiles=min_tiles, max_tiles=max_tiles, tile_size=tile_size
|
| 303 |
+
)
|
| 304 |
+
|
| 305 |
+
resized_image = super().resize(
|
| 306 |
+
image, SizeDict(height=target_height, width=target_width), resample=resample, antialias=antialias
|
| 307 |
+
)
|
| 308 |
+
|
| 309 |
+
# split the image into patches
|
| 310 |
+
processed_images = split_to_tiles(resized_image, num_tiles_height=grid_height, num_tiles_width=grid_width)
|
| 311 |
+
|
| 312 |
+
# Re-order processed images to a nested image structure, so it can be reordered back correctly
|
| 313 |
+
# Note that the images can't be stacked because the thumbnail image is of bigger size than patches
|
| 314 |
+
# Each image in sublist will be of shape (1, C, H, W)
|
| 315 |
+
processed_images = list(processed_images)
|
| 316 |
+
|
| 317 |
+
if use_thumbnail and grid_width * grid_height != 1:
|
| 318 |
+
total_patches += 1
|
| 319 |
+
thumbnail_image = super().resize(
|
| 320 |
+
image,
|
| 321 |
+
SizeDict(height=thumbnail_size[0], width=thumbnail_size[1]),
|
| 322 |
+
resample=resample,
|
| 323 |
+
antialias=antialias,
|
| 324 |
+
)
|
| 325 |
+
for i in range(batch_size):
|
| 326 |
+
processed_images[i] = list(processed_images[i]) + list(thumbnail_image[i][None, ...])
|
| 327 |
+
|
| 328 |
+
return processed_images, grid_width, grid_height
|
| 329 |
+
|
| 330 |
+
# Adapted from Qwen-VL with minor differences
|
| 331 |
+
def smart_resize(
|
| 332 |
+
self,
|
| 333 |
+
height: int,
|
| 334 |
+
width: int,
|
| 335 |
+
downsample_factor: int,
|
| 336 |
+
min_image_tokens: int,
|
| 337 |
+
max_image_tokens: int,
|
| 338 |
+
encoder_patch_size: int,
|
| 339 |
+
) -> tuple[int, int]:
|
| 340 |
+
"""
|
| 341 |
+
Rescales the image so that the following conditions are met:
|
| 342 |
+
1. Both dimensions (height and width) are divisible by 'encoder_patch_size' * 'downsample_factor'.
|
| 343 |
+
This ensures no padding is needed in the downsampling step.
|
| 344 |
+
2. The total number of pixels is within the range ['smart_resize_min_pixels', 'smart_resize_max_pixels'].
|
| 345 |
+
3. The aspect ratio of the image is maintained as closely as possible.
|
| 346 |
+
"""
|
| 347 |
+
total_factor = encoder_patch_size * downsample_factor
|
| 348 |
+
smart_resize_min_pixels = min_image_tokens * encoder_patch_size**2 * downsample_factor**2
|
| 349 |
+
smart_resize_max_pixels = max_image_tokens * encoder_patch_size**2 * downsample_factor**2
|
| 350 |
+
|
| 351 |
+
h_bar = max(total_factor, round_by_factor(height, total_factor))
|
| 352 |
+
w_bar = max(total_factor, round_by_factor(width, total_factor))
|
| 353 |
+
|
| 354 |
+
if h_bar * w_bar > smart_resize_max_pixels:
|
| 355 |
+
beta = math.sqrt((height * width) / smart_resize_max_pixels)
|
| 356 |
+
math.floor(height / beta / total_factor) * total_factor
|
| 357 |
+
h_bar = max(total_factor, math.floor(height / beta / total_factor) * total_factor)
|
| 358 |
+
w_bar = max(total_factor, math.floor(width / beta / total_factor) * total_factor)
|
| 359 |
+
elif h_bar * w_bar < smart_resize_min_pixels:
|
| 360 |
+
beta = math.sqrt(smart_resize_min_pixels / (height * width))
|
| 361 |
+
h_bar = math.ceil(height * beta / total_factor) * total_factor
|
| 362 |
+
w_bar = math.ceil(width * beta / total_factor) * total_factor
|
| 363 |
+
|
| 364 |
+
return w_bar, h_bar
|
| 365 |
+
|
| 366 |
+
def _is_image_too_large(
|
| 367 |
+
self,
|
| 368 |
+
height: int,
|
| 369 |
+
width: int,
|
| 370 |
+
max_image_tokens: int,
|
| 371 |
+
encoder_patch_size: int,
|
| 372 |
+
downsample_factor: int,
|
| 373 |
+
max_pixels_tolerance: float,
|
| 374 |
+
) -> bool:
|
| 375 |
+
"""Check if the image is too large to be processed as one tile."""
|
| 376 |
+
total_factor = encoder_patch_size * downsample_factor
|
| 377 |
+
|
| 378 |
+
h_bar = max(encoder_patch_size, round_by_factor(height, total_factor))
|
| 379 |
+
w_bar = max(encoder_patch_size, round_by_factor(width, total_factor))
|
| 380 |
+
return h_bar * w_bar > max_image_tokens * encoder_patch_size**2 * downsample_factor**2 * max_pixels_tolerance
|
| 381 |
+
|
| 382 |
+
def resize_and_split(
|
| 383 |
+
self,
|
| 384 |
+
images: "torch.Tensor",
|
| 385 |
+
downsample_factor: int,
|
| 386 |
+
min_tiles: int,
|
| 387 |
+
max_tiles: int,
|
| 388 |
+
use_thumbnail: bool,
|
| 389 |
+
min_image_tokens: int,
|
| 390 |
+
max_image_tokens: int,
|
| 391 |
+
encoder_patch_size: int,
|
| 392 |
+
tile_size: int,
|
| 393 |
+
max_pixels_tolerance: float,
|
| 394 |
+
resample: "PILImageResampling | tvF.InterpolationMode | int | None",
|
| 395 |
+
) -> tuple[list["torch.Tensor"], list[list[int]], list[list[int]], list[list[tuple[int, int]]]]:
|
| 396 |
+
batch_size, _, height, width = images.shape
|
| 397 |
+
do_image_splitting = not min_tiles == max_tiles == 1
|
| 398 |
+
is_image_large = self._is_image_too_large(
|
| 399 |
+
height=height,
|
| 400 |
+
width=width,
|
| 401 |
+
max_image_tokens=max_image_tokens,
|
| 402 |
+
encoder_patch_size=encoder_patch_size,
|
| 403 |
+
downsample_factor=downsample_factor,
|
| 404 |
+
max_pixels_tolerance=max_pixels_tolerance,
|
| 405 |
+
)
|
| 406 |
+
|
| 407 |
+
new_width, new_height = self.smart_resize(
|
| 408 |
+
height=height,
|
| 409 |
+
width=width,
|
| 410 |
+
downsample_factor=downsample_factor,
|
| 411 |
+
min_image_tokens=min_image_tokens,
|
| 412 |
+
max_image_tokens=max_image_tokens,
|
| 413 |
+
encoder_patch_size=encoder_patch_size,
|
| 414 |
+
)
|
| 415 |
+
|
| 416 |
+
# Big image will be cropped into patches and small images are just resized
|
| 417 |
+
if is_image_large and do_image_splitting:
|
| 418 |
+
images, num_cols, num_rows = self.crop_image_to_patches(
|
| 419 |
+
images,
|
| 420 |
+
min_tiles=min_tiles,
|
| 421 |
+
max_tiles=max_tiles,
|
| 422 |
+
tile_size=tile_size,
|
| 423 |
+
thumbnail_size=(new_height, new_width),
|
| 424 |
+
use_thumbnail=use_thumbnail,
|
| 425 |
+
resample=resample,
|
| 426 |
+
)
|
| 427 |
+
else:
|
| 428 |
+
num_rows = num_cols = 1
|
| 429 |
+
images = super().resize(images, SizeDict(height=new_height, width=new_width), resample=resample)
|
| 430 |
+
# Make a list and treat it as single crop per image so it can be re-grouped back correctly
|
| 431 |
+
images = [[image] for image in images]
|
| 432 |
+
|
| 433 |
+
num_rows = [num_rows] * batch_size
|
| 434 |
+
num_cols = [num_cols] * batch_size
|
| 435 |
+
image_sizes = [[new_height, new_width]] * batch_size
|
| 436 |
+
return images, num_rows, num_cols, image_sizes
|
| 437 |
+
|
| 438 |
+
def _preprocess(
|
| 439 |
+
self,
|
| 440 |
+
images: list["torch.Tensor"],
|
| 441 |
+
do_resize: bool,
|
| 442 |
+
resample: "PILImageResampling | tvF.InterpolationMode | int | None",
|
| 443 |
+
do_rescale: bool,
|
| 444 |
+
rescale_factor: float,
|
| 445 |
+
do_normalize: bool,
|
| 446 |
+
image_mean: float | list[float],
|
| 447 |
+
image_std: float | list[float],
|
| 448 |
+
downsample_factor: int,
|
| 449 |
+
do_image_splitting: bool,
|
| 450 |
+
min_tiles: int,
|
| 451 |
+
max_tiles: int,
|
| 452 |
+
use_thumbnail: bool,
|
| 453 |
+
min_image_tokens: int,
|
| 454 |
+
max_image_tokens: int,
|
| 455 |
+
encoder_patch_size: int,
|
| 456 |
+
tile_size: int,
|
| 457 |
+
max_pixels_tolerance: float,
|
| 458 |
+
do_pad: bool,
|
| 459 |
+
return_row_col_info: bool,
|
| 460 |
+
return_tensors: str | TensorType | None,
|
| 461 |
+
disable_grouping: bool | None,
|
| 462 |
+
**kwargs,
|
| 463 |
+
) -> BatchFeature:
|
| 464 |
+
if not do_image_splitting:
|
| 465 |
+
min_tiles = 1
|
| 466 |
+
max_tiles = 1
|
| 467 |
+
logger.debug(
|
| 468 |
+
"Image splitting is disabled, setting min_tiles and max_tiles to 1. Set do_image_splitting=True to enable splitting."
|
| 469 |
+
)
|
| 470 |
+
|
| 471 |
+
if do_image_splitting and min_tiles > max_tiles:
|
| 472 |
+
raise ValueError("min_tiles must be less than or equal to max_tiles")
|
| 473 |
+
|
| 474 |
+
max_thumbnail_image_patches = max_image_tokens * downsample_factor**2
|
| 475 |
+
tile_size_patches = (tile_size // encoder_patch_size) ** 2 if do_image_splitting else 0
|
| 476 |
+
max_num_patches = max(
|
| 477 |
+
max_thumbnail_image_patches,
|
| 478 |
+
tile_size_patches,
|
| 479 |
+
)
|
| 480 |
+
|
| 481 |
+
grouped_images, grouped_images_index = group_images_by_shape(images, disable_grouping=disable_grouping)
|
| 482 |
+
resized_images_grouped = {}
|
| 483 |
+
resized_image_sizes = {}
|
| 484 |
+
rows_grouped, cols_grouped = {}, {}
|
| 485 |
+
for shape, stacked_images in grouped_images.items():
|
| 486 |
+
num_rows = [1] * stacked_images.shape[0]
|
| 487 |
+
num_cols = [1] * stacked_images.shape[0]
|
| 488 |
+
height, width = stacked_images.shape[-2:]
|
| 489 |
+
image_sizes = [[height, width]] * stacked_images.shape[0]
|
| 490 |
+
do_resize = True
|
| 491 |
+
|
| 492 |
+
if do_resize:
|
| 493 |
+
stacked_images, num_rows, num_cols, image_sizes = self.resize_and_split(
|
| 494 |
+
stacked_images,
|
| 495 |
+
downsample_factor=downsample_factor,
|
| 496 |
+
min_tiles=min_tiles,
|
| 497 |
+
max_tiles=max_tiles,
|
| 498 |
+
use_thumbnail=use_thumbnail,
|
| 499 |
+
min_image_tokens=min_image_tokens,
|
| 500 |
+
max_image_tokens=max_image_tokens,
|
| 501 |
+
encoder_patch_size=encoder_patch_size,
|
| 502 |
+
tile_size=tile_size,
|
| 503 |
+
max_pixels_tolerance=max_pixels_tolerance,
|
| 504 |
+
resample=resample,
|
| 505 |
+
)
|
| 506 |
+
|
| 507 |
+
rows_grouped[shape] = num_rows
|
| 508 |
+
cols_grouped[shape] = num_cols
|
| 509 |
+
resized_image_sizes[shape] = image_sizes
|
| 510 |
+
resized_images_grouped[shape] = stacked_images
|
| 511 |
+
resized_images = reorder_images(resized_images_grouped, grouped_images_index)
|
| 512 |
+
batch_rows = reorder_images(rows_grouped, grouped_images_index)
|
| 513 |
+
batch_cols = reorder_images(cols_grouped, grouped_images_index)
|
| 514 |
+
resized_image_sizes = reorder_images(resized_image_sizes, grouped_images_index)
|
| 515 |
+
|
| 516 |
+
grouped_images, grouped_images_index = group_images_by_shape(
|
| 517 |
+
resized_images, disable_grouping=disable_grouping, is_nested=True
|
| 518 |
+
)
|
| 519 |
+
|
| 520 |
+
processed_images_grouped = {}
|
| 521 |
+
processed_masks, processed_spatial_shapes = {}, {}
|
| 522 |
+
for shape, stacked_images in grouped_images.items():
|
| 523 |
+
# Fused rescale and normalize
|
| 524 |
+
stacked_images = self.rescale_and_normalize(
|
| 525 |
+
stacked_images, do_rescale, rescale_factor, do_normalize, image_mean, image_std
|
| 526 |
+
)
|
| 527 |
+
batch_size, *_, height, width = stacked_images.shape
|
| 528 |
+
num_patches_height = height // encoder_patch_size
|
| 529 |
+
num_patches_width = width // encoder_patch_size
|
| 530 |
+
|
| 531 |
+
stacked_images = convert_image_to_patches(stacked_images, encoder_patch_size)
|
| 532 |
+
processed_spatial_shapes[shape] = [[num_patches_height, num_patches_width]] * batch_size
|
| 533 |
+
|
| 534 |
+
if do_pad:
|
| 535 |
+
stacked_images, pixel_mask = pad_along_first_dim(stacked_images, max_num_patches)
|
| 536 |
+
processed_masks[shape] = [pixel_mask] * batch_size
|
| 537 |
+
|
| 538 |
+
processed_images_grouped[shape] = stacked_images
|
| 539 |
+
|
| 540 |
+
processed_images = reorder_images(processed_images_grouped, grouped_images_index, is_nested=True)
|
| 541 |
+
data = {"pixel_values": torch.cat([torch.stack(images) for images in processed_images])}
|
| 542 |
+
|
| 543 |
+
if do_pad:
|
| 544 |
+
processed_masks = reorder_images(processed_masks, grouped_images_index, is_nested=True)
|
| 545 |
+
processed_spatial_shapes = reorder_images(processed_spatial_shapes, grouped_images_index, is_nested=True)
|
| 546 |
+
processed_masks = torch.cat([torch.stack(masks) for masks in processed_masks])
|
| 547 |
+
processed_spatial_shapes = torch.cat(
|
| 548 |
+
[torch.tensor(spatial_shape) for spatial_shape in processed_spatial_shapes]
|
| 549 |
+
)
|
| 550 |
+
data.update({"pixel_attention_mask": processed_masks, "spatial_shapes": processed_spatial_shapes})
|
| 551 |
+
|
| 552 |
+
if return_row_col_info:
|
| 553 |
+
data["image_rows"] = batch_rows
|
| 554 |
+
data["image_cols"] = batch_cols
|
| 555 |
+
data["image_sizes"] = resized_image_sizes
|
| 556 |
+
|
| 557 |
+
encoding = BatchFeature(data=data, tensor_type=return_tensors)
|
| 558 |
+
return encoding
|
| 559 |
+
|
| 560 |
+
|
| 561 |
+
__all__ = ["Lfm2VlImageProcessor"]
|
third_party/transformers/src/transformers/models/lfm2_vl/modeling_lfm2_vl.py
ADDED
|
@@ -0,0 +1,482 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
# 🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨
|
| 2 |
+
# This file was automatically generated from src/transformers/models/lfm2_vl/modular_lfm2_vl.py.
|
| 3 |
+
# Do NOT edit this file manually as any edits will be overwritten by the generation of
|
| 4 |
+
# the file from the modular. If any change should be done, please apply the change to the
|
| 5 |
+
# modular_lfm2_vl.py file directly. One of our CI enforces this.
|
| 6 |
+
# 🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨
|
| 7 |
+
# Copyright 2025 the HuggingFace Inc. team. All rights reserved.
|
| 8 |
+
#
|
| 9 |
+
# Licensed under the Apache License, Version 2.0 (the "License");
|
| 10 |
+
# you may not use this file except in compliance with the License.
|
| 11 |
+
# You may obtain a copy of the License at
|
| 12 |
+
#
|
| 13 |
+
# http://www.apache.org/licenses/LICENSE-2.0
|
| 14 |
+
#
|
| 15 |
+
# Unless required by applicable law or agreed to in writing, software
|
| 16 |
+
# distributed under the License is distributed on an "AS IS" BASIS,
|
| 17 |
+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
| 18 |
+
# See the License for the specific language governing permissions and
|
| 19 |
+
# limitations under the License.
|
| 20 |
+
|
| 21 |
+
from dataclasses import dataclass
|
| 22 |
+
|
| 23 |
+
import torch
|
| 24 |
+
from torch import nn
|
| 25 |
+
|
| 26 |
+
from ...activations import ACT2FN
|
| 27 |
+
from ...cache_utils import Cache
|
| 28 |
+
from ...generation import GenerationMixin
|
| 29 |
+
from ...modeling_outputs import BaseModelOutputWithPast, BaseModelOutputWithPooling, ModelOutput
|
| 30 |
+
from ...modeling_utils import PreTrainedModel
|
| 31 |
+
from ...processing_utils import Unpack
|
| 32 |
+
from ...utils import TransformersKwargs, auto_docstring, can_return_tuple, torch_compilable_check
|
| 33 |
+
from ..auto import AutoModel
|
| 34 |
+
from .configuration_lfm2_vl import Lfm2VlConfig
|
| 35 |
+
|
| 36 |
+
|
| 37 |
+
class Lfm2VlMultiModalProjector(nn.Module):
|
| 38 |
+
def __init__(self, config: Lfm2VlConfig):
|
| 39 |
+
super().__init__()
|
| 40 |
+
in_channels = config.vision_config.hidden_size * (config.downsample_factor**2)
|
| 41 |
+
self.factor = config.downsample_factor
|
| 42 |
+
self.use_layer_norm = config.projector_use_layernorm
|
| 43 |
+
self.layer_norm = nn.LayerNorm(in_channels) if config.projector_use_layernorm else None
|
| 44 |
+
self.linear_1 = nn.Linear(
|
| 45 |
+
in_channels,
|
| 46 |
+
config.projector_hidden_size,
|
| 47 |
+
bias=config.projector_bias,
|
| 48 |
+
)
|
| 49 |
+
self.act = ACT2FN[config.projector_hidden_act]
|
| 50 |
+
self.linear_2 = nn.Linear(
|
| 51 |
+
config.projector_hidden_size,
|
| 52 |
+
config.text_config.hidden_size,
|
| 53 |
+
bias=config.projector_bias,
|
| 54 |
+
)
|
| 55 |
+
|
| 56 |
+
def forward(self, image_features: torch.Tensor):
|
| 57 |
+
image_features = self.pixel_unshuffle(image_features)
|
| 58 |
+
if self.use_layer_norm:
|
| 59 |
+
image_features = self.layer_norm(image_features)
|
| 60 |
+
hidden_states = self.linear_1(image_features)
|
| 61 |
+
hidden_states = self.act(hidden_states)
|
| 62 |
+
hidden_states = self.linear_2(hidden_states)
|
| 63 |
+
return hidden_states
|
| 64 |
+
|
| 65 |
+
def pixel_unshuffle(self, hidden_states: torch.Tensor):
|
| 66 |
+
batch_size, width, height, channels = hidden_states.size()
|
| 67 |
+
hidden_states = hidden_states.reshape(batch_size, width, height // self.factor, channels * self.factor)
|
| 68 |
+
hidden_states = hidden_states.permute(0, 2, 1, 3)
|
| 69 |
+
hidden_states = hidden_states.reshape(
|
| 70 |
+
batch_size, height // self.factor, width // self.factor, channels * self.factor**2
|
| 71 |
+
)
|
| 72 |
+
hidden_states = hidden_states.permute(0, 2, 1, 3)
|
| 73 |
+
return hidden_states
|
| 74 |
+
|
| 75 |
+
|
| 76 |
+
@auto_docstring
|
| 77 |
+
class Lfm2VlPreTrainedModel(PreTrainedModel):
|
| 78 |
+
config: Lfm2VlConfig
|
| 79 |
+
base_model_prefix = "model"
|
| 80 |
+
input_modalities = ("image", "text")
|
| 81 |
+
supports_gradient_checkpointing = True
|
| 82 |
+
_skip_keys_device_placement = "past_key_values"
|
| 83 |
+
|
| 84 |
+
_supports_flash_attn = True
|
| 85 |
+
_supports_sdpa = True
|
| 86 |
+
_can_compile_fullgraph = False
|
| 87 |
+
_supports_flex_attn = True
|
| 88 |
+
_supports_attention_backend = True
|
| 89 |
+
|
| 90 |
+
|
| 91 |
+
@dataclass
|
| 92 |
+
@auto_docstring(
|
| 93 |
+
custom_intro="""
|
| 94 |
+
Base class for Lfm2Vl causal language model (or autoregressive) outputs.
|
| 95 |
+
"""
|
| 96 |
+
)
|
| 97 |
+
class Lfm2VlCausalLMOutputWithPast(ModelOutput):
|
| 98 |
+
r"""
|
| 99 |
+
loss (`torch.FloatTensor` of shape `(1,)`, *optional*, returned when `labels` is provided):
|
| 100 |
+
Language modeling loss (for next-token prediction).
|
| 101 |
+
logits (`torch.FloatTensor` of shape `(batch_size, sequence_length, config.vocab_size)`):
|
| 102 |
+
Prediction scores of the language modeling head (scores for each vocabulary token before SoftMax).
|
| 103 |
+
past_key_values (`Cache`, *optional*, returned when `use_cache=True` is passed or when `config.use_cache=True`):
|
| 104 |
+
It is a [`~cache_utils.Cache`] instance. For more details, see our [kv cache guide](https://huggingface.co/docs/transformers/en/kv_cache).
|
| 105 |
+
|
| 106 |
+
Contains pre-computed hidden-states (key and values in the self-attention blocks) that can be used (see
|
| 107 |
+
`past_key_values` input) to speed up sequential decoding.
|
| 108 |
+
image_hidden_states (`torch.FloatTensor`, *optional*):
|
| 109 |
+
A `torch.FloatTensor` of size `(batch_size, num_images, sequence_length, hidden_size)`.
|
| 110 |
+
image_hidden_states of the model produced by the vision encoder and after projecting the last hidden state.
|
| 111 |
+
"""
|
| 112 |
+
|
| 113 |
+
loss: torch.FloatTensor | None = None
|
| 114 |
+
logits: torch.FloatTensor | None = None
|
| 115 |
+
past_key_values: Cache | None = None
|
| 116 |
+
hidden_states: tuple[torch.FloatTensor] | None = None
|
| 117 |
+
attentions: tuple[torch.FloatTensor] | None = None
|
| 118 |
+
image_hidden_states: torch.FloatTensor | None = None
|
| 119 |
+
|
| 120 |
+
|
| 121 |
+
@dataclass
|
| 122 |
+
@auto_docstring(
|
| 123 |
+
custom_intro="""
|
| 124 |
+
Base class for Lfm2Vl outputs, with hidden states and attentions.
|
| 125 |
+
"""
|
| 126 |
+
)
|
| 127 |
+
class Lfm2VlModelOutputWithPast(BaseModelOutputWithPast):
|
| 128 |
+
r"""
|
| 129 |
+
past_key_values (`Cache`, *optional*, returned when `use_cache=True` is passed or when `config.use_cache=True`):
|
| 130 |
+
It is a [`~cache_utils.Cache`] instance. For more details, see our [kv cache guide](https://huggingface.co/docs/transformers/en/kv_cache).
|
| 131 |
+
|
| 132 |
+
Contains pre-computed hidden-states (key and values in the self-attention blocks) that can be used (see
|
| 133 |
+
`past_key_values` input) to speed up sequential decoding.
|
| 134 |
+
image_hidden_states (`torch.FloatTensor`, *optional*):
|
| 135 |
+
A `torch.FloatTensor` of size `(batch_size, num_images, sequence_length, hidden_size)`.
|
| 136 |
+
image_hidden_states of the model produced by the vision encoder and after projecting the last hidden state.
|
| 137 |
+
"""
|
| 138 |
+
|
| 139 |
+
image_hidden_states: torch.FloatTensor | None = None
|
| 140 |
+
|
| 141 |
+
|
| 142 |
+
@auto_docstring(
|
| 143 |
+
custom_intro="""
|
| 144 |
+
The Lfm2Vl model which consists of a vision backbone and a language model, without a language modeling head.
|
| 145 |
+
"""
|
| 146 |
+
)
|
| 147 |
+
class Lfm2VlModel(Lfm2VlPreTrainedModel):
|
| 148 |
+
def __init__(self, config: Lfm2VlConfig):
|
| 149 |
+
super().__init__(config)
|
| 150 |
+
self.vision_tower = AutoModel.from_config(config.vision_config)
|
| 151 |
+
|
| 152 |
+
self.multi_modal_projector = Lfm2VlMultiModalProjector(config)
|
| 153 |
+
self.language_model = AutoModel.from_config(config.text_config)
|
| 154 |
+
self.post_init()
|
| 155 |
+
|
| 156 |
+
def get_input_embeddings(self):
|
| 157 |
+
return self.language_model.get_input_embeddings()
|
| 158 |
+
|
| 159 |
+
def set_input_embeddings(self, value):
|
| 160 |
+
self.language_model.set_input_embeddings(value)
|
| 161 |
+
|
| 162 |
+
@can_return_tuple
|
| 163 |
+
@auto_docstring(
|
| 164 |
+
custom_intro="Obtains image last hidden states from the vision tower and apply multimodal projection."
|
| 165 |
+
)
|
| 166 |
+
def get_image_features(
|
| 167 |
+
self,
|
| 168 |
+
pixel_values: torch.FloatTensor,
|
| 169 |
+
spatial_shapes: torch.Tensor,
|
| 170 |
+
pixel_attention_mask: torch.Tensor,
|
| 171 |
+
**kwargs: Unpack[TransformersKwargs],
|
| 172 |
+
) -> tuple | BaseModelOutputWithPooling:
|
| 173 |
+
r"""
|
| 174 |
+
pixel_values (`torch.FloatTensor]` of shape `(batch_size, channels, height, width)`):
|
| 175 |
+
The tensors corresponding to the input images.
|
| 176 |
+
spatial_shapes (`torch.Tensor` of shape `(batch_size, 2)`):
|
| 177 |
+
The spatial shapes of the input images.
|
| 178 |
+
pixel_attention_mask (`torch.Tensor` of shape `(batch_size, height, width)`):
|
| 179 |
+
The pixel attention mask of the input images.
|
| 180 |
+
"""
|
| 181 |
+
image_outputs = self.vision_tower(
|
| 182 |
+
pixel_values=pixel_values,
|
| 183 |
+
spatial_shapes=spatial_shapes,
|
| 184 |
+
pixel_attention_mask=pixel_attention_mask,
|
| 185 |
+
return_dict=True,
|
| 186 |
+
**kwargs,
|
| 187 |
+
)
|
| 188 |
+
last_hidden_state = image_outputs.last_hidden_state
|
| 189 |
+
|
| 190 |
+
img_feature_lengths = pixel_attention_mask.sum(dim=1)
|
| 191 |
+
image_features = []
|
| 192 |
+
|
| 193 |
+
for img_idx in range(last_hidden_state.size(0)):
|
| 194 |
+
feature = last_hidden_state[img_idx]
|
| 195 |
+
# unpad the image representation
|
| 196 |
+
feature = feature[: img_feature_lengths[img_idx], :].unsqueeze(0)
|
| 197 |
+
|
| 198 |
+
# reshape to original height and width
|
| 199 |
+
feature_org_h, feature_org_w = spatial_shapes[img_idx]
|
| 200 |
+
feature = feature.reshape(1, feature_org_h, feature_org_w, -1)
|
| 201 |
+
|
| 202 |
+
# project the image representation
|
| 203 |
+
img_embedding = self.multi_modal_projector(feature)
|
| 204 |
+
|
| 205 |
+
# flatten here to handle variable length in naflex
|
| 206 |
+
img_embedding = img_embedding.reshape(-1, img_embedding.size(-1))
|
| 207 |
+
image_features.append(img_embedding)
|
| 208 |
+
|
| 209 |
+
image_outputs.pooler_output = image_features
|
| 210 |
+
return image_outputs
|
| 211 |
+
|
| 212 |
+
def get_placeholder_mask(
|
| 213 |
+
self, input_ids: torch.LongTensor, inputs_embeds: torch.FloatTensor, image_features: torch.FloatTensor
|
| 214 |
+
):
|
| 215 |
+
"""
|
| 216 |
+
Obtains multimodal placeholder mask from `input_ids` or `inputs_embeds`, and checks that the placeholder token count is
|
| 217 |
+
equal to the length of multimodal features. If the lengths are different, an error is raised.
|
| 218 |
+
"""
|
| 219 |
+
if input_ids is None:
|
| 220 |
+
special_image_mask = inputs_embeds == self.get_input_embeddings()(
|
| 221 |
+
torch.tensor(self.config.image_token_id, dtype=torch.long, device=inputs_embeds.device)
|
| 222 |
+
)
|
| 223 |
+
special_image_mask = special_image_mask.all(-1)
|
| 224 |
+
else:
|
| 225 |
+
special_image_mask = input_ids == self.config.image_token_id
|
| 226 |
+
|
| 227 |
+
n_image_tokens = special_image_mask.sum()
|
| 228 |
+
special_image_mask = special_image_mask.unsqueeze(-1).expand_as(inputs_embeds).to(inputs_embeds.device)
|
| 229 |
+
n_image_features = image_features.shape[0]
|
| 230 |
+
torch_compilable_check(
|
| 231 |
+
inputs_embeds[special_image_mask].numel() == image_features.numel(),
|
| 232 |
+
f"Image features and image tokens do not match, tokens: {n_image_tokens}, features: {n_image_features}",
|
| 233 |
+
)
|
| 234 |
+
return special_image_mask
|
| 235 |
+
|
| 236 |
+
@can_return_tuple
|
| 237 |
+
@auto_docstring
|
| 238 |
+
def forward(
|
| 239 |
+
self,
|
| 240 |
+
input_ids: torch.LongTensor | None = None,
|
| 241 |
+
attention_mask: torch.Tensor | None = None,
|
| 242 |
+
position_ids: torch.LongTensor | None = None,
|
| 243 |
+
pixel_values: torch.FloatTensor | None = None,
|
| 244 |
+
spatial_shapes: torch.Tensor | None = None,
|
| 245 |
+
pixel_attention_mask: torch.Tensor | None = None,
|
| 246 |
+
past_key_values: Cache | None = None,
|
| 247 |
+
inputs_embeds: torch.FloatTensor | None = None,
|
| 248 |
+
use_cache: bool | None = None,
|
| 249 |
+
**kwargs: Unpack[TransformersKwargs],
|
| 250 |
+
) -> tuple | Lfm2VlModelOutputWithPast:
|
| 251 |
+
r"""
|
| 252 |
+
spatial_shapes (`torch.Tensor` of shape `(batch_size, 2)`, *optional*):
|
| 253 |
+
The spatial shapes of the input images.
|
| 254 |
+
pixel_attention_mask (`torch.Tensor` of shape `(batch_size, height, width)`, *optional*):
|
| 255 |
+
The pixel attention mask of the input images.
|
| 256 |
+
"""
|
| 257 |
+
|
| 258 |
+
if (input_ids is None) ^ (inputs_embeds is not None):
|
| 259 |
+
raise ValueError("You must specify exactly one of input_ids or inputs_embeds")
|
| 260 |
+
|
| 261 |
+
if inputs_embeds is None:
|
| 262 |
+
inputs_embeds = self.get_input_embeddings()(input_ids)
|
| 263 |
+
|
| 264 |
+
if pixel_values is not None:
|
| 265 |
+
image_features = self.get_image_features(
|
| 266 |
+
pixel_values=pixel_values,
|
| 267 |
+
spatial_shapes=spatial_shapes,
|
| 268 |
+
pixel_attention_mask=pixel_attention_mask,
|
| 269 |
+
return_dict=True,
|
| 270 |
+
).pooler_output
|
| 271 |
+
image_features = torch.cat(image_features, dim=0).to(inputs_embeds.device, inputs_embeds.dtype)
|
| 272 |
+
special_image_mask = self.get_placeholder_mask(
|
| 273 |
+
input_ids=input_ids,
|
| 274 |
+
inputs_embeds=inputs_embeds,
|
| 275 |
+
image_features=image_features,
|
| 276 |
+
)
|
| 277 |
+
inputs_embeds = inputs_embeds.masked_scatter(special_image_mask, image_features)
|
| 278 |
+
|
| 279 |
+
outputs = self.language_model(
|
| 280 |
+
attention_mask=attention_mask,
|
| 281 |
+
position_ids=position_ids,
|
| 282 |
+
past_key_values=past_key_values,
|
| 283 |
+
inputs_embeds=inputs_embeds,
|
| 284 |
+
use_cache=use_cache,
|
| 285 |
+
**kwargs,
|
| 286 |
+
)
|
| 287 |
+
|
| 288 |
+
return Lfm2VlModelOutputWithPast(
|
| 289 |
+
last_hidden_state=outputs.last_hidden_state,
|
| 290 |
+
past_key_values=outputs.past_key_values,
|
| 291 |
+
hidden_states=outputs.hidden_states,
|
| 292 |
+
attentions=outputs.attentions,
|
| 293 |
+
image_hidden_states=image_features if pixel_values is not None else None,
|
| 294 |
+
)
|
| 295 |
+
|
| 296 |
+
|
| 297 |
+
@auto_docstring(
|
| 298 |
+
custom_intro="""
|
| 299 |
+
The LFM2_VL model which consists of a vision backbone and a language model.
|
| 300 |
+
"""
|
| 301 |
+
)
|
| 302 |
+
class Lfm2VlForConditionalGeneration(Lfm2VlPreTrainedModel, GenerationMixin):
|
| 303 |
+
_tied_weights_keys = {"lm_head.weight": "model.language_model.embed_tokens.weight"}
|
| 304 |
+
|
| 305 |
+
def __init__(self, config: Lfm2VlConfig):
|
| 306 |
+
super().__init__(config)
|
| 307 |
+
self.model = Lfm2VlModel(config)
|
| 308 |
+
self.lm_head = nn.Linear(config.text_config.hidden_size, config.text_config.vocab_size, bias=False)
|
| 309 |
+
self.post_init()
|
| 310 |
+
|
| 311 |
+
def get_input_embeddings(self):
|
| 312 |
+
return self.model.get_input_embeddings()
|
| 313 |
+
|
| 314 |
+
def set_input_embeddings(self, value):
|
| 315 |
+
self.model.set_input_embeddings(value)
|
| 316 |
+
|
| 317 |
+
def get_output_embeddings(self) -> nn.Module:
|
| 318 |
+
return self.lm_head
|
| 319 |
+
|
| 320 |
+
@auto_docstring
|
| 321 |
+
def get_image_features(
|
| 322 |
+
self,
|
| 323 |
+
pixel_values: torch.FloatTensor,
|
| 324 |
+
spatial_shapes: torch.Tensor,
|
| 325 |
+
pixel_attention_mask: torch.Tensor,
|
| 326 |
+
**kwargs: Unpack[TransformersKwargs],
|
| 327 |
+
) -> tuple | BaseModelOutputWithPooling:
|
| 328 |
+
r"""
|
| 329 |
+
pixel_values (`torch.FloatTensor]` of shape `(batch_size, channels, height, width)`):
|
| 330 |
+
The tensors corresponding to the input images.
|
| 331 |
+
spatial_shapes (`torch.Tensor` of shape `(batch_size, 2)`):
|
| 332 |
+
The spatial shapes of the input images.
|
| 333 |
+
pixel_attention_mask (`torch.Tensor` of shape `(batch_size, height, width)`):
|
| 334 |
+
The pixel attention mask of the input images.
|
| 335 |
+
"""
|
| 336 |
+
return self.model.get_image_features(
|
| 337 |
+
pixel_values=pixel_values,
|
| 338 |
+
spatial_shapes=spatial_shapes,
|
| 339 |
+
pixel_attention_mask=pixel_attention_mask,
|
| 340 |
+
**kwargs,
|
| 341 |
+
)
|
| 342 |
+
|
| 343 |
+
@can_return_tuple
|
| 344 |
+
def forward(
|
| 345 |
+
self,
|
| 346 |
+
input_ids: torch.LongTensor | None = None,
|
| 347 |
+
pixel_values: torch.FloatTensor | None = None,
|
| 348 |
+
spatial_shapes: torch.Tensor | None = None,
|
| 349 |
+
pixel_attention_mask: torch.Tensor | None = None,
|
| 350 |
+
attention_mask: torch.Tensor | None = None,
|
| 351 |
+
position_ids: torch.LongTensor | None = None,
|
| 352 |
+
past_key_values: Cache | None = None,
|
| 353 |
+
inputs_embeds: torch.FloatTensor | None = None,
|
| 354 |
+
labels: torch.LongTensor | None = None,
|
| 355 |
+
use_cache: bool | None = None,
|
| 356 |
+
logits_to_keep: int | torch.Tensor = 0,
|
| 357 |
+
**kwargs: Unpack[TransformersKwargs],
|
| 358 |
+
) -> tuple | Lfm2VlCausalLMOutputWithPast:
|
| 359 |
+
r"""
|
| 360 |
+
pixel_values (`torch.FloatTensor` of shape `(batch_size, channels, height, width)`, *optional*):
|
| 361 |
+
The input image tensors.
|
| 362 |
+
spatial_shapes (`torch.Tensor` of shape `(batch_size, 2)`, *optional*):
|
| 363 |
+
The spatial shapes of the input images.
|
| 364 |
+
pixel_attention_mask (`torch.Tensor` of shape `(batch_size, height, width)`, *optional*):
|
| 365 |
+
The pixel attention mask of the input images.
|
| 366 |
+
labels (`torch.LongTensor` of shape `(batch_size, sequence_length)`, *optional*):
|
| 367 |
+
Labels for computing the masked language modeling loss. Indices should either be in `[0, ...,
|
| 368 |
+
config.vocab_size]` or -100 (see `input_ids` docstring). Tokens with indices set to `-100` are ignored
|
| 369 |
+
(masked), the loss is only computed for the tokens with labels in `[0, ..., config.vocab_size]`.
|
| 370 |
+
|
| 371 |
+
Example:
|
| 372 |
+
|
| 373 |
+
```python
|
| 374 |
+
>>> from PIL import Image
|
| 375 |
+
>>> import httpx
|
| 376 |
+
>>> from io import BytesIO
|
| 377 |
+
>>> from transformers import AutoProcessor, AutoModelForImageTextToText
|
| 378 |
+
>>> from transformers.image_utils import load_image
|
| 379 |
+
|
| 380 |
+
>>> model = AutoModelForImageTextToText.from_pretrained(
|
| 381 |
+
... "LiquidAI/LFM2-VL-1.6B",
|
| 382 |
+
... )
|
| 383 |
+
>>> processor = AutoProcessor.from_pretrained(
|
| 384 |
+
... "LiquidAI/LFM2-VL-1.6B",
|
| 385 |
+
... )
|
| 386 |
+
|
| 387 |
+
>>> url = "https://www.ilankelman.org/stopsigns/australia.jpg"
|
| 388 |
+
>>> image = load_image(url)
|
| 389 |
+
|
| 390 |
+
>>> conversation = [
|
| 391 |
+
... {
|
| 392 |
+
... "role": "user",
|
| 393 |
+
... "content": [
|
| 394 |
+
... {"type": "image", "image": image},
|
| 395 |
+
... {"type": "text", "text": "What is in this image?"},
|
| 396 |
+
... ],
|
| 397 |
+
... },
|
| 398 |
+
... ]
|
| 399 |
+
|
| 400 |
+
>>> inputs = processor.apply_chat_template(
|
| 401 |
+
... conversation,
|
| 402 |
+
... add_generation_prompt=True,
|
| 403 |
+
... tokenize=True,
|
| 404 |
+
... return_dict=True,
|
| 405 |
+
... return_tensors="pt"
|
| 406 |
+
... )
|
| 407 |
+
|
| 408 |
+
>>> # Generate
|
| 409 |
+
>>> outputs = model.generate(**inputs, max_new_tokens=45)
|
| 410 |
+
>>> processor.batch_decode(outputs, skip_special_tokens=True)[0]
|
| 411 |
+
'This image depicts a vibrant street scene in what appears to be a Chinatown or similar cultural area. The focal point is a large red stop sign with white lettering, mounted on a pole.'
|
| 412 |
+
```"""
|
| 413 |
+
outputs = self.model(
|
| 414 |
+
input_ids=input_ids,
|
| 415 |
+
pixel_values=pixel_values,
|
| 416 |
+
spatial_shapes=spatial_shapes,
|
| 417 |
+
pixel_attention_mask=pixel_attention_mask,
|
| 418 |
+
attention_mask=attention_mask,
|
| 419 |
+
position_ids=position_ids,
|
| 420 |
+
past_key_values=past_key_values,
|
| 421 |
+
inputs_embeds=inputs_embeds,
|
| 422 |
+
use_cache=use_cache,
|
| 423 |
+
**kwargs,
|
| 424 |
+
)
|
| 425 |
+
|
| 426 |
+
hidden_states = outputs[0]
|
| 427 |
+
# Only compute necessary logits, and do not upcast them to float if we are not computing the loss
|
| 428 |
+
slice_indices = slice(-logits_to_keep, None) if isinstance(logits_to_keep, int) else logits_to_keep
|
| 429 |
+
logits = self.lm_head(hidden_states[:, slice_indices, :])
|
| 430 |
+
|
| 431 |
+
loss = None
|
| 432 |
+
if labels is not None:
|
| 433 |
+
loss = self.loss_function(
|
| 434 |
+
logits=logits,
|
| 435 |
+
labels=labels,
|
| 436 |
+
vocab_size=self.config.text_config.vocab_size,
|
| 437 |
+
**kwargs,
|
| 438 |
+
)
|
| 439 |
+
|
| 440 |
+
return Lfm2VlCausalLMOutputWithPast(
|
| 441 |
+
loss=loss,
|
| 442 |
+
logits=logits,
|
| 443 |
+
past_key_values=outputs.past_key_values,
|
| 444 |
+
hidden_states=outputs.hidden_states,
|
| 445 |
+
attentions=outputs.attentions,
|
| 446 |
+
image_hidden_states=outputs.image_hidden_states,
|
| 447 |
+
)
|
| 448 |
+
|
| 449 |
+
def prepare_inputs_for_generation(
|
| 450 |
+
self,
|
| 451 |
+
input_ids,
|
| 452 |
+
past_key_values=None,
|
| 453 |
+
inputs_embeds=None,
|
| 454 |
+
pixel_values=None,
|
| 455 |
+
attention_mask=None,
|
| 456 |
+
logits_to_keep=None,
|
| 457 |
+
is_first_iteration=False,
|
| 458 |
+
**kwargs,
|
| 459 |
+
):
|
| 460 |
+
# Overwritten -- in specific circumstances we don't want to forward image inputs to the model
|
| 461 |
+
|
| 462 |
+
model_inputs = super().prepare_inputs_for_generation(
|
| 463 |
+
input_ids,
|
| 464 |
+
past_key_values=past_key_values,
|
| 465 |
+
inputs_embeds=inputs_embeds,
|
| 466 |
+
attention_mask=attention_mask,
|
| 467 |
+
logits_to_keep=logits_to_keep,
|
| 468 |
+
is_first_iteration=is_first_iteration,
|
| 469 |
+
**kwargs,
|
| 470 |
+
)
|
| 471 |
+
|
| 472 |
+
if is_first_iteration or not kwargs.get("use_cache", True):
|
| 473 |
+
# Pixel values are used only in the first iteration if available
|
| 474 |
+
# In subsequent iterations, they are already merged with text and cached
|
| 475 |
+
# NOTE: first iteration doesn't have to be prefill, it can be the first
|
| 476 |
+
# iteration with a question and cached system prompt (continue generate from cache)
|
| 477 |
+
model_inputs["pixel_values"] = pixel_values
|
| 478 |
+
|
| 479 |
+
return model_inputs
|
| 480 |
+
|
| 481 |
+
|
| 482 |
+
__all__ = ["Lfm2VlForConditionalGeneration", "Lfm2VlPreTrainedModel", "Lfm2VlModel"]
|
third_party/transformers/src/transformers/models/lfm2_vl/modular_lfm2_vl.py
ADDED
|
@@ -0,0 +1,359 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
# Copyright 2025 the HuggingFace Inc. team. All rights reserved.
|
| 2 |
+
#
|
| 3 |
+
# Licensed under the Apache License, Version 2.0 (the "License");
|
| 4 |
+
# you may not use this file except in compliance with the License.
|
| 5 |
+
# You may obtain a copy of the License at
|
| 6 |
+
#
|
| 7 |
+
# http://www.apache.org/licenses/LICENSE-2.0
|
| 8 |
+
#
|
| 9 |
+
# Unless required by applicable law or agreed to in writing, software
|
| 10 |
+
# distributed under the License is distributed on an "AS IS" BASIS,
|
| 11 |
+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
| 12 |
+
# See the License for the specific language governing permissions and
|
| 13 |
+
# limitations under the License.
|
| 14 |
+
"""PyTorch Lfm2-VL model."""
|
| 15 |
+
|
| 16 |
+
import torch
|
| 17 |
+
from torch import nn
|
| 18 |
+
|
| 19 |
+
from ...activations import ACT2FN
|
| 20 |
+
from ...cache_utils import Cache
|
| 21 |
+
from ...modeling_outputs import BaseModelOutputWithPooling
|
| 22 |
+
from ...processing_utils import Unpack
|
| 23 |
+
from ...utils import TransformersKwargs, auto_docstring, can_return_tuple, logging, torch_compilable_check
|
| 24 |
+
from ..llava.modeling_llava import (
|
| 25 |
+
LlavaCausalLMOutputWithPast,
|
| 26 |
+
LlavaForConditionalGeneration,
|
| 27 |
+
LlavaModel,
|
| 28 |
+
LlavaModelOutputWithPast,
|
| 29 |
+
LlavaPreTrainedModel,
|
| 30 |
+
)
|
| 31 |
+
from .configuration_lfm2_vl import Lfm2VlConfig
|
| 32 |
+
|
| 33 |
+
|
| 34 |
+
logger = logging.get_logger(__name__)
|
| 35 |
+
|
| 36 |
+
|
| 37 |
+
class Lfm2VlMultiModalProjector(nn.Module):
|
| 38 |
+
def __init__(self, config: Lfm2VlConfig):
|
| 39 |
+
super().__init__()
|
| 40 |
+
in_channels = config.vision_config.hidden_size * (config.downsample_factor**2)
|
| 41 |
+
self.factor = config.downsample_factor
|
| 42 |
+
self.use_layer_norm = config.projector_use_layernorm
|
| 43 |
+
self.layer_norm = nn.LayerNorm(in_channels) if config.projector_use_layernorm else None
|
| 44 |
+
self.linear_1 = nn.Linear(
|
| 45 |
+
in_channels,
|
| 46 |
+
config.projector_hidden_size,
|
| 47 |
+
bias=config.projector_bias,
|
| 48 |
+
)
|
| 49 |
+
self.act = ACT2FN[config.projector_hidden_act]
|
| 50 |
+
self.linear_2 = nn.Linear(
|
| 51 |
+
config.projector_hidden_size,
|
| 52 |
+
config.text_config.hidden_size,
|
| 53 |
+
bias=config.projector_bias,
|
| 54 |
+
)
|
| 55 |
+
|
| 56 |
+
def forward(self, image_features: torch.Tensor):
|
| 57 |
+
image_features = self.pixel_unshuffle(image_features)
|
| 58 |
+
if self.use_layer_norm:
|
| 59 |
+
image_features = self.layer_norm(image_features)
|
| 60 |
+
hidden_states = self.linear_1(image_features)
|
| 61 |
+
hidden_states = self.act(hidden_states)
|
| 62 |
+
hidden_states = self.linear_2(hidden_states)
|
| 63 |
+
return hidden_states
|
| 64 |
+
|
| 65 |
+
def pixel_unshuffle(self, hidden_states: torch.Tensor):
|
| 66 |
+
batch_size, width, height, channels = hidden_states.size()
|
| 67 |
+
hidden_states = hidden_states.reshape(batch_size, width, height // self.factor, channels * self.factor)
|
| 68 |
+
hidden_states = hidden_states.permute(0, 2, 1, 3)
|
| 69 |
+
hidden_states = hidden_states.reshape(
|
| 70 |
+
batch_size, height // self.factor, width // self.factor, channels * self.factor**2
|
| 71 |
+
)
|
| 72 |
+
hidden_states = hidden_states.permute(0, 2, 1, 3)
|
| 73 |
+
return hidden_states
|
| 74 |
+
|
| 75 |
+
|
| 76 |
+
class Lfm2VlPreTrainedModel(LlavaPreTrainedModel):
|
| 77 |
+
_can_compile_fullgraph = False
|
| 78 |
+
base_model_prefix = "model"
|
| 79 |
+
|
| 80 |
+
|
| 81 |
+
class Lfm2VlCausalLMOutputWithPast(LlavaCausalLMOutputWithPast):
|
| 82 |
+
pass
|
| 83 |
+
|
| 84 |
+
|
| 85 |
+
class Lfm2VlModelOutputWithPast(LlavaModelOutputWithPast):
|
| 86 |
+
pass
|
| 87 |
+
|
| 88 |
+
|
| 89 |
+
class Lfm2VlModel(LlavaModel):
|
| 90 |
+
def __init__(self, config: Lfm2VlConfig):
|
| 91 |
+
super().__init__(config)
|
| 92 |
+
|
| 93 |
+
@can_return_tuple
|
| 94 |
+
@auto_docstring(
|
| 95 |
+
custom_intro="Obtains image last hidden states from the vision tower and apply multimodal projection."
|
| 96 |
+
)
|
| 97 |
+
def get_image_features(
|
| 98 |
+
self,
|
| 99 |
+
pixel_values: torch.FloatTensor,
|
| 100 |
+
spatial_shapes: torch.Tensor,
|
| 101 |
+
pixel_attention_mask: torch.Tensor,
|
| 102 |
+
**kwargs: Unpack[TransformersKwargs],
|
| 103 |
+
) -> tuple | BaseModelOutputWithPooling:
|
| 104 |
+
r"""
|
| 105 |
+
pixel_values (`torch.FloatTensor]` of shape `(batch_size, channels, height, width)`):
|
| 106 |
+
The tensors corresponding to the input images.
|
| 107 |
+
spatial_shapes (`torch.Tensor` of shape `(batch_size, 2)`):
|
| 108 |
+
The spatial shapes of the input images.
|
| 109 |
+
pixel_attention_mask (`torch.Tensor` of shape `(batch_size, height, width)`):
|
| 110 |
+
The pixel attention mask of the input images.
|
| 111 |
+
"""
|
| 112 |
+
image_outputs = self.vision_tower(
|
| 113 |
+
pixel_values=pixel_values,
|
| 114 |
+
spatial_shapes=spatial_shapes,
|
| 115 |
+
pixel_attention_mask=pixel_attention_mask,
|
| 116 |
+
return_dict=True,
|
| 117 |
+
**kwargs,
|
| 118 |
+
)
|
| 119 |
+
last_hidden_state = image_outputs.last_hidden_state
|
| 120 |
+
|
| 121 |
+
img_feature_lengths = pixel_attention_mask.sum(dim=1)
|
| 122 |
+
image_features = []
|
| 123 |
+
|
| 124 |
+
for img_idx in range(last_hidden_state.size(0)):
|
| 125 |
+
feature = last_hidden_state[img_idx]
|
| 126 |
+
# unpad the image representation
|
| 127 |
+
feature = feature[: img_feature_lengths[img_idx], :].unsqueeze(0)
|
| 128 |
+
|
| 129 |
+
# reshape to original height and width
|
| 130 |
+
feature_org_h, feature_org_w = spatial_shapes[img_idx]
|
| 131 |
+
feature = feature.reshape(1, feature_org_h, feature_org_w, -1)
|
| 132 |
+
|
| 133 |
+
# project the image representation
|
| 134 |
+
img_embedding = self.multi_modal_projector(feature)
|
| 135 |
+
|
| 136 |
+
# flatten here to handle variable length in naflex
|
| 137 |
+
img_embedding = img_embedding.reshape(-1, img_embedding.size(-1))
|
| 138 |
+
image_features.append(img_embedding)
|
| 139 |
+
|
| 140 |
+
image_outputs.pooler_output = image_features
|
| 141 |
+
return image_outputs
|
| 142 |
+
|
| 143 |
+
def get_placeholder_mask(
|
| 144 |
+
self, input_ids: torch.LongTensor, inputs_embeds: torch.FloatTensor, image_features: torch.FloatTensor
|
| 145 |
+
):
|
| 146 |
+
"""
|
| 147 |
+
Obtains multimodal placeholder mask from `input_ids` or `inputs_embeds`, and checks that the placeholder token count is
|
| 148 |
+
equal to the length of multimodal features. If the lengths are different, an error is raised.
|
| 149 |
+
"""
|
| 150 |
+
if input_ids is None:
|
| 151 |
+
special_image_mask = inputs_embeds == self.get_input_embeddings()(
|
| 152 |
+
torch.tensor(self.config.image_token_id, dtype=torch.long, device=inputs_embeds.device)
|
| 153 |
+
)
|
| 154 |
+
special_image_mask = special_image_mask.all(-1)
|
| 155 |
+
else:
|
| 156 |
+
special_image_mask = input_ids == self.config.image_token_id
|
| 157 |
+
|
| 158 |
+
n_image_tokens = special_image_mask.sum()
|
| 159 |
+
special_image_mask = special_image_mask.unsqueeze(-1).expand_as(inputs_embeds).to(inputs_embeds.device)
|
| 160 |
+
n_image_features = image_features.shape[0]
|
| 161 |
+
torch_compilable_check(
|
| 162 |
+
inputs_embeds[special_image_mask].numel() == image_features.numel(),
|
| 163 |
+
f"Image features and image tokens do not match, tokens: {n_image_tokens}, features: {n_image_features}",
|
| 164 |
+
)
|
| 165 |
+
return special_image_mask
|
| 166 |
+
|
| 167 |
+
@can_return_tuple
|
| 168 |
+
@auto_docstring
|
| 169 |
+
def forward(
|
| 170 |
+
self,
|
| 171 |
+
input_ids: torch.LongTensor | None = None,
|
| 172 |
+
attention_mask: torch.Tensor | None = None,
|
| 173 |
+
position_ids: torch.LongTensor | None = None,
|
| 174 |
+
pixel_values: torch.FloatTensor | None = None,
|
| 175 |
+
spatial_shapes: torch.Tensor | None = None,
|
| 176 |
+
pixel_attention_mask: torch.Tensor | None = None,
|
| 177 |
+
past_key_values: Cache | None = None,
|
| 178 |
+
inputs_embeds: torch.FloatTensor | None = None,
|
| 179 |
+
use_cache: bool | None = None,
|
| 180 |
+
**kwargs: Unpack[TransformersKwargs],
|
| 181 |
+
) -> tuple | Lfm2VlModelOutputWithPast:
|
| 182 |
+
r"""
|
| 183 |
+
spatial_shapes (`torch.Tensor` of shape `(batch_size, 2)`, *optional*):
|
| 184 |
+
The spatial shapes of the input images.
|
| 185 |
+
pixel_attention_mask (`torch.Tensor` of shape `(batch_size, height, width)`, *optional*):
|
| 186 |
+
The pixel attention mask of the input images.
|
| 187 |
+
"""
|
| 188 |
+
|
| 189 |
+
if (input_ids is None) ^ (inputs_embeds is not None):
|
| 190 |
+
raise ValueError("You must specify exactly one of input_ids or inputs_embeds")
|
| 191 |
+
|
| 192 |
+
if inputs_embeds is None:
|
| 193 |
+
inputs_embeds = self.get_input_embeddings()(input_ids)
|
| 194 |
+
|
| 195 |
+
if pixel_values is not None:
|
| 196 |
+
image_features = self.get_image_features(
|
| 197 |
+
pixel_values=pixel_values,
|
| 198 |
+
spatial_shapes=spatial_shapes,
|
| 199 |
+
pixel_attention_mask=pixel_attention_mask,
|
| 200 |
+
return_dict=True,
|
| 201 |
+
).pooler_output
|
| 202 |
+
image_features = torch.cat(image_features, dim=0).to(inputs_embeds.device, inputs_embeds.dtype)
|
| 203 |
+
special_image_mask = self.get_placeholder_mask(
|
| 204 |
+
input_ids=input_ids,
|
| 205 |
+
inputs_embeds=inputs_embeds,
|
| 206 |
+
image_features=image_features,
|
| 207 |
+
)
|
| 208 |
+
inputs_embeds = inputs_embeds.masked_scatter(special_image_mask, image_features)
|
| 209 |
+
|
| 210 |
+
outputs = self.language_model(
|
| 211 |
+
attention_mask=attention_mask,
|
| 212 |
+
position_ids=position_ids,
|
| 213 |
+
past_key_values=past_key_values,
|
| 214 |
+
inputs_embeds=inputs_embeds,
|
| 215 |
+
use_cache=use_cache,
|
| 216 |
+
**kwargs,
|
| 217 |
+
)
|
| 218 |
+
|
| 219 |
+
return Lfm2VlModelOutputWithPast(
|
| 220 |
+
last_hidden_state=outputs.last_hidden_state,
|
| 221 |
+
past_key_values=outputs.past_key_values,
|
| 222 |
+
hidden_states=outputs.hidden_states,
|
| 223 |
+
attentions=outputs.attentions,
|
| 224 |
+
image_hidden_states=image_features if pixel_values is not None else None,
|
| 225 |
+
)
|
| 226 |
+
|
| 227 |
+
|
| 228 |
+
class Lfm2VlForConditionalGeneration(LlavaForConditionalGeneration):
|
| 229 |
+
@auto_docstring
|
| 230 |
+
def get_image_features(
|
| 231 |
+
self,
|
| 232 |
+
pixel_values: torch.FloatTensor,
|
| 233 |
+
spatial_shapes: torch.Tensor,
|
| 234 |
+
pixel_attention_mask: torch.Tensor,
|
| 235 |
+
**kwargs: Unpack[TransformersKwargs],
|
| 236 |
+
) -> tuple | BaseModelOutputWithPooling:
|
| 237 |
+
r"""
|
| 238 |
+
pixel_values (`torch.FloatTensor]` of shape `(batch_size, channels, height, width)`):
|
| 239 |
+
The tensors corresponding to the input images.
|
| 240 |
+
spatial_shapes (`torch.Tensor` of shape `(batch_size, 2)`):
|
| 241 |
+
The spatial shapes of the input images.
|
| 242 |
+
pixel_attention_mask (`torch.Tensor` of shape `(batch_size, height, width)`):
|
| 243 |
+
The pixel attention mask of the input images.
|
| 244 |
+
"""
|
| 245 |
+
return self.model.get_image_features(
|
| 246 |
+
pixel_values=pixel_values,
|
| 247 |
+
spatial_shapes=spatial_shapes,
|
| 248 |
+
pixel_attention_mask=pixel_attention_mask,
|
| 249 |
+
**kwargs,
|
| 250 |
+
)
|
| 251 |
+
|
| 252 |
+
@can_return_tuple
|
| 253 |
+
def forward(
|
| 254 |
+
self,
|
| 255 |
+
input_ids: torch.LongTensor | None = None,
|
| 256 |
+
pixel_values: torch.FloatTensor | None = None,
|
| 257 |
+
spatial_shapes: torch.Tensor | None = None,
|
| 258 |
+
pixel_attention_mask: torch.Tensor | None = None,
|
| 259 |
+
attention_mask: torch.Tensor | None = None,
|
| 260 |
+
position_ids: torch.LongTensor | None = None,
|
| 261 |
+
past_key_values: Cache | None = None,
|
| 262 |
+
inputs_embeds: torch.FloatTensor | None = None,
|
| 263 |
+
labels: torch.LongTensor | None = None,
|
| 264 |
+
use_cache: bool | None = None,
|
| 265 |
+
logits_to_keep: int | torch.Tensor = 0,
|
| 266 |
+
**kwargs: Unpack[TransformersKwargs],
|
| 267 |
+
) -> tuple | Lfm2VlCausalLMOutputWithPast:
|
| 268 |
+
r"""
|
| 269 |
+
pixel_values (`torch.FloatTensor` of shape `(batch_size, channels, height, width)`, *optional*):
|
| 270 |
+
The input image tensors.
|
| 271 |
+
spatial_shapes (`torch.Tensor` of shape `(batch_size, 2)`, *optional*):
|
| 272 |
+
The spatial shapes of the input images.
|
| 273 |
+
pixel_attention_mask (`torch.Tensor` of shape `(batch_size, height, width)`, *optional*):
|
| 274 |
+
The pixel attention mask of the input images.
|
| 275 |
+
labels (`torch.LongTensor` of shape `(batch_size, sequence_length)`, *optional*):
|
| 276 |
+
Labels for computing the masked language modeling loss. Indices should either be in `[0, ...,
|
| 277 |
+
config.vocab_size]` or -100 (see `input_ids` docstring). Tokens with indices set to `-100` are ignored
|
| 278 |
+
(masked), the loss is only computed for the tokens with labels in `[0, ..., config.vocab_size]`.
|
| 279 |
+
|
| 280 |
+
Example:
|
| 281 |
+
|
| 282 |
+
```python
|
| 283 |
+
>>> from PIL import Image
|
| 284 |
+
>>> import httpx
|
| 285 |
+
>>> from io import BytesIO
|
| 286 |
+
>>> from transformers import AutoProcessor, AutoModelForImageTextToText
|
| 287 |
+
>>> from transformers.image_utils import load_image
|
| 288 |
+
|
| 289 |
+
>>> model = AutoModelForImageTextToText.from_pretrained(
|
| 290 |
+
... "LiquidAI/LFM2-VL-1.6B",
|
| 291 |
+
... )
|
| 292 |
+
>>> processor = AutoProcessor.from_pretrained(
|
| 293 |
+
... "LiquidAI/LFM2-VL-1.6B",
|
| 294 |
+
... )
|
| 295 |
+
|
| 296 |
+
>>> url = "https://www.ilankelman.org/stopsigns/australia.jpg"
|
| 297 |
+
>>> image = load_image(url)
|
| 298 |
+
|
| 299 |
+
>>> conversation = [
|
| 300 |
+
... {
|
| 301 |
+
... "role": "user",
|
| 302 |
+
... "content": [
|
| 303 |
+
... {"type": "image", "image": image},
|
| 304 |
+
... {"type": "text", "text": "What is in this image?"},
|
| 305 |
+
... ],
|
| 306 |
+
... },
|
| 307 |
+
... ]
|
| 308 |
+
|
| 309 |
+
>>> inputs = processor.apply_chat_template(
|
| 310 |
+
... conversation,
|
| 311 |
+
... add_generation_prompt=True,
|
| 312 |
+
... tokenize=True,
|
| 313 |
+
... return_dict=True,
|
| 314 |
+
... return_tensors="pt"
|
| 315 |
+
... )
|
| 316 |
+
|
| 317 |
+
>>> # Generate
|
| 318 |
+
>>> outputs = model.generate(**inputs, max_new_tokens=45)
|
| 319 |
+
>>> processor.batch_decode(outputs, skip_special_tokens=True)[0]
|
| 320 |
+
'This image depicts a vibrant street scene in what appears to be a Chinatown or similar cultural area. The focal point is a large red stop sign with white lettering, mounted on a pole.'
|
| 321 |
+
```"""
|
| 322 |
+
outputs = self.model(
|
| 323 |
+
input_ids=input_ids,
|
| 324 |
+
pixel_values=pixel_values,
|
| 325 |
+
spatial_shapes=spatial_shapes,
|
| 326 |
+
pixel_attention_mask=pixel_attention_mask,
|
| 327 |
+
attention_mask=attention_mask,
|
| 328 |
+
position_ids=position_ids,
|
| 329 |
+
past_key_values=past_key_values,
|
| 330 |
+
inputs_embeds=inputs_embeds,
|
| 331 |
+
use_cache=use_cache,
|
| 332 |
+
**kwargs,
|
| 333 |
+
)
|
| 334 |
+
|
| 335 |
+
hidden_states = outputs[0]
|
| 336 |
+
# Only compute necessary logits, and do not upcast them to float if we are not computing the loss
|
| 337 |
+
slice_indices = slice(-logits_to_keep, None) if isinstance(logits_to_keep, int) else logits_to_keep
|
| 338 |
+
logits = self.lm_head(hidden_states[:, slice_indices, :])
|
| 339 |
+
|
| 340 |
+
loss = None
|
| 341 |
+
if labels is not None:
|
| 342 |
+
loss = self.loss_function(
|
| 343 |
+
logits=logits,
|
| 344 |
+
labels=labels,
|
| 345 |
+
vocab_size=self.config.text_config.vocab_size,
|
| 346 |
+
**kwargs,
|
| 347 |
+
)
|
| 348 |
+
|
| 349 |
+
return Lfm2VlCausalLMOutputWithPast(
|
| 350 |
+
loss=loss,
|
| 351 |
+
logits=logits,
|
| 352 |
+
past_key_values=outputs.past_key_values,
|
| 353 |
+
hidden_states=outputs.hidden_states,
|
| 354 |
+
attentions=outputs.attentions,
|
| 355 |
+
image_hidden_states=outputs.image_hidden_states,
|
| 356 |
+
)
|
| 357 |
+
|
| 358 |
+
|
| 359 |
+
__all__ = ["Lfm2VlForConditionalGeneration", "Lfm2VlPreTrainedModel", "Lfm2VlModel"]
|
third_party/transformers/src/transformers/models/lfm2_vl/processing_lfm2_vl.py
ADDED
|
@@ -0,0 +1,272 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
# Copyright 2025 the HuggingFace Inc. team. All rights reserved.
|
| 2 |
+
#
|
| 3 |
+
# Licensed under the Apache License, Version 2.0 (the "License");
|
| 4 |
+
# you may not use this file except in compliance with the License.
|
| 5 |
+
# You may obtain a copy of the License at
|
| 6 |
+
#
|
| 7 |
+
# http://www.apache.org/licenses/LICENSE-2.0
|
| 8 |
+
#
|
| 9 |
+
# Unless required by applicable law or agreed to in writing, software
|
| 10 |
+
# distributed under the License is distributed on an "AS IS" BASIS,
|
| 11 |
+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
| 12 |
+
# See the License for the specific language governing permissions and
|
| 13 |
+
# limitations under the License.
|
| 14 |
+
import math
|
| 15 |
+
|
| 16 |
+
from ...feature_extraction_utils import BatchFeature
|
| 17 |
+
from ...image_utils import ImageInput, make_nested_list_of_images
|
| 18 |
+
from ...processing_utils import (
|
| 19 |
+
ProcessingKwargs,
|
| 20 |
+
ProcessorMixin,
|
| 21 |
+
TextKwargs,
|
| 22 |
+
Unpack,
|
| 23 |
+
)
|
| 24 |
+
from ...tokenization_utils_base import BatchEncoding, TextInput
|
| 25 |
+
from ...utils import auto_docstring, logging
|
| 26 |
+
|
| 27 |
+
|
| 28 |
+
logger = logging.get_logger(__name__)
|
| 29 |
+
|
| 30 |
+
|
| 31 |
+
class Lfm2VlTextKwargs(TextKwargs, total=False):
|
| 32 |
+
"""
|
| 33 |
+
use_image_special_tokens (`bool`, *optional*, defaults to `True`):
|
| 34 |
+
Whether to use special image tokens (`<|image_start|>` and `<|image_end|>`) to delimit image sequences
|
| 35 |
+
in the text. When enabled, images are wrapped with these tokens to clearly mark image boundaries.
|
| 36 |
+
When disabled, only the image token itself is used without delimiters.
|
| 37 |
+
"""
|
| 38 |
+
|
| 39 |
+
use_image_special_tokens: bool | None
|
| 40 |
+
|
| 41 |
+
|
| 42 |
+
class Lfm2VlProcessorKwargs(ProcessingKwargs, total=False):
|
| 43 |
+
text_kwargs: Lfm2VlTextKwargs
|
| 44 |
+
_defaults = {
|
| 45 |
+
"images_kwargs": {
|
| 46 |
+
"return_row_col_info": True,
|
| 47 |
+
},
|
| 48 |
+
"text_kwargs": {
|
| 49 |
+
"use_image_special_tokens": True,
|
| 50 |
+
"add_special_tokens": False,
|
| 51 |
+
"padding": False,
|
| 52 |
+
"is_split_into_words": False,
|
| 53 |
+
},
|
| 54 |
+
}
|
| 55 |
+
|
| 56 |
+
|
| 57 |
+
@auto_docstring
|
| 58 |
+
class Lfm2VlProcessor(ProcessorMixin):
|
| 59 |
+
def __init__(
|
| 60 |
+
self,
|
| 61 |
+
image_processor,
|
| 62 |
+
tokenizer,
|
| 63 |
+
chat_template: str | None = None,
|
| 64 |
+
**kwargs,
|
| 65 |
+
):
|
| 66 |
+
self.image_token = getattr(tokenizer, "image_token", "<image>")
|
| 67 |
+
self.image_token_id = (
|
| 68 |
+
tokenizer.image_token_id
|
| 69 |
+
if hasattr(tokenizer, "image_token_id")
|
| 70 |
+
else tokenizer.convert_tokens_to_ids(self.image_token)
|
| 71 |
+
)
|
| 72 |
+
self.image_start_token = getattr(tokenizer, "image_start_token", "<|image_start|>")
|
| 73 |
+
self.image_end_token = getattr(tokenizer, "image_end_token", "<|image_end|>")
|
| 74 |
+
self.image_thumbnail_token = getattr(tokenizer, "image_thumbnail_token", "<|img_thumbnail|>")
|
| 75 |
+
super().__init__(image_processor, tokenizer, chat_template=chat_template, **kwargs)
|
| 76 |
+
|
| 77 |
+
@auto_docstring
|
| 78 |
+
def __call__(
|
| 79 |
+
self,
|
| 80 |
+
images: ImageInput | list[ImageInput] | list[list[ImageInput]] | None = None,
|
| 81 |
+
text: TextInput | list[TextInput] | None = None,
|
| 82 |
+
**kwargs: Unpack[Lfm2VlProcessorKwargs],
|
| 83 |
+
) -> BatchEncoding:
|
| 84 |
+
if text is None and images is None:
|
| 85 |
+
raise ValueError("You must provide one of `text` or `images`.")
|
| 86 |
+
|
| 87 |
+
if images is not None and text is None:
|
| 88 |
+
raise ValueError(
|
| 89 |
+
"You must provide `text` when `images` is provided. Minimal text consists of a single image token."
|
| 90 |
+
)
|
| 91 |
+
|
| 92 |
+
output_kwargs = self._merge_kwargs(
|
| 93 |
+
Lfm2VlProcessorKwargs,
|
| 94 |
+
tokenizer_init_kwargs=self.tokenizer.init_kwargs,
|
| 95 |
+
**kwargs,
|
| 96 |
+
)
|
| 97 |
+
|
| 98 |
+
if isinstance(text, str):
|
| 99 |
+
text = [text]
|
| 100 |
+
elif not isinstance(text, list) and not isinstance(text[0], str):
|
| 101 |
+
raise TypeError("Invalid input text. Please provide a string, or a list of strings")
|
| 102 |
+
|
| 103 |
+
n_images_in_text = [sample.count(self.image_token) for sample in text]
|
| 104 |
+
if sum(n_images_in_text) > 0 and images is None:
|
| 105 |
+
raise ValueError(f"We detected {sum(n_images_in_text)} tokens in the text but no images were passed")
|
| 106 |
+
|
| 107 |
+
inputs = {}
|
| 108 |
+
use_image_special_tokens = output_kwargs["text_kwargs"].pop("use_image_special_tokens")
|
| 109 |
+
|
| 110 |
+
if images is not None:
|
| 111 |
+
images = self.image_processor.fetch_images(images)
|
| 112 |
+
batched_images = make_nested_list_of_images(images)
|
| 113 |
+
vision_inputs = self.image_processor(batched_images, **output_kwargs["images_kwargs"])
|
| 114 |
+
|
| 115 |
+
n_images_in_images = [len(sublist) for sublist in batched_images]
|
| 116 |
+
if n_images_in_images != n_images_in_text:
|
| 117 |
+
raise ValueError(
|
| 118 |
+
f"The number of images in the text {n_images_in_text} and images {n_images_in_images} should be the same."
|
| 119 |
+
)
|
| 120 |
+
|
| 121 |
+
text = self.expand_text_with_placeholders(
|
| 122 |
+
text,
|
| 123 |
+
batched_images,
|
| 124 |
+
image_rows=vision_inputs.pop("image_rows"),
|
| 125 |
+
image_cols=vision_inputs.pop("image_cols"),
|
| 126 |
+
image_sizes=vision_inputs.pop("image_sizes"),
|
| 127 |
+
use_image_special_tokens=use_image_special_tokens,
|
| 128 |
+
**output_kwargs["images_kwargs"],
|
| 129 |
+
)
|
| 130 |
+
inputs.update(vision_inputs)
|
| 131 |
+
|
| 132 |
+
return_tensors = output_kwargs["text_kwargs"].pop("return_tensors", None)
|
| 133 |
+
|
| 134 |
+
text_inputs = self.tokenizer(text, **output_kwargs["text_kwargs"])
|
| 135 |
+
inputs.update(text_inputs)
|
| 136 |
+
|
| 137 |
+
return BatchFeature(inputs, tensor_type=return_tensors)
|
| 138 |
+
|
| 139 |
+
def expand_text_with_placeholders(
|
| 140 |
+
self,
|
| 141 |
+
text: list[str],
|
| 142 |
+
images: list[list[ImageInput]],
|
| 143 |
+
image_rows: list[list[int]],
|
| 144 |
+
image_cols: list[list[int]],
|
| 145 |
+
image_sizes: list[list[int]],
|
| 146 |
+
use_image_special_tokens: bool,
|
| 147 |
+
**images_kwargs,
|
| 148 |
+
) -> list[str]:
|
| 149 |
+
use_thumbnail = images_kwargs.get("use_thumbnail", self.image_processor.use_thumbnail)
|
| 150 |
+
image_data = iter(zip(image_rows, image_cols, image_sizes))
|
| 151 |
+
|
| 152 |
+
prompt_strings = []
|
| 153 |
+
for sample_text, sample_images in zip(text, images):
|
| 154 |
+
text_parts = sample_text.split(self.image_token)
|
| 155 |
+
result_parts = []
|
| 156 |
+
|
| 157 |
+
for i, _ in enumerate(sample_images):
|
| 158 |
+
result_parts.append(text_parts[i])
|
| 159 |
+
|
| 160 |
+
rows, cols, image_size = next(image_data)
|
| 161 |
+
tokens_per_tile, tokens_for_image = self._get_image_num_tokens(image_size, **images_kwargs)
|
| 162 |
+
image_tokens = self._build_image_tokens(
|
| 163 |
+
rows,
|
| 164 |
+
cols,
|
| 165 |
+
tokens_per_tile,
|
| 166 |
+
tokens_for_image,
|
| 167 |
+
use_thumbnail,
|
| 168 |
+
use_image_special_tokens,
|
| 169 |
+
)
|
| 170 |
+
result_parts.append(image_tokens)
|
| 171 |
+
|
| 172 |
+
# Add remaining text after the last image
|
| 173 |
+
if len(sample_images) < len(text_parts):
|
| 174 |
+
result_parts.append(text_parts[-1])
|
| 175 |
+
|
| 176 |
+
prompt_strings.append("".join(result_parts))
|
| 177 |
+
|
| 178 |
+
return prompt_strings
|
| 179 |
+
|
| 180 |
+
def _build_image_tokens(
|
| 181 |
+
self,
|
| 182 |
+
rows: int,
|
| 183 |
+
cols: int,
|
| 184 |
+
tokens_per_tile: int,
|
| 185 |
+
tokens_for_image: int,
|
| 186 |
+
use_thumbnail: bool,
|
| 187 |
+
use_image_special_tokens: bool,
|
| 188 |
+
) -> str:
|
| 189 |
+
"""Build the expanded token string for a single image."""
|
| 190 |
+
parts = []
|
| 191 |
+
|
| 192 |
+
if use_image_special_tokens:
|
| 193 |
+
parts.append(self.image_start_token)
|
| 194 |
+
|
| 195 |
+
is_multi_tile = rows > 1 or cols > 1
|
| 196 |
+
if is_multi_tile:
|
| 197 |
+
for row in range(rows):
|
| 198 |
+
for col in range(cols):
|
| 199 |
+
if use_image_special_tokens:
|
| 200 |
+
parts.append(f"<|img_row_{row + 1}_col_{col + 1}|>")
|
| 201 |
+
parts.append(self.image_token * tokens_per_tile)
|
| 202 |
+
|
| 203 |
+
if use_thumbnail:
|
| 204 |
+
if use_image_special_tokens:
|
| 205 |
+
parts.append(self.image_thumbnail_token)
|
| 206 |
+
parts.append(self.image_token * tokens_for_image)
|
| 207 |
+
else:
|
| 208 |
+
parts.append(self.image_token * tokens_for_image)
|
| 209 |
+
|
| 210 |
+
if use_image_special_tokens:
|
| 211 |
+
parts.append(self.image_end_token)
|
| 212 |
+
|
| 213 |
+
return "".join(parts)
|
| 214 |
+
|
| 215 |
+
def _compute_tokens_per_tile(self, tile_size: int, encoder_patch_size: int, downsample_factor: int) -> int:
|
| 216 |
+
"""Compute the number of tokens for a single tile."""
|
| 217 |
+
num_patches = tile_size // encoder_patch_size
|
| 218 |
+
downsampled_patches = math.ceil(num_patches / downsample_factor)
|
| 219 |
+
return downsampled_patches * downsampled_patches
|
| 220 |
+
|
| 221 |
+
def _compute_tokens_for_image(self, image_size: list[int], encoder_patch_size: int, downsample_factor: int) -> int:
|
| 222 |
+
"""Compute the number of tokens for a resized image (used for single-tile or thumbnail)."""
|
| 223 |
+
image_height, image_width = image_size
|
| 224 |
+
patches_h = math.ceil((image_height // encoder_patch_size) / downsample_factor)
|
| 225 |
+
patches_w = math.ceil((image_width // encoder_patch_size) / downsample_factor)
|
| 226 |
+
return patches_h * patches_w
|
| 227 |
+
|
| 228 |
+
def _get_image_num_tokens(self, image_size: list[int], **images_kwargs) -> tuple[int, int]:
|
| 229 |
+
"""
|
| 230 |
+
Compute token counts for image processing.
|
| 231 |
+
|
| 232 |
+
Returns:
|
| 233 |
+
tuple[int, int]: (tokens_per_tile, tokens_for_image)
|
| 234 |
+
- tokens_per_tile: tokens for each tile in multi-tile mode
|
| 235 |
+
- tokens_for_image: tokens for the resized image (single-tile) or thumbnail (multi-tile)
|
| 236 |
+
"""
|
| 237 |
+
tile_size = images_kwargs.get("tile_size", self.image_processor.tile_size)
|
| 238 |
+
downsample_factor = images_kwargs.get("downsample_factor", self.image_processor.downsample_factor)
|
| 239 |
+
encoder_patch_size = images_kwargs.get("encoder_patch_size", self.image_processor.encoder_patch_size)
|
| 240 |
+
|
| 241 |
+
tokens_per_tile = self._compute_tokens_per_tile(tile_size, encoder_patch_size, downsample_factor)
|
| 242 |
+
tokens_for_image = self._compute_tokens_for_image(image_size, encoder_patch_size, downsample_factor)
|
| 243 |
+
|
| 244 |
+
return tokens_per_tile, tokens_for_image
|
| 245 |
+
|
| 246 |
+
def batch_decode(self, *args, **kwargs):
|
| 247 |
+
"""
|
| 248 |
+
This method forwards all its arguments to LFM2Tokeniser's [`~PreTrainedTokenizer.batch_decode`]. Please
|
| 249 |
+
refer to the docstring of this method for more information.
|
| 250 |
+
"""
|
| 251 |
+
batched_decode_output = self.tokenizer.batch_decode(*args, **kwargs)
|
| 252 |
+
return batched_decode_output
|
| 253 |
+
|
| 254 |
+
def decode(self, *args, **kwargs):
|
| 255 |
+
"""
|
| 256 |
+
This method forwards all its arguments to LFM2Tokeniser's [`~PreTrainedTokenizer.decode`]. Please refer to
|
| 257 |
+
the docstring of this method for more information.
|
| 258 |
+
"""
|
| 259 |
+
decode_output = self.tokenizer.decode(*args, **kwargs)
|
| 260 |
+
return decode_output
|
| 261 |
+
|
| 262 |
+
@property
|
| 263 |
+
def model_input_names(self):
|
| 264 |
+
tokenizer_input_names = self.tokenizer.model_input_names
|
| 265 |
+
image_processor_input_names = self.image_processor.model_input_names
|
| 266 |
+
|
| 267 |
+
# LFM2-VL has no dedicated tokenizer class and uses the Base class with default model input names
|
| 268 |
+
tokenizer_input_names = [name for name in tokenizer_input_names if name != "token_type_ids"]
|
| 269 |
+
return list(tokenizer_input_names + image_processor_input_names)
|
| 270 |
+
|
| 271 |
+
|
| 272 |
+
__all__ = ["Lfm2VlProcessor"]
|
third_party/transformers/src/transformers/models/minimax_m2/__init__.py
ADDED
|
@@ -0,0 +1,28 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
# Copyright 2025 the HuggingFace Team. All rights reserved.
|
| 2 |
+
#
|
| 3 |
+
# Licensed under the Apache License, Version 2.0 (the "License");
|
| 4 |
+
# you may not use this file except in compliance with the License.
|
| 5 |
+
# You may obtain a copy of the License at
|
| 6 |
+
#
|
| 7 |
+
# http://www.apache.org/licenses/LICENSE-2.0
|
| 8 |
+
#
|
| 9 |
+
# Unless required by applicable law or agreed to in writing, software
|
| 10 |
+
# distributed under the License is distributed on an "AS IS" BASIS,
|
| 11 |
+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
| 12 |
+
# See the License for the specific language governing permissions and
|
| 13 |
+
# limitations under the License.
|
| 14 |
+
|
| 15 |
+
from typing import TYPE_CHECKING
|
| 16 |
+
|
| 17 |
+
from ...utils import _LazyModule
|
| 18 |
+
from ...utils.import_utils import define_import_structure
|
| 19 |
+
|
| 20 |
+
|
| 21 |
+
if TYPE_CHECKING:
|
| 22 |
+
from .configuration_minimax_m2 import *
|
| 23 |
+
from .modeling_minimax_m2 import *
|
| 24 |
+
else:
|
| 25 |
+
import sys
|
| 26 |
+
|
| 27 |
+
_file = globals()["__file__"]
|
| 28 |
+
sys.modules[__name__] = _LazyModule(__name__, _file, define_import_structure(_file), module_spec=__spec__)
|
third_party/transformers/src/transformers/models/minimax_m2/configuration_minimax_m2.py
ADDED
|
@@ -0,0 +1,94 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
# 🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨
|
| 2 |
+
# This file was automatically generated from src/transformers/models/minimax_m2/modular_minimax_m2.py.
|
| 3 |
+
# Do NOT edit this file manually as any edits will be overwritten by the generation of
|
| 4 |
+
# the file from the modular. If any change should be done, please apply the change to the
|
| 5 |
+
# modular_minimax_m2.py file directly. One of our CI enforces this.
|
| 6 |
+
# 🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨
|
| 7 |
+
# Copyright 2025 the MiniMax AI Team and HuggingFace Team. All rights reserved.
|
| 8 |
+
#
|
| 9 |
+
# Licensed under the Apache License, Version 2.0 (the "License");
|
| 10 |
+
# you may not use this file except in compliance with the License.
|
| 11 |
+
# You may obtain a copy of the License at
|
| 12 |
+
#
|
| 13 |
+
# http://www.apache.org/licenses/LICENSE-2.0
|
| 14 |
+
#
|
| 15 |
+
# Unless required by applicable law or agreed to in writing, software
|
| 16 |
+
# distributed under the License is distributed on an "AS IS" BASIS,
|
| 17 |
+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
| 18 |
+
# See the License for the specific language governing permissions and
|
| 19 |
+
# limitations under the License.
|
| 20 |
+
|
| 21 |
+
|
| 22 |
+
from huggingface_hub.dataclasses import strict
|
| 23 |
+
|
| 24 |
+
from ...configuration_utils import PreTrainedConfig
|
| 25 |
+
from ...modeling_rope_utils import RopeParameters
|
| 26 |
+
from ...utils import auto_docstring
|
| 27 |
+
|
| 28 |
+
|
| 29 |
+
@auto_docstring(checkpoint="MiniMaxAI/MiniMax-Text-01-hf")
|
| 30 |
+
@strict
|
| 31 |
+
class MiniMaxM2Config(PreTrainedConfig):
|
| 32 |
+
r"""
|
| 33 |
+
Example:
|
| 34 |
+
|
| 35 |
+
```python
|
| 36 |
+
>>> from transformers import MiniMaxM2Model, MiniMaxM2Config
|
| 37 |
+
|
| 38 |
+
>>> # Initializing a MiniMaxM2 style configuration
|
| 39 |
+
>>> configuration = MiniMaxM2Config()
|
| 40 |
+
|
| 41 |
+
>>> # Initializing a model from the MiniMaxM2 style configuration
|
| 42 |
+
>>> model = MiniMaxM2Model(configuration)
|
| 43 |
+
|
| 44 |
+
>>> # Accessing the model configuration
|
| 45 |
+
>>> configuration = model.config
|
| 46 |
+
```"""
|
| 47 |
+
|
| 48 |
+
model_type = "minimax_m2"
|
| 49 |
+
keys_to_ignore_at_inference = ["past_key_values"]
|
| 50 |
+
base_model_tp_plan = {
|
| 51 |
+
"layers.*.self_attn.q_proj": "colwise_gather_output",
|
| 52 |
+
"layers.*.self_attn.k_proj": "colwise_gather_output",
|
| 53 |
+
"layers.*.self_attn.v_proj": "colwise_gather_output",
|
| 54 |
+
"layers.*.self_attn.o_proj": "rowwise_split_input",
|
| 55 |
+
"layers.*.mlp.experts.gate_up_proj": "packed_colwise",
|
| 56 |
+
"layers.*.mlp.experts.down_proj": "rowwise",
|
| 57 |
+
"layers.*.mlp.experts": "moe_tp_experts",
|
| 58 |
+
}
|
| 59 |
+
base_model_pp_plan = {
|
| 60 |
+
"embed_tokens": (["input_ids"], ["inputs_embeds"]),
|
| 61 |
+
"layers": (["hidden_states", "attention_mask"], ["hidden_states"]),
|
| 62 |
+
"norm": (["hidden_states"], ["hidden_states"]),
|
| 63 |
+
}
|
| 64 |
+
attribute_map = {
|
| 65 |
+
"num_experts": "num_local_experts",
|
| 66 |
+
}
|
| 67 |
+
default_theta = 5000000.0
|
| 68 |
+
|
| 69 |
+
vocab_size: int = 200064
|
| 70 |
+
hidden_size: int = 3072
|
| 71 |
+
intermediate_size: int = 1536
|
| 72 |
+
num_hidden_layers: int = 62
|
| 73 |
+
num_attention_heads: int = 48
|
| 74 |
+
num_key_value_heads: int = 8
|
| 75 |
+
head_dim: int = 128
|
| 76 |
+
hidden_act: str = "silu"
|
| 77 |
+
max_position_embeddings: int = 196608
|
| 78 |
+
initializer_range: float = 0.02
|
| 79 |
+
rms_norm_eps: float = 1e-06
|
| 80 |
+
use_cache: bool = True
|
| 81 |
+
pad_token_id: int | None = None
|
| 82 |
+
bos_token_id: int | None = 200034
|
| 83 |
+
eos_token_id: int | list[int] | None = 200020
|
| 84 |
+
tie_word_embeddings: bool = False
|
| 85 |
+
attention_dropout: float | int = 0.0
|
| 86 |
+
num_experts_per_tok: int = 8
|
| 87 |
+
num_local_experts: int = 256
|
| 88 |
+
output_router_logits: bool = False
|
| 89 |
+
router_aux_loss_coef: float = 0.001
|
| 90 |
+
router_jitter_noise: float = 0.0
|
| 91 |
+
rope_parameters: RopeParameters | dict | None = None
|
| 92 |
+
|
| 93 |
+
|
| 94 |
+
__all__ = ["MiniMaxM2Config"]
|
third_party/transformers/src/transformers/models/minimax_m2/modeling_minimax_m2.py
ADDED
|
@@ -0,0 +1,691 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
# 🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨
|
| 2 |
+
# This file was automatically generated from src/transformers/models/minimax_m2/modular_minimax_m2.py.
|
| 3 |
+
# Do NOT edit this file manually as any edits will be overwritten by the generation of
|
| 4 |
+
# the file from the modular. If any change should be done, please apply the change to the
|
| 5 |
+
# modular_minimax_m2.py file directly. One of our CI enforces this.
|
| 6 |
+
# 🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨
|
| 7 |
+
# Copyright 2025 the MiniMax AI Team and HuggingFace Team. All rights reserved.
|
| 8 |
+
#
|
| 9 |
+
# Licensed under the Apache License, Version 2.0 (the "License");
|
| 10 |
+
# you may not use this file except in compliance with the License.
|
| 11 |
+
# You may obtain a copy of the License at
|
| 12 |
+
#
|
| 13 |
+
# http://www.apache.org/licenses/LICENSE-2.0
|
| 14 |
+
#
|
| 15 |
+
# Unless required by applicable law or agreed to in writing, software
|
| 16 |
+
# distributed under the License is distributed on an "AS IS" BASIS,
|
| 17 |
+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
| 18 |
+
# See the License for the specific language governing permissions and
|
| 19 |
+
# limitations under the License.
|
| 20 |
+
|
| 21 |
+
|
| 22 |
+
from collections.abc import Callable
|
| 23 |
+
from typing import Optional
|
| 24 |
+
|
| 25 |
+
import torch
|
| 26 |
+
import torch.nn.functional as F
|
| 27 |
+
from torch import nn
|
| 28 |
+
|
| 29 |
+
from ... import initialization as init
|
| 30 |
+
from ...activations import ACT2FN
|
| 31 |
+
from ...cache_utils import Cache, DynamicCache
|
| 32 |
+
from ...generation import GenerationMixin
|
| 33 |
+
from ...integrations import use_experts_implementation, use_kernel_forward_from_hub, use_kernelized_func
|
| 34 |
+
from ...masking_utils import create_causal_mask
|
| 35 |
+
from ...modeling_layers import GradientCheckpointingLayer
|
| 36 |
+
from ...modeling_outputs import MoeCausalLMOutputWithPast, MoeModelOutputWithPast
|
| 37 |
+
from ...modeling_rope_utils import ROPE_INIT_FUNCTIONS, dynamic_rope_update
|
| 38 |
+
from ...modeling_utils import ALL_ATTENTION_FUNCTIONS, PreTrainedModel
|
| 39 |
+
from ...processing_utils import Unpack
|
| 40 |
+
from ...utils import TransformersKwargs, auto_docstring, can_return_tuple
|
| 41 |
+
from ...utils.generic import maybe_autocast, merge_with_config_defaults
|
| 42 |
+
from ...utils.output_capturing import OutputRecorder, capture_outputs
|
| 43 |
+
from .configuration_minimax_m2 import MiniMaxM2Config
|
| 44 |
+
|
| 45 |
+
|
| 46 |
+
class MiniMaxM2TopKRouter(nn.Module):
|
| 47 |
+
def __init__(self, config):
|
| 48 |
+
super().__init__()
|
| 49 |
+
self.top_k = config.num_experts_per_tok
|
| 50 |
+
self.num_experts = config.num_local_experts
|
| 51 |
+
self.hidden_dim = config.hidden_size
|
| 52 |
+
self.weight = nn.Parameter(torch.empty(self.num_experts, self.hidden_dim))
|
| 53 |
+
|
| 54 |
+
def forward(self, hidden_states, e_score_correction_bias):
|
| 55 |
+
hidden_states = hidden_states.reshape(-1, self.hidden_dim)
|
| 56 |
+
router_logits = F.linear(hidden_states.to(self.weight.dtype), self.weight) # (seq_len, num_experts)
|
| 57 |
+
# Main difference to other Moe, using Sigmoid activation instead of Softmax
|
| 58 |
+
routing_weights = nn.functional.sigmoid(router_logits.float())
|
| 59 |
+
scores_for_choice = routing_weights + e_score_correction_bias
|
| 60 |
+
_, top_k_index = torch.topk(scores_for_choice, self.top_k, dim=-1, sorted=False)
|
| 61 |
+
top_k_weights = routing_weights.gather(1, top_k_index)
|
| 62 |
+
top_k_weights /= top_k_weights.sum(dim=-1, keepdim=True)
|
| 63 |
+
router_scores = top_k_weights
|
| 64 |
+
return router_logits, router_scores, top_k_index
|
| 65 |
+
|
| 66 |
+
|
| 67 |
+
@use_experts_implementation
|
| 68 |
+
class MiniMaxM2Experts(nn.Module):
|
| 69 |
+
"""Collection of expert weights stored as 3D tensors."""
|
| 70 |
+
|
| 71 |
+
def __init__(self, config: MiniMaxM2Config):
|
| 72 |
+
super().__init__()
|
| 73 |
+
self.num_experts = config.num_local_experts
|
| 74 |
+
self.hidden_dim = config.hidden_size
|
| 75 |
+
self.intermediate_dim = config.intermediate_size
|
| 76 |
+
self.gate_up_proj = nn.Parameter(torch.empty(self.num_experts, 2 * self.intermediate_dim, self.hidden_dim))
|
| 77 |
+
self.down_proj = nn.Parameter(torch.empty(self.num_experts, self.hidden_dim, self.intermediate_dim))
|
| 78 |
+
self.act_fn = ACT2FN[config.hidden_act]
|
| 79 |
+
|
| 80 |
+
def forward(
|
| 81 |
+
self,
|
| 82 |
+
hidden_states: torch.Tensor,
|
| 83 |
+
top_k_index: torch.Tensor,
|
| 84 |
+
top_k_weights: torch.Tensor,
|
| 85 |
+
) -> torch.Tensor:
|
| 86 |
+
final_hidden_states = torch.zeros_like(hidden_states)
|
| 87 |
+
with torch.no_grad():
|
| 88 |
+
expert_mask = torch.nn.functional.one_hot(top_k_index, num_classes=self.num_experts)
|
| 89 |
+
expert_mask = expert_mask.permute(2, 1, 0)
|
| 90 |
+
expert_hit = torch.greater(expert_mask.sum(dim=(-1, -2)), 0).nonzero()
|
| 91 |
+
|
| 92 |
+
for expert_idx in expert_hit:
|
| 93 |
+
expert_idx = expert_idx[0]
|
| 94 |
+
if expert_idx == self.num_experts:
|
| 95 |
+
continue
|
| 96 |
+
top_k_pos, token_idx = torch.where(expert_mask[expert_idx])
|
| 97 |
+
current_state = hidden_states[token_idx]
|
| 98 |
+
gate, up = nn.functional.linear(current_state, self.gate_up_proj[expert_idx]).chunk(2, dim=-1)
|
| 99 |
+
current_hidden_states = self.act_fn(gate) * up
|
| 100 |
+
current_hidden_states = nn.functional.linear(current_hidden_states, self.down_proj[expert_idx])
|
| 101 |
+
current_hidden_states = current_hidden_states * top_k_weights[token_idx, top_k_pos, None]
|
| 102 |
+
final_hidden_states.index_add_(0, token_idx, current_hidden_states.to(final_hidden_states.dtype))
|
| 103 |
+
|
| 104 |
+
return final_hidden_states
|
| 105 |
+
|
| 106 |
+
|
| 107 |
+
class MiniMaxM2SparseMoeBlock(nn.Module):
|
| 108 |
+
def __init__(self, config):
|
| 109 |
+
super().__init__()
|
| 110 |
+
self.top_k = config.num_experts_per_tok
|
| 111 |
+
self.jitter_noise = config.router_jitter_noise
|
| 112 |
+
self.gate = MiniMaxM2TopKRouter(config)
|
| 113 |
+
self.experts = MiniMaxM2Experts(config)
|
| 114 |
+
self.register_buffer("e_score_correction_bias", torch.zeros(config.num_local_experts))
|
| 115 |
+
|
| 116 |
+
def forward(self, hidden_states: torch.Tensor) -> tuple[torch.Tensor, torch.Tensor]:
|
| 117 |
+
batch_size, sequence_length, hidden_dim = hidden_states.shape
|
| 118 |
+
if self.training and self.jitter_noise > 0:
|
| 119 |
+
hidden_states *= torch.empty_like(hidden_states).uniform_(1.0 - self.jitter_noise, 1.0 + self.jitter_noise)
|
| 120 |
+
hidden_states = hidden_states.view(-1, hidden_states.shape[-1])
|
| 121 |
+
_, top_k_weights, top_k_index = self.gate(hidden_states, self.e_score_correction_bias)
|
| 122 |
+
hidden_states = self.experts(hidden_states, top_k_index, top_k_weights)
|
| 123 |
+
hidden_states = hidden_states.reshape(batch_size, sequence_length, hidden_dim)
|
| 124 |
+
return hidden_states
|
| 125 |
+
|
| 126 |
+
|
| 127 |
+
@use_kernel_forward_from_hub("RMSNorm")
|
| 128 |
+
class MiniMaxM2RMSNorm(nn.Module):
|
| 129 |
+
def __init__(self, hidden_size, eps: float = 1e-6) -> None:
|
| 130 |
+
"""
|
| 131 |
+
MiniMaxM2RMSNorm is equivalent to T5LayerNorm
|
| 132 |
+
"""
|
| 133 |
+
super().__init__()
|
| 134 |
+
self.weight = nn.Parameter(torch.ones(hidden_size))
|
| 135 |
+
self.variance_epsilon = eps
|
| 136 |
+
|
| 137 |
+
def forward(self, hidden_states: torch.Tensor) -> torch.Tensor:
|
| 138 |
+
input_dtype = hidden_states.dtype
|
| 139 |
+
hidden_states = hidden_states.to(torch.float32)
|
| 140 |
+
variance = hidden_states.pow(2).mean(-1, keepdim=True)
|
| 141 |
+
hidden_states = hidden_states * torch.rsqrt(variance + self.variance_epsilon)
|
| 142 |
+
return self.weight * hidden_states.to(input_dtype)
|
| 143 |
+
|
| 144 |
+
def extra_repr(self):
|
| 145 |
+
return f"{tuple(self.weight.shape)}, eps={self.variance_epsilon}"
|
| 146 |
+
|
| 147 |
+
|
| 148 |
+
class MiniMaxM2RotaryEmbedding(nn.Module):
|
| 149 |
+
inv_freq: torch.Tensor # fix linting for `register_buffer`
|
| 150 |
+
|
| 151 |
+
def __init__(self, config: MiniMaxM2Config, device=None):
|
| 152 |
+
super().__init__()
|
| 153 |
+
self.max_seq_len_cached = config.max_position_embeddings
|
| 154 |
+
self.original_max_seq_len = config.max_position_embeddings
|
| 155 |
+
|
| 156 |
+
self.config = config
|
| 157 |
+
|
| 158 |
+
self.rope_type = self.config.rope_parameters["rope_type"]
|
| 159 |
+
rope_init_fn: Callable = self.compute_default_rope_parameters
|
| 160 |
+
if self.rope_type != "default":
|
| 161 |
+
rope_init_fn = ROPE_INIT_FUNCTIONS[self.rope_type]
|
| 162 |
+
inv_freq, self.attention_scaling = rope_init_fn(self.config, device)
|
| 163 |
+
|
| 164 |
+
self.register_buffer("inv_freq", inv_freq, persistent=False)
|
| 165 |
+
self.register_buffer("original_inv_freq", inv_freq.clone(), persistent=False)
|
| 166 |
+
|
| 167 |
+
@staticmethod
|
| 168 |
+
def compute_default_rope_parameters(
|
| 169 |
+
config: MiniMaxM2Config | None = None,
|
| 170 |
+
device: Optional["torch.device"] = None,
|
| 171 |
+
seq_len: int | None = None,
|
| 172 |
+
) -> tuple["torch.Tensor", float]:
|
| 173 |
+
"""
|
| 174 |
+
Computes the inverse frequencies according to the original RoPE implementation
|
| 175 |
+
Args:
|
| 176 |
+
config ([`~transformers.PreTrainedConfig`]):
|
| 177 |
+
The model configuration.
|
| 178 |
+
device (`torch.device`):
|
| 179 |
+
The device to use for initialization of the inverse frequencies.
|
| 180 |
+
seq_len (`int`, *optional*):
|
| 181 |
+
The current sequence length. Unused for this type of RoPE.
|
| 182 |
+
Returns:
|
| 183 |
+
Tuple of (`torch.Tensor`, `float`), containing the inverse frequencies for the RoPE embeddings and the
|
| 184 |
+
post-processing scaling factor applied to the computed cos/sin (unused in this type of RoPE).
|
| 185 |
+
"""
|
| 186 |
+
base = config.rope_parameters["rope_theta"]
|
| 187 |
+
partial_rotary_factor = config.rope_parameters.get("partial_rotary_factor", 1.0)
|
| 188 |
+
head_dim = getattr(config, "head_dim", None) or config.hidden_size // config.num_attention_heads
|
| 189 |
+
dim = int(head_dim * partial_rotary_factor)
|
| 190 |
+
|
| 191 |
+
attention_factor = 1.0 # Unused in this type of RoPE
|
| 192 |
+
|
| 193 |
+
# Compute the inverse frequencies
|
| 194 |
+
inv_freq = 1.0 / (
|
| 195 |
+
base ** (torch.arange(0, dim, 2, dtype=torch.int64).to(device=device, dtype=torch.float) / dim)
|
| 196 |
+
)
|
| 197 |
+
return inv_freq, attention_factor
|
| 198 |
+
|
| 199 |
+
@torch.no_grad()
|
| 200 |
+
@dynamic_rope_update # power user: used with advanced RoPE types (e.g. dynamic rope)
|
| 201 |
+
def forward(self, x, position_ids):
|
| 202 |
+
inv_freq_expanded = self.inv_freq[None, :, None].float().expand(position_ids.shape[0], -1, 1).to(x.device)
|
| 203 |
+
position_ids_expanded = position_ids[:, None, :].float()
|
| 204 |
+
|
| 205 |
+
device_type = x.device.type if isinstance(x.device.type, str) and x.device.type != "mps" else "cpu"
|
| 206 |
+
with maybe_autocast(device_type=device_type, enabled=False): # Force float32
|
| 207 |
+
freqs = (inv_freq_expanded.float() @ position_ids_expanded.float()).transpose(1, 2)
|
| 208 |
+
emb = torch.cat((freqs, freqs), dim=-1)
|
| 209 |
+
cos = emb.cos() * self.attention_scaling
|
| 210 |
+
sin = emb.sin() * self.attention_scaling
|
| 211 |
+
|
| 212 |
+
return cos.to(dtype=x.dtype), sin.to(dtype=x.dtype)
|
| 213 |
+
|
| 214 |
+
|
| 215 |
+
def repeat_kv(hidden_states: torch.Tensor, n_rep: int) -> torch.Tensor:
|
| 216 |
+
"""
|
| 217 |
+
This is the equivalent of torch.repeat_interleave(x, dim=1, repeats=n_rep). The hidden states go from (batch,
|
| 218 |
+
num_key_value_heads, seqlen, head_dim) to (batch, num_attention_heads, seqlen, head_dim)
|
| 219 |
+
"""
|
| 220 |
+
batch, num_key_value_heads, slen, head_dim = hidden_states.shape
|
| 221 |
+
if n_rep == 1:
|
| 222 |
+
return hidden_states
|
| 223 |
+
hidden_states = hidden_states[:, :, None, :, :].expand(batch, num_key_value_heads, n_rep, slen, head_dim)
|
| 224 |
+
return hidden_states.reshape(batch, num_key_value_heads * n_rep, slen, head_dim)
|
| 225 |
+
|
| 226 |
+
|
| 227 |
+
def eager_attention_forward(
|
| 228 |
+
module: nn.Module,
|
| 229 |
+
query: torch.Tensor,
|
| 230 |
+
key: torch.Tensor,
|
| 231 |
+
value: torch.Tensor,
|
| 232 |
+
attention_mask: torch.Tensor | None,
|
| 233 |
+
scaling: float,
|
| 234 |
+
dropout: float = 0.0,
|
| 235 |
+
**kwargs: Unpack[TransformersKwargs],
|
| 236 |
+
):
|
| 237 |
+
key_states = repeat_kv(key, module.num_key_value_groups)
|
| 238 |
+
value_states = repeat_kv(value, module.num_key_value_groups)
|
| 239 |
+
|
| 240 |
+
attn_weights = torch.matmul(query, key_states.transpose(2, 3)) * scaling
|
| 241 |
+
if attention_mask is not None:
|
| 242 |
+
attn_weights = attn_weights + attention_mask
|
| 243 |
+
|
| 244 |
+
attn_weights = nn.functional.softmax(attn_weights, dim=-1, dtype=torch.float32).to(query.dtype)
|
| 245 |
+
attn_weights = nn.functional.dropout(attn_weights, p=dropout, training=module.training)
|
| 246 |
+
attn_output = torch.matmul(attn_weights, value_states)
|
| 247 |
+
attn_output = attn_output.transpose(1, 2).contiguous()
|
| 248 |
+
|
| 249 |
+
return attn_output, attn_weights
|
| 250 |
+
|
| 251 |
+
|
| 252 |
+
def apply_rotary_pos_emb(q, k, cos, sin, unsqueeze_dim=1):
|
| 253 |
+
"""Applies Rotary Position Embedding to the query and key tensors.
|
| 254 |
+
|
| 255 |
+
Args:
|
| 256 |
+
q (`torch.Tensor`): The query tensor.
|
| 257 |
+
k (`torch.Tensor`): The key tensor.
|
| 258 |
+
cos (`torch.Tensor`): The cosine part of the rotary embedding.
|
| 259 |
+
sin (`torch.Tensor`): The sine part of the rotary embedding.
|
| 260 |
+
unsqueeze_dim (`int`, *optional*, defaults to 1):
|
| 261 |
+
The 'unsqueeze_dim' argument specifies the dimension along which to unsqueeze cos[position_ids] and
|
| 262 |
+
sin[position_ids] so that they can be properly broadcasted to the dimensions of q and k. For example, note
|
| 263 |
+
that cos[position_ids] and sin[position_ids] have the shape [batch_size, seq_len, head_dim]. Then, if q and
|
| 264 |
+
k have the shape [batch_size, heads, seq_len, head_dim], then setting unsqueeze_dim=1 makes
|
| 265 |
+
cos[position_ids] and sin[position_ids] broadcastable to the shapes of q and k. Similarly, if q and k have
|
| 266 |
+
the shape [batch_size, seq_len, heads, head_dim], then set unsqueeze_dim=2.
|
| 267 |
+
Returns:
|
| 268 |
+
`tuple(torch.Tensor)` comprising of the query and key tensors rotated using the Rotary Position Embedding.
|
| 269 |
+
"""
|
| 270 |
+
cos = cos.unsqueeze(unsqueeze_dim)
|
| 271 |
+
sin = sin.unsqueeze(unsqueeze_dim)
|
| 272 |
+
|
| 273 |
+
# Keep half or full tensor for later concatenation
|
| 274 |
+
rotary_dim = cos.shape[-1]
|
| 275 |
+
q_rot, q_pass = q[..., :rotary_dim], q[..., rotary_dim:]
|
| 276 |
+
k_rot, k_pass = k[..., :rotary_dim], k[..., rotary_dim:]
|
| 277 |
+
|
| 278 |
+
# Apply rotary embeddings on the first half or full tensor
|
| 279 |
+
q_embed = (q_rot * cos) + (rotate_half(q_rot) * sin)
|
| 280 |
+
k_embed = (k_rot * cos) + (rotate_half(k_rot) * sin)
|
| 281 |
+
|
| 282 |
+
# Concatenate back to full shape
|
| 283 |
+
q_embed = torch.cat([q_embed, q_pass], dim=-1)
|
| 284 |
+
k_embed = torch.cat([k_embed, k_pass], dim=-1)
|
| 285 |
+
return q_embed, k_embed
|
| 286 |
+
|
| 287 |
+
|
| 288 |
+
def rotate_half(x):
|
| 289 |
+
"""Rotates half the hidden dims of the input."""
|
| 290 |
+
x1 = x[..., : x.shape[-1] // 2]
|
| 291 |
+
x2 = x[..., x.shape[-1] // 2 :]
|
| 292 |
+
return torch.cat((-x2, x1), dim=-1)
|
| 293 |
+
|
| 294 |
+
|
| 295 |
+
@use_kernelized_func(apply_rotary_pos_emb)
|
| 296 |
+
class MiniMaxM2Attention(nn.Module):
|
| 297 |
+
"""Multi-headed attention from 'Attention Is All You Need' paper"""
|
| 298 |
+
|
| 299 |
+
def __init__(self, config: MiniMaxM2Config, layer_idx: int):
|
| 300 |
+
super().__init__()
|
| 301 |
+
self.config = config
|
| 302 |
+
self.layer_idx = layer_idx
|
| 303 |
+
self.head_dim = getattr(config, "head_dim", config.hidden_size // config.num_attention_heads)
|
| 304 |
+
self.num_key_value_groups = config.num_attention_heads // config.num_key_value_heads
|
| 305 |
+
self.scaling = self.head_dim**-0.5
|
| 306 |
+
self.attention_dropout = config.attention_dropout
|
| 307 |
+
self.is_causal = True
|
| 308 |
+
self.q_proj = nn.Linear(config.hidden_size, config.num_attention_heads * self.head_dim, bias=False)
|
| 309 |
+
self.k_proj = nn.Linear(config.hidden_size, config.num_key_value_heads * self.head_dim, bias=False)
|
| 310 |
+
self.v_proj = nn.Linear(config.hidden_size, config.num_key_value_heads * self.head_dim, bias=False)
|
| 311 |
+
self.o_proj = nn.Linear(config.num_attention_heads * self.head_dim, config.hidden_size, bias=False)
|
| 312 |
+
self.q_norm = MiniMaxM2RMSNorm(config.num_attention_heads * self.head_dim, config.rms_norm_eps)
|
| 313 |
+
self.k_norm = MiniMaxM2RMSNorm(config.num_key_value_heads * self.head_dim, config.rms_norm_eps)
|
| 314 |
+
|
| 315 |
+
def forward(
|
| 316 |
+
self,
|
| 317 |
+
hidden_states: torch.Tensor,
|
| 318 |
+
position_embeddings: tuple[torch.Tensor, torch.Tensor],
|
| 319 |
+
attention_mask: torch.Tensor | None,
|
| 320 |
+
past_key_values: Cache | None = None,
|
| 321 |
+
**kwargs: Unpack[TransformersKwargs],
|
| 322 |
+
) -> tuple[torch.Tensor, torch.Tensor | None]:
|
| 323 |
+
input_shape = hidden_states.shape[:-1]
|
| 324 |
+
hidden_shape = (*input_shape, -1, self.head_dim)
|
| 325 |
+
|
| 326 |
+
query_states = self.q_norm(self.q_proj(hidden_states))
|
| 327 |
+
key_states = self.k_norm(self.k_proj(hidden_states))
|
| 328 |
+
value_states = self.v_proj(hidden_states)
|
| 329 |
+
|
| 330 |
+
query_states = query_states.view(hidden_shape).transpose(1, 2)
|
| 331 |
+
key_states = key_states.view(hidden_shape).transpose(1, 2)
|
| 332 |
+
value_states = value_states.view(hidden_shape).transpose(1, 2)
|
| 333 |
+
|
| 334 |
+
cos, sin = position_embeddings
|
| 335 |
+
query_states, key_states = apply_rotary_pos_emb(query_states, key_states, cos, sin)
|
| 336 |
+
|
| 337 |
+
if past_key_values is not None:
|
| 338 |
+
key_states, value_states = past_key_values.update(key_states, value_states, self.layer_idx)
|
| 339 |
+
|
| 340 |
+
attention_interface: Callable = ALL_ATTENTION_FUNCTIONS.get_interface(
|
| 341 |
+
self.config._attn_implementation, eager_attention_forward
|
| 342 |
+
)
|
| 343 |
+
|
| 344 |
+
attn_output, attn_weights = attention_interface(
|
| 345 |
+
self,
|
| 346 |
+
query_states,
|
| 347 |
+
key_states,
|
| 348 |
+
value_states,
|
| 349 |
+
attention_mask,
|
| 350 |
+
dropout=0.0 if not self.training else self.attention_dropout,
|
| 351 |
+
scaling=self.scaling,
|
| 352 |
+
**kwargs,
|
| 353 |
+
)
|
| 354 |
+
|
| 355 |
+
attn_output = attn_output.reshape(*input_shape, -1).contiguous()
|
| 356 |
+
attn_output = self.o_proj(attn_output)
|
| 357 |
+
return attn_output, attn_weights
|
| 358 |
+
|
| 359 |
+
|
| 360 |
+
class MiniMaxM2DecoderLayer(GradientCheckpointingLayer):
|
| 361 |
+
def __init__(self, config: MiniMaxM2Config, layer_idx: int):
|
| 362 |
+
super().__init__()
|
| 363 |
+
self.hidden_size = config.hidden_size
|
| 364 |
+
|
| 365 |
+
self.self_attn = MiniMaxM2Attention(config, layer_idx)
|
| 366 |
+
|
| 367 |
+
self.mlp = MiniMaxM2SparseMoeBlock(config)
|
| 368 |
+
self.input_layernorm = MiniMaxM2RMSNorm(config.hidden_size, eps=config.rms_norm_eps)
|
| 369 |
+
self.post_attention_layernorm = MiniMaxM2RMSNorm(config.hidden_size, eps=config.rms_norm_eps)
|
| 370 |
+
|
| 371 |
+
def forward(
|
| 372 |
+
self,
|
| 373 |
+
hidden_states: torch.Tensor,
|
| 374 |
+
position_embeddings: tuple[torch.Tensor, torch.Tensor] | None = None,
|
| 375 |
+
attention_mask: torch.Tensor | None = None,
|
| 376 |
+
position_ids: torch.LongTensor | None = None,
|
| 377 |
+
past_key_values: Cache | None = None,
|
| 378 |
+
**kwargs: Unpack[TransformersKwargs],
|
| 379 |
+
) -> torch.Tensor:
|
| 380 |
+
residual = hidden_states
|
| 381 |
+
hidden_states = self.input_layernorm(hidden_states)
|
| 382 |
+
hidden_states, _ = self.self_attn(
|
| 383 |
+
hidden_states=hidden_states,
|
| 384 |
+
position_embeddings=position_embeddings,
|
| 385 |
+
attention_mask=attention_mask,
|
| 386 |
+
position_ids=position_ids,
|
| 387 |
+
past_key_values=past_key_values,
|
| 388 |
+
**kwargs,
|
| 389 |
+
)
|
| 390 |
+
hidden_states = residual + hidden_states
|
| 391 |
+
residual = hidden_states
|
| 392 |
+
hidden_states = self.post_attention_layernorm(hidden_states)
|
| 393 |
+
hidden_states = self.mlp(hidden_states)
|
| 394 |
+
hidden_states = residual + hidden_states
|
| 395 |
+
return hidden_states
|
| 396 |
+
|
| 397 |
+
|
| 398 |
+
@auto_docstring
|
| 399 |
+
class MiniMaxM2PreTrainedModel(PreTrainedModel):
|
| 400 |
+
config: MiniMaxM2Config
|
| 401 |
+
base_model_prefix = "model"
|
| 402 |
+
supports_gradient_checkpointing = True
|
| 403 |
+
_no_split_modules = ["MiniMaxM2DecoderLayer"]
|
| 404 |
+
_skip_keys_device_placement = ["past_key_values"]
|
| 405 |
+
_supports_flash_attn = True
|
| 406 |
+
_supports_sdpa = True
|
| 407 |
+
_supports_flex_attn = True
|
| 408 |
+
|
| 409 |
+
_can_compile_fullgraph = True
|
| 410 |
+
_supports_attention_backend = True
|
| 411 |
+
_can_record_outputs = {
|
| 412 |
+
"router_logits": OutputRecorder(MiniMaxM2TopKRouter, index=0),
|
| 413 |
+
"hidden_states": MiniMaxM2DecoderLayer,
|
| 414 |
+
"attentions": MiniMaxM2Attention,
|
| 415 |
+
}
|
| 416 |
+
|
| 417 |
+
@torch.no_grad()
|
| 418 |
+
def _init_weights(self, module):
|
| 419 |
+
super()._init_weights(module)
|
| 420 |
+
std = self.config.initializer_range
|
| 421 |
+
if isinstance(module, MiniMaxM2Experts):
|
| 422 |
+
init.normal_(module.gate_up_proj, mean=0.0, std=std)
|
| 423 |
+
init.normal_(module.down_proj, mean=0.0, std=std)
|
| 424 |
+
elif isinstance(module, MiniMaxM2TopKRouter):
|
| 425 |
+
init.normal_(module.weight, mean=0.0, std=std)
|
| 426 |
+
elif isinstance(module, MiniMaxM2SparseMoeBlock):
|
| 427 |
+
init.zeros_(module.e_score_correction_bias)
|
| 428 |
+
|
| 429 |
+
|
| 430 |
+
@auto_docstring
|
| 431 |
+
class MiniMaxM2Model(MiniMaxM2PreTrainedModel):
|
| 432 |
+
def __init__(self, config: MiniMaxM2Config):
|
| 433 |
+
super().__init__(config)
|
| 434 |
+
self.padding_idx = config.pad_token_id
|
| 435 |
+
self.vocab_size = config.vocab_size
|
| 436 |
+
|
| 437 |
+
self.embed_tokens = nn.Embedding(config.vocab_size, config.hidden_size, self.padding_idx)
|
| 438 |
+
self.layers = nn.ModuleList(
|
| 439 |
+
[MiniMaxM2DecoderLayer(config, layer_idx) for layer_idx in range(config.num_hidden_layers)]
|
| 440 |
+
)
|
| 441 |
+
self.norm = MiniMaxM2RMSNorm(config.hidden_size, eps=config.rms_norm_eps)
|
| 442 |
+
self.rotary_emb = MiniMaxM2RotaryEmbedding(config=config)
|
| 443 |
+
self.gradient_checkpointing = False
|
| 444 |
+
|
| 445 |
+
# Initialize weights and apply final processing
|
| 446 |
+
self.post_init()
|
| 447 |
+
|
| 448 |
+
@merge_with_config_defaults
|
| 449 |
+
@capture_outputs
|
| 450 |
+
@auto_docstring
|
| 451 |
+
def forward(
|
| 452 |
+
self,
|
| 453 |
+
input_ids: torch.LongTensor | None = None,
|
| 454 |
+
attention_mask: torch.Tensor | None = None,
|
| 455 |
+
position_ids: torch.LongTensor | None = None,
|
| 456 |
+
past_key_values: Cache | None = None,
|
| 457 |
+
inputs_embeds: torch.FloatTensor | None = None,
|
| 458 |
+
use_cache: bool | None = None,
|
| 459 |
+
**kwargs: Unpack[TransformersKwargs],
|
| 460 |
+
) -> MoeModelOutputWithPast:
|
| 461 |
+
if (input_ids is None) ^ (inputs_embeds is not None):
|
| 462 |
+
raise ValueError("You must specify exactly one of input_ids or inputs_embeds")
|
| 463 |
+
|
| 464 |
+
if use_cache and past_key_values is None:
|
| 465 |
+
past_key_values = DynamicCache(config=self.config)
|
| 466 |
+
|
| 467 |
+
if inputs_embeds is None:
|
| 468 |
+
inputs_embeds = self.embed_tokens(input_ids)
|
| 469 |
+
|
| 470 |
+
if position_ids is None:
|
| 471 |
+
past_seen_tokens = past_key_values.get_seq_length() if past_key_values is not None else 0
|
| 472 |
+
position_ids = torch.arange(inputs_embeds.shape[1], device=inputs_embeds.device) + past_seen_tokens
|
| 473 |
+
position_ids = position_ids.unsqueeze(0)
|
| 474 |
+
|
| 475 |
+
# No sliding window opposed to mixtral
|
| 476 |
+
causal_mask = create_causal_mask(
|
| 477 |
+
config=self.config,
|
| 478 |
+
inputs_embeds=inputs_embeds,
|
| 479 |
+
attention_mask=attention_mask,
|
| 480 |
+
past_key_values=past_key_values,
|
| 481 |
+
position_ids=position_ids,
|
| 482 |
+
)
|
| 483 |
+
|
| 484 |
+
hidden_states = inputs_embeds
|
| 485 |
+
position_embeddings = self.rotary_emb(hidden_states, position_ids=position_ids)
|
| 486 |
+
|
| 487 |
+
for decoder_layer in self.layers[: self.config.num_hidden_layers]:
|
| 488 |
+
hidden_states = decoder_layer(
|
| 489 |
+
hidden_states,
|
| 490 |
+
attention_mask=causal_mask,
|
| 491 |
+
position_ids=position_ids,
|
| 492 |
+
past_key_values=past_key_values,
|
| 493 |
+
use_cache=use_cache,
|
| 494 |
+
position_embeddings=position_embeddings,
|
| 495 |
+
**kwargs,
|
| 496 |
+
)
|
| 497 |
+
|
| 498 |
+
hidden_states = self.norm(hidden_states)
|
| 499 |
+
|
| 500 |
+
return MoeModelOutputWithPast( # only diff with Mistral is the output type, we need MoE
|
| 501 |
+
last_hidden_state=hidden_states,
|
| 502 |
+
past_key_values=past_key_values,
|
| 503 |
+
)
|
| 504 |
+
|
| 505 |
+
|
| 506 |
+
def load_balancing_loss_func(
|
| 507 |
+
gate_logits: torch.Tensor | tuple[torch.Tensor] | None,
|
| 508 |
+
num_experts: int | None = None,
|
| 509 |
+
top_k=2,
|
| 510 |
+
attention_mask: torch.Tensor | None = None,
|
| 511 |
+
) -> torch.Tensor | int:
|
| 512 |
+
r"""
|
| 513 |
+
Computes auxiliary load balancing loss as in Switch Transformer - implemented in Pytorch.
|
| 514 |
+
|
| 515 |
+
See Switch Transformer (https://huggingface.co/papers/2101.03961) for more details. This function implements the loss
|
| 516 |
+
function presented in equations (4) - (6) of the paper. It aims at penalizing cases where the routing between
|
| 517 |
+
experts is too unbalanced.
|
| 518 |
+
|
| 519 |
+
Args:
|
| 520 |
+
gate_logits:
|
| 521 |
+
Logits from the `gate`, should be a tuple of model.config.num_hidden_layers tensors of
|
| 522 |
+
shape [batch_size X sequence_length, num_experts].
|
| 523 |
+
num_experts:
|
| 524 |
+
Number of experts
|
| 525 |
+
top_k:
|
| 526 |
+
The number of experts to route per-token, can be also interpreted as the `top-k` routing
|
| 527 |
+
parameter.
|
| 528 |
+
attention_mask (`torch.Tensor`, *optional*):
|
| 529 |
+
The attention_mask used in forward function
|
| 530 |
+
shape [batch_size X sequence_length] if not None.
|
| 531 |
+
|
| 532 |
+
Returns:
|
| 533 |
+
The auxiliary loss.
|
| 534 |
+
"""
|
| 535 |
+
if gate_logits is None or not isinstance(gate_logits, tuple):
|
| 536 |
+
return 0
|
| 537 |
+
|
| 538 |
+
if isinstance(gate_logits, tuple):
|
| 539 |
+
compute_device = gate_logits[0].device
|
| 540 |
+
concatenated_gate_logits = torch.cat([layer_gate.to(compute_device) for layer_gate in gate_logits], dim=0)
|
| 541 |
+
|
| 542 |
+
routing_weights = torch.nn.functional.softmax(concatenated_gate_logits, dim=-1)
|
| 543 |
+
|
| 544 |
+
_, selected_experts = torch.topk(routing_weights, top_k, dim=-1)
|
| 545 |
+
|
| 546 |
+
expert_mask = torch.nn.functional.one_hot(selected_experts, num_experts)
|
| 547 |
+
|
| 548 |
+
if attention_mask is None:
|
| 549 |
+
# Compute the percentage of tokens routed to each experts
|
| 550 |
+
tokens_per_expert = torch.mean(expert_mask.float(), dim=0)
|
| 551 |
+
|
| 552 |
+
# Compute the average probability of routing to these experts
|
| 553 |
+
router_prob_per_expert = torch.mean(routing_weights, dim=0)
|
| 554 |
+
else:
|
| 555 |
+
batch_size, sequence_length = attention_mask.shape
|
| 556 |
+
num_hidden_layers = concatenated_gate_logits.shape[0] // (batch_size * sequence_length)
|
| 557 |
+
|
| 558 |
+
# Compute the mask that masks all padding tokens as 0 with the same shape of expert_mask
|
| 559 |
+
expert_attention_mask = (
|
| 560 |
+
attention_mask[None, :, :, None, None]
|
| 561 |
+
.expand((num_hidden_layers, batch_size, sequence_length, top_k, num_experts))
|
| 562 |
+
.reshape(-1, top_k, num_experts)
|
| 563 |
+
.to(compute_device)
|
| 564 |
+
)
|
| 565 |
+
|
| 566 |
+
# Compute the percentage of tokens routed to each experts
|
| 567 |
+
tokens_per_expert = torch.sum(expert_mask.float() * expert_attention_mask, dim=0) / torch.sum(
|
| 568 |
+
expert_attention_mask, dim=0
|
| 569 |
+
)
|
| 570 |
+
|
| 571 |
+
# Compute the mask that masks all padding tokens as 0 with the same shape of tokens_per_expert
|
| 572 |
+
router_per_expert_attention_mask = (
|
| 573 |
+
attention_mask[None, :, :, None]
|
| 574 |
+
.expand((num_hidden_layers, batch_size, sequence_length, num_experts))
|
| 575 |
+
.reshape(-1, num_experts)
|
| 576 |
+
.to(compute_device)
|
| 577 |
+
)
|
| 578 |
+
|
| 579 |
+
# Compute the average probability of routing to these experts
|
| 580 |
+
router_prob_per_expert = torch.sum(routing_weights * router_per_expert_attention_mask, dim=0) / torch.sum(
|
| 581 |
+
router_per_expert_attention_mask, dim=0
|
| 582 |
+
)
|
| 583 |
+
|
| 584 |
+
overall_loss = torch.sum(tokens_per_expert * router_prob_per_expert.unsqueeze(0))
|
| 585 |
+
return overall_loss * num_experts
|
| 586 |
+
|
| 587 |
+
|
| 588 |
+
@auto_docstring
|
| 589 |
+
class MiniMaxM2ForCausalLM(MiniMaxM2PreTrainedModel, GenerationMixin):
|
| 590 |
+
_tied_weights_keys = {"lm_head.weight": "model.embed_tokens.weight"}
|
| 591 |
+
_tp_plan = {"lm_head": "colwise_gather_output"}
|
| 592 |
+
_pp_plan = {"lm_head": (["hidden_states"], ["logits"])}
|
| 593 |
+
|
| 594 |
+
def __init__(self, config):
|
| 595 |
+
super().__init__(config)
|
| 596 |
+
self.model = MiniMaxM2Model(config)
|
| 597 |
+
self.vocab_size = config.vocab_size
|
| 598 |
+
self.lm_head = nn.Linear(config.hidden_size, config.vocab_size, bias=False)
|
| 599 |
+
self.router_aux_loss_coef = config.router_aux_loss_coef
|
| 600 |
+
self.num_experts = config.num_local_experts
|
| 601 |
+
self.num_experts_per_tok = config.num_experts_per_tok
|
| 602 |
+
|
| 603 |
+
# Initialize weights and apply final processing
|
| 604 |
+
self.post_init()
|
| 605 |
+
|
| 606 |
+
@can_return_tuple
|
| 607 |
+
@auto_docstring
|
| 608 |
+
def forward(
|
| 609 |
+
self,
|
| 610 |
+
input_ids: torch.LongTensor | None = None,
|
| 611 |
+
attention_mask: torch.Tensor | None = None,
|
| 612 |
+
position_ids: torch.LongTensor | None = None,
|
| 613 |
+
past_key_values: Cache | None = None,
|
| 614 |
+
inputs_embeds: torch.FloatTensor | None = None,
|
| 615 |
+
labels: torch.LongTensor | None = None,
|
| 616 |
+
use_cache: bool | None = None,
|
| 617 |
+
output_router_logits: bool | None = None,
|
| 618 |
+
logits_to_keep: int | torch.Tensor = 0,
|
| 619 |
+
**kwargs: Unpack[TransformersKwargs],
|
| 620 |
+
) -> MoeCausalLMOutputWithPast:
|
| 621 |
+
r"""
|
| 622 |
+
labels (`torch.LongTensor` of shape `(batch_size, sequence_length)`, *optional*):
|
| 623 |
+
Labels for computing the masked language modeling loss. Indices should either be in `[0, ...,
|
| 624 |
+
config.vocab_size]` or -100 (see `input_ids` docstring). Tokens with indices set to `-100` are ignored
|
| 625 |
+
(masked), the loss is only computed for the tokens with labels in `[0, ..., config.vocab_size]`.
|
| 626 |
+
|
| 627 |
+
Example:
|
| 628 |
+
|
| 629 |
+
```python
|
| 630 |
+
>>> from transformers import AutoTokenizer, MiniMaxM2ForCausalLM
|
| 631 |
+
|
| 632 |
+
>>> model = MiniMaxM2ForCausalLM.from_pretrained("mistralai/MiniMaxM2-8x7B-v0.1")
|
| 633 |
+
>>> tokenizer = AutoTokenizer.from_pretrained("mistralai/MiniMaxM2-8x7B-v0.1")
|
| 634 |
+
|
| 635 |
+
>>> prompt = "Hey, are you conscious? Can you talk to me?"
|
| 636 |
+
>>> inputs = tokenizer(prompt, return_tensors="pt")
|
| 637 |
+
|
| 638 |
+
>>> # Generate
|
| 639 |
+
>>> generate_ids = model.generate(inputs.input_ids, max_length=30)
|
| 640 |
+
>>> tokenizer.batch_decode(generate_ids, skip_special_tokens=True, clean_up_tokenization_spaces=False)[0]
|
| 641 |
+
"Hey, are you conscious? Can you talk to me?\nI'm not conscious, but I can talk to you."
|
| 642 |
+
```"""
|
| 643 |
+
|
| 644 |
+
output_router_logits = (
|
| 645 |
+
output_router_logits if output_router_logits is not None else self.config.output_router_logits
|
| 646 |
+
)
|
| 647 |
+
|
| 648 |
+
# decoder outputs consists of (dec_features, layer_state, dec_hidden, dec_attn)
|
| 649 |
+
outputs: MoeModelOutputWithPast = self.model(
|
| 650 |
+
input_ids=input_ids,
|
| 651 |
+
attention_mask=attention_mask,
|
| 652 |
+
position_ids=position_ids,
|
| 653 |
+
past_key_values=past_key_values,
|
| 654 |
+
inputs_embeds=inputs_embeds,
|
| 655 |
+
use_cache=use_cache,
|
| 656 |
+
output_router_logits=output_router_logits,
|
| 657 |
+
**kwargs,
|
| 658 |
+
)
|
| 659 |
+
|
| 660 |
+
hidden_states = outputs.last_hidden_state
|
| 661 |
+
# Only compute necessary logits, and do not upcast them to float if we are not computing the loss
|
| 662 |
+
slice_indices = slice(-logits_to_keep, None) if isinstance(logits_to_keep, int) else logits_to_keep
|
| 663 |
+
logits = self.lm_head(hidden_states[:, slice_indices, :])
|
| 664 |
+
|
| 665 |
+
loss = None
|
| 666 |
+
if labels is not None:
|
| 667 |
+
loss = self.loss_function(logits, labels, self.vocab_size, **kwargs)
|
| 668 |
+
|
| 669 |
+
aux_loss = None
|
| 670 |
+
if output_router_logits:
|
| 671 |
+
aux_loss = load_balancing_loss_func(
|
| 672 |
+
outputs.router_logits,
|
| 673 |
+
self.num_experts,
|
| 674 |
+
self.num_experts_per_tok,
|
| 675 |
+
attention_mask,
|
| 676 |
+
)
|
| 677 |
+
if labels is not None:
|
| 678 |
+
loss += self.router_aux_loss_coef * aux_loss.to(loss.device) # make sure to reside in the same device
|
| 679 |
+
|
| 680 |
+
return MoeCausalLMOutputWithPast(
|
| 681 |
+
loss=loss,
|
| 682 |
+
aux_loss=aux_loss,
|
| 683 |
+
logits=logits,
|
| 684 |
+
past_key_values=outputs.past_key_values,
|
| 685 |
+
hidden_states=outputs.hidden_states,
|
| 686 |
+
attentions=outputs.attentions,
|
| 687 |
+
router_logits=outputs.router_logits,
|
| 688 |
+
)
|
| 689 |
+
|
| 690 |
+
|
| 691 |
+
__all__ = ["MiniMaxM2ForCausalLM", "MiniMaxM2Model", "MiniMaxM2PreTrainedModel"]
|
third_party/transformers/src/transformers/models/minimax_m2/modular_minimax_m2.py
ADDED
|
@@ -0,0 +1,246 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
# Copyright 2025 the MiniMax AI Team and HuggingFace Team. All rights reserved.
|
| 2 |
+
#
|
| 3 |
+
# Licensed under the Apache License, Version 2.0 (the "License");
|
| 4 |
+
# you may not use this file except in compliance with the License.
|
| 5 |
+
# You may obtain a copy of the License at
|
| 6 |
+
#
|
| 7 |
+
# http://www.apache.org/licenses/LICENSE-2.0
|
| 8 |
+
#
|
| 9 |
+
# Unless required by applicable law or agreed to in writing, software
|
| 10 |
+
# distributed under the License is distributed on an "AS IS" BASIS,
|
| 11 |
+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
| 12 |
+
# See the License for the specific language governing permissions and
|
| 13 |
+
# limitations under the License.
|
| 14 |
+
|
| 15 |
+
|
| 16 |
+
import torch
|
| 17 |
+
import torch.nn.functional as F
|
| 18 |
+
from huggingface_hub.dataclasses import strict
|
| 19 |
+
from torch import nn
|
| 20 |
+
|
| 21 |
+
from ... import initialization as init
|
| 22 |
+
from ...cache_utils import Cache, DynamicCache
|
| 23 |
+
from ...configuration_utils import PreTrainedConfig
|
| 24 |
+
from ...masking_utils import create_causal_mask
|
| 25 |
+
from ...modeling_outputs import MoeModelOutputWithPast
|
| 26 |
+
from ...modeling_rope_utils import RopeParameters
|
| 27 |
+
from ...modeling_utils import PreTrainedModel
|
| 28 |
+
from ...processing_utils import Unpack
|
| 29 |
+
from ...utils import TransformersKwargs, auto_docstring
|
| 30 |
+
from ...utils.generic import merge_with_config_defaults
|
| 31 |
+
from ...utils.output_capturing import capture_outputs
|
| 32 |
+
from ..flex_olmo.modeling_flex_olmo import FlexOlmoAttention
|
| 33 |
+
from ..glm4_moe.modeling_glm4_moe import (
|
| 34 |
+
Glm4MoeRotaryEmbedding,
|
| 35 |
+
apply_rotary_pos_emb, # noqa: F401
|
| 36 |
+
)
|
| 37 |
+
from ..mixtral.modeling_mixtral import (
|
| 38 |
+
MixtralExperts,
|
| 39 |
+
MixtralForCausalLM,
|
| 40 |
+
MixtralModel,
|
| 41 |
+
MixtralPreTrainedModel,
|
| 42 |
+
MixtralRMSNorm,
|
| 43 |
+
MixtralSparseMoeBlock,
|
| 44 |
+
MixtralTopKRouter,
|
| 45 |
+
)
|
| 46 |
+
|
| 47 |
+
|
| 48 |
+
@auto_docstring(checkpoint="MiniMaxAI/MiniMax-Text-01-hf")
|
| 49 |
+
@strict
|
| 50 |
+
class MiniMaxM2Config(PreTrainedConfig):
|
| 51 |
+
r"""
|
| 52 |
+
Example:
|
| 53 |
+
|
| 54 |
+
```python
|
| 55 |
+
>>> from transformers import MiniMaxM2Model, MiniMaxM2Config
|
| 56 |
+
|
| 57 |
+
>>> # Initializing a MiniMaxM2 style configuration
|
| 58 |
+
>>> configuration = MiniMaxM2Config()
|
| 59 |
+
|
| 60 |
+
>>> # Initializing a model from the MiniMaxM2 style configuration
|
| 61 |
+
>>> model = MiniMaxM2Model(configuration)
|
| 62 |
+
|
| 63 |
+
>>> # Accessing the model configuration
|
| 64 |
+
>>> configuration = model.config
|
| 65 |
+
```"""
|
| 66 |
+
|
| 67 |
+
model_type = "minimax_m2"
|
| 68 |
+
keys_to_ignore_at_inference = ["past_key_values"]
|
| 69 |
+
base_model_tp_plan = {
|
| 70 |
+
"layers.*.self_attn.q_proj": "colwise_gather_output",
|
| 71 |
+
"layers.*.self_attn.k_proj": "colwise_gather_output",
|
| 72 |
+
"layers.*.self_attn.v_proj": "colwise_gather_output",
|
| 73 |
+
"layers.*.self_attn.o_proj": "rowwise_split_input",
|
| 74 |
+
"layers.*.mlp.experts.gate_up_proj": "packed_colwise",
|
| 75 |
+
"layers.*.mlp.experts.down_proj": "rowwise",
|
| 76 |
+
"layers.*.mlp.experts": "moe_tp_experts",
|
| 77 |
+
}
|
| 78 |
+
base_model_pp_plan = {
|
| 79 |
+
"embed_tokens": (["input_ids"], ["inputs_embeds"]),
|
| 80 |
+
"layers": (["hidden_states", "attention_mask"], ["hidden_states"]),
|
| 81 |
+
"norm": (["hidden_states"], ["hidden_states"]),
|
| 82 |
+
}
|
| 83 |
+
attribute_map = {
|
| 84 |
+
"num_experts": "num_local_experts",
|
| 85 |
+
}
|
| 86 |
+
default_theta = 5000000.0
|
| 87 |
+
|
| 88 |
+
vocab_size: int = 200064
|
| 89 |
+
hidden_size: int = 3072
|
| 90 |
+
intermediate_size: int = 1536
|
| 91 |
+
num_hidden_layers: int = 62
|
| 92 |
+
num_attention_heads: int = 48
|
| 93 |
+
num_key_value_heads: int = 8
|
| 94 |
+
head_dim: int = 128
|
| 95 |
+
hidden_act: str = "silu"
|
| 96 |
+
max_position_embeddings: int = 196608
|
| 97 |
+
initializer_range: float = 0.02
|
| 98 |
+
rms_norm_eps: float = 1e-06
|
| 99 |
+
use_cache: bool = True
|
| 100 |
+
pad_token_id: int | None = None
|
| 101 |
+
bos_token_id: int | None = 200034
|
| 102 |
+
eos_token_id: int | list[int] | None = 200020
|
| 103 |
+
tie_word_embeddings: bool = False
|
| 104 |
+
attention_dropout: float | int = 0.0
|
| 105 |
+
num_experts_per_tok: int = 8
|
| 106 |
+
num_local_experts: int = 256
|
| 107 |
+
output_router_logits: bool = False
|
| 108 |
+
router_aux_loss_coef: float = 0.001
|
| 109 |
+
router_jitter_noise: float = 0.0
|
| 110 |
+
rope_parameters: RopeParameters | dict | None = None
|
| 111 |
+
|
| 112 |
+
|
| 113 |
+
class MiniMaxM2TopKRouter(MixtralTopKRouter):
|
| 114 |
+
def forward(self, hidden_states, e_score_correction_bias):
|
| 115 |
+
hidden_states = hidden_states.reshape(-1, self.hidden_dim)
|
| 116 |
+
router_logits = F.linear(hidden_states.to(self.weight.dtype), self.weight) # (seq_len, num_experts)
|
| 117 |
+
# Main difference to other Moe, using Sigmoid activation instead of Softmax
|
| 118 |
+
routing_weights = nn.functional.sigmoid(router_logits.float())
|
| 119 |
+
scores_for_choice = routing_weights + e_score_correction_bias
|
| 120 |
+
_, top_k_index = torch.topk(scores_for_choice, self.top_k, dim=-1, sorted=False)
|
| 121 |
+
top_k_weights = routing_weights.gather(1, top_k_index)
|
| 122 |
+
top_k_weights /= top_k_weights.sum(dim=-1, keepdim=True)
|
| 123 |
+
router_scores = top_k_weights
|
| 124 |
+
return router_logits, router_scores, top_k_index
|
| 125 |
+
|
| 126 |
+
|
| 127 |
+
class MiniMaxM2Experts(MixtralExperts):
|
| 128 |
+
pass
|
| 129 |
+
|
| 130 |
+
|
| 131 |
+
class MiniMaxM2SparseMoeBlock(MixtralSparseMoeBlock):
|
| 132 |
+
def __init__(self, config):
|
| 133 |
+
super().__init__()
|
| 134 |
+
self.register_buffer("e_score_correction_bias", torch.zeros(config.num_local_experts))
|
| 135 |
+
|
| 136 |
+
def forward(self, hidden_states: torch.Tensor) -> tuple[torch.Tensor, torch.Tensor]:
|
| 137 |
+
batch_size, sequence_length, hidden_dim = hidden_states.shape
|
| 138 |
+
if self.training and self.jitter_noise > 0:
|
| 139 |
+
hidden_states *= torch.empty_like(hidden_states).uniform_(1.0 - self.jitter_noise, 1.0 + self.jitter_noise)
|
| 140 |
+
hidden_states = hidden_states.view(-1, hidden_states.shape[-1])
|
| 141 |
+
_, top_k_weights, top_k_index = self.gate(hidden_states, self.e_score_correction_bias)
|
| 142 |
+
hidden_states = self.experts(hidden_states, top_k_index, top_k_weights)
|
| 143 |
+
hidden_states = hidden_states.reshape(batch_size, sequence_length, hidden_dim)
|
| 144 |
+
return hidden_states
|
| 145 |
+
|
| 146 |
+
|
| 147 |
+
class MiniMaxM2RMSNorm(MixtralRMSNorm):
|
| 148 |
+
pass
|
| 149 |
+
|
| 150 |
+
|
| 151 |
+
class MiniMaxM2RotaryEmbedding(Glm4MoeRotaryEmbedding):
|
| 152 |
+
pass
|
| 153 |
+
|
| 154 |
+
|
| 155 |
+
class MiniMaxM2Attention(FlexOlmoAttention):
|
| 156 |
+
def __init__(self, config: MiniMaxM2Config, layer_idx: int):
|
| 157 |
+
super().__init__(config, layer_idx)
|
| 158 |
+
self.q_proj = nn.Linear(config.hidden_size, config.num_attention_heads * self.head_dim, bias=False)
|
| 159 |
+
self.k_proj = nn.Linear(config.hidden_size, config.num_key_value_heads * self.head_dim, bias=False)
|
| 160 |
+
self.v_proj = nn.Linear(config.hidden_size, config.num_key_value_heads * self.head_dim, bias=False)
|
| 161 |
+
self.o_proj = nn.Linear(config.num_attention_heads * self.head_dim, config.hidden_size, bias=False)
|
| 162 |
+
|
| 163 |
+
|
| 164 |
+
class MiniMaxM2PreTrainedModel(MixtralPreTrainedModel):
|
| 165 |
+
@torch.no_grad()
|
| 166 |
+
def _init_weights(self, module):
|
| 167 |
+
PreTrainedModel._init_weights(self, module)
|
| 168 |
+
std = self.config.initializer_range
|
| 169 |
+
if isinstance(module, MiniMaxM2Experts):
|
| 170 |
+
init.normal_(module.gate_up_proj, mean=0.0, std=std)
|
| 171 |
+
init.normal_(module.down_proj, mean=0.0, std=std)
|
| 172 |
+
elif isinstance(module, MiniMaxM2TopKRouter):
|
| 173 |
+
init.normal_(module.weight, mean=0.0, std=std)
|
| 174 |
+
elif isinstance(module, MiniMaxM2SparseMoeBlock):
|
| 175 |
+
init.zeros_(module.e_score_correction_bias)
|
| 176 |
+
|
| 177 |
+
|
| 178 |
+
class MiniMaxM2Model(MixtralModel):
|
| 179 |
+
@merge_with_config_defaults
|
| 180 |
+
@capture_outputs
|
| 181 |
+
@auto_docstring
|
| 182 |
+
def forward(
|
| 183 |
+
self,
|
| 184 |
+
input_ids: torch.LongTensor | None = None,
|
| 185 |
+
attention_mask: torch.Tensor | None = None,
|
| 186 |
+
position_ids: torch.LongTensor | None = None,
|
| 187 |
+
past_key_values: Cache | None = None,
|
| 188 |
+
inputs_embeds: torch.FloatTensor | None = None,
|
| 189 |
+
use_cache: bool | None = None,
|
| 190 |
+
**kwargs: Unpack[TransformersKwargs],
|
| 191 |
+
) -> MoeModelOutputWithPast:
|
| 192 |
+
if (input_ids is None) ^ (inputs_embeds is not None):
|
| 193 |
+
raise ValueError("You must specify exactly one of input_ids or inputs_embeds")
|
| 194 |
+
|
| 195 |
+
if use_cache and past_key_values is None:
|
| 196 |
+
past_key_values = DynamicCache(config=self.config)
|
| 197 |
+
|
| 198 |
+
if inputs_embeds is None:
|
| 199 |
+
inputs_embeds = self.embed_tokens(input_ids)
|
| 200 |
+
|
| 201 |
+
if position_ids is None:
|
| 202 |
+
past_seen_tokens = past_key_values.get_seq_length() if past_key_values is not None else 0
|
| 203 |
+
position_ids = torch.arange(inputs_embeds.shape[1], device=inputs_embeds.device) + past_seen_tokens
|
| 204 |
+
position_ids = position_ids.unsqueeze(0)
|
| 205 |
+
|
| 206 |
+
# No sliding window opposed to mixtral
|
| 207 |
+
causal_mask = create_causal_mask(
|
| 208 |
+
config=self.config,
|
| 209 |
+
inputs_embeds=inputs_embeds,
|
| 210 |
+
attention_mask=attention_mask,
|
| 211 |
+
past_key_values=past_key_values,
|
| 212 |
+
position_ids=position_ids,
|
| 213 |
+
)
|
| 214 |
+
|
| 215 |
+
hidden_states = inputs_embeds
|
| 216 |
+
position_embeddings = self.rotary_emb(hidden_states, position_ids=position_ids)
|
| 217 |
+
|
| 218 |
+
for decoder_layer in self.layers[: self.config.num_hidden_layers]:
|
| 219 |
+
hidden_states = decoder_layer(
|
| 220 |
+
hidden_states,
|
| 221 |
+
attention_mask=causal_mask,
|
| 222 |
+
position_ids=position_ids,
|
| 223 |
+
past_key_values=past_key_values,
|
| 224 |
+
use_cache=use_cache,
|
| 225 |
+
position_embeddings=position_embeddings,
|
| 226 |
+
**kwargs,
|
| 227 |
+
)
|
| 228 |
+
|
| 229 |
+
hidden_states = self.norm(hidden_states)
|
| 230 |
+
|
| 231 |
+
return MoeModelOutputWithPast( # only diff with Mistral is the output type, we need MoE
|
| 232 |
+
last_hidden_state=hidden_states,
|
| 233 |
+
past_key_values=past_key_values,
|
| 234 |
+
)
|
| 235 |
+
|
| 236 |
+
|
| 237 |
+
class MiniMaxM2ForCausalLM(MixtralForCausalLM):
|
| 238 |
+
pass
|
| 239 |
+
|
| 240 |
+
|
| 241 |
+
__all__ = [
|
| 242 |
+
"MiniMaxM2Config",
|
| 243 |
+
"MiniMaxM2ForCausalLM",
|
| 244 |
+
"MiniMaxM2Model", # noqa: F822
|
| 245 |
+
"MiniMaxM2PreTrainedModel", # noqa: F822
|
| 246 |
+
]
|
third_party/transformers/src/transformers/models/mixtral/__init__.py
ADDED
|
@@ -0,0 +1,27 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
# Copyright 2023 Mixtral AI and The HuggingFace Inc. team. All rights reserved.
|
| 2 |
+
#
|
| 3 |
+
# Licensed under the Apache License, Version 2.0 (the "License");
|
| 4 |
+
# you may not use this file except in compliance with the License.
|
| 5 |
+
# You may obtain a copy of the License at
|
| 6 |
+
#
|
| 7 |
+
# http://www.apache.org/licenses/LICENSE-2.0
|
| 8 |
+
#
|
| 9 |
+
# Unless required by applicable law or agreed to in writing, software
|
| 10 |
+
# distributed under the License is distributed on an "AS IS" BASIS,
|
| 11 |
+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
| 12 |
+
# See the License for the specific language governing permissions and
|
| 13 |
+
# limitations under the License.
|
| 14 |
+
from typing import TYPE_CHECKING
|
| 15 |
+
|
| 16 |
+
from ...utils import _LazyModule
|
| 17 |
+
from ...utils.import_utils import define_import_structure
|
| 18 |
+
|
| 19 |
+
|
| 20 |
+
if TYPE_CHECKING:
|
| 21 |
+
from .configuration_mixtral import *
|
| 22 |
+
from .modeling_mixtral import *
|
| 23 |
+
else:
|
| 24 |
+
import sys
|
| 25 |
+
|
| 26 |
+
_file = globals()["__file__"]
|
| 27 |
+
sys.modules[__name__] = _LazyModule(__name__, _file, define_import_structure(_file), module_spec=__spec__)
|
third_party/transformers/src/transformers/models/mixtral/configuration_mixtral.py
ADDED
|
@@ -0,0 +1,93 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
# Copyright 2023 Mixtral AI and the HuggingFace Inc. team. All rights reserved.
|
| 2 |
+
#
|
| 3 |
+
# Licensed under the Apache License, Version 2.0 (the "License");
|
| 4 |
+
# you may not use this file except in compliance with the License.
|
| 5 |
+
# You may obtain a copy of the License at
|
| 6 |
+
#
|
| 7 |
+
# http://www.apache.org/licenses/LICENSE-2.0
|
| 8 |
+
#
|
| 9 |
+
# Unless required by applicable law or agreed to in writing, software
|
| 10 |
+
# distributed under the License is distributed on an "AS IS" BASIS,
|
| 11 |
+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
| 12 |
+
# See the License for the specific language governing permissions and
|
| 13 |
+
# limitations under the License.
|
| 14 |
+
"""Mixtral model configuration"""
|
| 15 |
+
|
| 16 |
+
from huggingface_hub.dataclasses import strict
|
| 17 |
+
|
| 18 |
+
from ...configuration_utils import PreTrainedConfig
|
| 19 |
+
from ...modeling_rope_utils import RopeParameters
|
| 20 |
+
from ...utils import auto_docstring
|
| 21 |
+
|
| 22 |
+
|
| 23 |
+
@auto_docstring(checkpoint="mistralai/Mixtral-8x7B-v0.1")
|
| 24 |
+
@strict
|
| 25 |
+
class MixtralConfig(PreTrainedConfig):
|
| 26 |
+
r"""
|
| 27 |
+
Example:
|
| 28 |
+
|
| 29 |
+
```python
|
| 30 |
+
>>> from transformers import MixtralModel, MixtralConfig
|
| 31 |
+
|
| 32 |
+
>>> # Initializing a Mixtral 7B style configuration
|
| 33 |
+
>>> configuration = MixtralConfig()
|
| 34 |
+
|
| 35 |
+
>>> # Initializing a model from the Mixtral 7B style configuration
|
| 36 |
+
>>> model = MixtralModel(configuration)
|
| 37 |
+
|
| 38 |
+
>>> # Accessing the model configuration
|
| 39 |
+
>>> configuration = model.config
|
| 40 |
+
```"""
|
| 41 |
+
|
| 42 |
+
model_type = "mixtral"
|
| 43 |
+
keys_to_ignore_at_inference = ["past_key_values"]
|
| 44 |
+
default_theta = 1000000.0
|
| 45 |
+
base_model_tp_plan = {
|
| 46 |
+
"layers.*.self_attn.q_proj": "colwise",
|
| 47 |
+
"layers.*.self_attn.k_proj": "colwise",
|
| 48 |
+
"layers.*.self_attn.v_proj": "colwise",
|
| 49 |
+
"layers.*.self_attn.o_proj": "rowwise",
|
| 50 |
+
"layers.*.mlp.experts.gate_up_proj": "packed_colwise",
|
| 51 |
+
"layers.*.mlp.experts.down_proj": "rowwise",
|
| 52 |
+
"layers.*.mlp.experts": "moe_tp_experts",
|
| 53 |
+
}
|
| 54 |
+
base_model_pp_plan = {
|
| 55 |
+
"embed_tokens": (["input_ids"], ["inputs_embeds"]),
|
| 56 |
+
"layers": (["hidden_states", "attention_mask"], ["hidden_states"]),
|
| 57 |
+
"norm": (["hidden_states"], ["hidden_states"]),
|
| 58 |
+
}
|
| 59 |
+
attribute_map = {"num_experts": "num_local_experts"}
|
| 60 |
+
|
| 61 |
+
vocab_size: int = 32000
|
| 62 |
+
hidden_size: int = 4096
|
| 63 |
+
intermediate_size: int = 14336
|
| 64 |
+
num_hidden_layers: int = 32
|
| 65 |
+
num_attention_heads: int = 32
|
| 66 |
+
num_key_value_heads: int = 8
|
| 67 |
+
head_dim: int | None = None
|
| 68 |
+
hidden_act: str = "silu"
|
| 69 |
+
max_position_embeddings: int = 4096 * 32
|
| 70 |
+
initializer_range: float = 0.02
|
| 71 |
+
rms_norm_eps: float = 1e-5
|
| 72 |
+
use_cache: bool = True
|
| 73 |
+
pad_token_id: int | None = None
|
| 74 |
+
bos_token_id: int | None = 1
|
| 75 |
+
eos_token_id: int | list[int] | None = 2
|
| 76 |
+
tie_word_embeddings: bool = False
|
| 77 |
+
sliding_window: int | None = None
|
| 78 |
+
attention_dropout: float | int = 0.0
|
| 79 |
+
num_experts_per_tok: int = 2
|
| 80 |
+
num_local_experts: int = 8
|
| 81 |
+
output_router_logits: bool = False
|
| 82 |
+
router_aux_loss_coef: float = 0.001
|
| 83 |
+
router_jitter_noise: float = 0.0
|
| 84 |
+
rope_parameters: RopeParameters | dict | None = None
|
| 85 |
+
|
| 86 |
+
def __post_init__(self, **kwargs):
|
| 87 |
+
if self.num_key_value_heads is None:
|
| 88 |
+
self.num_key_value_heads = self.num_attention_heads
|
| 89 |
+
|
| 90 |
+
super().__post_init__(**kwargs)
|
| 91 |
+
|
| 92 |
+
|
| 93 |
+
__all__ = ["MixtralConfig"]
|
third_party/transformers/src/transformers/models/mixtral/convert_mixtral_weights_to_hf.py
ADDED
|
@@ -0,0 +1,243 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
# Copyright 2023 Mistral AI and The HuggingFace Inc. team. All rights reserved.
|
| 2 |
+
#
|
| 3 |
+
# Licensed under the Apache License, Version 2.0 (the "License");
|
| 4 |
+
# you may not use this file except in compliance with the License.
|
| 5 |
+
# You may obtain a copy of the License at
|
| 6 |
+
#
|
| 7 |
+
# http://www.apache.org/licenses/LICENSE-2.0
|
| 8 |
+
#
|
| 9 |
+
# Unless required by applicable law or agreed to in writing, software
|
| 10 |
+
# distributed under the License is distributed on an "AS IS" BASIS,
|
| 11 |
+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
| 12 |
+
# See the License for the specific language governing permissions and
|
| 13 |
+
# limitations under the License.
|
| 14 |
+
import argparse
|
| 15 |
+
import json
|
| 16 |
+
import os
|
| 17 |
+
|
| 18 |
+
import torch
|
| 19 |
+
|
| 20 |
+
from transformers import (
|
| 21 |
+
MixtralConfig,
|
| 22 |
+
MixtralForCausalLM,
|
| 23 |
+
)
|
| 24 |
+
|
| 25 |
+
|
| 26 |
+
"""
|
| 27 |
+
Sample usage:
|
| 28 |
+
|
| 29 |
+
```
|
| 30 |
+
python src/transformers/models/mixtral/convert_mixtral_weights_to_hf.py \
|
| 31 |
+
--input_dir /path/to/downloaded/mixtral/weights --model_size 7B --output_dir /output/path
|
| 32 |
+
```
|
| 33 |
+
|
| 34 |
+
Thereafter, models can be loaded via:
|
| 35 |
+
|
| 36 |
+
```py
|
| 37 |
+
from transformers import MixtralForCausalLM
|
| 38 |
+
|
| 39 |
+
model = MixtralForCausalLM.from_pretrained("/output/path")
|
| 40 |
+
```
|
| 41 |
+
|
| 42 |
+
Important note: you need to be able to host the whole model in RAM to execute this script (even if the biggest versions
|
| 43 |
+
come in several checkpoints they each contain a part of each weight of the model, so we need to load them all in RAM).
|
| 44 |
+
"""
|
| 45 |
+
|
| 46 |
+
|
| 47 |
+
def compute_intermediate_size(n, ffn_dim_multiplier=1, multiple_of=256):
|
| 48 |
+
return multiple_of * ((int(ffn_dim_multiplier * int(8 * n / 3)) + multiple_of - 1) // multiple_of)
|
| 49 |
+
|
| 50 |
+
|
| 51 |
+
def read_json(path):
|
| 52 |
+
with open(path, "r") as f:
|
| 53 |
+
return json.load(f)
|
| 54 |
+
|
| 55 |
+
|
| 56 |
+
def write_json(text, path):
|
| 57 |
+
with open(path, "w") as f:
|
| 58 |
+
json.dump(text, f)
|
| 59 |
+
|
| 60 |
+
|
| 61 |
+
def write_model(model_path, input_base_path, model_size):
|
| 62 |
+
os.makedirs(model_path, exist_ok=True)
|
| 63 |
+
|
| 64 |
+
params = read_json(os.path.join(input_base_path, "params.json"))
|
| 65 |
+
num_shards = 1
|
| 66 |
+
|
| 67 |
+
# For some reason this is a string in the params.json
|
| 68 |
+
sliding_window = int(params["sliding_window"]) if "sliding_window" in params else None
|
| 69 |
+
n_layers = params["num_hidden_layers"]
|
| 70 |
+
n_heads = params["num_attention_heads"]
|
| 71 |
+
n_heads_per_shard = n_heads // num_shards
|
| 72 |
+
dim = params["hidden_size"]
|
| 73 |
+
dims_per_head = dim // n_heads
|
| 74 |
+
base = params.get("rope_theta", 10000.0)
|
| 75 |
+
max_position_embeddings = 4096 * 8
|
| 76 |
+
num_local_experts = params["num_local_experts"]
|
| 77 |
+
ffn_dim = params["intermediate_size"]
|
| 78 |
+
|
| 79 |
+
vocab_size = params["vocab_size"]
|
| 80 |
+
|
| 81 |
+
if "num_key_value_heads" in params:
|
| 82 |
+
num_key_value_heads = params["num_key_value_heads"] # for GQA / MQA
|
| 83 |
+
num_local_key_value_heads = num_key_value_heads // num_shards
|
| 84 |
+
key_value_dim = dims_per_head * num_local_key_value_heads
|
| 85 |
+
else: # compatibility with other checkpoints
|
| 86 |
+
num_key_value_heads = n_heads
|
| 87 |
+
num_local_key_value_heads = n_heads_per_shard
|
| 88 |
+
key_value_dim = dim
|
| 89 |
+
|
| 90 |
+
# permute for sliced rotary
|
| 91 |
+
def permute(w, n_heads=n_heads, dim1=dim, dim2=dim):
|
| 92 |
+
return w.view(n_heads, dim1 // n_heads // 2, 2, dim2).transpose(1, 2).reshape(dim1, dim2)
|
| 93 |
+
|
| 94 |
+
print(f"Fetching all parameters from the checkpoint at {input_base_path}.")
|
| 95 |
+
# Load weights
|
| 96 |
+
loaded = [
|
| 97 |
+
torch.load(os.path.join(input_base_path, f"consolidated.{i:02d}.pt"), map_location="cpu", weights_only=True)
|
| 98 |
+
for i in range(8)
|
| 99 |
+
]
|
| 100 |
+
|
| 101 |
+
merged_state_dict = {}
|
| 102 |
+
for state_dict in loaded:
|
| 103 |
+
merged_state_dict.update(state_dict)
|
| 104 |
+
|
| 105 |
+
state_dict = {}
|
| 106 |
+
|
| 107 |
+
for layer_i in range(n_layers):
|
| 108 |
+
# Sharded
|
| 109 |
+
# Note that attention.w{q,k,v,o}, feed_fordward.w[1,2,3], attention_norm.weight and ffn_norm.weight share
|
| 110 |
+
# the same storage object, saving attention_norm and ffn_norm will save other weights too, which is
|
| 111 |
+
# redundant as other weights will be stitched from multiple shards. To avoid that, they are cloned.
|
| 112 |
+
|
| 113 |
+
state_dict.update(
|
| 114 |
+
{
|
| 115 |
+
f"model.layers.{layer_i}.input_layernorm.weight": merged_state_dict[
|
| 116 |
+
f"layers.{layer_i}.attention_norm.weight"
|
| 117 |
+
].clone(),
|
| 118 |
+
f"model.layers.{layer_i}.post_attention_layernorm.weight": merged_state_dict[
|
| 119 |
+
f"layers.{layer_i}.ffn_norm.weight"
|
| 120 |
+
].clone(),
|
| 121 |
+
}
|
| 122 |
+
)
|
| 123 |
+
|
| 124 |
+
state_dict[f"model.layers.{layer_i}.self_attn.q_proj.weight"] = permute(
|
| 125 |
+
merged_state_dict[f"layers.{layer_i}.attention.wq.weight"]
|
| 126 |
+
.view(n_heads_per_shard, dims_per_head, dim)
|
| 127 |
+
.reshape(dim, dim)
|
| 128 |
+
)
|
| 129 |
+
state_dict[f"model.layers.{layer_i}.self_attn.k_proj.weight"] = permute(
|
| 130 |
+
merged_state_dict[f"layers.{layer_i}.attention.wk.weight"]
|
| 131 |
+
.view(num_local_key_value_heads, dims_per_head, dim)
|
| 132 |
+
.reshape(key_value_dim, dim),
|
| 133 |
+
num_key_value_heads,
|
| 134 |
+
key_value_dim,
|
| 135 |
+
dim,
|
| 136 |
+
)
|
| 137 |
+
state_dict[f"model.layers.{layer_i}.self_attn.v_proj.weight"] = (
|
| 138 |
+
merged_state_dict[f"layers.{layer_i}.attention.wv.weight"]
|
| 139 |
+
.view(num_local_key_value_heads, dims_per_head, dim)
|
| 140 |
+
.reshape(key_value_dim, dim)
|
| 141 |
+
)
|
| 142 |
+
|
| 143 |
+
state_dict[f"model.layers.{layer_i}.self_attn.o_proj.weight"] = merged_state_dict[
|
| 144 |
+
f"layers.{layer_i}.attention.wo.weight"
|
| 145 |
+
]
|
| 146 |
+
|
| 147 |
+
w1 = merged_state_dict[f"layers.{layer_i}.block_sparse_moe.w1"]
|
| 148 |
+
w2 = merged_state_dict[f"layers.{layer_i}.block_sparse_moe.w2"]
|
| 149 |
+
w3 = merged_state_dict[f"layers.{layer_i}.block_sparse_moe.w3"]
|
| 150 |
+
|
| 151 |
+
experts_w1 = [
|
| 152 |
+
w1[ffn_dim * expert_idx : ffn_dim * (expert_idx + 1), :].clone(memory_format=torch.contiguous_format)
|
| 153 |
+
for expert_idx in range(num_local_experts)
|
| 154 |
+
]
|
| 155 |
+
|
| 156 |
+
for idx, expert_block in enumerate(experts_w1):
|
| 157 |
+
expert_key = f"model.layers.{layer_i}.block_sparse_moe.experts.{idx}.w1"
|
| 158 |
+
state_dict[expert_key + ".weight"] = expert_block.clone()
|
| 159 |
+
|
| 160 |
+
experts_w2 = [
|
| 161 |
+
w2[ffn_dim * expert_idx : ffn_dim * (expert_idx + 1), :].clone(memory_format=torch.contiguous_format)
|
| 162 |
+
for expert_idx in range(num_local_experts)
|
| 163 |
+
]
|
| 164 |
+
|
| 165 |
+
for idx, expert_block in enumerate(experts_w2):
|
| 166 |
+
expert_key = f"model.layers.{layer_i}.block_sparse_moe.experts.{idx}.w2"
|
| 167 |
+
state_dict[expert_key + ".weight"] = expert_block.T.clone(memory_format=torch.contiguous_format)
|
| 168 |
+
|
| 169 |
+
experts_w3 = [
|
| 170 |
+
w3[ffn_dim * expert_idx : ffn_dim * (expert_idx + 1), :].clone(memory_format=torch.contiguous_format)
|
| 171 |
+
for expert_idx in range(num_local_experts)
|
| 172 |
+
]
|
| 173 |
+
|
| 174 |
+
for idx, expert_block in enumerate(experts_w3):
|
| 175 |
+
expert_key = f"model.layers.{layer_i}.block_sparse_moe.experts.{idx}.w3"
|
| 176 |
+
state_dict[expert_key + ".weight"] = expert_block.clone()
|
| 177 |
+
|
| 178 |
+
state_dict[f"model.layers.{layer_i}.block_sparse_moe.gate.weight"] = merged_state_dict[
|
| 179 |
+
f"layers.{layer_i}.block_sparse_moe.gate.weight"
|
| 180 |
+
]
|
| 181 |
+
|
| 182 |
+
state_dict.update(
|
| 183 |
+
{
|
| 184 |
+
"model.norm.weight": merged_state_dict["norm.weight"],
|
| 185 |
+
"model.embed_tokens.weight": merged_state_dict["tok_embeddings.weight"],
|
| 186 |
+
"lm_head.weight": merged_state_dict["output.weight"],
|
| 187 |
+
}
|
| 188 |
+
)
|
| 189 |
+
|
| 190 |
+
config = MixtralConfig(
|
| 191 |
+
hidden_size=dim,
|
| 192 |
+
intermediate_size=ffn_dim,
|
| 193 |
+
num_attention_heads=params["num_attention_heads"],
|
| 194 |
+
num_hidden_layers=params["num_hidden_layers"],
|
| 195 |
+
rms_norm_eps=params["rms_norm_eps"],
|
| 196 |
+
num_key_value_heads=num_key_value_heads,
|
| 197 |
+
vocab_size=vocab_size,
|
| 198 |
+
rope_theta=base,
|
| 199 |
+
max_position_embeddings=max_position_embeddings,
|
| 200 |
+
sliding_window=sliding_window,
|
| 201 |
+
num_local_experts=num_local_experts,
|
| 202 |
+
)
|
| 203 |
+
|
| 204 |
+
print("Loading the checkpoint in a Mixtral model.")
|
| 205 |
+
with torch.device("meta"):
|
| 206 |
+
model = MixtralForCausalLM(config)
|
| 207 |
+
# Avoid saving this as part of the config.
|
| 208 |
+
del model.config._name_or_path
|
| 209 |
+
model.config.dtype = torch.float16
|
| 210 |
+
print("Saving in the Transformers format.")
|
| 211 |
+
|
| 212 |
+
model.load_state_dict(state_dict, strict=True, assign=True)
|
| 213 |
+
|
| 214 |
+
for n, p in model.named_parameters():
|
| 215 |
+
assert p.device.type != "meta", f"{n} has not been loaded!"
|
| 216 |
+
|
| 217 |
+
model.save_pretrained(model_path)
|
| 218 |
+
|
| 219 |
+
|
| 220 |
+
def main():
|
| 221 |
+
parser = argparse.ArgumentParser()
|
| 222 |
+
parser.add_argument(
|
| 223 |
+
"--input_dir",
|
| 224 |
+
help="Location of Mixtral weights, which contains tokenizer.model and model folders",
|
| 225 |
+
required=True,
|
| 226 |
+
)
|
| 227 |
+
parser.add_argument(
|
| 228 |
+
"--model_size",
|
| 229 |
+
choices=["7B"],
|
| 230 |
+
help="'f' models correspond to the finetuned versions, and are specific to the Mixtral official release. For more details on Mixtral, check out the original repo: https://huggingface.co/mistral-ai",
|
| 231 |
+
default="7B",
|
| 232 |
+
)
|
| 233 |
+
parser.add_argument("--output_dir", help="Location to write HF model", required=True)
|
| 234 |
+
args = parser.parse_args()
|
| 235 |
+
write_model(
|
| 236 |
+
model_path=args.output_dir,
|
| 237 |
+
input_base_path=args.input_dir,
|
| 238 |
+
model_size=args.model_size,
|
| 239 |
+
)
|
| 240 |
+
|
| 241 |
+
|
| 242 |
+
if __name__ == "__main__":
|
| 243 |
+
main()
|
third_party/transformers/src/transformers/models/mixtral/modeling_mixtral.py
ADDED
|
@@ -0,0 +1,702 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
# 🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨
|
| 2 |
+
# This file was automatically generated from src/transformers/models/mixtral/modular_mixtral.py.
|
| 3 |
+
# Do NOT edit this file manually as any edits will be overwritten by the generation of
|
| 4 |
+
# the file from the modular. If any change should be done, please apply the change to the
|
| 5 |
+
# modular_mixtral.py file directly. One of our CI enforces this.
|
| 6 |
+
# 🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨
|
| 7 |
+
# Copyright 2023 Mistral AI and the HuggingFace Inc. team. All rights reserved.
|
| 8 |
+
#
|
| 9 |
+
# This code is based on EleutherAI's GPT-NeoX library and the GPT-NeoX
|
| 10 |
+
# and OPT implementations in this library. It has been modified from its
|
| 11 |
+
# original forms to accommodate minor architectural differences compared
|
| 12 |
+
# to GPT-NeoX and OPT used by the Meta AI team that trained the model.
|
| 13 |
+
#
|
| 14 |
+
# Licensed under the Apache License, Version 2.0 (the "License");
|
| 15 |
+
# you may not use this file except in compliance with the License.
|
| 16 |
+
# You may obtain a copy of the License at
|
| 17 |
+
#
|
| 18 |
+
# http://www.apache.org/licenses/LICENSE-2.0
|
| 19 |
+
#
|
| 20 |
+
# Unless required by applicable law or agreed to in writing, software
|
| 21 |
+
# distributed under the License is distributed on an "AS IS" BASIS,
|
| 22 |
+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
| 23 |
+
# See the License for the specific language governing permissions and
|
| 24 |
+
# limitations under the License.
|
| 25 |
+
|
| 26 |
+
from collections.abc import Callable
|
| 27 |
+
from typing import Optional
|
| 28 |
+
|
| 29 |
+
import torch
|
| 30 |
+
import torch.nn.functional as F
|
| 31 |
+
from torch import nn
|
| 32 |
+
|
| 33 |
+
from ... import initialization as init
|
| 34 |
+
from ...activations import ACT2FN
|
| 35 |
+
from ...cache_utils import Cache, DynamicCache
|
| 36 |
+
from ...generation import GenerationMixin
|
| 37 |
+
from ...integrations import (
|
| 38 |
+
use_experts_implementation,
|
| 39 |
+
use_kernel_forward_from_hub,
|
| 40 |
+
use_kernel_func_from_hub,
|
| 41 |
+
use_kernelized_func,
|
| 42 |
+
)
|
| 43 |
+
from ...masking_utils import create_causal_mask, create_sliding_window_causal_mask
|
| 44 |
+
from ...modeling_flash_attention_utils import FlashAttentionKwargs
|
| 45 |
+
from ...modeling_layers import (
|
| 46 |
+
GenericForQuestionAnswering,
|
| 47 |
+
GenericForSequenceClassification,
|
| 48 |
+
GenericForTokenClassification,
|
| 49 |
+
GradientCheckpointingLayer,
|
| 50 |
+
)
|
| 51 |
+
from ...modeling_outputs import MoeCausalLMOutputWithPast, MoeModelOutputWithPast
|
| 52 |
+
from ...modeling_rope_utils import ROPE_INIT_FUNCTIONS, dynamic_rope_update
|
| 53 |
+
from ...modeling_utils import ALL_ATTENTION_FUNCTIONS, PreTrainedModel
|
| 54 |
+
from ...processing_utils import Unpack
|
| 55 |
+
from ...utils import TransformersKwargs, auto_docstring, can_return_tuple
|
| 56 |
+
from ...utils.generic import maybe_autocast, merge_with_config_defaults
|
| 57 |
+
from ...utils.output_capturing import OutputRecorder, capture_outputs
|
| 58 |
+
from .configuration_mixtral import MixtralConfig
|
| 59 |
+
|
| 60 |
+
|
| 61 |
+
@use_experts_implementation
|
| 62 |
+
class MixtralExperts(nn.Module):
|
| 63 |
+
"""Collection of expert weights stored as 3D tensors."""
|
| 64 |
+
|
| 65 |
+
def __init__(self, config: MixtralConfig):
|
| 66 |
+
super().__init__()
|
| 67 |
+
self.num_experts = config.num_local_experts
|
| 68 |
+
self.hidden_dim = config.hidden_size
|
| 69 |
+
self.intermediate_dim = config.intermediate_size
|
| 70 |
+
self.gate_up_proj = nn.Parameter(torch.empty(self.num_experts, 2 * self.intermediate_dim, self.hidden_dim))
|
| 71 |
+
self.down_proj = nn.Parameter(torch.empty(self.num_experts, self.hidden_dim, self.intermediate_dim))
|
| 72 |
+
self.act_fn = ACT2FN[config.hidden_act]
|
| 73 |
+
|
| 74 |
+
def forward(
|
| 75 |
+
self,
|
| 76 |
+
hidden_states: torch.Tensor,
|
| 77 |
+
top_k_index: torch.Tensor,
|
| 78 |
+
top_k_weights: torch.Tensor,
|
| 79 |
+
) -> torch.Tensor:
|
| 80 |
+
final_hidden_states = torch.zeros_like(hidden_states)
|
| 81 |
+
with torch.no_grad():
|
| 82 |
+
expert_mask = torch.nn.functional.one_hot(top_k_index, num_classes=self.num_experts)
|
| 83 |
+
expert_mask = expert_mask.permute(2, 1, 0)
|
| 84 |
+
expert_hit = torch.greater(expert_mask.sum(dim=(-1, -2)), 0).nonzero()
|
| 85 |
+
|
| 86 |
+
for expert_idx in expert_hit:
|
| 87 |
+
expert_idx = expert_idx[0]
|
| 88 |
+
if expert_idx == self.num_experts:
|
| 89 |
+
continue
|
| 90 |
+
top_k_pos, token_idx = torch.where(expert_mask[expert_idx])
|
| 91 |
+
current_state = hidden_states[token_idx]
|
| 92 |
+
gate, up = nn.functional.linear(current_state, self.gate_up_proj[expert_idx]).chunk(2, dim=-1)
|
| 93 |
+
current_hidden_states = self.act_fn(gate) * up
|
| 94 |
+
current_hidden_states = nn.functional.linear(current_hidden_states, self.down_proj[expert_idx])
|
| 95 |
+
current_hidden_states = current_hidden_states * top_k_weights[token_idx, top_k_pos, None]
|
| 96 |
+
final_hidden_states.index_add_(0, token_idx, current_hidden_states.to(final_hidden_states.dtype))
|
| 97 |
+
|
| 98 |
+
return final_hidden_states
|
| 99 |
+
|
| 100 |
+
|
| 101 |
+
class MixtralTopKRouter(nn.Module):
|
| 102 |
+
def __init__(self, config):
|
| 103 |
+
super().__init__()
|
| 104 |
+
self.top_k = config.num_experts_per_tok
|
| 105 |
+
self.num_experts = config.num_local_experts
|
| 106 |
+
self.hidden_dim = config.hidden_size
|
| 107 |
+
self.weight = nn.Parameter(torch.empty(self.num_experts, self.hidden_dim))
|
| 108 |
+
|
| 109 |
+
def forward(self, hidden_states):
|
| 110 |
+
hidden_states = hidden_states.reshape(-1, self.hidden_dim)
|
| 111 |
+
router_logits = F.linear(hidden_states, self.weight) # (seq_len, num_experts)
|
| 112 |
+
router_logits = torch.nn.functional.softmax(router_logits.float(), dim=-1)
|
| 113 |
+
router_top_value, router_indices = torch.topk(router_logits, self.top_k, dim=-1) # (seq_len, top_k)
|
| 114 |
+
router_top_value /= router_top_value.sum(dim=-1, keepdim=True)
|
| 115 |
+
router_scores = router_top_value
|
| 116 |
+
return router_logits, router_scores, router_indices
|
| 117 |
+
|
| 118 |
+
|
| 119 |
+
class MixtralSparseMoeBlock(nn.Module):
|
| 120 |
+
def __init__(self, config):
|
| 121 |
+
super().__init__()
|
| 122 |
+
self.top_k = config.num_experts_per_tok
|
| 123 |
+
self.jitter_noise = config.router_jitter_noise
|
| 124 |
+
self.gate = MixtralTopKRouter(config)
|
| 125 |
+
self.experts = MixtralExperts(config)
|
| 126 |
+
|
| 127 |
+
def forward(self, hidden_states: torch.Tensor) -> tuple[torch.Tensor, torch.Tensor]:
|
| 128 |
+
batch_size, sequence_length, hidden_dim = hidden_states.shape
|
| 129 |
+
if self.training and self.jitter_noise > 0:
|
| 130 |
+
hidden_states *= torch.empty_like(hidden_states).uniform_(1.0 - self.jitter_noise, 1.0 + self.jitter_noise)
|
| 131 |
+
hidden_states = hidden_states.view(-1, hidden_states.shape[-1])
|
| 132 |
+
_, top_k_weights, top_k_index = self.gate(hidden_states)
|
| 133 |
+
hidden_states = self.experts(hidden_states, top_k_index, top_k_weights)
|
| 134 |
+
hidden_states = hidden_states.reshape(batch_size, sequence_length, hidden_dim)
|
| 135 |
+
return hidden_states
|
| 136 |
+
|
| 137 |
+
|
| 138 |
+
@use_kernel_forward_from_hub("RMSNorm")
|
| 139 |
+
class MixtralRMSNorm(nn.Module):
|
| 140 |
+
def __init__(self, hidden_size, eps: float = 1e-6) -> None:
|
| 141 |
+
"""
|
| 142 |
+
MixtralRMSNorm is equivalent to T5LayerNorm
|
| 143 |
+
"""
|
| 144 |
+
super().__init__()
|
| 145 |
+
self.weight = nn.Parameter(torch.ones(hidden_size))
|
| 146 |
+
self.variance_epsilon = eps
|
| 147 |
+
|
| 148 |
+
def forward(self, hidden_states: torch.Tensor) -> torch.Tensor:
|
| 149 |
+
input_dtype = hidden_states.dtype
|
| 150 |
+
hidden_states = hidden_states.to(torch.float32)
|
| 151 |
+
variance = hidden_states.pow(2).mean(-1, keepdim=True)
|
| 152 |
+
hidden_states = hidden_states * torch.rsqrt(variance + self.variance_epsilon)
|
| 153 |
+
return self.weight * hidden_states.to(input_dtype)
|
| 154 |
+
|
| 155 |
+
def extra_repr(self):
|
| 156 |
+
return f"{tuple(self.weight.shape)}, eps={self.variance_epsilon}"
|
| 157 |
+
|
| 158 |
+
|
| 159 |
+
class MixtralRotaryEmbedding(nn.Module):
|
| 160 |
+
inv_freq: torch.Tensor # fix linting for `register_buffer`
|
| 161 |
+
|
| 162 |
+
def __init__(self, config: MixtralConfig, device=None):
|
| 163 |
+
super().__init__()
|
| 164 |
+
self.max_seq_len_cached = config.max_position_embeddings
|
| 165 |
+
self.original_max_seq_len = config.max_position_embeddings
|
| 166 |
+
|
| 167 |
+
self.config = config
|
| 168 |
+
|
| 169 |
+
self.rope_type = self.config.rope_parameters["rope_type"]
|
| 170 |
+
rope_init_fn: Callable = self.compute_default_rope_parameters
|
| 171 |
+
if self.rope_type != "default":
|
| 172 |
+
rope_init_fn = ROPE_INIT_FUNCTIONS[self.rope_type]
|
| 173 |
+
inv_freq, self.attention_scaling = rope_init_fn(self.config, device)
|
| 174 |
+
|
| 175 |
+
self.register_buffer("inv_freq", inv_freq, persistent=False)
|
| 176 |
+
self.register_buffer("original_inv_freq", inv_freq.clone(), persistent=False)
|
| 177 |
+
|
| 178 |
+
@staticmethod
|
| 179 |
+
def compute_default_rope_parameters(
|
| 180 |
+
config: MixtralConfig | None = None,
|
| 181 |
+
device: Optional["torch.device"] = None,
|
| 182 |
+
seq_len: int | None = None,
|
| 183 |
+
) -> tuple["torch.Tensor", float]:
|
| 184 |
+
"""
|
| 185 |
+
Computes the inverse frequencies according to the original RoPE implementation
|
| 186 |
+
Args:
|
| 187 |
+
config ([`~transformers.PreTrainedConfig`]):
|
| 188 |
+
The model configuration.
|
| 189 |
+
device (`torch.device`):
|
| 190 |
+
The device to use for initialization of the inverse frequencies.
|
| 191 |
+
seq_len (`int`, *optional*):
|
| 192 |
+
The current sequence length. Unused for this type of RoPE.
|
| 193 |
+
Returns:
|
| 194 |
+
Tuple of (`torch.Tensor`, `float`), containing the inverse frequencies for the RoPE embeddings and the
|
| 195 |
+
post-processing scaling factor applied to the computed cos/sin (unused in this type of RoPE).
|
| 196 |
+
"""
|
| 197 |
+
base = config.rope_parameters["rope_theta"]
|
| 198 |
+
dim = getattr(config, "head_dim", None) or config.hidden_size // config.num_attention_heads
|
| 199 |
+
|
| 200 |
+
attention_factor = 1.0 # Unused in this type of RoPE
|
| 201 |
+
|
| 202 |
+
# Compute the inverse frequencies
|
| 203 |
+
inv_freq = 1.0 / (
|
| 204 |
+
base ** (torch.arange(0, dim, 2, dtype=torch.int64).to(device=device, dtype=torch.float) / dim)
|
| 205 |
+
)
|
| 206 |
+
return inv_freq, attention_factor
|
| 207 |
+
|
| 208 |
+
@torch.no_grad()
|
| 209 |
+
@dynamic_rope_update # power user: used with advanced RoPE types (e.g. dynamic rope)
|
| 210 |
+
def forward(self, x, position_ids):
|
| 211 |
+
inv_freq_expanded = self.inv_freq[None, :, None].float().expand(position_ids.shape[0], -1, 1).to(x.device)
|
| 212 |
+
position_ids_expanded = position_ids[:, None, :].float()
|
| 213 |
+
|
| 214 |
+
device_type = x.device.type if isinstance(x.device.type, str) and x.device.type != "mps" else "cpu"
|
| 215 |
+
with maybe_autocast(device_type=device_type, enabled=False): # Force float32
|
| 216 |
+
freqs = (inv_freq_expanded.float() @ position_ids_expanded.float()).transpose(1, 2)
|
| 217 |
+
emb = torch.cat((freqs, freqs), dim=-1)
|
| 218 |
+
cos = emb.cos() * self.attention_scaling
|
| 219 |
+
sin = emb.sin() * self.attention_scaling
|
| 220 |
+
|
| 221 |
+
return cos.to(dtype=x.dtype), sin.to(dtype=x.dtype)
|
| 222 |
+
|
| 223 |
+
|
| 224 |
+
def rotate_half(x):
|
| 225 |
+
"""Rotates half the hidden dims of the input."""
|
| 226 |
+
x1 = x[..., : x.shape[-1] // 2]
|
| 227 |
+
x2 = x[..., x.shape[-1] // 2 :]
|
| 228 |
+
return torch.cat((-x2, x1), dim=-1)
|
| 229 |
+
|
| 230 |
+
|
| 231 |
+
@use_kernel_func_from_hub("rotary_pos_emb")
|
| 232 |
+
def apply_rotary_pos_emb(q, k, cos, sin, unsqueeze_dim=1):
|
| 233 |
+
"""Applies Rotary Position Embedding to the query and key tensors.
|
| 234 |
+
|
| 235 |
+
Args:
|
| 236 |
+
q (`torch.Tensor`): The query tensor.
|
| 237 |
+
k (`torch.Tensor`): The key tensor.
|
| 238 |
+
cos (`torch.Tensor`): The cosine part of the rotary embedding.
|
| 239 |
+
sin (`torch.Tensor`): The sine part of the rotary embedding.
|
| 240 |
+
unsqueeze_dim (`int`, *optional*, defaults to 1):
|
| 241 |
+
The 'unsqueeze_dim' argument specifies the dimension along which to unsqueeze cos[position_ids] and
|
| 242 |
+
sin[position_ids] so that they can be properly broadcasted to the dimensions of q and k. For example, note
|
| 243 |
+
that cos[position_ids] and sin[position_ids] have the shape [batch_size, seq_len, head_dim]. Then, if q and
|
| 244 |
+
k have the shape [batch_size, heads, seq_len, head_dim], then setting unsqueeze_dim=1 makes
|
| 245 |
+
cos[position_ids] and sin[position_ids] broadcastable to the shapes of q and k. Similarly, if q and k have
|
| 246 |
+
the shape [batch_size, seq_len, heads, head_dim], then set unsqueeze_dim=2.
|
| 247 |
+
Returns:
|
| 248 |
+
`tuple(torch.Tensor)` comprising of the query and key tensors rotated using the Rotary Position Embedding.
|
| 249 |
+
"""
|
| 250 |
+
cos = cos.unsqueeze(unsqueeze_dim)
|
| 251 |
+
sin = sin.unsqueeze(unsqueeze_dim)
|
| 252 |
+
q_embed = (q * cos) + (rotate_half(q) * sin)
|
| 253 |
+
k_embed = (k * cos) + (rotate_half(k) * sin)
|
| 254 |
+
return q_embed, k_embed
|
| 255 |
+
|
| 256 |
+
|
| 257 |
+
def repeat_kv(hidden_states: torch.Tensor, n_rep: int) -> torch.Tensor:
|
| 258 |
+
"""
|
| 259 |
+
This is the equivalent of torch.repeat_interleave(x, dim=1, repeats=n_rep). The hidden states go from (batch,
|
| 260 |
+
num_key_value_heads, seqlen, head_dim) to (batch, num_attention_heads, seqlen, head_dim)
|
| 261 |
+
"""
|
| 262 |
+
batch, num_key_value_heads, slen, head_dim = hidden_states.shape
|
| 263 |
+
if n_rep == 1:
|
| 264 |
+
return hidden_states
|
| 265 |
+
hidden_states = hidden_states[:, :, None, :, :].expand(batch, num_key_value_heads, n_rep, slen, head_dim)
|
| 266 |
+
return hidden_states.reshape(batch, num_key_value_heads * n_rep, slen, head_dim)
|
| 267 |
+
|
| 268 |
+
|
| 269 |
+
def eager_attention_forward(
|
| 270 |
+
module: nn.Module,
|
| 271 |
+
query: torch.Tensor,
|
| 272 |
+
key: torch.Tensor,
|
| 273 |
+
value: torch.Tensor,
|
| 274 |
+
attention_mask: torch.Tensor | None,
|
| 275 |
+
scaling: float,
|
| 276 |
+
dropout: float = 0.0,
|
| 277 |
+
**kwargs: Unpack[TransformersKwargs],
|
| 278 |
+
):
|
| 279 |
+
key_states = repeat_kv(key, module.num_key_value_groups)
|
| 280 |
+
value_states = repeat_kv(value, module.num_key_value_groups)
|
| 281 |
+
|
| 282 |
+
attn_weights = torch.matmul(query, key_states.transpose(2, 3)) * scaling
|
| 283 |
+
if attention_mask is not None:
|
| 284 |
+
attn_weights = attn_weights + attention_mask
|
| 285 |
+
|
| 286 |
+
attn_weights = nn.functional.softmax(attn_weights, dim=-1, dtype=torch.float32).to(query.dtype)
|
| 287 |
+
attn_weights = nn.functional.dropout(attn_weights, p=dropout, training=module.training)
|
| 288 |
+
attn_output = torch.matmul(attn_weights, value_states)
|
| 289 |
+
attn_output = attn_output.transpose(1, 2).contiguous()
|
| 290 |
+
|
| 291 |
+
return attn_output, attn_weights
|
| 292 |
+
|
| 293 |
+
|
| 294 |
+
@use_kernelized_func(apply_rotary_pos_emb)
|
| 295 |
+
class MixtralAttention(nn.Module):
|
| 296 |
+
"""Multi-headed attention from 'Attention Is All You Need' paper"""
|
| 297 |
+
|
| 298 |
+
def __init__(self, config: MixtralConfig, layer_idx: int):
|
| 299 |
+
super().__init__()
|
| 300 |
+
self.config = config
|
| 301 |
+
self.layer_idx = layer_idx
|
| 302 |
+
self.head_dim = getattr(config, "head_dim", None) or config.hidden_size // config.num_attention_heads
|
| 303 |
+
self.num_key_value_groups = config.num_attention_heads // config.num_key_value_heads
|
| 304 |
+
self.scaling = self.head_dim**-0.5
|
| 305 |
+
self.attention_dropout = config.attention_dropout
|
| 306 |
+
self.is_causal = True
|
| 307 |
+
self.q_proj = nn.Linear(config.hidden_size, config.num_attention_heads * self.head_dim, bias=False)
|
| 308 |
+
self.k_proj = nn.Linear(config.hidden_size, config.num_key_value_heads * self.head_dim, bias=False)
|
| 309 |
+
self.v_proj = nn.Linear(config.hidden_size, config.num_key_value_heads * self.head_dim, bias=False)
|
| 310 |
+
self.o_proj = nn.Linear(config.num_attention_heads * self.head_dim, config.hidden_size, bias=False)
|
| 311 |
+
|
| 312 |
+
def forward(
|
| 313 |
+
self,
|
| 314 |
+
hidden_states: torch.Tensor,
|
| 315 |
+
position_embeddings: tuple[torch.Tensor, torch.Tensor],
|
| 316 |
+
attention_mask: torch.Tensor | None,
|
| 317 |
+
past_key_values: Cache | None = None,
|
| 318 |
+
**kwargs: Unpack[FlashAttentionKwargs],
|
| 319 |
+
) -> tuple[torch.Tensor, torch.Tensor | None]:
|
| 320 |
+
input_shape = hidden_states.shape[:-1]
|
| 321 |
+
hidden_shape = (*input_shape, -1, self.head_dim)
|
| 322 |
+
|
| 323 |
+
query_states = self.q_proj(hidden_states).view(hidden_shape).transpose(1, 2)
|
| 324 |
+
key_states = self.k_proj(hidden_states).view(hidden_shape).transpose(1, 2)
|
| 325 |
+
value_states = self.v_proj(hidden_states).view(hidden_shape).transpose(1, 2)
|
| 326 |
+
|
| 327 |
+
cos, sin = position_embeddings
|
| 328 |
+
query_states, key_states = apply_rotary_pos_emb(query_states, key_states, cos, sin)
|
| 329 |
+
|
| 330 |
+
if past_key_values is not None:
|
| 331 |
+
key_states, value_states = past_key_values.update(key_states, value_states, self.layer_idx)
|
| 332 |
+
|
| 333 |
+
attention_interface: Callable = ALL_ATTENTION_FUNCTIONS.get_interface(
|
| 334 |
+
self.config._attn_implementation, eager_attention_forward
|
| 335 |
+
)
|
| 336 |
+
|
| 337 |
+
attn_output, attn_weights = attention_interface(
|
| 338 |
+
self,
|
| 339 |
+
query_states,
|
| 340 |
+
key_states,
|
| 341 |
+
value_states,
|
| 342 |
+
attention_mask,
|
| 343 |
+
dropout=0.0 if not self.training else self.attention_dropout,
|
| 344 |
+
scaling=self.scaling,
|
| 345 |
+
sliding_window=getattr(self.config, "sliding_window", None), # main diff with Llama
|
| 346 |
+
**kwargs,
|
| 347 |
+
)
|
| 348 |
+
|
| 349 |
+
attn_output = attn_output.reshape(*input_shape, -1).contiguous()
|
| 350 |
+
attn_output = self.o_proj(attn_output)
|
| 351 |
+
return attn_output, attn_weights
|
| 352 |
+
|
| 353 |
+
|
| 354 |
+
class MixtralDecoderLayer(GradientCheckpointingLayer):
|
| 355 |
+
def __init__(self, config: MixtralConfig, layer_idx: int):
|
| 356 |
+
super().__init__()
|
| 357 |
+
self.hidden_size = config.hidden_size
|
| 358 |
+
|
| 359 |
+
self.self_attn = MixtralAttention(config, layer_idx)
|
| 360 |
+
|
| 361 |
+
self.mlp = MixtralSparseMoeBlock(config)
|
| 362 |
+
self.input_layernorm = MixtralRMSNorm(config.hidden_size, eps=config.rms_norm_eps)
|
| 363 |
+
self.post_attention_layernorm = MixtralRMSNorm(config.hidden_size, eps=config.rms_norm_eps)
|
| 364 |
+
|
| 365 |
+
def forward(
|
| 366 |
+
self,
|
| 367 |
+
hidden_states: torch.Tensor,
|
| 368 |
+
position_embeddings: tuple[torch.Tensor, torch.Tensor] | None = None,
|
| 369 |
+
attention_mask: torch.Tensor | None = None,
|
| 370 |
+
position_ids: torch.LongTensor | None = None,
|
| 371 |
+
past_key_values: Cache | None = None,
|
| 372 |
+
**kwargs: Unpack[TransformersKwargs],
|
| 373 |
+
) -> torch.Tensor:
|
| 374 |
+
residual = hidden_states
|
| 375 |
+
hidden_states = self.input_layernorm(hidden_states)
|
| 376 |
+
hidden_states, _ = self.self_attn(
|
| 377 |
+
hidden_states=hidden_states,
|
| 378 |
+
position_embeddings=position_embeddings,
|
| 379 |
+
attention_mask=attention_mask,
|
| 380 |
+
position_ids=position_ids,
|
| 381 |
+
past_key_values=past_key_values,
|
| 382 |
+
**kwargs,
|
| 383 |
+
)
|
| 384 |
+
hidden_states = residual + hidden_states
|
| 385 |
+
residual = hidden_states
|
| 386 |
+
hidden_states = self.post_attention_layernorm(hidden_states)
|
| 387 |
+
hidden_states = self.mlp(hidden_states)
|
| 388 |
+
hidden_states = residual + hidden_states
|
| 389 |
+
return hidden_states
|
| 390 |
+
|
| 391 |
+
|
| 392 |
+
@auto_docstring
|
| 393 |
+
class MixtralPreTrainedModel(PreTrainedModel):
|
| 394 |
+
config: MixtralConfig
|
| 395 |
+
base_model_prefix = "model"
|
| 396 |
+
supports_gradient_checkpointing = True
|
| 397 |
+
_no_split_modules = ["MixtralDecoderLayer"]
|
| 398 |
+
_skip_keys_device_placement = ["past_key_values"]
|
| 399 |
+
_supports_flash_attn = True
|
| 400 |
+
_supports_sdpa = True
|
| 401 |
+
_supports_flex_attn = True
|
| 402 |
+
|
| 403 |
+
_can_compile_fullgraph = True
|
| 404 |
+
_supports_attention_backend = True
|
| 405 |
+
_can_record_outputs = {
|
| 406 |
+
"router_logits": OutputRecorder(MixtralTopKRouter, index=0),
|
| 407 |
+
"hidden_states": MixtralDecoderLayer,
|
| 408 |
+
"attentions": MixtralAttention,
|
| 409 |
+
}
|
| 410 |
+
|
| 411 |
+
@torch.no_grad()
|
| 412 |
+
def _init_weights(self, module):
|
| 413 |
+
super()._init_weights(module)
|
| 414 |
+
std = self.config.initializer_range
|
| 415 |
+
if isinstance(module, MixtralExperts):
|
| 416 |
+
init.normal_(module.gate_up_proj, mean=0.0, std=std)
|
| 417 |
+
init.normal_(module.down_proj, mean=0.0, std=std)
|
| 418 |
+
elif isinstance(module, MixtralTopKRouter):
|
| 419 |
+
init.normal_(module.weight, mean=0.0, std=std)
|
| 420 |
+
|
| 421 |
+
|
| 422 |
+
@auto_docstring
|
| 423 |
+
class MixtralModel(MixtralPreTrainedModel):
|
| 424 |
+
def __init__(self, config: MixtralConfig):
|
| 425 |
+
super().__init__(config)
|
| 426 |
+
self.padding_idx = config.pad_token_id
|
| 427 |
+
self.vocab_size = config.vocab_size
|
| 428 |
+
|
| 429 |
+
self.embed_tokens = nn.Embedding(config.vocab_size, config.hidden_size, self.padding_idx)
|
| 430 |
+
self.layers = nn.ModuleList(
|
| 431 |
+
[MixtralDecoderLayer(config, layer_idx) for layer_idx in range(config.num_hidden_layers)]
|
| 432 |
+
)
|
| 433 |
+
self.norm = MixtralRMSNorm(config.hidden_size, eps=config.rms_norm_eps)
|
| 434 |
+
self.rotary_emb = MixtralRotaryEmbedding(config=config)
|
| 435 |
+
self.gradient_checkpointing = False
|
| 436 |
+
|
| 437 |
+
# Initialize weights and apply final processing
|
| 438 |
+
self.post_init()
|
| 439 |
+
|
| 440 |
+
@merge_with_config_defaults
|
| 441 |
+
@capture_outputs
|
| 442 |
+
@auto_docstring
|
| 443 |
+
def forward(
|
| 444 |
+
self,
|
| 445 |
+
input_ids: torch.LongTensor | None = None,
|
| 446 |
+
attention_mask: torch.Tensor | None = None,
|
| 447 |
+
position_ids: torch.LongTensor | None = None,
|
| 448 |
+
past_key_values: Cache | None = None,
|
| 449 |
+
inputs_embeds: torch.FloatTensor | None = None,
|
| 450 |
+
use_cache: bool | None = None,
|
| 451 |
+
**kwargs: Unpack[TransformersKwargs],
|
| 452 |
+
) -> MoeModelOutputWithPast:
|
| 453 |
+
if (input_ids is None) ^ (inputs_embeds is not None):
|
| 454 |
+
raise ValueError("You must specify exactly one of input_ids or inputs_embeds")
|
| 455 |
+
|
| 456 |
+
if use_cache and past_key_values is None:
|
| 457 |
+
past_key_values = DynamicCache(config=self.config)
|
| 458 |
+
|
| 459 |
+
if inputs_embeds is None:
|
| 460 |
+
inputs_embeds = self.embed_tokens(input_ids)
|
| 461 |
+
|
| 462 |
+
if position_ids is None:
|
| 463 |
+
past_seen_tokens = past_key_values.get_seq_length() if past_key_values is not None else 0
|
| 464 |
+
position_ids = torch.arange(inputs_embeds.shape[1], device=inputs_embeds.device) + past_seen_tokens
|
| 465 |
+
position_ids = position_ids.unsqueeze(0)
|
| 466 |
+
|
| 467 |
+
mask_function = create_causal_mask if self.config.sliding_window is None else create_sliding_window_causal_mask
|
| 468 |
+
causal_mask = mask_function(
|
| 469 |
+
config=self.config,
|
| 470 |
+
inputs_embeds=inputs_embeds,
|
| 471 |
+
attention_mask=attention_mask,
|
| 472 |
+
past_key_values=past_key_values,
|
| 473 |
+
position_ids=position_ids,
|
| 474 |
+
)
|
| 475 |
+
|
| 476 |
+
hidden_states = inputs_embeds
|
| 477 |
+
position_embeddings = self.rotary_emb(hidden_states, position_ids=position_ids)
|
| 478 |
+
|
| 479 |
+
for decoder_layer in self.layers[: self.config.num_hidden_layers]:
|
| 480 |
+
hidden_states = decoder_layer(
|
| 481 |
+
hidden_states,
|
| 482 |
+
attention_mask=causal_mask,
|
| 483 |
+
position_ids=position_ids,
|
| 484 |
+
past_key_values=past_key_values,
|
| 485 |
+
use_cache=use_cache,
|
| 486 |
+
position_embeddings=position_embeddings,
|
| 487 |
+
**kwargs,
|
| 488 |
+
)
|
| 489 |
+
|
| 490 |
+
hidden_states = self.norm(hidden_states)
|
| 491 |
+
|
| 492 |
+
return MoeModelOutputWithPast( # only diff with Mistral is the output type, we need MoE
|
| 493 |
+
last_hidden_state=hidden_states,
|
| 494 |
+
past_key_values=past_key_values,
|
| 495 |
+
)
|
| 496 |
+
|
| 497 |
+
|
| 498 |
+
def load_balancing_loss_func(
|
| 499 |
+
gate_logits: torch.Tensor | tuple[torch.Tensor] | None,
|
| 500 |
+
num_experts: int | None = None,
|
| 501 |
+
top_k=2,
|
| 502 |
+
attention_mask: torch.Tensor | None = None,
|
| 503 |
+
) -> torch.Tensor | int:
|
| 504 |
+
r"""
|
| 505 |
+
Computes auxiliary load balancing loss as in Switch Transformer - implemented in Pytorch.
|
| 506 |
+
|
| 507 |
+
See Switch Transformer (https://huggingface.co/papers/2101.03961) for more details. This function implements the loss
|
| 508 |
+
function presented in equations (4) - (6) of the paper. It aims at penalizing cases where the routing between
|
| 509 |
+
experts is too unbalanced.
|
| 510 |
+
|
| 511 |
+
Args:
|
| 512 |
+
gate_logits:
|
| 513 |
+
Logits from the `gate`, should be a tuple of model.config.num_hidden_layers tensors of
|
| 514 |
+
shape [batch_size X sequence_length, num_experts].
|
| 515 |
+
num_experts:
|
| 516 |
+
Number of experts
|
| 517 |
+
top_k:
|
| 518 |
+
The number of experts to route per-token, can be also interpreted as the `top-k` routing
|
| 519 |
+
parameter.
|
| 520 |
+
attention_mask (`torch.Tensor`, *optional*):
|
| 521 |
+
The attention_mask used in forward function
|
| 522 |
+
shape [batch_size X sequence_length] if not None.
|
| 523 |
+
|
| 524 |
+
Returns:
|
| 525 |
+
The auxiliary loss.
|
| 526 |
+
"""
|
| 527 |
+
if gate_logits is None or not isinstance(gate_logits, tuple):
|
| 528 |
+
return 0
|
| 529 |
+
|
| 530 |
+
if isinstance(gate_logits, tuple):
|
| 531 |
+
compute_device = gate_logits[0].device
|
| 532 |
+
concatenated_gate_logits = torch.cat([layer_gate.to(compute_device) for layer_gate in gate_logits], dim=0)
|
| 533 |
+
|
| 534 |
+
routing_weights = torch.nn.functional.softmax(concatenated_gate_logits, dim=-1)
|
| 535 |
+
|
| 536 |
+
_, selected_experts = torch.topk(routing_weights, top_k, dim=-1)
|
| 537 |
+
|
| 538 |
+
expert_mask = torch.nn.functional.one_hot(selected_experts, num_experts)
|
| 539 |
+
|
| 540 |
+
if attention_mask is None:
|
| 541 |
+
# Compute the percentage of tokens routed to each experts
|
| 542 |
+
tokens_per_expert = torch.mean(expert_mask.float(), dim=0)
|
| 543 |
+
|
| 544 |
+
# Compute the average probability of routing to these experts
|
| 545 |
+
router_prob_per_expert = torch.mean(routing_weights, dim=0)
|
| 546 |
+
else:
|
| 547 |
+
batch_size, sequence_length = attention_mask.shape
|
| 548 |
+
num_hidden_layers = concatenated_gate_logits.shape[0] // (batch_size * sequence_length)
|
| 549 |
+
|
| 550 |
+
# Compute the mask that masks all padding tokens as 0 with the same shape of expert_mask
|
| 551 |
+
expert_attention_mask = (
|
| 552 |
+
attention_mask[None, :, :, None, None]
|
| 553 |
+
.expand((num_hidden_layers, batch_size, sequence_length, top_k, num_experts))
|
| 554 |
+
.reshape(-1, top_k, num_experts)
|
| 555 |
+
.to(compute_device)
|
| 556 |
+
)
|
| 557 |
+
|
| 558 |
+
# Compute the percentage of tokens routed to each experts
|
| 559 |
+
tokens_per_expert = torch.sum(expert_mask.float() * expert_attention_mask, dim=0) / torch.sum(
|
| 560 |
+
expert_attention_mask, dim=0
|
| 561 |
+
)
|
| 562 |
+
|
| 563 |
+
# Compute the mask that masks all padding tokens as 0 with the same shape of tokens_per_expert
|
| 564 |
+
router_per_expert_attention_mask = (
|
| 565 |
+
attention_mask[None, :, :, None]
|
| 566 |
+
.expand((num_hidden_layers, batch_size, sequence_length, num_experts))
|
| 567 |
+
.reshape(-1, num_experts)
|
| 568 |
+
.to(compute_device)
|
| 569 |
+
)
|
| 570 |
+
|
| 571 |
+
# Compute the average probability of routing to these experts
|
| 572 |
+
router_prob_per_expert = torch.sum(routing_weights * router_per_expert_attention_mask, dim=0) / torch.sum(
|
| 573 |
+
router_per_expert_attention_mask, dim=0
|
| 574 |
+
)
|
| 575 |
+
|
| 576 |
+
overall_loss = torch.sum(tokens_per_expert * router_prob_per_expert.unsqueeze(0))
|
| 577 |
+
return overall_loss * num_experts
|
| 578 |
+
|
| 579 |
+
|
| 580 |
+
@auto_docstring
|
| 581 |
+
class MixtralForCausalLM(MixtralPreTrainedModel, GenerationMixin):
|
| 582 |
+
_tied_weights_keys = {"lm_head.weight": "model.embed_tokens.weight"}
|
| 583 |
+
_tp_plan = {"lm_head": "colwise_gather_output"}
|
| 584 |
+
_pp_plan = {"lm_head": (["hidden_states"], ["logits"])}
|
| 585 |
+
|
| 586 |
+
def __init__(self, config):
|
| 587 |
+
super().__init__(config)
|
| 588 |
+
self.model = MixtralModel(config)
|
| 589 |
+
self.vocab_size = config.vocab_size
|
| 590 |
+
self.lm_head = nn.Linear(config.hidden_size, config.vocab_size, bias=False)
|
| 591 |
+
self.router_aux_loss_coef = config.router_aux_loss_coef
|
| 592 |
+
self.num_experts = config.num_local_experts
|
| 593 |
+
self.num_experts_per_tok = config.num_experts_per_tok
|
| 594 |
+
|
| 595 |
+
# Initialize weights and apply final processing
|
| 596 |
+
self.post_init()
|
| 597 |
+
|
| 598 |
+
@can_return_tuple
|
| 599 |
+
@auto_docstring
|
| 600 |
+
def forward(
|
| 601 |
+
self,
|
| 602 |
+
input_ids: torch.LongTensor | None = None,
|
| 603 |
+
attention_mask: torch.Tensor | None = None,
|
| 604 |
+
position_ids: torch.LongTensor | None = None,
|
| 605 |
+
past_key_values: Cache | None = None,
|
| 606 |
+
inputs_embeds: torch.FloatTensor | None = None,
|
| 607 |
+
labels: torch.LongTensor | None = None,
|
| 608 |
+
use_cache: bool | None = None,
|
| 609 |
+
output_router_logits: bool | None = None,
|
| 610 |
+
logits_to_keep: int | torch.Tensor = 0,
|
| 611 |
+
**kwargs: Unpack[TransformersKwargs],
|
| 612 |
+
) -> MoeCausalLMOutputWithPast:
|
| 613 |
+
r"""
|
| 614 |
+
labels (`torch.LongTensor` of shape `(batch_size, sequence_length)`, *optional*):
|
| 615 |
+
Labels for computing the masked language modeling loss. Indices should either be in `[0, ...,
|
| 616 |
+
config.vocab_size]` or -100 (see `input_ids` docstring). Tokens with indices set to `-100` are ignored
|
| 617 |
+
(masked), the loss is only computed for the tokens with labels in `[0, ..., config.vocab_size]`.
|
| 618 |
+
|
| 619 |
+
Example:
|
| 620 |
+
|
| 621 |
+
```python
|
| 622 |
+
>>> from transformers import AutoTokenizer, MixtralForCausalLM
|
| 623 |
+
|
| 624 |
+
>>> model = MixtralForCausalLM.from_pretrained("mistralai/Mixtral-8x7B-v0.1")
|
| 625 |
+
>>> tokenizer = AutoTokenizer.from_pretrained("mistralai/Mixtral-8x7B-v0.1")
|
| 626 |
+
|
| 627 |
+
>>> prompt = "Hey, are you conscious? Can you talk to me?"
|
| 628 |
+
>>> inputs = tokenizer(prompt, return_tensors="pt")
|
| 629 |
+
|
| 630 |
+
>>> # Generate
|
| 631 |
+
>>> generate_ids = model.generate(inputs.input_ids, max_length=30)
|
| 632 |
+
>>> tokenizer.batch_decode(generate_ids, skip_special_tokens=True, clean_up_tokenization_spaces=False)[0]
|
| 633 |
+
"Hey, are you conscious? Can you talk to me?\nI'm not conscious, but I can talk to you."
|
| 634 |
+
```"""
|
| 635 |
+
|
| 636 |
+
output_router_logits = (
|
| 637 |
+
output_router_logits if output_router_logits is not None else self.config.output_router_logits
|
| 638 |
+
)
|
| 639 |
+
|
| 640 |
+
# decoder outputs consists of (dec_features, layer_state, dec_hidden, dec_attn)
|
| 641 |
+
outputs: MoeModelOutputWithPast = self.model(
|
| 642 |
+
input_ids=input_ids,
|
| 643 |
+
attention_mask=attention_mask,
|
| 644 |
+
position_ids=position_ids,
|
| 645 |
+
past_key_values=past_key_values,
|
| 646 |
+
inputs_embeds=inputs_embeds,
|
| 647 |
+
use_cache=use_cache,
|
| 648 |
+
output_router_logits=output_router_logits,
|
| 649 |
+
**kwargs,
|
| 650 |
+
)
|
| 651 |
+
|
| 652 |
+
hidden_states = outputs.last_hidden_state
|
| 653 |
+
# Only compute necessary logits, and do not upcast them to float if we are not computing the loss
|
| 654 |
+
slice_indices = slice(-logits_to_keep, None) if isinstance(logits_to_keep, int) else logits_to_keep
|
| 655 |
+
logits = self.lm_head(hidden_states[:, slice_indices, :])
|
| 656 |
+
|
| 657 |
+
loss = None
|
| 658 |
+
if labels is not None:
|
| 659 |
+
loss = self.loss_function(logits, labels, self.vocab_size, **kwargs)
|
| 660 |
+
|
| 661 |
+
aux_loss = None
|
| 662 |
+
if output_router_logits:
|
| 663 |
+
aux_loss = load_balancing_loss_func(
|
| 664 |
+
outputs.router_logits,
|
| 665 |
+
self.num_experts,
|
| 666 |
+
self.num_experts_per_tok,
|
| 667 |
+
attention_mask,
|
| 668 |
+
)
|
| 669 |
+
if labels is not None:
|
| 670 |
+
loss += self.router_aux_loss_coef * aux_loss.to(loss.device) # make sure to reside in the same device
|
| 671 |
+
|
| 672 |
+
return MoeCausalLMOutputWithPast(
|
| 673 |
+
loss=loss,
|
| 674 |
+
aux_loss=aux_loss,
|
| 675 |
+
logits=logits,
|
| 676 |
+
past_key_values=outputs.past_key_values,
|
| 677 |
+
hidden_states=outputs.hidden_states,
|
| 678 |
+
attentions=outputs.attentions,
|
| 679 |
+
router_logits=outputs.router_logits,
|
| 680 |
+
)
|
| 681 |
+
|
| 682 |
+
|
| 683 |
+
class MixtralForSequenceClassification(GenericForSequenceClassification, MixtralPreTrainedModel):
|
| 684 |
+
pass
|
| 685 |
+
|
| 686 |
+
|
| 687 |
+
class MixtralForTokenClassification(GenericForTokenClassification, MixtralPreTrainedModel):
|
| 688 |
+
pass
|
| 689 |
+
|
| 690 |
+
|
| 691 |
+
class MixtralForQuestionAnswering(GenericForQuestionAnswering, MixtralPreTrainedModel):
|
| 692 |
+
pass
|
| 693 |
+
|
| 694 |
+
|
| 695 |
+
__all__ = [
|
| 696 |
+
"MixtralForCausalLM",
|
| 697 |
+
"MixtralForQuestionAnswering",
|
| 698 |
+
"MixtralModel",
|
| 699 |
+
"MixtralPreTrainedModel",
|
| 700 |
+
"MixtralForSequenceClassification",
|
| 701 |
+
"MixtralForTokenClassification",
|
| 702 |
+
]
|
third_party/transformers/src/transformers/models/mixtral/modular_mixtral.py
ADDED
|
@@ -0,0 +1,448 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
# Copyright 2023 Mistral AI and the HuggingFace Inc. team. All rights reserved.
|
| 2 |
+
#
|
| 3 |
+
# This code is based on EleutherAI's GPT-NeoX library and the GPT-NeoX
|
| 4 |
+
# and OPT implementations in this library. It has been modified from its
|
| 5 |
+
# original forms to accommodate minor architectural differences compared
|
| 6 |
+
# to GPT-NeoX and OPT used by the Meta AI team that trained the model.
|
| 7 |
+
#
|
| 8 |
+
# Licensed under the Apache License, Version 2.0 (the "License");
|
| 9 |
+
# you may not use this file except in compliance with the License.
|
| 10 |
+
# You may obtain a copy of the License at
|
| 11 |
+
#
|
| 12 |
+
# http://www.apache.org/licenses/LICENSE-2.0
|
| 13 |
+
#
|
| 14 |
+
# Unless required by applicable law or agreed to in writing, software
|
| 15 |
+
# distributed under the License is distributed on an "AS IS" BASIS,
|
| 16 |
+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
| 17 |
+
# See the License for the specific language governing permissions and
|
| 18 |
+
# limitations under the License.
|
| 19 |
+
"""PyTorch Mixtral model."""
|
| 20 |
+
|
| 21 |
+
import torch
|
| 22 |
+
import torch.nn.functional as F
|
| 23 |
+
from torch import nn
|
| 24 |
+
|
| 25 |
+
from ... import initialization as init
|
| 26 |
+
from ...activations import ACT2FN
|
| 27 |
+
from ...cache_utils import Cache, DynamicCache
|
| 28 |
+
from ...integrations import use_experts_implementation
|
| 29 |
+
from ...masking_utils import create_causal_mask, create_sliding_window_causal_mask
|
| 30 |
+
from ...modeling_layers import GradientCheckpointingLayer
|
| 31 |
+
from ...modeling_outputs import MoeCausalLMOutputWithPast, MoeModelOutputWithPast
|
| 32 |
+
from ...modeling_utils import PreTrainedModel
|
| 33 |
+
from ...processing_utils import Unpack
|
| 34 |
+
from ...utils import TransformersKwargs, logging
|
| 35 |
+
from ...utils.output_capturing import OutputRecorder
|
| 36 |
+
from ..mistral.modeling_mistral import (
|
| 37 |
+
MistralAttention,
|
| 38 |
+
MistralForCausalLM,
|
| 39 |
+
MistralForQuestionAnswering,
|
| 40 |
+
MistralForSequenceClassification,
|
| 41 |
+
MistralForTokenClassification,
|
| 42 |
+
MistralModel,
|
| 43 |
+
MistralPreTrainedModel,
|
| 44 |
+
MistralRMSNorm,
|
| 45 |
+
MistralRotaryEmbedding,
|
| 46 |
+
)
|
| 47 |
+
from .configuration_mixtral import MixtralConfig
|
| 48 |
+
|
| 49 |
+
|
| 50 |
+
logger = logging.get_logger(__name__)
|
| 51 |
+
|
| 52 |
+
|
| 53 |
+
def load_balancing_loss_func(
|
| 54 |
+
gate_logits: torch.Tensor | tuple[torch.Tensor] | None,
|
| 55 |
+
num_experts: int | None = None,
|
| 56 |
+
top_k=2,
|
| 57 |
+
attention_mask: torch.Tensor | None = None,
|
| 58 |
+
) -> torch.Tensor | int:
|
| 59 |
+
r"""
|
| 60 |
+
Computes auxiliary load balancing loss as in Switch Transformer - implemented in Pytorch.
|
| 61 |
+
|
| 62 |
+
See Switch Transformer (https://huggingface.co/papers/2101.03961) for more details. This function implements the loss
|
| 63 |
+
function presented in equations (4) - (6) of the paper. It aims at penalizing cases where the routing between
|
| 64 |
+
experts is too unbalanced.
|
| 65 |
+
|
| 66 |
+
Args:
|
| 67 |
+
gate_logits:
|
| 68 |
+
Logits from the `gate`, should be a tuple of model.config.num_hidden_layers tensors of
|
| 69 |
+
shape [batch_size X sequence_length, num_experts].
|
| 70 |
+
num_experts:
|
| 71 |
+
Number of experts
|
| 72 |
+
top_k:
|
| 73 |
+
The number of experts to route per-token, can be also interpreted as the `top-k` routing
|
| 74 |
+
parameter.
|
| 75 |
+
attention_mask (`torch.Tensor`, *optional*):
|
| 76 |
+
The attention_mask used in forward function
|
| 77 |
+
shape [batch_size X sequence_length] if not None.
|
| 78 |
+
|
| 79 |
+
Returns:
|
| 80 |
+
The auxiliary loss.
|
| 81 |
+
"""
|
| 82 |
+
if gate_logits is None or not isinstance(gate_logits, tuple):
|
| 83 |
+
return 0
|
| 84 |
+
|
| 85 |
+
if isinstance(gate_logits, tuple):
|
| 86 |
+
compute_device = gate_logits[0].device
|
| 87 |
+
concatenated_gate_logits = torch.cat([layer_gate.to(compute_device) for layer_gate in gate_logits], dim=0)
|
| 88 |
+
|
| 89 |
+
routing_weights = torch.nn.functional.softmax(concatenated_gate_logits, dim=-1)
|
| 90 |
+
|
| 91 |
+
_, selected_experts = torch.topk(routing_weights, top_k, dim=-1)
|
| 92 |
+
|
| 93 |
+
expert_mask = torch.nn.functional.one_hot(selected_experts, num_experts)
|
| 94 |
+
|
| 95 |
+
if attention_mask is None:
|
| 96 |
+
# Compute the percentage of tokens routed to each experts
|
| 97 |
+
tokens_per_expert = torch.mean(expert_mask.float(), dim=0)
|
| 98 |
+
|
| 99 |
+
# Compute the average probability of routing to these experts
|
| 100 |
+
router_prob_per_expert = torch.mean(routing_weights, dim=0)
|
| 101 |
+
else:
|
| 102 |
+
batch_size, sequence_length = attention_mask.shape
|
| 103 |
+
num_hidden_layers = concatenated_gate_logits.shape[0] // (batch_size * sequence_length)
|
| 104 |
+
|
| 105 |
+
# Compute the mask that masks all padding tokens as 0 with the same shape of expert_mask
|
| 106 |
+
expert_attention_mask = (
|
| 107 |
+
attention_mask[None, :, :, None, None]
|
| 108 |
+
.expand((num_hidden_layers, batch_size, sequence_length, top_k, num_experts))
|
| 109 |
+
.reshape(-1, top_k, num_experts)
|
| 110 |
+
.to(compute_device)
|
| 111 |
+
)
|
| 112 |
+
|
| 113 |
+
# Compute the percentage of tokens routed to each experts
|
| 114 |
+
tokens_per_expert = torch.sum(expert_mask.float() * expert_attention_mask, dim=0) / torch.sum(
|
| 115 |
+
expert_attention_mask, dim=0
|
| 116 |
+
)
|
| 117 |
+
|
| 118 |
+
# Compute the mask that masks all padding tokens as 0 with the same shape of tokens_per_expert
|
| 119 |
+
router_per_expert_attention_mask = (
|
| 120 |
+
attention_mask[None, :, :, None]
|
| 121 |
+
.expand((num_hidden_layers, batch_size, sequence_length, num_experts))
|
| 122 |
+
.reshape(-1, num_experts)
|
| 123 |
+
.to(compute_device)
|
| 124 |
+
)
|
| 125 |
+
|
| 126 |
+
# Compute the average probability of routing to these experts
|
| 127 |
+
router_prob_per_expert = torch.sum(routing_weights * router_per_expert_attention_mask, dim=0) / torch.sum(
|
| 128 |
+
router_per_expert_attention_mask, dim=0
|
| 129 |
+
)
|
| 130 |
+
|
| 131 |
+
overall_loss = torch.sum(tokens_per_expert * router_prob_per_expert.unsqueeze(0))
|
| 132 |
+
return overall_loss * num_experts
|
| 133 |
+
|
| 134 |
+
|
| 135 |
+
@use_experts_implementation
|
| 136 |
+
class MixtralExperts(nn.Module):
|
| 137 |
+
"""Collection of expert weights stored as 3D tensors."""
|
| 138 |
+
|
| 139 |
+
def __init__(self, config: MixtralConfig):
|
| 140 |
+
super().__init__()
|
| 141 |
+
self.num_experts = config.num_local_experts
|
| 142 |
+
self.hidden_dim = config.hidden_size
|
| 143 |
+
self.intermediate_dim = config.intermediate_size
|
| 144 |
+
self.gate_up_proj = nn.Parameter(torch.empty(self.num_experts, 2 * self.intermediate_dim, self.hidden_dim))
|
| 145 |
+
self.down_proj = nn.Parameter(torch.empty(self.num_experts, self.hidden_dim, self.intermediate_dim))
|
| 146 |
+
self.act_fn = ACT2FN[config.hidden_act]
|
| 147 |
+
|
| 148 |
+
def forward(
|
| 149 |
+
self,
|
| 150 |
+
hidden_states: torch.Tensor,
|
| 151 |
+
top_k_index: torch.Tensor,
|
| 152 |
+
top_k_weights: torch.Tensor,
|
| 153 |
+
) -> torch.Tensor:
|
| 154 |
+
final_hidden_states = torch.zeros_like(hidden_states)
|
| 155 |
+
with torch.no_grad():
|
| 156 |
+
expert_mask = torch.nn.functional.one_hot(top_k_index, num_classes=self.num_experts)
|
| 157 |
+
expert_mask = expert_mask.permute(2, 1, 0)
|
| 158 |
+
expert_hit = torch.greater(expert_mask.sum(dim=(-1, -2)), 0).nonzero()
|
| 159 |
+
|
| 160 |
+
for expert_idx in expert_hit:
|
| 161 |
+
expert_idx = expert_idx[0]
|
| 162 |
+
if expert_idx == self.num_experts:
|
| 163 |
+
continue
|
| 164 |
+
top_k_pos, token_idx = torch.where(expert_mask[expert_idx])
|
| 165 |
+
current_state = hidden_states[token_idx]
|
| 166 |
+
gate, up = nn.functional.linear(current_state, self.gate_up_proj[expert_idx]).chunk(2, dim=-1)
|
| 167 |
+
current_hidden_states = self.act_fn(gate) * up
|
| 168 |
+
current_hidden_states = nn.functional.linear(current_hidden_states, self.down_proj[expert_idx])
|
| 169 |
+
current_hidden_states = current_hidden_states * top_k_weights[token_idx, top_k_pos, None]
|
| 170 |
+
final_hidden_states.index_add_(0, token_idx, current_hidden_states.to(final_hidden_states.dtype))
|
| 171 |
+
|
| 172 |
+
return final_hidden_states
|
| 173 |
+
|
| 174 |
+
|
| 175 |
+
class MixtralTopKRouter(nn.Module):
|
| 176 |
+
def __init__(self, config):
|
| 177 |
+
super().__init__()
|
| 178 |
+
self.top_k = config.num_experts_per_tok
|
| 179 |
+
self.num_experts = config.num_local_experts
|
| 180 |
+
self.hidden_dim = config.hidden_size
|
| 181 |
+
self.weight = nn.Parameter(torch.empty(self.num_experts, self.hidden_dim))
|
| 182 |
+
|
| 183 |
+
def forward(self, hidden_states):
|
| 184 |
+
hidden_states = hidden_states.reshape(-1, self.hidden_dim)
|
| 185 |
+
router_logits = F.linear(hidden_states, self.weight) # (seq_len, num_experts)
|
| 186 |
+
router_logits = torch.nn.functional.softmax(router_logits.float(), dim=-1)
|
| 187 |
+
router_top_value, router_indices = torch.topk(router_logits, self.top_k, dim=-1) # (seq_len, top_k)
|
| 188 |
+
router_top_value /= router_top_value.sum(dim=-1, keepdim=True)
|
| 189 |
+
router_scores = router_top_value
|
| 190 |
+
return router_logits, router_scores, router_indices
|
| 191 |
+
|
| 192 |
+
|
| 193 |
+
class MixtralSparseMoeBlock(nn.Module):
|
| 194 |
+
def __init__(self, config):
|
| 195 |
+
super().__init__()
|
| 196 |
+
self.top_k = config.num_experts_per_tok
|
| 197 |
+
self.jitter_noise = config.router_jitter_noise
|
| 198 |
+
self.gate = MixtralTopKRouter(config)
|
| 199 |
+
self.experts = MixtralExperts(config)
|
| 200 |
+
|
| 201 |
+
def forward(self, hidden_states: torch.Tensor) -> tuple[torch.Tensor, torch.Tensor]:
|
| 202 |
+
batch_size, sequence_length, hidden_dim = hidden_states.shape
|
| 203 |
+
if self.training and self.jitter_noise > 0:
|
| 204 |
+
hidden_states *= torch.empty_like(hidden_states).uniform_(1.0 - self.jitter_noise, 1.0 + self.jitter_noise)
|
| 205 |
+
hidden_states = hidden_states.view(-1, hidden_states.shape[-1])
|
| 206 |
+
_, top_k_weights, top_k_index = self.gate(hidden_states)
|
| 207 |
+
hidden_states = self.experts(hidden_states, top_k_index, top_k_weights)
|
| 208 |
+
hidden_states = hidden_states.reshape(batch_size, sequence_length, hidden_dim)
|
| 209 |
+
return hidden_states
|
| 210 |
+
|
| 211 |
+
|
| 212 |
+
class MixtralRMSNorm(MistralRMSNorm):
|
| 213 |
+
pass
|
| 214 |
+
|
| 215 |
+
|
| 216 |
+
class MixtralRotaryEmbedding(MistralRotaryEmbedding):
|
| 217 |
+
pass
|
| 218 |
+
|
| 219 |
+
|
| 220 |
+
class MixtralAttention(MistralAttention):
|
| 221 |
+
pass
|
| 222 |
+
|
| 223 |
+
|
| 224 |
+
class MixtralDecoderLayer(GradientCheckpointingLayer):
|
| 225 |
+
def __init__(self, config: MixtralConfig, layer_idx: int):
|
| 226 |
+
super().__init__()
|
| 227 |
+
self.hidden_size = config.hidden_size
|
| 228 |
+
|
| 229 |
+
self.self_attn = MixtralAttention(config, layer_idx)
|
| 230 |
+
|
| 231 |
+
self.mlp = MixtralSparseMoeBlock(config)
|
| 232 |
+
self.input_layernorm = MixtralRMSNorm(config.hidden_size, eps=config.rms_norm_eps)
|
| 233 |
+
self.post_attention_layernorm = MixtralRMSNorm(config.hidden_size, eps=config.rms_norm_eps)
|
| 234 |
+
|
| 235 |
+
def forward(
|
| 236 |
+
self,
|
| 237 |
+
hidden_states: torch.Tensor,
|
| 238 |
+
position_embeddings: tuple[torch.Tensor, torch.Tensor] | None = None,
|
| 239 |
+
attention_mask: torch.Tensor | None = None,
|
| 240 |
+
position_ids: torch.LongTensor | None = None,
|
| 241 |
+
past_key_values: Cache | None = None,
|
| 242 |
+
**kwargs: Unpack[TransformersKwargs],
|
| 243 |
+
) -> torch.Tensor:
|
| 244 |
+
residual = hidden_states
|
| 245 |
+
hidden_states = self.input_layernorm(hidden_states)
|
| 246 |
+
hidden_states, _ = self.self_attn(
|
| 247 |
+
hidden_states=hidden_states,
|
| 248 |
+
position_embeddings=position_embeddings,
|
| 249 |
+
attention_mask=attention_mask,
|
| 250 |
+
position_ids=position_ids,
|
| 251 |
+
past_key_values=past_key_values,
|
| 252 |
+
**kwargs,
|
| 253 |
+
)
|
| 254 |
+
hidden_states = residual + hidden_states
|
| 255 |
+
residual = hidden_states
|
| 256 |
+
hidden_states = self.post_attention_layernorm(hidden_states)
|
| 257 |
+
hidden_states = self.mlp(hidden_states)
|
| 258 |
+
hidden_states = residual + hidden_states
|
| 259 |
+
return hidden_states
|
| 260 |
+
|
| 261 |
+
|
| 262 |
+
class MixtralPreTrainedModel(MistralPreTrainedModel):
|
| 263 |
+
_can_record_outputs = {
|
| 264 |
+
"router_logits": OutputRecorder(MixtralTopKRouter, index=0),
|
| 265 |
+
"hidden_states": MixtralDecoderLayer,
|
| 266 |
+
"attentions": MixtralAttention,
|
| 267 |
+
}
|
| 268 |
+
|
| 269 |
+
@torch.no_grad()
|
| 270 |
+
def _init_weights(self, module):
|
| 271 |
+
PreTrainedModel._init_weights(self, module)
|
| 272 |
+
std = self.config.initializer_range
|
| 273 |
+
if isinstance(module, MixtralExperts):
|
| 274 |
+
init.normal_(module.gate_up_proj, mean=0.0, std=std)
|
| 275 |
+
init.normal_(module.down_proj, mean=0.0, std=std)
|
| 276 |
+
elif isinstance(module, MixtralTopKRouter):
|
| 277 |
+
init.normal_(module.weight, mean=0.0, std=std)
|
| 278 |
+
|
| 279 |
+
|
| 280 |
+
class MixtralModel(MistralModel):
|
| 281 |
+
def forward(
|
| 282 |
+
self,
|
| 283 |
+
input_ids: torch.LongTensor | None = None,
|
| 284 |
+
attention_mask: torch.Tensor | None = None,
|
| 285 |
+
position_ids: torch.LongTensor | None = None,
|
| 286 |
+
past_key_values: Cache | None = None,
|
| 287 |
+
inputs_embeds: torch.FloatTensor | None = None,
|
| 288 |
+
use_cache: bool | None = None,
|
| 289 |
+
**kwargs: Unpack[TransformersKwargs],
|
| 290 |
+
) -> MoeModelOutputWithPast:
|
| 291 |
+
if (input_ids is None) ^ (inputs_embeds is not None):
|
| 292 |
+
raise ValueError("You must specify exactly one of input_ids or inputs_embeds")
|
| 293 |
+
|
| 294 |
+
if use_cache and past_key_values is None:
|
| 295 |
+
past_key_values = DynamicCache(config=self.config)
|
| 296 |
+
|
| 297 |
+
if inputs_embeds is None:
|
| 298 |
+
inputs_embeds = self.embed_tokens(input_ids)
|
| 299 |
+
|
| 300 |
+
if position_ids is None:
|
| 301 |
+
past_seen_tokens = past_key_values.get_seq_length() if past_key_values is not None else 0
|
| 302 |
+
position_ids = torch.arange(inputs_embeds.shape[1], device=inputs_embeds.device) + past_seen_tokens
|
| 303 |
+
position_ids = position_ids.unsqueeze(0)
|
| 304 |
+
|
| 305 |
+
mask_function = create_causal_mask if self.config.sliding_window is None else create_sliding_window_causal_mask
|
| 306 |
+
causal_mask = mask_function(
|
| 307 |
+
config=self.config,
|
| 308 |
+
inputs_embeds=inputs_embeds,
|
| 309 |
+
attention_mask=attention_mask,
|
| 310 |
+
past_key_values=past_key_values,
|
| 311 |
+
position_ids=position_ids,
|
| 312 |
+
)
|
| 313 |
+
|
| 314 |
+
hidden_states = inputs_embeds
|
| 315 |
+
position_embeddings = self.rotary_emb(hidden_states, position_ids=position_ids)
|
| 316 |
+
|
| 317 |
+
for decoder_layer in self.layers[: self.config.num_hidden_layers]:
|
| 318 |
+
hidden_states = decoder_layer(
|
| 319 |
+
hidden_states,
|
| 320 |
+
attention_mask=causal_mask,
|
| 321 |
+
position_ids=position_ids,
|
| 322 |
+
past_key_values=past_key_values,
|
| 323 |
+
use_cache=use_cache,
|
| 324 |
+
position_embeddings=position_embeddings,
|
| 325 |
+
**kwargs,
|
| 326 |
+
)
|
| 327 |
+
|
| 328 |
+
hidden_states = self.norm(hidden_states)
|
| 329 |
+
|
| 330 |
+
return MoeModelOutputWithPast( # only diff with Mistral is the output type, we need MoE
|
| 331 |
+
last_hidden_state=hidden_states,
|
| 332 |
+
past_key_values=past_key_values,
|
| 333 |
+
)
|
| 334 |
+
|
| 335 |
+
|
| 336 |
+
class MixtralForCausalLM(MistralForCausalLM):
|
| 337 |
+
_tied_weights_keys = {"lm_head.weight": "model.embed_tokens.weight"}
|
| 338 |
+
|
| 339 |
+
def __init__(self, config):
|
| 340 |
+
super().__init__(config)
|
| 341 |
+
self.model = MixtralModel(config)
|
| 342 |
+
self.router_aux_loss_coef = config.router_aux_loss_coef
|
| 343 |
+
self.num_experts = config.num_local_experts
|
| 344 |
+
self.num_experts_per_tok = config.num_experts_per_tok
|
| 345 |
+
|
| 346 |
+
def forward(
|
| 347 |
+
self,
|
| 348 |
+
input_ids: torch.LongTensor | None = None,
|
| 349 |
+
attention_mask: torch.Tensor | None = None,
|
| 350 |
+
position_ids: torch.LongTensor | None = None,
|
| 351 |
+
past_key_values: Cache | None = None,
|
| 352 |
+
inputs_embeds: torch.FloatTensor | None = None,
|
| 353 |
+
labels: torch.LongTensor | None = None,
|
| 354 |
+
use_cache: bool | None = None,
|
| 355 |
+
output_router_logits: bool | None = None,
|
| 356 |
+
logits_to_keep: int | torch.Tensor = 0,
|
| 357 |
+
**kwargs: Unpack[TransformersKwargs],
|
| 358 |
+
) -> MoeCausalLMOutputWithPast:
|
| 359 |
+
r"""
|
| 360 |
+
labels (`torch.LongTensor` of shape `(batch_size, sequence_length)`, *optional*):
|
| 361 |
+
Labels for computing the masked language modeling loss. Indices should either be in `[0, ...,
|
| 362 |
+
config.vocab_size]` or -100 (see `input_ids` docstring). Tokens with indices set to `-100` are ignored
|
| 363 |
+
(masked), the loss is only computed for the tokens with labels in `[0, ..., config.vocab_size]`.
|
| 364 |
+
|
| 365 |
+
Example:
|
| 366 |
+
|
| 367 |
+
```python
|
| 368 |
+
>>> from transformers import AutoTokenizer, MixtralForCausalLM
|
| 369 |
+
|
| 370 |
+
>>> model = MixtralForCausalLM.from_pretrained("mistralai/Mixtral-8x7B-v0.1")
|
| 371 |
+
>>> tokenizer = AutoTokenizer.from_pretrained("mistralai/Mixtral-8x7B-v0.1")
|
| 372 |
+
|
| 373 |
+
>>> prompt = "Hey, are you conscious? Can you talk to me?"
|
| 374 |
+
>>> inputs = tokenizer(prompt, return_tensors="pt")
|
| 375 |
+
|
| 376 |
+
>>> # Generate
|
| 377 |
+
>>> generate_ids = model.generate(inputs.input_ids, max_length=30)
|
| 378 |
+
>>> tokenizer.batch_decode(generate_ids, skip_special_tokens=True, clean_up_tokenization_spaces=False)[0]
|
| 379 |
+
"Hey, are you conscious? Can you talk to me?\nI'm not conscious, but I can talk to you."
|
| 380 |
+
```"""
|
| 381 |
+
|
| 382 |
+
output_router_logits = (
|
| 383 |
+
output_router_logits if output_router_logits is not None else self.config.output_router_logits
|
| 384 |
+
)
|
| 385 |
+
|
| 386 |
+
# decoder outputs consists of (dec_features, layer_state, dec_hidden, dec_attn)
|
| 387 |
+
outputs: MoeModelOutputWithPast = self.model(
|
| 388 |
+
input_ids=input_ids,
|
| 389 |
+
attention_mask=attention_mask,
|
| 390 |
+
position_ids=position_ids,
|
| 391 |
+
past_key_values=past_key_values,
|
| 392 |
+
inputs_embeds=inputs_embeds,
|
| 393 |
+
use_cache=use_cache,
|
| 394 |
+
output_router_logits=output_router_logits,
|
| 395 |
+
**kwargs,
|
| 396 |
+
)
|
| 397 |
+
|
| 398 |
+
hidden_states = outputs.last_hidden_state
|
| 399 |
+
# Only compute necessary logits, and do not upcast them to float if we are not computing the loss
|
| 400 |
+
slice_indices = slice(-logits_to_keep, None) if isinstance(logits_to_keep, int) else logits_to_keep
|
| 401 |
+
logits = self.lm_head(hidden_states[:, slice_indices, :])
|
| 402 |
+
|
| 403 |
+
loss = None
|
| 404 |
+
if labels is not None:
|
| 405 |
+
loss = self.loss_function(logits, labels, self.vocab_size, **kwargs)
|
| 406 |
+
|
| 407 |
+
aux_loss = None
|
| 408 |
+
if output_router_logits:
|
| 409 |
+
aux_loss = load_balancing_loss_func(
|
| 410 |
+
outputs.router_logits,
|
| 411 |
+
self.num_experts,
|
| 412 |
+
self.num_experts_per_tok,
|
| 413 |
+
attention_mask,
|
| 414 |
+
)
|
| 415 |
+
if labels is not None:
|
| 416 |
+
loss += self.router_aux_loss_coef * aux_loss.to(loss.device) # make sure to reside in the same device
|
| 417 |
+
|
| 418 |
+
return MoeCausalLMOutputWithPast(
|
| 419 |
+
loss=loss,
|
| 420 |
+
aux_loss=aux_loss,
|
| 421 |
+
logits=logits,
|
| 422 |
+
past_key_values=outputs.past_key_values,
|
| 423 |
+
hidden_states=outputs.hidden_states,
|
| 424 |
+
attentions=outputs.attentions,
|
| 425 |
+
router_logits=outputs.router_logits,
|
| 426 |
+
)
|
| 427 |
+
|
| 428 |
+
|
| 429 |
+
class MixtralForSequenceClassification(MistralForSequenceClassification):
|
| 430 |
+
pass
|
| 431 |
+
|
| 432 |
+
|
| 433 |
+
class MixtralForTokenClassification(MistralForTokenClassification):
|
| 434 |
+
pass
|
| 435 |
+
|
| 436 |
+
|
| 437 |
+
class MixtralForQuestionAnswering(MistralForQuestionAnswering):
|
| 438 |
+
pass
|
| 439 |
+
|
| 440 |
+
|
| 441 |
+
__all__ = [
|
| 442 |
+
"MixtralForCausalLM",
|
| 443 |
+
"MixtralForQuestionAnswering",
|
| 444 |
+
"MixtralModel",
|
| 445 |
+
"MixtralPreTrainedModel",
|
| 446 |
+
"MixtralForSequenceClassification",
|
| 447 |
+
"MixtralForTokenClassification",
|
| 448 |
+
]
|
third_party/transformers/src/transformers/models/mra/__init__.py
ADDED
|
@@ -0,0 +1,27 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
# Copyright 2024 The HuggingFace Team. All rights reserved.
|
| 2 |
+
#
|
| 3 |
+
# Licensed under the Apache License, Version 2.0 (the "License");
|
| 4 |
+
# you may not use this file except in compliance with the License.
|
| 5 |
+
# You may obtain a copy of the License at
|
| 6 |
+
#
|
| 7 |
+
# http://www.apache.org/licenses/LICENSE-2.0
|
| 8 |
+
#
|
| 9 |
+
# Unless required by applicable law or agreed to in writing, software
|
| 10 |
+
# distributed under the License is distributed on an "AS IS" BASIS,
|
| 11 |
+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
| 12 |
+
# See the License for the specific language governing permissions and
|
| 13 |
+
# limitations under the License.
|
| 14 |
+
from typing import TYPE_CHECKING
|
| 15 |
+
|
| 16 |
+
from ...utils import _LazyModule
|
| 17 |
+
from ...utils.import_utils import define_import_structure
|
| 18 |
+
|
| 19 |
+
|
| 20 |
+
if TYPE_CHECKING:
|
| 21 |
+
from .configuration_mra import *
|
| 22 |
+
from .modeling_mra import *
|
| 23 |
+
else:
|
| 24 |
+
import sys
|
| 25 |
+
|
| 26 |
+
_file = globals()["__file__"]
|
| 27 |
+
sys.modules[__name__] = _LazyModule(__name__, _file, define_import_structure(_file), module_spec=__spec__)
|
third_party/transformers/src/transformers/models/mra/configuration_mra.py
ADDED
|
@@ -0,0 +1,76 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
# Copyright 2023 The HuggingFace Inc. team. All rights reserved.
|
| 2 |
+
#
|
| 3 |
+
# Licensed under the Apache License, Version 2.0 (the "License");
|
| 4 |
+
# you may not use this file except in compliance with the License.
|
| 5 |
+
# You may obtain a copy of the License at
|
| 6 |
+
#
|
| 7 |
+
# http://www.apache.org/licenses/LICENSE-2.0
|
| 8 |
+
#
|
| 9 |
+
# Unless required by applicable law or agreed to in writing, software
|
| 10 |
+
# distributed under the License is distributed on an "AS IS" BASIS,
|
| 11 |
+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
| 12 |
+
# See the License for the specific language governing permissions and
|
| 13 |
+
# limitations under the License.
|
| 14 |
+
"""MRA model configuration"""
|
| 15 |
+
|
| 16 |
+
from huggingface_hub.dataclasses import strict
|
| 17 |
+
|
| 18 |
+
from ...configuration_utils import PreTrainedConfig
|
| 19 |
+
from ...utils import auto_docstring
|
| 20 |
+
|
| 21 |
+
|
| 22 |
+
@auto_docstring(checkpoint="uw-madison/mra-base-512-4")
|
| 23 |
+
@strict
|
| 24 |
+
class MraConfig(PreTrainedConfig):
|
| 25 |
+
r"""
|
| 26 |
+
block_per_row (`int`, *optional*, defaults to 4):
|
| 27 |
+
Used to set the budget for the high resolution scale.
|
| 28 |
+
approx_mode (`str`, *optional*, defaults to `"full"`):
|
| 29 |
+
Controls whether both low and high resolution approximations are used. Set to `"full"` for both low and
|
| 30 |
+
high resolution and `"sparse"` for only low resolution.
|
| 31 |
+
initial_prior_first_n_blocks (`int`, *optional*, defaults to 0):
|
| 32 |
+
The initial number of blocks for which high resolution is used.
|
| 33 |
+
initial_prior_diagonal_n_blocks (`int`, *optional*, defaults to 0):
|
| 34 |
+
The number of diagonal blocks for which high resolution is used.
|
| 35 |
+
|
| 36 |
+
Example:
|
| 37 |
+
|
| 38 |
+
```python
|
| 39 |
+
>>> from transformers import MraConfig, MraModel
|
| 40 |
+
|
| 41 |
+
>>> # Initializing a Mra uw-madison/mra-base-512-4 style configuration
|
| 42 |
+
>>> configuration = MraConfig()
|
| 43 |
+
|
| 44 |
+
>>> # Initializing a model (with random weights) from the uw-madison/mra-base-512-4 style configuration
|
| 45 |
+
>>> model = MraModel(configuration)
|
| 46 |
+
|
| 47 |
+
>>> # Accessing the model configuration
|
| 48 |
+
>>> configuration = model.config
|
| 49 |
+
```"""
|
| 50 |
+
|
| 51 |
+
model_type = "mra"
|
| 52 |
+
|
| 53 |
+
vocab_size: int = 50265
|
| 54 |
+
hidden_size: int = 768
|
| 55 |
+
num_hidden_layers: int = 12
|
| 56 |
+
num_attention_heads: int = 12
|
| 57 |
+
intermediate_size: int = 3072
|
| 58 |
+
hidden_act: str = "gelu"
|
| 59 |
+
hidden_dropout_prob: float | int = 0.1
|
| 60 |
+
attention_probs_dropout_prob: float | int = 0.1
|
| 61 |
+
max_position_embeddings: int = 512
|
| 62 |
+
type_vocab_size: int = 1
|
| 63 |
+
initializer_range: float = 0.02
|
| 64 |
+
layer_norm_eps: float = 1e-5
|
| 65 |
+
block_per_row: int = 4
|
| 66 |
+
approx_mode: str = "full"
|
| 67 |
+
initial_prior_first_n_blocks: int = 0
|
| 68 |
+
initial_prior_diagonal_n_blocks: int = 0
|
| 69 |
+
pad_token_id: int | None = 1
|
| 70 |
+
bos_token_id: int | None = 0
|
| 71 |
+
eos_token_id: int | list[int] | None = 2
|
| 72 |
+
add_cross_attention: bool = False
|
| 73 |
+
tie_word_embeddings: bool = True
|
| 74 |
+
|
| 75 |
+
|
| 76 |
+
__all__ = ["MraConfig"]
|
third_party/transformers/src/transformers/models/mra/convert_mra_pytorch_to_pytorch.py
ADDED
|
@@ -0,0 +1,109 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
# Copyright 2023 The HuggingFace Inc. team.
|
| 2 |
+
#
|
| 3 |
+
# Licensed under the Apache License, Version 2.0 (the "License");
|
| 4 |
+
# you may not use this file except in compliance with the License.
|
| 5 |
+
# You may obtain a copy of the License at
|
| 6 |
+
#
|
| 7 |
+
# http://www.apache.org/licenses/LICENSE-2.0
|
| 8 |
+
#
|
| 9 |
+
# Unless required by applicable law or agreed to in writing, software
|
| 10 |
+
# distributed under the License is distributed on an "AS IS" BASIS,
|
| 11 |
+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
| 12 |
+
# See the License for the specific language governing permissions and
|
| 13 |
+
# limitations under the License.
|
| 14 |
+
"""Convert MRA checkpoints from the original repository. URL: https://github.com/mlpen/mra-attention"""
|
| 15 |
+
|
| 16 |
+
import argparse
|
| 17 |
+
|
| 18 |
+
import torch
|
| 19 |
+
|
| 20 |
+
from transformers import MraConfig, MraForMaskedLM
|
| 21 |
+
|
| 22 |
+
|
| 23 |
+
def rename_key(orig_key):
|
| 24 |
+
if "model" in orig_key:
|
| 25 |
+
orig_key = orig_key.replace("model.", "")
|
| 26 |
+
if "norm1" in orig_key:
|
| 27 |
+
orig_key = orig_key.replace("norm1", "attention.output.LayerNorm")
|
| 28 |
+
if "norm2" in orig_key:
|
| 29 |
+
orig_key = orig_key.replace("norm2", "output.LayerNorm")
|
| 30 |
+
if "norm" in orig_key:
|
| 31 |
+
orig_key = orig_key.replace("norm", "LayerNorm")
|
| 32 |
+
if "transformer" in orig_key:
|
| 33 |
+
layer_num = orig_key.split(".")[0].split("_")[-1]
|
| 34 |
+
orig_key = orig_key.replace(f"transformer_{layer_num}", f"encoder.layer.{layer_num}")
|
| 35 |
+
if "mha.attn" in orig_key:
|
| 36 |
+
orig_key = orig_key.replace("mha.attn", "attention.self")
|
| 37 |
+
if "mha" in orig_key:
|
| 38 |
+
orig_key = orig_key.replace("mha", "attention")
|
| 39 |
+
if "W_q" in orig_key:
|
| 40 |
+
orig_key = orig_key.replace("W_q", "self.query")
|
| 41 |
+
if "W_k" in orig_key:
|
| 42 |
+
orig_key = orig_key.replace("W_k", "self.key")
|
| 43 |
+
if "W_v" in orig_key:
|
| 44 |
+
orig_key = orig_key.replace("W_v", "self.value")
|
| 45 |
+
if "ff.0" in orig_key:
|
| 46 |
+
orig_key = orig_key.replace("ff.0", "intermediate.dense")
|
| 47 |
+
if "ff.2" in orig_key:
|
| 48 |
+
orig_key = orig_key.replace("ff.2", "output.dense")
|
| 49 |
+
if "ff" in orig_key:
|
| 50 |
+
orig_key = orig_key.replace("ff", "output.dense")
|
| 51 |
+
if "mlm_class" in orig_key:
|
| 52 |
+
orig_key = orig_key.replace("mlm.mlm_class", "cls.predictions.decoder")
|
| 53 |
+
if "mlm" in orig_key:
|
| 54 |
+
orig_key = orig_key.replace("mlm", "cls.predictions.transform")
|
| 55 |
+
if "backbone.backbone.encoders" in orig_key:
|
| 56 |
+
orig_key = orig_key.replace("backbone.backbone.encoders", "encoder.layer")
|
| 57 |
+
if "cls" not in orig_key:
|
| 58 |
+
orig_key = "mra." + orig_key
|
| 59 |
+
|
| 60 |
+
return orig_key
|
| 61 |
+
|
| 62 |
+
|
| 63 |
+
def convert_checkpoint_helper(max_position_embeddings, orig_state_dict):
|
| 64 |
+
for key in orig_state_dict.copy():
|
| 65 |
+
val = orig_state_dict.pop(key)
|
| 66 |
+
|
| 67 |
+
if ("pooler" in key) or ("sen_class" in key):
|
| 68 |
+
continue
|
| 69 |
+
else:
|
| 70 |
+
orig_state_dict[rename_key(key)] = val
|
| 71 |
+
|
| 72 |
+
orig_state_dict["cls.predictions.bias"] = orig_state_dict["cls.predictions.decoder.bias"]
|
| 73 |
+
orig_state_dict["mra.embeddings.position_ids"] = torch.arange(max_position_embeddings).expand((1, -1)) + 2
|
| 74 |
+
|
| 75 |
+
return orig_state_dict
|
| 76 |
+
|
| 77 |
+
|
| 78 |
+
def convert_mra_checkpoint(checkpoint_path, mra_config_file, pytorch_dump_path):
|
| 79 |
+
orig_state_dict = torch.load(checkpoint_path, map_location="cpu", weights_only=True)["model_state_dict"]
|
| 80 |
+
config = MraConfig.from_json_file(mra_config_file)
|
| 81 |
+
model = MraForMaskedLM(config)
|
| 82 |
+
|
| 83 |
+
new_state_dict = convert_checkpoint_helper(config.max_position_embeddings, orig_state_dict)
|
| 84 |
+
|
| 85 |
+
print(model.load_state_dict(new_state_dict))
|
| 86 |
+
model.eval()
|
| 87 |
+
model.save_pretrained(pytorch_dump_path)
|
| 88 |
+
|
| 89 |
+
print(f"Checkpoint successfully converted. Model saved at {pytorch_dump_path}")
|
| 90 |
+
|
| 91 |
+
|
| 92 |
+
if __name__ == "__main__":
|
| 93 |
+
parser = argparse.ArgumentParser()
|
| 94 |
+
# Required parameters
|
| 95 |
+
parser.add_argument(
|
| 96 |
+
"--pytorch_model_path", default=None, type=str, required=True, help="Path to Mra pytorch checkpoint."
|
| 97 |
+
)
|
| 98 |
+
parser.add_argument(
|
| 99 |
+
"--config_file",
|
| 100 |
+
default=None,
|
| 101 |
+
type=str,
|
| 102 |
+
required=True,
|
| 103 |
+
help="The json file for Mra model config.",
|
| 104 |
+
)
|
| 105 |
+
parser.add_argument(
|
| 106 |
+
"--pytorch_dump_path", default=None, type=str, required=True, help="Path to the output PyTorch model."
|
| 107 |
+
)
|
| 108 |
+
args = parser.parse_args()
|
| 109 |
+
convert_mra_checkpoint(args.pytorch_model_path, args.config_file, args.pytorch_dump_path)
|
third_party/transformers/src/transformers/models/mra/modeling_mra.py
ADDED
|
@@ -0,0 +1,1332 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
# Copyright 2023 University of Wisconsin-Madison and The HuggingFace Inc. team. All rights reserved.
|
| 2 |
+
#
|
| 3 |
+
# Licensed under the Apache License, Version 2.0 (the "License");
|
| 4 |
+
# you may not use this file except in compliance with the License.
|
| 5 |
+
# You may obtain a copy of the License at
|
| 6 |
+
#
|
| 7 |
+
# http://www.apache.org/licenses/LICENSE-2.0
|
| 8 |
+
#
|
| 9 |
+
# Unless required by applicable law or agreed to in writing, software
|
| 10 |
+
# distributed under the License is distributed on an "AS IS" BASIS,
|
| 11 |
+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
| 12 |
+
# See the License for the specific language governing permissions and
|
| 13 |
+
# limitations under the License.
|
| 14 |
+
"""PyTorch MRA model."""
|
| 15 |
+
|
| 16 |
+
import math
|
| 17 |
+
|
| 18 |
+
import torch
|
| 19 |
+
from torch import nn
|
| 20 |
+
from torch.nn import BCEWithLogitsLoss, CrossEntropyLoss, MSELoss
|
| 21 |
+
|
| 22 |
+
from ... import initialization as init
|
| 23 |
+
from ...activations import ACT2FN
|
| 24 |
+
from ...modeling_layers import GradientCheckpointingLayer
|
| 25 |
+
from ...modeling_outputs import (
|
| 26 |
+
BaseModelOutputWithCrossAttentions,
|
| 27 |
+
MaskedLMOutput,
|
| 28 |
+
MultipleChoiceModelOutput,
|
| 29 |
+
QuestionAnsweringModelOutput,
|
| 30 |
+
SequenceClassifierOutput,
|
| 31 |
+
TokenClassifierOutput,
|
| 32 |
+
)
|
| 33 |
+
from ...modeling_utils import PreTrainedModel
|
| 34 |
+
from ...pytorch_utils import apply_chunking_to_forward
|
| 35 |
+
from ...utils import (
|
| 36 |
+
auto_docstring,
|
| 37 |
+
is_cuda_platform,
|
| 38 |
+
is_kernels_available,
|
| 39 |
+
is_ninja_available,
|
| 40 |
+
is_torch_cuda_available,
|
| 41 |
+
logging,
|
| 42 |
+
)
|
| 43 |
+
from .configuration_mra import MraConfig
|
| 44 |
+
|
| 45 |
+
|
| 46 |
+
logger = logging.get_logger(__name__)
|
| 47 |
+
|
| 48 |
+
mra_cuda_kernel = None
|
| 49 |
+
|
| 50 |
+
|
| 51 |
+
def load_cuda_kernels():
|
| 52 |
+
global mra_cuda_kernel
|
| 53 |
+
if not is_kernels_available():
|
| 54 |
+
raise ImportError("kernels is not installed, please install it with `pip install kernels`")
|
| 55 |
+
from ...integrations.hub_kernels import get_kernel
|
| 56 |
+
|
| 57 |
+
mra_cuda_kernel = get_kernel("kernels-community/mra")
|
| 58 |
+
|
| 59 |
+
|
| 60 |
+
def sparse_max(sparse_qk_prod, indices, query_num_block, key_num_block):
|
| 61 |
+
"""
|
| 62 |
+
Computes maximum values for softmax stability.
|
| 63 |
+
"""
|
| 64 |
+
if len(sparse_qk_prod.size()) != 4:
|
| 65 |
+
raise ValueError("sparse_qk_prod must be a 4-dimensional tensor.")
|
| 66 |
+
|
| 67 |
+
if len(indices.size()) != 2:
|
| 68 |
+
raise ValueError("indices must be a 2-dimensional tensor.")
|
| 69 |
+
|
| 70 |
+
if sparse_qk_prod.size(2) != 32:
|
| 71 |
+
raise ValueError("The size of the second dimension of sparse_qk_prod must be 32.")
|
| 72 |
+
|
| 73 |
+
if sparse_qk_prod.size(3) != 32:
|
| 74 |
+
raise ValueError("The size of the third dimension of sparse_qk_prod must be 32.")
|
| 75 |
+
|
| 76 |
+
index_vals = sparse_qk_prod.max(dim=-2).values.transpose(-1, -2)
|
| 77 |
+
index_vals = index_vals.contiguous()
|
| 78 |
+
|
| 79 |
+
indices = indices.int()
|
| 80 |
+
indices = indices.contiguous()
|
| 81 |
+
|
| 82 |
+
max_vals, max_vals_scatter = mra_cuda_kernel.index_max(index_vals, indices, query_num_block, key_num_block)
|
| 83 |
+
max_vals_scatter = max_vals_scatter.transpose(-1, -2)[:, :, None, :]
|
| 84 |
+
|
| 85 |
+
return max_vals, max_vals_scatter
|
| 86 |
+
|
| 87 |
+
|
| 88 |
+
def sparse_mask(mask, indices, block_size=32):
|
| 89 |
+
"""
|
| 90 |
+
Converts attention mask to a sparse mask for high resolution logits.
|
| 91 |
+
"""
|
| 92 |
+
if len(mask.size()) != 2:
|
| 93 |
+
raise ValueError("mask must be a 2-dimensional tensor.")
|
| 94 |
+
|
| 95 |
+
if len(indices.size()) != 2:
|
| 96 |
+
raise ValueError("indices must be a 2-dimensional tensor.")
|
| 97 |
+
|
| 98 |
+
if mask.shape[0] != indices.shape[0]:
|
| 99 |
+
raise ValueError("mask and indices must have the same size in the zero-th dimension.")
|
| 100 |
+
|
| 101 |
+
batch_size, seq_len = mask.shape
|
| 102 |
+
num_block = seq_len // block_size
|
| 103 |
+
|
| 104 |
+
batch_idx = torch.arange(indices.size(0), dtype=torch.long, device=indices.device)
|
| 105 |
+
mask = mask.reshape(batch_size, num_block, block_size)
|
| 106 |
+
mask = mask[batch_idx[:, None], (indices % num_block).long(), :]
|
| 107 |
+
|
| 108 |
+
return mask
|
| 109 |
+
|
| 110 |
+
|
| 111 |
+
def mm_to_sparse(dense_query, dense_key, indices, block_size=32):
|
| 112 |
+
"""
|
| 113 |
+
Performs Sampled Dense Matrix Multiplication.
|
| 114 |
+
"""
|
| 115 |
+
batch_size, query_size, dim = dense_query.size()
|
| 116 |
+
_, key_size, dim = dense_key.size()
|
| 117 |
+
|
| 118 |
+
if query_size % block_size != 0:
|
| 119 |
+
raise ValueError("query_size (size of first dimension of dense_query) must be divisible by block_size.")
|
| 120 |
+
|
| 121 |
+
if key_size % block_size != 0:
|
| 122 |
+
raise ValueError("key_size (size of first dimension of dense_key) must be divisible by block_size.")
|
| 123 |
+
|
| 124 |
+
dense_query = dense_query.reshape(batch_size, query_size // block_size, block_size, dim).transpose(-1, -2)
|
| 125 |
+
dense_key = dense_key.reshape(batch_size, key_size // block_size, block_size, dim).transpose(-1, -2)
|
| 126 |
+
|
| 127 |
+
if len(dense_query.size()) != 4:
|
| 128 |
+
raise ValueError("dense_query must be a 4-dimensional tensor.")
|
| 129 |
+
|
| 130 |
+
if len(dense_key.size()) != 4:
|
| 131 |
+
raise ValueError("dense_key must be a 4-dimensional tensor.")
|
| 132 |
+
|
| 133 |
+
if len(indices.size()) != 2:
|
| 134 |
+
raise ValueError("indices must be a 2-dimensional tensor.")
|
| 135 |
+
|
| 136 |
+
if dense_query.size(3) != 32:
|
| 137 |
+
raise ValueError("The third dimension of dense_query must be 32.")
|
| 138 |
+
|
| 139 |
+
if dense_key.size(3) != 32:
|
| 140 |
+
raise ValueError("The third dimension of dense_key must be 32.")
|
| 141 |
+
|
| 142 |
+
dense_query = dense_query.contiguous()
|
| 143 |
+
dense_key = dense_key.contiguous()
|
| 144 |
+
|
| 145 |
+
indices = indices.int()
|
| 146 |
+
indices = indices.contiguous()
|
| 147 |
+
|
| 148 |
+
return mra_cuda_kernel.mm_to_sparse(dense_query, dense_key, indices.int())
|
| 149 |
+
|
| 150 |
+
|
| 151 |
+
def sparse_dense_mm(sparse_query, indices, dense_key, query_num_block, block_size=32):
|
| 152 |
+
"""
|
| 153 |
+
Performs matrix multiplication of a sparse matrix with a dense matrix.
|
| 154 |
+
"""
|
| 155 |
+
batch_size, key_size, dim = dense_key.size()
|
| 156 |
+
|
| 157 |
+
if key_size % block_size != 0:
|
| 158 |
+
raise ValueError("key_size (size of first dimension of dense_key) must be divisible by block_size.")
|
| 159 |
+
|
| 160 |
+
if sparse_query.size(2) != block_size:
|
| 161 |
+
raise ValueError("The size of the second dimension of sparse_query must be equal to the block_size.")
|
| 162 |
+
|
| 163 |
+
if sparse_query.size(3) != block_size:
|
| 164 |
+
raise ValueError("The size of the third dimension of sparse_query must be equal to the block_size.")
|
| 165 |
+
|
| 166 |
+
dense_key = dense_key.reshape(batch_size, key_size // block_size, block_size, dim).transpose(-1, -2)
|
| 167 |
+
|
| 168 |
+
if len(sparse_query.size()) != 4:
|
| 169 |
+
raise ValueError("sparse_query must be a 4-dimensional tensor.")
|
| 170 |
+
|
| 171 |
+
if len(dense_key.size()) != 4:
|
| 172 |
+
raise ValueError("dense_key must be a 4-dimensional tensor.")
|
| 173 |
+
|
| 174 |
+
if len(indices.size()) != 2:
|
| 175 |
+
raise ValueError("indices must be a 2-dimensional tensor.")
|
| 176 |
+
|
| 177 |
+
if dense_key.size(3) != 32:
|
| 178 |
+
raise ValueError("The size of the third dimension of dense_key must be 32.")
|
| 179 |
+
|
| 180 |
+
sparse_query = sparse_query.contiguous()
|
| 181 |
+
|
| 182 |
+
indices = indices.int()
|
| 183 |
+
indices = indices.contiguous()
|
| 184 |
+
dense_key = dense_key.contiguous()
|
| 185 |
+
|
| 186 |
+
dense_qk_prod = mra_cuda_kernel.sparse_dense_mm(sparse_query, indices, dense_key, query_num_block)
|
| 187 |
+
dense_qk_prod = dense_qk_prod.transpose(-1, -2).reshape(batch_size, query_num_block * block_size, dim)
|
| 188 |
+
return dense_qk_prod
|
| 189 |
+
|
| 190 |
+
|
| 191 |
+
def transpose_indices(indices, dim_1_block, dim_2_block):
|
| 192 |
+
return ((indices % dim_2_block) * dim_1_block + torch.div(indices, dim_2_block, rounding_mode="floor")).long()
|
| 193 |
+
|
| 194 |
+
|
| 195 |
+
class MraSampledDenseMatMul(torch.autograd.Function):
|
| 196 |
+
@staticmethod
|
| 197 |
+
def forward(ctx, dense_query, dense_key, indices, block_size):
|
| 198 |
+
sparse_qk_prod = mm_to_sparse(dense_query, dense_key, indices, block_size)
|
| 199 |
+
ctx.save_for_backward(dense_query, dense_key, indices)
|
| 200 |
+
ctx.block_size = block_size
|
| 201 |
+
return sparse_qk_prod
|
| 202 |
+
|
| 203 |
+
@staticmethod
|
| 204 |
+
def backward(ctx, grad):
|
| 205 |
+
dense_query, dense_key, indices = ctx.saved_tensors
|
| 206 |
+
block_size = ctx.block_size
|
| 207 |
+
query_num_block = dense_query.size(1) // block_size
|
| 208 |
+
key_num_block = dense_key.size(1) // block_size
|
| 209 |
+
indices_T = transpose_indices(indices, query_num_block, key_num_block)
|
| 210 |
+
grad_key = sparse_dense_mm(grad.transpose(-1, -2), indices_T, dense_query, key_num_block)
|
| 211 |
+
grad_query = sparse_dense_mm(grad, indices, dense_key, query_num_block)
|
| 212 |
+
return grad_query, grad_key, None, None
|
| 213 |
+
|
| 214 |
+
@staticmethod
|
| 215 |
+
def operator_call(dense_query, dense_key, indices, block_size=32):
|
| 216 |
+
return MraSampledDenseMatMul.apply(dense_query, dense_key, indices, block_size)
|
| 217 |
+
|
| 218 |
+
|
| 219 |
+
class MraSparseDenseMatMul(torch.autograd.Function):
|
| 220 |
+
@staticmethod
|
| 221 |
+
def forward(ctx, sparse_query, indices, dense_key, query_num_block):
|
| 222 |
+
sparse_qk_prod = sparse_dense_mm(sparse_query, indices, dense_key, query_num_block)
|
| 223 |
+
ctx.save_for_backward(sparse_query, indices, dense_key)
|
| 224 |
+
ctx.query_num_block = query_num_block
|
| 225 |
+
return sparse_qk_prod
|
| 226 |
+
|
| 227 |
+
@staticmethod
|
| 228 |
+
def backward(ctx, grad):
|
| 229 |
+
sparse_query, indices, dense_key = ctx.saved_tensors
|
| 230 |
+
query_num_block = ctx.query_num_block
|
| 231 |
+
key_num_block = dense_key.size(1) // sparse_query.size(-1)
|
| 232 |
+
indices_T = transpose_indices(indices, query_num_block, key_num_block)
|
| 233 |
+
grad_key = sparse_dense_mm(sparse_query.transpose(-1, -2), indices_T, grad, key_num_block)
|
| 234 |
+
grad_query = mm_to_sparse(grad, dense_key, indices)
|
| 235 |
+
return grad_query, None, grad_key, None
|
| 236 |
+
|
| 237 |
+
@staticmethod
|
| 238 |
+
def operator_call(sparse_query, indices, dense_key, query_num_block):
|
| 239 |
+
return MraSparseDenseMatMul.apply(sparse_query, indices, dense_key, query_num_block)
|
| 240 |
+
|
| 241 |
+
|
| 242 |
+
class MraReduceSum:
|
| 243 |
+
@staticmethod
|
| 244 |
+
def operator_call(sparse_query, indices, query_num_block, key_num_block):
|
| 245 |
+
batch_size, num_block, block_size, _ = sparse_query.size()
|
| 246 |
+
|
| 247 |
+
if len(sparse_query.size()) != 4:
|
| 248 |
+
raise ValueError("sparse_query must be a 4-dimensional tensor.")
|
| 249 |
+
|
| 250 |
+
if len(indices.size()) != 2:
|
| 251 |
+
raise ValueError("indices must be a 2-dimensional tensor.")
|
| 252 |
+
|
| 253 |
+
_, _, block_size, _ = sparse_query.size()
|
| 254 |
+
batch_size, num_block = indices.size()
|
| 255 |
+
|
| 256 |
+
sparse_query = sparse_query.sum(dim=2).reshape(batch_size * num_block, block_size)
|
| 257 |
+
|
| 258 |
+
batch_idx = torch.arange(indices.size(0), dtype=torch.long, device=indices.device)
|
| 259 |
+
global_idxes = (
|
| 260 |
+
torch.div(indices, key_num_block, rounding_mode="floor").long() + batch_idx[:, None] * query_num_block
|
| 261 |
+
).reshape(batch_size * num_block)
|
| 262 |
+
temp = torch.zeros(
|
| 263 |
+
(batch_size * query_num_block, block_size), dtype=sparse_query.dtype, device=sparse_query.device
|
| 264 |
+
)
|
| 265 |
+
output = temp.index_add(0, global_idxes, sparse_query).reshape(batch_size, query_num_block, block_size)
|
| 266 |
+
|
| 267 |
+
output = output.reshape(batch_size, query_num_block * block_size)
|
| 268 |
+
return output
|
| 269 |
+
|
| 270 |
+
|
| 271 |
+
def get_low_resolution_logit(query, key, block_size, mask=None, value=None):
|
| 272 |
+
"""
|
| 273 |
+
Compute low resolution approximation.
|
| 274 |
+
"""
|
| 275 |
+
batch_size, seq_len, head_dim = query.size()
|
| 276 |
+
|
| 277 |
+
num_block_per_row = seq_len // block_size
|
| 278 |
+
|
| 279 |
+
value_hat = None
|
| 280 |
+
if mask is not None:
|
| 281 |
+
token_count = mask.reshape(batch_size, num_block_per_row, block_size).sum(dim=-1)
|
| 282 |
+
query_hat = query.reshape(batch_size, num_block_per_row, block_size, head_dim).sum(dim=-2) / (
|
| 283 |
+
token_count[:, :, None] + 1e-6
|
| 284 |
+
)
|
| 285 |
+
key_hat = key.reshape(batch_size, num_block_per_row, block_size, head_dim).sum(dim=-2) / (
|
| 286 |
+
token_count[:, :, None] + 1e-6
|
| 287 |
+
)
|
| 288 |
+
if value is not None:
|
| 289 |
+
value_hat = value.reshape(batch_size, num_block_per_row, block_size, head_dim).sum(dim=-2) / (
|
| 290 |
+
token_count[:, :, None] + 1e-6
|
| 291 |
+
)
|
| 292 |
+
else:
|
| 293 |
+
token_count = block_size * torch.ones(batch_size, num_block_per_row, dtype=torch.float, device=query.device)
|
| 294 |
+
query_hat = query.reshape(batch_size, num_block_per_row, block_size, head_dim).mean(dim=-2)
|
| 295 |
+
key_hat = key.reshape(batch_size, num_block_per_row, block_size, head_dim).mean(dim=-2)
|
| 296 |
+
if value is not None:
|
| 297 |
+
value_hat = value.reshape(batch_size, num_block_per_row, block_size, head_dim).mean(dim=-2)
|
| 298 |
+
|
| 299 |
+
low_resolution_logit = torch.matmul(query_hat, key_hat.transpose(-1, -2)) / math.sqrt(head_dim)
|
| 300 |
+
|
| 301 |
+
low_resolution_logit_row_max = low_resolution_logit.max(dim=-1, keepdims=True).values
|
| 302 |
+
|
| 303 |
+
if mask is not None:
|
| 304 |
+
low_resolution_logit = (
|
| 305 |
+
low_resolution_logit - 1e4 * ((token_count[:, None, :] * token_count[:, :, None]) < 0.5).float()
|
| 306 |
+
)
|
| 307 |
+
|
| 308 |
+
return low_resolution_logit, token_count, low_resolution_logit_row_max, value_hat
|
| 309 |
+
|
| 310 |
+
|
| 311 |
+
def get_block_idxes(
|
| 312 |
+
low_resolution_logit, num_blocks, approx_mode, initial_prior_first_n_blocks, initial_prior_diagonal_n_blocks
|
| 313 |
+
):
|
| 314 |
+
"""
|
| 315 |
+
Compute the indices of the subset of components to be used in the approximation.
|
| 316 |
+
"""
|
| 317 |
+
batch_size, total_blocks_per_row, _ = low_resolution_logit.shape
|
| 318 |
+
|
| 319 |
+
if initial_prior_diagonal_n_blocks > 0:
|
| 320 |
+
offset = initial_prior_diagonal_n_blocks // 2
|
| 321 |
+
temp_mask = torch.ones(total_blocks_per_row, total_blocks_per_row, device=low_resolution_logit.device)
|
| 322 |
+
diagonal_mask = torch.tril(torch.triu(temp_mask, diagonal=-offset), diagonal=offset)
|
| 323 |
+
low_resolution_logit = low_resolution_logit + diagonal_mask[None, :, :] * 5e3
|
| 324 |
+
|
| 325 |
+
if initial_prior_first_n_blocks > 0:
|
| 326 |
+
low_resolution_logit[:, :initial_prior_first_n_blocks, :] = (
|
| 327 |
+
low_resolution_logit[:, :initial_prior_first_n_blocks, :] + 5e3
|
| 328 |
+
)
|
| 329 |
+
low_resolution_logit[:, :, :initial_prior_first_n_blocks] = (
|
| 330 |
+
low_resolution_logit[:, :, :initial_prior_first_n_blocks] + 5e3
|
| 331 |
+
)
|
| 332 |
+
|
| 333 |
+
top_k_vals = torch.topk(
|
| 334 |
+
low_resolution_logit.reshape(batch_size, -1), num_blocks, dim=-1, largest=True, sorted=False
|
| 335 |
+
)
|
| 336 |
+
indices = top_k_vals.indices
|
| 337 |
+
|
| 338 |
+
if approx_mode == "full":
|
| 339 |
+
threshold = top_k_vals.values.min(dim=-1).values
|
| 340 |
+
high_resolution_mask = (low_resolution_logit >= threshold[:, None, None]).float()
|
| 341 |
+
elif approx_mode == "sparse":
|
| 342 |
+
high_resolution_mask = None
|
| 343 |
+
else:
|
| 344 |
+
raise ValueError(f"{approx_mode} is not a valid approx_model value.")
|
| 345 |
+
|
| 346 |
+
return indices, high_resolution_mask
|
| 347 |
+
|
| 348 |
+
|
| 349 |
+
def mra2_attention(
|
| 350 |
+
query,
|
| 351 |
+
key,
|
| 352 |
+
value,
|
| 353 |
+
mask,
|
| 354 |
+
num_blocks,
|
| 355 |
+
approx_mode,
|
| 356 |
+
block_size=32,
|
| 357 |
+
initial_prior_first_n_blocks=0,
|
| 358 |
+
initial_prior_diagonal_n_blocks=0,
|
| 359 |
+
):
|
| 360 |
+
"""
|
| 361 |
+
Use Mra to approximate self-attention.
|
| 362 |
+
"""
|
| 363 |
+
if mra_cuda_kernel is None:
|
| 364 |
+
return torch.zeros_like(query).requires_grad_()
|
| 365 |
+
|
| 366 |
+
batch_size, num_head, seq_len, head_dim = query.size()
|
| 367 |
+
meta_batch = batch_size * num_head
|
| 368 |
+
|
| 369 |
+
if seq_len % block_size != 0:
|
| 370 |
+
raise ValueError("sequence length must be divisible by the block_size.")
|
| 371 |
+
|
| 372 |
+
num_block_per_row = seq_len // block_size
|
| 373 |
+
|
| 374 |
+
query = query.reshape(meta_batch, seq_len, head_dim)
|
| 375 |
+
key = key.reshape(meta_batch, seq_len, head_dim)
|
| 376 |
+
value = value.reshape(meta_batch, seq_len, head_dim)
|
| 377 |
+
|
| 378 |
+
if mask is not None:
|
| 379 |
+
query = query * mask[:, :, None]
|
| 380 |
+
key = key * mask[:, :, None]
|
| 381 |
+
value = value * mask[:, :, None]
|
| 382 |
+
|
| 383 |
+
if approx_mode == "full":
|
| 384 |
+
low_resolution_logit, token_count, low_resolution_logit_row_max, value_hat = get_low_resolution_logit(
|
| 385 |
+
query, key, block_size, mask, value
|
| 386 |
+
)
|
| 387 |
+
elif approx_mode == "sparse":
|
| 388 |
+
with torch.no_grad():
|
| 389 |
+
low_resolution_logit, token_count, low_resolution_logit_row_max, _ = get_low_resolution_logit(
|
| 390 |
+
query, key, block_size, mask
|
| 391 |
+
)
|
| 392 |
+
else:
|
| 393 |
+
raise Exception('approx_mode must be "full" or "sparse"')
|
| 394 |
+
|
| 395 |
+
with torch.no_grad():
|
| 396 |
+
low_resolution_logit_normalized = low_resolution_logit - low_resolution_logit_row_max
|
| 397 |
+
indices, high_resolution_mask = get_block_idxes(
|
| 398 |
+
low_resolution_logit_normalized,
|
| 399 |
+
num_blocks,
|
| 400 |
+
approx_mode,
|
| 401 |
+
initial_prior_first_n_blocks,
|
| 402 |
+
initial_prior_diagonal_n_blocks,
|
| 403 |
+
)
|
| 404 |
+
|
| 405 |
+
high_resolution_logit = MraSampledDenseMatMul.operator_call(
|
| 406 |
+
query, key, indices, block_size=block_size
|
| 407 |
+
) / math.sqrt(head_dim)
|
| 408 |
+
max_vals, max_vals_scatter = sparse_max(high_resolution_logit, indices, num_block_per_row, num_block_per_row)
|
| 409 |
+
high_resolution_logit = high_resolution_logit - max_vals_scatter
|
| 410 |
+
if mask is not None:
|
| 411 |
+
high_resolution_logit = high_resolution_logit - 1e4 * (1 - sparse_mask(mask, indices)[:, :, :, None])
|
| 412 |
+
high_resolution_attn = torch.exp(high_resolution_logit)
|
| 413 |
+
high_resolution_attn_out = MraSparseDenseMatMul.operator_call(
|
| 414 |
+
high_resolution_attn, indices, value, num_block_per_row
|
| 415 |
+
)
|
| 416 |
+
high_resolution_normalizer = MraReduceSum.operator_call(
|
| 417 |
+
high_resolution_attn, indices, num_block_per_row, num_block_per_row
|
| 418 |
+
)
|
| 419 |
+
|
| 420 |
+
if approx_mode == "full":
|
| 421 |
+
low_resolution_attn = (
|
| 422 |
+
torch.exp(low_resolution_logit - low_resolution_logit_row_max - 1e4 * high_resolution_mask)
|
| 423 |
+
* token_count[:, None, :]
|
| 424 |
+
)
|
| 425 |
+
|
| 426 |
+
low_resolution_attn_out = (
|
| 427 |
+
torch.matmul(low_resolution_attn, value_hat)[:, :, None, :]
|
| 428 |
+
.repeat(1, 1, block_size, 1)
|
| 429 |
+
.reshape(meta_batch, seq_len, head_dim)
|
| 430 |
+
)
|
| 431 |
+
low_resolution_normalizer = (
|
| 432 |
+
low_resolution_attn.sum(dim=-1)[:, :, None].repeat(1, 1, block_size).reshape(meta_batch, seq_len)
|
| 433 |
+
)
|
| 434 |
+
|
| 435 |
+
log_correction = low_resolution_logit_row_max.repeat(1, 1, block_size).reshape(meta_batch, seq_len) - max_vals
|
| 436 |
+
if mask is not None:
|
| 437 |
+
log_correction = log_correction * mask
|
| 438 |
+
|
| 439 |
+
low_resolution_corr = torch.exp(log_correction * (log_correction <= 0).float())
|
| 440 |
+
low_resolution_attn_out = low_resolution_attn_out * low_resolution_corr[:, :, None]
|
| 441 |
+
low_resolution_normalizer = low_resolution_normalizer * low_resolution_corr
|
| 442 |
+
|
| 443 |
+
high_resolution_corr = torch.exp(-log_correction * (log_correction > 0).float())
|
| 444 |
+
high_resolution_attn_out = high_resolution_attn_out * high_resolution_corr[:, :, None]
|
| 445 |
+
high_resolution_normalizer = high_resolution_normalizer * high_resolution_corr
|
| 446 |
+
|
| 447 |
+
context_layer = (high_resolution_attn_out + low_resolution_attn_out) / (
|
| 448 |
+
high_resolution_normalizer[:, :, None] + low_resolution_normalizer[:, :, None] + 1e-6
|
| 449 |
+
)
|
| 450 |
+
|
| 451 |
+
elif approx_mode == "sparse":
|
| 452 |
+
context_layer = high_resolution_attn_out / (high_resolution_normalizer[:, :, None] + 1e-6)
|
| 453 |
+
else:
|
| 454 |
+
raise Exception('config.approx_mode must be "full" or "sparse"')
|
| 455 |
+
|
| 456 |
+
if mask is not None:
|
| 457 |
+
context_layer = context_layer * mask[:, :, None]
|
| 458 |
+
|
| 459 |
+
context_layer = context_layer.reshape(batch_size, num_head, seq_len, head_dim)
|
| 460 |
+
|
| 461 |
+
return context_layer
|
| 462 |
+
|
| 463 |
+
|
| 464 |
+
class MraEmbeddings(nn.Module):
|
| 465 |
+
"""Construct the embeddings from word, position and token_type embeddings."""
|
| 466 |
+
|
| 467 |
+
def __init__(self, config):
|
| 468 |
+
super().__init__()
|
| 469 |
+
self.word_embeddings = nn.Embedding(config.vocab_size, config.hidden_size, padding_idx=config.pad_token_id)
|
| 470 |
+
self.position_embeddings = nn.Embedding(config.max_position_embeddings + 2, config.hidden_size)
|
| 471 |
+
self.token_type_embeddings = nn.Embedding(config.type_vocab_size, config.hidden_size)
|
| 472 |
+
|
| 473 |
+
self.LayerNorm = nn.LayerNorm(config.hidden_size, eps=config.layer_norm_eps)
|
| 474 |
+
self.dropout = nn.Dropout(config.hidden_dropout_prob)
|
| 475 |
+
|
| 476 |
+
# position_ids (1, len position emb) is contiguous in memory and exported when serialized
|
| 477 |
+
self.register_buffer("position_ids", torch.arange(config.max_position_embeddings).expand((1, -1)) + 2)
|
| 478 |
+
self.register_buffer(
|
| 479 |
+
"token_type_ids",
|
| 480 |
+
torch.zeros(self.position_ids.size(), dtype=torch.long, device=self.position_ids.device),
|
| 481 |
+
persistent=False,
|
| 482 |
+
)
|
| 483 |
+
|
| 484 |
+
def forward(self, input_ids=None, token_type_ids=None, position_ids=None, inputs_embeds=None):
|
| 485 |
+
if input_ids is not None:
|
| 486 |
+
input_shape = input_ids.size()
|
| 487 |
+
else:
|
| 488 |
+
input_shape = inputs_embeds.size()[:-1]
|
| 489 |
+
|
| 490 |
+
seq_length = input_shape[1]
|
| 491 |
+
|
| 492 |
+
if position_ids is None:
|
| 493 |
+
position_ids = self.position_ids[:, :seq_length]
|
| 494 |
+
|
| 495 |
+
# Setting the token_type_ids to the registered buffer in constructor where it is all zeros, which usually occurs
|
| 496 |
+
# when its auto-generated, registered buffer helps users when tracing the model without passing token_type_ids, solves
|
| 497 |
+
# issue #5664
|
| 498 |
+
if token_type_ids is None:
|
| 499 |
+
if hasattr(self, "token_type_ids"):
|
| 500 |
+
buffered_token_type_ids = self.token_type_ids[:, :seq_length]
|
| 501 |
+
buffered_token_type_ids_expanded = buffered_token_type_ids.expand(input_shape[0], seq_length)
|
| 502 |
+
token_type_ids = buffered_token_type_ids_expanded
|
| 503 |
+
else:
|
| 504 |
+
token_type_ids = torch.zeros(input_shape, dtype=torch.long, device=self.position_ids.device)
|
| 505 |
+
|
| 506 |
+
if inputs_embeds is None:
|
| 507 |
+
inputs_embeds = self.word_embeddings(input_ids)
|
| 508 |
+
token_type_embeddings = self.token_type_embeddings(token_type_ids)
|
| 509 |
+
embeddings = inputs_embeds + token_type_embeddings
|
| 510 |
+
|
| 511 |
+
position_embeddings = self.position_embeddings(position_ids)
|
| 512 |
+
embeddings += position_embeddings
|
| 513 |
+
|
| 514 |
+
embeddings = self.LayerNorm(embeddings)
|
| 515 |
+
embeddings = self.dropout(embeddings)
|
| 516 |
+
return embeddings
|
| 517 |
+
|
| 518 |
+
|
| 519 |
+
class MraSelfAttention(nn.Module):
|
| 520 |
+
def __init__(self, config):
|
| 521 |
+
super().__init__()
|
| 522 |
+
if config.hidden_size % config.num_attention_heads != 0 and not hasattr(config, "embedding_size"):
|
| 523 |
+
raise ValueError(
|
| 524 |
+
f"The hidden size ({config.hidden_size}) is not a multiple of the number of attention "
|
| 525 |
+
f"heads ({config.num_attention_heads})"
|
| 526 |
+
)
|
| 527 |
+
|
| 528 |
+
kernel_loaded = mra_cuda_kernel is not None
|
| 529 |
+
if is_torch_cuda_available() and is_cuda_platform() and is_ninja_available() and not kernel_loaded:
|
| 530 |
+
try:
|
| 531 |
+
load_cuda_kernels()
|
| 532 |
+
except Exception as e:
|
| 533 |
+
logger.warning(f"Could not load the custom kernel for multi-scale deformable attention: {e}")
|
| 534 |
+
|
| 535 |
+
self.num_attention_heads = config.num_attention_heads
|
| 536 |
+
self.attention_head_size = int(config.hidden_size / config.num_attention_heads)
|
| 537 |
+
self.all_head_size = self.num_attention_heads * self.attention_head_size
|
| 538 |
+
|
| 539 |
+
self.query = nn.Linear(config.hidden_size, self.all_head_size)
|
| 540 |
+
self.key = nn.Linear(config.hidden_size, self.all_head_size)
|
| 541 |
+
self.value = nn.Linear(config.hidden_size, self.all_head_size)
|
| 542 |
+
|
| 543 |
+
self.dropout = nn.Dropout(config.attention_probs_dropout_prob)
|
| 544 |
+
|
| 545 |
+
self.num_block = (config.max_position_embeddings // 32) * config.block_per_row
|
| 546 |
+
self.num_block = min(self.num_block, int((config.max_position_embeddings // 32) ** 2))
|
| 547 |
+
|
| 548 |
+
self.approx_mode = config.approx_mode
|
| 549 |
+
self.initial_prior_first_n_blocks = config.initial_prior_first_n_blocks
|
| 550 |
+
self.initial_prior_diagonal_n_blocks = config.initial_prior_diagonal_n_blocks
|
| 551 |
+
|
| 552 |
+
def forward(self, hidden_states, attention_mask=None):
|
| 553 |
+
batch_size, seq_len, _ = hidden_states.shape
|
| 554 |
+
query_layer = (
|
| 555 |
+
self.query(hidden_states)
|
| 556 |
+
.view(batch_size, -1, self.num_attention_heads, self.attention_head_size)
|
| 557 |
+
.transpose(1, 2)
|
| 558 |
+
)
|
| 559 |
+
key_layer = (
|
| 560 |
+
self.key(hidden_states)
|
| 561 |
+
.view(batch_size, -1, self.num_attention_heads, self.attention_head_size)
|
| 562 |
+
.transpose(1, 2)
|
| 563 |
+
)
|
| 564 |
+
value_layer = (
|
| 565 |
+
self.value(hidden_states)
|
| 566 |
+
.view(batch_size, -1, self.num_attention_heads, self.attention_head_size)
|
| 567 |
+
.transpose(1, 2)
|
| 568 |
+
)
|
| 569 |
+
|
| 570 |
+
# revert changes made by get_extended_attention_mask
|
| 571 |
+
attention_mask = 1.0 + attention_mask / 10000.0
|
| 572 |
+
attention_mask = (
|
| 573 |
+
attention_mask.squeeze()
|
| 574 |
+
.repeat(1, self.num_attention_heads, 1)
|
| 575 |
+
.reshape(batch_size * self.num_attention_heads, seq_len)
|
| 576 |
+
.int()
|
| 577 |
+
)
|
| 578 |
+
|
| 579 |
+
# The CUDA kernels are most efficient with inputs whose size is a multiple of a GPU's warp size (32). Inputs
|
| 580 |
+
# smaller than this are padded with zeros.
|
| 581 |
+
gpu_warp_size = 32
|
| 582 |
+
|
| 583 |
+
if self.attention_head_size < gpu_warp_size:
|
| 584 |
+
pad_size = batch_size, self.num_attention_heads, seq_len, gpu_warp_size - self.attention_head_size
|
| 585 |
+
|
| 586 |
+
query_layer = torch.cat([query_layer, torch.zeros(pad_size, device=query_layer.device)], dim=-1)
|
| 587 |
+
key_layer = torch.cat([key_layer, torch.zeros(pad_size, device=key_layer.device)], dim=-1)
|
| 588 |
+
value_layer = torch.cat([value_layer, torch.zeros(pad_size, device=value_layer.device)], dim=-1)
|
| 589 |
+
|
| 590 |
+
context_layer = mra2_attention(
|
| 591 |
+
query_layer.float(),
|
| 592 |
+
key_layer.float(),
|
| 593 |
+
value_layer.float(),
|
| 594 |
+
attention_mask.float(),
|
| 595 |
+
self.num_block,
|
| 596 |
+
approx_mode=self.approx_mode,
|
| 597 |
+
initial_prior_first_n_blocks=self.initial_prior_first_n_blocks,
|
| 598 |
+
initial_prior_diagonal_n_blocks=self.initial_prior_diagonal_n_blocks,
|
| 599 |
+
)
|
| 600 |
+
|
| 601 |
+
if self.attention_head_size < gpu_warp_size:
|
| 602 |
+
context_layer = context_layer[:, :, :, : self.attention_head_size]
|
| 603 |
+
|
| 604 |
+
context_layer = context_layer.reshape(batch_size, self.num_attention_heads, seq_len, self.attention_head_size)
|
| 605 |
+
|
| 606 |
+
context_layer = context_layer.permute(0, 2, 1, 3).contiguous()
|
| 607 |
+
new_context_layer_shape = context_layer.size()[:-2] + (self.all_head_size,)
|
| 608 |
+
context_layer = context_layer.view(*new_context_layer_shape)
|
| 609 |
+
|
| 610 |
+
outputs = (context_layer,)
|
| 611 |
+
|
| 612 |
+
return outputs
|
| 613 |
+
|
| 614 |
+
|
| 615 |
+
# Copied from transformers.models.bert.modeling_bert.BertSelfOutput
|
| 616 |
+
class MraSelfOutput(nn.Module):
|
| 617 |
+
def __init__(self, config):
|
| 618 |
+
super().__init__()
|
| 619 |
+
self.dense = nn.Linear(config.hidden_size, config.hidden_size)
|
| 620 |
+
self.LayerNorm = nn.LayerNorm(config.hidden_size, eps=config.layer_norm_eps)
|
| 621 |
+
self.dropout = nn.Dropout(config.hidden_dropout_prob)
|
| 622 |
+
|
| 623 |
+
def forward(self, hidden_states: torch.Tensor, input_tensor: torch.Tensor) -> torch.Tensor:
|
| 624 |
+
hidden_states = self.dense(hidden_states)
|
| 625 |
+
hidden_states = self.dropout(hidden_states)
|
| 626 |
+
hidden_states = self.LayerNorm(hidden_states + input_tensor)
|
| 627 |
+
return hidden_states
|
| 628 |
+
|
| 629 |
+
|
| 630 |
+
class MraAttention(nn.Module):
|
| 631 |
+
def __init__(self, config):
|
| 632 |
+
super().__init__()
|
| 633 |
+
self.self = MraSelfAttention(config)
|
| 634 |
+
self.output = MraSelfOutput(config)
|
| 635 |
+
|
| 636 |
+
def forward(self, hidden_states, attention_mask=None):
|
| 637 |
+
self_outputs = self.self(hidden_states, attention_mask)
|
| 638 |
+
attention_output = self.output(self_outputs[0], hidden_states)
|
| 639 |
+
outputs = (attention_output,) + self_outputs[1:] # add attentions if we output them
|
| 640 |
+
return outputs
|
| 641 |
+
|
| 642 |
+
|
| 643 |
+
# Copied from transformers.models.bert.modeling_bert.BertIntermediate
|
| 644 |
+
class MraIntermediate(nn.Module):
|
| 645 |
+
def __init__(self, config):
|
| 646 |
+
super().__init__()
|
| 647 |
+
self.dense = nn.Linear(config.hidden_size, config.intermediate_size)
|
| 648 |
+
if isinstance(config.hidden_act, str):
|
| 649 |
+
self.intermediate_act_fn = ACT2FN[config.hidden_act]
|
| 650 |
+
else:
|
| 651 |
+
self.intermediate_act_fn = config.hidden_act
|
| 652 |
+
|
| 653 |
+
def forward(self, hidden_states: torch.Tensor) -> torch.Tensor:
|
| 654 |
+
hidden_states = self.dense(hidden_states)
|
| 655 |
+
hidden_states = self.intermediate_act_fn(hidden_states)
|
| 656 |
+
return hidden_states
|
| 657 |
+
|
| 658 |
+
|
| 659 |
+
# Copied from transformers.models.bert.modeling_bert.BertOutput
|
| 660 |
+
class MraOutput(nn.Module):
|
| 661 |
+
def __init__(self, config):
|
| 662 |
+
super().__init__()
|
| 663 |
+
self.dense = nn.Linear(config.intermediate_size, config.hidden_size)
|
| 664 |
+
self.LayerNorm = nn.LayerNorm(config.hidden_size, eps=config.layer_norm_eps)
|
| 665 |
+
self.dropout = nn.Dropout(config.hidden_dropout_prob)
|
| 666 |
+
|
| 667 |
+
def forward(self, hidden_states: torch.Tensor, input_tensor: torch.Tensor) -> torch.Tensor:
|
| 668 |
+
hidden_states = self.dense(hidden_states)
|
| 669 |
+
hidden_states = self.dropout(hidden_states)
|
| 670 |
+
hidden_states = self.LayerNorm(hidden_states + input_tensor)
|
| 671 |
+
return hidden_states
|
| 672 |
+
|
| 673 |
+
|
| 674 |
+
class MraLayer(GradientCheckpointingLayer):
|
| 675 |
+
def __init__(self, config):
|
| 676 |
+
super().__init__()
|
| 677 |
+
self.chunk_size_feed_forward = config.chunk_size_feed_forward
|
| 678 |
+
self.seq_len_dim = 1
|
| 679 |
+
self.attention = MraAttention(config)
|
| 680 |
+
self.add_cross_attention = config.add_cross_attention
|
| 681 |
+
self.intermediate = MraIntermediate(config)
|
| 682 |
+
self.output = MraOutput(config)
|
| 683 |
+
|
| 684 |
+
def forward(self, hidden_states, attention_mask=None):
|
| 685 |
+
self_attention_outputs = self.attention(hidden_states, attention_mask)
|
| 686 |
+
attention_output = self_attention_outputs[0]
|
| 687 |
+
|
| 688 |
+
outputs = self_attention_outputs[1:] # add self attentions if we output attention weights
|
| 689 |
+
|
| 690 |
+
layer_output = apply_chunking_to_forward(
|
| 691 |
+
self.feed_forward_chunk, self.chunk_size_feed_forward, self.seq_len_dim, attention_output
|
| 692 |
+
)
|
| 693 |
+
outputs = (layer_output,) + outputs
|
| 694 |
+
|
| 695 |
+
return outputs
|
| 696 |
+
|
| 697 |
+
def feed_forward_chunk(self, attention_output):
|
| 698 |
+
intermediate_output = self.intermediate(attention_output)
|
| 699 |
+
layer_output = self.output(intermediate_output, attention_output)
|
| 700 |
+
return layer_output
|
| 701 |
+
|
| 702 |
+
|
| 703 |
+
class MraEncoder(nn.Module):
|
| 704 |
+
def __init__(self, config):
|
| 705 |
+
super().__init__()
|
| 706 |
+
self.config = config
|
| 707 |
+
self.layer = nn.ModuleList([MraLayer(config) for _ in range(config.num_hidden_layers)])
|
| 708 |
+
self.gradient_checkpointing = False
|
| 709 |
+
|
| 710 |
+
def forward(
|
| 711 |
+
self,
|
| 712 |
+
hidden_states,
|
| 713 |
+
attention_mask=None,
|
| 714 |
+
output_hidden_states=False,
|
| 715 |
+
return_dict=True,
|
| 716 |
+
):
|
| 717 |
+
all_hidden_states = () if output_hidden_states else None
|
| 718 |
+
|
| 719 |
+
for i, layer_module in enumerate(self.layer):
|
| 720 |
+
if output_hidden_states:
|
| 721 |
+
all_hidden_states = all_hidden_states + (hidden_states,)
|
| 722 |
+
|
| 723 |
+
layer_outputs = layer_module(hidden_states, attention_mask)
|
| 724 |
+
|
| 725 |
+
hidden_states = layer_outputs[0]
|
| 726 |
+
|
| 727 |
+
if output_hidden_states:
|
| 728 |
+
all_hidden_states = all_hidden_states + (hidden_states,)
|
| 729 |
+
|
| 730 |
+
if not return_dict:
|
| 731 |
+
return tuple(v for v in [hidden_states, all_hidden_states] if v is not None)
|
| 732 |
+
return BaseModelOutputWithCrossAttentions(
|
| 733 |
+
last_hidden_state=hidden_states,
|
| 734 |
+
hidden_states=all_hidden_states,
|
| 735 |
+
)
|
| 736 |
+
|
| 737 |
+
|
| 738 |
+
# Copied from transformers.models.bert.modeling_bert.BertPredictionHeadTransform
|
| 739 |
+
class MraPredictionHeadTransform(nn.Module):
|
| 740 |
+
def __init__(self, config):
|
| 741 |
+
super().__init__()
|
| 742 |
+
self.dense = nn.Linear(config.hidden_size, config.hidden_size)
|
| 743 |
+
if isinstance(config.hidden_act, str):
|
| 744 |
+
self.transform_act_fn = ACT2FN[config.hidden_act]
|
| 745 |
+
else:
|
| 746 |
+
self.transform_act_fn = config.hidden_act
|
| 747 |
+
self.LayerNorm = nn.LayerNorm(config.hidden_size, eps=config.layer_norm_eps)
|
| 748 |
+
|
| 749 |
+
def forward(self, hidden_states: torch.Tensor) -> torch.Tensor:
|
| 750 |
+
hidden_states = self.dense(hidden_states)
|
| 751 |
+
hidden_states = self.transform_act_fn(hidden_states)
|
| 752 |
+
hidden_states = self.LayerNorm(hidden_states)
|
| 753 |
+
return hidden_states
|
| 754 |
+
|
| 755 |
+
|
| 756 |
+
# Copied from transformers.models.bert.modeling_bert.BertLMPredictionHead with Bert->Mra
|
| 757 |
+
class MraLMPredictionHead(nn.Module):
|
| 758 |
+
def __init__(self, config):
|
| 759 |
+
super().__init__()
|
| 760 |
+
self.transform = MraPredictionHeadTransform(config)
|
| 761 |
+
|
| 762 |
+
# The output weights are the same as the input embeddings, but there is
|
| 763 |
+
# an output-only bias for each token.
|
| 764 |
+
self.decoder = nn.Linear(config.hidden_size, config.vocab_size, bias=True)
|
| 765 |
+
self.bias = nn.Parameter(torch.zeros(config.vocab_size))
|
| 766 |
+
|
| 767 |
+
def forward(self, hidden_states):
|
| 768 |
+
hidden_states = self.transform(hidden_states)
|
| 769 |
+
hidden_states = self.decoder(hidden_states)
|
| 770 |
+
return hidden_states
|
| 771 |
+
|
| 772 |
+
|
| 773 |
+
# Copied from transformers.models.bert.modeling_bert.BertOnlyMLMHead with Bert->Mra
|
| 774 |
+
class MraOnlyMLMHead(nn.Module):
|
| 775 |
+
def __init__(self, config):
|
| 776 |
+
super().__init__()
|
| 777 |
+
self.predictions = MraLMPredictionHead(config)
|
| 778 |
+
|
| 779 |
+
def forward(self, sequence_output: torch.Tensor) -> torch.Tensor:
|
| 780 |
+
prediction_scores = self.predictions(sequence_output)
|
| 781 |
+
return prediction_scores
|
| 782 |
+
|
| 783 |
+
|
| 784 |
+
@auto_docstring
|
| 785 |
+
# Copied from transformers.models.yoso.modeling_yoso.YosoPreTrainedModel with Yoso->Mra,yoso->mra
|
| 786 |
+
class MraPreTrainedModel(PreTrainedModel):
|
| 787 |
+
config: MraConfig
|
| 788 |
+
base_model_prefix = "mra"
|
| 789 |
+
supports_gradient_checkpointing = True
|
| 790 |
+
|
| 791 |
+
@torch.no_grad()
|
| 792 |
+
def _init_weights(self, module: nn.Module):
|
| 793 |
+
"""Initialize the weights"""
|
| 794 |
+
super()._init_weights(module)
|
| 795 |
+
if isinstance(module, MraLMPredictionHead):
|
| 796 |
+
init.zeros_(module.bias)
|
| 797 |
+
elif isinstance(module, MraEmbeddings):
|
| 798 |
+
init.copy_(module.position_ids, torch.arange(module.position_ids.shape[-1]).expand((1, -1)) + 2)
|
| 799 |
+
init.zeros_(module.token_type_ids)
|
| 800 |
+
|
| 801 |
+
|
| 802 |
+
@auto_docstring
|
| 803 |
+
class MraModel(MraPreTrainedModel):
|
| 804 |
+
def __init__(self, config):
|
| 805 |
+
super().__init__(config)
|
| 806 |
+
self.config = config
|
| 807 |
+
|
| 808 |
+
self.embeddings = MraEmbeddings(config)
|
| 809 |
+
self.encoder = MraEncoder(config)
|
| 810 |
+
|
| 811 |
+
# Initialize weights and apply final processing
|
| 812 |
+
self.post_init()
|
| 813 |
+
|
| 814 |
+
def get_input_embeddings(self):
|
| 815 |
+
return self.embeddings.word_embeddings
|
| 816 |
+
|
| 817 |
+
def set_input_embeddings(self, value):
|
| 818 |
+
self.embeddings.word_embeddings = value
|
| 819 |
+
|
| 820 |
+
@auto_docstring
|
| 821 |
+
def forward(
|
| 822 |
+
self,
|
| 823 |
+
input_ids: torch.Tensor | None = None,
|
| 824 |
+
attention_mask: torch.Tensor | None = None,
|
| 825 |
+
token_type_ids: torch.Tensor | None = None,
|
| 826 |
+
position_ids: torch.Tensor | None = None,
|
| 827 |
+
inputs_embeds: torch.Tensor | None = None,
|
| 828 |
+
output_hidden_states: bool | None = None,
|
| 829 |
+
return_dict: bool | None = None,
|
| 830 |
+
**kwargs,
|
| 831 |
+
) -> tuple | BaseModelOutputWithCrossAttentions:
|
| 832 |
+
output_hidden_states = (
|
| 833 |
+
output_hidden_states if output_hidden_states is not None else self.config.output_hidden_states
|
| 834 |
+
)
|
| 835 |
+
return_dict = return_dict if return_dict is not None else self.config.return_dict
|
| 836 |
+
|
| 837 |
+
if input_ids is not None and inputs_embeds is not None:
|
| 838 |
+
raise ValueError("You cannot specify both input_ids and inputs_embeds at the same time")
|
| 839 |
+
elif input_ids is not None:
|
| 840 |
+
self.warn_if_padding_and_no_attention_mask(input_ids, attention_mask)
|
| 841 |
+
input_shape = input_ids.size()
|
| 842 |
+
elif inputs_embeds is not None:
|
| 843 |
+
input_shape = inputs_embeds.size()[:-1]
|
| 844 |
+
else:
|
| 845 |
+
raise ValueError("You have to specify either input_ids or inputs_embeds")
|
| 846 |
+
|
| 847 |
+
batch_size, seq_length = input_shape
|
| 848 |
+
device = input_ids.device if input_ids is not None else inputs_embeds.device
|
| 849 |
+
|
| 850 |
+
if attention_mask is None:
|
| 851 |
+
attention_mask = torch.ones(((batch_size, seq_length)), device=device)
|
| 852 |
+
|
| 853 |
+
if token_type_ids is None:
|
| 854 |
+
if hasattr(self.embeddings, "token_type_ids"):
|
| 855 |
+
buffered_token_type_ids = self.embeddings.token_type_ids[:, :seq_length]
|
| 856 |
+
buffered_token_type_ids_expanded = buffered_token_type_ids.expand(batch_size, seq_length)
|
| 857 |
+
token_type_ids = buffered_token_type_ids_expanded
|
| 858 |
+
else:
|
| 859 |
+
token_type_ids = torch.zeros(input_shape, dtype=torch.long, device=device)
|
| 860 |
+
|
| 861 |
+
# We can provide a self-attention mask of dimensions [batch_size, from_seq_length, to_seq_length]
|
| 862 |
+
# ourselves in which case we just need to make it broadcastable to all heads.
|
| 863 |
+
extended_attention_mask: torch.Tensor = self.get_extended_attention_mask(attention_mask, input_shape)
|
| 864 |
+
|
| 865 |
+
embedding_output = self.embeddings(
|
| 866 |
+
input_ids=input_ids,
|
| 867 |
+
position_ids=position_ids,
|
| 868 |
+
token_type_ids=token_type_ids,
|
| 869 |
+
inputs_embeds=inputs_embeds,
|
| 870 |
+
)
|
| 871 |
+
encoder_outputs = self.encoder(
|
| 872 |
+
embedding_output,
|
| 873 |
+
attention_mask=extended_attention_mask,
|
| 874 |
+
output_hidden_states=output_hidden_states,
|
| 875 |
+
return_dict=return_dict,
|
| 876 |
+
)
|
| 877 |
+
sequence_output = encoder_outputs[0]
|
| 878 |
+
|
| 879 |
+
if not return_dict:
|
| 880 |
+
return (sequence_output,) + encoder_outputs[1:]
|
| 881 |
+
|
| 882 |
+
return BaseModelOutputWithCrossAttentions(
|
| 883 |
+
last_hidden_state=sequence_output,
|
| 884 |
+
hidden_states=encoder_outputs.hidden_states,
|
| 885 |
+
attentions=encoder_outputs.attentions,
|
| 886 |
+
cross_attentions=encoder_outputs.cross_attentions,
|
| 887 |
+
)
|
| 888 |
+
|
| 889 |
+
|
| 890 |
+
@auto_docstring
|
| 891 |
+
class MraForMaskedLM(MraPreTrainedModel):
|
| 892 |
+
_tied_weights_keys = {
|
| 893 |
+
"cls.predictions.decoder.bias": "cls.predictions.bias",
|
| 894 |
+
"cls.predictions.decoder.weight": "mra.embeddings.word_embeddings.weight",
|
| 895 |
+
}
|
| 896 |
+
|
| 897 |
+
def __init__(self, config):
|
| 898 |
+
super().__init__(config)
|
| 899 |
+
|
| 900 |
+
self.mra = MraModel(config)
|
| 901 |
+
self.cls = MraOnlyMLMHead(config)
|
| 902 |
+
|
| 903 |
+
# Initialize weights and apply final processing
|
| 904 |
+
self.post_init()
|
| 905 |
+
|
| 906 |
+
def get_output_embeddings(self):
|
| 907 |
+
return self.cls.predictions.decoder
|
| 908 |
+
|
| 909 |
+
def set_output_embeddings(self, new_embeddings):
|
| 910 |
+
self.cls.predictions.decoder = new_embeddings
|
| 911 |
+
self.cls.predictions.bias = new_embeddings.bias
|
| 912 |
+
|
| 913 |
+
@auto_docstring
|
| 914 |
+
def forward(
|
| 915 |
+
self,
|
| 916 |
+
input_ids: torch.Tensor | None = None,
|
| 917 |
+
attention_mask: torch.Tensor | None = None,
|
| 918 |
+
token_type_ids: torch.Tensor | None = None,
|
| 919 |
+
position_ids: torch.Tensor | None = None,
|
| 920 |
+
inputs_embeds: torch.Tensor | None = None,
|
| 921 |
+
labels: torch.Tensor | None = None,
|
| 922 |
+
output_hidden_states: bool | None = None,
|
| 923 |
+
return_dict: bool | None = None,
|
| 924 |
+
**kwargs,
|
| 925 |
+
) -> tuple | MaskedLMOutput:
|
| 926 |
+
r"""
|
| 927 |
+
labels (`torch.LongTensor` of shape `(batch_size, sequence_length)`, *optional*):
|
| 928 |
+
Labels for computing the masked language modeling loss. Indices should be in `[-100, 0, ...,
|
| 929 |
+
config.vocab_size]` (see `input_ids` docstring) Tokens with indices set to `-100` are ignored (masked), the
|
| 930 |
+
loss is only computed for the tokens with labels in `[0, ..., config.vocab_size]`.
|
| 931 |
+
"""
|
| 932 |
+
return_dict = return_dict if return_dict is not None else self.config.return_dict
|
| 933 |
+
|
| 934 |
+
outputs = self.mra(
|
| 935 |
+
input_ids,
|
| 936 |
+
attention_mask=attention_mask,
|
| 937 |
+
token_type_ids=token_type_ids,
|
| 938 |
+
position_ids=position_ids,
|
| 939 |
+
inputs_embeds=inputs_embeds,
|
| 940 |
+
output_hidden_states=output_hidden_states,
|
| 941 |
+
return_dict=return_dict,
|
| 942 |
+
)
|
| 943 |
+
|
| 944 |
+
sequence_output = outputs[0]
|
| 945 |
+
prediction_scores = self.cls(sequence_output)
|
| 946 |
+
|
| 947 |
+
masked_lm_loss = None
|
| 948 |
+
if labels is not None:
|
| 949 |
+
loss_fct = CrossEntropyLoss() # -100 index = padding token
|
| 950 |
+
masked_lm_loss = loss_fct(prediction_scores.view(-1, self.config.vocab_size), labels.view(-1))
|
| 951 |
+
|
| 952 |
+
if not return_dict:
|
| 953 |
+
output = (prediction_scores,) + outputs[1:]
|
| 954 |
+
return ((masked_lm_loss,) + output) if masked_lm_loss is not None else output
|
| 955 |
+
|
| 956 |
+
return MaskedLMOutput(
|
| 957 |
+
loss=masked_lm_loss,
|
| 958 |
+
logits=prediction_scores,
|
| 959 |
+
hidden_states=outputs.hidden_states,
|
| 960 |
+
attentions=outputs.attentions,
|
| 961 |
+
)
|
| 962 |
+
|
| 963 |
+
|
| 964 |
+
# Copied from transformers.models.yoso.modeling_yoso.YosoClassificationHead with Yoso->Mra
|
| 965 |
+
class MraClassificationHead(nn.Module):
|
| 966 |
+
"""Head for sentence-level classification tasks."""
|
| 967 |
+
|
| 968 |
+
def __init__(self, config):
|
| 969 |
+
super().__init__()
|
| 970 |
+
self.dense = nn.Linear(config.hidden_size, config.hidden_size)
|
| 971 |
+
self.dropout = nn.Dropout(config.hidden_dropout_prob)
|
| 972 |
+
self.out_proj = nn.Linear(config.hidden_size, config.num_labels)
|
| 973 |
+
|
| 974 |
+
self.config = config
|
| 975 |
+
|
| 976 |
+
def forward(self, features, **kwargs):
|
| 977 |
+
x = features[:, 0, :] # take <s> token (equiv. to [CLS])
|
| 978 |
+
x = self.dropout(x)
|
| 979 |
+
x = self.dense(x)
|
| 980 |
+
x = ACT2FN[self.config.hidden_act](x)
|
| 981 |
+
x = self.dropout(x)
|
| 982 |
+
x = self.out_proj(x)
|
| 983 |
+
return x
|
| 984 |
+
|
| 985 |
+
|
| 986 |
+
@auto_docstring(
|
| 987 |
+
custom_intro="""
|
| 988 |
+
MRA Model transformer with a sequence classification/regression head on top (a linear layer on top of
|
| 989 |
+
the pooled output) e.g. for GLUE tasks.
|
| 990 |
+
"""
|
| 991 |
+
)
|
| 992 |
+
class MraForSequenceClassification(MraPreTrainedModel):
|
| 993 |
+
def __init__(self, config):
|
| 994 |
+
super().__init__(config)
|
| 995 |
+
self.num_labels = config.num_labels
|
| 996 |
+
self.mra = MraModel(config)
|
| 997 |
+
self.classifier = MraClassificationHead(config)
|
| 998 |
+
|
| 999 |
+
# Initialize weights and apply final processing
|
| 1000 |
+
self.post_init()
|
| 1001 |
+
|
| 1002 |
+
@auto_docstring
|
| 1003 |
+
def forward(
|
| 1004 |
+
self,
|
| 1005 |
+
input_ids: torch.Tensor | None = None,
|
| 1006 |
+
attention_mask: torch.Tensor | None = None,
|
| 1007 |
+
token_type_ids: torch.Tensor | None = None,
|
| 1008 |
+
position_ids: torch.Tensor | None = None,
|
| 1009 |
+
inputs_embeds: torch.Tensor | None = None,
|
| 1010 |
+
labels: torch.Tensor | None = None,
|
| 1011 |
+
output_hidden_states: bool | None = None,
|
| 1012 |
+
return_dict: bool | None = None,
|
| 1013 |
+
**kwargs,
|
| 1014 |
+
) -> tuple | SequenceClassifierOutput:
|
| 1015 |
+
r"""
|
| 1016 |
+
labels (`torch.LongTensor` of shape `(batch_size,)`, *optional*):
|
| 1017 |
+
Labels for computing the sequence classification/regression loss. Indices should be in `[0, ...,
|
| 1018 |
+
config.num_labels - 1]`. If `config.num_labels == 1` a regression loss is computed (Mean-Square loss), If
|
| 1019 |
+
`config.num_labels > 1` a classification loss is computed (Cross-Entropy).
|
| 1020 |
+
"""
|
| 1021 |
+
return_dict = return_dict if return_dict is not None else self.config.return_dict
|
| 1022 |
+
|
| 1023 |
+
outputs = self.mra(
|
| 1024 |
+
input_ids,
|
| 1025 |
+
attention_mask=attention_mask,
|
| 1026 |
+
token_type_ids=token_type_ids,
|
| 1027 |
+
position_ids=position_ids,
|
| 1028 |
+
inputs_embeds=inputs_embeds,
|
| 1029 |
+
output_hidden_states=output_hidden_states,
|
| 1030 |
+
return_dict=return_dict,
|
| 1031 |
+
)
|
| 1032 |
+
|
| 1033 |
+
sequence_output = outputs[0]
|
| 1034 |
+
logits = self.classifier(sequence_output)
|
| 1035 |
+
|
| 1036 |
+
loss = None
|
| 1037 |
+
if labels is not None:
|
| 1038 |
+
if self.config.problem_type is None:
|
| 1039 |
+
if self.num_labels == 1:
|
| 1040 |
+
self.config.problem_type = "regression"
|
| 1041 |
+
elif self.num_labels > 1 and (labels.dtype == torch.long or labels.dtype == torch.int):
|
| 1042 |
+
self.config.problem_type = "single_label_classification"
|
| 1043 |
+
else:
|
| 1044 |
+
self.config.problem_type = "multi_label_classification"
|
| 1045 |
+
|
| 1046 |
+
if self.config.problem_type == "regression":
|
| 1047 |
+
loss_fct = MSELoss()
|
| 1048 |
+
if self.num_labels == 1:
|
| 1049 |
+
loss = loss_fct(logits.squeeze(), labels.squeeze())
|
| 1050 |
+
else:
|
| 1051 |
+
loss = loss_fct(logits, labels)
|
| 1052 |
+
elif self.config.problem_type == "single_label_classification":
|
| 1053 |
+
loss_fct = CrossEntropyLoss()
|
| 1054 |
+
loss = loss_fct(logits.view(-1, self.num_labels), labels.view(-1))
|
| 1055 |
+
elif self.config.problem_type == "multi_label_classification":
|
| 1056 |
+
loss_fct = BCEWithLogitsLoss()
|
| 1057 |
+
loss = loss_fct(logits, labels)
|
| 1058 |
+
if not return_dict:
|
| 1059 |
+
output = (logits,) + outputs[1:]
|
| 1060 |
+
return ((loss,) + output) if loss is not None else output
|
| 1061 |
+
|
| 1062 |
+
return SequenceClassifierOutput(
|
| 1063 |
+
loss=loss,
|
| 1064 |
+
logits=logits,
|
| 1065 |
+
hidden_states=outputs.hidden_states,
|
| 1066 |
+
attentions=outputs.attentions,
|
| 1067 |
+
)
|
| 1068 |
+
|
| 1069 |
+
|
| 1070 |
+
@auto_docstring
|
| 1071 |
+
class MraForMultipleChoice(MraPreTrainedModel):
|
| 1072 |
+
def __init__(self, config):
|
| 1073 |
+
super().__init__(config)
|
| 1074 |
+
|
| 1075 |
+
self.mra = MraModel(config)
|
| 1076 |
+
self.pre_classifier = nn.Linear(config.hidden_size, config.hidden_size)
|
| 1077 |
+
self.classifier = nn.Linear(config.hidden_size, 1)
|
| 1078 |
+
|
| 1079 |
+
# Initialize weights and apply final processing
|
| 1080 |
+
self.post_init()
|
| 1081 |
+
|
| 1082 |
+
@auto_docstring
|
| 1083 |
+
def forward(
|
| 1084 |
+
self,
|
| 1085 |
+
input_ids: torch.Tensor | None = None,
|
| 1086 |
+
attention_mask: torch.Tensor | None = None,
|
| 1087 |
+
token_type_ids: torch.Tensor | None = None,
|
| 1088 |
+
position_ids: torch.Tensor | None = None,
|
| 1089 |
+
inputs_embeds: torch.Tensor | None = None,
|
| 1090 |
+
labels: torch.Tensor | None = None,
|
| 1091 |
+
output_hidden_states: bool | None = None,
|
| 1092 |
+
return_dict: bool | None = None,
|
| 1093 |
+
**kwargs,
|
| 1094 |
+
) -> tuple | MultipleChoiceModelOutput:
|
| 1095 |
+
r"""
|
| 1096 |
+
input_ids (`torch.LongTensor` of shape `(batch_size, num_choices, sequence_length)`):
|
| 1097 |
+
Indices of input sequence tokens in the vocabulary.
|
| 1098 |
+
|
| 1099 |
+
Indices can be obtained using [`AutoTokenizer`]. See [`PreTrainedTokenizer.encode`] and
|
| 1100 |
+
[`PreTrainedTokenizer.__call__`] for details.
|
| 1101 |
+
|
| 1102 |
+
[What are input IDs?](../glossary#input-ids)
|
| 1103 |
+
token_type_ids (`torch.LongTensor` of shape `(batch_size, num_choices, sequence_length)`, *optional*):
|
| 1104 |
+
Segment token indices to indicate first and second portions of the inputs. Indices are selected in `[0,
|
| 1105 |
+
1]`:
|
| 1106 |
+
|
| 1107 |
+
- 0 corresponds to a *sentence A* token,
|
| 1108 |
+
- 1 corresponds to a *sentence B* token.
|
| 1109 |
+
|
| 1110 |
+
[What are token type IDs?](../glossary#token-type-ids)
|
| 1111 |
+
position_ids (`torch.LongTensor` of shape `(batch_size, num_choices, sequence_length)`, *optional*):
|
| 1112 |
+
Indices of positions of each input sequence tokens in the position embeddings. Selected in the range `[0,
|
| 1113 |
+
config.max_position_embeddings - 1]`.
|
| 1114 |
+
|
| 1115 |
+
[What are position IDs?](../glossary#position-ids)
|
| 1116 |
+
inputs_embeds (`torch.FloatTensor` of shape `(batch_size, num_choices, sequence_length, hidden_size)`, *optional*):
|
| 1117 |
+
Optionally, instead of passing `input_ids` you can choose to directly pass an embedded representation. This
|
| 1118 |
+
is useful if you want more control over how to convert *input_ids* indices into associated vectors than the
|
| 1119 |
+
model's internal embedding lookup matrix.
|
| 1120 |
+
labels (`torch.LongTensor` of shape `(batch_size,)`, *optional*):
|
| 1121 |
+
Labels for computing the multiple choice classification loss. Indices should be in `[0, ...,
|
| 1122 |
+
num_choices-1]` where `num_choices` is the size of the second dimension of the input tensors. (See
|
| 1123 |
+
`input_ids` above)
|
| 1124 |
+
"""
|
| 1125 |
+
return_dict = return_dict if return_dict is not None else self.config.return_dict
|
| 1126 |
+
num_choices = input_ids.shape[1] if input_ids is not None else inputs_embeds.shape[1]
|
| 1127 |
+
|
| 1128 |
+
input_ids = input_ids.view(-1, input_ids.size(-1)) if input_ids is not None else None
|
| 1129 |
+
attention_mask = attention_mask.view(-1, attention_mask.size(-1)) if attention_mask is not None else None
|
| 1130 |
+
token_type_ids = token_type_ids.view(-1, token_type_ids.size(-1)) if token_type_ids is not None else None
|
| 1131 |
+
position_ids = position_ids.view(-1, position_ids.size(-1)) if position_ids is not None else None
|
| 1132 |
+
inputs_embeds = (
|
| 1133 |
+
inputs_embeds.view(-1, inputs_embeds.size(-2), inputs_embeds.size(-1))
|
| 1134 |
+
if inputs_embeds is not None
|
| 1135 |
+
else None
|
| 1136 |
+
)
|
| 1137 |
+
|
| 1138 |
+
outputs = self.mra(
|
| 1139 |
+
input_ids,
|
| 1140 |
+
attention_mask=attention_mask,
|
| 1141 |
+
token_type_ids=token_type_ids,
|
| 1142 |
+
position_ids=position_ids,
|
| 1143 |
+
inputs_embeds=inputs_embeds,
|
| 1144 |
+
output_hidden_states=output_hidden_states,
|
| 1145 |
+
return_dict=return_dict,
|
| 1146 |
+
)
|
| 1147 |
+
|
| 1148 |
+
hidden_state = outputs[0] # (bs * num_choices, seq_len, dim)
|
| 1149 |
+
pooled_output = hidden_state[:, 0] # (bs * num_choices, dim)
|
| 1150 |
+
pooled_output = self.pre_classifier(pooled_output) # (bs * num_choices, dim)
|
| 1151 |
+
pooled_output = nn.ReLU()(pooled_output) # (bs * num_choices, dim)
|
| 1152 |
+
logits = self.classifier(pooled_output)
|
| 1153 |
+
|
| 1154 |
+
reshaped_logits = logits.view(-1, num_choices)
|
| 1155 |
+
|
| 1156 |
+
loss = None
|
| 1157 |
+
if labels is not None:
|
| 1158 |
+
loss_fct = CrossEntropyLoss()
|
| 1159 |
+
loss = loss_fct(reshaped_logits, labels)
|
| 1160 |
+
|
| 1161 |
+
if not return_dict:
|
| 1162 |
+
output = (reshaped_logits,) + outputs[1:]
|
| 1163 |
+
return ((loss,) + output) if loss is not None else output
|
| 1164 |
+
|
| 1165 |
+
return MultipleChoiceModelOutput(
|
| 1166 |
+
loss=loss,
|
| 1167 |
+
logits=reshaped_logits,
|
| 1168 |
+
hidden_states=outputs.hidden_states,
|
| 1169 |
+
attentions=outputs.attentions,
|
| 1170 |
+
)
|
| 1171 |
+
|
| 1172 |
+
|
| 1173 |
+
@auto_docstring
|
| 1174 |
+
class MraForTokenClassification(MraPreTrainedModel):
|
| 1175 |
+
def __init__(self, config):
|
| 1176 |
+
super().__init__(config)
|
| 1177 |
+
self.num_labels = config.num_labels
|
| 1178 |
+
|
| 1179 |
+
self.mra = MraModel(config)
|
| 1180 |
+
self.dropout = nn.Dropout(config.hidden_dropout_prob)
|
| 1181 |
+
self.classifier = nn.Linear(config.hidden_size, config.num_labels)
|
| 1182 |
+
|
| 1183 |
+
# Initialize weights and apply final processing
|
| 1184 |
+
self.post_init()
|
| 1185 |
+
|
| 1186 |
+
@auto_docstring
|
| 1187 |
+
def forward(
|
| 1188 |
+
self,
|
| 1189 |
+
input_ids: torch.Tensor | None = None,
|
| 1190 |
+
attention_mask: torch.Tensor | None = None,
|
| 1191 |
+
token_type_ids: torch.Tensor | None = None,
|
| 1192 |
+
position_ids: torch.Tensor | None = None,
|
| 1193 |
+
inputs_embeds: torch.Tensor | None = None,
|
| 1194 |
+
labels: torch.Tensor | None = None,
|
| 1195 |
+
output_hidden_states: bool | None = None,
|
| 1196 |
+
return_dict: bool | None = None,
|
| 1197 |
+
**kwargs,
|
| 1198 |
+
) -> tuple | TokenClassifierOutput:
|
| 1199 |
+
r"""
|
| 1200 |
+
labels (`torch.LongTensor` of shape `(batch_size, sequence_length)`, *optional*):
|
| 1201 |
+
Labels for computing the token classification loss. Indices should be in `[0, ..., config.num_labels - 1]`.
|
| 1202 |
+
"""
|
| 1203 |
+
return_dict = return_dict if return_dict is not None else self.config.return_dict
|
| 1204 |
+
|
| 1205 |
+
outputs = self.mra(
|
| 1206 |
+
input_ids,
|
| 1207 |
+
attention_mask=attention_mask,
|
| 1208 |
+
token_type_ids=token_type_ids,
|
| 1209 |
+
position_ids=position_ids,
|
| 1210 |
+
inputs_embeds=inputs_embeds,
|
| 1211 |
+
output_hidden_states=output_hidden_states,
|
| 1212 |
+
return_dict=return_dict,
|
| 1213 |
+
)
|
| 1214 |
+
|
| 1215 |
+
sequence_output = outputs[0]
|
| 1216 |
+
|
| 1217 |
+
sequence_output = self.dropout(sequence_output)
|
| 1218 |
+
logits = self.classifier(sequence_output)
|
| 1219 |
+
|
| 1220 |
+
loss = None
|
| 1221 |
+
if labels is not None:
|
| 1222 |
+
loss_fct = CrossEntropyLoss()
|
| 1223 |
+
# Only keep active parts of the loss
|
| 1224 |
+
if attention_mask is not None:
|
| 1225 |
+
active_loss = attention_mask.view(-1) == 1
|
| 1226 |
+
active_logits = logits.view(-1, self.num_labels)
|
| 1227 |
+
active_labels = torch.where(
|
| 1228 |
+
active_loss, labels.view(-1), torch.tensor(loss_fct.ignore_index).type_as(labels)
|
| 1229 |
+
)
|
| 1230 |
+
loss = loss_fct(active_logits, active_labels)
|
| 1231 |
+
else:
|
| 1232 |
+
loss = loss_fct(logits.view(-1, self.num_labels), labels.view(-1))
|
| 1233 |
+
|
| 1234 |
+
if not return_dict:
|
| 1235 |
+
output = (logits,) + outputs[1:]
|
| 1236 |
+
return ((loss,) + output) if loss is not None else output
|
| 1237 |
+
|
| 1238 |
+
return TokenClassifierOutput(
|
| 1239 |
+
loss=loss,
|
| 1240 |
+
logits=logits,
|
| 1241 |
+
hidden_states=outputs.hidden_states,
|
| 1242 |
+
attentions=outputs.attentions,
|
| 1243 |
+
)
|
| 1244 |
+
|
| 1245 |
+
|
| 1246 |
+
@auto_docstring
|
| 1247 |
+
class MraForQuestionAnswering(MraPreTrainedModel):
|
| 1248 |
+
def __init__(self, config):
|
| 1249 |
+
super().__init__(config)
|
| 1250 |
+
|
| 1251 |
+
config.num_labels = 2
|
| 1252 |
+
self.num_labels = config.num_labels
|
| 1253 |
+
|
| 1254 |
+
self.mra = MraModel(config)
|
| 1255 |
+
self.qa_outputs = nn.Linear(config.hidden_size, config.num_labels)
|
| 1256 |
+
|
| 1257 |
+
# Initialize weights and apply final processing
|
| 1258 |
+
self.post_init()
|
| 1259 |
+
|
| 1260 |
+
@auto_docstring
|
| 1261 |
+
def forward(
|
| 1262 |
+
self,
|
| 1263 |
+
input_ids: torch.Tensor | None = None,
|
| 1264 |
+
attention_mask: torch.Tensor | None = None,
|
| 1265 |
+
token_type_ids: torch.Tensor | None = None,
|
| 1266 |
+
position_ids: torch.Tensor | None = None,
|
| 1267 |
+
inputs_embeds: torch.Tensor | None = None,
|
| 1268 |
+
start_positions: torch.Tensor | None = None,
|
| 1269 |
+
end_positions: torch.Tensor | None = None,
|
| 1270 |
+
output_hidden_states: bool | None = None,
|
| 1271 |
+
return_dict: bool | None = None,
|
| 1272 |
+
**kwargs,
|
| 1273 |
+
) -> tuple | QuestionAnsweringModelOutput:
|
| 1274 |
+
return_dict = return_dict if return_dict is not None else self.config.return_dict
|
| 1275 |
+
|
| 1276 |
+
outputs = self.mra(
|
| 1277 |
+
input_ids,
|
| 1278 |
+
attention_mask=attention_mask,
|
| 1279 |
+
token_type_ids=token_type_ids,
|
| 1280 |
+
position_ids=position_ids,
|
| 1281 |
+
inputs_embeds=inputs_embeds,
|
| 1282 |
+
output_hidden_states=output_hidden_states,
|
| 1283 |
+
return_dict=return_dict,
|
| 1284 |
+
)
|
| 1285 |
+
|
| 1286 |
+
sequence_output = outputs[0]
|
| 1287 |
+
|
| 1288 |
+
logits = self.qa_outputs(sequence_output)
|
| 1289 |
+
start_logits, end_logits = logits.split(1, dim=-1)
|
| 1290 |
+
start_logits = start_logits.squeeze(-1)
|
| 1291 |
+
end_logits = end_logits.squeeze(-1)
|
| 1292 |
+
|
| 1293 |
+
total_loss = None
|
| 1294 |
+
if start_positions is not None and end_positions is not None:
|
| 1295 |
+
# If we are on multi-GPU, split add a dimension
|
| 1296 |
+
if len(start_positions.size()) > 1:
|
| 1297 |
+
start_positions = start_positions.squeeze(-1)
|
| 1298 |
+
if len(end_positions.size()) > 1:
|
| 1299 |
+
end_positions = end_positions.squeeze(-1)
|
| 1300 |
+
# sometimes the start/end positions are outside our model inputs, we ignore these terms
|
| 1301 |
+
ignored_index = start_logits.size(1)
|
| 1302 |
+
start_positions = start_positions.clamp(0, ignored_index)
|
| 1303 |
+
end_positions = end_positions.clamp(0, ignored_index)
|
| 1304 |
+
|
| 1305 |
+
loss_fct = CrossEntropyLoss(ignore_index=ignored_index)
|
| 1306 |
+
start_loss = loss_fct(start_logits, start_positions)
|
| 1307 |
+
end_loss = loss_fct(end_logits, end_positions)
|
| 1308 |
+
total_loss = (start_loss + end_loss) / 2
|
| 1309 |
+
|
| 1310 |
+
if not return_dict:
|
| 1311 |
+
output = (start_logits, end_logits) + outputs[1:]
|
| 1312 |
+
return ((total_loss,) + output) if total_loss is not None else output
|
| 1313 |
+
|
| 1314 |
+
return QuestionAnsweringModelOutput(
|
| 1315 |
+
loss=total_loss,
|
| 1316 |
+
start_logits=start_logits,
|
| 1317 |
+
end_logits=end_logits,
|
| 1318 |
+
hidden_states=outputs.hidden_states,
|
| 1319 |
+
attentions=outputs.attentions,
|
| 1320 |
+
)
|
| 1321 |
+
|
| 1322 |
+
|
| 1323 |
+
__all__ = [
|
| 1324 |
+
"MraForMaskedLM",
|
| 1325 |
+
"MraForMultipleChoice",
|
| 1326 |
+
"MraForQuestionAnswering",
|
| 1327 |
+
"MraForSequenceClassification",
|
| 1328 |
+
"MraForTokenClassification",
|
| 1329 |
+
"MraLayer",
|
| 1330 |
+
"MraModel",
|
| 1331 |
+
"MraPreTrainedModel",
|
| 1332 |
+
]
|
third_party/transformers/src/transformers/models/nemotron_h/__init__.py
ADDED
|
@@ -0,0 +1,27 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
# Copyright 2026 The HuggingFace Team. All rights reserved.
|
| 2 |
+
#
|
| 3 |
+
# Licensed under the Apache License, Version 2.0 (the "License");
|
| 4 |
+
# you may not use this file except in compliance with the License.
|
| 5 |
+
# You may obtain a copy of the License at
|
| 6 |
+
#
|
| 7 |
+
# http://www.apache.org/licenses/LICENSE-2.0
|
| 8 |
+
#
|
| 9 |
+
# Unless required by applicable law or agreed to in writing, software
|
| 10 |
+
# distributed under the License is distributed on an "AS IS" BASIS,
|
| 11 |
+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
| 12 |
+
# See the License for the specific language governing permissions and
|
| 13 |
+
# limitations under the License.
|
| 14 |
+
from typing import TYPE_CHECKING
|
| 15 |
+
|
| 16 |
+
from ...utils import _LazyModule
|
| 17 |
+
from ...utils.import_utils import define_import_structure
|
| 18 |
+
|
| 19 |
+
|
| 20 |
+
if TYPE_CHECKING:
|
| 21 |
+
from .configuration_nemotron_h import *
|
| 22 |
+
from .modeling_nemotron_h import *
|
| 23 |
+
else:
|
| 24 |
+
import sys
|
| 25 |
+
|
| 26 |
+
_file = globals()["__file__"]
|
| 27 |
+
sys.modules[__name__] = _LazyModule(__name__, _file, define_import_structure(_file), module_spec=__spec__)
|