Obsah
1. Od projektu Scikit-learn ke knihovně PyTorch
2. Přímý předchůdce knihovny PyTorch: nástroj Torch
3. Zpracování vektorů, matic a tenzorů
5. Konfigurace projektu (pyproject.toml)
6. Základní datová struktura, s níž se v knihovně PyTorch pracuje
7. Tenzor: homogenní n-dimenzionální pole s volitelným typem
9. Základní konstruktory tenzorů
11. Vynulování všech prvků tenzoru libovolného řádu metodou zero_
12. Použití konstruktoru zeros pro tenzory různých řádů a tvarů
13. Použití konstruktoru ones pro tenzory různých řádů a tvarů
14. Konstrukce jednotkové matice
15. Použití konstruktoru range
18. Repositář s demonstračními příklady
1. Od projektu Scikit-learn ke knihovně PyTorch
V seriálu o datové analýze s využitím programovacího jazyka Python jsme se až doposud zabývali projektem Scikit-learn, který uživatelům-programátorům nabízí mnoho postupů a nástrojů pro zpracování dat, tvorbu různě složitých či naopak interně jednoduchých modelů, shlukovou analýzu (clustering) atd. Tento projekt mj. umožňuje konstrukci a trénink neuronových sítí, přičemž výsledkem bude model provádějící buď klasifikaci či regresi. Díky tomu, že se se všemi modely pracuje prakticky totožným způsobem a uživatelé mají k dispozici i nástroje pro ověření kvality modelů, se Scikit-learn v oblasti zpracování dat i strojového učení využívá velmi často a mnohdy se jedná o první projekt, s nímž se zájemci o oblast zpracování dat, strojového učení (a částečně i umělé inteligence) setkají. A v mnoha oblastech se skutečně jedná ideální nástroj.
Obrázek 1: Logo projektu Scikit-learn.
Ovšem v případě, že běžná shluková analýza či jednodušší modely nedostačují, což jsou typicky oblasti „hlubokého“ strojového učení (deep learning) a především tehdy, pokud je zapotřebí například rozpoznávat audio signály nebo rastrové obrázky, se ukazuje, že by bylo vhodnější mít k dispozici specializovanější nástroj, který by dokázal pracovat s rozsáhlými neuronovými sítěmi, s konvolučními sítěmi atd. A vzhledem k tomu, že výpočty prováděné při tréninku těchto sítí jsou velmi náročné (a na druhou stranu unifikované a prováděné nad dlouhými vektory) by takový nástroj měl umožnit výpočty s využitím moderních GPU. Takové projekty pochopitelně existují a v ekosystému programovacího jazyka Python se jedná zejména o knihovnu PyTorch. A právě popisem možností této knihovny se budeme zabývat v tomto článku i v článcích navazujících.
Obrázek 2: Logo projektu PyTorch.
2. Přímý předchůdce knihovny PyTorch: nástroj Torch
Knihovna PyTorch, kterou se budeme zabývat, ve skutečnosti nevznikla na zelené louce. Jejím přímým předchůdcem je knihovna nazvaná Torch, která byla (a vlastně ještě doposud je) používána nejenom v oboru strojového učení (machine learning), ale i pro „obyčejné“ zpracování vektorů a tenzorů. Pro psaní skriptů se v Torchi používá programovací jazyk Lua. Ten je interpretovaný a i když se jedná o jeden z nejrychlejších interpretrů, tak pochopitelně nemůže soutěžit s překladači, resp. překládanými programovacími jazyky. Interně se ovšem v Torchi prakticky všechny výpočty provádí v nativních céčkových knihovnách a popř. se využívá i CUDA, tj. využívají se zde možnosti grafických akcelerátorů. Možnosti knihovny Torch však ve skutečnosti přesahují „pouhou“ práci s tenzory, protože obsahuje i moduly pro lineární algebru a především pro neuronové sítě, což je poměrně rozsáhlé téma, kterému se budeme věnovat v samostatném článku (již zaměřeného na PyTorch).
Obrázek 3: Logo projektu Torch.
Společně se zvyšujícím se počtem vývojářů, kteří začali používat programovací jazyk Python, se ukazovalo, že by bylo namísto jazyka Lua (což je sice skvělý jazyk, který ovšem nikdy významně nepřesáhl oblast své niky) vhodnější založit projekt na Pythonu. To se skutečně stalo a přibližně od roku 2017 se vývoj přesunul od projektu Torch k PyTorchi. Oba projekty jsou sice stále dosti podobné, ale jak uvidíme v dalších kapitolách, některé operace se přece jen odlišují. Na rozdíly narazíme vlastně hned na začátku, protože v jazyce Lua se prvky polí indexují od jedničky, kdežto v Pythonu se prvky seznamů (o od nich specializovaných polí) indexují od nuly. Nicméně i přes tyto rozdíly je přechod od Torche k PyTorchi relativně snadný, protože i základy, na nichž jsou obě knihovny postaveny, jsou podobné.
Obrázek 4: Logo programovacího jazyka Lua, který svými vlastnostmi soutěží s Pythonem. Ovšem Lua se využívá primárně jako jazyk vkládaný do dalších aplikací (příkladem z moderní éry je Neovim), kdežto Python se z původně pouze skriptovacího jazyka stal plnohodnotný projekt využívaný i pro skutečně rozsáhlé aplikace.
3. Zpracování vektorů, matic a tenzorů
Jednou poměrně rozsáhlou oblastí v IT je zpracování vektorů, matic i tenzorů, protože s těmito strukturami se můžeme setkat v různých disciplínách, například ve finančnictví, pojišťovnictví, statistice, zpracování numerických dat, simulacích, strojovém učení (a s klasickými tenzory třeba ve fyzice) atd. Současně se jedná i o velmi zajímavou oblast, neboť právě kvůli co nejrychlejší práci s velkými maticemi byly vytvořeny speciální výpočetní bloky v některých superpočítačích (příkladem mohou být superpočítače Cray). Současné knihovny dokážou v případě potřeby využít jak některá rozšíření instrukčních sad (SIMD instrukce typu AXV(512), SSE-x, původně též MMX či 3DNow!), tak i programovatelné grafické akcelerátory (GPU, v současnosti je lídrem v tomto oboru NVidia.
Práce s vektory a maticemi byla (a samozřejmě doposud je) podporována v překladačích FORTRANu, které začaly být po vzniku superpočítačů vybaveny algoritmy, které dokázaly převést některé typy programových smyček na „vektorové operace“. Paralelně vznikly i specializované jazyky určené téměř výhradně pro práci s vektory i maticemi – příkladem jsou jazyky APL a J.
V současnosti je používáno relativně velké množství programovacích jazyků, popř. specializovaných knihoven orientovaných na práci s vektory, maticemi, tenzory atd. Z komerčních nástrojů je zapotřebí jmenovat především známý MATLAB vydávaný společností MathWorks, nativní práci s maticemi a vektory ovšem velmi dobře podporuje také nástroj GNU Octave (https://gnu.org/software/octave/), jazyk R (http://www.r-project.org/) a také relativně nový jazyk Julia (http://julialang.org/, zajímavé výsledky benchmarků lze najít na adrese http://julialang.org/benchmarks/). Z knihoven jmenujme především oblíbenou a dnes dosti intenzivně využívanou Pythonovskou knihovnu NumPy (http://www.numpy.org/).
Framework PyTorch je mj. určen pro zpracování vektorů, matic i tenzorů (tj. zobecnění vektorů), a to s využitím programovacího jazyka Python namísto specializovaného jazyka (Julia, Matlab, R). A tyto datové struktury jsou dále využívány v dalších oblastech, které PyTorch podporuje – v první řadě se jedná o neuronové sítě.
4. Instalace knihovny PyTorch
Před prvními pokusy s knihovnou PyTorch si ji pochopitelně musíme nainstalovat. To je ovšem složitější, než v případě běžných Pythonovských balíčků, protože se přímo nepoužívá PyPi, ale vlastní registr s balíčky. Přejděte tedy na stránku https://pytorch.org/get-started/locally/#start-locally, kde si můžete vybrat svoji platformu (Linux, Windows, Mac), správce balíčků (což bude s velkou pravděpodobností pip), jazyk (pochopitelně Python) a taktéž to, zda budete chtít nainstalovat PyTorch s podporou CUDA či bez této podpory. Využití platformy CUDA sice povede k velkému nárůstu rychlosti tréninku neuronových sítí, ovšem na druhou stranu samotná instalace naroste o přibližně 4GB (!). Proto může být pro první kroky snazší si nainstalovat pouze „CPU“ variantu PyTorche – všechny vlastnosti zůstanou zachovány, pouze se pro výpočty bude stále používat běžný mikroprocesor a nikoli GPU.
Na výše uvedené stránce se po výběru kritérií zobrazí příkaz, který lze použít pro instalaci PyTorche.
5. Konfigurace projektu (pyproject.toml)
V případě, že pro správu Pythonovských projektů používáte projektový soubor pyproject.toml a například nástroj PDM, je možné specifikovat konfiguraci projektu takovým způsobem, že se stáhne a nainstaluje korektní varianta PyTorche. Příkladem může být specifikace PyTorche ve variantě pro CPU:
[[tool.pdm.source]] type = "find_links" url = "https://download.pytorch.org/whl/cpu/torch_stable.html" name = "torch" [build-system] requires = ["pdm-backend"] build-backend = "pdm.backend" [project] name = "skvely projekt zalozeny na PyTorchi" version = "0.1.0" description = "skvely projekt zalozeny na PyTorchi" authors = [] dependencies = [ ... ... ... "torch==2.5.1+cpu", ... ... ... ] # PyTorch vyzaduje minimalne Python 3.9 (priklady otestovany v 3.11 a 3.12) requires-python = "==3.9.*" readme = "README.md" license = {file = "LICENSE"}
6. Základní datová struktura, s níž se v knihovně PyTorch pracuje
V knihovně PyTorch se základní datová struktura jmenuje Tensor. Tato struktura umožňuje reprezentovat skalární hodnoty (tenzory nultého řádu), běžné vektory (tenzory prvního řádu), běžné matice, „3D matice“ atd. Interně je struktura objektů typu Tensor až překvapivě jednoduchá – základem je jednorozměrné pole doplněné o metadata, v nichž je uložen počet dimenzí, velikost dimenzí, hodnoty stride používané při přístupu k prvkům interního pole atd. Nad tenzory je navíc možné vytvářet různé pohledy (views), které mohou být určeny buď pouze pro čtení či pro čtení i zápis (pohled může například reprezentovat tenzor se změněným tvarem – shape).
7. Tenzor: homogenní n-dimenzionální pole s volitelným typem
Samotné interní pole objektů typu Tensor je vždy homogenní, což znamená že může obsahovat pouze prvky stejného typu, ovšem tento typ je konfigurovatelný. Implicitně se jedná o hodnoty typu double (celý objekt má v takovém případě konkrétní typ DoubleTensor), ovšem existují i další typy, které je možné v případě potřeby zvolit (například při zpracování obrázků, audio dat atd.):
Jméno typu | Význam |
---|---|
torch.bool | tenzor s prvky typu bool |
torch.int8 | tenzor s prvky typu signed char (osmibitové celé číslo) |
torch.int16 | tenzor s prvky typu signed short (16bitové celé číslo) |
torch.int32 | tenzor s prvky typu signed int (32bitové celé číslo) |
torch.int64 | tenzor s prvky typu signed long (64bitové celé číslo) |
torch.uint8 | tenzor s prvky typu unsigned char (osmibitové celé číslo) |
torch.uint16 | tenzor s prvky typu unsigned short (16bitové celé číslo) |
torch.uint32 | tenzor s prvky typu unsigned int (32bitové celé číslo) |
torch.uint64 | tenzor s prvky typu unsigned long (64bitové celé číslo) |
torch.quint8 nebo torch.qint8 | diskretizované celočíselné hodnoty (8bit) |
torch.quint4×2 | diskretizované celočíselné hodnoty (4bit), velmi omezené použití |
torch.qint32 | diskretizované celočíselné hodnoty (32bit) |
torch.bfloat16 | tenzor s prvky typu bfloat16 (https://www.root.cz/clanky/brain-floating-point-ndash-novy-format-ulozeni-cisel-pro-strojove-uceni-a-chytra-cidla/) |
torch.float16 nebo torch.half | tenzor s prvky typu half float (https://www.root.cz/clanky/interni-reprezentace-numerickych-hodnot-od-skutecneho-pocitacoveho-praveku-po-ieee-754–2008-dokonceni/#k10) |
torch.float32 nebo torch.float | tenzor s prvky typu float (32bitová FP hodnota) |
torch.float64 nebo torch.double | tenzor s prvky typu double (64bitová FP hodnota) |
torch.float8_e4m3fn | speciální formát osmibitových hodnot s plovoucí řádovou čárkou |
torch.float8_e5m2 | speciální formát osmibitových hodnot s plovoucí řádovou čárkou |
torch.complex32 nebo torch.chalf | komplexní čísla s 16bitovými FP hodnotami |
torch.complex64 nebo torch.cfloat | komplexní čísla s 32bitovými FP hodnotami |
torch.complex128 nebo torch.cdouble | komplexní čísla s 64bitovými FP hodnotami |
8. Datové typy pro tenzory uložené v paměti CPU i GPU kompatibilní se staršími verzemi Torche a PyTorche
Pro zajištění zpětné kompatibility lze použít i tyto názvy datových typů:
Jméno typu | Význam |
---|---|
torch.BoolTensor | tenzor s prvky typu bool |
torch.CharTensor | tenzor s prvky typu char |
torch.ByteTensor | tenzor s prvky typu unsigned char (osmibitové celé číslo) |
torch.ShortTensor | tenzor s prvky typu short (16bitové celé číslo) |
torch.IntTensor | tenzor s prvky typu int (32bitové celé číslo) |
torch.LongTensor | tenzor s prvky typu long (64bitové celé číslo) |
torch.BFloat16Tensor | tenzor s prvky typu bfloat16 (https://www.root.cz/clanky/brain-floating-point-ndash-novy-format-ulozeni-cisel-pro-strojove-uceni-a-chytra-cidla/) |
torch.HalfTensor | tenzor s prvky typu half float (https://www.root.cz/clanky/interni-reprezentace-numerickych-hodnot-od-skutecneho-pocitacoveho-praveku-po-ieee-754–2008-dokonceni/#k10) |
torch.FloatTensor | tenzor s prvky typu float (32bitová FP hodnota) |
torch.DoubleTensor | tenzor s prvky typu double (64bitová FP hodnota) |
Varianty ukládané do paměti GPU se jmenují nepatrně odlišně:
Jméno typu |
---|
torch.cuda.BoolTensor |
torch.cuda.CharTensor |
torch.cuda.ByteTensor |
torch.cuda.ShortTensor |
torch.cuda.IntTensor |
torch.cuda.LongTensor |
torch.cuda.BFloat16Tensor |
torch.cuda.HalfTensor |
torch.cuda.FloatTensor |
torch.cuda.DoubleTensor |
9. Základní konstruktory tenzorů
Již v úvodních kapitolách dnešního článku jsme si řekli, že základní datovou strukturou knihovny PyTorch jsou N-dimenzionální pole, která mohou být použita pro uložení komponent tenzorů. V této kapitole si ukážeme základní konstruktory objektů typu Tensor (prozatím se omezíme na komponenty tenzorů, které jsou typu Double).
Vytvoření skaláru, neboli tenzoru nultého řádu a inicializace jeho (jediné) komponenty:
# skutecny skalar - tenzor nulteho radu s1 = torch.tensor(100) print(s1)
Povšimněte si rozdílu mezi skalárem a jednoprvkovým vektorem – tyto struktury se chovají značně odlišně (i zápis je odlišný – tensor vs. Tensor):
# konstrukce tenzoru prvniho radu (jednoprvkovy vektor) s2 = torch.Tensor(1) print(s2)
Výsledky:
tensor(100) tensor([-1.0842e-19])
Přístup k jediné složce jednoprvkového vektoru s její modifikací:
s2[0] = 42 print(s2)
Inicializace jednoprvkového vektoru:
# konstrukce tenzoru (jednoprvkovy vektor) s jeho inicializaci s2 = torch.tensor([-1]) print(s2) # pristup k (jedine) slozce tenzoru s2[0] = 42 print(s2)
Výsledky:
tensor([-1]) tensor([42])
Vytvoření vektoru, neboli tenzoru prvního řádu. V tomto konkrétním případě se jedná o tříprvkový vektor:
# konstrukce tenzoru prvniho radu (vektoru) v1 = torch.Tensor(3) print(v1)
Inicializace komponent vektoru:
# inicializace jednotlivych prvku vektoru v1[0] = 10 v1[1] = 20 v1[2] = 30 print(v1)
Výsledek:
tensor([10., 20., 30.])
Alternativně lze vektor (tenzor prvního řádu) vytvořit a současně inicializovat jeho komponenty. Použije se přitom běžný seznam tak, jak ho známe z programovacího jazyka Python:
# konstrukce tenzoru prvniho radu (vektoru) s inicializaci prvku v2 = torch.Tensor([1, 2, 3]) print(v2)
Výsledek:
tensor([1., 2., 3.])
Možná je i tato konstrukce:
# konstrukce tenzoru prvniho radu (tenzoru) # s inicializací výsledkem generátoru range v3 = torch.Tensor(range(10)) print(v3)
Výsledek:
tensor([0., 1., 2., 3., 4., 5., 6., 7., 8., 9.])
10. Tenzory vyšších řádů
Vytvoření a inicializace tenzoru druhého řádu, který může být reprezentován maticí:
# konstrukce tenzoru druheho radu (matice) m1 = torch.Tensor(3, 3) print(m1)
Výsledná matice se zobrazí následujícím způsobem (prvky nejsou inicializovány):
tensor([[ 9.8455e-42, 2.7700e+30, 2.6378e+23], [ 1.7259e+25, 4.8953e-26, -9.0072e+15], [ 4.1205e+21, 1.7036e+19, 2.6177e+30]])
Inicializace prvků matice:
# konstrukce tenzoru druheho radu (matice) m2 = torch.Tensor([[1, 2, 3], [4, 5, 6], [7, 8, 9]]) print(m2)
Výsledky:
tensor([[1., 2., 3.], [4., 5., 6.], [7., 8., 9.]])
A konečně tenzor třetího řádu reprezentovaný „3D maticí“:
# 2D struktury - matice m1 = [[1, 2, 3], [4, 5, 6], [7, 8, 9]] m2 = [[10, 20, 30], [40, 50, 60], [70, 80, 90]] # konstrukce tenzoru tretiho radu c = torch.Tensor([m1, m2]) print(c)
Výsledek se na 2D obrazovce zobrazí takto:
tensor([[[ 1., 2., 3.], [ 4., 5., 6.], [ 7., 8., 9.]], [[10., 20., 30.], [40., 50., 60.], [70., 80., 90.]]])
Nebo přímý zápis:
# 3D struktura m3 = [[[1, 2, 3], [4, 5, 6], [7, 8, 9]], [[10, 20, 30], [40, 50, 60], [70, 80, 90]]] # konstrukce tenzoru tretiho radu c = torch.Tensor(m3) print(c)
Výsledek:
tensor([[[ 1., 2., 3.], [ 4., 5., 6.], [ 7., 8., 9.]], [[10., 20., 30.], [40., 50., 60.], [70., 80., 90.]]])
11. Vynulování všech prvků tenzoru libovolného řádu metodou zero_
Metodou nazvanou zero_ je možné tenzor libovolného řádu modifikovat, a to konkrétně takovým způsobem, že se nastaví hodnoty všech jeho prvků na nulu. Je to snadné, pouze nesmíme zapomenout na podtržítko uvedené na konci jména této metody:
Skalár a vektor s jedním prvkem:
# toto je skutecny skalar s1 = torch.tensor(1).zero_() print(s1) # konstrukce tenzoru prvniho radu s jednim prvkem # vynulovani prvku s2 = torch.Tensor(1).zero_() print(s2)
Výsledky:
tensor(0) tensor([0.])
Vektor (tenzor prvního řádu) s vynulovanými prvky:
# konstrukce tenzoru prvniho radu # s vynulovanim vsech prvku v1 = torch.Tensor(3).zero_() print(v1)
Výsledek:
tensor([0., 0., 0.])
Matice (tenzor druhého řádu) s vynulovanými prvky:
# konstrukce tenzoru druheho radu # s vynulovanim vsech prvku m1 = torch.Tensor(3, 3).zero_() print(m1)
Výsledek:
tensor([[0., 0., 0.], [0., 0., 0.], [0., 0., 0.]])
3D pole:
# konstrukce tenzoru tretiho radu # vynulovanim vsech prvku c = torch.Tensor(2, 3, 4).zero_() print(c)
Výsledky:
tensor([[[0., 0., 0., 0.], [0., 0., 0., 0.], [0., 0., 0., 0.]], [[0., 0., 0., 0.], [0., 0., 0., 0.], [0., 0., 0., 0.]]])
12. Použití konstruktoru zeros pro tenzory různých řádů a tvarů
Výhodnější a rychlejší cesta ke konstrukci tenzoru zvoleného řádu (a tvaru) však spočívá v použití konstruktoru zeros(), kterému se předá n hodnot reprezentujících velikosti jednotlivých dimenzí. Opět se podívejme na příklady:
import torch # konstrukce tenzoru prvniho radu, vyplneni nulami v1 = torch.zeros(1) print(v1) # konstrukce tenzoru prvniho radu, vyplneni nulami v2 = torch.zeros(10) print(v2) # konstrukce tenzoru druheho radu, vyplneni nulami m1 = torch.zeros(3, 4) print(m1) # konstrukce tenzoru tretiho radu, vyplneni nulami c1 = torch.zeros(3, 4, 5) print(c1)
Ze zobrazených výsledků je patrné, jakým způsobem jsou tenzory zkonstruovány a vyplněny nulami:
tensor([0.]) tensor([0., 0., 0., 0., 0., 0., 0., 0., 0., 0.]) tensor([[0., 0., 0., 0.], [0., 0., 0., 0.], [0., 0., 0., 0.]]) tensor([[[0., 0., 0., 0., 0.], [0., 0., 0., 0., 0.], [0., 0., 0., 0., 0.], [0., 0., 0., 0., 0.]], [[0., 0., 0., 0., 0.], [0., 0., 0., 0., 0.], [0., 0., 0., 0., 0.], [0., 0., 0., 0., 0.]], [[0., 0., 0., 0., 0.], [0., 0., 0., 0., 0.], [0., 0., 0., 0., 0.], [0., 0., 0., 0., 0.]]])
13. Použití konstruktoru ones pro tenzory různých řádů a tvarů
Způsob reprezentace tenzorů druhého řádu sice připomíná matice, ovšem zde se nesmíme nechat zmýlit – další konstruktor tenzorů se sice jmenuje ones, ale nevytváří (v 2D případě) jednotkovou matici s jedničkami pouze na hlavní diagonále, nýbrž matici, v níž mají všechny prvky hodnotu 1. V ostatních ohledech se konstruktor ones podobá výše popsanému konstruktoru zeros, takže jen velmi krátce:
import torch # konstrukce tenzoru, vyplneni jednickami v1 = torch.ones(1) print(v1) print() # konstrukce tenzoru prvniho radu, vyplneni jednickami v2 = torch.ones(10) print(v2) print() # konstrukce tenzoru druheho radu, vyplneni jednickami m1 = torch.ones(3, 4) print(m1) print() # konstrukce tenzoru tretiho radu, vyplneni jednickami c1 = torch.ones(3, 4, 5) print(c1) print()
Takto zkonstruované tenzory vypadají následovně:
tensor([1.]) tensor([1., 1., 1., 1., 1., 1., 1., 1., 1., 1.]) tensor([[1., 1., 1., 1.], [1., 1., 1., 1.], [1., 1., 1., 1.]]) tensor([[[1., 1., 1., 1., 1.], [1., 1., 1., 1., 1.], [1., 1., 1., 1., 1.], [1., 1., 1., 1., 1.]], [[1., 1., 1., 1., 1.], [1., 1., 1., 1., 1.], [1., 1., 1., 1., 1.], [1., 1., 1., 1., 1.]], [[1., 1., 1., 1., 1.], [1., 1., 1., 1., 1.], [1., 1., 1., 1., 1.], [1., 1., 1., 1., 1.]]])
14. Konstrukce jednotkové matice
Pro konstrukci jednotkové matice, v níž jsou jedničky uloženy jen na hlavní diagonále a zbylé prvky jsou nulové, se používá konstruktor pojmenovaný eye. Tomu lze předat jen jedinou hodnotu – a to velikost čtvercové matice:
import torch # konstrukce jednotkove matice m1 = torch.eye(10) print(m1) print()
Výsledná matice bude vypadat následovně:
tensor([[1., 0., 0., 0., 0., 0., 0., 0., 0., 0.], [0., 1., 0., 0., 0., 0., 0., 0., 0., 0.], [0., 0., 1., 0., 0., 0., 0., 0., 0., 0.], [0., 0., 0., 1., 0., 0., 0., 0., 0., 0.], [0., 0., 0., 0., 1., 0., 0., 0., 0., 0.], [0., 0., 0., 0., 0., 1., 0., 0., 0., 0.], [0., 0., 0., 0., 0., 0., 1., 0., 0., 0.], [0., 0., 0., 0., 0., 0., 0., 1., 0., 0.], [0., 0., 0., 0., 0., 0., 0., 0., 1., 0.], [0., 0., 0., 0., 0., 0., 0., 0., 0., 1.]])
I když je to divné, je možné specifikovat i počet sloupců. Výsledkem pak bude (nejednotková) obdélníková matice:
# konstrukce jednotkove matice se specifikaci sloupcu m2 = torch.eye(10, 15) print(m2) print()
Opět se podívejme na výsledek:
tensor([[1., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0.], [0., 1., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0.], [0., 0., 1., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0.], [0., 0., 0., 1., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0.], [0., 0., 0., 0., 1., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0.], [0., 0., 0., 0., 0., 1., 0., 0., 0., 0., 0., 0., 0., 0., 0.], [0., 0., 0., 0., 0., 0., 1., 0., 0., 0., 0., 0., 0., 0., 0.], [0., 0., 0., 0., 0., 0., 0., 1., 0., 0., 0., 0., 0., 0., 0.], [0., 0., 0., 0., 0., 0., 0., 0., 1., 0., 0., 0., 0., 0., 0.], [0., 0., 0., 0., 0., 0., 0., 0., 0., 1., 0., 0., 0., 0., 0.]])
15. Použití konstruktoru range
Další typ konstruktoru je možné použít pro vytvoření vektoru obsahujícího aritmetickou řadu s volitelným krokem. Tento konstruktor se jmenuje range a lze mu předat hodnotu prvního a posledního prvku, popř. i krok mezi hodnotami sousedních prvků. Krok může být kladný i záporný a samozřejmě se nemusí jednat o celé číslo. Podle očekávání je implicitní hodnota kroku rovna jedné. Knihovna PyTorch kontroluje nenulovost kroku a taktéž to, zda se skutečně vytvoří korektní aritmetická řada. Opět se podívejme na několik jednoduchých příkladů:
import torch # konstrukce tenzoru, vyplneni sekvenci v1 = torch.range(10, 20) print(v1) # specifikace kroku v2 = torch.range(10, 20, 2) print(v2) # zaporny krok v3 = torch.range(10, 0, -1) print(v3) # krok, ktery neni celociselny v4 = torch.range(0, 10, 0.5) print(v4)
Čtveřice vektorů, která byla zkonstruována tímto skriptem, má následující obsah:
v1 = torch.range(10, 20) tensor([10., 11., 12., 13., 14., 15., 16., 17., 18., 19., 20.]) v2 = torch.range(10, 20, 2) tensor([10., 12., 14., 16., 18., 20.]) v3 = torch.range(10, 0, -1) tensor([10., 9., 8., 7., 6., 5., 4., 3., 2., 1., 0.]) v4 = torch.range(0, 10, 0.5) tensor([ 0.0000, 0.5000, 1.0000, 1.5000, 2.0000, 2.5000, 3.0000, 3.5000, 4.0000, 4.5000, 5.0000, 5.5000, 6.0000, 6.5000, 7.0000, 7.5000, 8.0000, 8.5000, 9.0000, 9.5000, 10.0000])
16. Konstruktor arange
V knihovně Numpy je range nahrazena za konstruktor arange (což znamená array range). Ta se chová tak, že horní mez již není do výsledného vektoru uložena. A stejný konstruktor je v současnosti k dispozici i v knihovně PyTorch:
import torch # konstrukce tenzoru, vyplneni sekvenci v1 = torch.arange(10, 20) print(v1) # specifikace kroku v2 = torch.arange(10, 20, 2) print(v2) # zaporny krok v3 = torch.arange(10, 0, -1) print(v3) # krok, ktery neni celociselny v4 = torch.arange(0, 10, 0.5) print(v4)
Povšimněte si, že získané výsledky jsou skutečně odlišné od výsledků skriptu z předchozí kapitoly – vždy chybí poslední prvek vektoru:
v1 = torch.range(10, 20) tensor([10, 11, 12, 13, 14, 15, 16, 17, 18, 19]) v2 = torch.range(10, 20, 2) tensor([10, 12, 14, 16, 18]) v3 = torch.range(10, 0, -1) tensor([10, 9, 8, 7, 6, 5, 4, 3, 2, 1]) v4 = torch.range(0, 10, 0.5) tensor([0.0000, 0.5000, 1.0000, 1.5000, 2.0000, 2.5000, 3.0000, 3.5000, 4.0000, 4.5000, 5.0000, 5.5000, 6.0000, 6.5000, 7.0000, 7.5000, 8.0000, 8.5000, 9.0000, 9.5000])
17. Obsah navazujícího článku
V navazujícím článku si vysvětlíme, jakým způsobem jsou tenzory uloženy v paměti počítače, resp. alternativně v paměti GPU (nebo spíše TPU – Tensor Processing Unit). Se způsobem uložení do jisté míry souvisí i získání pohledu (view) na tenzor. A následně si popíšeme i různé operace, které je možné s tenzory provádět jako s celkem – změna tvaru (shape), takzvaný broadcasting, operace „zúžení“ a pochopitelně i operace prováděné mezi prvky dvou tenzorů. Získáme tak velmi dobrý základ, který využijeme při konstrukci, tréninku a provádění predikcí neuronovými sítěmi.
18. 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:
19. Odkazy na Internetu
- Seriál Programovací jazyk Lua na Rootuhttps://www.root.cz/serialy/programovaci-jazyk-lua/
- PDM: moderní správce balíčků a virtuálních prostředí Pythonuhttps://www.root.cz/clanky/pdm-moderni-spravce-balicku-a-virtualnich-prostredi-pythonu/
- Interní reprezentace numerických hodnot: od skutečného počítačového pravěku po IEEE 754–2008https://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á čidlahttps://www.root.cz/clanky/brain-floating-point-ndash-novy-format-ulozeni-cisel-pro-strojove-uceni-a-chytra-cidla/
- Stránky projektu PyTorchhttps://pytorch.org/
- Informace o instalaci PyTorchehttps://pytorch.org/get-started/locally/
- Tenzor (Wikipedia)https://cs.wikipedia.org/wiki/Tenzor
- Introduction to Tensorshttps://www.youtube.com/watch?v=uaQeXi4E7gA
- Introduction to Tensors: Transformation Ruleshttps://www.youtube.com/watch?v=j6DazQDbEhQ
- Tensor Attributeshttps://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 2Ahttps://www.youtube.com/watch?v=A95jdIuUUW0
- Visualization of tensors – part 2Bhttps://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 Unithttps://en.wikipedia.org/wiki/Tensor_Processing_Unit