एक GPU पर सोलह दिनों का कम्प्यूट
एक सिंगल लॉन्ग रन
ANDREA-120M RTX 4090 पर ~23 दिन लेता है (FP16, 6 स्टेप्स/मिन, 200K स्टेप्स)। वॉल पावर, कर्नेल पैनिक्स, प्रॉक्सी क्रैशेस, & जानबूझकर कॉन्फिग चेंजेस उस विंडो में सब होते हैं। चेकपॉइंट्स के बिना एक छोटी सी रुकावट पूरा रन फेंक देती है।
v1 ने एक गलती (lr=0.001 बहुत आक्रामक) से 27K स्टेप्स खो दिए क्योंकि लॉन्च पॉइंट से कोई चेकपॉइंट करीब नहीं था। v2 ने वो सबक लिया: चेकपॉइंट कैडेंस हर 100 स्टेप्स पर गिरा दिया, & CUDA सिग्नल हैंडलर SIGTERM पर चेकपॉइंट राइट गारंटी करता है।
तीन भूमिकाएँ
एक चेकपॉइंट तीन नौकरियाँ एक साथ करता है:
1. रिकवरी पॉइंट। प्रोसेस मर जाता है, मशीन रीबूट होती है, कर्नेल पैनिक: नवीनतम step_NNNNNN.bin से फिर से शुरू करें।
2. पॉलिश पिवट। स्टेप 112,619: पुनः प्रशिक्षण के बिना पाठ्यक्रम बदलें। SIGUSR1 एक साफ चेकपॉइंट लागू करता है, प्रॉक्सी रुक जाता है, नई कैप्स और फ्लोर्स सबमिट हो जाती हैं, CUDA नए पॉलिसी के तहत सहेजे गए पॉइंट से फिर से शुरू होता है।
3. ऑडिट फोर्क। समान प्रारंभिक वेट्स पर दो कॉन्फ़िग्स की तुलना करें: एक चेकपॉइंट कॉपी करें, दो विचलित ब्रांचेस को आगे चलाएँ, देखें कि कौन सा अभिसरित होता है।
हर 100 स्टेप्स के बीच ~17 मिनट का ट्रेनिंग समय मिलता है, जो 6 स्टेप्स/मिनट पर लिखने के बीच का है। 100 स्टेप्स sample_every से भी मेल खाते हैं: हर चेकपॉइंट एक ताज़ा सैंपल ऑडिट से मेल खाता है, & हर सैंपल ऑडिट एक रिकवरेबल पॉइंट से मेल खाता है।
एक फाइल के लिए तीन भूमिकाएँ
एक फाइल में पाँच क्षेत्र
प्रारूप
हर step_NNNNNN.bin में पाँच सन्निकट क्षेत्र होते हैं:
[int32 step] [int32 n_params] [n_params x float32 weights] [n_params x float32 m] [n_params x float32 v]
क्षेत्र दर क्षेत्र
हेडर (कुल 8 बाइट्स). एक 32-बिट स्टेप नंबर हमें बताता है कि यह स्नैपशॉट ट्रेनिंग के किस चरण में स्थित है; एक 32-बिट पैरामीटर काउंट हमें बताता है कि तीन ट्रेलिंग ऐरे प्रत्येक कितने बड़े हैं।
वेट्स (n_params x 4 बाइट्स). हर सीखा गया पैरामीटर, फ्लैट। क्रम मॉडल के पैरामीटर इटरेटर से मेल खाता है: टोकन और पोजीशन एम्बेडिंग्स, फिर प्रति-लेयर अटेंशन और MLP वेट्स, फिर आउटपुट हेड।
एडम पहला मोमेंट m (n_params x 4 बाइट्स). पिछले ग्रेडिएंट्स का EMA (beta1 = 0.9)। वेट्स के समान आकार। AdamW रिज़्यूम्पशन के लिए आवश्यक।
Adam का दूसरा क्षण v (n_params x 4 bytes). पिछले वर्गीकृत ग्रेडिएंट्स का EMA (beta2 = 0.999). वेट्स के समान आकार. AdamW resumption के लिए आवश्यक.
कुल आकार
कुल बाइट्स = 8 + 12 x n_params. ANDREA-12M (12.8M params): डिस्क पर 154 MB (147 MB गोल). ANDREA-120M (~120M params) FP32: ~1.44 GB. समान आकार के तीन ऐरे, एक के बाद एक स्टैक, छोटे हेडर के साथ.
m & v क्यों सहेजें
Vanilla Adam प्रति-पैरामीटर लर्निंग रेट्स को m & v के माध्यम से ट्रैक करता है. चेकपॉइंट लिखते समय उन्हें ड्रॉप करें & resumed run शून्य मोमेंटम & शून्य variance अनुमान से शुरू होता है, जो एक स्टेप के लिए लर्निंग रेट 0 के बराबर है फिर अचानक रैंप. लॉस स्पाइक्स; मॉडल अपने वर्तमान basin से बाहर गिर सकता है. m & v सहेजने से resume बिट-समान (dataloader randomness को छोड़कर) never-stopped baseline के बराबर होता है.
एक चेकपॉइंट का आकार निर्धारण
SIGTERM और SIGUSR1
CUDA सिग्नल्स को क्यों हैंडल करता है
ट्रेनिंग एक लंबे समय तक चलने वाली फोरग्राउंड प्रक्रिया के रूप में चलती है। जब प्रॉक्सी या ऑपरेटर GPU को रोकना चाहता है, तो CUDA इंजन को एक सिग्नल भेजा जाता है। हैंडलर के बिना, डिफ़ॉल्ट SIGTERM प्रक्रिया को तुरंत मार देता है: इन-फ्लाइट ग्रेडिएंट कम्प्यूटेशन फेंक दिया जाता है, पिछले चेकपॉइंट के बाद से नवीनतम वेट्स खो जाते हैं। हैंडलर के साथ, इंजन पहले चेकपॉइंट लिखता है फिर साफ़-सुथरे तरीके से बाहर निकलता है।
SIGTERM: लिखें और बाहर निकलें
स्टॉप बटन, systemctl stop, या पैरेंट प्रॉक्सी से kill द्वारा भेजा जाता है। CUDA वर्तमान स्टेप को पूरा करता है, step_NNNNNN.bin को डिस्क पर लिखता है, फिर बाहर निकलता है। इस स्थिति से रिकवरी के लिए केवल नवीनतम .bin की आवश्यकता है: इन-फ्लाइट आंशिक स्टेप के अलावा कोई काम खोया नहीं जाता।
SIGUSR1: लिखें और जारी रखें
ऑपरेटर या प्रॉक्सी स्क्रिप्ट द्वारा मांग पर भेजा जाता है। CUDA वर्तमान स्टेप को पूरा करता है, step_NNNNNN.bin लिखता है, फिर ऐसा करते हुए जारी रखता है जैसे कुछ हुआ ही न हो। उपयोगी के लिए: कॉन्फ़िग चेंज से ठीक पहले एक ऑडिट पॉइंट ट्रिगर करना; ज्ञात-भले पल पर वेट्स कैप्चर करना; चेकपॉइंट को बाहरी सैंपल-क्वालिटी ग्रेडिंग रन के साथ संरेखित करना।
पोलिश पिवट अनुक्रम (चरण 112,619)
1. ऑपरेटर CUDA को SIGUSR1 भेजता है। चेकपॉइंट अगली 100-चरण सीमा पर लिखा जाता है (चरण 112,700)।
2. ऑपरेटर प्रॉक्सी को रोकता है।
3. .samples.json और .state.json को संग्रहित किया जाता है (नमूना लॉग और बैंडिट स्थिति को ऐतिहासिक रिकॉर्ड के रूप में संरक्षित किया जाता है)।
4. .loss.json अपनी जगह पर रहता है। संचयी प्रशिक्षण इतिहास; कभी संग्रहित नहीं किया जाता।
5. प्रॉक्सी नए कैप्स और फ्लोर्स के तहत पुनः आरंभ होता है।
6. CUDA step_112700.bin से पूर्ण वेट्स, m, और v के साथ ताजा बैंडिट के साथ पुनः आरंभ होता है।
लॉस हिस्ट्री पिवट के पार बिना रुके जारी रहती है। सैंपल लॉग साफ़-सुथरा रीसेट होता है। बैंडिट नई पॉलिसी के तहत ताज़ा शुरुआत पाता है।
सिग्नल चुनना
क्यूमुलेटिव ट्रेनिंग हिस्ट्री
तीन साइडकार फाइलें
हर चेकपॉइंट के साथ, प्रॉक्सी रन डायरेक्टरी में तीन JSON साइडकार फाइलें बनाए रखता है:
- .loss.json -- हर स्टेप के लिए एक एंट्री, हमेशा। रन के अंत तक ~200,000 एंट्री। संचयी ट्रेनिंग इतिहास।
- .samples.json -- ऑडिट के लिए हाल की उत्पन्न सैंपल। पॉलिश पिवोट्स पर रीसेट।
- .state.json -- बैंडिट आर्म पुल्स, EMA रिवार्ड्स, फेज काउंटर्स। पॉलिश पिवोट्स पर रीसेट।
क्या रीसेट होता है, क्या बना रहता है
पोलिश पिवट्स नीति परिवर्तन हैं, रन रीसेट नहीं। मॉडल के वेट्स, m, v, और लॉस हिस्ट्री सभी बिना रुके जारी रहते हैं। बैंडिट के संचित रिवॉर्ड्स जारी नहीं रहते: नए कैप्स और फ्लोर्स एक अलग नीति परिभाषित करते हैं, और बैंडिट को नए नीति के तहत साफ स्थिति से फिर से सीखना पड़ता है।
क्यों .loss.json बरकरार रहता है
लॉस हिस्ट्री रन के ऑडिट ट्रेल के रूप में कार्य करती है। ANDREA-120M (चरण 110K पर लॉस EMA, पोलिश-पिवट रिकवरी, चरण 112K पर अभिसरण) के बारे में हर प्रकाशित दावा इस फाइल की प्रविष्टियों पर ट्रेस करता है। चरणों के बीच .loss.json को आर्काइव करना पाठकों को रन को पुनर्निर्माण करने के लिए टुकड़ों को जोड़ने के लिए मजबूर करेगा; इसे केवल अपेंड-ओनली और अछूत रखना प्रोवेनेंस को संरक्षित करता है।
ज़ॉम्बी आर्म लेसन
चरण 112,619 ने .state.json में एक repo-docstrings आर्म पाया जो पूर्व रन से वजन 1.546 ले जा रहा था। बैंडिट स्टेट को पहले रीस्टार्ट के पार संरक्षित किया गया था लेकिन डेटा स्रोत अब उपलब्ध नहीं था, जिससे ज़ॉम्बी पुल्स उत्पन्न हुए जो एक्सप्लोरेशन अकाउंटिंग को विकृत करते थे। लेसन: बैंडिट स्टेट को रीस्टार्ट्स के पार आश्चर्यजनक तरीकों से ड्रिफ्ट करने की अनुमति है। लॉस हिस्ट्री एकमात्र फाइल है जो रन की पूरी आयु के लिए अछूती रहनी चाहिए।
एक नियम जो सब कुछ नियंत्रित करता है
.samples.json और .state.json को चरणों के बीच स्वतंत्र रूप से संग्रहित करें। कभी .loss.json को संग्रहित न करें। सबसे नया .loss.json हमेशा प्रशिक्षण इतिहास का आधिकारिक रिकॉर्ड होता है।
नियम का अनुप्रयोग
क्या बनाया गया & क्यों
पाँच निर्णय
1. Cadence: हर 100 स्टेप्स पर। Recovery point granularity ~17 मिनट। sample_every के साथ संरेखित ताकि हर चेकपॉइंट एक ताज़ा सैंपल ऑडिट से मेल खाए।
2. Format: हेडर + 3 arrays। न्यूनतम: 8-बाइट हेडर बताता है कि प्रत्येक ट्रेलिंग array कितना बड़ा है। कोई मेटाडेटा ब्लोट नहीं। जब m & v सेव होते हैं तो बिट-समतुल्य रिज्यूम।
3. Signals: SIGTERM & SIGUSR1। दो भूमिकाएँ, दो सिग्नल। डिफ़ॉल्ट systemd शटडाउन को SIGTERM के माध्यम से साफ़ चेकपॉइंट मिलता है; ऑन-डिमांड ऑडिट पॉइंट्स को SIGUSR1 के माध्यम से बिना रुकावट के साफ़ चेकपॉइंट मिलता है।
4. Loss continuity: कभी आर्काइव नहीं। संचयी ट्रेनिंग इतिहास polish pivots, रीस्टार्ट्स, & पॉलिसी बदलावों के पार बना रहता है। पूरे रन के लिए एक ऑडिट ट्रेल।
5. Bandit state: रीसेट की अनुमति। Bandit policy एक समय में एक कॉन्फ़िग के अधीन रहता है। Polish pivots रीसेट करते हैं; loss history जारी रहता है। दो अलग लाइफटाइम्स एक ही रन डायरेक्टरी साझा करते हैं।
यह पाठ क्या जोड़ता है
- गतिविधि 23 (grow_a_language_model_sample_audit). sample_every cadence चेकपॉइंट cadence से मेल खाता है; दोनों हर 100 स्टेप्स पर फायर करते हैं।
- गतिविधि 24 (grow_a_language_model_microgpt_to_andrea). v1 collapse, v2.5 patch, v3 polish pivot सभी को साफ चेकपॉइंट्स की आवश्यकता है काम करने के लिए।
- गतिविधि 10 (grow_a_language_model_adamw). चेकपॉइंट में m और v को सेव करना महत्वपूर्ण है क्योंकि AdamW का अपडेट नियम दोनों पर निर्भर करता है। इन्हें ड्रॉप करें और रिज्यूम करने पर विचलन होता है।
एक अंतिम इंजीनियरिंग सत्य
कोड लेखकों से अधिक टिकता है। इन्फ्रास्ट्रक्चर बिल्डर्स से अधिक टिकता है। एक सरल चेकपॉइंट फॉर्मेट हर फैंसी रिज्यूम स्कीम से अधिक टिकता है जिसने ऑप्टिमाइजर स्टेट सेव न करने का वादा किया था। बाइट्स सेव करें; रन सेव करें।