Main Content

이 페이지의 최신 내용은 아직 번역되지 않았습니다. 최신 내용은 영문으로 볼 수 있습니다.

이진 분류를 위한 서포트 벡터 머신

서포트 벡터 머신 이해하기

분리 가능한 데이터

데이터가 정확히 두 개의 클래스를 가지는 경우 서포트 벡터 머신(SVM)을 사용할 수 있습니다. SVM은 두 개의 클래스를 구분하는 최적의 초평면을 찾음으로써 데이터를 분류합니다. SVM에서 최적의 초평면이란 두 클래스 간에 최대의 마진을 갖는 초평면을 의미합니다. 마진은 내부 데이터 점이 없는 초평면에 평행인 슬래브(Slab)의 최대 너비를 의미합니다.

서포트 벡터는 분리 초평면에 가장 가까운 데이터 점입니다. 이러한 점은 슬래브의 경계상에 존재합니다. 다음 그림은 이러한 정의를 시각적으로 보여줍니다. 여기서 +는 유형 1의 데이터 점을 나타내며 -는 유형 -1의 데이터 점을 나타냅니다.

수학적 정식화: 원문제(Primal).  아래 논의는 Hastie, Tibshirani, Friedman [1]과 Christianini, Shawe-Taylor [2]의 설명을 따릅니다.

훈련 데이터는 점 집합(벡터) xj와 점 집합의 범주 yj입니다. 일부 차원 d의 경우 xj ∊ Rd이고 yj = ±1입니다. 초평면의 방정식은 다음과 같습니다.

f(x)=xβ+b=0

여기서 β ∊ Rd이고 b는 실수입니다.

다음 문제는 가장 적합한 분리 초평면(즉, 결정 경계)을 정의합니다. 모든 데이터 점 (xj,yj)에 대해 다음이 성립하는 ||β||를 최소화하는 β와 b를 구합니다.

yjf(xj)1.

서포트 벡터는 경계상에 존재하며 yjf(xj)=1.을 충족하는 xj입니다.

수학적 편의를 위해 이 문제는 일반적으로 β를 최소화하는 문제와 동일한 문제로 지정됩니다. 이는 2차 계획법 문제입니다. 최적해 (β^,b^)를 통해 다음과 같이 벡터 z의 분류를 수행할 수 있습니다.

class(z)=sign(zβ^+b^)=sign(f^(z)).

f^(z)분류 점수이고 z가 결정 경계로부터 떨어진 거리를 나타냅니다.

수학적 정식화: 쌍대 문제(Dual).  쌍대 2차 계획법 문제를 푸는 것이 계산량 측면에서 더 간단합니다. 쌍대 문제를 얻으려면 양의 라그랑주 승수 αj에 각 제약 조건을 곱한 값을 취한 후 목적 함수에서 뺍니다.

LP=12ββjαj(yj(xjβ+b)1),

여기서는 β와 b에 대한 LP의 정상점을 찾습니다. LP의 기울기를 0으로 설정하면 다음을 얻게 됩니다.

β=jαjyjxj0=jαjyj.(1)

LP에 대입하면 쌍대 문제 LD를 얻게 됩니다.

LD=jαj12jkαjαkyjykxjxk,

여기서는 αj ≥ 0에 대해 최대화합니다. 일반적으로, 많은 αj는 최대 0입니다. 쌍대 문제의 해에서 0이 아닌 αj수식 1에 표시된 대로 초평면을 정의하고, αjyjxj의 합으로 β를 반환합니다. 0이 아닌 αj에 대응하는 데이터 점 xj서포트 벡터입니다.

0이 아닌 αj에 대한 LD의 도함수의 최적값은 0입니다. 이로부터 다음을 얻을 수 있습니다.

yjf(xj)1=0.

특히 이 경우, 0이 아닌 αj를 갖는 j를 이용하여 해에서 b의 값을 구할 수 있습니다.

쌍대 문제는 표준 2차 계획법 문제입니다. 일례로 Optimization Toolbox™의 quadprog (Optimization Toolbox) 솔버는 이러한 유형의 문제에 대한 해를 구합니다.

분리가 불가능한 데이터

데이터가 분리 초평면에 잘 맞지 않을 수 있습니다. 이 경우, SVM은 소프트 마진(Soft Margin)을 사용할 수 있습니다. 이는 모든 데이터 점은 아니지만 많은 데이터 점을 분리하는 초평면을 의미합니다.

소프트 마진에 대한 표준적인 정식화로는 다음 두 가지가 있습니다. 두 공식 모두 여유 변수 ξj와 벌점 모수 C를 가집니다.

  • L1-노름(Norm) 문제는 다음과 같습니다.

    minβ,b,ξ(12ββ+Cjξj)

    조건

    yjf(xj)1ξjξj0.

    ξj를 제곱 대신 여유 변수로 사용하면 L1-노름인 것입니다. fitcsvm의 세 가지 솔버 옵션 SMO, ISDA, L1QP는 L1-노름 문제를 최소화합니다.

  • L2-노름 문제는 다음과 같습니다.

    minβ,b,ξ(12ββ+Cjξj2)

    동일한 제약 조건이 적용됩니다.

이러한 정식화에서는 C를 늘리면 여유 변수 ξj에 더 많은 가중치가 적용된다는 것을 알 수 있습니다. 즉, 최적화가 클래스 간에 더 엄격한 분리를 수행하려 한다는 것을 알 수 있습니다. 이와 마찬가지로, C의 크기가 작아지면 오분류에 대한 중요성은 낮아집니다.

수학적 정식화: 쌍대 문제(Dual).  더 손쉬운 계산 방법을 알아보기 위해 이 소프트 마진 정식화에 대한 L1 쌍대 문제가 있다고 가정해 보겠습니다. 라그랑주 승수 μj를 사용하여 L1-노름(Norm) 문제에 대한 최소화할 함수는 다음과 같습니다.

LP=12ββ+Cjξjjαj(yif(xj)(1ξj))jμjξj,

여기서는 β, b, 양의 ξj에 대한 LP의 정상점을 찾습니다. LP의 기울기를 0으로 설정하면 다음을 얻게 됩니다.

β=jαjyjxjjαjyj=0αj=Cμjαj,μj,ξj0.

이러한 방정식으로부터 다음 쌍대 문제 식을 바로 얻을 수 있습니다.

maxαjαj12jkαjαkyjykxjxk

이때 제약 조건은 다음과 같습니다.

jyjαj=00αjC.

마지막 부등식 0 ≤ αj ≤ C는 C가 상자 제약 조건인 이유를 보여줍니다. C는 라그랑주 승수 αj의 허용 값을 “상자”의 내부, 즉 경계 영역 내로 유지합니다.

b에 대한 기울기 방정식은 서포트 벡터에 대응되는 0이 아닌 αj의 세트로 해 b를 제공합니다.

유사한 방식으로 L2-노름 문제의 쌍대 문제를 작성하고 이에 대한 해를 구할 수 있습니다. 자세한 내용은 Christianini, Shawe-Taylor [2](6장)을 참조하십시오.

fitcsvm 구현.  두 쌍대 소프트 마진 문제 모두 2차 계획법 문제입니다. 내부적으로, fitcsvm은 문제에 대한 해를 구하는 데 사용할 수 있는 여러 다양한 알고리즘을 가집니다.

  • 단일 클래스나 이진 분류의 경우, 데이터에서 예상되는 이상값에 대한 비율(OutlierFraction 참조)을 설정하지 않으면 디폴트 솔버로 순차적 최소규모 최적화(SMO)가 사용됩니다. SMO는 일련의 2점 최소화를 통해 1-노름 문제를 최소화합니다. 최적화를 수행하는 동안 SMO는 선형 제약 조건 iαiyi=0,을 따르고 모델에 편향 항을 명시적으로 포함시킵니다. SMO는 비교적 빠릅니다. SMO에 대한 자세한 내용은 [3] 항목을 참조하십시오.

  • 이진 분류의 경우, 데이터에서 예상되는 이상값에 대한 비율을 설정하면 디폴트 솔버로 반복 단일 데이터 알고리즘(ISDA)이 사용됩니다. SMO와 마찬가지로, ISDA는 1-노름 문제의 해를 구합니다. SMO와 달리, ISDA는 일련의 1점 최소화를 통해 최소화하며, 선형 제약 조건을 따르지 않고, 모델에 편향 항을 명시적으로 포함시키지도 않습니다. ISDA에 대한 자세한 내용은 [4] 항목을 참조하십시오.

  • 단일 클래스 또는 이진 분류의 경우 Optimization Toolbox 라이선스를 가지고 있으면 quadprog (Optimization Toolbox)를 사용하여 1-노름 문제의 해를 구해 볼 수 있습니다. quadprog는 메모리를 많이 사용하지만, 높은 정밀도로 2차 계획법의 해를 구합니다. 자세한 내용은 2차 계획법 정의 (Optimization Toolbox) 항목을 참조하십시오.

커널을 사용한 비선형 변환

일부 이진 분류 문제의 경우, 명확한 분류 기준이 되는 단순한 초평면이 존재하지 않습니다. 이러한 문제를 위해 SVM 분리 초평면의 단순성을 거의 유지하는 수학적 접근 방법의 변형이 존재합니다.

이 접근 방법은 재생 커널 이론에서 나온 다음과 같은 결과를 사용합니다.

  • 다음 속성을 갖는 함수 G(x1,x2) 클래스가 있습니다. 선형 공간 S와, 다음 조건에 따라 x를 S로 매핑하는 함수 φ가 있습니다.

    G(x1,x2) = <φ(x1),φ(x2)>.

    내적은 공간 S에서 수행됩니다.

  • 이 함수 클래스는 다음을 포함합니다.

    • 다항식: 양의 정수 p에 대해 다음과 같습니다.

      G(x1,x2) = (1 + x1′x2)p.

    • 방사형 기저 함수(가우스):

      G(x1,x2) = exp(–∥x1–x2)∥2).

    • 다층 퍼셉트론 또는 시그모이드(신경망): 양수 p1과 음수 p2에 대해 다음과 같습니다.

      G(x1,x2) = tanh(p1x1′x2 + p2).

      참고

커널을 사용하는 수학적 접근 방법은 초평면의 계산 방법에 따라 달리집니다. 초평면 분류의 모든 계산은 내적만 사용합니다. 따라서, 비선형 커널에서 동일한 계산과 해 알고리즘을 사용하여 비선형 분류기를 얻을 수 있습니다. 결과로 생성되는 분류기는 특정 공간 S에 있는 초곡면이지만 공간 S를 식별하거나 검토할 필요는 없습니다.

서포트 벡터 머신 사용하기

지도 학습 모델과 마찬가지로, 먼저 서포트 벡터 머신을 훈련시킨 후 분류기를 교차 검증해야 합니다. 훈련된 머신을 사용하여 새 데이터를 분류(예측)합니다. 또한, 만족스러운 예측 정확도를 얻기 위해 다양한 SVM 커널 함수를 사용할 수 있으며, 이 경우 커널 함수의 모수를 조정해야 합니다.

SVM 분류기 훈련시키기

fitcsvm을 사용하여 SVM 분류기를 훈련시키고 필요한 경우 교차 검증합니다. 가장 일반적인 구문은 다음과 같습니다.

SVMModel = fitcsvm(X,Y,'KernelFunction','rbf',...
    'Standardize',true,'ClassNames',{'negClass','posClass'});

입력값은 다음과 같습니다.

  • X — 예측 변수 데이터로 구성된 행렬입니다(여기서 각 행은 하나의 관측값이고, 각 열은 하나의 예측 변수임).

  • Y — 클래스 레이블로 구성된 배열로 각 행이 X의 행 값에 대응합니다. Y는 categorical형 배열, 문자형 배열, string형 배열, 논리형 벡터 또는 숫자형 벡터, 또는 문자형 벡터로 구성된 셀형 배열일 수 있습니다.

  • KernelFunction — 2-클래스 학습의 경우 디폴트 값은 'linear'입니다. 이는 데이터를 초평면으로 분리합니다. 값 'gaussian'(또는 'rbf')은 단일 클래스 학습인 경우 디폴트 값이며, 가우스(또는 방사형 기저 함수) 커널을 사용하도록 지정합니다. SVM 분류기를 성공적으로 훈련시키기 위한 중요한 단계는 적합한 커널 함수를 선택하는 것입니다.

  • Standardize — 분류기를 훈련시키기 전에 소프트웨어가 예측 변수를 표준화해야 할지 여부를 나타내는 플래그입니다.

  • ClassNames — 음성 클래스와 양성 클래스 간을 구분하거나 데이터에 포함시킬 클래스를 지정합니다. 음성 클래스는 첫 번째 요소(또는 문자형 배열의 행), 즉, 'negClass'이고 양성 클래스는 두 번째 요소(또는 문자형 배열의 행), 즉, 'posClass'입니다. ClassNamesY와 같은 데이터형이어야 합니다. 특히, 다른 분류기의 성능을 비교하는 경우 클래스 이름을 지정하는 것이 좋습니다.

결과로 생성되는 훈련된 모델(SVMModel)은 SVM 알고리즘을 통해 최적화된 모수를 포함합니다. 이를 통해 새 데이터를 분류할 수 있습니다.

훈련을 제어하는 데 사용할 수 있는 추가 이름-값 쌍은 fitcsvm 함수 도움말 페이지를 참조하십시오.

SVM 분류기로 새 데이터 분류하기

predict를 사용하여 새 데이터를 분류합니다. 훈련된 SVM 분류기(SVMModel)를 사용하여 새 데이터를 분류하는 구문은 다음과 같습니다.

[label,score] = predict(SVMModel,newX);

결과로 생성되는 벡터 labelX의 각 행에 대한 분류를 나타냅니다. score는 소프트 점수로 구성된 nx2 행렬입니다. 각 행은 새 관측값 X의 행에 대응됩니다. 첫 번째 열에는 음성 클래스로 분류되는 관측값의 점수가 포함되고, 두 번째 열에는 양성 클래스로 분류되는 관측값의 점수가 포함됩니다.

점수가 아니라 사후 확률을 추정하려면, 훈련된 SVM 분류기(SVMModel)를 먼저 fitPosterior에 전달해야 합니다. 이 함수는 점수-사후 확률 변환 함수를 점수에 피팅합니다. 구문은 다음과 같습니다.

ScoreSVMModel = fitPosterior(SVMModel,X,Y);

분류기 ScoreSVMModel의 속성 ScoreTransform은 최적의 변환 함수를 포함합니다. ScoreSVMModelpredict로 전달합니다. 점수를 반환하는 대신, 출력 인수 score는 음성 클래스(score의 1열) 또는 양성 클래스(score의 2열)로 분류되는 관측값의 사후 확률을 포함합니다.

SVM 분류기 조정하기

fitcsvm'OptimizeHyperparameters' 이름-값 쌍의 인수를 사용하여 교차 검증 손실을 최소화하는 모수 값을 구할 수 있습니다. 적합한 모수는 'BoxConstraint', 'KernelFunction', 'KernelScale', 'PolynomialOrder', 'Standardize'입니다. 예제는 베이즈 최적화를 사용하여 SVM 분류기 피팅 최적화하기 항목을 참조하십시오. 또는, Optimize a Cross-Validated SVM Classifier Using bayesopt에 나와 있는 것처럼 bayesopt 함수를 사용할 수도 있습니다. bayesopt 함수를 사용하면 더욱 유연한 사용자 지정 최적화를 구현할 수 있습니다. bayesopt 함수를 사용할 경우, fitcsvm 함수를 사용할 때는 최적화할 수 없는 모수를 포함하여 모든 모수를 최적화할 수 있습니다.

다음 방식에 따라 분류기의 모수를 수동으로 조정해 볼 수도 있습니다.

  1. 데이터를 fitcsvm으로 전달하고 이름-값 쌍의 인수 'KernelScale','auto'를 설정합니다. 훈련된 SVM 모델을 SVMModel이라고 한다고 가정합니다. 소프트웨어는 발견적(heuristic) 절차에 따라 커널 스케일을 선택합니다. 발견적 절차는 부표본추출을 사용합니다. 따라서 결과를 재현하려면 분류기를 훈련시키기 전에 rng를 사용하여 난수 시드값을 설정하십시오.

  2. 분류기를 crossval로 전달하여 교차 검증합니다. 기본적으로, 소프트웨어는 10겹 교차 검증을 수행합니다.

  3. 교차 검증된 SVM 모델을 kfoldLoss로 전달하여 분류 오차를 추정하고 유지합니다.

  4. SVM 분류기를 유지하되, 'KernelScale''BoxConstraint' 이름-값 쌍의 인수를 조정합니다.

    • BoxConstraint — 한 가지 전략은 상자 제약 조건 모수의 등비 수열을 사용해 보는 것입니다. 예를 들어, 인자 10으로 1e-5부터 1e5까지 11개 값을 취합니다. BoxConstraint를 늘리면 서포트 벡터의 개수가 줄어들 수 있지만, 훈련 시간이 늘어날 수도 있습니다.

    • KernelScale — 한 가지 전략은 원래 커널 스케일로 스케일링된 RBF 시그마 모수의 등비 수열을 사용해 보는 것입니다. 다음과 같은 방법으로 이 작업을 수행합니다.

      1. 점 표기법을 사용하여 원래 커널 스케일 즉, ks를 가져옵니다(ks = SVMModel.KernelParameters.Scale).

      2. 원래 커널 스케일에 대한 새 스케일링 인자를 사용합니다. 예를 들어, 인자 10을 사용하여 ks1e-5에서 1e5까지 11개 값을 곱합니다.

가장 낮은 분류 오차를 생성하는 모델을 선택합니다. 정확도를 더 향상시키기 위해 모수를 추가로 미세 조정해야 할 수 있습니다. 초기 모수로 시작하고, 이번에는 인자 1.2를 사용하여 또 다른 교차 검증 단계를 수행합니다.

가우스 커널을 사용하여 SVM 분류기를 훈련시키기

이 예제에서는 가우스 커널 함수를 사용하여 비선형 분류기를 생성하는 방법을 보여줍니다. 먼저, 2차원 단위 원판 내부의 점들로 하나의 클래스를 구성하고 반지름 1에서 반지름 2까지의 원환에 포함된 점들로 또 하나의 클래스를 구성합니다. 그런 다음, 가우스 방사형 기저 함수 커널을 사용하여 데이터를 기준으로 분류기를 생성합니다. 모델이 대칭 원형이기 때문에 디폴트 선형 분류기는 이 문제에 확실히 부적합합니다. 상자 제약 조건 모수를 Inf로 설정하여 오분류되는 훈련 점이 없는 엄격한 분류를 합니다. 다른 커널 함수는 엄격한 분류를 제공하지 못할 수 있으므로 이러한 엄격한 상자 제약 조건에서 동작하지 않을 수 있습니다. rbf 분류기가 클래스를 분리할 수 있는 경우에도 결과가 과잉훈련될 수 있습니다.

반지름이 1인 단위 원판 내부에 균등 분포된 100개의 점을 생성합니다. 반지름 r을 균등 확률 변수의 제곱근으로 생성하고, 각도 t를 (0, 2π) 범위에서 균등하게 생성하여 데이터 점을 (r cos(t), r sin(t))에 배치하면 됩니다.

rng(1); % For reproducibility
r = sqrt(rand(100,1)); % Radius
t = 2*pi*rand(100,1);  % Angle
data1 = [r.*cos(t), r.*sin(t)]; % Points

원환에 균등분포된 100개 점을 생성합니다. 반지름이 제곱근에 비례하지만, 이번에는 1부터 4 사이 균등분포된 제곱근에 비례합니다.

r2 = sqrt(3*rand(100,1)+1); % Radius
t2 = 2*pi*rand(100,1);      % Angle
data2 = [r2.*cos(t2), r2.*sin(t2)]; % points

점을 플로팅하고, 비교를 위해 반지름 1과 반지름 2를 사용한 원을 플로팅합니다.

figure;
plot(data1(:,1),data1(:,2),'r.','MarkerSize',15)
hold on
plot(data2(:,1),data2(:,2),'b.','MarkerSize',15)
ezpolar(@(x)1);ezpolar(@(x)2);
axis equal
hold off

한 행렬에 두 데이터를 모두 할당하고, 분류 벡터를 생성합니다.

data3 = [data1;data2];
theclass = ones(200,1);
theclass(1:100) = -1;

KernelFunction'rbf'로 설정하고 BoxConstraintInf로 설정하여 SVM 분류기를 훈련시킵니다. 결정 경계를 플로팅하고 서포트 벡터에 플래그를 지정합니다.

%Train the SVM Classifier
cl = fitcsvm(data3,theclass,'KernelFunction','rbf',...
    'BoxConstraint',Inf,'ClassNames',[-1,1]);

% Predict scores over the grid
d = 0.02;
[x1Grid,x2Grid] = meshgrid(min(data3(:,1)):d:max(data3(:,1)),...
    min(data3(:,2)):d:max(data3(:,2)));
xGrid = [x1Grid(:),x2Grid(:)];
[~,scores] = predict(cl,xGrid);

% Plot the data and the decision boundary
figure;
h(1:2) = gscatter(data3(:,1),data3(:,2),theclass,'rb','.');
hold on
ezpolar(@(x)1);
h(3) = plot(data3(cl.IsSupportVector,1),data3(cl.IsSupportVector,2),'ko');
contour(x1Grid,x2Grid,reshape(scores(:,2),size(x1Grid)),[0 0],'k');
legend(h,{'-1','+1','Support Vectors'});
axis equal
hold off

fitcsvm은 반지름이 1인 원에 가까운 분류기를 생성합니다. 훈련 데이터가 무작위 데이터라 차이가 발생하고 있습니다.

디폴트 모수로 훈련시키는 경우 더 근접한 원형 분류 경계가 생성되지만, 이는 일부 훈련 데이터를 오분류합니다. 또한, BoxConstraint의 디폴트 값이 1이어서 서포트 벡터가 더 많이 생성됩니다.

cl2 = fitcsvm(data3,theclass,'KernelFunction','rbf');
[~,scores2] = predict(cl2,xGrid);

figure;
h(1:2) = gscatter(data3(:,1),data3(:,2),theclass,'rb','.');
hold on
ezpolar(@(x)1);
h(3) = plot(data3(cl2.IsSupportVector,1),data3(cl2.IsSupportVector,2),'ko');
contour(x1Grid,x2Grid,reshape(scores2(:,2),size(x1Grid)),[0 0],'k');
legend(h,{'-1','+1','Support Vectors'});
axis equal
hold off

사용자 지정 커널을 사용하여 SVM 분류기 훈련시키기

이 예제에서는 시그모이드 커널과 같은 사용자 지정 커널 함수를 사용하여 SVM 분류기를 훈련시키고 사용자 지정 커널 함수 모수를 조정하는 방법을 보여줍니다.

단위원 내부 임의의 점으로 구성된 집합을 생성합니다. 제1사분면과 제3사분면의 점은 양성 클래스에 속하는 것으로 레이블을 지정하고 제2사분면과 제4사분면의 점은 음성 클래스에 속하는 것으로 레이블을 지정합니다.

rng(1);  % For reproducibility
n = 100; % Number of points per quadrant

r1 = sqrt(rand(2*n,1));                     % Random radii
t1 = [pi/2*rand(n,1); (pi/2*rand(n,1)+pi)]; % Random angles for Q1 and Q3
X1 = [r1.*cos(t1) r1.*sin(t1)];             % Polar-to-Cartesian conversion

r2 = sqrt(rand(2*n,1));
t2 = [pi/2*rand(n,1)+pi/2; (pi/2*rand(n,1)-pi/2)]; % Random angles for Q2 and Q4
X2 = [r2.*cos(t2) r2.*sin(t2)];

X = [X1; X2];        % Predictors
Y = ones(4*n,1);
Y(2*n + 1:end) = -1; % Labels

데이터를 플로팅합니다.

figure;
gscatter(X(:,1),X(:,2),Y);
title('Scatter Diagram of Simulated Data')

특징 공간의 두 행렬을 입력값으로 받아 시그모이드 커널을 사용하여 이 입력값을 그람 행렬(Gram matrix)로 변환하는 함수를 작성합니다.

function G = mysigmoid(U,V)
% Sigmoid kernel function with slope gamma and intercept c
gamma = 1;
c = -1;
G = tanh(gamma*U*V' + c);
end

이 코드를 MATLAB® 경로에 mysigmoid라는 파일로 저장합니다.

시그모이드 커널 함수를 사용하여 SVM 분류기를 훈련시킵니다. 데이터를 표준화하는 것이 좋습니다.

Mdl1 = fitcsvm(X,Y,'KernelFunction','mysigmoid','Standardize',true);

Mdl1은 추정된 모수를 포함하는 ClassificationSVM 분류기입니다.

데이터를 플로팅하고 서포트 벡터와 결정 경계를 식별합니다.

    % Compute the scores over a grid
d = 0.02; % Step size of the grid
[x1Grid,x2Grid] = meshgrid(min(X(:,1)):d:max(X(:,1)),...
    min(X(:,2)):d:max(X(:,2)));
xGrid = [x1Grid(:),x2Grid(:)];        % The grid
[~,scores1] = predict(Mdl1,xGrid); % The scores

figure;
h(1:2) = gscatter(X(:,1),X(:,2),Y);
hold on
h(3) = plot(X(Mdl1.IsSupportVector,1),...
    X(Mdl1.IsSupportVector,2),'ko','MarkerSize',10);
    % Support vectors
contour(x1Grid,x2Grid,reshape(scores1(:,2),size(x1Grid)),[0 0],'k');
    % Decision boundary
title('Scatter Diagram with the Decision Boundary')
legend({'-1','1','Support Vectors'},'Location','Best');
hold off

분류의 정확도를 향상시키기 위하여, 커널 모수를 조정할 수 있습니다. 이렇게 하면 표본내 오분류율을 줄일 수도 있지만, 우선 표본외 오분류율을 확인해야 합니다.

10겹 교차 검증을 사용하여 표본외 오분류율을 확인합니다.

CVMdl1 = crossval(Mdl1);
misclass1 = kfoldLoss(CVMdl1);
misclass1
misclass1 =

    0.1350

표본외 오분류율은 13.5%입니다.

다른 시그모이드 함수를 작성하되, gamma = 0.5;를 설정합니다.

function G = mysigmoid2(U,V)
% Sigmoid kernel function with slope gamma and intercept c
gamma = 0.5;
c = -1;
G = tanh(gamma*U*V' + c);
end

이 코드를 MATLAB® 경로에 mysigmoid2라는 파일로 저장합니다.

조정한 시그모이드 커널을 사용하여 또 다른 SVM 분류기를 훈련시킵니다. 데이터와 결정 영역을 플로팅하고, 표본외 오분류율을 확인합니다.

Mdl2 = fitcsvm(X,Y,'KernelFunction','mysigmoid2','Standardize',true);
[~,scores2] = predict(Mdl2,xGrid);

figure;
h(1:2) = gscatter(X(:,1),X(:,2),Y);
hold on
h(3) = plot(X(Mdl2.IsSupportVector,1),...
    X(Mdl2.IsSupportVector,2),'ko','MarkerSize',10);
title('Scatter Diagram with the Decision Boundary')
contour(x1Grid,x2Grid,reshape(scores2(:,2),size(x1Grid)),[0 0],'k');
legend({'-1','1','Support Vectors'},'Location','Best');
hold off

CVMdl2 = crossval(Mdl2);
misclass2 = kfoldLoss(CVMdl2);
misclass2
misclass2 =

    0.0450

시그모이드 기울기를 조정한 결과, 더 정확한 표본내 피팅을 이룬 것으로 보이며 교차 검증률 또한 66% 이상 줄어듭니다.

베이즈 최적화를 사용하여 SVM 분류기 피팅 최적화하기

이 예제에서는 fitcsvm 함수와 OptimizeHyperparameters 이름-값 쌍을 사용하여 SVM 분류를 최적화하는 방법을 보여줍니다. 이 분류는 가우스 혼합 모델의 점 위치를 사용한 것입니다. The Elements of Statistical Learning, Hastie, Tibshirani, and Friedman (2009)의 17페이지에 이 모델에 대한 설명이 나와 있습니다. 이 모델은 평균 (1,0)과 단위 분산의 2차원 독립 정규분포로 분산되고 "녹색" 클래스에 속하는 10개 기준점을 생성하는 것으로 시작합니다. 또한, 평균 (0,1)과 단위 분산의 2차원 독립 정규분포로 분산되고 "빨간색" 클래스에 속하는 10개 기준점도 생성합니다. 다음과 같이 각 클래스(녹색과 빨간색)에 대해 임의의 100개 점을 생성합니다.

  1. 해당 색상별로 임의로 균일하게 분포하는 기준점 m을 선택합니다.

  2. 평균이 m이고 분산이 I/5인(여기서 I는 2x2 단위 행렬임) 2차원 정규분포를 띠는 독립적인 임의의 점을 생성합니다. 이 예제에서는 분산 I/50을 사용하여 최적화의 이점을 더 확실하게 보여줍니다.

점과 분류기 생성하기

각 클래스에 대해 10개 기준점을 생성합니다.

rng default % For reproducibility
grnpop = mvnrnd([1,0],eye(2),10);
redpop = mvnrnd([0,1],eye(2),10);

기준점을 표시합니다.

plot(grnpop(:,1),grnpop(:,2),'go')
hold on
plot(redpop(:,1),redpop(:,2),'ro')
hold off

일부 빨간색 기준점이 녹색 기준점에 가깝기 때문에 위치만 기준으로 하여 데이터 점을 분류하는 것이 어려울 수 있습니다.

각 클래스에 대해 100개 데이터 점을 생성합니다.

redpts = zeros(100,2);grnpts = redpts;
for i = 1:100
    grnpts(i,:) = mvnrnd(grnpop(randi(10),:),eye(2)*0.02);
    redpts(i,:) = mvnrnd(redpop(randi(10),:),eye(2)*0.02);
end

데이터 점을 표시합니다.

figure
plot(grnpts(:,1),grnpts(:,2),'go')
hold on
plot(redpts(:,1),redpts(:,2),'ro')
hold off

분류를 위한 데이터 준비하기

데이터를 한 행렬에 저장하고, 각 점의 클래스에 레이블을 지정하는 벡터 grp를 생성합니다.

cdata = [grnpts;redpts];
grp = ones(200,1);
% Green label 1, red label -1
grp(101:200) = -1;

교차 검증 준비하기

교차 검증에 사용할 분할을 설정합니다. 이 단계에서는 최적화가 각 단계에 사용하는 훈련 세트와 검정 세트를 정합니다.

c = cvpartition(200,'KFold',10);

피팅 최적화하기

양호한 피팅, 즉 교차 검증 손실이 적은 피팅을 구하려면 베이즈 최적화를 사용하도록 옵션을 설정하십시오. 모든 최적화에 동일한 교차 검증 분할 c를 사용합니다.

재현이 가능하도록 'expected-improvement-plus' 수집 함수를 사용합니다.

opts = struct('Optimizer','bayesopt','ShowPlots',true,'CVPartition',c,...
    'AcquisitionFunctionName','expected-improvement-plus');
svmmod = fitcsvm(cdata,grp,'KernelFunction','rbf',...
    'OptimizeHyperparameters','auto','HyperparameterOptimizationOptions',opts)
|=====================================================================================================|
| Iter | Eval   | Objective   | Objective   | BestSoFar   | BestSoFar   | BoxConstraint|  KernelScale |
|      | result |             | runtime     | (observed)  | (estim.)    |              |              |
|=====================================================================================================|
|    1 | Best   |       0.345 |     0.51679 |       0.345 |       0.345 |      0.00474 |       306.44 |
|    2 | Best   |       0.115 |     0.18443 |       0.115 |     0.12678 |       430.31 |       1.4864 |
|    3 | Accept |        0.52 |     0.13467 |       0.115 |      0.1152 |     0.028415 |     0.014369 |
|    4 | Accept |        0.61 |     0.15058 |       0.115 |     0.11504 |       133.94 |    0.0031427 |
|    5 | Accept |        0.34 |     0.14258 |       0.115 |     0.11504 |     0.010993 |       5.7742 |
|    6 | Best   |       0.085 |     0.11448 |       0.085 |    0.085039 |       885.63 |      0.68403 |
|    7 | Accept |       0.105 |    0.093757 |       0.085 |    0.085428 |       0.3057 |      0.58118 |
|    8 | Accept |        0.21 |    0.097925 |       0.085 |     0.09566 |      0.16044 |      0.91824 |
|    9 | Accept |       0.085 |     0.12164 |       0.085 |     0.08725 |       972.19 |      0.46259 |
|   10 | Accept |         0.1 |     0.10145 |       0.085 |    0.090952 |       990.29 |        0.491 |
|   11 | Best   |        0.08 |     0.12452 |        0.08 |    0.079362 |       2.5195 |        0.291 |
|   12 | Accept |        0.09 |    0.098778 |        0.08 |     0.08402 |       14.338 |      0.44386 |
|   13 | Accept |         0.1 |    0.098501 |        0.08 |     0.08508 |    0.0022577 |      0.23803 |
|   14 | Accept |        0.11 |    0.093424 |        0.08 |    0.087378 |       0.2115 |      0.32109 |
|   15 | Best   |        0.07 |     0.11532 |        0.07 |    0.081507 |        910.2 |      0.25218 |
|   16 | Best   |       0.065 |     0.11326 |       0.065 |    0.072457 |       953.22 |      0.26253 |
|   17 | Accept |       0.075 |     0.12262 |       0.065 |    0.072554 |       998.74 |      0.23087 |
|   18 | Accept |       0.295 |     0.11651 |       0.065 |    0.072647 |       996.18 |       44.626 |
|   19 | Accept |        0.07 |     0.12281 |       0.065 |     0.06946 |       985.37 |      0.27389 |
|   20 | Accept |       0.165 |    0.096372 |       0.065 |    0.071622 |     0.065103 |      0.13679 |
|=====================================================================================================|
| Iter | Eval   | Objective   | Objective   | BestSoFar   | BestSoFar   | BoxConstraint|  KernelScale |
|      | result |             | runtime     | (observed)  | (estim.)    |              |              |
|=====================================================================================================|
|   21 | Accept |       0.345 |    0.094329 |       0.065 |    0.071764 |        971.7 |       999.01 |
|   22 | Accept |        0.61 |     0.10339 |       0.065 |    0.071967 |    0.0010168 |    0.0010005 |
|   23 | Accept |       0.345 |     0.09488 |       0.065 |    0.071959 |    0.0010674 |       999.18 |
|   24 | Accept |        0.35 |    0.096074 |       0.065 |    0.071863 |    0.0010003 |       40.628 |
|   25 | Accept |        0.24 |     0.16217 |       0.065 |    0.072124 |       996.55 |       10.423 |
|   26 | Accept |        0.61 |     0.11167 |       0.065 |    0.072068 |       958.64 |    0.0010026 |
|   27 | Accept |        0.47 |     0.10976 |       0.065 |     0.07218 |       993.69 |     0.029723 |
|   28 | Accept |         0.3 |    0.091906 |       0.065 |    0.072291 |       993.15 |       170.01 |
|   29 | Accept |        0.16 |     0.25883 |       0.065 |    0.072104 |       992.81 |       3.8594 |
|   30 | Accept |       0.365 |     0.10465 |       0.065 |    0.072112 |    0.0010017 |     0.044287 |

__________________________________________________________
Optimization completed.
MaxObjectiveEvaluations of 30 reached.
Total function evaluations: 30
Total elapsed time: 30.3878 seconds.
Total objective function evaluation time: 3.9881

Best observed feasible point:
    BoxConstraint    KernelScale
    _____________    ___________

       953.22          0.26253  

Observed objective function value = 0.065
Estimated objective function value = 0.073726
Function evaluation time = 0.11326

Best estimated feasible point (according to models):
    BoxConstraint    KernelScale
    _____________    ___________

       985.37          0.27389  

Estimated objective function value = 0.072112
Estimated function evaluation time = 0.11822
svmmod = 
  ClassificationSVM
                         ResponseName: 'Y'
                CategoricalPredictors: []
                           ClassNames: [-1 1]
                       ScoreTransform: 'none'
                      NumObservations: 200
    HyperparameterOptimizationResults: [1×1 BayesianOptimization]
                                Alpha: [77×1 double]
                                 Bias: -0.2352
                     KernelParameters: [1×1 struct]
                       BoxConstraints: [200×1 double]
                      ConvergenceInfo: [1×1 struct]
                      IsSupportVector: [200×1 logical]
                               Solver: 'SMO'


  Properties, Methods

최적화된 모델의 손실을 구합니다.

lossnew = kfoldLoss(fitcsvm(cdata,grp,'CVPartition',c,'KernelFunction','rbf',...
    'BoxConstraint',svmmod.HyperparameterOptimizationResults.XAtMinObjective.BoxConstraint,...
    'KernelScale',svmmod.HyperparameterOptimizationResults.XAtMinObjective.KernelScale))
lossnew = 0.0650

이 손실은 최적화 결과에서 "관측된 목적 함수 값" 아래에 보고되는 손실과 동일합니다.

최적화된 분류기를 시각화합니다.

d = 0.02;
[x1Grid,x2Grid] = meshgrid(min(cdata(:,1)):d:max(cdata(:,1)),...
    min(cdata(:,2)):d:max(cdata(:,2)));
xGrid = [x1Grid(:),x2Grid(:)];
[~,scores] = predict(svmmod,xGrid);
figure;
h = nan(3,1); % Preallocation
h(1:2) = gscatter(cdata(:,1),cdata(:,2),grp,'rg','+*');
hold on
h(3) = plot(cdata(svmmod.IsSupportVector,1),...
    cdata(svmmod.IsSupportVector,2),'ko');
contour(x1Grid,x2Grid,reshape(scores(:,2),size(x1Grid)),[0 0],'k');
legend(h,{'-1','+1','Support Vectors'},'Location','Southeast');
axis equal
hold off

SVM 분류 모델에 대한 사후 확률 영역 플로팅하기

이 예제에서는 관측값으로 구성된 그리드에서 SVM 모델의 사후 확률을 예측하고 그 그리드에 사후 확률을 플로팅하는 방법을 보여줍니다. 사후 확률을 플로팅하면 결정 경계가 분명해집니다.

피셔(Fisher)의 붓꽃 데이터 세트를 불러옵니다. 꽃잎 길이와 꽃잎 너비를 사용하여 분류기를 훈련시키고 데이터에서 virginica 종을 제거합니다.

load fisheriris
classKeep = ~strcmp(species,'virginica');
X = meas(classKeep,3:4);
y = species(classKeep);

이 데이터를 사용하여 SVM 분류기를 훈련시킵니다. 클래스의 순서를 지정하는 것이 좋습니다.

SVMModel = fitcsvm(X,y,'ClassNames',{'setosa','versicolor'});

최적의 점수 변환 함수를 추정합니다.

rng(1); % For reproducibility
[SVMModel,ScoreParameters] = fitPosterior(SVMModel); 
Warning: Classes are perfectly separated. The optimal score-to-posterior transformation is a step function.
ScoreParameters
ScoreParameters = struct with fields:
                        Type: 'step'
                  LowerBound: -0.8431
                  UpperBound: 0.6897
    PositiveClassProbability: 0.5000

클래스는 분리 가능하기 때문에 최적의 점수 변환 함수는 계단 함수입니다. ScoreParameters의 필드 LowerBoundUpperBound는 클래스 분리 초평면(마진) 내에서 관측값에 대응되는 점수 구간의 하한 끝점과 상한 끝점을 나타냅니다. 어떠한 훈련 관측값도 이 마진 내에 속하지 않습니다. 새 점수가 구간 내에 있으면 소프트웨어가 대응되는 관측값을 양성 클래스 사후 확률, 즉 ScoreParametersPositiveClassProbability 필드의 값에 할당합니다.

관측된 예측 변수 공간에서 값의 그리드를 정의합니다. 그리드의 각 인스턴스에 대해 사후 확률을 예측합니다.

xMax = max(X);
xMin = min(X);
d = 0.01;
[x1Grid,x2Grid] = meshgrid(xMin(1):d:xMax(1),xMin(2):d:xMax(2));

[~,PosteriorRegion] = predict(SVMModel,[x1Grid(:),x2Grid(:)]);

양성 클래스 사후 확률 영역과 훈련 데이터를 플로팅합니다.

figure;
contourf(x1Grid,x2Grid,...
        reshape(PosteriorRegion(:,2),size(x1Grid,1),size(x1Grid,2)));
h = colorbar;
h.Label.String = 'P({\it{versicolor}})';
h.YLabel.FontSize = 16;
caxis([0 1]);
colormap jet;

hold on
gscatter(X(:,1),X(:,2),y,'mc','.x',[15,10]);
sv = X(SVMModel.IsSupportVector,:);
plot(sv(:,1),sv(:,2),'yo','MarkerSize',15,'LineWidth',2);
axis tight
hold off

2-클래스 학습에는 클래스가 분리 가능한 경우 세 개의 영역이 존재합니다. 하나는 관측값이 양성 클래스 사후 확률 0을 가지고, 다른 하나는 1을 가지며, 나머지는 양성 클래스 사전 확률을 가집니다.

선형 서포트 벡터 머신을 사용하여 이미지 분석하기

이 예제에서는 선형 SVM 이진 학습기로 구성된 오류 수정 출력 코드(ECOC) 모델을 훈련시켜 이미지에서 형상이 차지하는 사분면이 무엇인지 확인하는 방법을 보여줍니다. 이 예제에서는 서포트 벡터, 해당 레이블, 추정된 α 계수를 저장하는 ECOC 모델의 디스크 공간 사용량도 보여줍니다.

데이터 세트 생성하기

50x50 이미지에 반지름이 5인 원을 임의로 배치합니다. 5000개 이미지를 생성합니다. 각 이미지에 대해 원이 차지하는 사분면을 나타내는 레이블을 생성합니다. 1사분면은 오른쪽 위에 있고, 2사분면은 왼쪽 위에 있으며, 3사분면은 왼쪽 아래에 있고, 4사분면은 오른쪽 아래에 있습니다. 예측 변수는 각 픽셀의 농도입니다.

d = 50;  % Height and width of the images in pixels
n = 5e4; % Sample size

X = zeros(n,d^2); % Predictor matrix preallocation 
Y = zeros(n,1);   % Label preallocation
theta = 0:(1/d):(2*pi);
r = 5;            % Circle radius
rng(1);           % For reproducibility

for j = 1:n
    figmat = zeros(d);                       % Empty image
    c = datasample((r + 1):(d - r - 1),2);   % Random circle center
    x = r*cos(theta) + c(1);                 % Make the circle 
    y = r*sin(theta) + c(2);               
    idx = sub2ind([d d],round(y),round(x));  % Convert to linear indexing
    figmat(idx) = 1;                         % Draw the circle
    X(j,:) = figmat(:);                % Store the data
    Y(j) = (c(2) >= floor(d/2)) + 2*(c(2) < floor(d/2)) + ...
        (c(1) < floor(d/2)) + ...
        2*((c(1) >= floor(d/2)) & (c(2) < floor(d/2))); % Determine the quadrant
end

관측값을 플로팅합니다.

figure
imagesc(figmat)
h = gca;
h.YDir = 'normal';
title(sprintf('Quadrant %d',Y(end)))

ECOC 모델 훈련시키기

25% 홀드아웃 표본을 사용하여 훈련 표본 인덱스와 홀드아웃 표본 인덱스를 지정합니다.

p = 0.25;
CVP = cvpartition(Y,'Holdout',p); % Cross-validation data partition
isIdx = training(CVP);            % Training sample indices
oosIdx = test(CVP);               % Test sample indices

이진 학습기의 서포트 벡터를 저장하도록 지정하는 SVM 템플릿을 생성합니다. 이 템플릿과 훈련 데이터를 fitcecoc로 전달하여 모델을 훈련시킵니다. 훈련 표본의 분류 오차를 확인합니다.

t = templateSVM('SaveSupportVectors',true);
MdlSV = fitcecoc(X(isIdx,:),Y(isIdx),'Learners',t);
isLoss = resubLoss(MdlSV)
isLoss = 0

MdlSV는 훈련된 ClassificationECOC 다중클래스 모델입니다. 이는 훈련 데이터와 각 이진 학습기의 서포트 벡터를 저장합니다. 이미지 분석의 데이터 세트와 같은 대규모 데이터 세트의 경우, 이 모델은 많은 메모리를 사용할 수 있습니다.

ECOC 모델이 사용하는 디스크 공간의 크기를 확인합니다.

infoMdlSV = whos('MdlSV');
mbMdlSV = infoMdlSV.bytes/1.049e6
mbMdlSV = 763.6151

이 모델은 763.6MB를 사용합니다.

모델의 효율성 향상시키기

표본외 성과를 평가할 수 있습니다. 또한, 모델이 서포트 벡터, 관련 모수, 훈련 데이터를 포함하지 않는 간소화된 모델로 과적합되었는지 여부도 평가할 수 있습니다.

훈련된 ECOC 모델에서 서포트 벡터와 관련 모수를 삭제합니다. 그런 다음, compact를 사용하여 결과로 생성된 모델에서 훈련 데이터를 삭제합니다.

Mdl = discardSupportVectors(MdlSV);
CMdl = compact(Mdl);
info = whos('Mdl','CMdl');
[bytesCMdl,bytesMdl] = info.bytes;
memReduction = 1 - [bytesMdl bytesCMdl]/infoMdlSV.bytes
memReduction = 1×2

    0.0626    0.9996

이 경우, 서포트 벡터를 삭제하면 메모리 사용량이 약 6% 정도 줄어듭니다. 서포트 벡터를 간소화하고 삭제하면 크기가 약 99.96% 줄어듭니다.

서포트 벡터를 관리하는 다른 방법은 100과 같은 더 큰 상자 제약 조건을 지정하여 훈련 과정 중에 그 개수를 줄이는 것입니다. 더 적은 수의 서포트 벡터를 사용하는 SVM 모델이 더 바람직하고 메모리를 덜 사용하지만 상자 제약 조건의 값을 늘리면 훈련 시간이 늘어나는 경향이 있습니다.

작업 공간에서 MdlSVMdl을 제거합니다.

clear Mdl MdlSV

홀드아웃 표본 성능 평가하기

홀드아웃 표본의 분류 오차를 계산합니다. 홀드아웃 표본 예측의 표본을 플로팅합니다.

oosLoss = loss(CMdl,X(oosIdx,:),Y(oosIdx))
oosLoss = 0
yHat = predict(CMdl,X(oosIdx,:));
nVec = 1:size(X,1);
oosIdx = nVec(oosIdx);

figure;
for j = 1:9
    subplot(3,3,j)
    imagesc(reshape(X(oosIdx(j),:),[d d]))
    h = gca;
    h.YDir = 'normal';
    title(sprintf('Quadrant: %d',yHat(j)))
end
text(-1.33*d,4.5*d + 1,'Predictions','FontSize',17)

이 모델은 어떠한 홀드아웃 표본 관측값도 오분류하지 않습니다.

참고 항목

| |

관련 항목

참고 문헌

[1] Hastie, T., R. Tibshirani, and J. Friedman. The Elements of Statistical Learning, second edition. New York: Springer, 2008.

[2] Christianini, N., and J. Shawe-Taylor. An Introduction to Support Vector Machines and Other Kernel-Based Learning Methods. Cambridge, UK: Cambridge University Press, 2000.

[3] Fan, R.-E., P.-H. Chen, and C.-J. Lin. “Working set selection using second order information for training support vector machines.” Journal of Machine Learning Research, Vol 6, 2005, pp. 1889–1918.

[4] Kecman V., T. -M. Huang, and M. Vogt. “Iterative Single Data Algorithm for Training Kernel Machines from Huge Data Sets: Theory and Performance.” In Support Vector Machines: Theory and Applications. Edited by Lipo Wang, 255–274. Berlin: Springer-Verlag, 2005.