[PYTHON] Apprentissage automatique _ Rendre le perceptron simple non linéaire

Envisagez d'effectuer une classification binaire du vecteur d'entrée $ \ textbf {x} = (x_1, x_2, \ cdots, x_N) $ en utilisant la fonction $ f (\ textbf {x}) $ définie par l'équation suivante. ..


f(\textbf{x}) = \phi(\sum_{p=1}^{P} \sum_{n=1}^{N} w_{n,p} \, {x_n} ^p + w_{0})\\

\\

 \phi(y) = 

  \left\{
    \begin{array}{l}
      1 \quad (y \geq 0) \\
      -1 \quad (otherwise)
    \end{array}
  \right.

Où $ w_ {n, p} $ est le paramètre de poids, $ N $ est la dimension du vecteur d'entrée $ \ textbf {x} $, et $ P $ est l'ordre du polypole. Le paramètre de poids $ w_ {n, p} $ est erreur quadratique moyenne


l(\textbf{W}) = \sum_{i=1}^{I} (y_i - f(\textbf{x}_i))^2

[Méthode de descente de gradient probabiliste](https://ja.wikipedia.org/wiki/%E7%A2%BA%E7%8E%87%E7%9A%84%E5%8B%BE%E9%85% Il est obtenu en minimisant avec 8D% E9% 99% 8D% E4% B8% 8B% E6% B3% 95). Un exemple de la formule de mise à jour du paramètre de poids $ w_ {n, p} $ pendant l'entraînement est illustré ci-dessous.


 w_{0} \leftarrow w_{0} + \eta \sum_{i=1}^{I} (y_i - f(\textbf{x}_i)) \\
 w_{n,p} \leftarrow w_{n,p} + \eta \sum_{i=1}^{I} ((y_i - f(\textbf{x}_i)) ( \sum_{n=1}^{N} {x_{n,i}} \, ^{p} ))

$ \ Eta $ est le taux d'apprentissage, $ (\ textbf {x} _i, y_i) $ est la $ i $ ème donnée de l'enseignant et $ I $ est la taille du lot.

Lorsque $ P = 1 $, la fonction $ f (\ textbf {x}) $ correspond au bien connu Simple Perceptron et à la fonction $ Ce qui est entré dans \ phi $ est une fonction linéaire de $ \ textbf {x} $. D'un autre côté, lorsque $ P> 1 $, la fonction $ \ phi $ est entrée dans le polypoly $ \ textbf {x} $, pas une fonction linéaire. En augmentant l'ordre $ P $, la non-linéarité de la fonction $ f (\ textbf {x}) $ peut être renforcée. La fonction $ f (\ textbf {x}) $ est considérée comme une version non linéaire de Simple Perceptron.

Afin de voir l'effet de la commande $ P $, nous nous sommes entraînés à l'aide du jeu de données Iris et avons visualisé les résultats de la classification. Les résultats expérimentaux sont présentés ci-dessous.

Le linéaire est le résultat lorsque l'ordre $ P = 1 $ (perceptron simple), et les poly2 et poly3 sont les résultats lorsque l'ordre $ P = 2 $ et $ P = 3 $. On voit qu'en augmentant la commande $ P $, il devient possible de gérer des classifications compliquées.

Voici le code source utilisé dans l'expérience.

MyClass.py


import numpy as np
from numpy.random import *


class MyClass(object):

    def __init__(self, eta=0.01, n_iter=10, shuffle=True, random_state=None, model='linear'):
        self.eta = eta
        self.n_iter = n_iter
        self.w_initialized = False
        self.shuffle = shuffle
        self.model=model
        if random_state:
            seed(random_state)
        
    def fit(self, X, y):
        self._initialize_weights(X.shape[1])
        self.cost_ = []
        for i in range(self.n_iter):
            if self.shuffle:
                X, y = self._shuffle(X, y)
            cost = []
            for xi, target in zip(X, y):
                cost.append(self._update_weights(xi, target))
            avg_cost = sum(cost) / len(y)
            self.cost_.append(avg_cost)
        return self

    def _shuffle(self, X, y):
        r = np.random.permutation(len(y))
        return X[r], y[r]
    
    def _initialize_weights(self, m):
        self.w1 = randn(m)
        self.w2 = randn(m)
        self.w3 = randn(m)
        self.b = randn(1)
        self.w_initialized = True
        
    def _update_weights(self, xi, target):
        output = self.activation(xi)
        error = (target - output)
        if self.model == 'linear':
            self.w1 += self.eta * xi * error
        elif self.model == 'poly2':
            self.w1 += self.eta * xi * error
            self.w2 += self.eta * (xi**2) * error
        elif self.model == 'poly3':
            self.w1 += self.eta * xi * error
            self.w2 += self.eta * (xi**2) * error
            self.w3 += self.eta * (xi**3) * error
        self.b += self.eta * error
        cost = 0.5 * error**2
        return cost

    def activation(self, X):
        if self.model == 'linear':
            return np.dot(X, self.w1) + self.b
        elif self.model == 'poly2':
            return np.dot(X, self.w1) + np.dot((X**2), self.w2) + self.b
        elif self.model == 'poly3':
            return np.dot(X, self.w1) + np.dot((X**2), self.w2) + np.dot((X**3), self.w3)  + self.b

    def predict(self, X):
        return np.where(self.activation(X) >= 0.0, 1, -1)

plot_decision_regions.py


import numpy as np
import matplotlib.pyplot as plt


def plot_decision_regions(X, y, classifier, resolution=0.02):

    '''
    https://github.com/rasbt/python-machine-learning-book/tree/master/code/ch02
    '''
    
    # setup marker generator and color map
    markers = ('o', 's', 'x', '^', 'v')
    colors = ('red', 'blue', 'lightgreen', 'gray', 'cyan')
    cmap = ListedColormap(colors[:len(np.unique(y))])

    # plot the decision surface
    x1_min, x1_max = X[:, 0].min() - 1, X[:, 0].max() + 1
    x2_min, x2_max = X[:, 1].min() - 1, X[:, 1].max() + 1
    xx1, xx2 = np.meshgrid(np.arange(x1_min, x1_max, resolution),
                           np.arange(x2_min, x2_max, resolution))
    Z = classifier.predict(np.array([xx1.ravel(), xx2.ravel()]).T)
    Z = Z.reshape(xx1.shape)
    plt.contourf(xx1, xx2, Z, alpha=0.4, cmap=cmap)
    plt.xlim(xx1.min(), xx1.max())
    plt.ylim(xx2.min(), xx2.max())

    # plot class samples
    for idx, cl in enumerate(np.unique(y)):
        plt.scatter(x=X[y == cl, 0], y=X[y == cl, 1],
                    alpha=0.9, c=cmap(idx), s=100,
                    edgecolor='black',
                    marker=markers[idx], 
                    label=cl)

main.py


import matplotlib.pyplot as plt
import numpy as np
import pandas as pd
from numpy.random import *
from MyClass import MyClass
from plot_decision_regions import plot_decision_regions


# load dataset
df = pd.read_csv('https://archive.ics.uci.edu/ml/'
                 'machine-learning-databases/iris/iris.data', header=None)
df.tail()

# select setosa and versicolor
y = df.iloc[0:100, 4].values
y = np.where(y == 'Iris-setosa', -1, 1)

# extract x and y
X = df.iloc[0:100, [0,1]].values

# normarize X
X_std = np.copy(X)
X_std[:, 0] = (X[:, 0] - X[:, 0].mean()) / X[:, 0].std()
X_std[:, 1] = (X[:, 1] - X[:, 1].mean()) / X[:, 1].std()

model_names = ['linear', 'poly2', 'poly3']
for model in model_names:
    
    # import model
    ada = MyClass(n_iter=50, eta=0.01, random_state=1, model=model)
    
    # fitting
    ada.fit(X_std, y)

    # predict & plot
    plot_decision_regions(X_std, y, classifier=ada)
    plt.title(model)
    plt.xlabel('x [normarized]')
    plt.ylabel('y [normarized]')
    plt.legend(loc='upper left')
    plt.tight_layout()
    plt.savefig(model + '.png', dpi=300)
    plt.show()

    del ada
    

référence:

https://github.com/rasbt/python-machine-learning-book

Fais toi!

Recommended Posts

Apprentissage automatique _ Rendre le perceptron simple non linéaire
Algorithme d'apprentissage automatique (perceptron simple)
Introduction à l'apprentissage automatique à partir de Simple Perceptron
Algorithme d'apprentissage automatique (analyse de régression unique)
Explication et mise en œuvre du perceptron simple
perceptron
Apprentissage automatique avec python (2) Analyse de régression simple
Discriminateur linéaire - Discriminateur linéaire de Fisher, Perceptron simple, IRLS
[Super Introduction] Apprentissage automatique utilisant Python - De la construction d'environnement à l'implémentation de perceptron simple-