[PYTHON] Mit PyTorch viel regeln, von linearer multipler Regression bis hin zu logistischer Regression, mehrschichtigem Perzeptron und Autoencoder

Verwenden Sie PyTorch, um die Grundideen des Tiefenlernens zu lernen.

Grundlegende Teile von PyTorch

Angenommen, Sie haben Daten, die durch den Array-Typ numpy wie folgt dargestellt werden:

import numpy as np
x1 = np.array([0.12, 0.21])
x2 = np.array([0.34, 0.43])
x3 = np.array([0.56, 0.65])

Sie können eine lineare Verknüpfung wie folgt erstellen.

z = 0.5 * x1 + 0.3 * x2 + 0.2 * x3
z
array([0.274, 0.364])

Pytorch verwendet ein Numpy-Array, das in einen Tensortyp konvertiert wurde.

import torch
x1 = torch.from_numpy(x1).float()
x2 = torch.from_numpy(x2).float()
x3 = torch.from_numpy(x3).float()

Sie können lineare Verknüpfungen auf die gleiche Weise erstellen.

z = 0.5 * x1 + 0.3 * x2 + 0.2 * x3
z
tensor([0.2740, 0.3640])

Es mag ärgerlich erscheinen, aber durch weitere Konvertierung des Tensortyps in den Variablentyp wird es möglich, automatisch zu differenzieren (den Gradienten zu berechnen).

from torch.autograd import Variable
x1 = Variable(x1)
x2 = Variable(x2)
x3 = Variable(x3)

Sie können lineare Verknüpfungen auf die gleiche Weise erstellen.

z = 0.5 * x1 + 0.3 * x2 + 0.2 * x3
z
tensor([0.2740, 0.3640])

Pytoach bietet eine lineare Verknüpfungsfunktion. Lassen Sie uns vorher die lineare Verknüpfung mit numpy ausdrücken.

import numpy as np
W = np.array([[ 5,  1, -2 ],
       [ 3,  -5, -1 ]], dtype=np.float32) #Gewichtsmatrix

b = np.array([2, -3], dtype=np.float32) #Bias Begriff

Sie können eine lineare Verknüpfung wie folgt erstellen.

x = np.array([0, 1, 2]) #1 Datensatz mit 3 Variablen
y = x.dot(W.T) + b
y
array([ -1., -10.])

Wenn die Daten, die aus 3 Variablen bestehen, 5 Datensätze sind, ist dies wie folgt.

x = np.array(range(15)).astype(np.float32).reshape(5, 3)
x
array([[ 0.,  1.,  2.],
       [ 3.,  4.,  5.],
       [ 6.,  7.,  8.],
       [ 9., 10., 11.],
       [12., 13., 14.]], dtype=float32)
y = x.dot(W.T) + b
y
array([[ -1., -10.],
       [ 11., -19.],
       [ 23., -28.],
       [ 35., -37.],
       [ 47., -46.]], dtype=float32)

Das Obige ist die lineare Verknüpfung mit numpy. In Pytorch ist die Funktion, die eine lineare Verknüpfung darstellt, wie folgt definiert:

h = torch.nn.Linear(3,2) #Lineare Aktionsfunktion y, die einen dreidimensionalen Vektor eingibt und einen zweidimensionalen Vektor ausgibt= Wx + b

Standardmäßig enthalten die Gewichtsmatrix W und der Bias-Term b Zufallszahlen. Der Zweck des tiefen Lernens besteht darin, diese Koeffizienten zu optimieren.

h.weight #Random ist standardmäßig eingegeben
Parameter containing:
tensor([[-0.2569, -0.5403,  0.4155],
        [-0.5554,  0.5284,  0.3978]], requires_grad=True)
h.bias #Random ist standardmäßig eingegeben
Parameter containing:
tensor([-0.5164, -0.2875], requires_grad=True)

Übrigens, um Tensortypdaten in Numpy-Array-Typ zu konvertieren, gehen Sie wie folgt vor.

h.weight.detach().numpy()
array([[-0.256898  , -0.54026437,  0.41552007],
       [-0.55537015,  0.5283861 ,  0.39781755]], dtype=float32)
h.bias.detach().numpy()
array([-0.5163672 , -0.28754294], dtype=float32)

Lassen Sie uns nun eine lineare Transformation mit Pytorch durchführen.

x = Variable(torch.from_numpy(x).float()) #Konvertieren von Array-Typ → Tensortyp → Variablentyp
y = h(x) #Lineare Transformation
y.data.detach().numpy() #Überprüfen Sie den erhaltenen Wert mit dem Array-Typ
array([[-0.22559142,  1.0364783 ],
       [-1.3705183 ,  2.1489787 ],
       [-2.515445  ,  3.2614794 ],
       [-3.660372  ,  4.37398   ],
       [-4.805299  ,  5.48648   ]], dtype=float32)
x = x.detach().numpy()
x.dot(h.weight.detach().numpy().T) + h.bias.detach().numpy() #Überprüfung der Konten
array([[-0.22559142,  1.0364783 ],
       [-1.3705183 ,  2.1489787 ],
       [-2.515445  ,  3.2614794 ],
       [-3.660372  ,  4.37398   ],
       [-4.805299  ,  5.48648   ]], dtype=float32)

Ayame-Daten

Lassen Sie uns nun als Übung von Pytorch eine lineare multiple Regression durchführen. Als zu verarbeitende Daten behandeln wir die Daten von Iris (Ayame), die häufig im Bereich des maschinellen Lernens verwendet werden.

import numpy as np
from sklearn import datasets
iris = datasets.load_iris() #Irisdaten lesen
data = iris.data.astype(np.float32)
X = data[:, :3] #Die ersten drei der Irismessdaten werden als erklärende Variablen verwendet.
Y = data[:, 3].reshape(len(data), 1) #Der letzte sei die Zielvariable.
#Die ungeraden Daten seien die Lehrerdaten und die geraden Daten die Testdaten.
index = np.arange(Y.size)
X_train = X[index[index % 2 != 0], :] #Erklärende Variable (Lehrerdaten)
X_test = X[index[index % 2 == 0], :] #Erklärende Variable (Testdaten)
Y_train = Y[index[index % 2 != 0], :] #Objektive Variable (Lehrerdaten)
Y_test = Y[index[index % 2 == 0], :] #Zielvariable (Testdaten)

Die Daten werden durch den Tensortyp dargestellt.

import torch
X_train = torch.from_numpy(X_train).float()
X_test = torch.from_numpy(X_test).float()
Y_train = torch.from_numpy(Y_train).float()
Y_test = torch.from_numpy(Y_test).float()
X_train.shape
torch.Size([75, 3])

Kombinieren Sie die erklärenden und objektiven Variablen zu TensorDataset-Typdaten.

from torch.utils.data import TensorDataset
train = TensorDataset(X_train, Y_train)
train[0]
(tensor([4.9000, 3.0000, 1.4000]), tensor([0.2000]))

Beim Deep Learning werden Lehrerdaten in kleine "Batch" unterteilt und gelernt.

from torch.utils.data import DataLoader
train_loader = DataLoader(train, batch_size=10, shuffle=True)

Multiple lineare Regression (MLR)

Definiert eine Klasse, die eine lineare multiple Regression durchführt.

class MLR(torch.nn.Module):
    def __init__(self, n_input, n_output):
        super(MLR, self).__init__()
        self.l1 = torch.nn.Linear(n_input, n_output)

    def forward(self, x):
        return self.l1(x)

Erstellen Sie ein Objekt dieser Klasse.

model = MLR(3, 1) #Lineares multiples Regressionsmodell mit 3 Variableneingabe und 1 Variablenausgabe

Das Ziel ist es, den Fehler zu minimieren (im Deep Learning als "Verlust" bezeichnet), diesen Fehler jedoch zu definieren.

criterion = torch.nn.MSELoss() # mean square error

Wählen Sie einen Algorithmus, der den Fehler minimiert.

optimizer = torch.optim.SGD(model.parameters(), lr=0.01) #Probabilistische Gradientenabstiegsmethode

"Vorhersagen" mit einer Vorwärtsberechnung, Berechnen des Fehlers und Wiederholen des Vorgangs der Ausbreitung des Fehlers in die Rückwärtsrichtung.

from torch.autograd import Variable
loss_history = []
for epoch in range(100):
    total_loss = 0
    for x_train, y_train in train_loader:
        x_train = Variable(x_train)
        y_train = Variable(y_train)
        optimizer.zero_grad()
        y_pred = model(x_train)
        loss = criterion(y_pred, y_train)
        loss.backward()
        optimizer.step()
        total_loss += loss.item()
    loss_history.append(total_loss)
    if (epoch +1) % 10 == 0:
        print(epoch + 1, total_loss)
10 0.5098993554711342
20 0.49431246891617775
30 0.37891835160553455
40 0.38362359534949064
50 0.602457270026207
60 0.4444280909374356
70 0.41419393196702003
80 0.4345690496265888
90 0.38460623472929
100 0.3826814219355583

Haben Sie gesehen, dass der Fehler (Verlust) abnimmt? Lassen Sie uns die Geschichte veranschaulichen.

%matplotlib inline
import matplotlib.pyplot as plt
plt.plot(loss_history)
[<matplotlib.lines.Line2D at 0x7fc33444d128>]

output_54_1.png

Schauen wir uns nun das y-y-Diagramm an, in dem die vorhergesagten und gemessenen Werte verglichen werden. Je näher es an der Diagonale liegt, desto besser ist die Vorhersage.

%matplotlib inline
import matplotlib.pyplot as plt
plt.figure(figsize=(6,6))
plt.scatter(Y_train.flatten(), model.forward(X_train).data.flatten(), alpha=0.5)
plt.plot([min(Y), max(Y)], [min(Y), max(Y)])
plt.grid()
plt.legend()
plt.xlabel('Observed')
plt.ylabel('Predicted')
plt.show()

output_56_1.png

Logistische Regression (LR)

Als nächstes führen wir eine logistische Regression durch, eine Methode zur Rückkehr zur Sigmoidfunktion (logistische Funktion), die auch als Klassifizierungsmethode verwendet wird.

Ayame-Daten

Verwenden wir dieses Mal die vier Messdaten von Ayame als erklärende Variable und die Sorten von Ayame (3 Typen) als Zielvariable.

import numpy as np
from sklearn import datasets
iris = datasets.load_iris() #Irisdaten lesen
X = iris.data.astype(np.float32) #4 Variablen als erklärende Variablen
Y = iris.target #Ayame-Sorten (3 Arten) als objektive Variablen
#Eine Sorte Iris-In heißen Vektor konvertieren.
Y_ohv = np.zeros(3 * Y.size).reshape(Y.size, 3).astype(np.float32)
for i in range(Y.size):
    Y_ohv[i, Y[i]] = 1.0 # one-hot vector
#Die ungeraden Daten seien die Lehrerdaten und die geraden Daten die Testdaten.
index = np.arange(Y.size)
X_train = X[index[index % 2 != 0], :] #Erklärende Variable (Lehrerdaten)
X_test = X[index[index % 2 == 0], :] #Erklärende Variable (Testdaten)
Y_train = Y_ohv[index[index % 2 != 0], :] #Zielvariable eins-heißer Vektor (Lehrerdaten)
Y_test = Y_ohv[index[index % 2 == 0], :] #Zielvariable eins-heißer Vektor (Testdaten)
Y_ans_train = Y[index[index % 2 != 0]] #Objektive Variable (Lehrerdaten)
Y_ans_test = Y[index[index % 2 == 0]] #Zielvariable (Testdaten)
import torch
from torch.utils.data import TensorDataset
from torch.utils.data import DataLoader

X_train = torch.from_numpy(X_train).float()
X_test = torch.from_numpy(X_test).float()
Y_train = torch.from_numpy(Y_train).float()
Y_test = torch.from_numpy(Y_test).float()

train = TensorDataset(X_train, Y_train)

train_loader = DataLoader(train, batch_size=10, shuffle=True)
train[0]
(tensor([4.9000, 3.0000, 1.4000, 0.2000]), tensor([1., 0., 0.]))
#import torch.nn.functional as F
class LR(torch.nn.Module):
    def __init__(self, n_input, n_output):
        super(LR, self).__init__()
        self.l1 = torch.nn.Linear(n_input, n_output)

    def forward(self, x):
        h1 = self.l1(x)
        h2 = torch.sigmoid(h1)
        return h2
model = LR(4, 3)
criterion = torch.nn.MSELoss()
optimizer = torch.optim.SGD(model.parameters(), lr=0.01)

from torch.autograd import Variable
loss_history = []
for epoch in range(1000):
    total_loss = 0
    for x_train, y_train in train_loader:
        x_train = Variable(x_train)
        y_train = Variable(y_train)
        optimizer.zero_grad()
        y_pred = model(x_train)
        loss = criterion(y_pred, y_train)
        loss.backward()
        optimizer.step()
        total_loss += loss.item()
    loss_history.append(total_loss)
    if (epoch +1) % 100 == 0:
        print(epoch + 1, total_loss)
100 1.63955856859684
200 1.2039469927549362
300 0.9843573123216629
400 0.9481473788619041
500 0.847799651324749
600 0.857478104531765
700 0.8010830879211426
800 0.8148728087544441
900 0.8013908714056015
1000 0.7699911445379257
%matplotlib inline
import matplotlib.pyplot as plt
plt.plot(loss_history)
[<matplotlib.lines.Line2D at 0x7fc3317298d0>]

output_65_1.png

Lassen Sie uns die richtige Antwortrate finden, wenn das Produkt mit dem maximalen Ausgabewert das "vorhergesagte Produkt" ist.

Y_pred = model.forward(X_train)
nrow, ncol = Y_pred.data.shape

count = 0
for i in range(nrow):
    cls = np.argmax(Y_pred.data[i, :])
    if cls == Y_ans_train[i]:
        count += 1

print(count, " / ", nrow, " = ", count / nrow)
65  /  75  =  0.8666666666666667

Mehrschichtiges Perzeptron (MLP)

Bisher habe ich mit Pytorch lineare multiple Regressions- und logistische Regressionsmodelle erstellt. Wenn Sie die Schicht verdicken, wird sie auf die gleiche Weise zu "tiefem Lernen". Das einfachste Modell für tiefes Lernen ist das mehrschichtige Perzeptron.

Rückgabe per MLP

import numpy as np
from sklearn import datasets
iris = datasets.load_iris() #Irisdaten lesen
data = iris.data.astype(np.float32)
X = data[:, :3] #Die ersten drei der Irismessdaten werden als erklärende Variablen verwendet.
Y = data[:, 3].reshape(len(data), 1) #Der letzte sei die Zielvariable.

#Die ungeraden Daten seien die Lehrerdaten und die geraden Daten die Testdaten.
index = np.arange(Y.size)
X_train = X[index[index % 2 != 0], :] #Erklärende Variable (Lehrerdaten)
X_test = X[index[index % 2 == 0], :] #Erklärende Variable (Testdaten)
Y_train = Y[index[index % 2 != 0], :] #Objektive Variable (Lehrerdaten)
Y_test = Y[index[index % 2 == 0], :] #Zielvariable (Testdaten)

import torch
X_train = torch.from_numpy(X_train).float()
X_test = torch.from_numpy(X_test).float()
Y_train = torch.from_numpy(Y_train).float()
Y_test = torch.from_numpy(Y_test).float()

from torch.utils.data import TensorDataset
train = TensorDataset(X_train, Y_train)

from torch.utils.data import DataLoader
train_loader = DataLoader(train, batch_size=10, shuffle=True)
#import torch.nn.functional as F
class MLPR(torch.nn.Module):
    def __init__(self, n_input, n_hidden, n_output):
        super(MLPR, self).__init__()
        self.l1 = torch.nn.Linear(n_input, n_hidden)
        self.l2 = torch.nn.Linear(n_hidden, n_output)

    def forward(self, x):
        h1 = self.l1(x)
        h2 = torch.sigmoid(h1)
        h3 = self.l2(h2)
        return h3
model = MLPR(3, 3, 1)
criterion = torch.nn.MSELoss()
optimizer = torch.optim.SGD(model.parameters(), lr=0.01)

from torch.autograd import Variable
loss_history = []
for epoch in range(1000):
    total_loss = 0
    for x_train, y_train in train_loader:
        x_train = Variable(x_train)
        y_train = Variable(y_train)
        optimizer.zero_grad()
        y_pred = model(x_train)
        loss = criterion(y_pred, y_train)
        loss.backward()
        optimizer.step()
        total_loss += loss.item()
    loss_history.append(total_loss)
    if (epoch +1) % 100 == 0:
        print(epoch + 1, total_loss)
100 0.40582243632525206
200 0.3966686334460974
300 0.4202105160802603
400 0.3585368797648698
500 0.3776881340891123
600 0.3534861374646425
700 0.40271759033203125
800 0.37439848855137825
900 0.40052078012377024
1000 0.35703002475202084
%matplotlib inline
import matplotlib.pyplot as plt
plt.plot(loss_history)
[<matplotlib.lines.Line2D at 0x7fc3316929e8>]

output_72_1.png

%matplotlib inline
import matplotlib.pyplot as plt
plt.figure(figsize=(6,6))
plt.scatter(Y_train.flatten(), model.forward(X_train).data.flatten(), alpha=0.5)
plt.plot([min(Y), max(Y)], [min(Y), max(Y)])
plt.grid()
plt.legend()
plt.xlabel('Observed')
plt.ylabel('Predicted')
plt.show()
No handles with labels found to put in legend.

output_73_1.png

Klassifizierung nach MLP

import numpy as np
from sklearn import datasets
iris = datasets.load_iris() #Irisdaten lesen
X = iris.data.astype(np.float32) #4 Variablen als erklärende Variablen
Y = iris.target #Ayame-Sorten (3 Arten) als objektive Variablen
#Eine Sorte Iris-In heißen Vektor konvertieren.
Y_ohv = np.zeros(3 * Y.size).reshape(Y.size, 3).astype(np.float32)
for i in range(Y.size):
    Y_ohv[i, Y[i]] = 1.0 # one-hot vector
#Die ungeraden Daten seien die Lehrerdaten und die geraden Daten die Testdaten.
index = np.arange(Y.size)
X_train = X[index[index % 2 != 0], :] #Erklärende Variable (Lehrerdaten)
X_test = X[index[index % 2 == 0], :] #Erklärende Variable (Testdaten)
Y_train = Y_ohv[index[index % 2 != 0], :] #Zielvariable eins-heißer Vektor (Lehrerdaten)
Y_test = Y_ohv[index[index % 2 == 0], :] #Zielvariable eins-heißer Vektor (Testdaten)
Y_ans_train = Y[index[index % 2 != 0]] #Objektive Variable (Lehrerdaten)
Y_ans_test = Y[index[index % 2 == 0]] #Zielvariable (Testdaten)
import torch
from torch.utils.data import TensorDataset
from torch.utils.data import DataLoader

X_train = torch.from_numpy(X_train).float()
X_test = torch.from_numpy(X_test).float()
Y_train = torch.from_numpy(Y_train).float()
Y_test = torch.from_numpy(Y_test).float()

train = TensorDataset(X_train, Y_train)

train_loader = DataLoader(train, batch_size=10, shuffle=True)
class MLPC(torch.nn.Module):
    def __init__(self, n_input, n_hidden, n_output):
        super(MLPC, self).__init__()
        self.l1 = torch.nn.Linear(n_input, n_hidden)
        self.l2 = torch.nn.Linear(n_hidden, n_output)

    def forward(self, x):
        h1 = self.l1(x)
        h2 = torch.sigmoid(h1)
        h3 = self.l2(h2)
        h4 = torch.sigmoid(h3)
        return h4
model = MLPC(4, 3, 3)
criterion = torch.nn.MSELoss()
optimizer = torch.optim.SGD(model.parameters(), lr=0.01)

from torch.autograd import Variable
loss_history = []
for epoch in range(5000):
    total_loss = 0
    for x_train, y_train in train_loader:
        x_train = Variable(x_train)
        y_train = Variable(y_train)
        optimizer.zero_grad()
        y_pred = model(x_train)
        loss = criterion(y_pred, y_train)
        loss.backward()
        optimizer.step()
        total_loss += loss.item()
    loss_history.append(total_loss)
    if (epoch +1) % 500 == 0:
        print(epoch + 1, total_loss)
500 1.645580604672432
1000 1.3838596642017365
1500 1.1801470965147018
2000 1.0481771975755692
2500 1.004256546497345
3000 0.9521581381559372
3500 0.9244466200470924
4000 0.8533390164375305
4500 0.845703762024641
5000 0.7936465740203857
%matplotlib inline
import matplotlib.pyplot as plt
plt.plot(loss_history)
[<matplotlib.lines.Line2D at 0x7fc331581c18>]

output_81_1.png

Y_pred = model.forward(X_train)
nrow, ncol = Y_pred.data.shape

count = 0
for i in range(nrow):
    cls = np.argmax(Y_pred.data[i, :])
    if cls == Y_ans_train[i]:
        count += 1

print(count, " / ", nrow, " = ", count / nrow)
67  /  75  =  0.8933333333333333

Auto Encoder (AE)

Ein Autoencoder ist ein neuronales Netzwerk, das zu sich selbst zurückkehrt. Der Wandler von Eingangsschicht zu Zwischenschicht wird als Codierercodierer bezeichnet, und der Wandler von Zwischenschicht zu Ausgangsschicht wird als Decodiererdecodierer bezeichnet. "Dimensionsreduktion" (Dimensionsreduktion) kann durchgeführt werden, indem die Anzahl der Neuronen in der mittleren Schicht auf weniger als die Eingabedaten reduziert wird.

import numpy as np
from sklearn import datasets
iris = datasets.load_iris() #Irisdaten lesen
data = iris.data.astype(np.float32)
X = data 

index = np.arange(Y.size)
X_train = X[index[index % 2 != 0], :] #Erklärende Variable (Lehrerdaten)
X_test = X[index[index % 2 == 0], :] #Erklärende Variable (Testdaten)

import torch
X_train = torch.from_numpy(X_train).float()
X_test = torch.from_numpy(X_test).float()

from torch.utils.data import TensorDataset
train = TensorDataset(X_train, X_train)

from torch.utils.data import DataLoader
train_loader = DataLoader(train, batch_size=10, shuffle=True)
class MLPR(torch.nn.Module):
    def __init__(self, n_input, n_hidden, n_output):
        super(MLPR, self).__init__()
        self.l1 = torch.nn.Linear(n_input, n_hidden)
        self.l2 = torch.nn.Linear(n_hidden, n_output)

    def forward(self, x):
        h1 = self.l1(x)
        h2 = torch.sigmoid(h1)
        h3 = self.l2(h2)
        return h3

    def project(self, x):
        h1 = self.l1(x)
        h2 = torch.sigmoid(h1)
        return h2
model = MLPR(4, 2, 4)
criterion = torch.nn.MSELoss()
optimizer = torch.optim.SGD(model.parameters(), lr=0.01)

from torch.autograd import Variable
loss_history = []
for epoch in range(500):
    total_loss = 0
    for x_train, y_train in train_loader:
        x_train = Variable(x_train)
        y_train = Variable(y_train)
        optimizer.zero_grad()
        y_pred = model(x_train)
        loss = criterion(y_pred, y_train)
        loss.backward()
        optimizer.step()
        total_loss += loss.item()
    loss_history.append(total_loss)
    if (epoch +1) % 50 == 0:
        print(epoch + 1, total_loss)
50 7.260494828224182
100 3.8141910433769226
150 2.6670321971178055
200 1.9922174364328384
250 1.538402482867241
300 1.2299609556794167
350 1.1305854469537735
400 1.0665423274040222
450 1.0088475532829762
500 0.9823619686067104
%matplotlib inline
import matplotlib.pyplot as plt
plt.plot(loss_history)
[<matplotlib.lines.Line2D at 0x7fc33154e2e8>]

output_87_1.png

Zeigen Sie die auf die mittlere Ebene projizierten Daten an

latent = model.project(X_train)
%matplotlib inline
import matplotlib.pyplot as plt
plt.scatter(latent.data[0:50, 0], latent.data[0:50, 1], alpha=0.5)
plt.scatter(latent.data[50:100, 0], latent.data[50:100, 1], alpha=0.5)
plt.scatter(latent.data[100:150, 0], latent.data[100:150, 1], alpha=0.5)
plt.grid()

output_90_0.png

Aufgabe

Recommended Posts

Mit PyTorch viel regeln, von linearer multipler Regression bis hin zu logistischer Regression, mehrschichtigem Perzeptron und Autoencoder
Lineare multiple Regression, logistische Regression, mehrschichtiges Perzeptron, Auto-Encoder, Chainer Yo!
[Maschinelles Lernen] Verstehen der linearen multiplen Regression sowohl aus Scikit-Lernen als auch aus Mathematik
Erster TensorFlow (überarbeitete Ausgabe) - Lineare und logistische Regression
Lernen Sie während der Implementierung mit Scipy die Grundlagen der logistischen Regression und des mehrschichtigen Perzeptrons
Einführung in OPTIMIZER ~ Von der linearen Regression über Adam bis Eva
"Lineare Regression" und "Probabilistische Version der linearen Regression" in Python "Bayes lineare Regression"