Линейный SVM
SVM является классификатором максимальной маржи, т.е. он максимизирует ширину или границу, отделяющую положительный класс от отрицательного.Функция потерь линейного SVM в случае двоичной классификации приведена ниже.
Она может быть получена из более обобщенного мультикласса линейных потерь SVM (также называется потерей шарнира), показанным ниже (с Δ = 1).
Примечание: во всех вышеперечисленныхУравнения, весовой вектор w
включает в себя смещение b
Как, черт возьми, кто-то придумал эту потерю? Позволяет раскопать.
На изображении выше показаны точки данных, принадлежащие положительному классу, отделенные от точки данных, принадлежащей отрицательному классу, разделяющей гиперплоскостью (показана сплошной линией).Однако таких разделяющих гиперплоскостей может быть много.SVM находит разделяющую гиперплоскость так, чтобы расстояние гиперплоскости до ближайшей положительной точки данных и до ближайшей отрицательной точки данных было максимальным (показано пунктирной линией).
Математически SVM находит вектор весов w
(включая смещение), такой что
Если метки (y
) из + ve class и -ve class равны +1
и -1
соответственно, тогда SVM находит w
такой, что
• Еслиточка данных находится на правильной стороне гиперплоскости (правильно классифицирована), тогда
• Если точка данных находится на неправильной стороне (пропущена классификация) затем
Таким образом, потеря для точки данных, которая является мерой классификации ошибок, может быть записана как
Регуляризация
Если вектор весов w
правильно классифицирует данные (X
), то любой кратный из этих векторов весов λw
, где λ>1
также правильно классифицирует данные (ноль потерь).Это потому, что преобразование λW
растягивает все балльные значения и, следовательно, также их абсолютные различия.Регуляризация L2 штрафует большие веса, добавляя потерю регуляризации к потере шарнира.
Например, если x=[1,1,1,1]
и два весовых вектора w1=[1,0,0,0]
, w2=[0.25,0.25,0.25,0.25]
.Тогда dot(W1,x) =dot(w2,x) =1
, т.е. оба вектора веса приводят к одному и тому же точечному произведению и, следовательно, к одинаковой потере шарнира.Но штраф L2 w1
составляет 1.0
, в то время как штраф L2 w2
составляет всего 0.25
.Следовательно, регуляризация L2 предпочитает w2
над w1
.Классификатор рекомендуется принимать во внимание все входные измерения в небольших количествах, а не несколько входных измерений и очень сильно.Это улучшает обобщение модели и приводит к меньшему переоснащению.
L2 штраф приводит к свойству максимального запаса в SVM.Если SVM выражается как задача оптимизации, то обобщенная форма Лагранжа для задачи ограниченной квадратичной оптимизации выглядит следующим образом:
Теперь, когда мы знаем потериВ функции линейного SVM мы можем использовать градиент приличный (или другие оптимизаторы), чтобы найти весовые векторы, которые минимизируют потери.
Код
import tensorflow as tf
import numpy as np
import matplotlib.pyplot as plt
from sklearn import datasets
# Load Data
iris = datasets.load_iris()
X = iris.data[:, :2][iris.target != 2]
y = iris.target[iris.target != 2]
# Change labels to +1 and -1
y = np.where(y==1, y, -1)
# Linear Model with L2 regularization
model = tf.keras.Sequential()
model.add(tf.keras.layers.Dense(1, activation='linear', kernel_regularizer=tf.keras.regularizers.l2()))
# Hinge loss
def hinge_loss(y_true, y_pred):
return tf.maximum(0., 1- y_true*y_pred)
# Train the model
model.compile(optimizer='adam', loss=hinge_loss)
model.fit(X, y, epochs=50000, verbose=False)
# Plot the learned decision boundary
x_min, x_max = X[:, 0].min() - 1, X[:, 0].max() + 1
y_min, y_max = X[:, 1].min() - 1, X[:, 1].max() + 1
xx, yy = np.meshgrid(np.arange(x_min, x_max, 0.01),
np.arange(y_min, y_max, 0.01))
Z = model.predict(np.c_[xx.ravel(), yy.ravel()])
Z = Z.reshape(xx.shape)
cs = plt.contourf(xx, yy, Z, cmap=plt.cm.coolwarm, alpha=0.8)
plt.scatter(X[:, 0], X[:, 1], c=y, cmap=plt.cm.Set1)
plt.show()
SVM также можно выразить как ограниченную задачу квадратичной оптимизации.Преимущество этой формулировки состоит в том, что мы можем использовать трюк ядра для классификации нелинейно разделимых данных (используя разные ядра).LIBSVM реализует алгоритм последовательной минимальной оптимизации (SMO) для машин с ядрами опорных векторов (SVM).
Код
from sklearn.svm import SVC
# SVM with linear kernel
clf = SVC(kernel='linear')
clf.fit(X, y)
# Plot the learned decision boundary
x_min, x_max = X[:, 0].min() - 1, X[:, 0].max() + 1
y_min, y_max = X[:, 1].min() - 1, X[:, 1].max() + 1
xx, yy = np.meshgrid(np.arange(x_min, x_max, 0.01),
np.arange(y_min, y_max, 0.01))
Z = model.predict(np.c_[xx.ravel(), yy.ravel()])
Z = Z.reshape(xx.shape)
cs = plt.contourf(xx, yy, Z, cmap=plt.cm.coolwarm, alpha=0.8)
plt.scatter(X[:, 0], X[:, 1], c=y, cmap=plt.cm.Set1)
plt.show()
Наконец
Линейная модель SVM с использованием tf, которую вы можете использовать дляпостановка задачи:
# Prepare Data
# 10 Binary features
df = pd.DataFrame(np.random.randint(0,2,size=(1000, 10)))
# 1 floating value feature
df[11] = np.random.uniform(0,100000, size=(1000))
# True Label
df[12] = pd.DataFrame(np.random.randint(0, 2, size=(1000)))
# Convert data to zero mean unit variance
scalar = StandardScaler().fit(df[df.columns.drop(12)])
X = scalar.transform(df[df.columns.drop(12)])
y = np.array(df[12])
# convert label to +1 and -1. Needed for hinge loss
y = np.where(y==1, +1, -1)
# Model
model = tf.keras.Sequential()
model.add(tf.keras.layers.Dense(1, activation='linear',
kernel_regularizer=tf.keras.regularizers.l2()))
# Hinge Loss
def my_loss(y_true, y_pred):
return tf.maximum(0., 1- y_true*y_pred)
# Train model
model.compile(optimizer='adam', loss=my_loss)
model.fit(X, y, epochs=100, verbose=True)
Кросс-фолд-кросс-валидация и прогнозирование
import tensorflow as tf
import numpy as np
import matplotlib.pyplot as plt
from sklearn import datasets
from sklearn.model_selection import KFold
from sklearn.metrics import roc_curve, auc
# Load Data
iris = datasets.load_iris()
X = iris.data[:, :2][iris.target != 2]
y_ = iris.target[iris.target != 2]
# Change labels to +1 and -1
y = np.where(y_==1, +1, -1)
# Hinge loss
def hinge_loss(y_true, y_pred):
return tf.maximum(0., 1- y_true*y_pred)
def get_model():
# Linear Model with L2 regularization
model = tf.keras.Sequential()
model.add(tf.keras.layers.Dense(1, activation='linear', kernel_regularizer=tf.keras.regularizers.l2()))
model.compile(optimizer='adam', loss=hinge_loss)
return model
def sigmoid(x):
return 1 / (1 + np.exp(-x))
predict = lambda model, x : sigmoid(model.predict(x).reshape(-1))
predict_class = lambda model, x : np.where(predict(model, x)>0.5, 1, 0)
kf = KFold(n_splits=2, shuffle=True)
# K Fold cross validation
best = (None, -1)
for i, (train_index, test_index) in enumerate(kf.split(X)):
X_train, X_test = X[train_index], X[test_index]
y_train, y_test = y[train_index], y[test_index]
model = get_model()
model.fit(X_train, y_train, epochs=5000, verbose=False, batch_size=128)
y_pred = model.predict_classes(X_test)
val = roc_auc_score(y_test, y_pred)
print ("CV Fold {0}: AUC: {1}".format(i+1, auc))
if best[1] < val:
best = (model, val)
# ROC Curve using the best model
y_score = predict(best[0], X)
fpr, tpr, _ = roc_curve(y_, y_score)
roc_auc = auc(fpr, tpr)
print (roc_auc)
# Plot ROC
plt.figure()
lw = 2
plt.plot(fpr, tpr, color='darkorange',
lw=lw, label='ROC curve (area = %0.2f)' % roc_auc)
plt.plot([0, 1], [0, 1], color='navy', lw=lw, linestyle='--')
plt.xlim([0.0, 1.0])
plt.ylim([0.0, 1.05])
plt.xlabel('False Positive Rate')
plt.ylabel('True Positive Rate')
plt.legend(loc="lower right")
plt.show()
# Make predictions
y_score = predict_class(best[0], X)
прогнозирование
Поскольку выходные данные модели являются линейными, мы должны нормализовать ее для вероятностей, чтобы делать прогнозы. Если это бинарная классификация, мы можем использовать sigmoid
, если это мультиклассовая классификация, то мы можем использовать softmax
. Ниже приведен код для двоичной классификации
predict = lambda model, x : sigmoid(model.predict(x).reshape(-1))
predict_class = lambda model, x : np.where(predict(model, x)>0.5, 1, 0)
Ссылки
- CS231n
- Мой блокнот Kaggle