5장 서포트 벡터 머신

주요 내용

참고: 핵심 설명과 코드는 🔑로 표시되었으며 굳이 알아둘 필요가 없는 코드는 ✋로 표시되었다.

기본 설정

5.1 선형 SVM 분류 (p. 205)

그림 5-1 코드 (p. 206)

붓꽃 데이터에서 세토사(setosa) 품종과 버시컬러(versicolor) 품종만을 대상으로 선형 SVM 분류기(하드 마진 분류)를 학습시킨다.

아래 함수는 SVM 분류 모델로 학습된 내용을 그래프로 보여준다. 3개의 인자가 요구된다.

아래 코드는 그림 5-1을 그린다.

그림 5-2 코드 (p. 206)

아래 코드는 SVM이 특성 축척에 민감하다는 것을 보여주는 그림을 그려준다.

5.1.1 소프트 마진 분류 (p.206)

그림 5-3 코드 (p. 207)

아래 코드는 그림 5-1에서 사용한 붓꽃 데이터에 이상치 두 개를 추가할 때 SVM을 이용한 하드 마진 분류의 문제를 보여준다.

선형 소프트 마진 분류 학습

아래 코드는 마진 오류를 허용하는, 즉 소프트 마진 분류를 지원하는 선형 SVM 학습법을 보여준다.

주의사항: LinearSVC 모델의 C에 의한 규제에 편향(절편)도 포함된다. 따라서 평균을 빼서 0으로 편향을 없애는 것이 중요하다. 하지만 표준화 축척 조정을 하면 자연스럽게 해결된다.

[5.5, 1.7] 특성을 갖는 붓꽃에 대한 예측은 양성, 즉 버지니카 품종이다.

그림 5-4 코드 (p. 207)

아래 코드는 소프트 마진 분류에 사용되는 규제(C)의 역할을 보여주는 그림을 그린다. 규제 C에 선형적으로 반비례하여 규제 강도가 정해진다. C=float("inf"), 즉 무한대이면 마진을 전혀 허용하지 않는 하드 마진 분류 모델이 된다.

참고: 원시 데이터(raw data)의 결정경계

훈련을 통해 학습된 결정경계의 파라미터는 모두 표준화된 값들을 대상으로 하였기 때문에 원시 데이터에 대한 결정경계 도로와 서포트 벡터를 그림으로 표시하려면 표준화 과정을 되돌리는 값을 사용해야 한다.

$\mathbf{x}$를 원시 데이터(raw data) 벡터라고 하고 $\mathbf{z}$를 표준화된 벡터이라 할 때 다음 관계가 성립한다.

$$ \mathbf{z} = \frac{\mathbf{x}-\mu}{\sigma} \tag{*} $$

훈련된 LinearSVC 모델의 결정경계 함수(decision function)는 아래 선형함수이다.

$$ h(\mathbf{z}) = w_1 z_1 + \cdots + w_n z_n + b $$

원시 데이터 $\mathbf{x}$에 대한 결정경계 또한 위 결정경계 함수에 의존하도록 해야 한다. $\mathbf{x}$와 결정경계 함수와의 관계를 확인하기 위해 위 식에 $(*)$ 를 대입하여 $x_i$와 결정경계 함수 사이의 관계를 확인한다.

$$ \begin{align*} w_1 z_1 + \cdots + w_n z_n + b &= w_1 \frac{x_1-\mu}{\sigma} + \cdots + w_n \frac{x_n-\mu}{\sigma} + b \\ &= \frac{w_1}{\sigma} x_1 + \cdots + \frac{w_n}{\sigma} x_n + \left (w_1 \left (-\frac{\mu}{\sigma}\right) + \cdots + w_n \left (-\frac{\mu}{\sigma}\right) + b\right) \\ &= \frac{w_1}{\sigma} x_1 + \cdots + \frac{w_n}{\sigma} x_n + h (-\mu / \sigma) \end{align*} $$

결론적으로, 원시 데이터의 각 특성 $x_i$에 대한 파라미터 $w'_i$와 편항 $b'$은 아래와 같다.

$$ \begin{align*} w'_i & = w_i/\sigma \\[1ex] b' & = h (-\mu / \sigma) \end{align*} $$

참고: https://github.com/ageron/handson-ml/issues/250

아래 코드는 위 설명을 반영하여 원시 데이터에 대한 결정경계 함수의 파라미터와 편향을 계산한다. 코드에 사용된 객체의 속성은 다음과 같다.

plot_svc_decision_boundary() 함수를 이용하여 C 값의 영향력을 보여주는 그림을 그린다.

LinearSVC와 유사한 모델

5.2 비선형 SVM 분류 (p. 209)

참고: 비선형 분류를 지원하는 SVM 모델은 사이킷런의 SVC 클래스이며, LinearSVC 클래스는 선형 분류만 지원한다.

다항 특성과 선형 SVM: 아이디어 소개(p. 209)

다항 특성을 추가하여 비선형 회귀문제를 선형 회귀로 해결하는 방식을 4장에서 살펴 보았다. 동일한 아이디어로 선형 SVM 분류기를 비선형 SVM 분류 모델로 훈련시키는 것을 보여준다.

그림 5-5 코드 (p. 209)

아래 코드는 2차 다항 특성을 추가할 경우 비선형 분류 문제를 선형 분류로 해결할 수 있음을 보여주는 그림을 그린다.

그림 5-6 코드 (p. 210)

아래 코드는 moons 데이터셋을 불러온다. moons 데이터셋은 지정된 수의 데이터가 선형 분류가 불가능한 두 개의 반달 모양으로 구분되어 있다.

X는 x, y 좌표로 구성된 100개의 데이터를 담는다.

y는 100개 샘플의 레이블을 담고 있다.

아래 함수는 moons 데이터셋을 색깔과 모양으로 구분한 산점도를 그린다.

아래 코드는 3차 다항 특성을 추가할 경우 moons 데이터셋을 선형 분류로 해결할 수 있음을 보여주는 그림을 그린다.

아래 함수는 훈련된 SVM 모델의 결정경계를 그려준다.

3차 다항 특성을 추가하여 훈련된 SVM 분류기의 성능을 아래 그림이 확인시켜 준다.

5.2.1 다항 커널 (p. 211)

다항 특성 추가 기법은 모든 선형 회귀/분류 모델과 함께 사용할 수 있다. 하지만 다항 특성을 추가해서 훈련하는 비용이 경우에 따라 매우 비쌀 수 있다.

그런데 SVM의 경우 커널 트릭(kernel trick)을 사용하면 실제로는 특성을 추가하지 않지만 특성을 추가한 효과를 얻을 수 있다. SVC 모델의 경우 poly 커널과 적절한 다항 차수(degree)를 지정하면 해당 차수만큼의 다항 특성을 추가한 효과를 낸다.

예를 들어 아래 코드는 3차와 10차 다항 특성을 추가한 효과를 이용하여 moons 데이터셋을 분류한 결과를 그림으로 보여준다.

plot_predictions() 함수를 활용하여 두 개의 그래프를 그린다.

5.2.2 유사도 특성: 아이디어 소개 (p. 212)

유사도 특성을 추가하여 고차원 데이터셋을 생성한 후 선형분류를 시도한다. 추가되는 유사도 특성은 사용되는 랜드마크 수에 의존한다.

가우시안 RBF(식 5-1)

랜드마크 $\ell$(엘)과 샘플 $\mathbf{x}$ 사이의 유사도를 아래 함수값으로 계산한다. $\gamma$ 값이 클수록 가까운 샘플을 선호하게 되어 즉 샘플들 사이의 영향을 보다 적게 고려한다. 따라서 모델의 자유도를 높이게 되어 과대적합 위험이 커진다.

$$ {\displaystyle \phi_{\gamma}(\mathbf{x}, \boldsymbol{\ell})} = {\displaystyle \exp({\displaystyle -\gamma \left\| \mathbf{x} - \boldsymbol{\ell} \right\|^2})} $$

그림 5-8 코드 (p. 213)

아래 코드는 앞서 그림 5.5 코드에서 소개한 선형적으로 구분할 수 없었던 데이터셋(X1D)을 가우시안 RBF 함수를 적용하여 선형적으로 구분할 수 있음을 보여준다.

코드에 사용된 랜드마크는 -2와 1 두 개이며, 따라서 2개의 유사도 특성이 데이터셋에 추가된다.

예를 들어, x=-1과 두 개의 랜드마크 사이의 유사도는 다음과 같다.

아래 그림에서 $\mathbf{x}$로 표기된 점이 x=-1에 해당한다.

5.2.3 가우시안 RBF 커널 (p. 213)

모든 샘플을 랜드마크로 지정하는 것이 가장 간단하다. 그런데 이렇게 하면 특성 수가 샘플 수 $m$만큼 늘어난다. 따라서 훈련 세트가 매우 클 경우 매우 많은 특성이 생겨난다.

하지만 RBF 커널을 이용하면 다항 커널의 경우처럼 유사도 특성을 실제로는 추가하지 않지만 추가한 효과를 내게 할 수 있다. 사용법은 kernel="rbf"와 적절한 gamma 하이퍼파라미터 값을 지정하면 된다.

그림 5-9 코드 (p. 214)

아래 코드는 gammaC의 조합 네 경우를 그림으로 보여준다.

5.3 SVM 회귀 (p. 216)

그림 5-10 코드 (p. 216)

아래 코드는 선형 SVM 회귀를 설명하기 위해 선형 회귀 학습이 가능한 50개의 샘플을 잡음을 섞어 생성한다.

두 개의 LinearSVR 모델을 훈련시킨다.

find_support_vectors() 함수는 마진 오류 샘플들의 인덱스를 찾는다.

plot_svm_regression() 함수는 SVM 회귀 결과를 결정경계와 함께 그림으로 그려준다. 사용된 인자는 다음과 같다.

아래 코드는 epsilon을 달리하는 두 LinearSVR 모델의 훈련 결과를 보여준다.

그림 5-11 코드 (p. 217)

아래 코드는 다중 커널을 이용하는 비선형 SVM 회귀를 설명하기 위해 100개의 샘플을 2차 다항식과 잡음을 이용하여 생성한다.

참고: 사이킷런 최신 버전에서 gamma="scale"이 기본값이다. 그러면 gamma가 아래 값으로 자동 지정된다.

$$ \frac{1}{\text{특성 수} \cdot \text{특성의 분산}} $$

2차 다항 커널을 사용하는 두 개의 SVR 모델을 훈련시킨다. C 규제를 달리한다.

아래 코드는 마진 오류 허용 정도 C를 달리하며 2차 다항 커널을 사용하는 두 SVR 모델의 훈련 결과를 보여준다.

왼편 그래프(C=100) 오른편 그래프(C=0.01)
규제 보다 약함 규제 보다 강함
샘플에 덜 민감 샘플에 더 민감
마진 오류 보다 적게 마진 오류 보다 많이

✋ 5.4 SVM 이론 (p. 218)

여기서는 책에서 이론 설명을 위해 사용되는 그림을 그리는 코드만 제공된다.

주의사항: SVM 이론을 설명할 때 편의상 파라미터를 $\theta_0, \dots, \theta_n$ 대신에 절편과 특성 파라미터 벡터를 아래처럼 분리해서 사용한다.

$$ \begin{align*} b &= \theta_0 \\ w_i &= \theta_i \quad (i = 1, \dots, n) \end{align*} $$

그림 5-12 코드 (p. 219)

아래 코드는 버지니카 품종 여부 판정을 위해 훈련시킨 선형 SVM 분류 모델을 보여준다.

그림 5-13 코드 (p. 220)

아래 코드는 SVM의 목적함수를 설명하는 그림을 그린다.

힌지 손실 함수 그래프 코드 (p. 227)

아래 코드는 힌지 손실 함수의 그래프를 그린다.

🔑 부록 A: 훈련 시간 측정

moons 데이터셋을 이용한 이진분류 모델을 이용하여 모델의 훈련시간을 간단하게 측정하는 방법을 소개한다.

아래 코드는 tol(조기종료 조건)을 변경할 때마다 훈련 시간을 측정한 결과를 선 그래프로 보여준다.

🔑 부록 B: 선형 SVM 분류기 구현하기

경사하강법을 이용하여 선형 SVM 분류기를 직접 구현하는 과정을 보여준다.

선형 SVM 분류기 클래스 선언

MyLinearSVC 클래스를 선언한다. 비용함수는 책 227쪽, 식 5-13에서 소개한 아래 함수이다.

$$ J(\mathbf{w}, b) = \dfrac{1}{2} \mathbf{w}^T \mathbf{w} \,+\, C {\displaystyle \sum_{i=1}^{m}\max\left(0, 1 - t^{(i)} (\mathbf{w}^T \mathbf{x}^{(i)} + b) \right)} $$

훈련 세트로 붓꽃 데이터셋을 사용한다. 버지니카 품종 여부를 판단하는 이진분류 훈련을 진행한다.

MyLinearSVC 모델을 훈련시킨다. (사이킷런의 SVC 모델 보다 좀 많이 느리다.)

훈련 과정 중에 비용함숫값의 변화는 다음과 같다.

학습된 절편(b)와 특성 파라미터(w)는 다음과 같다.

사이킷런의 SVC 모델과의 성능 비교

동일한 데이터셋에 대해 사이킷런의 SVC 모델을 사용한다. 조기종료 조건 tol=1e-3이 충족될 때까지 반복 학습함에도 불구하고 학습 속도가 훨씬 빠르다.

학습된 w와 b는 매우 이전과 매우 유사하다.

실제로 두 모델의 성능을 그래프로 그려보면 다음과 같다.

SGDClassifier 모델과의 성능 비교

SGDClassifier 모델을 SVM 용도로 훈련시키기 위해 힌지 손실 함수를 사용한다.

SGDClassifier 모델은 원래 SVM 용도로 만들어지지 않았기에 서포트 벡터에 대한 정보를 제공하지 않는다. 아래 코드는 필요한 정보를 구하는 방버을 보여주며 이를 이용하여 결정 경계 도로를 함께 그려준다.

주의사항: 파라미터를 $\theta_0, \dots, \theta_n$으로 사용한다. 즉, 다음이 성립한다.

$$ \begin{align*} \theta_0 &= b \\ \theta_i &= w_i\quad (i = 1, \dots, n) \end{align*} $$

연습문제 해답

1. to 7.

부록 A 참조.

8.

문제: 선형적으로 분리되는 데이터셋에 LinearSVC를 훈련시켜보세요. 그런 다음 같은 데이터셋에 SVCSGDClassifier를 적용해보세요. 거의 비슷한 모델이 만들어지는지 확인해보세요.

Iris 데이터셋을 사용하겠습니다. Iris Setosa와 Iris Versicolor 클래스는 선형적으로 구분이 가능합니다.

이 3개 모델의 결정경계를 그려 보겠습니다:

아주 비슷하네요!

9.

문제: MNIST 데이터셋에 SVM 분류기를 훈련시켜보세요. SVM 분류기는 이진 분류기라서 OvA 전략을 사용해 10개의 숫자를 분류해야 합니다. 처리 속도를 높이기 위해 작은 검증 세트로 하이퍼파라미터를 조정하는 것이 좋습니다. 어느 정도까지 정확도를 높일 수 있나요?

먼저 데이터셋을 로드하고 훈련 세트와 테스트 세트로 나눕니다. train_test_split() 함수를 사용할 수 있지만 보통 처음 60,000개의 샘플을 훈련 세트로 사용하고 나머지는 10,000개를 테스트 세트로 사용합니다(이렇게 하면 다른 사람들의 모델과 성능을 비교하기 좋습니다):

많은 훈련 알고리즘은 훈련 샘플의 순서에 민감하므로 먼저 이를 섞는 것이 좋은 습관입니다. 하지만 이 데이터셋은 이미 섞여있으므로 이렇게 할 필요가 없습니다.

선형 SVM 분류기부터 시작해보죠. 이 모델은 자동으로 OvA(또는 OvR) 전략을 사용하므로 특별히 처리해 줄 것이 없습니다. 간단하네요!

경고: 이 작업은 하드웨어에 따라 몇 분이 걸릴 수 있습니다.

훈련 세트에 대한 예측을 만들어 정확도를 측정해 보겠습니다(최종 모델을 선택해 훈련시킨 것이 아니기 때문에 아직 테스트 세트를 사용해서는 안됩니다):

MNIST에서 89.5% 정확도면 나쁜 성능입니다. 선형 모델이 MNIST 문제에 너무 단순하기 때문이지만 먼저 데이터의 축척을 조정할 필요가 있습니다:

경고: 이 작업은 하드웨어에 따라 몇 분이 걸릴 수 있습니다.

훨씬 나아졌지만(에러율을 절반으로 줄였습니다) 여전히 MNIST에서 좋은 성능은 아닙니다. SVM을 사용한다면 커널 함수를 사용해야 합니다. RBF 커널(기본값)로 SVC를 적용해 보겠습니다.

노트: 향후 버전을 위해 사이킷런 0.22에서 기본값인 gamma="scale"을 지정합니다.

아주 좋네요 6배나 적은 데이터에서 모델을 훈련시켰지만 더 좋은 성능을 얻었습니다. 교차 검증을 사용한 랜덤 서치로 하이퍼파라미터 튜닝을 해보겠습니다. 진행을 빠르게 하기 위해 작은 데이터셋으로 작업하겠습니다:

이 점수는 낮지만 1,000개의 샘플만 사용한 것을 기억해야 합니다. 전체 데이터셋으로 최선의 모델을 재훈련시켜 보겠습니다:

경고: 사용하는 하드웨어에 따라 다음 셀을 실행하는데 몇 시간이 걸릴 수 있습니다.

아주 훌륭하네요! 이 모델을 선택하겠습니다. 이제 테스트 세트로 모델을 테스트합니다:

아주 나쁘지 않지만 확실히 모델이 다소 과대적합되었습니다. 하이퍼파라미터를 조금 더 수정할 수 있지만(가령, C와/나 gamma를 감소시킵니다) 그렇게 하면 테스트 세트에 과대적합될 위험이 있습니다. 다른 사람들은 하이퍼파라미터 C=5gamma=0.005에서 더 나은 성능(98% 이상의 정확도)을 얻었습니다. 훈련 세트를 더 많이 사용해서 더 오래 랜덤 서치를 수행하면 이런 값을 얻을 수 있을지 모릅니다.

10.

문제: 캘리포니아 주택 가격 데이터셋에 SVM 회귀를 훈련시켜보세요.

사이킷런의 fetch_california_housing() 함수를 사용해 데이터셋을 로드합니다:

훈련 세트와 테스트 세트로 나눕니다:

데이터의 축척을 조정하는 것을 잊지 마세요:

먼저 간단한 LinearSVR을 훈련시켜 보죠:

훈련 세트에 대한 성능을 확인해 보겠습니다:

RMSE를 확인해 보겠습니다:

훈련 세트에서 타깃은 만달러 단위입니다. RMSE는 기대할 수 있는 에러의 정도를 대략 가늠하게 도와줍니다(에러가 클수록 큰 폭으로 증가합니다). 이 모델의 에러가 대략 $10,000 정도로 예상할 수 있습니다. 썩 훌륭하지 않네요. RBF 커널이 더 나을지 확인해 보겠습니다. 하이퍼파라미터 Cgamma의 적절한 값을 찾기 위해 교차 검증을 사용한 랜덤 서치를 적용하겠습니다:

이제 훈련 세트에서 RMSE를 측정해 보겠습니다:

선형 모델보다 훨씬 나아졌네요. 이 모델을 선택하고 테스트 세트에서 평가해 보겠습니다: