C.W.K.
Stream
Lesson 03 of 10 · published

.backward() 와 .grad 버퍼

~12 min · backward, grad, scalar

Level 0Tensor 호기심
0 XP0/62 lessons0/13 achievements
0/120 XP to next level120 XP to go0% complete

gradient 가 land 하는 법 — 그리고 누적할 때

tensor.backward() 가 backward pass 트리거 호출. scalar 에 호출 기대 — scalar 아니면 'incoming gradient' 인자 제공해서 backward 에게 각 output element 가중치 알려줘야 함. 정상 supervised learning 에선 loss 가 항상 scalar 라 이 인자 거의 안 나타나.

.grad accumulator

backward 후 gradient 가 leaf_tensor.grad 에 land. 중요한 사실: 반복 backward 호출이 기존 .grad 에 더해, overwrite 안 함. 모든 training loop 위에 optimizer.zero_grad() 가 있는 이유 — accumulator reset.

가끔 누적 행동이 유용 — gradient accumulation (여러 mini-batch 에 gradient 누적해서 큰 batch simulate) 을 trivial 하게 해줘.

Non-scalar output

non-scalar tensor 에 .backward() 호출해야 하면 같은 shape 의 tensor 를 'virtual incoming gradient' 로 넘겨야 함 — vector-Jacobian product (vJp). 실전엔 research 코드 (per-sample gradient, custom loss) 에서 정상 training 보다 자주 봐.

Code

Scalar backward — 표준 케이스·python
import torch

x = torch.tensor([1.0, 2.0, 3.0], requires_grad=True)
y = (x ** 2).sum()        # collapse to scalar
y.backward()
print(x.grad)             # tensor([2., 4., 6.])
누적 — zero_grad 가 존재하는 이유·python
import torch

x = torch.tensor(2.0, requires_grad=True)

(x ** 2).backward()       # dy/dx = 4
print(x.grad)             # tensor(4.)

(x ** 3).backward()       # dy/dx = 12, but accumulates with the 4
print(x.grad)             # tensor(16.) — 4 + 12

# The fix in real training:
x.grad = None             # or .zero_() — both work; None is faster
(x ** 3).backward()
print(x.grad)             # tensor(12.)
Gradient accumulation — 작은 GPU 에서 큰 batch·python
import torch
import torch.nn as nn

model = nn.Linear(10, 2)
optimizer = torch.optim.SGD(model.parameters(), lr=1e-3)
loss_fn = nn.MSELoss()
accumulation_steps = 4

optimizer.zero_grad()
for i in range(8):  # 8 mini-batches → effective batch = 8 * micro-batch
    x = torch.randn(16, 10)
    y = torch.randn(16, 2)
    loss = loss_fn(model(x), y) / accumulation_steps   # scale!
    loss.backward()                                     # accumulates

    if (i + 1) % accumulation_steps == 0:
        optimizer.step()
        optimizer.zero_grad()

External links

Exercise

누적 버그 의도적 재현: zero_grad 빠진 5-step training loop. 매 step 후 parameter L2 norm print. 그 다음 zero_grad 추가하고 다시 돌려. norm trajectory 가 극적으로 갈라져야 함 — 두 plot 모두 메모리 보조로 note 에 보관.

Progress

Progress is local-only — sign in to sync across devices.
이 페이지에서 버그를 발견하셨거나 피드백이 있으세요?문제 신고

댓글 0

🔔 답글 알림 (로그인 필요)
로그인댓글을 남기려면 로그인해 주세요.

아직 댓글이 없어요. 첫 댓글을 남겨보세요.