옵티마이저(Optimizers) — SGD, 모멘텀(Momentum), Adam, AdamW

경사하강법(gradient descent)은 어느 방향으로 가야 하는지 알려줍니다. 얼마나 멀리, 얼마나 빠르게 갈지는 말해 주지 않습니다. SGD는 나침반이고, Adam은 교통 정보를 가진 GPS에 가깝습니다.

유형: Build

언어: Python

선수 지식: Lesson 03.05 손실 함수(Loss Functions)

소요 시간: 약 75분

학습 목표

  • Python으로 SGD, 모멘텀(momentum)을 포함한 SGD, Adam, AdamW 옵티마이저(optimizer)를 처음부터 구현합니다.
  • Adam의 편향 보정(bias correction)이 초기 학습 단계(early training step)에서 0으로 초기화된 모멘트 추정값(zero-initialized moment estimate)을 어떻게 보정하는지 설명합니다.
  • 같은 과제(task)에서 AdamW가 Adam + L2 정규화(L2 regularization)보다 더 나은 일반화(generalization)를 만드는 이유를 보여 줍니다.
  • 트랜스포머(transformer), CNN, GAN, 파인튜닝(fine-tuning) 상황에 맞는 옵티마이저와 기본 하이퍼파라미터(hyperparameter)를 선택합니다.

문제

기울기(gradient)를 계산했습니다. 가중치(weight) #4,721을 0.003만큼 줄이면 손실(loss)이 줄어든다는 것도 알았습니다. 그런데 0.003은 어떤 단위인가요? 무엇으로 스케일(scale)해야 하나요? 단계(step) 1과 단계 1,000에서 같은 크기로 움직여야 할까요?

기본 경사하강법(vanilla gradient descent)은 모든 파라미터(parameter)에 매 단계(step)마다 같은 학습률(learning rate)을 적용합니다.

w = w - lr * gradient

이 방식은 실제 신경망 학습(neural network training)에서 세 가지 문제를 만듭니다.

첫째, 진동(oscillation)입니다. 손실 지형(loss landscape)은 매끄러운 그릇(bowl)보다 길고 좁은 계곡(valley)에 가깝습니다. 기울기는 계곡을 따라가는 완만한 방향(shallow direction)이 아니라 계곡을 가로지르는 가파른 방향(steep direction)을 가리키기 쉽습니다. 그래서 경사하강법은 좁은 방향으로 튕기며 유용한 방향(useful direction)으로는 조금씩만 나아갑니다. 손실(loss)이 빠르게 떨어진 뒤 정체 구간(plateau)에 머무는 상황을 본 적이 있을 것입니다. 모델이 수렴한 것이 아니라 진동하는 경우가 많습니다.

둘째, 모든 파라미터에 하나의 학습률을 쓰는 것은 맞지 않습니다. 어떤 가중치는 큰 업데이트(update)가 필요합니다. 아직 초기의 과소적합(underfitting) 단계에 있을 수 있습니다. 다른 가중치는 최적값(optimal value) 근처라 아주 작은 업데이트만 필요합니다. 앞의 가중치에 맞는 학습률은 뒤의 가중치를 망치고, 그 반대도 마찬가지입니다.

셋째, 안장점(saddle point)입니다. 고차원 손실 지형(high-dimensional loss landscape)에는 기울기가 거의 0인 평평한 영역(flat region)이 넓게 존재합니다. 기본 SGD는 기울기 속도만큼 기어가므로 사실상 0에 가까운 속도로 움직입니다. 모델이 막힌 것처럼 보입니다. 실제로는 막힌 것이 아니라, 반대편에 유용한 하강(descent) 방향이 있는 평평한 영역에 있을 수 있습니다. 하지만 SGD에는 밀고 지나갈 장치가 없습니다.

Adam은 이 세 문제를 모두 다룹니다. 파라미터마다 두 개의 이동 평균(running average)을 유지합니다. 평균 기울기(mean gradient, 모멘텀)는 진동을 다루고, 평균 제곱 기울기(mean squared gradient, 적응형 비율)는 서로 다른 스케일(scale)을 다룹니다. 처음 몇 단계(step)에 대한 편향 보정(bias correction)을 더하면 기본 하이퍼파라미터(default hyperparameter)로 80%의 문제에서 작동하는 하나의 옵티마이저가 됩니다. 이 강의에서는 Adam을 처음부터 만들어 나머지 20%에서 언제 왜 실패하는지까지 이해합니다.

사전 테스트

2문제 · 이 강의를 시작하기 전에 얼마나 알고 있는지 확인해보세요

1.경사하강법(gradient descent)에서 모멘텀(momentum)은 어떤 문제를 해결하나요?

2.Adam과 AdamW의 핵심 차이는 무엇인가요?

0/2 답변 완료

개념

확률적 경사하강법(Stochastic Gradient Descent; SGD)

가장 단순한 옵티마이저입니다. 미니배치(mini-batch)에서 기울기를 계산하고 반대 방향으로 한 단계(step) 나아갑니다.

w = w - lr * gradient

"확률적(stochastic)"이라는 말은 전체 데이터셋(dataset)이 아니라 무작위 부분집합(random subset), 즉 미니배치로 기울기를 추정한다는 뜻입니다. 이 잡음(noise)은 실제로 유용할 수 있습니다. 날카로운 지역 최솟값(sharp local minimum)에서 빠져나오는 데 도움이 됩니다. 하지만 이 잡음은 진동도 만듭니다.

학습률(learning rate)이 유일한 조절 손잡이(knob)입니다. 너무 크면 손실이 발산(diverge)합니다. 너무 작으면 학습(training)이 영원히 걸립니다. 최적값은 아키텍처(architecture), 데이터(data), 배치 크기(batch size), 현재 학습 단계(training stage)에 따라 달라집니다. 현대 신경망(modern network)의 기본 SGD에서는 보통 0.01-0.1 범위를 씁니다. 하지만 하나의 학습 실행 안에서도 이상적인 학습률은 바뀝니다.

모멘텀(Momentum)

공이 비탈길을 굴러 내려가는 비유는 너무 자주 쓰이지만 정확합니다. 기울기만으로 한 단계 나아가지 않고, 과거 기울기(past gradient)를 누적하는 속도(velocity)를 유지합니다.

m_t = beta * m_{t-1} + gradient
w = w - lr * m_t

beta는 보통 0.9입니다. beta = 0.9이면 모멘텀은 대략 최근 10개 기울기의 평균처럼 동작합니다. 1 / (1 - 0.9) = 10이기 때문입니다.

이것이 진동을 줄이는 이유는 간단합니다. 같은 방향을 가리키는 기울기는 누적됩니다. 방향이 번갈아 바뀌는 기울기는 서로 상쇄됩니다. 좁은 계곡에서 "가로지르는(across)" 성분은 매 단계마다 부호가 바뀌며 약해지고, "따라가는(along)" 성분은 일관되게 유지되어 증폭됩니다. 결과는 유용한 방향으로의 부드러운 가속입니다.

실제 숫자로 보면, 조건이 나쁜 손실 지형(badly conditioned loss landscape)에서 SGD만 쓰면 10,000 단계가 걸릴 수 있습니다. 같은 문제에서 모멘텀을 포함한 SGD(beta=0.9)는 보통 3,000-5,000 단계가 걸립니다. 속도 향상은 사소하지 않습니다.

RMSProp

RMSProp은 파라미터별 적응형 학습률(per-parameter adaptive learning rate)을 실제로 유용하게 만든 초기 방법입니다. Hinton이 Coursera 강의에서 제안했으며, 정식 논문으로 발표되지는 않았습니다.

s_t = beta * s_{t-1} + (1 - beta) * gradient^2
w = w - lr * gradient / (sqrt(s_t) + epsilon)

s_t는 제곱 기울기(squared gradient)의 이동 평균입니다. 지속적으로 큰 기울기를 가진 파라미터는 큰 수로 나뉘어 유효 학습률(effective learning rate)이 작아집니다. 작은 기울기를 가진 파라미터는 작은 수로 나뉘어 유효 학습률이 커집니다.

이 방식은 "모든 파라미터에 하나의 학습률" 문제를 해결합니다. 이미 큰 업데이트를 많이 받은 가중치는 목표 근처에 있을 가능성이 높으므로 느리게 움직입니다. 작은 업데이트만 받은 가중치는 덜 훈련되었을 수 있으므로 빠르게 움직입니다.

엡실론(epsilon, 보통 1e-8)은 어떤 파라미터가 아직 업데이트되지 않았을 때 0으로 나누는 일을 막습니다.

Adam: 모멘텀(Momentum) + RMSProp

Adam은 두 아이디어를 합칩니다. 파라미터마다 두 개의 지수 이동 평균(exponential moving average)을 유지합니다.

m_t = beta1 * m_{t-1} + (1 - beta1) * gradient
v_t = beta2 * v_{t-1} + (1 - beta2) * gradient^2

많은 설명에서 건너뛰는 핵심 세부사항은 편향 보정(bias correction)입니다. 단계 1에서 m_1 = (1 - beta1) * gradient입니다. beta1 = 0.9라면 실제 기울기의 0.1배라 10배나 작습니다. 이동 평균(moving average)이 아직 워밍업(warmup)되지 않았기 때문입니다. 편향 보정이 이를 보상합니다.

m_hat = m_t / (1 - beta1^t)
v_hat = v_t / (1 - beta2^t)

단계 1에서 beta1 = 0.9라면 m_hat = m_1 / (1 - 0.9) = m_1 / 0.1이 되어 실제 기울기를 복원합니다. 단계 100에서는 (1 - 0.9^100)이 거의 1.0이므로 보정 효과는 사라집니다. 편향 보정은 처음 약 10 단계에서 중요하고, 약 50 단계 이후에는 거의 무관합니다.

업데이트(update)는 다음과 같습니다.

w = w - lr * m_hat / (sqrt(v_hat) + epsilon)

Adam의 기본값(default)은 lr=0.001, beta1=0.9, beta2=0.999, epsilon=1e-8입니다. 이 기본값은 80%의 문제에서 작동합니다. 잘 안 맞으면 먼저 학습률을 바꿉니다. 그다음 beta2를 검토합니다. beta1이나 epsilon은 거의 바꾸지 않습니다.

AdamW: 올바른 가중치 감쇠(Weight Decay)

L2 정규화(L2 regularization)는 손실에 lambda * w^2를 더합니다. 기본 SGD(vanilla SGD)에서는 이것이 가중치 감쇠(weight decay), 즉 각 단계에서 가중치에서 lambda * w를 빼는 것과 동등합니다. 하지만 Adam에서는 이 동등성(equivalence)이 깨집니다.

Loshchilov와 Hutter의 통찰은 이것입니다. 손실에 L2를 더한 뒤 Adam이 기울기를 처리하면, 정규화 항(regularization term)도 적응형 학습률(adaptive learning rate)에 의해 스케일됩니다. 기울기 분산(gradient variance)이 큰 파라미터는 정규화를 덜 받고, 분산이 작은 파라미터는 더 받습니다. 우리가 원하는 것은 기울기 통계(gradient statistics)와 무관한 균일한 정규화(uniform regularization)입니다.

AdamW는 Adam 업데이트 이후 가중치에 가중치 감쇠를 직접 적용해 이 문제를 고칩니다.

w = w - lr * m_hat / (sqrt(v_hat) + epsilon) - lr * lambda * w

가중치 감쇠 항(lr * lambda * w)은 Adam의 적응형 계수(adaptive factor)로 스케일되지 않습니다. 모든 파라미터가 같은 비율로 줄어듭니다(shrink).

이 차이는 작아 보이지만 실제로는 큽니다. AdamW는 사실상 모든 과제에서 Adam + L2 정규화보다 더 나은 해로 수렴합니다. PyTorch에서 트랜스포머(transformer), 확산 모델(diffusion model), 대부분의 현대 아키텍처(modern architecture)를 학습할 때 기본 옵티마이저로 쓰입니다. BERT, GPT, LLaMA, Stable Diffusion 모두 AdamW로 학습되었습니다.

학습률(Learning Rate): 가장 중요한 하이퍼파라미터

graph TD
    LR["학습률(Learning Rate)"] --> TooHigh["너무 큼"]
    LR --> JustRight["적절함"]
    LR --> TooLow["너무 작음"]

    TooHigh --> Diverge["손실 폭주<br/>가중치 NaN<br/>학습 중단"]
    JustRight --> Converge["손실이 꾸준히 감소<br/>좋은 최솟값<br/>일반화 잘 됨"]
    TooLow --> Stall["손실이 매우 느리게 감소<br/>정체<br/>연산 낭비"]

    JustRight --> Schedule["대개 스케줄링 필요"]
    Schedule --> Warmup["워밍업: 처음 1-10% 단계에서 점진 상승"]
    Schedule --> Decay["감쇠: 코사인 또는 선형"]

하이퍼파라미터를 하나만 튜닝(tune)한다면 학습률을 튜닝합니다. 학습률의 10배 변화는 많은 아키텍처 결정(architecture decision)보다 큰 영향을 줍니다.

  • SGD: lr = 0.01 ~ 0.1
  • Adam/AdamW: lr = 1e-4 ~ 3e-4
  • 사전 학습 모델 파인튜닝(pretrained model fine-tuning): lr = 1e-5 ~ 5e-5
  • 워밍업(warmup): 처음 1-10% 단계 동안 선형으로 점진 상승

옵티마이저 비교(Optimizer Comparison)

flowchart LR
    subgraph "최적화 경로(Optimization Path)"
        SGD_P["SGD<br/>계곡을 가로지르며 진동<br/>느리지만 평탄한 최솟값을 찾음"]
        Mom_P["SGD + 모멘텀<br/>더 부드러운 경로<br/>SGD보다 약 3배 빠름"]
        Adam_P["Adam<br/>파라미터별 적응형<br/>빠른 수렴"]
        AdamW_P["AdamW<br/>Adam + 올바른 감쇠<br/>더 나은 일반화"]
    end
    SGD_P --> Mom_P --> Adam_P --> AdamW_P

언제 어떤 옵티마이저가 유리한가

flowchart TD
    Task["무엇을 학습하나요?"] --> Type{"모델 종류?"}

    Type -->|"트랜스포머 / LLM"| AdamW["AdamW<br/>lr=1e-4, wd=0.01-0.1"]
    Type -->|"CNN / ResNet"| SGD_M["SGD + 모멘텀<br/>lr=0.1, momentum=0.9"]
    Type -->|"GAN"| Adam2["Adam<br/>lr=2e-4, beta1=0.5"]
    Type -->|"파인튜닝"| AdamW2["AdamW<br/>lr=2e-5, wd=0.01"]
    Type -->|"잘 모르겠음"| Default["AdamW로 시작<br/>lr=3e-4, wd=0.01"]

만들어 보기

단계 1: 기본 SGD(Vanilla SGD)

class SGD:
    def __init__(self, lr=0.01):
        self.lr = lr

    def step(self, params, grads):
        for i in range(len(params)):
            params[i] -= self.lr * grads[i]

단계 2: 모멘텀을 포함한 SGD

class SGDMomentum:
    def __init__(self, lr=0.01, beta=0.9):
        self.lr = lr
        self.beta = beta
        self.velocities = None

    def step(self, params, grads):
        if self.velocities is None:
            self.velocities = [0.0] * len(params)
        for i in range(len(params)):
            self.velocities[i] = self.beta * self.velocities[i] + grads[i]
            params[i] -= self.lr * self.velocities[i]

단계 3: Adam

Adam은 m, v, t를 유지하고 편향 보정(bias correction)을 적용합니다.

import math

class Adam:
    def __init__(self, lr=0.001, beta1=0.9, beta2=0.999, epsilon=1e-8):
        self.lr = lr
        self.beta1 = beta1
        self.beta2 = beta2
        self.epsilon = epsilon
        self.m = None
        self.v = None
        self.t = 0

    def step(self, params, grads):
        if self.m is None:
            self.m = [0.0] * len(params)
            self.v = [0.0] * len(params)

        self.t += 1

        for i in range(len(params)):
            self.m[i] = self.beta1 * self.m[i] + (1 - self.beta1) * grads[i]
            self.v[i] = self.beta2 * self.v[i] + (1 - self.beta2) * grads[i] ** 2

            m_hat = self.m[i] / (1 - self.beta1 ** self.t)
            v_hat = self.v[i] / (1 - self.beta2 ** self.t)

            params[i] -= self.lr * m_hat / (math.sqrt(v_hat) + self.epsilon)

단계 4: AdamW

AdamW는 Adam 업데이트와 가중치 감쇠를 분리(decouple)합니다.

class AdamW:
    def __init__(self, lr=0.001, beta1=0.9, beta2=0.999, epsilon=1e-8, weight_decay=0.01):
        self.lr = lr
        self.beta1 = beta1
        self.beta2 = beta2
        self.epsilon = epsilon
        self.weight_decay = weight_decay
        self.m = None
        self.v = None
        self.t = 0

    def step(self, params, grads):
        if self.m is None:
            self.m = [0.0] * len(params)
            self.v = [0.0] * len(params)

        self.t += 1

        for i in range(len(params)):
            self.m[i] = self.beta1 * self.m[i] + (1 - self.beta1) * grads[i]
            self.v[i] = self.beta2 * self.v[i] + (1 - self.beta2) * grads[i] ** 2

            m_hat = self.m[i] / (1 - self.beta1 ** self.t)
            v_hat = self.v[i] / (1 - self.beta2 ** self.t)

            params[i] -= self.lr * m_hat / (math.sqrt(v_hat) + self.epsilon)
            params[i] -= self.lr * self.weight_decay * params[i]

단계 5: 학습 비교

Lesson 05의 원형 데이터셋(circle dataset)에서 같은 2층 신경망(two-layer network)을 네 옵티마이저로 학습합니다. SGD, 모멘텀, Adam, AdamW의 수렴(convergence)과 최종 정확도(final accuracy)를 비교합니다.

import random

def sigmoid(x):
    x = max(-500, min(500, x))
    return 1.0 / (1.0 + math.exp(-x))

def make_circle_data(n=200, seed=42):
    random.seed(seed)
    data = []
    for _ in range(n):
        x = random.uniform(-2, 2)
        y = random.uniform(-2, 2)
        label = 1.0 if x * x + y * y < 1.5 else 0.0
        data.append(([x, y], label))
    return data


class OptimizerTestNetwork:
    def __init__(self, optimizer, hidden_size=8):
        random.seed(0)
        self.hidden_size = hidden_size
        self.optimizer = optimizer

        self.w1 = [[random.gauss(0, 0.5) for _ in range(2)] for _ in range(hidden_size)]
        self.b1 = [0.0] * hidden_size
        self.w2 = [random.gauss(0, 0.5) for _ in range(hidden_size)]
        self.b2 = 0.0

    def get_params(self):
        params = []
        for row in self.w1:
            params.extend(row)
        params.extend(self.b1)
        params.extend(self.w2)
        params.append(self.b2)
        return params

    def set_params(self, params):
        idx = 0
        for i in range(self.hidden_size):
            for j in range(2):
                self.w1[i][j] = params[idx]
                idx += 1
        for i in range(self.hidden_size):
            self.b1[i] = params[idx]
            idx += 1
        for i in range(self.hidden_size):
            self.w2[i] = params[idx]
            idx += 1
        self.b2 = params[idx]

    def forward(self, x):
        self.x = x
        self.z1 = []
        self.h = []
        for i in range(self.hidden_size):
            z = self.w1[i][0] * x[0] + self.w1[i][1] * x[1] + self.b1[i]
            self.z1.append(z)
            self.h.append(max(0.0, z))

        self.z2 = sum(self.w2[i] * self.h[i] for i in range(self.hidden_size)) + self.b2
        self.out = sigmoid(self.z2)
        return self.out

    def compute_grads(self, target):
        eps = 1e-15
        p = max(eps, min(1 - eps, self.out))
        d_loss = -(target / p) + (1 - target) / (1 - p)
        d_sigmoid = self.out * (1 - self.out)
        d_out = d_loss * d_sigmoid

        grads = [0.0] * (self.hidden_size * 2 + self.hidden_size + self.hidden_size + 1)
        idx = 0
        for i in range(self.hidden_size):
            d_relu = 1.0 if self.z1[i] > 0 else 0.0
            d_h = d_out * self.w2[i] * d_relu
            grads[idx] = d_h * self.x[0]
            grads[idx + 1] = d_h * self.x[1]
            idx += 2

        for i in range(self.hidden_size):
            d_relu = 1.0 if self.z1[i] > 0 else 0.0
            grads[idx] = d_out * self.w2[i] * d_relu
            idx += 1

        for i in range(self.hidden_size):
            grads[idx] = d_out * self.h[i]
            idx += 1

        grads[idx] = d_out
        return grads

    def train(self, data, epochs=300):
        losses = []
        for epoch in range(epochs):
            total_loss = 0.0
            correct = 0
            for x, y in data:
                pred = self.forward(x)
                grads = self.compute_grads(y)
                params = self.get_params()
                self.optimizer.step(params, grads)
                self.set_params(params)

                eps = 1e-15
                p = max(eps, min(1 - eps, pred))
                total_loss += -(y * math.log(p) + (1 - y) * math.log(1 - p))
                if (pred >= 0.5) == (y >= 0.5):
                    correct += 1
            avg_loss = total_loss / len(data)
            accuracy = correct / len(data) * 100
            losses.append((avg_loss, accuracy))
            if epoch % 75 == 0 or epoch == epochs - 1:
                print(f"    Epoch {epoch:3d}: 손실={avg_loss:.4f}, 정확도={accuracy:.1f}%")
        return losses

사용하기

PyTorch 옵티마이저는 파라미터 그룹(parameter group), 기울기 클리핑(gradient clipping), 학습률 스케줄링(learning rate scheduling)을 처리합니다.

import torch
import torch.optim as optim

model = torch.nn.Sequential(
    torch.nn.Linear(784, 256),
    torch.nn.ReLU(),
    torch.nn.Linear(256, 10),
)

optimizer = optim.AdamW(model.parameters(), lr=3e-4, weight_decay=0.01)
scheduler = optim.lr_scheduler.CosineAnnealingLR(optimizer, T_max=100)

for epoch in range(100):
    optimizer.zero_grad()
    output = model(torch.randn(32, 784))
    loss = torch.nn.functional.cross_entropy(output, torch.randint(0, 10, (32,)))
    loss.backward()
    torch.nn.utils.clip_grad_norm_(model.parameters(), max_norm=1.0)
    optimizer.step()
    scheduler.step()

패턴은 항상 같습니다.

zero_grad -> forward -> loss -> backward -> clip(optional) -> step -> schedule(optional)

순서를 외워야 합니다. scheduler.step()optimizer.step()보다 먼저 호출하는 식의 순서 오류는 찾기 어려운 버그(subtle bug)를 만듭니다.

CNN에서는 여전히 SGD + 모멘텀을 선호하는 경우가 많습니다. SGD는 더 평탄한 최솟값(flatter minima)을 찾아 일반화가 좋을 수 있습니다. 트랜스포머와 LLM에서는 워밍업과 코사인 감쇠(warmup + cosine decay)를 사용하는 AdamW가 보편적인 기본값입니다.

산출물 만들기

이 강의의 산출물은 다음입니다.

  • outputs/prompt-optimizer-selector.md: 아키텍처에 맞는 옵티마이저와 학습률을 고르는 의사결정 프롬프트(decision prompt)

연습문제

  1. 네스테로프 모멘텀(Nesterov momentum)을 구현합니다. 현재 위치(current position)가 아니라 미리 본 위치(lookahead position) w - lr * beta * v에서 기울기를 계산합니다. 원형 데이터셋에서 표준 모멘텀(standard momentum)과 수렴 속도를 비교합니다.
  2. 처음 10% 학습 단계 동안 0에서 max_lr까지 선형으로 상승하고 이후 코사인 감쇠(cosine decay)하는 학습률 워밍업 스케줄(learning rate warmup schedule)을 구현합니다. 워밍업이 있는 Adam과 워밍업이 없는 Adam을 비교합니다.
  3. Adam 학습 중 파라미터별 유효 학습률(effective learning rate)을 추적합니다. lr * m_hat / (sqrt(v_hat) + eps)로 계산합니다. 10, 50, 200 단계 후 분포(distribution)를 살펴봅니다.
  4. 전체 기울기 노름(global norm) 기준 기울기 클리핑(gradient clipping)을 구현합니다. max_norm=1.0으로 두고 높은 학습률에서 클리핑 유무에 따라 NaN으로 발산하는 실행 횟수를 비교합니다.
  5. 큰 가중치로 초기화한 신경망에서 Adam과 AdamW를 비교합니다. weight_decay=0.1로 200 에포크(epoch) 학습하며 L2 노름이 어떻게 줄어드는지 봅니다.

핵심 용어

용어흔한 설명실제 의미
학습률(Learning rate)"걸음 크기(step size)"기울기 업데이트에 곱하는 스칼라. 학습에서 가장 영향력 큰 하이퍼파라미터
SGD"기본 경사하강법"미니배치 기울기에 lr을 곱해 가중치를 업데이트하는 확률적 경사하강법
모멘텀(Momentum)"공이 굴러 내려가는 비유"과거 기울기들의 지수 이동 평균. 진동을 줄이고 일관된 방향을 가속
RMSProp"적응형 학습률"최근 기울기의 RMS로 각 파라미터 기울기를 나눠 파라미터별 학습률을 조정
Adam"기본 옵티마이저"모멘텀(1차 모먼트)과 RMSProp(2차 모먼트)을 편향 보정과 결합한 옵티마이저
AdamW"제대로 된 Adam"분리된 가중치 감쇠(decoupled weight decay)를 사용하는 Adam. 정규화를 기울기와 분리
편향 보정(Bias correction)"이동 평균의 워밍업"Adam의 모먼트 추정값이 0으로 초기화되어 초반에 작아지는 문제를 보정
가중치 감쇠(Weight decay)"가중치를 줄임"각 단계에서 가중치 값의 일부를 빼 큰 가중치에 페널티를 주는 정규화 기법
학습률 스케줄(Learning rate schedule)"학습률을 시간에 따라 바꿈"워밍업과 코사인 감쇠처럼 학습 중 학습률을 조정하는 함수
기울기 클리핑(Gradient clipping)"기울기 노름 제한"기울기 노름이 임곗값(threshold)을 넘으면 줄여(scale down) 폭주하는 업데이트를 막는 방법

더 읽을거리

실습 코드

이 강의의 실습 코드 1개

main
Code

산출물

이 강의에서 생성된 프롬프트, 스킬, 코드 산출물 1개

prompt-optimizer-selector

A decision prompt for choosing the right optimizer and learning rate for any architecture

Prompt

확인 문제

3문제 · 모두 맞추면 완료 표시가 가능합니다

1.Adam이 초기 학습 단계(early training step)에서 편향 보정(bias correction)을 사용하는 이유는 무엇인가요?

2.Adam의 표준 기본 하이퍼파라미터(standard default hyperparameter)는 무엇인가요?

3.현대 트랜스포머(modern transformer)와 LLM 학습(training)의 기본 옵티마이저(optimizer)는 무엇인가요?

0/3 답변 완료