ظهور مدلهای زبانی بزرگ (LLM) نیازمندیهای زیرساخت را بهطور بنیادین تغییر داده است. برخلاف میکروسرویسهای سنتی، بارهای کاری استنباط LLM مصرفکننده منابع هستند و به شدت به قابلیتهای سختافزاری حساساند. هنگامی که سازمانها از توسعه به تولید میروند، با یک منظره سختافزاری تکهتکهشده مواجه میشوند: خوشههای GPU برای آموزش و استنباط با پهنای باند بالا، نمونههای فقط CPU برای استقرار لبه یا بهینهشده از نظر هزینه، و معماریهای CPU متفاوت (amd64 در مقابل arm64) در میان ارائهدهندگان ابری. اطمینان از اجرای قابلاعتماد کنтейنرهای استنباط LLM شما در سراسر این طیف، به استراتژیهای ساخت پیشرفته نیاز دارد.
چالش سختافزارهای ناهمگن
یک تصویر Docker استاندارد که روی یک لپتاپ توسعه با GPU NVIDIA ساخته شده باشد، روی یک گره تولید فقط CPU شکست خواهد خورد و برعکس. علاوه بر این، ترکیب کتابخانههای CUDA در یک تصویر پایه، اگر دستگاه هدف درایورهای NVIDIA نداشته باشد، باعث تورم و تعارض وابستگیها میشود. در LLMOps، ما باید نگرانیها را جدا کنیم: منطق برنامه، وزنهای مدل و وابستگیهای زمان اجرا (CUDA/CPU) باید ماژولار باشند.
استراتژی ۱: جداسازی تصاویر پایه بر اساس معماری
به جای یک تصویر "جهانی" تکقطبی، تصاویر پایه متمایز را برای اهداف سختافزاری مختلف حفظ کنید.
- تصویر GPU: مبتنی بر
nvidia/cuda:11.8-runtime-ubuntu22.04. شامل جعبهابزارهای CUDA و کتابخانههای خاص GPU مانندflash-attn. - تصویر CPU: مبتنی بر
python:3.10-slim. شامل MKL یا OpenBLAS برای ریاضیات بهینهشده CPU، اما بدون هیچ وابستگی CUDA.
استراتژی ۲: مدیریت ماژولار وابستگیها
از مکانیزم وابستگی شرطی Python برای نصب بستهها فقط زمانی استفاده کنید که سختافزار مربوطه شناسایی شود. این کار از مشکلات ImportError در گرههای ناسازگار جلوگیری میکند.
# requirements-gpu.txt
torch==2.0.1+cu118
transformers==4.36.0
flash-attn==2.3.6 # فقط GPU
# requirements-cpu.txt
torch==2.0.1
transformers==4.36.0
در Dockerfile خود، از آرگومانهای ساخت برای انتخاب فایل requirements صحیح استفاده کنید:
ARG BUILD_VARIANT=cpu
RUN if [ "$BUILD_VARIANT" = "gpu" ]; then \
pip install -r requirements-gpu.txt; \
else \
pip install -r requirements-cpu.txt; \
fi
استراتژی ۳: بهرهگیری از BuildX برای ساختهای چندمعماری
برای اهداف CPU، باید هم amd64 و هم arm64 (رایج در AWS Graviton و Apple Silicon) را پشتیبانی کنید. از Docker Buildx برای ایجاد مانیفستهای چندمعماری استفاده کنید، بدون نیاز به سختافزار واقعی برای هر معماری.
docker buildx create --use
docker buildx build --platform linux/amd64,linux/arm64 \
--build-arg BUILD_VARIANT=cpu \
-t my-llm-app:cpu-mixed .
استراتژی ۴: جداسازی وزنهای مدل
هرگز وزنهای مدل بزرگ (۷B تا ۱۳B پارامتر) را در تصویر Docker خود پخت نکنید. تصاویر به چند گیگابایت میرسند و خطوط CI/CD و دریافت از رجیستری را کند میکنند. به جای آن، از مونتاژ حجمها یا دریافت وزنها از یک رجیستری (مانند Hugging Face Hub) هنگام راهاندازی کنтейنر استفاده کنید. این کار اطمینان میدهد که تصویر شما سبک و قابل نسخهبندی باقی میماند، در حالی که مدلها میتوانند بهصورت مستقل بهروزرسانی شوند.
بهترین روشهای پیادهسازی CI/CD
۱. کشسازی لایهای تهاجمی: pip install برای وابستگیهای اصلی را در لایههای اولیه نگه دارید. فقط کد برنامه را در لایههای بعدی کپی کنید.
۲. بررسیهای سلامت: CMD HEALTHCHECK را پیادهسازی کنید که در دسترس بودن GPU (با استفاده از nvidia-smi) یا تعداد هستههای CPU را قبل از اعلام آماده بودن سرویس تأیید میکند.
۳. اصطلاح برچسبگذاری: از برچسبهایی مانند my-llm:v1.0-gpu و my-llm:v1.0-cpu برای جلوگیری از ناهماهنگیهای تصادفی در استقرار استفاده کنید.
نتیجهگیری
کنтейنریسازی استنباط LLM درباره ایجاد یک تصویر یکسایز-برای-همه نیست. این درباره ساخت یک پورتفولیو از آرتیفکتهای بهینهشده و خاص سختافزار است. با جدا کردن وابستگیهای زمان اجرا، بهرهگیری از آرگومانهای ساخت و جداسازی وزنهای مدل از کد برنامه، میتوانید استقرارهای LLM قابلاعتماد، مقیاسپذیر و بهینه از نظر هزینه را در سراسر هر توپولوژی سختافزاری دستیاب کنید. با Dockerfileهای ماژولار در مراحل اولیه خط لوله LLMOps خود شروع کنید تا از بدهی فنی هنگام مقیاسپذیر شدن زیرساخت خود جلوگیری کنید.