1 पॉइंट द्वारा GN⁺ 2024-01-23 | 1 टिप्पणियां | WhatsApp पर शेयर करें
  • LoRA(Low-Rank Adaptation) एक तकनीक है जो पूरे LLM को दोबारा train किए बिना केवल छोटी low-rank matrices को update करके fine-tuning की लागत घटाती है, और यह Studio LoRA layer को सीधे implement करके उसका व्यवहार दिखाता है
  • मुख्य विचार सामान्य fine-tuning में weights के बदलाव ΔW को दो छोटी matrices A, B के गुणनफल से approximate करना है; rank r जितना छोटा होगा, trainable parameters और representation capacity दोनों उतने ही कम होंगे
  • 5,000×10,000 weight matrix में 5 करोड़ parameters होते हैं, लेकिन r=8 LoRA केवल B 5,000×8 और A 8×10,000 जोड़ता है, जिससे यह 1.2 लाख parameters के साथ 400 गुना छोटा हो जाता है
  • DistilBERT-आधारित IMDb sentiment classification में basic LoRA ने Test acc 89.44% दर्ज किया, जो केवल आखिरी दो layers train करने वाले 86.22% से अधिक था और full fine-tuning के 92.31% से कम था
  • hyperparameter search के बाद LoRA ने लगभग 5 लाख trainable parameters के साथ Val acc 92.96%, Test acc 92.39% हासिल किया, जो 6,69,55,010 parameters train करने वाली full fine-tuning से थोड़ा अधिक accurate रहा

LoRA fine-tuning की लागत कैसे घटाता है

  • LoRA का पूरा नाम Low-Rank Adaptation है, और यह LLMs को अधिक कुशलता से fine-tune करने की तकनीक है
  • सामान्य fine-tuning deep learning model के सभी parameters को adjust करती है, लेकिन LoRA केवल छोटी low-rank matrices के set को update करता है
  • pretrained LLM कई tasks में इस्तेमाल हो सकता है, लेकिन किसी specific dataset या task के लिए उसे अनुकूल बनाना हो तो fine-tuning उपयोगी होती है
  • जैसे-जैसे model बड़ा होता है, सभी layers को update करने का तरीका compute cost के लिहाज से भारी होता जाता है

ΔW को छोटी matrices के गुणनफल से approximate करना

  • सामान्य fine-tuning में weight matrix W के update को ΔW के रूप में calculate किया जाता है
  • LoRA ΔW को दो छोटी matrices A और B के गुणनफल से approximate करता है
    • अगर आप PCA या SVD से परिचित हैं, तो इसे ΔW को A और B में decompose करने जैसी विधि के रूप में देख सकते हैं
  • rank r LoRA का hyperparameter है
    • छोटा r trainable parameters की संख्या घटाता है, training तेज कर सकता है, और compute requirements कम कर सकता है
    • साथ ही task-specific information capture करने वाली low-rank matrices की capacity भी कम हो जाती है
  • 5,000×10,000 weight matrix का उदाहरण:
    • सामान्य update ΔW: कुल 5 करोड़ parameters
    • r=8 LoRA: B 5,000×8, A 8×10,000
    • अतिरिक्त parameters: 80,000 + 40,000 = 120,000
    • सामान्य fine-tuning की तुलना में 400 गुना छोटा
  • वास्तविक उपयोग में performance और cost का संतुलन खोजने के लिए कई r values के साथ प्रयोग करना चाहिए

PyTorch से LoRA layer implement करना

  • basic LoRALayer input dimension, output dimension, rank, और scaling coefficient 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 उस layer का input dimension है जिस पर LoRA लागू किया जाएगा, और out_dim output dimension है
  • rank A, B matrices की complexity और LoRA द्वारा जोड़े जाने वाले parameters की संख्या control करता है
  • alpha यह तय करता है कि LoRA existing model weights में होने वाले बदलाव की मात्रा कितनी होगी
    • alpha अधिक होने पर model behavior में बड़ा adjustment होता है
    • alpha कम होने पर बदलाव अधिक सूक्ष्म होता है
  • A को छोटे random numbers से initialize किया जाता है और standard deviation rank के square root से तय होता है
    • यह choice शुरुआती A values को बहुत बड़ा होने से रोकने के लिए है
  • B को 0 से initialize किया जाता है
    • training शुरू होने से पहले B=0 होता है, इसलिए AB=0
    • backpropagation से A और B update होने से पहले LoRALayer original weights को प्रभावित नहीं करता

Linear layer को LinearWithLoRA से बदलना

  • LoRA आम तौर पर neural network की Linear/feedforward layers पर लागू होता है
  • अगर existing forward दो Linear layers को क्रम से call करता है, तो LoRA लागू करने के बाद हर Linear output में LoRA output जोड़ा जाता है
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
  • existing PyTorch model को modify करते समय हर Linear layer को 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 original Linear layer और नए LoRALayer दोनों को साथ रखता है
  • pretrained model की Linear layers को LinearWithLoRA से बदलने पर LoRA attach करके fine-tuning की जा सकती है

DistilBERT से IMDb classification experiment

  • practical example generated text की बजाय text classification का इस्तेमाल करता है, क्योंकि इसमें accuracy evaluate करना आसान है
  • model Hugging Face transformers का pretrained DistilBERT इस्तेमाल करता है
from transformers import AutoModelForSequenceClassification

model = AutoModelForSequenceClassification.from_pretrained(
    "distilbert-base-uncased", num_labels=2)
  • केवल नए LoRA weights train करने के लिए model के सभी parameters का requires_grad False set किया जाता है
for param in model.parameters():
    param.requires_grad = False
  • DistilBERT में 6 Transformer layers हैं, और हर layer के अंदर Linear layers होती हैं
    • attention में q_lin, k_lin, v_lin, out_lin होते हैं
    • FFN में lin1, lin2 होते हैं
    • output side में pre_classifier, classifier दो Linear layers होती हैं

LoRA को चुनिंदा रूप से लागू करने की settings

  • basic LoRA setting attention के केवल query और value weight matrices पर LoRA लागू करती है
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
  • loop चलाकर DistilBERT की हर Transformer layer में selected Linear layers को LinearWithLoRA से replace किया जाता है
    • lora_query=True हो तो q_lin replace होता है
    • lora_key=True हो तो k_lin replace होता है
    • lora_value=True हो तो v_lin replace होता है
    • lora_projection=True हो तो out_lin replace होता है
    • lora_mlp=True हो तो ffn.lin1, ffn.lin2 replace होते हैं
    • lora_head=True हो तो pre_classifier, classifier replace होते हैं
  • replacement के बाद model output में देखा जा सकता है कि q_lin और v_lin आदि LinearWithLoRA में बदल गए हैं

Basic LoRA और सामान्य fine-tuning की तुलना

  • basic LoRA settings से IMDb Movie Reviews classification train करने के परिणाम:
    • Train acc: 92.15%
    • Val acc: 89.98%
    • Test acc: 89.44%
  • केवल आखिरी दो output layers fine-tune करने के परिणाम:
    • Train acc: 86.68%
    • Val acc: 87.26%
    • Test acc: 86.22%
    • trainable parameters की संख्या: 592,130
  • basic LoRA में Test acc केवल आखिरी दो layers train करने की विधि से अधिक था, और trainable parameters की संख्या 147,456 के साथ और भी कम थी
  • सभी layers को traditional तरीके से fine-tune करने के परिणाम:
    • Train acc: 96.41%
    • Val acc: 92.80%
    • Test acc: 92.31%
    • trainable parameters की संख्या: 66,955,010
  • full fine-tuning की Test acc basic LoRA से लगभग 2% अधिक है, लेकिन यह LoRA setting की तुलना में लगभग 450 गुना अधिक parameters update करती है

LoRA hyperparameter search

  • LoRA performance lora_r, lora_alpha, और target layer settings के अनुसार बदल सकती है
  • 03_finetune-lora.py hyperparameters को command-line arguments के रूप में लेता है
python 03_finetune-lora.py --lora_alpha 32 --lora_r 16
  • अन्य LoRA targets को भी साथ में enable किया जा सकता है
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 सभी available GPUs पर यह grid चलाता है
    • 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"]
  • script को Visual Studio Code, command-line terminal, या Job के रूप में चलाया जा सकता है, और Job पूरा होने के बाद अपने-आप बंद हो जाता है
  • results results.txt में save होते हैं

Grid search से मिली best settings

  • results.txt के आधार पर सबसे अच्छा hyperparameter configuration यह है
lora_r: 8
lora_alpha: 1
lora_query: True
lora_key: False
lora_value: True
lora_projection: False
lora_mlp: True
lora_head: False
  • इस setting के परिणाम:
    • Val acc: 92.96%
    • Test acc: 92.39%
  • इस LoRA setting में trainable parameters लगभग 500k हैं, जो full fine-tuning के 66M parameters से काफी कम हैं
  • accuracy full fine-tuning के Val acc 92.80%, Test acc 92.31% से थोड़ी अधिक है

Execution environment और अतिरिक्त resources

  • Studio के top पर Run click करने से code सहित environment clone किया जा सकता है
  • Studio clone करने के बाद code files को बिना किसी अतिरिक्त installation, download या setup step के run किया जा सकता है
  • संबंधित notebooks और scripts:
    • 00_lora-layer.ipynb: LoRA layer implementation
    • 01_finetune-last-layers.ipynb: आखिरी layers fine-tuning
    • 02_finetune-with-lora.ipynb: LoRA fine-tuning
    • 03_finetune-lora.py: LoRA hyperparameter arguments से execution
    • 03_gridsearch.py: LoRA hyperparameter grid search
    • 04_finetune-all-layers.ipynb: सभी layers की fine-tuning
  • अतिरिक्त resources:

1 टिप्पणियां

 
GN⁺ 2024-01-23
Hacker News टिप्पणियां
  • तकनीक का प्रवाह Maxime Labonne के LLMs 101 के अनुसार चल रहा है: https://github.com/mlabonne/llm-course#4-supervised-fine-tun...

  • LoRA != LoRa है, इसलिए बार-बार भ्रम होता है। पहले से मौजूद संक्षिप्त नाम को फिर से इस्तेमाल करना मुझे पसंद नहीं

    • मेरे साथ भी यही है। मेरा मुख्य काम machine learning है, फिर भी—या शायद इसी वजह से—जब भी बहुत कम context वाली जगह पर यह संक्षिप्त नाम दिखता है, मैं एक पल के लिए रुक जाता हूं
      HN के front page जैसी जगहों पर खासकर, जहां दोनों अर्थ स्वाभाविक लगते हैं
    • “Low-Rank Adaptation” के अलावा इसका दूसरा मतलब क्या है? फर्क search करना भी मुश्किल है
    • ऐसा तब होता है जब लोग इतने specialized हो जाते हैं कि अपने bubble के बाहर क्या हो रहा है, इसकी परवाह नहीं करते
    • software वालों द्वारा hardware से जुड़े नाम उठा लेने का trend मुझे पसंद नहीं
    • अफसोस है कि अब तक दो असंबंधित technologies एक ही acronym इस्तेमाल करने लगी हैं
  • computer science में अब भी अजीब लगता है कि कोई कहता है, “हमें ठीक-ठीक नहीं पता कि ये संख्याएं, यानी hyperparameters, result को कैसे प्रभावित करती हैं, इसलिए कई values आजमाकर जो सबसे अच्छा चले उसे इस्तेमाल करें”

    • “कई values आजमाकर जो सबसे अच्छा चले उसे इस्तेमाल करें” क्या value खोजने के लिए Monte Carlo simulation इस्तेमाल करने जैसा नहीं है?
      कभी-कभी optimal/सही जवाब के बजाय local maximum में फंस सकते हैं, लेकिन फिर भी यह काम करता है। closed-form formula से हल नहीं कर सकते, इसलिए अरबों बार random samples लेकर मनचाही value ढूंढने जैसा है; यह नहीं कह रहा कि LLM भी वही हैं, लेकिन ऐसा approach काफी बार इस्तेमाल होता है
    • यह engineered चीज़ और discovered चीज़ के फर्क जैसा लगता है
      अब तक industry का ज्यादातर हिस्सा engineering से design किया गया था, और LLM discovered चीज़ों के ज्यादा करीब हैं
    • ऐसी bottom-up tinkering Dijkstra ने खुद जैसा देखा था, अमेरिका में computer science की शुरुआत के तरीके से भी मिलती-जुलती है: https://www.cs.utexas.edu/users/EWD/transcriptions/EWD06xx/E...
      आदर्श रूप से theoretical foundation चाहिए, लेकिन theory बनाने या validate करने लायक data निकालने के लिए कभी-कभी random search जरूरी होती है
    • Minsky और दूसरों द्वारा perceptron को nonlinear functions model न कर पाने के कारण कमतर बताने का असर भी बड़ा था। LLM आधुनिक CPU और GPU के बिना वैसे भी निकलना मुश्किल था, लेकिन इसका मतलब यह नहीं कि हम पहले से बेहतर theoretical foundation नहीं रख सकते थे
      हम जहां होना चाहिए था, उससे कई साल पीछे हैं। 1990s में game industry में काम करते समय “common sense” यह था कि neural networks ज्यादा से ज्यादा dead end हैं और बुरे हाल में scam। कुछ authorities ने सबको रोक दिया, जिसकी वजह से इतना समय गंवाना सच में अफसोसनाक है; इस बार ऐसा दोहराया नहीं जाना चाहिए
    • Stable Diffusion settings को study करने का अनुभव भी कुछ ऐसा ही है। जल्दी ही समझ में आ जाता है कि इसमें बहुत अनुमानबाजी मिली हुई है
  • कब fine-tuning करना चाहिए और कब RAG इस्तेमाल करना चाहिए, यह अभी साफ नहीं है
    पहले मुझे लगता था कि fine-tuning मुख्यतः model के behavior को बदलने के लिए होती है, लेकिन हाल में कुछ companies knowledge जोड़ने के लिए भी fine-tuning इस्तेमाल करती दिखती हैं। fine-tuning के मुख्य use cases जानना चाहूंगा

    • मुख्य use case अब भी behavior change ही मानता हूं। instruction fine-tuning, classification के लिए fine-tuning आदि उसी में आते हैं
      weights में knowledge जोड़ना pre-training से सबसे अच्छा होता है। या generation के दौरान query करने के लिए बाहरी database या documents हों, तो सवाल की तरह RAG इस्तेमाल कर सकते हैं। संदर्भ के लिए, NeurIPS 2023 LLM Efficiency Challenge में 24 घंटे के अंदर 1 GPU पर “best” LLM fine-tune करने वाले सभी winners ने LoRA या QLoRA (quantized LoRA) इस्तेमाल किया था

    • अगर अतिरिक्त data संक्षिप्त नहीं है या context की जरूरत है, तो fine-tuning RAG से बेहतर है
      context बहुत ज्यादा हो या focus धुंधला हो तो prompt-following कमजोर पड़ सकती है, और RAG model को higher-dimensional token associations सीखने नहीं देता। इसलिए जरूरी सामग्री supporting material से किस्मत से खींचकर लानी पड़ती है, और तब वह किसी advanced search engine से खास बेहतर नहीं रहता। government या बड़ी companies के internal documents जैसे specialized corpora के मामले में यह खास समस्या है, जिनकी अपनी सूक्ष्म बोलियां public datasets में अच्छी तरह नहीं दिखतीं

    • मेरी समझ के अनुसार fine-tuning असामान्य रूप से प्रभावी है [0]। in-context learning काफी हद तक base model कितना शक्तिशाली है और RAG को कैसे बनाया गया है—यानी query processing, embedding search, result ranking वगैरह—पर निर्भर करती है [1]
      पढ़े गए papers के अनुसार fine-tuning नया domain knowledge जोड़ सकती है या specific knowledge को मजबूत कर सकती है, जबकि RAG केवल reinforcement तक सीमित है। हालांकि अलग trade-offs वाली दोनों techniques कभी-कभी समान स्तर की capability दिखाती हैं [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

    • ये autoregressive models हैं। अगर कोई नई तरह की sequence है जिसमें आगे आने वाले elements को पिछले हिस्से से predict किया जा सकता है, और वह तरीका model ने पहले जो देखा है उससे अलग है, तो fine-tuning उचित लगती है
      किसी specific data situation में क्या करना है, यह तय करने के लिए यह काफी vague है, लेकिन मोटे heuristic के रूप में पर्याप्त हो सकता है। knowledge जोड़ना इसमें आता है या नहीं, यह experiment के बिना शायद पसंद का मामला हो

  • अच्छा लेख है। मैं इस क्षेत्र का व्यक्ति नहीं हूं, लेकिन जब मैंने मूल paper पढ़ा था, तो मेरी समझ यह थी कि LoRA केवल आखिरी dense layer पर लागू होता है, और सभी layers पर स्वतंत्र रूप से लागू नहीं होता। हो सकता है मैंने गलत पढ़ा हो
    लिंक वाले implementation में ऐसा क्यों है, थोड़ा खोदकर देखा तो पता चला कि QLoRA ने यही तरीका इस्तेमाल किया था, और लगता है इसके कुछ रोचक प्रभाव हैं। QLoRA के इस निर्णय पर कोई note जोड़ना अच्छा रहेगा। हालांकि यह क्यों काम करता है, यह मुझे ठीक से नहीं पता; beginner के नज़रिए से आखिरी layer पर LoRA लागू करना समझ में आता है, लेकिन हर linear layer पर बार-बार लागू करने का आधार intuitively समझ नहीं आता। क्या आप इसका intuition समझा सकते हैं?

    • Machine learning में बहुत-सी चीज़ों की तरह, कौन-सी layer इस्तेमाल करनी है यह theory से ज़्यादा empirical evidence पर निर्भर करता है। सामान्य LoRA training pipeline में base model को freeze किया जाता है और केवल LoRA layers को adjust किया जाता है
      जितनी ज़्यादा layers को LoRA layers से बदला जाता है, optimization की freedom उतनी बढ़ती है। कुछ fine-tuning तरीके केवल आखिरी layer को fine-tune करने की सलाह देते हैं, क्योंकि माना जाता है कि उसमें input का “सबसे high-level” representation होता है। दूसरे तरीके सभी layers को fine-tune करते हैं। ज़्यादातर यह data और problem पर निर्भर करता है, और LoRA इसी convention को जस-का-तस reflect करता है
  • मुझे Axolotl का “from scratch” नहीं, बल्कि configuration से शुरू करने वाला approach पसंद है। Axolotl Mistral, Llama 2 fine-tuning को support करता है, और sample packing, FlashAttention, xFormers जैसी कई आधुनिक techniques को भी support करता है
    मैं LoRA को scratch से सीखने के बजाय fine-tuning data इकट्ठा करने और curate करने पर focus करता हूं, यानी data-centric fine-tuning करता हूं

  • नाम रखना वाकई मुश्किल है। पहले मुझे लगा था कि यह “long range” वाले LoRa या IoT sensor communication LoRaWAN की बात है

  • fine-tuning के लिए सबसे ज़्यादा इस्तेमाल होने वाली libraries कौन-सी हैं? “from scratch” नहीं, उस approach के हिसाब से

  • वाह, मुझे भी शुरुआत में स्वाभाविक रूप से लगा था कि यह LoRa की ही बात है

  • LoRA की performance cost कितनी होती है?

    • training के दौरान backpropagation से केवल कुछ parameters update होते हैं, इसलिए यह full fine-tuning से ज़्यादा efficient है
      inference के दौरान दो options हैं। forward pass के दौरान LoRA values को dynamically जोड़ने पर theory में थोड़ी slowdown हो सकती है, लेकिन अगर आप हर customer के लिए छोटे weight sets अलग से रखना चाहते हैं तो यह फायदा भी हो सकता है। वजह यह है कि आप एक बड़ा base model ही चला सकते हैं और customer-specific LoRA weights को on-the-fly apply कर सकते हैं। अगर LoRA weights को base model में फिर से merge कर दिया जाए, तो base model जैसी ही exact performance मिल सकती है