<jupyter_start><jupyter_text>Notebook này cài đặt mạng học sâu bằng Pytorch cho bộ dữ liệu FashionMNIST. Ta cài đặt 2 kiến trúc: Multi-layer Perceptron là mô hình baseline và Convolutional Neural Network là mô hình cải tiến để dự đoán các class của bộ dữ liệu<jupyter_code># Import một số module cần thiết
import os, sys
import numpy as np
import pandas as pd
import warnings, random
warnings.filterwarnings('ignore')
print(os.listdir('../input/fashionmnist'))<jupyter_output>['t10k-labels-idx1-ubyte', 'train-images-idx3-ubyte', 'fashion-mnist_train.csv', 'train-labels-idx1-ubyte', 't10k-images-idx3-ubyte', 'fashion-mnist_test.csv']<jupyter_text>Load data từ ổ đĩa bằng phương thức read_csv() của pandas.<jupyter_code># Đọc lên tập train và test
train = pd.read_csv('../input/fashionmnist/fashion-mnist_train.csv')
test = pd.read_csv('../input/fashionmnist/fashion-mnist_test.csv')
train.shape, test.shape
train_label = train.label
train.drop(columns = 'label', inplace = True)

test_label = test.label
test.drop(columns = 'label', inplace = True)<jupyter_output><empty_output><jupyter_text>Bước 1: Chuẩn bị dữ liệu<jupyter_code>import torch
from torch import nn
from torch.utils.data import TensorDataset, Dataset, DataLoader, SubsetRandomSampler
from torchvision import datasets, transforms
import random<jupyter_output><empty_output><jupyter_text>Xây dựng class kế thừa từ class Dataset, ta đặt tên là **FashionData**.* Gồm 2 phương thức: get_item( ) and len().* get_item( ) trả về những hình ảnh và nhãn tương ứng và len( ) trả về số lượng phần tử trong dataset.<jupyter_code># Viết class Dataset
class FashionDataset(Dataset):
    def __init__(self, data, label, transform = None):
        self.data = data
        self.label = label
  
    def __len__(self):
        return(len(self.data))

    def __getitem__(self,idx):
        self.x = self.data.loc[idx,:].values
        self.y = self.label.loc[idx]
        return(self.x, self.y)
# Chia dữ liệu ban đầu thành 2 tập train và validation
indices = len(train)
indices = [a for a in range(indices)]
split = 0.20 # Tỉ lệ chia
split = int(np.floor(split*len(train)))
random.shuffle(indices)
train_idx, valid_idx = indices[split:], indices[:split]

train_sampler = SubsetRandomSampler(train_idx)
valid_sampler = SubsetRandomSampler(valid_idx)<jupyter_output><empty_output><jupyter_text>Tạo Dataloader cho tập train, validation và test<jupyter_code># Tạo các DataLoader
training = FashionDataset(train, train_label, transforms.ToTensor())
training_loader = DataLoader(training, batch_size=64, sampler=train_sampler)

valid_loader = DataLoader(training, batch_size=64, sampler=valid_sampler)

testing = FashionDataset(test, test_label, transforms.ToTensor())
testing_loader = DataLoader(testing, batch_size=64)<jupyter_output><empty_output><jupyter_text>Bước 2: Xây dựng kiến trúc mô hìnhChúng ta sẽ xây dựng kiến trúc mạng và huấn luyện nó trên tập train. Liên tục đánh giá nó trên tập validation  2.1) Mô hình Baseline: Multi Layer Perceptron<jupyter_code>pymodel_mlp = nn.Sequential(nn.Linear(784,784),
                        nn.ReLU(),
                        nn.Dropout(p=0.3),
                        nn.BatchNorm1d(784),
                        nn.Linear(784,256),
                        nn.ReLU(),
                        nn.Dropout(p=0.4),
                        nn.BatchNorm1d(256),
                        nn.Linear(256,128),
                        nn.ReLU(),
                        nn.Dropout(p=0.3),
                        nn.BatchNorm1d(128),
                        nn.Linear(128,64),
                        nn.ReLU(),
                        nn.Dropout(p=0.4),
                        nn.BatchNorm1d(64),
                        nn.Linear(64,10),
                        nn.LogSoftmax(dim = 1),)

criterion = nn.NLLLoss()
optimizer = torch.optim.Adam(pymodel_mlp.parameters(), lr = 0.008)
# Nếu có GPU có sẵn thì sử dụng để tính toán nhanh, không thì sử dụng CPU.
device = torch.device("cuda" if torch.cuda.is_available() else "cpu")
pymodel_mlp = pymodel_mlp.to(device)

epoch = 15
valid_score = np.inf
torch_valid_loss = []
torch_valid_acc  = []

for e in range(epoch):
    training_loss = 0
    valid_loss  = 0

    running_loss = 0
    pymodel_mlp.train()
    for image, label in training_loader :
        optimizer.zero_grad()
        image = image.to(device)
        label = label.to(device)
        out = pymodel_mlp(image.float())
        loss = criterion(out,label)
        running_loss += loss.item()
        loss.backward()
        optimizer.step()
  
    with torch.no_grad():
        running_valid = 0
        acc_valid = 0
        pymodel_mlp.eval()
        for image, label in valid_loader:
            image = image.to(device)
            label = label.to(device)
            out = pymodel_mlp(image.float())
            loss = criterion(out, label)
            top_p, top_class = torch.exp(out).topk(1, dim = 1)
            equal = top_class == label.view(top_class.shape)
            accuracy = torch.mean(equal.type(torch.FloatTensor))
            running_valid += loss.item()
            acc_valid += accuracy.item()
    
    if running_valid < valid_score :
        torch.save(pymodel_mlp.state_dict(), 'checkpoint.pth')
        print('\nError changes from {} to {}'.format(valid_score/len(valid_loader), running_valid/len(valid_loader)))
        valid_score = running_valid
        print('Saved model\n')
        
    training_loss = running_loss/len(training_loader)
    valid_loss    = running_valid/len(valid_loader)

    torch_valid_loss.append(valid_loss)
    torch_valid_acc.append(acc_valid/len(valid_loader))
    print('Epoch : %s\nTraining_error : %s\nValid_error    : %s\nAccuracy_valid : %s\n------------------------------' 
          %(e+1, training_loss, valid_loss, acc_valid/len(valid_loader)))<jupyter_output>Error changes from inf to 6.771843608548033
Saved model

Epoch : 1
Training_error : 0.7322680272261302
Valid_error    : 6.771843608548033
Accuracy_valid : 0.8072639627659575
------------------------------
Epoch : 2
Training_error : 0.5962818371852239
Valid_error    : 13.718641571145742
Accuracy_valid : 0.836186835106383
------------------------------
Epoch : 3
Training_error : 0.5740795629024505
Valid_error    : 2094.3073560289563
Accuracy_valid : 0.8265458776595744
------------------------------
Epoch : 4
Training_error : 0.5376429861783981
Valid_error    : 619.3068311193839
Accuracy_valid : 0.84375
------------------------------
Epoch : 5
Training_error : 0.5316599046389262
Valid_error    : 188.66686529674112
Accuracy_valid : 0.8376828457446809
------------------------------
Epoch : 6
Training_error : 0.5182517867485682
Valid_error    : 654.6007492765784
Accuracy_valid : 0.8408410904255319
------------------------------
Epoch : 7
Training_error : 0.4947331133087476
Valid_error    : [...]<jupyter_text>2.2) Mô hình cải tiến: Convolutional Neural Network<jupyter_code>from torch.nn import functional as f
class net(nn.Module):
    def __init__(self):
        super().__init__()
        self.conv2d_32 = nn.Conv2d(1,32,3,padding=1)
        self.conv2d_64 = nn.Conv2d(32,64,3,padding=1)
        self.max2d     = nn.MaxPool2d(2,2)
        self.conv2d_128 = nn.Conv2d(64,128,3,padding=1)
        self.conv2d_256 = nn.Conv2d(128,256,3, stride = 2,padding=1)
        self.linear1    = nn.Linear(3*3*256, 256)
        self.linear2    = nn.Linear(256,64)
        self.linear3    = nn.Linear(64,10)
        self.batch2d1     = nn.BatchNorm2d(64)
        self.batch2d2    = nn.BatchNorm2d(256)
        self.batch1d     = nn.BatchNorm1d(64)
        self.drop      = nn.Dropout(p=0.3)
        self.flat      = nn.Flatten()
    
    def forward(self,x):
        x = x.view(-1,1,28,28)
        x = f.relu(self.conv2d_32(x))
        x = f.relu(self.conv2d_64(x))
        x = self.batch2d1(x)
        x = f.relu(self.max2d(x))
        x = self.drop(x)
        
        x = f.relu(self.conv2d_128(x))
        x = f.relu(self.conv2d_256(x))
        x = self.batch2d2(x)
        x = f.relu(self.max2d(x))
        x = self.drop(x)
        
        x = self.flat(x)
        x = f.relu(self.linear1(x))
        x = self.drop(x)
        x = f.relu(self.linear2(x))
        x = self.drop(x)
        x = self.batch1d(x)
        x = f.log_softmax(self.linear3(x), dim=1)
        return(x)

pymodel_cnn = net()
criterion = nn.NLLLoss()
optimizer = torch.optim.Adam(pymodel_cnn.parameters(), lr = 0.008)
# Nếu có GPU có sẵn thì sử dụng để tính toán nhanh, không thì sử dụng CPU.
device = torch.device("cuda" if torch.cuda.is_available() else "cpu")
pymodel_cnn = pymodel_cnn.to(device)
epoch = 15
valid_score = np.inf
torch_valid_loss_cnn = []
torch_valid_acc_cnn  = []

for e in range(epoch):
    training_loss = 0
    valid_loss  = 0

    running_loss = 0
    pymodel_cnn.train()
    for image, label in training_loader :
        optimizer.zero_grad()
        image = image.to(device)
        label = label.to(device)
        out = pymodel_cnn(image.float())
        loss = criterion(out,label)
        running_loss += loss.item()
        loss.backward()
        optimizer.step()
  
    with torch.no_grad():
        running_valid = 0
        acc_valid = 0
        pymodel_cnn.eval()
        for image, label in valid_loader:
            image = image.to(device)
            label = label.to(device)
            out = pymodel_cnn(image.float())
            loss = criterion(out, label)
            top_p, top_class = torch.exp(out).topk(1, dim = 1)
            equal = top_class == label.view(top_class.shape)
            accuracy = torch.mean(equal.type(torch.FloatTensor))
            running_valid += loss.item()
            acc_valid += accuracy.item()
    
    if running_valid < valid_score :
        torch.save(pymodel_cnn.state_dict(), 'checkpoint_cnn.pth')
        print('\nError changes from {} to {}'.format(valid_score/len(valid_loader), running_valid/len(valid_loader)))
        valid_score = running_valid
        print('Saved model\n')

    training_loss = running_loss/len(training_loader)
    valid_loss    = running_valid/len(valid_loader)

    torch_valid_loss_cnn.append(valid_loss)
    torch_valid_acc_cnn.append(acc_valid/len(valid_loader))
    print('Epoch : %s\nTraining_error : %s\nValid_error    : %s\nAccuracy_valid : %s\n------------------------------' 
          %(e+1, training_loss, valid_loss, acc_valid/len(valid_loader)))<jupyter_output>Error changes from inf to 0.38667745690079447
Saved model

Epoch : 1
Training_error : 0.6233714703321457
Valid_error    : 0.38667745690079447
Accuracy_valid : 0.8584607712765957
------------------------------

Error changes from 0.38667745690079447 to 0.3736149507792706
Saved model

Epoch : 2
Training_error : 0.4194109150568644
Valid_error    : 0.3736149507792706
Accuracy_valid : 0.8848071808510638
------------------------------

Error changes from 0.3736149507792706 to 0.26328977427267014
Saved model

Epoch : 3
Training_error : 0.3568503102560838
Valid_error    : 0.26328977427267014
Accuracy_valid : 0.9043384308510638
------------------------------

Error changes from 0.26328977427267014 to 0.2631223768867711
Saved model

Epoch : 4
Training_error : 0.3243477244079113
Valid_error    : 0.2631223768867711
Accuracy_valid : 0.9053357712765957
------------------------------

Error changes from 0.2631223768867711 to 0.2363481508131991
Saved model

Epoch : 5
Training_error : 0.30347501216332[...]<jupyter_text>Bước 3: <NAME> trên tập testLoad mô hình tốt nhất trên MLP và kiểm tra nó trên tập test<jupyter_code>state = torch.load('checkpoint.pth')
pymodel_mlp.load_state_dict(state)
torch_test_loss  = []
torch_test_acc   = []

for e in range(1):
    testing_loss = 0
    running_test = 0
    acc_test = 0
    pymodel_mlp.eval()
    for image, label in testing_loader:
        image = image.to(device)
        label = label.to(device)
        out = pymodel_mlp(image.float())
        loss = criterion(out, label)
        top_p, top_class = torch.exp(out).topk(1, dim = 1)
        equal = top_class == label.view(top_class.shape)
        accuracy = torch.mean(equal.type(torch.FloatTensor))
        running_test += loss.item()
        acc_test += accuracy.item()
    testing_loss = running_test/len(testing_loader)
    torch_test_loss.append(testing_loss)
    torch_test_acc.append(acc_test/len(testing_loader))
    print('Epoch : %s\nTesting_error : %s\nAccuracy_test : %s\n----------------' %(e+1, testing_loss, acc_test/len(testing_loader)))<jupyter_output>Epoch : 1
Testing_error : 13.163866264425266
Accuracy_test : 0.8158837579617835
----------------<jupyter_text>**ACC trên tập test của MLP là 81.58%** Load mô hình tốt nhất trên CNN và kiểm tra nó trên tập test<jupyter_code>state = torch.load('checkpoint_cnn.pth')
pymodel_cnn.load_state_dict(state)

torch_test_loss_cnn  = []
torch_test_acc_cnn   = []

for e in range(1):
    testing_loss = 0
    running_test = 0
    acc_test = 0
    pymodel_cnn.eval()
    with torch.no_grad():
        for image, label in testing_loader:
            image = image.to(device)
            label = label.to(device)
            out = pymodel_cnn(image.float())
            loss = criterion(out, label)
            top_p, top_class = torch.exp(out).topk(1, dim = 1)
            equal = top_class == label.view(top_class.shape)
            accuracy = torch.mean(equal.type(torch.FloatTensor))
            running_test += loss.item()
            acc_test += accuracy.item()
    testing_loss = running_test/len(testing_loader)
    torch_test_loss_cnn.append(testing_loss)
    torch_test_acc_cnn.append(acc_test/len(testing_loader))
    print('Epoch : %s\nTesting_error : %s\nAccuracy_test : %s\n----------------' %(e+1, testing_loss, acc_test/len(testing_loader)))<jupyter_output>Epoch : 1
Testing_error : 0.19408955674167652
Accuracy_test : 0.9325238853503185
----------------
{'fraction_non_alphanumeric': 0.13566565261480515, 'fraction_numerical': 0.07431551499348109, 'mean_word_length': 2.6720744680851065, 'pattern_counts': {'":': 0, '<': 35, '<?xml version=': 0, '>': 33, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'chain_length': '9', 'dir': 'jupyter-structured-clean-dedup', 'id': '343284', 'license': 'MIT', 'n_tokens_mistral': 5700, 'n_tokens_neox': 5051, 'n_words': 959, 'path': 'fit-cdio-cv-apps-lab01-mlp-cnn-with-pytorch.ipynb', 'repo_name': 'huynhtruc0309/FIT_CDIO_CV_APPS_Lab01', 'size': '13824'}