딥러닝/딥러닝: 기초 개념

손실 함수의 미분

qordnswnd123 2025. 1. 14. 14:49

1. 손실 함수의 미분

1) 손실 함수의 미분

손실 함수의 미분이란, 모델이 어떻게 하면 더 잘 학습할 수 있을지 알려주는 지도와 같습니다.

모델을 훈련시키기 위해서는 모델의 예측이 실제와 얼마나 차이는지를 나타내는 손실을 줄여야 합니다.

이때 손실 함수의 미분은 손실을 어느 방향으로, 얼마만큼 조정해야 하는지를 알려주는 나침반과 같은 역할을 합니다.

2) 언제, 왜 사용하는가?

손실 함수의 미분은 모델을 훈련시킬 때, 즉 모델의 성능을 개선하기 위해 사용됩니다.

모델이 예측하는 값과 실제 값 사이의 차이를 줄이기 위해서는, 모델의 '가중치'와 '편향' 같은 매개변수를 적절히 조정해야 합니다.

이런 조정 과정에서 손실 함수의 미분은 어떤 방향으로 얼마만큼 조정해야 하는지를 알려줍니다.

3) 손실 함수의 미분의 특징

※ 방향성 제공
손실 함수의 미분은 모델 파라미터를 조정해야 하는 방향을 알려줍니다.

만약 손실 함수가 기울기가 음수라면, 현재 매개변수에 대해 손실이 감소하는 방향이므로, 모델을 이 방향으로 조정해야 합니다.

손실 함수가 기울기가 커지기를 원한다면, 이 반대 방향으로 조정해야 합니다.

반대로, 손실 함수의 기울기가 양수라면, 현재 매개변수가 손실을 증가시키는 방향에 있다는 것을 나타냅니다.

이 경우에는 매개변수를 기울기가 커지는 반대 방향, 즉 음의 방향으로 조정함 으로써 손실을 줄일 수 있습니다.

매개변수 업데이트 시 기울기 부호에 반대로 방향을 조정하는 것이 중요합니다.

왜냐하면 우리는 손실을 증가시키기 위한 것이 아니라 줄이려고 하기 때문입니다.

 

※ 크기 조정

손실 함수의 미분값(기울기)의 크기는 매개변수를 조정할 때 얼마나 큰 단계를 밟아야 하는지를 알려줍니다.

큰 기울기의 절댓값은 매개변수가 손실 함수의 최소값에서 멀리 떨어져 있음을 나타내며, 따라서 더 큰 조정이 필요하다는 신호로 해석될 수 있습니다.

이는 손실 함수의 현재 포인트가 정사가 급한 지점에 위치해 있음을 의미하며, 이 경우 모델은 상대적으로 큰 변화를 통해 빠르게 손실을 감소시킬 가능성이 있습니다.

반면에 작은 기울기 값은 매개변수가 최적점에 가깝거나, 평평한 지역(지역 최소값이나 안장점)에 있음을 나타냅니다.

이 경우에는 작은 조정이 필요하며, 이는 모델이 점진적 및 미묘한 개선을 통해 최적화를 향해 나아가야 함을 의미합니다.

만약 매우 작은 기울기로 인해 매개변수 업데이트가 미비하다면, 이는 학습 속도가 매우 느려지거나 전혀 진전되지 않을 수 있습니다.

이와 같이 미분값의 크기는 학습률(learning rate)과 함께 매개변수 업데이트의 실제 크기를 결정하는 데 중요한 역할을 합니다.

※ 최적화 지표

손실 함수의 미분값이 0에 가까워지는 지점을 찾는 것이 최적화 과정의 핵심 목표 중 하나입니다.

이 지점을 극값이라고 합니다. 손실 함수의 기울기가 0에 도달했을 때, 모델 파라미터의 조정은 멈추게 됩니다.

이는 더 이상의 조정으로 손실을 감소시킬 수 없음을 나타냅니다.

실제로 기계 학습에서는 완벽한 '0' 기울기에 도달하는 것보다는 충분히 작은 기울기 값에 도달하여 더 이상의 손실 감소가 중요하지 않은 지점을 찾는 것을 목표로 합니다.

 

4) 수식

손실 함수 (L)을 모델 매개변수 (w)로 미분한 값은 이렇게 표현됩니다. [∂L/∂w]
이는 매개변수 (w)를 조금 변화시켰을 때, 손실 (L)이 어떻게 변하는지를 보여줍니다.

 

5) 주의사항

미분값을 통해 파라미터를 업데이트할 때는 너무 크게 조정하지 않도록 주의해야 합니다.

손실 함수의 미분값은 모델 학습 과정에서 매우 중요한 역할을 합니다.

이 값은 모델 파라미터의 조정이 필요한 방향을 가리키며, 이를 통해 모델의 성능을 점차 개선해 나갈 수 있습니다.

모델을 학습시키는 과정에서 손실 함수의 미분값은 경사 하강법(Gradient Descent)과 같은 최적화 알고리즘에 의해 사용되어, 손실을 최소화하는 파라미터로 모델을 조정하는 데 도움을 줍니다.


2. 문제 1

※ F.mse_loss 함수

F.mse_loss 함수는 Mean Squared Error 손실을 계산하는 PyTorch 함수입니다.

MSE 손실 함수는 예측값과 실제값 사이의 차이의 제곱의 평균을 계산합니다.

  • mse_loss1 = F.mse_loss(prediction1, actual_value)는 첫 번째 예측값(prediction1)과 실제값(actual_value)에 대한 MSE 손실을 계산합니다.
  • mse_loss2 = F.mse_loss(prediction2, actual_value)는 두 번째 예측값(prediction2)과 실제값에 대한 MSE 손실을 계산합니다.

※ 미분 계산
.backward() 메소드는 계산된 손실 함수에 대한 역전파를 수행합니다.

이 과정에서 파라미터(여기서는 예측값 prediction1과 prediction2)에 대한 손실 함수의 그래디언트가 자동으로 계산됩니다.

  • mse_loss1.backward()는 prediction1에 대한 mse_loss1의 미분값을 계산하고, 이 값을 prediction1.grad에 저장합니다.
  • 마찬가지로, mse_loss2.backward()는 prediction2에 대한 mse_loss2의 미분값을 계산하고, prediction2.grad에 저장합니다.

※ 그래디언트(미분값) 출력
그래디언트는 최적화 과정에서 파라미터를 얼마나 조정해야 하는지를 나타내는 중요한 지표입니다.

  • gradient_pred_1 = prediction1.grad.item()는 첫 번째 예측값의 그래디언트를 가져옵니다.
  • gradient_pred_2 = prediction2.grad.item()는 두 번째 예측값의 그래디언트를 가져옵니다.

그래디언트 값이 크면 파라미터를 크게 조정해야 함을 의미하며, 값이 작으면 더 작은 조정이 필요함을 의미합니다.

 

import torch
import torch.nn.functional as F

# 모델의 예측값 파라미터 정의
prediction1 = torch.tensor([3.0], requires_grad=True)
prediction2 = torch.tensor([10.0], requires_grad=True)

# 실제 값 레이블 정의
actual_value = torch.tensor([2.0])

# 첫 번째 예측값에 대한 MSE 손실 계산
mse_loss1 = F.mse_loss(prediction1, actual_value)

# 두 번째 예측값에 대한 MSE 손실 계산
mse_loss2 = F.mse_loss(prediction2, actual_value)

# 첫 번째 손실에 대한 미분 계산
mse_loss1.backward()

# 두 번째 손실에 대한 미분 계산
mse_loss2.backward()

# 미분값(그래디언트) 출력
gradient_pred_1 = prediction1.grad.item()
gradient_pred_2 = prediction2.grad.item()

print(f'첫 번째 예측값의 MSE 손실 함수 미분값: {gradient_pred_1}')
print(f'두 번째 예측값의 MSE 손실 함수 미분값: {gradient_pred_2}')
첫 번째 예측값의 MSE 손실 함수 미분값: 2.0
두 번째 예측값의 MSE 손실 함수 미분값: 16.0

 

※결과 해석

MSE 손실 함수의 미분값, 즉 그래디언트는 모델 파라미터를 업데이트하는 데 사용되는 방향과 크기를 나타냅니다.

여기서 중요한 것은 미분값(그래디언트)의 절댓값이 '응용을 직접적으로 의미하지는 않는다'는 점입니다.

그래디언트의 값은 최적의 파라미터를 수렴하기 위한 방향성과 속도로 제공됩니다.

  • 미분값이 0.02일 경우: 이는 파라미터가 실제 레이블과 비교하여 비교적 작은 오차를 가지고 있으며, 손실 함수를 최소화하기 위해 파라미터를 업데이트할 때 상대적으로 작은 조정이 필요함을 나타냅니다. 즉, 모델이 이미 비교적 좋은 예측을 하고 있으니, 작은 조정으로 충분할 수 있습니다.
  • 미분값이 16.0인 경우: 이는 파라미터가 실제 레이블과 상당히 큰 오차를 가지고 있으며, 손실 함수를 최소화하기 위해 파라미터를 업데이트할 때 큰 조정이 필요함을 나타냅니다. 즉, 현재 모델의 상태가 최적화와 멀리 떨어져 있으며 더 많은 조정이 필요하다는 신호로 해석할 수 있습니다.

그러나 큰 그래디언트 값이 항상 좋은 것은 아닙니다.

너무 큰 그래디언트 값은 학습 과정에서 "그래디언트 폭주(Gradient Exploding)"의 문제를 초래할 수 있으며, 이는 최적화 과정을 불안정하게 만들 수 있습니다.

반대로, 너무 작은 그래디언트 값은 "그래디언트 소실(Gradient Vanishing)" 문제를 일으킬 수 있으며, 이는 학습이 실제로 진행되지 않을 수 있음을 의미합니다.

결론적으로, 더 작든 또는 더 큰 그래디언트 값 자체는 '더 좋은 것'으로 간주하기 보다는, 모델의 학습 과정에서 이러한 그래디언트 값들이 어떻게 변화하는지, 그리고 최종적으로 모델이 좋은 성능을 달성하는지를 주목하는 것이 중요합니다.

모델의 성능은 손실 함수의 값을 최소화하고, 검증 데이터셋에 대한 예측 정확도를 최대화하는 방향으로 개선되어야 합니다.


3. 문제 2

※ torch.nn.BCELoss

torch.nn.BCELoss는 Binary Cross-Entropy 손실을 계산하기 위한 PyTorch의 손실 함수 클래스입니다.

이 클래스는 이진 분류 문제에서 모델의 예측 확률과 실제 레이블 간의 차이를 측정하는 데 사용됩니다.

BCELoss 클래스를 사용할 때 주의할 점은 입력값으로 모델의 예측 확률을 전달해야 한다는 것입니다.

이 때문에 예측값에 시그모이드 활성화 함수를 적용하여 0과 1 사이의 값을 확률로 변환해야 합니다.

 

코드의 주요 부분 설명:

  • prob1과 prob2: 각각 첫 번째와 두 번째 예측값에 시그모이드 함수를 적용하여 얻은 예측 확률입니다.
  • bce_loss: BCELoss 클래스의 인스턴스를 생성합니다. 이 객체를 사용하여 예측 확률과 실제 레이블 사이의 BCE 손실을 계산할 수 있습니다.
  • bce_loss1과 bce_loss2: 각각 첫 번째와 두 번째 예측 확률에 대한 BCE 손실을 계산합니다.
  • .backward(): 메소드는 각 손실 값에 대한 역전파를 수행하여, 예측값에 대한 손실 함수의 미분값(그래디언트)을 계산합니다. 이 그래디언트는 모델을 학습시킬 때 파라미터를 업데이트하는 데 사용됩니다.
  • gradient_pred1과 gradient_pred2: 각 예측값에 대한 그래디언트 값을 출력합니다. 이 값들은 예측값이 실제 레이블로부터 얼마나 벗어나 있는지, 그리고 얼마나 조정해야 하는지를 나타내는 정보를 제공합니다.
import torch
import torch.nn as nn

# 첫 번째 예측값, 두 번째 예측값, 실제값 정의
prediction1 = torch.tensor([1.0], requires_grad=True)
prediction2 = torch.tensor([3.0], requires_grad=True)

actual_label = torch.tensor([0.0])

# 시그모이드 활성화 함수 적용
prob1 = torch.sigmoid(prediction1)
prob2 = torch.sigmoid(prediction2)

# BCELoss 객체 생성
bce_loss = nn.BCELoss()

# 첫 번째, 두 번째 파라미터에 대한 BCE 손실 계산
bce_loss1 = bce_loss(prob1, actual_label)
bce_loss2 = bce_loss(prob2, actual_label)

# 첫 번째, 두 번째 손실에 대한 미분 계산
bce_loss1.backward()
bce_loss2.backward()

# 미분값(그래디언트) 출력
gradient_pred1 = prediction1.grad.item()
gradient_pred2 = prediction2.grad.item()

print(f'첫 번째 예측값의 BCE 손실 함수 미분값: {gradient_pred1}')
print(f'두 번째 예측값의 BCE 손실 함수 미분값: {gradient_pred2}')
첫 번째 예측값의 BCE 손실 함수 미분값: 0.7310585975646973
두 번째 예측값의 BCE 손실 함수 미분값: 0.9525740742683411

 

※ 결과 해석

결과에서 첫 번째 예측값의 Binary Cross-Entropy (BCE) 손실 함수에 대한 미분값은 약 0.7311이고, 두 번째 예측값의 미분값은 약 0.9526입니다. 이러한 미분값(그래디언트)은 예측값을 조정하기 위한 방향과 크기를 나타냅니다.

 

첫 번째 예측값의 미분값 해석 (약 0.7311):

첫 번째 예측값은 1.0이었고, 이에 대한 시그모이드 활성화 함수 적용 결과는 약 0.7311입니다. 실제 레이블이 0.0이므로, 예측 확률과 실제 레이블 사이에는 상당한 차이가 있습니다. 이로 인한 손실의 그래디언트가 약 0.7311로 계산되며, 이는 파라미터(예측값)를 감소시켜야 함을 나타냅니다. 그러나 그래디언트 값이 1에 가깝지 않아서(즉, 너무 크지 않아서) 파라미터 조정의 폭이 상대적으로 작을 것입니다.

 

두 번째 예측값의 미분값 해석 (약 0.9526):

두 번째 예측값은 3.0이었고, 이에 대한 시그모이드 활성화 함수 적용 결과는 0.9526에 가까운 매우 높은 확률입니다. 실제 레이블이 0.0 상황에서 이러한 높은 예측 확률은 큰 오류를 의미합니다. 따라서, 이 경우의 손실 함수 그래디언트는 약 0.9526로 계산되었으며, 이는 예측값을 크게 감소시켜야 함을 나타냅니다. 그래디언트 값이 1에 매우 가까우므로, 파라미터 조정의 폭이 상대적으로 클 것입니다.

 

종합적인 해석:

두 그래디언트 값 모두 예측값을 실제 레이블 방향으로 조정해야 함을 나타냅니다. 하지만 두 번째 예측값의 그래디언트가 더 크기 때문에, 이 예측값이 더 큰 조정을 필요로 합니다. 이는 두 번째 예측값의 실제 레이블과의 오차가 더 크기 때문입니다. 이러한 그래디언트 정보는 경사 하강법 같은 최적화 알고리즘을 통해 모델의 예측 성능을 개선하는 데 사용될 수 있습니다.


4. 문제3

※ logits = torch.tensor([0.1, 0.2, 0.7], requires_grad=True)

모델의 예측값(로짓)을 나타내는 텐서를 정의합니다. 여기서는 3개의 클래스에 대한 예측값이며 각 값은 모델이 해당 클래스에 속한다고 예측하는 확신의 정도를 나타냅니다. requires_grad=True는 이 텐서에 대한 연산을 추적하여 그래디언트를 계산할 수 있게 합니다.

※ target = torch.tensor([0])

실제 레이블을 나타내는 텐서를 정의합니다. 이 예제에서는 첫 번째 클래스(인덱스 0)가 정답이라고 가정합니다.

※ cross_entropy_loss = nn.CrossEntropyLoss()

손실을 계산하기 위한 CrossEntropyLoss 객체를 생성합니다. 이 객체는 로짓과 실제 레이블을 입력으로 받아 CCE 손실을 계산합니다.

※ loss = cross_entropy_loss(logits.unsqueeze(0), target)

계산된 로짓에 unsqueeze(0)을 사용하여 배치 차원을 추가합니다. nn.CrossEntropyLoss는 일반적으로 배치 처리를 기대하기 때문입니다. 그런 다음 로짓과 실제 레이블을 cross_entropy_loss 객체에 전달하여 CCE 손실을 계산합니다.

※ loss.backward()

손실에 대한 역전파를 수행하여 로짓의 그래디언트를 계산합니다. 이 과정은 모델의 예측이 실제 레이블과 어떻게 다른지를 기반으로 하여, 모델의 파라미터를 어떻게 조정해야 하는지에 대한 정보를 제공합니다.

※ gradient_logits = logits.grad

역전파 후 계산된 그래디언트를 logits.grad를 통해 접근하고, 이를 gradient_logits 변수에 할당합니다.

※ print(f'로짓 세트의 CCE 손실 함수 미분값: {gradient_logits}')

최종적으로, 계산된 그래디언트(미분값)를 출력합니다. 이 그래디언트는 로짓에 대해 조정해야 할 손실 함수의 방향을 나타내며, 각 클래스의 예측 확률을 실제 레이블에 더 가깝게 만들기 위해 모델 파라미터를 어떻게 조정해야 하는지를 알려줍니다.

import torch
import torch.nn as nn

# 두 개의 로짓 세트 정의 (각 세트는 3개 클래스에 대한 예측값 포함)
logits = torch.tensor([0.1, 0.2, 0.7], requires_grad=True)

# 실제 레이블 (여기서는 0번 클래스가 정답)
target = torch.tensor([0])

# CrossEntropyLoss 객체 생성
cross_entropy_loss = nn.CrossEntropyLoss()

# 첫 번째 및 두 번째 로짓 세트에 대한 CCE 손실 계산
loss = cross_entropy_loss(logits.unsqueeze(0), target)  # unsqueeze(0)은 배치 차원을 추가

# 첫 번째 및 두 번째 손실에 대한 미분 계산
loss.backward()

# 미분값(그래디언트) 출력
gradient_logits = logits.grad

print(f'로짓 세트의 CCE 손실 함수 미분값: {gradient_logits}')
로짓 세트의 CCE 손실 함수 미분값: tensor([-0.7454,  0.2814,  0.4640])

 

※ 결과 해석

결과에서 로짓 세트의 Categorical Cross-Entropy (CCE) 손실 함수에 대한 미분값, 즉 그래디언트는 각 클래스에 대해 다음과 같습니다:
[−0.7454,0.2814,0.4640] 이 그래디언트 값은 로짓 세트(모델의 클래스별 예측 점수)에 대한 손실 함수의 변화를 나타냅니다. 각 값은 해당 클래스에 대한 예측 확률을 증가시키거나 감소시키기 위해 로짓 값을 어떻게 조정해야 하는지를 알려줍니다.

첫 번째 클래스 (그래디언트: -0.7454):
이 값이 음수라는 것은 첫 번째 클래스의 로짓 값을 증가시켜야 한다는 것을 의미합니다. 실제 레이블이 첫 번째 클래스이므로, 모델의 예측 확률이 더 높아야 함을 나타냅니다.
그래디언트의 절댓값이 상대적으로 크기 때문에, 이 클래스에 대한 예측 확률을 증가시키는 방향으로 로짓을 상당히 조정해야 합니다.

두 번째 클래스 (그래디언트: 0.2814):
이 값이 양수라는 것은 두 번째 클래스의 로짓 값을 감소시켜야 한다는 것을 의미합니다. 모델이 이 클래스에 대해 과대 예측하고 있으며, 이 클래스의 예측 확률을 낮추어야 함을 나타냅니다.

세 번째 클래스 (그래디언트: 0.4640):
마찬가지로, 이 값이 양수라는 것은 세 번째 클래스의 로짓 값을 감소시켜야 한다는 것을 의미합니다. 이 경우도 모델이 이 클래스에 대해 과대 예측하고 있음을 나타내며, 예측 확률을 낮추기 위한 조정이 필요합니다.

 

이 그래디언트 값은 모델 학습 과정에서 경사 하강법 같은 최적화 알고리즘을 사용하여 각 클래스별 로짓 데이터를 업데이트하는 데 사용됩니다. 각 반복마다 이러한 그래디언트 정보를 바탕으로 파라미터를 조정함으로써, 모델은 점차 실제 레이블에 대해 예측 확률을 개선해 나갈 수 있습니다.