CNN: Sıfırdan Üretime Evrişimli Ağlar
Bilgisayar fotoğraftaki kediyi nasıl "görür"? Trafik işaretini insan yüzünden nasıl ayırt edersiniz? Cevap yatıyor Evrişimsel Sinir Ağları (CNN)derin öğrenme mimarisi bilgisayar görüşünde devrim yaratan şey. Sürücüsüz arabalardan tıbbi görüntüleme teşhisine kadar, CNN'ler her gün kullandığımız milyonlarca uygulamanın arkasındaki görünmez motordur.
Serinin bu ilk makalesinde Derin Öğrenme ile Bilgisayarlı Görme, inşa edeceğiz CNN'leri sıfırdan anlamanız: ne oldukları, evrişimli filtrelerin nasıl çalıştığı, Hangi mimariler tarih yazdı ve PyTorch'ta eksiksiz bir CNN'nin nasıl uygulanacağı ve eğitileceği. Tamamladığınızda gerçek görüntüleri sınıflandırma ve modeli üretime geçirme becerilerine sahip olacaksınız.
Seriye Genel Bakış
| # | Öğe | Odak |
|---|---|---|
| 1 | Buradasınız - CNN: Evrişimsel Ağlar | Mimari, eğitim, dağıtım |
| 2 | Öğrenmeyi ve İnce Ayarı Aktar | Önceden eğitilmiş modeller, etki alanı uyarlaması |
| 3 | YOLO ile Nesne Algılama | Gerçek zamanlı nesne algılama |
| 4 | Anlamsal Segmentasyon | Piksel düzeyinde sınıflandırma |
| 5 | GAN ve Difüzyon ile Görüntü Üretimi | Sentetik görüntü oluşturma |
| 6 | Uç Dağıtımı ve Optimizasyonu | Gömülü cihazlardaki modeller |
Ne Öğreneceksiniz
- Bir bilgisayar görüntüleri nasıl temsil eder (pikseller, RGB kanalları, tensörler)
- Evrişim işlemi: çekirdek, özellik haritaları, kayan pencere
- Bir CNN'nin temel bileşenleri: evrişimler, havuzlama, aktivasyonlar
- Mimarilerin evrimi: LeNet-5'ten ConvNeXt'e
- ResNet ve bağlantıları atla: kaybolan degradenin nasıl çözüleceği
- PyTorch'ta tam uygulama: CIFAR-10 sınıflandırması için CNN
- Transfer öğrenimi: ImageNet'te önceden eğitilmiş modellerin yeniden kullanılması
- Değerlendirme metrikleri: doğruluk, kesinlik, hatırlama, karışıklık matrisi
- Dağıtım: eğitilmiş modelden üretim çıkarımına (ONNX, TorchScript)
1. Piksellerden Özelliklere: Bir Bilgisayar Görüntüleri Nasıl Görür?
Biz insanlar için fotoğrafa bakmak doğal bir eylemdir. Beynimiz anında tanır şekiller, renkler, konturlar ve nesneler. Ancak bir bilgisayar için görüntü yalnızca sayılardan oluşan bir tablodur. Her piksel, ışık yoğunluğunu gösteren sayısal değerlerle temsil edilir.
1.1 Sayıların Matrisi Olarak Bir Görüntü
Gri tonlamalı görüntü, her hücrenin 0 (siyah) arasında bir değer içerdiği 2 boyutlu bir dizidir.
ve 255 (beyaz). Renkli bir görüntü aşağıdakilerden oluşur: üç kanal (Kırmızı, Yeşil, Mavi),
her biri ayrı bir matris. Bu nedenle 224x224 renkli görüntü bir boyut tensörüdür
3 x 224 x 224veya 150.528 sayısal değer.
Immagine 4x4 (scala di grigi, valori 0-255):
+-----+-----+-----+-----+
| 10 | 20 | 30 | 40 |
+-----+-----+-----+-----+
| 50 | 120 | 180 | 60 |
+-----+-----+-----+-----+
| 70 | 200 | 220 | 80 |
+-----+-----+-----+-----+
| 90 | 100 | 110 | 130 |
+-----+-----+-----+-----+
Immagine a colori (3 canali RGB):
Canale R: [[10, 20, ...], ...] --> tonalita di rosso
Canale G: [[30, 40, ...], ...] --> tonalita di verde
Canale B: [[50, 60, ...], ...] --> tonalita di blu
Tensore finale: shape = (3, H, W) --> (canali, altezza, larghezza)
1.2 Yoğun Sinir Ağları Neden Yeterli Değil
Akla gelen ilk yaklaşım, görüntüyü 1 boyutlu bir vektöre düzleştirip içinden geçirmektir. tamamen bağlı (yoğun) bir sinir ağına. 224x224x3'lük bir görüntü için bu şu anlama gelir: bir giriş katmanı 150.528 nöron. 1000 nörondan oluşan gizli bir katmanla, yalnızca ilk katmanda zaten 150 milyon parametreye sahip olursunuz.
Görüntüler için Yoğun Ağların Sorunları
- Parametre patlaması: Milyonlarca ağırlık zaten ilk katmanda, hesaplama açısından engelleyici
- Uzamsal değişmezlik yok: Bir kedi 10 piksel sağa doğru hareket ederse ağ artık onu tanımaz
- 2 boyutlu yapının kaybı: Görüntünün düzleştirilmesi komşu pikseller arasındaki uzamsal ilişkileri yok eder
- Aşırı uyum: Çok az veri ile çok fazla parametre genellemeye değil ezberlemeye yol açar
CNN'ler tüm bu sorunları üç temel öngörüden yararlanarak çözüyor: bölge (görsel desenler yereldir), yük paylaşımı (aynı filtre görüntünün her yerinde çalışır) e çeviri değişmezliği (bir kenar, nerede olursa olsun, bir kenardır).
2. Evrişim Operasyonu
La evrişim CNN'lerin kalbindeki matematiksel işlemdir. Küçük bir filtre (dedi çekirdek) her konumda bir toplam hesaplayarak giriş görüntüsünü kaydırır kapsanan piksellerin ağırlıklandırılması. Sonuç, adı verilen yeni bir dizidir. özellik haritaları, belirli bir deseni (dikey kenar, yatay kenar, köşe, doku) vurgular.
2.1 Çekirdek ve Kayar Pencere
Çekirdek, kaydırılan küçük bir ağırlık matrisidir (tipik olarak 3x3 veya 5x5) (slaytlar) giriş görüntüsünün tamamı boyunca. Her pozisyonda çekirdek değerleri alttaki piksellerle öğe öğe çarpılır ve tek bir sonuç elde etmek için bir araya getirilir çıktı özellik haritasındaki değer.
Input (5x5): Kernel (3x3):
+---+---+---+---+---+ +----+----+----+
| 1 | 2 | 3 | 0 | 1 | | -1 | 0 | 1 |
+---+---+---+---+---+ +----+----+----+
| 0 | 1 | 2 | 3 | 1 | | -1 | 0 | 1 |
+---+---+---+---+---+ +----+----+----+
| 1 | 0 | 1 | 2 | 0 | | -1 | 0 | 1 |
+---+---+---+---+---+ +----+----+----+
| 2 | 1 | 0 | 1 | 3 | (Filtro per bordi verticali)
+---+---+---+---+---+
| 0 | 1 | 2 | 1 | 0 |
+---+---+---+---+---+
Posizione (0,0): applica kernel ai pixel evidenziati [*]
[*1][*2][*3] 0 1
[*0][*1][*2] 3 1 Calcolo:
[*1][*0][*1] 2 0 (-1x1)+(0x2)+(1x3)+(-1x0)+(0x1)+(1x2)+(-1x1)+(0x0)+(1x1)
2 1 0 1 3 = -1 + 0 + 3 + 0 + 0 + 2 - 1 + 0 + 1 = 4
0 1 2 1 0
Output feature map (3x3):
+---+---+---+
| 4 | . | . | <-- Il 4 appena calcolato
+---+---+---+
| . | . | . | Il kernel scorre e calcola ogni cella
+---+---+---+
| . | . | . |
+---+---+---+
Klasik Çekirdek Türleri
| Çekirdek | Kapsam | Değerler (3x3) |
|---|---|---|
| Dikey kenarlık | Dikey geçişleri algıla | [-1, 0, 1] tekrarlandı |
| Yatay kenarlık | Yatay geçişleri algıla | [-1,-1,-1], [0,0,0], [1,1,1] |
| Bileme | Keskinliği artırır | [0,-1,0], [-1,5,-1], [0,-1,0] |
| Gauss bulanıklığı | Gauss bulanıklığı | [1,2,1], [2,4,2], [1,2,1] / 16 |
CNN'ler ile geleneksel görüntü işleme arasındaki temel fark şudur: CNN'lerde çekirdek değerleri elle ayarlanmaz. ağ otomatik olarak öğrenir eğitim sırasında en uygun filtreleri geri yayılım. İlk katmanlar basit kenarları ve dokuları algılamayı öğrenirken, katmanlar basit kenarları ve dokuları algılamayı öğrenir. daha derin olanlar bu özellikleri giderek daha karmaşık hale gelen desenlerde (gözler, tekerlekler, yüzler) birleştirir.
3. CNN'in Bileşenleri
Bir CNN, her biri belirli bir role sahip olan farklı katman türlerinden oluşur. Her bileşenin ne yaptığını anlamak, etkili mimariler tasarlamak için kritik öneme sahiptir.
3.1 Evrişimsel Katman
Evrişimsel katman girişe birden fazla filtre uygulayarak bir özellik haritası üretir. her filtre. Bir RGB görüntüsüne 32 adet 3x3 filtre uygularsanız 32 adet özellik haritası elde edersiniz, her biri farklı bir deseni vurguluyor. Anahtar parametreler şunlardır:
Evrişimsel Katman parametreleri
| Parametre | Tanım | Tipik Değerler |
|---|---|---|
| Çekirdek boyutu | Filtre boyutu (genişlik x yükseklik) | 3x3, 5x5, 7x7 |
| Adım | Filtre kaydırma adımı | 1, 2 |
| Dolgu | Girişin kenarlarına eklenen pikseller | 0 (geçerli), 1 (3x3 için aynı) |
| Filtre sayısı | Çıktıda kaç tane özellik haritası var | 32, 64, 128, 256, 512 |
Formula dimensione output:
output_size = (input_size - kernel_size + 2 * padding) / stride + 1
Esempio: input 32x32, kernel 3x3
Stride=1, Padding=0: (32 - 3 + 0) / 1 + 1 = 30x30 (si riduce)
Stride=1, Padding=1: (32 - 3 + 2) / 1 + 1 = 32x32 (same padding)
Stride=2, Padding=1: (32 - 3 + 2) / 2 + 1 = 16x16 (dimezza)
Stride=1, Padding=1 ("same"):
Input: [A B C D E] Output: [A B C D E] --> stessa dimensione
(con zero-padding ai bordi)
Stride=2 (dimezza la risoluzione):
Input: [A B C D E F] Output: [A C E] --> meta dimensione
(salta un pixel ad ogni passo)
3.2 Aktivasyon Fonksiyonu (ReLU)
Her evrişimden sonra doğrusal olmayan bir aktivasyon fonksiyonu uygulanır. En yaygın
orada ReLU (Düzeltilmiş Doğrusal Birim): f(x) = max(0, x).
ReLU tüm negatif değerleri sıfırlar ve pozitif olanları değiştirmeden bırakır. Doğrusallık olmadan,
bir dizi evrişim tek bir doğrusal dönüşüme eşdeğer olacaktır,
ağı karmaşık kalıpları öğrenemez hale getiriyor.
ReLU: f(x) = max(0, x) Semplice, veloce, standard
LeakyReLU: f(x) = x se x>0, 0.01x altrimenti Evita "dying ReLU"
GELU: f(x) = x * Phi(x) Usata nei Transformers, smooth
Swish: f(x) = x * sigmoid(x) Usata in EfficientNet
Input feature map: Dopo ReLU:
+----+-----+----+ +----+----+----+
| -3 | 5 | -1 | | 0 | 5 | 0 |
+----+-----+----+ +----+----+----+
| 2 | -7 | 4 | | 2 | 0 | 4 |
+----+-----+----+ +----+----+----+
| -2 | 1 | -5 | | 0 | 1 | 0 |
+----+-----+----+ +----+----+----+
3.3 Havuzlama Katmanları
Havuzlama, özellik haritalarının uzamsal boyutlarını azaltarak parametre sayısını azaltır ve ağın özellik konumundaki küçük değişikliklere karşı daha dayanıklı hale getirilmesi. İki tür ana olanlar Maksimum Havuzlama (her pencerede maksimum değeri alır) e Ortalama Havuzlama (ortalamayı hesaplayın).
Input (4x4): Output (2x2):
+----+----+----+----+ +----+----+
| 12 | 20| 30| 0 | | 20 | 30 | max(12,20,0,8)=20
+----+----+----+----+ --> +----+----+ max(30,0,2,14)=30
| 0 | 8 | 2 | 14 | | 15 | 16 |
+----+----+----+----+ +----+----+
| 15 | 2 | 3 | 16 |
+----+----+----+----+ Riduce 4x4 --> 2x2
| 1 | 6 | 7 | 8 | (dimezza altezza e larghezza)
+----+----+----+----+
Max Pooling: prende il massimo --> preserva le feature più forti
Avg Pooling: calcola la media --> effetto di smoothing
Global Average Pooling: media su tutta la feature map --> un singolo valore per canale
3.4 Toplu Normalleştirme
La Toplu Normalleştirme (BatchNorm) her katmanın çıktısını normalleştirir yani ortalama ve birim varyansı sıfırdır. Bu, eğitimi stabilize eder, daha yüksek öğrenme oranlarına sahiptir ve hafif bir düzenleyici görevi görür. Pratikte uyuyor aktivasyondan önce her evrişimden sonra bir BatchNorm katmanı.
4. Tipik CNN Mimarisi
Standart bir CNN yinelenen bir modeli izler: özellik çıkarma blokları (evrişim + aktivasyon + havuzlama) ve ardından son sınıflandırma için tamamen bağlı katmanlar gelir. Derinlik arttıkça özellik haritalarının mekansal boyutu azalır ancak sayıları artar Giderek daha soyut kalıpları yakalayan kanallar.
Input Immagine (3 x 32 x 32)
|
v
[Conv2d 3->32, 3x3, pad=1] --> [BatchNorm] --> [ReLU] --> [MaxPool 2x2]
| Feature maps: 32 x 16 x 16
v
[Conv2d 32->64, 3x3, pad=1] --> [BatchNorm] --> [ReLU] --> [MaxPool 2x2]
| Feature maps: 64 x 8 x 8
v
[Conv2d 64->128, 3x3, pad=1] --> [BatchNorm] --> [ReLU] --> [MaxPool 2x2]
| Feature maps: 128 x 4 x 4
v
[Flatten] --> Vettore di 128 * 4 * 4 = 2048 valori
|
v
[Linear 2048 -> 256] --> [ReLU] --> [Dropout 0.5]
|
v
[Linear 256 -> 10] --> Output: 10 classi (es. CIFAR-10)
|
v
[Softmax] --> Probabilità per ogni classe: [0.02, 0.01, 0.85, ...]
Flusso delle dimensioni:
(3, 32, 32) -> (32, 16, 16) -> (64, 8, 8) -> (128, 4, 4) -> (2048) -> (256) -> (10)
[immagine] [bordi, texture] [parti] [oggetti] [decisione] [classe]
Öğrenilen Özellikler Hiyerarşisi
- Katman 1-2 (düşük seviye): Kenarlıklar, renk geçişleri, basit dokular
- Katman 3-5 (orta seviye): Köşeler, konturlar, nesnelerin parçaları (gözler, tekerlekler)
- Katman 6+ (yüksek seviye): Eksiksiz nesneler, sahneler, soyut kavramlar
Bu hiyerarşi eğitim sırasında otomatik olarak ortaya çıkar. Gerek yok ağa ne arayacağını söylemek için: filtreler verilere uyum sağlar.
5. CNN Mimarilerinin Evrimi
CNN'lerin tarihi, her biri yenilikçi mimarilerle işaretlenmiştir. alanı değiştiren fikirler. Bu evrimi bilmek anlamak için temeldir modern mimari seçimler.
CNN Mimarilerinin Zaman Çizelgesi
| Yıl | Mimarlık | Anahtar Yenilik | İlk 1 ImageNet |
|---|---|---|---|
| 1998 | LeNet-5 | İlk pratik CNN (rakam tanıma) | Yok |
| 2012 | AlexNet | GPU eğitimi, ReLU, Bırakma | %63,3 |
| 2014 | VGGNet | Tek tip 3x3 filtreli derin ağlar | %74,5 |
| 2014 | GoogleLeNet/Başlangıç | Başlangıç modülleri, çok ölçekli paralel | %74,8 |
| 2015 | ResNet | Bağlantıları atlayın, 152'den fazla katman ağı | %78,6 |
| 2019 | EfficientNet | Bileşik ölçeklendirme (derinlik+genişlik+çözünürlük) | %84,4 |
| 2022 | Dönüşüm | Vision Transformers'tan ilham alan modernize edilmiş CNN | %87,8 |
5.1 LeNet-5 (1998) - Öncü
Yann LeCun tarafından el yazısı rakam tanıma (MNIST) için tasarlanan LeNet-5 ve pratikte başarılı olan ilk CNN. Yalnızca 5 katman ve 60.000 parametreyle kanıtlandı kıvrımların görüntülerden ayırt edici özellikleri öğrenebileceği. Bunun için kullanıldı banka çeklerini otomatik olarak okur.
5.2 AlexNet (2012) - Devrim
AlexNet, ImageNet 2012 yarışmasını büyük bir farkla kazanarak hatayı azalttı %26'dan %16'ya. Temel yenilikler: GPU eğitimi (iki NVIDIA GTX 580), fonksiyon Sigmoid yerine ReLU aktivasyonu, düzenlileştirme ve veri artırma için Bırakma. Bu sonuç, akademi ve endüstriyi derin öğrenmenin işe yaradığına ikna etti.
5.3 VGGNet (2014) - Derinlik Önemlidir
VGG, daha derin ağların daha iyi sonuçlar verdiğini gösterdi. Onun ana fikri ve sadelik açısından radikal: yalnızca 3x3 yığılmış filtreler kullanın. Ardışık iki 3x3 katman tek bir 5x5 katmanla aynı alıcı alana sahiptirler, ancak giderek daha fazla parametreye sahiptirler doğrusal olmama. VGG-16'nın 16 katmanı ve 138 milyon parametresi vardır.
5.4 EfficientNet (2019) - Akıllı Ölçeklendirme
EfficientNet şunları tanıttı: bileşik ölçeklendirme: sadece artırmak yerine derinlik (VGG gibi) veya genişlik, üç boyutu da eşit şekilde ölçeklendirir (derinlik, genişlik, giriş çözünürlüğü) dengeli katsayılarla. EfficientNet-B0 Rapora göre ImageNet'te yalnızca 5,3 milyon parametreyle %77,1 doğruluk elde ediliyor benzeri görülmemiş doğruluk parametreleri.
5.5 ConvNeXt (2022) - Modernize Edilmiş CNN
ConvNeXt, Vision Transformers'tan ilham alan tekniklerle modernize edilen CNN'lerin, transformatör mimarileriyle rekabet edebilir (ve onları aşabilirler). Yenilikler şunları içerir: 7x7 derinlemesine ayrılabilir çekirdekler, BatchNorm yerine LayerNorm, GELU aktivasyonu, ve artan boyutlara sahip "izomorfik" bir tasarım. ConvNeXt V2, sürümde E-ConvNeXt-Tiny, yalnızca 2,0 GFLOP ile %80,6 İlk 1'e ulaştı ve dağıtım için mükemmel verimli.
6. ResNet ve Bağlantıları Atla
ResNet (Artık Ağlar)He ve diğerleri tarafından önerilmiştir. 2015 yılında çözüldü Derin öğrenmenin temel sorunlarından biri: bozulma sorunu. ResNet'ten önce, derin bir ağa katman eklemek sonuçları iyileştirmek yerine daha da kötüleştiriyordu. eğitim setinde bile. Çözüm basit olduğu kadar zariftir.
6.1 Kaybolan Gradyan Problemi
Geri yayılım sırasında gradyanlar tekrar tekrar çarpılır. ağın katmanları. Bu çarpmalar 1'den küçük değerler üretiyorsa gradyanlar ilk katmanlara doğru ilerledikçe katlanarak "kaybolurlar". 50 veya daha fazla katmanda degradeler o kadar küçük olur ki ilk birkaç katman durur öğrenmek için. Son çalışmalar, bağlantıları atlama olmadan L2'nin Geçiş bağlantılarında degradelerin sayısı ilk katmanlarda büyük ölçüde azalırken ağ boyunca aynı kalır.
Rete profonda SENZA skip connections (50 layer):
Layer 50 Layer 49 Layer 48 ... Layer 2 Layer 1
grad=1.0 * 0.8 * 0.8 ... * 0.8 * 0.8
Gradiente al layer 1: 0.8^49 = 0.00001 --> quasi zero!
I primi layer NON apprendono.
Rete profonda CON skip connections (ResNet):
Il gradiente ha un "percorso diretto" attraverso le skip connections.
Non viene moltiplicato ripetutamente per valori piccoli.
Gradiente al layer 1: ~0.5 --> i layer apprendono normalmente!
6.2 Çözüm: Artık Öğrenme
ResNet'in harika fikri basit: bir bloğun dönüşümü öğrenmek yerine
tamamlandı H(x), onun sadece öğrenmesini sağlarsın fark (artık)
girişle ilgili olarak: F(x) = H(x) - x. Bloğun çıktısı şöyle olur
y = F(x) + x, Nerede x bloğun üzerinden "atlayan" giriştir
bir bağlantıyı atla (veya kısayol bağlantısı).
Blocco Standard: Residual Block:
x x ------+
| | |
v v | (skip connection)
[Conv 3x3] [Conv 3x3] |
| | |
[BatchNorm] [BatchNorm] |
| | |
[ReLU] [ReLU] |
| | |
[Conv 3x3] [Conv 3x3] |
| | |
[BatchNorm] [BatchNorm] |
| | |
v v |
H(x) = output F(x) + x <--+
|
[ReLU]
|
v
output
Se F(x) = 0, l'output è semplicemente x (identità).
La rete può "saltare" un blocco se non serve.
Questo rende il training di reti profonde stabile.
çünkü işe yarıyor
Kalıntıyı öğrenmek F(x) = 0 (yani "hiçbir şey yapmamak") çok daha kolaydır
tam bir kimlik dönüşümünü öğrenmekten daha iyidir. Bir katman kullanışlı değilse ağ
basitçe öğren F(x) = 0 ve girişi değişmeden iletir. Bu izin verir
Performans kaybı olmadan yüzlerce katmana sahip ağlar oluşturmak.
7. CNN'i eğitmek
Bir CNN'yi eğitmek, tüm çekirdekler (filtreler) için en uygun değerleri bulmak anlamına gelir ve tamamen bağlı katmanların ağırlıkları. Bu yinelenen bir süreç aracılığıyla gerçekleşir ileri geçiş, kayıp hesaplaması ve gradyan geri yayılımı.
7.1 Kayıp Fonksiyonu
Görüntü sınıflandırması için standart kayıp fonksiyonu şu şekildedir: Çapraz Entropi Kaybı. Ağ tarafından tahmin edilen olasılıkların gerçek etiketlerden ne kadar saptığını ölçer. Mükemmel bir tahmin kayıp = 0 üretir; tamamen yanlış bir tahmin ortaya çıkıyor sonsuza uzanan kayıp.
Etichetta reale (one-hot): [0, 0, 1, 0, 0, 0, 0, 0, 0, 0] (classe "gatto" = indice 2)
Predizione buona: [0.02, 0.03, 0.85, 0.02, 0.01, 0.02, 0.01, 0.02, 0.01, 0.01]
Loss = -log(0.85) = 0.16 --> Loss bassa, predizione corretta
Predizione cattiva: [0.30, 0.25, 0.05, 0.10, 0.05, 0.05, 0.05, 0.05, 0.05, 0.05]
Loss = -log(0.05) = 3.00 --> Loss alta, predizione sbagliata
7.2 Optimize Ediciler
Optimize edici, ağ ağırlıklarını kaybı azaltacak yönde günceller. En çok kullanılanlar şunlardır:
Optimize Edici Karşılaştırması
| Optimize Edici | Özellikler | Ne zaman kullanılmalı? |
|---|---|---|
| SGD + Momentum | Basit, sağlam, kararlı yakınsama | Uzun eğitim, maksimum nihai doğruluk |
| Adem | Uyarlanabilir öğrenme oranı, hızlı yakınsama | Prototip oluşturma, küçük/orta ölçekli ağlar |
| Adam W | Adem doğru kilo kaybıyla | CNN için önerilen modern standart |
7.3 Veri Arttırma
La veri artırma aşırı uyumu önlemek için temel bir tekniktir ve ağ genellemesini iyileştirin. Rastgele dönüşümlerin uygulanmasından oluşur varyasyonlar oluşturmak için görüntüleri eğitmek (döndürmeler, döndürmeler, kırpmalar, parlaklık değişiklikleri) yeni veri toplamadan sentetik.
Immagine Originale: Trasformazioni:
+-------+ [Flip orizzontale] --> Immagine specchiata
| Gatto | [Rotazione +-15 gradi]--> Leggera rotazione
| --o-- | [Random Crop] --> Ritaglio casuale
| /|\ | [Color Jitter] --> Variazione colori
+-------+ [Gaussian Noise] --> Aggiunta rumore
[Cutout/Erasing] --> Maschera rettangolare casuale
[MixUp] --> Media pesata di 2 immagini
[CutMix] --> Porzione di un'immagine sovrapposta
Effetto: da 50.000 immagini di training, ogni epoca vede variazioni
diverse, come se avessi milioni di immagini uniche.
8. PyTorch'ta uygulamayı tamamlayın
Teoriden pratiğe geçelim. Sınıflandırma için tam bir CNN uygulayacağız veri kümesinin görüntüleri CIFAR-10 (10 sınıfta 60.000 32x32 görüntü: uçak, araba, kuş, kedi, geyik, köpek, kurbağa, at, gemi, kamyon).
8.1 Kurulum ve Veri Kümesi
import torch
import torch.nn as nn
import torch.optim as optim
import torchvision
import torchvision.transforms as transforms
from torch.utils.data import DataLoader
# Trasformazioni con data augmentation per il training
train_transform = transforms.Compose([
transforms.RandomHorizontalFlip(p=0.5),
transforms.RandomCrop(32, padding=4),
transforms.ColorJitter(brightness=0.2, contrast=0.2),
transforms.ToTensor(),
transforms.Normalize(
mean=[0.4914, 0.4822, 0.4465], # Media CIFAR-10
std=[0.2470, 0.2435, 0.2616] # Std CIFAR-10
),
])
# Trasformazioni per il test (nessuna augmentation)
test_transform = transforms.Compose([
transforms.ToTensor(),
transforms.Normalize(
mean=[0.4914, 0.4822, 0.4465],
std=[0.2470, 0.2435, 0.2616]
),
])
# Caricamento dataset
train_dataset = torchvision.datasets.CIFAR10(
root='./data', train=True, download=True, transform=train_transform
)
test_dataset = torchvision.datasets.CIFAR10(
root='./data', train=False, download=True, transform=test_transform
)
# DataLoader con batching e shuffling
train_loader = DataLoader(train_dataset, batch_size=128, shuffle=True, num_workers=4)
test_loader = DataLoader(test_dataset, batch_size=128, shuffle=False, num_workers=4)
CLASSES = ['aereo', 'auto', 'uccello', 'gatto', 'cervo',
'cane', 'rana', 'cavallo', 'nave', 'camion']
8.2 Modelin Tanımı
class ResidualBlock(nn.Module):
"""Blocco residuale con skip connection."""
def __init__(self, in_channels: int, out_channels: int, stride: int = 1):
super().__init__()
self.conv1 = nn.Conv2d(
in_channels, out_channels, kernel_size=3,
stride=stride, padding=1, bias=False
)
self.bn1 = nn.BatchNorm2d(out_channels)
self.conv2 = nn.Conv2d(
out_channels, out_channels, kernel_size=3,
stride=1, padding=1, bias=False
)
self.bn2 = nn.BatchNorm2d(out_channels)
self.relu = nn.ReLU(inplace=True)
# Skip connection: se le dimensioni cambiano, usa conv 1x1
self.shortcut = nn.Sequential()
if stride != 1 or in_channels != out_channels:
self.shortcut = nn.Sequential(
nn.Conv2d(in_channels, out_channels, kernel_size=1,
stride=stride, bias=False),
nn.BatchNorm2d(out_channels)
)
def forward(self, x: torch.Tensor) -> torch.Tensor:
identity = self.shortcut(x)
out = self.relu(self.bn1(self.conv1(x)))
out = self.bn2(self.conv2(out))
out = out + identity # Skip connection
out = self.relu(out)
return out
class CIFAR10CNN(nn.Module):
"""CNN con blocchi residuali per classificazione CIFAR-10."""
def __init__(self, num_classes: int = 10):
super().__init__()
# Primo layer convoluzionale
self.conv1 = nn.Conv2d(3, 32, kernel_size=3, padding=1, bias=False)
self.bn1 = nn.BatchNorm2d(32)
self.relu = nn.ReLU(inplace=True)
# Blocchi residuali con profondità crescente
self.layer1 = self._make_layer(32, 64, num_blocks=2, stride=1)
self.layer2 = self._make_layer(64, 128, num_blocks=2, stride=2)
self.layer3 = self._make_layer(128, 256, num_blocks=2, stride=2)
# Classificatore finale
self.global_avg_pool = nn.AdaptiveAvgPool2d((1, 1))
self.dropout = nn.Dropout(0.3)
self.fc = nn.Linear(256, num_classes)
def _make_layer(
self, in_ch: int, out_ch: int, num_blocks: int, stride: int
) -> nn.Sequential:
layers = [ResidualBlock(in_ch, out_ch, stride)]
for _ in range(1, num_blocks):
layers.append(ResidualBlock(out_ch, out_ch, stride=1))
return nn.Sequential(*layers)
def forward(self, x: torch.Tensor) -> torch.Tensor:
x = self.relu(self.bn1(self.conv1(x))) # (B, 32, 32, 32)
x = self.layer1(x) # (B, 64, 32, 32)
x = self.layer2(x) # (B, 128, 16, 16)
x = self.layer3(x) # (B, 256, 8, 8)
x = self.global_avg_pool(x) # (B, 256, 1, 1)
x = x.view(x.size(0), -1) # (B, 256)
x = self.dropout(x)
x = self.fc(x) # (B, 10)
return x
8.3 Eğitim Döngüleri
def train_model(
model: nn.Module,
train_loader: DataLoader,
test_loader: DataLoader,
epochs: int = 50,
lr: float = 0.01
) -> dict:
"""Addestra il modello e restituisce la storia del training."""
device = torch.device('cuda' if torch.cuda.is_available() else 'cpu')
model = model.to(device)
criterion = nn.CrossEntropyLoss()
optimizer = optim.SGD(
model.parameters(), lr=lr, momentum=0.9, weight_decay=1e-4
)
scheduler = optim.lr_scheduler.OneCycleLR(
optimizer, max_lr=lr, epochs=epochs,
steps_per_epoch=len(train_loader)
)
history = {'train_loss': [], 'test_loss': [], 'test_acc': []}
for epoch in range(epochs):
# --- Training ---
model.train()
running_loss = 0.0
for images, labels in train_loader:
images, labels = images.to(device), labels.to(device)
optimizer.zero_grad()
outputs = model(images)
loss = criterion(outputs, labels)
loss.backward()
optimizer.step()
scheduler.step()
running_loss += loss.item()
avg_train_loss = running_loss / len(train_loader)
# --- Evaluation ---
model.eval()
test_loss = 0.0
correct = 0
total = 0
with torch.no_grad():
for images, labels in test_loader:
images, labels = images.to(device), labels.to(device)
outputs = model(images)
loss = criterion(outputs, labels)
test_loss += loss.item()
_, predicted = outputs.max(1)
total += labels.size(0)
correct += predicted.eq(labels).sum().item()
avg_test_loss = test_loss / len(test_loader)
accuracy = 100.0 * correct / total
history['train_loss'].append(avg_train_loss)
history['test_loss'].append(avg_test_loss)
history['test_acc'].append(accuracy)
print(
f"Epoch [{epoch+1}/{epochs}] "
f"Train Loss: {avg_train_loss:.4f} | "
f"Test Loss: {avg_test_loss:.4f} | "
f"Accuracy: {accuracy:.2f}%"
)
return history
# Esecuzione
model = CIFAR10CNN(num_classes=10)
history = train_model(model, train_loader, test_loader, epochs=50, lr=0.1)
# Output atteso dopo 50 epoche con OneCycleLR:
# Test Accuracy: ~92-93%
CIFAR-10 için Önerilen Eğitim Parametreleri
| Parametre | Değer | Motivasyon |
|---|---|---|
| Parti boyutu | 128 | Hız ve eğim kararlılığı arasındaki denge |
| Öğrenme oranı | 0.1 (OneCycleLR ile) | Zamanlamalı SGD üstün doğruluk sağlar |
| Ağırlık azalması | 1e-4 | Aşırı uyumu önlemek için L2 düzenlemesi |
| Çağlar | 50 | OneCycleLR ile yakınsama için 50 dönem yeterlidir |
| Bırakılanlar | 0,3 | Son katmandan önce ek düzenleme |
9. Öğrenimi Aktarın
Uygulamada nadiren bir CNN'i sıfırdan eğitirsiniz. öğrenmeyi aktar önceden eğitilmiş modelleri büyük veri kümelerinde yeniden kullanmanıza olanak tanır (1,2 milyon veri kümesiyle ImageNet gibi) resim ve 1.000 sınıf) ve bunları kendi probleminize uyarlayın. Bu azaltır Eğitim sürelerini ve ihtiyaç duyulan veri miktarını önemli ölçüde azaltır ve performansı artırır.
9.1 Özellik Çıkarma ve İnce Ayar Karşılaştırması
İki Transfer Öğrenme Stratejisi
| Strateji | Nasıl Çalışır? | Ne zaman kullanılmalı? |
|---|---|---|
| Özellik Çıkarma | Önceden eğitilmiş tüm katmanları dondurun, yalnızca son sınıflandırıcıyı eğitin | Az veri (<1.000 resim), ImageNet'e benzer alan adı |
| İnce Ayar | Son N katmanı çözün ve düşük öğrenme oranıyla yeniden eğitin | Daha fazla veri mevcut, ImageNet dışında alan adı |
import torchvision.models as models
def create_transfer_model(
num_classes: int,
freeze_backbone: bool = True
) -> nn.Module:
"""Crea un modello con transfer learning da ResNet-18."""
# Carica ResNet-18 pre-addestrato su ImageNet
model = models.resnet18(weights=models.ResNet18_Weights.DEFAULT)
# Strategia 1: Feature Extraction (congela il backbone)
if freeze_backbone:
for param in model.parameters():
param.requires_grad = False
# Sostituisci il classificatore finale
num_features = model.fc.in_features # 512 per ResNet-18
model.fc = nn.Sequential(
nn.Dropout(0.3),
nn.Linear(num_features, 256),
nn.ReLU(),
nn.Dropout(0.2),
nn.Linear(256, num_classes)
)
return model
# Feature extraction: solo il classificatore viene addestrato
feature_model = create_transfer_model(num_classes=10, freeze_backbone=True)
# Fine-tuning: tutto il modello viene riaddestrato
finetune_model = create_transfer_model(num_classes=10, freeze_backbone=False)
# Per il fine-tuning, usa un learning rate più basso
optimizer = optim.AdamW([
{'params': finetune_model.layer4.parameters(), 'lr': 1e-4},
{'params': finetune_model.fc.parameters(), 'lr': 1e-3},
], weight_decay=1e-2)
Guida al Transfer Learning:
Dati simili a ImageNet Dati diversi da ImageNet
(oggetti, animali, scene) (medico, satellite, micro)
+---------------------------+---------------------------+
Pochi dati | Feature Extraction | Feature Extraction |
(<1.000 img) | Congela tutto, addestra FC | + Aumenta data augment. |
+---------------------------+---------------------------+
Molti dati | Fine-tuning ultimi layer | Fine-tuning completo |
(>5.000 img) | LR basso per il backbone | o training da zero |
+---------------------------+---------------------------+
10. Değerlendirme Metrikleri
Bir CNN'in iyi çalışıp çalışmadığını anlamak için tek başına doğruluk yeterli değildir. Dengesiz veri kümeleriyle (örneğin %95 A sınıfı, %5 B sınıfı), her zaman "A sınıfı"nı tahmin eden bir modelin doğruluğu %95'tir ama tamamen işe yaramaz. Daha ayrıntılı ölçümlere ihtiyaç var.
Görüntü Sınıflandırmasına İlişkin Metrikler
| Metrik | Neyi ölçer | Formül |
|---|---|---|
| Kesinlik | Toplam içindeki doğru tahminlerin yüzdesi | TP + TN / Toplam |
| Kesinlik | Olumlu tahminlerden kaç tanesi doğru? | TP / (TP + FP) |
| Hatırlamak | Gerçek pozitiflerden kaç tanesi bulundu? | TP / (TP + FN) |
| F1 Skorları | Kesinlik ve geri çağırmanın harmonik ortalaması | 2 * (P * R) / (P + R) |
Confusion Matrix (predizioni vs realta):
Predetto: aereo auto uccel gatto cervo cane rana caval nave camion
Reale:
aereo [92] 1 2 0 0 0 1 0 3 1
auto 0 [95] 0 0 0 0 0 0 1 4
uccello 3 0 [85] 3 2 2 3 1 1 0
gatto 0 1 2 [78] 1 12 3 2 0 1
cervo 1 0 3 2 [88] 1 2 3 0 0
Interpretazione:
- Diagonale = predizioni corrette (più alto = meglio)
- Fuori diagonale = errori (confusioni tra classi)
- gatto vs cane: 12 gatti classificati come cani --> classi "confuse"
from sklearn.metrics import (
classification_report,
confusion_matrix
)
import numpy as np
def evaluate_model(
model: nn.Module,
test_loader: DataLoader,
device: torch.device,
class_names: list[str]
) -> dict:
"""Valuta il modello e restituisce metriche dettagliate."""
model.eval()
all_preds = []
all_labels = []
with torch.no_grad():
for images, labels in test_loader:
images = images.to(device)
outputs = model(images)
_, predicted = outputs.max(1)
all_preds.extend(predicted.cpu().numpy())
all_labels.extend(labels.numpy())
preds_array = np.array(all_preds)
labels_array = np.array(all_labels)
# Report dettagliato per classe
report = classification_report(
labels_array, preds_array,
target_names=class_names, output_dict=True
)
# Confusion matrix
cm = confusion_matrix(labels_array, preds_array)
# Accuracy globale
accuracy = np.mean(preds_array == labels_array) * 100
print(f"Accuracy globale: {accuracy:.2f}%")
print(classification_report(
labels_array, preds_array, target_names=class_names
))
return {'accuracy': accuracy, 'report': report, 'confusion_matrix': cm}
11. Dağıtım: Eğitimli Modelden Üretime
Bir modeli eğitmek işin yalnızca yarısıdır. Üretime sokmak için ihraç etmeniz gerekiyor optimize edilmiş bir formatta bir çıkarım API'si oluşturun ve her şeyi kapsayıcıya alın ölçeklenebilir dağıtım için.
11.1 Modelin Dışa Aktarılması
Dışa Aktarma Formatları
| Biçim | Kullanmak | Avantajları |
|---|---|---|
| TorchScript | Python olmadan PyTorch'tan Çıkarım | Python bağımlılığı yok, tam serileştirme |
| ONNX | Evrensel format, çoklu çerçeve | TensorRT, OpenVINO, CoreML ile uyumlu |
| TensorRT | NVIDIA GPU'lar için optimize edilmiş çıkarım | Yerel PyTorch'tan 5 kata kadar daha hızlı |
import torch.onnx
def export_model(model: nn.Module, export_path: str) -> None:
"""Esporta il modello in TorchScript e ONNX."""
model.eval()
dummy_input = torch.randn(1, 3, 32, 32)
# --- TorchScript ---
scripted_model = torch.jit.trace(model, dummy_input)
scripted_model.save(f"{export_path}/model_scripted.pt")
print("TorchScript salvato.")
# --- ONNX ---
torch.onnx.export(
model,
dummy_input,
f"{export_path}/model.onnx",
input_names=['image'],
output_names=['prediction'],
dynamic_axes={
'image': {0: 'batch_size'},
'prediction': {0: 'batch_size'}
},
opset_version=17
)
print("ONNX salvato.")
export_model(model, './exports')
11.2 FastAPI ile Çıkarım API'si
# inference_api.py
from fastapi import FastAPI, UploadFile
from PIL import Image
import torch
import torchvision.transforms as transforms
import io
app = FastAPI(title="CNN Image Classifier")
# Carica il modello TorchScript
model = torch.jit.load("./exports/model_scripted.pt")
model.eval()
CLASSES = ['aereo', 'auto', 'uccello', 'gatto', 'cervo',
'cane', 'rana', 'cavallo', 'nave', 'camion']
preprocess = transforms.Compose([
transforms.Resize((32, 32)),
transforms.ToTensor(),
transforms.Normalize(
mean=[0.4914, 0.4822, 0.4465],
std=[0.2470, 0.2435, 0.2616]
),
])
@app.post("/predict")
async def predict(file: UploadFile):
"""Classifica un'immagine caricata."""
image_bytes = await file.read()
image = Image.open(io.BytesIO(image_bytes)).convert("RGB")
tensor = preprocess(image).unsqueeze(0)
with torch.no_grad():
outputs = model(tensor)
probabilities = torch.softmax(outputs, dim=1)
confidence, predicted = probabilities.max(1)
return {
"class": CLASSES[predicted.item()],
"confidence": round(confidence.item() * 100, 2),
"all_probabilities": {
name: round(prob.item() * 100, 2)
for name, prob in zip(CLASSES, probabilities[0])
}
}
# Esecuzione: uvicorn inference_api:app --host 0.0.0.0 --port 8000
11.3 Docker ile Konteynerleştirme
FROM python:3.11-slim
WORKDIR /app
COPY requirements.txt .
RUN pip install --no-cache-dir -r requirements.txt
COPY exports/ ./exports/
COPY inference_api.py .
EXPOSE 8000
CMD ["uvicorn", "inference_api:app", "--host", "0.0.0.0", "--port", "8000"]
# Build: docker build -t cnn-classifier .
# Run: docker run -p 8000:8000 cnn-classifier
# Test: curl -X POST -F "file=@cat.jpg" http://localhost:8000/predict
Pipeline: Training --> Export --> Container --> Deploy
[Training] [Export] [Container] [Deploy]
PyTorch + GPU --> TorchScript/ONNX --> Docker --> Kubernetes
50 epoche ~10 MB file FastAPI Auto-scaling
~92% accuracy Ottimizzato Health checks Load balancer
No dipendenza Python GPU opzionale Monitoring
Alternativa serverless:
Export ONNX --> AWS Lambda + ONNX Runtime --> API Gateway
Pro: Pay-per-use, zero infrastruttura da gestire
Contro: Cold start (~2s), limite 250MB package
Sonuçlar ve Sonraki Adımlar
Bu makalede Evrişimli Sinir Ağları hakkında kapsamlı bir anlayış oluşturduk. temel bilgilerden başlayarak (bilgisayarın görüntüleri nasıl gördüğü, evrişim işlemi) yukarıya doğru pratik uygulamaya (PyTorch'ta kalan bloklarla CNN) ve üretimde dağıtıma (TorchScript, ONNX, FastAPI, Docker).
1998'deki LeNet-5'ten 2022'deki ConvNeXt'e kadar mimarilerin evriminin nasıl olduğunu gördük. bağlantıları atlama (ResNet) gibi fikirler sayesinde performansı giderek geliştirdi, bileşik ölçeklendirme (EfficientNet) ve transformatörden ilham alan tasarım (ConvNeXt).
Hatırlanması Gereken Önemli Noktalar
- CNN'ler istismar ediyor bölge, yük paylaşımı e mekansal değişmezlik görüntüleri verimli bir şekilde işlemek için
- Standart mimari şu modeli takip eder: Conv + BatchNorm + ReLU + Pooling, artan derinlikle tekrarlanır
- Le bağlantıları atla (ResNet), kaybolmayan degradeler olmadan derin ağları eğitmek için gereklidir
- Il öğrenmeyi aktar Özellikle az veriyle sıfırdan eğitime neredeyse her zaman tercih edilir
- La veri artırma genelleme açısından önemlidir ve veri toplama açısından maliyeti sıfırdır
- Üretim için ihracat ONNX o TorchScript ve Docker ile kapsayıcıya alın
Serinin bir sonraki makalesinde konuyu daha derinlemesine ele alacağız. Öğrenmeyi ve İnce Ayarı Aktar: doğru önceden eğitilmiş modelin nasıl seçileceği, aşamalı ince ayar stratejileri, alan uyarlaması ve bilginin damıtılması gibi ileri teknikler. Üçüncü makalede yüzleşeceğiz YOLO ile Nesne Algılamanesne algılama sistemi endüstride en çok kullanılan gerçek zamanlı.
Ek Kaynaklar
- Orijinal ResNet kağıdı: “Görüntü Tanıma için Derin Kalıntı Öğrenme” (He ve diğerleri, 2015)
- Kağıt Dönüşümü: "2020'ler için Bir ConvNet" (Liu ve diğerleri, 2022)
- Kağıt EfficientNet: “EfficientNet: CNN'ler için Model Ölçeklendirmeyi Yeniden Düşünmek” (Tan ve Le, 2019)
- PyTorch Belgeleri: CNN ve Torchvision ile ilgili eğitimler
- CS231n Stanford: Görsel Tanıma için Evrişimli Sinir Ağları (çevrimiçi kurs)
- ONNX Çalışma Zamanı: Optimize edilmiş platformlar arası çıkarım belgeleri







