Sekarang A.I, M.L menjadi topik hangat, kami akan melakukan pembelajaran mendalam. Ini akan menjadi hal yang cukup sederhana. Sekadar mengetahui arsitektur dasar dan sebagainya. Sebelum kita melanjutkan, pastikan Anda telah menyiapkan Python 3 (sebaiknya) dan Anaconda. Semua langkah pengaturan dan repo kode dapat ditemukan di sini. Mari kita gali lebih dalam.

Impor Perpustakaan

import torch
import numpy as np
from torchvision import datasets
import torchvision.transforms as transforms
from torch.utils.data.sampler import SubsetRandomSampler

Persiapan data

Pengunduhan mungkin memakan waktu beberapa saat, dan Anda akan melihat kemajuan Anda saat data dimuat. Anda juga dapat memilih untuk mengubah batch_size jika Anda ingin memuat lebih banyak data sekaligus. Sel ini akan membuat DataLoader untuk setiap kumpulan data kita.

# number of subprocesses to use for data loading
num_workers = 0
# how many samples per batch to load
batch_size = 20
# percentage of training set to use as validation
valid_size = 0.2
# convert data to torch.FloatTensor
transform = transforms.ToTensor()
# choose the training and testing datasets
train_data = datasets.MNIST(root = 'data', train = True, download = True, transform = transform)
test_data = datasets.MNIST(root = 'data', train = False, download = True, transform = transform)
# obtain training indices that will be used for validation
num_train = len(train_data)
indices = list(range(num_train))
np.random.shuffle(indices)
split = int(np.floor(valid_size * num_train))
train_index, valid_index = indices[split:], indices[:split]
# define samplers for obtaining training and validation batches
train_sampler = SubsetRandomSampler(train_index)
valid_sampler = SubsetRandomSampler(valid_index)
# prepare data loaders
train_loader = torch.utils.data.DataLoader(train_data, batch_size = batch_size, 
                                           sampler = train_sampler, num_workers = num_workers)
valid_loader = torch.utils.data.DataLoader(train_data, batch_size = batch_size,
                                          sampler = valid_sampler, num_workers = num_workers)
test_loader = torch.utils.data.DataLoader(test_data, batch_size = batch_size,
                                         num_workers = num_workers)

Visualisasikan sekumpulan data pelatihan

Langkah pertama dalam tugas klasifikasi adalah melihat data, memastikan data dimuat dengan benar, lalu melakukan observasi awal tentang pola dalam data tersebut.

import matplotlib.pyplot as plt
%matplotlib inline
    
# obtain one batch of training images
dataiter = iter(train_loader)
images, labels = dataiter.next()
images = images.numpy()
# plot the images in the batch, along with the corresponding labels
fig = plt.figure(figsize=(25, 4))
for idx in np.arange(20):
    ax = fig.add_subplot(2, 20/2, idx+1, xticks=[], yticks=[])
    ax.imshow(np.squeeze(images[idx]), cmap='gray')
    # print out the correct label for each image
    # .item() gets the value contained in a Tensor
    ax.set_title(str(labels[idx].item()))

Lihat Gambar Lebih Detail

img = np.squeeze(images[1])
fig = plt.figure(figsize = (12,12)) 
ax = fig.add_subplot(111)
ax.imshow(img, cmap='gray')
width, height = img.shape
thresh = img.max()/2.5
for x in range(width):
    for y in range(height):
        val = round(img[x][y],2) if img[x][y] !=0 else 0
        ax.annotate(str(val), xy=(y,x),
                    horizontalalignment='center',
                    verticalalignment='center',
                    color='white' if img[x][y]<thresh else 'black')

Definisikan Arsitektur Jaringan

Arsitektur akan bertanggung jawab untuk melihat Tensor nilai piksel 784-dim sebagai masukan untuk setiap gambar, dan menghasilkan Tensor dengan panjang 10 (jumlah kelas kami) yang menunjukkan skor kelas untuk gambar masukan. Contoh khusus ini menggunakan dua lapisan tersembunyi dan dropout untuk menghindari overfitting.

import torch.nn as nn
import torch.nn.functional as F
# define NN architecture
class Net(nn.Module):
    def __init__(self):
        super(Net,self).__init__()
        # number of hidden nodes in each layer (512)
        hidden_1 = 512
        hidden_2 = 512
        # linear layer (784 -> hidden_1)
        self.fc1 = nn.Linear(28*28, 512)
        # linear layer (n_hidden -> hidden_2)
        self.fc2 = nn.Linear(512,512)
        # linear layer (n_hidden -> 10)
        self.fc3 = nn.Linear(512,10)
        # dropout layer (p=0.2)
        # dropout prevents overfitting of data
        self.droput = nn.Dropout(0.2)
        
    def forward(self,x):
        # flatten image input
        x = x.view(-1,28*28)
        # add hidden layer, with relu activation function
        x = F.relu(self.fc1(x))
        # add dropout layer
        x = self.droput(x)
         # add hidden layer, with relu activation function
        x = F.relu(self.fc2(x))
        # add dropout layer
        x = self.droput(x)
        # add output layer
        x = self.fc3(x)
        return x
# initialize the NN
model = Net()
print(model)

Tentukan fungsi Kerugian dan Pengoptimal

Disarankan agar Anda menggunakan kerugian lintas entropi untuk klasifikasi. Jika Anda melihat dokumentasi (ditautkan di atas), Anda dapat melihat bahwa fungsi entropi silang PyTorch menerapkan fungsi softmax ke lapisan keluaran dan kemudian menghitung kehilangan log.

# specify loss function (categorical cross-entropy)
criterion = nn.CrossEntropyLoss()
# specify optimizer (stochastic gradient descent) and learning rate = 0.01
optimizer = torch.optim.SGD(model.parameters(),lr = 0.01)

Latih jaringan

Langkah-langkah untuk pelatihan/pembelajaran dari sekumpulan data dijelaskan dalam komentar di bawah ini: Hapus gradien dari semua variabel yang dioptimalkan Terusan maju: hitung keluaran yang diprediksi dengan meneruskan masukan ke model Hitung kerugiannya Lintasan mundur: hitung gradien kerugian dengan hormat untuk memodelkan parameter Lakukan satu langkah pengoptimalan (pembaruan parameter) Perbarui kerugian pelatihan rata-rata Loop berikut dilatih selama 50 epoch; lihatlah bagaimana nilai kerugian pelatihan menurun seiring waktu. Kami ingin menguranginya sekaligus menghindari overfitting pada data pelatihan.

# number of epochs to train the model
n_epochs = 50
# initialize tracker for minimum validation loss
valid_loss_min = np.Inf  # set initial "min" to infinity
for epoch in range(n_epochs):
    # monitor losses
    train_loss = 0
    valid_loss = 0
    
     
    ###################
    # train the model #
    ###################
    model.train() # prep model for training
    for data,label in train_loader:
        # clear the gradients of all optimized variables
        optimizer.zero_grad()
        # forward pass: compute predicted outputs by passing inputs to the model
        output = model(data)
        # calculate the loss
        loss = criterion(output,label)
        # backward pass: compute gradient of the loss with respect to model parameters
        loss.backward()
        # perform a single optimization step (parameter update)
        optimizer.step()
        # update running training loss
        train_loss += loss.item() * data.size(0)
        
        
     ######################    
    # validate the model #
    ######################
    model.eval()  # prep model for evaluation
    for data,label in valid_loader:
        # forward pass: compute predicted outputs by passing inputs to the model
        output = model(data)
        # calculate the loss
        loss = criterion(output,label)
        # update running validation loss 
        valid_loss = loss.item() * data.size(0)
    
    # print training/validation statistics 
    # calculate average loss over an epoch
    train_loss = train_loss / len(train_loader.sampler)
    valid_loss = valid_loss / len(valid_loader.sampler)
    
    print('Epoch: {} \tTraining Loss: {:.6f} \tValidation Loss: {:.6f}'.format(
        epoch+1, 
        train_loss,
        valid_loss
        ))
    
    # save model if validation loss has decreased
    if valid_loss <= valid_loss_min:
        print('Validation loss decreased ({:.6f} --> {:.6f}).  Saving model ...'.format(
        valid_loss_min,
        valid_loss))
        torch.save(model.state_dict(), 'model.pt')
        valid_loss_min = valid_loss

Muat Model dengan Kerugian Validasi Terendah

model.load_state_dict(torch.load('model.pt'))

Uji Jaringan yang dilatih

Terakhir, kami menguji model terbaik kami pada data pengujian yang sebelumnya tidak terlihat dan mengevaluasi performanya. Menguji data yang tidak terlihat adalah cara yang baik untuk memeriksa apakah model kita dapat digeneralisasi dengan baik. Mungkin berguna juga untuk menganalisis secara terperinci dan melihat bagaimana kinerja model ini di setiap kelas serta melihat kerugian dan keakuratannya secara keseluruhan.

# initialize lists to monitor test loss and accuracy
test_loss = 0.0
class_correct = list(0. for i in range(10))
class_total = list(0. for i in range(10))
model.eval() # prep model for evaluation
for data, target in test_loader:
    # forward pass: compute predicted outputs by passing inputs to the model
    output = model(data)
    # calculate the loss
    loss = criterion(output, target)
    # update test loss 
    test_loss += loss.item()*data.size(0)
    # convert output probabilities to predicted class
    _, pred = torch.max(output, 1)
    # compare predictions to true label
    correct = np.squeeze(pred.eq(target.data.view_as(pred)))
    # calculate test accuracy for each object class
    for i in range(len(target)):
        label = target.data[i]
        class_correct[label] += correct[i].item()
        class_total[label] += 1
# calculate and print avg test loss
test_loss = test_loss/len(test_loader.sampler)
print('Test Loss: {:.6f}\n'.format(test_loss))
for i in range(10):
    if class_total[i] > 0:
        print('Test Accuracy of %5s: %2d%% (%2d/%2d)' % (
            str(i), 100 * class_correct[i] / class_total[i],
            np.sum(class_correct[i]), np.sum(class_total[i])))
    else:
        print('Test Accuracy of %5s: N/A (no training examples)' % (classes[i]))
print('\nTest Accuracy (Overall): %2d%% (%2d/%2d)' % (
    100. * np.sum(class_correct) / np.sum(class_total),
    np.sum(class_correct), np.sum(class_total)))

Visualisasikan Contoh Hasil Tes

Sel ini menampilkan gambar uji dan labelnya dalam format ini: prediksi (kebenaran dasar). Teks akan berwarna hijau untuk contoh yang diklasifikasikan secara akurat dan merah untuk prediksi yang salah.

# obtain one batch of test images
dataiter = iter(test_loader)
images, labels = dataiter.next()
# get sample outputs
output = model(images)
# convert output probabilities to predicted class
_, preds = torch.max(output, 1)
# prep images for display
images = images.numpy()
# plot the images in the batch, along with predicted and true labels
fig = plt.figure(figsize=(25, 4))
for idx in np.arange(20):
    ax = fig.add_subplot(2, 20/2, idx+1, xticks=[], yticks=[])
    ax.imshow(np.squeeze(images[idx]), cmap='gray')
    ax.set_title("{} ({})".format(str(preds[idx].item()), str(labels[idx].item())),
                 color=("green" if preds[idx]==labels[idx] else "red"))