پرش به محتوا
← همهٔ یادداشت‌ها

RAPIDS روی GPU ابری: اجرای pandas روی کارت گرافیک با cuDF

·۷ دقیقه مطالعه·تیم جی‌پی‌یو

آب کف‌آلود و فیروزه‌ای یک رودخانهٔ کوهستانی که با سرعت از میان سنگ‌ها و قلوه‌سنگ‌ها می‌گذرد، با جنگل سرسبز در پس‌زمینه.

اگر اسکریپت pandas شما روی یک فایل CSV چندگیگابایتی دقیقه‌ها طول می‌کشد، با قالب NVIDIA RAPIDS روی GPU ابری می‌توانید همان کد را بدون بازنویسی روی کارت گرافیک اجرا کنید. ابزار این کار cudf.pandas است: یک خط اضافه می‌کنید و عملیات‌هایی مثل groupby، merge و فیلتر کردن روی GPU انجام می‌شود؛ هر چیزی هم که روی GPU پشتیبانی نشود، خودکار روی CPU اجرا می‌شود.

این آموزش برای تحلیلگر داده، دانشجو یا برنامه‌نویسی است که با pandas کار می‌کند ولی کارت گرافیک مناسب ندارد. کل کار، از اجاره تا گرفتن نتیجهٔ بنچمارک، حدود نیم ساعت طول می‌کشد و با ارزان‌ترین کارت مناسب، هزینه‌اش در زمان نوشتن این مطلب کمتر از ۲۱ هزار تومان است.

پیش‌نیازها

انتخاب ماشین مناسب برای cuDF روی GPU ابری

مهم‌ترین نکته این است که RAPIDS فقط روی کارت‌های نسل Volta و جدیدتر کار می‌کند؛ یعنی کارت‌هایی با compute capability برابر ۷٫۰ یا بیشتر. پشتیبانی از کارت‌های نسل Pascal از نسخهٔ 24.02 حذف شده است. پس GTX 1080، GTX 1080 Ti، Tesla P100 و Tesla P40 به کار این آموزش نمی‌آیند، هرچند ارزان‌اند. سری RTX 20، RTX 30، RTX 40 و Tesla V100 همه مناسب‌اند.

دومین نکته VRAM است. cuDF داده را در حافظهٔ کارت گرافیک نگه می‌دارد و هر عملیات هم برای نتیجه‌های میانی جای اضافه لازم دارد. یک قاعدهٔ سرانگشتی: VRAM شما دو تا سه برابر حجم دیتافریم در حافظه باشد. اگر داده جا نشود، cudf.pandas کار را روی CPU ادامه می‌دهد؛ خطا نمی‌دهد، ولی دیگر سریع هم نیست.

  • پیشنهاد اقتصادی: RTX 3060 با ۱۲ گیگابایت VRAM، در زمان نوشتن این مطلب از حدود ۲۱ هزار تومان در ساعت. برای دیتافریم‌هایی تا چند گیگابایت کافی است.
  • پیشنهاد میانه: RTX A4000 با ۱۶ گیگابایت، در زمان نوشتن این مطلب از حدود ۲۷ هزار تومان در ساعت.
  • پیشنهاد سریع: RTX 3090 با ۲۴ گیگابایت، در زمان نوشتن این مطلب از حدود ۵۱ هزار تومان در ساعت. برای داده‌های بزرگ‌تر و joinهای سنگین.

همهٔ این‌ها را در بازار GPU با فیلتر مدل کارت و حافظه پیدا می‌کنید. قیمت ساعتی هر ماشین موقع اجاره قفل می‌شود.

اجاره و راه‌اندازی

۱. در بازار، ماشین مورد نظر را باز کنید و در بخش قالب، NVIDIA RAPIDS را انتخاب کنید.

۲. دکمهٔ اجاره را بزنید و صبر کنید تا وضعیت ماشین «آماده» شود. از این لحظه هزینه دقیقه‌ای از کیف پول کم می‌شود.

۳. در صفحهٔ ماشین، دستور SSH آماده را با یک کلیک کپی کنید و در ترمینال خودتان اجرا کنید. اگر لینک Jupyter هم ظاهر شد، می‌توانید کارها را در نوت‌بوک انجام دهید؛ توکنش کنار همان لینک است. روش کار با Jupyter روی ماشین اجاره‌ای در پست Jupyter روی GPU ابری: اولین کد PyTorch شما آمده است.

۴. بعد از ورود، مطمئن شوید کارت گرافیک دیده می‌شود و cuDF نصب است:

nvidia-smi
python -c "import cudf; print(cudf.__version__)"

دستور اول نام کارت، نسخهٔ درایور و VRAM آزاد را نشان می‌دهد. دستور دوم باید فقط یک شمارهٔ نسخه چاپ کند. اگر خطای ModuleNotFoundError گرفتید، احتمالاً قالب دیگری انتخاب شده است.

اجرای pandas روی GPU با cudf.pandas

ساخت داده و اسکریپت بنچمارک

برای این‌که چیزی دانلود نکنیم، یک دیتافریم مصنوعی با ۵۰ میلیون ردیف می‌سازیم؛ چیزی شبیه جدول فروش با شناسهٔ مشتری، شهر و مبلغ. این اسکریپت را در ماشین بسازید:

cat > bench.py <<'EOF'
import time
import numpy as np
import pandas as pd

n = 50_000_000
rng = np.random.default_rng(0)
df = pd.DataFrame({
    "customer": rng.integers(0, 1_000_000, n),
    "city": rng.integers(0, 300, n),
    "amount": rng.random(n) * 1000,
})

t = time.perf_counter()
by_city = df.groupby("city")["amount"].agg(["sum", "mean", "count"])
top = df.groupby("customer")["amount"].sum().nlargest(10)
big = df[df["amount"] > 900].sort_values("amount")
print(f"elapsed: {time.perf_counter() - t:.2f} s")
print(top.head(3))
EOF

دیتافریم در این اندازه حدود ۱٫۲ گیگابایت جا می‌گیرد، پس روی کارت ۱۲ گیگ هم راحت اجرا می‌شود.

مقایسهٔ CPU و GPU

اول همان اسکریپت را با pandas معمولی اجرا کنید:

python bench.py

حالا بدون تغییر حتی یک خط از کد، همان فایل را با cudf.pandas اجرا کنید:

python -m cudf.pandas bench.py

خط elapsed در دو اجرا را مقایسه کنید. نتیجهٔ top در هر دو باید یکسان باشد؛ این یعنی خروجی عوض نشده و فقط محل اجرا فرق کرده است. میزان سرعت‌گرفتن به نوع کارت، اندازهٔ داده و نوع عملیات بستگی دارد، پس عدد را روی کار واقعی خودتان بسنجید، نه روی ادعای کسی.

استفاده در Jupyter

در نوت‌بوک، این خط را در اولین سلول و قبل از import pandas اجرا کنید:

%load_ext cudf.pandas
import pandas as pd

از این به بعد همهٔ کدهای pandas همان نوت‌بوک از cuDF استفاده می‌کنند. اگر pandas را قبلاً import کرده بودید، کرنل را ری‌استارت کنید و از اول شروع کنید.

داخل اسکریپت خودتان

اگر نمی‌خواهید از python -m استفاده کنید، این دو خط را بالای فایل، پیش از import کردن pandas، بگذارید:

import cudf.pandas
cudf.pandas.install()

import pandas as pd

کدام بخش روی GPU اجرا شد؟

ابزار پروفایل cudf.pandas نشان می‌دهد هر تابع روی GPU اجرا شده یا به CPU برگشته است. از خط فرمان:

python -m cudf.pandas --profile bench.py

در Jupyter هم کافی است %%cudf.pandas.profile را خط اول یک سلول بنویسید، یا برای گزارش خط‌به‌خط %%cudf.pandas.line_profile. اگر عملیات مهمی روی CPU برمی‌گردد، همان‌جا گلوگاه کد شماست.

کار با داده‌های خودتان

فایل CSV یا Parquet خودتان را با scp یا rsync به ماشین بفرستید؛ روشش در پست دانلود مدل هوش مصنوعی روی سرور GPU: scp و rsync آمده است. اگر داده روی اینترنت است، مستقیم روی ماشین دانلودش کنید؛ ماشین‌ها خارج از ایران‌اند و دانلود روی خود ماشین با سرعت گیگابیتی انجام می‌شود. خواندن Parquet معمولاً از CSV سریع‌تر است، پس اگر یک فایل را چند بار می‌خوانید، یک بار به Parquet تبدیلش کنید.

اگر به مشکل خوردید

  • خطای CUDA out of memory یا کند شدن ناگهانی: داده از VRAM بزرگ‌تر است. ستون‌های لازم را با پارامتر usecols بخوانید، نوع ستون‌ها را کوچک‌تر کنید (مثلاً float32 به‌جای float64) یا ماشینی با VRAM بیشتر بگیرید.
  • پیام دربارهٔ پشتیبانی نشدن کارت یا compute capability: کارت شما از نسل Pascal یا قدیمی‌تر است. ماشین را حذف کنید و یک کارت RTX یا V100 بگیرید.
  • سرعت هیچ فرقی نکرد: احتمالاً pandas قبل از %load_ext یا install() وارد شده است، یا داده آن‌قدر کوچک است که هزینهٔ انتقال به GPU از سودش بیشتر است. برای دیتافریم‌های چند هزار ردیفی، CPU کافی است.
  • قطع شدن SSH وسط اجرای طولانی: اسکریپت را با nohup python -m cudf.pandas bench.py > out.log 2>&1 & اجرا کنید تا با بسته شدن ترمینال متوقف نشود.

هزینه و صرفه‌جویی

برای این آموزش یک ساعت کاملاً کافی است و کار واقعی شما احتمالاً هم کوتاه است: خواندن داده، چند تحلیل و ذخیرهٔ نتیجه. هزینه دقیقه‌ای حساب می‌شود، پس به محض تمام شدن کار، ماشین را متوقف یا حذف کنید؛ ماشین متوقف‌شده هزینه ندارد.

یادتان باشد دیسک ماشین با حذف آن پاک می‌شود. نتیجه‌ها را قبل از حذف با df.to_parquet("result.parquet") ذخیره کنید و به سیستم خودتان یا فضای ابری‌تان بفرستید. اگر داده بزرگ است، اول کد را روی بخش کوچکی از آن روی همین ماشین امتحان کنید و بعد کل داده را اجرا کنید تا وقت گران GPU صرف رفع خطای تایپی نشود.

قدم بعدی

اگر کار شما فقط تحلیل داده نیست و مدل یادگیری ماشین هم آموزش می‌دهید، قالب‌های PyTorch و TensorFlow CUDA را امتحان کنید. برای انتخاب کارت بر اساس نوع کار هم پست انتخاب کارت گرافیک هوش مصنوعی: راهنمای VRAM هر کار را بخوانید. مستندات رسمی cudf.pandas و پیش‌نیازهای نصب RAPIDS هم مرجع خوبی برای جزئیات‌اند.

پرسش‌های متداول

آیا برای اجرای pandas روی GPU باید کدم را عوض کنم؟

نه. با python -m cudf.pandas یا %load_ext cudf.pandas همان کد pandas بدون تغییر اجرا می‌شود. عملیات‌های پشتیبانی‌شده روی GPU و بقیه خودکار روی CPU اجرا می‌شوند.

cuDF روی کدام کارت گرافیک کار می‌کند؟

روی کارت‌های NVIDIA نسل Volta و جدیدتر با compute capability ۷٫۰ یا بیشتر، مثل سری RTX 20 تا RTX 40 و Tesla V100. کارت‌های نسل Pascal مثل GTX 1080 و Tesla P100 دیگر پشتیبانی نمی‌شوند.

cuDF چقدر از pandas سریع‌تر است؟

بستگی به اندازهٔ داده و نوع عملیات دارد. در دیتافریم‌های میلیون‌ردیفی و عملیات‌هایی مثل groupby و join تفاوت معمولاً چشمگیر است، ولی روی داده‌های کوچک ممکن است فرقی حس نکنید. بهترین راه، اجرای بنچمارک همین آموزش روی دادهٔ خودتان است.

اگر داده از حافظهٔ کارت گرافیک بزرگ‌تر باشد چه می‌شود؟

cudf.pandas کار را روی CPU ادامه می‌دهد و خطا نمی‌دهد، ولی سرعت به اندازهٔ pandas معمولی برمی‌گردد. راه درست، خواندن ستون‌های لازم، کوچک کردن نوع داده یا اجارهٔ کارتی با VRAM بیشتر است.


تصویر کاور: «Rapids on Giffre river (Samoens)» اثر Tangopaso، از ویکی‌مدیا کامنز، لایسنس Public Domain.