'이 사진은 강아지? 고양이? 토끼?' — 클래스마다 점수를 매기고, 소프트맥스로 합이 100%인 확률로 바꿔 셋 중 하나를 고르는 다중 분류예요.
가로축은 귀 길이, 세로축은 몸무게예요. 점의 색 = 정답 클래스, 배경색 = 모델이 그 위치를 분류한 클래스(진할수록 확신). 선형 모델이라 색 영역의 경계가 전부 직선인 것에 주목하세요. 클릭하면 선택한 클래스의 점 추가, 같은 클래스 점을 다시 클릭하면 삭제돼요.
파라미터가 9개라 슬라이더 대신 경사하강법이 교차 엔트로피 손실을 줄이는 방향으로 자동으로 조절해요.
캔버스 위에서 마우스를 움직이면 그 위치의 세 클래스 확률이 여기에 나타나요.
학습이 진행되면 손실은 내려가고 정확도는 올라가요. 정확도 100%가 돼도 손실은 계속 조금씩 줄어드는 것도 관찰해 보세요 — 모델이 점점 더 “확신”하는 거예요.
각 클래스의 점수는 z_k = w_k1·x + w_k2·y + b_k (k = 0, 1, 2). 클래스가 2개면 소프트맥스는 로지스틱 회귀의 시그모이드와 완전히 같아져요 — 그래서 “로지스틱 회귀의 다중 클래스 확장”이라고 불러요.
import torch
import torch.nn as nn
# 데이터: (귀 길이, 몸무게) → 정답 0(강아지) / 1(고양이) / 2(토끼)
X = torch.tensor(features, dtype=torch.float32) # [N, 2]
y = torch.tensor(labels) # [N], 값은 0/1/2
# 모델: 특징 2개 → 클래스 3개의 점수(로짓) z
model = nn.Linear(2, 3)
loss_fn = nn.CrossEntropyLoss() # softmax + 교차 엔트로피를 한 번에
optimizer = torch.optim.SGD(model.parameters(), lr=0.02)
for epoch in range(2000):
z = model(X) # 각 클래스의 점수 (softmax 전)
loss = loss_fn(z, y) # 정답 확률이 낮을수록 큰 벌점
optimizer.zero_grad()
loss.backward() # 기울기 계산
optimizer.step() # 파라미터 한 걸음 이동
# 새 사진 예측: 세 확률(합=1) 중 가장 큰 클래스 고르기
probs = torch.softmax(model(X_new), dim=1)
pred = probs.argmax(dim=1)