선형 회귀는 가장 단순하고 유용한 모델 중 하나다. 입력 $x$로부터 목표값 $y$를 다음과 같은  직선으로 예측한다.

$$\hat y = mx+b$$ 여기서 $m$은 직선의 기울기, $b$는 절편이며, 이들이 학습을 통해 결정해야 할 모델의 파라미터(parameter)이다. 예측값과 관측값의 차이인 residual은 다음과 같이 정의한다.

$$r= y - \hat y$$

이제 주어진 residual이 모델의 예측 오차를 얼마나 크게 나타내는지를 정량화할 필요가 있다. 이를 위해 손실함수(loss function)​를 정의한다. 손실함수는 하나의 데이터에 대해 예측이 관측값에서 얼마나 벗어났는지를 수치로 나타낸다. 여러 데이터에 대한 손실을 종합하면 모델 전체의 예측 성능을 나타내는 비용함수(cost function)를 정의할 수 있다. 모델을 학습한다는 것은 결국 이 비용함수의 값을 가능한 한 작게 만드는 파라미터 $m$과 $b$를 찾는 과정이라고 할 수 있다.

 

이를 위해 널리 사용되는 방법이 경사하강법(gradient descent method)​이다. 파라미터 공간에서 비용함수의 gradient를 구하면 비용함수가 가장 빠르게 증가하는 방향을 알 수 있다. 따라서 그 반대 방향으로 파라미터를 조금씩 이동시키면 비용함수를 점차 감소시킬 수 있다. 이 과정을 반복함으로써 더 좋은 예측을 하는 $m$과 $b$를 찾아간다.

 

선형 회귀에서 가장 널리 사용되는 비용함수 중 하나가 평균제곱오차(Mean Squared Error, MSE)​이다. $N$개의 데이터에 대해 residual을

$$r_i=y_i-\hat y_i$$라고 하면 MSE 비용함수는 각각의 residual을 제곱한 평균인

$$J=\frac{1}{N}\sum_{i}r_i^2$$로 정의된다. Residual을 단순히 더하지 않고 제곱하는 데에는 두 가지 중요한 이유가 있다. 우선 양의 residual과 음의 residual이 서로 상쇄되는 것을 막을 수 있다. 또한 residual의 크기가 커질수록 훨씬 큰 손실을 부여하므로, 크게 잘못된 예측을 적극적으로 교정하도록 모델을 학습시킬 수 있다.

 

MSE는 미분 가능한 매끄러운 함수이기 때문에 gradient descent를 적용하기에도 매우 편리하다. 제곱 손실을 residual에 대한 미분은$$\frac{d}{dr}r^2=2r$$이다. 따라서 residual의 크기가 클수록 해당 데이터가 gradient에 미치는 영향도 커진다.

 

선형 회귀 $\hat{y}_i = mx_i + b$에 대해서는 $r_i=y_i-(mx_i+b)$이므로 비용함수는

$$J(m,b)=\frac{1}{N}\sum_{i}\left[y_i-(mx_i+b)\right]^2$$이므로 $m$과 $b$에 대한 gradient는 

$$\nabla J = \left(-\frac{2}{N} \sum_i x_i r_i,    -\frac{2}{N}\sum_{i}r_i \right)$$가 된다. Gradient descent에서는 이 gradient의 반대 방향으로

 $$m \leftarrow m-\eta\frac{\partial J}{\partial m},\qquad    b\leftarrow b-\eta\frac{\partial J}{\partial b}$$와 같이 파라미터를 조금씩 변화시킨다. 여기서 $\eta$는 한 번에 얼마나 이동할지를 결정하는 learning rate이다.

 

MSE가 큰 오차를 강하게 교정한다는 성질은 일반적으로는 장점이지만, 데이터에 이상치(outlier)​가 존재하면 문제가 될 수 있다. 예를 들어 대부분의 데이터에서 residual의 크기가 $1$ 정도인데 하나의 이상치에서 residual이 $10$이라고 하자. MSE에서 각각의 손실은 $1^2=1$, $10^2=100$이 된다. 따라서 단 하나의 이상치가 정상적인 데이터 하나보다 $100$배나 큰 손실을 만들어낸다. 

 

Gradient의 관점에서 보면 문제가 더욱 분명해진다. 제곱 손실의 gradient는 $L'(r)=2r$이므로 residual이 커질수록 gradient의 크기도 제한 없이 증가한다. 결국 소수의 매우 큰 residual이 전체 gradient를 지배할 수 있다. 그 결과 gradient descent는 대부분의 데이터를 잘 설명하는 방향보다 몇 개의 이상치의 오차를 줄이는 방향으로 파라미터가 지나치게 움직일 수 있다. 즉, MSE를 이용한 line fitting에서는 이상치 때문에 회귀 직선 자체가 이상치 쪽으로 끌려갈 수 있다.

 

이 문제를 줄이는 가장 단순한 방법은 residual을 제곱하지 않고 절댓값을 사용하는 것이다.

$$L(r)=|r|$$이를 절대오차(absolute error)라고 한다. Residual이 $1$이면 손실은 $1$, residual이 $10$이면 손실은 $10$이다. MSE처럼 $1$과 $100$으로 차이가 증폭되지 않는다. 더 중요한 차이는 gradient에 있다. $r \neq 0$에서 $L' (r) = \text{sign}(r)$이므로 residual이 아무리 커져도 gradient의 크기는 $1$을 넘지 않는다. 따라서 하나의 outlier가 전체 gradient를 압도하는 현상을 크게 줄일 수 있다.

 

하지만 절대오차에도 문제가 있다. $|r|$은 $r=0$에서 뾰족한 모양을 가지므로 그 지점에서 미분 가능하지 않다. 또한 $r$이 매우 작아져도 gradient의 크기가 계속 $1$로 유지되기 때문에 최소점 근처에서 MSE처럼 부드럽게 감소하지 않는다.

 

따라서 다음 두 성질을 동시에 가지는 손실함수를 고려하는 것이 바람직하다.

  • residual이 작을 때는 MSE처럼 제곱함수를 사용하여 최소점 근처에서 부드럽게 학습한다.
  • residual이 클 때는 절댓값 함수처럼 선형적으로 증가시켜 이상치가 gradient를 지나치게 지배하지 못하게 한다.

이 두 가지 성질을 결합한 것이 Huber loss이다. Huber loss는 residual의 크기가 어떤 기준값 $\delta$보다 작을 때는 제곱함수를 사용하고, 그보다 클 때는 절댓값에 비례하는 선형함수 전환한다.

$$ L_\delta(r) = \begin{cases} \frac{1}{2} r^2  & |r| \le \delta \\ \delta \left( |r|-   \frac{1}{2}\delta \right) & |r| > \delta \end{cases} $$여기서 $\delta$는 제곱 영역과 선형 영역을 나누는 기준값이다. 앞에서 사용한 제곱 손실 $r^2$과 비교하면 작은 residual 영역에서 $1/2$이라는 상수배의 차이가 있지만, 이는 gradient의 전체 크기만 바꿀 뿐 제곱 손실의 본질적인 성질에는 영향을 주지 않는다.

 

Huber loss를 residual에 대해 미분하면

$$\frac{dL_\delta}{dr} = \begin{cases}  -\delta,&r<-\delta,\\  r,&|r|\le\delta,\\  \delta,&r>\delta  \end{cases}$$가 된다. 작은 residual 영역에서는 미분값이 $r$에 비례하므로 예측값이 실제값에 가까워질수록 자연스럽게 0으로 감소한다. 반면 $|r|>\delta$가 되면 미분값의 크기는 $\delta$로 제한된다. 따라서 residual이 아무리 커지더라도 하나의 outlier가 gradient에 미치는 영향은 일정 수준 이상으로 증가하지 않는다.

이러한 특성은 Huber loss의 주요 장점 중 하나이다. MSE에서는 residual이 커질수록 gradient도 함께 증가하므로, 소수의 큰 outlier가 전체 gradient descent의 방향에 과도한 영향을 줄 수 있다. 반면 Huber loss에서는 residual이 일정 수준을 넘으면 gradient의 크기가 제한되므로, 큰 이상치가 최적화 과정을 지나치게 좌우하는 현상을 완화할 수 있다.

Huber loss는 작은 residual 영역에서는 MSE처럼 동작하고, 큰 residual 영역에서는 absolute error와 유사하게 동작하는 비용함수이다. 따라서 작은 오차에 대해서는 MSE의 부드러운 최적화 특성을 활용하면서, 큰 오차에 대해서는 영향력을 제한하여 이상치에 대한 민감도를 낮출 수 있다. 이러한 점에서 Huber loss는 MSE와 absolute error의 장점을 적절히 결합한 비용함수라고 볼 수 있다.

 

// line fitting code with Huber loss;

std::vector<double> train_huber(const std::vector<double>& xdata, 
                                const std::vector<double>& ydata,
                                double delta, double learn_rate, int iters) {
    double m = 0.0; // initialize slope
    double b = 0.0; // initialize intercept
    const double tol = 1e-8;
    while (iters--) {
        double grad_m = 0.0, grad_b = 0.0;
        for (int i = xdata.size(); i-->0; ) {
            double prediction = m * xdata[i] + b;
            double residual = ydata[i] - prediction;

            // if residual is within the L2 threshold
            double dL_dr;
            if (fabs(residual) <= delta) dL_dr = residual;
            else                         dL_dr = (residual > 0) ? delta : -delta;
            // chain rule: dr/dm = -x, dr/db = -1
            // dL/dm = (dL/dr) * (dr/dm) = -dL_dr * x
            grad_m += -dL_dr * xdata[i];
            grad_b += -dL_dr;
        }
        // average_gradient;
        grad_m /= xdata.size();
        grad_b /= xdata.size();
        // gradient descent update 
        m -= learn_rate * grad_m;
        b -= learn_rate * grad_b;
        if (sqrt(grad_m * grad_m + grad_b * grad_b) < tol) break;
    }
    std::vector<double> line(2);
    line[0] = m; line[1] = b;
    return line;
}

'Image Recognition > Fundamental' 카테고리의 다른 글

FFT를 이용한 inverse FFT  (0) 2024.07.31
FFT 구현  (0) 2024.07.31
CLAHE (2)  (1) 2024.06.26
Approximate Distance Transform  (0) 2024.06.02
Graph-based Segmentation  (1) 2024.05.26
,