PEFT documentation

LoRA

You are viewing main version, which requires installation from source. If you'd like regular pip install, checkout the latest stable version (v0.21.0).
Hugging Face's logo
Join the Hugging Face community

and get access to the augmented documentation experience

to get started

LoRA

LoRAは最も人気のあるPEFT手法の一つであり、PEFTを始めたばかりの方にとっての良い出発点です。当初は大型言語モデル向けに開発されましたが、その効率性と効果の高さから、拡散モデルの学習手法としても非常に人気があります。

低ランク適応(LoRA)は、大きな行列を2つの小さな低ランク行列に分解するPEFT手法です。これにより、ファインチューニングが必要なパラメータ数が大幅に削減されます。

論文の抄録は以下の通りです:

自然言語処理における重要なパラダイムは、汎用ドメインデータを用いた大規模事前学習と、特定のタスクやドメインへの適応です。より大きなモデルを事前学習するにつれて、モデルの全パラメータを再学習するフルファインチューニングは、実行可能性が低くなります。GPT-3 175Bを例にとると、175Bパラメータを持つファインチューニング済みモデルの独立したインスタンスをデプロイすることは、コスト的に現実的ではありません。そこで、我々はLow-Rank Adaptation(LoRA)を提案します。LoRAは、事前学習済みモデルの重みを凍結し、Transformerアーキテクチャの各層に学習可能なランク分解行列を注入することで、下流タスクにおける学習可能なパラメータ数を大幅に削減します。Adamを用いたGPT-3 175Bのファインチューニングと比較して、LoRAは学習可能なパラメータ数を10,000分の1、GPUメモリ要件を3分の1に削減できます。LoRAは、学習可能なパラメータ数が少なく、学習スループットが高く、アダプタとは異なり追加の推論レイテンシがないにもかかわらず、RoBERTa、DeBERTa、GPT-2、GPT-3においてモデル品質の面でファインチューニングと同等以上の性能を発揮します。また、言語モデル適応におけるランク不足に関する実証的な調査を行い、LoRAの有効性について考察しました。PyTorchモデルへのLoRA統合を容易にするパッケージを公開し、RoBERTa、DeBERTa、GPT-2の実装とモデルチェックポイントをこのURLで提供しています。

LoRA は重みの更新 ΔW\Delta W を、2 つのより小さい行列( 更新行列) )で低ランク分解を用いて表します。これらの新しい行列は、全体のパラメータ数を低く保ちながら新しいデータに適応するように学習できます。元の重み行列は凍結されたまま、これ以上の更新を受け取りません。最終的な結果を生成するには、元の重みと追加の適応済み重みを結合します。また、推論のレイテンシーを排除するために、アダプタの重みをベースモデルにマージすることもできます。

このアプローチには、いくつかの利点があります:

  • LoRAは、学習可能なパラメータの数を大幅に削減することで、ファインチューニングをより効率的にします。
  • 元の事前学習済み重みは凍結されたまま保持されるため、それらを基盤として、さまざまな下流タスクに対応する軽量かつポータブルな複数のLoRAモデルを構築できます。
  • LoRAは他のパラメータ効率手法と直交しており、それらの多くと組み合わせることができます。
  • LoRAを使用してファインチューニングされたモデルの性能は、完全にファインチューニングされたモデルの性能と同等です。

原理的には、LoRAはニューラルネットワーク内の重み行列の任意の部分集合に適用でき、学習可能なパラメータ数を削減できます。ただし、簡便さとさらなるパラメータ効率を考慮して、LoRAは通常、Transformerモデルのattentionブロックにのみ適用されます。他のレイヤーも対象にすることを検討する価値があるかもしれません。LoRAモデルにおける学習可能なパラメータの最終的な数は、更新行列のサイズに依存します。このサイズは主に、ランクrと元の重み行列の形状によって決定されます。

低ランク行列の初期化は、タスク認識(CorDA、EVA、Astra)、収束の高速化(PiSSA)、量子化の緩和(LoftQ)など、さまざまなユースケースを念頭に置いて行うことができます。ここではほんの一例を挙げました。異なる初期化方法については、以下を参照してください。デフォルトの初期化では、LoRAが何もしない(no-op)状態となり、既存のモデルに大きく干渉することなく、徐々に新しい動作を学習するように設計されています。

使用方法

低ランク更新行列のサイズは、rank(またはr)によって決定されます。ランクが高いほど、モデルには学習させるためのパラメータが増えますが、同時にモデルの学習能力も高まります。次の例では、アテンションブロックのquery行列とvalue行列を対象とします。設定する他の重要なパラメータとしては、lora_alpha(スケーリング係数)、bias(none、all、またはLoRAバイアスパラメータのみを学習するか)、そしてmodules_to_save(LoRA層以外で学習および保存するモジュール)があります。これらのパラメータ(およびそれ以外)はすべて、LoraConfigに定義されています。

from peft import LoraConfig, get_peft_model

config = LoraConfig(
    r=16,
    lora_alpha=16,
    target_modules=["query", "value"],
    lora_dropout=0.1,
    bias="none",
    modules_to_save=["classifier"],
)
model = get_peft_model(model, config)
model.print_healthcheck()

ベンチマーク概要

初期化

LoRA重みの初期化は、LoraConfigのパラメータinit_lora_weightsによって制御されます。デフォルトでは、PEFTは重みAにKaiming-uniform、重みBにゼロでLoRA重みを初期化し、恒等変換(参照実装と同じ)になります。

transformers.Conv1Dレイヤー(GPT-2の投影など)では、重みがnn.Linearのレイアウトではなく(in_features, out_features)として保存されているため、fan_in_fan_out=Trueを使用してください。サポートされている重みベースのイニシャライザーは、分解にはLinearレイアウトを使用し、ベースの重みを更新する際に保存されたレイアウトを復元します。LoRA-GAの"stable"スケーリングも、保存レイアウトに関係なく出力次元を使用します。

init_lora_weights="gaussian" を渡すことも可能です。名前の通り、重み A をガウス分布で、重み B をゼロで初期化します(Diffusers が LoRA の重みを初期化する方式です)。

from peft import LoraConfig

config = LoraConfig(init_lora_weights="gaussian", ...)

デバッグやテストに有用なinit_lora_weights=Falseというオプションも用意されています。このオプションを使用するのは、この場合のみとすべきです。このオプションを選択すると、LoRAの重みは、恒等変換を引き起こさないように初期化されます。

from peft import LoraConfig

config = LoraConfig(init_lora_weights=False, ...)
NoRA
PiSSA
MiCA
CorDA
Astra
OLoRA
EVA
LoftQ
rsLoRA
LoRA-GA

Normalized Low-Rank Adaptation (NoRA)は、LoRAのダウンプロジェクション行列を正規化します。PEFTは、LoraConfig内のinit_lora_weights="nora"を通じて、この正規化を初期化時のみ適用します。具体的には、ランダムに初期化されたLoRA A重みの列を正規化し、LoRA B重みをゼロに初期化します。両方の行列は学習可能であり、ベースの重みは変更されません。

線形層の場合、アダプター重みの更新は $\Delta W = sBA$ となり、 AA の形状は (r, in_features), BB の形状は (out_features, r), 、 ss は LoRA スケーリング係数です。NoRA は、LoRA 線形層によって作成されたランダムな A 重みから開始し、ランク次元にわたって各列を正規化します: A:,j←A:,jmax⁡(∥A:,j∥2,10−6),B←0. A_{:,j} \leftarrow \frac{A_{:,j}}{\max(\lVert A_{:,j} \rVert_2, 10^{-6})}, \qquad B \leftarrow 0.

B がゼロであるため、学習前のアダプター重みの更新はゼロです。bias="none"およびlora_bias=Falseの場合、アダプターは初期状態でベースモデルの出力を保持します。NoRA はキャリブレーションデータセットや重みの分解を必要としません。

NoRA については、推奨設定は lora_alpha を r と等しくすること(alpha/rank の比率が 1:1 になること)です。例えば、r=8, lora_alpha=8 のようにします。デフォルトの use_rslora=False では、スケーリング係数が 1 に保たれます。rank-stabilized LoRA を有効にすると、係数は lora_alpha / sqrt(r) に変更されます。

以下の例では、小さなPyTorchモデルの2つの線形層にNoRAを適用しています。

from torch import nn

from peft import LoraConfig, get_peft_model

model = nn.Sequential(
    nn.Linear(32, 32),
    nn.ReLU(),
    nn.Linear(32, 16),
)

config = LoraConfig(
    r=8,
    lora_alpha=8,
    target_modules=["0", "2"],
    init_lora_weights="nora",
    bias="none",
    lora_bias=False,
    use_rslora=False,
)
model = get_peft_model(model, config)
model.print_healthcheck()

Transformersモデルの場合、target_modulesに、適応させたい線形層の名前を設定します。例えば、モデルにそれらの名前が存在する場合は、["q_proj", "v_proj"]のように指定します。

NoRAは既存のLoRA設定、学習、保存、読み込みAPIを使用するため、個別のNoraConfigやNoraModelクラスはありません。共有される設定およびモデルAPIについては、LoraConfigおよびLoraModelを参照してください。

NoRAは、torch.nn.Linearのターゲットモジュール、またはtarget_parametersで直接渡されたnn.Parameterをサポートしています。埋め込みや畳み込み層などはサポートされていません。

トレーニング

このセクションでは、モデルに低ランクアダプタを適用してデータを供給するだけでなく、より複雑なトレーニングシナリオをどのように処理するかを示します。

QLoRAスタイルの学習

PEFTのデフォルトのLoRA設定では、各アテンションブロックのクエリ層とバリュー層に学習可能な重みが追加されます。しかし、Transformerモデルのすべての線形層に学習可能な重みを追加するQLoRAは、完全なファインチューニングモデルと同等のパフォーマンスを提供できます。QLoRAと同様にすべての線形層にLoRAを適用するには、target_modules="all-linear"を設定します(アーキテクチャによって異なる可能性がある個別のモジュール名を指定するよりも簡単です)。

config = LoraConfig(target_modules="all-linear", ...)

PEFTアダプターに量子化を適用する方法の詳細については、量子化ガイドを参照してください。

LoRAによるメモリ効率の良いレイヤー複製

モデルの性能を向上させるためのアプローチとして、与えられたサイズの事前学習済みモデルから、モデル内のレイヤーを複製してモデルを拡張し、より大きなモデルを構築する方法があります。例えば、SOLAR論文で説明されているように、7Bモデルを10Bモデルに拡張します。PEFT LoRAは、レイヤーの複製後にそのレイヤーに接続されたLoRAアダプターを用いたさらなるファインチューニングをサポートする、メモリ効率の高い方法でこの種の拡張をサポートしています。複製されたレイヤーは基盤となる重みを共有するため、追加のメモリを消費せず、必要な追加メモリはアダプターの重みのメモリのみです。この機能を使用するには、layer_replication引数を含む設定を作成します。

config = LoraConfig(layer_replication=[[0,4], [2,5]], ...)

元のモデルが5層[0, 1, 2 ,3, 4]であったと仮定すると、この操作により[0, 1, 2, 3, 2, 3, 4]のように配置された7層のモデルが作成されます。これはmergekitのパススルーマージ規約に従っており、開始位置を含む・終了位置を含まないタプルで指定された層のシーケンスを積み重ねて最終モデルを構築します。最終モデルの各層には、それぞれ固有のLoRAアダプターセットが割り当てられます。

Fewshot-Metamath-OrcaVicuna-Mistral-10B は、この手法を用いて Mistral-7B を 10B に拡張して学習させたモデルの例です。adapter_config.json には、この手法をファインチューニングに適用する LoRA アダプターの設定のサンプルが示されています。

ランクとアルファ(スケーリング)の細かい制御

デフォルトでは、LoraConfig で指定された内容に基づき、LoRA の対象となるすべてのレイヤーに同じランク r と同じ lora_alpha(LoRA のスケーリングを決定する)が適用されます。ただし、レイヤーごとに異なる値を指定したい場合があります。これは、LoraConfig に rank_pattern と alpha_pattern 引数を渡すことで可能です。これらの引数は、キーがレイヤー名、値がランク/アルファ値である辞書である必要があります。キーには正規表現(regex)を指定できます。rank_pattern と alpha_pattern に明示的に記載されていないすべての LoRA レイヤーには、デフォルトの r と lora_alpha の値が適用されます。

例として、次のような構造を持つモデルがあると仮定します。

>>> print(model)
Outer(
  (foo): Linear(...)
  (module): Middle(
    (foo): Linear(...)
    (foobar): Linear(...)
    (module): Inner(
      (foo): Linear(...)
      (barfoo): Linear(...)
    )
  )
)
  • rank_pattern={"foo": 42} は、すべての foo レイヤーに一致します。foobar も barfoo も一致しません。
  • rank_pattern={"^foo": 42} はモデルの foo レイヤーのみを一致させ、module.foo や module.module.foo には一致しません。これは、正規表現において ^ が「文字列の先頭」を意味するため、foo のみが "foo" で始まる一方、他のレイヤー名にはプレフィックスが付いているためです。
  • rank_pattern={"^module.foo": 42} は、同じ理由により、module.foo にはマッチしますが、module.module.foo にはマッチしません。
  • rank_pattern={"module.foo": 42} は module.foo と module.module.foo の両方にマッチしますが、foo にはマッチしません。
  • rank_pattern={"^foo": 42, "^module.module.foo": 55} は、それぞれ foo と module.module.foo にマッチしますが、module.foo にはマッチしません。
  • PEFTが自動的に追加するため、マッチの終わりを示すために$を指定する必要はありません。

同じロジックがalpha_patternにも適用されます。迷ったら、正規表現で凝ったことをせず、異なるランク/アルファを持つ各モジュールの完全な名前を^プレフィックス付きで渡すだけで問題ありません。

実行可能なターゲットモジュールを自動的に検出する

peft.helpers.KappaTuneSelector は、KappaTune論文で提案された条件数に基づくターゲット選択戦略を実装しています。すべてのnn.Linearモジュールをスキャンし、MoEエキスパートの重みが融合された3次元のnn.Parameterテンソルとして保存されているモデル(例: Llama-4、Qwen3-MoE)ではそれらのパラメータも対象とし、それぞれについて行列の条件数 κ = σ_max / σ_min を計算します。その後、最も各向同性なレイヤー(κが最小のレイヤー)を選択します。これらの各向同性レイヤーは、高エントロピーの性質により新しい情報をより容易に吸収できるため、ファインチューニングの理想的な候補となります。これにより、特化された各向異性レイヤーはそのまま維持され、継続的学習におけるカタストロフィック・フォーゲッティングを軽減できます。

LoraConfigの最適なtarget_modulesを取得するワンライナーとして、peft.helpers.find_kappa_target_modules()を使用します:

from peft import LoraConfig, get_peft_model
from peft.helpers import find_kappa_target_modules

model = AutoModelForCausalLM.from_pretrained("mistralai/Mixtral-8x7B-Instruct-v0.1")

targets = find_kappa_target_modules(model, top_p=0.2)
config = LoraConfig(
    target_modules=targets["target_modules"],
    target_parameters=targets["target_parameters"] if stable_modules_dic["target_parameters"] else None,
    r=64,
    lora_alpha=32,
    task_type="CAUSAL_LM",
)
peft_model = get_peft_model(model, config)

完全な例はこちらを参照してください。

nn.Parameterを直接ターゲットにする

一般的には、モジュール(例: nn.Linear)を対象にするために target_modules を使用します。ただし、状況によってはこれができない場合があります。例えば、HF Transformers の多くの mixture of expert (MoE) レイヤーでは、nn.Linear の代わりに nn.Parameter が使用されています。PEFT は通常、LoRA に対して forward メソッドを上書きしますが、nn.Parameter にはこれが存在しません。したがって、そのパラメータに LoRA を適用するには、target_parameters で対象に指定する必要があります。例えば、Llama4 の場合は、以下を渡すことができます: target_parameters=['feed_forward.experts.gate_up_proj', 'feed_forward.experts.down_proj]。

エキスパートパラメータを対象とする場合、PEFTは実行時にかなりのオーバーヘッドを追加する可能性があります。その理由は、必要とされるエキスパートが少量であっても、PEFTは常に各エキスパートのLoRA寄与を実体化するためです。学習中は、シーケンスの経過に伴い、通常、エキスパートの大部分が少なくとも一度は活性化されるため、この影響は小さくなります。しかし、推論時には通常KVキャッシュが使用され、最後のトークンのみ計算すればよいため、活性化されるエキスパートは少量にとどまります。したがって、MoE層にLoRAを使用すると、推論時に大幅なスローダウンが発生する可能性があります。そのため、重みをマージすること(model.merge_adapter()またはmodel = model.merge_and_unload())を推奨します。これにより、PEFTのオーバーヘッドを除去できます。

この問題に関するより詳細な調査は、MoE最適化に関するプルリクエストで確認できます。

注意事項

  • 現在、この引数は2次元または3次元のnn.Parameterを対象とできます。3次元のパラメータの場合、0次元目がエキスパート次元であると仮定されます。
  • target_parameters を使用する複数の LoRA アダプター(model.add_adapter または model.load_adapter を介して追加されたもの)はサポートされていますが、すべてが同じパラメータセットを対象とする必要があります。

MoEエキスパートパラメータとvLLM

Transformers の一部の MoE モデルでは、エキスパートの重みが nn.Linear モジュールではなく、nn.Parameter テンソル(多くの場合は 3 次元)として保存されています。 これらのエキスパートに LoRA を適用するには、target_parameters を使用し、rank_pattern でレイヤーごとのランクを設定します:

num_experts = getattr(model.config, "num_local_experts", None) or model.config.num_experts
effective_r = max(1, r // num_experts)
config = LoraConfig(
    r=r,
    lora_alpha=32,
    target_modules=["q_proj", "v_proj"],
    target_parameters=[
        # Mixtral / Qwen3-MoE / GPT-OSS
        "mlp.experts.gate_up_proj",
        "mlp.experts.down_proj",
        # Llama4
        # "feed_forward.experts.gate_up_proj",
        # "feed_forward.experts.down_proj",
    ],
    rank_pattern={
        "experts.gate_up_proj": effective_r,
        "experts.down_proj": effective_r,
    },
)

これにより、LoRAのパラメータ総量はdense層とほぼ同じ予算に保たれます(Schulman et. al. の LoRA Without Regret を参照)。エキスパート以外のモジュールには、デフォルトのランク r が使用されます。

ファインチューニング済みのモデルによる高速推論は、例えば、v0.11.2 以降で融合された MoE エキスパート層をサポートする vLLM を使用することで可能です。

LoRAとトークンを効率的に同時に学習

PEFT LoRA アダプターは、trainable_token_indices パラメーターを使用して新しいトークンの追加をサポートしています。これにより、特定の層のファインチューニングと並行して、他のトークンのチューニングを行うことができます。指定されたトークンのみが学習され、他のすべてのトークンは変更されません。埋め込み行列全体を学習させる場合と異なり、既存のトークン埋め込みから得られた学習済みコンテキストを失うことなく、メモリを節約できます。この手法は、内部で TrainableTokensModel のレイヤーを使用しています。

# for layer 'embed_tokens'
config = LoraConfig(trainable_token_indices=[idx_1, idx_2, ...], ...)

# specific embedding layer
config = LoraConfig(trainable_token_indices={'emb_tokens': [idx_1, idx_2, ...]}, ...)

以下のスニペットでは、モデルに新しいトークンを追加し、モデルの他のレイヤーと並行して学習する方法を示しています。

from transformers import AutoTokenizer, AutoModelForCausalLM
from peft import get_peft_model, LoraConfig

base_model = AutoModelForCausalLM.from_pretrained("mistralai/Mistral-7B-v0.1")
tokenizer = AutoTokenizer.from_pretrained("mistralai/Mistral-7B-v0.1")

# we define our new tokens and add them to the tokenizer as special tokens
special_tokens = ['<|start_think|>', '<|stop_think|>']
tokenizer.add_special_tokens({'additional_special_tokens': special_tokens})

# make room for new tokens in the embedding matrix if it isn't big enough already
base_model.resize_token_embeddings(max(len(tokenizer), base_model.model.embed_tokens.num_embeddings))

# typical LoRA config with `trainable_token_indices` targeting embedding layer `embed_tokens`
# and specifically our new tokens we just added
lora_config = LoraConfig(
    target_modules='all-linear',
    trainable_token_indices={'embed_tokens': tokenizer.convert_tokens_to_ids(special_tokens)},
)
peft_model = get_peft_model(base_model, lora_config)

# proceed to train the model like normal
[...]

トークン重みは、LoRA 重みとともにアダプタの state dict の一部として保存されます。フルファインチューニングや埋め込み行列の保存を行う場合、はるかに大きなファイルが保存されることになります。

VRAMをどの程度節約できるかを示すために、上記の例について、埋め込み行列を完全に学習させる場合(modules_to_save=["embed_tokens"])、埋め込み行列にLoRAを使用する場合(target_modules=[..., "embed_tokens"]、ランク32)、および学習可能なトークンを使用する場合(trainable_token_indices=[...]、6トークン)の簡易的な比較を行いました。

学習可能なトークンLoRA完全ファインチューニング
VRAM15,562 MB15,581MB約16,500MB
インフルエンス6トークンすべてのトークンすべてのトークン

重みの共有

多くの因果言語モデルは、2つ以上の重みが同じ基礎パラメータを共有する重みタイイングを使用しています。最も一般的なケースでは、入力埋め込み重み(embed_tokens)と出力投影重み(lm_head)が同じテンソルを共有します。これは、パラメータ数を削減しつつ、通常はモデルの品質を維持できるためです。

PEFTがこれらのタイドウェイトをファインチューニングの対象とした際にどのように扱うかは、必ずしも自明ではありません。LoRAの場合、LoraConfigのensure_weight_tyingが、PEFTがこれらのレイヤーに対してアダプター側の更新を明示的にタイド状態に保つべきかを制御します。実際には、これはmodules_to_save、target_modules、およびtrainable_token_indicesに影響を与える可能性があります。なお、このロジックはレイヤーの命名("embed_tokens"、"lm_head")に関して慣習に部分的に依存しており、これらの慣習が使用されない場合、正常な動作は保証されません。

以下の表は、期待される動作を要約しています。

modules_to_save

ベースモデルの重みが結合されていますensure_weight_tyingLoraConfigのshape動作
いいえFalsemodules_to_save=["embed_tokens"] または ["lm_head"]選択したレイヤーにのみModulesToSaveWrapperを追加します
いいえTruemodules_to_save=["embed_tokens"] または ["lm_head"]警告を出し、選択したレイヤーにのみModulesToSaveWrapperを追加します
はいFalsemodules_to_save=["embed_tokens"] または ["lm_head"]別々に扱う
はいTruemodules_to_save=["embed_tokens"] または ["lm_head"]タイドレイヤーをラップし、ラッパーもタイド状態を維持する
いいえFalsemodules_to_save=["embed_tokens", "lm_head"]別々に扱う
いいえTruemodules_to_save=["embed_tokens", "lm_head"]警告を出し、別個として扱う
はいFalsemodules_to_save=["embed_tokens", "lm_head"]警告を出し、別個として扱う
はいTruemodules_to_save=["embed_tokens", "lm_head"]ModulesToSaveWrapperを関連付けます

target_modules

ベースモデルの重みが結合されていますensure_weight_tyingLoraConfigのshape動作
いいえFalsetarget_modules=["embed_tokens"] または ["lm_head"]選択したレイヤーにのみLoRAを追加
いいえTruetarget_modules=["embed_tokens"] または ["lm_head"]警告を出し、選択したレイヤーにのみLoRAを追加します
はいFalsetarget_modules=["embed_tokens"] または ["lm_head"]別々に扱う
はいTruetarget_modules=["embed_tokens"] または ["lm_head"]LoRAアダプターを固定する
いいえFalsetarget_modules=["embed_tokens", "lm_head"]別々に扱う
いいえTruetarget_modules=["embed_tokens", "lm_head"]警告を出し、別個として扱う
はいFalsetarget_modules=["embed_tokens", "lm_head"]警告を出し、別個として扱う
はいTruetarget_modules=["embed_tokens", "lm_head"]LoRAアダプターを固定する

trainable_token_indices

学習可能なトークンについては、LM headとembeddingが結合されている場合でも、ユーザーとしてこれらに対して異なるトークンをファインチューニングしたい場合があります。そのため、以下の例の表では、同じトークンのファインチューニングと異なるトークンのファインチューニングを区別しています。

ベースモデルの重みが結合されていますensure_weight_tyingLoraConfigのshape動作
いいえFalsetrainable_token_indices=[1, 2, 3]埋め込みのみで学習可能なトークン
いいえTruetrainable_token_indices=[1, 2, 3]警告し、その後、埋め込みのみで学習可能なトークン
はいFalsetrainable_token_indices=[1, 2, 3]結合された学習可能なトークン
はいTruetrainable_token_indices=[1, 2, 3]結合された学習可能なトークン
いいえFalsetrainable_token_indices={"lm_head": [1, 2], "embed_tokens": [1, 2]}別々に扱う
いいえTruetrainable_token_indices={"lm_head": [1, 2], "embed_tokens": [1, 2]}警告を出し、別個として扱う
はいFalsetrainable_token_indices={"lm_head": [1, 2], "embed_tokens": [1, 2]}結合された学習可能なトークン
はいTruetrainable_token_indices={"lm_head": [1, 2], "embed_tokens": [1, 2]}結合された学習可能なトークン
いいえFalsetrainable_token_indices={"lm_head": [1, 2], "embed_tokens": [3, 4]}別々に扱う
いいえTruetrainable_token_indices={"lm_head": [1, 2], "embed_tokens": [3, 4]}警告を出し、別個として扱う
はいFalsetrainable_token_indices={"lm_head": [1, 2], "embed_tokens": [3, 4]}別々に扱う
はいTruetrainable_token_indices={"lm_head": [1, 2], "embed_tokens": [3, 4]}エラー

ユーザーにとって、これは次のことを意味します:

  • 一般的に、タイドされている重みをファインチューニングしつつ、そのタイド状態を維持したい場合は、ensure_weight_tying=True を渡してください。
  • ベースモデルの重みが未結合の場合、ensure_weight_tying=Trueでは結合を強制できず、警告のみが表示されます。
  • trainable_token_indices については、ensure_weight_tying=True の場合、結合されたレイヤーは同じトークンインデックスを使用する必要があります。

オプティマイザー

LoRAの学習には、オプションとして特殊なオプティマイザーを含めることができます。現在、PEFTはLoRA-FA、LoRA+、およびRiemannian-preconditioned LoRAをサポートしています。

LoRA-FA Optimizer

LoRA-FA に記載されているように、LoRA-FA を使用することで、LoRA トレーニングはより効果的かつ効率的になります。LoRA-FA は、行列 A を固定し、行列 B のみチューニングすることで、アクティベーションのメモリ消費量を削減します。トレーニング中は、B の勾配が最適化され、フルパラメータファインチューニングの勾配を近似するようにします。さらに、LoRA-FA のメモリ消費量はランクに敏感ではありません($A$ のアクティベーションを消去するため)、そのため、メモリ消費量を増やすことなく lora rank を拡大してパフォーマンスを向上させることができます。

from peft import LoraConfig, get_peft_model
from peft.optimizers import create_lorafa_optimizer
from transformers import Trainer, get_cosine_schedule_with_warmup

base_model = AutoModelForCausalLM.from_pretrained("meta-llama/Meta-Llama-3-8B-Instruct")

config = LoraConfig(...)
model = get_peft_model(base_model, config)

optimizer = create_lorafa_optimizer(
    model=model,
    r=128,
    lora_alpha=32,
    lr=7e-5,
)

scheduler = get_cosine_schedule_with_warmup(
    optimizer,
    num_warmup_steps=100,
    num_training_steps=1000,
)

trainer = Trainer(
    ...,
    optimizers=(optimizer, scheduler),
)

LoRA+で最適化されたLoRA

LoRAの学習は、LoRA+を使用して最適化できます。これはアダプター行列AとBに異なる学習率を使用し、ファインチューニングの速度を最大2倍、パフォーマンスを1〜2%向上させることが示されています。

from peft import LoraConfig, get_peft_model
from peft.optimizers import create_loraplus_optimizer
from transformers import Trainer
import bitsandbytes as bnb

base_model = ...
config = LoraConfig(...)
model = get_peft_model(base_model, config)

optimizer = create_loraplus_optimizer(
    model=model,
    optimizer_cls=bnb.optim.Adam8bit,
    lr=5e-5,
    loraplus_lr_ratio=16,
)
scheduler = None

...
trainer = Trainer(
    ...,
    optimizers=(optimizer, scheduler),
)

Riemannian-preconditioned LoRA

LoRA の学習は、 Riemannian Preconditioned LoRA. すべてのオプティマイザーステップで、LoRA 行列 AA および BB の勾配は、 r×rr \times r のプリコンディショナーで乗算されます。このプリコンディショナーは、低ランク行列多様体上で、ユークリッド勾配をリーマン(スケーリングされた勾配)方向へ再スケーリングします。これにより更新の条件付けが改善され、収束が向上する可能性があります。プリコンディショナーは $r \times r$ であるため、LoRA ランクに対するメモリおよび実行時間のオーバーヘッドは小さくなります。 create_riemannian_optimizer は、任意のベースオプティマイザークラス(例: torch.optim.AdamW または torch.optim.SGD): )をラップします。LoRA 以外のパラメータはベースオプティマイザによって変更なしで更新され、 nn.Linear-形状の LoRA レイヤー(lora_A / lora_B) にプリコンディショニングが適用されます。

from peft import LoraConfig, get_peft_model
from peft.optimizers import create_riemannian_optimizer
from transformers import Trainer, get_cosine_schedule_with_warmup
import torch

base_model = AutoModelForCausalLM.from_pretrained("meta-llama/Meta-Llama-3-8B-Instruct")

config = LoraConfig(...)
model = get_peft_model(base_model, config)

optimizer = create_riemannian_optimizer(
    model=model,
    optimizer_cls=torch.optim.AdamW,
    lr=5e-5,
    reg=1e-2,
)

scheduler = get_cosine_schedule_with_warmup(
    optimizer,
    num_warmup_steps=100,
    num_training_steps=1000,
)

trainer = Trainer(
    ...,
    optimizers=(optimizer, scheduler),
)

reg は、 r×rr \times r 行列の対角成分に逆行列を計算する前に加えられる減衰項であり、LoRA 係数が(ほぼ)ランク不足の場合にプリコンディショナーを安定化させます。

Post-Training

このセクションでは、学習済みアダプターに対する潜在的な後処理手法を示します。

LoRAの重みをベースモデルにマージする

While LoRA is significantly smaller and faster to train, you may encounter latency issues during inference due to separately loading the base model and the LoRA adapter. To eliminate latency, use the merge_and_unload() function to merge the adapter weights with the base model. This allows you to use the newly merged model as a standalone model. The merge_and_unload() function doesn’t keep the adapter weights in memory.

以下は、LoRAアダプターのマージの直観を説明する図です:

以下のスニペットでは、PEFTを使用してこれを実行する方法を示します。

from transformers import AutoModelForCausalLM
from peft import PeftModel

base_model = AutoModelForCausalLM.from_pretrained("mistralai/Mistral-7B-v0.1")
peft_model_id = "alignment-handbook/zephyr-7b-sft-lora"
model = PeftModel.from_pretrained(base_model, peft_model_id)
model = model.merge_and_unload()

返されたモデルを变数に代入して使用することが重要です。merge_and_unload() はインプレース操作ではありません。後でアダプタをアンマージしたり、削除して別のものをロードできるように、重みのコピーを保持する必要がある場合は、代わりに merge_adapter() 関数を使用してください。これで、unmerge_adapter() を使用してベースモデルに戻すオプションが利用可能になります。

from transformers import AutoModelForCausalLM
from peft import PeftModel

base_model = AutoModelForCausalLM.from_pretrained("mistralai/Mistral-7B-v0.1")
peft_model_id = "alignment-handbook/zephyr-7b-sft-lora"
model = PeftModel.from_pretrained(base_model, peft_model_id)
model.merge_adapter()

# unmerge the LoRA layers from the base model
model.unmerge_adapter()

量子化モデルでは、アンマージングは厳密ではありません。マージングはベースの重みを再量子化するため、マージングとアンマージングのサイクルを繰り返すと丸め誤差が蓄積する可能性があります。量子化された重みへのアダプタのマージングを参照してください。

複数のアダプターがアクティブな状態で、そのうち一部のみがマージされている場合、マージされていないアダプターは静かに適用されません。この動作はPEFT v1.0で変更されます。アクティブなアダプターの一部のみをマージするを参照してください。

weights パラメータでユーザーが指定した重み付けスキームに基づいて、複数の LoRA を新しいアダプターにマージするには、add_weighted_adapter() 関数が便利です。以下にエンドツーエンドの例を示します。

まずベースモデルを読み込みます:

from transformers import AutoModelForCausalLM
from peft import PeftModel
import torch

base_model = AutoModelForCausalLM.from_pretrained(
    "mistralai/Mistral-7B-v0.1", dtype=torch.float16, device_map="auto"
)

次に、最初のアダプターを読み込みます:

peft_model_id = "alignment-handbook/zephyr-7b-sft-lora"
model = PeftModel.from_pretrained(base_model, peft_model_id, adapter_name="sft")

次に、別のアダプターを読み込み、最初のものとマージします:

weighted_adapter_name = "sft-dpo"
model.load_adapter("alignment-handbook/zephyr-7b-dpo-lora", adapter_name="dpo")
model.add_weighted_adapter(
    adapters=["sft", "dpo"],
    weights=[0.7, 0.3],
    adapter_name=weighted_adapter_name,
    combination_type="linear"
)
model.set_adapter(weighted_adapter_name)

combination_typeにはいくつかサポートされているメソッドがあります。詳細については、ドキュメントを参照してください。なお、データ型としてtorch.float16またはtorch.bfloat16を使用する場合、combination_typeに“svd”を指定することはサポートされていません。

次に、推論を実行します:

device = torch.accelerator.current_accelerator().type if hasattr(torch, "accelerator") else "cuda"

tokenizer = AutoTokenizer.from_pretrained("mistralai/Mistral-7B-v0.1")

prompt = "Hey, are you conscious? Can you talk to me?"
inputs = tokenizer(prompt, return_tensors="pt")
inputs = {k: v.to(device) for k, v in inputs.items()}

with torch.no_grad():
    generate_ids = model.generate(**inputs, max_length=30)
outputs = tokenizer.batch_decode(generate_ids, skip_special_tokens=True, clean_up_tokenization_spaces=False)[0]
print(outputs)

侵入次元削減によるベースモデルの性能回復

論文 LoRA vs Full Fine-tuning: An Illusion of Equivalence は、LoRA 学習が、すでに学習された重みとはほとんど共通点のない追加の次元を重みに導入し、学習済みの情報の忘却を引き起こすことを主張しています。PEFT は、peft.tuners.lora.intruders.reduce_intruder_dimension() で提案された緩和策を実装しています。

この緩和策では、読み込まれたLoRAを持つPEFTモデルを取得し、既存のアダプターと並んで読み込まれる新しい修正済みアダプターを作成します。この新しいアダプターがアクティブなアダプターとなります。

使用例:

from peft.tuners.lora.intruders import reduce_intruder_dimension

peft_model = AutoPeftModelForCausalLM.from_pretrained('hubnemo/llama-3.2b-metamathqa-lora64')

reduce_intruder_dimension(
    peft_model,
    mitigation_lambda=0.75,
)

peft_model.generate(...)

ミティゲーションの効果を調整するために使用できるハイパーパラメータはいくつか存在しますが、論文の図8に示されているように、アダプタが学習したタスクの精度と、ベースモデルの知識の忘却の間には常にトレードオフの関係があります。ミティゲーションは、過去の知識の忘却への影響を軽減するためにアダプタから情報を削除しますが、その結果、アダプタが学習したタスクに関する一部の情報も失われることになります。

デフォルト値は2つの要素のバランスを良好に保つように設定されていますが、お使いのアダプター、モデル、データに対してデフォルト値が最適であることは保証されていません。そのため、その影響を測定するためのベンチマークを用意しておくことが賢明です。

アダプターを読み込む

アダプターは、load_adapter() を使用して事前学習済みモデルに読み込むことができます。これは、重みがマージされていない異なるアダプターを試す際に便利です。アクティブなアダプターの重みは、set_adapter() 関数で設定します。

from transformers import AutoModelForCausalLM
from peft import PeftModel

base_model = AutoModelForCausalLM.from_pretrained("mistralai/Mistral-7B-v0.1")
peft_model_id = "alignment-handbook/zephyr-7b-sft-lora"
model = PeftModel.from_pretrained(base_model, peft_model_id)

# load different adapter
model.load_adapter("alignment-handbook/zephyr-7b-dpo-lora", adapter_name="dpo")

# set adapter as active
model.set_adapter("dpo")

ベースモデルを返すには、すべてのLoRAモジュールをアンロードするためにunload()を使用するか、アダプタを完全に削除するためにdelete_adapter()を使用できます。unload()はインプレース操作ではないため、返されたモデルを变数に代入して使用することを忘れないでください。

# unload adapter
model = model.unload()

# delete adapter
model.delete_adapter("dpo")

テンソル並列

LoRAは、Transformersが提供するテンソル並列性(TP)をサポートしています。ベースモデルがtp_plan付きで読み込まれると、PEFTは各ターゲットモジュールのTP設定を自動的に検出し、LoRAアダプター重みに適切なフックを追加することで、テンソル並列計算に正しく参加できるようにします。

LoRA での Tensor Parallelism のサポートには、transformers >= 5.4.0 が必要です。 DTensor ベースの Tensor Parallelism API には、peft >= 0.21.1 および transformers >= 5.17.0 が必要です。

使用法は標準的なLoRAワークフローと同一です。PEFTでラップする前に、ベースモデルをtp_plan付きで読み込むだけです。

from transformers import AutoModelForCausalLM
from peft import get_peft_model, LoraConfig

model = AutoModelForCausalLM.from_pretrained("meta-llama/Llama-3.1-8B", tp_plan="auto")
lora_config = LoraConfig(r=16, target_modules=["q_proj", "v_proj"])
model = get_peft_model(model, lora_config)

save_pretrained / from_pretrained を通じた保存と読み込みは、通常どおり動作します。PEFT は保存前に、シャーディングされたアダプター重みをフルテンソルに集約するため、チェックポイントは移植可能であり、学習時に使用したデバイス数に依存しません。

TP プランなしでテンソル並列性を適用する場合(例: PyTorch の parallelize_module を使用する場合)、PEFT は、重みのデバイスメッシュに "tp" という名前の次元がある場合、シャードされた nn.Linear の LoRA 重みをそのローカルシャードのサイズに設定し、それ以外の場合は(FSDP2 と同様に)レイヤー全体の形状に設定します。PEFT は、これらの LoRA 重みに TP フックを追加したり、保存時にそれらをガザリングしたりしません。TP メッシュの次元名が異なる場合は、PEFT モデルを作成する前に追加してください:

from peft.utils.integrations import TpMeshDimRegistry

TpMeshDimRegistry.register("tp_dim")

推論

このセクションでは、LoRAを用いた推論時に実行できる処理、例えばアダプターのカップリング解除などを紹介します。

アクティベーション LoRA (aLoRA)

Activated LoRA (aLoRA) は、因果言語モデル向けの低ランクアダプターアーキテクチャであり、既存のベースモデルの KV キャッシュを再利用することで、より効率的な推論を実現します。このアプローチは、ほとんどのタスクや生成においてベースモデルに依存する推論パイプラインに最も適しています。ただし、チェーン内の特定のタスクを実行するために aLoRA アダプターを使用します。例えば、ベースモデルの生成出力を確認したり修正したりする場合です。このような設定では、推論時間が1桁以上高速化される可能性があります。aLoRA に関する詳細や多くの使用例については、aLoRA の 論文を参照してください。

この手法は、各入力内で呼び出しシーケンス(alora_invocation_tokens)の最後の出現箇所をスキャンします(これは1トークンだけの場合もあります)。呼び出しシーケンスの開始位置から始まるトークンから、アダプター重みが有効化されます。呼び出しシーケンス以降の入力も適応され、生成されるすべてのトークンに適応された重みが使用されます。それ以前のトークンの重みは適応されず、因果的言語モデルにおける因果的アテンションマスクにより、それらのトークンのキャッシュはベースモデルのキャッシュと互換性があります。使用法は標準的なLoRAと非常に似ています。主な違いは、アダプターを作成する際に呼び出しシーケンスを指定する必要がある点です:

from peft import LoraConfig

config = LoraConfig(alora_invocation_tokens=alora_invocation_tokens, task_type="CAUSAL_LM", ...)

alora_invocation_tokens は整数トークン ID のリストです。所望の呼び出し文字列が与えられた場合、以下のように取得できます。

invocation_string = "placeholder"
alora_invocation_tokens = tokenizer.encode(invocation_string, add_special_tokens=False).

トークナイザーはベースモデルのトークナイザーです。検索文字列にSOS/EOSトークンが追加されて検索が失敗するのを防ぐために、add_special_tokens=Falseを使用してください。

注記

  • aLoRAは、キャッシュの再利用に焦点を当てているため、task_type=CAUSAL_LMタスクのみサポートされています。
  • 重みがより少ないトークンで適応されるため、aLoRAはLoRAよりも高いランク(r)を必要とすることがよくあります(常にではありません)。r=32は良い出発点となり得ます。
  • aLoRAの重みは定義上、ベースモデルにマージできません。アダプタの重みはトークンの部分集合に選択的に適用されるためです。マージを試みるとエラーが発生します。
  • Beam searchは現在サポートされていません。
  • ベースモデルに存在しない新しいトークンをトークナイザーに追加することは、一般的には推奨されません。これにより、ベースモデルとアダプターモデルが重複するコンテキストで動作するという、両方のターゲットユースケースが複雑になる可能性があります。この問題を回避するには、アダプターを学習する前に、ベースモデルに学習可能なトークンを追加してください。

呼び出しシーケンスの選択とSFTの設計

alora_invocation_tokensシーケンスは自動的に追加されないため、手動で追加する必要があります。モデルの性能を最大化しつつキャッシュの再利用を損なわないよう、アダプター重みの有効化は、長い入力の後、かつアダプター固有のプロンプティングの開始時に行うことを推奨します。他のモデルと同様に、フォーマットは学習時とテスト時で一致させる必要があります。

ベースモデルにチャットテンプレートがあり、アダプターをトレーニングして所望の出力を生成することを目的とする、次の例を考慮してください。

  • オプション 1: タスク固有のプロンプトがない場合、つまり入力がassistantプロンプト付きのチャット履歴である場合、呼び出し文字列には、チャットテンプレートのassistantプロンプト(例: <|start_of_role|>assistant<|end_of_role|>)が自然な選択です。モデルのプロンプトを確認するには、モデルのチャットテンプレートをご覧ください。
  • オプション 2: アダプタに、そのアダプタが学習しているタスクを説明するタスク固有のプロンプトがあり、そのプロンプトが生成の直前にuserターンとして配置される場合、チャットテンプレートのuserプロンプト(例: <|start_of_role|>user<|end_of_role|>)が呼び出し文字列の自然な選択となります。

呼び出し文字列を決定した後、モデルのトークナイザーを取得し、alora_invocation_tokens を以下のように取得します。

alora_invocation_tokens = tokenizer.encode(invocation_string, add_special_tokens=False).

推論セットアップの例は、alora finetuningにあります。

呼び出し文字列にカスタム文字列を使用する場合は、境界でのトークナイゼーションの問題を避けるため、文字列の先頭と末尾が特殊トークンであることを確認してください。

その理由を理解するために、トークナイザーにおいて ‘a’、‘b’、‘c’、および ‘ab’ がトークン(それぞれ番号 1、2、3、4)であると想像してください。alora_invocation_tokens = [2, 3] であると仮定します。次に、入力文字列が “abc” であるとします。“ab” がトークンであるため、これは [4,3] としてトークン化されます。したがって、文字列内に “bc” が含まれているにもかかわらず、alora_invocation_tokens は検出されません。しかし、呼び出し文字列の開始と終了が特殊トークンであれば、特殊トークンは他の文字と同一のトークンにトークン化されることはないため、この失敗ケースは決して発生しません。

生成におけるキャッシュの使用(および再利用)

aLoRAの主な目的は、ベースモデルとaLoRAアダプターモデル間でKVキャッシュを相互に利用可能にすることです。ベースモデルとアダプターモデルのKV値は互換性がなく、呼び出しシーケンスの前にこの相互利用を実現する必要があります。具体的には、あるモデルの生成時に保存されたキーと値を、その後の生成に再利用することで、コンテキストトークンに対するコストの高いプリフィル操作を回避できます。ベースモデルとaLoRAアダプター間でキャッシュを共有する際、主に2つのパターンがあります。

  1. ベースモデルが何かを生成し、その後、aLoRAアダプターが呼び出されてフォローアップの生成を行います。例えば、ベースモデルが質問に回答し、ハルシネーション検出用に訓練されたaLoRAがベースモデルの応答を確認します。
  2. aLoRA アダプターが何かを生成し、ベースモデルまたは別の aLoRA アダプターが、元の aLoRA と部分的にコンテキストが重複するフォローアップ生成を呼び出される場合です。例えば、ユーザーがクエリを提供し、aLoRA がクエリをより自己完結型に書き換えて RAG システムでの検索を改善します。その後、ドキュメントが検索されコンテキストに読み込まれ、aLoRA がこれらのドキュメントが質問に関連しているかを確認し、最後にベースモデルが回答を生成します。

上記の動作をデモストレーションするために、transformersのDynamicCacheを使用します。適応されたキャッシュの値とベースのキャッシュの値が混在しないよう注意してください。特に、コンテキストが部分的に重複している場合(パターン2)には、キャッシュを共有するために追加の手順が必要です。

パターン1: ベースモデルの後にaLoRAここでは、ベースモデルからの入力全体と生成結果が、呼び出しシーケンスとともにaLoRAアダプターに入力されます。

from transformers import DynamicCache
...
cache = DynamicCache()
inputs_base = tokenizer(prompt_base, return_tensors="pt")
# Generate from base model and save cache
with model_alora.disable_adapter():
    output = model_alora.generate(inputs_base["input_ids"].to(device),attention_mask=inputs_base["attention_mask"].to(device),past_key_values = cache,return_dict_in_generate=True)
output_text_base = tokenizer.decode(output.sequences[0])
cache = output.past_key_values

# Generate with aLoRA adapter from cache
prompt_alora = output_text + INVOCATION_STRING
inputs_alora = tokenizer(prompt_alora, return_tensors="pt").to(device)
output = model_alora.generate(**inputs_alora, past_key_values=cache)
output_text_alora = tokenizer.decode(output[0])

# Note: cache is now tainted with adapter values and cannot be used in base model from here on!

パターン2: aLoRAによる生成の後に、ベースモデル(または別のaLoRA)による部分コンテキスト重複を伴う処理ここでは、ベースモデルを使用して共有コンテキストをプリフィルし、その後生成を行います。

from transformers import DynamicCache
import copy
...
cache = DynamicCache()
inputs_shared = tokenizer(prompt_shared, return_tensors="pt").to(device)

# Prefill from base model and save cache
with model_alora.disable_adapter():
    with torch.no_grad():
        model_alora(**inputs_shared, past_key_values=cache)
cache_copy = copy.deepcopy(cache)

# Generate from aLoRA using prefilled cache
prompt_alora = prompt_shared + INVOCATION_STRING
inputs_alora = tokenizer(prompt_alora, return_tensors="pt").to(device)
output = model_alora.generate(**inputs_alora, past_key_values=cache)
output_text_alora = tokenizer.decode(output[0])

# Generate from base model using saved cache not tainted by aLoRA KV values
prompt_base = prompt_shared
inputs_base = tokenizer(prompt_base, return_tensors="pt").to(device)
with model_alora.disable_adapter():
    output = model_alora.generate(**inputs_base, past_key_values=cache_copy)
output_text_base = tokenizer.decode(output[0])

同一バッチ内で異なるLoRAアダプターを使用して推論を行う

通常、PEFTでは各推論バッチが同じアダプタを使用する必要があります。これは時に煩わしくなる場合があります。異なるLoRAアダプタで使用するサンプルを含むバッチが存在する可能性があるためです。例えば、英語で良好に動作するベースモデルと、フランス語用とドイツ語用の2つのLoRAアダプタがある場合を想定します。通常、各バッチが1つの言語のサンプルのみを含むようにバッチを分割する必要があり、異なる言語を同じバッチに組み合わせることはできません。

幸いなことに、adapter_name 引数を使用することで、異なる LoRA アダプターを同じバッチに混在させることができます。以下では、その具体的な動作例を示します。まず、ベースモデル、英語、そしてフランス語とドイツ語の2つのアダプターを、次のように読み込みます。

from transformers import AutoTokenizer, AutoModelForCausalLM
from peft import PeftModel

model_id = ...
tokenizer = AutoTokenizer.from_pretrained(model_id)

model = AutoModelForCausalLM.from_pretrained(model_id)
# load the LoRA adapter for French
peft_model = PeftModel.from_pretrained(model, <path>, adapter_name="adapter_fr")
# next, load the LoRA adapter for German
peft_model.load_adapter(<path>, adapter_name="adapter_de")

次に、英語、フランス語、ドイツ語の3言語すべてを含むサンプルでテキストを生成します。最初の3つのサンプルは英語、次の3つはフランス語、最後の3つはドイツ語です。adapter_names引数を使用して、各サンプルに使用するアダプターを指定できます。ベースモデルが英語に使用されるため、これらのサンプルには特別な文字列"__base__"を使用します。次の3つのサンプルには、フランス語のLoRAファインチューニングのアダプター名、ここでは"adapter_fr"を指定します。最後の3つのサンプルには、ドイツ語のLoRAファインチューニングのアダプター名、ここでは"adapter_de"を指定します。これにより、ベースモデルと2つのアダプターを単一のバッチで使用できます。

inputs = tokenizer(
    [
        "Hello, my dog is cute",
        "Hello, my cat is awesome",
        "Hello, my fish is great",
        "Salut, mon chien est mignon",
        "Salut, mon chat est génial",
        "Salut, mon poisson est super",
        "Hallo, mein Hund ist süß",
        "Hallo, meine Katze ist toll",
        "Hallo, mein Fisch ist großartig",
    ],
    return_tensors="pt",
    padding=True,
)

adapter_names = [
    "__base__", "__base__", "__base__",
    "adapter_fr", "adapter_fr", "adapter_fr",
    "adapter_de", "adapter_de", "adapter_de",
]
output = peft_model.generate(**inputs, adapter_names=adapter_names, max_new_tokens=20)

ここでは順序は重要ではなく、上記の例のようにバッチ内のサンプルをアダプターごとにグループ化する必要はありません。adapter_names引数がサンプルと正しく対応していることを確認するだけです。

さらに、modules_to_save 機能でも同じアプローチが機能します。この機能により、分類タスク用のカスタムヘッドなどの特定のニューラルネットワーク層を保存し、異なる LoRA アダプター間で再利用できます。

注意事項

この機能にはいくつかのデメリットがあります。具体的には以下の通りです。

  • 推論でのみ動作し、トレーニングには対応していません。
  • with model.disable_adapter() コンテキストによるアダプターの無効化は、adapter_names より優先されます。
  • merge_adapter メソッドを使用して一部のアダプター重みがベース重みにマージされている場合、adapter_names を渡すことはできません。まず、model.unmerge_adapter() を呼び出してすべてのアダプターをアンマージしてください。なお、adapter_names 以外でも、アクティブなアダプターのうち一部のみをマージする場合は、同様の注意点 があります。
  • 明白な理由により、merge_and_unload()を呼び出した後ではこれを使用できません。この場合、すべてのLoRAアダプターがベースの重みにマージされるためです。
  • この機能は現在DoRAと互換性がありません。使用する場合は、LoraConfigでuse_dora=Falseを設定してください。
  • modules_to_save 機能は、現在 Linear、Embedding、Conv2d および Conv1d 型のレイヤーのみサポートされています。
  • 推論には、 adapter_names, 特にバッチ内の異なるアダプタの数が多い場合、想定されるオーバーヘッドがあります。これは、バッチサイズが実質的にアダプタごとのサンプル数に削減されるためです。ランタイムのパフォーマンスが最優先であれば、以下のことを試してください。
    • バッチサイズを大きくします。
    • 同じバッチに多数の異なるアダプターが含まれることを避け、均質なバッチを優先してください。これは、同じアダプターを持つサンプルをバッファリングし、少数の異なるアダプターでのみ推論を実行することで実現できます。
    • 多数の異なるアダプターでの動作に特化したLoRAX、punica、S-LoRAなどの代替実装をご覧ください。

LoRAアダプターの構成と再利用

Arrow

Arrowは、Polytroponと同様に与えられたタスクを解決するために複数の事前学習済みタスク固有のLoRAアダプターを組み合わせることを目的としたモジュール型ルーティングアルゴリズムですが、ファインチューニングは不要です。すべてのアダプターを単純にマージするのではなく、Arrowは勾配なしのトークン単位のMixture-of-Experts (MoE) ルーティング機構を導入します。推論時、まず各LoRAのSVD分解から上位の右特異ベクトルを抽出してプロトタイプを計算します。次に、各トークン表現をこれらのプロトタイプと比較し、コサイン類似度を用いてルーティング係数を取得します。トークンは上位k個の最も関連性の高いLoRAアダプターに割り当てられ、係数はsoftmaxで正規化された後、その出力が線形に結合されます。これにより、既存のLoRAモジュールを新しいタスクに効果的に再利用でき、より強力なゼロショット汎化が実現されます。

In PEFT, Arrow is enabled through [`ArrowConfig]andcreate_arrow_model. You can also configure parameters such astop_k(the number of LoRA adapters combined per token),router_temperature(the softmax temperature applied to the routing coefficients), andrng_seed` (for reproducibility).

from peft import create_arrow_model, ArrowConfig
from transformers import AutoModelForCausalLM

# Loading the model
base_model = AutoModelForCausalLM.from_pretrained("microsoft/Phi-3-mini-4k-instruct")

# Creating the Arrow config
arrow_config = ArrowConfig(
    top_k=3,
    router_temperature=1.0,
    rng_seed=42,
)

# The LoRA adapters below were trained on a clustered FLAN dataset.
# Task clustering was performed using the Model-Based Clustering (MBC) method,
# as described in the Arrow paper.
# While one could train a separate LoRA for each task and let Arrow route tokens among them,
# training LoRAs on clusters of tasks instead provides an indirect optimization for
# transfer across the multi-task dataset.
task_specific_adapter_paths = [
        f"TahaBa/phi3-mini-clustered-flan/ts_expert_{i}" for i in range(10)
    ]

# Creating the Arrow model
model = create_arrow_model(
        base_model=base_model,
        task_specific_adapter_paths=task_specific_adapter_paths,
        arrow_config=arrow_config,
    )

# Now the forward path could be called on this model, like a normal PeftModel.

さらに、create_arrow_modelを呼び出した後でも、アダプターを追加または削除できます。例えば、新しいアダプターをファインチューニングしたり、不要なアダプターを破棄したりする場合です。アダプターが配置されたら、推論でArrowを使用するために"arrow_router"をアクティブにできます。なお、create_arrow_modelの後に新しいLoRAアダプターを追加してファインチューニングしたい場合は、create_arrow_modelでは"arrow_router"がデフォルトでアクティブ化されるため、新しいアダプターを明示的にアクティブに設定する必要があります。

from trl import SFTTrainer, SFTConfig

# Adding a new adapter and activating it
model.add_adapter(adapter_name='new_adapter')
model.set_adapter('new_adapter')

# Now the model could be trained along the `new_adapter`.
trainer = SFTTrainer(
        model=model,
        args=SFTConfig(...),
        ...
    )

# Once the training is done, you can activate `arrow_router` and use it in inference
model.set_adapter('arrow_router')    # Model is ready to be used at inference time now

GenKnowSub

GenKnowSubは、ルーティングの前にタスク固有のLoRAアダプターを精製することで、Arrowを拡張します。その核心となるアイデアは、否定による忘却の原理に基づき、LoRA空間にエンコードされた一般知識を減算することです。これにより、タスクアダプターはより分離され、タスクに関連するシグナルに集中するようになります。具体的には、GenKnowSubは一般(タスク固有でない)LoRAアダプターのセットから低次元の「一般」部分空間を推定し、Arrowのトークン単位のルーティングに先立って、各タスクアダプターのLoRA更新からこの成分を除去します。これにより、多くのタスクアダプターを組み合わせる際の合成性(compositionality)が向上し、干渉が軽減されるのが一般的です。

PEFTでは、ArrowConfigでuse_gks=Trueを設定し、create_arrow_modelにgeneral_adapter_pathsを指定することで、GenKnowSubを有効にします:

from peft import create_arrow_model, ArrowConfig
from transformers import AutoModelForCausalLM

# Loading the model
base_model = AutoModelForCausalLM.from_pretrained("microsoft/Phi-3-mini-4k-instruct")

# Creating the Arrow config
arrow_config = ArrowConfig(
    top_k=3,
    router_temperature=1.0,
    use_gks=True,
    rng_seed=42,
)

# Path to task-specific, trained on flan clustered dataset (as we explained before.)
task_specific_adapter_paths = [
        f"TahaBa/phi3-mini-clustered-flan/ts_expert_{i}" for i in range(10)
    ]
# These general adapters are trained on English, German, and French Wikipedia dataset,
# with causal language modelling objective, each pair like: (507 token tsentence, 5 token completion), and the loss computed on the completion
general_adapter_paths = [
        "TahaBa/phi3-mini-general-adapters/cluster0_batch16_prop1.0_langen/checkpoint-17",
        "TahaBa/phi3-mini-general-adapters/cluster0_batch16_prop1.0_langfr/checkpoint-35",
        "TahaBa/phi3-mini-general-adapters/cluster0_batch16_prop1.0_langger/checkpoint-17"
    ]

# Creating the Arrow model
model = create_arrow_model(
        base_model=base_model,
        task_specific_adapter_paths=task_specific_adapter_paths,
        general_adapter_paths=general_adapter_paths,
        arrow_config=arrow_config,
    )

# Now the forward path could be called on this model, like a normal PeftModel.

一般的な知識をエンコードするために、GenKnowSub はルーティングが開始される前に、提供された一般的なアダプタの平均を、各タスク固有のアダプタから一度だけ引き算します。さらに、create_arrow_model の呼び出し後にアダプタを追加または削除する機能(Arrow セクションで説明されている通り)も、この場合引き続きサポートされています。

Arrow + GenKnowSub を使用する際に注意すべき点:

  • すべての LoRA アダプタ(タスク固有および汎用)は、同じ rank と target_modules を共有する必要があります。

  • これらの設定に不一致がある場合、create_arrow_modelでエラーが発生します。

  • タスクアダプター間で異なるスケーリング係数(lora_alpha)を持つことはサポートされており、Arrow が自動的に処理します。

  • 動的ルーティング動作のため、"arrow_router"のマージはサポートされていません。

  • create_arrow_model において、タスクアダプターはtask_iとして、汎用アダプターはgks_jとして読み込まれます(ここでiとjはインデックスです)。この関数は、target_modules、rank、およびアダプターがLinearレイヤーかLinear4bitレイヤーに適用されるかの整合性を保証します。その後、"arrow_router"モジュールを追加して有効化します。このプロセスのカスタマイズには、create_arrow_modelをオーバーライドする必要があります。

  • この実装は、4ビット量子化(bitsandbytes経由)と互換性があります:

    from transformers import AutoModelForCausalLM, BitsAndBytesConfig
    import torch
    
    # Quantisation config
    bnb_config = BitsAndBytesConfig(
            load_in_4bit=True,
            bnb_4bit_quant_type="nf4",
            bnb_4bit_compute_dtype=torch.bfloat16,
            bnb_4bit_use_double_quant=False,
        )
    
    # Loading the model
    base_model = AutoModelForCausalLM.from_pretrained(
        "microsoft/Phi-3-mini-4k-instruct",
        dtype=torch.bfloat16,
        device_map="auto",
        quantization_config=bnb_config,
    )
    
    # Now call create_arrow_model() as we explained before.

API

LoraConfig

クラス peft.LoraConfig

< >

( 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 = 8target_modules: Optional[Union[list[str], str]] = Noneexclude_modules: Optional[Union[list[str], str]] = Nonelora_alpha: int = 8lora_dropout: float = 0.0fan_in_fan_out: bool = Falsebias: Literal['none', 'all', 'lora_only'] = 'none'use_rslora: bool = Falsemodules_to_save: Optional[list[str]] = Noneinit_lora_weights: bool | Literal['gaussian', 'eva', 'olora', 'pissa', 'pissa_niter_[number of iters]', 'corda', 'astra', 'loftq', 'orthogonal', 'mica', 'nora'] = Truelayers_to_transform: Optional[Union[list[int], int]] = Nonelayers_pattern: Optional[Union[list[str], str]] = Nonerank_pattern: Optional[dict] = <factory>alpha_pattern: Optional[dict] = <factory>megatron_config: Optional[dict] = Nonemegatron_core: Optional[str] = 'megatron.core'trainable_token_indices: Optional[Union[list[int], dict[str, list[int]]]] = Noneloftq_config: Union[LoftQConfig, dict] = <factory>eva_config: Optional[EvaConfig] = Nonecorda_config: Optional[CordaConfig] = Noneastra_config: Optional[AstraConfig] = Nonelora_ga_config: Optional[LoraGAConfig] = Noneuse_dora: bool = Falsevelora_config: Optional[Union[VeloraConfig, dict]] = Nonealora_invocation_tokens: Optional[list[int]] = Noneuse_qalora: bool = Falseqalora_group_size: int = 16monteclora_config: Optional[MontecloraConfig] = Nonelayer_replication: Optional[list[tuple[int, int]]] = Noneruntime_config: LoraRuntimeConfig = <factory>lora_bias: bool = Falsetarget_parameters: Optional[list[str]] = Noneuse_bdlora: Optional[BdLoraConfig] = Nonearrow_config: Optional[ArrowConfig] = Nonekasa_config: Optional[KasaConfig] = Noneensure_weight_tying: bool = False )

パラメータ

  • r (int) — LoRA アテンション次元(「ランク」)。
  • target_modules (Optional[Union[List[str], str]]) — アダプタを適用するモジュールの名前です。このパラメータが指定されている場合、指定された名前のモジュールのみが置き換えられます。文字列を渡す場合は、正規表現によるマッチングが行われます。文字列のリストを渡す場合は、完全一致が行われるか、モジュール名が渡された文字列のいずれかで終わるかがチェックされます。このパラメータが ‘all-linear’ として指定されている場合、すべての linear/Conv1D モジュールが選択されます(モデルが PreTrainedModel の場合、出力層は除外されます)。このパラメータが指定されていない場合、モデルのアーキテクチャに基づいてモジュールが選択されます。アーキテクチャが不明な場合はエラーが発生します — この場合、ターゲットモジュールを手動で指定する必要があります。モジュールをターゲットにしない場合(target_parameters を適用したい場合など)、target_modules=[] を設定してください。
  • exclude_modules (Optional[Union[List[str], str]]) — アダプタを適用しないモジュールの名前。文字列を渡す場合、正規表現によるマッチングが行われます。文字列のリストを渡す場合、完全一致が行われるか、モジュール名が渡された文字列のいずれかで終わるかがチェックされます。
  • lora_alpha (int) — Lora スケーリング用の alpha パラメータ。
  • lora_dropout (float) — Lora層のドロップアウト確率です。
  • fan_in_fan_out (bool) — 置き換えるレイヤーが重みを (fan_in, fan_out) の形式で保存している場合は、これを True に設定してください。例えば、gpt-2 は重みを (fan_in, fan_out) の形式で保存する Conv1D を使用しているため、これを True に設定する必要があります。
  • bias (str) — LoRA のバイアスタイプです。‘none’、‘all’、‘lora_only’ のいずれかを指定できます。‘all’ または ‘lora_only’ を指定した場合、対応するバイアスが学習中に更新されます。この設定により、アダプターを無効にしても、適応なしのベースモデルが生成する出力と同じ結果は得られない点にご注意ください。
  • use_rslora (bool) — True に設定すると、より良い動作が証明されている Rank-Stabilized LoRA を使用し、アダプタのスケーリング係数を lora_alpha/math.sqrt(r) に設定します。それ以外の場合は、lora_alpha/r という元のデフォルト値が使用されます。
  • modules_to_save (List[str]) — 最終チェックポイントに保存されるよう、学習可能に設定するアダプタ層以外のモジュールのリスト。
  • init_lora_weights (bool | Literal["gaussian", "eva", "olora", "pissa", "pissa_niter_[number of iters]", "corda", "astra", "loftq", "orthogonal", "mica", "nora"]) — アダプタ層の重みの初期化方法。True(デフォルト)を渡すと、Microsoft の参照実装のデフォルト初期化が適用され、LoRA B の重みが 0 に設定されます。これにより、追加のトレーニングを行わない限り、LoRA アダプタは何もしない(no-op)状態になります。初期化を False に設定すると、LoRA A と B がランダムに初期化され、トレーニング前に LoRA が no-op にならない状態になります。この設定はデバッグ目的で意図されています。'gaussian' を渡すと、線形層およびレイヤーに対して LoRA ランクでスケーリングされたガウス初期化が適用されます。 'loftq' を渡すと、LoftQ 初期化が使用されます。 'eva' を渡すと、 Explained Variance Adaptation. EVA は、層の入力アクティベーションの SVD に基づいて LoRA を初期化し、ファインチューニングデータに適応できるため、SOTA のパフォーマンスを実現します。 'olora' を渡すと、OLoRA 初期化が使用されます。 'pissa' を渡すと、 https://huggingface.co/papers/2404.02948’ Principal Singular values and Singular vectors Adaptation (PiSSA) が初期化されます。PiSSA は LoRA よりも収束が速く、最終的に優れたパフォーマンスを実現します。さらに、PiSSA は QLoRA と比べて量子化誤差を低減し、さらなる性能向上をもたらします。'pissa_niter_[number of iters]' を渡すと、Fast-SVD ベースの PiSSA 初期化が開始されます。ここで [number of iters] は FSVD を実行する部分空間反復の回数を示し、非負の整数でなければなりません。[number of iters] が 16 に設定されている場合、7B モデルの初期化を数秒で完了でき、トレーニング効果は SVD を使用する場合とほぼ同等です。'corda' を渡すと、Context-Oriented Decomposition Adaptation が初期化されます。これは Instruction-Previewed Mode では PiSSA よりもさらに収束が速く、Knowledge-Preserved Mode では LoRA よりも世界知識をよりよく保持します。'astra' を渡すと、Activation-Space Tail-Eigenvector Low-Rank Adaptation が初期化されます。これは、小さなキャリブレーションデータセットから推定された出力アクティベーションの固有空間にベース重みを射影します。"orthogonal" を渡すと、LoRA A と B が直交するように初期化されます。これは "olora" に似ていますが、ベース重みは変更されません(r が偶数であることが必要で、現在は線形層のみサポートされています)。"mica" を渡すと、Minor Component Adaptation (MiCA) が初期化されます。MiCA は、ベース重みの最小の固有値に関連する r 個の左固有ベクトルから B を初期化し、A をゼロに設定し、トレーニング中に B をフリーズします。更新されるのは A のみです。現在は線形層と埋め込み層でサポートされています。"nora" を渡すと、Normalized Low-Rank Adaptation (NoRA) が初期化されます。NoRA は、ランダムに初期化された LoRA A 重みの各列を L2 ノルム 1 に正規化し、LoRA B 重みをゼロに設定します。正規化は初期化時のみ適用され、ベース重みは変更されず、A と B の両方が学習可能のままです。推奨される設定は、use_rslora=False で lora_alpha を r に等しくすることです。これにより、1:1 の比率とスケーリング係数 1 が維持されます。現在は線形層と、target_parameters で対象とされた nn.Parameters でサポートされています。

    Principal Singular values and Singular vectors Adaptation (PiSSA) は、LoRA よりも収束が速く、最終的に優れたパフォーマンスを実現します。さらに、PiSSA は QLoRA と比べて量子化誤差を低減するため、さらなる性能向上につながります。'pissa_niter_[number of iters]' を渡すと、Fast-SVD ベースの PiSSA 初期化が開始されます。ここで [number of iters] は FSVD を実行する部分空間反復の回数を示し、非負の整数でなければなりません。[number of iters] が 16 に設定されている場合、7B モデルの初期化を数秒で完了でき、その学習効果は SVD を使用した場合とほぼ同等です。'corda' を渡すと、Context-Oriented Decomposition Adaptation の初期化が行われます。これは Instruction-Previewed Mode では PiSSA よりもさらに収束が速く、Knowledge-Preserved Mode では LoRA よりも世界知識をよりよく保持します。'astra' を渡すと、Activation-Space Tail-Eigenvector Low-Rank Adaptation の初期化が行われます。これは、小さなキャリブレーションデータセットから推定された出力活性化の固有空間にベースウェイトを射影します。"orthogonal" を渡すと、LoRA の A と B が直交するように初期化されます。これは "olora" に似ていますが、ベースウェイトは変更されません(r が偶数であることが必要で、現在は線形層のみサポートされています)。"mica" を渡すと、Minor Component Adaptation (MiCA) の初期化が行われます。これは、ベースウェイトの最小の固有値に関連する r 個の左固有ベクトルから B を初期化し、A をゼロに設定し、学習中は B を凍結します。更新されるのは A のみです。現在は線形層と埋め込み層をサポートしています。"nora" を渡すと、Normalized Low-Rank Adaptation (NoRA) の初期化が行われます。これは、ランダムに初期化された LoRA A ウェイトの各列を L2 ノルム 1 に正規化し、LoRA B ウェイトをゼロに設定します。正規化は初期化時のみ適用され、ベースウェイトは変更されず、A と B の両方が学習可能のままです。推奨される設定は、lora_alpha を r に等しくし、use_rslora=False とすることです。これにより、1:1 の比率とスケーリング係数 1 が維持されます。現在は線形層と、target_parameters で対象とされた nn.Parameter をサポートしています。

  • layers_to_transform (Union[List[int], int]) — 変換対象のレイヤーのインデックスです。int のリストが渡された場合、このリストに指定されたレイヤーのインデックスにアダプターが適用されます。単一の整数が渡された場合、そのインデックスのレイヤーに変換が適用されます。
  • layers_pattern (Optional[Union[List[str], str]]) — layers_to_transform が None と異なる場合にのみ使用されるレイヤーパターン名です。これはモデルの nn.ModuleList を対象とすべきで、通常は 'layers' または 'h' と呼ばれます。
  • rank_pattern (dict) — r で指定されるデフォルトのランクとは異なるランクを持つ、レイヤー名または正規表現からランクへのマッピングです。例えば、{'^model.decoder.layers.0.encoder_attn.k_proj': 16}。
  • alpha_pattern (dict) — lora_alpha で指定されるデフォルトの alpha と異なる alpha を、レイヤー名または正規表現にマッピングするための辞書です。例えば、{'^model.decoder.layers.0.encoder_attn.k_proj': 16} のように指定します。
  • megatron_config (Optional[dict]) — Megatron 用の TransformerConfig の引数です。LoRA の並列線形層を作成するために使用されます。Megatron 由来の core_transformer_config_from_args(get_args()) のようにして取得できます。これらの引数は、Megatron の TransformerConfig を初期化するために使用されます。megatron の ColumnParallelLinear および RowParallelLinear 層に LoRA を適用する場合、このパラメータを指定する必要があります。
  • megatron_core (Optional[str]) — 使用する Megatron のコアモジュールです。デフォルトは "megatron.core" です。
  • trainable_token_indices (Optional[Union[List[int], dict[str, List[int]]]]) — peft.TrainableTokensModel メソッドを使用し、埋め込み行列全体を再学習することなく、選択的にファインチューニングするトークンインデックスを指定できます。トークンインデックスの指定方法は2つあります。1つ目は、インデックスのリストを指定する方法で、これによりモデルの入力埋め込み層(見つからない場合は embed_tokens)が対象となります。もう1つは、埋め込みモジュールの名前をキーとし、トークンインデックスのリストを値とする辞書を指定する方法です。例えば {'embed_tokens': [0, 1, ...]} のように指定します。FSDP での学習には、非一様な requires_grad による問題を回避するために use_orig_params=True が必要です。
  • loftq_config (Optional[LoftQConfig]) — LoftQ の設定です。これが None でない場合、LoftQ を使用してバックボーンの重みを量子化し、LoRA 層を初期化します。また、init_lora_weights='loftq' も渡す必要があります。この場合、LoftQ がモデル自体を量子化するため、量子化済みモデルを渡さないでください。LoftQ は、target_parameters を介して対象とされるものを含む線形層にのみ適用されます。埋め込み層や畳み込み層はサポートされておらず、代わりにデフォルトの LoRA 初期化が使用されます。nn.MultiheadAttention 層はサポートされておらず、エラーが発生します。
  • eva_config (Optional[EvaConfig]) — EVA の設定です。最低限、dataset 引数を設定する必要があります(ファインチューニングで使用したのと同じデータセットを使用してください)。
  • corda_config (Optional[CordaConfig]) — CorDAの設定です。これがNoneでない場合、CorDAを使用してアダプタ層を構築します。また、init_lora_weights='corda'も渡してください。
  • astra_config (Optional[AstraConfig]) — Astra の設定です。これが None でない場合、Astra を使用してアダプタ層を構築します。この場合、init_lora_weights='astra' も渡し、get_peft_model の前に preprocess_astra を呼び出してください。
  • lora_ga_config (Optional[LoraGAConfig]) — LoRA-GA の設定です。この引数が渡された場合、LoRA-GA を使用してアダプター層を初期化します。この場合、init_lora_weights='lora_ga' も設定してください。
  • use_dora (bool) — 「Weight-Decomposed Low-Rank Adaptation」(DoRA)を有効にします。この手法は、重みの更新を大きさ(magnitude)と方向(direction)の2つの部分に分解します。方向は通常の LoRA で処理され、大きさは別の学習可能なパラメータで処理されます。これにより、特に低ランクの場合に LoRA のパフォーマンスが向上する可能性があります。現在、DoRA は linear レイヤーと Conv2D レイヤーのみをサポートしています。DoRA は純粋な LoRA よりもオーバーヘッドが大きくなるため、推論時には重みのマージが推奨されます。詳細については、https://huggingface.co/papers/2402.09353を参照してください。
  • velora_config (Optional[VeloraConfig]) — velora_config を指定して VeLoRA を有効にします。VeLoRA は、LoRA A 射影のバックワードパスをカスタムなものに置き換え、完全な入力アクティベーションの代わりに圧縮されたアクティベーションを保存します。
  • kasa_config (Optional[KasaConfig]) — KasaConfig を指定することで、KaSA (Knowledge-aware Singular-value Adaptation) を有効にします。KaSA は、一度だけ SVD を実行して、凍結されたベース重みの r 番目に小さい特異成分を切り捨て、LoRA の A 因子と B 因子の間に特異値の学習可能な対角行列を挿入します。現在サポートされているのは線形層のみです。
  • alora_invocation_tokens (List[int]) — None 以外の場合、‘Activated LoRA’ (aLoRA)を有効にします。 alora_invocation_tokens は、アダプタ用のトークン化された呼び出し文字列です(すべてのモデル入力文字列に存在する必要があります)。この手法では、alora_invocation_tokens 以降のトークンの間のみ、アダプタの重みが選択的に有効化されます。CausalLM で使用する場合、呼び出し前の KV キャッシュはベースモデル(およびこの方式で動作する他の aLoRA アダプタ)のものと交換可能になります。その結果、ベースモデルの推論とアダプタの推論を切り替える推論パイプライン(例:エージェント型パイプライン、例は論文を参照)では、プリフィル操作を保存することで、LoRA に対して大幅な節約が実現されます。共有コンテキストの長さに依存しますが、vLLM 上では、アダプタ推論全体で 1 桁以上の高速化が得られる場合があります。なお、重みの選択的な適用により、マージは不可能です。
  • use_qalora (bool) — 現在、GPTQでのみ実装されています。Quantization-Aware Low-Rank Adaptation (QALoRA)を有効にします。この手法は、量子化対応トレーニングとLoRAを組み合わせることで、量子化モデルの性能を向上させます。これにより、特に低ランクの場合にLoRAの性能が向上します。現在、QALoRAは線形層のみをサポートしています。
  • qalora_group_size (int) — QALoRAプーリングのグループサイズパラメータ。次元削減係数を制御します。入力次元はこのサイズでグループ化され、プーリングされることで計算コストが削減されます。値を大きくすると圧縮率が高まりますが、モデルの品質が低下する可能性があります。このパラメータは、1つのプーリングされた特徴量を作成するために何元の元の特征量を平均するかを決定します。use_qalora=True の場合のみ使用されます。
  • monteclora_config (Optional[MontecloraConfig]) — Monteclora(Monte Carlo Low-Rank Adaptation)の設定です。指定された場合、LoRA アダプターの上にバリアショナル・モンテカルロ・サンプリングを追加するために Monteclora が使用されます。個々のハイパーパラメータの詳細については、MontecloraConfigを参照してください。
  • layer_replication (List[Tuple[int, int]]) — 指定された範囲に従って元のモデルのレイヤーを積み重ねることで、新しいレイヤーのスタックを構築します。これにより、ベースモデルの重みを重複させずにモデルを拡張(または縮小)できます。新しいレイヤーにはすべて、個別の LoRA アダプターが接続されます。
  • runtime_config (LoraRuntimeConfig) — ランタイム設定(保存または復元されないもの)。
  • lora_bias (bool) — デフォルトはFalseです。LoRA Bパラメータのバイアス項を有効にするかどうかを指定します。通常は、これを無効にすべきです。主な使用例は、LoRA重みが完全にファインチューニングされたパラメータから抽出された場合で、そのパラメータのバイアスを考慮に入れる必要がある場合です。
  • target_parameters (List[str]、任意) — LoRA に置き換えるパラメータ名のリストです。この引数は target_modules と同様に動作しますが、モジュール名ではなくパラメータ名を渡す必要があります。一般的には、モジュール(例: nn.Linear)を対象にするために target_modules を使用します。ただし、状況によってはこれができない場合があります。例えば、HF Transformers の多くの mixture of expert (MoE) レイヤーでは、nn.Linear の代わりに nn.Parameter が使用されています。PEFT は通常、LoRA のために forward メソッドを上書きしますが、nn.Parameter には forward メソッドが存在しません。そのため、そのパラメータに LoRA を適用するには、target_parameters で対象に指定する必要があります。例えば、Llama4 の場合は、target_parameters=['feed_forward.experts.gate_up_proj', 'feed_forward.experts.down_proj] のように渡すことができます。正規表現マッチング用の文字列を渡す機能は、まだ実装されていません。また、モデルがコンパイルされ、target_parameters を使用している場合、再コンパイルやグラフの破断が予想されます。両方を同時に使用することは推奨されません。
  • use_bdlora (Optional[BdLoraConfig]) — BdLoraConfig を指定することで、BD-LoRA(Block-Diagonal LoRA)を有効にします。この手法では、LoRA-A または LoRA-B 係数にブロック対角行列を使用することで、分散環境における通信オーバーヘッドを排除し、より高速なマルチ LoRA サービングを可能にします。
  • arrow_config (Optional[ArrowConfig]) — モデルにアロールーティングを適用するために必要な設定です。
  • ensure_weight_tying (bool, 省略可) — peft の初期化後に重みをタイするかどうかを指定します。これにより、modules_to_save および target_modules を介して渡されたレイヤーに追加されたアダプターも、タイされたレイヤーとして扱われます。

これは、LoraModelの設定を保存するための設定クラスです。

to_dict

< >

( )

アダプターモデルの設定を辞書として返します。ランタイム設定は削除されます。

LoraModel

クラス peft.LoraModel

< >

( 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 (LoraConfig) — Loraモデルの設定です。
  • adapter_name (str) — アダプターの名前。デフォルトは"default"です。
  • low_cpu_mem_usage (bool、optional、デフォルトはFalse) — メタデバイス上に空のアダプター重みを生成します。読み込みプロセスを高速化するために有用です。

戻り値

torch.nn.Module

Loraモデル。

事前学習済みのTransformersモデルからLow Rank Adapter (LoRA)モデルを作成します。

この手法の詳細は、https://huggingface.co/papers/2106.09685に記載されています。

例:

>>> from transformers import AutoModelForSeq2SeqLM
>>> from peft import LoraConfig, get_peft_model

>>> config = LoraConfig(
...     task_type="SEQ_2_SEQ_LM",
...     r=8,
...     lora_alpha=32,
...     target_modules=["q", "v"],
...     lora_dropout=0.01,
... )

>>> model = AutoModelForSeq2SeqLM.from_pretrained("t5-base")
>>> lora_model = get_peft_model(model, config)
>>> import torch
>>> import transformers
>>> from peft import LoraConfig, get_peft_model, prepare_model_for_kbit_training

>>> rank = ...
>>> target_modules = ["q_proj", "k_proj", "v_proj", "out_proj", "fc_in", "fc_out", "wte"]
>>> config = LoraConfig(
...     r=4, lora_alpha=16, target_modules=target_modules, lora_dropout=0.1, bias="none", task_type="CAUSAL_LM"
... )
>>> quantization_config = transformers.BitsAndBytesConfig(load_in_8bit=True)

>>> tokenizer = transformers.AutoTokenizer.from_pretrained(
...     "kakaobrain/kogpt",
...     revision="KoGPT6B-ryan1.5b-float16",  # or float32 version: revision=KoGPT6B-ryan1.5b
...     bos_token="[BOS]",
...     eos_token="[EOS]",
...     unk_token="[UNK]",
...     pad_token="[PAD]",
...     mask_token="[MASK]",
... )
>>> model = transformers.GPTJForCausalLM.from_pretrained(
...     "kakaobrain/kogpt",
...     revision="KoGPT6B-ryan1.5b-float16",  # or float32 version: revision=KoGPT6B-ryan1.5b
...     pad_token_id=tokenizer.eos_token_id,
...     use_cache=False,
...     device_map={"": rank},
...     torch_dtype=torch.float16,
...     quantization_config=quantization_config,
... )
>>> model = prepare_model_for_kbit_training(model)
>>> lora_model = get_peft_model(model, config)

属性:

add_weighted_adapter

< >

( adapters: list[str]weights: list[float]adapter_name: strcombination_type: Literal['svd', 'linear', 'cat', 'ties', 'ties_svd', 'dare_ties', 'dare_linear', 'dare_ties_svd', 'dare_linear_svd', 'magnitude_prune', 'magnitude_prune_svd'] = 'svd'svd_rank: int | None = Nonesvd_clamp: int | None = Nonesvd_full_matrices: bool = Truesvd_driver: str | None = Nonedensity: float | None = Nonemajority_sign_method: Literal['total', 'frequency'] = 'total' )

パラメータ

  • adapters (list) — マージするアダプター名のリスト。
  • weights (list) — 各アダプターに対する重みのリストです。重みは正または負の値をとり、アダプター効果の加算と減算の両方が可能です。
  • adapter_name (str) — 新しいアダプターの名前。
  • combination_type (str) — マージの種類は、[svd、linear、cat、ties、ties_svd、dare_ties、dare_linear、 dare_ties_svd、dare_linear_svd、magnitude_prune、magnitude_prune_svd] のいずれかです。cat の combination_type を使用する場合、結果のアダプターのランクは、すべてのアダプターのランクの合計に等しくなります(混合アダプターが大きくなりすぎて、OOM エラーが発生する可能性があります)。なお、cat と svd は正確な手法であり、高い精度が得られますが、linear は効率的ではあるものの非常に粗い近似であり、可能であれば避けるべきです。
  • svd_rank (int、省略可) — svd の出力アダプターのランクです。None が指定された場合、マージするアダプターの最大ランクが使用されます。
  • svd_clamp (float, 任意) — SVD分解の出力をクランプするための分位数の閾値です。Noneが指定された場合、クランプは行われません。デフォルトはNoneです。
  • svd_full_matrices (bool, 省略可能) — フル SVD を計算するか、縮小 SVD を計算するかを制御し、それに応じて返されるテンソル U と Vh の形状を決定します。デフォルト値は True です。
  • svd_driver (str, 任意) — 使用する cuSOLVER メソッドの名前です。このキーワード引数は、CUDA 上でマージを行う場合にのみ機能します。[None, gesvd, gesvdj, gesvda] のいずれかになります。詳細については、torch.linalg.svd のドキュメントを参照してください。デフォルト値は None です。
  • density (float, 任意) — 0 から 1 までの値。0 はすべての値がプルーニングされることを、1 はプルーニングされないことを意味します。[ties, ties_svd, dare_ties, dare_linear, dare_ties_svd, dare_linear_svd, magnintude_prune, magnitude_prune_svd] と併せて使用してください。
  • majority_sign_method (str) — 符号値の大きさ(magnitude)を取得するために使用するメソッドです。[“total”, “frequency”] のいずれかである必要があります。 [ties, ties_svd, dare_ties, dare_ties_svd] と併せて使用してください。

このメソッドは、指定されたアダプターを指定された重みでマージして、新しいアダプターを追加します。

cat の combination_type を使用する際は、結果として得られるアダプターの rank が、すべてのアダプターの rank の合計に等しくなる点に注意してください。そのため、混合アダプターが大きくなりすぎて OOM エラーが発生する可能性があります。

subtract_mutated_init

< >

( output_state_dict: dict[str, torch.Tensor]adapter_name: strkwargs = None )

この関数は、output_state_dict内のPiSSA/CorDA/OLoRAアダプタのパラメータと、adapter_name内のPiSSA/CorDA/OLoRAの初期値を比較することで、PiSSA/CorDA/OLoRAの更新量を計算し、PiSSA/CorDA/OLoRAをLoRAに変換します。

PiSSAのような手法は、学習のためにモデルのベース重みの一部を除去するため、簡単に差し替えられません。ただし、事前学習時の初期重みと事後学習後の重みの両方が既知であれば、\Delta Wを計算し、それをLoRAアダプターとして使用できます。

計算ステップ:

  • W=Wres+A0B0W = W_{res} + A_0 B_0 (PiSSA 初期化
  • W+ΔW=Wres+ABW + \Delta W = W_{res} + A B ((学習後の PiSSA)
  • ΔW=Wres+AB−W=Wres+AB−Wres−A0B0\Delta W = W_{res} + AB - W = W_{res} + AB - W_{res} - A_0 B_0 (LoRA の dW の導出
  • ΔW=AB−A0B0\Delta W = AB - A_0 B_0

ユーティリティ

ArrowConfig

クラス peft.ArrowConfig

< >

( top_k: int = 3router_temperature: float = 1.0use_gks: bool = Falserng_seed: Optional[int] = None )

これは、ArrowおよびGenKnowSubアルゴリズムの設定を保存するためのサブ設定クラスです。Arrowは、https://huggingface.co/papers/2405.11157で提案された、学習済みのLoRAモジュールを組み合わせることで新しいタスクを解決するためのルーティングアルゴリズムです。GenKnowSubは、https://aclanthology.org/2025.acl-short.54/で紹介された、Arrowによって組み合わせられる前に学習済みモジュールを洗練するための手法です。

LoftQ

replace_lora_weights_loftq

peft.replace_lora_weights_loftq

< >

( peft_modelmodel_path: Optional[str] = Noneadapter_name: str = 'default'callback: Optional[Callable[[torch.nn.Module, str], bool]] = None )

パラメータ

  • peft_model (PeftModel) — 重みを置き換える対象のモデル。LoRA レイヤーを持つ量子化済み PEFT モデルである必要があります。
  • model_path (Optional[str]) — モデルのsafetensorsファイルへのパスです。モデルがHugging Faceのモデルの場合、この値はモデルのconfigから推論されます。それ以外の場合は、指定する必要があります。
  • adapter_name (str) — 置き換える重みを持つアダプタの名前です。デフォルトのアダプタ名は “default” です。
  • callback (Optional[Callable[[PeftModel, str], bool]]) — 各モジュールの置換後に呼び出されるコールバック関数です。この関数は、モデルと現在のモジュール名を入力として受け取り、置換を保持するかどうかを示すブール値を返す必要があります。コールバックが False を返す場合、置換はロールバックされます。これにより、LoftQ の初期化が実際にモデルの量子化誤差を低減していることを確認できるため、非常に有用です。例えば、このコールバックは与えられた入力に対する logits を生成し、同じ入力を与えた元の非量子化モデルの logits と比較して、改善がある場合のみ True を返すようにできます。これは貪欲な最適化であるため、この関数を複数回呼び出すことで段階的な改善が得られる可能性があります。

LoftQ技術を使用して、bitsandbytesで量子化されたモデルのLoRA重みを置き換えます。

置換は、ローカルに保存されたsafetensorsモデルファイルから非量子化された重みをロードし、元の重みと量子化された重みの間の量子化誤差を最小化するようにLoRAの重みを初期化することで、オンザフライで行われます。

pickleでは遅延読み込みが不可能なため、通常のPyTorchチェックポイントファイルはサポートできません。

モデルサイズによって、この関数の呼び出しが完了するまでに時間がかかる場合があります。

LoftQConfig

class peft.LoftQConfig

< >

( loftq_bits: int = 4loftq_iter: int = 1 )

パラメータ

  • loftq_bits (int) — LoftQ の量子化ビット数。
  • loftq_iter (int) — LoftQの交互反復回数。

これは、LoraModelの設定を保存するためのサブ設定クラスです。

Eva

EvaConfig

クラス peft.EvaConfig

< >

( rho: float = 2.0tau: float = 0.99use_label_mask: bool = Truelabel_mask_value: int = -100whiten: bool = Falseadjust_scaling_factors: bool = True )

パラメータ

  • rho (float) — EVA の再分配に使用する Rho の値(>= 1.0)。レイヤーの最大ランクは lora_r * rho です。デフォルトは 2.0 で、レイヤーに許可される最大ランクが 2r であることを意味します。rho を大きくすると、レイヤー間のランクの再分配の自由度が高まります。事前学習済みモデルの中には、ランクの再分配に対して敏感な場合があります。そのため、性能が期待値を下回っている場合は、rho=1.0(再分配なし)を試すことが有効です。
  • tau (float) — 早期停止のためのコサイン類似度の閾値です。連続する2つのSVDステップ間の右特異ベクトルのコサイン類似度を比較します。コサイン類似度がこの閾値を超えている場合、SVDの反復処理が停止されます。デフォルト値は0.99です。
  • use_label_mask (bool) — Use label mask for EVA initialization. This means that positions where labels=label_mask_value are ignored for the SVD computation. Setting use_label_mask=True is preferred in most cases and can be especially beneficial for multi-turn conversations. The default value is True. Filtering out items based on the label mask can sometimes lead to a small batch size and as a result instabilities in the SVD computation. For cases where a large share of batch items would be filtered out, set use_label_mask=False.
  • label_mask_value (int) — use_label_mask=True の場合、無視するトークンをマスクするために検索する値です。デフォルトは -100 です。
  • whiten (bool) — 固有ベクトルにホワイトニングを適用します。デフォルトは False です。 ホワイトニングは、ビジョン分野における EVA に有益であることが示されています。
  • adjust_scaling_factors (bool) — ランク再分配後に LoRA スケーリング係数を調整します。これを True に設定すると、すべての LoRA グラディエントがランクに関係なく同じスケールになるようにスケーリング係数が調整されます。デフォルトは True です。

これは、EVAによるデータ駆動型初期化の設定を保存するためのサブ設定クラスです。EVAはExplained Variance Adaptationで紹介されました。

initialize_lora_eva_weights

peft.initialize_lora_eva_weights

< >

( model: Moduledataloader: collections.abc.Iterable | None = Noneeva_state_dict: dict | None = Noneforward_fn: collections.abc.Callable | None = <function forward_fn_dict at 0x7fadfac44d50>prepare_model_inputs_fn: collections.abc.Callable | None = <function prepare_model_inputs_fn_language_modeling at 0x7fadfac44b40>prepare_layer_inputs_fn: collections.abc.Callable | dict[str, collections.abc.Callable] | None = <function prepare_layer_inputs_fn_language_modeling at 0x7fadfac44ca0>adapter_name: str = 'default'gather_distributed_inputs: bool = Trueshow_progress_bar: bool = True ) → model (torch.nn.Module)

パラメータ

  • model (PeftModel) — SVD を計算する Peft モデル。
  • dataloader (Optional[Iterable]) — フォワードパスに使用するdataloader。Noneの場合、eva_state_dictを指定する必要があります。
  • eva_state_dict (Optional[dict]) — モデルに読み込む state_dict です。None の場合、dataloader を提供する必要があり、get_eva_state_dict を使用して state_dict が計算されます。
  • forward_fn (Callable) — フォワードパスに使用するフォワード関数です。2つの引数 model と inputs を受け取ります。デフォルトの動作は return model(**inputs) です。
  • prepare_model_inputs_fn (Optional[Callable]) — This function receives the model inputs and the peft_config and passes the output to prepare_layer_inputs_fn. Can be used to modify the input to the SVD computation based on the original model inputs. For example for language modeling the attention mask is used to determine which indices are padding tokens and should not be used for SVD. Any function defined here expects two arguments: model_input and peft_config. peft.tuners.lora.eva.prepare_model_inputs_fn_language_modeling is used by default.
  • prepare_layer_inputs_fn (Union[Callable, Dict[str, Callable], None]) — この関数は、レイヤーの入力、モデルの入力(prepare_model_inputs_fnによって変更された可能性がある)、およびレイヤー名を受け取り、その特定のレイヤーの SVD に使用すべき入力を返します。ここで定義されるカスタム関数は、layer_input、model_input、layer_name の 3 つの引数を受け取り、2 次元テンソルを返す必要があります。デフォルトのロジックは peft.tuners.lora.eva.prepare_layer_inputs_fn_language_modeling にあり、言語モデリングに動作します。この場合、model_inputs は SVD に使用するインデックスを決定するために使用されるマスクです(prepare_model_inputs_fn_language_modelingによって作成されます)。
  • adapter_name (str) — 重みの初期化を行うアダプターの名前。
  • gather_distributed_inputs (bool) — すべてのランクからレイヤーの入力を集約するかどうか。デフォルトは True で、分散環境では SVD の計算のためにすべてのランクからレイヤーの入力が集約されます。非分散環境では、この引数は無視されます。分散環境で非分散のデータローダーを使用している場合は、False に設定してください。
  • show_progress_bar (bool) — 進捗バーを表示するかどうか。デフォルトは True です。

戻り値

model (torch.nn.Module)

初期化されたLoRA重みを持つモデル。

EVAメソッドを使用して、LoRA層の重みを初期化します。

この関数は、EVA 手法を使用して LoRA レイヤーの重みを初期化します。各アダプターレイヤーについて SVD を計算し、それに応じて重みを更新します。

get_eva_state_dict

peft.get_eva_state_dict

< >

( model: Moduledataloader: Iterablepeft_config: peft.tuners.lora.config.LoraConfig | None = Noneforward_fn: collections.abc.Callable | None = <function forward_fn_dict at 0x7fadfac44d50>prepare_model_inputs_fn: collections.abc.Callable | None = <function prepare_model_inputs_fn_language_modeling at 0x7fadfac44b40>prepare_layer_inputs_fn: collections.abc.Callable | dict[str, collections.abc.Callable] | None = <function prepare_layer_inputs_fn_language_modeling at 0x7fadfac44ca0>adapter_name: str = 'default'gather_distributed_inputs: bool = Trueshow_progress_bar: bool = True ) → eva_state_dict (dict)

パラメータ

  • model (torch.nn.Module) — SVDを計算する対象のモデルです。PeftModelである必要はありません。
  • dataloader (Iterable) — 前向きパスに使用するdataloader。
  • peft_config (Optional[LoraConfig]) — LoRA層の設定です。modelがPeftModelでない場合にのみ必要です。
  • forward_fn (Callable) — フォワードパスに使用するフォワード関数です。2つの引数 model と inputs を受け取ります。デフォルトの動作は return model(**inputs) です。
  • prepare_model_inputs_fn (Optional[Callable]) — This function receives the model inputs and the peft_config and passes the output to prepare_layer_inputs_fn. Can be used to modify the input to the SVD computation based on the original model inputs. For example for language modeling the attention mask is used to determine which indices are padding tokens and should not be used for SVD. Any function defined here expects two arguments: model_input and peft_config. peft.tuners.lora.eva.prepare_model_inputs_fn_language_modeling is used by default.
  • prepare_layer_inputs_fn (Union[Callable, Dict[str, Callable], None]) — この関数は、レイヤーの入力、モデルの入力(prepare_model_inputs_fnによって変更された可能性がある)、およびレイヤー名を受け取り、その特定のレイヤーの SVD に使用すべき入力を返します。ここで定義されるカスタム関数は、layer_input、model_input、layer_name の 3 つの引数を受け取り、2 次元テンソルを返す必要があります。デフォルトのロジックは peft.tuners.lora.eva.prepare_layer_inputs_fn_language_modeling にあり、言語モデリングに動作します。この場合、model_inputs は SVD に使用するインデックスを決定するために使用されるマスクです(prepare_model_inputs_fn_language_modelingによって作成されます)。
  • adapter_name (str) — SVDを計算するアダプタの名前。
  • gather_distributed_inputs (bool) — すべてのランクからレイヤーの入力を集約するかどうか。デフォルトは True で、分散環境では SVD の計算のためにすべてのランクからレイヤーの入力が集約されます。非分散環境では、この引数は無視されます。分散環境で非分散のデータローダーを使用している場合は、False に設定してください。
  • show_progress_bar (bool) — 進捗バーを表示するかどうか。デフォルトは True です。

戻り値

eva_state_dict (dict)

各層のSVD成分を含む状態辞書。

モデルの各層についてSVDを計算します。

この関数は、モデルの各層に対して特異値分解(SVD)を計算します。SVDの成分を計算するために、増分PCA手法を使用します。また、この関数はコサイン類似度を用いて、計算された成分の収束を確認します。各層のランク分布は、説明分散比に基づいて決定されます。

LoraGAConfig

クラス peft.LoraGAConfig

< >

( direction: Literal['ArBr', 'A2rBr', 'ArB2r', 'random'] = 'ArB2r'scale: Literal['stable', 'weight_svd', 'gd_scale', 'unit'] = 'stable'stable_gamma: int = 16 )

パラメータ

  • direction (Literal["ArBr", "A2rBr", "ArB2r", "random"]) — 勾配 SVD 成分を lora_A と lora_B 行列に分配する戦略。
    • “ArBr”: 交互インデックス(Aが奇数、Bが偶数)
    • “A2rBr”: A はインデックス [r:2r] を取得し、B はインデックス [:r] を取得します
    • “ArB2r”: A はインデックス [:r] を、B はインデックス [r:2r] を取得します(推奨)
    • “random”: インデックスのランダム選択 デフォルト: “ArB2r”
  • scale (Literal["stable", "weight_svd", "gd_scale", "unit"]) — アダプターの初期化に使用するスケーリング戦略。
    • “stable”: gammaパラメータを用いた安定なスケーリング
    • “weight_svd”: 重み行列の固有値に基づくスケーリング
    • “gd_scale”: 勾配降下法に基づくスケーリング
    • “unit”: 追加のスケーリングなし デフォルト: “stable”
  • stable_gamma (int) — 安定スケーリング手法のGammaパラメータ。デフォルト: 16

これは、LoRA-GA初期化の設定を保存するためのサブ設定クラスです。

LoRA-GA (Low-Rank Adaptation with Gradient Approximation) は、初期化時に勾配情報を利用し、初期アダプター重みをフルファインチューニングの勾配方向に整えることで、より高速な収束(2〜4倍の高速化)を実現します。

参考文献: https://arxiv.org/abs/2407.05000

ユーティリティ

peft.tuners.lora.loraga.estimate_gradients

< >

( model: Modulelora_config: LoraConfigtrain_step: Callable )

LoRA-GAの初期化のために勾配を推定します。

この関数は、ターゲットモジュールの重みに対してのみ勾配の計算を有効にし、train_step コールバックを実行します。これは、グローバルに勾配を有効にするよりもメモリ効率に優れています。

peft.preprocess_loraga

< >

( model: Modulelora_config: LoraConfigtrain_step: Callablecache_file: str | None = None )

パラメータ

  • model (nn.Module) — 前処理を行うモデル。
  • lora_config (LoraConfig) — モデルのLoRA設定です。lora_config.lora_ga_configを設定する必要があります。
  • train_step (Callable[[], None]) — 勾配推定を実行するためのコールバックです。通常、このコールバック内でモデルのフォワードパスとバックワードパスを実行します。このコールバック内のすべての呼び出しにわたって、勾配が累積されます。
  • cache_file (Optional[str]) — 勾配の保存/読み込みに使用するキャッシュファイルへの任意のパスです。指定され、ファイルが存在する場合、勾配はキャッシュから読み込まれます。それ以外の場合、勾配は推定され、このパスに保存されます。

勾配を推定することにより、モデルに必要なLoRA-GAフィールドを構築します。

各線形層について、提供されたtrain_stepコールバックを実行することで勾配が推定されます。これらの勾配はその後、モジュールに付与され、初期化時に使用されます。

完了後、各ターゲットモジュールに対して以下のフィールドが設定されます: _peft_loraga_grad (torch.Tensor): 重み行列の累積勾配。

侵入次元削減

peft.tuners.lora.intruders.reduce_intruder_dimension

< >

( peft_modelold_adapter_name = 'default'new_adapter_name = 'intruder_reduced'top_k = 10threshold_epsilon = 0.5mitigation_lambda = 0.75logging_sink = <built-in function print> )

パラメータ

  • peft_model — old_adapter_name で指定された名前の LoRA アダプターが読み込まれた PEFT モデルです。現在、混合モデルはサポートされていません。
  • top_k (デフォルト — 10) イントレーダー検出に考慮する上位k次元を指定します。値が大きいほど、イントレーダー検出の分析に考慮される次元数が増え、誤検出(false positives)の発生可能性も高くなります。ベース重みとアダプター重みの間のコサイン類似度に対して、次元の影響力(特異値分解によって決定される)で概ねソートされた状態で操作するため、top-kが10の場合、最も「重要」な10次元が対象となります。
  • threshold_epsilon (デフォルト — 0.5) ベース重みとアダプター重みの間のコサイン類似度がイントルダーとみなされる閾値です。 論文によると、イントルダー次元は事前学習済み固有ベクトルに対してほぼゼロの絶対コサイン類似性を示します。この値が低いほど、潜在的なイントルダー次元として識別されるものは少なくなります。値が高いほど、誤検出(false-positive)がイントルダーとして考慮される可能性が高くなります。
  • mitigation_lambda (デフォルト — 0.75) アダプターのデルタ重みから減算されるイントルダー次元の相対的な割合です。値が大きいほど、イントルダー次元から減算される量は多くなりますが、失われる情報量も多くなります。トレードオフの分析については、論文の Figure 8 を参照してください。
  • logging_sink (デフォルト — print) ミティゲーションプロセスに関する情報を出力する関数です。出力を一切行わない場合は None に設定してください。

https://huggingface.co/papers/2410.21228(“LoRA vs Full Fine-tuning: An Illusion of Equivalence”)に基づくイントルダー次元の軽減。

このメソッドは、学習済みの低ランクアダプターを後処理することで、以前の知識を回復(すなわち、忘却を緩和)できます。ただし、これにはタスク精度の低下というコストが伴います。migration_lambdaの値を調整することで、これらの2つの要素のトレードオフを調整できます。

ミティゲーションが完了すると、new_adapter_name で設定された名前を持つ新しいアダプターが作成され、これが現在アクティブなアダプターとして設定されます。したがって、ミティゲーション後のモデルでの推論は、修正されたアダプターを使用します。元のアダプターに戻すには、peft_model.set_adapter(<old_adapter_name>) を使用できます。

現在、この手法が他のデルタ重み手法に一般化できるかどうか不明であるため、LoRAのみがサポートされています。

Update on GitHub