안녕하세요? 오늘은 SVM 이론에 대해 공부해봅시다..
저자는 이번 SVM이론은 깊이 알려는 사람한테 좋고, 처음 접하는 사람은 넘어가도 좋다는데요!..
그래도 알아둬서 나쁠 건 없죠!
먼저, 표기법을 정리합니다.
4장에서 편향과 입력 특성의 가중치 까지 전체 모델 파라미터를 하나의 벡터 에 넣는다고 했습니다.
그리고 모든 샘플에 편향에 해당하는 입력값 을 추가합니다.
이 장에서는, SVM을 다룰 때 조금 더 편리한(그리고 더 일반적인) 다른 표기법을 사용하겠습니다.
편향을 b라 하고, 특성의 가중치 벡터를 라 하겠습니다. 따라서 입력 특성 벡터에 편향을 위한 특성이 추가되지 않습니다.
[결정 함수와 예측]
선형 SVM 분류기 모델은 단순히 결정 함수 를 계산해서 새로운 샘플 x의 클래스를 예측합니다. 결괏값이 0보다 크면 예측된 클래스 은 양성 클래스(1) 가 됩니다. 그렇지 않으면 음성 클래스(0)이 됩니다.
*선형 SVM분류기의 예측
아래의 오른쪽에 있는 모델의 결정 함수가 잘 나타나있습니다. 특성이 2개인 (꽃잎의 너비와 길이) 데이터셋이기 때문에 2차원 평면입니다. 결정 경계는 결정 함수의 값이 0인 점들로 이루어져 있습니다. 이는 두 평면의 교차점으로, 직선입니다.
(아래의 그림에는 굵은 실선으로 나타남)
#SVM 이론 / Iris 결정 경계 함수
iris = datasets.load_iris()
X = iris['data'][:, (2, 3)] #petal length, petal width
y = (iris['target'] == 2).astype(np.float64) # Iris -Virginica
from mpl_toolkits.mplot3d import Axes3D
def plot_3D_decision_function(ax, w, b, x1_lim=[4, 6], x2_lim=[0.8, 2.8]):
x1_in_bounds = (X[:, 0] > x1_lim[0]) & (X[:, 0] < x1_lim[1])
X_crop = X[x1_in_bounds]
y_crop = y[x1_in_bounds]
x1s = np.linspace(x1_lim[0], x1_lim[1], 20)
x2s = np.linspace(x2_lim[0], x2_lim[1], 20)
x1, x2 = np.meshgrid(x1s, x2s)
xs = np.c_[x1.ravel(), x2.ravel()]
df = (xs.dot(w) + b).reshape(x1.shape)
m = 1 / np.linalg.norm(w)
boundary_x2s = -x1s*(w[0]/w[1])-b/w[1]
margin_x2s_1 = -x1s*(w[0]/w[1])-(b-1)/w[1]
margin_x2s_2 = -x1s*(w[0]/w[1])-(b+1)/w[1]
ax.plot_surface(x1s, x2, np.zeros_like(x1),
color="b", alpha=0.2, cstride=100, rstride=100)
ax.plot(x1s, boundary_x2s, 0, "k-", linewidth=2, label=r"$h=0$")
ax.plot(x1s, margin_x2s_1, 0, "k--", linewidth=2, label=r"$h=\pm 1$")
ax.plot(x1s, margin_x2s_2, 0, "k--", linewidth=2)
ax.plot(X_crop[:, 0][y_crop==1], X_crop[:, 1][y_crop==1], 0, "g^")
ax.plot_wireframe(x1, x2, df, alpha=0.3, color="k")
ax.plot(X_crop[:, 0][y_crop==0], X_crop[:, 1][y_crop==0], 0, "bs")
ax.axis(x1_lim + x2_lim)
ax.text(4.5, 2.5, 3.8, "결정 함수 $h$", fontsize=15)
ax.set_xlabel(r"꽃잎 길이", fontsize=15, labelpad=15)
ax.set_ylabel(r"꽃잎 너비", fontsize=15, rotation=25, labelpad=15)
ax.set_zlabel(r"$h = \mathbf{w}^T \mathbf{x} + b$", fontsize=18, labelpad=10)
ax.legend(loc="upper left", fontsize=16)
fig = plt.figure(figsize=(11, 6))
ax1 = fig.add_subplot(111, projection='3d')
plot_3D_decision_function(ax1, w=svm_clf2.coef_[0], b=svm_clf2.intercept_[0])
plt.show()
점선은 결정 함수의 값이 1 또는 -1인 점들을 나타냅니다.
이 선분은 결정 경계에 나란하고 일정한 거리만큼 떨어져서 마진을 형성하고 있습니다.
선형 SVM 분류기를 훈련한다는 것은 마진 오류를 하나도 발생하지 않거나(하드 마진), 제한적인 마진 오류를 가지면서(소프트 마진) 가능한 마진을 크게 하는 w와 b를 찾는 것입니다.
조금 더 일반적으로 말하면, n개의 특성이 있을 때 결정 함수는 n차원의 초평면(hyperplane)이고, 결정 경계는 (n-1)차원의 초평면입니다.
[목적 함수]
결정 함수의 기울기를 생각해보면, 이는 가중치 벡터 의 노름과 같습니다.
이 기울기를 2로 나누면 결정 함수의 값이 이 되는 점들이 결정 경계로부터 2배 만큼 더 멀어집니다.
즉 기울기를 2로 나누는 것은 마진에 2를 곱하는 것과 같습니다.
아래의 그림처럼 2차원으로 시각화하면 이해하기 쉽습니다.
가중치 벡터 w가 작을수록 마진은 커집니다.
def plot_2D_decision_function(w, b, ylabel=True, x1_lim=[-3, 3]):
x1 = np.linspace(x1_lim[0], x1_lim[1], 200)
y = w * x1 + b
m = 1 / w
plt.plot(x1, y)
plt.plot(x1_lim, [1, 1], "k:")
plt.plot(x1_lim, [-1, -1], "k:")
plt.axhline(y=0, color='k')
plt.axvline(x=0, color='k')
plt.plot([m, m], [0, 1], "k--")
plt.plot([-m, -m], [0, -1], "k--")
plt.plot([-m, m], [0, 0], "k-o", linewidth=3)
plt.axis(x1_lim + [-2, 2])
plt.xlabel(r"$x_1$", fontsize=16)
if ylabel:
plt.ylabel(r"$w_1 x_1$ ", rotation=0, fontsize=16)
plt.title(r"$w_1 = {}$".format(w), fontsize=16)
plt.figure(figsize=(12, 3.2))
plt.subplot(121)
plot_2D_decision_function(1, 0)
plt.subplot(122)
plot_2D_decision_function(0.5, 0, ylabel=False)
plt.show()
마진을 크게 하기 위해 ||w||를 최소화하려고 합니다. 그러나 마진 오류를 하나도 만들지 않으려면(하드 마진),
결정 함수가 모든 양성 훈련 샘플에서는 1보다 커야 하고, 음성 훈련 샘플에서는 -1보다 작아야 합니다.
음성 샘플 일 때, 로, 양섬 샘플일 때 , 로 정의하면
앞서 말한 제약조건을 모든 샘플에서 로 표현할 수 있습니다.
그러므로, 하드 마진 선형 SVM 분류기의 목적 함수를 제약이 있는 최적화(constrained optimization) 문제로 표현할 수 있습니다.
[ 하드 마진 선형 SVM 분류기의 목적 함수 ]
** 를 최소화하는 대신 인를 최소화 합니다.
** 같은 결과를 내지만 (어떤 값을 최소화하는 w와 b는 그 값을 제곱하여 2로 나눈 것도 최소화합니다.)
** 이 깔끔하고, 간단하게 미분이 되기 때문입니다. (미분 결과는 w입니다.)
** 반면 는 w=0에서 미분할 수 없습니다. 최적화 알고리즘은 미분할 수 있는 함수에서 잘 작동합니다.
소프트 마진 분류기의 목적 함수를 구성하려면, 각 샘플에 대해 슬랙 변수(slack variable) 을 도입해야 합니다.
는 i번째 샘플이 얼마나 마진을 위반할지 정합니다. 이 문제는 두 개의 상충되는 목표를 가지고 있습니다.
마진 오류를 최소화하기 위해 가능한 한 슬랙 변수의 값을 작게 만드는 것과 마진을 크게 하기 위해 를 가능한 작게 만드는 것입니다. 여기에 하이퍼파라미터 C가 등장합니다. 이 파라미터는 두 목표 사이의 트레이드오프를 정의합니다.
결국 아래의 제약을 가진 최적화 문제가 됩니다.
[ 소프트 마진 선형 SVM 분류기의 목적 함수 ]
[콰드라틱 프로그래밍 ]
하드 마진과 소프트마진 문제는 모두 선형적 제약 조건이 있는 볼록 함수의 이차 최적화 문제입니다.
이런 문제를 콰드라틱 프로그래밍(Quadratic Programming, QP) 문제라고 합니다.
여러 가지 테크닉으로 QP문제를 푸는 알고리즘이 있지만 이 책의 범위를 벗어납니다.
(더 많이 알고 싶다면 저자가 소개해준 곳이 있네요.)
(http://goo.gl/FGXuLw, 스티브 보이드와 리벤 반덴버그의 Convex Optimization)
(http://goo.gl/rTo3Af, 리차드 브라운의 동영상 강의)
일반적인 문제 공식은 아래와 같습니다.
[QP 문제]
여기서,
1) p는 차원의 벡터, (=모델 파라미터 수)
2) H는 크기 행렬
3) f는 차원의 벡터
4) A는 크기 행렬(= 제약 수)
5) b는 차원의 벡터
[TIP]
SVM 회귀를 위한 목적 함수는 분류의 경우와 조금 다릅니다.
회귀에서는 결정 경계의 양쪽으로 모든 샘플을 담기 위한 도로의 오차 폭을 두 개의 슬랙변수 라고 할 때,
와 두 조건을 만족하는 목적 함수를 구성합니다.
사실, 식 는 개의 제약을 정의하고 있습니다.
일 때, 인 제약이 있습니다.
여기서 는 A의 i번째 행의 원소를 포함하는 벡터이고 는 b의 i번째 원소입니다.
다음과 같이 QP파라미터를 지정하면 하드 마진을 갖는 선형 SVM 분류기의 목적 함수를 간단하게 검증할 수 있습니다.
1) , 여기서 n은 특성 수입니다. (편향 때문에 +1이 추가되었습니다.)
2) , 여기서 m은 훈련 샘플 수 입니다.
3) H는 크기이고, 왼쪽 맨 위의 원소가 0(편향을 제외하기 위해)인 것을 제외하고는 단위행렬입니다.
4) f=0, 모두 0으로 채워진 차원의 벡터입니다.
5) b=1, 모두 1로 채워진 차원의 벡터입니다.
6) 여기서 는 편향을 위해 특성 을 추가한 와 같습니다.
하드 마진 선형 SVM 분류기를 훈련시키는 한 가지 방법은 이미 준비되어 있는 QP알고리즘에 관련 파라미터를 전달하면 됩니다.
결과 벡터 p는 편향 와 특성 가중치 를 담고 있습니다.
하지만, 커널 트릭을 사용하려면 제약이 있는 최적화 문제를 다른 형태로 바꿔야 합니다.
오늘은 SVM 이론에 대해 처음으로 알아보았는데요 ! 너무 어렵네요 ㅋㅋ
머리에서 자연스럽게 스쳐지나갔습니다. 하지만 한번 봤으니 나중에 봤을 때는 어느 정도 더 이해가 가겠죠!
블로그
출처
이 글의 상당 부분은 [핸즈온 머신러닝, 한빛미디어/오렐리앙 제롱/박해선] 서적을 참고하였습니다.
나머지는 부수적인 함수나 메서드에 대해 부족한 설명을 적어두었습니다.
학습용으로 포스팅 하는 것이기 때문에 복제보다는 머신러닝에 관심이 있다면 구매해보시길 추천합니다.
도움이 되셨다면 로그인 없이 가능한
아래 하트♥공감 버튼을 꾹 눌러주세요!
'## 오래된 게시글 (미관리) ## > Python (Linux)' 카테고리의 다른 글
42. Python - 5장 연습문제 (0) | 2019.02.10 |
---|---|
41. Python - SVM 이론 2 (0) | 2019.02.10 |
39. Python - SVM 회귀 (0) | 2019.02.07 |
38. Python - 비선형 SVM 분류, 다항 커널과 RBF커널 (2) | 2019.02.03 |
37. Python - 서포트 벡터 머신(소프트 마진 분류) (0) | 2019.02.02 |