무엇을 보고 무엇을 맞히는가
지도학습은 입력 x와 정답으로 취급할 목표 y의 쌍을 이용해 모형을 조정하는 방법이다. 센서 특징에서 거리 값을 예측하거나 영상에서 물체 종류를 고르는 문제가 예다. 정답이라는 말은 데이터 수집/라벨 정책이 정한 목표라는 뜻이지 모든 환경에서 절대 참값이라는 보장은 아니다. 시연자의 행동과 실제 성공한 결과도 구별해야 한다. 잘못 정렬한 센서와 목표를 학습하면 코드는 정상이어도 잘못된 관계를 맞춘다.
모형 f_w는 조절 가능한 파라미터 w를 사용해 예측값 ŷ를 만든다. 손실 L은 예측과 목표의 차이를 수치로 표현한다. 최적화는 이 손실을 줄이는 파라미터를 찾는 과정이다. 딥러닝은 여러 층으로 표현을 학습하는 모형을 쓰지만 손실/경사/갱신의 구분은 작은 모형에서도 관찰할 수 있다. 여기서는 모든 값이 정규화된 무차원 합성 수치이며 실제 관절에 바로 전달할 명령이 아니다.
두 표본 (x,y)=(1,2),(2,4)와 모형 ŷ=wx를 쓰자. 절편은 없고 w 하나만 학습한다. 평균 제곱 오차 MSE는 n개 표본의 제곱 오차 평균이다. i는 표본 번호, n은 표본 수다. 이번에는 표본당 출력이 하나여서 n=2가 평균의 분모다. 여러 출력의 PyTorch MSELoss(mean)는 전체 원소에 대해 평균하므로 출력 차원까지 늘면 분모도 그에 맞게 달라진다.
w=0이면 예측은 [0,0], 오차는 [−2,−4], 손실은 (4+16)/2=10이다. 제곱은 큰 오차의 영향을 키운다. 절댓값 오차 L1과 같은 손실은 다른 민감도와 최적 예측을 가질 수 있다. 예를 들어 같은 입력의 목표가 −1/+1로 반반이면 MSE는 예측 0에서 최소지만 두 실제 행동 중 어느 것도 아닐 수 있다. 장애물을 왼쪽/오른쪽으로 피하는 행동을 평균냈다고 성공 행동이 되는 것은 아니다. 손실의 숫자와 작업의 성공 조건을 따로 정한다.
경사는 어느 방향을 말하는가
경사 g=dL/dw는 현재 w를 조금 늘릴 때 손실이 얼마나 변하는지 나타낸다. 오차 e_i=wx_i−y_i라 두면 제곱 오차를 e_i로 미분한 2e_i와 e_i를 w로 미분한 x_i를 곱한다. 이것이 연쇄법칙이다. 두 표본의 기여를 평균해 다음 경사를 얻는다.
그림 M11.01-1. 각 칸은 서로 다른 역할/근거다. 아래 방향은 자료/처리의 연결이며 실제 성공을 자동으로 보장하지 않는다. 직접 제작한 개념도이며 본문의 조건과 함께 읽는다.
η는 학습률로 한 번에 이동할 크기를 정하는 양수다. w=0에서 첫 표본 기여는 2×(−2)×1/2=−2, 둘째는 2×(−4)×2/2=−8이라 g=−10이다. η=0.1이면 w_new=0−0.1×(−10)=1이다. 새 예측은 [1,2], 새 손실은 (1+4)/2=2.5다. 음의 경사이므로 w를 늘리는 쪽이 이 점에서 손실을 줄인다. ‘경사에 음수가 있으니 파라미터를 빼야 한다’처럼 갱신식의 두 부호를 따로 놓치지 않는다.
다음 단계는 w=1에서 경사를 다시 계산한다. g=−5이므로 η=0.1이면 w=1.5, 손실은 0.625다. 처음 구한 경사 −10을 계속 재사용하는 것이 아니다. η=0.5를 첫 단계부터 쓰면 w=5, 손실은 22.5로 처음 10보다 커진다. 작은 모형에서도 너무 큰 학습률은 최적점 너머로 뛰어갈 수 있다. 복잡한 비선형 모형에서는 한 번 감소하거나 gradient가 작다는 이유만으로 전역 최적해나 일반화를 보장하지 않는다.
역전파는 갱신과 다른 단계다
순전파 forward는 입력에서 예측과 손실을 계산한다. 역전파 backward는 계산 그래프의 연쇄법칙을 이용해 파라미터에 대한 경사를 계산한다. optimizer의 step은 그 경사와 알고리즘 상태로 파라미터를 변경한다. PyTorch 공식 autograd 설명처럼 연산 그래프를 추적하는 자동미분이며, 손실을 여러 번 조금 바꾸어 빼는 유한차분과 같은 방법은 아니다.
PyTorch의 .grad는 기본적으로 기울기를 누적한다. 서로 독립된 두 학습 단계를 의도한다면 매 단계 전에 zero_grad로 이전 값을 비운다. 의도한 gradient accumulation은 여러 작은 배치를 합쳐 학습하는 별도 설계이며 분모/갱신 빈도를 맞춰야 한다. 이번 예에서 초기화 없이 w=1의 새 경사 −5를 이전 −10에 더하면 .grad=−15이고 η=0.1의 다음 w는 2.5가 된다. 올바른 새 경사만 쓴 1.5와 다르다.
전체 훈련 자료를 한 번 훑는 것을 epoch, 한 번의 계산에 묶는 자료를 batch라고 부른다. 이번 두 표본은 하나의 batch다. 실제 학습에서는 배치 순서와 파라미터 초기값·자료 분할·정규화·손실 reduction도 기록한다. 작은 손실을 얻는 것과 보지 않은 환경에서 맞는 것은 M11.03에서 분리해 검증한다. 기존 5.1 행동 복제의 회귀를 읽기 전에 목표 행동 표현과 손실의 의미를 이 구분으로 확인한다.
선택 CPU 예제와 확인 범위
아래는 완전한 Python 코드다. PyTorch가 이미 있는 경우에만 선택 실행하며 기본 종이 활동을 대신할 필요는 없다. 작성 시 실제 Darwin 환경의 PyTorch 2.13.0 CPU에서 실행해 아래 출력과 일치했다. Ubuntu 24.04에서 실행했다고 표시하지 않으며, 현재 공식 stable API 문서가 연결하는 버전과 로컬 실행 버전도 구별한다. 실제 영상/VLA/로봇 학습 성능의 증거는 아니다.
import torch
x = torch.tensor([1.0, 2.0], dtype=torch.float64)
y = torch.tensor([2.0, 4.0], dtype=torch.float64)
w = torch.nn.Parameter(torch.tensor(0.0, dtype=torch.float64))
optimizer = torch.optim.SGD([w], lr=0.1)
optimizer.zero_grad(set_to_none=True)
loss = ((w * x - y) ** 2).mean()
loss.backward()
print(f"before w={w.item():.3f} loss={loss.item():.3f} grad={w.grad.item():.3f}")
optimizer.step()
with torch.no_grad():
new_loss = ((w * x - y) ** 2).mean()
print(f"after w={w.item():.3f} loss={new_loss.item():.3f}")
before w=0.000 loss=10.000 grad=-10.000
after w=1.000 loss=2.500
loss.backward만 하고 step을 빼면 경사는 있어도 w는 그대로다. no_grad는 마지막 평가 계산의 그래프 추적을 끄는 용도로 썼다. 학습 순전파 전체를 no_grad에 넣으면 필요한 경사 경로가 사라진다. NaN 손실이나 경사가 나오면 학습률을 무조건 낮추기 전에 입력의 유한 값·정규화/shape·손실 정의를 검사한다.