Herkese merhaba, uzun bir süredir hem derslerim, hem de çalıştığım kurumdaki yoğunluklar nedeniyle bir şeyler yazacak vaktim olmuyordu. Bir dersin ödevi için profesörüm 35000 görseli işlememizi gerektiren bir soru yazmış. Yardımcı olsun diye de veriyi kendi hazırladığı ön kodu bize sunmuş. Ben de o hazırlayadursun, ben de oyuna gireyim deyip kodu başlattıktan 30 dk sonra kodun hala bitmediğini gördüğümde açıp kodu okumak istedim. Ve gördüğüm çarpıcı bir gerçek vardı: Profesörüm CUDA kullanmamıştı! Onun kodunu düzenlerken size bu teknolojinin ne kadar büyük oranlarda hız kazandırdığını anlatan bir yazı hazırlayabileceğim aklıma geldi.
CUDA, NVIDIA tarafından gerçekleştirilen ve grafik kartlarının üzerinde sadece görüntü işlemlerinin yanı sıra matris hesapları da yapmamıza izin veren bir teknolojidir. Ekran kartlarının üstünde binlerce bulunan CUDA çekirdekleri paralel bir biçimde hesap yapar, bu sayede sıralı bir işlemden onlarca kat daha hızlı hesaplama yapabilirsiniz. Benim elimde NVIDIA GeForce RTX 4070 Super kartı var, dolayısıyla blog üzerindeki bütün hesaplama örneklerini bununla yapacağım. İşlemcim ise AMD Ryzen 7 7700 8-Core CPU.
Elimdeki AMD işlemcisi, yaklaşık olarak 0.5-1.0 TFLOPS (Saniye başı yapılan işlem sayısı (trilyon)) sunarken NVIDIA GeForce RTX 4070 Super ekran kartı için bu durum yaklaşık 28-30 TFLOPS arasıdır. yani 30 ile 60 katlık bir performans artışından söz edebiliriz. Peki CUDA nasıl kullanılır? Bunun için yapay zeka işlemlerinde de sıkça kullanılan PyTorch kütüphanesini kullanacağım. Siz herhangi bir matrix işlemini destekleyen kütüphaneyi kullanabilirsiniz (NumPy hariç! Eğer NumPy kullanmak istiyorsanız CUDA kernel işlemlerini kendiniz yazmalısınız.) Torch'un cuda destekleyen bir versiyonunu pip paket yöneticisi aracılığıyla ortamıma indirmek için PyTorch'un internet sitesine gidiyorum ve CUDA 11.8 sürümü için PyTorch kütüphanesini indiriyorum.
Başarılı bir şekilde kuruluyor. Şimdi bir versiyon kontrolü sağlayalım.
Oldukça basit bir şekilde CUDA destekleyen PyTorch sürümünü kurmuş olduk. Şimdi performans testi yapalım, bunun için benim örneğimde olan 35000 tane, her birisi 64x64 boyutuna sahip görüntü matrisinin bir sebepten karesini almam gerektiği hayali bir senaryo oluşturalım. Her bir matrisin boyutu (35000,64,64) olacaktır. PyTorch kütüphanesinde bir Matrisi (tensoru) GPU'ya yüklemek aslında çok kolay, isterseniz bir A matrisi için A.to(device) diyebilirsiniz, isterseniz A tensorunu oluştururken (device="cuda") parametresini geçebilirsiniz. Ben ikinci yolu tercih ettim. Burada dikkat etmeniz gereken 2 temel husus var:
1 - GPU'lar genellikle yük altında değilken uyurlar. Onları uyandırmak için asıl işlemi yapmadan önce kendi işleminize eşdeğer büyüklükte bir adet boş işlem yapmanız performans açısından karlı olacaktır. Bu sayede GPU ayağa kalkarken yapacağı optimizasyonları halletmiş olacaktır. Sonrasında isterseniz yüzlerce kez CUDA çekirdeklerini kullanabilirsiniz.
2 - CUDA asenkron çalıştığı için, yapmak istediğimiz işlemlerin bittiğine emin olmamız gerekiyor. Bunun için ise bir çarpım işlemimizin bittiğinde diğerini tetiklemeden önce "
torch.cuda.synchronize()" komutunu çağırıyoruz.
Şimdi örnek koda ve çıktısına göz atalım:
Gördüğünüz üzere yaklaşık 15 kat hız sağladı bize sadece bu basit işlem için. Daha çok ve komplike işlemlerde bu oran artacaktır. Sizin ekran kartı ve işlemci modelinize göre bu sayılar değişiklik gösterse de özellikle derin öğrenme, görüntü işleme gibi konularda mutlaka kullanmanızı tavsiye ettiğim bir teknoloji. Buraya kadar okuduğunuz için teşekkür ederim, keyifli forumlar
CUDA, NVIDIA tarafından gerçekleştirilen ve grafik kartlarının üzerinde sadece görüntü işlemlerinin yanı sıra matris hesapları da yapmamıza izin veren bir teknolojidir. Ekran kartlarının üstünde binlerce bulunan CUDA çekirdekleri paralel bir biçimde hesap yapar, bu sayede sıralı bir işlemden onlarca kat daha hızlı hesaplama yapabilirsiniz. Benim elimde NVIDIA GeForce RTX 4070 Super kartı var, dolayısıyla blog üzerindeki bütün hesaplama örneklerini bununla yapacağım. İşlemcim ise AMD Ryzen 7 7700 8-Core CPU.
Elimdeki AMD işlemcisi, yaklaşık olarak 0.5-1.0 TFLOPS (Saniye başı yapılan işlem sayısı (trilyon)) sunarken NVIDIA GeForce RTX 4070 Super ekran kartı için bu durum yaklaşık 28-30 TFLOPS arasıdır. yani 30 ile 60 katlık bir performans artışından söz edebiliriz. Peki CUDA nasıl kullanılır? Bunun için yapay zeka işlemlerinde de sıkça kullanılan PyTorch kütüphanesini kullanacağım. Siz herhangi bir matrix işlemini destekleyen kütüphaneyi kullanabilirsiniz (NumPy hariç! Eğer NumPy kullanmak istiyorsanız CUDA kernel işlemlerini kendiniz yazmalısınız.) Torch'un cuda destekleyen bir versiyonunu pip paket yöneticisi aracılığıyla ortamıma indirmek için PyTorch'un internet sitesine gidiyorum ve CUDA 11.8 sürümü için PyTorch kütüphanesini indiriyorum.
Bash:
pip3 install torch torchvision torchaudio --index-url https://download.pytorch.org/whl/cu118
Başarılı bir şekilde kuruluyor. Şimdi bir versiyon kontrolü sağlayalım.
Kod:
>>> import torch
>>> torch.__version__
'2.7.0+cu118'
>>> torch.cuda.is_available()
True
>>>
Oldukça basit bir şekilde CUDA destekleyen PyTorch sürümünü kurmuş olduk. Şimdi performans testi yapalım, bunun için benim örneğimde olan 35000 tane, her birisi 64x64 boyutuna sahip görüntü matrisinin bir sebepten karesini almam gerektiği hayali bir senaryo oluşturalım. Her bir matrisin boyutu (35000,64,64) olacaktır. PyTorch kütüphanesinde bir Matrisi (tensoru) GPU'ya yüklemek aslında çok kolay, isterseniz bir A matrisi için A.to(device) diyebilirsiniz, isterseniz A tensorunu oluştururken (device="cuda") parametresini geçebilirsiniz. Ben ikinci yolu tercih ettim. Burada dikkat etmeniz gereken 2 temel husus var:
1 - GPU'lar genellikle yük altında değilken uyurlar. Onları uyandırmak için asıl işlemi yapmadan önce kendi işleminize eşdeğer büyüklükte bir adet boş işlem yapmanız performans açısından karlı olacaktır. Bu sayede GPU ayağa kalkarken yapacağı optimizasyonları halletmiş olacaktır. Sonrasında isterseniz yüzlerce kez CUDA çekirdeklerini kullanabilirsiniz.
2 - CUDA asenkron çalıştığı için, yapmak istediğimiz işlemlerin bittiğine emin olmamız gerekiyor. Bunun için ise bir çarpım işlemimizin bittiğinde diğerini tetiklemeden önce "
torch.cuda.synchronize()" komutunu çağırıyoruz.
Şimdi örnek koda ve çıktısına göz atalım:
Python:
import torch
import time
import sys
A = torch.randn(35000, 64, 64)
start = time.time()
torch.matmul(A, A)
end = time.time()
print(f"[CPU] Süre: {end - start:.4f} saniye")
if torch.cuda.is_available():
A_gpu = torch.randn(35000, 64, 64, device="cuda")
# warm-up
torch.matmul(A_gpu, A_gpu)
torch.cuda.synchronize()
start = time.time()
torch.matmul(A_gpu, A_gpu)
torch.cuda.synchronize()
end = time.time()
print(f"[GPU] Süre: {end - start:.4f} saniye")
else:
sys.exit()
Bash:
PS C:\Users\Hacknology\tht> python .\cuda_tutorial.py
[CPU] Süre: 0.0590 saniye
[GPU] Süre: 0.0040 saniye
Gördüğünüz üzere yaklaşık 15 kat hız sağladı bize sadece bu basit işlem için. Daha çok ve komplike işlemlerde bu oran artacaktır. Sizin ekran kartı ve işlemci modelinize göre bu sayılar değişiklik gösterse de özellikle derin öğrenme, görüntü işleme gibi konularda mutlaka kullanmanızı tavsiye ettiğim bir teknoloji. Buraya kadar okuduğunuz için teşekkür ederim, keyifli forumlar