logo

경사하강법

경사하강법

경사하강법(gradient descent)은 손실을 줄이는 방향으로 모델 파라미터를 반복해서 수정하는 최적화 방법.

  1. 현재 파라미터 로 예측 계산
  2. 정답 와 비교해 손실 계산
  3. 파라미터에 대한 손실의 그래디언트 계산
  4. 그래디언트의 반대 방향으로 파라미터 수정

는 한 번에 이동할 크기를 조절하는 학습률.

경사하강법에서 손실을 줄이는 방향으로 파라미터를 이동하는 과정

학습률

학습률(learning rate)은 그래디언트에 곱해 파라미터의 이동 폭을 결정.

  • 너무 작으면 손실이 천천히 감소
  • 너무 크면 최소점 주변을 지나치거나 손실이 발산할 수 있음
  • 적절한 크기는 모델, 데이터, 배치 크기, 옵티마이저에 따라 달라짐

그래디언트가 0에 가까워도 반드시 최소점은 아님. 최대점, 안장점, 평탄한 구간에서도 그래디언트가 0에 가까울 수 있음.

큰 학습률과 작은 학습률의 경사하강법 이동 차이

계산 예시

다음 데이터에 원점을 지나는 직선 를 적합. 손실은 평균 제곱 오차이고 학습률은 0.1.

13
26
39
412

1단계

에서 예측과 그래디언트를 계산.

31039-6
620636-24
930981-54
124012144-96
평균67.5-45

그래디언트가 -45이므로 를 증가시키면 손실 감소.

2단계

에서 같은 계산 반복.

314.5-1.52.253
629-3912
9313.5-4.520.2527
12418-63648
평균16.8822.5

그래디언트가 22.5이므로 를 감소시키면 손실 감소.

3단계

에서 다시 계산.

312.250.750.56-1.5
624.51.52.25-6
936.752.255.06-13.5
124939-24
평균4.22-11.25

업데이트를 반복하면 는 손실이 가장 작은 값인 3에 가까워짐.

손실 표면의 어려움

신경망의 손실 표면은 여러 차원의 비선형 형태. 국소 최소점, 안장점, 평탄한 구간에서는 학습이 느려질 수 있음. 미니배치에서 생기는 그래디언트의 변동이 이러한 구간을 벗어나는 데 도움을 줄 수 있지만 탈출을 보장하지는 않음.

국소최소점과 전역최소점

안장점의 3차원 손실 표면

그래디언트 계산에 사용하는 데이터

한 번의 파라미터 업데이트에 사용하는 데이터 수에 따라 계산 방식이 달라짐.

  • 배치 경사하강법(batch gradient descent): 전체 훈련 데이터로 그래디언트 계산. 업데이트당 계산량이 크지만 같은 파라미터에서는 일정한 그래디언트 생성
  • 확률적 경사하강법(stochastic gradient descent): 사례 하나로 그래디언트 계산. 업데이트가 빠르지만 방향의 변동이 큼
  • 미니배치 경사하강법(mini-batch gradient descent): 일부 사례로 그래디언트 계산. 병렬 계산 효율과 그래디언트 변동 사이의 균형 제공

딥러닝에서 SGD라고 부르는 훈련은 대개 사례 하나가 아니라 미니배치를 사용.

Keras 모델 훈련

compile()에서 옵티마이저, 손실 함수, 평가 지표를 설정. fit()은 미니배치마다 예측, 손실 계산, 그래디언트 계산, 파라미터 수정을 반복.

실습 준비

import os

os.environ["KERAS_BACKEND"] = "torch"

import keras
import numpy as np

(x_train, y_train), _ = keras.datasets.mnist.load_data()

cond = (y_train == 0) | (y_train == 1)
x_train_binary = x_train[cond]
y_train_binary = np.where(y_train[cond] == 0, 0, 1)

keras.utils.set_random_seed(812)  # 실행 결과 재현용 난수 초기값

model = keras.models.Sequential(
    [
        keras.layers.Rescaling(1 / 255),  # 픽셀값을 0~1 범위로 변환
        keras.layers.Flatten(),  # 28×28 이미지를 길이 784의 벡터로 변환
        keras.layers.Dense(1, activation="sigmoid"),
    ]
)

학습률이 0.0001인 SGD로 이항 교차 엔트로피를 최소화하도록 모델을 설정.

model.compile(
    optimizer=keras.optimizers.SGD(learning_rate=0.0001),
    loss="binary_crossentropy",
    metrics=["accuracy"],
)

훈련 데이터를 32개씩 나누어 5번 반복 학습.

history = model.fit(
    x_train_binary,
    y_train_binary,
    epochs=5,
    batch_size=32,
)
실행 결과
Epoch 1/5
396/396 ━━━━━━━━━━━━━━━━━━━━ 3s 5ms/step - accuracy: 0.2869 - loss: 0.7754
Epoch 2/5
396/396 ━━━━━━━━━━━━━━━━━━━━ 2s 4ms/step - accuracy: 0.5919 - loss: 0.6509
Epoch 3/5
396/396 ━━━━━━━━━━━━━━━━━━━━ 2s 4ms/step - accuracy: 0.8305 - loss: 0.5583
Epoch 4/5
396/396 ━━━━━━━━━━━━━━━━━━━━ 2s 4ms/step - accuracy: 0.9333 - loss: 0.4871
Epoch 5/5
396/396 ━━━━━━━━━━━━━━━━━━━━ 2s 4ms/step - accuracy: 0.9739 - loss: 0.4307
history.history["loss"][-1]  # 마지막 에포크의 훈련 손실
실행 결과
0.4306652247905731
history.history["accuracy"][-1]  # 마지막 에포크의 훈련 정확도
실행 결과
0.9739439487457275

5번째 에포크의 훈련 손실은 약 0.431, 훈련 정확도는 약 97.4%. 두 값은 훈련 데이터에서 계산한 결과이므로 일반화 성능은 별도 데이터로 평가해야 함.

Previous
손실 함수