튜토리얼 · 2
밑바닥부터
같은 문제를 아무것도 없는 데서부터: 날텐서와 손으로 쓴 기울기 스텝, 그다음
nn.Linear, 그다음 optim, 그다음
DataLoader. 한 겹씩 얹을 때마다 방금 직접 본 일을 하던 코드가
지워진다.
"nn 이 실제로 무엇을 하는가" 에 답하는 튜토리얼이다. 아래에 마법은
없고, 끝나면 루프가 앞으로 쓸 모든 학습 루프와 같은 모양이 된다.
0 · 문제
y = 2x − 1 위에 잡음이 얹힌 점들에 직선을 맞춘다. 눈으로 확인할 만큼
작고, 모든 조각이 실제로 돌아야 할 만큼은 진짜다.
1 · 손으로
파라미터 둘, 직접 쓴 손실, 직접 적용하는 스텝. borch 가 여기서 하는 일은 미분 하나뿐이다 — autograd 가 그것이고, 손으로 쓰고 싶지 않은 유일한 조각이다.
갱신을 noGrad 로 감싼 것을 보라. 파라미터를 바꾸는 일은 기울기를
구하려는 그 계산의 일부가 아니고, torch 의 옵티마이저도 정확히 이렇게 한다.
borch 가 torch 와 갈리는 자리가 하나 있다. torch 라면
w -= lr * w.grad 라고 쓰겠지만, 여기서 sub_ 와
mul_ 은 수를 받고 텐서를 받는 제자리 연산은
addcmul_ 이다. 그래서 스텝이
w.addcmul_(w.grad, one, -lr) 이고 이는
w += -lr · grad · 1 이다. sub_ 에 텐서를 넘기면 예외가
안 나고 조용히 NaN 이 된다 — 이 문단이 생긴 이유다.
2 · nn.Linear 가 파라미터를 들게
층이 weight 와 bias 를 들고 순방향을 안다. 사라지는 것:
텐서 둘을 만드는 일, 그 모양을 기억하는 일, x @ w + b 를 적는 일.
그대로인 것: 나머지 전부.
3 · optim 이 걸음을 걷게
zeroGrad() 와 step() 이 방금 쓴 두 고리를 대신한다.
이제 옵티마이저는 갈아 끼울 수 있는 것이다 — 아래 줄의 SGD 를
Adam 으로 바꾸면 곡선의 모양이 달라진다.
4 · DataLoader 가 배치를 나눠 주게
마지막 조각. 64 점이면 전체를 한 번에 써도 됐지만 진짜 데이터는 안 들어간다.
루프 몸통은 하나도 안 바뀐다 — 바뀌는 것은 x 와 y 가
어디서 오느냐뿐이다.