Code › codeit-ai-sprint

선형회귀와 손실 함수

집값 예측 예제로 정리한 선형회귀, 평균 제곱 오차, 손실 함수의 의미

오늘은 선형회귀(linear regression)와 손실 함수(loss function)를 배웠다. 집 크기로 집 가격을 예측하는 예제가 나왔는데, 강의를 따라가다 보니 핵심은 어떤 선이 더 나은지를 숫자로 평가하는게 중요해 보였다.

예를 들어 집 크기가 30평일 때 가격이 얼마일지 예측한다고 해보자. 이미 여러 집의 크기와 가격 데이터가 있다면, 그 점들 사이를 가장 그럴듯하게 지나가는 직선을 하나 찾을 수 있다. 이 선을 최적선(the line of best fit)이라고 부르고, 선형회귀는 결국 이 최적선을 찾아서 새로운 입력에 대한 값을 예측하는 방식으로 이해했다.

여기서 집 크기는 입력변수(input variable 또는 feature)이고, 집 가격은 목표변수(target variable 또는 output variable)다. 맞추려는 값이 집 가격이므로 목표변수는 가격이고, 집 크기는 가격을 맞추기 위해 사용하는 정보이므로 입력변수다.


머신러닝은 크게 지도학습, 비지도학습, 강화학습으로 나뉜다고 한다. 선형회귀는 지도학습(supervised learning)에 들어가는데, 이유는 학습 데이터에 입력과 정답이 함께 있기 때문이다. 집 크기만 던져주고 알아서 구조를 찾게 하는 게 아니라, “이 크기의 집은 이 가격이었다”라는 답을 같이 주면서 모델을 학습시킨다.

이 지점에서 분류(classification)와 회귀(regression)도 같이 나왔다. 분류는 아파트, 주택, 오피스텔처럼 정해진 범주 중 하나를 고르는 문제이고, 회귀는 집 가격처럼 연속적인 값을 예측하는 문제라고 한다.

지금은 결과가 “종류”이면 분류, 결과가 연속적으로 변하는 “숫자 값”이면 회귀로 구분한다고 했고, 숫자로 표현된 값이라고 해서 전부 회귀는 아니고, 그 값이 연속적으로 움직이는 예측 대상인지가 기준이다. 집 가격은 5억, 5억 1천만, 5억 2천만처럼 이어지는 값이므로 회귀 문제다.


선형회귀에서 사용하는 선은 가설 함수(hypothesis function)로 표현한다. 직선이므로 익숙한 형태로는 이렇게 쓸 수 있다.

y=ax+by = ax + b

여기서 중요한 건 아직 기호 자체가 아니라, 여러 직선 중 어떤 직선이 데이터에 더 잘 맞는지 판단해야 한다는 점이다. 같은 집 크기 데이터가 있어도 선을 어떻게 긋느냐에 따라 예측 가격이 달라지고, 그래서 각 선의 예측이 실제 가격과 얼마나 차이 나는지를 계산해야 한다.

이때 나온 개념이 평균 제곱 오차(MSE, Mean Squared Error)였다. 모델이 예측한 값과 실제 값이 완전히 같으면 오차는 0이지만, 대부분은 조금씩 빗나가고 각 데이터마다 예측값과 실제값의 차이가 생긴다. 평균 제곱 오차는 이 차이를 제곱한 뒤 평균을 낸 값이다.

MSE=1mi=1m(h(x(i))y(i))2\text{MSE} = \frac{1}{m}\sum_{i=1}^{m}\left(h(x^{(i)}) - y^{(i)}\right)^2

여기서 mm은 학습 데이터의 개수이고, x(i)x^{(i)}ii번째 입력값, y(i)y^{(i)}ii번째 실제 정답이다. h(x(i))h(x^{(i)})는 현재 가설 함수가 ii번째 입력에 대해 예측한 값이다.

오차를 제곱하는 이유도 이제 조금 이해됐다. 예측값이 실제값보다 크든 작든 제곱하면 양수가 되기 때문에 오차들이 서로 상쇄되지 않고, 큰 오차에는 더 큰 패널티가 들어간다. 예를 들어 오차가 2이면 제곱해서 4가 되지만, 오차가 10이면 100이 되기 때문에 많이 틀린 예측을 더 강하게 나쁘게 보는 방식이다.

평균 제곱 오차는 “이 선이 전체 데이터에 대해 얼마나 많이 틀렸는지”를 숫자로 나타낸 값이다. 값이 작을수록 실제 데이터에 더 잘 맞는 선이고, 값이 클수록 예측이 많이 빗나간 선이다.


평균 제곱 오차로 선을 평가하는 흐름을 보고 나서, 강의에서는 직선의 모양을 정하는 값을 θ로 표현했다. 익숙한 y=ax+by = ax + b에서 aabb를 직접 쓰는 대신, 머신러닝 표기에서는 보통 이렇게 쓴다고 한다.

hθ(x)=θ0+θ1xh_\theta(x) = \theta_0 + \theta_1 x

여기서 hθ(x)h_\theta(x)는 입력 xx를 넣었을 때 모델이 예측한 값을 뜻한다. 집값 예측으로 보면 xx는 집 크기이고, hθ(x)h_\theta(x)는 모델이 예측한 집 가격이다.

θ1\theta_1은 직선의 기울기이고, 집 크기가 1만큼 커질 때 예측 가격이 얼마나 증가하는지를 결정한다. 반면 θ0\theta_0은 상수항으로, xx가 0일 때도 남아 있는 값이고 그래프에서는 직선이 세로축과 만나는 위치를 정한다. 그래서 θ0\theta_0은 입력값에 곱해지는 값이라기보다, 전체 예측값을 위아래로 옮기는 역할을 한다고 이해했다.

결국 선형회귀에서 찾으려는 것은 가장 적절한 θ 값들이다. θ0\theta_0θ1\theta_1을 어떻게 정하느냐에 따라 선의 위치와 기울기가 달라지고, 같은 집 크기를 넣어도 예측 가격이 달라진다.


손실 함수(loss function)는 가설 함수의 예측이 실제 값에서 얼마나 벗어났는지 계산하는 함수다. 선형회귀에서는 평균 제곱 오차가 손실 함수의 값으로 쓰인다.

강의에서는 손실 함수를 J로 표현했다.

J(θ)=12mi=1m(hθ(x(i))y(i))2J(\theta) = \frac{1}{2m}\sum_{i=1}^{m}\left(h_\theta(x^{(i)}) - y^{(i)}\right)^2

손실 함수를 보면 평균 제곱 오차와 거의 같은데 분모에 2가 곱해져 있는 부분만 달랐다. 지금은 평균 제곱 오차를 “오차를 계산하는 방식”으로 보고, 손실 함수는 “현재 θ\theta를 넣었을 때 그 오차 값을 반환하는 함수”이다.

또 하나 헷갈렸던 건 왜 손실 함수의 입력이 xxyy가 아니라 θ\theta인지였다. 식 안에는 xxyy도 분명히 들어가는데, 왜 J(x,y)J(x, y)가 아니라 J(θ)J(\theta)라고 쓰는 걸까.

이 부분은 데이터를 고정된 값으로 보면 이해가 조금 됐다. 학습 데이터에 들어 있는 집 크기 xx와 실제 가격 yy는 이미 정해져 있다. 내가 바꿀 수 있는 것은 데이터가 아니라 가설 함수의 모양이고, 그 모양은 θ0\theta_0θ1\theta_1이 정한다.

그래서 손실 함수의 출력은 결국 θ\theta를 어떻게 설정했느냐에 따라 달라진다. 같은 데이터라도 θ\theta가 달라지면 직선이 바뀌고, 직선이 바뀌면 예측값이 바뀌며, 예측값이 바뀌면 평균 제곱 오차도 달라진다. 그래서 손실 함수는 J(θ)라고 쓴다.

식 앞의 계수가 원래 평균을 낼 때처럼 1m\frac{1}{m}이 아니라 12m\frac{1}{2m}인 것도 나왔다. 엄밀히 말하면 이 식은 평균 제곱 오차에 12\frac{1}{2}를 곱한 형태라 값은 절반이 되지만, 어떤 θ\theta에서 값이 가장 작아지는지는 바뀌지 않는다. 여기서 2가 붙는 이유는 이후 계산을 편하게 하기 위한 것이라고 한다.


오늘 정리한 범위에서는 선형회귀를 “최적선을 찾는 문제”로, 손실 함수는 “그 선이 얼마나 좋은지 숫자로 평가하는 방법”으로 정리했다. 입력 데이터와 정답은 이미 주어져 있고, 실제로 조정하는 대상은 θ\theta다. 그래서 여러 θ\theta 중에서 손실 함수의 값이 가장 작아지는 쪽을 찾는 것이 선형회귀 학습의 목표다.

아직 손실을 줄이는 구체적인 방법까지는 정리하지 않았다. 일단 오늘은 평균 제곱 오차가 왜 손실 함수로 쓰이는지, 그리고 왜 손실 함수의 입력을 θ\theta로 두는지까지 잡고 넘어가기로 했다.