İlk çalışan evrişimli sinir ağı için görüntüleri tensöre dönüştürüp eğitim ve test verilerini ayırın,
Örnekte giriş görüntüleri 28×28 piksel ve tek kanallıdır. İki evrişim katmanından sonra özellik haritasının boyutu 64×7×7 olur. Bu çıktı düzleştirilerek tam bağlantılı katmana verilir ve son katman 10 rakam sınıfı için 10 ham skor üretir. Ham skorlar
İkinci evrişim katmanının çıktısı 64×7×7 boyutundadır.
Eğitim doğruluğu yükselirken test doğruluğu belirgin biçimde geriliyorsa model eğitim verisini ezberliyor olabilir. Daha fazla test verisi eklemek bu sorunu çözmez; eğitim dönemini azaltmak, düzenlileştirme eklemek veya veri çeşitliliğini artırmak gibi yöntemler ayrıca değerlendirilmelidir.
nn.Conv2d ve nn.MaxPool2d katmanlarından oluşan bir model tanımlayın, kayıp fonksiyonuyla ağırlıkları güncelleyin ve test doğruluğunu ölçün. Aşağıdaki örnek, PyTorch ve MNIST kullanarak el yazısı rakamları sınıflandırır; çalıştırıldığında her görüntü için 0 ile 9 arasında bir sınıf tahmini üretir.Gerekli parçalar
Evrişimli sinir ağı, görüntüdeki küçük yerel örüntüleri öğrenmek için evrişim katmanlarını kullanır. İlk katmanlar kenar ve basit şekilleri, sonraki katmanlar ise daha karmaşık parçaları öğrenebilir. Havuzlama katmanları görüntünün uzamsal boyutunu küçültürken önemli özelliklerin korunmasına yardımcı olur.Örnekte giriş görüntüleri 28×28 piksel ve tek kanallıdır. İki evrişim katmanından sonra özellik haritasının boyutu 64×7×7 olur. Bu çıktı düzleştirilerek tam bağlantılı katmana verilir ve son katman 10 rakam sınıfı için 10 ham skor üretir. Ham skorlar
CrossEntropyLoss tarafından doğrudan kullanılabildiği için modelin sonunda ayrıca Softmax eklenmez.MNIST ile çalışan örnek
Ön koşul olarak Python ortamınızda PyTorch ve torchvision kurulu olmalıdır. Veri kümesinin ilk çalıştırmada indirilmesi için internet bağlantısı gerekir. Aşağıdaki koducnn_mnist.py adıyla kaydedin.
Python:
import torch
from torch import nn
from torch.utils.data import DataLoader
from torchvision import datasets
from torchvision.transforms import ToTensor
# İşlemci veya kullanılabilir CUDA aygıtını seç
cihaz = "cuda" if torch.cuda.is_available() else "cpu"
print("Kullanılan aygıt:", cihaz)
# Eğitim ve test verilerini yükle
transform = ToTensor()
train_data = datasets.MNIST(
root="data",
train=True,
download=True,
transform=transform,
)
test_data = datasets.MNIST(
root="data",
train=False,
download=True,
transform=transform,
)
train_loader = DataLoader(train_data, batch_size=64, shuffle=True)
test_loader = DataLoader(test_data, batch_size=64, shuffle=False)
class EvrisimliAg(nn.Module):
def __init__(self):
super().__init__()
self.ozellikler = nn.Sequential(
nn.Conv2d(1, 32, kernel_size=3, padding=1),
nn.ReLU(),
nn.MaxPool2d(kernel_size=2),
nn.Conv2d(32, 64, kernel_size=3, padding=1),
nn.ReLU(),
nn.MaxPool2d(kernel_size=2),
)
self.siniflandirici = nn.Sequential(
nn.Flatten(),
nn.Linear(64 * 7 * 7, 128),
nn.ReLU(),
nn.Linear(128, 10),
)
def forward(self, x):
x = self.ozellikler(x)
return self.siniflandirici(x)
model = EvrisimliAg().to(cihaz)
kayip_fonksiyonu = nn.CrossEntropyLoss()
optimizer = torch.optim.Adam(model.parameters(), lr=0.001)
def egit(model, veri_yukleyici, kayip_fonksiyonu, optimizer):
model.train()
toplam_kayip = 0.0
for goruntuler, etiketler in veri_yukleyici:
goruntuler = goruntuler.to(cihaz)
etiketler = etiketler.to(cihaz)
tahminler = model(goruntuler)
kayip = kayip_fonksiyonu(tahminler, etiketler)
optimizer.zero_grad()
kayip.backward()
optimizer.step()
toplam_kayip += kayip.item()
return toplam_kayip / len(veri_yukleyici)
def test_et(model, veri_yukleyici, kayip_fonksiyonu):
model.eval()
toplam_kayip = 0.0
dogru = 0
toplam = 0
with torch.no_grad():
for goruntuler, etiketler in veri_yukleyici:
goruntuler = goruntuler.to(cihaz)
etiketler = etiketler.to(cihaz)
tahminler = model(goruntuler)
toplam_kayip += kayip_fonksiyonu(tahminler, etiketler).item()
dogru += (tahminler.argmax(dim=1) == etiketler).sum().item()
toplam += etiketler.size(0)
ortalama_kayip = toplam_kayip / len(veri_yukleyici)
dogruluk = 100 * dogru / toplam
return ortalama_kayip, dogruluk
for donem in range(1, 4):
egitim_kaybi = egit(
model,
train_loader,
kayip_fonksiyonu,
optimizer,
)
test_kaybi, test_dogrulugu = test_et(
model,
test_loader,
kayip_fonksiyonu,
)
print(
f"Dönem {donem}: "
f"eğitim kaybı={egitim_kaybi:.4f}, "
f"test kaybı={test_kaybi:.4f}, "
f"test doğruluğu={test_dogrulugu:.2f}%"
)
# Bir test görüntüsü için örnek tahmin
model.eval()
goruntu, gercek_etiket = test_data[0]
with torch.no_grad():
skorlar = model(goruntu.unsqueeze(0).to(cihaz))
tahmin = skorlar.argmax(dim=1).item()
print("Gerçek etiket:", gercek_etiket)
print("Tahmin edilen etiket:", tahmin)
Kodu çalıştırma
- Çalışma ortamını hazırlayın. PyTorch ve torchvision paketlerinin kurulu olduğu bir Python ortamı açın. Paketler kurulu değilse kullandığınız işletim sistemi ve donanım için uyumlu PyTorch kurulumunu tamamlayın.
- Dosyayı kaydedin. Kodu
cnn_mnist.pyadıyla kaydedin. Dosya adında veya kodun girintilerinde değişiklik yapmayın; Python sınıf ve döngü bloklarını girintiyle ayırt eder. - Programı çalıştırın. Terminalde dosyanın bulunduğu klasöre geçip
python cnn_mnist.pykomutunu çalıştırın. İlk çalıştırmada MNIST dosyalarıdataklasörüne indirilir. - Eğitim çıktısını kontrol edin. Her dönem sonunda eğitim kaybı, test kaybı ve test doğruluğu yazdırılır. Eğitim ilerledikçe kaybın genel olarak azalması ve doğruluğun artması beklenir; kesin değer donanıma, paket sürümüne ve rastgele başlangıçlara göre değişebilir.
- Örnek tahmini inceleyin. Programın sonundaki gerçek etiket ile tahmin edilen etiketi karşılaştırın. İki değer aynıysa yalnızca seçilen görüntü doğru sınıflandırılmıştır; bu tek örnek, modelin bütün test kümesindeki başarısını kanıtlamaz. Genel değerlendirme için test doğruluğunu kullanın.
Modelin bölümleri ne yapıyor?
Conv2d(1, 32, 3) tek kanallı görüntüden 32 özellik haritası çıkarır. ReLU doğrusal olmayanlık ekler. MaxPool2d(2) yükseklik ve genişliği yarıya indirir; bu nedenle 28×28 görüntü ilk havuzlamadan sonra 14×14, ikinci havuzlamadan sonra 7×7 olur.İkinci evrişim katmanının çıktısı 64×7×7 boyutundadır.
Flatten bunu 3 boyutlu özellik haritasından 3136 elemanlı vektöre dönüştürür. Bu yüzden ilk Linear katmanının giriş boyutu 64 * 7 * 7 olarak yazılmıştır. Girdi boyutunu veya havuzlama sayısını değiştirirseniz bu değer de yeniden hesaplanmalıdır.CrossEntropyLoss ile eğitim yaparken etiketler 0-9 arası tamsayı sınıflar olmalıdır. Modelin son katmanındaki 10 değer olasılık değil, sınıflar için karşılaştırılabilir ham skorlardır. En yüksek skoru argmax ile seçmek tahmini verir.Çıktıyı yorumlama ve yaygın hatalar
Doğruluk yaklaşık yüzde 10 civarında kalıyorsa modelin on sınıftan birini neredeyse rastgele seçmesi söz konusu olabilir. Bu durumda veri etiketlerinin sınıf çıktılarıyla uyumlu olduğunu, görüntülerinToTensor() ile yüklendiğini, optimizer.zero_grad(), backward() ve optimizer.step() çağrılarının eğitim döngüsünde bulunduğunu kontrol edin.Eğitim doğruluğu yükselirken test doğruluğu belirgin biçimde geriliyorsa model eğitim verisini ezberliyor olabilir. Daha fazla test verisi eklemek bu sorunu çözmez; eğitim dönemini azaltmak, düzenlileştirme eklemek veya veri çeşitliliğini artırmak gibi yöntemler ayrıca değerlendirilmelidir.
64 * 7 * 7 boyut hatası alırsanız sorun genellikle evrişim veya havuzlama katmanlarından sonra oluşan boyutun değişmesidir. Modelin forward metodunda geçici olarak print(x.shape) kullanarak düzleştirme öncesi şekli kontrol edin ve tanı tamamlandıktan sonra bu geçici satırı kaldırın.