VGG16_Implementation on CIFAR10

장성민·2021년 2월 19일

Implementation

목록 보기
1/1
post-thumbnail

VGG16_Implementation on CIFAR10

import torch
import torch.nn as nn
import torch.optim as optim
from torch.utils.data import DataLoader

import torchvision.datasets as datasets
import torchvision.transforms as transforms


import numpy as np
import matplotlib.pyplot as plt
torch.manual_seed(0)

<torch._C.Generator at 0x7f662cd9eb58>

Data: CIFAR10

# standardization
standardization = transforms.Compose([
    transforms.ToTensor(),
    transforms.Normalize(mean=[0.4913, 0.4821, 0.4465], std = [0.2470, 0.2434, 0.2615])
])

train_dataset = datasets.CIFAR10(root = './data', train=True, download=True, transform=standardization)
test_dataset = datasets.CIFAR10(root = './data', train=False, download=True, transform=standardization)
BATCH_SIZE = 64
train_loader = DataLoader(dataset = train_dataset, batch_size = BATCH_SIZE, shuffle=True)
test_loader = DataLoader(dataset = test_dataset, batch_size = BATCH_SIZE, shuffle=True)
print('train:', train_loader.dataset.data.shape) # 32 by 32 pictures with RGB channels
print('test:', test_loader.dataset.data.shape)

train: (50000, 32, 32, 3)
test: (10000, 32, 32, 3)

np.random.seed(42)
random_train_pictures = [np.random.randint(1, 50000) for i in range(10)]

plt.figure(figsize=(20, 2))
for i in range(len(random_train_pictures)):
    plt.subplot(1, 10, i+1)
    plt.imshow(train_loader.dataset.data[random_train_pictures[i]])
    plt.axis('off')
    plt.title(f'Class: {str(train_loader.dataset.targets[random_train_pictures[i]])}')

VGG 16 modeling

''' 1. make_layers: 13개의 conv층 ''' # 13 + 3 = vgg16

cfg = {'13conv2d': [8, 8, 'M', 16, 16, 32, 32, 32,
                    'M', 64, 64, 128, 128, 256, 256, 'M']}

def make_layers(cfg, batch_norm=True):
    layers = []
    in_channels = 3
    
    for v in cfg:
        if v == 'M':
            layers += [nn.MaxPool2d(kernel_size=2, stride=2)]
        else:
            conv2d = nn.Conv2d(in_channels, v, kernel_size=3, padding=1)
            if batch_norm:
                layers += [conv2d, nn.BatchNorm2d(v), nn.ReLU(inplace=True)]
            else:
                layers += [conv2d, nn.ReLU(inplace=True)]
            in_channels = v
            
    return nn.Sequential(*layers)
conv = make_layers(cfg['13conv2d'], batch_norm=True)
''' 2. VGG Implementation '''

class VGG(nn.Module):
    def __init__(self, conv_layers, num_classes=10, init_weights=True):
        super(VGG, self).__init__()
        
        self.conv_layers = conv_layers
        
        # self.avgpool = nn.AdaptiveAvgPool2d((7, 7))
        
        self.classifier = nn.Sequential(
            nn.Linear(256 * 4 * 4, 2048), # 32->(16, 8, 4): 3번 pooling
            nn.ReLU(True),
            nn.Dropout(),
            nn.Linear(2048, 1024),
            nn.ReLU(True),
            nn.Dropout(),
            nn.Linear(1024, num_classes),
         ) # FC layer
        
        if init_weights:
            self._initialize_weights()
            
    def forward(self, x):
        x = self.conv_layers(x)
        #x = self.avgpool(x)
        x = x.view(x.size(0), -1)
        x = self.classifier(x)
        return x
    
    
    def _initialize_weights(self):
        for m in self.modules(): 
            if isinstance(m, nn.Conv2d): 
                nn.init.kaiming_normal_(m.weight, mode='fan_out', nonlinearity='relu')
                if m.bias is not None:  
                    nn.init.constant_(m.bias, 0)
            elif isinstance(m, nn.BatchNorm2d):
                nn.init.constant_(m.weight, 1)
                nn.init.constant_(m.bias, 0)
            elif isinstance(m, nn.Linear):
                nn.init.normal_(m.weight, 0, 0.01)
                nn.init.constant_(m.bias, 0)
vgg16 = VGG(conv, num_classes=10, init_weights=True)

Optimizer & Loss

DEVICE = 'cuda' if torch.cuda.is_available() else 'cpu'

model = vgg16.to(DEVICE)
loss_func = nn.CrossEntropyLoss()
optimizer = optim.Adam(model.parameters(), lr=0.002)
lr_sche = optim.lr_scheduler.StepLR(optimizer, step_size=5, gamma=0.9)
    # -> 5 step을 거칠 때마다, lr을 x0.9만큼 줄여주면서 학습시킨다.

for i in model.named_children():
    print(i)

('conv_layers', Sequential(
(0): Conv2d(3, 8, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1))
(1): BatchNorm2d(8, eps=1e-05, momentum=0.1, affine=True, track_running_stats=True)
(2): ReLU(inplace=True)
(3): Conv2d(8, 8, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1))
(4): BatchNorm2d(8, eps=1e-05, momentum=0.1, affine=True, track_running_stats=True)
(5): ReLU(inplace=True)
(6): MaxPool2d(kernel_size=2, stride=2, padding=0, dilation=1, ceil_mode=False)
(7): Conv2d(8, 16, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1))
(8): BatchNorm2d(16, eps=1e-05, momentum=0.1, affine=True, track_running_stats=True)
(9): ReLU(inplace=True)
(10): Conv2d(16, 16, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1))
(11): BatchNorm2d(16, eps=1e-05, momentum=0.1, affine=True, track_running_stats=True)
(12): ReLU(inplace=True)
(13): Conv2d(16, 32, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1))
(14): BatchNorm2d(32, eps=1e-05, momentum=0.1, affine=True, track_running_stats=True)
(15): ReLU(inplace=True)
(16): Conv2d(32, 32, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1))
(17): BatchNorm2d(32, eps=1e-05, momentum=0.1, affine=True, track_running_stats=True)
(18): ReLU(inplace=True)
(19): Conv2d(32, 32, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1))
(20): BatchNorm2d(32, eps=1e-05, momentum=0.1, affine=True, track_running_stats=True)
(21): ReLU(inplace=True)
(22): MaxPool2d(kernel_size=2, stride=2, padding=0, dilation=1, ceil_mode=False)
(23): Conv2d(32, 64, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1))
(24): BatchNorm2d(64, eps=1e-05, momentum=0.1, affine=True, track_running_stats=True)
(25): ReLU(inplace=True)
(26): Conv2d(64, 64, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1))
(27): BatchNorm2d(64, eps=1e-05, momentum=0.1, affine=True, track_running_stats=True)
(28): ReLU(inplace=True)
(29): Conv2d(64, 128, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1))
(30): BatchNorm2d(128, eps=1e-05, momentum=0.1, affine=True, track_running_stats=True)
(31): ReLU(inplace=True)
(32): Conv2d(128, 128, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1))
(33): BatchNorm2d(128, eps=1e-05, momentum=0.1, affine=True, track_running_stats=True)
(34): ReLU(inplace=True)
(35): Conv2d(128, 256, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1))
(36): BatchNorm2d(256, eps=1e-05, momentum=0.1, affine=True, track_running_stats=True)
(37): ReLU(inplace=True)
(38): Conv2d(256, 256, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1))
(39): BatchNorm2d(256, eps=1e-05, momentum=0.1, affine=True, track_running_stats=True)
(40): ReLU(inplace=True)
(41): MaxPool2d(kernel_size=2, stride=2, padding=0, dilation=1, ceil_mode=False)
))
('classifier', Sequential(
(0): Linear(in_features=4096, out_features=2048, bias=True)
(1): ReLU(inplace=True)
(2): Dropout(p=0.5, inplace=False)
(3): Linear(in_features=2048, out_features=1024, bias=True)
(4): ReLU(inplace=True)
(5): Dropout(p=0.5, inplace=False)
(6): Linear(in_features=1024, out_features=10, bias=True)
))

Training & Test

Training

total_batch = len(train_loader)
loss_arr = []
epochs = 20

for epoch in range(epochs):
    avg_loss = 0
    lr_sche.step()
    for num, (image, label) in enumerate(train_loader):
        x = image.to(DEVICE)
        y_ = label.to(DEVICE)
        
        optimizer.zero_grad()
        output = model.forward(x)
        
        loss = loss_func(output, y_)
        loss.backward()
        optimizer.step()
        
        avg_loss += loss / total_batch
        
    loss_arr.append(avg_loss)    
    print(f'[Epoch: {epoch+1} loss = {avg_loss}]')
print('Training Finished !')

[Epoch: 1 loss = 2.0779025554656982][Epoch: 2 loss = 1.6878807544708252]
[Epoch: 3 loss = 1.4266715049743652][Epoch: 4 loss = 1.2422521114349365]
[Epoch: 5 loss = 1.099440336227417][Epoch: 6 loss = 1.0087822675704956]
[Epoch: 7 loss = 0.9483529925346375][Epoch: 8 loss = 0.8998845219612122]
[Epoch: 9 loss = 0.8499659299850464][Epoch: 10 loss = 0.8105672597885132]
[Epoch: 11 loss = 0.7675001621246338][Epoch: 12 loss = 0.7369272708892822]
[Epoch: 13 loss = 0.7075254917144775][Epoch: 14 loss = 0.6865513324737549]
[Epoch: 15 loss = 0.6421639919281006][Epoch: 16 loss = 0.62006014585495]
[Epoch: 17 loss = 0.5950868129730225][Epoch: 18 loss = 0.5761401653289795]
[Epoch: 19 loss = 0.5545189380645752][Epoch: 20 loss = 0.5190139412879944]
Training Finished !

# 손실 그래프
# matplotlib의 plot 함수를 이용해 손실이 어떻게 줄어가는지 확인합니다. 
plt.plot(loss_arr)
plt.show()

Test

correct = 0
total = 0

with torch.no_grad():
    for num, (image, label) in enumerate(test_loader):
        x = image.to(DEVICE)
        y_ = label.to(DEVICE)
        outputs = model.forward(x)
        
        _, predicted = torch.max(outputs.data, 1)
        
        total += y_.size(0)
        correct += (predicted == y_).sum().item()

print(f'Accuracy: {correct / total * 100}%')

Accuracy: 74.97%

profile
AI린이

0개의 댓글