بازگشت به وبلاگ

کانتکست ۱۲۸k روی دسکتاپ دروغ است. کش KV آن را بلعید.

۳۱ شهریور ۱۴۰۵

هر کارت مدل محلی حالا به پنجرهٔ کانتکست ۱۲۸k می‌نازد. روی دسکتاپ، آن عدد قرارداد اجاره‌ای است که رم شما بدون خواندن امضایش کرده. آنچه تعیین می‌کند سند بلندی را تا کجا می‌توانید جلو ببرید وزن‌ها نیستند — کش KV است، که با کانتکست مثل مالیاتی که با ارز دیگری توافق شده، رشد می‌کند.

پنجرهٔ کانتکست قابلیتی نیست که روشن و خاموشش کنید. اجارهٔ حافظه است که هر ثانیهٔ کار سرور، پرداختش می‌کنید.

کانتکست ۱۲۸k واقعاً چقدر رم می‌خورد؟

ریاضیاتش عمومی و کوتاه است. همان‌طور که Transformer Inference Arithmetic توضیح می‌دهد، کش KV برای هر لایه، هر سر KV و هر توکن دو تنسور نگه می‌دارد — key و value:

cache_bytes = 2 × لایه‌ها × کانتکست × سرهای_KV × head_dim × بایت_هر_عنصر

Llama 3.1 8B را بردارید: ۳۲ لایه، ۸ سر KV، و head_dim برابر ۱۲۸ — مستقیم از config.json در Hugging Face. در ۱۳۱٬۰۷۲ توکن با fp16 (۲ بایت):

2 × 32 × 131072 × 8 × 128 × 2 = 17,179,869,184 بایت ≈ 16 GiB

وزن‌های همین مدل در fp16 حدود ۱۶ گیب هستند. در بیشترین کانتکست، کش هم‌اندازهٔ مدلی است که به آن تعلق دارد. «مدل 8B که در ۱۶ گیب جا می‌شود» لحظه‌ای که num_ctx را به ۱۲۸k می‌برید، بی‌سر و صدا به مشکل ۳۲ گیبی تبدیل می‌شود.

چرا کش همراه پنجره بزرگ می‌شود؟

چون مکانیزم توجه باید هر توکن را با همهٔ توکن‌های پیش از آن مقایسه کند، و استنتاج خودبازگشتی است — هیچ چیز دوباره محاسبه نمی‌شود، همه‌چیز به خاطر سپرده می‌شود. کل ترفند سریع‌کردن تولید همین است: key و value هر توکن یک بار محاسبه و ذخیره می‌شود. حافظهٔ هر توکن ثابت است، پس کل مصرف خطی با کانتکست بالا می‌رود. ۱۲۸k «عدد بزرگ‌تر» نیست — ۱۲۸ برابر کش پنجرهٔ ۱k است، برای تمام نشست رزرو شده.

Grouped-query attention (GQA) تخفیف سمت مدل است: سرهای KV کمتر، کش لاغرتر. Qwen2.5 7B با ۲۸ لایه فقط ۴ سر KV دارد (config اینجاست)، پس همان پنجرهٔ ۱۲۸k در fp16 حدود ۷ گیب هزینه دارد — آرامش واقعی، و یکی از دلایل دوستانه‌تر بودن این مدل‌ها روی ماشین‌های ضعیف‌تر.

مدل (fp16)لایه × سر KVکش KV در 128kوزن‌هاکش نسبت به وزن
Llama 3.1 8B32 × 8~16 GiB~16 GiB~۱۰۰٪
Qwen2.5 7B28 × 4~7 GiB~15 GiB~۴۷٪

خودتان حساب کنید — کل راستی‌آزمایی همین است:

def kv_cache_gib(layers, kv_heads, head_dim, ctx, bytes_per=2):
    return 2 * layers * ctx * kv_heads * head_dim * bytes_per / 2**30

print(kv_cache_gib(32, 8, 128, 131_072))  # Llama 3.1 8B  -> 16.0
print(kv_cache_gib(28, 4, 128, 131_072))  # Qwen2.5 7B    -> 7.0

آنچه عدد تبلیغاتی نمی‌گوید

این دفترِ صادقانهٔ این استدلال است — همراه با جاهایی که خم می‌شود:

  • prefill صورتحساب دوم است. پیش از نخستین توکن پاسخ، کل پرامپت یک‌جا پردازش می‌شود. پرامپت ۱۰۰k توکنی یعنی جویدن ۱۰۰k توکن تا دیدن اولین حرف. روی 3060، این دقیقه است نه میلی‌ثانیه.
  • مدل‌های sliding-window حساب را به هم می‌ریزند — به سود شما. معماری‌های سبک Mistral توجه را در هر لایه به پنجره‌ای ثابت محدود می‌کنند و کش دیگر رشد نمی‌کند. فرمول ساده آن‌ها را بیش از حد حساب می‌کند. این نوشتار دربارهٔ ترنسفورمرهای با توجه کامل است — یعنی بیشترِ چیزی که مردم اجرا می‌کنند.
  • کوانتیزه‌کردن KV واقعی است اما جزئی. llama.cpp می‌تواند KV را در q8_0 نگه دارد — کش تقریباً نصف، به بهای کمی ریسک کیفیت. نصفِ ۱۶ گیب هنوز ۸ گیب است.
  • مشخصات به‌ندرت تعداد سرهای KV را می‌نویسند. باید در config.json بگردید — و همین خودش می‌گوید قرار بوده آن عدد چطور خوانده شود.

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

هیچ‌کس ۱۲۸٬۰۰۰ توکن را نمی‌خواند. رم شما به هر حال پول همه را می‌دهد.

درمانش کسل‌کننده است: کانتکست را روی چیزی بگذارید که بار کاری‌تان واقعاً مصرف می‌کند. پنجرهٔ ۳۲k یک‌چهارم کش ۱۲۸k آب می‌خورد و تقریباً هر پرامپتی که یک توسعه‌دهندهٔ تنها واقعاً می‌فرستد را پوشش می‌دهد. این همان نظم دفتریِ ریاضیات رم برای مدل‌های محلی است — اندازهٔ مدل نصف بودجه است، و سطوح کوانتیزاسیون وزن‌ها را آب می‌کنند اما حساب کش را دست نمی‌زنند.

اگر کش قیمت واقعی کانتکست است، چرا کارت‌ها پنجره را می‌فروشند و هرگز صورتحساب را نه؟ و دور اعتراف: بزرگ‌ترین کانتکستی که تا آخرین توکن واقعاً پر کرده‌اید چه بوده — و خروجی، آن گیگابایت‌ها را جبران کرد؟ کامنت‌ها باز است؛ نوشتهٔ بعدی این سری به نفعِ بازنده خواهد ایستاد.

FAQ

پنجرهٔ کانتکست ۱۲۸k چقدر رم مصرف می‌کند؟

برای Llama 3.1 8B در fp16، تنها کش KV در ۱۳۱٬۰۷۲ توکن حدود ۱۶ گیب وزن دارد — تقریباً هم‌اندازهٔ وزن‌های مدل. فرمول: ۲ × لایه‌ها × کانتکست × سرهای KV × head_dim × بایت.

چرا کانتکست بلند حافظهٔ بیشتری مصرف می‌کند؟

هر توکن در کش، برای هر لایهٔ توجه تنسورهای key و value را نگه می‌دارد. کانتکست دو برابر، کش دو برابر. حتی اگر پنجره را هیچ‌وقت پر نکنید، تخصیص حافظه برقرار است.

چطور مصرف حافظهٔ کش KV را در مدل‌های محلی کم کنم؟

کانتکست را روی مقدار واقعی مصرف بگذارید، مدل‌های grouped-query attention را انتخاب کنید (سرهای KV کمتر)، جایی که ران‌تایم پشتیبانی می‌کند کش KV را به q8 کوانتیزه کنید، یا از معماری‌های sliding-window و هیبریدی استفاده کنید.

— mrsaynothing

— mrsaynothing

نظرات، پیش از انتشار تست بار شده‌اند. معمولاً.

استدلال بعدی با ایمیل

هر نوشته یک ایمیل. تأییدش کن یا ریشه‌کنش کن.

self-hosted · بدون واسطه‌های ثالث · لغو اشتراک با یک کلیک

این چیست؟

git stash: یک فایل، بی‌آنکه بقیه به‌هم بریزد

این نوشته‌ها را می‌پسندید؟ این همان کاری است که برای زندگی از آن درمی‌آورم. استخدامم کنید