Realizace neuronových sítí s využitím knihovny PyTorch (2. část)

22. 4. 2025
Doba čtení: 42 minut

Sdílet

Autor: Redakce
Ukážeme si tvorbu a konfiguraci neuronové sítě, natrénování této sítě, její otestování, vizualizaci získaných výsledků atd. Taktéž se zmíníme o problému přeučení a nedoučení.

Obsah

1. Deklarace třídy představující neuronovou síť

2. Definice vrstev neuronové sítě

3. Pomocný modul pro přípravu trénovacích a testovacích dat

4. Trénink neuronové sítě

5. Třetí demonstrační příklad: trénink neuronové sítě

6. Vizualizace výsledků tréninku

7. Čtvrtý demonstrační příklad: trénink neuronové sítě se zobrazením kvality tréninku

8. Přidání dalších vrstev do neuronové sítě

9. Pátý demonstrační příklad: neuronová síť s jednou skrytou vrstvou

10. Riziko nedoučení složitější neuronové sítě

11. Šestý demonstrační příklad: neuronová síť s více skrytými vrstvami, která nebude dotrénována

12. Sedmý demonstrační příklad: vliv parametru learning_rate na rychlosti naučení sítě

13. Porovnání účelové funkce všech tří doposud použitých neuronových sítí

14. Ověření kvality neuronové sítě

15. Osmý demonstrační příklad: výpočet kvality neuronové sítě

16. Vizualizace predikce neuronové sítě: body patřící do první nebo druhé skupiny

17. Devátý demonstrační příklad: vizualizace predikce neuronové sítě

18. Výsledky získané devátým demonstračním příkladem

19. Repositář s demonstračními příklady

20. Odkazy na Internetu

1. Deklarace třídy představující neuronovou síť

Dnešní článek je, částečně na rozdíl od článku předchozího, zaměřen prakticky. Ukážeme si v něm tvorbu a konfiguraci neuronové sítě, natrénování této sítě, její otestování, vizualizaci výsledků atd. Taktéž se zmíníme o problému přeučení a nedoučení. Celý postup si ukážeme krok za krokem a z tohoto důvodu je dnešní první příklad triviální. Je v něm ukázáno, jakým způsobem se s využitím knihovny PyTorch deklaruje třída představující neuronovou síť. V té nejjednodušší podobě postačuje nadeklarovat novou třídu odvozenou od třídy torch.nn.Module:

from torch import nn
 
 
class NeuralNetwork(nn.Module):
    """Třída reprezentující neuronovou síť."""
 
    def __init__(self):
        super().__init__()
 
 
# konstrukce neuronové sítě
nn1 = NeuralNetwork()
 
# výpis základních informací o neuronové síti
print(nn1)

Po spuštění tohoto skriptu se zobrazí základní informace o této síti:

NeuralNetwork()
Poznámka: ve skutečnosti se prozatím o skutečnou síť nejedná; viz další text.

2. Definice vrstev neuronové sítě

Minule jsme si řekli, že umělé neuronové sítě se typicky skládají z vrstev neuronů. Velmi jednoduchá síť může vypadat následovně:

Obrázek 1: Uspořádání neuronů do vrstev ve feed-forward síti.

V PyTorchi je přidání nové vrstvy (resp. přesněji řečeno propojení mezi vrstvami) relativně snadné. Ukažme si tu nejjednodušší konfiguraci sítě, tj. síť, která bude mít input_dim vstupů a output_dim výstupů. Mezi vstupy a výstupy se provádí výpočet běžné afinní (lineární) transformace a v metodě forward aplikace aktivační funkce. Tím je vlastně realizována funkce umělého neuronu – váhování vstupů a přičtení biasu. Interně je tato část realizována maticí input_dim×output_dim vah a vektorem s biasy. Výpočet s využitím aktivační funkce je deklarován v metodě forward. Tento výpočet je prováděn se všemi vstupy a výsledek je poslán na výstup neuronové sítě:

from torch import nn
 
 
class NeuralNetwork(nn.Module):
    """Třída reprezentující neuronovou síť."""
 
    def __init__(self, input_dim, output_dim):
        super().__init__()
        # vrstvy neuronové sítě
        self.layer_1 = nn.Linear(input_dim, output_dim)

 
    def forward(self, x):
        # propagace hodnot přes neuronovou síť
        x = nn.functional.sigmoid(self.layer_1(x))
        return x
 
 
# konfigurace vrstev neuronové sítě
input_dim = 2
output_dim = 1
 
# konstrukce neuronové sítě
nn2 = NeuralNetwork(input_dim, output_dim)
 
# výpis základních informací o neuronové síti
print(nn2)
 
# výpis informace o vrstvě neuronové sítě
print(nn2.layer_1)
 
# výpis informace o transformační matici a biasech
print(nn2.layer_1.weight)
print(nn2.layer_1.bias)

Po spuštění se nejdříve vypíše informace o celé neuronové síti:

NeuralNetwork(
  (layer_1): Linear(in_features=2, out_features=1, bias=True)
)

Dále se vypíše informace o její jediné vrstvě:

Linear(in_features=2, out_features=1, bias=True)

A na závěr obsah transformační matice (2×1) a vektor biasů (má jediný bias). Ve výchozím nastavení jsou tyto hodnoty náhodné:

Parameter containing:
tensor([[0.2180, 0.6056]], requires_grad=True)
 
Parameter containing:
tensor([0.2079], requires_grad=True)

Tato síť tedy pro vstupy [x1, x2] provádí výpočet:

y = x1 * 0,2180 + x2 * 0,6056 + 0,2079

Což je triviální lineární transformace z roviny na přímku.

Poznámka: jak přesně pracuje funkce nn.Linear si ukážeme příště.

3. Pomocný modul pro přípravu trénovacích a testovacích dat

Pro neuronové sítě, které budeme tvořit v rámci dalších kapitol, je nutné připravit trénovací a testovací data. Základy jsme si již ukázali minule. Připomeňme si, že jsme k tomuto účelu použili funkci sklearn.datasets.make_circles určenou pro vygenerování sady bodů v rovině, přičemž každý bod patří buď do vnější nebo vnitřní kružnice (každý bod má nastaven příslušný label). Následně se sada bodů rozdělí na trénovací data a testovací data – tyto skupiny bodů se nepřekrývají a jsou ze vstupu vybrány náhodně.

pytorch-nn-1

Obrázek 2: Trénovací a testovací data získaná rozdělením bodů získanýchfunkcí make_circles.

Skript byl upraven do takové podoby, aby trénovací a testovací data vracel z funkce compute_train_and_test_data, což nám později usnadní použití tohoto modulu:

from sklearn.datasets import make_circles
from sklearn.model_selection import train_test_split
import torch
import numpy as np
from torch.utils.data import Dataset, DataLoader
 
 
# konverze původních dat z NumPy do tenzorů
class Data(Dataset):
    def __init__(self, X, y):
        self.X = torch.from_numpy(X.astype(np.float32))
        self.y = torch.from_numpy(y.astype(np.float32))
        self.len = self.X.shape[0]
 
    def __getitem__(self, index):
        return self.X[index], self.y[index]
 
    def __len__(self):
        return self.len
 
 
def compute_train_and_test_data(
    n_samples=2000, factor=0.5, noise=0.05, test_size=1 / 3
):
    samples, labels = make_circles(n_samples=n_samples, factor=factor, noise=noise)
 
    # rozdělení na trénovací a testovací množinu
    X_train, X_test, y_train, y_test = train_test_split(
        samples, labels, test_size=test_size, random_state=26
    )
 
    # trénovací a testovací sada
 
    # trénovací sada
    train_data = Data(X_train, y_train)
 
    # testovací sada
    test_data = Data(X_test, y_test)
 
    return train_data, test_data

Použití tohoto modulu je snadné:

# trénovací a testovací data
from compute_train_and_test_data import compute_train_and_test_data
 
train_data, test_data = compute_train_and_test_data()
 
print(train_data.X)
print(train_data.y)
 
print()
print(test_data.X)
print(test_data.y)

Po spuštění se vypíše matice X a vektor y pro trénovací i testovací data:

tensor([[ 0.4599,  0.0053],
        [ 0.7305,  0.6499],
        [ 0.2827,  0.4137],
        ...,
        [-0.4188, -0.3083],
        [ 0.0909, -0.5549],
        [-0.4897,  0.2897]])
tensor([1., 0., 1.,  ..., 1., 1., 1.])
 
tensor([[-0.2496,  0.9122],
        [ 0.4308,  0.2262],
        [ 0.5084,  0.2717],
        ...,
        [ 0.4003,  0.3459],
        [-0.3190, -0.9857],
        [-0.3120,  0.3337]])
tensor([0., 1., 1., 1., 1., 1., 0., 1., 0., 0., 1., 0., 0., 0., 0., 1., 0., 0.,
        ...
        ...
        ...

4. Trénink neuronové sítě

Nejzajímavější je vlastní proces tréninku (učení) neuronové sítě. Ten může probíhat několika způsoby, ovšem nejčastější je učení založené na tom, že na vstup sítě přivedeme data, u nichž dopředu známe očekávaný výsledek (takzvaná trénovací data). Neuronová síť pro tato vstupní data provede svůj odhad (z počátku náhodný, v dalším kroku velmi špatný, potom lepší atd.) a na základě rozdílů mezi odhadem sítě a očekávaným výsledkem se více či méně sofistikovanými algoritmy nepatrně pozmění váhy wi na vstupech do neuronů (včetně biasu, tedy w0).

Obrázek 3: Idealizovaný model neuronu s biasem. V průběhu tréninku se upravují váhy wi.

Konkrétní míra změn váhy na vstupech neuronů v jednotlivých vrstvách sítě je globálně řízena dalším parametrem či několika parametry, z nichž ten nejdůležitější ovlivňuje rychlost učení. Ta by neměla být příliš nízká (to ovšem vyžaduje objemná trénovací data nebo jejich opakování), ale ani příliš vysoká, protože by síť mohla „oscilovat“ mezi několika neoptimálními stavy. Základní algoritmus učení neuronové sítě se jmenuje backpropagation, protože se váhy skutečně mění v opačném směru – od výstupů (na něž se přivede vypočtená chyba) ke vstupům. Asi nejlépe je tento koncept popsán v článku dostupném na adrese https://mattmazur.com/2015/03/17/a-step-by-step-backpropagation-example/, tuto část za nás však vykoná knihovna PyTorch ve fázi učení zcela automaticky.

5. Třetí demonstrační příklad: trénink neuronové sítě

Trénink neuronové sítě je ukázán v dnešním třetím demonstračním příkladu. Ten je rozdělen do čtyř částí. První část již známe – ta slouží pro konstrukci neuronové sítě, která je v našem případě reprezentována objektem typu NeuralNetwork. Ve druhé části získáme trénovací data (prozatím skutečně jen trénovací data) z modulu compute_train_and_test_data popsaného ve třetí kapitole. V části třetí je provedeno vlastní učení (trénink) neuronové sítě s využitím trénovacích dat. A konečně v části čtvrté si necháme vypsat hodnoty vypočtené takzvanou účelovou funkcí (loss function), jejíž hodnoty reprezentují rozdíly mezi očekávaným výsledkem (ten při tréninku pochopitelně musíme znát) a odhadem neuronové sítě. V ideálním případě by měly tyto hodnoty postupně klesat, protože síť by měla v procesu učení zlepšovat své odhady:

from torch import nn
from torch import optim
from torch.utils.data import DataLoader
 
 
class NeuralNetwork(nn.Module):
    """Třída reprezentující neuronovou síť."""
 
    def __init__(self, input_dim, output_dim):
        super().__init__()
        # vrstvy neuronové sítě
        self.layer_1 = nn.Linear(input_dim, output_dim)
 
    def forward(self, x):
        # propagace hodnot přes neuronvou síť
        x = nn.functional.sigmoid(self.layer_1(x))
        return x
 
 
# konfigurace vrstev neuronové sítě
input_dim = 2
output_dim = 1
 
# konstrukce neuronové sítě
nn3 = NeuralNetwork(input_dim, output_dim)
 
# výpis základních informací o neuronové síti
print(nn3)
 
 
# příprava na trénink neuronové sítě
learning_rate = 0.1
loss_fn = nn.BCELoss()
 
optimizer = optim.SGD(nn3.parameters(), lr=learning_rate)
 
# trénovací data
from compute_train_and_test_data import compute_train_and_test_data
 
train_data, _ = compute_train_and_test_data()
 
# zpracovat trénovací data
batch_size = 64
train_dataloader = DataLoader(dataset=train_data, batch_size=batch_size, shuffle=True)
print("Batches: ", len(train_dataloader))
 
# vlastní trénink
print("Training started")
num_epochs = 100
loss_values = []
for epoch in range(num_epochs):
    print(f"    Epoch {epoch}: ", end="")
    last_lost_value = None
    for X, y in train_dataloader:
        optimizer.zero_grad()
 
        # dopředný tok + zpětný tok + optimalizace
        pred = nn3(X)
 
        # výpočet účelové funkce
        loss = loss_fn(pred, y.unsqueeze(-1))
        loss_values.append(loss.item())
        loss.backward()
        optimizer.step()
        last_lost_value = loss.item()
        print(".", end="")
    print(last_lost_value)
 
print("Training completed")
 
print("Loss values")
for i, loss_value in enumerate(loss_values):
    print(i, loss_value)
Poznámka: přesné významy všech prováděných kroků si podrobněji vysvětlíme příště. Nyní je nutné pouze znát celkovou strukturu skriptu.

Výsledky ukazují jednotlivé prováděné kroky:

Konstrukce neuronové sítě:

NeuralNetwork(
  (layer_1): Linear(in_features=2, out_features=1, bias=True)
)

Rozdělená trénovací data:

Batches:  21

Trénink neuronové sítě:

Training started
    Epoch 0: .....................0.7136642932891846
    Epoch 1: .....................0.7086359858512878
    Epoch 2: .....................0.7138426899909973
    Epoch 3: .....................0.71360182762146
    Epoch 4: .....................0.7031393051147461
    Epoch 5: .....................0.6998087763786316
    Epoch 6: .....................0.685001790523529
    Epoch 7: .....................0.701408326625824
    Epoch 8: .....................0.6959707140922546
    Epoch 9: .....................0.6810523271560669
    Epoch 10: .....................0.6941555738449097
    ...
    ...
    ...
    Epoch 87: .....................0.6884103417396545
    Epoch 88: .....................0.698021650314331
    Epoch 89: .....................0.6896729469299316
    Epoch 90: .....................0.691299557685852
    Epoch 91: .....................0.6931966543197632
    Epoch 92: .....................0.6909589171409607
    Epoch 93: .....................0.6942797899246216
    Epoch 94: .....................0.6978365182876587
    Epoch 95: .....................0.6871546506881714
    Epoch 96: .....................0.6888548135757446
    Epoch 97: .....................0.6873869299888611
    Epoch 98: .....................0.6864196062088013
    Epoch 99: .....................0.6999951601028442
Training completed

Hodnoty účelové funkce v průběhu tréninku:

Loss values
0 0.7395060062408447
1 0.7825191020965576
2 0.7868967652320862
3 0.786351203918457
4 0.7562863826751709
5 0.7235647439956665
6 0.742216944694519
7 0.6739267110824585
8 0.7016011476516724
9 0.7245702147483826
10 0.664133608341217
...
...
...
82 0.697323203086853
83 0.6908646821975708
84 0.6865593791007996
85 0.6937276124954224
86 0.7040309309959412
87 0.6995502710342407
88 0.7057774066925049

6. Vizualizace výsledků tréninku

Tabulka s hodnotami účelové funkce nám může prozradit, jak rychle (a zda vůbec) se síť dokáže učit. Počáteční hodnota této funkce může být vysoká (resp. přesněji řečeno blízká jedničce), protože na začátku učení jsou váhy jednotlivých neuronů nastaveny na náhodnou hodnotu. Ovšem v průběhu tréninku se na vstup sítě zapisují trénovací hodnoty, na výstupu jsou zjištěny rozdíly mezi očekávaným výsledkem a výsledkem, který poskytne síť a podle rozdílu těchto hodnot jsou postupně (od poslední vrstvy) váhy neuronů upravovány tak, aby byl další výsledek (v ideálním případě) lepší.

Neuronová síť by se tedy měla postupně zlepšovat a hodnota účelové funkce by měla postupně klesat směrem k nule. Je zde mnoho proměnných, které tento postup ovlivňují a postupně se s nimi seznámíme v rámci dalšího textu. Základem ovšem bude vizualizace účelové funkce, tj. změny její hodnoty v čase. Pokud nebude hodnota klesat ani po několika stech či tisících kroků, bude nutné změnit parametry sítě (počet vrstev, počet neuronů, typ aktivačních funkcí atd.).

7. Čtvrtý demonstrační příklad: trénink neuronové sítě se zobrazením kvality tréninku

Čtvrtý demonstrační příklad se do značné míry podobá příkladu třetímu, ovšem s tím rozdílem, že výsledky průběhu tréninku jsou zobrazeny formou grafu (poslední, pátá část skriptu). Pro vizualizaci opět použijeme, podobně jako v předchozím článku, knihovnu Matplotlib. Povšimněte si, že Matplotlib dokáže pracovat s n-dimenzionálními poli knihovny NumPy, ale nikoli už z tenzory knihovny PyTorch:

from torch import nn
from torch import optim
from torch.utils.data import DataLoader
import matplotlib.pyplot as plt
import numpy as np
 
 
class NeuralNetwork(nn.Module):
    """Třída reprezentující neuronovou síť."""
 
    def __init__(self, input_dim, output_dim):
        super().__init__()
        # vrstvy neuronové sítě
        self.layer_1 = nn.Linear(input_dim, output_dim)
 
    def forward(self, x):
        # propagace hodnot přes neuronvou síť
        x = nn.functional.sigmoid(self.layer_1(x))
        return x
 
 
# konfigurace vrstev neuronové sítě
input_dim = 2
output_dim = 1
 
# konstrukce neuronové sítě
nn4 = NeuralNetwork(input_dim, output_dim)
 
# výpis základních informací o neuronové síti
print(nn4)
 
 
# příprava na trénink neuronové sítě
learning_rate = 0.1
loss_fn = nn.BCELoss()
 
optimizer = optim.SGD(nn4.parameters(), lr=learning_rate)
 
# trénovací data
from compute_train_and_test_data import compute_train_and_test_data
 
train_data, _ = compute_train_and_test_data()
 
# zpracovat trénovací data
batch_size = 64
train_dataloader = DataLoader(dataset=train_data, batch_size=batch_size, shuffle=True)
print("Batches: ", len(train_dataloader))
 
# vlastní trénink
print("Training started")
num_epochs = 100
loss_values = []
for epoch in range(num_epochs):
    print(f"    Epoch {epoch}: ", end="")
    last_lost_value = None
    for X, y in train_dataloader:
        optimizer.zero_grad()
 
        # dopředný tok + zpětný tok + optimalizace
        pred = nn4(X)
 
        # výpočet účelové funkce
        loss = loss_fn(pred, y.unsqueeze(-1))
        loss_values.append(loss.item())
        loss.backward()
        optimizer.step()
        last_lost_value = loss.item()
        print(".", end="")
    print(last_lost_value)
 
print("Training completed")
 
step = range(len(loss_values))
 
# příprava na vykreslení grafu
fig, ax = plt.subplots(figsize=(6.4, 4.8))
plt.plot(step, np.array(loss_values))
plt.title("Průběh tréninku neuronové sítě")
plt.xlabel("Epocha")
plt.ylabel("Účelová funkce")
 
# uložení do souboru
plt.savefig("nn_4.png")
 
# vykreslení grafu
plt.show()

Ze zobrazeného grafu je patrné, že naše neuronová síť je velmi mizerná a vlastně se nedokáže skutečně natrénovat (protože vstupní data mají složité interní vztahy, složitější, než lze naučit dva neurony):

PyTorch NN

Obrázek 4: Průběh učení neuronové sítě bez skryté vrstvy.

8. Přidání dalších vrstev do neuronové sítě

Mohlo by se zdát, že větší neuronová síť (tedy více neuronů) může znamenat, že dostaneme i kvalitnější model a tím pádem i lepší výsledky. Ovšem v praxi můžeme narazit na úplný opak, a to ve chvíli, kdy se neuronová síť nedokáže správně zaučit – datová sada je buď příliš malá, nebo je neuronů tolik, že gradient při změně jejich vah je příliš malý nebo dokonce nulový. Ovšem zaměřme se nejdříve na případ, kdy vyšší počet vrstev a neuronů v těchto vrstvách má dobrý vliv na kvalitu modelu. Do nové verze naší neuronové sítě přidáme další vrstvu. Již se nebude jednat o vrstvu vstupní ani výstupní, ale o takzvanou skrytou vrstvu:

self.layer_1 = nn.Linear(input_dim, hidden_dim)
self.layer_2 = nn.Linear(hidden_dim, output_dim)

Konfigurace vrstev:

input_dim = 2
hidden_dim = 10
output_dim = 1

Na vstupu neuronové sítě jsou dva vstupy, což odpovídá dvojicím souřadnic bodů [x, y]. Výsledkem (výstupem) je jediná hodnota, která bude naznačovat, do které skupiny body patří. A skrytá vrstva bude mít deset neuronů. To je již poměrně komplikovaná síť 2→10→1 neurony, která by mohla mít lepší učící schopnosti, než první verze sítě.

Mimochodem: pochopitelně se změní i výpočet prováděný neuronovou sítí. Ten nyní může vypadat takto (v každé vrstvě použijeme odlišné aktivační funkce):

def forward(self, x):
    # propagace hodnot přes neuronvou síť
    x = torch.nn.functional.relu(self.layer_1(x))
    x = torch.nn.functional.sigmoid(self.layer_2(x))
    return x

9. Pátý demonstrační příklad: neuronová síť s jednou skrytou vrstvou

V pátém demonstračním příkladu použijeme pro trénink a vyhodnocení neuronové sítě síť s jednou skrytou vrstvou. Konfigurace sítě přesně odpovídá popisu z osmé kapitoly:

import torch
from torch import nn
from torch import optim
from torch.utils.data import DataLoader
import matplotlib.pyplot as plt
import numpy as np
 
 
class NeuralNetwork(nn.Module):
    """Třída reprezentující neuronovou síť."""
 
    def __init__(self, input_dim, hidden_dim, output_dim):
        super().__init__()
        # vrstvy neuronové sítě
        self.layer_1 = nn.Linear(input_dim, hidden_dim)
        self.layer_2 = nn.Linear(hidden_dim, output_dim)
 
    def forward(self, x):
        # propagace hodnot přes neuronvou síť
        x = torch.nn.functional.relu(self.layer_1(x))
        x = torch.nn.functional.sigmoid(self.layer_2(x))
        return x
 
 
# konfigurace vrstev neuronové sítě
input_dim = 2
hidden_dim = 10
output_dim = 1
 
# konstrukce neuronové sítě
nn5 = NeuralNetwork(input_dim, hidden_dim, output_dim)
 
# výpis základních informací o neuronové síti
print(nn5)
 
 
# příprava na trénink neuronové sítě
learning_rate = 0.1
loss_fn = nn.BCELoss()
 
optimizer = optim.SGD(nn5.parameters(), lr=learning_rate)
 
# trénovací data
from compute_train_and_test_data import compute_train_and_test_data
 
train_data, _ = compute_train_and_test_data()
 
# zpracovat trénovací data
batch_size = 64
train_dataloader = DataLoader(dataset=train_data, batch_size=batch_size, shuffle=True)
print("Batches: ", len(train_dataloader))
 
# vlastní trénink
print("Training started")
num_epochs = 100
loss_values = []
for epoch in range(num_epochs):
    print(f"    Epoch {epoch}: ", end="")
    last_lost_value = None
    for X, y in train_dataloader:
        optimizer.zero_grad()
 
        # dopředný tok + zpětný tok + optimalizace
        pred = nn5(X)
 
        # výpočet účelové funkce
        loss = loss_fn(pred, y.unsqueeze(-1))
        loss_values.append(loss.item())
        loss.backward()
        optimizer.step()
        last_lost_value = loss.item()
        print(".", end="")
    print(last_lost_value)
 
print("Training completed")
 
step = range(len(loss_values))
 
# příprava na vykreslení grafu
fig, ax = plt.subplots(figsize=(6.4, 4.8))
plt.plot(step, np.array(loss_values))
plt.title("Průběh tréninku neuronové sítě")
plt.xlabel("Epocha")
plt.ylabel("Účelová funkce")
 
# uložení do souboru
plt.savefig("nn_5.png")
 
# vykreslení grafu
plt.show()
PyTorch NN

Obrázek 5: Průběh učení neuronové sítě s jednou skrytou vrstvou.

10. Riziko nedoučení složitější neuronové sítě

Při porovnání průběhů účelové funkce pro neuronovou síť bez skryté vrstvy a pro sít s jednou vrstvou jsou výsledky zřejmé: první síť se nedokáže učit, kdežto druhá ano:

PyTorch NN

Obrázek 6: Průběh učení neuronové sítě bez skryté vrstvy a sítě s jednou skrytou vrstvou.

Z toho by mohl plynout chybný závěr, že čím více vrstev (a čím více neuronů) bude neuronová síť obsahovat, tím bude kvalitnější a bude se i lépe učit. V praxi tomu tak není, protože se zde projevuje další proměnná – learning rate. Tu potřebujeme mít dostatečně velkou na to, aby se síť s každými dalšími trénovacími daty učila, ale na druhou stranu dostatečně malou, aby nedocházelo k oscilacím. Navíc u rozsáhlých sítí dochází k efektu nazvanému vanishing gradient, kterému se budeme podrobněji věnovat příště. Ovšem závěr je (pro tuto chvíli) následující: neuronová síť má být dostatečně rozsáhlá, aby se naučila řešit náš problém, ale ne rozsáhlejší.

Mimochodem – obrázek 6 byl vypočten tímto skriptem, který v sobě spojuje předchozí dva příklady (a několik zjednodušení):

import torch
from torch import nn
from torch import optim
from torch.utils.data import DataLoader
import matplotlib.pyplot as plt
import numpy as np
 
 
class NeuralNetwork4(nn.Module):
    """Třída reprezentující neuronovou síť."""
 
    def __init__(self, input_dim, output_dim):
        super().__init__()
        # vrstvy neuronové sítě
        self.layer_1 = nn.Linear(input_dim, output_dim)
 
    def forward(self, x):
        # propagace hodnot přes neuronovou síť
        x = nn.functional.sigmoid(self.layer_1(x))
        return x
 
 
class NeuralNetwork5(nn.Module):
    """Třída reprezentující neuronovou síť."""
 
    def __init__(self, input_dim, hidden_dim, output_dim):
        super().__init__()
        # vrstvy neuronové sítě
        self.layer_1 = nn.Linear(input_dim, hidden_dim)
        self.layer_2 = nn.Linear(hidden_dim, output_dim)
 
    def forward(self, x):
        # propagace hodnot přes neuronovou síť
        x = torch.nn.functional.relu(self.layer_1(x))
        x = torch.nn.functional.sigmoid(self.layer_2(x))
        return x
 
 
# konstrukce dvou neuronových sítí
nn4 = NeuralNetwork4(2, 1)
nn5 = NeuralNetwork5(2, 10, 1)
 
# příprava na trénink neuronové sítě
learning_rate = 0.1
loss_fn = nn.BCELoss()
 
optimizer4 = optim.SGD(nn4.parameters(), lr=learning_rate)
optimizer5 = optim.SGD(nn5.parameters(), lr=learning_rate)
 
# trénovací data
from compute_train_and_test_data import compute_train_and_test_data
 
train_data, _ = compute_train_and_test_data()
 
# zpracovat trénovací data
batch_size = 64
train_dataloader = DataLoader(dataset=train_data, batch_size=batch_size, shuffle=True)
print("Batches: ", len(train_dataloader))
 
# vlastní trénink
print("Training started")
num_epochs = 100
loss_values_4 = []
loss_values_5 = []
for epoch in range(num_epochs):
    print(f"    Epoch {epoch}: ", end="")
    for X, y in train_dataloader:
        optimizer4.zero_grad()
 
        # dopředný tok + zpětný tok + optimalizace
        pred = nn4(X)
 
        # výpočet účelové funkce
        loss = loss_fn(pred, y.unsqueeze(-1))
        loss_values_4.append(loss.item())
        loss.backward()
        optimizer4.step()
 
        optimizer5.zero_grad()
 
        # dopředný tok + zpětný tok + optimalizace
        pred = nn5(X)
 
        # výpočet účelové funkce
        loss = loss_fn(pred, y.unsqueeze(-1))
        loss_values_5.append(loss.item())
        loss.backward()
        optimizer5.step()
        print(".", end="")
    print()
 
print("Training completed")
 
step = range(len(loss_values_4))
 
# příprava na vykreslení grafu
fig, ax = plt.subplots(figsize=(6.4, 4.8))
plt.plot(step, np.array(loss_values_4), label="nn4")
plt.plot(step, np.array(loss_values_5), label="nn5")
plt.title("Průběh tréninku neuronové sítě")
plt.xlabel("Epocha")
plt.ylabel("Účelová funkce")
plt.legend(loc="best")
 
# uložení do souboru
plt.savefig("nn_4_5.png")
 
# vykreslení grafu
plt.show()

11. Šestý demonstrační příklad: neuronová síť s více skrytými vrstvami, která nebude dotrénována

V dalším demonstračním příkladu je vytvořena sít s mnoha vrstvami, které způsobí nedoučení sítě, protože máme málo trénovacích dat a především hodnota learning date je nastavena velmi nízko:

    def __init__(self, input_dim, hidden_dim, output_dim):
        super().__init__()
        # vrstvy neuronové sítě
        self.layer_1 = nn.Linear(input_dim, hidden_dim)
        self.layer_2 = nn.Linear(hidden_dim, hidden_dim)
        self.layer_3 = nn.Linear(hidden_dim, hidden_dim)
        self.layer_4 = nn.Linear(hidden_dim, output_dim)

Nastavení parametrů učení:

# příprava na trénink neuronové sítě
learning_rate = 0.1
loss_fn = nn.BCELoss()
 
optimizer = optim.SGD(nn6.parameters(), lr=learning_rate)

Tato mnohem komplikovanější síť bude ve skutečnosti prakticky stejně nekvalitní, jako zcela první síť bez skrytých vrstev:

PyTorch NN

Obrázek 7: Účelová funkce s větším množstvím skrytých vrstev, které ve výsledku vedou k jejímu nedoučení.

Zdrojový kód tohoto příkladu vypadá následovně:

import torch
from torch import nn
from torch import optim
from torch.utils.data import DataLoader
import matplotlib.pyplot as plt
import numpy as np
 
 
class NeuralNetwork(nn.Module):
    """Třída reprezentující neuronovou síť."""
 
    def __init__(self, input_dim, hidden_dim, output_dim):
        super().__init__()
        # vrstvy neuronové sítě
        self.layer_1 = nn.Linear(input_dim, hidden_dim)
        self.layer_2 = nn.Linear(hidden_dim, hidden_dim)
        self.layer_3 = nn.Linear(hidden_dim, hidden_dim)
        self.layer_4 = nn.Linear(hidden_dim, output_dim)
 
    def forward(self, x):
        # propagace hodnot přes neuronvou síť
        x = torch.nn.functional.relu(self.layer_1(x))
        x = torch.nn.functional.sigmoid(self.layer_2(x))
        x = torch.nn.functional.sigmoid(self.layer_3(x))
        x = torch.nn.functional.sigmoid(self.layer_4(x))
        return x
 
 
# konfigurace vrstev neuronové sítě
input_dim = 2
hidden_dim = 10
output_dim = 1
 
# konstrukce neuronové sítě
nn6 = NeuralNetwork(input_dim, hidden_dim, output_dim)
 
# výpis základních informací o neuronové síti
print(nn6)
 
 
# příprava na trénink neuronové sítě
learning_rate = 0.1
loss_fn = nn.BCELoss()
 
optimizer = optim.SGD(nn6.parameters(), lr=learning_rate)
 
# trénovací data
from compute_train_and_test_data import compute_train_and_test_data
 
train_data, _ = compute_train_and_test_data()
 
# zpracovat trénovací data
batch_size = 64
train_dataloader = DataLoader(dataset=train_data, batch_size=batch_size, shuffle=True)
print("Batches: ", len(train_dataloader))
 
# vlastní trénink
print("Training started")
num_epochs = 100
loss_values = []
for epoch in range(num_epochs):
    print(f"    Epoch {epoch}: ", end="")
    last_lost_value = None
    for X, y in train_dataloader:
        optimizer.zero_grad()
 
        # dopředný tok + zpětný tok + optimalizace
        pred = nn6(X)
 
        # výpočet účelové funkce
        loss = loss_fn(pred, y.unsqueeze(-1))
        loss_values.append(loss.item())
        loss.backward()
        optimizer.step()
        last_lost_value = loss.item()
        print(".", end="")
    print(last_lost_value)
 
print("Training completed")
 
step = range(len(loss_values))
 
# příprava na vykreslení grafu
fig, ax = plt.subplots(figsize=(6.4, 4.8))
plt.plot(step, np.array(loss_values))
plt.title("Průběh tréninku neuronové sítě")
plt.xlabel("Epocha")
plt.ylabel("Účelová funkce")
 
# uložení do souboru
plt.savefig("nn_6.png")
 
# vykreslení grafu
plt.show()

12. Sedmý demonstrační příklad: vliv parametru learning_rate na rychlosti naučení sítě

Zkusme nyní zjistit, co se stane ve chvíli, kdy sice stále budeme používat neuronovou síť s více skrytými vrstvami, ovšem zvýšíme hodnotu parametru learning rate.

Konfigurace neuronové sítě:

    def __init__(self, input_dim, hidden_dim, output_dim):
        super().__init__()
        # vrstvy neuronové sítě
        self.layer_1 = nn.Linear(input_dim, hidden_dim)
        self.layer_2 = nn.Linear(hidden_dim, hidden_dim)
        self.layer_3 = nn.Linear(hidden_dim, hidden_dim)
        self.layer_4 = nn.Linear(hidden_dim, output_dim)

Parametry učení neuronové sítě:

# příprava na trénink neuronové sítě
learning_rate = 0.5
loss_fn = nn.BCELoss()
 
optimizer = optim.SGD(nn7.parameters(), lr=learning_rate)

Tato síť se bude učit rychleji a nedojde k efektu vanishing gradient, takže průběh účelové funkce bude téměř dokonalý:

PyTorch NN

Obrázek 8: Účelová funkce pro neuronovou síť s více skrytými vrstvami a zvýšenou hodnotou learning rate.

Celý zdrojový kód příkladu:

import torch
from torch import nn
from torch import optim
from torch.utils.data import DataLoader
import matplotlib.pyplot as plt
import numpy as np
 
 
class NeuralNetwork(nn.Module):
    """Třída reprezentující neuronovou síť."""
 
    def __init__(self, input_dim, hidden_dim, output_dim):
        super().__init__()
        # vrstvy neuronové sítě
        self.layer_1 = nn.Linear(input_dim, hidden_dim)
        self.layer_2 = nn.Linear(hidden_dim, hidden_dim)
        self.layer_3 = nn.Linear(hidden_dim, hidden_dim)
        self.layer_4 = nn.Linear(hidden_dim, output_dim)
 
    def forward(self, x):
        # propagace hodnot přes neuronvou síť
        x = torch.nn.functional.relu(self.layer_1(x))
        x = torch.nn.functional.sigmoid(self.layer_2(x))
        x = torch.nn.functional.sigmoid(self.layer_3(x))
        x = torch.nn.functional.sigmoid(self.layer_4(x))
        return x
 
 
# konfigurace vrstev neuronové sítě
input_dim = 2
hidden_dim = 10
output_dim = 1
 
# konstrukce neuronové sítě
nn7 = NeuralNetwork(input_dim, hidden_dim, output_dim)
 
# výpis základních informací o neuronové síti
print(nn7)
 
 
# příprava na trénink neuronové sítě
learning_rate = 0.5
loss_fn = nn.BCELoss()
 
optimizer = optim.SGD(nn7.parameters(), lr=learning_rate)
 
# trénovací data
from compute_train_and_test_data import compute_train_and_test_data
 
train_data, _ = compute_train_and_test_data()
 
# zpracovat trénovací data
batch_size = 64
train_dataloader = DataLoader(dataset=train_data, batch_size=batch_size, shuffle=True)
print("Batches: ", len(train_dataloader))
 
# vlastní trénink
print("Training started")
num_epochs = 100
loss_values = []
for epoch in range(num_epochs):
    print(f"    Epoch {epoch}: ", end="")
    last_lost_value = None
    for X, y in train_dataloader:
        optimizer.zero_grad()
 
        # dopředný tok + zpětný tok + optimalizace
        pred = nn7(X)
 
        # výpočet účelové funkce
        loss = loss_fn(pred, y.unsqueeze(-1))
        loss_values.append(loss.item())
        loss.backward()
        optimizer.step()
        last_lost_value = loss.item()
        print(".", end="")
    print(last_lost_value)
 
print("Training completed")
 
step = range(len(loss_values))
 
# příprava na vykreslení grafu
fig, ax = plt.subplots(figsize=(6.4, 4.8))
plt.plot(step, np.array(loss_values))
plt.title("Průběh tréninku neuronové sítě")
plt.xlabel("Epocha")
plt.ylabel("Účelová funkce")
 
# uložení do souboru
plt.savefig("nn_7.png")
 
# vykreslení grafu
plt.show()

13. Porovnání účelové funkce všech tří doposud použitých neuronových sítí

Zajímavé bude porovnání účelové funkce získané při tréninku všech tří neuronových sítí, které jsme si popsali v předchozích kapitolách. Jedná se postupně o síť bez skrytých vrstev, síť s jednou skrytou vrstvou (10 neuronů) a parametrem learning rate nastaveným na hodnotu 0,1 a konečně o síť se třemi skrytými vrstvami (10→10→10 neuronů), ovšem s parametrem learning rate nastaveným na hodnotu 0,5 (rychlejší učení, menší pravděpodobnost vanishing gradientu):

PyTorch NN

Obrázek 9: Porovnání účelové funkce všech tří doposud použitých neuronových sítí.

Z tohoto průběhu je patrné, že poslední síť s mnoha skrytými vrstvami bude ve výsledku kvalitnější, ovšem musíme zajistit dostatečně dlouhý trénink (množství trénovacích dat atd.), protože je síť zpočátku tréninku horší, než jednodušší sítě. Až později dojde k žádoucímu zlomu a poklesu hodnoty účelové funkce. V tomto okamžiku by se mohlo s tréninkem skončit, aby se ušetřily zdroje a zabránilo se případnému přetrénování. Naproti tomu první síť je tak primitivní, že ani delší trénink její schopnosti nezlepší:

PyTorch NN

Obrázek 10: Porovnání v případě, že se provede dvojnásobek tréninku.

14. Ověření kvality neuronové sítě

Zjištění hodnot účelové funkce je sice užitečné (už jen proto, že naznačuje, kdy je vhodné trénink ukončit), ale stále nám nic neříká o tom, jak kvalitně dokáže neuronová síť predikovat výsledky na základě zadaných vstupů – což je vlastně jediný účel, proč jsme neuronovou síť vytvořili. Z tohoto důvodu musíme provést test sítě, a to s využitím testovacích (validačních) dat. Tato data by se neměla překrývat s trénovacími daty, protože nás příliš nezajímá, že se síť dokáže naučit nazpaměť předané výsledky (na to by stačila triviální implementace cache), ale spíše její schopnosti generalizace.

Do sítě tedy budeme posílat testovací data a porovnávat výsledky sítě s očekávanými výsledky (ty známe). Povšimněte si způsobu převodu reálného čísla na výstupu sítě (hodnoty v rozsahu 0 až 1 – jedná se o obor hodnot aktivační funkce sigmoid) na binární hodnotu říkající, zda vstupní bod [X1, X2] náleží do prvního nebo do druhého mezikruží. Zbylé programové řádky pouze slouží pro výpočet přesnosti v rozsahu 0 až 100%:

test_dataloader = DataLoader(dataset=test_data, batch_size=batch_size, shuffle=True)
 
correct = 0
total = 0
 
import itertools
 
with torch.no_grad():
    for X, y in test_dataloader:
        outputs = nn8(X)
        predicted = np.where(outputs.numpy() < 0.5, 0, 1)
        predicted = list(itertools.chain(*predicted))
        total += y.size(0)
        correct += (predicted == y.numpy()).sum().item()
 
print(f"Accuracy: {100 * correct // total}%")
Poznámka: přesný popis toho, jak se získává a zpracovává predikce sítě, bude uveden příště.

15. Osmý demonstrační příklad: výpočet kvality neuronové sítě

V pořadí již osmém demonstračním příkladu provedeme výpočet resp. přesněji řečeno ověření kvality neuronové sítě. Máme k dispozici testovací data odlišná od trénovacích dat. Necháme tedy síť předpovědět, které body z testovacích dat patří do první skupiny (mezikruží) a které do skupiny druhé. Poté již jednoduchou statistikou zjistíme míru přesnosti neuronové sítě:

import torch
from torch import nn
from torch import optim
from torch.utils.data import DataLoader
import matplotlib.pyplot as plt
import numpy as np
 
 
class NeuralNetwork(nn.Module):
    """Třída reprezentující neuronovou síť."""
 
    def __init__(self, input_dim, hidden_dim, output_dim):
        super().__init__()
        # vrstvy neuronové sítě
        self.layer_1 = nn.Linear(input_dim, hidden_dim)
        self.layer_2 = nn.Linear(hidden_dim, hidden_dim)
        self.layer_3 = nn.Linear(hidden_dim, output_dim)
 
    def forward(self, x):
        # propagace hodnot přes neuronvou síť
        x = torch.nn.functional.relu(self.layer_1(x))
        x = torch.nn.functional.sigmoid(self.layer_2(x))
        x = torch.nn.functional.sigmoid(self.layer_3(x))
        return x
 
 
# konfigurace vrstev neuronové sítě
input_dim = 2
hidden_dim = 10
output_dim = 1
 
# konstrukce neuronové sítě
nn8 = NeuralNetwork(input_dim, hidden_dim, output_dim)
 
# výpis základních informací o neuronové síti
print(nn8)
 
 
# příprava na trénink neuronové sítě
learning_rate = 0.1
loss_fn = nn.BCELoss()
 
optimizer = optim.SGD(nn8.parameters(), lr=learning_rate)
 
# trénovací data
from compute_train_and_test_data import compute_train_and_test_data
 
train_data, test_data = compute_train_and_test_data()
 
# zpracovat trénovací data
batch_size = 64
train_dataloader = DataLoader(dataset=train_data, batch_size=batch_size, shuffle=True)
print("Batches: ", len(train_dataloader))
 
# vlastní trénink
print("Training started")
num_epochs = 20
loss_values = []
for epoch in range(num_epochs):
    print(f"    Epoch {epoch}: ", end="")
    last_lost_value = None
    for X, y in train_dataloader:
        optimizer.zero_grad()
 
        # dopředný tok + zpětný tok + optimalizace
        pred = nn8(X)
 
        # výpočet účelové funkce
        loss = loss_fn(pred, y.unsqueeze(-1))
        loss_values.append(loss.item())
        loss.backward()
        optimizer.step()
        last_lost_value = loss.item()
        print(".", end="")
    print(last_lost_value)
 
print("Training completed")
 
test_dataloader = DataLoader(dataset=test_data, batch_size=batch_size, shuffle=True)
 
correct = 0
total = 0
 
import itertools
 
with torch.no_grad():
    for X, y in test_dataloader:
        outputs = nn8(X)
        predicted = np.where(outputs.numpy() < 0.5, 0, 1)
        predicted = list(itertools.chain(*predicted))
        total += y.size(0)
        correct += (predicted == y.numpy()).sum().item()
 
print(f"Accuracy: {100 * correct // total}%")

Výsledky (nejdůležitější je poslední řádek):

NeuralNetwork(
  (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)
)
Batches:  21
Training started
    Epoch 0: .....................0.6994423866271973
    Epoch 1: .....................0.6892452836036682
    Epoch 2: .....................0.6878048181533813
    Epoch 3: .....................0.6901800632476807
    Epoch 4: .....................0.6891487240791321
    Epoch 5: .....................0.6901738047599792
    Epoch 6: .....................0.6905770897865295
    Epoch 7: .....................0.6840065121650696
    Epoch 8: .....................0.6886505484580994
    Epoch 9: .....................0.6881945133209229
    Epoch 10: .....................0.6873928904533386
    ...
    ...
    ...
    Epoch 90: .....................0.030736887827515602
    Epoch 91: .....................0.033318083733320236
    Epoch 92: .....................0.026814712211489677
    Epoch 93: .....................0.02321838028728962
    Epoch 94: .....................0.023601409047842026
    Epoch 95: .....................0.026054512709379196
    Epoch 96: .....................0.03182302415370941
    Epoch 97: .....................0.021505670621991158
    Epoch 98: .....................0.02354506216943264
    Epoch 99: .....................0.024997740983963013
Training completed
Accuracy: 100%

16. Vizualizace predikce neuronové sítě: body patřící do první nebo druhé skupiny

Výsledek, který jsme získali skriptem uvedeným v deváté kapitole, nám pouze jednorozměrným číslem určuje míru úspěšnosti neuronové sítě při predikcích. Ovšem v praxi je mnohem lepší si výsledky vhodným způsobem vizualizovat, protože jen tak lze zjistit, v jakých oblastech dává síť nekorektní odpovědi atd. V našem konkrétním případě je vizualizace až triviálně snadná, protože na vstupu jsou body v rovině a výstupem sítě je hodnota říkající, zda bod patří do prvního či druhého mezikruží. To znamená, že si můžeme vykreslit vstupní body do grafu a obarvit je podle toho, jestli síť odpověděla 1 nebo 2 (ve skutečnosti je odpovědí reálné číslo z rozsahu 0 až 1, to je však snadno převoditelné na binární hodnotu). Do skriptu doplníme tento kód, který zajistí vizualizaci:

import itertools
 
all_predicts = []
x_coords = []
y_coords = []
 
with torch.no_grad():
    for X, y in test_dataloader:
        outputs = nn9(X)
        predicted = np.where(outputs.numpy() < 0.5, 0, 1)
        predicted = list(itertools.chain(*predicted))
        all_predicts += predicted
        coords = X.tolist()
        for coord in coords:
            x_coords.append(coord[0])
            y_coords.append(coord[1])
 
# velikost obrázku s grafem
plt.subplots(figsize=(6.4, 6.4))
 
# vizualizace
plt.scatter(x_coords, y_coords, s=1.5, c=all_predicts, cmap=plt.cm.Set1)
 
# popisek grafu
plt.title("Predikované výsledky")
 
# uložení grafu do souboru
plt.savefig("nn_9.png")
 
# vykreslení na obrazovku
plt.show()

17. Devátý demonstrační příklad: vizualizace predikce neuronové sítě

Postup popsaný v šestnácté kapitole je součástí dnešního posledního demonstračního příkladu, jehož zdrojový kód vypadá následovně:

import torch
from torch import nn
from torch import optim
from torch.utils.data import DataLoader
import matplotlib.pyplot as plt
import numpy as np
 
# budeme provádět vykreslování de facto standardní knihovnou Matplotlib
import matplotlib.pyplot as plt
 
 
class NeuralNetwork(nn.Module):
    """Třída reprezentující neuronovou síť."""
 
    def __init__(self, input_dim, hidden_dim, output_dim):
        super().__init__()
        # vrstvy neuronové sítě
        self.layer_1 = nn.Linear(input_dim, hidden_dim)
        self.layer_2 = nn.Linear(hidden_dim, hidden_dim)
        self.layer_3 = nn.Linear(hidden_dim, output_dim)
 
    def forward(self, x):
        # propagace hodnot přes neuronvou síť
        x = torch.nn.functional.relu(self.layer_1(x))
        x = torch.nn.functional.sigmoid(self.layer_2(x))
        x = torch.nn.functional.sigmoid(self.layer_3(x))
        return x
 
 
# konfigurace vrstev neuronové sítě
input_dim = 2
hidden_dim = 10
output_dim = 1
 
# konstrukce neuronové sítě
nn9 = NeuralNetwork(input_dim, hidden_dim, output_dim)
 
# výpis základních informací o neuronové síti
print(nn9)
 
 
# příprava na trénink neuronové sítě
learning_rate = 0.1
loss_fn = nn.BCELoss()
 
optimizer = optim.SGD(nn9.parameters(), lr=learning_rate)
 
# trénovací data
from compute_train_and_test_data import compute_train_and_test_data
 
train_data, test_data = compute_train_and_test_data()
 
# zpracovat trénovací data
batch_size = 64
train_dataloader = DataLoader(dataset=train_data, batch_size=batch_size, shuffle=True)
print("Batches: ", len(train_dataloader))
 
# vlastní trénink
print("Training started")
num_epochs = 200
loss_values = []
for epoch in range(num_epochs):
    print(f"    Epoch {epoch}: ", end="")
    last_lost_value = None
    for X, y in train_dataloader:
        optimizer.zero_grad()
 
        # dopředný tok + zpětný tok + optimalizace
        pred = nn9(X)
 
        # výpočet účelové funkce
        loss = loss_fn(pred, y.unsqueeze(-1))
        loss_values.append(loss.item())
        loss.backward()
        optimizer.step()
        last_lost_value = loss.item()
        print(".", end="")
    print(last_lost_value)
 
print("Training completed")
 
test_dataloader = DataLoader(dataset=test_data, batch_size=batch_size, shuffle=True)
 
import itertools
 
all_predicts = []
x_coords = []
y_coords = []
 
with torch.no_grad():
    for X, y in test_dataloader:
        outputs = nn9(X)
        predicted = np.where(outputs.numpy() < 0.5, 0, 1)
        predicted = list(itertools.chain(*predicted))
        all_predicts += predicted
        coords = X.tolist()
        for coord in coords:
            x_coords.append(coord[0])
            y_coords.append(coord[1])
 
# velikost obrázku s grafem
plt.subplots(figsize=(6.4, 6.4))
 
# vizualizace
plt.scatter(x_coords, y_coords, s=1.5, c=all_predicts, cmap=plt.cm.Set1)
 
# popisek grafu
plt.title("Predikované výsledky")
 
# uložení grafu do souboru
plt.savefig("nn_9.png")
 
# vykreslení na obrazovku
plt.show()

18. Výsledky získané devátým demonstračním příkladem

Okomentované výsledky získané devátým demonstračním příkladem pro různě nastavené neuronové sítě:

PyTorch NN

Obrázek 11: Korektně naučená síť – každý bod je ohodnocen správně.

PyTorch NN

Obrázek 12: Nekorektně naučená síť – největší chyby vidíme ve spodní části grafu.

PyTorch NN

Obrázek 13: Korektně naučená síť – každý bod je ohodnocen správně (větší množství testovacích dat).

PyTorch NN

Obrázek 14: Nekorektně naučená síť; tentokrát je problematický první kvadrant.

zabbix_tip

PyTorch NN

Obrázek 15: Korektně naučená síť v případě, že se mezikruží dotýkají.

19. Repositář s demonstračními příklady

Všechny demonstrační příklady využívající knihovnu PyTorch lze nalézt v repositáři https://github.com/tisnik/most-popular-python-libs. Následují odkazy na jednotlivé příklady:

# Příklad Stručný popis Adresa příkladu
1 tensor_constructor_scalar1.py konstrukce tenzoru nultého a prvního řádu https://github.com/tisnik/most-popular-python-libs/blob/master/PyTorch/ten­sor_constructor_scalar1.py
2 tensor_constructor_scalar2.py inicializace tenzoru prvního řádu s jedním prvkem https://github.com/tisnik/most-popular-python-libs/blob/master/PyTorch/ten­sor_constructor_scalar2.py
3 tensor_constructor_vector1.py konstrukce tenzoru prvního řádu (tříprvkový vektor) https://github.com/tisnik/most-popular-python-libs/blob/master/PyTorch/ten­sor_constructor_vector1.py
4 tensor_constructor_vector2.py konstrukce tenzoru prvního řádu s inicializací prvků https://github.com/tisnik/most-popular-python-libs/blob/master/PyTorch/ten­sor_constructor_vector2.py
5 tensor_constructor_vector3.py konstrukce tenzoru prvního řádu s využitím generátoru range https://github.com/tisnik/most-popular-python-libs/blob/master/PyTorch/ten­sor_constructor_vector3.py
6 tensor_constructor_matrix1.py vytvoření a inicializace tenzoru druhého řádu, který může být reprezentován maticí https://github.com/tisnik/most-popular-python-libs/blob/master/PyTorch/ten­sor_constructor_matrix1.py
7 tensor_constructor_matrix2.py inicializace prvků matice https://github.com/tisnik/most-popular-python-libs/blob/master/PyTorch/ten­sor_constructor_matrix2.py
8 tensor_constructor_3D1.py tenzor třetího řádu reprezentovaný „3D maticí“ https://github.com/tisnik/most-popular-python-libs/blob/master/PyTorch/ten­sor_constructor_3D1.py
9 tensor_constructor_3D2.py tenzor třetího řádu reprezentovaný „3D maticí“ (jiná forma inicializace) https://github.com/tisnik/most-popular-python-libs/blob/master/PyTorch/ten­sor_constructor_3D2.py
       
10 tensor_constructor_scalar_zero.py vynulování prvků tenzoru nultého řádu https://github.com/tisnik/most-popular-python-libs/blob/master/PyTorch/ten­sor_constructor_scalar_ze­ro.py
11 tensor_constructor_vector_zero.py vynulování prvků tenzoru prvního řádu https://github.com/tisnik/most-popular-python-libs/blob/master/PyTorch/ten­sor_constructor_vector_ze­ro.py
12 tensor_constructor_matrix_zero.py vynulování prvků tenzoru druhého řádu https://github.com/tisnik/most-popular-python-libs/blob/master/PyTorch/ten­sor_constructor_matrix_ze­ro.py
13 tensor_constructor_3D_zero.py vynulování prvků tenzoru třetího řádu https://github.com/tisnik/most-popular-python-libs/blob/master/PyTorch/ten­sor_constructor_3D_zero.py
       
14 tensor_zeros_shape.py použití konstruktoru zeros pro tenzory různých řádů a tvarů https://github.com/tisnik/most-popular-python-libs/blob/master/PyTorch/ten­sor_zeros_shape.py
15 tensor_ones_shape.py použití konstruktoru ones pro tenzory různých řádů a tvarů https://github.com/tisnik/most-popular-python-libs/blob/master/PyTorch/ten­sor_ones_shape.py
16 tensor_eye.py konstrukce jednotkové matice https://github.com/tisnik/most-popular-python-libs/blob/master/PyTorch/tensor_eye.py
       
17 tensor_range.py využití konstruktoru range https://github.com/tisnik/most-popular-python-libs/blob/master/PyTorch/ten­sor_range.py
18 tensor_arange.py využití konstruktoru arange https://github.com/tisnik/most-popular-python-libs/blob/master/PyTorch/ten­sor_arange.py
       
19 tensor_shape.py zjištění tvaru tenzoru https://github.com/tisnik/most-popular-python-libs/blob/master/PyTorch/ten­sor_shape.py
20 tensor_zeros_shape.py zjištění tvaru tenzoru vytvořeného konstruktorem zeros https://github.com/tisnik/most-popular-python-libs/blob/master/PyTorch/ten­sor_zeros_shape.py
21 tensor_ones_shape.py zjištění tvaru tenzoru vytvořeného konstruktorem ones https://github.com/tisnik/most-popular-python-libs/blob/master/PyTorch/ten­sor_ones_shape.py
22 tensor_read_dtype.py zjištění, jakého typu jsou prvky tenzoru https://github.com/tisnik/most-popular-python-libs/blob/master/PyTorch/ten­sor_read_dtype.py
23 tensor_set_dtype.py nastavení či změna typu prvků tenzoru https://github.com/tisnik/most-popular-python-libs/blob/master/PyTorch/ten­sor_set_dtype.py
       
24 tensor_storage1.py získání datové struktury se zdrojem dat pro tenzor https://github.com/tisnik/most-popular-python-libs/blob/master/PyTorch/ten­sor_storage1.py
25 tensor_storage2.py získání datové struktury se zdrojem dat pro tenzor https://github.com/tisnik/most-popular-python-libs/blob/master/PyTorch/ten­sor_storage2.py
26 tensor_storage3.py získání datové struktury se zdrojem dat pro tenzor https://github.com/tisnik/most-popular-python-libs/blob/master/PyTorch/ten­sor_storage3.py
27 tensor_storage_casts.py přetypování datové struktury se zdrojem dat pro tenzor https://github.com/tisnik/most-popular-python-libs/blob/master/PyTorch/ten­sor_storage_casts.py
       
28 tensor_slice_operation1.py konstrukce řezu z tenzoru prvního řádu https://github.com/tisnik/most-popular-python-libs/blob/master/PyTorch/ten­sor_slice_operation1.py
29 tensor_slice_operation2.py konstrukce řezu z tenzoru druhého řádu (přes řádky a sloupce) https://github.com/tisnik/most-popular-python-libs/blob/master/PyTorch/ten­sor_slice_operation2.py
30 tensor_slice_operation3.py konstrukce řezu s jeho následnou modifikací https://github.com/tisnik/most-popular-python-libs/blob/master/PyTorch/ten­sor_slice_operation3.py
31 tensor_slice_operation4.py konstrukce řezu s jeho následnou modifikací (odlišné operace od předchozího příkladu) https://github.com/tisnik/most-popular-python-libs/blob/master/PyTorch/ten­sor_slice_operation4.py
32 tensor_is_slice.py test základních vlastností řezů https://github.com/tisnik/most-popular-python-libs/blob/master/PyTorch/ten­sor_is_slice.py
       
33 tensor_stride1.py význam atributů stride a storage_offset https://github.com/tisnik/most-popular-python-libs/blob/master/PyTorch/ten­sor_stride1.py
34 tensor_stride2.py význam atributů stride a storage_offset https://github.com/tisnik/most-popular-python-libs/blob/master/PyTorch/ten­sor_stride2.py
35 tensor_stride3.py význam atributů stride a storage_offset https://github.com/tisnik/most-popular-python-libs/blob/master/PyTorch/ten­sor_stride3.py
       
36 tensor_reshape.py změna tvaru tenzoru operací reshape https://github.com/tisnik/most-popular-python-libs/blob/master/PyTorch/ten­sor_reshape.py
37 tensor_reshape2.py změna tvaru tenzoru operací reshape https://github.com/tisnik/most-popular-python-libs/blob/master/PyTorch/ten­sor_reshape2.py
       
38 tensor_narrow_operation1.py operace nad celým tenzorem typu narrow, první ukázka https://github.com/tisnik/most-popular-python-libs/blob/master/PyTorch/ten­sor_narrow_operation1.py
39 tensor_narrow_operation1_B.py operace nad celým tenzorem typu narrow, první ukázka přepsaná do volání metody https://github.com/tisnik/most-popular-python-libs/blob/master/PyTorch/ten­sor_narrow_operation1_B.py
40 tensor_narrow_operation2.py operace nad celým tenzorem typu narrow, druhá ukázka https://github.com/tisnik/most-popular-python-libs/blob/master/PyTorch/ten­sor_narrow_operation2.py
41 tensor_narrow_operation2_B.py operace nad celým tenzorem typu narrow, druhá ukázka přepsaná do volání metody https://github.com/tisnik/most-popular-python-libs/blob/master/PyTorch/ten­sor_narrow_operation2_B.py
42 tensor_narrow_operation3.py operace nad celým tenzorem typu narrow, třetí ukázka https://github.com/tisnik/most-popular-python-libs/blob/master/PyTorch/ten­sor_narrow_operation3.py
43 tensor_narrow_operation3_B.py operace nad celým tenzorem typu narrow, třetí ukázka přepsaná do volání metody https://github.com/tisnik/most-popular-python-libs/blob/master/PyTorch/ten­sor_narrow_operation3_B.py
44 tensor_narrow_operation4.py přepis původní matice přes pohled na ni (view) https://github.com/tisnik/most-popular-python-libs/blob/master/PyTorch/ten­sor_narrow_operation4.py
45 tensor_narrow_operation5.py přepis původní matice přes pohled na ni (view)narrow, třetí ukázka https://github.com/tisnik/most-popular-python-libs/blob/master/PyTorch/ten­sor_narrow_operation5.py
       
46 tensor_operator_add.py součet dvou tenzorů prvek po prvku https://github.com/tisnik/most-popular-python-libs/blob/master/PyTorch/ten­sor_operator_add.py
47 tensor_operator_sub.py rozdíl dvou tenzorů prvek po prvku https://github.com/tisnik/most-popular-python-libs/blob/master/PyTorch/ten­sor_operator_sub.py
48 tensor_operator_mul.py součin dvou tenzorů prvek po prvku https://github.com/tisnik/most-popular-python-libs/blob/master/PyTorch/ten­sor_operator_mul.py
49 tensor_operator_div.py podíl dvou tenzorů prvek po prvku https://github.com/tisnik/most-popular-python-libs/blob/master/PyTorch/ten­sor_operator_div.py
50 tensor_dot_product.py skalární součin dvou tenzorů prvního řádu https://github.com/tisnik/most-popular-python-libs/blob/master/PyTorch/ten­sor_dot_product.py
50 tensor_operator_matmul.py maticové násobení (dvou tenzorů druhého řádu) https://github.com/tisnik/most-popular-python-libs/blob/master/PyTorch/ten­sor_operator_matmul.py
51 tensor_operator_matmul2.py maticové násobení (dvou tenzorů druhého řádu) https://github.com/tisnik/most-popular-python-libs/blob/master/PyTorch/ten­sor_operator_matmul2.py
52 tensor_operator_matmul3.py maticové násobení v případě nekompatibilních tvarů matic https://github.com/tisnik/most-popular-python-libs/blob/master/PyTorch/ten­sor_operator_matmul3.py
53 tensor_operator_matmul4.py maticové násobení s broadcastingem https://github.com/tisnik/most-popular-python-libs/blob/master/PyTorch/ten­sor_operator_matmul4.py
54 tensor_operator_matmul5.py násobení vektoru a matice https://github.com/tisnik/most-popular-python-libs/blob/master/PyTorch/ten­sor_operator_matmul5.py
       
55 tensor_broadcast1.py operace broadcast (součin každého prvku tenzoru se skalárem) https://github.com/tisnik/most-popular-python-libs/blob/master/PyTorch/ten­sor_broadcast1.py
56 tensor_broadcast2.py operace broadcast (součin tenzoru druhého řádu s vektorem) https://github.com/tisnik/most-popular-python-libs/blob/master/PyTorch/ten­sor_broadcast2.py
57 tensor_broadcast3.py operace broadcast (součin vektoru s tenzorem druhého řádu) https://github.com/tisnik/most-popular-python-libs/blob/master/PyTorch/ten­sor_broadcast3.py
58 tensor_broadcast4.py operace broadcast (součet tenzorů druhého a třetího řádu) https://github.com/tisnik/most-popular-python-libs/blob/master/PyTorch/ten­sor_broadcast4.py
       
59 tensor_sparse.py konstrukce řídkého tenzoru https://github.com/tisnik/most-popular-python-libs/blob/master/PyTorch/ten­sor_sparse.py
       
60 activation_function_relu_.py aktivační funkce ReLU vypočtená knihovnou NumPy https://github.com/tisnik/most-popular-python-libs/blob/master/PyTorch/ac­tivation_function_relu_num­py.py
61 activation_function_relu_pytorch.py aktivační funkce ReLU vypočtená knihovnou PyTorch https://github.com/tisnik/most-popular-python-libs/blob/master/PyTorch/ac­tivation_function_relu_py­torch.py
62 activation_function_sigmoid_.py aktivační funkce sigmoid vypočtená knihovnou NumPy https://github.com/tisnik/most-popular-python-libs/blob/master/PyTorch/ac­tivation_function_sigmoid_num­py.py
63 activation_function_sigmoid_pytorch.py aktivační funkce sigmoid vypočtená knihovnou PyTorch https://github.com/tisnik/most-popular-python-libs/blob/master/PyTorch/ac­tivation_function_sigmoid_py­torch.py
64 activation_function_tanh_.py aktivační funkce tanh vypočtená knihovnou NumPy https://github.com/tisnik/most-popular-python-libs/blob/master/PyTorch/ac­tivation_function_tanh_num­py.py
65 activation_function_tanh_pytorch.py aktivační funkce tanh vypočtená knihovnou PyTorch https://github.com/tisnik/most-popular-python-libs/blob/master/PyTorch/ac­tivation_function_tanh_py­torch.py
       
66 make_circles.py vygenerování dat pro neuronovou síť funkcí make_circles https://github.com/tisnik/most-popular-python-libs/blob/master/PyTorch/ma­ke_circles.py
67 make_circles_labels.py vizualizace dat společně s jejich skupinou (ohodnocením) https://github.com/tisnik/most-popular-python-libs/blob/master/PyTorch/ma­ke_circles_labels.py
68 make_more_noise_circles.py získání náhodnějších dat funkcí make_circles https://github.com/tisnik/most-popular-python-libs/blob/master/PyTorch/ma­ke_more_noise_circles.py
69 make_data_set.py náhodné rozdělení datové sady funkcí train_test_split https://github.com/tisnik/most-popular-python-libs/blob/master/PyTorch/ma­ke_data_set.py
70 prepare_for_training.py konverze původních dat z n-dimenzionálních polí do tenzorů https://github.com/tisnik/most-popular-python-libs/blob/master/PyTorch/pre­pare_for_training.py
       
71 compute_train_and_test_data.py výpočet trénovacích a testovacích dat pro neuronové sítě https://github.com/tisnik/most-popular-python-libs/blob/master/PyTorch/com­pute_train_and_test_data.py
72 print_train_and_test_data.py tisk dat získaných předchozím skriptem https://github.com/tisnik/most-popular-python-libs/blob/master/PyTorch/prin­t_train_and_test_data.py
73 nn01.py deklarace třídy představující neuronovou síť https://github.com/tisnik/most-popular-python-libs/blob/master/PyTorch/nn01.py
74 nn02.py definice vrstev neuronové sítě https://github.com/tisnik/most-popular-python-libs/blob/master/PyTorch/nn02.py
75 nn03.py trénink neuronové sítě https://github.com/tisnik/most-popular-python-libs/blob/master/PyTorch/nn03.py
76 nn04.py trénink neuronové sítě se zobrazením kvality tréninku https://github.com/tisnik/most-popular-python-libs/blob/master/PyTorch/nn04.py
77 nn05.py neuronová síť s jednou skrytou vrstvou https://github.com/tisnik/most-popular-python-libs/blob/master/PyTorch/nn05.py
78 nn06.py neuronová síť s více skrytými vrstvami, která nebude dotrénována https://github.com/tisnik/most-popular-python-libs/blob/master/PyTorch/nn06.py
79 nn07.py vliv parametru learning_rate na rychlosti naučení sítě https://github.com/tisnik/most-popular-python-libs/blob/master/PyTorch/nn07.py
80 nn08.py výpočet kvality neuronové sítě https://github.com/tisnik/most-popular-python-libs/blob/master/PyTorch/nn08.py
81 nn09.py vizualizace predikce neuronové sítě https://github.com/tisnik/most-popular-python-libs/blob/master/PyTorch/nn09.py

20. Odkazy na Internetu

  1. Seriál Programovací jazyk Lua na Rootu:
    https://www.root.cz/seria­ly/programovaci-jazyk-lua/
  2. PDM: moderní správce balíčků a virtuálních prostředí Pythonu:
    https://www.root.cz/clanky/pdm-moderni-spravce-balicku-a-virtualnich-prostredi-pythonu/
  3. PyTorch Tutorial: Building a Simple Neural Network From Scratch
    https://www.datacamp.com/tu­torial/pytorch-tutorial-building-a-simple-neural-network-from-scratch
  4. Interní reprezentace numerických hodnot: od skutečného počítačového pravěku po IEEE 754–2008:
    https://www.root.cz/clanky/interni-reprezentace-numerickych-hodnot-od-skutecneho-pocitacoveho-praveku-po-ieee-754–2008/
  5. Interní reprezentace numerických hodnot: od skutečného počítačového pravěku po IEEE 754–2008 (dokončení):
    https://www.root.cz/clanky/interni-reprezentace-numerickych-hodnot-od-skutecneho-pocitacoveho-praveku-po-ieee-754–2008-dokonceni/
  6. Brain Floating Point – nový formát uložení čísel pro strojové učení a chytrá čidla:
    https://www.root.cz/clanky/brain-floating-point-ndash-novy-format-ulozeni-cisel-pro-strojove-uceni-a-chytra-cidla/
  7. Stránky projektu PyTorch:
    https://pytorch.org/
  8. Informace o instalaci PyTorche:
    https://pytorch.org/get-started/locally/
  9. Tenzor (Wikipedia):
    https://cs.wikipedia.org/wiki/Tenzor
  10. Introduction to Tensors:
    https://www.youtube.com/wat­ch?v=uaQeXi4E7gA
  11. Introduction to Tensors: Transformation Rules:
    https://www.youtube.com/wat­ch?v=j6DazQDbEhQ
  12. Tensor Attributes:
    https://pytorch.org/docs/sta­ble/tensor_attributes.html
  13. Tensors Explained Intuitively: Covariant, Contravariant, Rank :
    https://www.youtube.com/wat­ch?v=CliW7kSxxWU
  14. What is the relationship between PyTorch and Torch?:
    https://stackoverflow.com/qu­estions/44371560/what-is-the-relationship-between-pytorch-and-torch
  15. What is a tensor anyway?? (from a mathematician):
    https://www.youtube.com/wat­ch?v=K7f2pCQ3p3U
  16. Visualization of tensors – part 1 :
    https://www.youtube.com/wat­ch?v=YxXyN2ifK8A
  17. Visualization of tensors – part 2A:
    https://www.youtube.com/wat­ch?v=A95jdIuUUW0
  18. Visualization of tensors – part 2B:
    https://www.youtube.com/wat­ch?v=A95jdIuUUW0
  19. What the HECK is a Tensor?!?:
    https://www.youtube.com/wat­ch?v=bpG3gqDM80w
  20. Stránka projektu Torch
    http://torch.ch/
  21. Torch na GitHubu (několik repositářů)
    https://github.com/torch
  22. Torch (machine learning), Wikipedia
    https://en.wikipedia.org/wi­ki/Torch_%28machine_learnin­g%29
  23. Torch Package Reference Manual
    https://github.com/torch/tor­ch7/blob/master/README.md
  24. Torch Cheatsheet
    https://github.com/torch/tor­ch7/wiki/Cheatsheet
  25. An Introduction to Tensors
    https://math.stackexchange­.com/questions/10282/an-introduction-to-tensors
  26. Differences between a matrix and a tensor
    https://math.stackexchange­.com/questions/412423/dif­ferences-between-a-matrix-and-a-tensor
  27. Qualitatively, what is the difference between a matrix and a tensor?
    https://math.stackexchange­.com/questions/1444412/qu­alitatively-what-is-the-difference-between-a-matrix-and-a-tensor?
  28. Tensors for Neural Networks, Clearly Explained!!!:
    https://www.youtube.com/wat­ch?v=L35fFDpwIM4
  29. Tensor Processing Unit:
    https://en.wikipedia.org/wi­ki/Tensor_Processing_Unit
  30. Třída Storage:
    http://docs.pytorch.wiki/en/sto­rage.html
  31. Funkce torch.dot
    https://pytorch.org/docs/sta­ble/generated/torch.dot.html#tor­ch.dot
  32. Funkce torch.narrow
    https://pytorch.org/docs/sta­ble/generated/torch.narrow­.html
  33. Funkce torch.matmul
    https://pytorch.org/docs/sta­ble/generated/torch.matmul­.html
  34. Funkce torch.reshape
    https://pytorch.org/docs/sta­ble/generated/torch.resha­pe.html
  35. Funkce torch.arange
    https://pytorch.org/docs/sta­ble/generated/torch.arange­.html
  36. Funkce torch.range
    https://pytorch.org/docs/sta­ble/generated/torch.range­.html
  37. Třída torch.Tensor
    https://pytorch.org/docs/sta­ble/tensors.html
  38. Atributy tenzorů
    https://pytorch.org/docs/sta­ble/tensor_attributes.html
  39. Pohledy vytvořené nad tenzory
    https://pytorch.org/docs/sta­ble/tensor_view.html
  40. Broadcasting v knihovně
    https://numpy.org/doc/sta­ble/user/basics.broadcastin­g.html
  41. Broadcasting semantics (v knihovně PyTorch)
    https://pytorch.org/docs/sta­ble/notes/broadcasting.html
  42. Dot Product In Physics: What Is The Physical Meaning of It?
    https://profoundphysics.com/dot-product-in-physics-what-is-the-physical-meaning-of-it/
  43. scikit-learn: Getting Started
    https://scikit-learn.org/stable/getting_started.html
  44. Support Vector Machines
    https://scikit-learn.org/stable/modules/svm.html
  45. Use Deep Learning to Detect Programming Languages
    http://searene.me/2017/11/26/use-neural-networks-to-detect-programming-languages/
  46. Data pro neuronové sítě
    http://archive.ics.uci.edu/ml/in­dex.php
  47. Feedforward neural network
    https://en.wikipedia.org/wi­ki/Feedforward_neural_net­work
  48. Biologické algoritmy (4) – Neuronové sítě
    https://www.root.cz/clanky/biologicke-algoritmy-4-neuronove-site/
  49. Biologické algoritmy (5) – Neuronové sítě
    https://www.root.cz/clanky/biologicke-algoritmy-5-neuronove-site/
  50. Umělá neuronová síť (Wikipedia)
    https://cs.wikipedia.org/wi­ki/Um%C4%9Bl%C3%A1_neuronov%C3%A1_s%C3%AD%C5%A5
  51. AI vs Machine Learning (Youtube)
    https://www.youtube.com/wat­ch?v=4RixMPF4×is
  52. Machine Learning | What Is Machine Learning? | Introduction To Machine Learning | 2024 | Simplilearn (Youtube)
    https://www.youtube.com/wat­ch?v=ukzFI9rgwfU
  53. A Gentle Introduction to Machine Learning (Youtube)
    https://www.youtube.com/wat­ch?v=Gv9_4yMHFhI
  54. Machine Learning vs Deep Learning
    https://www.youtube.com/wat­ch?v=q6kJ71tEYqM
  55. Umělá inteligence (slajdy)
    https://slideplayer.cz/sli­de/12119218/
  56. Úvod do umělé inteligence
    https://slideplayer.cz/slide/2505525/
  57. Umělá inteligence I / Artificial Intelligence I
    https://ktiml.mff.cuni.cz/~bartak/ui/

Autor článku

Vystudoval VUT FIT a v současné době pracuje na projektech vytvářených v jazycích Python a Go.