PEFT documentation
PaCA: Partial Connection Adaptation
PaCA: Partial Connection Adaptation
PaCA(ICLR 2025)は、学習速度とアクティベーションメモリをターゲットとするPEFT手法です。各ターゲットとなる事前学習済み重みの、r 個のランダムに選択された入力列(「部分接続」)をファインチューニングします。学習可能なパラメータはこれらの列の更新のみであり、LoRAとは異なり、PaCAは追加の低ランク行列を一切加えません。
LoRAのような手法は、事前学習済みレイヤーの隣に小さな低ランクのブランチを実行します。このブランチはFLOPsをほとんど必要としませんが、事前学習済みレイヤーと逐次実行され、バックワードパスのために入力活性化の独自のコピーを保持します。PaCAはこれら両方を回避します:
- レイヤーごとに1回のGEMM。 適応された列は、事前学習済み重みの行列積の直前に書き込まれ、直後に復元されるため、前向きと後向きはそれぞれ1回の行列積のみを実行し、凍結されたベースレイヤーと完全に同じ動作になります。
- 部分活性化。適応された列の勾配は、対応する
r個の入力チャネルにのみ依存するため、バックワードパスでは完全な入力の代わりに、それらのチャネルのみが保存されます。
結果として得られる重みの観点では、PaCA アダプターは、A 行列が固定された列セレクターであるランク r の LoRA アダプターと同等です: W' = W + delta @ S。ここで S は r 列を選択します。したがって、convert_to_lora() を使用して、例えば LoRA 推論スタックでサーブするために、損失なくランク r の LoRA アダプターに変換できます。
PaCAを使用するタイミング:
- LoRAレベルの精度を維持しつつ、より高速なファインチューニングステップと低いアクティベーションメモリを必要とする場合(例:同じGPU上でより長いシーケンスやより大きなバッチを処理したい場合)に適用できます。
- ベースの重みに正確にマージされるアダプター(更新が通常の列更新である)が必要です。
現在の制約:
- サポートされているのは
nn.Linearレイヤー(量子化された線形レイヤーを含む)のみです。 - PaCAはベースレイヤーの
forwardを呼び出すのではなく、matmul自体を実行するため、ベースレイヤーに登録されたforwardフックは呼び出されません(警告が出力されます)。代わりに、PaCAレイヤーにフックを登録してください。 - ミックスされたアダプターバッチ(
adapter_names引数)はサポートされていません。 - sharded weights(FSDP、DeepSpeed ZeRO-3)を用いたトレーニングは、まだテストされていません。
torch.compileはサポートされています。コンパイル下では、カラムスワップ、matmul、およびリストアが不透明なカスタムオペレーション(torch.ops.peft.paca_linear_forward/_backward)として実行されるため、コンパイラはベースの重みをコピーしません。これにはtorch.library.custom_op(PyTorch >= 2.4)が必要です。それ以外の場合は、eager 実装がトレースされます。paca_alpha / rはカラムの更新をスケーリングするため、実質的な学習率の乗数として機能します。- 推論では、アダプタをマージしてください(
merge_and_unload())。マージされていない forward は、呼び出しのたびにカラムを切り替えます。
使用方法
from transformers import AutoModelForCausalLM
from peft import PacaConfig, get_peft_model
model = AutoModelForCausalLM.from_pretrained("meta-llama/Llama-3.2-3B")
config = PacaConfig(r=16, paca_alpha=16, target_modules="all-linear", random_seed=0)
model = get_peft_model(model, config)
model.print_trainable_parameters()デフォルトでは、対象の各レイヤーはr列をランダムに選択してファインチューニングします。論文では、この方法は重みノルムまたは累積勾配に基づいて列を選択する場合と同等の性能を示しました。別の選択戦略を試す場合や、レイヤーごとの列数を異なるものにする場合は、paca_indices_patternを渡します。そのキーは、LoRAのrank_patternと同様に、レイヤー名または正規表現です。
config = PacaConfig(
r=16,
paca_alpha=16,
target_modules=["q_proj", "v_proj"],
paca_indices_pattern={"layers.0.self_attn.q_proj": [0, 2, 4, 6], "layers.1.self_attn.v_proj": list(range(32))},
)キーに一致するレイヤーは指定された列をファインチューニングし、その他の対象レイヤーはr個のランダムな列を選択します。スケーリングはpaca_alpha / rであり、すべてのレイヤーで設定のrを使用するため、paca_alphaはすべてのレイヤーで同じ意味を持ちます。
論文の抄録は以下の通りです:
従来のパラメータ効率型ファインチューニング(PEFT)アルゴリズムは、モデル全体ではなく、追加の少数のアダプタパラメータのみを学習させることで、大規模ニューラルネットワークモデルのファインチューニングにおけるメモリ使用量と計算コストを削減します。 しかし、PEFTによる計算コストの削減が必ずしもトレーニング時間の短縮に直結するとは限りません。アダプタ層の計算コストは事前学習済み層よりもはるかに小さいものの、これら2種類の層はGPU上で逐次処理されることが広く知られており、これが大きなレイテンシオーバーヘッドを生み出します。 LoRAとそのバリアントは、推論時に低ランクのアダプタ行列を事前学習済み重みとマージすることで、このレイテンシオーバーヘッドを回避します。ただし、トレーニング中は事前学習済み重みを凍結したまま低ランクのアダプタ行列を継続的に更新する必要があるため、これらの層をマージすることはできません。さらに、LoRAとそのバリアントはアクティベーションメモリを削減しません。最初の低ランクアダプタ行列は、事前学習済み重みの重み勾配を計算するために、事前学習済み重みへの入力アクティベーションを必要とするためです。この問題を緩和するために、私たちは、モデルにアダプタ層を導入するのではなく、事前学習済み重み内のランダムに選択された部分接続をファインチューニングするPartial Connection Adaptation(PaCA)を提案します。PaCAは、アダプタ層と事前学習済み層の逐次処理による時間オーバーヘッドを排除することでトレーニング速度を向上させるだけでなく、勾配計算のためにフルアクティベーションではなく部分アクティベーションのみを保存すればよいため、アクティベーションメモリも削減します。LoRAと比較して、PaCAはMMLUデータセットでのファインチューニングやOasst1データセットでのインストラクションチューニングなど、さまざまなファインチューニングシナリオにおいて同等の精度を維持しながら、トレーニング時間を22%、総メモリ使用量を16%削減します。 また、PaCAは量子化と組み合わせることができ、LLaMA3.1-70Bのような大規模モデルのファインチューニングを可能にします。さらに、LoRAと比較して、PaCAはNVIDIA A100 GPUおよびINTEL Gaudi2 HPUの両方で、シーケンス長を23%長くしてトレーニングでき、スループットを16%向上させます。
ベンチマーク概要
API
PacaConfig
クラス peft.PacaConfig
< 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 = 8paca_alpha: int = 8target_modules: list[str] | str | None = Noneexclude_modules: list[str] | str | None = Nonelayers_to_transform: list[int] | int | None = Nonelayers_pattern: list[str] | str | None = Nonerandom_seed: int | None = Nonepaca_indices_pattern: dict | None = <factory>init_weights: bool = Truemodules_to_save: list[str] | None = None )
パラメータ
- r (
int、任意、デフォルトは8) — 各対象レイヤーでファインチューニングされる入力列(部分接続)の数です。形状が(out_features, in_features)の重みに対して、PaCA はr * out_features個のパラメータを学習します。これは、ランクがrの LoRA アダプターのB行列のパラメータ数と同じです。in_featuresを超えてはいけません。 - paca_alpha (
int、任意、デフォルトは8) — スケーリング係数です。選択された列の更新量はpaca_alpha / r * deltaとなります。lora_alphaと同様に、アダプタの有効な学習率の乗数として機能します。 - target_modules (
Union[list[str], str], 省略可) — PaCA に置き換えるモジュール名のリスト、またはモジュール名の正規表現です。例えば、['q_proj', 'v_proj']や'.*decoder.*(SelfAttention|EncDecAttention).*(q|v)$'のように指定します。これを'all-linear'として指定した場合、出力層を除くすべての線形モジュールが選択されます。サポートされるのはnn.Linearレイヤーのみです。 - 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'と呼ばれます。 - random_seed (
int、任意、デフォルトはNone) — 部分接続を選択するために使用されるシードです。各レイヤーは、このシードとレイヤー名から導出された異なる選択を使用します。Noneの場合、グローバルなtorch乱数生成器が使用されます。選択されたインデックスは常にアダプターチェックポイントに保存されるため、学習済みアダプターを読み込む際にシードは必要ありません。 - paca_indices_pattern (
dict, オプション) — レイヤー名または正規表現から、r個のランダムに選択された列の代わりに、該当するレイヤーでファインチューニングされる入力列のインデックスへの任意のマッピングです。例えば{'^model.layers.0.self_attn.q_proj': [0, 2, 4]}のように指定できます。これにより、レイヤーごとに異なる数の列を指定することも可能です。レイヤーのインデックスは一意で、in_featuresより小さい必要があります。スケーリングはpaca_alpha / rであり、すべてのレイヤーでこの設定のrが使用され、指定されたインデックスの数には依存しません。どのキーにも一致しないターゲットレイヤーは、r個の列がランダムに選択されます。 - init_weights (
bool、任意、デフォルトはTrue) —Trueの場合、選択されたカラムの更新がゼロに初期化され、つまり適応後のモデルは初期化時点でベースモデルと同一になります。Falseに設定すると、ランダムな値で初期化されます。これはテスト目的でのみ使用することを想定しています。 - modules_to_save (
list[str], 任意) — PaCA レイヤーを除き、最終チェックポイントで学習可能かつ保存されるように設定するモジュールのリストです。例えば、シーケンス分類やトークン分類タスクでは、最終層のclassifier/scoreがランダムに初期化されるため、学習可能かつ保存される必要があります。
これはPacaModelの設定を保存するための設定クラスです。
PaCA(Partial Connection Adaptation、https://huggingface.co/papers/2503.01905)は、対象となる事前学習済み重みの各々からランダムに選択されたr個の入力列(部分接続)をファインチューニングします。学習可能なパラメータはこれらの列の更新のみであり、LoRAとは異なり、PaCAは追加の低ランク行列を一切加えません。行列積(matmul)の直前に適応された列が事前学習済み重みにスワップインされ、直後に元に戻されるため、フォワードパスとバックワードパスのそれぞれで単一のGEMMが実行されます。また、バックワードパスでは選択されたr個の入力チャネルのみがメモリに保持されます。
PacaModel
クラス peft.PacaModel
< 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 (PreTrainedModel) — 適応させる対象のモデル。
- config (PacaConfig) — PaCAモデルの設定。
- adapter_name (
str) — アダプターの名前。デフォルトは"default"です。 - low_cpu_mem_usage (
bool、optional、デフォルトはFalse) — メタデバイス上に空のアダプター重みを生成します。読み込みプロセスを高速化するために有用です。
戻り値
torch.nn.Module
PaCAモデル。
事前学習済みモデルからPartial Connection Adaptation (PaCA)モデルを作成します。この手法はhttps://huggingface.co/papers/2503.01905に説明されています。
例:
>>> from transformers import AutoModelForCausalLM
>>> from peft import PacaConfig, get_peft_model
>>> base_model = AutoModelForCausalLM.from_pretrained("facebook/opt-125m")
>>> config = PacaConfig(r=16, paca_alpha=16, target_modules="all-linear")
>>> model = get_peft_model(base_model, config)属性:
- model (PreTrainedModel) — 適応させる対象のモデル。
- peft_config (PacaConfig): PaCAモデルの設定です。