اجرای مدل‌های هوش مصنوعی با زبان سلام: بارگذاری مدل‌های زبانی GGUF، اجرای ONNX و ساخت ابزار یادگیری ماشین بدون پایتون

کتابخانه‌ی استاندارد سلام می‌تواند مدل‌های زبانی GGUF را بخواند، مدل‌های کوچک خانواده‌ی Llama را روی پردازنده اجرا کند و گراف‌های ONNX را به کار بیندازد، همه با کد خالص سلام. در این نوشته می‌بینیم چه چیزی کار می‌کند، چه هزینه‌ای دارد و برای چه کاری ساخته نشده است.

در این مقاله
  1. منظور از «اجرای هوش مصنوعی» در این نوشته
  2. خواندن فایل مدل‌های GGUF با ai.gguf
  3. اجرای یک مدل زبانی کوچک با ai.llm
  4. اجرای مدل‌های ONNX با ai.onnx
  5. لایه‌ی تانسور در زیر همه‌ی این‌ها
  6. آموزش مدل‌های کوچک روی پردازنده
  7. یک زبان بومی کجا کمک می‌کند و کجا نه
  8. آینده‌ی هوش مصنوعی در زبان سلام: گام‌های بعدی
  9. پرسش‌های متداول درباره‌ی اجرای هوش مصنوعی با زبان سلام

بله، می‌توانید مدل‌های هوش مصنوعی را از یک برنامه‌ی سلام اجرا کنید، در محدوده‌ای روشن. کتابخانه‌ی استاندارد زبان برنامه‌نویسی سلام یک خواننده‌ی GGUF (ai.gguf)، یک موتور استنتاج کوچک برای خانواده‌ی Llama (ai.llm)، یک اجراکننده‌ی گراف ONNX (ai.onnx) و زیر آن‌ها بسته‌های تانسور، مشتق‌گیری خودکار و شبکه‌ی عصبی دارد. استنتاج هوش مصنوعی (AI Inference) در سلام یعنی بارگذاری فایل یک مدل آموزش‌دیده و محاسبه‌ی خروجی‌های آن درون یک فایل اجرایی بومی، بدون مفسر پایتون و بدون هیچ کتابخانه‌ی زمان اجرای بیرونی. این کار فقط روی پردازنده (CPU) انجام می‌شود، برای مدل‌های کوچک اندازه شده و جایگزین llama.cpp، ONNX Runtime یا PyTorch روی کارت گرافیک نیست.

این نوشته در دسته‌ی «آینده» آمده، چون پرسش جالب این است که این مسیر به کجا می‌رود. اما آینده باید از امروز شروع شود؛ پس بیشتر آنچه در ادامه می‌آید چیزی است که امروز در مخزن هست، با برنامه‌های واقعی و محدودیت‌هایی که مستندات خود بسته‌ها بیان کرده‌اند.

منظور از «اجرای هوش مصنوعی» در این نوشته

وقتی می‌گوییم «هوش مصنوعی اجرا کنیم»، ممکن است منظورمان چند کار کاملاً متفاوت باشد. بهتر است آن‌ها را از هم جدا کنیم، چون سلام برخی را خوب، برخی را تا حدی و برخی را اصلاً پوشش نمی‌دهد.

کارابزار رایج در جاهای دیگرسلام امروز
آموزش یک مدل بزرگ روی کارت گرافیکPyTorch، JAXپوشش داده نمی‌شود: کتابخانه کدی برای GPU ندارد
سرویس‌دادن یک مدل بزرگ به کاربران زیادvLLM، سرور llama.cpp، APIهای میزبانی‌شدهفراخوانی چنین سروری از راه HTTP
اجرای یک مدل زبانی کوچک درون برنامهllama.cppai.llm با فایل GGUF کمتر از ۲ گیگابایت
اجرای یک دسته‌بند یا مدل embedding صادرشدهONNX Runtimeai.onnx، حدود ۶۵ عملگر
آموزش یک شبکه‌ی کوچک روی پردازندهPyTorch روی CPUai.nn، ai.autograd، ai.optim
یادگیری ماشین کلاسیک روی داده‌های جدولیscikit-learnai.ml
تبادل آرایه با پایتونفایل‌های NumPynpy پرونده‌های .npy و .npz را می‌خواند و می‌نویسد

الگو روشن است: سلام در سر کوچک و تعبیه‌شده‌ی این طیف به کار می‌آید، جایی که برنامه به مدل به‌عنوان یکی از اجزایش نیاز دارد و شما یک فایل اجرایی بومی می‌خواهید که محیط پایتونی کنارش نباشد. در سر بزرگ طیف، پاسخ صادقانه این است که یک سرور را فراخوانی کنید.

خواندن فایل مدل‌های GGUF با ai.gguf

GGUF قالب فایل llama.cpp است. یک فایل، فراداده (معماری، اندازه‌ها، واژگان توکن‌ساز، قالب گفت‌وگو) و همه‌ی وزن‌ها را، که معمولاً کوانتیزه شده‌اند، در خود نگه می‌دارد. بسته‌ی ai.gguf این فایل را تجزیه می‌کند: بارگذاری جی‌جی‌یو‌اف (LoadGguf) سرآیند و فهرست تانسورها را می‌خواند، فراداده صحیح و فراداده رشته کلیدهای فراداده را برمی‌گردانند و بارگذاری تانسور اعشاری (LoadTensorF32) یک وزن را به تانسوری از عددهای اعشاری ۳۲ بیتی باز می‌کند.

برنامه‌ی زیر فایل مدلی را که در خط فرمان داده شده بررسی می‌کند. این برنامه این‌جا فقط بررسی گونه می‌شود و اجرا نمی‌شود، چون به یک مدل دانلودشده نیاز دارد.

سلام
واردسازی هوش مصنوعی.جی‌جی‌یو‌اف
واردسازی سیستم عامل

تابع ریشه:
    آرگ‌ها := سیستم عامل.آرگومان ها()
    اگر آرگ‌ها.طول() < ۲:
        سرچاپ «روش استفاده: inspect model.gguf»
        برگشت ۱
    پایان
    ناپایا مدل := جی‌جی‌یو‌اف.جی‌جی‌یو‌اف {}
    تلاش:
        مدل = جی‌جی‌یو‌اف.بارگذاری جی‌جی‌یو‌اف(آرگ‌ها.بگیر(۱))
    گرفتن خطا خ:
        سرچاپ «این فایل GGUF خواندنی نیست:»، خ.به رشته()
        برگشت ۱
    پایان
    معماری := مدل.فراداده رشته(«general.architecture»)
    سرچاپ «مدل:»، مدل.فراداده رشته(«general.name»)، «(» + معماری + «)»
    سرچاپ «لایه‌ها:»، مدل.فراداده صحیح(معماری + «.block_count»، ۰)
    سرچاپ «طول زمینه:»، مدل.فراداده صحیح(معماری + «.context_length»، ۰)
    ناپایا ناخوانا := ۰
    تکرار مدل.تانسورها.طول() در ای:
        اگر جی‌جی‌یو‌اف.بایت‌های تانسور(مدل، ای) < ۰:
            ناخوانا++
        پایان
    پایان
    سرچاپ مدل.تانسورها.طول()، «تانسور،»، ناخوانا، «تا با گونه‌ی وزنی که این بسته باز نمی‌کند»
    مدل.آزادسازی()
پایان

شمارش آخر به خاطر محدودیت اصلی بسته اهمیت دارد. این بسته پنج گونه‌ی وزن را می‌خواند: F32، F16، Q8_0، Q4_0 و Q4_1. کوانتیزه‌های K که بیشتر فایل‌های دانلودی از آن‌ها استفاده می‌کنند، مانند Q4_K_M، و همچنین BF16 پشتیبانی نمی‌شوند و TensorBytes برای آن‌ها مقدار -1 برمی‌گرداند. LoadGguf همچنین کل فایل را اول در حافظه می‌خواند و هر بافر حداکثر ۲ گیگابایت جا دارد. در عمل یعنی باید فایل Q8_0 یا Q4_0 یک مدل کوچک مانند Qwen2.5 0.5B یا TinyLlama 1.1B را انتخاب کنید.

اجرای یک مدل زبانی کوچک با ai.llm

بسته‌ی ai.llm روی خواننده‌ی GGUF ساخته شده و مدل‌های خانواده‌ی Llama را روی پردازنده و با کد خالص سلام اجرا می‌کند. این بسته چیدمان لایه‌های Llama (RMSNorm، موقعیت‌دهی چرخشی، توجه گروهی پرسش (GQA) و بلوک پیشخور SwiGLU) را به‌علاوه‌ی بایاس‌های توجه که Qwen2 به کار می‌برد پیاده می‌کند. مستندات بسته Qwen2.5 Instruct را آزموده‌شده معرفی می‌کند؛ Llama و Mistral هم همین چیدمان را دارند. معماری‌هایی با چیدمان متفاوت، مانند Phi، یا بارگذاری نمی‌شوند یا خروجی بی‌معنا می‌دهند.

این بسته اجزایی را دارد که از یک موتور استنتاج کوچک انتظار می‌رود: توکن‌سازهای BPE و SentencePiece، حافظه‌ی نهان کلید و مقدار (KV cache)، تابع Forward برای یک گام، یک Sampler با دما، top-k، top-p و جریمه‌ی تکرار، و Generate برای کل حلقه‌ی تولید. هزینه‌ها در صفحه‌ی بسته صریح آمده‌اند و ارزش دارد که دوباره و بی‌پرده گفته شوند:

  • حافظه. هر وزن هنگام بارگذاری مدل به f32 باز می‌شود؛ پس Qwen2.5 0.5B، که فایلش ۰٫۷ گیگابایت است، حدود ۳ گیگابایت حافظه می‌خواهد. اندازه‌ی حافظه‌ی نهان کلید و مقدار از طول زمینه گرفته می‌شود؛ پس کم کردن cfg.ctx حافظه را صرفه‌جویی می‌کند.
  • سرعت. مستندات می‌گوید روی یک رایانه‌ی معمولی انتظار چند ثانیه برای هر توکن را داشته باشید، حتی در ساخت --release که بررسی مرزها را از حلقه‌های درونی حذف می‌کند.
  • کیفیت. مدلی با نیم میلیارد پارامتر جمله‌های روان می‌نویسد و واقعیت‌ها را اشتباه می‌گوید. مثال گفت‌وگوی خود بسته نشان می‌دهد که Qwen2.5 0.5B آبی بودن آسمان را با قطره‌های آب توضیح می‌دهد.

پس ai.llm ابزاری برای مجموعه‌ی محدودی از کارهاست: بازنویسی یا دسته‌بندی متن‌های کوتاه به‌صورت آفلاین، یک کمک‌کار محلی درون ابزاری که اجازه‌ی تماس شبکه‌ای ندارد، و بیش از همه، یادگرفتن گام‌به‌گام سازوکار یک ترنسفورمر با کدی که می‌شود خواندش. برای هر چیز بزرگ‌تر، صفحه‌ی خود بسته پیشنهاد می‌کند llama.cpp یا یک API را از راه net.http فراخوانی کنید.

اجرای مدل‌های ONNX با ai.onnx

ONNX قالب رایج تبادل مدل‌های آموزش‌دیده است: در PyTorch، TensorFlow یا scikit-learn آموزش دهید، یک بار صادر کنید و هر جا که زمان اجرای ONNX باشد اجرا کنید. بسته‌ی ai.onnx چنین زمان اجرایی است که با سلام نوشته شده. بارگذاری اونیکس (LoadOnnx) فایل را می‌خواند و اجرا (Run) برای هر ورودی گراف یک تانسور می‌گیرد و خروجی‌ها را به شکل تانسورهای معمولی برمی‌گرداند.

یک کاربرد رایج، دسته‌بند کوچکی است که از پایتون صادر شده و درون یک ابزار بومی خط فرمان عرضه می‌شود:

سلام
واردسازی هوش مصنوعی.اونیکس
واردسازی هوش مصنوعی.تانسور
واردسازی سیستم عامل
واردسازی تبدیل

تابع ریشه:
    آرگ‌ها := سیستم عامل.آرگومان ها()
    اگر آرگ‌ها.طول() < ۶:
        سرچاپ «روش استفاده: classify model.onnx f1 f2 f3 f4»
        برگشت ۱
    پایان
    ناپایا موفق := نادرست
    ناپایا مدل := اونیکس.بارگذاری اونیکس(آرگ‌ها.بگیر(۱)، موفق)
    اگر وارونه موفق:
        سرچاپ «بارگذاری نشد:»، مدل.خطا
        برگشت ۱
    پایان
    ناپایا ویژگی‌ها := وکتور {} برگردان وکتور<اعشار۳۲>
    تکرار ۴ در ای:
        ویژگی‌ها.بیفزا(تبدیل.تجزیه اعشار با پیش فرض(آرگ‌ها.بگیر(ای + ۲)، ۰.۰) برگردان اعشار۳۲)
    پایان
    ناپایا ابعاد := تانسور.شکل دو(۱، ۴)
    ناپایا داده‌ها := وکتور {} برگردان وکتور<تانسور.تانسور>
    داده‌ها.بیفزا(تانسور.از آرایه(ابعاد، ویژگی‌ها))
    ناپایا خروجی‌ها := اونیکس.اجرا(مدل، داده‌ها، موفق)
    اگر وارونه موفق:
        سرچاپ «استنتاج شکست خورد:»، مدل.خطا
        برگشت ۱
    پایان
    ناپایا امتیازها := خروجی‌ها.بگیر(۰)
    سرچاپ «شکل خروجی»، تانسور.رشته شکل(امتیازها)
    سرچاپ «دسته‌ی پیش‌بینی‌شده»، تانسور.نمایه بیشینه همه(امتیازها)
    مدل.آزادسازی()
پایان

هیچ‌چیز در این بسته برنامه را با یک فایل خراب متوقف نمی‌کند: هر شکستی موفق را نادرست می‌کند و دلیلش را در مدل.خطا می‌گذارد. محدودیت‌ها همان‌هایی‌اند که باید پیش از صادر کردن مدل بررسی کنید. همه‌ی تانسورها درون بسته f32 هستند؛ پس مقدارهای بزرگ int64 دقت از دست می‌دهند. حدود ۶۵ عملگر پیاده شده که برای لایه‌های پیشخور، کانولوشنی و نرمال‌سازی کافی است؛ LSTM، Resize و عملگرهای کوانتیزه با خطای unsupported op شکست می‌خورند. Conv گروه‌بندی ندارد (پس کانولوشن depthwise ندارد) و dilation هم ندارد. بسیاری از دسته‌بندها و مدل‌های embedding کوچک در این مجموعه جا می‌شوند؛ بسیاری از مدل‌های امروزی بینایی و زبان جا نمی‌شوند.

لایه‌ی تانسور در زیر همه‌ی این‌ها

همه‌ی این بسته‌ها روی ai.tensor سوارند؛ کتابخانه‌ای از آرایه‌های چندبعدی f32 با حساب پخشی (broadcasting)، ضرب ماتریسی، کاهش‌ها، softmax و تابع‌های فعال‌سازی رایج. عملیات بزرگ خودشان را میان نخ‌ها پخش می‌کنند: به‌طور پیش‌فرض یک نخ برای هر هسته و حداکثر ۸ نخ.

قلب بازیابی اطلاعات و سازوکار توجه یک محاسبه‌ی کوچک مشترک است: امتیاز دادن به یک پرسش در برابر مجموعه‌ای از بردارها با ضرب ماتریسی، و سپس تبدیل امتیازها به وزن با softmax. این‌جا همین کار را با چهار «embedding سند» بسیار کوچک می‌بینید:

سلام
واردسازی هوش مصنوعی.تانسور
واردسازی تبدیل

تابع سطرها(تعداد: صحیح، پهنا: صحیح، مقدارها: اعشار۶۴[]): تانسور.تانسور:
    ناپایا داده := وکتور {} برگردان وکتور<اعشار۳۲>
    هر م در مقدارها:
        داده.بیفزا(م برگردان اعشار۳۲)
    پایان
    ناپایا ابعاد := تانسور.شکل دو(تعداد، پهنا)
    برگشت تانسور.از آرایه(ابعاد، داده)
پایان

تابع ریشه:
    نام‌ها := [«فاکتور»، «رسید»، «تعطیلات»، «ساحل»]
    ناپایا سندها := سطرها(۴، ۳، [۰.۹، ۰.۱، ۰.۰، ۰.۸، ۰.۲، ۰.۱، ۰.۰، ۰.۹، ۰.۴، ۰.۱، ۰.۸، ۰.۶])
    ناپایا پرسش := سطرها(۳، ۱، [۱.۰، ۰.۰، ۰.۱])
    ناپایا امتیازها := تانسور.ضرب ماتریسی(سندها، پرسش)
    ناپایا ابعاد تخت := تانسور.شکل یک(۴)
    ناپایا تخت := تانسور.تغییر شکل(امتیازها، ابعاد تخت)
    ناپایا وزن‌ها := تانسور.بیشینه نرم(تخت)
    تکرار ۴ در ای:
        سرچاپ نام‌ها[ای]، تبدیل.قالب اعشار با دقت(تخت.عنصر(ای)، ۲)، تبدیل.قالب اعشار با دقت(وزن‌ها.عنصر(ای)، ۳)
    پایان
    سرچاپ «نزدیک‌ترین:»، نام‌ها[تانسور.نمایه بیشینه همه(وزن‌ها)]
    تانسور.آزادسازی(سندها)
    تانسور.آزادسازی(پرسش)
    تانسور.آزادسازی(امتیازها)
    تانسور.آزادسازی(تخت)
    تانسور.آزادسازی(وزن‌ها)
پایان
خروجیفاکتور 0.90 0.355 رسید 0.81 0.325 تعطیلات 0.04 0.150 ساحل 0.16 0.170 نزدیک‌ترین: فاکتور

به فراخوانی‌های تانسور.آزادسازی دقت کنید. سلام زباله‌روب (Garbage Collector) ندارد؛ پس بافر یک تانسور تا وقتی آزادش نکنید زنده می‌ماند. در یک نمونه‌ی ده‌خطی این کار اضافه است، و در یک سرویس پرعمر مزیت است، چون مصرف حافظه قابل‌پیش‌بینی است و مکث زباله‌روبی وجود ندارد. نوشته‌ی مدیریت حافظه در سلام قاعده‌ها را شرح می‌دهد.

درباره‌ی سرعت، سنجه‌ی (Benchmark) پروژه دو ردیف دارد که از کتابخانه‌های ماتریس و تانسور خود سلام در برابر حلقه‌های دست‌نویس C، C++، Rust و Go استفاده می‌کنند. کتابخانه‌ی سلام در ضرب ماتریسی تانسور جلوتر بود (۷٫۳ میلی‌ثانیه در برابر ۳۸٫۱ میلی‌ثانیه برای C++) و در ردیفی با تعداد زیادی عملیات ماتریسی کوچک بسیار عقب‌تر (۳۶٫۴ میلی‌ثانیه در برابر ۴٫۱ میلی‌ثانیه برای C). صفحه‌ی سرعت به دلیلی درست این ردیف‌ها را از میانگین‌ها بیرون نگه می‌دارد: این‌ها کتابخانه‌ها را مقایسه می‌کنند، نه کامپایلرها را. درباره‌ی مقایسه‌ی سلام با یک BLAS بهینه‌شده یا کارت گرافیک هم چیزی نمی‌گویند.

آموزش مدل‌های کوچک روی پردازنده

همین مجموعه می‌تواند آموزش هم بدهد. ai.nn لایه‌های خطی، کانولوشنی، بازگشتی و ترنسفورمر دارد، ai.autograd عملیات را روی یک نوار ثبت می‌کند و گرادیان‌ها را حساب می‌کند، و ai.optim بهینه‌سازهای SGD، Adam و RMSProp را دارد. کوچک‌ترین آزمون صادقانه XOR است، مسئله‌ای که با یک خط راست حل نمی‌شود:

سلام
واردسازی هوش مصنوعی.شبکه عصبی
واردسازی هوش مصنوعی.مشتق‌گیری خودکار
واردسازی هوش مصنوعی.بهینه‌سازی
واردسازی هوش مصنوعی.تانسور

تابع جدول(مقدارها: اعشار۶۴[]، تعداد: صحیح، پهنا: صحیح): تانسور.تانسور:
    ناپایا داده := وکتور {} برگردان وکتور<اعشار۳۲>
    هر م در مقدارها:
        داده.بیفزا(م برگردان اعشار۳۲)
    پایان
    ناپایا ابعاد := تانسور.شکل دو(تعداد، پهنا)
    برگشت تانسور.از آرایه(ابعاد، داده)
پایان

تابع ریشه:
    ناپایا ایکس := جدول([۰.۰، ۰.۰، ۰.۰، ۱.۰، ۱.۰، ۰.۰، ۱.۰، ۱.۰]، ۴، ۲)
    ناپایا ایگرگ := جدول([۰.۰، ۱.۰، ۱.۰، ۰.۰]، ۴، ۱)
    ناپایا مخزن := شبکه عصبی.مخزن پارامتر {}
    ناپایا مولد := تانسور.مولد تصادفی جدید(۱۱)
    ناپایا شبکه := شبکه عصبی.ترتیبی {}
    شبکه.افزودن(شبکه عصبی.لایه خطی جدید(مخزن، «hidden»، ۲، ۶، مولد))
    شبکه.افزودن(شبکه عصبی.لایه تانژانت هذلولی {})
    شبکه.افزودن(شبکه عصبی.لایه خطی جدید(مخزن، «out»، ۶، ۱، مولد))
    ناپایا آدام := بهینه‌سازی.آدام { نرخ یادگیری = ۰.۰۵ }
    ناپایا نوار := مشتق‌گیری خودکار.نوار جدید(۱)
    تکرار ۶۰۰ در گام:
        نوار.بازنشانی()
        مخزن.صفر کردن گرادیان()
        لوجیت‌ها := شبکه.پیشرو(نوار، مخزن، مشتق‌گیری خودکار.ورودی(نوار، ایکس))
        زیان := مشتق‌گیری خودکار.آنتروپی دودویی لوجیت(نوار، لوجیت‌ها، مشتق‌گیری خودکار.ثابت(نوار، ایگرگ))
        مشتق‌گیری خودکار.پس‌انتشار(نوار، زیان)
        آدام.گام(مخزن)
        اگر گام % ۲۰۰ == ۰:
            سرچاپ «گام»، گام، «زیان کمتر از ۰٫۱:»، مشتق‌گیری خودکار.مقدار(نوار، زیان).عنصر(۰) < ۰.۱
        پایان
    پایان
    نوار.بازنشانی()
    احتمال‌ها := تانسور.سیگموئید(مشتق‌گیری خودکار.مقدار(نوار، شبکه.پیشرو(نوار، مخزن، مشتق‌گیری خودکار.ورودی(نوار، ایکس))))
    تکرار ۴ در ای:
        سرچاپ ایکس.در دو(ای، ۰)، «xor»، ایکس.در دو(ای، ۱)، «->»، (احتمال‌ها.عنصر(ای) + ۰.۵) برگردان صحیح
    پایان
    نوار.آزادسازی()
    آدام.آزادسازی()
    مخزن.آزادسازی()
پایان
خروجیگام 0 زیان کمتر از ۰٫۱: false گام 200 زیان کمتر از ۰٫۱: true گام 400 زیان کمتر از ۰٫۱: true 0 xor 0 -> 0 0 xor 1 -> 1 1 xor 0 -> 1 1 xor 1 -> 0

این یک نمونه‌ی اسباب‌بازی است و عمداً هم همین است. کارهای آموزشی واقع‌بینانه روی پردازنده کوچک‌اند: یک مدل جدولی، یک شبکه‌ی کانولوشنی کوچک، مدلی که روی چند هزار نمونه تنظیم دقیق (fine-tune) می‌کنید. برای الگوریتم‌های کلاسیک روی جدول‌ها (درخت تصمیم، k-means، رگرسیون لجستیک) بسته‌ی ai.ml کوتاه‌تر است و حلقه‌ی آموزش نمی‌خواهد. نوشته‌ی یادگیری ماشین با سلام این بسته‌ها را عمیق‌تر بررسی می‌کند.

یک زبان بومی کجا کمک می‌کند و کجا نه

سه جا هست که اجرای مدل‌ها از سلام مزیتی واقعی است و نه فقط یک کنجکاوی.

  1. عرضه‌ی مدل درون یک ابزار. برنامه‌ی سلام به یک فایل اجرایی بدون ماشین مجازی تبدیل می‌شود. یک دسته‌بند ONNX یا یک مدل embedding کوچک می‌تواند درون یک ابزار خط فرمان، یک برنامه‌ی رومیزی یا یک سرور جابه‌جا شود، بدون آنکه پایتونی کنارش نصب باشد.
  2. محیط‌های آفلاین و محدود. جایی که برنامه به یک API میزبانی‌شده دسترسی ندارد، یک مدل محلی کوچک تنها گزینه است و جابه‌جا کردن یک فایل اجرایی خودبسنده به چنین دستگاهی آسان است.
  3. یادگیری. هر لایه از این مجموعه، از تجزیه‌گر GGUF تا حلقه‌ی توجه، کد معمولی سلام در std/ai/ است. یک دانشجو می‌تواند کل مسیر از بایت‌های روی دیسک تا توکن نمونه‌برداری‌شده را بخواند، به انگلیسی یا فارسی، بدون آنکه به C++ یا CUDA برود.

و جاهایی هم هست که امروز ابزار درستی نیست. کتابخانه پشتیبانی GPU ندارد. وزن‌ها به f32 باز می‌شوند؛ پس مصرف حافظه چند برابر اندازه‌ی فایل است. قالب‌های فایل تا حدی پوشش داده شده‌اند (کوانتیزه‌ی K ندارد، حدود ۶۵ عملگر ONNX). زیست‌بوم اطراف این بسته‌ها در برابر پایتون بسیار کوچک است و خود بسته‌ها هم جوان‌اند. اگر کار شما سرویس‌دادن یک مدل بزرگ به کاربران زیاد است، یک سرور استنتاج اختصاصی را پشت یک فراخوانی HTTP بگذارید و سرویس اطرافش را با سلام بنویسید؛ نوشته‌ی ساخت وب‌سرورهای سریع با سلام این سمت ماجرا را پوشش می‌دهد.

آینده‌ی هوش مصنوعی در زبان سلام: گام‌های بعدی

همه‌ی آنچه در این بخش می‌آید چشم‌انداز است، نه نقشه‌ی راهی که پروژه منتشر کرده باشد. با خواندن محدودیت‌های کنونی، گام‌های سودمند بعدی تقریباً روشن‌اند:

  • وزن‌های کوانتیزه با نگاشت حافظه. خواندن فایل GGUF با mmap و محاسبه‌ی مستقیم روی بلوک‌های کوانتیزه، به‌جای باز کردن به f32، مصرف حافظه را چند برابر کم می‌کند و سقف ۲ گیگابایت را برمی‌دارد. کتابخانه‌ی استاندارد از قبل بسته‌ی os.mmap را دارد؛ پس این قطعه‌ی سازنده موجود است.
  • قالب‌های بیشتر. پشتیبانی از کوانتیزه‌های K در ai.gguf و عملگرهای بیشتر ONNX (Resize، کانولوشن گروهی، عملگرهای کوانتیزه) امکان بارگذاری مدل‌های دانلودی بسیار بیشتری را فراهم می‌کند.
  • مسیرهای SIMD و GPU. پشتوانه‌ی بومی (Native Backend) از قبل می‌تواند با --cpu=x86-64-v3 کد AVX2 تولید کند؛ کتابخانه‌ی تانسوری که آگاهانه از دستورهای برداری استفاده کند، و بعدها مسیری برای GPU، داستان سرعت را عوض می‌کند.
  • سنجش در برابر رقیبان واقعی. تنها عددهای منتشرشده کتابخانه‌ی تانسور سلام را با حلقه‌های دست‌نویس مقایسه می‌کنند. یک مقایسه‌ی منصفانه با llama.cpp و ONNX Runtime روی یک مدل یکسان دقیقاً نشان می‌دهد چقدر راه مانده است.

هیچ‌کدام از این‌ها وعده داده نشده است. این‌ها شکاف‌هایی‌اند که یک مشارکت‌کننده می‌تواند برشان دارد، و نوشته‌ی ساخت زیست‌بوم متن‌باز یک زبان توضیح می‌دهد که کار بیرونی چطور به پروژه می‌رسد.

پرسش‌های متداول درباره‌ی اجرای هوش مصنوعی با زبان سلام

آیا زبان سلام می‌تواند مدل‌های Llama یا Qwen را اجرا کند؟

مدل‌های کوچک، بله. ai.llm مدل‌هایی با چیدمان Llama را از فایل GGUF روی پردازنده اجرا می‌کند و Qwen2.5 Instruct نمونه‌ی آزموده‌شده است. فایل باید کمتر از ۲ گیگابایت باشد و وزن‌های F32، F16، Q8_0، Q4_0 یا Q4_1 داشته باشد، و باید انتظار چند ثانیه برای هر توکن را داشته باشید.

آیا سلام زمان اجرای ONNX دارد؟

بله، ai.onnx گراف‌های ONNX را با کد خالص سلام و بدون کتابخانه‌ی ONNX Runtime می‌خواند و اجرا می‌کند. حدود ۶۵ عملگر را، همه در f32، پیاده می‌کند که بسیاری از مدل‌های پیشخور، کانولوشنی و نرمال‌سازی را پوشش می‌دهد، اما لایه‌های بازگشتی، Resize و گراف‌های کوانتیزه را نه.

آیا سلام برای یادگیری ماشین از کارت گرافیک (GPU) پشتیبانی می‌کند؟

نه. کتابخانه‌ی تانسور روی پردازنده اجرا می‌شود و عملیات بزرگ را میان نخ‌ها پخش می‌کند. برای آموزش روی GPU یا سرویس‌دادن مدل‌های بزرگ، از یک چارچوب یا سرور اختصاصی استفاده کنید و آن را از سلام فراخوانی کنید.

برای استفاده از این بسته‌ها به پایتون نیاز دارم؟

نه. این بسته‌ها بخشی از کتابخانه‌ی استاندارد سلام‌اند و جز خود کامپایلر به نصب چیزی نیاز ندارند. پایتون فقط برای ساختن خود مدل به کار می‌آید، مثلاً صادر کردن یک مدل PyTorch به ONNX یا ذخیره‌ی آرایه‌ها با NumPy تا بسته‌ی npy آن‌ها را بخواند.

راه پیش رو

یک زبان برنامه‌نویسی تازه چطور زیست‌بوم متن‌باز خودش را می‌سازد: بسته‌ها، فهرست بسته‌ها، مستندات و مشارکت‌کنندگان در سلام

هر زبانی به اندازه‌ی کدهای اطرافش مفید است. در این نوشته می‌بینیم مدیر بسته، کتابخانه‌ی استاندارد، مستندات و روند مشارکت در سلام چطور ساخته شده‌اند، و با صداقت می‌گوییم که این زیست‌بوم هنوز چقدر کوچک است.

خواندن مقاله
راه پیش رو

سلام در آموزش برنامه‌نویسی: آموزش مبتدیان، علوم کامپیوتر و طراحی کامپایلر با یک زبان دوزبانه

سلام به دانش‌آموز اجازه می‌دهد با فارسی شروع کند، بی‌آنکه زبان را عوض کند به واژه‌های کلیدی انگلیسی برسد، و بعدها کامپایلری واقعی را بخواند که با همان زبان نوشته شده است. امروز چه چیزی برای معلمان آماده است و کلاس‌های درس هنوز به چه نیاز دارند.

خواندن مقاله
راه پیش رو

برنامه‌نویسی چندزبانه و آینده‌ی کد به زبان مادری: آیا مدل دوزبانه‌ی سلام برای زبان‌های دیگر هم کار می‌کند؟

سلام کد انگلیسی و فارسی را با یک بخش آغازین، یک کتابخانه‌ی استاندارد و یک مجموعه کد خطا کامپایل می‌کند. این نوشته طراحی آن را باز می‌کند و می‌پرسد افزودن زبان انسانی سوم چه کاری می‌طلبد و اصلاً ایده‌ی خوبی هست یا نه.

خواندن مقاله