دستورهای GPU در پایتورچ که همه باید بدانند
امروزه GPU-ها یکی از ضروریترین ابزارها برای کار در حوزه یادگیری عمیق و هوشمصنوعی هستند. استفاده از قدرت GPU-ها سرعت انجام محاسبات را به شکل چشمگیری افزایش داده که همین امر منجر به آموزش و ارزیابی مدلها با سرعت بیشتری شده است. در این نوشته، به بررسی برخی از دستورات مفید مرتبط با GPU در پایتون و پایتورچ میپردازیم.
چرا GPU
قبل از اینکه به دستورات بپردازیم، بیایید ببینیم که چرا GPU-ها در حوزه یادگیری عمیق ضروری هستند. برخلاف CPU-ها که هستههای کمی دارند و برای انجام پردازشهای سری مناسب هستند، GPUها هستههای زیادی دارند که برای انجام محاسبات به صورت موازی و همزمان طراحی شدهاند.
همین امر باعث میشود GPU-ها برای کارهایی مثل آموزش مدلهای یادگیری عمیق، پردازش ویدئو و تسکهای مشابه که در آن حجم زیادی از دادهها به صورت موازی پردازش میشوند، ایدهآل باشند. بهرهگیری از GPU-ها میتواند زمان آموزش مدلهای یادگیری عمیق را به شدت کاهش داده و آموزش مدلهای بزرگ را امکانپذیر کند..
راهاندازی محیط GPU
قبل از استفاده از دستورات GPU، اطمینان حاصل کنید سیستم شما یک GPU سازگار دارد! طبیعتا بدون GPU استفاده از امکانات آن هم امکانپذیر نیست. همچنین بررسی کنید که درایورهای GPU روی سیستم شما نصب شده باشد.
در قدم بعدی نیاز است که CUDA و فریمورک Pytorch ورژن GPU را روی سیستم خود نصب کنید. حالا شما میتوانید از GPU در کدنویسیهای خود استفاده کنید. در ادامه، تعدادی از دستورهای مفید و مرتبط با GPU در پایتورچ را با هم مرور میکنیم.
بررسی در دسترس بودن GPU
شاید اولین سوالی که بعد از راهاندازی GPU به ذهن ما خطور میکند این است: همه مراحل نصب را به درستی انجام دادهام؟ یکی از راههای چک کردن این مساله، استفاده از کد زیر است:
torch.cuda.is_available()
در صورتی که GPU در دسترس باشد، نتیجه دستور بالا True است. در غیر این صورت نتیجه False خواهد بود.
import torch
انتقال تنسورها به GPU
برای اینکه از سرعت بالای GPU در انجام محاسبات استفاده کنیم، نیاز است که ابتدا متغیرهایی که داریم را به GPU انتقال دهیم. مثلا اگر بخواهیم دو تنسور را در هم ضرب کنیم، برای بهرهگیری از سرعت GPU، هردو تنسور باید در حافظه GPU باشند. برای انتقال یک تنسور به جیپییو از دستور زیر استفاده میشود:
tensor1 = torch.tensor([1, 2, 3]).to('cuda')
اگر بیش از یک GPU دارید باید به این شکل، شماره GPU را نیز مشخص کنید:
tensor1 = torch.tensor([1, 2, 3]).to('cuda:0')
اندیس GPU از صفر شروع میشود. اینجا چون ما یک GPU بیشتر نداریم همان شماره صفر را انتخاب کردیم.
از کجا بفهمیم انتقال درست انجام شده؟
حالا برای اینکه چک کنیم که این تنسور واقعا به GPU منتقل شده از دستور زیر استفاده میکنیم:
tensor1.device.type
'cuda'
اگر یک تنسور را قبلا تعریف کردید و حالا میخواهید آن را به جیپییو انتقال دهید باید به این شکل این کار را انجام دهید:
tensor2 = torch.tensor([1, 2, 3]) tensor2 = tensor2.to('cuda') tensor2.device.type
'cuda'
دقت کنید که متغیر tensor2 را overwrite کردهایم. اگر این کار را انجام ندهیم، انتقال به درستی انجام نخواهد شد.
انتقال مدل به GPU
ابتدا یک مدل خیلی ساده تعریف میکنیم و یک Instance از آن میسازیم:
import torch import torch.nn as nn class SimpleModel(nn.Module): def __init__(self): super(SimpleModel, self).__init__() self.fc1 = nn.Linear(100, 50) self.fc2 = nn.Linear(50, 10) self.relu = nn.ReLU() def forward(self, x): x = self.fc1(x) x = self.relu(x) x = self.fc2(x) return x model = SimpleModel()
برای انتقال مدل به جیپییو، مشابه با بخش قبل عمل میکنیم. فقط نیازی به overwrite کردن نیست. اگرچه با انجام این کار (overwrite) هم مشکلی به وجود نخواهد آمد:
model.to('cuda')
برای چک کردن اینکه مدل واقعا به GPU منتقل شده، از دستور زیر استفاده میکنیم:
next(model.parameters()).is_cuda
در صورتی که پارامترهای مدل در GPU باشند، یعنی انتقال درست انجام شده و تمامی محاسبات مرتبط با آن در جیپییو انجام خواهد شد.
پاک کردن کش GPU
هنگامی که مدلها و مجموعه دادههای یادگیری عمیق بزرگتر میشوند، مدیریت حافظه اهمیت زیادی پیدا میکند. پاکسازی مداوم حافظه GPU میتواند از وقوع خطای out-of-memory در طول آموزش جلوگیری کند. برای پاک کردن حافظه اشغال شده توسط متغیرهایی که اضافی هستند از دستور زیر استفاده میشود:
torch.cuda.empty_cache()
ذخیره GPU در متغیر device
یک تکه کد هست که احتمالا در 99 درصد کدهایی که باز میکنید ببینید! در این کد ابتدا در دسترس بودن GPU بررسی میشود. یک متغیر معمولا با نام device انتخاب شده و اگر GPU در دسترس بود، ‘cuda’ را در آن ذخیره میکنند. اگر هم GPU در دسترس نباشد، ‘cpu’ را در device ذخیره میکند:
device = torch.device('cuda' if torch.cuda.is_available() else 'cpu') print('Using device:', device)
حالا در کدها زمانی که میخواهند تنسور یا مدلی را به GPU انتقال دهند، به جای to(‘cuda’) مینویسند to(device)!
چرا device؟
شاید به این فکر میکنید که خب، میتوانید به جای device، همان cuda را بگذارید. چه لزومی به تعریف device است؟ در بخشهای قبل دیدید که برای منتقل کردن تنسورها و مدل به GPU، یک تکه کد باید اضافه کنید که این انتقال را انجام بدهد.
در این کد ما به جای اینکه بنویسیم cuda، مینویسیم device. چرا؟ فکر کنید بخواهید کدهایتان را روی یک سیستم بدون GPU اجرا کنید؛ در این صورت باید آستینها را بالا بزنید و تکتک کدهایی که تاکنون نوشتید را ویرایش کنید.
اما با تعریف device دیگر نیازی به این کار نیست چون به صورت اتوماتیک، همان ابتدای کد، مشخص میشود که device کدام است CPU یا GPU و بدون ویرایش کدهایتان میتوانید آن را روی هر سیستمی اجرا کنید.
نتیجهگیری
در این پست به بررسی چند دستور رایج مرتبط با GPU در پایتون و پایتورچ پرداختیم. گفتیم که بهرهگیری از GPU میتواند زمان پردازشهای انجام شده را به شدت کاهش دهد و دستورهایی را بررسی کردیم که تنسورها و مدلها را به جیپییو منتقل میکنند. همچنین دستورهایی را بررسی کردیم که نشان میدادند این انتقالها به درستی انجام شدهاند یا خیر. در نهایت هم یک دستور برای پاک کردن کش معرفی کردیم. همچنین توضیح دادیم که چرا باید ابتدای کدهایمان یک متغیر device تعریف کرده و cuda را در آن ذخیره کنیم. حالا شما بگویید چه دستوری هست که جایش در این پست خالی است؟ نظر خود را کامنت کنید.
دیدگاهتان را بنویسید