PEFT documentation
PSOFT
PSOFT
PSOFT é um método de ajuste fino eficiente em parâmetros baseado em Ajuste Fino Ortogonal (OFT) que preserva as relações geométricas dos vetores de colunas dos pesos pré-treinados, ao mesmo tempo em que atinge um equilíbrio entre desempenho e eficiência multidimensional, incluindo contagem de parâmetros, uso de memória e custo computacional. Ao restringir as transformações ortogonais a um subespaço principal de baixo posto derivado dos pesos pré-treinados, o PSOFT preenche a lacuna entre LoRA e OFT, oferecendo tanto garantias teóricas quanto adaptabilidade prática. Sua eficácia é validada por meio de extensas avaliações em diversos benchmarks, incluindo GLUE, VTAB-1K, GSM8K, MATH e benchmarks de raciocínio de senso comum.
- Apenas camadas
nn.Linearsão suportadas. - Camadas quantizadas não são suportadas.
O resumo do artigo é:
Impulsionado pelo rápido crescimento dos parâmetros dos modelos, o ajuste fino eficiente de parâmetros (PEFT) tornou-se essencial para adaptar grandes modelos a diversas tarefas de baixo nível sob recursos computacionais limitados. Dentro desse paradigma, o ajuste fino ortogonal e suas variantes preservam as representações semânticas dos modelos pré-treinados, mas enfrentam dificuldades para alcançar simultaneamente expressividade e eficiência em termos de contagem de parâmetros, memória e computação. Para superar essa limitação, propomos o Ajuste Fino Ortogonal Eficiente com Adaptação do Subespaço Principal (PSOFT), que confina as transformações ortogonais ao subespaço principal dos pesos pré-treinados. Especificamente, o PSOFT constrói esse subespaço por meio de decomposição de matrizes para permitir transformações compatíveis, estabelece uma condição teórica que mantém estritamente a geometria desse subespaço para a preservação semântica essencial e introduz vetores ajustáveis eficientes que relaxam gradualmente a ortogonalidade durante o treinamento para aumentar a adaptabilidade. Experimentos extensivos em 35 tarefas de PLN e CV em quatro modelos representativos demonstram que o PSOFT oferece uma solução prática e escalável para alcançar simultaneamente preservação semântica, expressividade e eficiência multidimensional no PEFT.
Como o PSOFT funciona
O PSOFT decompõe cada matriz de pesos em e usando SVD:
O subespaço principal é construído a partir dos componentes singulares de ordem $r$:
(PSOFT-SO: PSOFT com ortogonalidade estrita)
(PSOFT-RO: PSOFT com ortogonalidade relaxada
Durante o treinamento, $A$, $B$ e são congelados, e apenas (ou com e $\beta$) é treinável.
Para compatibilidade com o framework PEFT (que espera atualizações aditivas de pesos), o PSOFT é implementado na seguinte forma aditiva:
Parâmetros Treináveis
Após aplicar o PSOFT:
- Os pesos originais do modelo ($A$, $B$, e $W_{\text{res}}$) são congelados.
- Somente a matriz ortogonal (e, opcionalmente, $\alpha$, $\beta$) são treináveis.
- Nenhum parâmetro de viés adicional é introduzido.
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)Opções de Configuração
Modo Diferente
(PSOFT-SO: PSOFT com ortogonalidade estrita)
config = PsoftConfig(psoft_orth=True,psoft_mag_a=False,psoft_mag_b=False)(PSOFT-RO: PSOFT com ortogonalidade relaxada)
config = PsoftConfig(psoft_orth=True,psoft_mag_a=True,psoft_mag_b=True)Boas Práticas
- Escolha do rank: ranks menores (por exemplo,
32–128) são adequados para tarefas mais simples, enquanto ranks maiores (por exemplo,64–256) oferecem maior expressividade para tarefas mais complexas, ao custo de um aumento no número de parâmetros e na computação. - Scaling Factor: O fator de escala é tipicamente definido como no PSOFT.
- Taxa de aprendizado: Use taxas de aprendizado padrão (por exemplo,
1e-4a5e-3) para um treinamento estável. - Inicialização SVD: a opção
lowranké mais eficiente em termos de memória e computação do quefull, tornando-a mais adequada para modelos grandes. - Aproximação de Cayley–Neumann: Quando o rank é grande, habilitar a aproximação de Cayley–Neumann pode melhorar significativamente a eficiência computacional, enquanto o benefício é menos pronunciado para ranks pequenos. Na prática, um pequeno número de termos da série de Neumann (tipicamente
5) geralmente fornece um bom equilíbrio entre precisão e eficiência.
Visão geral do benchmark
API
PsoftConfig
classe 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) — Padrão: 32. O rank PSOFT (r) controla a capacidade do adaptador por meio de uma transformação R de r*r. Ranks menores, de 32 a 128, são tipicamente suficientes para tarefas simples. Tarefas mais complexas podem se beneficiar de 64 a 256, aumentando a expressividade ao custo de parâmetros e computação adicionais. Consulte o artigo para configurações validadas empiricamente: https://openreview.net/forum?id=FSHrinMArK. - target_modules (
Optional[Union[List[str], str]]) — Os nomes dos módulos aos quais o adaptador será aplicado. Se especificado, apenas os módulos com os nomes especificados serão substituídos. Ao passar uma string, uma correspondência de regex será realizada. Ao passar uma lista de strings, uma correspondência exata será realizada ou será verificado se o nome do módulo termina com qualquer uma das strings passadas. Se especificado como ‘all-linear’, todos os módulos lineares/Conv1D serão escolhidos (se o modelo for um PreTrainedModel, a camada de saída será excluída). Se não for especificado, os módulos serão escolhidos de acordo com a arquitetura do modelo. Se a arquitetura não for conhecida, um erro será lançado — nesse caso, você deve especificar os módulos de destino manualmente. - exclude_modules (
Optional[Union[List[str], str]]) — Os nomes dos módulos para os quais o adaptador não deve ser aplicado. Ao passar uma string, será realizada uma correspondência por expressão regular. Ao passar uma lista de strings, será realizada uma correspondência exata ou será verificado se o nome do módulo termina com qualquer uma das strings passadas. - psoft_alpha (
int) — Padrão: 32. Controla o fator de escala do PSOFT. Mesma semântica que o alpha do LoRA. - psoft_dropout (
float) — Padrão: 0.0. Dropout para o caminho PSOFT. Mesma semântica que o dropout do LoRA. - fan_in_fan_out (
bool) — Defina como True se a camada a ser substituída armazenar os pesos como (fan_in, fan_out). Por exemplo, o gpt-2 usaConv1D, que armazena os pesos como (fan_in, fan_out), e portanto este parâmetro deve ser definido comoTrue. - ab_svd_init (
Literal["psoft_init", "pissa_init"]) — Padrão: ‘psoft_init’. Estratégia de inicialização para A e B usada para construir o subespaço principal em PSOFT. ‘psoft_init’: inicialização baseada em SVD com A ortogonal por linhas, garantindo ortogonalidade estrita (PSOFT). ‘pissa_init’: inicialização baseada em SVD com A e B simétricos (PiSSA padrão). - psoft_svd (
Literal["full", "lowrank"]) — Padrão: ‘full’. Backend de SVD para inicialização: ‘full’ usa torch.linalg.svd; ‘lowrank’ usa torch.svd_lowrank. - psoft_svd_lowrank_niter (
int) — Usado apenas quando psoft_svd=‘lowrank’. Padrão: 10. Número de iterações de potência usadas por torch.svd_lowrank quando psoft_svd=‘lowrank’. - psoft_orth (
bool) — Padrão: ‘True’. Se True, restringe R a ser ortogonal por meio da parametrização de Cayley, preservando as relações geométricas entre as colunas dos vetores de pesos pré-treinados. Se False, R é uma matriz livre, sem restrições de ortogonalidade. - psoft_mag_b (
bool) — Padrão: ‘True’. Se True, aprende um vetor de escala diagonal no lado ‘output’ de R. Comumente usado em conjunto com psoft_mag_a para aumentar a adaptabilidade à tarefa, com leve distorção na geometria pré-treinada. - psoft_mag_a (
bool) — Padrão: ‘True’. Se True, aprende um vetor de escala diagonal no lado ‘input’ de R. Comumente usado em conjunto com psoft_mag_b para aumentar a adaptabilidade à tarefa, com leve distorção na geometria pré-treinada. - use_cayley_neumann (
bool) — Padrão: ‘False’. Indica se deve ou não usar a formulação de Cayley-Neumann do PSOFT. Defina como True para melhorar a eficiência computacional, mas isso resulta em um erro de aproximação maior para a ortogonalidade. - num_cayley_neumann_terms (
int) — Padrão: 5. Usado apenas quando use_cayley_neumann=True. Número de termos de Cayley-Neumann a serem usados. Um número maior resulta em menor erro de aproximação para a ortogonalidade. - cayley_neumann_eps (
optional[float]) — Padrão é ‘None’. Usado apenas quando use_cayley_neumann=True. Limite opcional da norma de Frobenius para a matriz geradora Q na aproximação de Cayley-Neumann. Se None (padrão), nenhum redimensionamento é aplicado. Se definido para um valor em (0, 1) (por exemplo, 0.9), Q é redimensionado sempre que ||Q||_F exceder o limite para melhorar a estabilidade numérica. Veja https://spherelab.ai/oftv2/ para detalhes. - init_weights (
bool) — Padrão: ‘True’. Se as camadas PSOFT devem ter seus pesos inicializados com a inicialização padrão. Não altere esta configuração, a menos que saiba exatamente o que está fazendo. - modules_to_save (
List[str]) — Lista de módulos, além das camadas de adaptador, que devem ser configurados como treináveis e salvos no checkpoint final. - layers_to_transform (
Union[List[int], int]) — Os índices das camadas a serem transformadas. Se uma lista de inteiros for passada, o adaptador será aplicado aos índices das camadas especificados nessa lista. Se um único inteiro for passado, as transformações serão aplicadas à camada nesse índice. - layers_pattern (
Optional[Union[List[str], str]]) — O nome do padrão de camadas, usado apenas selayers_to_transformfor diferente deNone. Isso deve apontar para onn.ModuleListdo modelo, que frequentemente é chamado de'layers'ou'h'.
Configuração para PSOFT (Fine-Tuning Ortogonal Eficiente com Adaptação de Subespaço Principal).
PSOFT insere uma transformação ortogonal R de r*r entre as matrizes de baixo rank A e B, de modo que a atualização de baixo rank é ΔW = B @ (R-I) @ A. Apenas R (e vetores ajustáveis opcionais) são treinados; A e B são inicializados com psoft_init (baseado em SVD, A ortogonal por linha) e congelados.
PsoftModel
classe 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).
Insere uma transformação ortogonal (ou escalonada) R de r*r entre A e B de baixo rank: ΔW = B @ (R-I) @ A. Use ab_svd_init=“psoft_init” para inicializar A/B a partir do SVD e congelá-los, treinando apenas R (e vetores de magnitude opcionais).