Python ve PyTorch Eğitimi

Temel Python kavramlarından PyTorch ile derin öğrenmeye

Python Temelleri

Python Veri Yapıları (Containerlar)

Listeler (Lists)

Listeler, Python'da en çok kullanılan veri yapılarından biridir. Değiştirilebilir, sıralı ve farklı veri tiplerini içerebilen koleksiyonlardır.

# Liste tanımlama
meyveler = ['elma', 'armut', 'muz', 'çilek']
karışık_liste = [1, 'python', 3.14, True]

# Liste elemanlarına erişim
print(meyveler[0]) # 'elma'
print(meyveler[-1]) # 'çilek' - son eleman

# Liste dilimleme (slicing)
print(meyveler[1:3]) # ['armut', 'muz']

# Liste metodları
meyveler.append('kivi') # Listeye eleman ekleme
meyveler.remove('armut') # Listeden eleman çıkarma
meyveler.sort() # Listeyi sıralama

Sözlükler (Dictionaries)

Sözlükler, anahtar-değer çiftlerini saklayan koleksiyonlardır. Anahtarlar benzersiz olmalıdır.

# Sözlük tanımlama
öğrenci = {
    'ad': 'Ahmet',
    'yaş': 20,
    'dersler': ['Matematik', 'Fizik', 'Programlama']
}

# Sözlük elemanlarına erişim
print(öğrenci['ad']) # 'Ahmet'
print(öğrenci.get('yaş')) # 20

# Sözlük metodları
print(öğrenci.keys()) # Tüm anahtarları listele
print(öğrenci.values()) # Tüm değerleri listele
öğrenci['bölüm'] = 'Bilgisayar Mühendisliği' # Yeni anahtar-değer ekleme

Demetler (Tuples)

Demetler, liste benzeri ancak değiştirilemeyen (immutable) koleksiyonlardır.

# Demet tanımlama
koordinat = (10, 20)
RGB = (255, 0, 0) # Kırmızı renk

# Demet elemanlarına erişim
print(koordinat[0]) # 10

# Demetler değiştirilemez
# koordinat[0] = 15 # Bu hata verir!

Kümeler (Sets)

Kümeler, sırasız ve benzersiz elemanlar içeren koleksiyonlardır.

# Küme tanımlama
meyveler = {'elma', 'armut', 'muz', 'elma'} # Tekrar eden 'elma' bir kez sayılır
print(meyveler) # {'elma', 'armut', 'muz'}

# Küme işlemleri
A = {1, 2, 3, 4}
B = {3, 4, 5, 6}
print(A | B) # Birleşim: {1, 2, 3, 4, 5, 6}
print(A & B) # Kesişim: {3, 4}
print(A - B) # Fark: {1, 2}
Döngüler, İteratorlar ve Generator'lar

For Döngüsü

Python'da for döngüsü, bir koleksiyon üzerinde yineleme yapmak için kullanılır.

# Liste üzerinde for döngüsü
meyveler = ['elma', 'armut', 'muz']
for meyve in meyveler:
    print(meyve)

# range() ile for döngüsü
for i in range(5):
    print(i) # 0, 1, 2, 3, 4

# enumerate() ile for döngüsü - indeks ve değer alma
for i, meyve in enumerate(meyveler):
    print(f"{i}. indeks: {meyve}")

While Döngüsü

While döngüsü, belirli bir koşul doğru olduğu sürece çalışır.

sayac = 0
while sayac < 5:
    print(sayac)
    sayac += 1 # Sayacı artır, aksi halde sonsuz döngü oluşur

İteratorlar

İteratorlar, bir koleksiyonun elemanlarını tek tek elde etmeyi sağlayan nesnelerdir.

# Iterator oluşturma
meyveler = ['elma', 'armut', 'muz']
iter_meyveler = iter(meyveler)

# next() ile tek tek elemanlara erişim
print(next(iter_meyveler)) # 'elma'
print(next(iter_meyveler)) # 'armut'
print(next(iter_meyveler)) # 'muz'
# print(next(iter_meyveler)) # StopIteration hatası!

Generator'lar

Generator'lar, büyük veri kümeleri için bellek verimli şekilde çalışan özel bir iterator türüdür.

# Generator fonksiyonu tanımlama
def sayı_üret(n):
    for i in range(n):
        yield i * i # yield ile değer döndürme

# Generator kullanımı
for sayı in sayı_üret(5):
    print(sayı) # 0, 1, 4, 9, 16

# Generator ifadesi (expression)
kareler = (x**2 for x in range(5))
print(list(kareler)) # [0, 1, 4, 9, 16]
Fonksiyonlar

Fonksiyon Tanımlama ve Çağırma

Fonksiyonlar, tekrar kullanılabilir kod blokları oluşturmanızı sağlar.

# Basit fonksiyon tanımlama
def selamla(isim):
    return f"Merhaba, {isim}!"

# Fonksiyon çağırma
mesaj = selamla("Ahmet")
print(mesaj) # "Merhaba, Ahmet!"

Parametreler ve Argümanlar

# Varsayılan parametre değerleri
def güç_hesapla(taban, üs=2):
    return taban ** üs

print(güç_hesapla(3)) # 9 (3^2)
print(güç_hesapla(3, 3)) # 27 (3^3)

# İsimlendirilerek argüman geçme
print(güç_hesapla(üs=3, taban=2)) # 8 (2^3)

*args ve **kwargs

*args değişken sayıda konumsal argümanı, **kwargs ise değişken sayıda anahtar-değer argümanını kabul eder.

def örnek_fonksiyon(*args, **kwargs):
    print("Konumsal argümanlar:", args)
    print("Anahtar-değer argümanları:", kwargs)

örnek_fonksiyon(1, 2, 3, ad="Ahmet", yaş=25)
# Çıktı:
# Konumsal argümanlar: (1, 2, 3)
# Anahtar-değer argümanları: {'ad': 'Ahmet', 'yaş': 25}

Lambda Fonksiyonları

Lambda fonksiyonları, tek satırda tanımlanabilen isimsiz fonksiyonlardır.

# Lambda fonksiyonu
kare_al = lambda x: x * x
print(kare_al(5)) # 25

# Sıralama işleminde lambda kullanımı
öğrenciler = [
    {'ad': 'Ali', 'not': 85},
    {'ad': 'Ayşe', 'not': 92},
    {'ad': 'Mehmet', 'not': 78}
]

sıralı_öğrenciler = sorted(öğrenciler, key=lambda x: x['not'], reverse=True)
print(sıralı_öğrenciler) # Nota göre azalan sırada
Sınıflar ve Nesne Yönelimli Programlama

Sınıf Tanımlama

Sınıflar, veri ve davranışı bir arada tutan yapılardır.

class Araba:
    # Constructor (yapıcı metod)
    def __init__(self, marka, model, yıl):
        self.marka = marka
        self.model = model
        self.yıl = yıl
        self.km = 0

    # Instance metodu
    def bilgi_göster(self):
        return f"{self.yıl} {self.marka} {self.model}, {self.km} km"

    def sür(self, mesafe):
        self.km += mesafe

# Nesne oluşturma ve kullanma
araba1 = Araba("Toyota", "Corolla", 2020)
araba1.sür(150)
print(araba1.bilgi_göster()) # "2020 Toyota Corolla, 150 km"

Kalıtım (Inheritance)

Kalıtım, bir sınıfın başka bir sınıftan özellik ve davranış miras almasını sağlar.

# Temel sınıf
class Shape:
    def __init__(self, color="black"):
        self.color = color

    def get_area(self):
        pass # Soyut metod, alt sınıflar tarafından uygulanacak

    def get_color(self):
        return self.color

# Alt sınıf (Circle)
class Circle(Shape):
    def __init__(self, radius, color="red"):
        super().__init__(color) # Üst sınıfın constructor'ını çağırma
        self.radius = radius

    def get_area(self):
        import math
        return math.pi * self.radius ** 2

# Alt sınıfları kullanma
daire = Circle(5)
print(f"Dairenin rengi: {daire.get_color()}") # "Dairenin rengi: red"
print(f"Dairenin alanı: {daire.get_area():.2f}") # "Dairenin alanı: 78.54"

Özel Metodlar (Magic Methods)

Python sınıflarında, özel davranışlar tanımlamak için "__" ile başlayan ve biten metotlar kullanılır.

class Nokta:
    def __init__(self, x, y):
        self.x = x
        self.y = y

    def __str__(self):
        return f"Nokta({self.x}, {self.y})"

    def __add__(self, other):
        return Nokta(self.x + other.x, self.y + other.y)

p1 = Nokta(1, 2)
p2 = Nokta(3, 4)
p3 = p1 + p2 # __add__ metodu çağrılır
print(p3) # __str__ metodu çağrılır - "Nokta(4, 6)"
Dosya İşlemleri

Metin Dosyası Okuma ve Yazma

# Dosya yazma
with open('ornek.txt', 'w', encoding='utf-8') as f:
    f.write("Merhaba, Dünya!\n")
    f.write("Python öğreniyorum.")

# Dosya okuma
with open('ornek.txt', 'r', encoding='utf-8') as f:
    içerik = f.read()
    print(içerik)

# Satır satır okuma
with open('ornek.txt', 'r', encoding='utf-8') as f:
    for satır in f:
        print(satır.strip())

JSON Dosyası İşlemleri

import json

# Python nesnesinden JSON'a dönüştürme ve dosyaya yazma
veri = {
    'ad': 'Ahmet',
    'yaş': 25,
    'dersler': ['Python', 'Veri Bilimi', 'Makine Öğrenimi']
}

with open('veri.json', 'w', encoding='utf-8') as f:
    json.dump(veri, f, ensure_ascii=False, indent=4)

# JSON dosyasını okuma ve Python nesnesine dönüştürme
with open('veri.json', 'r', encoding='utf-8') as f:
    okunan_veri = json.load(f)

print(okunan_veri['ad']) # 'Ahmet'

CSV Dosyası İşlemleri

import csv

# CSV dosyası yazma
öğrenciler = [
    ['Ad', 'Soyad', 'Not'],
    ['Ali', 'Yılmaz', 85],
    ['Ayşe', 'Demir', 92],
    ['Mehmet', 'Kaya', 78]
]

with open('öğrenciler.csv', 'w', newline='', encoding='utf-8') as f:
    writer = csv.writer(f)
    writer.writerows(öğrenciler)

# CSV dosyası okuma
with open('öğrenciler.csv', 'r', encoding='utf-8') as f:
    reader = csv.reader(f)
    for satır in reader:
        print(satır)

PyTorch Temelleri

Dataset ve DataLoader

PyTorch Dataset Nedir?

Dataset, veri kümesini temsil eden ve veri erişimi sağlayan bir soyut sınıftır. PyTorch'ta özel veri kümeleri için torch.utils.data.Dataset sınıfından türetilir.

import torch
from torch.utils.data import Dataset

class CümleDataset(Dataset):
    def __init__(self, cümleler):
        self.cümleler = cümleler

    def __len__(self):
        return len(self.cümleler)

    def __getitem__(self, idx):
        cümle = self.cümleler[idx]
        return cümle

# Örnek veri kümesi oluşturma
cümleler = [
    "PyTorch ile derin öğrenme çok keyifli.",
    "Python programlama dili çok pratik.",
    "Yapay zeka geleceğin teknolojisi.",
    "Veri bilimi birçok alanda kullanılıyor."
]

dataset = CümleDataset(cümleler)
print(len(dataset)) # 4
print(dataset[0]) # "PyTorch ile derin öğrenme çok keyifli."

DataLoader Nedir?

DataLoader, Dataset'ten verileri batch'ler halinde yükleyen bir yardımcı sınıftır. Ayrıca veri karıştırma, paralel yükleme gibi özellikleri de sağlar.

from torch.utils.data import DataLoader

# DataLoader oluşturma (batch_size=2)
dataloader = DataLoader(dataset, batch_size=2, shuffle=True)

# Batch'leri yazdırma
for i, batch in enumerate(dataloader):
    print(f"Batch {i+1}:")
    for cümle in batch:
        print(f" - {cümle}")

Custom Collate Function

Collate fonksiyonu, batch içindeki verilerin nasıl birleştirileceğini özelleştirmenizi sağlar.

def custom_collate_fn(batch):
    # Her cümlenin ilk 10 karakterini al
    kısa_cümleler = [cümle[:10] + "..." for cümle in batch]
    return kısa_cümleler

# Özel collate fonksiyonu ile DataLoader oluşturma
custom_dataloader = DataLoader(
    dataset,
    batch_size=2,
    shuffle=True,
    collate_fn=custom_collate_fn
)

# Özel formatlı batch'leri yazdırma
print("\nÖzel Collate Function ile:")
for i, batch in enumerate(custom_dataloader):
    print(f"Batch {i+1}:")
    for kısa_cümle in batch:
        print(f" - {kısa_cümle}")
PyTorch ile Sinir Ağları

Yapay Sinir Ağı (ANN) Sınıfı Oluşturma

PyTorch'ta sinir ağları torch.nn.Module sınıfından türetilir.

import torch
import torch.nn as nn
import torch.nn.functional as F

class SimpleANN(nn.Module):
    def __init__(self, input_size, hidden_size, output_size):
        super(SimpleANN, self).__init__()
        # Katmanları tanımlama
        self.fc1 = nn.Linear(input_size, hidden_size)
        self.fc2 = nn.Linear(hidden_size, output_size)

    def forward(self, x):
        # İleri yayılım (forward propagation)
        x = F.relu(self.fc1(x)) # İlk katmandan çıkışı ReLU aktivasyonu uygula
        x = self.fc2(x) # Çıkış katmanı
        return x

# Örnek sinir ağı kullanımı
input_size = 10 # Giriş boyutu
hidden_size = 20 # Gizli katman boyutu
output_size = 2 # Çıkış boyutu

model = SimpleANN(input_size, hidden_size, output_size)
print(model)

# Örnek bir girdi ile forward işlemi
dummy_input = torch.randn(1, input_size)
output = model(dummy_input)
print(f"Çıktı boyutu: {output.shape}")

Forward Fonksiyonu ve Çalışma Mantığı

Forward fonksiyonu, sinir ağının ileri yayılım işlemini tanımlar. Veriler ağ üzerinden geçirilirken nasıl işleneceğini belirler.

Not: forward() fonksiyonu, module(input) şeklinde çağrı yapıldığında otomatik olarak çağrılır. Yani model(x) çağrısı, aslında model.forward(x) çağrısıdır.

Forward fonksiyonunun çalışma adımları:

  1. Girdi verileri ilk katmana verilir: self.fc1(x)
  2. Doğrusal dönüşüm sonucuna aktivasyon fonksiyonu uygulanır: F.relu(...)
  3. Ara katman çıktısı bir sonraki katmana iletilir
  4. Son katmandan çıkan sonuç döndürülür

PyTorch'un otomatik diferansiyel özelliği sayesinde, forward işlemi sırasında hesaplama grafiği oluşturulur ve backpropagation (geri yayılım) için kullanılır.

PyTorch Module Sınıfı ve Kalıtım

PyTorch'ta tüm sinir ağı modellerimiz nn.Module sınıfından türetilir. Bu kalıtım sayesinde:

  • Modelleri iç içe kullanabilme
  • Ağırlıkları otomatik takip edebilme
  • GPU'ya taşıma ve model kaydetme gibi işlemleri kolayca yapabilme
  • Diğer faydalı metodlara erişim
# Daha karmaşık bir model örneği
class ComplexNN(nn.Module):
    def __init__(self):
        super().__init__()
        # Alt modüller tanımlama
        self.feature_extractor = nn.Sequential(
            nn.Linear(784, 256),
            nn.ReLU(),
            nn.Linear(256, 64),
            nn.ReLU()
        )
        self.classifier = nn.Linear(64, 10)

    def forward(self, x):
        features = self.feature_extractor(x)
        output = self.classifier(features)
        return output