강의자료 · 인공지능응용

Multiclass Classification과 Logits

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

1. CSV의 입력 확인

CSV의 앞 16열이 특징, 마지막 열이 Class Index입니다. Label은 0부터 C−1까지의 정수여야 합니다. 각 특징을 (값−평균)/표준편차로 바꾸어 규모를 맞추며, 새 데이터에도 같은 평균과 표준편차를 사용합니다.

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__)
from pathlib import Path
from urllib.request import urlretrieve
p=Path('data_multinomial_classification.csv')
if not p.exists():
    urlretrieve('https://nii-lab.github.io/assets/courses/ai-applications/multiclass/data_multinomial_classification.csv',p)
a=np.loadtxt(p,delimiter=',',dtype=np.float32)
x_raw=torch.tensor(a[:,:16]); labels=torch.tensor(a[:,-1],dtype=torch.long)
classes=torch.unique(labels);print('data:',a.shape,'classes:',classes)
mean=x_raw.mean(0);scale=x_raw.std(0).clamp_min(1e-6)
x=(x_raw-mean)/scale
y=labels
assert torch.equal(classes,torch.arange(len(classes)))
print(x.shape,y.shape,y.dtype)

B. 직접 수행

  1. 데이터를 읽는 셀을 실행하세요. x_raw와 x의 shape·dtype, 처음 다섯 행을 각각 출력하세요. 두 출력에 전처리 전·후라고 표시하세요.
  2. 같은 셀의 labels와 y에서 shape·dtype·처음 다섯 값을 출력하세요. Label을 Loss에 전달할 형태로 바꾼 부분을 찾으세요.
  3. 새 표본을 예측할 때 왜 학습 데이터의 mean·scale을 그대로 써야 하는지, 각 Feature가 모델에 입력되는 척도와 연결해 설명하세요.

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

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

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

2. 기준 학습 실행

Linear의 출력 개수는 Class 수입니다. CrossEntropyLoss는 이 Logit과 정답 Index를 받습니다. 비교할 때 train_classifier(lr=…, epochs=1000)처럼 epoch 수를 고정하세요.

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

def train_classifier(lr=0.1,epochs=2000):
    torch.manual_seed(42);m=nn.Linear(16,len(classes));opt=torch.optim.SGD(m.parameters(),lr=lr)
    criterion=nn.CrossEntropyLoss();losses=[];accuracies=[]
    for _ in range(epochs):
        m.train();logits=m(x);loss=criterion(logits,y)
        opt.zero_grad();loss.backward();opt.step()
        with torch.no_grad():
            logits=m(x);prediction=logits.argmax(1)
            losses.append(criterion(logits,y).item());accuracies.append((prediction==labels).float().mean().item())
    return m,losses,accuracies
model,losses,accuracies=train_classifier()
print('Training accuracy:',accuracies[-1])
fig,axes=plt.subplots(1,2,figsize=(10,3));axes[0].plot(losses);axes[1].plot(accuracies)
for ax,yl in zip(axes,['Training loss','Training accuracy']):ax.set(xlabel='Epoch',ylabel=yl);ax.grid()
plt.show()

B. 직접 수행

  1. train_classifier를 Learning Rate η∈{0.001,0.01,0.1}\eta\in\{0.001,0.01,0.1\}, 각각 1000 epoch로 호출하세요. 함수 안의 Seed와 모델 초기화를 유지하세요.
  2. 각 호출이 반환한 마지막 Loss·Training Accuracy를 Learning Rate별 표로 적으세요. Loss와 Accuracy의 변화는 반환한 두 기록을 같은 epoch에서 대조하세요.
  3. Loss는 줄지만 Accuracy는 그대로인 구간이 있다면 한 곳을 골라 표시하세요. 정답 Class의 Probability와 최종 Class 판정의 차이로 설명하세요. 해당 구간이 없으면 없다고 적으세요.

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

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

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

3. 출력을 해석하기

확률은 각 Class를 얼마나 그럴듯하게 예측했는지 나타내고, 최종 Class는 그중 선택한 답 하나입니다. 확률과 선택 결과를 나란히 출력해 확인합니다.

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

with torch.no_grad():
    logits=model(x);probability=logits.softmax(1);prediction=logits.argmax(1)
print('first predictions:',prediction[:10]);print('labels:',labels[:10]);print(probability[:10])
wrong=(prediction!=labels).nonzero().flatten()[:3]
print('wrong indices:',wrong)
for i in wrong:print(i.item(),prediction[i].item(),labels[i].item(),probability[i])
assert torch.allclose(probability.sum(1),torch.ones(len(x)),atol=1e-5)

B. 직접 수행

  1. 실습용 Notebook에서 logits=model(x) 계산이 포함된 예측 결과 코드 셀을 찾으세요. 앞 활동에서 학습한 model을 그대로 사용합니다.
  2. 표본 index 0–9를 10행으로, Logit·Probability·예측 Label·정답 Label을 네 열로 기록하세요. 값은 각각 logits[:10], probability[:10], prediction[:10], labels[:10]에서 확인합니다.
  3. 제공된 assert 안의 torch.allclose 호출을 별도 셀에서 출력하고, 전체 표본의 Probability 합 검사 결과를 참/거짓으로 기록하세요. 이어서 logits.argmax(1)와 probability.argmax(1)를 원소별로 대조해 일치 여부를 기록하세요.
  4. 오분류를 최대 3개 골라 표본 index·실제 Label·예측 Label을 적으세요. 없으면 ‘없음’으로 기록하세요.

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

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

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

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

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

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

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

Class 번호를 Float Tensor로 전달한 경우

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

    with torch.no_grad():
        debug_logits = model(x)
    debug_target = y.float()
    print("original Target:", y.shape, y.dtype)
    print("Float Target:", debug_target.shape, debug_target.dtype)
    try:
        F.cross_entropy(debug_logits, debug_target)
    except (RuntimeError, ValueError) as error:
        print(type(error).__name__, str(error))
    print("integer Target Loss:", F.cross_entropy(debug_logits, y).item())
  2. 출력 아래에 Text Cell을 추가해 다음 두 가지를 적으세요.

    • 두 Target의 shape와 dtype, 오류 메시지에서 요구하는 dtype.
    • 각 샘플의 Class 번호 하나를 담은 Target에서, 같은 번호라도 Float Tensor로 전달하면 Loss를 계산할 수 없는 이유.

    y.float()는 새 Tensor를 만듭니다. 원래 y는 그대로이므로 마지막 줄에서는 정수형 Target으로 Loss를 계산합니다.

저장 전 확인

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

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

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