Классификатор SVM также является простым двоичным классификатором, который часто задают во время собеседований по машинному обучению.

Для простоты и подготовки к собеседованию мы сосредотачиваемся на линейной SVM по бинарной классификации с подходом оптимизации градиентного спуска.

Проблема: классифицируйте два класса в Y с заданным набором данных с двумя измерениями входных данных X1 и X2.

Мы пытаемся провести линейную линию, которая может разделить два класса, и сделать расстояния от любого класса максимальными.

Линия представлена

w*x + b = 0

Для метки 1 w * x + b ≥ 1

Для метки -1 w * x + b ≤ -1

Расстояние между двумя классами составляет

2/|w|

Мы хотим максимально увеличить это расстояние.

Если мы хотим найти линию, которая идеально разделяет два класса, мы называем этот тип функции стоимости SVM функцией стоимости Hard-Margin.

Если мы позволим ошибочно классифицировать некоторые выбросы, мы можем использовать Hinge-Loss при проектировании функции стоимости.

Этот образец реализации C ++ (менее 100 строк) предназначен для программирования на доске или понимания алгоритма.

В реальном мире оптимизацию SVM необходимо реализовать с помощью SMO (последовательная минимальная оптимизация).

double getHingeLoss (double & x1, double & x2, int & y, double & w1, двойной и w2, двойной и b)

{

двойной проигрыш = 0;

if(y==1)

{

проигрыш = 1- (w1 * x1 + w2 * x2 + b);

}

еще

{

проигрыш = 1+ (w1 * x1 + w2 * x2 + b);

}

если (убыток ‹0) убыток = 0;

возврат убытка;

}

// наклон: а

// перехват: b

// производная от w: dw

// производная от перехвата: db

double getSVMCost (vector ‹double› & x1, vector ‹double› & x2, vector ‹int› & y,

двойной w1, двойной w2, двойной b,

double и dw1, double и dw2, double и db)

{

int n = static_castint› (y.size ());

// потеря петли

двойная стоимость = 0;

dw1 = 0;

dw2 = 0;

db = 0;

для (int i = 0; i ‹n; i ++)

{

двойная потеря = getHingeLoss (x1 [i], x2 [i], y [i], w1, w2, b);

стоимость + = убыток;

// когда убыток = 0, все производные равны 0

если (убыток ›0)

{

dw1 += (-x1[i]*y[i]);

dw2 += (-x2[i]*y[i]);

db += (-y[i]);

}

}

стоимость / = n;

dw1 /= n;

dw2 /= n;

db /=n;

возврат стоимости;

}

void trainSVM (вектор ‹double› & x1, vector ‹double› & x2, vector ‹int› & y)

{

двойная скорость = 0,0005;

двойной порог = 0,001;

двойной w1 = 1;

двойной w2 = 1;

двойной b = 0;

двойной dw1 = 0;

двойной dw2 = 0;

двойной db = 0;

int iter = 0;

в то время как (верно)

{

double cost = getSVMCost (x1, x2, y, w1, w2, b, dw1, dw2, db);

если (iter% 1000 == 0)

{

cout ‹---------------- ”Iter:« ‹* iter ‹< “cost =« ‹< cost ‹* «dw1 =« ‹< dw1 ‹< «dw2 =« ‹< dw2 ‹< «db =« ‹< db ‹< endl;

}

iter ++;

if (абс (dw1) ‹порог && абс (dw2)‹ порог && абс (дб) ‹порог)

{

cout <

перерыв;

}

w1 - = lrate * dw1;

w2 - = lrate * dw2;

b - = lrate * db;

}

}

int main () {

// возраст

вектор ‹двойной› X1 = {35,27,19,25,26,45,46,48,47,29,27,28,27,30,28,23,27,18} ;

// доход в тыс.

вектор ‹двойной› X2 = {20,57,76,33,52,26,28,29,49,43,137,44,90,49,84,20,54,44};

// покупаем дом

вектор ‹int› Y = {-1, -1, -1, -1, -1, 1, 1, 1, 1, -1, 1, -1, -1, -1 , -1, -1, -1, -1};

trainSVM (X1, X2, Y);

возврат 0;

}

Терминальные выходы:

Iter: 1055000 стоимость = 0,0304599 dw1 = -1,5 dw2 = -7,61111 дБ = -0,0555556

Iter: 1056000 стоимость = 0,00825617 dw1 = 3,05556 dw2 = 9,66667 дБ = 0,111111

Iter: 1057000 стоимость = 0,0116667 dw1 = 3,05556 dw2 = 9,66667 дБ = 0,111111

Iter: 1058000 стоимость = 0,0302824 dw1 = -4 dw2 = -9,05556 db = -0,111111

Iter: 1059000 стоимость = 0,00058179 dw1 = -1,5 dw2 = -7,61111 дБ = -0,0555556

y = 0.272056 * x1 + 0.0428889 * x2 + -12.221