Классификатор 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_cast ‹int› (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