Machine Learning의 민족/핸즈온 머신러닝
< 핸즈온 머신러닝 - SVM >
댕구리댕댕구리
2022. 6. 2. 19:49
728x90
반응형
SMALL
Chapter_5 서포트 벡터 머신.ipynb
Colaboratory notebook
colab.research.google.com
1. 선형 SVM 분류
1 - 1. 라지 마진 분류
- 왼쪽: 점선으로 나타난 결정 경계를 만든 모델은 클래스를 적절하게 분류하지 못함
- 오른쪽: 실선(SVM 분류기의 결정 경계), 클래스 사이에 가장 폭이 넓은 도로 찾음
- 훈련 샘플을 더 추가해도 결정 경계에는 영향 없음
- 경계에 위치한 샘플에 의해 전적으로 결정
- 이러한 샘플을 서포트 벡터로 지정
1 - 2. 소프트 마진 분류
- 하드 마진 분류: 모든 샘플이 도로 바깥쪽에 올바르게 분류
- 문제점
- 첫 번째: 데이터가 선형적으로 구분되어야 작동
- 두 번째: 이상치에 민감
- so) 좀 더 유연한 모델이 필요
- 소프트 마진 분류: 폭을 가능한 넓게 유지하는 것과 마진 오류 사이에 적절한 균형 필요
import numpy as np
from sklearn import datasets
from sklearn.pipeline import Pipeline
from sklearn.preprocessing import StandardScaler
from sklearn.svm import LinearSVC
iris = datasets.load_iris()
X = iris['data'][:, (2, 3)] #꽃잎 길이, 꽃잎 너비
y = (iris["target"] == 2).astype(np.float64) # Iris-Virginica
svm_clf = Pipeline([
('scaler', StandardScaler()),
("Linear_svc", LinearSVC(C=1, loss="hinge")), ])
svm_clf.fit(X, y)
# SVM 분류기는 로지스틱 회귀 분류기와는 다르게 클래스에 대한 확률을 제공하지 않습니다.
svm_clf.predict([[5.5, 1.7]])
2. 비선형 SVM 분류
- 비선형 데이터를 다루는 방법은 다항 특성과 같은 특성을 더 추가
- 왼쪽: 특성 x1만을 가진 간단한 데이터 셋
- 오른쪽: x2 = (x1)**2를 추가해 만들어진 2차원 데이터 셋은 선형 구분 가능
- PolynomialFeatures 변환기와 StandardScaler, LinearSVC를 연결한 Pipeline 생성
from sklearn.datasets import make_moons
from sklearn.pipeline import Pipeline
from sklearn.preprocessing import PolynomialFeatures
X, y = make_moons(n_samples = 100, noise = 0.15)
polynomial_svm_clf = Pipeline([
('poly_features', PolynomialFeatures(degree = 3)),
('scaler', StandardScaler()),
('svm_clf', LinearSVC(C =10, loss = 'hinge'))
])
polynomial_svm_clf.fit(X, y)
import matplotlib.pyplot as plt
from sklearn.datasets import make_moons
X, y = make_moons(n_samples=100, noise=0.15, random_state=42)
def plot_dataset(X, y, axes):
plt.plot(X[:, 0][y==0], X[:, 1][y==0], "bs")
plt.plot(X[:, 0][y==1], X[:, 1][y==1], "g^")
plt.axis(axes)
plt.grid(True, which='both')
plt.xlabel(r"$x_1$", fontsize=20)
plt.ylabel(r"$x_2$", fontsize=20, rotation=0)
plot_dataset(X, y, [-1.5, 2.5, -1, 1.5])
plt.show()
def plot_predictions(clf, axes):
x0s = np.linspace(axes[0], axes[1], 100)
x1s = np.linspace(axes[2], axes[3], 100)
x0, x1 = np.meshgrid(x0s, x1s)
X = np.c_[x0.ravel(), x1.ravel()]
y_pred = clf.predict(X).reshape(x0.shape)
y_decision = clf.decision_function(X).reshape(x0.shape)
plt.contourf(x0, x1, y_pred, cmap=plt.cm.brg, alpha=0.2)
plt.contourf(x0, x1, y_decision, cmap=plt.cm.brg, alpha=0.1)
plot_predictions(polynomial_svm_clf, [-1.5, 2.5, -1, 1.5])
plot_dataset(X, y, [-1.5, 2.5, -1, 1.5])
plt.show()
2 - 1. 다항식 커널
- 커널 트릭: 특성을 추가하지 않으면서 다항식 특성을 많이 추가한 것과 같은 결과 도출
- 모델이 과적합이면 다항식의 차수를 줄이고, 과소적합이면 차수를 늘림
from sklearn.svm import SVC
poly_kernel_svm_clf = Pipeline([
('scaler', StandardScaler()),
('svm_clf', SVC(kernel = 'poly', degree = 3, coef0 = 1, C = 5))
])
poly_kernel_svm_clf.fit(X, y)
poly100_kernel_svm_clf = Pipeline([
("scaler", StandardScaler()),
("svm_clf", SVC(kernel="poly", degree=10, coef0=100, C=5))
])
poly100_kernel_svm_clf.fit(X, y)
fig, axes = plt.subplots(ncols=2, figsize=(10.5, 4), sharey=True)
plt.sca(axes[0])
plot_predictions(poly_kernel_svm_clf, [-1.5, 2.45, -1, 1.5])
plot_dataset(X, y, [-1.5, 2.4, -1, 1.5])
plt.title(r"$d=3, r=1, C=5$", fontsize=18)
plt.sca(axes[1])
plot_predictions(poly100_kernel_svm_clf, [-1.5, 2.45, -1, 1.5])
plot_dataset(X, y, [-1.5, 2.4, -1, 1.5])
plt.title(r"$d=10, r=100, C=5$", fontsize=18)
plt.ylabel("")
plt.show()
2 - 2. 유사도 측정
- 각 샘플이 특정 랜드마크와 얼마나 닮았는지 측정하는 유사도 함수로 계산한 특성을 추가
- 데이터 셋에 있는 모든 샘플 위치에 랜드마크를 설정
- 차원이 매우 커짐 따라서, 변환된 훈련 세트가 선형적으로 구분될 가능성이 높음
- 단점: 훈련 세트에 있는 n개의 특성을 가진 m개의 샘플이 m개의 특성을 가진 m개의 샘플로 변환
2 - 3. 가우시안 RBF 커널
rbf_kernel_svm_clf = Pipeline([
('scaler', StandardScaler()),
('svm_clf',SVC(kernel = 'rbf', gamma = 5, C = 0.001))
])
rbf_kernel_svm_clf.fit(X, y)
- gamma 증가
- gamma를 증가시키면 종 모양의 그래프가 좁아져 각 샘플의 영향 범위가 작아짐
- 결정경계는 좀 더 불규칙해지고 각 샘플에 따라 구불구불하게 휘어짐
- gamma 감소
- 넓은 종 모양 그래프를 만들며 샘플이 넓은 범위에 걸쳐 영향을 주므로 결정경계가 더 부드러워짐
- 하이퍼파라미터 y가 규제의 역할, 모델이 과대적합인 경우에는 감소 / 과소적합인 경우에는 증가
- 통상적으로 선형 커널을 먼저 시도해보는 것을 추천
- LinearSVC가 SVC(kernel = 'linear)보다 훨씬 빠름
2 - 4. 계산 복잡도
3. SVM 회귀
- 제한된 마진 오류안에서 도로 안에 가능한 한 많은 샘플이 들어가도록 학습
- 왼쪽: 마진을 크게, 오른쪽: 마진을 작게
from sklearn.svm import LinearSVR
svm_reg = LinearSVR(epsilon = 1.5)
svm_reg.fit(X, y)
from sklearn.svm import SVR
svm_poly_reg = SVR(kernel = 'poly', degree = 2, C = 100, epsilon = 0.1)
svm_poly_reg.fit(X, y)
4. SVM 이론
- b: 편향 / w: 특성의 가중치 벡터
4 - 1. 결정 함수와 예측
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, "Decision function $h$", fontsize=16)
ax.set_xlabel(r"Petal length", fontsize=16, labelpad=10)
ax.set_ylabel(r"Petal width", fontsize=16, labelpad=10)
ax.set_zlabel(r"$h = \mathbf{w}^T \mathbf{x} + b$", fontsize=18, labelpad=5)
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()
- 특성이 2개인 데이터셋이기 때문에 2차원 평면
- 결정 경계는 결정 함구의 값이 0인 점들로 구성
- 점섬은 결정 함수의 값이 1 or -1인 점들을 나타냄
4 - 2. 목적 함수
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)
fig, axes = plt.subplots(ncols=2, figsize=(9, 3.2), sharey=True)
plt.sca(axes[0])
plot_2D_decision_function(1, 0)
plt.sca(axes[1])
plot_2D_decision_function(0.5, 0, ylabel=False)
plt.show()
- 가중치 벡터 w가 작을수록 마진이 증가
- 소프트 마진 분류기의 목적 함수를 구성하려면 각 샘플에 대해 슬랙 변수를 도입
- 슬랙 변수는 i번째 샘플이 얼마나 마진을 위반할지 결정
4 - 3. 콰드라틱 프로그래밍
- 하드 마진과 소프트 마진 문제는 모두 선형적인 제약 조건이 있는 볼록 함수의 이차 최적화 문제
4 - 4. 쌍대 문제
- 훈련 샘플 수가 특성 개수보다 작을 때 원 문제보다 쌍대 문제 푸는 것이 빠름
4 - 5. 커널 SVM
- 두 개의 2차원 벡터 a, b에 2차 다항식 매핑을 적용한 다음 변환된 벡터로 점곱
4 - 6. 힌지 손실
- max(0, 1-t) 함수
- t >= 1일 때 0
- 기울기
- t < 1이면 -1
- t >1 이면 0
- t =1인 경우, 미분은 불가능. 그러나 서브그레이디언트를 사용해 경사 하강법 사용(-1, 0 사이의 값 사용)
t = np.linspace(-2, 4, 200)
h = np.where(1 - t < 0, 0, 1 - t) # max(0, 1-t)
plt.figure(figsize=(5,2.8))
plt.plot(t, h, "b-", linewidth=2, label="$max(0, 1 - t)$")
plt.grid(True, which='both')
plt.axhline(y=0, color='k')
plt.axvline(x=0, color='k')
plt.yticks(np.arange(-1, 2.5, 1))
plt.xlabel("$t$", fontsize=16)
plt.axis([-2, 4, -1, 2.5])
plt.legend(loc="upper right", fontsize=16)
plt.show()
핸즈온 머신러닝
머신러닝 전문가로 이끄는 최고의 실전 지침서 텐서플로 2.0을 반영한 풀컬러 개정판 『핸즈온 머신러닝』은 지능형 시스템을 구축하려면 반드시 알아야 할 머신러닝, 딥러닝 분야 핵심 개념과
book.naver.com
728x90
반응형
LIST