# OFT

    

Control de la difusión de texto a imagen mediante ajuste fino ortogonal

[Orthogonal Finetuning (OFT)](https://hf.co/papers/2306.07280) y [OFTv2](https://huggingface.co/papers/2506.19847) son un método desarrollado para adaptar modelos de difusión de texto a imagen. Funciona reparametrizando las matrices de pesos preentrenadas con su matriz ortogonal para preservar la información del modelo preentrenado. Para reducir el número de parámetros, OFT introduce una estructura de bloque diagonal en la matriz ortogonal. El método se centra principalmente en preservar el rendimiento generativo de un modelo preentrenado en el modelo afinado. Intenta mantener la misma similitud coseno ([energía hipersférica](https://huggingface.co/papers/1805.09298)) entre todas las neuronas por pares en una capa, ya que esto captura mejor la información semántica entre las neuronas. Esto significa que OFT es más capaz de preservar el sujeto y es mejor para la generación controlable (similar a [ControlNet](https://huggingface.co/docs/diffusers/using-diffusers/controlnet)).

El resumen del artículo es:

*Los grandes modelos de difusión de texto a imagen poseen capacidades impresionantes para generar imágenes fotorrealistas a partir de indicaciones de texto. Cómo guiar o controlar de manera efectiva a estos potentes modelos para que realicen diferentes tareas posteriores se convierte en un problema abierto importante. Para abordar este desafío, introducimos un método de ajuste fino fundamentado: Orthogonal Finetuning (OFT), para adaptar los modelos de difusión de texto a imagen a tareas posteriores. A diferencia de los métodos existentes, OFT puede preservar de forma demostrable la energía hipersférica, que caracteriza la relación neuronal por pares en la hipersfera unitaria. Descubrimos que esta propiedad es crucial para preservar la capacidad de generación semántica de los modelos de difusión de texto a imagen. Para mejorar la estabilidad del ajuste fino, proponemos además Constrained Orthogonal Finetuning (COFT), que impone una restricción de radio adicional a la hipersfera. Específicamente, consideramos dos tareas importantes de ajuste fino de texto a imagen: la generación dirigida por sujeto, cuyo objetivo es generar imágenes específicas de un sujeto a partir de unas pocas imágenes de dicho sujeto y una indicación de texto, y la generación controlable, cuyo objetivo es permitir que el modelo reciba señales de control adicionales. Demostramos empíricamente que nuestro marco OFT supera a los métodos existentes en calidad de generación y velocidad de convergencia*.

OFT preserva la energía hipersférica al aprender una transformación ortogonal para las neuronas, de modo que la similitud de coseno entre ellas permanezca inalterada, lo que potencialmente conduce a un menor olvido del conocimiento aprendido previamente. En la práctica, esto implica tomar el producto matricial de una matriz ortogonal con la matriz de pesos preentrenada. Sin embargo, para ser eficiente en parámetros, la matriz ortogonal se representa como una matriz diagonal por bloques con bloques de rango `r`. Mientras que LoRA reduce el número de parámetros entrenables mediante estructuras de bajo rango, OFT reduce el número de parámetros entrenables mediante una estructura de matriz diagonal por bloques dispersa.

## Resumen de las pruebas de rendimiento

<iframe src="https://peft-internal-testing-peft-method-comparison-embed.hf.space/?highlight[type]=OFT" frameborder="0" width="850" height="1000"
>

## Fusionar los pesos de OFT en el modelo base

De manera similar a LoRA, los pesos aprendidos por OFT pueden integrarse en las matrices de pesos preentrenadas mediante la función [`~OFTModel.merge_and_unload()`. Esta función fusiona los pesos del adaptador con el modelo base, lo que permite utilizar el modelo recién fusionado de forma efectiva como un modelo independiente.

## Uso de ejemplo de OFT

Para usar OFT para el ajuste fino cuantizado con [TRL](https://github.com/huggingface/trl) para el ajuste fino `SFT`, `PPO` o `DPO`, siga el siguiente esquema:

```py
from transformers import AutoTokenizer, AutoModelForCausalLM, BitsAndBytesConfig
from trl import SFTTrainer
from peft import OFTConfig

if use_quantization:
    bnb_config = BitsAndBytesConfig(
        load_in_4bit=True,
        bnb_4bit_quant_type="nf4",
        bnb_4bit_compute_dtype=torch.bfloat16,
        bnb_4bit_use_double_quant=True,
        bnb_4bit_quant_storage=torch.bfloat16,
    )

model = AutoModelForCausalLM.from_pretrained(
    "model_name",
    quantization_config=bnb_config
)
tokenizer = AutoTokenizer.from_pretrained("model_name")

# Configure OFT
peft_config = OFTConfig(
    oft_block_size=32,
    use_cayley_neumann=True,
    target_modules="all-linear",
    bias="none",
    task_type="CAUSAL_LM"
)

trainer = SFTTrainer(
    model=model,
    train_dataset=ds['train'],
    peft_config=peft_config,
    processing_class=tokenizer,
    args=training_arguments,
    data_collator=collator,
)

trainer.train()
```

# API

## OFTConfig[[peft.OFTConfig]]

#### peft.OFTConfig[[peft.OFTConfig]]

```python
peft.OFTConfig(task_type: Optional[Union[str, TaskType]] = None, peft_type: Optional[Union[str, PeftType]] = None, auto_mapping: Optional[dict] = None, peft_version: Optional[str] = None, base_model_name_or_path: Optional[str] = None, revision: Optional[str] = None, inference_mode: bool = False, r: int = 0, oft_block_size: int = 32, module_dropout: float = 0.0, target_modules: Optional[Union[list[str], str]] = None, fan_in_fan_out: bool = False, bias: Literal['none', 'all', 'oft_only'] = 'none', exclude_modules: Optional[Union[list[str], str]] = None, init_weights: bool = True, layers_to_transform: Optional[Union[list[int], int]] = None, layers_pattern: Optional[Union[list[str], str]] = None, modules_to_save: Optional[list[str]] = None, coft: bool = False, eps: float = 6e-05, block_share: bool = False, use_cayley_neumann: bool = True, num_cayley_neumann_terms: int = 5)
```

[Fuente](https://github.com/huggingface/peft/blob/main/src/peft/tuners/oft/config.py#L28)

**Parámetros:**

r (`int`) : rango de OFT, número de bloques de OFT por capa inyectada. Un `r` mayor resulta en matrices de actualización más dispersas con menos parámetros entrenables. Solo puede especificar `r` o `oft_block_size`, pero no ambos simultáneamente, porque `r` × `oft_block_size` = dimensión de la capa. Por simplicidad, le permitimos especificar `r` o `oft_block_size` e inferir el otro. El valor predeterminado es `r = 0`; se recomienda al usuario establecer `oft_block_size` en su lugar para mayor claridad.

oft_block_size (`int`) : Tamaño del bloque OFT en las distintas capas. Un `oft_block_size` mayor genera matrices de actualización más densas con más parámetros entrenables. Elige `oft_block_size` de modo que sea divisible por la dimensión de entrada de la capa (`in_features`), por ejemplo, 4, 8, 16. Solo puedes especificar `r` o `oft_block_size`, pero no ambos a la vez, ya que `r` × `oft_block_size` = dimensión de la capa. Por simplicidad, te permitimos especificar `r` o `oft_block_size` y se infiere el otro. El valor predeterminado es `oft_block_size = 32`.

use_cayley_neumann (bool) : Especifica si se debe usar la parametrización de Cayley-Neumann (eficiente pero aproximada) o la parametrización de Cayley estándar (exacta pero computacionalmente costosa debido a la inversa de matriz). Recomendamos establecerla en `True` para una mejor eficiencia, aunque el rendimiento puede ser ligeramente peor debido al error de aproximación. Pruebe ambas configuraciones (`True` y `False`) según sus necesidades. El valor predeterminado es `False`.

module_dropout (`float`) : La probabilidad de dropout multiplicativo, que establece los bloques OFT como identidad durante el entrenamiento, de manera similar a la capa de dropout en LoRA.

target_modules (`Optional[Union[list[str], str]]`) : Los nombres de los módulos a los que se aplicará el adaptador. Si se especifica, solo se reemplazarán los módulos con los nombres indicados. Al pasar una cadena de texto, se realizará una coincidencia mediante expresión regular. Al pasar una lista de cadenas de texto, se realizará una coincidencia exacta o se verificará si el nombre del módulo termina con alguna de las cadenas pasadas. Si se especifica como 'all-linear', se seleccionarán todos los módulos lineales, excluyendo la capa de salida. Si no se especifica, los módulos se seleccionarán según la arquitectura del modelo. Si la arquitectura no es conocida, se generará un error; en este caso, debe especificar los módulos objetivo manualmente.

fan_in_fan_out (`bool`) : Establezca este valor en True si la capa que se va a reemplazar almacena el peso como (fan_in, fan_out).

bias (`str`) : Tipo de sesgo para OFT. Puede ser 'none', 'all' o 'oft_only'. Si es 'all' o 'oft_only', los sesgos correspondientes se actualizarán durante el entrenamiento. Tenga en cuenta que esto significa que, incluso al desactivar los adaptadores, el modelo no producirá la misma salida que habría producido el modelo base sin adaptación.

exclude_modules (`Optional[Union[List[str], str]]`) : Los nombres de los módulos a los que no se aplicará el adaptador. Al pasar una cadena de caracteres, se realizará una coincidencia con una expresión regular. Al pasar una lista de cadenas de caracteres, se realizará una coincidencia exacta o se comprobará si el nombre del módulo termina con alguna de las cadenas de caracteres pasadas.

init_weights (`bool`) : Si se debe realizar la inicialización de los pesos de OFT.

layers_to_transform (`Union[List[int], int]`) : Los índices de las capas a transformar. Si se pasa una lista de enteros, se aplicará el adaptador a los índices de capa especificados en esta lista. Si se pasa un solo entero, se aplicarán las transformaciones a la capa en este índice.

layers_pattern (`Optional[Union[List[str], str]]`) : El nombre del patrón de la capa, utilizado solo si `layers_to_transform` es diferente de `None`. Esto debe apuntar al `nn.ModuleList` del modelo, que a menudo se llama `'layers'` o `'h'`.

modules_to_save (`List[str]`) : Lista de módulos, aparte de las capas de adaptador, que se configurarán como entrenables y se guardarán en el punto de control final.

coft (`bool`) : Si se debe usar la variante restringida de OFT o no, desactivado por defecto.

eps (`float`) : La intensidad de control de COFT. El grado de libertad de rotación. Solo tiene efecto si `coft` está establecido en True.

block_share (`bool`) : Si se comparten o no los parámetros de OFT entre bloques. Por defecto, es `False`.

Esta es la clase de configuración para almacenar la configuración de un [OFTModel](/docs/peft/main/es/package_reference/oft#peft.OFTModel).

#### check_kwargs[[peft.OFTConfig.check_kwargs]]

```python
check_kwargs(**kwargs)
```

[Fuente](https://github.com/huggingface/peft/blob/main/src/peft/tuners/oft/config.py#L198)

**Parámetros:**

kwargs (argumentos de palabra clave adicionales, *opcional*) : Argumentos de palabra clave adicionales que se pasan a la inicialización de la clase hija.

Comprueba si los kwargs son válidos para la configuración.

## OFTModel[[peft.OFTModel]]

#### peft.OFTModel[[peft.OFTModel]]

```python
peft.OFTModel(model, peft_config: Union[PeftConfig, dict[str, PeftConfig]], adapter_name: str, low_cpu_mem_usage: bool = False, state_dict: Optional[dict[str, torch.Tensor]] = None)
```

[Fuente](https://github.com/huggingface/peft/blob/main/src/peft/tuners/oft/model.py#L44)

**Parámetros:**

model (`torch.nn.Module`) : El modelo al que se adjuntarán las capas del adaptador de sintonización.

config ([OFTConfig](/docs/peft/main/es/package_reference/oft#peft.OFTConfig)) : La configuración del modelo OFT.

adapter_name (`str`) : El nombre del adaptador, por defecto es `"default"`.

low_cpu_mem_usage (`bool`, `optional`, por defecto `False`) : Crea pesos de adaptador vacíos en el dispositivo meta. Útil para acelerar el proceso de carga.

**Devuelve:** `torch.nn.Module`

El modelo OFT.

Crea un modelo de Orthogonal Finetuning a partir de un modelo preentrenado. El método se describe en https://huggingface.co/papers/2306.07280

Ejemplo:
```py
>>> from diffusers import StableDiffusionPipeline
>>> from peft import OFTModel, OFTConfig

>>> config_te = OFTConfig(
...     r=8,
...     target_modules=["k_proj", "q_proj", "v_proj", "out_proj", "fc1", "fc2"],
...     module_dropout=0.0,
...     init_weights=True,
... )
>>> config_unet = OFTConfig(
...     r=8,
...     target_modules=[
...         "proj_in",
...         "proj_out",
...         "to_k",
...         "to_q",
...         "to_v",
...         "to_out.0",
...         "ff.net.0.proj",
...         "ff.net.2",
...     ],
...     module_dropout=0.0,
...     init_weights=True,
... )

>>> model = StableDiffusionPipeline.from_pretrained("runwayml/stable-diffusion-v1-5")
>>> model.text_encoder = OFTModel(model.text_encoder, config_te, "default")
>>> model.unet = OFTModel(model.unet, config_unet, "default")
```

**Atributos**:
- **model** (`~torch.nn.Module`) -- El modelo que se va a adaptar.
- **peft_config** ([OFTConfig](/docs/peft/main/es/package_reference/oft#peft.OFTConfig)): La configuración del modelo OFT.

