# Monkey patching (recurso experimental)

O monkey patching permite substituir componentes de modelos globalmente sem modificar o código original do modelo. Uma vez registrados, os patches são aplicados automaticamente ao carregar qualquer modelo com [from_pretrained()](/docs/transformers/main/pt/main_classes/model#transformers.PreTrainedModel.from_pretrained) ou `~PreTrainedModel.from_config`. Isso permite reestruturar modelos para requisitos específicos, como compatibilidade com quantização, aplicar otimizações ou experimentar variantes arquitetônicas.

> [!WARNING]
> **O monkey patching deve ser usado como último recurso** quando você precisa alterar o layout e a estrutura de um módulo e/ou seus pesos. Para muitas necessidades de personalização e otimização, tente usar a [interface de Atenção](./attention_interface), a [interface de Especialistas](./experts_interface) ou o [registro de Kernels](./kernel_doc/overview) em vez disso. Use monkey patching apenas quando precisar de alterações estruturais que não podem ser alcançadas apenas por meio de implementações de forward personalizadas (por exemplo, para compatibilidade com bibliotecas de quantização, fusão de camadas ou experimentos arquitetônicos).

## Início rápido

Aqui está um exemplo simples mostrando como substituir um componente de um modelo:

```python
from transformers import AutoModelForCausalLM
from transformers.models.llama.modeling_llama import LlamaAttention
from transformers.monkey_patching import register_patch_mapping

# Define your replacement class (must inherit from nn.Module)
class CustomLlamaAttention(LlamaAttention):
    def forward(self, *args, **kwargs):
        # Your custom implementation
        print("Using custom attention!")
        return super().forward(*args, **kwargs)

# Register the patch globally (only applies to transformers modeling modules)
register_patch_mapping(mapping={"LlamaAttention": CustomLlamaAttention})

# Load a model - the patch is automatically applied during initialization
model = AutoModelForCausalLM.from_pretrained("meta-llama/Llama-3.2-1B")

# All LlamaAttention layers in the model are now CustomLlamaAttention instances
print(type(model.model.layers[0].self_attn))  # <class '__main__.CustomLlamaAttention'>
```

## Como funciona

Os monkey patches funcionam por meio de um processo de duas etapas:

1. **Registro**: chame `register_patch_mapping` para adicionar mapeamentos a um registro global.

2. **Aplicação**: Os patches são aplicados automaticamente durante a inicialização do modelo:
   - **`from_pretrained` / `from_config`**: Os patches são aplicados **automaticamente** por meio de um gerenciador de contexto interno. Nenhuma ação adicional é necessária!
   - **Construção manual** (por exemplo, `Model(config)`): você deve usar o gerenciador de contexto `apply_patches` manualmente.

Uma vez registrados, os patches persistem e afetam todos os carregamentos de modelo subsequentes até que você os limpe com `clear_patch_mapping`.

**Limitações importantes**:

- Apenas classes nos módulos de modelagem do `transformers` podem ser modificadas (por exemplo, `LlamaAttention`, `LlamaMLP`).
- As chaves de mapeamento podem ser nomes de classe exatos ou padrões de expressão regular (veja [Correspondência de padrões](#pattern-matching) abaixo).

## Registro global

Use `register_patch_mapping` para registrar mapeamentos globalmente:

```python
from transformers.monkey_patching import register_patch_mapping

# Register a single patch
register_patch_mapping(
    mapping={"Qwen2MoeExperts": SequentialExperts}
)

# Register multiple patches at once
register_patch_mapping(
    mapping={
        "Qwen2MoeExperts": SequentialExperts,
        "Qwen2MoeAttention": CustomAttention,
    },
    # Overwrite existing patches if they exist
    overwrite=True,
)
```

## Correspondência de padrões

Você pode usar expressões regulares para corresponder a várias classes com um único padrão:

```python
from transformers.monkey_patching import register_patch_mapping

# Match all classes containing "Attention"
register_patch_mapping(
    mapping={".*Attention": CustomAttention}
)

# More examples
register_patch_mapping(
    mapping={
        ".*MoeExperts$": CustomExperts,           # Ends with "MoeExperts"
        "^Llama\\d+Attention$": CustomAttention,  # Llama2Attention, Llama3Attention, etc.
    }
)
```

**Importante**: correspondências exatas têm precedência sobre padrões. Se você registrar `"LlamaAttention"` e `".*Attention"`, as classes nomeadas `LlamaAttention` usarão a substituição de correspondência exata, enquanto outras classes correspondentes usarão a substituição de correspondência por padrão.

> [!WARNING]
> **Padrões de regex podem quebrar modelos silenciosamente.** Um padrão amplo como `".*Attention"` corresponderá a *todas* as classes cujo nome contenha "Attention" — incluindo classes de contêiner que envolvem a atenção que você realmente deseja substituir. Por exemplo, o BERT tem três classes relacionadas à atenção: `BertSelfAttention` e `BertCrossAttention` (as implementações internas de atenção) e `BertAttention` (um módulo externo que *contém* uma dessas classes internas). Aplicar um patch em todas as três com a mesma camada de atenção personalizada produz um modelo quebrado, pois o `BertAttention` externo não envolve mais o interno — ele *é* um, eliminando submódulos esperados como `self` e `output`. Prefira padrões estreitos (por exemplo, `".*SelfAttention$"`) ou nomes exatos de classes para evitar correspondências não intencionais.

Para desregistrar patches, use `unregister_patch_mapping`:

```python
from transformers.monkey_patching import unregister_patch_mapping

# Unregister a single patch (use exact name or pattern from registration)
unregister_patch_mapping(keys=["Qwen2MoeExperts"])

# Unregister multiple patches at once
unregister_patch_mapping(keys=["Qwen2MoeExperts", "Qwen2MoeAttention"])

# Unregister a pattern
unregister_patch_mapping(keys=[".*Attention"])
```

Para limpar todos os patches registrados, use `clear_patch_mapping`:

```python
from transformers.monkey_patching import clear_patch_mapping

clear_patch_mapping()
```

Para visualizar os patches atualmente registrados, use `get_patch_mapping`:

```python
from transformers.monkey_patching import get_patch_mapping

current_patches = get_patch_mapping()
print(current_patches)
```

## Construção manual de modelos

O gerenciador de contexto `apply_patches` é necessário apenas quando você está construindo modelos **manualmente** (por exemplo, `Model(config)`) sem usar `from_pretrained` ou `from_config`:

```python
from transformers import LlamaModel, LlamaConfig
from transformers.monkey_patching import register_patch_mapping, apply_patches

# Register patch globally
register_patch_mapping(mapping={"LlamaAttention": CustomAttention})

# For manual construction, you need the context manager
with apply_patches():
    model = LlamaModel(LlamaConfig())  # Uses CustomAttention

# Without the context manager, manual construction uses original classes
model = LlamaModel(LlamaConfig())  # Uses LlamaAttention

# But from_pretrained and from_config will always apply registered patches
model = LlamaModel.from_pretrained("meta-llama/Llama-3.2-1B")  # Uses CustomAttention
```

## Observações importantes

- **Tratamento de pesos**: O monkey patching substitui apenas classes, não pesos. Se a classe patcheada tiver um layout de pesos diferente, será necessário tratar as [conversões de pesos](./weightconverter) separadamente para garantir compatibilidade com os pesos pré-treinados. Consulte o [Exemplo completo](#complete-example) abaixo para ver como combinar monkey patches com mapeamentos de conversão de pesos.

- **Efeito global**: Os patches registrados com `register_patch_mapping` são aplicados globalmente a todos os modelos carregados após o registro. Use sempre `clear_patch_mapping` para limpar ao terminar, especialmente em testes, notebooks ou aplicações de longa duração.

- **Validação de classe**: A API valida automaticamente que as classes de substituição sejam subclasses de `nn.Module`. Se você passar uma classe inválida, receberá uma mensagem de erro clara.

- **Segurança de threads**: Todas as operações de patch são seguras para threads. Você pode registrar, desregistrar e aplicar patches com segurança a partir de múltiplas threads.

- **Comportamento de correspondência**: ao usar nomes de classe exatos, eles devem corresponder exatamente aos nomes de classe originais conforme aparecem no código-fonte do modelo (sensível a maiúsculas e minúsculas). Ao usar padrões de expressão regular, eles são correspondidos aos nomes de classe usando `re.search()`.

## Solução de problemas

### Meu patch não está sendo aplicado

**Verifique o nome da classe ou o padrão**: Certifique-se de que o nome da classe ou o padrão no seu mapeamento esteja correto:

```python
# For exact names - must match exactly (case-sensitive)
register_patch_mapping(mapping={"LlamaAttention": CustomAttention})

# For patterns - use valid regex
register_patch_mapping(mapping={".*Attention": CustomAttention})
```

**Verificar o registro**: use `get_patch_mapping` para confirmar que seu mapeamento foi registrado:

```python
print(get_patch_mapping())
# Shows all registered mappings: {'LlamaAttention': <class 'CustomAttention'>, '.*MLP': <class 'CustomMLP'>}
```

**Verificar a origem do modelo**: Encontre o nome exato da classe na origem do modelo:

```python
from transformers.models.llama import modeling_llama
print(dir(modeling_llama))  # Look for the class name
```

### Como sei se meu patch está funcionando?

Inspecione o modelo carregado para verificar o patch:

```python
model = AutoModelForCausalLM.from_pretrained("meta-llama/Llama-3.2-1B")

# Check the type of a specific module
print(type(model.model.layers[0].self_attn))  # Should show your custom class

# Or iterate through all modules
for name, module in model.named_modules():
    if 'attention' in name.lower():
        print(f"{name}: {type(module)}")
```

### Erros de incompatibilidade de forma dos pesos

Se a sua classe com patch tiver formas de pesos diferentes, registre uma conversão de pesos:

```python
from transformers.conversion_mapping import register_checkpoint_conversion_mapping, WeightConverter
from transformers.monkey_patching import register_patch_mapping

register_patch_mapping(
    mapping={
        "LlamaAttention": LlamaFusedAttention,
    }
)

register_checkpoint_conversion_mapping(
    model_type_or_class_name="llama",
    mapping=[
        WeightConverter(
            source_patterns=["q_proj", "k_proj", "v_proj"],
            target_patterns=["qkv_proj"],
            operations=[
                Concatenate(dim=0),
            ],
        )
    ],
    overwrite=True,
)
```

### Limpeza de patches

Sempre limpe os patches quando terminar para evitar afetar outros códigos:

```python
from transformers.monkey_patching import register_patch_mapping, clear_patch_mapping

try:
    register_patch_mapping(mapping={"LlamaAttention": CustomAttention})
    model = AutoModelForCausalLM.from_pretrained("meta-llama/Llama-2-7b-chat-hf")
    # ... use model ...
finally:
    clear_patch_mapping()  # Always clean up
```

## Exemplo completo

Aqui está um exemplo abrangente mostrando como reestruturar os módulos de especialistas e de atenção em um modelo Mixture-of-Experts (`qwen2_moe`) para compatibilidade com otimização e quantização. Isso demonstra:

1. Criando classes de substituição personalizadas que mantêm a mesma interface
2. Registrando monkey patches para múltiplos componentes
3. Tratando as conversões de pesos para a nova estrutura

```python
from typing import Unpack

import torch
import torch.nn as nn

from transformers import AutoModelForCausalLM, Concatenate, WeightConverter
from transformers.activations import ACT2FN
from transformers.cache_utils import Cache
from transformers.conversion_mapping import register_checkpoint_conversion_mapping
from transformers.integrations.sdpa_attention import sdpa_attention_forward
from transformers.models.qwen2_moe.modeling_qwen2_moe import apply_rotary_pos_emb
from transformers.monkey_patching import register_patch_mapping
from transformers.utils.generic import TransformersKwargs

class MoeMLP(nn.Module):
    def __init__(self, config):
        super().__init__()
        self.config = config
        self.num_experts = config.num_experts
        self.hidden_size = config.hidden_size
        self.intermediate_size = config.moe_intermediate_size
        self.gate_proj = nn.Linear(self.hidden_size, self.intermediate_size, bias=False)
        self.up_proj = nn.Linear(self.hidden_size, self.intermediate_size, bias=False)
        self.down_proj = nn.Linear(self.intermediate_size, self.hidden_size, bias=False)
        self.act_fn = ACT2FN[config.hidden_act]

    def forward(self, x):
        down_proj = self.down_proj(self.act_fn(self.gate_proj(x)) * self.up_proj(x))
        return down_proj

# Adapted from the original Qwen2MoeExperts
class ModuleListExperts(nn.ModuleList):
    def __init__(self, config):
        super().__init__()
        self.config = config
        self.num_experts = config.num_experts
        for _ in range(self.num_experts):
            self.append(MoeMLP(config))

    def forward(
        self, hidden_states: torch.Tensor, top_k_index: torch.Tensor, top_k_weights: torch.Tensor
    ) -> torch.Tensor:
        final_hidden_states = torch.zeros_like(hidden_states)
        with torch.no_grad():
            expert_mask = torch.nn.functional.one_hot(top_k_index, num_classes=self.num_experts)
            expert_mask = expert_mask.permute(2, 1, 0)

        for expert_idx in range(self.num_experts):
            top_k_pos, token_idx = torch.where(expert_mask[expert_idx])
            current_state = hidden_states[token_idx]
            current_hidden_states = self[expert_idx](current_state)
            current_hidden_states = current_hidden_states * top_k_weights[token_idx, top_k_pos, None]
            final_hidden_states.index_add_(0, token_idx, current_hidden_states.to(final_hidden_states.dtype))
        return final_hidden_states

# Adapted from the original Qwen2MoeAttention
class FusedQKVAttention(nn.Module):
    def __init__(self, config, layer_idx: int):
        super().__init__()
        self.config = config
        self.layer_idx = layer_idx
        self.head_dim = getattr(config, "head_dim", config.hidden_size // config.num_attention_heads)
        self.num_key_value_groups = config.num_attention_heads // config.num_key_value_heads
        self.scaling = self.head_dim**-0.5
        self.attention_dropout = config.attention_dropout
        self.is_causal = True

        self.qkv_proj = nn.Linear(config.hidden_size, 3 * config.num_attention_heads * self.head_dim, bias=True)
        self.o_proj = nn.Linear(config.num_attention_heads * self.head_dim, config.hidden_size, bias=False)

        if self.config.layer_types[layer_idx] == "sliding_attention":
            self.sliding_window = config.sliding_window

    def forward(
        self,
        hidden_states: torch.Tensor,
        position_embeddings: tuple[torch.Tensor, torch.Tensor] | None = None,
        attention_mask: torch.Tensor | None = None,
        past_key_values: Cache | None = None,
        **kwargs: Unpack[TransformersKwargs],
    ) -> tuple[torch.Tensor, torch.Tensor]:
        input_shape = hidden_states.shape[:-1]
        hidden_shape = (*input_shape, -1, self.head_dim)

        query_states, key_states, value_states = self.qkv_proj(hidden_states).chunk(3, dim=-1)

        query_states = query_states.view(hidden_shape).transpose(1, 2)
        key_states = key_states.view(hidden_shape).transpose(1, 2)
        value_states = value_states.view(hidden_shape).transpose(1, 2)

        cos, sin = position_embeddings
        query_states, key_states = apply_rotary_pos_emb(query_states, key_states, cos, sin)

        if past_key_values is not None:
            key_states, value_states = past_key_values.update(key_states, value_states, self.layer_idx)

        attn_output, attn_weights = sdpa_attention_forward(
            self,
            query_states,
            key_states,
            value_states,
            attention_mask,
            dropout=0.0 if not self.training else self.attention_dropout,
            scaling=self.scaling,
            **kwargs,
        )

        attn_output = attn_output.reshape(*input_shape, -1).contiguous()
        attn_output = self.o_proj(attn_output)
        return attn_output, attn_weights

# Registering monkey patches for the new attention and experts modules.
register_patch_mapping(
    mapping={
        "Qwen2MoeExperts": ModuleListExperts,
        "Qwen2MoeAttention": FusedQKVAttention,
    }
)

# Registering weight conversion mappings adapted for the new modules. This registration will:
# - Override the original conversion mapping for qwen2_moe which concatenated the experts into a single parameter format.
# - Concatenate the q_proj, k_proj, v_proj weights/biases into a single qkv_proj weight/bias for the new fused attention module.
register_checkpoint_conversion_mapping(
    model_type_or_class_name="qwen2_moe",
    mapping=[
        WeightConverter(
            source_patterns=["q_proj", "k_proj", "v_proj"],
            target_patterns=["qkv_proj"],
            operations=[Concatenate(dim=0)],
        ),
    ],
    overwrite=True,
)

model = AutoModelForCausalLM.from_pretrained("Qwen/Qwen1.5-MoE-A2.7B")
```

## Gravação e reprodução do roteamento de especialistas MoE

Workflows de treinamento de Mixture-of-Experts, como RLHF, precisam registrar para quais especialistas cada token foi roteado durante a geração e, em seguida, reproduzir esse roteamento exato em uma passada de treinamento separada. É possível construir esse fluxo de ponta a ponta usando os mecanismos existentes de monkey patching e captura de saída — sem necessidade de alterar os arquivos de modelagem.

O padrão tem três partes:

1. Uma **subclasse de roteador reproduzível** que pode, opcionalmente, ler índices de especialistas forçados de um atributo de instância.
2. Um **context manager** que define esses atributos em todos os roteadores antes de uma passagem de frente e os limpa em seguida.
3. Uma entrada no registro de captura de saída do modelo para que `output_<name>=True` exponha os índices por meio do caminho padrão `@capture_outputs`.

```python
from contextlib import contextmanager

import torch
import torch.nn.functional as F

from transformers import Qwen3MoeConfig, Qwen3MoeForCausalLM
from transformers.models.qwen3_moe.modeling_qwen3_moe import Qwen3MoeTopKRouter
from transformers.monkey_patching import apply_patches, register_patch_mapping
from transformers.utils.output_capturing import _CAN_RECORD_REGISTRY, OutputRecorder

class ReplayableQwen3MoeTopKRouter(Qwen3MoeTopKRouter):
    _forced_indices: torch.Tensor | None = None

    def forward(self, hidden_states):
        hidden_states = hidden_states.reshape(-1, self.hidden_dim)
        router_logits = F.linear(hidden_states, self.weight)
        router_logits = F.softmax(router_logits, dtype=torch.float, dim=-1)

        if self._forced_indices is not None:
            router_indices = self._forced_indices.to(router_logits.device).long()
            # Megatron-style replay: preserve expert path, recompute current scores
            router_top_value = router_logits.gather(-1, router_indices)
        else:
            router_top_value, router_indices = torch.topk(router_logits, self.top_k, dim=-1)

        if self.norm_topk_prob:
            router_top_value = router_top_value / router_top_value.sum(dim=-1, keepdim=True)
        return router_logits, router_top_value.to(router_logits.dtype), router_indices

@contextmanager
def replay_moe_routing(model, selected_experts_per_layer):
    routers = [m for m in model.modules() if isinstance(m, ReplayableQwen3MoeTopKRouter)]
    if len(routers) != len(selected_experts_per_layer):
        raise ValueError(f"Got {len(routers)} routers but {len(selected_experts_per_layer)} tensors")
    for r, t in zip(routers, selected_experts_per_layer):
        r._forced_indices = t
    try:
        yield
    finally:
        for r in routers:
            r._forced_indices = None

# Swap the router class and construct the model
register_patch_mapping({"Qwen3MoeTopKRouter": ReplayableQwen3MoeTopKRouter})
with apply_patches():
    model = Qwen3MoeForCausalLM(Qwen3MoeConfig(...)).eval()

# Expose `output_selected_experts=True` on the base model by adding an OutputRecorder
# at runtime. Index 2 of the router's tuple output is the expert indices.
inner = model.model
existing = _CAN_RECORD_REGISTRY.get(str(inner.__class__), {}) or {}
_CAN_RECORD_REGISTRY[str(inner.__class__)] = {
    **existing,
    "selected_experts": OutputRecorder(ReplayableQwen3MoeTopKRouter, index=2),
}

# Record
captured = inner(input_ids=input_ids, output_selected_experts=True)
selected_experts = captured.selected_experts  # tuple of (num_tokens, top_k) LongTensors

# Replay — same expert path regardless of current router weights
with replay_moe_routing(inner, list(selected_experts)):
    outputs = inner(input_ids=input_ids)
```

O Replay preserva os índices exatos dos especialistas e recalcula as pontuações de roteamento com os pesos atuais do roteador, de modo que os gradientes fluam pelos parâmetros ativos enquanto a seleção de especialistas permanece fixa. Este é o contrato mínimo de replay usado no treinamento de MoE no estilo Megatron.

### Interoperabilidade com vLLM

O `enable_return_routed_experts=True` do vLLM preenche `CompletionOutput.routed_experts` como um array `np.int32` de `(seq_len, num_layers, top_k)`. Converta-o para a lista por camada que este padrão espera com uma única expressão:

```python
selected = [
    torch.from_numpy(routed_experts[:, layer, :].copy()).long()
    for layer in range(routed_experts.shape[1])
]
with replay_moe_routing(model, selected):
    loss = model(input_ids=input_ids, labels=labels).loss
```

A mesma receita se aplica a outras famílias de MoE — subclasseie o `*TopKRouter` da família, corresponda ao contrato de retorno original (tipicamente `(router_logits, router_scores, router_indices)`) e registre o patch. Consulte a classe de roteador de cada modelo para a assinatura exata.

## Referência da API[[transformers.monkey_patching.register_patch_mapping]]

#### transformers.monkey_patching.register_patch_mapping[[transformers.monkey_patching.register_patch_mapping]]

```python
transformers.monkey_patching.register_patch_mapping(mapping: dict, overwrite: bool = False)
```

[Origem](https://github.com/huggingface/transformers/blob/main/src/transformers/monkey_patching.py#L85)

**Parâmetros:**

mapping (`Dict[str, type[nn.Module]]`) : Mapeamento de nomes de classes originais (ou padrões de expressão regular) para classes de substituição. Suporta: - Nomes de classes exatos: `"Qwen2MoeExperts"` → `CustomExperts` - Padrões de expressão regular: `".*Attention"` corresponde a `LlamaAttention`, `MistralAttention`, etc., ou `"^Llama\d+Attention$"` corresponde a `Llama2Attention`, `Llama3Attention`, etc.  Correspondências exatas têm precedência sobre padrões. Os padrões são correspondidos usando `re.search()`, portanto, podem corresponder em qualquer parte do nome da classe, a menos que você use âncoras (`^` para o início, `$` para o fim).

overwrite (`bool`, *opcional*, padrão `False`) : Se deve sobrescrever mapeamentos existentes para nomes de classes que já estão registrados.

Registre mapeamentos de patches para habilitar o patching automático durante a criação do modelo usando `from_pretrained`, `from_config` ou dentro do gerenciador de contexto `apply_patches`.

Use isso para registrar substituições de classes que serão aplicadas automaticamente ao carregar qualquer modelo. Isso é útil para compatibilidade com bibliotecas de quantização, otimizações estruturais e experimentação arquitetural. O mapeamento é global, pode crescer com múltiplas chamadas e pode ser limpo por completo.

Exemplo:
```python
from transformers import AutoModelForCausalLM
from transformers.monkey_patching import register_patch_mapping

# Define custom expert implementation
class SequentialExperts(nn.Module):
    ...

# Register exact class name
register_patch_mapping(
    mapping={"Qwen2MoeExperts": SequentialExperts}
)

# Register with regex pattern to match multiple classes
register_patch_mapping(
    mapping={".*Attention": CustomAttention}  # Matches LlamaAttention, MistralAttention, etc.
)

# Match specific model versions
register_patch_mapping(
    mapping={"^Llama\d+Attention$": CustomLlamaAttention}  # Matches Llama2Attention, Llama3Attention
)

# The patch will be automatically applied during loading
model = AutoModelForCausalLM.from_pretrained("meta-llama/Llama-3.2-1B")
```

Observação: Para conversões de pesos, use `~transformers.register_checkpoint_conversion_mapping` em vez disso.

#### transformers.monkey_patching.unregister_patch_mapping[[transformers.monkey_patching.unregister_patch_mapping]]

```python
transformers.monkey_patching.unregister_patch_mapping(keys: list)
```

[Origem](https://github.com/huggingface/transformers/blob/main/src/transformers/monkey_patching.py#L158)

**Parâmetros:**

keys (`List[str]`) : Lista de chaves de mapeamento (nomes de classes ou padrões de regex) a serem removidos do mapeamento de patch (por exemplo, `["Qwen2MoeExperts"]` ou `[".*Attention"]`).

Desregistre os mapeamentos de patch para desativar o patching automático.

Isso remove os mapeamentos especificados do registro global, impedindo que sejam aplicados durante o carregamento do modelo. Você deve fornecer exatamente o mesmo nome ou padrão que foi usado durante o registro.

Exemplo:
```python
from transformers import AutoModelForCausalLM
from transformers.monkey_patching import register_patch_mapping, unregister_patch_mapping

# Register a patch
register_patch_mapping(
    mapping={"Qwen2MoeExperts": CustomExperts}
)

# Unregister the patch
unregister_patch_mapping(["Qwen2MoeExperts"])

# The patch will no longer be applied during loading
model = AutoModelForCausalLM.from_pretrained("Qwen/Qwen1.5-MoE-A2.7B")
```

#### transformers.monkey_patching.clear_patch_mapping[[transformers.monkey_patching.clear_patch_mapping]]

```python
transformers.monkey_patching.clear_patch_mapping()
```

[Origem](https://github.com/huggingface/transformers/blob/main/src/transformers/monkey_patching.py#L209)

Limpar todos os mapeamentos de patch registrados.

Isso remove todos os mapeamentos registrados do registro global.

Exemplo:
```python
from transformers.monkey_patching import register_patch_mapping, clear_patch_mapping

# Register some patches
register_patch_mapping(
    mapping={"Qwen2MoeExperts": CustomExperts}
)

# Clear all patches
clear_patch_mapping()
```

#### transformers.monkey_patching.get_patch_mapping[[transformers.monkey_patching.get_patch_mapping]]

```python
transformers.monkey_patching.get_patch_mapping()
```

[Origem](https://github.com/huggingface/transformers/blob/main/src/transformers/monkey_patching.py#L198)

**Retorna:** `Dict[str, type[nn.Module]]`

Dicionário que mapeia nomes de classes ou padrões para classes de substituição.

Obtenha todos os mapeamentos de patch registrados.

#### transformers.monkey_patching.apply_patches[[transformers.monkey_patching.apply_patches]]

```python
transformers.monkey_patching.apply_patches()
```

[Origem](https://github.com/huggingface/transformers/blob/main/src/transformers/monkey_patching.py#L233)

Gerenciador de contexto para aplicar os monkey patches registrados dentro de um bloco de código.

Isso substitui temporariamente as classes originais pelas substituições registradas durante a execução do bloco e restaura as classes originais em seguida.

Exemplo:
```python
from transformers import Qwen2MoeModel, Qwen2MoeConfig
from transformers.monkey_patching import register_patch_mapping, apply_patches

# Register a patch
register_patch_mapping(
    mapping={"Qwen2MoeExperts": CustomExperts}
)

# Apply patches within the context
with apply_patches():
    # The model will use CustomExperts instead of Qwen2MoeExperts
    model = Qwen2MoeModel(Qwen2MoeConfig())

# Outside the context, original classes are restored
# The model will use Qwen2MoeExperts again
model = Qwen2MoeModel(Qwen2MoeConfig())
```

