PEFT documentation
PSOFT
PSOFT
PSOFT es un método de ajuste fino eficiente en parámetros basado en Ajuste Fino Ortogonal (OFT) que preserva las relaciones geométricas de los vectores de columnas de pesos preentrenados, al tiempo que logra un equilibrio entre el rendimiento y la eficiencia multidimensional, que incluye el número de parámetros, el uso de memoria y el coste computacional. Al restringir las transformaciones ortogonales a un subespacio principal de bajo rango derivado de los pesos preentrenados, PSOFT cierra la brecha entre LoRA y OFT, proporcionando tanto garantías teóricas como adaptabilidad práctica. Su eficacia se valida mediante evaluaciones exhaustivas en diversos conjuntos de referencia, incluidos GLUE, VTAB-1K, GSM8K, MATH y conjuntos de referencia de razonamiento de sentido común.
- Solo se admiten capas
nn.Linear. - No se admiten capas cuantizadas.
El resumen del artículo es:
Impulsado por el rápido crecimiento de los parámetros de los modelos, el ajuste fino eficiente de parámetros (PEFT) se ha vuelto esencial para adaptar modelos grandes a diversas tareas de bajo nivel con recursos computacionales limitados. Dentro de este paradigma, el ajuste fino ortogonal y sus variantes preservan las representaciones semánticas de los modelos preentrenados, pero tienen dificultades para lograr tanto expresividad como eficiencia en términos de número de parámetros, memoria y cómputo. Para superar esta limitación, proponemos el ajuste fino ortogonal eficiente con adaptación del subespacio principal (PSOFT), que confina las transformaciones ortogonales al subespacio principal de los pesos preentrenados. Específicamente, PSOFT construye este subespacio mediante descomposición de matrices para habilitar transformaciones compatibles, establece una condición teórica que mantiene estrictamente la geometría de este subespacio para la preservación semántica esencial, e introduce vectores ajustables eficientes que relajan gradualmente la ortogonalidad durante el entrenamiento para mejorar la adaptabilidad. Experimentos extensos en 35 tareas de NLP y CV a través de cuatro modelos representativos demuestran que PSOFT ofrece una solución práctica y escalable para lograr simultáneamente la preservación semántica, la expresividad y la eficiencia multidimensional en PEFT.
Cómo funciona PSOFT
PSOFT descompone cada matriz de pesos en y usando SVD:
El subespacio principal se construye a partir de los $r$ componentes singulares principales:
(PSOFT-SO: PSOFT con ortogonalidad estricta)
(PSOFT-RO: PSOFT con ortogonalidad relajada
Durante el entrenamiento, $A$, $B$ y se mantienen congelados, y solo (o con y $\beta$) es entrenable.
Para ser compatible con el marco PEFT (que espera actualizaciones aditivas de pesos), PSOFT se implementa en la siguiente forma aditiva:
Parámetros entrenables
Tras aplicar PSOFT:
- Los pesos del modelo original ($A$, $B$ y $W_{\text{res}}$) se mantienen congelados.
- Solo la matriz ortogonal (y opcionalmente $\alpha$, $\beta$) son entrenables.
- No se introducen parámetros de sesgo adicionales.
Uso básico
import torch
from transformers import AutoModelForCausalLM, AutoTokenizer
from peft import PsoftConfig, get_peft_model
# Load base model
model_id = "facebook/opt-125m"
model = AutoModelForCausalLM.from_pretrained(model_id)
# Configure PSOFT
config = PsoftConfig(
r=32, # the dimension of trainable matrix R,
psoft_alpha=32, # scaling factor (typically set to r in PSOFT),
target_modules=["q_proj", "v_proj"], # target attention projection layers
ab_svd_init="psoft_init", # principal subspace initialization
psoft_svd="full", # SVD method
psoft_orth=True, # enable orthogonal R (Cayley parameterization)
psoft_mag_a=True, # enable tunable vector alpha
psoft_mag_b=True, # enable tunable vector beta
use_cayley_neumann=False, # disable Cayley–Neumann approximation
num_cayley_neumann_terms=5, # number of Neumann series terms
cayley_neumann_eps=None, # improve numerical stability
)
# Apply PSOFT
model = get_peft_model(model, config)
model.train()
tokenizer = AutoTokenizer.from_pretrained(model_id)
tokenizer.pad_token = tokenizer.eos_token
# Train
inputs = tokenizer("Hello world", return_tensors="pt", padding=True)
loss = model(**inputs, labels=inputs["input_ids"]).loss
loss.backward()
trainable = [p for p in model.parameters() if p.requires_grad]
optimizer = torch.optim.AdamW(trainable, lr=5e-4)
optimizer.step()
optimizer.zero_grad(set_to_none=True)Opciones de configuración
Modo diferente
(PSOFT-SO: PSOFT con ortogonalidad estricta)
config = PsoftConfig(psoft_orth=True,psoft_mag_a=False,psoft_mag_b=False)(PSOFT-RO: PSOFT con ortogonalidad relajada)
config = PsoftConfig(psoft_orth=True,psoft_mag_a=True,psoft_mag_b=True)Buenas prácticas
- Elección del rango: los rangos más pequeños (p. ej.,
32–128) son adecuados para tareas más simples, mientras que los rangos más grandes (p. ej.,64–256) ofrecen una mayor expresividad para tareas más complejas, a costa de un aumento en los parámetros y la computación. - Scaling Factor: El factor de escala suele establecerse en en PSOFT.
- Tasa de aprendizaje: Utilice tasas de aprendizaje estándar (p. ej.,
1e-4a5e-3) para un entrenamiento estable. - Inicialización SVD: la opción
lowrankes más eficiente en memoria y cómputo quefull, lo que la hace más adecuada para modelos grandes. - Aproximación de Cayley–Neumann: cuando el rango es grande, habilitar la aproximación de Cayley–Neumann puede mejorar significativamente la eficiencia computacional, mientras que el beneficio es menos notable para rangos pequeños. En la práctica, un número pequeño de términos de la serie de Neumann (típicamente
5) suele ofrecer un buen equilibrio entre precisión y eficiencia.
Resumen de las pruebas de rendimiento
API
PsoftConfig
clase peft.PsoftConfig
< source >( task_type: Optional[Union[str, TaskType]] = Nonepeft_type: Optional[Union[str, PeftType]] = Noneauto_mapping: Optional[dict] = Nonepeft_version: Optional[str] = Nonebase_model_name_or_path: Optional[str] = Nonerevision: Optional[str] = Noneinference_mode: bool = Falser: int = 32target_modules: Optional[Union[list[str], str]] = Noneexclude_modules: Optional[Union[list[str], str]] = Nonepsoft_alpha: int = 32psoft_dropout: float = 0.0fan_in_fan_out: bool = Falseab_svd_init: Literal['psoft_init', 'pissa_init'] = 'psoft_init'psoft_svd: Literal['full', 'lowrank'] = 'full'psoft_svd_lowrank_niter: int = 10random_seed: int = 0psoft_orth: bool = Truepsoft_mag_b: bool = Truepsoft_mag_a: bool = Trueuse_cayley_neumann: bool = Falsenum_cayley_neumann_terms: int = 5cayley_neumann_eps: Optional[float] = Nonemodules_to_save: Optional[list[str]] = Noneinit_weights: bool = Truelayers_to_transform: Optional[Union[list[int], int]] = Nonelayers_pattern: Optional[Union[list[str], str]] = None )
Parámetros
- r (
int) — Por defecto, 32. El rango PSOFT (r) controla la capacidad del adaptador a través de una transformación R de r*r. Los rangos más pequeños, de 32 a 128, suelen ser suficientes para tareas simples. Las tareas más complejas pueden beneficiarse de rangos de 64 a 256, lo que aumenta la expresividad a costa de parámetros y cómputo adicionales. Consulte el artículo para ver configuraciones validadas empíricamente: https://openreview.net/forum?id=FSHrinMArK. - 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 caracteres, se realizará una coincidencia mediante expresión regular. Al pasar una lista de cadenas de caracteres, 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/Conv1D (si el modelo es un PreTrainedModel, excluyendo la capa de salida). Si no se especifica, los módulos se elegirá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. - 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 mediante 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. - psoft_alpha (
int) — Por defecto, 32. Controla el factor de escalado de PSOFT. Misma semántica que alpha de LoRA. - psoft_dropout (
float) — Valor predeterminado: 0.0. Dropout para la ruta PSOFT. Misma semántica que el dropout de LoRA. - fan_in_fan_out (
bool) — Establezca este valor en True si la capa que se va a reemplazar almacena los pesos como (fan_in, fan_out). Por ejemplo, gpt-2 utilizaConv1D, que almacena los pesos como (fan_in, fan_out), por lo que este valor debe establecerse enTrue. - ab_svd_init (
Literal["psoft_init", "pissa_init"]) — Por defecto, ‘psoft_init’. Estrategia de inicialización para A y B utilizada para construir el subespacio principal en PSOFT. ‘psoft_init’: inicialización basada en SVD con A ortogonal por filas, lo que garantiza una ortogonalidad estricta (PSOFT). ‘pissa_init’: inicialización basada en SVD con A y B simétricas (PiSSA estándar). - psoft_svd (
Literal["full", "lowrank"]) — Por defecto, ‘full’. Backend de SVD para la inicialización: ‘full’ usa torch.linalg.svd; ‘lowrank’ usa torch.svd_lowrank. - psoft_svd_lowrank_niter (
int) — Solo se utiliza cuando psoft_svd=‘lowrank’. El valor predeterminado es 10. Número de iteraciones de potencia utilizadas por torch.svd_lowrank cuando psoft_svd=‘lowrank’. - psoft_orth (
bool) — Por defecto, ‘True’. Si es True, restringe R para que sea ortogonal mediante parametrización de Cayley, preservando las relaciones geométricas entre las columnas de los vectores de pesos preentrenados. Si es False, R es una matriz libre sin restricciones de ortogonalidad. - psoft_mag_b (
bool) — Por defecto, ‘True’. Si es True, aprende un vector de escalado diagonal en el lado ‘output’ de R. Se suele combinar con psoft_mag_a para aumentar la adaptabilidad a la tarea, con una ligera distorsión de la geometría preentrenada. - psoft_mag_a (
bool) — Por defecto, ‘True’. Si es True, aprende un vector de escalado diagonal en el lado ‘input’ de R. Se suele combinar con psoft_mag_b para aumentar la adaptabilidad a la tarea, con una ligera distorsión de la geometría preentrenada. - use_cayley_neumann (
bool) — Por defecto, ‘False’. Indica si se debe utilizar la formulación de Cayley-Neumann de PSOFT o no. Establecerlo en True mejora la eficiencia computacional, pero a costa de un mayor error de aproximación para la ortogonalidad. - num_cayley_neumann_terms (
int) — Por defecto, 5. Solo se utiliza cuando use_cayley_neumann=True. Número de términos de Cayley-Neumann a utilizar. Un número mayor resulta en un menor error de aproximación para la ortogonalidad. - cayley_neumann_eps (
optional[float]) — Por defecto, ‘None’. Solo se utiliza cuando use_cayley_neumann=True. Límite opcional de la norma de Frobenius para la matriz generadora Q en la aproximación de Cayley-Neumann. Si es None (valor predeterminado), no se aplica ningún reescalado. Si se establece en un valor en (0, 1) (p. ej., 0.9), Q se reescala siempre que ||Q||_F supere el umbral para mejorar la estabilidad numérica. Consulte https://spherelab.ai/oftv2/ para obtener más detalles. - init_weights (
bool) — Por defecto, ‘True’. Indica si se deben inicializar los pesos de las capas PSOFT con su inicialización predeterminada. No cambies esta configuración, a menos que sepas exactamente lo que estás haciendo. - 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. - 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 capas, utilizado solo silayers_to_transformes diferente deNone. Esto debe apuntar alnn.ModuleListdel modelo, que a menudo se llama'layers'o'h'.
Configuración para PSOFT (Ajuste fino ortogonal eficiente con adaptación del subespacio principal).
PSOFT inserta una transformación ortogonal R de r*r entre las matrices de bajo rango A y B, de modo que la actualización de bajo rango es ΔW = B @ (R-I) @ A. Solo se entrena R (y los vectores ajustables opcionales); A y B se inicializan con psoft_init (basado en SVD, con A ortogonal por filas) y se congelan.
PsoftModel
clase peft.PsoftModel
< source >( modelpeft_config: Union[PeftConfig, dict[str, PeftConfig]]adapter_name: strlow_cpu_mem_usage: bool = Falsestate_dict: Optional[dict[str, torch.Tensor]] = None )
Modelo PSOFT (Efficient Orthogonal Fine-Tuning with Principal Subspace Adaptation).
Inserta una transformación ortogonal (o escalada) R de r*r entre A y B de bajo rango: ΔW = B @ (R-I) @ A. Use ab_svd_init="psoft_init" para inicializar A/B a partir de SVD y congelarlos, entrenando solo R (y vectores de magnitud opcionales).