CNN을 활용한 풍경 이미지 분류 실습1¶
- "problem"이라고 적힌 부분만 코드를 직접 작성하였음을 알림!
In [30]:
import pandas as pd
import os
# 파일과 csv를 포함하는 폴더 경로 지정
path = 'D:/workspaces/WinterStudy2022/5. Deep Learning basic/practice2_scene/Scene-Classification-Dataset-Split-main/'
# 전체 이미지 개수 출력하기
# 파일 os.listdir를 이용하여 디렉토리 내 파일을 리스트화하여 file_list에 저장한다.
file_list = os.listdir(path + 'train/')
print("file_list 확인 : ",file_list[:5])
print("file_list 타입확인 : ", type(file_list))
print('전체 이미지의 개수:', len(file_list))
file_list 확인 : ['buildings', 'forests', 'glacier', 'mountains', 'sea'] file_list 타입확인 : <class 'list'> 전체 이미지의 개수: 6
1. 학습 이미지 개수 출력¶
- 데이터 개수 계산
- os 라이브러리의 os.listdir()을 이용하여 이미지 폴더에 존재하는 파일 이름 목록을 얻을 수 있다.
In [31]:
import os
classes = ['buildings', 'forests', 'glacier', 'mountains', 'sea', 'street']
train_path = 'train/'
val_path = 'val/'
print("[ 학습 데이터셋 ]")
for i in range(6):
print(f'클래스 {i}의 개수: {len(os.listdir(path + train_path + classes[i]))}')
print("[ 검증 데이터셋 ]")
for i in range(6):
print(f'클래스 {i}의 개수: {len(os.listdir(path + val_path + classes[i]))}')
[ 학습 데이터셋 ] 클래스 0의 개수: 2105 클래스 1의 개수: 2205 클래스 2의 개수: 2363 클래스 3의 개수: 2438 클래스 4의 개수: 2224 클래스 5의 개수: 2292 [ 검증 데이터셋 ] 클래스 0의 개수: 523 클래스 1의 개수: 540 클래스 2의 개수: 594 클래스 3의 개수: 599 클래스 4의 개수: 560 클래스 5의 개수: 591
In [32]:
# path 경로를 train_path / val_path에 합치기
train_path = path + train_path
val_path = path + val_path
2. 데이터셋 불러오기¶
- pyTorch의 ImageFolder 라이브러리를 이용하여 자신만의 데이터셋 호출 가능
- ImageFolder 라이브러리는 다음과 같이 계층적인 폴더 구조에서 데이터셋을 불러올 때 사용할 수 있다
In [33]:
import torch
from torchvision import datasets, transforms
device = torch.device("cuda:0" if torch.cuda.is_available() else "cpu") # device object
transforms_train = transforms.Compose([
transforms.RandomResizedCrop((64, 64)),
transforms.RandomHorizontalFlip(),
transforms.ToTensor(),
transforms.Normalize([0.485, 0.456, 0.406], [0.229, 0.224, 0.225]) # 정규화(normalization)
])
transforms_val = transforms.Compose([
transforms.Resize((64, 64)),
transforms.ToTensor(),
transforms.Normalize([0.485, 0.456, 0.406], [0.229, 0.224, 0.225])
])
train_dataset = datasets.ImageFolder(train_path, transforms_train)
val_dataset = datasets.ImageFolder(val_path, transforms_val)
train_dataloader = torch.utils.data.DataLoader(train_dataset, batch_size=32, shuffle=True, num_workers=2)
val_dataloader = torch.utils.data.DataLoader(val_dataset, batch_size=32, shuffle=True, num_workers=2)
print('Training dataset size:', len(train_dataset))
print('Validation dataset size:', len(val_dataset))
class_names = train_dataset.classes
print('Class names:', class_names)
Training dataset size: 13627 Validation dataset size: 3407 Class names: ['buildings', 'forests', 'glacier', 'mountains', 'sea', 'street']
3. 이미지 시각화하기¶
- PyTorch로 불러온 데이터 시각화
- numpy형태로 변형한 뒤 matplotlib을 이용하기
In [5]:
import torchvision
import numpy as np
import matplotlib.pyplot as plt
# 화면에 출력되는 이미지 크기를 적절하게 조절하기
plt.rcParams['figure.figsize'] = [12, 8]
plt.rcParams['figure.dpi'] = 60
plt.rcParams.update({'font.size': 20})
def imshow(image, title):
# torch.Tensor => numpy 변환하기
image = image.numpy().transpose((1, 2, 0))
# 이미지 정규화(normalization) 해제하기
mean = np.array([0.485, 0.456, 0.406])
std = np.array([0.229, 0.224, 0.225])
image = std * image + mean
image = np.clip(image, 0, 1)
# 화면에 이미지 출력하기
plt.imshow(image)
plt.title(title)
plt.show()
# 학습 데이터셋에서 하나의 배치를 불러와 보기
iterator = iter(train_dataloader)
# 현재 배치에 포함된 이미지를 출력하기
inputs, classes = next(iterator)
out = torchvision.utils.make_grid(inputs[:4])
imshow(out, title=[class_names[x] for x in classes[:4]])
Problem1. convolution 연산 이해하기¶
- 출력 높이(output height) = (height + 2 * padding - filter_height)/stride + 1
- 출력 너비(output width) = (width + 2 * padding - filter_width) / stride + 1
- 아래 경우에 대하여 Convolution 연산을 수행한 뒤 출력 차원을 쓰세요
- height = 32, width = 32, filter_height = 5, filter_width = 5, stride = 2, padding = 2
- height = 64, width = 64, filter_height = 3, filter_width = 3, stride = 1, padding = 1
- height = 16, width = 16, filter_height = 4, filter_width = 4, stride = 2, padding = 1
- height = 60, width = 45, filter_height = 8, filter_width = 5, stride = 3, padding = 1
In [34]:
height = [32, 64, 16, 60]
width = [32, 64, 16, 45]
filter_height = [5, 3, 4, 8]
filter_width = [5, 3, 4, 5]
stride = [2, 1, 2, 3]
padding = [2, 1, 1, 1]
for i in range(4):
output_height = (height[i] + 2 * padding[i] - filter_height[i]) // stride[i] + 1
output_width = (width[i] + 2 * padding[i] - filter_width[i]) // stride[i] + 1
# formating을 이용한 출력
print(f'조건 {i+1}')
print(f'출력 높이: {output_height}, 출력 너비: {output_width}')
조건 1 출력 높이: 16, 출력 너비: 16 조건 2 출력 높이: 64, 출력 너비: 64 조건 3 출력 높이: 8, 출력 너비: 8 조건 4 출력 높이: 19, 출력 너비: 15
4. Lenet 아키텍처 이해하기¶
- Convolutional Neural Network를 최초로 적용한 간단한 아키텍처
- Convolution 연산과 Pooling 연산이 사용됨
In [35]:
import torch.nn as nn
import torch.nn.functional as F
class LeNet(nn.Module):
def __init__(self):
super(LeNet, self).__init__()
# → 차원(dimension): (3 x 64 x 64)
self.conv1 = nn.Conv2d(in_channels=3, out_channels=20, kernel_size=5, stride=1, padding=0)
# → 차원(dimension): (20 x 60 x 60)
self.pool1 = nn.MaxPool2d(kernel_size=2, stride=2)
# → 차원(dimension): (20 x 30 x 30)
self.conv2 = nn.Conv2d(in_channels=20, out_channels=50, kernel_size=5, stride=1, padding=0)
# → 차원(dimension): (50 x 26 x 26)
self.pool2 = nn.MaxPool2d(kernel_size=2, stride=2)
# → 차원(dimension): (50 x 13 x 13)
self.fc1 = nn.Linear(50 * 13 * 13, 500)
# → 차원(dimension): (500)
self.fc2 = nn.Linear(500, 6)
# → 차원(dimension): (6)
def forward(self, x):
x = self.pool1(self.conv1(x))
x = self.pool2(self.conv2(x))
x = torch.flatten(x, 1) # 배치(batch)를 제외한 모든 차원 flatten하기
x = F.relu(self.fc1(x))
x = self.fc2(x)
return x
5. 학습 및 평가 함수 이해하기¶
- 별도의 학습 함수와 평가 함수를 작성한다.
In [36]:
def train(net, epoch, optimizer, criterion, train_dataloader):
print('[ Train epoch: %d ]' % epoch)
net.train() # 모델을 학습 모드로 설정
train_loss = 0
correct = 0
total = 0
for batch_idx, (inputs, targets) in enumerate(train_dataloader):
inputs, targets = inputs.to(device), targets.to(device)
optimizer.zero_grad() # 기울기(gradient) 초기화
outputs = net(inputs) # 모델 입력하여 결과 계산
loss = criterion(outputs, targets) # 손실(loss) 값 계산
loss.backward() # 역전파를 통해 기울기(gradient) 계산
optimizer.step() # 계산된 기울기를 이용해 모델 가중치 업데이트
train_loss += loss.item()
_, predicted = outputs.max(1)
total += targets.size(0)
correct += predicted.eq(targets).sum().item()
print('Train accuarcy:', 100. * correct / total)
print('Train average loss:', train_loss / total)
return (100. * correct / total, train_loss / total)
def validate(net, epoch, val_dataloader):
print('[ Validation epoch: %d ]' % epoch)
net.eval() # 모델을 평가 모드로 설정
val_loss = 0
correct = 0
total = 0
for batch_idx, (inputs, targets) in enumerate(val_dataloader):
inputs, targets = inputs.to(device), targets.to(device)
outputs = net(inputs) # 모델 입력하여 결과 계산
val_loss += criterion(outputs, targets).item()
_, predicted = outputs.max(1)
total += targets.size(0)
correct += predicted.eq(targets).sum().item()
print('Accuarcy:', 100. * correct / total)
print('Average loss:', val_loss / total)
return (100. * correct / total, val_loss / total)
6. LeNet 학습하기¶
- LeNet 네트워크 학습
- 학습률을 수정해보면서 결과 확인해보기
- 학습률이 너무 크다면, 발산하여 손실값이 NaN으로 나오며 학습이 안 될 수도 있음
In [37]:
import time
import torch.optim as optim
net = LeNet()
net = net.to(device)
epoch = 30
learning_rate = 0.002
file_name = "LeNet.pt"
criterion = nn.CrossEntropyLoss()
optimizer = optim.SGD(net.parameters(), lr=learning_rate, momentum=0.9, weight_decay=0.0002)
train_result = []
val_result = []
start_time = time.time() # 시작 시간
for i in range(epoch):
train_acc, train_loss = train(net, i, optimizer, criterion, train_dataloader) # 학습(training)
val_acc, val_loss = validate(net, i + 1, val_dataloader) # 검증(validation)
# 학습된 모델 저장하기
state = {
'net': net.state_dict()
}
if not os.path.isdir('checkpoint'):
os.mkdir('checkpoint')
torch.save(state, './checkpoint/' + file_name)
print(f'Model saved! (time elapsed: {time.time() - start_time})')
# 현재 epoch에서의 정확도(accuracy)와 손실(loss) 값 저장하기
train_result.append((train_acc, train_loss))
val_result.append((val_acc, val_loss))
[ Train epoch: 0 ] Train accuarcy: 50.047699420268586 Train average loss: 0.039634443439530674 [ Validation epoch: 1 ] Accuarcy: 64.16201937188141 Average loss: 0.030139371276006764 Model saved! (time elapsed: 73.1419005393982) [ Train epoch: 1 ] Train accuarcy: 58.62625669626477 Train average loss: 0.03394294659897369 [ Validation epoch: 2 ] Accuarcy: 66.36336953331377 Average loss: 0.028052999716474052 Model saved! (time elapsed: 151.98290538787842) [ Train epoch: 2 ] Train accuarcy: 60.19666837895355 Train average loss: 0.03228769730933739 [ Validation epoch: 3 ] Accuarcy: 70.2377458174347 Average loss: 0.025138386173405042 Model saved! (time elapsed: 224.19524884223938) [ Train epoch: 3 ] Train accuarcy: 62.00924634915976 Train average loss: 0.031230858375332085 [ Validation epoch: 4 ] Accuarcy: 68.35926034634576 Average loss: 0.026169342652842344 Model saved! (time elapsed: 270.0648021697998) [ Train epoch: 4 ] Train accuarcy: 63.9539150216482 Train average loss: 0.02984053322528283 [ Validation epoch: 5 ] Accuarcy: 71.3824479013795 Average loss: 0.024633897647222257 Model saved! (time elapsed: 315.93928480148315) [ Train epoch: 5 ] Train accuarcy: 65.18676157628238 Train average loss: 0.029177900861642275 [ Validation epoch: 6 ] Accuarcy: 70.79542119166422 Average loss: 0.02471483010051885 Model saved! (time elapsed: 362.98106503486633) [ Train epoch: 6 ] Train accuarcy: 66.28017905628532 Train average loss: 0.02800294530096885 [ Validation epoch: 7 ] Accuarcy: 73.7892574112122 Average loss: 0.023896897577420684 Model saved! (time elapsed: 408.72923851013184) [ Train epoch: 7 ] Train accuarcy: 67.16812211051588 Train average loss: 0.027548522257950087 [ Validation epoch: 8 ] Accuarcy: 75.96125623715879 Average loss: 0.021529116123556076 Model saved! (time elapsed: 455.25031304359436) [ Train epoch: 8 ] Train accuarcy: 67.63777794085271 Train average loss: 0.02712950853579916 [ Validation epoch: 9 ] Accuarcy: 75.60904021132961 Average loss: 0.02167950276234019 Model saved! (time elapsed: 501.0195255279541) [ Train epoch: 9 ] Train accuarcy: 68.63579658031848 Train average loss: 0.026649458445797244 [ Validation epoch: 10 ] Accuarcy: 73.08482535955386 Average loss: 0.0234595863900298 Model saved! (time elapsed: 546.9631586074829) [ Train epoch: 10 ] Train accuarcy: 68.51838262273428 Train average loss: 0.02671748184533167 [ Validation epoch: 11 ] Accuarcy: 76.60698561784561 Average loss: 0.021853311481033564 Model saved! (time elapsed: 592.965428352356) [ Train epoch: 11 ] Train accuarcy: 69.47237102810597 Train average loss: 0.026101727723427965 [ Validation epoch: 12 ] Accuarcy: 77.13530965658937 Average loss: 0.020693233058989347 Model saved! (time elapsed: 639.0190849304199) [ Train epoch: 12 ] Train accuarcy: 69.9933954648859 Train average loss: 0.02565377031251271 [ Validation epoch: 13 ] Accuarcy: 75.22747285001468 Average loss: 0.02254624634605018 Model saved! (time elapsed: 684.5556094646454) [ Train epoch: 13 ] Train accuarcy: 70.57312688045792 Train average loss: 0.02531854296680626 [ Validation epoch: 14 ] Accuarcy: 77.42882301144702 Average loss: 0.020676554543971316 Model saved! (time elapsed: 730.5323414802551) [ Train epoch: 14 ] Train accuarcy: 70.14016291186614 Train average loss: 0.0255267792291474 [ Validation epoch: 15 ] Accuarcy: 77.10595832110361 Average loss: 0.02028486089759605 Model saved! (time elapsed: 776.5715506076813) [ Train epoch: 15 ] Train accuarcy: 70.50708152931679 Train average loss: 0.02512247682518783 [ Validation epoch: 16 ] Accuarcy: 79.13120046962136 Average loss: 0.019786837236042208 Model saved! (time elapsed: 824.26318359375) [ Train epoch: 16 ] Train accuarcy: 71.6885594775079 Train average loss: 0.02439749713487108 [ Validation epoch: 17 ] Accuarcy: 76.75374229527444 Average loss: 0.020659663170217453 Model saved! (time elapsed: 869.8538494110107) [ Train epoch: 17 ] Train accuarcy: 71.57114551992368 Train average loss: 0.02443455258626148 [ Validation epoch: 18 ] Accuarcy: 78.92574112122101 Average loss: 0.01976679241443821 Model saved! (time elapsed: 916.1279101371765) [ Train epoch: 18 ] Train accuarcy: 71.58582226462171 Train average loss: 0.02423774457961122 [ Validation epoch: 19 ] Accuarcy: 77.13530965658937 Average loss: 0.020708184788784813 Model saved! (time elapsed: 966.1549110412598) [ Train epoch: 19 ] Train accuarcy: 72.11418507375065 Train average loss: 0.023768802405873354 [ Validation epoch: 20 ] Accuarcy: 77.31141766950397 Average loss: 0.020887105283689596 Model saved! (time elapsed: 1022.6466948986053) [ Train epoch: 20 ] Train accuarcy: 73.15623394731048 Train average loss: 0.023658787700307073 [ Validation epoch: 21 ] Accuarcy: 77.13530965658937 Average loss: 0.020281799944538086 Model saved! (time elapsed: 1077.8278753757477) [ Train epoch: 21 ] Train accuarcy: 71.90137227562927 Train average loss: 0.023920919381750734 [ Validation epoch: 22 ] Accuarcy: 76.84179630173173 Average loss: 0.02150990145452078 Model saved! (time elapsed: 1142.4257462024689) [ Train epoch: 22 ] Train accuarcy: 72.18756879724077 Train average loss: 0.023684059743828038 [ Validation epoch: 23 ] Accuarcy: 78.86703845024948 Average loss: 0.02015281879537995 Model saved! (time elapsed: 1203.3417167663574) [ Train epoch: 23 ] Train accuarcy: 73.17091069200852 Train average loss: 0.02318586483559483 [ Validation epoch: 24 ] Accuarcy: 78.95509245670678 Average loss: 0.019290503576979597 Model saved! (time elapsed: 1270.2185666561127) [ Train epoch: 24 ] Train accuarcy: 72.4811036912013 Train average loss: 0.023325199440778845 [ Validation epoch: 25 ] Accuarcy: 78.01584972116231 Average loss: 0.020310875158489082 Model saved! (time elapsed: 1327.0974171161652) [ Train epoch: 25 ] Train accuarcy: 73.50847582006311 Train average loss: 0.022954063406516883 [ Validation epoch: 26 ] Accuarcy: 79.39536248899324 Average loss: 0.01912067592633866 Model saved! (time elapsed: 1382.1164076328278) [ Train epoch: 26 ] Train accuarcy: 73.25163278784765 Train average loss: 0.02296848338278582 [ Validation epoch: 27 ] Accuarcy: 79.27795714705019 Average loss: 0.01960812162226304 Model saved! (time elapsed: 1440.4519789218903) [ Train epoch: 27 ] Train accuarcy: 72.9360827768401 Train average loss: 0.023101103360929187 [ Validation epoch: 28 ] Accuarcy: 80.07044320516583 Average loss: 0.017875241124983367 Model saved! (time elapsed: 1487.6377375125885) [ Train epoch: 28 ] Train accuarcy: 74.19094444852132 Train average loss: 0.022096303308089708 [ Validation epoch: 29 ] Accuarcy: 80.80422659230994 Average loss: 0.018353062525221005 Model saved! (time elapsed: 1534.7096214294434) [ Train epoch: 29 ] Train accuarcy: 73.91942467160784 Train average loss: 0.02235509607966336 [ Validation epoch: 30 ] Accuarcy: 80.95098326973877 Average loss: 0.01915587472590247 Model saved! (time elapsed: 1581.745195388794)
In [38]:
# 정확도(accuracy) 커브 시각화
plt.subplot(211)
plt.plot([i for i in range(epoch)], [i[0] for i in train_result])
plt.plot([i for i in range(epoch)], [i[0] for i in val_result])
plt.title("Accuracy Curve")
plt.xlabel("Epoch")
plt.ylabel("Accuracy")
plt.legend(["train", "val"])
# 손실(loss) 커브 시각화
plt.subplot(212)
plt.plot([i for i in range(epoch)], [i[1] for i in train_result])
plt.plot([i for i in range(epoch)], [i[1] for i in val_result])
plt.title("Loss Curve")
plt.xlabel("Epoch")
plt.ylabel("Loss")
plt.legend(["train", "val"])
plt.tight_layout()
plt.show()
6. 혼동 행렬 시각화¶
- heatmap을 활용하여 분류모델이 각 클래스에 정확히 분류하는지 확인한다.
In [39]:
# 네트워크에 데이터셋을 입력하여 혼동 행렬(confusion matrix)을 계산하는 함수
def get_confusion_matrix(net, num_classes, data_loader):
net.eval() # 모델을 평가 모드로 설정
confusion_matrix = torch.zeros(num_classes, num_classes, dtype=torch.int32)
for batch_idx, (inputs, targets) in enumerate(data_loader):
inputs, targets = inputs.to(device), targets.to(device)
outputs = net(inputs)
_, predicted = outputs.max(1)
for t, p in zip(targets.view(-1), predicted.view(-1)):
confusion_matrix[t.long(), p.long()] += 1
return confusion_matrix
In [40]:
import pandas as pd
import seaborn as sns
net = LeNet()
net = net.to(device)
file_name = "./checkpoint/LeNet.pt"
checkpoint = torch.load(file_name)
net.load_state_dict(checkpoint['net'])
# 평가 데이터셋을 이용해 혼동 행렬(confusion matrix) 계산하기
confusion_matrix = get_confusion_matrix(net, 6, val_dataloader)
print("[ 각 클래스당 데이터 개수 ]")
print(confusion_matrix.sum(1))
print("[ 혼동 행렬(confusion matrix) 시각화 ]")
res = pd.DataFrame(confusion_matrix.numpy(), index = [i for i in range(6)], columns = [i for i in range(6)])
res.index.name = 'True label'
res.columns.name = 'Predicted label'
plt.figure(figsize = (10, 7))
sns.heatmap(res, annot=True, fmt="d", cmap='Blues')
plt.show()
print("[ 각 클래스에 따른 정확도 ]")
# (각 클래스마다 정답 개수 / 각 클래스마다 데이터의 개수)
print(confusion_matrix.diag() / confusion_matrix.sum(1))
print("[ 전체 평균 정확도 ]")
print(confusion_matrix.diag().sum() / confusion_matrix.sum())
[ 각 클래스당 데이터 개수 ] tensor([523, 540, 594, 599, 560, 591]) [ 혼동 행렬(confusion matrix) 시각화 ]
[ 각 클래스에 따른 정확도 ] tensor([0.7400, 0.9333, 0.8131, 0.6845, 0.8625, 0.8308]) [ 전체 평균 정확도 ] tensor(0.8095)
Problem 2. customLeNet 아키텍처 작성하기¶
- LeNet 아키텍처를 변경하여 CustomLeNet을 만들기
Layer | Type | Specification |
---|---|---|
1 | Input | image size: 3 X 64 X 64 |
2 | Convolution | # of kernel: 128, kernel size: 8 X 8, stride: 1, zero padding: 0 |
3 | Activation | ReLU |
4 | Pooling | max pooling, kernel size: 2 X 2, stride: 2 |
5 | Convolution | # of kernel: 256, kernel size: 8 X 8, stride: 1, zero padding: 0 |
6 | Activation | ReLU |
7 | Pooling | max pooling, kernel size: 2 X 2, stride: 2 |
8 | Convolution | # of kernel: 512, kernel size: 4 X 4, stride: 1, zero padding: 0 |
9 | Activation | ReLU |
10 | Pooling | max pooling, kernel size: 2 X 2, stride: 2 |
11 | Fully Connected | # of neuron: 4096 |
12 | Activation | ReLU |
13 | Fully Connected | # of neuron: 6 |
14 | Softmax | 6 classes |
In [41]:
class CustomLeNet(nn.Module):
def __init__(self):
super(CustomLeNet, self).__init__()
# → 차원(dimension): (3 x 64 x 64)
self.conv1 = nn.Conv2d(in_channels=3, out_channels=128, kernel_size=8, stride=1, padding=0)
# → 차원(dimension): (128 x 57 x 57)
self.pool1 = nn.MaxPool2d(kernel_size=2, stride=2)
# → 차원(dimension): (128 x 28 x 28)
self.conv2 = nn.Conv2d(in_channels=128, out_channels=256, kernel_size=8, stride=1, padding=0)
# → 차원(dimension): (256 x 21 x 21)
self.pool2 = nn.MaxPool2d(kernel_size=2, stride=2)
# → 차원(dimension): (256 x 10 x 10)
self.conv3 = nn.Conv2d(in_channels=256, out_channels=512, kernel_size=4, stride=1, padding=0)
# → 차원(dimension): (512 x 7 x 7)
self.pool3 = nn.MaxPool2d(kernel_size=2, stride=2)
# → 차원(dimension): (512 x 3 x 3)
self.fc1 = nn.Linear(512 * 3 * 3, 4096)
# → 차원(dimension): (4096)
self.fc2 = nn.Linear(4096, 6)
# → 차원(dimension): (6)
def forward(self, x):
x = self.pool1(self.conv1(x))
x = self.pool2(self.conv2(x))
x = self.pool3(self.conv3(x))
x = torch.flatten(x, 1) # 배치(batch)를 제외한 모든 차원 flatten하기
x = F.relu(self.fc1(x))
x = self.fc2(x)
return x
In [42]:
height = 64
width = 64
filter_height = 8
filter_width = 8
stride = 1
padding = 0
output_height = (height + 2 * padding - filter_height) // stride + 1
output_width = (width + 2 * padding - filter_width) // stride + 1
print('출력 높이:', output_height, '출력 너비:', output_width)
# (128 * 57 * 57)
출력 높이: 57 출력 너비: 57
In [43]:
height = 57
width = 57
filter_height = 2
filter_width = 2
stride = 2
padding = 0
output_height = (height + 2 * padding - filter_height) // stride + 1
output_width = (width + 2 * padding - filter_width) // stride + 1
print('출력 높이:', output_height, '출력 너비:', output_width)
# (128 * 28 * 28)
출력 높이: 28 출력 너비: 28
In [44]:
height = 28
width = 28
filter_height = 8
filter_width = 8
stride = 1
padding = 0
output_height = (height + 2 * padding - filter_height) // stride + 1
output_width = (width + 2 * padding - filter_width) // stride + 1
print('출력 높이:', output_height, '출력 너비:', output_width)
# (256 * 21 * 21)
출력 높이: 21 출력 너비: 21
In [45]:
height = 21
width = 21
filter_height = 2
filter_width = 2
stride = 2
padding = 0
output_height = (height + 2 * padding - filter_height) // stride + 1
output_width = (width + 2 * padding - filter_width) // stride + 1
print('출력 높이:', output_height, '출력 너비:', output_width)
# (256 * 10 * 10)
출력 높이: 10 출력 너비: 10
In [46]:
height = 10
width = 10
filter_height = 4
filter_width = 4
stride = 1
padding = 0
output_height = (height + 2 * padding - filter_height) // stride + 1
output_width = (width + 2 * padding - filter_width) // stride + 1
print('출력 높이:', output_height, '출력 너비:', output_width)
# (512 * 7 * 7)
출력 높이: 7 출력 너비: 7
In [47]:
height = 7
width = 7
filter_height = 2
filter_width = 2
stride = 2
padding = 0
output_height = (height + 2 * padding - filter_height) // stride + 1
output_width = (width + 2 * padding - filter_width) // stride + 1
print('출력 높이:', output_height, '출력 너비:', output_width)
# (512 * 3 * 3)
출력 높이: 3 출력 너비: 3
7. CustomLeNet 평가하기¶
- 새롭게 작성한 CustomLeNet과 앞선 LeNet 성능 비교
In [48]:
import time
import torch.optim as optim
net = CustomLeNet()
net = net.to(device)
epoch = 30
learning_rate = 0.002
file_name = "CustomLeNet.pt"
criterion = nn.CrossEntropyLoss()
optimizer = optim.SGD(net.parameters(), lr=learning_rate, momentum=0.9, weight_decay=0.0002)
train_result = []
val_result = []
start_time = time.time() # 시작 시간
for i in range(epoch):
train_acc, train_loss = train(net, i, optimizer, criterion, train_dataloader) # 학습(training)
val_acc, val_loss = validate(net, i + 1, val_dataloader) # 검증(validation)
# 학습된 모델 저장하기
state = {
'net': net.state_dict()
}
if not os.path.isdir('checkpoint'):
os.mkdir('checkpoint')
torch.save(state, './checkpoint/' + file_name)
print(f'Model saved! (time elapsed: {time.time() - start_time})')
# 현재 epoch에서의 정확도(accuracy)와 손실(loss) 값 저장하기
train_result.append((train_acc, train_loss))
val_result.append((val_acc, val_loss))
[ Train epoch: 0 ] Train accuarcy: 48.71211565274822 Train average loss: 0.04056373595264116 [ Validation epoch: 1 ] Accuarcy: 59.81802171998826 Average loss: 0.034273067422020916 Model saved! (time elapsed: 579.7438952922821) [ Train epoch: 1 ] Train accuarcy: 56.571512438541134 Train average loss: 0.03510560232326099 [ Validation epoch: 2 ] Accuarcy: 67.86028764308776 Average loss: 0.02768299581019942 Model saved! (time elapsed: 1113.6080205440521) [ Train epoch: 2 ] Train accuarcy: 58.831731122037134 Train average loss: 0.03328986123117845 [ Validation epoch: 3 ] Accuarcy: 68.85823304960375 Average loss: 0.02713490260252688 Model saved! (time elapsed: 1575.2637486457825) [ Train epoch: 3 ] Train accuarcy: 60.98921259264695 Train average loss: 0.03217701978586194 [ Validation epoch: 4 ] Accuarcy: 68.53536835926035 Average loss: 0.027108866315731946 Model saved! (time elapsed: 2023.7108659744263) [ Train epoch: 4 ] Train accuarcy: 61.833125412783446 Train average loss: 0.031238553458757094 [ Validation epoch: 5 ] Accuarcy: 67.94834164954506 Average loss: 0.02717829564116657 Model saved! (time elapsed: 2471.5440323352814) [ Train epoch: 5 ] Train accuarcy: 62.94855800983342 Train average loss: 0.030653785878917202 [ Validation epoch: 6 ] Accuarcy: 71.76401526269446 Average loss: 0.023972764738081208 Model saved! (time elapsed: 4659.8093473911285) [ Train epoch: 6 ] Train accuarcy: 64.23277317091069 Train average loss: 0.02982072843934589 [ Validation epoch: 7 ] Accuarcy: 72.87936601115351 Average loss: 0.02384857851317596 Model saved! (time elapsed: 5161.514049053192) [ Train epoch: 7 ] Train accuarcy: 64.70242900124752 Train average loss: 0.02916996242794102 [ Validation epoch: 8 ] Accuarcy: 72.70325799823893 Average loss: 0.024376268492859062 Model saved! (time elapsed: 5645.477423191071) [ Train epoch: 8 ] Train accuarcy: 64.90056505467088 Train average loss: 0.02925945749424205 [ Validation epoch: 9 ] Accuarcy: 73.14352803052539 Average loss: 0.023319722910168095 Model saved! (time elapsed: 6160.694763660431) [ Train epoch: 9 ] Train accuarcy: 66.47831510970866 Train average loss: 0.028301873229924623 [ Validation epoch: 10 ] Accuarcy: 74.7872028177282 Average loss: 0.023374738417170002 Model saved! (time elapsed: 6637.509428739548) [ Train epoch: 10 ] Train accuarcy: 66.4929918544067 Train average loss: 0.02822570326813443 [ Validation epoch: 11 ] Accuarcy: 71.52920457880833 Average loss: 0.024166807939063638 Model saved! (time elapsed: 7108.673500299454) [ Train epoch: 11 ] Train accuarcy: 66.66177441843399 Train average loss: 0.02792147151869409 [ Validation epoch: 12 ] Accuarcy: 73.70120340475492 Average loss: 0.023643644220989263 Model saved! (time elapsed: 7577.238320589066) [ Train epoch: 12 ] Train accuarcy: 67.19013722756293 Train average loss: 0.027535083457590277 [ Validation epoch: 13 ] Accuarcy: 75.13941884355738 Average loss: 0.022173286210346473 Model saved! (time elapsed: 8027.626682758331) [ Train epoch: 13 ] Train accuarcy: 67.55705584501358 Train average loss: 0.02732811276059057 [ Validation epoch: 14 ] Accuarcy: 74.75785148224244 Average loss: 0.022856730150973514 Model saved! (time elapsed: 8489.570006370544) [ Train epoch: 14 ] Train accuarcy: 67.87260585602114 Train average loss: 0.026996224989603766 [ Validation epoch: 15 ] Accuarcy: 73.23158203698269 Average loss: 0.023088231730887993 Model saved! (time elapsed: 8940.969098806381) [ Train epoch: 15 ] Train accuarcy: 67.94598957951126 Train average loss: 0.02674091563209396 [ Validation epoch: 16 ] Accuarcy: 75.13941884355738 Average loss: 0.02228612506323138 Model saved! (time elapsed: 9391.841868400574) [ Train epoch: 16 ] Train accuarcy: 68.69450355911059 Train average loss: 0.0267713029521782 [ Validation epoch: 17 ] Accuarcy: 75.43293219841503 Average loss: 0.021868448112939576 Model saved! (time elapsed: 9840.4931640625) [ Train epoch: 17 ] Train accuarcy: 68.68716518676158 Train average loss: 0.026474284860667368 [ Validation epoch: 18 ] Accuarcy: 76.92985030818902 Average loss: 0.020625252080936393 Model saved! (time elapsed: 10292.503539085388) [ Train epoch: 18 ] Train accuarcy: 68.51838262273428 Train average loss: 0.026298910709647603 [ Validation epoch: 19 ] Accuarcy: 75.66774288230114 Average loss: 0.021736858119039477 Model saved! (time elapsed: 10741.638511657715) [ Train epoch: 19 ] Train accuarcy: 68.97336170837308 Train average loss: 0.026121265150143534 [ Validation epoch: 20 ] Accuarcy: 71.85206926915174 Average loss: 0.024300919789389006 Model saved! (time elapsed: 11191.92315030098) [ Train epoch: 20 ] Train accuarcy: 69.07609892125926 Train average loss: 0.025929205893262988 [ Validation epoch: 21 ] Accuarcy: 73.7892574112122 Average loss: 0.023441309072700527 Model saved! (time elapsed: 11640.239911317825) [ Train epoch: 21 ] Train accuarcy: 69.31092683642768 Train average loss: 0.02581375941646207 [ Validation epoch: 22 ] Accuarcy: 75.8732022307015 Average loss: 0.021603420031256152 Model saved! (time elapsed: 12094.503950119019) [ Train epoch: 22 ] Train accuarcy: 70.27225361414838 Train average loss: 0.025230842705840906 [ Validation epoch: 23 ] Accuarcy: 76.2841209275022 Average loss: 0.021343513382891248 Model saved! (time elapsed: 12544.963587284088) [ Train epoch: 23 ] Train accuarcy: 70.17685477361121 Train average loss: 0.025129456945934256 [ Validation epoch: 24 ] Accuarcy: 76.04931024361609 Average loss: 0.021178867176966754 Model saved! (time elapsed: 12992.319269180298) [ Train epoch: 24 ] Train accuarcy: 71.05012108314376 Train average loss: 0.02469100673830132 [ Validation epoch: 25 ] Accuarcy: 74.99266216612855 Average loss: 0.0221804594290302 Model saved! (time elapsed: 13444.791308403015) [ Train epoch: 25 ] Train accuarcy: 70.47772803992075 Train average loss: 0.025013676990178146 [ Validation epoch: 26 ] Accuarcy: 76.7830936307602 Average loss: 0.020612866928544533 Model saved! (time elapsed: 13893.434000968933) [ Train epoch: 26 ] Train accuarcy: 69.86130476260365 Train average loss: 0.02551472791530525 [ Validation epoch: 27 ] Accuarcy: 76.46022894041678 Average loss: 0.021387877651838253 Model saved! (time elapsed: 14343.46400642395) [ Train epoch: 27 ] Train accuarcy: 70.50708152931679 Train average loss: 0.02495569307385777 [ Validation epoch: 28 ] Accuarcy: 75.96125623715879 Average loss: 0.020884607023320872 Model saved! (time elapsed: 14794.507151126862) [ Train epoch: 28 ] Train accuarcy: 71.02810596609672 Train average loss: 0.024371574579720244 [ Validation epoch: 29 ] Accuarcy: 77.45817434693278 Average loss: 0.020615311173844065 Model saved! (time elapsed: 15244.786772489548) [ Train epoch: 29 ] Train accuarcy: 70.62449548690101 Train average loss: 0.024797856414047772 [ Validation epoch: 30 ] Accuarcy: 77.72233636630466 Average loss: 0.021194808777735524 Model saved! (time elapsed: 15700.253757953644)
In [49]:
# 정확도(accuracy) 커브 시각화
plt.subplot(211)
plt.plot([i for i in range(epoch)], [i[0] for i in train_result])
plt.plot([i for i in range(epoch)], [i[0] for i in val_result])
plt.title("Accuracy Curve")
plt.xlabel("Epoch")
plt.ylabel("Accuracy")
plt.legend(["train", "val"])
# 손실(loss) 커브 시각화
plt.subplot(212)
plt.plot([i for i in range(epoch)], [i[1] for i in train_result])
plt.plot([i for i in range(epoch)], [i[1] for i in val_result])
plt.title("Loss Curve")
plt.xlabel("Epoch")
plt.ylabel("Loss")
plt.legend(["train", "val"])
plt.tight_layout()
plt.show()
In [50]:
import pandas as pd
import seaborn as sns
net = CustomLeNet()
net = net.to(device)
file_name = "./checkpoint/CustomLeNet.pt"
checkpoint = torch.load(file_name)
net.load_state_dict(checkpoint['net'])
# 평가 데이터셋을 이용해 혼동 행렬(confusion matrix) 계산하기
confusion_matrix = get_confusion_matrix(net, 6, val_dataloader)
print("[ 각 클래스당 데이터 개수 ]")
print(confusion_matrix.sum(1))
print("[ 혼동 행렬(confusion matrix) 시각화 ]")
res = pd.DataFrame(confusion_matrix.numpy(), index = [i for i in range(6)], columns = [i for i in range(6)])
res.index.name = 'True label'
res.columns.name = 'Predicted label'
plt.figure(figsize = (10, 7))
sns.heatmap(res, annot=True, fmt="d", cmap='Blues')
plt.show()
print("[ 각 클래스에 따른 정확도 ]")
# (각 클래스마다 정답 개수 / 각 클래스마다 데이터의 개수)
print(confusion_matrix.diag() / confusion_matrix.sum(1))
print("[ 전체 평균 정확도 ]")
print(confusion_matrix.diag().sum() / confusion_matrix.sum())
[ 각 클래스당 데이터 개수 ] tensor([523, 540, 594, 599, 560, 591]) [ 혼동 행렬(confusion matrix) 시각화 ]
[ 각 클래스에 따른 정확도 ] tensor([0.5641, 0.8926, 0.7929, 0.7312, 0.7911, 0.8782]) [ 전체 평균 정확도 ] tensor(0.7772)
'전문지식 함양 > TIL' 카테고리의 다른 글
[프로그래머스 겨울방학 인공지능 과정] Neural Image Caption 이론 (0) | 2022.02.20 |
---|---|
[프로그래머스 겨울방학 인공지능 과정] Sequence to Sequence Learning with Neural Networks - 이론 (0) | 2022.02.20 |
[프로그래머스 겨울방학 인공지능 과정] 자연어 처리 이론 기초1 (0) | 2022.02.14 |
[프로그래머스 겨울방학 인공지능 과정] GAN 이론 기초3 : CycleGAN (0) | 2022.02.09 |
[프로그래머스 겨울방학 인공지능 과정] python 풍경 이미지분류 알고리즘3(完) (0) | 2022.02.08 |