Pytorch Chapter 1.2
Bir önceki yazımda (bknz: Pytorch Chaper 1.1) tensorler konusuna giriş yapıp, Pytorch metodlarını kullanarak manuel ve random tensorler yaratmıştık. Bugünkü yazımda ise tensorler konusuna devam ederek Pytorch temellerini atmaya devam edeceğiz. Hazırsanız başlayalım!
Range of Tensors and Tensors-like
Bazen manuel veriseti oluşturmak veya verisetlerini manipüle etmek için kendi tensorlerimizi yaratmak isteyebiliriz. Bu tensorleri yaratırken başlangıç, bitiş, adım sayısı gibi parametrelerle istediğimiz aralıkta istediğimiz uzunlukta olmasını ayarlamak isteyebiliriz. Bu nedenle PyTorch bize torch.arange() methodunu sunmaktadır.
Şimdi 1'den başlayıp 10 kadar giden bir tensor oluşturalım
one_to_ten = torch.arange(start = 0 , end = 1000 , step = 11)
Bazen ise başka bir tensore benzeyen (tensor-like) bir tensor yaratmak isteyebiliriz. Yani başka bir tensor ile aynı shape’e sahip bir tensör oluşturmaktan bahsediyorum. Bunun için aşağıdaki örnek koda göz atabiliriz. ‘zeros_like()’
# Creating tensors like
ten_zeros = torch.zeros_like(input=one_to_ten)
ten_zeros
Bu örnekte 0'lardan oluşan bir tensor oluşturuyoruz. zeros_like methodunun içine bir başka tensor’ü input olarak vererek onun shape’ine sahip 0 larden oluşan bir tensor oluşturmuş oluyoruz.
Bu konuyla ilgili daha fazla pratik yapmak isterseniz farklı shape’lerde tensorler yaratıp ‘zeros_like’ ve ‘ones_like’ methodlarını kullanarak yeni tensorler yaratabilirsiniz.
Tensor Datatypes
PyTorch framework’ünde hem CPU hem de GPU için özel birden fazla farklı data tipi vardır. PyTorch’un resmi dökümanını inceleyerek bu tipleri inceleyebilirsiniz. En yaygın kullanılan tipler genelde torch.float32 ve torch.float oluyor. Bunların dışında torch.float16, torch.float64 gibi farklı uzunluklar için farklı veri tipleri de bulunmaktadır. Kesinlik değeri ne kadar yüksek olursa (8, 16, 32), bir sayıyı ifade etmek için o kadar fazla ayrıntı ve dolayısıyla veri kullanılır. Derin öğrenmede çok fazla tensör operasyonları yapıldığı için veri tipleri oldukça önem arz etmektedir, çünkü daha fazla ayrıntı -> daha fazla işlem -> daha fazla hesaplama gücü şeklinde zinvir bir reaksiyon başlatır. Bu nedenle, daha düşük hassasiyetli veri türlerinin hesaplanması genellikle daha hızlıdır ancak doğruluk gibi değerlendirme ölçümlerindeki performansın bir kısmından ödün verir (hesaplaması daha hızlı ancak daha az doğru).
Hadi şimdi farklı veri tiplerinde tensörler oluşturarak bu konuyu pekiştirelim!
float_32_tensor = torch.tensor([3.0, 6.0, 9.0],
dtype=None,
device=None,
requires_grad=False)
Daha önce görmediğimiz biçimde bir tensor oluşturduğumuzu fark etmişsinizdir. torch.tensor() methoduna verdiğimiz veri dışındaki anahtar kelimeler ilerleyen bölümlerde daha ayrıntılı açıklanacaktır fakat şimdiden giriş niteliğinde bilgi verebiliriz.
dtype -> Oluşturulacak verinin veri tipinin belirlenmesinde kullanılır.
device -> Oluşturulacak verinin hangi donanımda oluşturulacağını belirlemek için kullanılır. (gpu veya cpu)
requires_grad -> True olması tensor operasyonların kaydedilmesini sağlar.
print(float_32_tensor.shape, float_32_tensor.dtype, float_32_tensor.device)
Oluşturduğumuz tensorün shape’ine, veri tipine ve hangi donanımda olduğu bilgisine yukarıdaki gibi ulaşabiliriz. Şimdi bu tensor’ü float16'ya dönüştürmeye çalışalım. Çünkü veri boyunu küçülterek daha hızlı operasyon yapmak isteyebiliriz.
float_16_tensor = float_32_tensor.type(torch.float16)
float_16_tensor.dtype
Manipulating Tensors
Oluşturduğumuz tensorler üzerinde farklı matematiksel operasyonlar yaparak manipüle etmek isteyebiliriz. Bu başlıkta inceleyeceğimiz operasyonlar şu şekilde olacaktır;
- Addition
- Substraction
- Multiplication (element-wise)
- Division
- Matrix Multiplication
Addition
tensor = torch.tensor([1,2,3])
tensor + 10
Substraction
tensor = torch.tensor([1,2,3])
tensor - 10
Multiplication (element-wise)
tensor = torch.tensor([1,2,3])
tensor * 10
Multiplication ve Addition işlemleri için “*” veya “+” gibi semboller kullanmak yerine PyTorch’un built-in fonksiyonları da kullanilabilir.
torch.mul(tensor, 10) # Multiplication
torch.add(tensor, 10) # Addition
Matrix Multiplication
print(tensor, "*" ,tensor)
print(f"Equals: {tensor * tensor}")
Matrix çarpımını anlayabilmek için önce yukarıdaki örneği daha iyi anlayabilmek gerekir. Element-wise bir çarpma işlemi yaptığımızda çıkan sonucu ilgili görselde görebilirsiniz. Peki bu iki tensorü matrix çarpımı ile çarpsak ne sonuç elde ederdik? Tahmin etmek için aşağıdaki görselde yer alan işlemi inceleyebiliriz. Bu arada Matrix çarpımının bir diğer ismi “dot product” olarak da geçer.
Yukarıdaki örneği göz önünde bulundurduğumuzda [1,2,3] elemanlarından oluşan bir tensörü kendisiyle matrix çarpımı yaptığımızda elde edeceğimiz sonucun 14 olduğunu kestirebiliriz. PyTorch’ta bu işlemi “torch.matmul()” metoduyla gerçekleştirebiliriz.
torch.matmul(tensor,tensor)
Matrix çarpımı yapmak için uyulması gereken bazı kurallar vardır. Her matrix bu işlemi yapmak için uyumlu olmayabilir. Derin Öğrenme modeli kurarken karşılaşan en büyük problemlerden biri de bu kuraldan dolayı ortaya çıkar. İki matrix’in shape’lerinin belirli kurala uyması gerekir. Bu kural şu şekildedir;
The inner dimensions must match
Bu kuralları özellikle orijinal dilinde bırakmak istedim ki Türkçe çevirilerinde bir anlam kaymasına uğramasın. Peki ne demek bu “inner dimension”larının uygun olması aşağıdaki örneklerden anlayabiliriz.
- (2,3) @ (3,2)
- (3,2) @ (2,3)
- (6,4) @ (4,6)
Bu örneklerde matrix shape’lerini görüyoruz. İlk örnek 2x3 ve 3x2 boyutunda iki matrixin çarpımını temsil ediyor. Görüldüğü üzere iç kısımdaki boyutlar birbirleriyle eşleşiyor! (3–3)
- (3,2) @ (3,2)
Peki bu iki matrix bu kurala uyuyor mu? Hayır! Dolayısıyla bu işlemden hata alınacaktır.
Şimdi (3,2) shape’e sahip 2 matrix oluşturarak matrix çarpımı yaptırmayı PyTorch ile deneyelim. Gerçekten hata alıp alamayacağımızı kod üzerinden tespit edelim. “torch.rand()” metodundan bir önceki yazımda bahsetmiştim.
torch.matmul(torch.rand(3,2), torch.rand(3,2))
Görüldüğü üzere shape hatası aldığımız için bu işlemi gerçekleştiremedik. Peki bunu düzeltmeyi denesek?
torch.matmul(torch.rand(3,2), torch.rand(2,3))
Bu sefer sonuç elde edebildik. Bunun sebebi daha önce bahsettiğimiz “inner dimension” kuralıdır. (3,2) ve (2,3) shape’lerine sahip 2 matrix’in inner dimension’ları birbirleri ile eşleştiği için bu işlemi gerçekleştirebildik. Şimdi bunu kendi oluşturduğumuz manual tensor’ler üzerinden test edelim.
# Shapes for matrix multiplication
tensor_A = torch.tensor([[1,2],
[3,4],
[5,6]])
tensor_B = torch.tensor([[7,8,9],
[10,11,12]])
result = torch.mm(tensor_A, tensor_B) # torch.mm is the same as torch.matmul()
print(f"Tensor A Shape: {tensor_A.shape} @ Tensor B Shape: {tensor_B.shape} \n {result}")
Bu işlem sonucunu anlayamadıysak aşağıdaki görseldeki formül incelenebilir.
Ve bu konuyla beraber yazımızın sonuna gelmiş bulunmaktayız. Bir önceki yazımda da belirttiğim gibi takip ettiğim eğitim serisinden bu notları çıkarmaktayım. Eğitim serisine bu linkten ulaşabilirsiniz -> https://www.learnpytorch.io/00_pytorch_fundamentals/
Bir sonraki yazıda görüşmek üzere!