PEFT documentation
Lily: 層間の低ランク相互接続適応
Lily: 層間の低ランク相互接続適応
Lilyは、アダプター行列にクロスレイヤーの重み共有を導入するパラメータ効率の良いファインチューニング手法です。LoRAのように各レイヤーごとに独立したABペアを学習するのではなく、Lilyはローカル共有Aアダプター(各Aはstride_Aの連続するレイヤーのブロック内で共有される)と、グローバル共有Bエキスパート(num_B個のBアダプターからなる小さなプールがすべてのレイヤーで共有される)を使用します。各フォワードパスにおいて、軽量なデータ依存型ルーターがBエキスパートのsoftmax重み付き組み合わせを計算し、そのレイヤーと入力に対する有効なBを生成します。
この共有により、アダプタ行列の総数は標準的なLoRAの2NからN / stride_A + num_Bに削減でき、パラメータの予算を解放して、はるかに大きなランクrを使用できるようになります。通常、LoRAで使用するものの2×〜4×のランクが使用可能です。ランクの向上と相互接続性の改善により、重み更新ΔW = A × combined_Bの有効ランクが増加し、適応性能が向上します。
B の組み合わせはデータ依存であるため(ルーターの重みが実行時の入力活性化に依存する)、merge および unmerge はサポートされていません。デプロイメントにおいて重みのマージが必要な場合は、LoRA などの他の方法を検討してください。
Lilyには現在、以下の追加の制約があります。
- サポートされているのは
nn.Linearレイヤーのみです。 - 量子化レイヤーはサポートされていません。
これらの制約が使用ケースに合わない場合は、他の方法を検討してください。
論文の抄録は以下の通りです:
低ランク適応(LoRA)は、事前学習済み重み W に対して低ランクアダプタ A と B を通じて重み更新 ΔW = AB を学習する、広く利用されているパラメータ効率の良いファインチューニング(PEFT)手法です。LoRA はハードウェア効率を確保しますが、低ランクの重み更新が適応性能を制限します。本論文では、層間低ランク相互接続適応(Lily)を提案します。これは、局所的に共有される A と、グローバルに共有される B のエキスパートを導入した相互接続フレームワークを備えた新しい PEFT 手法です。この構造は、層ごとの冗長な AB ペアを排除し、同数または少ないパラメータ数でより高ランクの ΔW を可能にします。表現力を高めるために、データ依存型ルーターを使用して A と B の相互接続を決定し、B エキスパートが同じ挙動に収束することを防ぎ、ドメイン全体での表現力を向上させます。モダリティ、アーキテクチャ、モデルサイズにわたる実験により、Lily の優れた性能と効率が示されました。
ベンチマーク概要
API
LilyConfig
クラス 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 )
パラメータ
- r (
int) — Lily のランクです。各アダプタの内部隠れ次元と、重み更新A @ Bのランクを決定します。Lily では、LoRA と比べてアダプタの数が通常少ないため、各アダプタにより多くの容量を持たせる必要があり、LoRA で通常使用するランクの2x、3x、または4x程度の、より大きなrの使用が推奨されます。学習可能なパラメータの総数はr * (total_layers / stride_A + num_B)に比例して増加するため、stride_Aを大きく保ちつつnum_Bを小さくした状態でrを増加させることが、推奨されるトレードオフです。 - stride_A (
int) — 1つのAアダプターを共有する連続レイヤーの数。例えば、stride_A=4, の場合、隣接する4つのレイヤーが同じAアダプターを共有し、結果としてtotal_layers / stride_A個の異なるAアダプターが生成されます。Aアダプターは、サイズr.stride_Aを下回る値に設定しないでください。推奨値: 2、3、または4(つまり、2、3、または4レイヤーごとに共有)。stride_Aを大きくし(異なるAアダプターの数を減らし)、代わりにrを大きくする方が、逆のトレードオフ(stride_Aが小さく、rも小さい)よりもパフォーマンスが向上します。stride_A=1に設定すると、各レイヤーが独自のAアダプターを持つことになります。注: Aの共有は各ターゲット内(同じターゲットサフィックスを持つレイヤー)で行われます。例えば、target_modulesが['q_proj', 'v_proj']でstride_A=2に設定した場合、隣接する2つのq_projレイヤーがAアダプターを共有し、隣接する2つのv_projレイヤーが別のAアダプターを共有しますが、サフィックスが異なるため、q_projレイヤーとv_projレイヤーは互いにAアダプターを共有しません。- 推奨値:
2、3、または4(つまり、2、3、または4層ごとに共有)。stride_Aを大きくし(個々のAアダプタを減らし)、代わりにrを大きくする方が、逆のトレードオフ(stride_Aが小さく、rも小さい)よりもパフォーマンスが向上します。stride_A=1に設定すると、各層が独自のAアダプタを持つことになります。 注: Aの共有は各ターゲット内(同じターゲットサフィックスを持つ層)で行われます。例えば、['q_proj', 'v_proj']をstride_A=2に設定した場合、隣接する2つのq_proj層がAアダプタを共有し、隣接する2つのv_proj層が別のAアダプタを共有しますが、q_proj層とv_proj層はサフィックスが異なるため、互いにAアダプタを共有しません。
- 推奨値:
- num_B (
int) — 共有される B アダプタの数です。A アダプタ(レイヤーごとにグループ化される)とは異なり、すべての B アダプタはすべてのレイヤー全体でグローバルに共有されます。各フォワードパスにおいて、ルーターはすべてのnum_B個の B アダプタの重み付き組み合わせ(softmax 正規化された重みを使用)を計算し、単一の結合された B アダプタを生成します。この B アダプタは、低ランク表現を元の次元に射影します。num_Bはtotal_layers / stride_Aと同程度のオーダーに設定することをお勧めします。推奨値:total_layers / 2、total_layers / 3、またはtotal_layers / 4。stride_Aと同様に、大きなrを伴う小さなnum_Bを、小さなrを伴う大きなnum_Bより優先してください。注: ルーターを学習するには、少なくとも 2 つの B アダプタ(つまりnum_B >= 2)が必要です。これは、ルーターが B アダプタの重み付き組み合わせを計算することを学習するためです。注: B の共有は各ターゲット内(同じターゲットサフィックスを持つレイヤー)で行われます。例えば、target_modules が['q_proj', 'v_proj']であり、num_B=4と設定した場合、すべての q_proj レイヤーで共有される 4 つの B アダプタと、すべての v_proj レイヤーで共有される別の 4 つの B アダプタが存在します。しかし、q_proj レイヤーと v_proj レイヤーはサフィックスが異なるため、互いに B アダプタを共有しません。 - target_modules (
Union[List[str], str], 省略可) — Lily を適用するモジュールの名前です。モジュール名の文字列のリスト(例:['q_proj', 'v_proj'])または正規表現パターン(例:'.*decoder.*(SelfAttention|EncDecAttention).*(q|v)$')を指定できます。指定しない場合、Lily はサポートされているすべての線形層に適用されます。 - scaling (
float) — 凍結された重みのフォワードパスに追加する前に、結合されたアダプタの出力 (scaling * A @ combined_B) に適用されるスカラー乗数です。LoRA とは異なり、Lily はalpha / rの形式を使用せず、代わりにscalingが直接の乗数として機能します。この設計により、対数スケールで値をスウィープすることが容易になります (例:0.01、0.1、1.0、10.0)。最適な値はタスクに依存するため、ハイパーパラメータとして扱うべきです。1.0から始めることをお勧めします。 - modules_to_save (
List[str], 任意) — Lily のレイヤーを除き、最終的なチェックポイントで学習可能かつ保存されるように設定するモジュールのリストです。例えば、シーケンス分類やトークン分類のタスクでは、最終層のclassifier/scoreがランダムに初期化されるため、学習可能かつ保存される必要があります。 - exclude_modules (
Union[List[str], str], 省略可) — アダプタを適用しないモジュールの名前です。文字列を渡す場合、正規表現によるマッチングが行われます。文字列のリストを渡す場合、完全一致が行われるか、モジュール名が渡された文字列のいずれかで終わるかがチェックされます。 - layers_to_transform (
Union[list[int], int], 省略可) — 変換するレイヤーのインデックスです。この引数が指定されている場合、PEFT はこのリスト内で指定されたレイヤーインデックスのみを変換します。単一の整数が渡された場合、PEFT はそのインデックスのレイヤーのみを変換します。 - layers_pattern (
Optional[Union[List[str], str]]、省略可) —layers_to_transformが None 以外であり、かつレイヤーパターンが共通のレイヤーパターンに含まれない場合にのみ使用されるレイヤーパターンの名前です。これはモデルのnn.ModuleListを対象とすべきであり、通常は'layers'または'h'と呼ばれます。 - init_weights (
bool) — Lily アダプター重みの初期化にデフォルトの初期化スキームを使用するかどうか: A 行列は Kaiming uniform で初期化され、B 行列はゼロで初期化されるため、学習開始時のアダプター出力がゼロとなり、事前学習済みモデルを乱しません。特定の理由がない限り、これをTrueのままにしておくことを強く推奨します。
これはLilyModelの設定を保存するための設定クラスです。
LilyModel
クラス 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
パラメータ
- model (
torch.nn.Module) — 適応させる対象のモデル。 - config (LilyConfig) — Lilyモデルの設定です。
- adapter_name (
str) — アダプターの名前。デフォルトは"default"です。
戻り値
torch.nn.Module
Lily PEFTモデル。
事前学習済みのTransformersモデルから、Low-Rank Interconnected Adaptation Across Layers (Lily) モデルを作成します。
この手法の詳細は、https://arxiv.org/abs/2407.09946に記載されています。
属性:
- model (PreTrainedModel) — 適応させる対象のモデル。
- peft_config (LilyConfig): Lilyモデルの設定です。