← voidwest    research notes

الملف قال Q4. والـruntime قال f32.

خط أساس مجمّد لمسار K-quant loader الحالي ومسار التنفيذ الأصلي المفقود في Ember
محمد الثبيتي · 2026-08-01
Ember GGUF quantization CPU inference runtime systems Qwen LLaMA

مسار K-quant الحالي في Ember يقرأ التمثيل بشكل صحيح، لكنه يتخلص من فائدته وقت التشغيل. أوزان Q6_K وQ4_K_M تتحول من ملف GGUF إلى f32 وتبقى في الذاكرة، ثم تمر عبر generic f32 kernels. ما فيه حالياً native K-quant matmul أو packed execution path لها. يعني هذا reference loader، مو low-memory K-quant deployment.

وهذا يخلي المسار الحالي غير مناسب كـdeployment منخفض الذاكرة أو منخفض التأخير. الصفحة تثبت هذا الـbaseline قبل تنفيذ مسار native K-quant. النتيجة مو ادعاء أن Q4_K_M أو Q6_K غير فعالة بطبيعتها؛ هي ناتجة عن سياسة الـloader والـbackend الحالية في Ember، وما ينفع نعممها على GGUF أو K-quants أو low-bit quantization عموماً.

الحالة

pre-optimization engineering baseline فقط. الجدول يغطي عائلتين صغيرتين على جهاز محلي واحد. هذه مو نتيجة جديدة في quantization، ولا ادعاء production deployment، ولا مقارنة تقول إن Ember أسرع من llama.cpp.

السؤال

هل quantized checkpoint الأصغر ينتج بالضرورة deployment محلياً أصغر وأسرع؟

النتيجة

الـbenchmark المجمّد يقيس حجم الملف، ووقت التحميل مع prefill، وسرعة decode، وpeak RSS. العمود الأخير هو المفتاح: يسجل ما يحتفظ به Ember في الذاكرة ويشغله، مو فقط ما يقوله اسم الملف.

النموذج quantization حجم الملف load + prefill decode tok/s peak RSS تمثيل runtime
Qwen2.5-1.5B-InstructQ8_01807 MB0.97 s40.61941 MBcompressed-resident
Qwen2.5-1.5B-InstructQ6_K1396 MB14.4 s2.58713 MBpersistent f32 expansion
Qwen2.5-1.5B-InstructQ4_K_M1066 MB13.0 s2.68712 MBpersistent f32 expansion
Llama-3.2-1BQ8_01260 MB2.03 s149.62685 MBcompressed-resident
Llama-3.2-1BQ6_K974 MB16.4 s2.96965 MBpersistent f32 expansion
Llama-3.2-1BQ4_K_M770 MB15.9 s3.26965 MBpersistent f32 expansion

في Qwen، ملف Q4_K_M أصغر من Q8_0 على القرص بنحو 41%، لكنه يستهلك تقريباً 4.49× من peak RSS ويكون decode أبطأ بنحو 15.6×. وفي Llama، يصغر الملف بنحو 39%، بينما ترتفع الذاكرة إلى 2.59× وتصبح السرعة أبطأ بنحو 46.8×.

عبر مقارنات Q4/Q6 الأربع، يصبح decode أبطأ بين 15.6× و51.6×، وترتفع peak RSS بين 2.59× و4.49×. الحد الأعلى 51.6× هو Llama Q6_K، والأدنى 15.6× هو Qwen Q4_K_M.

الصورة نفسها تتكرر في العائلتين: الشيء الوحيد الذي يصغر مع Q6/Q4 هو الملف على القرص. ووقت التحميل يرتفع أيضاً من نحو ثانية أو ثانيتين في Q8_0 إلى نحو 13–16 ثانية في Q6_K وQ4_K_M.

ليش تنقلب الصورة؟

quantization في الـcheckpoint تصف طريقة ترميز الـtensors داخل الملف. ما تصف تلقائياً كيف يخزنها الـruntime أو أي kernels يشغلها. مسار Q8_0 في Ember يبقي الـblocks مكمّمة في الذاكرة ويستخدم مسار packed Q8.

مسار K-quant الحالي هو reference loader، مو native K-quant backend. الـloader يفك التكميم إلى f32 وقت التحميل، ويحتفظ بالـbuffers الموسعة، ثم يرسل العمل إلى تنفيذ f32 عام. ما فيه K-specific matmul أو packed kernel حالياً في Ember. الملف ما زال Q4 أو Q6 على القرص، لكن تمثيل الـdeployment داخل الذاكرة ليس كذلك.

Q8_0:
GGUF Q8 blocks
  → compressed-resident weights
  → packed Q8 kernels

Q4_K_M / Q6_K today (reference path):
GGUF K-quant blocks
  → full f32 expansion
  → generic f32 execution

إذا بقي compressed file mapping موجوداً في الذاكرة، فقد يعكس RSS التمثيل الأصلي والـbuffers الموسعة معاً. لذلك رقم RSS الواحد يحتاج تفكيكاً إلى file-backed وanonymous قبل ما نعامله كتفسير كامل للإقامة في الذاكرة.

checkpoint quantization مو هي deployment quantization

لاحقة GGUF أو اسم الملف ما تحدد وحدها ذاكرة العملية، تكلفة البداية، سرعة decode، الـworkspace المؤقت، سلوك الـkernels، أو مدة بقاء الـsource mapping. هذه قرارات يحددها الـloader وتخطيط الـtensors وسياسة الـdispatch والـbackend.

الـquantized checkpoint مجرد storage format إلى أن يحدد الـruntime كيف يجهزه ويشغله.

هذا هو الحد المفاهيمي في المراجعة. قول إن الملف Q4 صحيح. لكنه ما يكفي لوصف الـdeployment كله.

وش اللي تثبته هذه المراجعة؟

وش اللي ما تثبته؟

سياق reference implementation

llama.cpp هو الـexternal correctness and performance reference هنا. الـCPU backend المحسّن فيه يحافظ على أوزان K-quant مضغوطة في المسارات العادية، ويستخدم native quantized vector-dot kernels لـQ4_K وQ6_K وQ8_0، بدل الاحتفاظ بنسخة f32 كاملة من النموذج في التنفيذ العادي.

هذا هو الفرق المهم للمقارنة: الـreference يحافظ على تمثيل low-bit أثناء التشغيل، بينما مسار K-quant البحثي الحالي في Ember يحافظ على التخزين المكمّم ثم يحوله إلى أوزان f32.

قيود القياس

استخدم الـbenchmark نفس CPU affinity وإعداد الـthreads بين التهيئات. هذا يحسن المقارنة داخل الجدول، لكنه ما يحول التشغيل إلى دراسة واسعة للأجهزة.

وش لازم يظهر في المقارنات الجاية؟

الخطوة الجاية

المهمة التالية في Ember هي مقارنة التوسيع الكامل المبكر إلى f32، وبديل بذاكرة محدودة، وتنفيذ K-quant أصلي يحتفظ بالتمثيل المضغوط، مع llama.cpp كـexternal baseline.

المسارات المحسّنة لازم تحافظ أيضاً على دلالات activation tracing وcapture وpatching في Ember. الذاكرة الأقل أو السرعة الأعلى ما تكفي إذا تغيّر الشيء الذي تقيسه أداة البحث أو تتدخل فيه.

artifacts

مخرجات الـdeployment benchmark المجمدة والـrunner موجودة محلياً في research/pilots/arabic_quantization_001/deployment_benchmark.{json,csv} على فرع pilot-001 المحلي. هذا الفرع مو مساراً عاماً، لذلك ما أضيف رابطاً يوحي بعكس ذلك.

سياق التنفيذ العام موجود في src/quant_k.rs، src/loader.rs، src/residency.rs، ومذكرتي packed-Q8 packed-q8-research-memo.md وpacked-q8-lifecycle.md.

الخاتمة

الملف قال Q4. الـruntime اختار f32. وتكلفة الـdeployment تبعت تمثيل الـruntime.