تغییر یک رشته متنی ساده در فایل تنظیمات اکنون میتواند جایگزین ساعتها بازنویسی دستی کد در پژوهشهای مبتنی بر JAX شود. گوگل ریسرچ (Google Research) کتابخانه Kauldron را منتشر کرد؛ ابزاری برای به حداکثر رساندن سرعت پژوهش که کل فرآیند آموزش — از بهینهساز تا معماری مدل — را به شکل درختی از دیکشنریهای ساده و تغییرپذیر میبیند.
پژوهشهای مدرن یادگیری ماشین اغلب دچار «پراکندگی تنظیمات» (config sprawl) میشوند؛ وضعیتی که در آن ابرپارامترها (Hyperparameter) — شبیه به پیچهای تنظیم یک دستگاه رادیو قدیمی که هر کدام روی کیفیت صدا اثر میگذارند — در کلاسهای تودرتو یا مستقیماً درون تعریف مدل دفن شدهاند. این چالش با مفاهیم بنیادیتر ساختار مدلها گره خورده است؛ همانطور که در بررسی ارکان تبدیل ریاضیات به هوش مصنوعی اشاره کردیم، پیکربندی در کنار وزنها و توکنسازها، یکی از ستونهای اصلی شکلدهی به هوش مصنوعی است. همانطور که در تحلیل قبلی ما دربارهی اینکه گوگل ریسرچ چگونه از خودبهبودی منظم (regularized self-improvement) برای کاهش بیشبرازش در عاملهای هوش مصنوعی استفاده میکند اشاره کردیم، Kauldron جنبهی ساختاری این مشکل را هدف قرار داده است. این کتابخانه منطق «چگونه آموزش دهیم» را از کدهای پایتون خارج کرده و به یک لایهی دادهای منتقل میکند که قابل تبدیل به JSON و تغییر از طریق دستورات خط فرمان است.
سامانه تنظیمات دادهمحور
در قلب Kauldron، سیستمی به نام konfig قرار دارد که درختهای فراخوانی پایتون را به دیکشنریهای ساده تبدیل میکند. طبق مستندات این پروژه، وقتی محققی کتابخانهای مانند Optax را در بلوک konfig.imports() وارد میکند، سیستم بلافاصله یک شیء بهینهساز نمیسازد. در عوض، یک ConfigDict ایجاد میکند که نام تابع و آرگومانهای آن را ذخیره میکند.
برای مثال، فراخوانی optax.adam(learning_rate=0.003) در این بلوک، بهجای یک بهینهساز فعال، یک ConfigDict برمیگرداند. این تنظیمات تغییرپذیر است؛ محقق میتواند مقدار cfg.learning_rate = 1e-4 را تغییر دهد و تنها در لحظه نهایی با دستور konfig.resolve(cfg)، شیء واقعی را ایجاد کند. این رویکرد تضمین میکند که تنظیمات تا لحظه اجرا، صرفاً «داده» باقی بمانند.
به دلیل اینکه این تنظیمات دیکشنریهای تودرتو هستند، زنجیرههای پیچیده بهینهساز (Optimizer) — برای مثال زنجیرهای که clip_by_global_norm(1.0)، scale_by_adam(b2=0.99) و scale_by_learning_rate(0.003) را با هم ترکیب میکند — را میتوان به JSON صادر کرد و دوباره بهطور کامل بازسازی نمود. این یعنی دیگر نیازی به کلاسهای پایه، سیستمهای ثبت (registries) یا دکوراتورهای پیچیده در کتابخانههای مورد استفاده نیست. در واقع، کتابخانهای مثل Optax اصلاً نمیداند konfig وجود دارد.
یکی از حیاتیترین قابلیتها، cfg.ref است. در سیستمهای سنتی، اگر زمانبندی نرخ یادگیری به تعداد کل گامهای آموزش وابسته باشد، تغییر گامها مستلزم بهروزرسانی دستی زمانبندی است. Kauldron از ارجاعات استفاده میکند؛ یک زمانبندی کاهش کسینوسی (warmup-cosine decay) میتواند decay_steps خود را به cfg.ref.num_train_steps متصل کند، بهجای اینکه از یک مقدار سختافزاری مثل ۱۰۰۰ استفاده کند. اگر محقق گامها را از ۱۰۰۰ به ۲۰۰ تغییر دهد، زمانبندی بهطور خودکار در لحظه اجرا بازسازی میشود. بدون این واسط، یک جستوجوی گسترده روی گامهای آموزش منجر به نتایجی میشد که روی منحنیهای اشتباه آموزش دیدهاند و اعداد آنها هرچند باورپذیر، اما از نظر ریاضی غلط است.
جداسازی از طریق سیمکشی رشتهای
Kauldron از مکانیزمی به نام kontext برای اتصال اجزایی استفاده میکند که نباید از وجود یکدیگر باخبر باشند. بهجای اینکه یک تابع زیان برای امتیازدهی به خروجیها، مدل را وارد (import) کند، اجزا از طریق مسیرهای کلیدی رشتهای به هم متصل میشوند.
مکانیزمهای Kontext:
- زمینه به مثابه داده: یک زمینه (Context) دادههای تودرتوی معمولی است. مسیری مانند
batch.imageیاpreds.aux[0].posمستقیماً به کلیدهای دیکشنری، ویژگیها (attributes) و ایندکسهای لیست دسترسی پیدا میکند. - حاشیهنویسی کلیدها: هر شیئی میتواند ورودیهای خود را با برچسب
kontext.Keyتعریف کند. - تفکیک (Resolution): تابع
resolve_from_keyed_objدقیقاً همان مسیرها را از زمینه استخراج کرده و بهعنوان آرگومانهای کلیدی (keyword arguments) به تابع تحویل میدهد.
به عنوان مثال، یک معیار ارزیابی را میتوان طوری تنظیم کرد که پیشبینیها را در مسیر preds.logits و اهداف را در batch.label جستوجو کند. در این حالت، معیار هرگز مدل را وارد نمیکند و مدل هم خبری از معیار ندارد. تغییر مسیر یک معیار به یک تنسور دیگر، به سادگی تغییر یک رشته در فایل تنظیمات است. اگر مسیری نامعتبر باشد، kontext یک KeyError صادر میکند که دقیقاً لیست میکند چه دادههایی در دسترس بودهاند.
این جداسازی تا لایههای داخلی مدل نیز پیش میرود. با استفاده از متغیرهای میانی ثبتشده در Flax، محقق میتواند نرم یک لایه داخلی را با ارجاع به مسیری مثل interms.enc.__call__[0] رصد کند. این یعنی نظارت بر فعالسازهای داخلی مدل بدون اضافه کردن حتی یک خط کد لاگگذاری به متد __call__ مدل امکانپذیر است. این رویکرد در مدیریت متمرکز دادهها و زمینهها شباهت زیادی به استراتژیهای مقیاسپذیر دارد؛ همانطور که در تحلیل مدیریت Context در مقیاس سازمانی بررسی کردیم، تفکیک صحیح زمینهها برای عملیاتی کردن مدلهای زبانی در سطح سازمان حیاتی است.
ایمنی شکل در زمان اجرا
برای جلوگیری از خطاهای رایج «عدم تطابق شکل» (shape mismatch) که توسعه با JAX را دشوار میکند، Kauldron ماژول ktyping را پیاده کرده است. این ماژول بررسی شکل دادهها را در زمان اجرا با استفاده از محورهای نامگذاریشده انجام میدهد.
بهجای مقایسه تاپلهای بینام مثل (2, 16, 8)، محققان توابع را با محورهای نامدار مانند Float['*b n c'] و Float['c d'] حاشیهنویسی میکنند. دکوراتور مربوطه، هر نام محور را در اولین مشاهده ثبت کرده و این پیوند را در تمام آرگومانها و مقدار بازگشتی اجرا میکند.
اگر عدم تطابقی رخ دهد — مثلاً محور c در آرگومان اول ۸ باشد اما در آرگومان دوم ۵ باشد — سیستم فقط خطای شکل نمیدهد، بلکه یک بلوک «ابعاد استنتاجشده» (Inferred Dims) چاپ میکند. این بلوک دقیقاً نام محوری که باعث اختلاف شده را میگوید (مثلاً: "c already bound to 8, got 5") و یک جلسه عیبیابی طولانی را به یک اصلاح تکخطی تبدیل میکند. در مدلهایی که چندین تنسور همزمان در جریان هستند، این قابلیت نیاز به ردیابی دستی تاپلهای بینام را از بین میبرد.
مدیریت وضعیت و Trainer
شیء kd.train.Trainer بهعنوان چسب بین مدل، خط لوله داده، توابع زیان و بهینهساز عمل میکند. این ابزار بهگونهای طراحی شده است که بسیار سبک باشد و خروجیهای کمکی (مانند معیارها) را تنها در صورتی که صراحتاً درخواست شده باشد (مثلاً return_losses=True و return_metrics=True) تولید کند تا زمان پردازش در دستگاه کاهش یابد.
پیادهسازی تابع زیان و معیارها:
- توابع زیان: یک تابع زیان سفارشی، مانند پیادهسازی
LogCoshرا میتوان به صورت یک dataclass منجمد با فیلدهایkontext.Keyتعریف کرد. این تابع متدget_valuesرا برای بازگرداندن یک آرایه به ازای هر المان پیاده میکند؛ سپس چارچوب Kauldron خودش عملیات کاهش (reduction) و اعمال آرگومان وزن (مثلاًweight=0.5که نتیجه را دقیقاً نصف میکند) را مدیریت میکند. - معیارها: یک معیار در Kauldron بهجای یک عدد ساده، یک وضعیت (State) برمیگرداند که قابل ادغام است.
- ادغام وضعیت: با استفاده از
kd.metrics.sum_field()برای ردیابی جداگانه صورت و مخرج (مثلاًn_hitوn_total)، نتیجه نهایی فارغ از اندازه دستهها (batch size) دقیق باقی میماند.
این موضوع برای مدیریت دستههای «ناهمگون» (ragged) در پایان هر Epoch حیاتی است. اگر یک معیار روی یک دسته ۶ ردیفی و سپس روی یک دسته ۲ ردیفی محاسبه شود، ادغام وضعیتها نتیجهای دقیق میدهد، در حالی که میانگین گرفتن ساده از نرخهای هر دسته، از نظر ریاضی غلط است. این مکانیزم ادغام تجمعی (associative merge) همچنین اجازه میدهد Kauldron معیارها را در چندین دستگاه مختلف بدون نگرانی از ترتیب رسیدن نتایج، تجمیع کند.
سرعت پژوهش در عمل
مزیت عملی این معماری در زمان «جستوجوی ابرپارامترها» (Hyperparameter Sweeps) آشکار میشود. چون کل آزمایش یک تنظیمات (config) است، یک sweep صرفاً یک حلقه روی تغییرات تنظیمات است.
در یک نمایش اخیر با استفاده از یک مجموعه داده رگرسیون مصنوعی (تولید شده توسط np.random.default_rng)، پنج آزمایش مجزا اجرا شد که شامل موارد زیر بود:
۱. اجرای پایه (Baseline).
۲. کاهش عرض مدل به hidden=4.
۳. افزایش عرض مدل به hidden=128.
۴. افزایش نرخ یادگیری به ۰.۱.
۵. جایگزینی کامل بهینهساز Adam با optax.sgd(0.05).
تمام این موارد بدون تغییر حتی یک کاراکتر در کد مدل MLP یا تابع زیان LogCosh یا کد حلقه آموزش اجرا شدند. هر نسخه با یک ویرایش تکخطی در ConfigDict ایجاد شد و سپس به یک Trainer منجمد تبدیل گشت. در خط فرمان، این تغییرات بهصورت فلگهایی مثل --cfg.model.hidden=128 نوشته میشوند.
حفاظها و پایداری
برای حفظ یکپارچگی، Kauldron تخصیص اشیاء اجراشده (مانند یک ماژول فعال Flax) را درون ConfigDict بهشدت ممنوع کرده است. اگر محققی این کار را امتحان کند، سیستم بلافاصله یک ValueError صادر میکند. این کار تضمین میکند که هر تنظیماتی قابل سریالسازی، قابل مقایسه (diff) و قابل تغییر از خط فرمان باشد. یک تنظیمات نیمهپردازششده (half-resolved) قابل سریالسازی نیست، بنابراین سیستم بهجای شکست در مراحل بعدی که ردیابیشان سخت است، کل این وضعیت را از ابتدا رد میکند.
این انضباط به زیر-اشیاء نیز تسری مییابد. برای مثال، kd.data.InMemoryPipeline و kd.evals.Evaluator فیلدهای بذر (seed) و مجموعه داده (ds) خود را به صورت پیشفرض به تنظیمات ریشه (_FakeRootCfg) ارجاع میدهند. این فیلدها هنگام ساخت شیء در Trainer پر میشوند، اما اگر شیء بهصورت مستقل ساخته شود، باید صراحتاً مقداردهی شوند.
برای کارهای طولانیمدت، Kauldron از Checkpointer و Evaluator استفاده میکند. ارزیاب، مدل و توابع زیان را از تنظیمات ریشه به ارث میبرد و تنها به یک مجموعه داده و زمانبندی (مثلاً kd.evals.EveryNSteps(100)) نیاز دارد. اگر یک اجرای موقت (preemptible) متوقف شود، متد train() بهطور خودکار آخرین نقطه بازرسی را در دایرکتوری کاری (مثلاً /tmp/kauldron_resume) پیدا کرده و دقیقاً از همان گام متوقفشده ادامه میدهد. در یک تست، مدل آموزشدیده تا گام ۲۰۰، برای ۳۰۰ گام بازسازی شد و نوار پیشرفت بهدرستی از ۲۰۰ شروع شد، نه از صفر.
این معماری بار مدیریت آزمایش را از دوش برنامهنویس به دوش تنظیمات منتقل میکند. گوگل ریسرچ با تبدیل خط لوله ML به یک گراف دادهمحور بهجای یک اسکریپت سختافزاری، قصد دارد اصطکاک بین یک فرضیه و تست تجربی آن را به حداقل برساند.
گام بعدی شما
- اگر از JAX یا Flax استفاده میکنید، ساختار
ConfigDictرا برای جایگزینی کلاسهای تنظیمات سختافزاری بررسی کنید. - برای عیبیابی سریعتر ابعاد تنسورها، سیستم نامگذاری محورهای
ktypingرا در توابع خود پیاده کنید. - برای اجرای Sweepهای سریع، تنظیمات مدل خود را به فرمت JSON درآورید تا بتوانید آنها را از خط فرمان مدیریت کنید.
اما داستان سختافزاری این تحول حتی شگفتانگیزتر است — به تحلیل ما دربارهی تراشههای Blackwell مراجعه کنید.




گفتگو