[Alex] 데이터 장인의 블로그

[Machine Learning] SVM - 서포트 벡터 머신 본문

ML&DL/Machine Learning

[Machine Learning] SVM - 서포트 벡터 머신

Alex, Yoon 2020. 9. 11. 13:37

 

출처

ratsgo_서포트 벡터 머신

[서적] 파이썬 데이터 사이언스 핸드북

https://pierpaolo28.github.io/blog/blog6/

SVM: Feature Selection and Kernels

기반으로 한 학습내용 정리입니다. 

분류 = 분리

https://pierpaolo28.github.io/blog/blog6/

 분류 학습의 가장 기본적인 아이디어는 훈련 데이터의 공간에서 하나의 분할 초평면을 찾아 서로 다른 클래스의 데이터를 찾아내어 분리하는 것이다. 그렇다면 위의 그림에서 분류를 하기 위한 분할선을 하나 찾는다고 가정할 때, 왜 오른쪽 초록선이 기준이 되는 것일까? 

 그 이유는 가장 '견고'한 선이기 때문이다. 노이즈(이상값)나 어떠한 영향으로 인해 새로운 데이터가 분류 경계에 가까이 가게된다면 '오류'가 생기게 된다. 이러한 오류를 최대한 줄일 수 있도록 '분할선'을 학습하는 것이 서포트 벡터 머신 (SVM)에 가장 기본적인 이론이라고 할 수 있다. 

마진

서포트 벡터 머신에서는 '마진'을 극대화하는 선이 최적의 모델이 된다. 즉, SVM은  최대 '마진' 추정기의 대표적인 예이다. 

마진의 두가지 형태 - 하드 VS 소프트

SVM의 마진은 두가지 형태를 보이는데 '하드' 마진과 '소프트' 마진이다. 

  • 하드 마진: 오분류하는 결과를  고려하지 않고, 가장 적합한 초평면을 산출하는 방법. 

  • 소프트 마진:  모델에 허용 오차를 추가하여 데이터를 '일반화' 하는 방법. 어느정도의 오분류를 허용하고 더욱 '유연'하게 예측할 수 있도록 지원하는 것.

Scikit-Learn 에서 소프트 마진 SVM은 C인자를 통해 조절할 수 있다. C인자를 높게 산정할수록 오분류에 대한 패널티를 더하는 방법이다. 즉, '여유' 가지는 정도를 C인자로 정하는 것이라 할 수 있다. 

%matplotlib inline
import numpy as np
import matplotlib.pyplot as plt
from scipy import stats

# use seaborn plotting defaults
import seaborn as sns; sns.set()
from sklearn.datasets.samples_generator import make_blobs

X, y = make_blobs(n_samples=100, centers=2,
                  random_state=0, cluster_std=1.2)
plt.scatter(X[:, 0], X[:, 1], c=y, s=50, cmap='autumn');

def plot_svc_decision_function(model, ax=None, plot_support=True):
    """Plot the decision function for a 2D SVC"""
    if ax is None:
        ax = plt.gca()
    xlim = ax.get_xlim()
    ylim = ax.get_ylim()
    
    # create grid to evaluate model
    x = np.linspace(xlim[0], xlim[1], 30)
    y = np.linspace(ylim[0], ylim[1], 30)
    Y, X = np.meshgrid(y, x)
    xy = np.vstack([X.ravel(), Y.ravel()]).T
    P = model.decision_function(xy).reshape(X.shape)
    
    # plot decision boundary and margins
    ax.contour(X, Y, P, colors='k',
               levels=[-1, 0, 1], alpha=0.5,
               linestyles=['--', '-', '--'])
    
    # plot support vectors
    if plot_support:
        ax.scatter(model.support_vectors_[:, 0],
                   model.support_vectors_[:, 1],
                   s=300, linewidth=1, facecolors='none');
    ax.set_xlim(xlim)
    ax.set_ylim(ylim)
from sklearn.svm import SVC # "Support vector classifier"

X, y = make_blobs(n_samples=100, centers=2,
                  random_state=0, cluster_std=0.8)

fig, ax = plt.subplots(1, 2, figsize=(16, 6))
fig.subplots_adjust(left=0.0625, right=0.95, wspace=0.1)

for axi, C in zip(ax, [10.0, 0.1]):
    model = SVC(kernel='linear', C=C).fit(X, y)
    axi.scatter(X[:, 0], X[:, 1], c=y, s=50, cmap='autumn')
    plot_svc_decision_function(model, axi)
    axi.scatter(model.support_vectors_[:, 0],
                model.support_vectors_[:, 1],
                s=300, lw=1, facecolors='none');
    axi.set_title('C = {0:.1f}'.format(C), size=14)

 

SVM 마진을 부드럽게 할 것인지는 C인자로 조정.

C가 낮을수록 더욱 후하게 (Soft Margin 스럽게) 분류한다는 것을 알 수 있다. 즉 C인자(Cost)는 어느정도는 비용을 감수하면서 적절한 답을 찾는 방법의 정도를 나타내는 것이다. 

커널 SVM

SVM은 기본적으로 선형 분류를 위한 경계면을 만들어낸다. 하지만 비선형 형태의 분류를 어떻게 나타낼 수 있을까? 

출처: ratgo's blog

 위에서 보이는 것처럼 2차원에서 선형 분리가 되지 않을 수 있지만, 고차원(3차원)에서는 선형 분리가 가능할 수 있다. 이러한 원리를 기반으로 선형 분리가 불가능한 저차원 데이터를 고차원으로 변형하여 선형 분리를 나타낼 수 있다. 때문에 Kernel Trick이라는 Mapping 함수를 사용한다. Kernel Trick은 고차원 Mapping과 고차원에서의 내적 연산을 '한번에 할 수 있는 방법'이다. 이를 통해 여러가지 Kernel 함수를 통해 저차원에서 해결하지 못한 선형 분리를 고차원에서 해결할 수 있다.   

from sklearn.datasets.samples_generator import make_circles
X, y = make_circles(100, factor=.1, noise=.1)

clf = SVC(kernel='linear').fit(X, y)

plt.scatter(X[:, 0], X[:, 1], c=y, s=50, cmap='autumn')
plot_svc_decision_function(clf, plot_support=False);

여기서 '사영' 이라는 방법을 통해 저차원의 데이터를 고차원의 데이터로 변형한다.

# 방사형 기저함수의 function
r = np.exp(-(X ** 2).sum(1))

from mpl_toolkits import mplot3d
from ipywidgets import interact, fixed

ax = plt.subplot(projection='3d')
ax.scatter3D(X[:, 0], X[:, 1], r, c=y, s=50, cmap='autumn')

sklearn 에는 SVM 대표적인 Kernel 함수들이 기본적으로 내재되어 이를 사영 및 분류에 활용한다. 

clf = SVC(kernel='rbf', C=1E6) # 방사형 기저함수
clf.fit(X, y)

plt.scatter(X[:, 0], X[:, 1], c=y, s=50, cmap='autumn')
plot_svc_decision_function(clf)
plt.scatter(clf.support_vectors_[:, 0], clf.support_vectors_[:, 1],
            s=300, lw=1, facecolors='none');

대표적인 Kernel 함수

 

  • Linear (선형 함수)

  • Poly (다항식 함수) -> 엄청오래 걸림 비추

  • RBF (방사기저 함수) -> 가장 성능이 좋아 자주 사용됨.

  • Hyper-Tangent (쌍곡선 탄젠트 함수)

RBF 커널을 사용할 때, 감마 값에 따라 모양이 달라지므로 확인하여 조정한다. 

장점

  • 고차원, 저차원 데이터에서 잘 동작.

  • 모델 훈련 훈 예측 단계 매우 빠름.

  • 비교적 적은 수의 데이터에 의존 -> 적은 메모리 사용. 

단점

  • 모델 복잡도가 최악인 경우 -> 연산량 너무 커짐 

  • 매개변수, 전처리 신경 엄청 많이 씀 <-> 랜덤포레스트, 그라디언트 부스팅 (전처리 거의 필요 없음)

  • 확률적 해석이 불가능. 모델을 설명하기가 부적합 

데이터 세트가 커질수록 비용이 커진다. 100,000개 이상의 데이터셋에서는 속도와 메모리 관점에서 도전적인 과제

반응형
Comments