なんか色々増えてきたのでまとめるよ。
LoRA
LoRAは行列に対して、差分を学習します。このとき、という二つの行列でとすることで、学習対象のパラメータを大幅に削減します。1層目をdown層、2層目をup層と呼びます。学習時は入力に対して、出力をとします。これは計算量的には大きくなりますが、学習対象パラメータが大幅に削減されるメリットの方が大きいです。推論時はとすることで、計算量を増やさずに済みます。実際はLoRAの結果をでスケーリングします。はハイパーパラメータで、の増減でLoRAのスケールが変動することを防ぎ、を変えた時に学習率を変更せずに済むようになっています。
各アルゴリズムの総称として使われることもありますが、一番狭い意味では全結合層及び1×1畳み込み層に適用するものになっています。1×1畳み込み層にはピクセルごとに同じ全結合層を適用しているだけなので簡単に表現できます。
となります。このことからはrankと呼ばれています。上界だけどね。
のLoRAを考えてみましょう。するとLoRAは列ベクトルと行ベクトルの積になります。の各要素をとすると、
です。行基本変形を繰り返せば1行を残し全部0になることがすぐ分かり、になります。
一般ののときは、
みたいな感じになります。上の行目までで行基本変形を行えば三角行列的な形(足し算に対してだけど)にできるので、行目以降を0にできます。よってです。
LoCon
LoConはフィルターサイズが1×1以外の畳み込み層にもLoRAを適用する方法です。たとえば3×3フィルターの場合、1ピクセルの計算にスポットを当てれば、9マス×入力チャンネル⇒出力チャンネルの全結合層です。3×3畳み込み層の重みはなので数は合いますよね。LoRAの場合はこの変換を9マス×入力チャンネル⇒チャンネル⇒出力チャンネルと二つの変換に分解します。として、3×3畳み込み層にもLoRAを拡張できます。入力を合わせるために、down層のstrideやpaddingは元のモジュールと同じものにします。up層は1×1畳み込みです。
LoHa
LoHaは二つのLoRAのアダマール積をとる手法です。アダマール積とは単純に行列の要素ごとの積をとる演算です。
です。
LoRAの項目があった形になおすと、
個の足し算同士の掛け算によって、項が個になります。よってになります。パラメータ数が2倍になるのに対して、rankの上界が2乗になります。
LoKr
LoKRはクロネッカー積を使う手法です。
クロネッカー積とは行列に対して、以下のような行列を返す演算です。
行列と行列に対してクロネッカー積を適用すると、行列になります。
となります。右だけLoRAです。左までLoRAにする設定もあるようです。
クロネッカー積に関して、となるので、rank的にはめちゃくちゃ効率よくなります。ただし重み共有を使っているので、rank的にいいからといって表現力が高いかというと微妙だと思いますけどね。
IA3
各モジュールの入力もしくは出力をチャンネルごとにスケーリングします。数式的には対角行列を重みの左側もしくは右側にかけます。パラメータ数は非常に小さいです。入出力両方に適用すれば素朴に表現力があがりそうですが、そういった設定はないようですね。
GLoRA
GLoRAは差分だけでなく、元の重みへの入力に対してもLoRAを適用します。
元論文ではもっと複雑な設計ですが、省略した実装のようですね。これをLoKR版にしたGLoKRもあります。
LoRAと比べて表現力は増えていないんですが、元の重みを利用することで学習が早くなったりするんですかね(よく分かりません)。
DyLoRA
複数のrankのLoRAを同時に学習する方法です。LoRAはという形にできます。ここではの列目、はの行目です。DyLoRAではステップごとにランダムにを選び、とします。このように学習すると、任意のrankで、として生成できるようになります。のrankを学習するときに、以下のrankのLoRAに影響を与えないため勾配を無効にしています。rankは1ずつではなくブロック分けすることも可能です。
Norm
GroupNormやLayerNorm層も学習対象にします。重みやバイアスの差分を学習するというだけで特に難しいことはありません。
Full
を元の重みと同じサイズの行列にします。つまりやっていることは普通のファインチューニングと同じです。差分をとっておくのはVRAMの浪費でしかないんですが、LyCORIS上でフルファインチューニングを実装するにはそうするしかなかったんでしょう。一応差分に対してドロップアウトを実行できるというメリットはありますけどお。