9-bo‘lim
Qurilma va tezlik
CPU va GPU, device-agnostik kod yozish, .to() bilan ko'chirish, oqimlar soni va float32 ning ahamiyati.
Ushbu bo‘lim mundarijasi
Shu paytgacha kod CPU da ishladi. Katta modellarda esa GPU 10-50 barobar tezlik beradi. Yaxshi xabar shundaki, PyTorch da bunga o'tish uchun kodni qayta yozish shart emas.
Qurilmani tekshirish #
import torch
print("PyTorch:", torch.__version__)
print("CUDA mavjud:", torch.cuda.is_available())
qurilma = torch.device("cuda" if torch.cuda.is_available() else "cpu")
print("tanlangan qurilma:", qurilma)
print("oqimlar soni:", torch.get_num_threads())
PyTorch: 2.14.0+cpu
CUDA mavjud: False
tanlangan qurilma: cpu
oqimlar soni: 4
Bu darslik CPU li mashinada yozilgan, shuning uchun False chiqdi.
Muhimi shundaki, kod ikkala holatda ham ishlaydi.
qurilma = torch.device("cuda" if torch.cuda.is_available() else "cpu")
model = model.to(qurilma)
Shu ikki qator kodingizni har qanday mashinada ishlaydigan qiladi. GPU
bo'lsa ishlatadi, bo'lmasa CPU da davom etadi. .cuda() ni to'g'ridan-
to'g'ri yozmang - GPU yo'q mashinada dastur yiqiladi.
Ko'chirish #
x = torch.randn(3, 3)
print("tenzor qurilmasi:", x.device)
x = x.to(qurilma)
print("ko'chirilgandan keyin:", x.device)
import torch.nn as nn
model = nn.Linear(3, 1).to(qurilma)
print("model parametri:", next(model.parameters()).device)
tenzor qurilmasi: cpu
ko'chirilgandan keyin: cpu
model parametri: cpu
| Nima | Qanday ko'chiriladi | Eslatma |
|---|---|---|
| Tenzor | x = x.to(qurilma) | Yangi tenzor qaytaradi - natijani saqlang |
| Model | model.to(qurilma) | Joyida o'zgaradi, lekin model = model.to(...) yozish xavfsiz |
| Paket | xb, yb = xb.to(q), yb.to(q) | Har paketda sikl ichida bajariladi |
Bu GPU da eng ko'p uchraydigan xato. Model GPU da, ma'lumot esa CPU da qolib ketgan bo'ladi.
O'quv siklida har bir paketni ko'chirishni unutmang:
for xb, yb in oquv_dl:
xb, yb = xb.to(qurilma), yb.to(qurilma)
...
x.to(qurilma) natijani qaytaradi, tenzorni joyida o'zgartirmaydi -
x = x.to(...) deb yozing.
GPU qachon foyda beradi #
Tezlikni o'lchash #
Taxmin qilish o'rniga o'lchang:
import time
a = torch.randn(2000, 2000)
b = torch.randn(2000, 2000)
a @ b # birinchi chaqiruv - isitish uchun
t = time.perf_counter()
for _ in range(5):
c = a @ b
print(f"2000x2000 matritsa ko'paytmasi: {(time.perf_counter()-t)/5*1000:.1f} ms")
2000x2000 matritsa ko'paytmasi: 54.8 ms
Birinchi amal har doim sekinroq: xotira ajratiladi, kutubxona ichki jadvallarni tayyorlaydi. GPU da bu farq yanada kattaroq. Shuning uchun o'lchashdan oldin bir marta «isitish» chaqiruvi qilinadi.
CPU oqimlari #
CPU da PyTorch bir nechta yadrodan foydalanadi:
for n in [1, 2, 4]:
torch.set_num_threads(n)
a @ b
t = time.perf_counter()
for _ in range(3):
c = a @ b
print(f" {n} oqim: {(time.perf_counter()-t)/3*1000:7.1f} ms")
1 oqim: 141.6 ms
2 oqim: 68.8 ms
4 oqim: 52.9 ms
1 dan 2 oqimga o'tganda tezlik deyarli ikki barobar oshdi. 2 dan 4 ga o'tganda esa foyda kamaydi - bu odatiy hol, chunki yadrolar xotira kanalini baham ko'radi.
float32 va float64 #
X = torch.randn(4096, 512)
W = torch.randn(512, 512)
for nom, dt in [("float32", torch.float32), ("float64", torch.float64)]:
xa, wa = X.to(dt), W.to(dt)
xa @ wa
t = time.perf_counter()
for _ in range(3):
xa @ wa
print(f" {nom}: {(time.perf_counter()-t)/3*1000:7.1f} ms xotira = {xa.element_size()*xa.nelement()/1048576:.1f} MB")
float32: 8.3 ms xotira = 8.0 MB
float64: 12.1 ms xotira = 16.0 MB
float64 ikki barobar xotira oldi va sekinroq ishladi - hech qanday
foyda bermasdan.
| Tur | Hajmi | Qachon |
|---|---|---|
float32 | 4 bayt | Standart - deyarli har doim shu |
float16 / bfloat16 | 2 bayt | GPU da tezlik va xotira uchun (mixed precision) |
float64 | 8 bayt | Ilmiy hisob-kitob; chuqur o'rganishda kerak emas |
float64NumPy massivining sukut turi float64. Uni to'g'ridan-to'g'ri
torch.tensor(...) ga bersangiz, tenzor ham float64 bo'ladi va
modelning float32 parametrlari bilan to'qnashadi:
RuntimeError: expected scalar type Double but found Float
Yechim - turni ochiq ko'rsatish: torch.tensor(arr, dtype=torch.float32)
yoki tensor.float().
torch.cuda.is_available()natijasini o'z mashinangizda tekshiring.deviceo'zgaruvchisini yaratib, uni chop eting.- Tenzorni
.to(qurilma)bilan ko'chiring va.deviceni tekshiring. x.to(...)natijasini saqlamasdan sinab, tenzor o'zgarmaganini ko'ring.- 8-bo'limdagi o'quv siklini device-agnostik qilib qayta yozing.
2000x2000matritsa ko'paytmasi vaqtini o'lchang.- Isitish chaqiruvisiz o'lchab, farqni ko'ring.
set_num_threadsni 1, 2 va 4 qilib, uchta natijani jadvalga yozing.float32vafloat64tezligi hamda xotirasini solishtiring.- NumPy massividan
float64tenzor yasab, modelga berib, xatoni o'qing va tuzating.
Xulosa #
torch.cuda.is_available()GPU bor-yo'qligini aytadi.- Device-agnostik kod yozing:
torch.device("cuda" if ... else "cpu"). .cuda()ni to'g'ridan-to'g'ri yozmang - GPU yo'q mashinada yiqiladi.- Tenzor uchun
x = x.to(qurilma)- natijani saqlang, u joyida o'zgarmaydi. - Model va har bir paket bir xil qurilmada bo'lishi shart.
- «Expected all tensors to be on the same device» - eng ko'p uchraydigan GPU xatosi.
- GPU ning foydasi katta modellarda ko'rinadi; kichik modelda ko'chirish xarajati yutuqni yeydi.
- Tezlikni o'lchashda birinchi «isitish» chaqiruvini hisobga olmang.
- CPU da
set_num_threadstezlikka sezilarli ta'sir qiladi. - Chuqur o'rganishda
float32standart;float64faqat xotira va vaqt yeydi.
Keyingi bo'limda o'qitilgan modelni saqlash va qaytadan yuklashni ko'ramiz.
O‘qish tarixini saqlamoqchimisiz?
Tizimga kirsangiz, tugatgan bo‘limlaringiz saqlanadi va qoldirgan joyingizdan davom etasiz.
Xatolik topdingizmi?
Imlo xatosi, ishlamaydigan kod yoki noto‘g‘ri ma‘lumotni ko‘rsangiz - bizga xabar bering. Har bir xabar administrator tomonidan ko‘rib chiqiladi.