.. _sec_kaggle_cifar10:
Kaggle'da İmge Sınıflandırması (CIFAR-10)
=========================================
Şimdiye kadar, doğrudan tensör formatında imge veri kümelerini elde
etmek için derin öğrenme çerçevelerinin üst düzey API'lerini
kullanıyoruz. Ancak, özel imge veri kümeleri genellikle imge dosyaları
halinde gelir. Bu bölümde, ham imge dosyalarından başlayacağız ve
düzenleyeceğiz, okuyacağız, ardından bunları adım adım tensör formatına
dönüştüreceğiz.
Bilgisayarla görmede önemli bir veri kümesi olan
:numref:`sec_image_augmentation` içinde CIFAR-10 veri kümesi ile deney
yaptık. Bu bölümde, CIFAR-10 imge sınıflandırmasının Kaggle yarışmasını
uygulamak için önceki bölümlerde öğrendiğimiz bilgileri uygulayacağız.
Yarışmanın web adresi https://www.kaggle.com/c/cifar-10
:numref:`fig_kaggle_cifar10` yarışmanın web sayfasındaki bilgileri
gösterir. Sonuçları göndermek için bir Kaggle hesabına kayıt olmanız
gerekir.
.. _fig_kaggle_cifar10:
.. figure:: ../img/kaggle-cifar10.png
:width: 600px
CIFAR-10 imge sınıflandırma yarışması web sayfası bilgileri. Yarışma
veri kümesi "Data" ("Veri") sekmesine tıklanarak elde edilebilir.
.. raw:: html
.. raw:: html
.. raw:: latex
\diilbookstyleinputcell
.. code:: python
import collections
import math
import os
import shutil
import pandas as pd
from d2l import mxnet as d2l
from mxnet import gluon, init, npx
from mxnet.gluon import nn
npx.set_np()
.. raw:: html
.. raw:: html
.. raw:: latex
\diilbookstyleinputcell
.. code:: python
import collections
import math
import os
import shutil
import pandas as pd
import torch
import torchvision
from torch import nn
from d2l import torch as d2l
.. raw:: html
.. raw:: html
Veri Kümesini Elde Etme ve Düzenleme
------------------------------------
Yarışma veri kümesi, sırasıyla 50000 ve 300000 imge içeren bir eğitim
kümesi ve bir test kümesine ayrılmıştır. Test kümesinde, değerlendirme
için 10000 imge kullanılacak, kalan 290000 imgeler değerlendirilmeyecek:
Bunlar sadece test kümesinin *manuel* etiketli sonuçlarıyla hile yapmayı
zorlaştırmak için dahil edilmiştir. Bu veri kümesindeki imgeler,
yüksekliği ve genişliği 32 piksel olan png renkli (RGB kanalları) imge
dosyalarıdır. İmgeler, uçaklar, arabalar, kuşlar, kediler, geyik,
köpekler, kurbağalar, atlar, tekneler ve kamyonlar olmak üzere toplam 10
kategoriyi kapsar. :numref:`fig_kaggle_cifar10` şeklinin sol üst
köşesi veri kümesindeki uçakların, arabaların ve kuşların bazı
imgelerini gösterir.
Veri Kümesini İndirme
~~~~~~~~~~~~~~~~~~~~~
Kaggle'a girdi yaptıktan sonra :numref:`fig_kaggle_cifar10` içinde
gösterilen CIFAR-10 imge sınıflandırma yarışması web sayfasındaki “Veri”
("Data") sekmesine tıklayabilir ve “Tümünü İndir” ("Download All")
butonuna tıklayarak veri kümesini indirebiliriz. İndirilen dosyayı
``../data``'da açtıktan ve içinde ``train.7z`` ve ``test.7z``'yı
açtıktan sonra, tüm veri kümesini aşağıdaki yollarda bulacaksınız:
- ``../data/cifar-10/train/[1-50000].png``
- ``../data/cifar-10/test/[1-300000].png``
- ``../data/cifar-10/trainLabels.csv``
- ``../data/cifar-10/sampleSubmission.csv``
``train`` ve ``test`` dizinlerinin sırasıyla eğitim ve test imgelerini
içerdiği, ``trainLabels.csv`` eğitim imgeleri için etiketler sağlar ve
``sample_submission.csv`` örnek bir gönderim dosyasıdır.
Başlamayı kolaylaştırmak için ilk 1000 eğitim imgesi ve 5 rastgele test
imgesi içeren veri kümesinin küçük ölçekli bir örneğini sağlıyoruz.
Kaggle yarışmasının tam veri kümesini kullanmak için aşağıdaki ``demo``
değişkenini ``False`` olarak ayarlamanız gerekir.
.. raw:: html
.. raw:: html
.. raw:: latex
\diilbookstyleinputcell
.. code:: python
#@save
d2l.DATA_HUB['cifar10_tiny'] = (d2l.DATA_URL + 'kaggle_cifar10_tiny.zip',
'2068874e4b9a9f0fb07ebe0ad2b29754449ccacd')
# If you use the full dataset downloaded for the Kaggle competition, set
# `demo` to False
demo = True
if demo:
data_dir = d2l.download_extract('cifar10_tiny')
else:
data_dir = '../data/cifar-10/'
.. raw:: html
.. raw:: html
.. raw:: latex
\diilbookstyleinputcell
.. code:: python
#@save
d2l.DATA_HUB['cifar10_tiny'] = (d2l.DATA_URL + 'kaggle_cifar10_tiny.zip',
'2068874e4b9a9f0fb07ebe0ad2b29754449ccacd')
# If you use the full dataset downloaded for the Kaggle competition, set
# `demo` to False
demo = True
if demo:
data_dir = d2l.download_extract('cifar10_tiny')
else:
data_dir = '../data/cifar-10/'
.. raw:: html
.. raw:: html
Veri Kümesini Düzenleme
~~~~~~~~~~~~~~~~~~~~~~~
Model eğitimini ve testlerini kolaylaştırmak için veri kümeleri
düzenlememiz gerekiyor. Önce csv dosyasındaki etiketleri okuyalım.
Aşağıdaki işlev, dosya adının uzantısız kısmını etiketine eşleyen bir
sözlük döndürür.
.. raw:: html
.. raw:: html
.. raw:: latex
\diilbookstyleinputcell
.. code:: python
#@save
def read_csv_labels(fname):
"""Read `fname` to return a filename to label dictionary."""
with open(fname, 'r') as f:
# Skip the file header line (column name)
lines = f.readlines()[1:]
tokens = [l.rstrip().split(',') for l in lines]
return dict(((name, label) for name, label in tokens))
labels = read_csv_labels(os.path.join(data_dir, 'trainLabels.csv'))
print('# training examples:', len(labels))
print('# classes:', len(set(labels.values())))
.. raw:: latex
\diilbookstyleoutputcell
.. parsed-literal::
:class: output
# training examples: 1000
# classes: 10
.. raw:: html
.. raw:: html
.. raw:: latex
\diilbookstyleinputcell
.. code:: python
#@save
def read_csv_labels(fname):
"""Read `fname` to return a filename to label dictionary."""
with open(fname, 'r') as f:
# Skip the file header line (column name)
lines = f.readlines()[1:]
tokens = [l.rstrip().split(',') for l in lines]
return dict(((name, label) for name, label in tokens))
labels = read_csv_labels(os.path.join(data_dir, 'trainLabels.csv'))
print('# training examples:', len(labels))
print('# classes:', len(set(labels.values())))
.. raw:: latex
\diilbookstyleoutputcell
.. parsed-literal::
:class: output
# training examples: 1000
# classes: 10
.. raw:: html
.. raw:: html
Ardından, ``reorg_train_valid`` işlevini esas eğitim kümesinden
geçerleme kümesini bölmek için tanımlıyoruz. Bu işlevdeki
``valid_ratio`` argümanı, geçerleme kümesindeki örneklerin sayısının
orijinal eğitim kümesindeki örneklerin sayısına oranıdır. Daha somut
olarak, sınıfın en az örnek içeren imge sayısı :math:`n` ve oranı da
:math:`r` olsun. Geçerleme kümesi her sınıf için
:math:`\max(\lfloor nr\rfloor,1)` imge ayırır. Örnek olarak
``valid_ratio=0.1``'i kullanalım. Orijinal eğitim kümesi 50000 imgeye
sahip olduğundan, ``train_valid_test/train`` yolunda eğitim için
kullanılan 45000 imge olacak, diğer 5000 imge ``train_valid_test/valid``
yolunda geçerleme kümesi olarak bölünecek. Veri kümesini düzenledikten
sonra, aynı sınıfın imgeleri aynı klasörün altına yerleştirilir.
.. raw:: html
.. raw:: html
.. raw:: latex
\diilbookstyleinputcell
.. code:: python
#@save
def copyfile(filename, target_dir):
"""Bir dosyayı hedef dizine kopyalayın."""
os.makedirs(target_dir, exist_ok=True)
shutil.copy(filename, target_dir)
#@save
def reorg_train_valid(data_dir, labels, valid_ratio):
"""Doğrulama kümesini orijinal eğitim kümesinden ayırın."""
# Eğitim veri kümesinde en az örneğe sahip sınıfın örnek sayısı
n = collections.Counter(labels.values()).most_common()[-1][1]
# Geçerleme kümesi için sınıf başına örnek sayısı
n_valid_per_label = max(1, math.floor(n * valid_ratio))
label_count = {}
for train_file in os.listdir(os.path.join(data_dir, 'train')):
label = labels[train_file.split('.')[0]]
fname = os.path.join(data_dir, 'train', train_file)
copyfile(fname, os.path.join(data_dir, 'train_valid_test',
'train_valid', label))
if label not in label_count or label_count[label] < n_valid_per_label:
copyfile(fname, os.path.join(data_dir, 'train_valid_test',
'valid', label))
label_count[label] = label_count.get(label, 0) + 1
else:
copyfile(fname, os.path.join(data_dir, 'train_valid_test',
'train', label))
return n_valid_per_label
.. raw:: html
.. raw:: html
.. raw:: latex
\diilbookstyleinputcell
.. code:: python
#@save
def copyfile(filename, target_dir):
"""Bir dosyayı hedef dizine kopyalayın."""
os.makedirs(target_dir, exist_ok=True)
shutil.copy(filename, target_dir)
#@save
def reorg_train_valid(data_dir, labels, valid_ratio):
"""Doğrulama kümesini orijinal eğitim kümesinden ayırın."""
# Eğitim veri kümesinde en az örneğe sahip sınıfın örnek sayısı
n = collections.Counter(labels.values()).most_common()[-1][1]
# Geçerleme kümesi için sınıf başına örnek sayısı
n_valid_per_label = max(1, math.floor(n * valid_ratio))
label_count = {}
for train_file in os.listdir(os.path.join(data_dir, 'train')):
label = labels[train_file.split('.')[0]]
fname = os.path.join(data_dir, 'train', train_file)
copyfile(fname, os.path.join(data_dir, 'train_valid_test',
'train_valid', label))
if label not in label_count or label_count[label] < n_valid_per_label:
copyfile(fname, os.path.join(data_dir, 'train_valid_test',
'valid', label))
label_count[label] = label_count.get(label, 0) + 1
else:
copyfile(fname, os.path.join(data_dir, 'train_valid_test',
'train', label))
return n_valid_per_label
.. raw:: html
.. raw:: html
Aşağıdaki ``reorg_test`` işlevi tahmin sırasında veri yükleme için test
kümesini düzenler.
.. raw:: html
.. raw:: html
.. raw:: latex
\diilbookstyleinputcell
.. code:: python
#@save
def reorg_test(data_dir):
"""Tahmin sırasında veri yüklemesi için test kümesini düzenleyin."""
for test_file in os.listdir(os.path.join(data_dir, 'test')):
copyfile(os.path.join(data_dir, 'test', test_file),
os.path.join(data_dir, 'train_valid_test', 'test',
'unknown'))
.. raw:: html
.. raw:: html
.. raw:: latex
\diilbookstyleinputcell
.. code:: python
#@save
def reorg_test(data_dir):
"""Tahmin sırasında veri yüklemesi için test kümesini düzenleyin."""
for test_file in os.listdir(os.path.join(data_dir, 'test')):
copyfile(os.path.join(data_dir, 'test', test_file),
os.path.join(data_dir, 'train_valid_test', 'test',
'unknown'))
.. raw:: html
.. raw:: html
Son olarak, ``read_csv_labels``, ``reorg_train_valid`` ve ``reorg_test``
yukarıda tanımlanan işlevleri çağırmak için bir işlev kullanıyoruz.
.. raw:: html
.. raw:: html
.. raw:: latex
\diilbookstyleinputcell
.. code:: python
def reorg_cifar10_data(data_dir, valid_ratio):
labels = read_csv_labels(os.path.join(data_dir, 'trainLabels.csv'))
reorg_train_valid(data_dir, labels, valid_ratio)
reorg_test(data_dir)
.. raw:: html
.. raw:: html
.. raw:: latex
\diilbookstyleinputcell
.. code:: python
def reorg_cifar10_data(data_dir, valid_ratio):
labels = read_csv_labels(os.path.join(data_dir, 'trainLabels.csv'))
reorg_train_valid(data_dir, labels, valid_ratio)
reorg_test(data_dir)
.. raw:: html
.. raw:: html
Burada, veri kümesinin küçük ölçekli örneği için toplu iş boyutunu
yalnızca 32 olarak ayarlıyoruz. Kaggle yarışmasının tüm veri kümesini
eğitip test ederken, ``batch_size`` 128 gibi daha büyük bir tamsayıya
ayarlanmalıdır. Eğitim örneklerinin %10'unu hiper parametrelerin
ayarlanması için geçerleme kümesi olarak ayırdık.
.. raw:: html
.. raw:: html
.. raw:: latex
\diilbookstyleinputcell
.. code:: python
batch_size = 32 if demo else 128
valid_ratio = 0.1
reorg_cifar10_data(data_dir, valid_ratio)
.. raw:: html
.. raw:: html
.. raw:: latex
\diilbookstyleinputcell
.. code:: python
batch_size = 32 if demo else 128
valid_ratio = 0.1
reorg_cifar10_data(data_dir, valid_ratio)
.. raw:: html
.. raw:: html
İmge Artırma
------------
Aşırı öğrenmeyi bertaraf etmek için imge artırımı kullanıyoruz. Örneğin,
imgeler eğitim sırasında rastgele yatay olarak çevrilebilir. Renkli
imgelerin üç RGB kanalı için standartlaştırma da gerçekleştirebiliriz.
Aşağıda ayarlayabileceğiniz bu işlemlerin bazıları listelenmektedir.
.. raw:: html
.. raw:: html
.. raw:: latex
\diilbookstyleinputcell
.. code:: python
transform_train = gluon.data.vision.transforms.Compose([
# İmgeyi hem yükseklik hem de genişlikte 40 piksellik bir kareye ölçeklendirin
gluon.data.vision.transforms.Resize(40),
# Orijinal imgenin alanının 0.64 ila 1 katı arasında küçük bir kare
# oluşturmak için hem yükseklik hem de genişlikte 40 piksellik bir kare
# imgeyi rastgele kırpın ve ardından hem yükseklik hem de genişlikte
# 32 piksellik bir kareye ölçeklendirin
gluon.data.vision.transforms.RandomResizedCrop(32, scale=(0.64, 1.0),
ratio=(1.0, 1.0)),
gluon.data.vision.transforms.RandomFlipLeftRight(),
gluon.data.vision.transforms.ToTensor(),
# İmgenin her kanalını standartlaştırın
gluon.data.vision.transforms.Normalize([0.4914, 0.4822, 0.4465],
[0.2023, 0.1994, 0.2010])])
.. raw:: html
.. raw:: html
.. raw:: latex
\diilbookstyleinputcell
.. code:: python
transform_train = torchvision.transforms.Compose([
# İmgeyi hem yükseklik hem de genişlikte 40 piksellik bir kareye ölçeklendirin
torchvision.transforms.Resize(40),
# Orijinal imgenin alanının 0.64 ila 1 katı arasında küçük bir kare
# oluşturmak için hem yükseklik hem de genişlikte 40 piksellik bir kare
# imgeyi rastgele kırpın ve ardından hem yükseklik hem de genişlikte
# 32 piksellik bir kareye ölçeklendirin
torchvision.transforms.RandomResizedCrop(32, scale=(0.64, 1.0),
ratio=(1.0, 1.0)),
torchvision.transforms.RandomHorizontalFlip(),
torchvision.transforms.ToTensor(),
# İmgenin her kanalını standartlaştırın
torchvision.transforms.Normalize([0.4914, 0.4822, 0.4465],
[0.2023, 0.1994, 0.2010])])
.. raw:: html
.. raw:: html
Test sırasında, değerlendirme sonuçlarındaki rastgeleliği ortadan
kaldırmak için yalnızca imgeler üzerinde standartlaştırma
gerçekleştiriyoruz.
.. raw:: html
.. raw:: html
.. raw:: latex
\diilbookstyleinputcell
.. code:: python
transform_test = gluon.data.vision.transforms.Compose([
gluon.data.vision.transforms.ToTensor(),
gluon.data.vision.transforms.Normalize([0.4914, 0.4822, 0.4465],
[0.2023, 0.1994, 0.2010])])
.. raw:: html
.. raw:: html
.. raw:: latex
\diilbookstyleinputcell
.. code:: python
transform_test = torchvision.transforms.Compose([
torchvision.transforms.ToTensor(),
torchvision.transforms.Normalize([0.4914, 0.4822, 0.4465],
[0.2023, 0.1994, 0.2010])])
.. raw:: html
.. raw:: html
Veri Kümesini Okuma
-------------------
Ardından, ham imge dosyalarından oluşan düzenlenmiş veri kümesini
okuruz. Her örnek bir imge ve bir etiket içerir.
.. raw:: html
.. raw:: html
.. raw:: latex
\diilbookstyleinputcell
.. code:: python
train_ds, valid_ds, train_valid_ds, test_ds = [
gluon.data.vision.ImageFolderDataset(
os.path.join(data_dir, 'train_valid_test', folder))
for folder in ['train', 'valid', 'train_valid', 'test']]
.. raw:: html
.. raw:: html
.. raw:: latex
\diilbookstyleinputcell
.. code:: python
train_ds, train_valid_ds = [torchvision.datasets.ImageFolder(
os.path.join(data_dir, 'train_valid_test', folder),
transform=transform_train) for folder in ['train', 'train_valid']]
valid_ds, test_ds = [torchvision.datasets.ImageFolder(
os.path.join(data_dir, 'train_valid_test', folder),
transform=transform_test) for folder in ['valid', 'test']]
.. raw:: html
.. raw:: html
Eğitim sırasında yukarıda tanımlanan tüm imge artırım işlemlerini
belirtmemiz gerekir. Geçerleme kümesi hiper parametre ayarlama sırasında
model değerlendirmesi için kullanıldığında, imge artırımdan rastgelelik
getirilmemelidir. Son tahminden önce, tüm etiketlenmiş verileri tam
olarak kullanmak için modeli birleştirilmiş eğitim kümesi ve geçerleme
kümesi üzerinde eğitiriz.
.. raw:: html
.. raw:: html
.. raw:: latex
\diilbookstyleinputcell
.. code:: python
train_iter, train_valid_iter = [gluon.data.DataLoader(
dataset.transform_first(transform_train), batch_size, shuffle=True,
last_batch='discard') for dataset in (train_ds, train_valid_ds)]
valid_iter = gluon.data.DataLoader(
valid_ds.transform_first(transform_test), batch_size, shuffle=False,
last_batch='discard')
test_iter = gluon.data.DataLoader(
test_ds.transform_first(transform_test), batch_size, shuffle=False,
last_batch='keep')
.. raw:: html
.. raw:: html
.. raw:: latex
\diilbookstyleinputcell
.. code:: python
train_iter, train_valid_iter = [torch.utils.data.DataLoader(
dataset, batch_size, shuffle=True, drop_last=True)
for dataset in (train_ds, train_valid_ds)]
valid_iter = torch.utils.data.DataLoader(valid_ds, batch_size, shuffle=False,
drop_last=True)
test_iter = torch.utils.data.DataLoader(test_ds, batch_size, shuffle=False,
drop_last=False)
.. raw:: html
.. raw:: html
Modeli Tanımlama
----------------
.. raw:: html
.. raw:: html
Burada, :numref:`sec_resnet` içinde açıklanan uygulamadan biraz farklı
olan ``HybridBlock`` sınıfına dayanan artık blokları inşa ediyoruz. Bu,
hesaplama verimliliğini artırmak içindir.
.. raw:: latex
\diilbookstyleinputcell
.. code:: python
class Residual(nn.HybridBlock):
def __init__(self, num_channels, use_1x1conv=False, strides=1, **kwargs):
super(Residual, self).__init__(**kwargs)
self.conv1 = nn.Conv2D(num_channels, kernel_size=3, padding=1,
strides=strides)
self.conv2 = nn.Conv2D(num_channels, kernel_size=3, padding=1)
if use_1x1conv:
self.conv3 = nn.Conv2D(num_channels, kernel_size=1,
strides=strides)
else:
self.conv3 = None
self.bn1 = nn.BatchNorm()
self.bn2 = nn.BatchNorm()
def hybrid_forward(self, F, X):
Y = F.npx.relu(self.bn1(self.conv1(X)))
Y = self.bn2(self.conv2(Y))
if self.conv3:
X = self.conv3(X)
return F.npx.relu(Y + X)
Ardından, ResNet-18 modelini tanımlıyoruz.
.. raw:: latex
\diilbookstyleinputcell
.. code:: python
def resnet18(num_classes):
net = nn.HybridSequential()
net.add(nn.Conv2D(64, kernel_size=3, strides=1, padding=1),
nn.BatchNorm(), nn.Activation('relu'))
def resnet_block(num_channels, num_residuals, first_block=False):
blk = nn.HybridSequential()
for i in range(num_residuals):
if i == 0 and not first_block:
blk.add(Residual(num_channels, use_1x1conv=True, strides=2))
else:
blk.add(Residual(num_channels))
return blk
net.add(resnet_block(64, 2, first_block=True),
resnet_block(128, 2),
resnet_block(256, 2),
resnet_block(512, 2))
net.add(nn.GlobalAvgPool2D(), nn.Dense(num_classes))
return net
Eğitim başlamadan önce :numref:`subsec_xavier` içinde açıklanan Xavier
ilkletme işlemini kullanıyoruz.
.. raw:: latex
\diilbookstyleinputcell
.. code:: python
def get_net(devices):
num_classes = 10
net = resnet18(num_classes)
net.initialize(ctx=devices, init=init.Xavier())
return net
loss = gluon.loss.SoftmaxCrossEntropyLoss()
.. raw:: html
.. raw:: html
:numref:`sec_resnet`'te açıklanan ResNet-18 modelini tanımlıyoruz.
.. raw:: latex
\diilbookstyleinputcell
.. code:: python
def get_net():
num_classes = 10
net = d2l.resnet18(num_classes, 3)
return net
loss = nn.CrossEntropyLoss(reduction="none")
.. raw:: html
.. raw:: html
Eğitim Fonksiyonunu Tanımlama
-----------------------------
Modelleri seçeceğiz ve hiper parametreleri geçerleme kümesindeki modelin
performansına göre ayarlayacağız. Aşağıda, model eğitim fonksiyonunu,
``train``, tanımlıyoruz.
.. raw:: html
.. raw:: html
.. raw:: latex
\diilbookstyleinputcell
.. code:: python
def train(net, train_iter, valid_iter, num_epochs, lr, wd, devices, lr_period,
lr_decay):
trainer = gluon.Trainer(net.collect_params(), 'sgd',
{'learning_rate': lr, 'momentum': 0.9, 'wd': wd})
num_batches, timer = len(train_iter), d2l.Timer()
legend = ['train loss', 'train acc']
if valid_iter is not None:
legend.append('valid acc')
animator = d2l.Animator(xlabel='epoch', xlim=[1, num_epochs],
legend=legend)
for epoch in range(num_epochs):
metric = d2l.Accumulator(3)
if epoch > 0 and epoch % lr_period == 0:
trainer.set_learning_rate(trainer.learning_rate * lr_decay)
for i, (features, labels) in enumerate(train_iter):
timer.start()
l, acc = d2l.train_batch_ch13(
net, features, labels.astype('float32'), loss, trainer,
devices, d2l.split_batch)
metric.add(l, acc, labels.shape[0])
timer.stop()
if (i + 1) % (num_batches // 5) == 0 or i == num_batches - 1:
animator.add(epoch + (i + 1) / num_batches,
(metric[0] / metric[2], metric[1] / metric[2],
None))
if valid_iter is not None:
valid_acc = d2l.evaluate_accuracy_gpus(net, valid_iter,
d2l.split_batch)
animator.add(epoch + 1, (None, None, valid_acc))
measures = (f'train loss {metric[0] / metric[2]:.3f}, '
f'train acc {metric[1] / metric[2]:.3f}')
if valid_iter is not None:
measures += f', valid acc {valid_acc:.3f}'
print(measures + f'\n{metric[2] * num_epochs / timer.sum():.1f}'
f' examples/sec on {str(devices)}')
.. raw:: html
.. raw:: html
.. raw:: latex
\diilbookstyleinputcell
.. code:: python
def train(net, train_iter, valid_iter, num_epochs, lr, wd, devices, lr_period,
lr_decay):
trainer = torch.optim.SGD(net.parameters(), lr=lr, momentum=0.9,
weight_decay=wd)
scheduler = torch.optim.lr_scheduler.StepLR(trainer, lr_period, lr_decay)
num_batches, timer = len(train_iter), d2l.Timer()
legend = ['train loss', 'train acc']
if valid_iter is not None:
legend.append('valid acc')
animator = d2l.Animator(xlabel='epoch', xlim=[1, num_epochs],
legend=legend)
net = nn.DataParallel(net, device_ids=devices).to(devices[0])
for epoch in range(num_epochs):
net.train()
metric = d2l.Accumulator(3)
for i, (features, labels) in enumerate(train_iter):
timer.start()
l, acc = d2l.train_batch_ch13(net, features, labels,
loss, trainer, devices)
metric.add(l, acc, labels.shape[0])
timer.stop()
if (i + 1) % (num_batches // 5) == 0 or i == num_batches - 1:
animator.add(epoch + (i + 1) / num_batches,
(metric[0] / metric[2], metric[1] / metric[2],
None))
if valid_iter is not None:
valid_acc = d2l.evaluate_accuracy_gpu(net, valid_iter)
animator.add(epoch + 1, (None, None, valid_acc))
scheduler.step()
measures = (f'train loss {metric[0] / metric[2]:.3f}, '
f'train acc {metric[1] / metric[2]:.3f}')
if valid_iter is not None:
measures += f', valid acc {valid_acc:.3f}'
print(measures + f'\n{metric[2] * num_epochs / timer.sum():.1f}'
f' examples/sec on {str(devices)}')
.. raw:: html
.. raw:: html
Modeli Eğitme ve Geçerleme
--------------------------
Şimdi, modeli eğitebilir ve geçerleyebiliriz. Aşağıdaki tüm hiper
parametreler ayarlanabilir. Örneğin, dönem sayısını artırabiliriz.
``lr_period`` ve ``lr_decay`` sırasıyla 4 ve 0.9 olarak ayarlandığında,
optimizasyon algoritmasının öğrenme oranı her 4 dönem sonrasında 0.9 ile
çarpılır. Sadece gösterim kolaylığı için, burada sadece 20 dönemlik
eğitim yapıyoruz.
.. raw:: html
.. raw:: html
.. raw:: latex
\diilbookstyleinputcell
.. code:: python
devices, num_epochs, lr, wd = d2l.try_all_gpus(), 20, 0.02, 5e-4
lr_period, lr_decay, net = 4, 0.9, get_net(devices)
net.hybridize()
train(net, train_iter, valid_iter, num_epochs, lr, wd, devices, lr_period,
lr_decay)
.. raw:: latex
\diilbookstyleoutputcell
.. parsed-literal::
:class: output
train loss 0.796, train acc 0.715, valid acc 0.406
239.5 examples/sec on [gpu(0), gpu(1)]
.. figure:: output_kaggle-cifar10_42a34e_126_1.svg
.. raw:: html
.. raw:: html
.. raw:: latex
\diilbookstyleinputcell
.. code:: python
devices, num_epochs, lr, wd = d2l.try_all_gpus(), 20, 2e-4, 5e-4
lr_period, lr_decay, net = 4, 0.9, get_net()
train(net, train_iter, valid_iter, num_epochs, lr, wd, devices, lr_period,
lr_decay)
.. raw:: latex
\diilbookstyleoutputcell
.. parsed-literal::
:class: output
train loss 0.832, train acc 0.704, valid acc 0.484
1049.5 examples/sec on [device(type='cuda', index=0), device(type='cuda', index=1)]
.. figure:: output_kaggle-cifar10_42a34e_129_1.svg
.. raw:: html
.. raw:: html
Test Kümesini Sınıflandırma ve Kaggle'da Sonuçları Teslim Etme
--------------------------------------------------------------
Hiper parametrelerle umut verici bir model elde ettikten sonra, modeli
yeniden eğitmek ve test kümesini sınıflandırmak için tüm etiketli
verileri (geçerleme kümesi dahil) kullanırız.
.. raw:: html
.. raw:: html
.. raw:: latex
\diilbookstyleinputcell
.. code:: python
net, preds = get_net(devices), []
net.hybridize()
train(net, train_valid_iter, None, num_epochs, lr, wd, devices, lr_period,
lr_decay)
for X, _ in test_iter:
y_hat = net(X.as_in_ctx(devices[0]))
preds.extend(y_hat.argmax(axis=1).astype(int).asnumpy())
sorted_ids = list(range(1, len(test_ds) + 1))
sorted_ids.sort(key=lambda x: str(x))
df = pd.DataFrame({'id': sorted_ids, 'label': preds})
df['label'] = df['label'].apply(lambda x: train_valid_ds.synsets[x])
df.to_csv('submission.csv', index=False)
.. raw:: latex
\diilbookstyleoutputcell
.. parsed-literal::
:class: output
train loss 0.708, train acc 0.751
530.0 examples/sec on [gpu(0), gpu(1)]
.. figure:: output_kaggle-cifar10_42a34e_135_1.svg
.. raw:: html
.. raw:: html
.. raw:: latex
\diilbookstyleinputcell
.. code:: python
net, preds = get_net(), []
train(net, train_valid_iter, None, num_epochs, lr, wd, devices, lr_period,
lr_decay)
for X, _ in test_iter:
y_hat = net(X.to(devices[0]))
preds.extend(y_hat.argmax(dim=1).type(torch.int32).cpu().numpy())
sorted_ids = list(range(1, len(test_ds) + 1))
sorted_ids.sort(key=lambda x: str(x))
df = pd.DataFrame({'id': sorted_ids, 'label': preds})
df['label'] = df['label'].apply(lambda x: train_valid_ds.classes[x])
df.to_csv('submission.csv', index=False)
.. raw:: latex
\diilbookstyleoutputcell
.. parsed-literal::
:class: output
train loss 0.717, train acc 0.759
1209.9 examples/sec on [device(type='cuda', index=0), device(type='cuda', index=1)]
.. figure:: output_kaggle-cifar10_42a34e_138_1.svg
.. raw:: html
.. raw:: html
Yukarıdaki kod, biçimi Kaggle yarışmasının gereksinimini karşılayan bir
``submission.csv`` dosyası oluşturacaktır. Sonuçları Kaggle'a gönderme
yöntemi, :numref:`sec_kaggle_house` içindeki yönteme benzerdir.
Özet
----
- Gerekli formata düzenledikten sonra ham imge dosyalarını içeren veri
kümelerini okuyabiliriz.
.. raw:: html
.. raw:: html
- Bir imge sınıflandırma yarışmasında, evrişimli sinir ağlarını, imge
artırmayı ve hibrit programlamayı kullanabiliriz.
.. raw:: html
.. raw:: html
- Bir imge sınıflandırma yarışmasında evrişimli sinir ağları ve imge
artırmayı kullanabiliriz.
.. raw:: html
.. raw:: html
Alıştırmalar
------------
1. Bu Kaggle yarışması için CIFAR-10 veri kümesinin tamamını kullanın.
Hiper parametreleri ``batch_size = 128``, ``num_epochs = 100``,
``lr = 0.1``, ``lr_period = 50`` ve ``lr_decay = 0.1`` olarak
ayarlayın. Bu yarışmada hangi doğruluk ve sıralamayı elde
edebileceğinizi görün. Onları daha da geliştirebilir misin?
2. İmge artırmayı kullanmadığınızda hangi doğruluğu elde edebilirsiniz?
.. raw:: html
.. raw:: html
`Tartışmalar `__
.. raw:: html
.. raw:: html
`Tartışmalar `__
.. raw:: html
.. raw:: html