LLM 엔지니어링2장 · 신경망과 딥러닝의 기본 원리10 / 23← 이전목차다음 →MetaContents

2장. 신경망과 딥러닝의 기본 원리

학습률

안개 산에서 보폭을 정하는 일을 생각해 보세요. 보폭이 너무 작으면 해가 질 때까지 내려가지 못합니다. 너무 크면 골짜기를 건너뛰어 맞은편 비탈로 올라가 버립니다. 경사하강법의 보폭이 학습률입니다.

학습률이 너무 작을 때, 알맞을 때, 너무 클 때 손실 곡선 위의 걸음을 셋으로 나란히 그린 개념 그림

왼쪽 주황 점은 보폭이 너무 작아 여섯 걸음을 가도 아직 비탈 중간입니다. 가운데 청록 점은 몇 걸음 만에 바닥에 닿습니다. 오른쪽 마젠타 점은 보폭이 너무 커서 바닥을 건너뛰며 점점 위로 튕겨 나갑니다.

학습률 고르기

학습률일어나는 일손실 곡선의 모양
너무 작다(예: 0.0001)아주 느리게 줄어든다거의 평평하게 천천히 내려간다
알맞다(예: 0.001~0.01, Adam 기준)빠르게 줄고 안정된다처음에 크게 떨어지고 평평해진다
너무 크다(예: 0.5 이상)들쭉날쭉하거나 커진다오르내리거나 줄지 않는다

알맞은 학습률은 옵티마이저와 데이터마다 다릅니다. 실습 5에서 세 가지 학습률로 직접 견주어 봅니다.

옵티마이저

가중치를 고치는 도구를 옵티마이저라고 합니다. 위의 "새 w = w - 학습률 × 기울기"를 그대로 하는 것이 SGD 이고, 걸음마다 보폭을 알아서 조절하는 것이 Adam 입니다.

옵티마이저특징흔히 쓰는 학습률
torch.optim.SGD식 그대로. 단순하다0.01 ~ 0.1
torch.optim.Adam가중치마다 보폭을 조절한다. 처음 쓰기 좋다0.001 ~ 0.01
Python
import torch

w = torch.tensor([1.0], requires_grad=True)   # 학습할 가중치 하나
opt = torch.optim.SGD([w], lr=0.1)            # 이 가중치를 학습률 0.1 로 고치는 옵티마이저

loss = (w - 3) ** 2        # 바닥이 3 인 손실
loss.backward()            # 기울기 구하기: 2 × (1 - 3) = -4
opt.step()                 # w = 1 - 0.1 × (-4) = 1.4
print(w.item())

opt.step() 한 줄이 경사하강법 한 걸음입니다. w 는 1.0 에서 1.4 로 바닥 쪽(3)을 향해 움직입니다. 출력이 1.399999976158142 처럼 1.4 에 아주 조금 못 미치게 나오는데, PyTorch 텐서가 기본으로 소수를 float32(소수 7자리 안팎까지 정확한 형식)로 담기 때문에 생기는 작은 오차입니다.

requires_grad 와 backward() 를 짧게

두 가지는 다음 절 "역전파와 자동 미분"에서 자세히 봅니다. 여기서는 하는 일만 알아 둡니다.

코드하는 일안개 산으로 치면
requires_grad=True"이 값은 학습할 값이니 기울기를 구해 달라"고 표시한다. 표시한 텐서는 계산 과정이 기록된다"내 자리는 움직일 수 있다"고 이름표를 단다
loss.backward()기록해 둔 계산을 거꾸로 따라가 기울기를 구하고, 표시한 텐서의 .grad 에 넣어 둔다발밑의 경사를 더듬어 수첩에 적는다
opt.step().grad 에 적힌 기울기로 가중치를 고친다수첩을 보고 한 걸음 옮긴다

앞 절에서는 기울기를 2 * (w - 3) 으로 사람이 직접 적었습니다. backward() 는 이 식을 몰라도 같은 값을 구해 줍니다. 표시하지 않은 텐서(requires_grad 를 주지 않은 텐서)는 기울기를 구하지 않으므로, 데이터처럼 바뀌면 안 되는 값에는 표시하지 않습니다.

이 코드가 뜻하는 것

이 코드는 앞 절 "경사하강법"의 손으로 걷기를 PyTorch 로 한 걸음만 다시 한 것입니다. 바닥이 3 인 같은 손실에서, 출발점 1.0, 학습률 0.1 로 걸었습니다. 달라진 것은 기울기 계산과 가중치 고치기를 사람이 적지 않고 PyTorch 에 맡겼다는 점입니다.

할 일앞 절(손으로)이 코드(PyTorch)
기울기 구하기grad = 2 * (w - 3) 을 직접 적는다loss.backward() 가 구한다
한 걸음 옮기기w = w - lr * grad 를 직접 적는다opt.step() 이 한다
학습률 정하기lr = 0.3SGD([w], lr=0.1) 에 넣어 둔다

과정 안에 숨은 값을 하나씩 찍어 보면 무슨 일이 일어나는지 보입니다.

Python
import torch

w = torch.tensor([1.0], requires_grad=True)
opt = torch.optim.SGD([w], lr=0.1)

loss = (w - 3) ** 2
print("backward 전 기울기:", w.grad)        # 아직 구하지 않아 None
loss.backward()
print("backward 후 기울기:", w.grad)        # 2 × (1 - 3) = -4
opt.step()
print("step 후 가중치:", w)                 # 1 - 0.1 × (-4) = 1.4

실행하면 기울기는 backward() 전에는 None, 뒤에는 tensor([-4.]) 이고, step() 뒤의 가중치는 tensor([1.4000], requires_grad=True) 입니다. 기울기 -4 는 "w 를 키우면 손실이 줄어든다"는 뜻이라, 옵티마이저가 w 를 0.1 × 4 = 0.4 만큼 키웠습니다.

실제 학습은 이 세 줄(손실 계산, backward(), step())을 데이터를 바꿔 가며 수천 번 되풀이합니다. 가중치가 수백만 개여도 코드는 같고, backward() 가 모든 가중치의 기울기를, step() 이 모든 가중치의 갱신을 한꺼번에 해 줍니다. 되풀이할 때 꼭 필요한 한 줄(기울기 지우기)은 뒤의 "학습 루프" 절에서 봅니다.

주의할 점

  • 손실이 줄지 않고 nan(숫자가 아님)이 나오면 학습률부터 낮춰 봅니다. 대부분 보폭이 너무 커서 튕겨 나간 경우입니다.
  • 학습률도 사람이 정하는 설정이라, 원래는 검증용 데이터로 고릅니다.
← 이전 절2장 · 경사하강법다음 절 →2장 · 역전파와 자동 미분