파이토치

[파이토치] CNN

알 수 없는 사용자 2022. 2. 14. 13:05

Convolutional Neural Networks

CNN모델과 10개의 클래스를 가진 이미지 데이터인 CIFAR-10데이터를 이용하여 실습을 진행하였습니다.

 

transform = transforms.Compose(
    [transforms.ToTensor(),
     transforms.Normalize((0.50.50.5), (0.50.50.5))])

trainset = torchvision.datasets.CIFAR10(root='./data', train=True,
                                        download=True, transform=transform)

trainloader = torch.utils.data.DataLoader(trainset, batch_size=8, shuffle=True

testset = torchvision.datasets.CIFAR10(root='./data', train=False,
                                       download=True, transform=transform)
testloader = torch.utils.data.DataLoader(testset, batch_size=8, shuffle=False)
# CPU/GPU
device = torch.device("cuda:0" if torch.cuda.is_available() else "cpu")
print(f'{device} is available.')

1. 모델 선언

class Net(nn.Module):
    def __init__(self):
        super(Net, self).__init__()
        self.conv1 = nn.Conv2d(365# 합성곱 연산 (입력 채널수 3, 출력 채널수 6, 필터크기 5x5 , stride=1(defualt))
        self.pool1 = nn.MaxPool2d(22# 합성곱 연산 (필터크기 2, stride=2)
        self.conv2 = nn.Conv2d(6165# 합성곱 연산 (입력 채널수 6, 출력 채널수 16, 필터크기 5x5 , stride=1(defualt))
        self.pool2 = nn.MaxPool2d(22# 합성곱 연산 (필터크기 2, stride=2)
        self.fc1 = nn.Linear(16 * 5 * 5120# 5x5 피쳐맵 16개를 일렬로 피면 16*5*5개의 노드가 생성
        self.fc2 = nn.Linear(12010# 120개 노드에서 클래스의 개수인 10개의 노드로 연산

    def forward(selfx): # 실제 계산이 이루어진다.
        x = self.pool1(F.relu(self.conv1(x))) # conv1 -> ReLU -> pool1
        x = self.pool2(F.relu(self.conv2(x))) # conv2 -> ReLU -> pool2
        x = x.view(-116 * 5 * 5# 5x5 피쳐맵 16개를 일렬로 만든다.  # -1은 배치수 대신에 사용하였다.
        x = F.relu(self.fc1(x)) 
        x = self.fc2(x)

        return x

2. 모델 선언 (Preferable)

class Net(nn.Module):
    def __init__(self):
        super(Net, self).__init__()
        # sequential로 feature extraction layers를 하나로 묶을 수 있다.
        self.feature_extraction = nn.Sequential(nn.Conv2d(365), 
                                                nn.ReLU(),
                                                nn.MaxPool2d(22), 
                                                nn.Conv2d(6165),
                                                nn.ReLU(),
                                                nn.MaxPool2d(22))
        
        self.classifier = nn.Sequential(nn.Linear(16 * 5 * 5120),
                                        nn.ReLU(),
                                        nn.Linear(12010))
                                        
    def forward(selfx):
        x = self.feature_extraction(x)
        x = x.view(-116 * 5 * 5# 5x5 피쳐맵 16개를 일렬로 만든다.
        x = self.classifier(x)
 
        return x

net = Net().to(device) # 모델이 GPU연산을 가능하도록 한다.

 

criterion = nn.CrossEntropyLoss() # CrossEntropyLoss는 softmax 계산까지 포함되어 있으므로 모델의 마지막 output node에 별도의 활성화 함수를 사용하지 않아도 된다.
optimizer = optim.SGD(net.parameters(), lr=1e-3, momentum=0.9)
# 모델의 학습 과정인 4강에서 배운 인공 신경망과 동일하다.
loss_ = [] # 그래프를 그리기 위한 loss 저장용 리스트 
n = len(trainloader) # 배치 개수

for epoch in range(10):  # 10번 학습을 진행한다.

    running_loss = 0.0
    for i, data in enumerate(trainloader, 0):

        inputs, labels = data[0].to(device), data[1].to(device) # GPU연산이 가능한 배치 데이터 
        
        optimizer.zero_grad()

        outputs = net(inputs) # 예측값 산출 
        loss = criterion(outputs, labels) # 손실함수 계산
        loss.backward() # 손실함수 기준으로 역전파 선언
        optimizer.step() # 가중치 최적화

        # print statistics
        running_loss += loss.item()

    loss_.append(running_loss / n)    
    print('[%d] loss: %.3f' %(epoch + 1, running_loss / len(trainloader)))

print('Finished Training')
plt.plot(loss_)
plt.title("Training Loss")
plt.xlabel("epoch")
plt.show()

 
PATH = './models/cifar_net.pth' # 모델 저장 경로 
torch.save(net.state_dict(), PATH) # 모델 저장
# 모델 불러오기는 엄밀히 말하자면 모델의 파라메타를 불러오는 것이다. 따라서 모델의 뼈대를 먼저 선언하고
# 모델의 파라메타를 불러와 pretrained model을 만든다.

net = Net().to(device) # 모델을 먼저 불러오고 그 위에 파라메타를 덮어씌운다. 이때, GPU 모델로 저장을 했기 때문에, 불러올때도 GPU로 받아야한다.
net.load_state_dict(torch.load(PATH)) # 모델 파라메타 불러오기
# 평가 데이터를 이용해 정확도 구하기.
# output은 미니배치의 결과가 산출되기 때문에 for문을 통해서 test 전체의 예측값을 구한다.

correct = 0
total = 0
with torch.no_grad():
    
    for data in testloader:
        images, labels = data[0].to(device), data[1].to(device)
        outputs = net(images)
        _, predicted = torch.max(outputs.data, 1) # 벡터값에서 argmax를 하기위해 max()를 취한다. 즉, 최댓값의 위치
        total += labels.size(0# 개수 누적(총 개수)
        correct += (predicted == labels).sum().item() # 누적(맞으면 1, 틀리면 0으로 합산)
        
print('Accuracy of the network on the 10000 test images: %d %%' % (100 * correct / total))