이 모듈의 도달 목표

학습 루프를 만들고 평가하기

자동 미분 Tensor로 반복 학습 루프를 구성하고 학습·평가 데이터를 분리해 손실과 MAE로 모델 성능을 판단합니다.

결과물 · 자동 미분 학습 루프 평가기
약 6~8시간
  • 학습 루프의 gradient 초기화·순전파·손실·역전파·업데이트 순서를 설명한다
  • epoch별 손실을 기록하며 매개변수를 반복 학습한다
  • gradient 누적 오류를 찾아 수정한다
  • 학습과 평가 데이터를 분리해 MSE와 MAE를 해석한다
01

한 epoch는 전체 학습 절차를 한 번 수행한다

한 epoch에서는 gradient를 초기화하고, 현재 매개변수로 예측과 손실을 만든 뒤 backward를 실행하고 매개변수를 갱신합니다. 이 순서를 반복하면서 손실 기록을 남기면 학습이 실제로 진행되는지 확인할 수 있습니다.

일상에서 보면문제를 풀고 채점하고 틀린 이유를 반영해 다시 푸는 한 차례가 epoch 하나인 것과 같습니다.
steps = ['zero_grad', 'forward', 'loss', 'backward', 'update']
for step in steps:
    print(step)
실행 결과
zero_grad
forward
loss
backward
update
한 줄씩 보기
  1. 이전 gradient를 지웁니다.
  2. 현재 모델로 예측합니다.
  3. 틀린 정도를 계산합니다.
  4. 기울기를 역전파합니다.
  5. 기울기 반대 방향으로 갱신합니다.
직접 값 바꾸기update를 backward보다 먼저 하면 왜 안 되는지 설명하세요.
흔한 실수단계 순서가 바뀌면 현재 손실에서 구한 gradient로 현재 매개변수를 업데이트할 수 없습니다.

짧은 확인backward 직전에 반드시 준비돼 있어야 하는 값은 무엇일까요?

02

gradient는 epoch마다 0에서 다시 시작한다

자동 미분은 같은 Tensor의 gradient에 경로별 기여를 더합니다. 이 누적은 한 계산 그래프 안에서는 필요하지만 다음 epoch까지 남으면 서로 다른 모델 상태의 gradient가 섞이므로 매 반복 시작에 0으로 초기화합니다.

일상에서 보면오늘 장바구니 합계를 계산하기 전에 어제 합계를 지우는 것과 같습니다.
class Parameter:
    grad = -4.0

p = Parameter()
p.grad = 0.0
print(p.grad)
실행 결과
0.0
한 줄씩 보기
  1. 이전 계산의 gradient가 있다고 가정합니다.
  2. 새 epoch 시작에 0으로 바꿉니다.
  3. 이번 backward의 기여만 쌓이게 됩니다.
직접 값 바꾸기gradient를 초기화하지 않은 3회 학습과 초기화한 학습의 weight를 비교하세요.
흔한 실수data까지 0으로 만들면 학습한 매개변수 자체가 사라집니다. 초기화 대상은 grad입니다.

짧은 확인한 그래프 안에서는 gradient를 누적하면서 epoch 사이에는 지워야 하는 이유는 무엇일까요?

03

optimizer는 gradient를 실제 매개변수 변화로 바꾼다

backward는 기울기를 계산할 뿐 weight나 bias를 자동으로 바꾸지 않습니다. optimizer 단계에서 parameter.data -= learning_rate * parameter.grad를 실행해야 다음 epoch의 예측이 달라집니다.

일상에서 보면내비게이션이 방향을 알려 줘도 운전자가 핸들을 움직여야 차가 실제로 이동하는 것과 같습니다.
weight, grad, learning_rate = 0.0, -4.0, 0.5
weight -= learning_rate * grad
print(weight)
실행 결과
2.0
한 줄씩 보기
  1. 현재 가중치와 기울기를 준비합니다.
  2. 학습률만큼 기울기 반대 방향으로 이동합니다.
  3. 새 가중치가 다음 예측에 사용됩니다.
직접 값 바꾸기학습률을 0으로 두면 backward를 실행해도 weight가 바뀌지 않는지 확인하세요.
흔한 실수grad를 갱신하거나 data에 gradient를 더하면 올바른 경사하강 업데이트가 아닙니다.

짧은 확인backward 뒤에 모델의 예측을 실제로 바꾸는 단계는 무엇일까요?

04

학습 손실 기록은 루프의 건강 상태를 보여 준다

매 epoch 같은 기준의 MSE를 기록하면 손실이 감소하는지, 정체되는지, 발산하는지 볼 수 있습니다. 손실이 커지면 gradient 초기화, 업데이트 부호, 학습률과 데이터 shape를 차례로 점검합니다.

일상에서 보면운동할 때 매일 같은 방식으로 기록한 시간을 보면 훈련 효과와 이상 징후를 알 수 있는 것과 같습니다.
history = [4.0, 1.0, 0.25]
print(history[-1] < history[0])
실행 결과
True
한 줄씩 보기
  1. epoch별 손실을 순서대로 저장합니다.
  2. 마지막 손실과 첫 손실을 비교합니다.
  3. 감소 여부를 기본 건강 신호로 사용합니다.
직접 값 바꾸기[4, 6, 10]처럼 커지는 기록에서 가장 먼저 확인할 설정을 적어 보세요.
흔한 실수서로 다른 데이터나 손실 함수를 사용한 숫자를 같은 학습 곡선처럼 직접 비교하면 안 됩니다.

짧은 확인손실이 반복할수록 폭발한다면 어떤 세 가지를 확인해야 할까요?

05

평가는 학습에 쓰지 않은 데이터에서 매개변수를 고정하고 한다

학습 손실이 낮아도 처음 보는 입력에서 잘 작동한다는 보장은 없습니다. 평가 데이터에서는 backward와 update를 하지 않고 예측만 만든 뒤 MAE 같은 지표를 계산합니다. 평가 결과를 보고 다시 그 데이터에 맞춰 직접 업데이트하면 더 이상 독립 평가가 아닙니다.

일상에서 보면연습 문제로 공부한 뒤 답을 외우지 않은 새 시험지로 실력을 확인하는 것과 같습니다.
predictions = [3.0, 5.0]
targets = [4.0, 5.0]
mae = sum(abs(p-y) for p, y in zip(predictions, targets)) / len(targets)
print(mae)
실행 결과
0.5
한 줄씩 보기
  1. 고정된 모델의 평가 예측을 준비합니다.
  2. 보지 않은 정답과 절대 오차를 구합니다.
  3. 평균으로 평가 MAE를 계산합니다.
직접 값 바꾸기학습 MSE는 0인데 평가 MAE가 큰 경우 무엇을 의심해야 할지 적어 보세요.
흔한 실수평가 데이터로 gradient를 계산해 모델을 바꾸면 성능을 정직하게 측정할 수 없습니다.

짧은 확인평가 단계에서 backward와 optimizer step을 실행하지 않는 이유는 무엇일까요?

새 epoch 전에 gradient 초기화하기

  1. data와 grad 역할을 구분합니다.
  2. 매개변수 목록을 순회합니다.
  3. grad만 0으로 만듭니다.
  4. 여러 초기 gradient에서 같은 결과를 확인합니다.
class Parameter:
    def __init__(self, data, grad):
        self.data = data
        self.grad = grad

def zero_grad(parameters):
    for parameter in parameters:
        parameter.grad = 0.0

w_grad, b_grad = map(float, input().split())
w = Parameter(0.0, w_grad)
b = Parameter(0.0, b_grad)
zero_grad([w, b])
print(f'w.grad: {w.grad:.1f}')
print(f'b.grad: {b.grad:.1f}')

핵심을 확인해 볼까요?

5문항 중 4문항 이상 정답이면 완료됩니다. 오답 후에도 다시 제출할 수 있습니다.

1학습 루프의 올바른 순서는?
2epoch 시작에 zero_grad가 필요한 이유는?
3backward 직후 매개변수 data는 자동으로 바뀌는가?
4학습 손실이 계속 커질 때 확인할 항목이 아닌 것은?
5평가 데이터에서 하지 않아야 할 것은?