SAMSUNG 042024 Advertisement SAMSUNG 042024 Advertisement SAMSUNG 042024 Advertisement

ML v Pythone 15 – neurónové siete na klasifikačné úlohy

0

V prípade úloh tohoto typu nás zaujíma, čo to je, prípadne či nastane, alebo nenastane daná situácia.

Binárna klasifikácia - cieľ môže byť jednou z dvoch možností, napr. áno alebo nie. Napríklad či je huba jedlá, alebo nie je, či sledovaná osoba ochorie na danú chorobu, či bude schopná splácať úver a podobne. Zisťujeme to na základe zadaných parametrov.

Multi-class klasifikácia - cieľ identifikujeme výberom z  viac ako dvoch možností. Napríklad o aký predmet, či zviera sa jedná, či je na obrázku pes, mačka, alebo morča a podobne.

Klasifikácia viacerých značiek (multi-label ) - cieľu možno priradiť viac ako jednu možnosť. Napríklad článok, či video môžeme zaradiť do viacerých kategórií. Typickým príkladom je jedlo a cestovanie

Video s príkladmi

Príklad binárnej klasifikácie

Na vygenerovanie vzoriek využijeme knižnicu Scikit Learn, konkrétne funkciu make_blobs() na generovanie zhlukov bodov

https://scikit-learn.org/stable/modules/generated/sklearn.datasets.make_blobs.html

import torch
import matplotlib.pyplot as plt
from sklearn.datasets import make_blobs
from sklearn.model_selection import train_test_split
 
n_zhlukov = 2  #počet zhlukov
X, y = make_blobs(n_samples=1000, centers=n_zhlukov, cluster_std=1.3, random_state=42)
# random_state - inicializácia generátora náhodných čísel pre opakovanie experimentu
 
# vizualizácia
plt.figure(figsize=(10, 7))
plt.scatter(X[:, 0], X[:, 1], c=y, cmap=plt.cm.RdYlGn);

X - súradnice bodov

y - zaradenie do kategórie zelené, alebo červené

Údaje sú v poliach NumPy, pre výpočty s využitím knižnice PyTorch ich konvertujeme na tenzory.

X = torch.from_numpy(X).type(torch.float)
y = torch.from_numpy(y).type(torch.float)
 
# výpis prvých piatich hodnôt
X[:5], y[:5]
 
---výpis---
(tensor([[-1.4228,  7.5457],
         [ 6.8209,  1.2535],
         [ 3.2147,  0.1011],
         [ 5.3196,  1.2274],
         [ 4.4053,  6.1242]]),
 tensor([0., 1., 1., 1., 1.]))

Rozdelíme údaje na trénovaciu a testovaciu množinu a na trénovacej množine natrénujeme model neurónovej siete, aby sa naučila rozpoznávať vzory. V trénovacej množine bude 80% údajov v testovacej 20 %

from sklearn.model_selection import train_test_split
 
X_train, X_test, y_train, y_test = train_test_split(X, y,  test_size=0.2, random_state=42)
len(X_train), len(X_test), len(y_train), len(y_test) # kontrola veľkosti množín
 
---výpis---
(800, 200, 800, 200)

Vytvorenie modelu neurónovej siete

Využijeme triedu nn.Module. Na výpočet uprednostníme GPU ak máme k dispozícii kartu NVIDIA, takúto relatívne jednoduchú úlohu však v pohode zvládne aj CPU

Úlohou modelu je na základe vstupov X predpovedať výstupy y. Nakoľko model sa učí na známych prípadoch jedná sa o supervised learning.

V konštruktore vytvoríme dve nn.Linear vrstvy. Prvá vrstva self.layer_1 má 2 vstupné funkcie a vytvára 5 výstupných funkcií. Budeme teda využívať 5 skrytých neurónov. To umožní modelu učiť sa vzory z piatich čísel namiesto iba dvoch čísel, čo môže viesť k lepším výstupom. Zdôrazňujeme, že to môže a nemusí fungovať. Preto počet skrytých neurónov nastavíme ako parameter. Platí, že ďalšia vrstva, v našom prípade self.layer_2, musí mať rovnaké in_features ako predchádzajúca vrstva out_features.

S experimentovaním ohľadne počtu jednotiek skrytej vstvy sa môžete interaktívne pohrať tu https://playground.tensorflow.org/

Definujeme tiež metódu forward() na dopredný výpočet modelu

Model má dva vstupy (súradnice bodov x a y), 5 neurónov v skrytej vrstve a jeden výstup

import torch
from torch import nn
 
hidden_units =5 # počet skrytých neurónov
 
class Model1(nn.Module):
    def __init__(self):    # konštruktor
        super().__init__() # voláme konštruktor rodičovskej triedy
        # skúsime dve lineárne vrstvy
        self.layer_1 = nn.Linear(in_features=2, out_features=hidden_units) # 2 vstupné a 5  výstupných parametrov
        self.layer_2 = nn.Linear(in_features=hidden_units, out_features=1) # 5 vstupných a 1 výstupný parameter
 
    def forward(self, x):
        # výstup 2. vrstvy, ktorá má ako vstup výsp z prvej vrstvy
        return self.layer_2(self.layer_1(x))

Vytvoríme inštanciu triedy modelu

# inštancia modelu
model_1 = Model1()
model_1
 
---výpis---
Model1(
  (layer_1): Linear(in_features=2, out_features=5, bias=True)
  (layer_2): Linear(in_features=5, out_features=1, bias=True)
)

Definujeme stratovú funkciu a optimizér Keďže pracujeme s problémom binárnej klasifikácie, použime funkciu binary cross entropy los, čiže funkciu straty binárnej krížovej entropie. Funkcia zisťuje, ako nesprávne sú predpovede modelu, čím vyššia je strata, tým horší je model.

PyTorch má dve implementácie binárnej krížovej entropie:

torch.nn.BCELoss() - vytvára stratovú funkciu, ktorá meria binárnu krížovú entropiu medzi cieľom a vstupom

torch.nn.BCEWithLogitsLoss() funguje rovnako avšak má zabudovanú sigmoidnú vrstvu (nn.Sigmoid), takže by mala byť stabilnejšia

Pre optimalizátor použijeme torch.optim.SGD() na optimalizáciu parametrov modelu s rýchlosťou učenia 0,1.

loss_fn = nn.BCEWithLogitsLoss() # so sigmoidnnou vrstvou
# loss_fn = nn.BCELoss()
optimizer = torch.optim.SGD(params=model_1.parameters(), lr=0.1)

Skúsime predpovede zatiaľ nenatrénovaného modelu

Logity sú nenormalizované predpovede modelu. Sú výstupom metódy forward(). Kým model nebol trénovaný, tieto výstupy sú v podstate náhodné. V štatistike je funkcia logit kvantilovou funkciou spojenou so štandardnou logistickou distribúciou. Má mnoho použití pri analýze údajov a strojovom učení, najmä pri transformáciách údajov. Aby sme dostali nespracované výstupy (logity) modelu do podoby v ktorej ich môžeme porovnávať s výsledkami použijeme aktivačnú funkciu sigmoid.

Reálne výstupy majú hodnotu 0, alebo 1, výstupy netrénovaného modelu sa pohybujú okolo 0,5. Čím bližšie je hodnota k 0, tým viac si model myslí, že vzorka patrí do triedy 0, čím bližšie k 1, tým viac si model myslí, že vzorka patrí do triedy 1

y_logits = model_1(X_test)[:5]
print (y_logits)
y_predpoved = torch.sigmoid(y_logits)
print(y_predpoved)
 
---výpis---
tensor([[0.2127],
        [0.1823],
        [0.1463],
        [0.1845],
        [0.2230]], grad_fn=)
tensor([[0.5530],
        [0.5455],
        [0.5365],
        [0.5460],
        [0.5555]], grad_fn=)

Trénovanie modelu

Slučka obsahuje tieto kroky:

Dopredný prechod - model prejde všetkými trénovacími údajmi a vykoná výpočty funkcie forward().

Výpočet straty - výstupy modelu, čiže predpovede sa porovnajú s výsledkami aby sa zistilo ako sa predpovede líšia od pravdy a vyhodnotia sa, aby sa zistilo, nakoľko sú nesprávne.

Nulové gradienty - gradienty optimalizátorov sú nastavené na nulu, takže je možné ich prepočítať pre konkrétny tréningový krok.

Backpropagation čiže spätné šírenie pri strate, Vypočíta sa gradient straty vzhľadom na každý parameter modelu, ktorý sa má aktualizovať

Aktualizácia optimalizátora (gradient descent čiže klesanie gradientu) Aktualizujú sa parametre s ohľadom na gradienty strát, aby sa zlepšili.

torch.manual_seed(42)
 
epochs = 100 # počet iterácií - koľkokrát model prechádza tréningové dáta
 
# tréning
# -------
for epoch in range(epochs):
    model_1.train()
    y_logits = model_1(X_train).squeeze() # squeeze
    y_pred = torch.round(torch.sigmoid(y_logits)) # forward pass
    loss = loss_fn(y_logits, y_train) # aplikované na logit
    optimizer.zero_grad()
    loss.backward()
    optimizer.step()
 
    # testovanie
    # ----------
    model_1.eval()
    with torch.inference_mode():
        test_logits = model_1(X_test).squeeze()  # Forward pass
        test_pred = torch.round(torch.sigmoid(test_logits))
        test_loss = loss_fn(test_logits, y_test)
 
    # výpis priebehu
    if epoch % 10 == 0:
        print(f"Iterácia: {epoch} - Loss: {loss:.5f},  Test loss: {test_loss:.5f}")
 
---výpis---
Iterácia: 0 - Loss: 0.71093,  Test loss: 0.24971
Iterácia: 10 - Loss: 0.04977,  Test loss: 0.03926
Iterácia: 20 - Loss: 0.02748,  Test loss: 0.02068
...
Iterácia: 80 - Loss: 0.00901,  Test loss: 0.00503
Iterácia: 90 - Loss: 0.00826,  Test loss: 0.00444

Oveľa názornejšie to bude, keď vizualizujeme hranice rozhodovania. Vytvoríme na tento účel funkciu, ktorá bude univerzálna pre binárnu aj multiclass kategorizáciu

import numpy as np
 
# vykreslíme graf hraníc rozhodovania
def graf_hranic_rozhodovania(model: torch.nn.Module, X_tr: torch.Tensor, y_tr: torch.Tensor, X_te: torch.Tensor, y_te: torch.Tensor):
    def hranice_rozhodovania(X: torch.Tensor, y: torch.Tensor):
       # rozsah hodnôt (grafu) a mierka
       x_min, x_max = X[:, 0].min() - 0.1, X[:, 0].max() + 0.1
       y_min, y_max = X[:, 1].min() - 0.1, X[:, 1].max() + 0.1
       xx, yy = np.meshgrid(np.linspace(x_min, x_max, 101), np.linspace(y_min, y_max, 101))
 
       X_to_pred_on = torch.from_numpy(np.column_stack((xx.ravel(), yy.ravel()))).float()
 
       # predpovede
       model.eval()
       with torch.inference_mode():
           y_logits = model(X_to_pred_on)
 
       # binárna, alebo multiclass kategorizácia
       if len(torch.unique(y)) == 2:
           y_pred = torch.round(torch.sigmoid(y_logits))  # binarna
       else:
           y_pred = torch.softmax(y_logits, dim=1).argmax(dim=1)  # mutli-class
 
       # reshape
       y_pred = y_pred.reshape(xx.shape).detach().numpy()
       plt.contourf(xx, yy, y_pred, cmap=plt.cm.RdYlGn, alpha=0.7)
       plt.scatter(X[:, 0], X[:, 1], c=y, s=40, cmap=plt.cm.RdYlGn)
       plt.xlim(xx.min(), xx.max())
       plt.ylim(yy.min(), yy.max())
 
 
    plt.figure(figsize=(10, 5))
    plt.subplot(1, 2, 1)
    plt.title("Train")
    hranice_rozhodovania(X_tr, y_tr)
    plt.subplot(1, 2, 2)
    plt.title("Test")
    hranice_rozhodovania(X_te, y_te)

Vykreslíme hranice rozhodovania

graf_hranic_rozhodovania(model_1, X_train, y_train, X_test, y_test)

Príklad multi-class klasifikácie

Na vygenerovanie vzoriek využijeme knižnicu Scikit Learn, konkrétne funkciu make_blobs() na generovanie zhlukov bodov

https://scikit-learn.org/stable/modules/generated/sklearn.datasets.make_blobs.html

import torch
import matplotlib.pyplot as plt
from sklearn.datasets import make_blobs
from sklearn.model_selection import train_test_split
 
 
n_zhlukov = 3  #počet zhlukov
X, y = make_blobs(n_samples=1000, centers=n_zhlukov, cluster_std=1.5, random_state=42)
 
# vizualizácia
plt.figure(figsize=(10, 7))
plt.scatter(X[:, 0], X[:, 1], c=y, cmap=plt.cm.RdYlGn);

 

# konverzia na tenzory
X = torch.from_numpy(X).type(torch.float)
y = torch.from_numpy(y).type(torch.LongTensor)
 
# rozdelenie do testovacej a trénovacej množinu 80% - 20%
X_train, X_test, y_train, y_test = train_test_split(X, y,  test_size=0.2, random_state=42)
 
# Model neurónovej siete má tri vrstvy
class Model2(nn.Module):
    def __init__(self, input_features, output_features, hidden_units=8): # konštruktor
        super().__init__()  # povinné volanie konštruktora rodičovskej triedy
        self.linear_layer_stack = nn.Sequential(
            nn.Linear(in_features=input_features, out_features=hidden_units),
            nn.Linear(in_features=hidden_units, out_features=hidden_units),
            nn.Linear(in_features=hidden_units, out_features=output_features),
        )
 
    def forward(self, x):
        return self.linear_layer_stack(x)
 
# vytvorenie inštancie modelu
# Model má dva vstupy (súradnice bodov x a y), 8 neurónov v skrytej vrstve a tri výstupy (toľko je zhlukov)
model_2 = Model2(2, n_zhlukov, hidden_units=8)
model_2
 
---výpis---
Model2(
  (linear_layer_stack): Sequential(
    (0): Linear(in_features=2, out_features=8, bias=True)
    (1): Linear(in_features=8, out_features=8, bias=True)
    (2): Linear(in_features=8, out_features=3, bias=True)
  )
)

Funkcia softmax vypočíta pravdepodobnosť, že každá predikčná trieda je skutočne predpovedanou triedou v porovnaní so všetkými ostatnými možnými triedami.

# stratová funkcia a optimizér
loss_fn = nn.CrossEntropyLoss()
optimizer = torch.optim.SGD(model_2.parameters(), lr=0.1)
 
torch.manual_seed(42)
 
epochs = 100 # počet iterácií - koľkokrát model prechádza tréningové dáta
 
# tréning
# -------
for epoch in range(epochs):
    model_2.train()
    y_logits = model_2(X_train)
    y_pred = torch.softmax(y_logits, dim=1).argmax(dim=1) # forward pass
    loss = loss_fn(y_logits, y_train) # aplikované na logit
    optimizer.zero_grad()
    loss.backward()
    optimizer.step()
 
    # testovanie
    # ----------
    model_2.eval()
    with torch.inference_mode():
        test_logits = model_2(X_test)  # Forward pass
        test_pred = torch.softmax(test_logits, dim=1).argmax(dim=1)
        test_loss = loss_fn(test_logits, y_test)
 
    # výpis priebehu
    if epoch % 10 == 0:
        print(f"Iterácia: {epoch} - Loss: {loss:.5f},  Test loss: {test_loss:.5f}")
 
---výpis---
Iterácia: 0 - Loss: 0.65192,  Test loss: 0.19101
Iterácia: 10 - Loss: 0.03857,  Test loss: 0.03204
Iterácia: 20 - Loss: 0.02090,  Test loss: 0.01749
Iterácia: 30 - Loss: 0.01474,  Test loss: 0.01227
Iterácia: 40 - Loss: 0.01163,  Test loss: 0.00962
Iterácia: 50 - Loss: 0.00976,  Test loss: 0.00802
Iterácia: 60 - Loss: 0.00852,  Test loss: 0.00695
Iterácia: 70 - Loss: 0.00763,  Test loss: 0.00619
Iterácia: 80 - Loss: 0.00696,  Test loss: 0.00561
Iterácia: 90 - Loss: 0.00644,  Test loss: 0.00516
 
# vizualizácia
graf_hranic_rozhodovania(model_2, X_train, y_train, X_test, y_test)

Príklad binárnej klasifikácie 2

Dosiaľ tvorili hranice medzi zhlukmi objektov priamky. Ukážeme príklad, keď to bude krivka. Na vygenerovanie vzoriek využijeme knižnicu Scikit Learn, konkrétne funkciu na generovanie datasetov make_circles

https://scikit-learn.org/stable/modules/generated/sklearn.datasets.make_circles.html

Táto funkcia generuje dva kruhy menší vo vnútri väčšieho, pričom každý z kruhov tvorí zadaný počet vzoriek - bodov so súradnicami x a y

import matplotlib.pyplot as plt
import torch
from torch import nn
from sklearn.datasets import make_circles
from sklearn.model_selection import train_test_split
 
n_vzoriek = 1000
X, y = make_circles(n_vzoriek, noise=0.03, random_state=42, factor = 0.7) # factor udáva vzdialenosť kruhov
# c=y - mapovanie farieb na hodnoty y
 
plt.figure(figsize=(7, 7))
plt.scatter(X[:, 0], X[:, 1], c=y, cmap=plt.cm.RdYlGn);

Vytvoríme neurónovú sieť na odlíšenie bodov vo vonkajšom červenom (y=0) a vnútornom zelenom (y=1) kruhu.

Údaje sú v poliach NumPy, pre výpočty s využitím knižnice PyTorch ich konvertujeme na tenzory.

X = torch.from_numpy(X).type(torch.float)
y = torch.from_numpy(y).type(torch.float)
 
# výpis prvých piatich hodnôt
X[:5], y[:5]
 
---výpis---
(tensor([[ 0.6577,  0.2054],
         [-0.6575,  0.1370],
         [-0.7162,  0.1607],
         [-0.3512,  0.6024],
         [ 0.4422, -0.8967]]),
 tensor([1., 1., 1., 1., 0.]))
 
# Rozdelíme údaje na trénovaciu a testovaciu množinu
X_train, X_test, y_train, y_test = train_test_split(X, y,  test_size=0.2, random_state=42)
 
hidden_units =5 # počet skrytých neurónov
 
#Model neurónovej siete
class Model3(nn.Module):
    def __init__(self):    # konštruktor
        super().__init__() # voláme konštruktor rodičovskej triedy
        # skúsime dve lineárne vrstvy
        # moc to fungovať nebude body sú nie na priamke, ale na kružnici
        self.layer_1 = nn.Linear(in_features=2, out_features=hidden_units) # 2 vstupné a 5  výstupných parametrov
        self.layer_2 = nn.Linear(in_features=hidden_units, out_features=1) # 5 vstupných a 1 výstupný parameter
 
    def forward(self, x):
        # výstup 2. vrstvy, ktorá má ako vstup výsp z prvej vrstvy
        return self.layer_2(self.layer_1(x))
 
# inštancia modelu
model_3 = Model3()
model_3
 
---výpis---
output
Model3(
  (layer_1): Linear(in_features=2, out_features=5, bias=True)
  (layer_2): Linear(in_features=5, out_features=1, bias=True)
)
 
# definujeme stratovú funkciu a optimizér
loss_fn = nn.BCEWithLogitsLoss() # so sigmoidnnou vrstvou
# loss_fn = nn.BCELoss()
optimizer = torch.optim.SGD(params=model_3.parameters(), lr=0.1)
 
# vysvetlenie squeeze - zredukuje dimenzie
y_preds = torch.round(y_predpoved)
print("y_preds =",y_preds)
print("y_preds-squeze() =",y_preds.squeeze())
 
---výpis---
y_preds = tensor([[1.],
        [1.],
        [1.],
        [1.],
        [1.]], grad_fn=)
y_preds-squeze() = tensor([1., 1., 1., 1., 1.], grad_fn=)
 
torch.manual_seed(42)
 
epochs = 200 # počet iterácií - koľkokrát model prechádza tréningové dáta
 
# tréning
# -------
for epoch in range(epochs):
    model_3.train()
    y_logits = model_3(X_train).squeeze() # squeeze
    y_pred = torch.round(torch.sigmoid(y_logits)) # forward pass
    loss = loss_fn(y_logits, y_train) # aplikované na logit
    optimizer.zero_grad()
    loss.backward()
    optimizer.step()
 
    # testovanie
    # ----------
    model_3.eval()
    with torch.inference_mode():
        test_logits = model_3(X_test).squeeze()  # Forward pass
        test_pred = torch.round(torch.sigmoid(test_logits))
        test_loss = loss_fn(test_logits, y_test)
 
    # výpis priebehu
    if epoch % 10 == 0:
        print(f"Iterácia: {epoch} - Loss: {loss:.5f},  Test loss: {test_loss:.5f}")
 
---výpis---
Iterácia: 0 - Loss: 0.69566,  Test loss: 0.69720
Iterácia: 10 - Loss: 0.69399,  Test loss: 0.69615
Iterácia: 20 - Loss: 0.69338,  Test loss: 0.69587
...
Iterácia: 180 - Loss: 0.69297,  Test loss: 0.69530
Iterácia: 190 - Loss: 0.69297,  Test loss: 0.69527

Presnosť sa tréningom nezlepšuje. Prečo? To nám prezradí vizualizácia

# vizualizácia

graf_hranic_rozhodovania(model_3, X_train, y_train, X_test, y_test)

Model NS v aktuálnej podobe sa pokúša rozdeliť červené a zelené bodky pomocou hranice v tvare priamky. To vysvetľuje 50% presnosť. Kbody sú ale rozmiestnené v kruhoch. Model v tejto podobe nevyhovuje.

Vylepšenie modelu

Čo môžeme urobiť?

Pridanie ďalších vrstiev alebo prehĺbenie NS - každá vrstva potenciálne zlepšuje schopnosti učenia modelu, vie sa naučiť nový vzor v údajoch.

Pridanie skrytých neurónov alebo rozšírenie siete - viac skrytých jednotiek na vrstvu znamená potenciálne zlepšenie učebných schopností modelu

Dlhší tréning - počas väčšieho počtu iterácií by sa model mohol viac dozvedieť

Zmena aktivačnej funkcie - na niektoré prípady sa viac hodí snelineárna aktivačná funkcia

Zmena rýchlosti učenia - rýchlosť učenia optimalizátora, udáva ako model v každom kroku zmení parametre

Zmena stratovej funkcie - rôzne problémy vyžadujú rôzne stratové funkcie.

Pomôže model ktorý bude akceptovať nelineárny priebeh údajov, v našom prípade sú usporiadané do kruhov. Použijeme nelineárnu aktivačnú funkciu ReLu.

class Model4(nn.Module):
    def __init__(self):
        super().__init__()
        self.layer_1 = nn.Linear(in_features=2, out_features=10)
        self.layer_2 = nn.Linear(in_features=10, out_features=10)
        self.layer_3 = nn.Linear(in_features=10, out_features=1)
        self.relu = nn.ReLU()
 
    def forward(self, x):
      # medzi vrstvami je aktivačná funkcia ReLu
       return self.layer_3(self.relu(self.layer_2(self.relu(self.layer_1(x)))))
 
model_4 = Model4()
print(model_4)
 
---výpis---
Model4(
  (layer_1): Linear(in_features=2, out_features=10, bias=True)
  (layer_2): Linear(in_features=10, out_features=10, bias=True)
  (layer_3): Linear(in_features=10, out_features=1, bias=True)
  (relu): ReLU()
)

stratová funkcia aj optimizer zostávajú rovnaké

loss_fn = nn.BCEWithLogitsLoss() # so sigmoidnnou vrstvou
optimizer = torch.optim.SGD(params=model_4.parameters(), lr=0.1)

ideme trénovať pre 1000 a potom pre 2000 iterácií, kód tréningovej slučky je rovnaký

torch.manual_seed(42)
 
epochs = 2000 # počet iterácií - koľkokrát model prechádza tréningové dáta
 
# tréning
# -------
for epoch in range(epochs):
    model_4.train()
    y_logits = model_4(X_train).squeeze() # squeeze
    y_pred = torch.round(torch.sigmoid(y_logits)) # forward pass
    loss = loss_fn(y_logits, y_train) # aplikované na logit
    optimizer.zero_grad()
    loss.backward()
    optimizer.step()
 
    # testovanie
    # ----------
    model_4.eval()
    with torch.inference_mode():
        test_logits = model_4(X_test).squeeze()  # Forward pass
        test_pred = torch.round(torch.sigmoid(test_logits))
        test_loss = loss_fn(test_logits, y_test)
 
    # výpis priebehu
    if epoch % 100 == 0:
        print(f"Iterácia: {epoch} - Loss: {loss:.5f},  Test loss: {test_loss:.5f}")
 
---výpis---
Iterácia: 0 - Loss: 0.69303,  Test loss: 0.69321
Iterácia: 100 - Loss: 0.68938,  Test loss: 0.68911
Iterácia: 200 - Loss: 0.68490,  Test loss: 0.68423
...
Iterácia: 1700 - Loss: 0.01438,  Test loss: 0.02129
Iterácia: 1800 - Loss: 0.01258,  Test loss: 0.01875
Iterácia: 1900 - Loss: 0.01116,  Test loss: 0.01673

to je oveľa lepšie. Ukážeme vizualizáciu hraníc rozhodovania vrátane predpovedí pre 1000 iterácií

# predpovede by sa robili takto
model_4.eval()
with torch.inference_mode():
    y_predpovede = torch.round(torch.sigmoid(model_4(X_test))).squeeze()
 
# vizualizácia
graf_hranic_rozhodovania(model_4, X_train, y_train, X_test, y_test)

pre 2000 iterácií

Príklad pre body zoskupené do polkruhov

Na vygenerovanie vzoriek využijeme knižnicu Scikit Learn, konkrétne funkciu na generovanie datasetov make_moons

https://scikit-learn.org/stable/modules/generated/sklearn.datasets.make_moons

Táto funkcia generuje dva polkruhy, pričom každý z kruhov tvorí zadaný počet vzoriek - bodov so súradnicami x a y

from sklearn.datasets import make_moons
import matplotlib.pyplot as plt
 
n_vzoriek = 1000
X, y = make_moons(n_samples=n_vzoriek, noise=0.07, random_state=n_vzoriek)
 
plt.figure(figsize=(10, 7))
plt.scatter(X[:, 0], X[:, 1], c=y, cmap=plt.cm.RdYlGn);

#konverzia na tenzory
X = torch.tensor(X, dtype=torch.float)
y = torch.tensor(y, dtype=torch.float)
 
# rozdelenie na testovaciu a tréningovú množinu 80% - 20%
from sklearn.model_selection import train_test_split
X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.2, random_state=42)
 
class Model5(nn.Module):
    def __init__(self, in_features, out_features, hidden_units):
        super().__init__()
        self.layer1 = nn.Linear(in_features=in_features, out_features=hidden_units)
        self.layer2 = nn.Linear(in_features=hidden_units, out_features=hidden_units)
        self.layer3 = nn.Linear(in_features=hidden_units, out_features=out_features)
        self.relu = nn.ReLU()
 
    def forward(self, x):
        return self.layer3(self.relu(self.layer2(self.relu(self.layer1(x)))))
 
model_5 = Model5(in_features=2, out_features=1,hidden_units=10)
model_5
 
---výpis---
Model5(
  (layer1): Linear(in_features=2, out_features=10, bias=True)
  (layer2): Linear(in_features=10, out_features=10, bias=True)
  (layer3): Linear(in_features=10, out_features=1, bias=True)
  (relu): ReLU()
)
 
# stratová funkcia a optimizér
loss_fn = nn.BCEWithLogitsLoss()
optimizer = torch.optim.SGD(params=model_5.parameters(), lr=0.1)
 
torch.manual_seed(42)
 
epochs=1000
 
# tréning
# -------
for epoch in range(epochs):
  model_5.train()
  y_logits = model_5(X_train).squeeze()
  y_pred_probs = torch.sigmoid(y_logits)
  y_pred = torch.round(y_pred_probs)
  loss = loss_fn(y_logits, y_train) # loss = compare model raw outputs to desired model outputs
  optimizer.zero_grad()
  loss.backward()
  optimizer.step()
 
# testovanie
# ----------
  model_5.eval()
  with torch.inference_mode():
    test_logits = model_5(X_test).squeeze()
    test_pred = torch.round(torch.sigmoid(test_logits))
    test_loss = loss_fn(test_logits, y_test)
 
  if epoch % 100 == 0:
    print(f"Iterácia: {epoch} - Loss: {loss:.2f}  Test loss: {test_loss:.2f} ")
 
---výpis---
Iterácia: 0 - Loss: 0.70  Test loss: 0.69
Iterácia: 100 - Loss: 0.40  Test loss: 0.39
Iterácia: 200 - Loss: 0.24  Test loss: 0.24
...
Iterácia: 800 - Loss: 0.04  Test loss: 0.04
Iterácia: 900 - Loss: 0.03  Test loss: 0.03
 
# Predpovede
model_5.eval()
with torch.inference_mode():
    y_logits = model_5(X_test)
 
# vizualizácia
graf_hranic_rozhodovania(model_5, X_train, y_train, X_test, y_test))

Príklad pre zhluky bodov v špirále

# zhluky bodov v špirále
import numpy as np
import matplotlib.pyplot as plt
import torch
 
np.random.seed(42)
K = 3 # počet zhlukov - ramien špirály
N = 100 # počet bodov v zhluku
X = np.zeros((N*K,2)) # dvojrozmerná matica údajov
y = np.zeros(N*K, dtype='uint8') # výstup
for j in range(K):
  ix = range(N*j,N*(j+1))
  r = np.linspace(0.0,1,N) # polomer
  t = np.linspace(j*4,(j+1)*4,N) + np.random.randn(N)*0.2 # rozptyl
  X[ix] = np.c_[r*np.sin(t), r*np.cos(t)]
  y[ix] = j
 
# vizualizácia
plt.scatter(X[:, 0], X[:, 1], c=y, s=40, cmap=plt.cm.RdYlGn)
plt.show()

#konverzia na tenzory
X = torch.from_numpy(X).type(torch.float)
y = torch.from_numpy(y).type(torch.LongTensor)
 
# rozdelenie na testovaciu a tréningovú množinu 80% - 20%
from sklearn.model_selection import train_test_split
X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.2, random_state=42)
 
class Model6(nn.Module):
  def __init__(self):
    super().__init__()
    self.linear1 = nn.Linear(in_features=2, out_features=10)
    self.linear2 = nn.Linear(in_features=10, out_features=10)
    self.linear3 = nn.Linear(in_features=10, out_features=3)
    self.relu = nn.ReLU()
 
  def forward(self, x):
    return self.linear3(self.relu(self.linear2(self.relu(self.linear1(x)))))
 
model_6 = Model6()
model_6
 
---výpis---
Model6(
  (linear1): Linear(in_features=2, out_features=10, bias=True)
  (linear2): Linear(in_features=10, out_features=10, bias=True)
  (linear3): Linear(in_features=10, out_features=3, bias=True)
  (relu): ReLU()
)
 
# stratová funkcia a optimizér
loss_fn = nn.CrossEntropyLoss()
optimizer = torch.optim.Adam(model_6.parameters(), lr=0.02)
 
torch.manual_seed(42)
 
epochs=1000
 
# tréning
# -------
for epoch in range(epochs):
  model_6.train()
  y_logits = model_6(X_train)
  y_pred_probs = torch.sigmoid(y_logits)
  y_pred = torch.softmax(y_logits, dim=1).argmax(dim=1)
  loss = loss_fn(y_logits, y_train)
  optimizer.zero_grad()
  loss.backward()
  optimizer.step()
 
# testovanie
# ----------
  model_6.eval()
  with torch.inference_mode():
    test_logits = model_6(X_test)
    test_pred = torch.softmax(test_logits, dim=1).argmax(dim=1)
    test_loss = loss_fn(test_logits, y_test)
 
  if epoch % 100 == 0:
    print(f"Iterácia: {epoch} - Loss: {loss:.2f}  Test loss: {test_loss:.2f} ")
 
---výpis---
Iterácia: 0 - Loss: 1.12  Test loss: 1.10
Iterácia: 100 - Loss: 0.45  Test loss: 0.53
Iterácia: 200 - Loss: 0.12  Test loss: 0.09
Iterácia: 300 - Loss: 0.07  Test loss: 0.02
Iterácia: 400 - Loss: 0.05  Test loss: 0.01
Iterácia: 500 - Loss: 0.04  Test loss: 0.01
Iterácia: 600 - Loss: 0.03  Test loss: 0.01
Iterácia: 700 - Loss: 0.03  Test loss: 0.00
Iterácia: 800 - Loss: 0.02  Test loss: 0.00
Iterácia: 900 - Loss: 0.02  Test loss: 0.00
 
# vizualizácia
graf_hranic_rozhodovania(model_6, X_train, y_train, X_test, y_test)

Pre 1000 iterácií

Pre 2000 iterácií

Rekapitulácia doterajších dielov

ML v Pythone 14 – neurónová sieť na generovanie textu II

ML v Pythone 13 – vytvorenie a natrénovanie neurónovej siete ktorá rozozná či je huba jedlá

ML v Pythone 12 – neurónová sieť predpovedá výskyt cukrovky u indiánskeho kmeňa

ML v Pythone 11 – vytvorenie a učenie neurónovej siete na generovanie poviedok

ML v Pythone 10 – trénovanie neurónovej siete, príprava

ML v Pythone 9 – trénovanie neurónu

ML v Pythone 8 – príklad rozpoznávanie obrazu

ML v Pythone 7 – Využitie grafickej karty NVIDIA na výpočtovo náročné úlohy

ML v Pythone 6 – animované grafy a ich export ako video

ML v Pythone 5 – vizualizácia údajov pomocou grafov

Strojové učenie v Pythone 4 – práca s údajmi

ML v Pythone 3 – export a import údajov vo formáte CSV a Excel

Strojové učenie v Pythone 2 – knižnica Pandas na prácu s údajmi

Strojové učenie v Pythone 1 – prostredie Google Colab

Zobrazit Galériu

Luboslav Lacko

Všetky autorove články
neuronove siete strojove ucenie Python machine learning deep learning PyTorch

Pridať komentár

Mohlo by vás zaujímať

Mohlo by vás zaujímať