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>
# 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]])}')

''' 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)
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)
))
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()

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%