핸즈온머신러닝&딥러닝

서포트 벡터 머신 1

threegopark 2021. 6. 7. 15:02
728x90

서포트 벡터 머신(support vector machine, SVM)

 

  • 선형, 비선형 분류 (복잡한 분류, 작거나 중간 크기의 데이터 셋에 적합)
  • 회귀
  • 이상치 탐지

 

선형 SVM 분류 (선형적으로 구분되는 클래스)

 

  • 두 개의 클래스를 나누고 있을 뿐만 아니라 제일 가까운 훈련 샘플로부터 가능한 한 멀리 떨어져 있는 경계를 찾는 것 (= 라지 마진 분류)

서포트 벡터 : 오른쪽의 그림처럼 두 클래스를 선형적으로 구분할 수 있는 결정 경계를 설정하였을때 결정 경계를 넘지 않는 각 클래스의 데이터

 

(+ SVM은 특성의 스케일에 민감하다. 사이킷런의 StandardScaler를 사용하여 특성의 스케일을 조정하면 좋은 결정 경계를 찾을 수 있다.)

 

SVM - 소프트 마진 분류

 

  • 하드 마진 분류 : 위의 오른쪽 붓꽃 분류 그래프에서 점선 바깥쪽에 올바르게 분류한 경우
  • 이러한 하드 마진 분류는 선형적으로 구분될 수 있어야 제대로 작동하고, 이상치에 민감

(+ 위와 같이 다른 클래스의 분포 지점에 존재하는 이상치가 발견될 경우, 하드 마진 분류의 적용이 불가능하다.)

 

  • 하드 마진 분류의 한계를 극복한 보다 유연한 모델, 소프트 마진 분류
  • 소프트 마진 분류 : 도로의 폭 (실선과 점선의 너비)을 가능한 한 넓게 유지하는 것과 마진 오류(샘플이 도로 중간이나 반대쪽에 있는 경우) 사이에 적절한 균형을 잡는 SVM분류
  • SVM에는 다양한 하이퍼 파라미터 존재. 특히 하이퍼 파라미터 C를 조절함으로써 도로의 폭을 조절할 수 있음

(+ 하이퍼 파라미터 C의 값을 조절하여 SVM의 과대적합 등을 방지할 수 있다.)

 

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.float)

svm_clf = Pipeline([
    ("scaler", StandardScaler()),
    ("linear_svc", LinearSVC(C=1, loss="hinge"))
])

svm_clf.fit(X,y)

여기서 LinearSVC 클래스 대신에 선형 커널을 사용하는 SVC 클래스로 대체할 수 있다. 만약 SVC 클래스로 대체할 경우 SVC(kernel="linear", C= 1) 이라고 쓴다. 

또 다른 방법으로는 SGDClassifier(loss="hinge", alpha=1/(m*C)) 와 같이 SGDClassifier 모델을 사용하는 것이다. (경사 하강법 적용, 속도는 느리나 아주 큰 데이터셋에 적합하며 온라인 학습으로 분류 문제를 다룰 경우 유용하다.)

 

길이 5.5cm, 너비 1.7cm인 붓꽃 예측

svm_clf.predict([[5.5, 1.7]])

(+ SVM분류기는 로지스틱 회귀와 다르게 클래스에 대한 확률을 제공하지 않는다.)

 

 

 

비선형 SVM 분류

 

선형 SVM 분류기는 효율적이지만 선형적으로 분류할 수 없는 데이터셋의 경우 적용이 불가하다. 이러한 경우 다항 특성과 같은 특성을 하나 더 추가하여 분류하는 비선형 분류 방법을 사용할 수 있다.

하나의 특성만을 가지고 있는 x1 데이터셋은 두 데이터 범주를 구분할 수 없지만, (x1)^2 특성을 추가하여 만들어진 2차원 데이터셋은 두 데이터 범주를 선형적으로 구분할 수 있다.

 

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)

 

 

다항식 커널

 

위의 PolynomialFeatures() 메서드와 같이 다항식 특성을 추가하는 것은 대다수의 모델에서 잘 작동하지만 많이 생성되는 경우 모델이 느려질 수 있다. 뿐만 아니라 낮은 차수의 다항식은 복잡한 데이터셋을 잘 표현하지 못할 수 있다.

 

낮은 차수의 다항식의 설명력을 높이고, (실제로는 차수를 추가하지 않고) 많은 차수를 추가한 다항식과 비슷한 성능을 보이는 것이 바로 커널 트릭 이라는 기법이다.

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)
  • 3차 다항식 커널을 사용해 SVM 분류기 훈련
  • coef0 매개변수(상수항 r) : 모델이 높은 차수와 낮은 차수에 얼마나 영향을 받을지 조절(디폴트 값은 0으로 coef0 매개변수를 조절하여 고차항에게 받을 영향을 줄일 수 있다.)

 

유사도 특성

 

비선형 특성을 다루는 또 다른 기법은 각 샘플이 특정 랜드마크와 얼마나 닮았는지 측정하는 유사도 함수로 계산한 특성을 추가하는 것

예를 들어 앞에서 본 1차원 데이터셋에 두 개의 랜드마크 x1 = -2, x1 = 1을 추가하고, γ=0.3인 가우시안 방사 기저 함수 (RBF)를 유사도 함수로 정의한다.

가우시안 RBF

RBF 함수의 값

  • 랜드마크에서 아주 멀리 떨어진 경우 (안 닮은 경우) : 0
  • 랜드마크와 같은 위치인 경우 (닮은 경우) : 1
  • 즉, RBF는 0~1사이의 값들로 변화하며 종 모양으로 나타남
  • l => 랜드마크 지점, γ는 0보다 커야하며 값이 작을수록 폭이 넓은 종 모양이 된다.

x1 = -1 샘플을 살펴보자. 이 샘플은 첫 번째 랜드마크 (x1 = -2)로부터 1만큼 떨어져 있고 두 번째 랜드마크 (x1 = 1)로부터 2만큼 떨어져 있다. 그러므로 새로 만든 특성은 x2 = exp(-0.3 * 1^2) = 0.74 와 x3 = exp(-0.3 * 2^2) = 0.30 이다. 

이제 x2와 x3에 대한 그래프를 그려보자.

(x1 = -4 인 경우 x2와 x3를 구해보면

x2 = exp(-0.3 * 2^2) = 0.3012

x3 = exp(-0.3 * 5^2) = 0.00055

즉 위의 그래프 (0.3012, 0.00055) 에 그려지는 것이다. 이렇게 가우시안 방사 기저 함수를 통한 변환으로 비선형의 특성을 분류할 수 있게 된다.)

 

그렇다면 랜드마크는 어떻게 선택하는 것인가? 간단한 방법은 데이터셋에 있는 모든 샘플 위치에 랜드마크를 설정하는 것이다. 이렇게 하면 차원이 매우 커지고 따라서 변환된 훈련 세트가 선형적으로 구분될 가능성이 높다. 

하지만 이러한 방식의 단점은 훈련 세트에 있는 n개의 특성을 가진 m개의 샘플이 --> m개의 특성을 가진 m개의 샘플로 변환된다는 것, 즉, 훈련 세트가 매우 클 경우 아주 많은 특성이 만들어질 수 있다는 것이다.

 

 

 

가우시안 RBF 커널

 

가우시안 RBF 또한 특성을 추가하여 기존의 비선형 데이터를 분류하는 것이다. 이 말인즉슨, 추가 특성이 많이 생길 수 있다는 것이고 연산 비용이 폭발적으로 증가할 수 있다는 것이다.

하지만 가우시안 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와 C에 대해서 알아보자.

  • gamma(γ)를 증가시키면 종 모양 그래프가 좁아진다. (각 샘플의 영향 범위가 작아진다.) --> 결정 경계가 조금 더 불규칙해지고 각 샘플을 따라 구불구불해진다. (규제의 역할을 하는 감마)
  • 위 RBF 함수의 유사도 특성을 추가하는 그래프를 살펴보자. 감마의 값을 0.3으로 지정했을 때였다.

 

이외의 커널

  • 문자열 커널 (텍스트, DNA 서열 분류)
  • 문자열 서브시퀀스 커널
  • 레벤슈타인 거리 기반 커널