رده: زمان کامپایل: موزاییک، ترازبندی دسترسی به حافظه اثبات نشده
این خطا زمانی رخ میدهد که کامپایلر یک عملیات دسترسی به حافظه (مانند vector.load ، vector.store ، tpu.load یا tpu.store ) را تجزیه و تحلیل میکند و نمیتواند به صورت ایستا ثابت کند که شاخص پویای مورد استفاده برای یک بعد خاص، مضربی از اندازه کاشیکاری مورد نیاز است.
نمونه پیامهای خطا:
INTERNAL: Mosaic failed to compile TPU kernel: cannot statically prove that index in dimension 1 is a multiple of 128
at location: ...
The MLIR operation involved:
%14372 = "vector.load"(%14371, %93, %14363) : (memref<4x256xf32, #tpu.memory_space<vmem>>, index, index) -> vector<1x32xf32>
پایههای XLA: TPU
نمای کلی
وقتی هسته شما یک بردار را بارگذاری یا ذخیره میکند، آدرس حافظه (که از اشارهگر پایه به علاوه شاخص پویا محاسبه میشود) باید با اندازه کاشیکاری بردار روی سختافزار همتراز باشد. برای مثال، اگر یک بُعد با ۱۲۸ عنصر کاشیکاری شده باشد، شاخص پویای مورد استفاده برای دسترسی به آن باید 0 ، 128 ، 256 و غیره باشد. توجه داشته باشید که بسیاری از عملیات (مانند بارگذاریها و ذخیرهسازیهای بردار) چنین الزامی برای شاخصهای ایستا ندارند.
کامپایلر این الزام را با استفاده از تحلیل استاتیک اعمال میکند. این تحلیل تاریخچه متغیر شاخص را از طریق عملیات حسابی که آن را تولید کردهاند (مثلاً ضرب، جمع) ردیابی میکند. اگر کامپایلر نتواند (در زمان کامپایل) تضمین کند که مقدار حاصل همیشه بر اندازه کاشی قابل تقسیم باشد، این خطا را ایجاد میکند.
کامپایلر با «عدم ترازبندی اثباتشده» و «همترازی ناشناخته» به طور یکسان برخورد میکند. بنابراین اگر از اندیسی استفاده کنید که از نظر ریاضی، ناهمترازی آن تضمین شده باشد (مثلاً i * 128 + 32 )، کامپایلر همان خطا را ایجاد خواهد کرد.
بنابراین این خطا میتواند زمانی رخ دهد که
- شما از یک متغیر زمان اجرا (ایندکس پویا) برای دسترسی به حافظه استفاده میکنید.
- منطق محاسبه شاخص برای کامپایلر بسیار پیچیده است که بتواند آن را تجزیه و تحلیل کند.
- این شاخص از نظر ریاضی معتبر است اما فاقد اثبات صریح در کد است.
- تحلیل استاتیک «عدم همترازی اثباتشده» را تعیین میکند.
اشکالزدایی
برای رفع این خطا، گزینههای زیر را دارید:
۱. صراحتاً همترازی را تأیید کنید
اگر میدانید که اندیس شما معتبر است اما کامپایلر نمیتواند آن را اثبات کند، از عملیات tpu.assume_multiple استفاده کنید. این به عنوان یک قول به کامپایلر عمل میکند که یک مقدار بر یک عامل خاص قابل تقسیم است.
۲. از بارهای همتراز استفاده کنید و بچرخانید
در سناریوهایی که ناهمترازی عمدی است، به جای بارگذاری یک بخش بردار کوچک و غیرتراز شده:
- یک کاشی بزرگتر و کاملاً تراز شده را بارگذاری کنید و سپس مقادیر را به میزان پویا بچرخانید تا دادههای مورد نظر به موقعیت مورد نظر منتقل شوند (زیرا برشهای برداری با شاخصهای شروع پویا پشتیبانی نمیشوند). یا
- تانسور را تغییر شکل دهید یا آن را طوری لایهگذاری کنید که دادهها از اندیس ۰ شروع شوند و گام بین دسترسیها با تراز سختافزاری مطابقت داشته باشد.
- مثال: اگر روی تکههایی با اندازه ۳۲ و با شروع از آفست ۱ پیمایش کنید، آفستهای شما ۱، ۳۳، ۶۵... (همتراز نشده) هستند.
- راه حل: دادهها را دوباره در یک تانسور جدید بستهبندی کنید که در آن اولین تکه در ۰ و بُعد به ۱۲۸ افزایش یابد. مقادیر offset شما ۰، ۱۲۸، ۲۵۶... میشوند که نیاز به ترازبندی را برآورده میکند.
این روشها حافظه بیشتری مصرف میکنند اما اغلب منطق هسته را ساده میکنند و نیاز به ادعاهای همترازی دستی را از بین میبرند.