# import
import torch
import torch.nn as nn
import torch.nn.functional as F # 주로 사용하는 function들..
import torch.optim as optim # 최적화
from torchvision import datasets, transforms # 딥러닝에서 주로 사용하는 dataset이 있는 모듈
from matplotlib import pyplot as plt
%matplotlib inline
# cuda가 가능하면 cuda 아니면 cpu 설정
is_cuda = torch.cuda.is_available()
device = torch.device('cuda' if is_cuda else 'cpu')
print('Current cuda device is', device)
# 파라미터 설정
batch_size = 50 # batch_size : 몇 개의 데이터를 모아서 가중치를 업데이트하는 계산을 사용할 것인가?..
learning_rate = 0.0001
epoch_num = 15
# MNIST 데이터 불러오기
train_data = datasets.MNIST(root='./data', train=True,
download=True, # 처음에는 True설정하고 나중에는 이미 받았으니 False 하면 됨
transform=transforms.ToTensor())
# 웹에서 데이터 다운, 저장할 곳 지정
test_data = datasets.MNIST(root='./data', train=False,
transform= transforms.ToTensor())
print('number of training data : ', len(train_data))
print('number of test data : ', len(test_data))
# vs코드에서는 안됨;;
# image, label = train_data[0]
# plt.imshow(image.squeeze().numpy(), cmap = 'gray')
## squeeze() : torch에서는 채널의 차원이 가장 앞에 옴 ex) [1, 28, 28],
## 그림을 그릴 수 있도록 2차원으로 바꿔줌 1을 없애버려라..[28, 28] 형태로 만들어라..
# plt.title('label : %s' %label)
# plt.show()
# 미니 배치 구성
train_loader = torch.utils.data.DataLoader(dataset = train_data,
batch_size = batch_size, shuffle = True)
test_loader = torch.utils.data.DataLoader(dataset = test_data,
batch_size = batch_size, shuffle = True)
# shuffle = 데이터의 순서를 학습하지 못하게 하려고..?, 데이터의 미니 배치를 잘 구성하기 위해서..?
first_batch = train_loader.__iter__().__next__()
# 출력을 정렬하고자 할 때 이런 방식을 사용
# 15개의 공간을 확보, < : 왼쪽정렬, > : 오른쪽 정렬
# first_batch[1] :라벨, 50개씩 묶어서 50개 존재
# first_batch[0] : 50 - 데이터의 개수, 1 - 채널, 28,28 - 가로세로의 길이
print('{:15s} | {:<25s} | {}' .format('name', 'type', 'size') )
print('{:15s} | {:<25s} | {}' .format('Num of Batch', '', len(train_loader)) )
print('{:15s} | {:<25s} | {}' .format('first_batch', str(type(first_batch)), len(first_batch)) )
print('{:15s} | {:<25s} | {}' .format('first_batch[0]', str(type(first_batch[0])),
first_batch[0].shape) )
print('{:15s} | {:<25s} | {}' .format('first_batch[1]', str(type(first_batch[1])),
first_batch[1].shape) )
class CNN(nn.Module):
def __init__(self):
super(CNN, self).__init__()
# 사용할 레이어 정의
self.conv1 = nn.Conv2d(1, 32, 3, 1, padding='same')
# 1 : 입력 채널의 수, 32 : 32개의 채널을 가지도록 설정, 3 : 커널 사이즈 3*3, 1 : strides 옵션 , padding : 이미지 사이즈 줄어드는 것을 방지 https://wooono.tistory.com/234
self.conv2 = nn.Conv2d(32, 64, 3, 1, padding='same')
self.dropout = nn.Dropout2d(0.25)
self.fc1 = nn.Linear(3136, 1000) # 7(pooling layer 크기)*7*64(채널의 크기) = 3136 입출력의 개수를 정해주어야함
self.fc2 = nn.Linear(1000, 10)
def forward(self, x): # 모델 구성
x = self.conv1(x)
x = F.relu(x)
x = F.max_pool2d(x, 2) # 가중치 없음
x = self.conv2(x)
x = F.relu(x)
x = F.max_pool2d(x, 2)
x = self.dropout(x)
x = torch.flatten(x, 1) # 차원만 바꿈
x = self.fc1(x)
x = F.relu(x)
x = self.fc2(x)
output = F.log_softmax(x, dim=1) # log_softmax : 연산속도를 조금 더 높일 수 있음
return output
model = CNN().to(device) # 모델 선언하고, 설정한 장치(device)에 올려주는 것
optimizier = optim.Adam(model.parameters(), lr = learning_rate)
criterion = nn.CrossEntropyLoss()
model.train() # 학습을 하겠다는 선언
i = 1
for epoch in range(epoch_num):
for data, target in train_loader:
data = data.to(device)
target = target.to(device)
optimizier.zero_grad() # 다음에 갱신한 가중치를 사용하기 위해 초기화?..
output = model(data)
loss = criterion(output, target)
loss.backward() # loss를 가지고 역전파
optimizier.step() # 가중치 업데이트
if i % 1000 == 0:
print('Train Step : {}\tLoss: {:.3f}'.format(i, loss.item()))
i += 1
model.eval() # 평가모드, dropout은 적용되지 않음..?
correct = 0
for data, target in test_loader:
# data, target = Variable(data, volatile=True), Variable(target)
data = data.to(device)
target = target.to(device)
output = model(data)
prediction = output.data.max(1)[1]
correct += prediction.eq(target.data).sum() # 맞는 개수 확인하기 위해
print('Test set : Accuracy : {:.2f}%' .format(100 * correct / len(test_loader.dataset)))
어렵다...ㅠㅠ
💻 출처 : 제로베이스 데이터 취업 스쿨