Fortsetzung von Letztes Mal
Der Unterschied zum vorherigen Perceptron Der Punkt der Verwendung einer linearen Aktivierungsfunktion anstelle einer Einheitsschrittfunktion zum Aktualisieren von Gewichten
Lernen kann konvergiert werden, indem das Lernen so vorangetrieben wird, dass es zum Mindestwert der Kostenfunktion wird.
ADALINE kann das Gewicht ermitteln, das die Kostenfunktion minimiert, indem die Gradientenabstiegsmethode verwendet wird, indem eine differenzierbare Aktivierungsfunktion verwendet wird und die Summe der Fehlerquadrate als Kostenfunktion verwendet wird, um sie zu einer konvexen Funktion zu machen.
Ein Diagramm des Prinzips der Gradientenabstiegsmethode
Um die Gewichte mithilfe der Gradientenabstiegsmethode zu aktualisieren, gehen Sie einen Schritt zurück entlang des Gradienten $ \ nabla J (\ mathbf {w}) $ der Kostenfunktion $ J (\ mathbf {w}) $
Damit
Die Lernregeln von ADALINE sind Perceptron sehr ähnlich. Unten implementiert
import numpy as np
class AdalineGD(object):
"""ADAptive LInear NEuron-Klassifikator
Parameter
-----------
eta : float
Lernrate(0.Größer als 0 1.Wert kleiner oder gleich 0)
n_iter : int
Anzahl der Trainings in Trainingsdaten
random_state : int
Zufälliger Startwert für die Gewichtsinitialisierung
Attribut
-----------
w_ :1-dimensionales Array
Gewicht nach Anpassung
cost_ :aufführen<- error_Ist kosten_Ändern
Kostenfunktion der Summe der Fehlerquadrate in jeder Epoche
"""
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):
"""Passt zu Trainingsdaten
Parameter
------------
X : {Array-ähnliche Datenstruktur}, shape = [n_samples, n_features]
Trainingsdaten
n_Proben ist die Anzahl der Proben, n_Features ist die Anzahl der Features
y :Array-ähnliche Datenstruktur, shape = [n_samples]
Objektive Variable
Rückgabewert
------------
self : object
"""
rgen = np.random.RandomState(self.random_state)
self.w_ = rgen.normal(loc=0.0, scale=0.01, size=1 + X.shape[1])
self.cost_ = []
for _ in range(self.n_iter): #Wiederholen Sie die Trainingsdaten für die Anzahl der Trainings
net_input = self.net_input(X) #Sie müssen nicht wie bei einer Perceptron-Implementierung für jedes Sample eine Schleife ausführen (ich bin mir nicht sicher, warum Perceptron für jedes Sample eine Schleife durchführt).
#Weil die Aktivierungsmethode nur eine gleiche Funktion ist
#Dieser Code hat keine Auswirkung. Implementiert als bloßes Konzept der Aktivierungsfunktion.
#Bei der Implementierung der logistischen Regression scheint es nur notwendig zu sein, auf die Sigmoid-Funktion umzusteigen.
output = self.activation(net_input)
#Fehler y^(i) - φ(z^(i))Berechnung von
errors = y - output
#Gewicht w_1, ..., w_m Update
self.w_[1:] += self.eta * X.T.dot(errors)
#Gewicht w_Update 0
self.w_[0] += self.eta * errors.sum()
#Berechnung der Kostenfunktion
cost = (errors ** 2).sum() / 2.0
#Speicherung von Kosten
self.cost_.append(cost)
return self
def net_input(self, X):
"""Berechnen Sie die Gesamteingabe"""
return np.dot(X, self.w_[1:]) + self.w_[0] #Sie müssen nicht mit xi schleifen
def activation(self, X):
"""Berechnen Sie die Ausgabe der linearen Aktivierungsfunktion"""
return X
def predict(self, X):
"""Gibt die Klassenbezeichnung nach einem Schritt zurück"""
return np.where(self.activation(self.net_input(X)) >= 0.0, 1, -1)
Versuchen Sie es mit gut klassifizierten Daten von Perceptron.
import numpy as np
from sklearn.datasets import load_iris
import pandas as pd
iris = load_iris()
df = pd.DataFrame(iris.data, columns=iris.feature_names)
df['target'] = iris.target
df2 = df.query("target != 1").copy() #Etikett 1 ausschließen
df2["target"] -= 1 #Etikett 1-Auf 1 ausrichten
X = df2[['petal width (cm)', 'sepal width (cm)']].values
Y = df2['target'].values
import matplotlib.pyplot as plt
fig, ax = plt.subplots(nrows=1, ncols=2, figsize=(10, 4))
ada1 = AdalineGD(n_iter=10, eta=0.01).fit(X, Y)
ax[0].plot(range(1, len(ada1.cost_)+1), np.log10(ada1.cost_), marker='o')
ax[0].set_xlabel('Epochs')
ax[0].set_ylabel('log(Sum-squared-error)')
ax[0].set_title('Adaline - Learning rate 0.01')
ada2 = AdalineGD(n_iter=10, eta=0.0001).fit(X, Y)
ax[1].plot(range(1, len(ada2.cost_)+1), ada2.cost_, marker='o')
ax[1].set_xlabel('Epochs')
ax[1].set_ylabel('Sum-squared-error')
ax[1].set_title('Adaline - Learning rate 0.0001')
← ist das Protokoll der Summe der Fehlerquadrate für die Anzahl der Epochen bei einer Lernrate von 0,01 und → ist die Summe der Fehlerquadrate für die Anzahl der Epochen bei einer Lernrate von 0,0001.
Es stellt sich heraus, dass wenn Sie η nicht gut auswählen, es nicht gut konvergiert.
Wenn die Lernrate hoch ist, streben wir den in der Abbildung gezeigten Mindestwert an, springen jedoch über den Mindestwert und klettern zur gegenüberliegenden Bank.
Skalieren Sie Funktionen für die optimale Leistung von Algorithmen für maschinelles Lernen.
Diesmal standardisierte $ \ mathbf {x} '\ _j = \ frac {\ mathbf {x} \ _ j- \ mu_j} {\ sigma_j} $
Dies gibt den Daten die Eigenschaften einer Standardnormalverteilung und ermöglicht eine schnelle Konvergenz des Lernens.
#Standardisierung
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()
from sklearn import preprocessing
ss = preprocessing.StandardScaler()
X_std2 = ss.fit_transform(X)
print(X_std[:3])
print(X_std2[:3]) #das Gleiche
[[-1.02461719 0.71907625]
[-1.02461719 -0.4833924 ]
[-1.02461719 -0.00240494]]
[[-1.02461719 0.71907625]
[-1.02461719 -0.4833924 ]
[-1.02461719 -0.00240494]]
#Grenzplotfunktion früher implementiert
from matplotlib.colors import ListedColormap
def plot_decision_regions(X, y, classifier, resolution=0.02):
#Vorbereitung von Markern und Farbkarten
markers = ('s', 'x', 'o', '^', 'v')
colors = ('red', 'blue', 'lightgreen', 'gray', 'cyan')
cmap = ListedColormap(colors[:len(np.unique(y))])
#Entscheidungsbereichsdiagramm
x1_min, x1_max = X[:, 0].min() - 1, X[:, 0].max() + 1
x2_min, x2_max = X[:, 1].min() - 1, X[:, 1].max() + 1
#Generieren Sie Rasterpunkte
xx1, xx2 = np.meshgrid(np.arange(x1_min, x1_max, resolution),
np.arange(x2_min, x2_max, resolution))
#Vorhersage durch Konvertieren jedes Features in ein eindimensionales Array
Z = classifier.predict(np.array([xx1.ravel(), xx2.ravel()]).T)
#Konvertieren Sie Vorhersageergebnisse in die ursprüngliche Größe der Rasterpunktdaten
Z = Z.reshape(xx1.shape)
#Rasterpunktkonturdiagramm
plt.contourf(xx1, xx2, Z, alpha=0.3, cmap=cmap)
#Einstellung des Achsenbereichs
plt.xlim(xx1.min(), xx1.max())
plt.ylim(xx2.min(), xx2.max())
#Zeichnen Sie die Proben nach Klassen
for idx, cl in enumerate(np.unique(y)):
plt.scatter(x=X[y == cl, 0],
y=X[y == cl, 1],
alpha=0.8,
c=colors[idx],
marker=markers[idx],
label=cl,
edgecolor='black')
ada = AdalineGD(n_iter=15, eta=0.01)
ada.fit(X_std, Y)
plot_decision_regions(X_std, Y, classifier=ada)
plt.title('Adaline - Gradient Descent')
plt.xlabel('petal width [standardized]')
plt.ylabel('sepal width [standardized]')
plt.legend(loc='upper left')
plt.tight_layout()
plt.show()
plt.plot(range(1, len(ada.cost_) + 1), ada.cost_, marker='o')
plt.xlabel('Epochs')
plt.ylabel('Sum-squared-error')
plt.tight_layout()
plt.show()
Es ist zu sehen, dass es konvergiert hat und die Grenzen der Klassifizierung fest geschlossen sind.
Es kann bestätigt werden, dass die Standardisierung effektiv ist, da sie bei derselben Lernrate nicht gut konvergierte.
ada1 = AdalineGD(n_iter=15, eta=0.01)
ada1.fit(X, Y)
plot_decision_regions(X, Y, classifier=ada1)
plt.title('Adaline - Gradient Descent')
plt.xlabel('petal width [standardized]')
plt.ylabel('sepal width [standardized]')
plt.legend(loc='upper left')
plt.tight_layout()
plt.show()
plt.plot(range(1, len(ada1.cost_) + 1), ada1.cost_, marker='o')
plt.xlabel('Epochs')
plt.ylabel('Sum-squared-error')
plt.tight_layout()
plt.show()
↑ Auch wenn ich versucht habe, nicht standardisierte Daten zu verwenden, hat es nicht funktioniert.
Danach werde ich es mit den Daten versuchen, die beim letzten Mal nicht klassifiziert werden konnten.
import numpy as np
import matplotlib.pyplot as plt
df3 = df.query("target != 0").copy() #Label 0 ausschließen
y = df3.iloc[:, 4].values
y = np.where(y == 1, -1, 1) #Etikett 1-Stellen Sie 1 auf 1 und andere (Etikett 2) auf 1.
# plt.scatter(df3.iloc[:50, 1], df3.iloc[:50, 0], color='orange', marker='o', label='versicolor')
# plt.scatter(df3.iloc[50:, 1], df3.iloc[50:, 0], color='green', marker='o', label='virginica')
# plt.xlabel('sepal width [cm]')
# plt.ylabel('sepal length [cm]')
# plt.legend(loc='upper left')
# plt.show()
X2 = df3[['sepal width (cm)', 'sepal length (cm)']].values
from sklearn import preprocessing
sc = preprocessing.StandardScaler()
X2_std = sc.fit_transform(X2)
ada2 = AdalineGD(n_iter=15, eta=0.01)
ada2.fit(X2_std, y)
plot_decision_regions(X2_std, y, classifier=ada2)
plt.title('Adaline - Gradient Descent')
plt.xlabel('sepal width [standardized]')
plt.ylabel('sepal length [standardized]')
plt.legend(loc='upper left')
plt.tight_layout()
plt.show()
plt.plot(range(1, len(ada2.cost_) + 1), ada2.cost_, marker='o')
plt.xlabel('Epochs')
plt.ylabel('Sum-squared-error')
plt.tight_layout()
plt.show()
Natürlich ist es nicht linear und vollständig trennbar, aber da die Grenze an einer vernünftigen Position gezogen wird, kann sie zu den minimalen Kosten konvergiert haben.
Wenn die Anzahl der Daten groß ist, werden die Berechnungskosten der Methode bis zu diesem Punkt (Batch-Gradienten-Abstiegsmethode) hoch.
→ Verwenden Sie die probabilistische Gradientenabstiegsmethode
Aktualisieren Sie stattdessen die Gewichte Schritt für Schritt für jede Probe
Es ist wichtig, die Proben in zufälliger Reihenfolge zu sortieren. Die Vorteile dieser Methode sind, dass sie mit hoher Geschwindigkeit konvergiert, dass sie leicht aus flachen Mindestwerten herauskommt (es gibt viel Rauschen auf der Fehleroberfläche) und dass sie für das Online-Lernen verwendet werden kann.
Online-Lernen… Wenn neue Trainingsdaten eintreffen, trainieren Sie vor Ort und aktualisieren Sie das Modell. Sie können sich schnell an Änderungen anpassen.
Implementieren Sie ADALINE mithilfe der folgenden probabilistischen Gradientenabstiegsmethode
import numpy as np
from numpy.random import seed
class AdalineSGD(object):
"""ADAptive LInear NEuron-Klassifikator
Parameter
-----------
eta : float
Lernrate(0.Größer als 0 1.Wert kleiner oder gleich 0)
n_iter : int
Anzahl der Trainings in Trainingsdaten
shuffle : bool (Standardwert True)
Wenn dies der Fall ist, mischen Sie die Trainingsdaten pro Epoche, um eine Zirkulation zu vermeiden
random_state : int
Zufälliger Startwert für die Gewichtsinitialisierung
Attribut
-----------
w_ :1-dimensionales Array
Gewicht nach Anpassung
cost_ :aufführen
Die Fehlersumme der Quadrate kostet, um alle Trainingsmuster in jeder Epoche zu mitteln
"""
def __init__(self, eta=0.01, n_iter=10, shuffle=True, random_state=None):
self.eta = eta
self.n_iter = n_iter
self.w_initialized = False #Gewichtsinitialisierungsflag
self.shuffle = shuffle
self.random_state = random_state
def fit(self, X, y):
"""Passt zu Trainingsdaten
Parameter
------------
X : {Array-ähnliche Datenstruktur}, shape = [n_samples, n_features]
Trainingsdaten
n_Proben ist die Anzahl der Proben, n_Features ist die Anzahl der Features
y :Array-ähnliche Datenstruktur, shape = [n_samples]
Objektive Variable
Rückgabewert
------------
self : object
"""
#Erzeugung eines Gewichtsvektors
self._initialize_weights(X.shape[1])
self.cost_ = []
#Wiederholen Sie dies für die Anzahl der Schulungen
for i in range(self.n_iter):
#Mische Trainingsdaten, falls angegeben
if self.shuffle:
X, y = self._shuffle(X, y)
#Erstellen Sie eine Liste, um die Kosten für jede Probe zu speichern
cost = []
#Berechnung für jede Probe
for xi, target in zip(X, y):
#Gewichtsaktualisierung und Kostenberechnung mit Merkmal xi und Zielvariable y
cost.append(self._update_weights(xi, target))
#Berechnung der durchschnittlichen Kosten der Probe
avg_cost = sum(cost)/len(y)
#Lagerung der Durchschnittskosten
self.cost_.append(avg_cost)
return self
def partial_fit(self, X, y):
"""Passen Sie die Trainingsdaten an, ohne die Gewichte neu zu initialisieren"""
#Führen Sie die Initialisierung durch, wenn sie nicht initialisiert wurde
if not self.w_initialized:
self._initialize_weights(X.shape[1])
#Wenn die Anzahl der Elemente der Zielvariablen y 2 oder mehr beträgt
#Aktualisieren Sie die Gewichte mit den Merkmalsmengen xi und dem Ziel für jede Probe
if y.ravel().shape[0] > 1:
for xi, target in zip(X, y):
self._update_weights(xi, target)
#Wenn die Anzahl der Elemente der Zielvariablen y 1 ist.
#Aktualisieren Sie die Gewichte mit Merkmal X und Zielvariable y für die gesamte Stichprobe
else:
self._update_weights(X, y)
return self
def _shuffle(self, X, y):
"""Mische Trainingsdaten"""
r = self.rgen.permutation(len(y))
return X[r], y[r] #Das Mischen kann erreicht werden, indem ein Array an den Index übergeben wird
def _initialize_weights(self, m):
"""Initialisieren Sie Gewichte mit kleinen Zufallszahlen"""
self.rgen = np.random.RandomState(self.random_state)
self.w_ = self.rgen.normal(loc=0.0, scale=0.01, size=1 + m)
self.w_initialized = True
def _update_weights(self, xi, target):
"""Aktualisieren Sie die Gewichte mithilfe der ADALINE-Lernregeln"""
#Berechnung der Ausgabe der Aktivierungsfunktion
output = self.activation(self.net_input(xi))
#Fehlerberechnung
error = target - output
#Gewichtsaktualisierung
self.w_[1:] += self.eta * xi.dot(error)
self.w_[0] += self.eta * error
#Kostenkalkulation
cost = 0.5 * error**2
return cost
def net_input(self, X):
"""Berechnen Sie die Gesamteingabe"""
return np.dot(X, self.w_[1:]) + self.w_[0]
def activation(self, X):
"""Berechnen Sie die Ausgabe der linearen Aktivierungsfunktion"""
return X
def predict(self, X):
"""Gibt die Klassenbezeichnung nach einem Schritt zurück"""
return np.where(self.activation(self.net_input(X)) >= 0.0, 1, -1)
ada = AdalineSGD(n_iter=15, eta=0.01, random_state=1)
ada.fit(X_std, y)
plot_decision_regions(X_std, y, classifier=ada)
plt.title('Adaline - Stochastic Gradient Descent')
plt.xlabel('petal width [standardized]')
plt.ylabel('sepal width [standardized]')
plt.legend(loc='upper left')
plt.tight_layout()
plt.show()
plt.plot(range(1, len(ada.cost_) + 1), ada.cost_, marker='o')
plt.xlabel('Epochs')
plt.ylabel('Average Cost')
plt.show()
Die durchschnittlichen Kosten sinken bald. Die Grenze entspricht der Batch-Gradienten-Abstiegsmethode.
Für das Online-Lernen können Sie ein Update durchführen, indem Sie teilweise_fit aufrufen.
Nachdem ich Perceptron und ADALINE gelernt habe, habe ich mein Verständnis erheblich vertieft, sodass ich denke, dass es mit dieser Anwendung in Zukunft einfacher sein wird, andere Algorithmen für maschinelles Lernen zu verstehen. Es war also gut zu studieren.
Bis jetzt habe ich andere Algorithmen als Black Boxes verwendet, daher war es gut, den Inhalt kennen zu können.
Ich habe ein Notizbuch in Gist.
(Konzeptdiagramme usw. werden wie zuvor aus Kapitel 2 von "Theorie und Praxis von Python Data Learning Expert Data Scientists" zitiert.)
Recommended Posts