# Lily: 層間の低ランク相互接続適応

[Lily](https://huggingface.co/papers/2407.09946)は、アダプター行列にクロスレイヤーの重み共有を導入するパラメータ効率の良いファインチューニング手法です。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 の優れた性能と効率が示されました。

## ベンチマーク概要

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

# API

## LilyConfig[[peft.LilyConfig]]

#### peft.LilyConfig[[peft.LilyConfig]]

```python
peft.LilyConfig(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 = 32, stride_A: int = 1, num_B: int = 2, scaling: float = 1.0, target_modules: Optional[Union[list[str], str]] = None, exclude_modules: Optional[Union[list[str], str]] = None, modules_to_save: Optional[list[str]] = None, layers_to_transform: Optional[Union[list[int], int]] = None, layers_pattern: Optional[Union[list[str], str]] = None, init_weights: bool = True)
```

[ソース](https://github.com/huggingface/peft/blob/main/src/peft/tuners/lily/config.py#L24)

**パラメータ:**

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`は1以上である必要があります。推奨値: `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アダプターを共有しません。

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]`, *optional*) : 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]`, *optional*) : Lily レイヤーを除き、最終チェックポイントで学習可能かつ保存されるように設定するモジュールのリストです。例えば、シーケンス分類やトークン分類タスクでは、最終層の `classifier/score` がランダムに初期化されるため、学習可能かつ保存される必要があります。

exclude_modules (`Union[List[str], str]`、*optional*) : アダプタを適用しないモジュールの名前。文字列を渡す場合、正規表現によるマッチングが行われます。文字列のリストを渡す場合、完全一致が行われるか、モジュールの名前が渡された文字列のいずれかで終わるかがチェックされます。

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](/docs/peft/main/ja/package_reference/lily#peft.LilyModel)の設定を保存するための設定クラスです。

## LilyModel[[peft.LilyModel]]

#### peft.LilyModel[[peft.LilyModel]]

```python
peft.LilyModel(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)
```

[ソース](https://github.com/huggingface/peft/blob/main/src/peft/tuners/lily/model.py#L30)

**パラメータ:**

model (`torch.nn.Module`) : 適応させる対象のモデル。

config ([LilyConfig](/docs/peft/main/ja/package_reference/lily#peft.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](https://huggingface.co/docs/transformers/main/en/main_classes/model#transformers.PreTrainedModel)) -- 適応させる対象のモデル。
- **peft_config** ([LilyConfig](/docs/peft/main/ja/package_reference/lily#peft.LilyConfig)): Lilyモデルの設定です。

