1 poin oleh GN⁺ 2024-01-23 | 1 komentar | Bagikan ke WhatsApp
  • LoRA (Low-Rank Adaptation) adalah teknik untuk mengurangi biaya fine-tuning dengan memperbarui hanya matriks kecil berperingkat rendah tanpa melatih ulang seluruh LLM; Studio ini mengimplementasikan layer LoRA secara langsung untuk memeriksa cara kerjanya
  • Intinya adalah mengaproksimasi perubahan bobot ΔW pada fine-tuning umum sebagai hasil perkalian dua matriks kecil A dan B; makin kecil rank r, makin berkurang parameter pelatihan sekaligus kapasitas representasinya
  • Matriks bobot 5.000×10.000 memiliki 50 juta parameter, tetapi LoRA dengan r=8 hanya menambahkan B 5.000×8 dan A 8×10.000, sehingga menjadi 120 ribu parameter, 400 kali lebih kecil
  • Pada klasifikasi sentimen IMDb berbasis DistilBERT, LoRA dasar mencatat Test acc 89,44%, lebih tinggi daripada 86,22% saat hanya melatih dua layer terakhir, tetapi lebih rendah daripada 92,31% dari fine-tuning penuh
  • Setelah eksplorasi hyperparameter, LoRA mencatat Val acc 92,96% dan Test acc 92,39% dengan sekitar 500 ribu parameter pelatihan, menghasilkan akurasi sedikit lebih tinggi daripada fine-tuning penuh yang melatih 66.955.010 parameter

Biaya fine-tuning yang dikurangi LoRA

  • LoRA adalah singkatan dari Low-Rank Adaptation, sebuah teknik untuk melakukan fine-tuning LLM dengan lebih efisien
  • Fine-tuning umum menyesuaikan semua parameter model deep learning, tetapi LoRA hanya memperbarui sekumpulan kecil matriks berperingkat rendah
  • LLM pralatih dapat digunakan untuk banyak tugas, tetapi fine-tuning berguna untuk menyesuaikannya dengan dataset atau tugas tertentu
  • Makin besar model, pendekatan memperbarui semua layer makin membebani biaya komputasi

Mengaproksimasi ΔW sebagai perkalian matriks kecil

  • Dalam fine-tuning umum, pembaruan matriks bobot W dihitung sebagai ΔW
  • LoRA mengaproksimasi ΔW sebagai hasil perkalian dua matriks kecil A dan B
    • Jika Anda familier dengan PCA atau SVD, ini bisa dipandang mirip dengan memfaktorkan ΔW menjadi A dan B
  • Rank r adalah hyperparameter LoRA
    • r yang lebih kecil dapat mengurangi jumlah parameter pelatihan, mempercepat pelatihan, dan menurunkan kebutuhan komputasi
    • Pada saat yang sama, kapasitas matriks berperingkat rendah untuk menangkap informasi spesifik tugas juga menurun
  • Contoh matriks bobot 5.000×10.000:
    • Pembaruan umum ΔW: total 50 juta parameter
    • LoRA r=8: B 5.000×8, A 8×10.000
    • Parameter tambahan: 80.000 + 40.000 = 120.000
    • 400 kali lebih kecil dibanding fine-tuning umum
  • Dalam penggunaan nyata, berbagai nilai r perlu dicoba untuk menemukan keseimbangan antara performa dan biaya

Mengimplementasikan layer LoRA dengan PyTorch

  • LoRALayer dasar menerima dimensi input, dimensi output, rank, dan koefisien penskalaan alpha
class LoRALayer(torch.nn.Module):
    def __init__(self, in_dim, out_dim, rank, alpha):
        super().__init__()
        std_dev = 1 / torch.sqrt(torch.tensor(rank).float())
        self.A = torch.nn.Parameter(torch.randn(in_dim, rank) * std_dev)
        self.B = torch.nn.Parameter(torch.zeros(rank, out_dim))
        self.alpha = alpha

    def forward(self, x):
        x = self.alpha * (x @ self.A @ self.B)
        return x
  • in_dim adalah dimensi input layer tempat LoRA diterapkan, dan out_dim adalah dimensi output
  • rank mengendalikan kompleksitas matriks A dan B serta jumlah parameter yang ditambahkan LoRA
  • alpha menentukan besar perubahan yang diberikan LoRA pada bobot model yang sudah ada
    • Jika alpha tinggi, perilaku model disesuaikan lebih besar
    • Jika alpha rendah, perubahannya lebih halus
  • A diinisialisasi dengan bilangan acak kecil, dan simpangan bakunya ditentukan oleh akar kuadrat rank
    • Ini dipilih agar nilai awal A tidak terlalu besar
  • B diinisialisasi dengan nol
    • Sebelum pelatihan dimulai, karena B=0, maka AB=0
    • Sebelum A dan B diperbarui melalui backpropagation, LoRALayer tidak memengaruhi bobot asli

Mengganti layer Linear dengan LinearWithLoRA

  • LoRA biasanya diterapkan pada layer Linear/feed-forward dalam jaringan saraf
  • Jika forward yang ada memanggil dua layer Linear secara berurutan, setelah menerapkan LoRA, output LoRA ditambahkan ke output masing-masing Linear
def forward(self, x):
    x = self.linear_1(x) + self.lora_1(x)
    x = F.relu(x)
    x = self.linear_2(x) + self.lora_2(x)
    return logits
  • Saat memodifikasi model PyTorch yang ada, cara sederhananya adalah mengganti tiap layer Linear dengan LinearWithLoRA
class LinearWithLoRA(torch.nn.Module):
    def __init__(self, linear, rank, alpha):
        super().__init__()
        self.linear = linear
        self.lora = LoRALayer(
            linear.in_features, linear.out_features, rank, alpha
        )

    def forward(self, x):
        return self.linear(x) + self.lora(x)
  • LinearWithLoRA menyimpan layer Linear asli bersama LoRALayer baru
  • Dengan mengganti layer Linear pada model pralatih dengan LinearWithLoRA, Anda dapat memasang LoRA lalu melakukan fine-tuning

Eksperimen klasifikasi IMDb dengan DistilBERT

  • Contoh praktik ini menggunakan klasifikasi teks, yang akurasinya lebih mudah dievaluasi dibanding teks generatif
  • Model menggunakan DistilBERT pralatih dari Hugging Face transformers
from transformers import AutoModelForSequenceClassification

model = AutoModelForSequenceClassification.from_pretrained(
    "distilbert-base-uncased", num_labels=2)
  • Untuk melatih hanya bobot LoRA baru, requires_grad dari semua parameter model diatur ke False
for param in model.parameters():
    param.requires_grad = False
  • DistilBERT memiliki 6 layer Transformer, dan di dalam tiap layer ada layer Linear
    • Pada attention terdapat q_lin, k_lin, v_lin, out_lin
    • Pada FFN terdapat lin1, lin2
    • Di sisi output terdapat dua layer Linear, pre_classifier dan classifier

Konfigurasi untuk menerapkan LoRA secara selektif

  • Konfigurasi LoRA dasar menerapkan LoRA hanya pada matriks bobot query dan value di attention
lora_r = 8
lora_alpha = 16
lora_dropout = 0.05
lora_query = True
lora_key = False
lora_value = True
lora_projection = False
lora_mlp = False
lora_head = False
  • Dengan melakukan loop pada tiap layer Transformer di DistilBERT, layer Linear yang dipilih diganti dengan LinearWithLoRA
    • Jika lora_query=True, ganti q_lin
    • Jika lora_key=True, ganti k_lin
    • Jika lora_value=True, ganti v_lin
    • Jika lora_projection=True, ganti out_lin
    • Jika lora_mlp=True, ganti ffn.lin1, ffn.lin2
    • Jika lora_head=True, ganti pre_classifier, classifier
  • Setelah penggantian, output model dapat memperlihatkan bahwa q_lin, v_lin, dan lainnya telah berubah menjadi LinearWithLoRA

Perbandingan LoRA dasar dan fine-tuning umum

  • Hasil pelatihan klasifikasi IMDb Movie Reviews dengan konfigurasi LoRA dasar:
    • Train acc: 92,15%
    • Val acc: 89,98%
    • Test acc: 89,44%
  • Hasil fine-tuning hanya dua layer output terakhir:
    • Train acc: 86,68%
    • Val acc: 87,26%
    • Test acc: 86,22%
    • Jumlah parameter pelatihan: 592.130
  • LoRA dasar memiliki Test acc lebih tinggi daripada metode yang hanya melatih dua layer terakhir, dengan jumlah parameter pelatihan lebih sedikit, yaitu 147.456
  • Hasil fine-tuning seluruh layer dengan cara tradisional:
    • Train acc: 96,41%
    • Val acc: 92,80%
    • Test acc: 92,31%
    • Jumlah parameter pelatihan: 66.955.010
  • Fine-tuning penuh memiliki Test acc sekitar 2% lebih tinggi daripada LoRA dasar, tetapi memperbarui sekitar 450 kali lebih banyak parameter dibanding konfigurasi LoRA

Eksplorasi hyperparameter LoRA

  • Performa LoRA dapat bervariasi tergantung pada lora_r, lora_alpha, dan pengaturan layer target penerapan
  • 03_finetune-lora.py menerima hyperparameter sebagai argumen command-line
python 03_finetune-lora.py --lora_alpha 32 --lora_r 16
  • Target penerapan LoRA lainnya juga dapat diaktifkan bersamaan
python 03_finetune-lora.py \
--lora_alpha 32 \
--lora_r 16 \
--lora_query True \
--lora_key True \
--lora_value True \
--lora_projection True \
--lora_mlp True \
--lora_head True
  • 03_gridsearch.py menjalankan grid berikut pada semua GPU yang tersedia
    • alpha_values = [1, 4, 8, 16, 32, 64]
    • rank_values = [1, 2, 4, 8, 16, 32]
    • lora_query = ["True"]
    • lora_key = ["False", "True"]
    • lora_value = ["True"]
    • lora_projection = ["False", "True"]
    • lora_mlp = ["False", "True"]
    • lora_head = ["False", "True"]
  • Skrip dapat dijalankan melalui Visual Studio Code, terminal command-line, atau Job; Job akan otomatis berhenti setelah selesai
  • Hasil disimpan di results.txt

Konfigurasi terbaik dari pencarian grid

  • Berdasarkan results.txt, konfigurasi hyperparameter terbaik adalah sebagai berikut
lora_r: 8
lora_alpha: 1
lora_query: True
lora_key: False
lora_value: True
lora_projection: False
lora_mlp: True
lora_head: False
  • Hasil dari konfigurasi ini:
    • Val acc: 92,96%
    • Test acc: 92,39%
  • Konfigurasi LoRA ini memiliki sekitar 500k parameter pelatihan, jauh lebih sedikit daripada 66M parameter pada fine-tuning penuh
  • Akurasinya sedikit lebih tinggi daripada Val acc 92,80% dan Test acc 92,31% dari fine-tuning penuh

Lingkungan eksekusi dan materi tambahan

  • Dengan mengeklik Run di bagian atas Studio, Anda dapat menggandakan lingkungan yang berisi kode
  • Setelah Studio digandakan, file kode dapat dijalankan tanpa langkah instalasi, unduhan, atau konfigurasi tambahan
  • Notebook dan skrip terkait:
    • 00_lora-layer.ipynb: implementasi layer LoRA
    • 01_finetune-last-layers.ipynb: fine-tuning layer terakhir
    • 02_finetune-with-lora.ipynb: fine-tuning dengan LoRA
    • 03_finetune-lora.py: menjalankan LoRA dengan argumen hyperparameter
    • 03_gridsearch.py: pencarian grid hyperparameter LoRA
    • 04_finetune-all-layers.ipynb: fine-tuning seluruh layer
  • Materi tambahan:

1 komentar

 
GN⁺ 2024-01-23
Komentar Hacker News
  • Alur tekniknya mengikuti LLMs 101 dari Maxime Labonne: https://github.com/mlabonne/llm-course#4-supervised-fine-tun...

  • LoRA != LoRa, jadi terus bikin bingung. Saya tidak suka mereka memakai ulang akronim yang sudah ada

    • Saya juga begitu. Pekerjaan utama saya machine learning, tapi—atau mungkin justru karena itu—setiap kali melihat akronim ini di tempat yang konteksnya minim, saya selalu berhenti sejenak
      Terutama di tempat seperti halaman depan HN, di mana kedua makna sama-sama wajar
    • Selain “Low-Rank Adaptation”, artinya apa lagi? Mencari perbedaannya pun sulit
    • Hal seperti ini terjadi ketika orang terlalu terspesialisasi sampai tidak peduli apa yang terjadi di luar gelembung mereka sendiri
    • Saya tidak suka tren orang software mengambil nama yang terkait hardware lalu menempelkannya ke hal lain
    • Sayang sekali dua teknologi yang sejauh ini tidak saling terkait akhirnya memakai akronim yang sama
  • Masih terasa aneh bahwa di bidang ilmu komputer ada ucapan seperti “kita tidak tahu persis bagaimana angka-angka ini, yaitu hyperparameter, memengaruhi hasil, jadi mari coba berbagai nilai lalu pakai yang paling bagus”

    • “Coba berbagai nilai lalu pakai yang paling bagus” bukankah mirip memakai simulasi Monte Carlo untuk mencari nilai?
      Kadang bisa tersangkut di maksimum lokal alih-alih optimum/jawaban benar, tetapi tetap bekerja. Karena tidak bisa diselesaikan dengan rumus bentuk tertutup, kita mengambil sampel acak kira-kira miliaran kali untuk menemukan nilai yang diinginkan. Bukan berarti LLM juga persis sama, tetapi pendekatan seperti ini cukup sering dipakai
    • Rasanya seperti perbedaan antara sesuatu yang direkayasa dan sesuatu yang ditemukan
      Sampai sekarang sebagian besar industri ini adalah hal yang dirancang secara rekayasa, sedangkan LLM lebih dekat ke sesuatu yang ditemukan
    • Tambal sulam bottom-up semacam itu juga mirip dengan cara ilmu komputer dimulai di Amerika, sebagaimana diamati Dijkstra sendiri: https://www.cs.utexas.edu/users/EWD/transcriptions/EWD06xx/E...
      Idealnya memang perlu landasan teoretis, tetapi untuk menarik cukup data guna membuat atau memverifikasi teori, kadang diperlukan pencarian acak
    • Banyak juga karena Minsky dan orang-orang lain meremehkan perceptron dengan alasan tidak bisa memodelkan fungsi nonlinier. LLM mungkin memang sulit muncul tanpa CPU dan GPU modern, tetapi itu bukan berarti kita tidak bisa lebih dulu memiliki landasan teoretis yang lebih baik
      Kita tertinggal beberapa tahun dari posisi yang seharusnya. Saat saya bekerja di industri game pada 1990-an, “akal sehat” saat itu adalah bahwa neural network paling banter jalan buntu, paling buruk penipuan. Sangat disayangkan begitu banyak waktu hilang karena beberapa figur otoritatif mencegah semua orang mencobanya, dan kali ini kita harus memastikan hal itu tidak terulang
    • Rasanya mirip meneliti pengaturan Stable Diffusion. Yang cepat terlihat adalah bahwa di dalamnya banyak unsur tebakan
  • Masih belum jelas kapan harus melakukan fine-tuning dan kapan memakai RAG
    Dulu saya mengira fine-tuning terutama dipakai untuk mengubah perilaku model, tetapi belakangan beberapa perusahaan tampaknya juga memakai fine-tuning untuk menambahkan pengetahuan. Saya penasaran apa penggunaan utama fine-tuning

    • Menurut saya penggunaan utamanya masih perubahan perilaku. Misalnya instruction fine-tuning dan fine-tuning untuk klasifikasi
      Menambahkan pengetahuan ke bobot paling baik dilakukan lewat pre-training. Atau jika ada database eksternal atau dokumen yang akan dikueri saat generasi, gunakan RAG seperti untuk pertanyaan. Sebagai catatan, di NeurIPS 2023 LLM Efficiency Challenge, semua pemenang yang melakukan fine-tuning LLM “terbaik” dalam 24 jam dengan 1 GPU memakai LoRA atau QLoRA (LoRA terkuantisasi)

    • Jika data tambahan tidak ringkas atau membutuhkan konteks, fine-tuning lebih baik daripada RAG
      Jika konteks terlalu banyak atau fokusnya kabur, kepatuhan terhadap prompt bisa terdilusi, dan RAG tidak membuat model mempelajari asosiasi token berdimensi lebih tinggi. Jadi Anda harus beruntung mengambil konten yang dibutuhkan dari materi pelengkap, dan itu tidak jauh lebih baik daripada mesin pencari yang agak canggih. Ini terutama bermasalah ketika menangani korpus khusus yang memiliki mikro-dialek internal sendiri dan tidak banyak muncul di dataset publik, seperti dokumen internal pemerintah atau perusahaan besar

    • Sejauh pemahaman saya, fine-tuning luar biasa efektif [0]. Sebab in-context learning sangat bergantung pada seberapa kuat model dasar dan bagaimana RAG disusun, yaitu pemrosesan kueri, pencarian embedding, pemeringkatan hasil, dan sebagainya [1]
      Menurut paper yang saya baca, fine-tuning dapat menambahkan pengetahuan domain baru atau memperkuat pengetahuan tertentu, sedangkan RAG terbatas pada penguatan saja. Namun, dua teknik dengan trade-off berbeda ini kadang menunjukkan kemampuan pada tingkat yang mirip [2]

      [0] Fast.ai: Can Models learn from one sample, https://www.fast.ai/posts/2023-09-04-learning-jumps/ / https://archive.is/eJMPR

      [1] LlamaIndex: Advanced RAG, https://blog.llamaindex.ai/a-cheat-sheet-and-some-recipes-fo... / https://archive.is/qtBXX

      [2] Microsoft: RAG vs Fine-tuning: Pipelines, Tradeoffs, and a Case Study, https://arxiv.org/html/2401.08406v2#S6 / https://archive.is/UQ8Sa#S6

    • Ini adalah model autoregresif. Jika ada jenis sekuens baru yang elemen berikutnya dapat diprediksi dari bagian sebelumnya, dan caranya berbeda dari yang pernah dilihat model sebelumnya, fine-tuning tampaknya masuk akal
      Sebagai kriteria untuk menentukan apa yang harus dilakukan dalam situasi data tertentu, ini memang cukup kabur, tetapi mungkin cukup sebagai heuristik kasar. Apakah penambahan pengetahuan termasuk di sini mungkin soal selera tanpa eksperimen

  • Tulisan yang bagus. Saya bukan orang di bidang ini, tetapi saat membaca makalah aslinya, saya memahami bahwa LoRA hanya diterapkan pada lapisan padat terakhir, dan tidak diterapkan secara independen ke semua lapisan. Bisa jadi saya salah baca
    Setelah menelusuri kenapa implementasi di tautan itu seperti ini, ternyata QLoRA memakai cara ini dan tampaknya ada efek yang menarik. Akan bagus jika ditambahkan catatan tentang keputusan QLoRA tersebut. Namun saya tidak terlalu paham kenapa ini bekerja; dari sudut pandang pemula, menerapkan LoRA pada lapisan terakhir masuk akal, tetapi saya belum menangkap dasar untuk menerapkannya berulang pada setiap lapisan linear. Bisa jelaskan intuisiinyaa?

    • Seperti banyak hal dalam machine learning, pemilihan lapisan mana yang dipakai lebih banyak ditentukan oleh bukti empiris daripada teori. Dalam pipeline pelatihan LoRA yang umum, model dasar dibekukan dan hanya lapisan LoRA yang disesuaikan
      Semakin banyak lapisan yang diganti menjadi lapisan LoRA, semakin besar derajat kebebasan dalam optimisasi. Sebagian metode fine-tuning menyarankan hanya melakukan fine-tuning pada lapisan terakhir, karena diasumsikan memuat representasi input yang “paling tingkat tinggi”. Metode lain melakukan fine-tuning pada semua lapisan. Sebagian besar bergantung pada data dan masalahnya, dan LoRA mencerminkan praktik ini apa adanya
  • Saya lebih suka pendekatan mulai dari konfigurasi, bukan “dari nol” ala Axolotl. Axolotl mendukung fine-tuning Mistral dan Llama 2, serta banyak teknik modern seperti sample packing, FlashAttention, dan xFormers
    Alih-alih belajar LoRA dari nol, saya fokus mengumpulkan dan mengkurasi data fine-tuning, lalu melakukan fine-tuning yang berpusat pada data

  • Penamaan memang sulit. Awalnya saya kira ini membahas LoRa yang berarti “long range”, atau LoRaWAN untuk komunikasi sensor IoT

  • Library apa yang paling banyak dipakai untuk fine-tuning? Maksudnya untuk cara yang bukan “dari nol”

  • Wah, awalnya saya juga tentu saja mengira ini membahas LoRa

  • Seberapa besar biaya performa LoRA?

    • Saat pelatihan, ini lebih efisien daripada fine-tuning penuh karena hanya sebagian parameter yang diperbarui melalui backpropagation
      Saat inferensi, ada dua kemungkinan. Jika nilai LoRA ditambahkan secara dinamis selama forward pass, secara teori bisa sedikit lebih lambat, tetapi ini juga bisa menjadi keunggulan jika ingin mempertahankan set bobot kecil yang terpisah untuk tiap pelanggan. Sebab, kita bisa menjalankan satu model dasar besar saja dan menerapkan bobot LoRA per pelanggan secara langsung. Jika bobot LoRA digabungkan kembali ke model dasar, performanya bisa persis sama dengan model dasar