이미지 분류의 학습과 평가 분리하기
본인 사본을 만들어 실행·수정·기록하세요.
- 이름: ⟦여기에 직접 입력⟧
- 학번: ⟦여기에 직접 입력⟧
- Code Cell 실행: ▶ 또는
Shift+Enter, 위에서부터 순서대로. - Text Cell 작성: 더블클릭 →
직접 입력작성 →Shift+Enter. - 직접 작성 셀: 본인 코드 입력.
- 값 변경 후: 해당 셀과 뒤의 관련 셀 다시 실행.
로컬 실행 준비
- PyTorch·torchvision: 호환 버전을 함께 설치. Python 3.11 · PyTorch 2.12.1 · torchvision 0.27.1에서 실행 확인.
- MNIST: 처음 실행할 때 인터넷 연결 필요. 다운로드 위치:
mnist_data. - Mac의 python.org Python에서
CERTIFICATE_VERIFY_FAILED발생 시: Applications의 해당 Python 폴더에서Install Certificates.command실행 후 재시도.
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. 직접 수행
- 데이터를 준비하는 셀을 실행하세요.
train_data[0]에서 이미지의 shape와 Label을 출력하고, 이미지의 세 축이 무엇인지 적으세요. train_loader를 끝까지 순회해 Batch별 이미지 수를 리스트에 모으세요. 첫 Batch 크기·마지막 Batch 크기·전체 Batch 수를 적으세요.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. 직접 수행
QUICK_RUN=True인 데이터 셀과 CNN 학습·평가 셀을 차례로 실행하세요. 학습 epoch·학습 이미지 수·평가 이미지 수를 기록하세요.- 학습 코드에서
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. 직접 수행
examples와mistakes를 시각화한 결과의 정답·예측 Label을 각 이미지와 대조하세요. 맞힌 예와 틀린 예에서 어떤 숫자를 어떤 숫자로 예측했는지 적고, 틀린 이미지에서 눈에 띄는 특징을 설명하세요.- 기록한 Test Accuracy 옆에 평가에 사용한 이미지 수를 적으세요.
QUICK_RUN=True의 일부 표본 평가값인지, 전체 Test Set 평가값인지 구분합니다.
예상은 정확한 수치 대신 shape나 증가·감소 방향으로 적어도 됩니다. 코드는 위 예제를 참고해 작성하고, 설명만 묻는 항목은 아래 Text Cell에 답하세요.
# ✍ 직접 작성: 이 셀 아래에 본인의 코드를 추가하세요.
# 코드가 길어지면 Code Cell을 추가해도 됩니다.
C. 직접 기록 · 이 Text Cell을 더블클릭해서 수정
- 확인하거나 바꾼 조건: ⟦직접 입력⟧
- 실행 전 예상: ⟦직접 입력⟧
- 실제 출력/그래프에서 확인한 값: ⟦직접 입력⟧
- 예상과 차이 및 설명: ⟦직접 입력⟧
반복 숙달 · 실행 전에 판단하기
앞의 직접 수행에서 비교한 조건 세 가지를 이 표에 정리하세요. 이미 수행한 실험을 다시 추가할 필요는 없습니다. 비교가 부족하면 한 조건만 바꾸어 보충하세요.
| 변경 조건 | 예상 shape/수치/결과 | 실제 결과 | 오류가 있었다면 원인 |
|---|---|---|---|
| ⟦직접 입력 1⟧ | ⟦직접 입력⟧ | ⟦직접 입력⟧ | ⟦직접 입력⟧ |
| ⟦직접 입력 2⟧ | ⟦직접 입력⟧ | ⟦직접 입력⟧ | ⟦직접 입력⟧ |
| ⟦직접 입력 3⟧ | ⟦직접 입력⟧ | ⟦직접 입력⟧ | ⟦직접 입력⟧ |
# ✍ 반복 실험 코드
선택 실습 · 오류의 원인을 찾아 코드 고치기
Dropout을 켠 상태로 같은 영상을 두 번 평가한 경우
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()Text Cell에 각 mode의 최대 절대 차이를 적고, 같은 영상인데 출력이 달라지는 이유를 Dropout과 연결해 설명하세요. 이 코드는 Gradient 계산과 가중치 갱신 없이 평가하며, 끝난 뒤에는
evalmode입니다.
저장 전 확인
- 작성란과 출력·그래프를 확인하고 새 런타임에서 전체 셀을 순서대로 실행하세요.
- 본인 Drive에 저장한 뒤
.ipynb로 내려받으세요.
코드, 실제 Output·그래프, 직접 작성한 해석을 포함하세요. 제출은 KLAS를 이용하며 기한은 학기 일정과 최신 공지를 확인합니다.
파일명: 이름_학번_10주차.ipynb.