İçeriğe geç
Educora
Üniversite22 dk37 / 42

PyTorch: tensörler

PyTorch'u kur ve temel veri tipini öğren: tensör oluşturma, dtype ve shape, reshape/view, indeksleme, yayınlama (broadcasting), @ ile matris çarpımı, GPU ve NumPy ile birlikte çalışma.

Kendini test et
Bu derste öğreneceklerin
  • PyTorch'u sanal bir ortama kurmak ve CPU ile CUDA sürümlerini ayırt etmek
  • Tensör oluşturmak, shape ve dtype özelliklerini okumak ve değiştirmek
  • Yayınlama kurallarını ve matris çarpımını uygulayıp sonucun şeklini önceden söylemek
  • Tensörleri CPU ile GPU arasında taşımak ve NumPy dizilerine dönüştürmek

NumPy dizileri sayısal hesaplamalar için harikadır ama derin öğrenme için iki eksikleri vardır: GPU üzerinde çalışmazlar ve türevleri otomatik hesaplayamazlar. PyTorch tam olarak bu iki boşluğu doldurur. Temel nesnesi olan tensör, bir NumPy dizisine çok benzer ama ekran kartında yaşayabilir ve kendi gradyanlarını takip edebilir. Bu derste tensörlerle rahatça çalışmayı öğreneceksin; bir sonraki ders otomatik türev almaya ayrılmıştır.

PyTorch nedir ve nasıl kurulur

PyTorch, Meta'nın (eski adıyla Facebook) yapay zekâ araştırma laboratuvarında geliştirilmiş açık kaynaklı bir derin öğrenme kütüphanesidir; 2022'den beri Linux Foundation bünyesindeki PyTorch Foundation tarafından yönetilir. Araştırmacılar ve şirketler onu sinir ağları kurmak, eğitmek ve kullanıma sunmak için yaygın olarak kullanır. PyTorch tarayıcıda çalışmaz; bu yüzden bu modüldeki PyTorch kodlarını kendi bilgisayarında çalıştırmalısın, çıktılar ise her örneğin altında gösterilir.

  1. 1
    Sanal ortam oluştur

    Proje klasöründe python -m venv .venv çalıştır ve ortamı etkinleştir; böylece PyTorch diğer projelerine karışmaz.

  2. 2
    CPU ya da CUDA sürümünü seç

    NVIDIA ekran kartın yoksa bu modül için CPU sürümü tamamen yeterlidir. GPU (CUDA) sürümü için tam komutu pytorch.org sitesindeki seçiciden, işletim sistemini ve CUDA sürümünü seçerek al.

  3. 3
    Kur ve kontrol et

    pip install torch komutunu çalıştır, ardından Python'da import torch yazıp sürümü yazdır.

Terminal
python -m venv .venv
# Windows: .venv\Scripts\activate    macOS/Linux: source .venv/bin/activate
pip install torch numpy
# CPU-only build (smaller download):
pip install torch --index-url https://download.pytorch.org/whl/cpu
Python
import torch

print(torch.__version__)
print(torch.cuda.is_available())
Beklenen çıktı
2.14.0+cpu
False
Sürüm numarası sende farklı olabilir. NVIDIA GPU ve CUDA sürümü kuruluysa ikinci satır True yazar.
Tanım
Tensör

Aynı türden sayılardan oluşan çok boyutlu bir dizi. Boyut sayısı (ndim) 0 ise skaler, 1 ise vektör, 2 ise matris, 3 ve fazlası ise genel bir tensördür. Her tensörün bir shape (her boyuttaki uzunluk), bir dtype (eleman türü) ve bir device (CPU ya da GPU) özelliği vardır.

VerishapeAçıklama
bir kayıp değeri()skaler, 0 boyut
tablo verisi(N, D)N örnek, D öznitelik
renkli bir görüntü(3, H, W)RGB kanalları, yükseklik, genişlik
bir görüntü yığını(N, C, H, W)PyTorch'ta görüntüler için standart düzen
bir metin yığını(N, T, E)T token, her biri E boyutlu bir vektör

Tensör oluşturmak: shape ve dtype

Python
import torch

a = torch.tensor([[1, 2, 3], [4, 5, 6]])
print(a)
print(a.shape, a.ndim, a.dtype)
print(torch.tensor([1.5, 2.0]).dtype)
print(torch.zeros(2, 3))
print(torch.arange(0, 10, 3))
torch.manual_seed(42)
print(torch.rand(2, 2))
print(a.float().dtype, a.to(torch.float16).dtype)
Beklenen çıktı
tensor([[1, 2, 3],
        [4, 5, 6]])
torch.Size([2, 3]) 2 torch.int64
torch.float32
tensor([[0., 0., 0.],
        [0., 0., 0.]])
tensor([0, 3, 6, 9])
tensor([[0.8823, 0.9150],
        [0.3829, 0.9593]])
torch.float32 torch.float16
  • torch.tensor(...) türü kendisi belirler: tam sayılar → int64, ondalıklı sayılar → float32. NumPy'da ise ondalıklı sayılar için varsayılan float64'tür!
  • torch.zeros, torch.ones, torch.arange ve torch.linspace hazır tensörler, torch.rand (0 ile 1 arasında düzgün dağılım) ve torch.randn (standart normal dağılım) ise rastgele tensörler oluşturur.
  • torch.manual_seed(42) rastgele sayı üretecini sabitler; böylece sonuçlar tekrarlanabilir olur.
  • .float(), .long() ya da .to(torch.float16) türü değiştirir ve yeni bir tensör döndürür.
dtypeBaytTipik kullanım
torch.float324ağırlıklar, girdiler, kayıplar; varsayılan tür
torch.float16 / torch.bfloat162GPU'da karma hassasiyetli (mixed precision) hızlı eğitim
torch.int648sınıf etiketleri, indeksler, token numaraları
torch.bool1maskeler (örneğin x > 0)
numel = d₁ · d₂ · … · dₖ memory = numel · s
burada:
  • d₁ … dₖshape'teki boyutlar
  • numeleleman sayısı (x.numel())
  • sbir elemanın bayt cinsinden boyutu (x.element_size())
Örnek 1: bir görüntü yığını bellekte ne kadar yer kaplar?

224 × 224 boyutunda 64 renkli görüntüden oluşan bir yığın float32 olarak saklanıyor. Tensörün şekli nedir ve kaç bayt kaplar? float16 olsaydı ne olurdu?

Çözümü göster
Şekil: (64, 3, 224, 224).
numel = 64 · 3 · 224 · 224 = 9.633.792.
Bellek = 9.633.792 · 4 = 38.535.168 bayt ≈ 38,5 MB.
float16'da her eleman 2 bayt olduğundan bellek yarıya iner: ≈ 19,3 MB. Karma hassasiyetin GPU belleğinden tasarruf etmesinin nedeni tam olarak budur.

Yeniden şekillendirme ve indeksleme

Python
import torch

m = torch.arange(12).reshape(3, 4)
print(m)
print(m[0], m[:, 1])
print(m[1, 2].item())
print(m[m > 8])
v = m.view(2, 6)
print(v.shape, m.T.shape)
print(m.unsqueeze(0).shape, m.flatten().shape)
v[0, 0] = 100
print(m[0, 0])
Beklenen çıktı
tensor([[ 0,  1,  2,  3],
        [ 4,  5,  6,  7],
        [ 8,  9, 10, 11]])
tensor([0, 1, 2, 3]) tensor([1, 5, 9])
6
tensor([ 9, 10, 11])
torch.Size([2, 6]) torch.Size([4, 3])
torch.Size([1, 3, 4]) torch.Size([12])
tensor(100)
  • İndeksleme NumPy'daki gibidir: m[0] ilk satır, m[:, 1] ikinci sütun, m[m > 8] maskeyle seçimdir. .item(), tek elemanlı bir tensörü sıradan bir Python sayısına çevirir.
  • reshape(2, 6) ve view(2, 6), eleman sayısını değiştirmeden şekli değiştirir; bir boyut yerine -1 yazarsan PyTorch onu kendisi hesaplar: x.view(-1, 784).
  • view veriyi kopyalamaz, aynı belleğe başka bir “pencereden” bakar. Bu yüzden v[0, 0] = 100 işlemi m'yi de değiştirdi!
  • unsqueeze(0) 1 boyutlu yeni bir eksen ekler (örneğin tek bir görüntüyü yığına çevirmek için), squeeze() bu tür eksenleri siler, .T matrisin devriğini alır, permute ise eksenleri istediğin sırayla yeniden düzenler.

İşlemler: yayınlama ve matris çarpımı

+, -, *, /, ** operatörleri eleman bazında çalışır. sum, mean, max gibi indirgemeler dim ile verilen eksen boyunca hesaplanır: a.mean(dim=0) her sütunun ortalamasıdır. Şekilleri farklı tensörler yayınlama (broadcasting) kurallarıyla eşleştirilir:

  1. Şekiller sağdan sola karşılaştırılır; kısa olan şeklin soluna 1 boyutlu eksenler eklenmiş sayılır.
  2. İki boyut eşitse ya da biri 1 ise uyumludur.
  3. 1 boyutlu eksen, diğerinin uzunluğuna kadar “gerilir” (veri kopyalanmadan).
Python
import torch

a = torch.tensor([[1., 2.], [3., 4.]])
b = torch.tensor([10., 20.])
print(a + b)
print(a * a)
print(a @ a)
print(a.sum(), a.mean(dim=0))
X = torch.ones(64, 3)
W = torch.ones(3, 5)
print((X @ W).shape)
print((torch.ones(4, 1) + torch.ones(3)).shape)
Beklenen çıktı
tensor([[11., 22.],
        [13., 24.]])
tensor([[ 1.,  4.],
        [ 9., 16.]])
tensor([[ 7., 10.],
        [15., 22.]])
tensor(10.) tensor([2., 3.])
torch.Size([64, 5])
torch.Size([4, 3])
C = A @ B, Cᵢⱼ = ∑ₖ Aᵢₖ · Bₖⱼ, (m × n) @ (n × p) → (m × p)
burada:
  • A, Bboyutları m × n ve n × p olan matrisler
  • niç boyut; iki matriste de aynı olmalıdır
  • CᵢⱼA'nın i. satırı ile B'nin j. sütununun iç çarpımı

Matris çarpımı sinir ağlarının temel işlemidir: (N, D) boyutlu girdileri (D, K) boyutlu ağırlık matrisiyle çarparak tüm yığını tek seferde işleriz. Daha çok eksenli tensörlerde @ son iki eksene uygulanır, diğer eksenler yığın ekseni sayılır.

Örnek 2: sonucun şeklini önceden söyle

Her işlemin sonucunun şeklini bul ya da hata olacağını belirt: a) (64, 3) @ (3, 5); b) (4, 1) + (3,); c) (32, 10) + (10,); d) (2, 3) @ (2, 3); e) (8, 1, 6) + (7, 1).

Çözümü göster
a) İç boyutlar 3 = 3 “sadeleşir”: (64, 5).
b) (3,) → (1, 3); 4 ile 1 ve 1 ile 3 uyumludur: (4, 3).
c) (10,) → (1, 10) olur ve her satıra eklenir (sapma vektörü böyle çalışır): (32, 10).
d) İç boyutlar 3 ≠ 2: hata. Gereken A @ B.T idi: (2, 2).
e) (7, 1) → (1, 7, 1); eksen eksen: 8 ve 1 → 8, 1 ve 7 → 7, 6 ve 1 → 6: (8, 7, 6).

GPU ve NumPy ile çalışmak

Bir ekran kartında matris çarpımlarını paralel hesaplayan binlerce basit çekirdek vardır; büyük modelleri GPU'da eğitmek çoğu zaman CPU'ya göre kat kat, hatta onlarca kat daha hızlıdır. Standart yöntem: betiğin başında bir device seçmek, sonra modeli ve veriyi .to(device) ile oraya taşımak. Apple Silicon bilgisayarlarda GPU cihazının adı 'mps''tir.

Python
import numpy as np
import torch

device = 'cuda' if torch.cuda.is_available() else 'cpu'
x = torch.ones(2, 2, device=device)
print(device, x.device)
arr = np.array([1.0, 2.0, 3.0])
t = torch.from_numpy(arr)
arr[0] = 99
print(t)
back = (t * 2).numpy()
print(back, type(back).__name__)
Beklenen çıktı
cpu cpu
tensor([99.,  2.,  3.], dtype=torch.float64)
[198.   4.   6.] ndarray
GPU'su olmayan bir bilgisayarda çıktı böyledir; CUDA varsa ilk satır cuda cuda:0 olur.

torch.from_numpy(arr) dizinin belleğini paylaşır: arr[0] = 99 değişikliği tensörde de göründü. dtype'ın float64 kaldığına dikkat et; eğitimden önce .float() ile float32'ye çevir. Ters yönde .numpy() yalnızca CPU'daki tensörlerde çalışır: GPU'daki bir tensörü önce .cpu() ile geri getir, gradyan takip ediliyorsa önce .detach() çağır: t.detach().cpu().numpy().

Önemli noktalar

  • Tensör; shape, dtype ve device özellikleri olan çok boyutlu bir dizidir; PyTorch görüntüleri (N, C, H, W) şeklinde saklar.
  • Ondalıklı sayılar için varsayılan tür float32, etiketler ve indeksler için int64'tür.
  • view belleği paylaşır ve bitişik bellek ister; emin değilsen reshape kullan.
  • Yayınlama şekilleri sağdan karşılaştırır: boyutlar eşit olmalı ya da biri 1 olmalıdır. @ matris çarpımıdır: (m × n) @ (n × p) → (m × p).
  • Model ve veri .to(device) ile aynı cihaza taşınır; from_numpy ve .numpy() belleği paylaşır.

Kendini test et

10 soru. Her doğru cevap XP kazandırır.

1 / 10
torch.tensor([1.5, 2.0]).dtype nedir?