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
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
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()
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.
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ě.

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)
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):

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()

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:

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:

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ý:

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):

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ší:

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}%")
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ě:

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

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

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

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

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:
20. Odkazy na Internetu
- Seriál Programovací jazyk Lua na Rootu:
https://www.root.cz/serialy/programovaci-jazyk-lua/ - 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/ - PyTorch Tutorial: Building a Simple Neural Network From Scratch
https://www.datacamp.com/tutorial/pytorch-tutorial-building-a-simple-neural-network-from-scratch - 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/ - 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/ - 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/ - Stránky projektu PyTorch:
https://pytorch.org/ - Informace o instalaci PyTorche:
https://pytorch.org/get-started/locally/ - Tenzor (Wikipedia):
https://cs.wikipedia.org/wiki/Tenzor - Introduction to Tensors:
https://www.youtube.com/watch?v=uaQeXi4E7gA - Introduction to Tensors: Transformation Rules:
https://www.youtube.com/watch?v=j6DazQDbEhQ - Tensor Attributes:
https://pytorch.org/docs/stable/tensor_attributes.html - Tensors Explained Intuitively: Covariant, Contravariant, Rank :
https://www.youtube.com/watch?v=CliW7kSxxWU - What is the relationship between PyTorch and Torch?:
https://stackoverflow.com/questions/44371560/what-is-the-relationship-between-pytorch-and-torch - What is a tensor anyway?? (from a mathematician):
https://www.youtube.com/watch?v=K7f2pCQ3p3U - Visualization of tensors – part 1 :
https://www.youtube.com/watch?v=YxXyN2ifK8A - Visualization of tensors – part 2A:
https://www.youtube.com/watch?v=A95jdIuUUW0 - Visualization of tensors – part 2B:
https://www.youtube.com/watch?v=A95jdIuUUW0 - What the HECK is a Tensor?!?:
https://www.youtube.com/watch?v=bpG3gqDM80w - Stránka projektu Torch
http://torch.ch/ - Torch na GitHubu (několik repositářů)
https://github.com/torch - Torch (machine learning), Wikipedia
https://en.wikipedia.org/wiki/Torch_%28machine_learning%29 - Torch Package Reference Manual
https://github.com/torch/torch7/blob/master/README.md - Torch Cheatsheet
https://github.com/torch/torch7/wiki/Cheatsheet - An Introduction to Tensors
https://math.stackexchange.com/questions/10282/an-introduction-to-tensors - Differences between a matrix and a tensor
https://math.stackexchange.com/questions/412423/differences-between-a-matrix-and-a-tensor - Qualitatively, what is the difference between a matrix and a tensor?
https://math.stackexchange.com/questions/1444412/qualitatively-what-is-the-difference-between-a-matrix-and-a-tensor? - Tensors for Neural Networks, Clearly Explained!!!:
https://www.youtube.com/watch?v=L35fFDpwIM4 - Tensor Processing Unit:
https://en.wikipedia.org/wiki/Tensor_Processing_Unit - Třída Storage:
http://docs.pytorch.wiki/en/storage.html - Funkce torch.dot
https://pytorch.org/docs/stable/generated/torch.dot.html#torch.dot - Funkce torch.narrow
https://pytorch.org/docs/stable/generated/torch.narrow.html - Funkce torch.matmul
https://pytorch.org/docs/stable/generated/torch.matmul.html - Funkce torch.reshape
https://pytorch.org/docs/stable/generated/torch.reshape.html - Funkce torch.arange
https://pytorch.org/docs/stable/generated/torch.arange.html - Funkce torch.range
https://pytorch.org/docs/stable/generated/torch.range.html - Třída torch.Tensor
https://pytorch.org/docs/stable/tensors.html - Atributy tenzorů
https://pytorch.org/docs/stable/tensor_attributes.html - Pohledy vytvořené nad tenzory
https://pytorch.org/docs/stable/tensor_view.html - Broadcasting v knihovně
https://numpy.org/doc/stable/user/basics.broadcasting.html - Broadcasting semantics (v knihovně PyTorch)
https://pytorch.org/docs/stable/notes/broadcasting.html - 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/ - scikit-learn: Getting Started
https://scikit-learn.org/stable/getting_started.html - Support Vector Machines
https://scikit-learn.org/stable/modules/svm.html - Use Deep Learning to Detect Programming Languages
http://searene.me/2017/11/26/use-neural-networks-to-detect-programming-languages/ - Data pro neuronové sítě
http://archive.ics.uci.edu/ml/index.php - Feedforward neural network
https://en.wikipedia.org/wiki/Feedforward_neural_network - Biologické algoritmy (4) – Neuronové sítě
https://www.root.cz/clanky/biologicke-algoritmy-4-neuronove-site/ - Biologické algoritmy (5) – Neuronové sítě
https://www.root.cz/clanky/biologicke-algoritmy-5-neuronove-site/ - Umělá neuronová síť (Wikipedia)
https://cs.wikipedia.org/wiki/Um%C4%9Bl%C3%A1_neuronov%C3%A1_s%C3%AD%C5%A5 - AI vs Machine Learning (Youtube)
https://www.youtube.com/watch?v=4RixMPF4×is - Machine Learning | What Is Machine Learning? | Introduction To Machine Learning | 2024 | Simplilearn (Youtube)
https://www.youtube.com/watch?v=ukzFI9rgwfU - A Gentle Introduction to Machine Learning (Youtube)
https://www.youtube.com/watch?v=Gv9_4yMHFhI - Machine Learning vs Deep Learning
https://www.youtube.com/watch?v=q6kJ71tEYqM - Umělá inteligence (slajdy)
https://slideplayer.cz/slide/12119218/ - Úvod do umělé inteligence
https://slideplayer.cz/slide/2505525/ - Umělá inteligence I / Artificial Intelligence I
https://ktiml.mff.cuni.cz/~bartak/ui/