PEFT documentation
Prefixチューニング
Prefixチューニング

Prefix tuningは、事前学習済みモデルを凍結したまま学習可能なタスク固有のベクトル列を入力シーケンスの先頭に付加します。これらのプレフィックスパラメータは、モデルのすべてのレイヤーに挿入されます。
論文の抄録は以下の通りです:
ファインチューニングは、事前学習済み大規模言語モデルを活用して下流タスクを実行するための事実上の標準手法です。しかし、ファインチューニングは言語モデルのパラメータをすべて変更するため、タスクごとに完全なコピーを保存する必要があります。本論文では、自然言語生成タスクにおけるファインチューニングの軽量な代替手法として、プレフィックスチューニングを提案します。プレフィックスチューニングは、言語モデルのパラメータを凍結したまま、小さな連続的なタスク固有のベクトル(プレフィックスと呼ばれる)を最適化します。プレフィックスチューニングはプロンプティングから着想を得て、後続のトークンがプレフィックスを「仮想トークン」であるかのようにアテンションを向けることを可能にします。我々は、表からテキストへの生成タスクにGPT-2、要約タスクにBARTに対してプレフィックスチューニングを適用しました。その結果、パラメータのわずか0.1\%のみを学習することで、プレフィックスチューニングはフルデータ設定において同等の性能を達成し、低データ設定ではファインチューニングを上回り、訓練中に未見であったトピックを含む例への外挿性能も優れていることがわかりました。
注記 エンコーダー・デコーダーモデル(seq2seq)では、プレフィックスはデコーダーにのみ適用されますが、これは論文の仕様(例:図2)と一致しません。プレフィックスチューニングはこれらのモデルアーキテクチャでもファインチューニングできますが、性能が劣る可能性があります。エンコーダー・デコーダーモデルには、他のPEFT手法の使用を検討してください。
Prefix tuningはprompt tuningと非常に似ています。主な違いは、prefixパラメータがモデルのすべてのレイヤーに挿入されるのに対し、prompt tuningはモデルの入力埋め込みにのみpromptパラメータを追加することです。また、soft promptを直接学習すると不安定性が生じ、パフォーマンスが低下するため、prefixパラメータは別個のフィードフォワードネットワーク(FFN)によって最適化されます。FFNはsoft promptの更新後に破棄されます。
その結果、著者らは、パラメータ数が1000分の1であるにもかかわらず、prefix tuningはモデルの完全なファインチューニングと同等の性能を示し、データが少ない設定ではさらに優れた性能を発揮することを発見しました。
基本的な使用方法
タスクタイプと、追加して学習する仮想トークンの数を指定して、PrefixTuningConfig を作成します。
from peft import PrefixTuningConfig, get_peft_model
peft_config = PrefixTuningConfig(task_type="CAUSAL_LM", num_virtual_tokens=20)
model = get_peft_model(model, peft_config)
model.print_healthcheck()初期化の例
デフォルトでは、prefix tuningはランダムに初期化された仮想トークンを使用します。ベクトルをno-opに近い値で初期化するオプションもあります(ゼロに初期化しても、確率質量はわずかにシフトします)。これにより、KV-cacheに注入されるprefixの初期段階での影響が小さくなり、学習パフォーマンスの分散が低減されます。
PEFTは、既存のKVキャッシュのプレフィックス(プロンプトやコーパスの最初のpトークンなど)からプレフィックスチューニングアダプターを初期化するためのユーティリティも提供しています。これはprefix_projection=False(デフォルト)の場合のみサポートされます。その場合、学習されるパラメータはKVプレフィックスそのものだからです。
from transformers import AutoModelForCausalLM, AutoTokenizer
from peft import PrefixTuningConfig, get_peft_model, initialize_kv_prefix_from_text
base = AutoModelForCausalLM.from_pretrained("gpt2")
tok = AutoTokenizer.from_pretrained("gpt2")
peft_cfg = PrefixTuningConfig(task_type="CAUSAL_LM", num_virtual_tokens=20, prefix_projection=False)
model = get_peft_model(base, peft_cfg)
initialize_kv_prefix_from_text(
model,
tok,
text="...a long context with at least num_virtual_tokens tokens...",
use_chat_template=False,
)m peft import PrefixTuningConfig, get_peft_model, initialize_kv_prefix_from_text
base = AutoModelForCausalLM.from_pretrained("gpt2")
tok = AutoTokenizer.from_pretrained("gpt2")
peft_cfg = PrefixTuningConfig(task_type="CAUSAL_LM", num_virtual_tokens=20, prefix_projection=False)
model = get_peft_model(base, peft_cfg)
initialize_kv_prefix_from_text(
model,
tok,
text="...a long context with at least num_virtual_tokens tokens...",
use_chat_template=False,
)
num_virtual_tokens 以上のトークンを生成できる十分な長さのテキストであることを確認してください。そうでない場合、初期化に失敗します。
ガイドラインとして:
initialize_kv_prefix_from_textを使用してニュートラルな開始シーケンスから始めます。これは “Question: ” のような非常に短い文字列でも構いません。- それでも効果がなければ、タスクに関連性のあるより長いシーケンス(つまり、設計されたプロンプト)を使用してください。これにより、収容できる仮想トークンの数が増えるだけでなく、モデルの制御も強まります。
- 初期化テキストを使用できない場合、またはプレフィックスチューニングがそもそも実行可能かどうかを素早く確認したい場合は、zero initをprojectionなしで使用する
ベンチマーク概要
API
PrefixTuningConfig
クラス peft.PrefixTuningConfig
< 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 = Falsenum_virtual_tokens: int = Nonetoken_dim: int = Nonenum_transformer_submodules: Optional[int] = Nonenum_attention_heads: Optional[int] = Nonenum_layers: Optional[int] = Nonemodules_to_save: Optional[list[str]] = Noneinit_weights: typing.Literal['zero'] | None = Noneencoder_hidden_size: int = Noneprefix_projection: bool = False )
これはPrefixEncoderの設定を保存するための設定クラスです。
PrefixEncoder
クラス peft.PrefixEncoder
< source >( config )
パラメータ
- config (PrefixTuningConfig) — プレフィックスエンコーダーの設定です。
プレフィックスをエンコードするためのtorch.nnモデル。
例:
>>> from peft import PrefixEncoder, PrefixTuningConfig
>>> config = PrefixTuningConfig(
... peft_type="PREFIX_TUNING",
... task_type="SEQ_2_SEQ_LM",
... num_virtual_tokens=20,
... token_dim=768,
... num_transformer_submodules=1,
... num_attention_heads=12,
... num_layers=12,
... encoder_hidden_size=768,
... )
>>> prefix_encoder = PrefixEncoder(config)属性:
- embedding (
torch.nn.Embedding) — プレフィックスエンコーダーの埋め込み層です。 - transform (
torch.nn.Sequential) —prefix_projectionがTrueの場合、プレフィックス埋め込みを変換するための2層MLP。 - prefix_projection (
bool) — プレフィックス埋め込みを射影するかどうか。
入力形状: (batch_size, num_virtual_tokens)
出力の形状: (batch_size, num_virtual_tokens, 2*layers*hidden)
PEFTによって保存されたフラット化されたプロンプト埋め込み(prompt_embeddings)を読み込みます。
プレフィックスチューニングでは、学習されたパラメータがKVプレフィックスそのものとなるため(embedding.weightの形状は[num_virtual_tokens, num_layers*2*token_dim])、prefix_projection=Falseの場合のみサポートされています。
prefix_projection=Trueの場合、パラメータは(仮想トークン埋め込み+MLP)であり、フラット化されたKVプレフィックスからこれらのパラメータを復元するための逆変換を適用する一般的な方法はありません。