강의자료 · 인공지능응용

이미지 분류의 학습과 평가 분리하기

본인 사본을 만들어 실행·수정·기록하세요.

로컬 실행 준비

1. MNIST와 실행 규모

이번 실습은 QUICK_RUN=True를 유지해 학습 1200개·평가 300개로 진행합니다. 최초 실행은 MNIST를 다운로드하므로 인터넷이 필요합니다. 전체 데이터로 학습할 때는 사용한 표본 수를 함께 기록하세요.

A. 기준 예제 · 먼저 읽고 실행

import sys, numpy as np, matplotlib.pyplot as plt
import torch
from torch import nn
import torch.nn.functional as F
torch.manual_seed(42)
torch.set_num_threads(2)
print('Python:', sys.version.split()[0], '| PyTorch:', torch.__version__)
import torchvision
from torchvision import datasets,transforms
from torch.utils.data import DataLoader,Subset
QUICK_RUN=True # 직접 변경: 전체 데이터는 False
train_data=datasets.MNIST('mnist_data',train=True,download=True,transform=transforms.ToTensor())
test_data=datasets.MNIST('mnist_data',train=False,download=True,transform=transforms.ToTensor())
train_used=Subset(train_data,range(1200)) if QUICK_RUN else train_data
test_used=Subset(test_data,range(300)) if QUICK_RUN else test_data
train_loader=DataLoader(train_used,batch_size=64,shuffle=True,generator=torch.Generator().manual_seed(42))
test_loader=DataLoader(test_used,batch_size=128,shuffle=False)
print('Mode:', 'QUICK' if QUICK_RUN else 'FULL','train:',len(train_used),'test:',len(test_used))
img,label=train_data[0];print(img.shape,label);plt.imshow(img.squeeze(),cmap='gray');plt.show()

B. 직접 수행

  1. 데이터를 준비하는 셀을 실행하세요. train_data[0]에서 이미지의 shape와 Label을 출력하고, 이미지의 세 축이 무엇인지 적으세요.
  2. train_loader를 끝까지 순회해 Batch별 이미지 수를 리스트에 모으세요. 첫 Batch 크기·마지막 Batch 크기·전체 Batch 수를 적으세요.
  3. len(train_used)와 Batch Size 64로 예상한 마지막 Batch 크기를 계산해 출력값과 대조하세요.

예상은 정확한 수치 대신 shape나 증가·감소 방향으로 적어도 됩니다. 코드는 위 예제를 참고해 작성하고, 설명만 묻는 항목은 아래 Text Cell에 답하세요.

# ✍ 직접 작성: 이 셀 아래에 본인의 코드를 추가하세요.
# 코드가 길어지면 Code Cell을 추가해도 됩니다.

C. 직접 기록 · 이 Text Cell을 더블클릭해서 수정

2. CNN 학습과 평가

평가에서는 파라미터를 갱신하지 않습니다.

A. 기준 예제 · 먼저 읽고 실행

class CNN(nn.Module):
    def __init__(self):
        super().__init__()
        self.layer1=nn.Sequential(nn.Conv2d(1,32,3,padding=1),nn.ReLU(),nn.MaxPool2d(2))
        self.layer2=nn.Sequential(nn.Conv2d(32,64,3,padding=1),nn.ReLU(),nn.MaxPool2d(2))
        self.layer3=nn.Sequential(nn.Conv2d(64,128,3,padding=1),nn.ReLU(),nn.MaxPool2d(2,padding=1))
        self.fc1=nn.Linear(128*4*4,625);self.relu=nn.ReLU();self.dropout=nn.Dropout();self.fc2=nn.Linear(625,10)
    def forward(self,x):
        x=self.layer3(self.layer2(self.layer1(x)));x=x.flatten(1)
        return self.fc2(self.dropout(self.relu(self.fc1(x))))
model=CNN();optimizer=torch.optim.Adam(model.parameters(),lr=.001)
epochs=2 if QUICK_RUN else 5
loss_history=[];accuracy_history=[]
for epoch in range(epochs):
    model.train();total_loss=0.;correct=0;count=0
    for xb,yb in train_loader:
        logits=model(xb);loss=F.cross_entropy(logits,yb)
        optimizer.zero_grad();loss.backward();optimizer.step()
        total_loss+=loss.item()*len(yb);correct+=(logits.argmax(1)==yb).sum().item();count+=len(yb)
    loss_history.append(total_loss/count);accuracy_history.append(correct/count)
    print(epoch+1,loss_history[-1],accuracy_history[-1])
model.eval();correct=0;count=0;examples=[];mistakes=[]
with torch.no_grad():
    for xb,yb in test_loader:
        pred=model(xb).argmax(1);correct+=(pred==yb).sum().item();count+=len(yb)
        for image,truth,guess in zip(xb,yb,pred):
            item=(image.squeeze(),truth.item(),guess.item())
            if len(examples)<10:examples.append(item)
            if truth!=guess and len(mistakes)<5:mistakes.append(item)
print('TEST:',correct/count,'samples:',count)

B. 직접 수행

  1. QUICK_RUN=True인 데이터 셀과 CNN 학습·평가 셀을 차례로 실행하세요. 학습 epoch·학습 이미지 수·평가 이미지 수를 기록하세요.
  2. 학습 코드에서 model.train(), 평가 코드에서 model.eval()과 torch.no_grad()를 찾으세요. 각각 Dropout 동작과 Gradient 기록 중 무엇을 제어하는지 한 문장씩 설명하세요.

전체 데이터로 비교하고 싶다면 QUICK_RUN=False로 바꾼 뒤 데이터 셀부터 다시 실행할 수 있습니다.

예상은 정확한 수치 대신 shape나 증가·감소 방향으로 적어도 됩니다. 코드는 위 예제를 참고해 작성하고, 설명만 묻는 항목은 아래 Text Cell에 답하세요.

# ✍ 직접 작성: 이 셀 아래에 본인의 코드를 추가하세요.
# 코드가 길어지면 Code Cell을 추가해도 됩니다.

C. 직접 기록 · 이 Text Cell을 더블클릭해서 수정

3. 그래프와 오분류

실제 이미지와 예측을 함께 확인합니다.

A. 기준 예제 · 먼저 읽고 실행

fig,axes=plt.subplots(1,2,figsize=(9,3));axes[0].plot(loss_history);axes[1].plot(accuracy_history)
for ax,yl in zip(axes,['train loss','train accuracy']):ax.set(xlabel='Epoch',ylabel=yl);ax.grid()
plt.show()
for title,items in [('test examples',examples),('misclassified',mistakes)]:
    if not items:print(title,': none in evaluated subset');continue
    fig,axes=plt.subplots(1,len(items),figsize=(2*len(items),2),squeeze=False)
    for ax,(image,truth,guess) in zip(axes[0],items):ax.imshow(image,cmap='gray');ax.set_title(f'T:{truth} P:{guess}');ax.axis('off')
    fig.suptitle(title);plt.show()

B. 직접 수행

  1. examples와 mistakes를 시각화한 결과의 정답·예측 Label을 각 이미지와 대조하세요. 맞힌 예와 틀린 예에서 어떤 숫자를 어떤 숫자로 예측했는지 적고, 틀린 이미지에서 눈에 띄는 특징을 설명하세요.
  2. 기록한 Test Accuracy 옆에 평가에 사용한 이미지 수를 적으세요. QUICK_RUN=True의 일부 표본 평가값인지, 전체 Test Set 평가값인지 구분합니다.

예상은 정확한 수치 대신 shape나 증가·감소 방향으로 적어도 됩니다. 코드는 위 예제를 참고해 작성하고, 설명만 묻는 항목은 아래 Text Cell에 답하세요.

# ✍ 직접 작성: 이 셀 아래에 본인의 코드를 추가하세요.
# 코드가 길어지면 Code Cell을 추가해도 됩니다.

C. 직접 기록 · 이 Text Cell을 더블클릭해서 수정

반복 숙달 · 실행 전에 판단하기

앞의 직접 수행에서 비교한 조건 세 가지를 이 표에 정리하세요. 이미 수행한 실험을 다시 추가할 필요는 없습니다. 비교가 부족하면 한 조건만 바꾸어 보충하세요.

변경 조건 예상 shape/수치/결과 실제 결과 오류가 있었다면 원인
⟦직접 입력 1⟧ ⟦직접 입력⟧ ⟦직접 입력⟧ ⟦직접 입력⟧
⟦직접 입력 2⟧ ⟦직접 입력⟧ ⟦직접 입력⟧ ⟦직접 입력⟧
⟦직접 입력 3⟧ ⟦직접 입력⟧ ⟦직접 입력⟧ ⟦직접 입력⟧
# ✍ 반복 실험 코드

선택 실습 · 오류의 원인을 찾아 코드 고치기

Dropout을 켠 상태로 같은 영상을 두 번 평가한 경우

  1. CNN 학습과 평가까지 마친 뒤, 노트북 맨 아래에 Code Cell을 추가하고 다음 코드를 실행하세요.

    debug_image = test_used[0][0].unsqueeze(0)
    for training in [True, False]:
        model.train(training)
        with torch.no_grad():
            first = model(debug_image)
            second = model(debug_image)
        print("train" if training else "eval",
              "maximum difference:", (first - second).abs().max().item())
    model.eval()
  2. Text Cell에 각 mode의 최대 절대 차이를 적고, 같은 영상인데 출력이 달라지는 이유를 Dropout과 연결해 설명하세요. 이 코드는 Gradient 계산과 가중치 갱신 없이 평가하며, 끝난 뒤에는 eval mode입니다.

저장 전 확인

  1. 작성란과 출력·그래프를 확인하고 새 런타임에서 전체 셀을 순서대로 실행하세요.
  2. 본인 Drive에 저장한 뒤 .ipynb로 내려받으세요.

코드, 실제 Output·그래프, 직접 작성한 해석을 포함하세요. 제출은 KLAS를 이용하며 기한은 학기 일정과 최신 공지를 확인합니다.

파일명: 이름_학번_10주차.ipynb.