كيفية الحصول على 1.5 TFlops من أداء FP32 على نواة واحدة لوحدة المعالجة المركزية M1

جوت - 1.5tflop_m1 # كيفية الحصول على 1.5 TFlops من أداء FP32 على نواة M1 CPU واحدة * بواسطة [bvasti] (https://twitter.com/bvasti) ([mastodon] (https://sigmoid.social/@bvasti)) * **** إذا كنت في السوق لتدريب شبكات عصبية حديثة كبيرة ، لن تكون هذه المشاركة ذات صلة حقًا ، نظرًا لأنه أبطأ 100 مرة من A100 (156TFlops). إذن ما هي قيمة 1.5 TFlops على الأرض؟ - يعمل هذا على نواة واحدة من جهاز MacBook Air 2020 الذي يعمل بالبطارية - يعمل مع زمن انتقال يبلغ حوالي 0.5 * نانوثانية * لكل تعليمات نحن لا نعمل في مجال المسرعات السميكة أو نوى موتر GPU. نحن نتحدث عن أداء الجبر الخطي في العالم الحقيقي يعيش ** دورة واحدة ** بعيدًا عن سجلات وحدة المعالجة المركزية. الغريب أن أبل أخفت هذا عنا! في هذه المقالة ، سنتعرف على بعض التعليمات البرمجية لرفع تلك الستارة. كل التعليمات البرمجية تستخدم رأس `aarch.h` في كورسيكس مستودع رائع: https://github.com/corsix/amx ## ما هو معالج AMX المشترك؟ انها في الأساس SIMD على المنشطات. فارق مهم هو أن نسبة AMX: CPU ليست 1: 1 ؛ لا تحتوي كل النوى على معالج AMX الخاص بها. فيما يلي الأحجام التي يمكن للمرء استخدامها لتحميل أو تخزين القيم: ! [] (https://i.imgur.com/3gimUQ7.png) * الحد الأدنى * واسع مثل تسجيل AVX512 الكامل. ولكن من أين يتم تحميل هذه القيم أو تخزينها؟ من الواضح أن مثل هذه الأحجام ستستهلك ملف تسجيل النيون بأكمله بسرعة كبيرة. حسنًا ، هناك ملف تسجيل منفصل لـ AMX فقط وهذا غريب نوعًا ما. يتم تقسيم السجلات إلى مجموعات: X و Y و Z. لكل تعليمات ، تحتوي المجموعتان X و Y على إدخالات ومجموعة Z. يحمل النواتج. ! [] (https://i.imgur.com/PUTfqIY.png) كما نرى ، X و Y كبيرتان جدًا! كيلو بايت كامل بينهما. لكن Z يأخذ الكعكة وأكثر: ! [] (https://i.imgur.com/Xqtu1xG.png) (* المفسد: يمكن ملء 1024 بايت (1/4 من سجلات Z) بتعليمات AMX واحدة. *) إذن كيف ننتقل من X و Y إلى Z؟ حسنًا ، عدد الطرق كبير جدًا لدرجة أنه لا يتناسب تمامًا في ترميز ISA. وهكذا ، قررت شركة آبل ترميز معظم معلومات التعليمات في سجل للأغراض العامة. اتضح أن هذا رائع للعمل معه ، لأنه يسمح بذلك * تكوين وقت التشغيل * (سريعًا) للرمز الذي يعمل على AMX. الغرض من هذه المقالة هو ببساطة استخدام المعالج المشترك بأكبر قدر ممكن من الكفاءة. هناك تعليمات متجه إلى متجه والتي ستنتج متجهات بنفس الطول ، لكنها بعيدة كل البعد عن تشبع القدرات الحاسوبية لهذه الشريحة. بدلاً من ذلك ، سيتعين علينا استخدام منتج خارجي لإنجاز الأمور حقًا. ما هو المنتج الخارجي؟ بافتراض أن لديك متجهي إدخال $ \ mathbf {u} $ و $ \ mathbf {v} $: $$ \ mathbf {u} = \ begin {bmatrix} u_1 \\\\ u_2 \\\\ \ vdots \\\\ u_m \ end {bmatrix} ، \ رباعي \ mathbf {v} = \ start {bmatrix} v_1 \\\\ v_2 \\\\ \ vdots \\\\ v_n \ end {bmatrix} $$ المنتج الخارجي هو المصفوفة التي تحتوي على منتج كل المجموعات الزوجية الممكنة لعناصرها. (هذا يعطي بعض الدلائل عن سبب تسجيل مجموعة Z. أكبر بكثير من X و Y.) $$ \ mathbf {u} \ otimes \ mathbf {v} = \ ابدأ {bmatrix} u_1v_1 & \ Points & u_1v_n \\\\ u_2v_1 & \ Points & u_2v_n \\\\ \ vdots & \ ddots & \ vdots \\\\ u_mv_1 & \ dots & u_mv_n \ نهاية {bmatrix} $$ على شريحة AMX ، يتلخص هذا في تعليمات بسيطة للغاية يبدو كثيرًا مثل هذا: ! [] (https://i.imgur.com/yQa4cdq.png) وهناك علامة يمكنك تعيينها لتجميعها أيضًا من ملف النتيجة السابقة: ! [] (https://i.imgur.com/MPsmwnX.png) بذلك ، لدينا كل ما نحتاجه لكتابة ضرب المصفوفة: بشكل متكرر تحميل 16 تعويمًا من مصفوفات الإدخال الخاصة بنا وتجميعها المنتجات الخارجية في إخراج 16x16. لا يهم بعد التخفيض K! لنبسط المسألة ونبدل ضرب المصفوفة ضمنيًا. سيحتوي "A" و "B" (مدخلاتنا) على "K" (بُعد الاختزال الخاص بنا) كبعد * رئيسي *. لا يهم حقًا في الممارسة ، لكنه يبسط الكود لدينا كثيرًا. إليك مرجع يمكننا استخدامه للتحقق من حلنا المقترح: قسم غير مصنف في الرياض Reference_16x16xK باطل (عائم * A ، عائم * B ، عائم * C ، uint64_t K) { لـ (uint32_t m = 0 ؛ م <16 ؛ ++ م) { لـ (uint32_t n = 0 ؛ n <16 ؛ ++ n) { ج [ن * 16 + م] = 0 ؛ لـ (uint32_t k = 0؛ k

جوت - 1.5tflop_m1 # كيفية الحصول على 1.5 TFlops من أداء FP32 على نواة M1 CPU واحدة * بواسطة [bvasti] (https://twitter.com/bvasti) ([mastodon] (https://sigmoid.social/@bvasti)) * **** إذا كنت في السوق لتدريب شبكات عصبية حديثة كبيرة ، لن تكون هذه المشاركة ذات صلة حقًا ، نظرًا لأنه أبطأ 100 مرة من A100 (156TFlops). إذن ما هي قيمة 1.5 TFlops على الأرض؟ - يعمل هذا على نواة واحدة من جهاز MacBook Air 2020 الذي يعمل بالبطارية - يعمل مع زمن انتقال يبلغ حوالي 0.5 * نانوثانية * لكل تعليمات نحن لا نعمل في مجال المسرعات السميكة أو نوى موتر GPU. نحن نتحدث عن أداء الجبر الخطي في العالم الحقيقي يعيش ** دورة واحدة ** بعيدًا عن سجلات وحدة المعالجة المركزية. الغريب أن أبل أخفت هذا عنا! في هذه المقالة ، سنتعرف على بعض التعليمات البرمجية لرفع تلك الستارة. كل التعليمات البرمجية تستخدم رأس `aarch.h` في كورسيكس مستودع رائع: https://github.com/corsix/amx ## ما هو معالج AMX المشترك؟ انها في الأساس SIMD على المنشطات. فارق مهم هو أن نسبة AMX: CPU ليست 1: 1 ؛ لا تحتوي كل النوى على معالج AMX الخاص بها. فيما يلي الأحجام التي يمكن للمرء استخدامها لتحميل أو تخزين القيم: ! [] (https://i.imgur.com/3gimUQ7.png) * الحد الأدنى * واسع مثل تسجيل AVX512 الكامل. ولكن من أين يتم تحميل هذه القيم أو تخزينها؟ من الواضح أن مثل هذه الأحجام ستستهلك ملف تسجيل النيون بأكمله بسرعة كبيرة. حسنًا ، هناك ملف تسجيل منفصل لـ AMX فقط وهذا غريب نوعًا ما. يتم تقسيم السجلات إلى مجموعات: X و Y و Z. لكل تعليمات ، تحتوي المجموعتان X و Y على إدخالات ومجموعة Z. يحمل النواتج. ! [] (https://i.imgur.com/PUTfqIY.png) كما نرى ، X و Y كبيرتان جدًا! كيلو بايت كامل بينهما. لكن Z يأخذ الكعكة وأكثر: ! [] (https://i.imgur.com/Xqtu1xG.png) (* المفسد: يمكن ملء 1024 بايت (1/4 من سجلات Z) بتعليمات AMX واحدة. *) إذن كيف ننتقل من X و Y إلى Z؟ حسنًا ، عدد الطرق كبير جدًا لدرجة أنه لا يتناسب تمامًا في ترميز ISA. وهكذا ، قررت شركة آبل ترميز معظم معلومات التعليمات في سجل للأغراض العامة. اتضح أن هذا رائع للعمل معه ، لأنه يسمح بذلك * تكوين وقت التشغيل * (سريعًا) للرمز الذي يعمل على AMX. الغرض من هذه المقالة هو ببساطة استخدام المعالج المشترك بأكبر قدر ممكن من الكفاءة. هناك تعليمات متجه إلى متجه والتي ستنتج متجهات بنفس الطول ، لكنها بعيدة كل البعد عن تشبع القدرات الحاسوبية لهذه الشريحة. بدلاً من ذلك ، سيتعين علينا استخدام منتج خارجي لإنجاز الأمور حقًا. ما هو المنتج الخارجي؟ بافتراض أن لديك متجهي إدخال $ \ mathbf {u} $ و $ \ mathbf {v} $: $$ \ mathbf {u} = \ begin {bmatrix} u_1 \\\\ u_2 \\\\ \ vdots \\\\ u_m \ end {bmatrix} ، \ رباعي \ mathbf {v} = \ start {bmatrix} v_1 \\\\ v_2 \\\\ \ vdots \\\\ v_n \ end {bmatrix} $$ المنتج الخارجي هو المصفوفة التي تحتوي على منتج كل المجموعات الزوجية الممكنة لعناصرها. (هذا يعطي بعض الدلائل عن سبب تسجيل مجموعة Z. أكبر بكثير من X و Y.) $$ \ mathbf {u} \ otimes \ mathbf {v} = \ ابدأ {bmatrix} u_1v_1 & \ Points & u_1v_n \\\\ u_2v_1 & \ Points & u_2v_n \\\\ \ vdots & \ ddots & \ vdots \\\\ u_mv_1 & \ dots & u_mv_n \ نهاية {bmatrix} $$ على شريحة AMX ، يتلخص هذا في تعليمات بسيطة للغاية يبدو كثيرًا مثل هذا: ! [] (https://i.imgur.com/yQa4cdq.png) وهناك علامة يمكنك تعيينها لتجميعها أيضًا من ملف النتيجة السابقة: ! [] (https://i.imgur.com/MPsmwnX.png) بذلك ، لدينا كل ما نحتاجه لكتابة ضرب المصفوفة: بشكل متكرر تحميل 16 تعويمًا من مصفوفات الإدخال الخاصة بنا وتجميعها المنتجات الخارجية في إخراج 16x16. لا يهم بعد التخفيض K! لنبسط المسألة ونبدل ضرب المصفوفة ضمنيًا. سيحتوي "A" و "B" (مدخلاتنا) على "K" (بُعد الاختزال الخاص بنا) كبعد * رئيسي *. لا يهم حقًا في الممارسة ، لكنه يبسط الكود لدينا كثيرًا. إليك مرجع يمكننا استخدامه للتحقق من حلنا المقترح: قسم غير مصنف في الرياض Reference_16x16xK باطل (عائم * A ، عائم * B ، عائم * C ، uint64_t K) { لـ (uint32_t m = 0 ؛ م <16 ؛ ++ م) { لـ (uint32_t n = 0 ؛ n <16 ؛ ++ n) { ج [ن * 16 + م] = 0 ؛ لـ (uint32_t k = 0؛ k

What's Your Reaction?

like

dislike

love

funny

angry

sad

wow