PEFT documentation
Lily: Adaptación de bajo rango interconectada entre capas
Lily: Adaptación de bajo rango interconectada entre capas
Lily es una técnica de ajuste fino eficiente en parámetros que introduce el intercambio de pesos entre capas para las matrices de adaptador. En lugar de aprender un par AB independiente por capa, como en LoRA, Lily utiliza adaptadores A compartidos localmente (cada A se comparte entre un bloque de stride_A capas consecutivas) y expertos B compartidos globalmente (un pequeño conjunto de num_B adaptadores B se comparte entre todas las capas). En cada pasada hacia adelante, un enrutador ligero dependiente de los datos calcula una combinación ponderada con softmax de los expertos B para producir el B efectivo para esa capa y entrada.
Este intercambio puede reducir el número total de matrices de adaptador de 2N (LoRA estándar) a N / stride_A + num_B, liberando el presupuesto de parámetros para usar un rango r mucho mayor —típicamente 2×–4× lo que se usaría en LoRA. Un rango más alto y una mejor interconectividad aumentan el rango efectivo de la actualización de pesos ΔW = A × combined_B, lo que conduce a un mejor rendimiento de adaptación.
Dado que la combinación B es dependiente de los datos (los pesos del router dependen de las activaciones de entrada en tiempo de ejecución), merge y unmerge no están soportados. Si se requiere la fusión de pesos para su despliegue, considere otros métodos, como LoRA.
Lily tiene actualmente las siguientes restricciones adicionales:
- Solo se admiten capas
nn.Linear. - No se admiten capas cuantizadas.
Si estas restricciones no se ajustan a su caso de uso, considere otros métodos.
El resumen del artículo es:
La adaptación de bajo rango (LoRA) es un método de ajuste fino eficiente en parámetros (PEFT) ampliamente utilizado que aprende actualizaciones de pesos ΔW = AB para los pesos preentrenados W a través de adaptadores de bajo rango A y B. Si bien LoRA garantiza la eficiencia de hardware, sus actualizaciones de pesos de bajo rango limitan el rendimiento de la adaptación. En este artículo, proponemos la adaptación interconectada de bajo rango entre capas (Lily), un nuevo método PEFT que introduce un marco interconectado con expertos A compartidos localmente y expertos B compartidos globalmente. Esta estructura elimina las pares AB redundantes por capa, lo que permite un ΔW de rango superior con igual o menor número de parámetros. Para mejorar la expresividad, utilizamos enrutadores dependientes de los datos para determinar las interconexiones A-B, evitando que los expertos B converjan al mismo comportamiento y mejorando el poder representativo entre dominios. Los experimentos en diferentes modalidades, arquitecturas y tamaños de modelo demuestran el rendimiento y la eficiencia superiores de Lily.
Resumen de las pruebas de rendimiento
API
LilyConfig
clase peft.LilyConfig
< 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 = 32stride_A: int = 1num_B: int = 2scaling: float = 1.0target_modules: Optional[Union[list[str], str]] = Noneexclude_modules: Optional[Union[list[str], str]] = Nonemodules_to_save: Optional[list[str]] = Nonelayers_to_transform: Optional[Union[list[int], int]] = Nonelayers_pattern: Optional[Union[list[str], str]] = Noneinit_weights: bool = True )
Parámetros
- r (
int) — Rango de Lily. Determina la dimensión oculta interna de cada adaptador y el rango de la actualización de pesosA @ B. En Lily, dado que el número de adaptadores suele ser menor que en LoRA, cada adaptador necesita tener más capacidad, por lo que se recomienda usar unrmayor que en LoRA, típicamente2x,3xo4xel rango de LoRA que se usaría normalmente. El número total de parámetros entrenables escala conr * (total_layers / stride_A + num_B), por lo que aumentarrmanteniendostride_Agrande ynum_Bpequeño es el compromiso recomendado. - stride_A (
int) — El número de capas consecutivas que comparten un adaptador A. Por ejemplo, sistride_A=4, cada 4 capas adyacentes comparten el mismo adaptador A, lo que resulta entotal_layers / stride_Aadaptadores A distintos en total. El adaptador A comprime la entrada en una representación de bajo rango de tamañor.stride_Ano debe ser menor que- Valores sugeridos:
2,3o4(es decir, compartir cada 2, 3 o 4 capas). Mantenerstride_Agrande (menos adaptadores A distintos) y aumentarren su lugar conduce a un mejor rendimiento que el compromiso opuesto (pequeñostride_A, pequeñor). Establecerstride_A=1significa que cada capa tiene su propio adaptador A. NOTA: el compartimiento de A ocurre dentro de cada objetivo (capas con el mismo sufijo de objetivo). Por ejemplo, si sus target_modules son['q_proj', 'v_proj']y establecestride_A=2, entonces cada 2 capas q_proj adyacentes compartirán un adaptador A, y cada 2 capas v_proj adyacentes compartirán otro adaptador A, pero las capas q_proj y v_proj no compartirán adaptadores A entre sí ya que tienen sufijos diferentes.
- Valores sugeridos:
- num_B (
int) — El número de adaptadores B compartidos. A diferencia de los adaptadores A (que se agrupan por capa), todos los adaptadores B se comparten globalmente entre todas las capas. En cada pasada hacia adelante, un router calcula una combinación ponderada de todos losnum_Badaptadores B (usando pesos normalizados con softmax) para producir un único adaptador B combinado, que luego proyecta la representación de bajo rango de vuelta a la dimensión original. Se recomienda establecernum_Ben un orden similar al detotal_layers / stride_A. Valores sugeridos:total_layers / 2,total_layers / 3ototal_layers / 4. Al igual que constride_A, se prefiere unnum_Bmás pequeño con unrmás grande que unnum_Bmás grande con unrmás pequeño. NOTA: para entrenar el router, se necesitan al menos 2 adaptadores B (es decir,num_B >= 2), ya que el router aprende a calcular una combinación ponderada de los adaptadores B. NOTA: el compartimiento de B ocurre dentro de cada objetivo (capas con el mismo sufijo de objetivo). Por ejemplo, si tus target_modules son['q_proj', 'v_proj']y establecesnum_B=4, entonces habrá 4 adaptadores B compartidos entre todas las capas q_proj, y otros 4 adaptadores B compartidos entre todas las capas v_proj, pero las capas q_proj y v_proj no compartirán adaptadores B entre sí, ya que tienen sufijos diferentes. - target_modules (
Union[List[str], str], opcional) — Los nombres de los módulos a los que se aplicará Lily. Puede ser una lista de cadenas de nombres de módulos (p. ej.['q_proj', 'v_proj']) o un patrón de expresión regular (p. ej.'.*decoder.*(SelfAttention|EncDecAttention).*(q|v)$'). Si no se especifica, Lily se aplicará a todas las capas lineales compatibles. - scaling (
float) — Un multiplicador escalar aplicado a la salida combinada del adaptador (scaling * A @ combined_B) antes de sumarla a la paso de adelante del peso congelado. A diferencia de LoRA, Lily no utiliza una formulación dealpha / r; en su lugar,scalinges un multiplicador directo. Este diseño facilita realizar barridos de valores en una escala logarítmica (p. ej.0.01,0.1,1.0,10.0). El valor óptimo depende de la tarea y debe tratarse como un hiperparámetro. Recomendamos comenzar con1.0. - modules_to_save (
List[str], opcional) — Lista de módulos, aparte de las capas de Lily, que se configurarán como entrenables y se guardarán en el checkpoint final. Por ejemplo, en tareas de clasificación de secuencias o clasificación de tokens, la capa finalclassifier/scorese inicializa aleatoriamente y, por lo tanto, debe ser entrenable y guardada. - exclude_modules (
Union[List[str], str], opcional) — 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. - layers_to_transform (
Union[list[int], int], opcional) — Los índices de las capas a transformar. Si se especifica este argumento, PEFT transformará únicamente los índices de las capas especificados en esta lista. Si se pasa un solo entero, PEFT transformará únicamente la capa en ese índice. - layers_pattern (
Optional[Union[List[str], str]], opcional) — El nombre del patrón de capas, utilizado solo silayers_to_transformes diferente de None y si el patrón de capas no está en el patrón de capas común. Esto debe apuntar alnn.ModuleListdel modelo, que a menudo se llama'layers'o'h'. - init_weights (
bool) — Si se deben inicializar los pesos del adaptador Lily usando el esquema de inicialización predeterminado: las matrices A se inicializan con Kaiming uniform y las matrices B se inicializan a cero, lo que garantiza que la salida del adaptador sea cero al inicio del entrenamiento y no altere el modelo preentrenado. Se recomienda encarecidamente mantenerlo comoTruea menos que se tenga una razón específica para cambiarlo.
Esta es la clase de configuración para almacenar la configuración de un LilyModel.
LilyModel
clase peft.LilyModel
< source >( modelpeft_config: Union[PeftConfig, dict[str, PeftConfig]]adapter_name: strlow_cpu_mem_usage: bool = Falsestate_dict: Optional[dict[str, torch.Tensor]] = None ) → torch.nn.Module
Parámetros
- model (
torch.nn.Module) — El modelo que se va a adaptar. - config (LilyConfig) — La configuración del modelo Lily.
- adapter_name (
str) — El nombre del adaptador, por defecto es"default".
Devuelve
torch.nn.Module
El modelo PEFT de Lily.
Crea un modelo Low-Rank Interconnected Adaptation Across Layers (Lily) a partir de un modelo de transformers preentrenado.
El método se describe en detalle en https://arxiv.org/abs/2407.09946.
Atributos:
- model (PreTrainedModel) — El modelo que se va a adaptar.
- peft_config (LilyConfig): La configuración del modelo Lily.