
PyTorch Tensörleri A'dan Z'ye Geliştiriciler İçin Temel Kılavuz
buraxta / April 27, 2025
Derin öğrenme yolculuğuna çıkanlar için tensörler, bu dünyanın temel yapı taşlarıdır. PyTorch kütüphanesinin kalbinde yer alan tensörler, çok boyutlu veri yapılarını temsil eder ve derin öğrenme modellerinin tüm hesaplamaları bu yapılar üzerinde gerçekleştirilir. Bu yazıda, PyTorch tensörlerinin temellerinden başlayarak ileri düzey kullanımlarına kadar kapsamlı bir inceleme sunacağız.
1. Tensörlere Giriş
Tensörler, matematiksel olarak çok boyutlu dizileri temsil eden veri yapılarıdır. Sayılar (skalerler) 0-boyutlu tensörleri, vektörler 1-boyutlu tensörleri, matrisler 2-boyutlu tensörleri oluşturur. 3 ve daha fazla boyuta sahip yapılar genellikle "tensörler" olarak adlandırılır.
1.1. Tensör Oluşturma
PyTorch'ta tensör oluşturmanın birçok yolu vardır. İşte en temel yöntemler:
import torch
# Liste kullanarak tensör oluşturma
x = torch.tensor([1, 2, 3, 4])
print(x) # tensor([1, 2, 3, 4])
# Çok boyutlu tensör oluşturma
y = torch.tensor([[1, 2, 3], [4, 5, 6]])
print(y) # tensor([[1, 2, 3],
# [4, 5, 6]])
1.2. Rastgele Tensörler
Rastgele değerlerle doldurulmuş tensörler oluşturmak, özellikle sinir ağlarının ağırlıklarını başlatırken yaygın bir uygulamadır:
# 0 ile 1 arasında rastgele değerlerle tensör oluşturma
random_tensor = torch.rand(3, 4)
print(random_tensor)
# Normal dağılımdan (Gaussian) rastgele değerlerle tensör oluşturma
normal_random_tensor = torch.randn(3, 4)
print(normal_random_tensor)
# Belirli bir aralıkta rastgele tamsayılar
random_int_tensor = torch.randint(low=0, high=10, size=(3, 4))
print(random_int_tensor)
1.3. Sıfırlar ve Birler
Sıfırlar veya birlerle dolu tensörler oluşturmak:
# Sıfırlarla dolu tensör
zeros = torch.zeros(3, 4)
print(zeros)
# Birlerle dolu tensör
ones = torch.ones(2, 3)
print(ones)
# Belirli bir değerle dolu tensör
fill_tensor = torch.full((2, 3), fill_value=5.0)
print(fill_tensor)
1.4. Aralık ve Benzer Tensörler Oluşturma
Belirli bir aralıkta değerler içeren tensörler:
# 0'dan 10'a kadar artış miktarı 1 olan tensör
range_tensor = torch.arange(0, 10, step=1)
print(range_tensor) # tensor([0, 1, 2, 3, 4, 5, 6, 7, 8, 9])
# Eşit aralıklı 5 nokta içeren tensör (0'dan 10'a kadar)
linspace_tensor = torch.linspace(0, 10, steps=5)
print(linspace_tensor) # tensor([ 0.0000, 2.5000, 5.0000, 7.5000, 10.0000])
# Logaritmik ölçekte eşit aralıklı noktalar
logspace_tensor = torch.logspace(0.1, 1.0, steps=5)
print(logspace_tensor) # tensor([ 1.2589, 1.7783, 2.5119, 3.5481, 5.0119])
1.5. Tensör Veri Tipleri
PyTorch'ta farklı veri tipleri mevcuttur:
# Varsayılan olarak float32
float_tensor = torch.tensor([1.0, 2.0, 3.0])
print(float_tensor.dtype) # torch.float32
# Veri tipini belirterek tensör oluşturma
int_tensor = torch.tensor([1, 2, 3], dtype=torch.int32)
print(int_tensor.dtype) # torch.int32
# Yaygın kullanılan veri tipleri
long_tensor = torch.tensor([1, 2, 3], dtype=torch.long) # int64
double_tensor = torch.tensor([1.0, 2.0], dtype=torch.double) # float64
bool_tensor = torch.tensor([True, False], dtype=torch.bool)
2. Tensörlerden Bilgi Alma
Tensörlerin özellikleri hakkında bilgi edinmek:
tensor = torch.rand(3, 4, 5)
# Boyut (kaç boyutlu olduğu)
print(f"Dimension: {tensor.dim()}") # 3
# Shape (her boyuttaki eleman sayısı)
print(f"Shape: {tensor.shape}") # torch.Size([3, 4, 5])
print(f"Size: {tensor.size()}") # torch.Size([3, 4, 5])
# Eleman sayısı
print(f"Total elements: {tensor.numel()}") # 60
# Depolama ayrıntıları
print(f"Storage: {tensor.storage()}")
print(f"Stride: {tensor.stride()}") # Bellek düzenini gösterir
3. Tensör İşlemleri
3.1. Temel İşlemler
PyTorch'ta temel matematiksel işlemler:
# İki tensör tanımlayalım
tensor1 = torch.tensor([1, 2, 3])
tensor2 = torch.tensor([4, 5, 6])
# Toplama
add_result = tensor1 + tensor2 # veya torch.add(tensor1, tensor2)
print(f"Toplama: {add_result}") # tensor([5, 7, 9])
# Çıkarma
sub_result = tensor2 - tensor1 # veya torch.sub(tensor2, tensor1)
print(f"Çıkarma: {sub_result}") # tensor([3, 3, 3])
# Çarpma (element-wise)
mul_result = tensor1 * tensor2 # veya torch.mul(tensor1, tensor2)
print(f"Çarpma (element-wise): {mul_result}") # tensor([4, 10, 18])
# Bölme
div_result = tensor2 / tensor1 # veya torch.div(tensor2, tensor1)
print(f"Bölme: {div_result}") # tensor([4.0000, 2.5000, 2.0000])
# Üs alma
pow_result = tensor1 ** 2 # veya torch.pow(tensor1, 2)
print(f"Üs alma: {pow_result}") # tensor([1, 4, 9])
# Yerinde işlemler (in-place operations)
tensor1.add_(5) # Sonuç tensor1'e kaydedilir, _ soneki yerinde işlem yapar
print(f"Yerinde toplama sonrası tensor1: {tensor1}") # tensor([6, 7, 8])
3.2. Matris Çarpımı
Derin öğrenmede matris çarpımı oldukça önemlidir:
# İki matris tanımlayalım
mat1 = torch.tensor([[1, 2], [3, 4]], dtype=torch.float32)
mat2 = torch.tensor([[5, 6], [7, 8]], dtype=torch.float32)
# Matris çarpımı yöntemleri
mat_mul = torch.matmul(mat1, mat2)
mm_result = torch.mm(mat1, mat2) # Sadece 2D matrisler için
bmm_result = torch.bmm(mat1.unsqueeze(0), mat2.unsqueeze(0)) # Batch matris çarpımı
print(f"Matris çarpımı: \n{mat_mul}")
# tensor([[19., 22.],
# [43., 50.]])
# @ operatörü de matris çarpımı için kullanılabilir
at_result = mat1 @ mat2
print(f"@ ile matris çarpımı: \n{at_result}")
4. Derin Öğrenmede En Yaygın Hatalardan Biri: Shape Hataları
Derin öğrenme çalışmalarında en sık karşılaşılan sorunlardan biri tensörlerin şekil (shape) uyumsuzluklarıdır. Operasyonların gerçekleştirilebilmesi için tensörlerin uyumlu boyutlara sahip olması gerekir.
# Shape hatası örneği
tensor_a = torch.rand(3, 4)
tensor_b = torch.rand(5, 6)
try:
result = torch.matmul(tensor_a, tensor_b)
except RuntimeError as e:
print(f"Hata: {e}")
# Hata: mat1 ve mat2'nin boyutları uyumsuz: 3x4 ve 5x6 ...
# Doğru kullanım
tensor_c = torch.rand(4, 5) # tensor_a'nın sütun sayısı ve tensor_c'nin satır sayısı aynı olmalı
result = torch.matmul(tensor_a, tensor_c)
print(f"Doğru matris çarpımı şekli: {result.shape}") # torch.Size([3, 5])
4.1. Min, Max, Ortalama, Toplam (Agregasyon)
Tensörlerde agregasyon işlemleri:
test_tensor = torch.tensor([[1, 2, 3], [4, 5, 6], [7, 8, 9]])
# Minimum değer
min_val = torch.min(test_tensor)
print(f"Minimum değer: {min_val}") # tensor(1)
# Maksimum değer
max_val = torch.max(test_tensor)
print(f"Maksimum değer: {max_val}") # tensor(9)
# Ortalama
mean_val = torch.mean(test_tensor.float()) # mean fonksiyonu float tipi gerektirir
print(f"Ortalama: {mean_val}") # tensor(5.)
# Toplam
sum_val = torch.sum(test_tensor)
print(f"Toplam: {sum_val}") # tensor(45)
# Boyut üzerinde agregasyon
sum_dim0 = torch.sum(test_tensor, dim=0) # Sütunların toplamları
print(f"Sütun toplamları: {sum_dim0}") # tensor([12, 15, 18])
sum_dim1 = torch.sum(test_tensor, dim=1) # Satırların toplamları
print(f"Satır toplamları: {sum_dim1}") # tensor([6, 15, 24])
4.2. Pozisyonel Min/Max
Belirli bir eksende minimum ve maksimum değerler ve bu değerlerin indeksleri:
values, indices = torch.max(test_tensor, dim=1)
print(f"Satırlardaki maksimum değerler: {values}") # tensor([3, 6, 9])
print(f"Bu değerlerin indeksleri: {indices}") # tensor([2, 2, 2])
values, indices = torch.min(test_tensor, dim=0)
print(f"Sütunlardaki minimum değerler: {values}") # tensor([1, 2, 3])
print(f"Bu değerlerin indeksleri: {indices}") # tensor([0, 0, 0])
4.3. Veri Tipini Değiştirme
Tensörün veri tipini değiştirmek:
float_tensor = torch.tensor([1.5, 2.5, 3.5])
print(f"Orijinal veri tipi: {float_tensor.dtype}") # torch.float32
# float32'den int32'ye dönüştürme
int_tensor = float_tensor.type(torch.int32) # veya float_tensor.int()
print(f"Dönüştürülmüş veri tipi: {int_tensor.dtype}") # torch.int32
print(f"Dönüştürülmüş değerler: {int_tensor}") # tensor([1, 2, 3], dtype=torch.int32)
# int32'den float64'e dönüştürme
double_tensor = int_tensor.type(torch.float64) # veya int_tensor.double()
print(f"Yeni veri tipi: {double_tensor.dtype}") # torch.float64
4.4. Yeniden Şekillendirme, İstifleme, Sıkıştırma ve Genişletme
Tensörlerin şeklini değiştirmek için kullanılan önemli operasyonlar:
# Yeniden şekillendirme (reshape)
t = torch.tensor([[1, 2, 3], [4, 5, 6]])
reshaped = t.reshape(3, 2)
print(f"Orijinal: {t}, Şekil: {t.shape}") # torch.Size([2, 3])
print(f"Yeniden şekillendirilmiş: {reshaped}, Şekil: {reshaped.shape}") # torch.Size([3, 2])
# view vs reshape: view bellek paylaşır, eğer tensör sürekli değilse reshape kopyalar
viewed = t.view(3, 2) # Orijinal tensör sürekli bellek alanında olmalı
print(f"Görünüm (view): {viewed}, Şekil: {viewed.shape}") # torch.Size([3, 2])
# İstifleme (stacking)
t1 = torch.tensor([1, 2, 3])
t2 = torch.tensor([4, 5, 6])
stacked_v = torch.stack([t1, t2], dim=0) # Dikey istifleme
print(f"Dikey istifleme: \n{stacked_v}") # Şekil: torch.Size([2, 3])
stacked_h = torch.stack([t1, t2], dim=1) # Yatay istifleme
print(f"Yatay istifleme: \n{stacked_h}") # Şekil: torch.Size([3, 2])
# Ekleme (concatenate / cat)
cat_v = torch.cat([t1.unsqueeze(0), t2.unsqueeze(0)], dim=0) # Dikey ekleme
print(f"Dikey ekleme: \n{cat_v}") # Şekil: torch.Size([2, 3])
# Sıkıştırma (squeeze) - 1 boyutlu eksenleri kaldırır
unsqueezed = torch.zeros(2, 1, 3, 1)
squeezed = unsqueezed.squeeze() # Tüm 1 boyutlu eksenleri kaldırır
print(f"Sıkıştırma: {squeezed.shape}") # torch.Size([2, 3])
squeezed_specific = unsqueezed.squeeze(1) # Sadece belirtilen ekseni sıkıştırır
print(f"Belirli eksen sıkıştırma: {squeezed_specific.shape}") # torch.Size([2, 3, 1])
# Genişletme (unsqueeze) - 1 boyutlu eksenler ekler
t3 = torch.tensor([7, 8, 9])
unsqueezed_0 = t3.unsqueeze(0) # Başa yeni boyut ekler
print(f"0. eksende genişletme: {unsqueezed_0.shape}") # torch.Size([1, 3])
unsqueezed_1 = t3.unsqueeze(1) # Ortaya yeni boyut ekler
print(f"1. eksende genişletme: {unsqueezed_1.shape}") # torch.Size([3, 1])
5. İndeksleme (Tensörlerden Veri Seçme)
PyTorch'ta tensörlerden veri seçmek, Python dizileri ve NumPy dizilerindekine benzer şekilde çalışır:
# Örnek bir tensör oluşturalım
x = torch.tensor([[1, 2, 3], [4, 5, 6], [7, 8, 9]])
# Tek bir eleman seçme
element = x[1, 2] # 2. satır, 3. sütun (0-tabanlı indeksleme)
print(f"Seçilen eleman: {element}") # tensor(6)
# Satır seçme
row = x[1] # 2. satır
print(f"Seçilen satır: {row}") # tensor([4, 5, 6])
# Sütun seçme
column = x[:, 1] # 2. sütun
print(f"Seçilen sütun: {column}") # tensor([2, 5, 8])
# Dilim (slice) kullanarak seçim
slice_tensor = x[0:2, 1:3] # İlk 2 satır, 2. ve 3. sütunlar
print(f"Dilim: \n{slice_tensor}")
# tensor([[2, 3],
# [5, 6]])
# Gelişmiş indeksleme
indices = torch.tensor([0, 2]) # 1. ve 3. satırlar
selected_rows = x[indices]
print(f"Gelişmiş indeksleme ile seçilen satırlar: \n{selected_rows}")
# tensor([[1, 2, 3],
# [7, 8, 9]])
# Maskeleme (boolean indexing)
mask = x > 5
masked_values = x[mask]
print(f"Maskeleme sonucu: {masked_values}") # tensor([6, 7, 8, 9])
# İleri düzey seçme teknikleri
fancy_index = x[torch.tensor([[0, 1], [1, 2]])]
print(f"İleri düzey indeksleme: \n{fancy_index}")
6. PyTorch Tensörleri ve NumPy
PyTorch, NumPy dizileriyle kolayca etkileşim kurabilir:
import numpy as np
# NumPy dizisinden tensör oluşturma
numpy_array = np.array([[1, 2, 3], [4, 5, 6]])
tensor_from_numpy = torch.from_numpy(numpy_array)
print(f"NumPy'dan oluşturulan tensör: \n{tensor_from_numpy}")
# Tensörden NumPy dizisi oluşturma
numpy_from_tensor = tensor_from_numpy.numpy()
print(f"Tensörden oluşturulan NumPy: \n{numpy_from_tensor}")
# ÖNEMLİ: CPU'daki NumPy dizileri ve ilgili PyTorch tensörleri belleği paylaşır!
numpy_array[0, 0] = 100
print(f"NumPy değişti: \n{numpy_array}")
print(f"Tensör de değişti: \n{tensor_from_numpy}")
# GPU'da bulunan bir tensörü NumPy'a çevirirken, önce CPU'ya taşımak gerekir
# gpu_tensor.cpu().numpy()
7. Yeniden Üretilebilirlik (Rastgeleliği Kontrol Etme)
Rastgele işlemlerde tutarlı sonuçlar elde etmek için rastgele tohum (seed) değerini sabitlemek önemlidir:
# Rastgele tohum değerini sabitleme
torch.manual_seed(42)
random_tensor1 = torch.rand(3, 3)
print(f"Rastgele tensör 1: \n{random_tensor1}")
# Aynı tohum değerini tekrar kullanmak aynı sonuçları verir
torch.manual_seed(42)
random_tensor2 = torch.rand(3, 3)
print(f"Rastgele tensör 2: \n{random_tensor2}")
# İki tensörün aynı olduğunu kontrol etme
print(f"Tensörler aynı mı? {torch.equal(random_tensor1, random_tensor2)}") # True
# Tam yeniden üretilebilirlik için CUDA'nın da tohum değerini sabitleyin
if torch.cuda.is_available():
torch.cuda.manual_seed_all(42)
8. Tensörleri GPU'da Çalıştırma (Daha Hızlı Hesaplamalar)
Derin öğrenme işlemlerini hızlandırmak için GPU kullanımı çok önemlidir. PyTorch, CUDA ve Metal gibi farklı hesaplama platformlarını destekler.
8.1. GPU Edinme
GPU'lara erişim için farklı yollar mevcuttur:
- Yerel bilgisayarda NVIDIA GPU
- Google Colab (ücretsiz GPU)
- Kaggle Notebooks (ücretsiz GPU)
- AWS, GCP, Azure gibi bulut platformları
- Apple Silicon (Metal) kullanımı
8.2. PyTorch'u GPU Üzerinde Çalıştırma
# GPU'nun mevcut olup olmadığını kontrol etme
if torch.cuda.is_available():
print(f"CUDA cihaz sayısı: {torch.cuda.device_count()}")
print(f"Şu anki CUDA cihazı: {torch.cuda.current_device()}")
print(f"Cihaz adı: {torch.cuda.get_device_name(0)}")
else:
print("GPU mevcut değil, CPU kullanılacak.")
# Cihaz atama
device = torch.device("cuda" if torch.cuda.is_available() else "cpu")
print(f"Kullanılan cihaz: {device}")
# MPS (Metal Performance Shaders) kullanılabilirliğini kontrol etme (Apple Silicon)
if hasattr(torch, 'has_mps') and torch.has_mps:
print("MPS (Metal Performance Shaders) mevcut!")
device = torch.device("mps")
else:
print("MPS mevcut değil.")
8.3. Apple Silicon için PyTorch Kurulumu
Apple M1/M2/M3 işlemcili Mac'lerde Metal Performance Shaders (MPS) ile PyTorch kullanımı:
# Conda ile kurulum
conda install pytorch torchvision -c pytorch-nightly
# Pip ile kurulum (PyTorch 2.0+)
pip install torch torchvision
Kurulumdan sonra MPS kullanımını şu şekilde test edebilirsiniz:
# MPS kullanılabilirliğini kontrol etme
if hasattr(torch, 'has_mps') and torch.has_mps:
device = torch.device("mps")
print(f"MPS cihazı kullanılıyor: {device}")
else:
device = torch.device("cpu")
print(f"MPS mevcut değil, CPU kullanılıyor: {device}")
8.4. Tensörleri (ve Modelleri) GPU'ya Taşıma
# CPU'da bir tensör oluşturalım
cpu_tensor = torch.tensor([1, 2, 3])
print(f"CPU tensörü: {cpu_tensor.device}") # cpu
# GPU'ya (veya MPS'ye) taşıma
device_tensor = cpu_tensor.to(device)
print(f"Cihaz tensörü: {device_tensor.device}")
# Alternatif olarak, kurulumunuza bağlı olarak
if torch.cuda.is_available():
cuda_tensor = cpu_tensor.cuda()
print(f"CUDA tensörü: {cuda_tensor.device}")
# Hesaplama yapma
result = device_tensor + 10 # Otomatik olarak aynı cihazda kalır
print(f"Sonuç: {result}, Cihaz: {result.device}")
8.5. Tensörleri CPU'ya Geri Taşıma
# GPU'daki tensörü CPU'ya taşıma
cpu_result = device_tensor.cpu()
print(f"CPU'ya taşınan sonuç: {cpu_result}, Cihaz: {cpu_result.device}")
# veya
cpu_result = device_tensor.to("cpu")
Performans Karşılaştırması: CPU vs GPU
GPU'nun CPU'ya göre performans avantajını gösteren basit bir örnek:
import time
# Büyük tensörler ile çalışma
size = 5000
# CPU versiyonu
start_time = time.time()
cpu_tensor1 = torch.randn(size, size)
cpu_tensor2 = torch.randn(size, size)
cpu_result = torch.matmul(cpu_tensor1, cpu_tensor2)
cpu_time = time.time() - start_time
print(f"CPU süresi: {cpu_time:.4f} saniye")
# GPU versiyonu (eğer mevcutsa)
if torch.cuda.is_available() or (hasattr(torch, 'has_mps') and torch.has_mps):
start_time = time.time()
gpu_tensor1 = torch.randn(size, size, device=device)
gpu_tensor2 = torch.randn(size, size, device=device)
gpu_result = torch.matmul(gpu_tensor1, gpu_tensor2)
# Sonucu beklemek için senkronizasyon gerekir
if torch.cuda.is_available():
torch.cuda.synchronize()
gpu_time = time.time() - start_time
print(f"GPU süresi: {gpu_time:.4f} saniye")
print(f"Hızlanma: {cpu_time / gpu_time:.2f}x")
PyTorch tensörleri, derin öğrenme uygulamalarının temelini oluşturur. Bu rehberde, tensör oluşturma, manipülasyon, indeksleme ve GPU kullanımı gibi temel konuları ele aldık. Bu bilgiler, PyTorch ile sinir ağları oluşturmaya başlamadan önce sağlam bir temel sağlayacaktır.
Tensörlerle çalışırken, özellikle karmaşık modeller geliştirirken, boyut (shape) hatalarına dikkat etmek ve tensorlerin nasıl ve nerede depolandığını (CPU veya GPU) takip etmek kritik önem taşır. PyTorch'un sunduğu esnek ve güçlü araçlarla, derin öğrenme modellerinizi oluşturmaya ve eğitmeye başlayabilirsiniz.