5.6. GPU (Grafik İşleme Birimi)¶ Open the notebook in SageMaker Studio Lab
Section 1.5 için de, son yirmi yılda hesaplamanın hızlı büyümesini tartıştık. Özetle, GPU performansı 2000 yılından bu yana her on yılda bir 1000 kat artmıştır. Bu büyük fırsatlar sunarken aynı zamanda bu tür bir performansın sağlanması için önemli bir gereksinim olduğunu da göstermektedir.
Bu bölümde, araştırmanız için bu hesaplamalı performanstan nasıl yararlanılacağını tartışmaya başlıyoruz. Öncelikle tek GPU’ları kullanarak ve daha sonra, birden çok GPU ve birden çok sunucuyu (birden çok GPU ile) nasıl kullanacağınızı tartışacağız.
Özellikle, hesaplamalar için tek bir NVIDIA GPU’nun nasıl
kullanılacağını tartışacağız. İlk olarak kurulu en az bir NVIDIA GPU’nuz
olduğundan emin olun. Ardından, NVIDIA sürücüsünü ve
CUDA’yı indirin ve
uygun yere kurmak için istemleri takip edin. Bu hazırlıklar
tamamlandıktan sonra, nvidia-smi
, komutu grafik kartı bilgilerini
görüntülemek için kullanılabilir.
!nvidia-smi
Mon Oct 17 22:06:22 2022
+-----------------------------------------------------------------------------+
| NVIDIA-SMI 460.106.00 Driver Version: 460.106.00 CUDA Version: 11.2 |
|-------------------------------+----------------------+----------------------+
| GPU Name Persistence-M| Bus-Id Disp.A | Volatile Uncorr. ECC |
| Fan Temp Perf Pwr:Usage/Cap| Memory-Usage | GPU-Util Compute M. |
| | | MIG M. |
|===============================+======================+======================|
| 0 Tesla V100-SXM2... Off | 00000000:00:1B.0 Off | 0 |
| N/A 37C P0 49W / 300W | 1760MiB / 16160MiB | 0% Default |
| | | N/A |
+-------------------------------+----------------------+----------------------+
| 1 Tesla V100-SXM2... Off | 00000000:00:1C.0 Off | 0 |
| N/A 37C P0 39W / 300W | 3MiB / 16160MiB | 0% Default |
| | | N/A |
+-------------------------------+----------------------+----------------------+
| 2 Tesla V100-SXM2... Off | 00000000:00:1D.0 Off | 0 |
| N/A 42C P0 185W / 300W | 5472MiB / 16160MiB | 8% Default |
| | | N/A |
+-------------------------------+----------------------+----------------------+
| 3 Tesla V100-SXM2... Off | 00000000:00:1E.0 Off | 0 |
| N/A 40C P0 202W / 300W | 5408MiB / 16160MiB | 0% Default |
| | | N/A |
+-------------------------------+----------------------+----------------------+
+-----------------------------------------------------------------------------+
| Processes: |
| GPU GI CI PID Type Process name GPU Memory |
| ID ID Usage |
|=============================================================================|
| 2 N/A N/A 42922 C ...l-tr-release-0/bin/python 5469MiB |
| 3 N/A N/A 42922 C ...l-tr-release-0/bin/python 5405MiB |
+-----------------------------------------------------------------------------+
Bir MXNet tensörünün bir NumPy ndarray
’i ile neredeyse aynı
göründüğünü fark etmiş olabilirsiniz.
Ancak birkaç önemli farklılık var. MXNet’i NumPy’den ayıran temel özelliklerden biri, çeşitli donanım aygıtlarına desteğidir.
MXNet’te her dizilimin (array) bir bağlamı vardır. Şimdiye kadar, varsayılan olarak, tüm değişkenler ve ilişkili hesaplamalar CPU’ya atanmıştır. Tipik olarak, diğer bağlamlar çeşitli GPU’lar olabilir. İşleri birden çok sunucuya dağıttığımızda işler arap saçına dönebilir. Dizilimleri bağlamlara akıllıca atayarak, cihazlar arasında veri aktarımında harcanan zamanı en aza indirebiliriz. Örneğin, GPU’lu bir sunucuda sinir ağlarını eğitirken, genellikle modelin parametrelerinin GPU’da kalmasını tercih ederiz.
Ardından, MXNet’in GPU sürümünün kurulu olduğunu onaylamamız gerekiyor.
MXNet’in bir CPU sürümü zaten kuruluysa, önce onu kaldırmamız gerekir.
Örneğin, pip uninstall mxnet
komutunu kullanın, ardından CUDA
sürümünüze göre ilgili MXNet sürümünü kurun. CUDA 10.0’un kurulu
olduğunu varsayarsak, CUDA 10.0’u destekleyen MXNet sürümünü
pip install mxnet-cu100
aracılığıyla kurabilirsiniz.
!nvidia-smi
Mon Oct 17 22:48:03 2022
+-----------------------------------------------------------------------------+
| NVIDIA-SMI 460.106.00 Driver Version: 460.106.00 CUDA Version: 11.2 |
|-------------------------------+----------------------+----------------------+
| GPU Name Persistence-M| Bus-Id Disp.A | Volatile Uncorr. ECC |
| Fan Temp Perf Pwr:Usage/Cap| Memory-Usage | GPU-Util Compute M. |
| | | MIG M. |
|===============================+======================+======================|
| 0 Tesla V100-SXM2... Off | 00000000:00:1B.0 Off | 0 |
| N/A 39C P0 50W / 300W | 1760MiB / 16160MiB | 0% Default |
| | | N/A |
+-------------------------------+----------------------+----------------------+
| 1 Tesla V100-SXM2... Off | 00000000:00:1C.0 Off | 0 |
| N/A 38C P0 50W / 300W | 1542MiB / 16160MiB | 30% Default |
| | | N/A |
+-------------------------------+----------------------+----------------------+
| 2 Tesla V100-SXM2... Off | 00000000:00:1D.0 Off | 0 |
| N/A 38C P0 43W / 300W | 3MiB / 16160MiB | 0% Default |
| | | N/A |
+-------------------------------+----------------------+----------------------+
| 3 Tesla V100-SXM2... Off | 00000000:00:1E.0 Off | 0 |
| N/A 36C P0 53W / 300W | 1432MiB / 16160MiB | 22% Default |
| | | N/A |
+-------------------------------+----------------------+----------------------+
+-----------------------------------------------------------------------------+
| Processes: |
| GPU GI CI PID Type Process name GPU Memory |
| ID ID Usage |
|=============================================================================|
| 1 N/A N/A 32127 C ...l-tr-release-0/bin/python 1539MiB |
| 3 N/A N/A 32127 C ...l-tr-release-0/bin/python 1429MiB |
+-----------------------------------------------------------------------------+
PyTorch’ta her dizilimin bir aygıtı vardır, biz onu genellikle bağlam olarak adlandırırız. Şimdiye kadar, varsayılan olarak, tüm değişkenler ve ilişkili hesaplama CPU’ya atanmıştır. Tipik olarak, diğer bağlamlar çeşitli GPU’lar olabilir. İşleri birden çok sunucuya dağıttığımızda işler arap saçına dönebilir. Dizileri bağlamlara akıllıca atayarak, cihazlar arasında veri aktarımında harcanan zamanı en aza indirebiliriz. Örneğin, GPU’lu bir sunucuda sinir ağlarını eğitirken, genellikle modelin parametrelerinin GPU’da kalmasını tercih ederiz.
Ardından, PyTorch’un GPU sürümünün kurulu olduğunu onaylamamız
gerekiyor. PyTorch’un bir CPU sürümü zaten kuruluysa, önce onu
kaldırmamız gerekir. Örneğin, pip uninstall torch
komutunu kullanın,
ardından CUDA sürümünüze göre ilgili PyTorch sürümünü kurun. CUDA
10.0’un kurulu olduğunu varsayarsak, CUDA 10.0’u destekleyen PyTorch
sürümünü pip install torch-cu100
aracılığıyla kurabilirsiniz.
!nvidia-smi
Mon Oct 17 23:20:50 2022
+-----------------------------------------------------------------------------+
| NVIDIA-SMI 460.106.00 Driver Version: 460.106.00 CUDA Version: 11.2 |
|-------------------------------+----------------------+----------------------+
| GPU Name Persistence-M| Bus-Id Disp.A | Volatile Uncorr. ECC |
| Fan Temp Perf Pwr:Usage/Cap| Memory-Usage | GPU-Util Compute M. |
| | | MIG M. |
|===============================+======================+======================|
| 0 Tesla V100-SXM2... Off | 00000000:00:1B.0 Off | 0 |
| N/A 36C P0 49W / 300W | 1760MiB / 16160MiB | 0% Default |
| | | N/A |
+-------------------------------+----------------------+----------------------+
| 1 Tesla V100-SXM2... Off | 00000000:00:1C.0 Off | 0 |
| N/A 36C P0 35W / 300W | 3MiB / 16160MiB | 0% Default |
| | | N/A |
+-------------------------------+----------------------+----------------------+
| 2 Tesla V100-SXM2... Off | 00000000:00:1D.0 Off | 0 |
| N/A 34C P0 36W / 300W | 3MiB / 16160MiB | 0% Default |
| | | N/A |
+-------------------------------+----------------------+----------------------+
| 3 Tesla V100-SXM2... Off | 00000000:00:1E.0 Off | 0 |
| N/A 32C P0 37W / 300W | 3MiB / 16160MiB | 0% Default |
| | | N/A |
+-------------------------------+----------------------+----------------------+
+-----------------------------------------------------------------------------+
| Processes: |
| GPU GI CI PID Type Process name GPU Memory |
| ID ID Usage |
|=============================================================================|
+-----------------------------------------------------------------------------+
Bu bölümdeki programları çalıştırmak için en az iki GPU’ya ihtiyacınız var. Bunun çoğu masaüstü bilgisayar için abartılı olabileceğini, ancak bulutta (ör. AWS EC2 çoklu-GPU bulut sunucularını kullanarak) kolayca kullanılabileceğini unutmayın. Hemen hemen diğer bütün bölümler birden fazla GPU gerektirmez. Bunun burdaki kullanım nedeni, basitçe verilerin farklı cihazlar arasında nasıl aktığını göstermektir.
5.6.1. Hesaplama Cihazları¶
Depolama ve hesaplama için CPU ve GPU gibi cihazları belirtebiliriz. Varsayılan olarak, ana bellekte tensörler oluşturulur ve ardından bunu hesaplamak için CPU’yu kullanır.
MXNet’te CPU ve GPU, cpu()
ve gpu()
ile gösterilebilir.
cpu()
(veya parantez içindeki herhangi bir tam sayı), tüm fiziksel
CPU’lar ve bellek anlamına gelir. Bu, MXNet’in hesaplamalarının tüm CPU
çekirdeklerini kullanmaya çalışacağı anlamına gelir. Ancak, gpu()
yalnızca bir kartı ve ona denk gelen belleği temsil eder. Birden fazla
GPU varsa, \(i.\) GPU’yu (\(i\) 0’dan başlar) temsil etmek için
gpu(i)
’yu kullanırız. Ayrıca, gpu(0)
ve gpu()
eşdeğerdir.
from mxnet import np, npx
from mxnet.gluon import nn
npx.set_np()
npx.cpu(), npx.gpu(), npx.gpu(1)
(cpu(0), gpu(0), gpu(1))
PyTorch’ta CPU ve GPU, torch.device('cpu')
ve
torch.device('cuda')
ile gösterilebilir. cpu
aygıtının tüm
fiziksel CPU’lar ve bellek anlamına geldiğine dikkat edilmelidir. Bu,
PyTorch’un hesaplamalarının tüm CPU çekirdeklerini kullanmaya çalışacağı
anlamına gelir. Bununla birlikte, bir gpu
cihazı yalnızca bir kartı
ve ona denk gelen belleği temsil eder. Birden çok GPU varsa, \(i.\)
GPU (\(i\) 0’dan başlar) temsil etmek için
torch.device(f'cuda:{i}')
yi kullanırız. Ayrıca gpu:0
ve
gpu
eşdeğerdir.
import torch
from torch import nn
torch.device('cpu'), torch.device('cuda'), torch.device('cuda:1')
(device(type='cpu'), device(type='cuda'), device(type='cuda', index=1))
import tensorflow as tf
tf.device('/CPU:0'), tf.device('/GPU:0'), tf.device('/GPU:1')
(<tensorflow.python.eager.context._EagerDeviceContext at 0x7f2f4c078600>,
<tensorflow.python.eager.context._EagerDeviceContext at 0x7f2f4ba25980>,
<tensorflow.python.eager.context._EagerDeviceContext at 0x7f2f4ba25500>)
Mevcut GPU adetini sorgulayabiliriz.
npx.num_gpus()
2
torch.cuda.device_count()
2
len(tf.config.experimental.list_physical_devices('GPU'))
2
Şimdi, istenen GPU’lar var olmasa bile kodları çalıştırmamıza izin veren iki kullanışlı işlev tanımlıyoruz.
def try_gpu(i=0): #@save
"""Varsa gpu(i) döndürün, aksi takdirde cpu() döndürün."""
return npx.gpu(i) if npx.num_gpus() >= i + 1 else npx.cpu()
def try_all_gpus(): #@save
"""Mevcut tüm GPU'ları veya GPU yoksa [cpu()] döndürün."""
devices = [npx.gpu(i) for i in range(npx.num_gpus())]
return devices if devices else [npx.cpu()]
try_gpu(), try_gpu(10), try_all_gpus()
(gpu(0), cpu(0), [gpu(0), gpu(1)])
def try_gpu(i=0): #@save
"""Varsa gpu(i) döndürün, aksi takdirde cpu() döndürün."""
if torch.cuda.device_count() >= i + 1:
return torch.device(f'cuda:{i}')
return torch.device('cpu')
def try_all_gpus(): #@save
"""Mevcut tüm GPU'ları veya GPU yoksa [cpu()] döndürün."""
devices = [torch.device(f'cuda:{i}')
for i in range(torch.cuda.device_count())]
return devices if devices else [torch.device('cpu')]
try_gpu(), try_gpu(10), try_all_gpus()
(device(type='cuda', index=0),
device(type='cpu'),
[device(type='cuda', index=0), device(type='cuda', index=1)])
def try_gpu(i=0): #@save
"""Varsa gpu(i) döndürün, aksi takdirde cpu() döndürün."""
if len(tf.config.experimental.list_physical_devices('GPU')) >= i + 1:
return tf.device(f'/GPU:{i}')
return tf.device('/CPU:0')
def try_all_gpus(): #@save
"""Mevcut tüm GPU'ları veya GPU yoksa [cpu()] döndürün."""
num_gpus = len(tf.config.experimental.list_physical_devices('GPU'))
devices = [tf.device(f'/GPU:{i}') for i in range(num_gpus)]
return devices if devices else [tf.device('/CPU:0')]
try_gpu(), try_gpu(10), try_all_gpus()
(<tensorflow.python.eager.context._EagerDeviceContext at 0x7f2f4006ac40>,
<tensorflow.python.eager.context._EagerDeviceContext at 0x7f2f4006afc0>,
[<tensorflow.python.eager.context._EagerDeviceContext at 0x7f2f4006e040>,
<tensorflow.python.eager.context._EagerDeviceContext at 0x7f2f4006e0c0>])
5.6.2. Tensörler and GPUlar¶
Varsayılan olarak, CPU’da tensörler oluşturulur. Tensörün bulunduğu cihazı sorgulayabiliriz.
x = np.array([1, 2, 3])
x.ctx
cpu(0)
x = torch.tensor([1, 2, 3])
x.device
device(type='cpu')
x = tf.constant([1, 2, 3])
x.device
'/job:localhost/replica:0/task:0/device:GPU:0'
Birden çok terimle çalışmak istediğimizde, aynı bağlamda olmaları gerektiğine dikkat etmemiz önemlidir. Örneğin, iki tensörü toplarsak, her iki argümanın da aynı cihazda olduğundan emin olmamız gerekir—aksi takdirde çerçeve, sonucu nerede saklayacağını ve hatta hesaplamayı nerede gerçekleştireceğine nasıl karar vereceğini bilemez.
5.6.2.1. GPU’da Depolama¶
GPU’da bir tensör depolamanın birkaç yolu vardır. Örneğin, bir tensör
oluştururken bir depolama cihazı belirleyebiliriz. Sonra, ilk gpu
’da
tensör değişkeni X
’i oluşturuyoruz. Bir GPU’da oluşturulan tensör
yalnızca o GPU’nun belleğini harcar. GPU bellek kullanımını görüntülemek
için nvidia-smi
komutunu kullanabiliriz. Genel olarak, GPU bellek
sınırını aşan veriler oluşturmadığımızdan emin olmamız gerekir.
X = np.ones((2, 3), ctx=try_gpu())
X
array([[1., 1., 1.],
[1., 1., 1.]], ctx=gpu(0))
X = torch.ones(2, 3, device=try_gpu())
X
tensor([[1., 1., 1.],
[1., 1., 1.]], device='cuda:0')
with try_gpu():
X = tf.ones((2, 3))
X
<tf.Tensor: shape=(2, 3), dtype=float32, numpy=
array([[1., 1., 1.],
[1., 1., 1.]], dtype=float32)>
En az iki GPU’ya sahip olduğunuzu varsayarak, aşağıdaki kod ikinci GPU’da keyfi bir tensor oluşturacaktır.
Y = np.random.uniform(size=(2, 3), ctx=try_gpu(1))
Y
array([[0.67478997, 0.07540122, 0.9956977 ],
[0.09488854, 0.415456 , 0.11231736]], ctx=gpu(1))
Y = torch.rand(2, 3, device=try_gpu(1))
Y
tensor([[0.5575, 0.9225, 0.4448],
[0.2045, 0.3821, 0.9360]], device='cuda:1')
with try_gpu(1):
Y = tf.random.uniform((2, 3))
Y
<tf.Tensor: shape=(2, 3), dtype=float32, numpy=
array([[0.60182166, 0.2831906 , 0.12088335],
[0.911641 , 0.5682545 , 0.8583329 ]], dtype=float32)>
5.6.2.2. Kopyalama¶
X + Y
’yi hesaplamak istiyorsak, bu işlemi nerede
gerçekleştireceğimize karar vermemiz gerekir. Örneğin
Fig. 5.6.1 içinde gösterildiği gibi, X
’i ikinci GPU’ya
aktarabilir ve işlemi orada gerçekleştirebiliriz. Sadece X
ve
Y
’yi toplamayın, çünkü bu bir istisnayla sonuçlanacaktır. Koşma
zamanı motoru ne yapacağını bilemez: Veriyi aynı cihazda bulamaz ve
başarısız olur. Çünkü Y
ikinci GPU’da bulunur, ikisini toplamadan
önce X
’i taşımamız gerekir.
Fig. 5.6.1 İşlemi yapmadan önce verileri aynı cihaza kopyalayın.¶
Z = X.copyto(try_gpu(1))
print(X)
print(Z)
[[1. 1. 1.]
[1. 1. 1.]] @gpu(0)
[[1. 1. 1.]
[1. 1. 1.]] @gpu(1)
Z = X.cuda(1)
print(X)
print(Z)
tensor([[1., 1., 1.],
[1., 1., 1.]], device='cuda:0')
tensor([[1., 1., 1.],
[1., 1., 1.]], device='cuda:1')
with try_gpu(1):
Z = X
print(X)
print(Z)
tf.Tensor(
[[1. 1. 1.]
[1. 1. 1.]], shape=(2, 3), dtype=float32)
tf.Tensor(
[[1. 1. 1.]
[1. 1. 1.]], shape=(2, 3), dtype=float32)
Artık veriler aynı GPU’da olduğuna göre (hem Z
hem de Y
), onları
toplayabiliriz.
Y + Z
array([[1.6747899, 1.0754012, 1.9956977],
[1.0948886, 1.415456 , 1.1123173]], ctx=gpu(1))
Z
değişkeninizin halihazırda ikinci GPU’nuzda olduğunu hayal edin.
Gene de Z.copyto(gpu(1))
çağırırsak ne olur? Değişken istenen
cihazda zaten bulunsa bile, yeni bir kopya oluşturacak ve bellek tahsis
edecektir. Kodumuzun çalıştığı ortama bağlı olarak, aynı cihazda iki
değişkenin zaten var olduğu zamanlar vardır. Dolayısıyla, değişkenler şu
anda farklı cihazlarda bulunuyorsa yalnızca bir kopya yapmak isteriz. Bu
durumlarda, as_in_ctx
’i çağırabiliriz. Değişken zaten belirtilen
cihazda bulunuyorsa, bu işlem-yok (no-op) demektir. Özellikle bir kopya
yapmak istemediğiniz sürece, as_in_ctx
tercih edilen yöntemdir.
Z.as_in_ctx(try_gpu(1)) is Z
True
Y + Z
tensor([[1.5575, 1.9225, 1.4448],
[1.2045, 1.3821, 1.9360]], device='cuda:1')
Z
değişkeninizin halihazırda ikinci GPU’nuzda var olduğunu hayal
edin. Gene de Z.cuda(1)
diye çağırırsak ne olur? Kopyalamak ve yeni
bellek ayırmak yerine Z
’yi döndürür.
Z.cuda(1) is Z
True
Y + Z
<tf.Tensor: shape=(2, 3), dtype=float32, numpy=
array([[1.6018217, 1.2831906, 1.1208833],
[1.911641 , 1.5682545, 1.8583329]], dtype=float32)>
Z
değişkeninizin halihazırda ikinci GPU’nuzda ver olduğunu hayal
edin. Aynı cihaz kapsamı altında gene de Z2 = Z
’yi çağırırsak ne
olur? Kopyalamak ve yeni bellek ayırmak yerine Z
’yi döndürür.
with try_gpu(1):
Z2 = Z
Z2 is Z
True
5.6.2.3. Ek Notlar¶
İnsanlar hızlı olmalarını beklediklerinden makine öğrenmesi için GPU’ları kullanıyorlar. Ancak değişkenlerin cihazlar arasında aktarılması yavaştır. Bu yüzden, yapmanıza izin vermeden önce yavaş bir şey yapmak istediğinizden %100 emin olmanızı istiyoruz. Derin öğrenme çerçevesi kopyayı çökmeden otomatik olarak yaptıysa, yavaş çalışan bir kod yazdığınızı fark etmeyebilirsiniz.
Ayrıca, cihazlar (CPU, GPU’lar ve diğer makineler) arasında veri aktarımı, hesaplamadan çok daha yavaş bir şeydir. Ayrıca, daha fazla işlem ile ilerlemeden önce verilerin gönderilmesini (veya daha doğrusu alınmasını) beklememiz gerektiğinden bu paralelleştirmeyi çok daha zor hale getirir. Bu nedenle kopyalama işlemlerine büyük özen gösterilmelidir. Genel bir kural olarak, birçok küçük işlem, tek bir büyük işlemden çok daha kötüdür. Dahası, bir seferde birkaç işlem, koda serpiştirilmiş birçok tek işlemden çok daha iyidir, ne yaptığınızı biliyorsanız o ayrı. Bu durumda, bir aygıtın bir şey yapmadan önce bir diğerini beklemesi gerektiğinde bu tür işlemler onu engelleyebilir. Bu biraz, kahvenizi telefonla ön sipariş vermek ve siz istediğinizde hazır olduğunu öğrenmek yerine sırada bekleyerek sipariş etmek gibidir.
Son olarak, tensörleri yazdırdığımızda veya tensörleri NumPy formatına dönüştürdüğümüzde, veri ana bellekte değilse, çerçeve onu önce ana belleğe kopyalayacak ve bu da ek iletim yüküne neden olacaktır. Daha da kötüsü, şimdi Python’un her şeyi tamamlanmasını beklemesine neden olan o korkunç global yorumlayıcı kilidine tabidir.
5.6.3. Sinir Ağları ve GPUlar¶
Benzer şekilde, bir sinir ağı modeli cihazları belirtebilir. Aşağıdaki kod, model parametrelerini GPU’ya yerleştirir.
net = nn.Sequential()
net.add(nn.Dense(1))
net.initialize(ctx=try_gpu())
net = nn.Sequential(nn.Linear(3, 1))
net = net.to(device=try_gpu())
strategy = tf.distribute.MirroredStrategy()
with strategy.scope():
net = tf.keras.models.Sequential([
tf.keras.layers.Dense(1)])
INFO:tensorflow:Using MirroredStrategy with devices ('/job:localhost/replica:0/task:0/device:GPU:0', '/job:localhost/replica:0/task:0/device:GPU:1')
Aşağıdaki bölümlerde GPU’larda modellerin nasıl çalıştırılacağına dair daha birçok örnek göreceğiz, çünkü onlar hesaplama açısından biraz daha yoğun hale gelecekler.
Girdi, GPU’da bir tensör olduğunda, model sonucu aynı GPU’da hesaplayacaktır.
net(X)
array([[0.04995865],
[0.04995865]], ctx=gpu(0))
net(X)
tensor([[0.7531],
[0.7531]], device='cuda:0', grad_fn=<AddmmBackward0>)
net(X)
<tf.Tensor: shape=(2, 1), dtype=float32, numpy=
array([[-0.05073321],
[-0.05073321]], dtype=float32)>
Model parametrelerinin aynı GPU’da depolandığını doğrulayalım.
net[0].weight.data().ctx
gpu(0)
net[0].weight.data.device
device(type='cuda', index=0)
net.layers[0].weights[0].device, net.layers[0].weights[1].device
('/job:localhost/replica:0/task:0/device:GPU:0',
'/job:localhost/replica:0/task:0/device:GPU:0')
Kısacası tüm veriler ve parametreler aynı cihazda olduğu sürece modelleri verimli bir şekilde öğrenebiliriz. Sonraki bölümlerde bu tür birkaç örnek göreceğiz.
5.6.4. Özet¶
Depolama ve hesaplama için CPU veya GPU gibi cihazları belirleyebiliriz. Varsayılan olarak, veriler ana bellekte oluşturulur ve ardından hesaplamalar için CPU kullanılır.
Derin öğrenme çerçevesi, hesaplama için tüm girdi verilerinin aynı cihazda olmasını gerektirir, ister CPU ister aynı GPU olsun.
Verileri dikkatsizce taşıyarak önemli bir performans kaybına uğrayabilirsiniz. Tipik bir hata şudur: GPU’daki her minigrup için kaybı hesaplamak ve bunu komut satırında kullanıcıya geri bildirmek (veya bir NumPy
ndarray
’de kaydetmek), bu tüm GPU’ları durduran global yorumlayıcı kilidini tetikleyecektir. GPU içinde kayıt tutmak için bellek ayırmak ve yalnızca daha büyük kayıtları taşımak çok daha iyidir.
5.6.5. Alıştırmalar¶
Büyük matrislerin çarpımı gibi daha büyük bir hesaplama görevi deneyiniz ve CPU ile GPU arasındaki hız farkını görünüz. Az miktarda hesaplama içeren bir göreve ne olur?
GPU’daki model parametrelerini nasıl okuyup yazmalıyız?
\(100 \times 100\)’lük 1000 matris-matris çarpımını hesaplamak için gereken süreyi ölçünüz ve her seferde bir sonucun çıktı matrisinin Frobenius normunu günlüğe kaydetmeye karşılık GPU’da günlük tutma ve yalnızca son sonucu aktarmayı kıyaslayınız.
İki GPU’da iki matris-matris çarpımını aynı anda gerçekleştirme ile tek bir GPU’da sıralı gerçekleştirmenin ne kadar zaman aldığını ölçerek karşılaştırınız. İpucu: Neredeyse doğrusal bir ölçekleme görmelisiniz.