Алгоритм персептрона — классический алгоритм бинарной классификации

искусственный интеллект

Введение алгоритма

Алгоритм персептрона является классическим алгоритмом бинарной классификации.

Народное описание: На столе много апельсинов и яблок, и стоит очередь, так что яблоки и апельсины по обе стороны от очереди. Цель алгоритма персептрона состоит в том, чтобы найти эту линию.

Формальное описание (отрывок из "Алгоритмы машинного обучения" - Ли Ханг): Алгоритм персептрона представляет собой модель линейной классификации для двухклассовой классификации. Его входом является вектор признаков экземпляра, а выходом является класс экземпляра, принимая +1 и -1 двоичное значение. Персептрон соответствует гиперплоскости, которая делит экземпляры на положительные и отрицательные классы во входном пространстве (векторе признаков) и принадлежит дискриминационной модели. Целью алгоритма набора персептрона является поиск гиперплоскости классификации, которая в настоящее время разделяет обучающие данные.С этой целью импортируется функция потерь, основанная на неправильной классификации, и используется алгоритм градиентного спуска для минимизации функции потерь для получения модели персептрона. . Эта модель была предложена Розенблаттом в 1957 году и является основой нейронных сетей и машин опорных векторов.

Описание модели

Чтобы упростить описание проблемы, нарисуйте график с помощью matplotlib.

Краткое описание модели: Подставьте координаты всех точек в функцию, и результат может быть +1 или -1. На основании этого результата мишени делятся на две категории. Эта соответствующая функция становится персептроном.

Формальное описание модели:

Предположим, что входное пространство (пространство признаков) равноXX\subseteq RnR^n,

Выходное пространствоY={1,+1}Y=\{-1, +1\}.

входитьxXx\subseteq Xвекторное пространство, представляющее экземпляры, соответствующие точкам входного пространства (пространство признаков);

выводyYy\subseteq YПредставляет класс экземпляра. Следующая функция из входного пространства в выходное пространство:

f(x)=sign(wx+b)f(x)=знак(w·x+b)

называется перцептроном.

в:

wwиbbпараметры модели персептрона

wRnw\subseteq R^nназываются весами (или векторами)

bRb\subseteq Rпредвзятость

wxш хвыражатьwwиxxвнутренний продукт

Примечание:w=(w0,w1)w = (w_0, w_1), который является векторомx=(x0,x1)x=(x_0, x_1)тоже вектор. Обратите внимание, что это векторизованное представление.

signsignявляется символической функцией:

sign(x)={+1,x>01,x<0sign(x)=\begin{cases} +1, & x>0 \\ -1, & x<0 \\ \end{cases}

Как показано на рисунке:

стратегия обучения персептрона

Алгоритм персептрона пытается использовать гиперплоскость (представленную в виде линии в двумерном пространстве) для точного и правильного разделения положительных и отрицательных экземпляров. Чтобы найти такую ​​линию, мы можем посчитать все ошибочно классифицированные точки, сумму их расстояний от плоскости. Сначала рассмотрим формулу расстояния.

Средняя школа и старшая школа должны выучить формулу расстояния от точки до линии точка(x1,y1)(x_1, y_1)к прямой линииax+by+c=0ax+by+c=0Расстояние:

ax+by+ca2+b2\frac {|ax+by+c|} {\sqrt{a^2+b^2}}

Точно так же для модели персептрона, которую мы определили на предыдущем шаге, она представлена ​​в векторизованной форме,x0x_0к гиперплоскостиSSРасстояние:

1wwx0+b\frac {1} {||w||}|w x_0+b|

Во-вторых, для неправильно классифицированных данных(xi,yi)(x_i, y_i)Сказать,

distance={1w(wxi+b)>0,yi<01w(wxi+b)<0,yi>0Distance=\begin{cases} \frac {1}{||w||}(w·x_i+b)>0, & y_i0 \\ \end{case}

Упрощается до:

distance=1wyi(wxi+b)>0расстояние = -\frac{1}{||w||}y_i(w x_i+b)>0

Среди них, когдаwxi+b>0ш х_i+b>0час,yi=1y_i = -1;когдаwxi+b<0ш х_i+bчас,yi=+1y_i = +1;

Таким образом, мы находим расстояние от неправильно классифицированной точки до гиперплоскости. Предположим, что множество всех ошибочно классифицированных точек равноMM. Тогда сумма расстояний от всех ошибочно классифицированных точек до гиперплоскости:

1wxiеMyi(wxi+b)-\frac{1}{||w||}\sum_{x_i\in M}y_i(w x_i+b)

пс:wwиbbЕго можно увеличивать и уменьшать пропорционально. Но представляемая ими гиперплоскость инвариантна. Здесь мы не рассматриваем1w\frac{1}{||w||}можно получить функцию потерь обучения персептрона: данный тренировочный набор

T={(x1,y1),(x2,y2),...,(xN,yN)}T = \{(x_1, y_1), (x_2, y_2), ... , (x_N, y_N)\}

в:

xiеXRnx_i\in X \subseteq R^n

yiеY={1,+1}y_i\in Y = \{-1, +1\}

i=1,2,...,N

Функция потерь алгоритма персептрона

L(w,b)=xiеMyi(wxi+b)L(w,b)=-\sum_{x_i\in M}y_i(wx_i+b)

M — множество ошибочно классифицированных точек.

Таким образом, проблема решения модели персептрона теперь меняется на решениеw,bw, b, так чтоL(w,b)L(w,b)минимум. который:

minw,bL(w,b)\min_{w,b}L(w,b)

Шаги алгоритма обучения персептрона

Алгоритм градиентного спуска необходимо использовать в процессе решения, поэтому давайте сначала решим функцию потерьL(w,b)L(w,b)полоса градиента

wL(w,b)=xiеMyixi\nabla_w L(w,b)=-\sum_{x_i\in M}y_i x_i
bL(w,b)=xiеMyi\nabla_b L(w,b)=-\sum_{x_i\in M}y_i

Конкретные шаги алгоритма:

(1) Выберите начальное значениеw0,b0w_0,b_0;

(2) Выберите данные в обучающем наборе(xi,yi)(x_i, y_i);

(3) Еслиyi(wxi+b)<=0y_i(w x_i + b),

ww+нyixiw \leftarrow w + \eta y_i x_i
bb+нyib \leftarrow b + \eta y_i

(4) Переходите к (2) до тех пор, пока в тренировочном наборе не останется ошибочно классифицированных точек.

До сих пор мы описали шаги алгоритма персептрона. Далее делаем две вещи: 1, вызовите алгоритм персептрона в sklearn, 2 рукописный алгоритм персептрона и вызовите его.

Вызовите модель персептрона в sklearn

Сначала импортируйте необходимые библиотеки

import matplotlib.pyplot as plt
import numpy as np
from sklearn.datasets import load_iris

импортировать набор данных

iris = load_iris()
# 数据集中共有3类,每类50各,我们取0,1两类。
# 共有4个特征值,我们取第二个和第三个特征,方便分析。
data = iris.data[:,2:4][iris.target < 2]
target = iris.target[iris.target < 2]

Разделите данные на обучающие и тестовые наборы:

from sklearn.model_selection import train_test_split
X_train, X_test, y_train, y_test = train_test_split(data, target, test_size=0.33, random_state=42)

Давайте посмотрим на распределение набора данных:

plt.scatter(X_train[y_train==0][:, 0], X_train[y_train==0][:, 1], c='r',)
plt.scatter(X_train[y_train==1][:, 0], X_train[y_train==1][:, 1], c='g')

plt.xlim(-2, 6)
plt.ylim(-2, 6)

Результат выглядит следующим образом:

Далее импортируем модель персептрона и начинаем обучение

from sklearn.linear_model import Perceptron
clf = Perceptron()
clf.fit(X_train, y_train)
X_predict = clf.predict(X_test)
X_predict

Результат выглядит следующим образом:

array([1, 1, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 1, 0, 1, 1, 0, 0, 1, 1,
       0, 0, 1, 0, 0, 1, 0, 1, 0, 0, 1])

Сравните с y_test:

y_test

Результат выглядит следующим образом:

array([1, 1, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 1, 0, 1, 1, 0, 0, 1, 1,
       0, 0, 1, 0, 0, 1, 0, 1, 0, 0, 1])

Все прогнозы оказались точными. Давайте используем функцию оценки, чтобы увидеть точность:

clf.score(X_test, y_test)

Результат выглядит следующим образом:

1.0

Доказательство является точным на 100%, что связано с тем, что набор данных слишком мал. А набор данных полностью линейно разделим, поэтому точность достигает 100%.

Теперь найдутся друзья, которым не терпится увидеть полученную гиперплоскость (соответствующую разделительной линии в двумерной плоскости).

Посмотрим на параметры вектора после решенияwwБар:

clf.coef_

Результат выглядит следующим образом:

array([[0.8, 0.8]])

Посмотрите на б:

clf.intercept_

Результат выглядит следующим образом:

array([-2.])

Теперь, когда все параметры получены, соответствующий

0.8*x1+0.8*x22=00.8 * x_1 + 0.8 * x_2 - 2 = 0
Это:x1+x22.5=0То есть: х_1 + х_2 - 2,5 = 0

Теперь давайте нарисуем эту линию и предыдущие точки данных на том же графике, чтобы увидеть эффект:

plt.scatter(X_train[y_train==0][:, 0], X_train[y_train==0][:, 1], c='r',)
plt.scatter(X_train[y_train==1][:, 0], X_train[y_train==1][:, 1], c='g')

plt.xlim(-2, 6)
plt.ylim(-2, 6)

x_1 = np.arange(-2, 6, 0.01)
x_2 = - x_1 + 2.5
plt.plot(x_1, x_2)

Результат выглядит следующим образом:

Это всегда странно, линия слишком близко к красной области. Но ведь набор данных делится на два. Эффект уже полный.

Реализуйте алгоритм персептрона самостоятельно

На предыдущем шаге мы вызвали алгоритм персептрона в sklearn и реализовали бинарную классификацию выборок. Далее давайте сами реализуем алгоритм персептрона. и назовите это.

Код персептрона, реализованный мной, выглядит следующим образом:

#coding: utf-8


import numpy as np
import pandas as pd
import matplotlib.pyplot as plt
from matplotlib.colors import ListedColormap
from sklearn.metrics import accuracy_score

class Perceptron:

    
    def __init__(self, eta=0.01, n_iter=50, random_state=1):
        self.eta = eta
        self.n_iter = n_iter
        self.random_state = random_state
        
    def fit(self, X, y):
        """
        Fit training data.

        Parameters
        ----------
        X : {array-like}, shape = [n_samples, n_features]
          Training vectors, where n_samples is the number of samples and
          n_features is the number of features.
        y : array-like, shape = [n_samples]
          Target values.

        Returns
        -------
        self : object

        """
        assert X.ndim == 2, "X must be 2 dimensional"
        assert y.ndim == 1, "y must be 1 dimensional"
        assert X.shape[0] == y.shape[0], \
            "the size of X_train must be equal to the size of y_train"

        rgen = np.random.RandomState(self.random_state)
        self.w_ = rgen.normal(loc=0.0, scale=0.01, size=1 + X.shape[1])
        
        for _ in range(self.n_iter):
            assert X[self.predict(X)!=y].shape[0] == y[self.predict(X)!=y].shape[0], \
                "the size of X_train must be equal to the size of y_train"
            
            # M 表示错误分类的点
            M = X[self.predict(X)!=y]
            M_target = y[self.predict(X)!=y]

            if (len(M) > 0):
                
                # 每次迭代抽取一个错误点进行梯度下降 直到错误分类点的集合大小为0
                M_predict = np.array(self.predict(M))
            
                x_i = M[0]
                M_target_i = np.array([M_target[0]])
                M_predict_i = np.array([M_predict[0]])
                
                update = self.eta * (M_target_i - M_predict_i)
                self.w_[1:] += update * x_i
                self.w_[0] += update
            
        return self


    def _compute_value(self, X):
        assert X.ndim == 2, "the single input must be one dimenssional"
        
        return np.dot(X, self.w_[1:]) + self.w_[0]

    def predict(self, X):
        assert X.ndim == 2, "function predict: X must be 2 dimensional"
        return np.where(self._compute_value(X) >= 0.0, 1, -1)
    
    def score(self, X_test, y_test):
        """根据测试数据集 X_test 和 y_test 确定当前模型的准确度"""

        y_predict = self.predict(X_test)
        return accuracy_score(y_test, y_predict)

Затем мы вызываем его, чтобы увидеть эффект. (Импортируйте набор данных, разделите набор данных, используйте код на предыдущем шаге, теперь мы напрямую вызываем наш собственный алгоритм персептрона)

from Perceptron import Perceptron

clf = Perceptron(n_iter=10000, eta=0.1)
clf.fit(X_train, y_train)
clf.predict(X_test)
clf.score(X_test, y_test), clf.w_

Результат выглядит следующим образом:

(1.0, array([-0.38375655,  0.13388244,  0.19471828]))

Мы видим, что точность составляет 100%. clf.w_[0] соответствует нашей моделиbb

За исключением части, отличной от clf.w_[0], это означаетww, то есть clf.w_[1:]

Наносим точки и расчетную линию:

plt.scatter(X_train[y_train==1][:, 0], X_train[y_train==1][:, 1], c='r',)
plt.scatter(X_train[y_train==-1][:, 0], X_train[y_train==-1][:, 1], c='g')

plt.xlim(-2, 6)
plt.ylim(-2, 6)


y_1 = np.arange(-2, 6, 0.01)
y_2 = - clf.w_[1] / clf.w_[2] * y_1 - clf.w_[0] / clf.w_ [2]
plt.plot(y_1, y_2)

Результат выглядит следующим образом:

Видно, что сегментация набора данных была достигнута.

Суммировать

В самореализованном алгоритме есть параметр эта, который представляет скорость обучения, Чем больше эта, тем быстрее сходимость. Однако, если эта слишком велика, флуктуация процесса сходимости будет слишком большой. Вам нужно настроить параметры самостоятельно.

Также есть соответствующие параметры в соответствующем файле sklearn. Заинтересованные ребята могут сами выставлять разные значения и наблюдать за процессом сходимости.