Od projektu Scikit-learn ke knihovně PyTorch

5. 11. 2024
Doba čtení: 20 minut

Sdílet

 Autor: Pixabay
Začneme se zabývat knihovnou PyTorch, která je poměrně intenzivně využívána v oblasti strojového učení (machine learning) a zejména pak hlubokého učení (deep learning).

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ů

4. Instalace knihovny PyTorch

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

8. Datové typy pro tenzory uložené v paměti CPU i GPU kompatibilní se staršími verzemi Torche a PyTorche

9. Základní konstruktory tenzorů

10. Tenzory vyšších řádů

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

16. Konstruktor arange

17. Obsah navazujícího článku

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

19. Odkazy na Internetu

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 TorchPyTorchi. 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.

Poznámka: zde může docházet k určitým zmatkům, protože Pythonovský balíček s PyTorchem se ve skutečnosti jmenuje torch. Ovšem skutečně se jedná o PyTorch a nikoli o předchůdce této knihovny.

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

Poznámka: pojem tensor může být v tomto kontextu poněkud matoucí, protože v matematice a fyzice má tento termín velmi specifický význam a tenzory nejsou totožné s n-dimenzionálními poli (chybí nám totiž například informace o bázových vektorech, pro tenzory jsou definována pravidla pro jejich transformaci a i samotný tenzor má svoji obdobu v modelovaném systému, zatímco n-dimenzionální pole je skutečně jen polem čísel). Matematici a fyzici rádi zdůrazňují rozdíly mezi tenzory a n-dimenzionálními poli (vektory, matice, …) a mají pochopitelně pravdu. Ovšem z pohledu knihovny PyTorch se fyzikální význam tenzorů ztrácí a skutečně s nimi můžeme pracovat jako s n-dimenzionálními poli. A podobně s nimi pracují i TPU (Tensor Processing Unit(s)) v akcelerátorech.

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])
Poznámka: ve druhém případě nebyl vektor inicializován.

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.]]])
Poznámka: obecně není počet dimenzí prakticky omezen, ovšem setkáme se zejména s výše popsanými skaláry, vektory, maticemi a 3D poli.

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])
Poznámka: za povšimnutí stojí i varování, že tento konstruktor může být v budoucnosti z knihovny PyTorch odstraněn, protože jeho chování je odlišné od klasického Pythonu a jeho generátoru range.

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:

bitcoin školení listopad 24

  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:

# 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
8 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. Odkazy na Internetu

  1. Seriál Programovací jazyk Lua na Rootuhttps://www.root.cz/se­rialy/programovaci-jazyk-lua/
  2. 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/
  3. 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/
  4. Interní reprezentace numerických hodnot: od skutečného počítačového pravěku po IEEE 754–2008 (dokončení)https://www.ro­ot.cz/clanky/interni-reprezentace-numerickych-hodnot-od-skutecneho-pocitacoveho-praveku-po-ieee-754–2008-dokonceni/
  5. 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/
  6. Stránky projektu PyTorchhttps://pytorch.org/
  7. Informace o instalaci PyTorchehttps://pytorch.org/get-started/locally/
  8. Tenzor (Wikipedia)https://cs.wiki­pedia.org/wiki/Tenzor
  9. Introduction to Tensorshttps://www.youtube­.com/watch?v=uaQeXi4E7gA
  10. Introduction to Tensors: Transformation Ruleshttps://www.youtube.com/wat­ch?v=j6DazQDbEhQ
  11. Tensor Attributeshttps://pytorch­.org/docs/stable/tensor_at­tributes.html
  12. Tensors Explained Intuitively: Covariant, Contravariant, Rank https://www.youtube.com/wat­ch?v=CliW7kSxxWU
  13. What is the relationship between PyTorch and Torch?https://stackoverflow­.com/questions/44371560/what-is-the-relationship-between-pytorch-and-torch
  14. What is a tensor anyway?? (from a mathematician)https://www­.youtube.com/watch?v=K7f2pCQ3p3U
  15. Visualization of tensors – part 1 https://www.youtube.com/wat­ch?v=YxXyN2ifK8A
  16. Visualization of tensors – part 2Ahttps://www.youtube.com/wat­ch?v=A95jdIuUUW0
  17. Visualization of tensors – part 2Bhttps://www.youtube.com/wat­ch?v=A95jdIuUUW0
  18. What the HECK is a Tensor?!?https://www.youtu­be.com/watch?v=bpG3gqDM80w
  19. Stránka projektu Torch
    http://torch.ch/
  20. Torch na GitHubu (několik repositářů)
    https://github.com/torch
  21. Torch (machine learning), Wikipedia
    https://en.wikipedia.org/wi­ki/Torch_%28machine_learnin­g%29
  22. Torch Package Reference Manual
    https://github.com/torch/tor­ch7/blob/master/README.md
  23. Torch Cheatsheet
    https://github.com/torch/tor­ch7/wiki/Cheatsheet
  24. An Introduction to Tensors
    https://math.stackexchange­.com/questions/10282/an-introduction-to-tensors
  25. Differences between a matrix and a tensor
    https://math.stackexchange­.com/questions/412423/dif­ferences-between-a-matrix-and-a-tensor
  26. 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?
  27. Tensors for Neural Networks, Clearly Explained!!!https://www.y­outube.com/watch?v=L35fFDpwIM4
  28. Tensor Processing Unithttps://en.wikipedia.or­g/wiki/Tensor_Processing_U­nit

Autor článku

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