LoRA फाइन-ट्यूनिंग असल में क्या ट्रेन करती है?
"LoRA मॉडल का लगभग 1% ट्रेन करता है" यही आमतौर पर दी जाने वाली एक लाइन की सफ़ाई है। यह सही है, पर यह उन बातों को छिपा देती है जो तय करती हैं कि कोई रन आपकी मशीन पर फिट होगा या नहीं और कितना समय लेगा: किन layers में adapt
"LoRA मॉडल का लगभग 1% ट्रेन करता है" यही आमतौर पर दी जाने वाली एक लाइन की सफ़ाई है। यह सही है, पर यह उन बातों को छिपा देती है जो तय करती हैं कि कोई रन आपकी मशीन पर फिट होगा या नहीं और कितना समय लेगा: किन layers में adapters लगते हैं, rank से उनकी गिनती पर क्या असर पड़ता है, frozen weights किस precision में रखे जाते हैं, और छोटे dataset से असल में कितने optimizer steps मिलते हैं।
यहाँ ये नंबर एक ठोस रन के लिए निकाले गए हैं: Qwen2.5-1.5B-Instruct, rank 16, 16GB Apple Silicon Mac पर। सेटिंग्स डेस्कटॉप ऐप osFoundry के लोकल ट्रेनर के डिफ़ॉल्ट हैं, जो एक सादी transformers + PEFT + TRL स्क्रिप्ट है, इसलिए यह हिसाब किसी भी मिलते-जुलते सेटअप पर लागू होता है। (ऐप का LoRA फाइन-ट्यूनिंग पेज इसका UI दिखाता है।)
एक adapter यानी दो पतले matrices
d_out × d_in आकार के weight matrix W के लिए, LoRA W को freeze कर देता है और दो matrices सीखता है, A (r × d_in) और B (d_out × r)। Layer का आउटपुट W·x + (α/r)·B·A·x हो जाता है। B शून्य से शुरू होता है, इसलिए ट्रेनिंग ठीक बेस मॉडल से शुरू होती है।
उस layer में ट्रेन होने वाले पैरामीटर की संख्या r × (d_in + d_out) है। यह rank और layer की चौड़ाई के साथ सीधी रेखा में बढ़ती है, layer के क्षेत्रफल के साथ नहीं।
Adapters कहाँ लगते हैं
ट्रेनर हर transformer block की सातों linear projections पर adapters लगाता है:
target_modules=["q_proj", "k_proj", "v_proj", "o_proj",
"gate_proj", "up_proj", "down_proj"]
Qwen2.5-1.5B में 28 blocks हैं, hidden size 1536, MLP size 8960, और grouped-query attention है जिसमें 128 dimension के 2 KV heads हैं, इसलिए k और v 256 तक प्रोजेक्ट होते हैं। r = 16 पर हर block में:
| Layer | d_in → d_out | ट्रेन होने वाले |
|---|---|---|
| q_proj | 1536 → 1536 | 49,152 |
| k_proj | 1536 → 256 | 28,672 |
| v_proj | 1536 → 256 | 28,672 |
| o_proj | 1536 → 1536 | 49,152 |
| gate_proj | 1536 → 8960 | 167,936 |
| up_proj | 1536 → 8960 | 167,936 |
| down_proj | 8960 → 1536 | 167,936 |
यानी हर block में 659,456, और 28 blocks में 18,464,768: कुल 1.54B में से 18.5M ट्रेन होने वाले, यानी 1.2%।
दो बातें ध्यान खींचती हैं। MLP projections में adapter के तीन-चौथाई weights होते हैं, इसलिए उन्हें छोड़ देने पर (जैसा कुछ पुराने रेसिपी करते थे, जो सिर्फ़ q और v को adapt करते थे) गिनती घटकर लगभग 2.2M रह जाती है, यानी क्षमता का आठवाँ हिस्सा। और GQA की वजह से k और v पतले होते हैं, इसलिए उनके adapters सस्ते पड़ते हैं।
ज़्यादातर मेमोरी frozen weights में जाती है
Apple के GPU पर ट्रेनर मॉडल को float32 में लोड करता है:
torch_dtype = torch.float16 if device == "cuda" else torch.float32
MPS पर half precision में अक्सर NaN loss आता है, इसलिए वहाँ 32-बिट ही सुरक्षित विकल्प है। इससे frozen बेस 1.54B × 4 बाइट ≈ 6.2 GB का हो जाता है।
तुलना में ट्रेन होने वाला हिस्सा छोटा है। fp32 में 18.5M weights 74 MB हैं, उनके gradients 74 MB और, और AdamW हर weight के लिए दो moment अनुमान रखता है, यानी 148 MB और। कुल मिलाकर लगभग 0.3 GB। बाकी बजट activations में जाता है, जो batch size और sequence length के साथ बढ़ता है (ट्रेनर sequences को 2048 टोकन तक सीमित रखता है; चैट के छोटे जवाब इससे बहुत नीचे रहते हैं)।
16 GB के Mac में से GPU के लिए लगभग 12 GB इस्तेमाल हो सकते हैं, तो fp32 में 1.5B के लिए जगह बचती है। fp32 में 7B बेस ट्रेनिंग शुरू होने से पहले ही लगभग 30 GB का होता। इसीलिए Mac पर बेस मॉडल छोटा रखा जाता है, और इसीलिए QLoRA (4-बिट frozen weights) मौजूद है, हालाँकि bitsandbytes का 4-बिट रास्ता NVIDIA GPU माँगता है, इसलिए Mac पर सादा LoRA ही चलता है।
छोटे dataset से अपडेट आपकी सोच से कम मिलते हैं
ट्रेनर batch size 4 और 4 gradient-accumulation steps इस्तेमाल करता है, यानी हर optimizer अपडेट 16 उदाहरण देखता है। 200 pairs के साथ:
- 200 ÷ 4 = हर epoch में 50 forward/backward batches
- 50 ÷ 4 ≈ हर epoch में 13 optimizer अपडेट
- 3 epochs ≈ कुल 39 अपडेट, जिनमें पहले 10 learning-rate warmup हैं
2e-4 की learning rate और linear decay के साथ उनतालीस अपडेट लहज़ा बदलने के लिए काफ़ी हैं, नई जानकारी सिखाने के लिए नहीं। यह वही है जो व्यवहार में दिखता है: दो सौ के आसपास जवाब मॉडल के लिखने का ढंग बदलते हैं, उसकी जानकारी नहीं।
आखिर में क्या निकलता है
ट्रेनिंग के बाद सिर्फ़ adapter सेव होता है: 196 adapted layers में से हर एक के A और B, यानी कुछ दर्जन मेगाबाइट। इन्फ़रेंस के लिए ऐप उसे GGUF LoRA फ़ाइल में बदलता है और llama.cpp उसे बेस की quantized कॉपी के ऊपर लगाता है, यहाँ qwen2.5-1.5b-instruct को Q4_K_M में। बेस साझा रहता है, इसलिए कई adapters (हर लहज़े या काम के लिए एक) की कीमत हर एक की कुछ दर्जन MB है।
Precision के बेमेल पर ध्यान दें: adapter को fp32 बेस weights के सामने ट्रेन किया गया था और वह 4-बिट weights पर चलता है। छोटे style adapter के लिए यह फ़र्क आमतौर पर महसूस नहीं होता, पर यह एक वजह है कि merge करके दोबारा quantize किया गया मॉडल रनटाइम पर लगाए गए उसी adapter से थोड़ा अलग व्यवहार कर सकता है।
Originally published by Dev.to AI. Aggregated on AIWithGhost for educational purposes — full credit and traffic to the original publisher.

