Manipulace s tenzory v knihovně PyTorch (dokončení)

28. 11. 2024
Doba čtení: 28 minut

Sdílet

 Autor: Pixabay
V dnešním článku dokončíme popis vlastností tenzorů. Ukážeme si, jaké operace je možné s tenzory provádět, ať již se jedná o operace prováděné prvek po prvku, o takzvaný broadcasting nebo o komplikovanější činnosti.

Obsah

1. Manipulace s tenzory v knihovně PyTorch (dokončení)

2. Operace narrow aplikovaná na jednorozměrné vektory

3. Operace narrow aplikovaná na matice a tenzory vyšších řádů

4. Operace narrow nad dvourozměrnou maticí s výběrem druhé dimenze

5. Vytvoření pohledu na pohled

6. Operace narrow ve funkci zapisovatelných pohledů

7. Základní operace prováděné s dvojicí tenzorů metodou „prvek po prvku“

8. Součet, rozdíl, součin a podíl provedený metodou prvek po prvku

9. Skalární součin

10. Maticový součin

11. Broadcasting

12. Násobení všech prvků tenzoru skalární hodnotou

13. Broadcasting vektoru vs. násobení matice a vektoru

14. Broadcasting celé matice

15. Maticový součin s broadcastingem

16. Řídké tenzory

17. Ukázka konstrukce řídkého tenzoru

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

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

20. Odkazy na Internetu

1. Manipulace s tenzory v knihovně PyTorch (dokončení)

V dnešním článku dokončíme popis vlastností tenzorů implementovaných v knihovně PyTorch. Se základními operacemi, které je možné s tenzory provádět, jsme se již seznámili v úvodních dvou článcích [1] [2]. Dnes toto téma dokončíme. Ukážeme si totiž, jaké operace je možné s tenzory provádět, ať již se jedná o operace prováděné prvek po prvku, o takzvaný broadcasting nebo o komplikovanější činnosti. Potom budeme mít k dispozici prakticky všechny potřebné základní znalosti nutné pro využití tenzorů pro konstrukci a trénink neuronových sítí, což je ostatně primární funkce celé knihovny PyTorch.

Poznámka: připomeňme si, že knihovna PyTorch umožňuje, aby výpočty probíhaly na CPU (a to v nativním kódu, který Python pouze volá) nebo na GPU. A právě možnost velmi snadného přenosu výpočtů z CPU na GPU je jednou z nejdůležitějších vlastností knihovny PyTorch, protože nám to umožňuje provádět časově náročný trénink neuronových sítí na specializovaném hardware, takže výsledku dosáhneme několikanásobně rychleji v porovnání s výpočtem na CPU (a to i přesto, že se zde využívají SIMD operace, například z instrukčních sad AVX). Ostatně rozdíl poznáme již příště při konstrukci a tréninku jednoduché neuronové sítě.

2. Operace narrow aplikovaná na jednorozměrné vektory

S některými operacemi, které vrací pohled (view) na nějaký reálný tenzor (nebo též na jiný pohled), jsme se již setkali. Do této kategorie velmi často používaných operací patří i operace nazvaná narrow, která taktéž získá pohled na zvolený tenzor. Této operaci se, pokud se volá formou funkce a nikoli metody, předávají čtyři parametry: původní tenzor (nebo pohled), dimenze (resp. přesněji řečeno její index), první prvek v dané dimenzi a celkový počet prvků, které má pohled obsahovat. Při volání formou metody se pochopitelně vynechává první parametr se zdrojovým tenzorem.

Podívejme se nyní na ten nejjednodušší (ale stále praktický) případ, tedy na získání pohledu do jednorozměrného vektoru. Ten má pochopitelně jen jednu dimenzi (=1) a budeme chtít získat pohled na osm prvků původního vektoru začínajících druhým prvkem. Následně změníme hodnotu v novém vektoru, ale kvůli tomu, že se jedná o pohled na vektor původní, bude tato hodnota propsána i do původního vektoru. Pohled totiž neobsahuje vlastní data (prvky), ale pouze reference na původní vektor:

import torch
 
# konstrukce tenzoru - vektoru s deseti prvky
v1 = torch.Tensor([1, 2, 3, 4, 5, 6, 7, 8, 9, 10])
print(v1)
 
print()
 
# realizace operace narrow s výběrem dimenze číslo 0
v2 = torch.narrow(v1, 0, 1, 8)
print(v2)
 
print()
 
# modifikace vektoru pres pohled na nej
v2[0] = 99
print(v1)
print()
print(v2)

Výsledky, které získáme po spuštění tohoto skriptu, by měly vypadat následovně:

tensor([ 1.,  2.,  3.,  4.,  5.,  6.,  7.,  8.,  9., 10.])
 
tensor([2., 3., 4., 5., 6., 7., 8., 9.])
 
tensor([ 1., 99.,  3.,  4.,  5.,  6.,  7.,  8.,  9., 10.])
 
tensor([99.,  3.,  4.,  5.,  6.,  7.,  8.,  9.])

Operaci narrow lze ovšem volat i formou metody. Výsledky budou v obou případech totožné:

import torch
 
# konstrukce tenzoru - vektoru s deseti prvky
v1 = torch.Tensor([1, 2, 3, 4, 5, 6, 7, 8, 9, 10])
print(v1)
 
print()
 
# realizace operace narrow s výběrem dimenze číslo 0
v2 = v1.narrow(0, 1, 8)
print(v2)
 
print()
 
# modifikace vektoru pres pohled na nej
v2[0] = 99
print(v1)
print()
print(v2)

Výsledky budou, jak již víme, shodné s předchozím demonstračním příkladem.

3. Operace narrow aplikovaná na matice a tenzory vyšších řádů

Varianta operace narrow představená v předchozí kapitole nebyla příliš praktická, protože u jednorozměrných vektorů provádí jednoduchý řez (slice), který již dobře známe a dokážeme ho provést i jednoduššími prostředky. Mnohem užitečnější je použití operace narrow na matice a samozřejmě taktéž na tenzory vyšších řádů. Vraťme se k naší matici 4×4 prvky použité dříve. S využitím narrow získáme pohled na druhý a třetí řádek matice (pohybujeme se tedy po řádcích, neboť jsme zvolili první dimenzi). A opět je možné provést zápis do původní matice přes pohled na ni:

import torch
 
# konstrukce tenzoru (matice 4x4 prvky)
m1 = torch.Tensor([[1, 2, 3, 4], [5, 6, 7, 8], [9, 10, 11, 12], [13, 14, 15, 16]])
print(m1)
 
print()
 
# realizace operace narrow s výběrem dimenze číslo 0
m2 = torch.narrow(m1, 0, 1, 2)
print(m2)
 
print()
 
# modifikace puvodni matice pres jeji pohled
m2[0, 0] = 99
print(m1)
print()
print(m2)

Zobrazené výsledky představují původní matici, pohled na dva řádky z této matice, modifikovanou variantu původní matice a modifikovaný pohled:

tensor([[ 1.,  2.,  3.,  4.],
        [ 5.,  6.,  7.,  8.],
        [ 9., 10., 11., 12.],
        [13., 14., 15., 16.]])
 
tensor([[ 5.,  6.,  7.,  8.],
        [ 9., 10., 11., 12.]])
 
tensor([[ 1.,  2.,  3.,  4.],
        [99.,  6.,  7.,  8.],
        [ 9., 10., 11., 12.],
        [13., 14., 15., 16.]])
 
tensor([[99.,  6.,  7.,  8.],
        [ 9., 10., 11., 12.]])

Opět platí, že operaci narrow můžeme volat jako funkci pytorch.narrow i jako metodu muj_tenzor.narrow. To znamená, že předchozí příklad si můžeme převést do podoby:

import torch
 
# konstrukce tenzoru (matice 4x4 prvky)
m1 = torch.Tensor([[1, 2, 3, 4], [5, 6, 7, 8], [9, 10, 11, 12], [13, 14, 15, 16]])
print(m1)
 
print()
 
# realizace operace narrow s výběrem dimenze číslo 0
m2 = m1.narrow(0, 1, 2)
print(m2)
 
print()
 
# modifikace puvodni matice pres jeji pohled
m2[0, 0] = 99
print(m1)
print()
print(m2)
Poznámka: výsledky budou opět totožné s předchozím demonstračním příkladem.

4. Operace narrow nad dvourozměrnou maticí s výběrem druhé dimenze

V případě, že je první parametr metody narrow, resp. druhý parametr funkce pytorch.narrow roven jedné, bude se provádět výběr z matice po sloupcích a nikoli po řádcích, protože pracujeme s druhou a nikoli s první dimenzí. Opět si to pochopitelně můžeme ukázat na nějakém jednoduchém příkladu, jenž jako zdroj dat využívá naši matici 4×4 prvky. Nad touto maticí vytvoříme pohled na dva sloupce, tento pohled následně zobrazíme a pokusíme se matici změnit přes tento pohled:

import torch
 
# konstrukce tenzoru (matice 4x4 prvky)
m1 = torch.Tensor([[1, 2, 3, 4], [5, 6, 7, 8], [9, 10, 11, 12], [13, 14, 15, 16]])
print(m1)
 
print()
 
# realizace operace narrow s výběrem dimenze číslo 1
m2 = torch.narrow(m1, 1, 1, 2)
print(m2)
 
print()
 
# modifikace puvodni matice pres jeji pohled
m2[0, 0] = 99
print(m1)
print()
print(m2)

Výsledkem bude vytištěná původní matice, dále pohled na matici (dva sloupce), modifikovaná matice a modifikovaný pohled:

tensor([[ 1.,  2.,  3.,  4.],
        [ 5.,  6.,  7.,  8.],
        [ 9., 10., 11., 12.],
        [13., 14., 15., 16.]])
 
tensor([[ 2.,  3.],
        [ 6.,  7.],
        [10., 11.],
        [14., 15.]])
 
tensor([[ 1., 99.,  3.,  4.],
        [ 5.,  6.,  7.,  8.],
        [ 9., 10., 11., 12.],
        [13., 14., 15., 16.]])
 
tensor([[99.,  3.],
        [ 6.,  7.],
        [10., 11.],
        [14., 15.]])

Naprosto stejně můžeme namísto funkce pytorch.narrow použít metodu se shodným jménem:

import torch
 
# konstrukce tenzoru (matice 4x4 prvky)
m1 = torch.Tensor([[1, 2, 3, 4], [5, 6, 7, 8], [9, 10, 11, 12], [13, 14, 15, 16]])
print(m1)
 
print()
 
# realizace operace narrow s výběrem dimenze číslo 1
m2 = m1.narrow(1, 1, 2)
print(m2)
 
print()
 
# modifikace puvodni matice pres jeji pohled
m2[0, 0] = 99
print(m1)
print()
print(m2)

5. Vytvoření pohledu na pohled

Nic nám samozřejmě nebrání v tom, abychom nad nějakým pohledem vytvořili nový pohled. Tuto operaci lze provádět rekurzivně prakticky do jakékoli hloubky a skutečně se často setkáme s tím, že se namísto tenzorů pracuje s pohledy a taktéž pohledy na jiné pohledy. Ukažme si to na jednoduchém příkladu, v němž z původní matice 4×4 prvky vytvoříme pohled na dva sloupce a další pohled vybírající dva řádky z prvního pohledu:

import torch
 
# konstrukce tenzoru (matice 4x4 prvky)
m1 = torch.Tensor([[1, 2, 3, 4], [5, 6, 7, 8], [9, 10, 11, 12], [13, 14, 15, 16]])
print(m1)
print()
 
# pohled na původní matici
m2 = torch.narrow(m1, 1, 1, 2)
print(m2)
print()
 
# pohled na pohled
m3 = torch.narrow(m2, 0, 1, 2)
print(m3)
print()

Alternativní způsob zápisu založený na metodě narrow a nikoli na funkci pytorch.narrow:

import torch
 
# konstrukce tenzoru (matice 4x4 prvky)
m1 = torch.Tensor([[1, 2, 3, 4], [5, 6, 7, 8], [9, 10, 11, 12], [13, 14, 15, 16]])
print(m1)
print()
 
# pohled na původní matici
m2 = m1.narrow(1, 1, 2)
print(m2)
print()
 
# pohled na pohled
m3 = m2.narrow(0, 1, 2)
print(m3)
print()

V obou případech by se postupně měla zobrazit původní matice, pohled na tuto matici (dva sloupce) a následně pohled na pohled (dva řádky):

tensor([[ 1.,  2.,  3.,  4.],
        [ 5.,  6.,  7.,  8.],
        [ 9., 10., 11., 12.],
        [13., 14., 15., 16.]])
 
tensor([[ 2.,  3.],
        [ 6.,  7.],
        [10., 11.],
        [14., 15.]])
 
tensor([[ 6.,  7.],
        [10., 11.]])

6. Operace narrow ve funkci zapisovatelných pohledů

Již v předchozím textu jsme si ukázali, že tenzory jsou měnitelné jak přímo, tak i přes své pohledy. Navíc jsou nad pohledy definovány všechny metody měnící obsah tenzoru. To platí i pro operaci fill, kterou již dobře známe, ovšem pro úplnost si ji ještě připomeňme. Zkonstruujeme matici o rozměrech 4×4 prvky a přes dva pohledy získáme submatici 2×2 prvky (což je ovšem pohled). Tuto podmatici vyplníme hodnotami 99 právě operací fill. Tyto údaje se, jak již víme, propíšou do výchozí matice:

import torch
 
# konstrukce tenzoru (matice 4x4 prvky)
m1 = torch.Tensor([[1, 2, 3, 4], [5, 6, 7, 8], [9, 10, 11, 12], [13, 14, 15, 16]])
print(m1)
print()
 
# pohled na původní matici
m2 = torch.narrow(m1, 1, 1, 2)
print(m2)
print()
 
# pohled na pohled
m3 = torch.narrow(m2, 0, 1, 2)
print(m3)
print()
 
# změna všech prvků v pohledu
m3.fill_(99)
print(m1)

Postupně prováděné kroky jsou vypisovány na standardní výstup:

tensor([[ 1.,  2.,  3.,  4.],
        [ 5.,  6.,  7.,  8.],
        [ 9., 10., 11., 12.],
        [13., 14., 15., 16.]])
 
tensor([[ 2.,  3.],
        [ 6.,  7.],
        [10., 11.],
        [14., 15.]])
 
tensor([[ 6.,  7.],
        [10., 11.]])
 
tensor([[ 1.,  2.,  3.,  4.],
        [ 5., 99., 99.,  8.],
        [ 9., 99., 99., 12.],
        [13., 14., 15., 16.]])

Ještě se podívejme na složitější příklad, v němž operací fill vyplníme zvolený řádek/řádky, zvolený sloupec/sloupce a konečně vybranou podmatici:

import torch
 
# konstrukce tenzoru druheho radu
# s vynulovanim vsech prvku
m1 = torch.Tensor(5, 5).zero_()
print(m1)
print()
 
# vyplneni radku matice
m1.narrow(0, 2, 1).fill_(3)
print(m1)
print()
 
# vyplneni sloupce matice
m1.narrow(1, 2, 1).fill_(9)
print(m1)
print()
 
# vyplneni strednich 3x3 prvku matice
m1.narrow(1, 1, 3).narrow(0, 1, 3).fill_(1)
print(m1)
print()

Postupně měněná matice je vypsána na standardní výstup:

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.]])
 
tensor([[0., 0., 0., 0., 0.],
        [0., 0., 0., 0., 0.],
        [3., 3., 3., 3., 3.],
        [0., 0., 0., 0., 0.],
        [0., 0., 0., 0., 0.]])
 
tensor([[0., 0., 9., 0., 0.],
        [0., 0., 9., 0., 0.],
        [3., 3., 9., 3., 3.],
        [0., 0., 9., 0., 0.],
        [0., 0., 9., 0., 0.]])
 
tensor([[0., 0., 9., 0., 0.],
        [0., 1., 1., 1., 0.],
        [3., 1., 1., 1., 3.],
        [0., 1., 1., 1., 0.],
        [0., 0., 9., 0., 0.]])

7. Základní operace prováděné s dvojicí tenzorů metodou „prvek po prvku“

V knihovně PyTorch jsou definovány (resp. přesněji řečeno přetíženy) základní aritmetické operátory takovým způsobem, aby bylo možné provádět zvolenou operaci nad všemi odpovídajícími si prvky dvou tenzorů se stejným tvarem (shape). To například znamená, že operátor + dokáže sečíst odpovídající si prvky vektorů nebo matic a totéž platí i pro ostatní operátory. U součtu a rozdílu se vlastně jedná o běžný součet vektorů a matic, ovšem operace součinu a podílu je odlišná od „vektorového součinu“, „maticového součinu“ atd. Například pokud máme dva tenzory druhého řádu m1 a m2 se shodným tvarem, bude operace m1 * m2 znamenat, že výsledkem bude nový tenzor druhého řádu se stejným tvarem, přičemž jeho prvek [0, 0] bude odpovídat m1[0, 0] * m2[0, 0] atd.

Poznámka: jedná se o často volané operace, které jsou dobře optimalizovány. Buď běží na GPU s paralelními výpočetními jednotkami, nebo jsou na CPU použity příslušné SIMD operace – dnes typicky operace z nějaké verze AVX.

8. Součet, rozdíl, součin a podíl provedený metodou prvek po prvku

Otestování operace součtu, rozdílu, součinu a podílu dvou tenzorů si nejprve ukážeme na dvojici matic stejného tvaru (shape). Následující čtyři příklady pravděpodobně nevyžadují podrobnější popis:

import torch
 
# konstrukce tenzoru, vyplneni sekvenci
v1 = torch.range(1, 12)
print(v1)
print()
 
# konstrukce 2D matice z puvodniho vektoru
m1 = torch.reshape(v1, (4, 3))
print(m1)
print()
 
# vytvořeni druhe matice se stejnym tvarem
m2 = torch.ones(4, 3)
print(m2)
print()
 
# soucet metodou prvek po prvku
m3 = m1 + m2
print(m3)
print()

Tento demonstrační příklad vypíše součet matic prvek po prvku:

tensor([ 1.,  2.,  3.,  4.,  5.,  6.,  7.,  8.,  9., 10., 11., 12.])
 
tensor([[ 1.,  2.,  3.],
        [ 4.,  5.,  6.],
        [ 7.,  8.,  9.],
        [10., 11., 12.]])
 
tensor([[1., 1., 1.],
        [1., 1., 1.],
        [1., 1., 1.],
        [1., 1., 1.]])
 
tensor([[ 2.,  3.,  4.],
        [ 5.,  6.,  7.],
        [ 8.,  9., 10.],
        [11., 12., 13.]])

Rozdíl dvou matic provedený prvek po prvku:

import torch
 
# konstrukce tenzoru, vyplneni sekvenci
v1 = torch.range(1, 12)
print(v1)
print()
 
# konstrukce 2D matice z puvodniho vektoru
m1 = torch.reshape(v1, (4, 3))
print(m1)
print()
 
# vytvořeni druhe matice se stejnym tvarem
m2 = torch.ones(4, 3)
print(m2)
print()
 
# rozdil metodou prvek po prvku
m3 = m1 - m2
print(m3)
print()

Výsledky:

tensor([ 1.,  2.,  3.,  4.,  5.,  6.,  7.,  8.,  9., 10., 11., 12.])
 
tensor([[ 1.,  2.,  3.],
        [ 4.,  5.,  6.],
        [ 7.,  8.,  9.],
        [10., 11., 12.]])
 
tensor([[1., 1., 1.],
        [1., 1., 1.],
        [1., 1., 1.],
        [1., 1., 1.]])
 
tensor([[ 0.,  1.,  2.],
        [ 3.,  4.,  5.],
        [ 6.,  7.,  8.],
        [ 9., 10., 11.]])

Následuje součin provedený metodou prvek po prvku (pozor: v žádném případě se nejedná o maticový součin):

import torch
 
# konstrukce tenzoru, vyplneni sekvenci
v1 = torch.range(1, 12)
print(v1)
print()
 
# konstrukce 2D matice z puvodniho vektoru
m1 = torch.reshape(v1, (4, 3))
print(m1)
print()
 
# vytvořeni druhe matice se stejnym tvarem
m2 = torch.ones(4, 3) + torch.ones(4, 3)
print(m2)
print()
 
# soucin metodou prvek po prvku
m3 = m1 * m2
print(m3)
print()

Výsledky:

tensor([ 1.,  2.,  3.,  4.,  5.,  6.,  7.,  8.,  9., 10., 11., 12.])
 
tensor([[ 1.,  2.,  3.],
        [ 4.,  5.,  6.],
        [ 7.,  8.,  9.],
        [10., 11., 12.]])
 
tensor([[2., 2., 2.],
        [2., 2., 2.],
        [2., 2., 2.],
        [2., 2., 2.]])
 
tensor([[ 2.,  4.,  6.],
        [ 8., 10., 12.],
        [14., 16., 18.],
        [20., 22., 24.]])

A konečně podíl provedený metodou prvek po prvku:

import torch
 
# konstrukce tenzoru, vyplneni sekvenci
v1 = torch.range(1, 12)
print(v1)
print()
 
# konstrukce 2D matice z puvodniho vektoru
m1 = torch.reshape(v1, (4, 3))
print(m1)
print()
 
# vytvořeni druhe matice se stejnym tvarem
m2 = torch.ones(4, 3) + torch.ones(4, 3)
print(m2)
print()
 
# podil metodou prvek po prvku
m3 = m1 / m2
print(m3)
print()

Výsledky:

tensor([ 1.,  2.,  3.,  4.,  5.,  6.,  7.,  8.,  9., 10., 11., 12.])
 
tensor([[ 1.,  2.,  3.],
        [ 4.,  5.,  6.],
        [ 7.,  8.,  9.],
        [10., 11., 12.]])
 
tensor([[2., 2., 2.],
        [2., 2., 2.],
        [2., 2., 2.],
        [2., 2., 2.]])
 
tensor([[0.5000, 1.0000, 1.5000],
        [2.0000, 2.5000, 3.0000],
        [3.5000, 4.0000, 4.5000],
        [5.0000, 5.5000, 6.0000]])

9. Skalární součin

Mezi jednu z nejužitečnějších operací při analýze dat (a zdaleka nejenom v této oblasti, použijeme ho i v několika oblastech fyziky atd.) patří operace skalárního součinu (dot product), což je zajímavé, protože samotné provedení operace je vlastně triviální. Při této operaci se postupně násobí odpovídající si složky (prvky) dvou vektorů a jednotlivé mezivýsledky jsou sečteny, přičemž platí podmínka, že oba vektory musí mít shodnou délku.

Výsledkem výpočtu je tedy jediná skalární hodnota a právě proto má v češtině tato operace název skalární součin. Tuto operaci je v knihovně PyTorch možné provést několika různými způsoby. My si ukážeme dva způsoby, a to konkrétně zavolání funkce torch.dot a použití operátoru @, což je sice v Pythonu rezervovaný operátor, který ovšem nemá dopředu přiřazený žádný význam:

import torch
 
# konstrukce 1D tenzoru
v1 = torch.Tensor([2, 2, 3, 5])
print(v1)
print()
 
# konstrukce druheho 2D tenzoru
v2 = torch.Tensor([2, 2, 3, 5])
print(v2)
print()
 
# skalarni soucin zapsany funkci
s = torch.dot(v1, v2)
print(s)
print()
 
# skalarni soucin zapsany operatorem
s = v1 @ v2
print(s)
 
# vysledkem je 42 - nahoda???

Tento skript nejdříve vypíše oba vektory vstupující o operace a poté dva výsledky skalárního součinu:

tensor([2., 2., 3., 5.])
 
tensor([2., 2., 3., 5.])
 
tensor(42.)
 
tensor(42.)
Poznámka: výsledkem je tenzor nultého řádu, tedy skutečně skalár.

10. Maticový součin

Velmi často prováděnou (a taktéž do značné míry optimalizovanou) operací je operace maticového součinu, kterou lze chápat i jako formu rozšíření sémantiky skalárního součinu. Maticový součin je prováděn nad dvojicí tenzorů druhého řádu, přičemž počet sloupců prvního tenzoru musí odpovídat počtu řádků tenzoru druhého. Výsledkem je nový tenzor, jehož počet řádků odpovídá počtu řádků prvního tenzoru a počet sloupců naopak odpovídá počtu sloupců tenzoru druhého – výsledný tenzor tedy může být větší nebo menší, než oba tenzory, které do operace vstupují formou operandů. Maticové násobení je zapisováno buď funkcí torch.matmul nebo můžeme (opět) použít operátor @. Tento operátor se tedy bude chovat odlišně na základě toho, zda jsou vstupem vektory a/nebo matice.

Pokusme se nyní vynásobit matici se třemi sloupci a čtyřmi řádky druhou maticí, která má čtyři sloupce a tři řádky:

import torch
 
# konstrukce tenzoru, vyplneni sekvenci
v1 = torch.range(1, 12)
print(v1)
print()
 
# konstrukce prvni matice z puvodniho tenzoru
m1 = torch.reshape(v1, (4, 3))
print(m1)
print()
 
# konstrukce druhe matice z puvodniho tenzoru
m2 = torch.reshape(v1, (3, 4))
print(m2)
print()
 
# provedeni maticoveho soucinu
m3 = m1 @ m2
print(m3)

Výsledkem bude (podle očekávání) matice o velikosti 4×4 prvky:

tensor([ 1.,  2.,  3.,  4.,  5.,  6.,  7.,  8.,  9., 10., 11., 12.])
 
tensor([[ 1.,  2.,  3.],
        [ 4.,  5.,  6.],
        [ 7.,  8.,  9.],
        [10., 11., 12.]])
 
tensor([[ 1.,  2.,  3.,  4.],
        [ 5.,  6.,  7.,  8.],
        [ 9., 10., 11., 12.]])
 
tensor([[ 38.,  44.,  50.,  56.],
        [ 83.,  98., 113., 128.],
        [128., 152., 176., 200.],
        [173., 206., 239., 272.]])

Pokud obě matice vynásobíme v opačném pořadí, bude mít výsledná matice velikost jen 3×3 prvky:

import torch
 
# konstrukce tenzoru, vyplneni sekvenci
v1 = torch.range(1, 12)
print(v1)
print()
 
# konstrukce prvni matice z puvodniho tenzoru
m1 = torch.reshape(v1, (4, 3))
print(m1)
print()
 
# konstrukce druhe matice z puvodniho tenzoru
m2 = torch.reshape(v1, (3, 4))
print(m2)
print()
 
# provedeni maticoveho soucinu
# v opacnem poradi
m3 = m2 @ m1
print(m3)

Výsledky zobrazené tímto skriptem:

tensor([ 1.,  2.,  3.,  4.,  5.,  6.,  7.,  8.,  9., 10., 11., 12.])
 
tensor([[ 1.,  2.,  3.],
        [ 4.,  5.,  6.],
        [ 7.,  8.,  9.],
        [10., 11., 12.]])
 
tensor([[ 1.,  2.,  3.,  4.],
        [ 5.,  6.,  7.,  8.],
        [ 9., 10., 11., 12.]])
 
tensor([[ 70.,  80.,  90.],
        [158., 184., 210.],
        [246., 288., 330.]])

Knihovna PyTorch pochopitelně hlídá i situace, kdy není možné matice násobit, protože nemají odpovídající tvar:

import torch
 
# konstrukce tenzoru, vyplneni sekvenci
v1 = torch.range(1, 12)
print(v1)
print()
 
# konstrukce prvni matice z puvodniho tenzoru
m1 = torch.reshape(v1, (4, 3))
print(m1)
print()
 
# konstrukce druhe matice z puvodniho tenzoru
m2 = torch.reshape(v1, (6, 2))
print(m2)
print()
 
# pokus o provedeni maticoveho soucinu
m3 = m1 @ m2
print(m3)

Při pokusu o maticový součin je vyhozena běhová výjimka:

  v1 = torch.range(1, 12)
tensor([ 1.,  2.,  3.,  4.,  5.,  6.,  7.,  8.,  9., 10., 11., 12.])
 
tensor([[ 1.,  2.,  3.],
        [ 4.,  5.,  6.],
        [ 7.,  8.,  9.],
        [10., 11., 12.]])
 
tensor([[ 1.,  2.],
        [ 3.,  4.],
        [ 5.,  6.],
        [ 7.,  8.],
        [ 9., 10.],
        [11., 12.]])
 
Traceback (most recent call last):
  File "/home/ptisnovs/xy/src/tensor_operator_matmul_3.py", line 19, in <module>
    m3 = m1 @ m2
         ~~~^~~~
RuntimeError: mat1 and mat2 shapes cannot be multiplied (4x3 and 6x2)

11. Broadcasting

V předchozích kapitolách jsme mohli vidět, že v knihovně PyTorch je implementována podpora pro provádění operací nad celými tenzory (součet, rozdíl). Nesmíme ovšem zapomenout na podporu pro takzvaný broadcasting, tedy pro rozšíření tenzoru s menší dimenzí (resp. přesněji řečeno tenzoru nižšího řádu) takovým způsobem, aby bylo možné zvolenou operaci provést (tedy limitně lze přičíst skalár ke každému prvku libovolného N-rozměrného pole – tenzoru N-tého řádu). Jak však uvidíme v dalších kapitolách, provádí se nějaká forma broadastingu například i u výše zmíněného maticového součinu v případě, že jeden z tenzorů má menší řád, než tenzor druhý (a navíc speciálním případem je násobení matice a vektoru).

12. Násobení všech prvků tenzoru skalární hodnotou

Podívejme se nyní na tu nejjednodušší operaci, v níž je využitý broadcasting. Pokusíme se vynásobit všechny prvky tenzoru (v tomto případě se bude konkrétně jednat o matici) skalární hodnotou. To je možné, protože se operace násobení prvku tenzoru skalárem rozšíří na všechny prvky. Samotná realizace je triviální:

import torch
 
# konstrukce tenzoru, vyplneni sekvenci
v1 = torch.arange(1, 13)
print(v1)
print()
 
# vytvoreni matice z puvodniho vektoru
m1 = torch.reshape(v1, (4, 3))
print(m1)
print()
 
# vynasobeni kazdeho prvku matice skalarem
m2 = m1 * 10
print(m2)
print()

Tento skript nejdříve zobrazí vektor, ze kterého se zkonstruuje matice se třemi sloupci a čtyřmi řádky. Následně je každý prvek této matice vynásoben deseti:

tensor([ 1,  2,  3,  4,  5,  6,  7,  8,  9, 10, 11, 12])
 
tensor([[ 1,  2,  3],
        [ 4,  5,  6],
        [ 7,  8,  9],
        [10, 11, 12]])
 
tensor([[ 10,  20,  30],
        [ 40,  50,  60],
        [ 70,  80,  90],
        [100, 110, 120]])

13. Broadcasting vektoru vs. násobení matice a vektoru

Zajímavá situace nastane ve chvíli, kdy se pokusíme vynásobit matici a vektor s využitím operátoru *. V takovém případě se z vektoru sestrojí vhodná matice tak, že se celý vektor stane jedním řádkem matice a tyto řádky se zkopírují pod sebe tak, aby to odpovídalo počtu řádků původní matice. Posléze se provede násobení stylem prvek po prvku:

import torch
 
# konstrukce tenzoru, vyplneni sekvenci
v1 = torch.arange(1, 13)
print(v1)
print()
 
# vytvoreni matice z puvodniho vektoru
m1 = torch.reshape(v1, (4, 3))
print(m1)
print()
 
# jednorozmerny vektor
v2 = torch.Tensor([1, 2, -1])
print(v2)
print()
 
# nasobeni matice a vektoru prvek po prvku
m2 = m1 * v2
print(m2)
print()

Povšimněte si, jak nyní vypadá výsledná matice: prvky v prvním sloupci zůstaly zachovány, prvky ve druhém sloupci jsou vynásobeny dvojkou a prvky ve sloupci třetím hodnotou –1:

tensor([ 1,  2,  3,  4,  5,  6,  7,  8,  9, 10, 11, 12])
 
tensor([[ 1,  2,  3],
        [ 4,  5,  6],
        [ 7,  8,  9],
        [10, 11, 12]])
 
tensor([ 1.,  2., -1.])
 
tensor([[  1.,   4.,  -3.],
        [  4.,  10.,  -6.],
        [  7.,  16.,  -9.],
        [ 10.,  22., -12.]])

Tatáž operace broadcastingu se provede ve chvíli, kdy násobíme vektor a matici (nikoli matici a vektor) s využitím operátoru *:

import torch
 
# konstrukce tenzoru, vyplneni sekvenci
v1 = torch.arange(1, 13)
print(v1)
print()
 
# vytvoreni matice z puvodniho vektoru
m1 = torch.reshape(v1, (4, 3))
print(m1)
print()
 
# jednorozmerny vektor
v2 = torch.Tensor([1, 2, -1])
print(v2)
print()
 
# nasobeni vektoru a matice prvek po prvku
m2 = v2 * m1
print(m2)
print()

Výsledky budou v tomto případě stejné, jako v předchozím demonstračním příkladu:

tensor([ 1,  2,  3,  4,  5,  6,  7,  8,  9, 10, 11, 12])
 
tensor([[ 1,  2,  3],
        [ 4,  5,  6],
        [ 7,  8,  9],
        [10, 11, 12]])
 
tensor([ 1.,  2., -1.])
 
tensor([[  1.,   4.,  -3.],
        [  4.,  10.,  -6.],
        [  7.,  16.,  -9.],
        [ 10.,  22., -12.]])

Pokud ovšem potřebujete provést násobení vektoru maticí (například z důvodu otočení či jiné lineární transformace), je nutné použít operátor @:

import torch
 
# konstrukce tenzoru, vyplneni sekvenci
v1 = torch.range(1, 12)
print(v1)
print()
 
# konstrukce prvni matice z puvodniho tenzoru
m1 = torch.reshape(v1, (4, 3))
print(m1)
print()
 
# konstrukce vektoru
v2 = torch.tensor([1., 2., -1., 0])
print(v2)
print()
 
# provedeni maticoveho soucinu
m2 = v2 @ m1
print(m2)

Výsledek:

tensor([ 1.,  2.,  3.,  4.,  5.,  6.,  7.,  8.,  9., 10., 11., 12.])
 
tensor([[ 1.,  2.,  3.],
        [ 4.,  5.,  6.],
        [ 7.,  8.,  9.],
        [10., 11., 12.]])
 
tensor([ 1.,  2., -1.,  0.])
 
tensor([2., 4., 6.])

14. Broadcasting celé matice

V předchozí kapitole jsme si ukázali, jak je „broadcastována“ nějaká operace aplikovaná na vektor a matici. V takovém případě je vektor de facto rozšířen na vhodně velkou matici. Ovšem stejná operace probíhá i v případě použití vektorů vyšších řádů. To například znamená, že matice o velikosti 4×3 prvky je rozšířena na „3D pole“ v případě, pokud ji budeme sčítat s tenzorem o velikosti 5×4×3 prvky:

import torch
 
# konstrukce tenzoru, vyplneni sekvenci
v1 = torch.arange(1, 13)
print(v1)
print()
 
# tenzor druhého řádu
m1 = torch.reshape(v1, (4, 3))
print(m1)
print()
 
# tenzor třetího řádu
c1 = torch.ones(5, 4, 3)
print(c1)
print()
 
print(m1 + c1)

Tento skript nejdříve vypíše vektor, z něhož je zkonstruována matice se třemi sloupci a čtyřmi řádky. I tato matice je vypsána:

tensor([ 1,  2,  3,  4,  5,  6,  7,  8,  9, 10, 11, 12])
 
tensor([[ 1,  2,  3],
        [ 4,  5,  6],
        [ 7,  8,  9],
        [10, 11, 12]])

Následně je vypsán tenzor třetího řádu, což je vlastně 3D pole o rozměrech 3×4×5 prvků:

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

Při pokusu o součet tenzoru a matice se matice rozšíří na požadovanou velikost (opakováním jejího obsahu 5×):

tensor([[[ 2.,  3.,  4.],
         [ 5.,  6.,  7.],
         [ 8.,  9., 10.],
         [11., 12., 13.]],
 
        [[ 2.,  3.,  4.],
         [ 5.,  6.,  7.],
         [ 8.,  9., 10.],
         [11., 12., 13.]],
 
        [[ 2.,  3.,  4.],
         [ 5.,  6.,  7.],
         [ 8.,  9., 10.],
         [11., 12., 13.]],
 
        [[ 2.,  3.,  4.],
         [ 5.,  6.,  7.],
         [ 8.,  9., 10.],
         [11., 12., 13.]],
 
        [[ 2.,  3.,  4.],
         [ 5.,  6.,  7.],
         [ 8.,  9., 10.],
         [11., 12., 13.]]])

15. Maticový součin s broadcastingem

Pravděpodobně nejsložitější operací, v níž je broadcasting využitý, je maticový součin provedený ve chvíli, kdy se odlišují řády tenzorů a současně mají oba tenzory řád vyšší než 1 (v opačném případě by se provedlo násobení vektorem). Podívejme se na jednoduchý příklad:

import torch
 
# konstrukce tenzoru, vyplneni sekvenci
v1 = torch.range(1, 12)
print(v1)
print()
 
# konstrukce prvni matice z puvodniho tenzoru
m1 = torch.reshape(v1, (4, 3))
print(m1)
print()
 
# konstrukce druhe matice z puvodniho tenzoru
m2 = torch.Tensor([[[ 1,  1], [ 1,  1], [ 1,  1]],
                   [[ 2,  2], [ 2,  2], [ 2,  2]],
                   [[-1, -1], [-1, -2], [-1, -1]]])
print(m2)
print()
 
# pokus o provedeni maticoveho soucinu s broadcastem
m3 = m1 @ m2
print(m3)

Prvním tenzorem je matice, kdežto druhý tenzor má rozměry 2×2×3 prvky:

tensor([ 1.,  2.,  3.,  4.,  5.,  6.,  7.,  8.,  9., 10., 11., 12.])
 
tensor([[ 1.,  2.,  3.],
        [ 4.,  5.,  6.],
        [ 7.,  8.,  9.],
        [10., 11., 12.]])
 
tensor([[[ 1.,  1.],
         [ 1.,  1.],
         [ 1.,  1.]],
 
        [[ 2.,  2.],
         [ 2.,  2.],
         [ 2.,  2.]],
 
        [[-1., -1.],
         [-1., -2.],
         [-1., -1.]]])

A takto vypadá výsledek (maticového) součinu. Jedná se o tenzor s rozměry 2×4×3:

tensor([[[  6.,   6.],
         [ 15.,  15.],
         [ 24.,  24.],
         [ 33.,  33.]],
 
        [[ 12.,  12.],
         [ 30.,  30.],
         [ 48.,  48.],
         [ 66.,  66.]],
 
        [[ -6.,  -8.],
         [-15., -20.],
         [-24., -32.],
         [-33., -44.]]])
Poznámka: i když to může vypadat zvláštně, setkáme se v praxi i s touto operací, například u některých manipulací s konvolučními sítěmi.

16. Řídké tenzory

Již v paralelně vydávaných článcích o zpracování a analýze dat s využitím knihovny scikit-learn jsme se setkali s objektem typu řídká matice. Připomeňme si, že se jedná o takovou matici, která obsahuje mnoho nulových prvků (a obecně mnoho prvků se stejnou hodnotou). Taková matice vznikne například vektorizací dokumentů v případě, že máme velký slovník, který obsahuje tisíce až desetitisíce slov. Matici, kde je prakticky každý prvek nulový, lze uložit ve specializovaném tvaru tak, že si pouze zaznamenáme indexy a hodnoty nenulových prvků.

Podobně tomu je v knihovně PyTorch, která podporuje řídké tenzory. Jedná se o zobecnění řídké matice, protože řídký tenzor může být prakticky libovolného řádu. V takovém případě se řídký tenzor uloží formou vektorů souřadnic nenulových prvků a vektorů hodnot těchto prvků.

Poznámka: podpora řídkých tenzorů v GPU prozatím není dokonalá a většinou jsme omezeni pouze na celočíselné hodnoty a/nebo naopak na hodnoty typu float. Situace se ale v nových verzích PyTorche zlepšuje.

17. Ukázka konstrukce řídkého tenzoru

Ukažme si nyní poněkud umělý demonstrační příklad, v němž z běžného tenzoru druhého řádu (tj. z matice), který obsahuje mnoho nulových hodnot, zkonstruujeme metodou nazvanou to_sparse řídký tenzor, jehož atributy následně zobrazíme:

import torch
 
m1 = torch.tensor([[0, 1, 0, 0], [1, 2, 0, 0], [0, 0, 1, 0]])
print(m1)
print()
 
sparse = m1.to_sparse()
print(sparse)

Po spuštění tohoto skriptu se nejdříve zobrazí původní vektor (matice) a posléze i řídký tenzor:

tensor([[0, 1, 0, 0],
        [1, 2, 0, 0],
        [0, 0, 1, 0]])
 
tensor(indices=tensor([[0, 1, 1, 2],
                       [1, 0, 1, 2]]),
       values=tensor([1, 1, 2, 1]),
       size=(3, 4), nnz=4, layout=torch.sparse_coo)

Povšimněte si, jak jsou v řídkém tenzoru uloženy jednotlivé prvky. Máme zde souřadnice nenulových prvků a samozřejmě i jejich hodnoty. Můžeme například vyčíst, že na souřadnicích [1, 1] je uložena hodnota číslo 2. Příslušné souřadnice a hodnota jsou podtrženy:

bitcoin školení listopad 24

tensor(indices=tensor([[0, 1, 1, 2],
                       [1, 0, 1, 2]]),
       values=tensor([1, 1, 2, 1]),
       size=(3, 4), nnz=4, layout=torch.sparse_coo)

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

V navazujícím článku si ukážeme tu nejdůležitější funkcionalitu celého balíčku PyTorch. Je jím konstrukce neuronových sítí zvoleného typu a tvaru, trénink těchto sítí a jejich následné použití pro řešení konkrétních úloh. Zejména trénink neuronových sítí je přitom velmi náročný na výpočetní čas a z tohoto důvodu knihovna PyTorch umožňuje realizovat tyto výpočty na GPU, který je přesně pro tento typ úloh navržen.

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

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

# Příklad Stručný popis Adresa příkladu
1 tensor_constructor_scalar1.py konstrukce tenzoru nultého a prvního řádu https://github.com/tisnik/most-popular-python-libs/blob/master/PyTorch/ten­sor_constructor_scalar1.py
2 tensor_constructor_scalar2.py inicializace tenzoru prvního řádu s jedním prvkem https://github.com/tisnik/most-popular-python-libs/blob/master/PyTorch/ten­sor_constructor_scalar2.py
3 tensor_constructor_vector1.py konstrukce tenzoru prvního řádu (tříprvkový vektor) https://github.com/tisnik/most-popular-python-libs/blob/master/PyTorch/ten­sor_constructor_vector1.py
4 tensor_constructor_vector2.py konstrukce tenzoru prvního řádu s inicializací prvků https://github.com/tisnik/most-popular-python-libs/blob/master/PyTorch/ten­sor_constructor_vector2.py
5 tensor_constructor_vector3.py konstrukce tenzoru prvního řádu s využitím generátoru range https://github.com/tisnik/most-popular-python-libs/blob/master/PyTorch/ten­sor_constructor_vector3.py
6 tensor_constructor_matrix1.py vytvoření a inicializace tenzoru druhého řádu, který může být reprezentován maticí https://github.com/tisnik/most-popular-python-libs/blob/master/PyTorch/ten­sor_constructor_matrix1.py
7 tensor_constructor_matrix2.py inicializace prvků matice https://github.com/tisnik/most-popular-python-libs/blob/master/PyTorch/ten­sor_constructor_matrix2.py
8 tensor_constructor_3D1.py tenzor třetího řádu reprezentovaný „3D maticí“ https://github.com/tisnik/most-popular-python-libs/blob/master/PyTorch/ten­sor_constructor_3D1.py
9 tensor_constructor_3D2.py tenzor třetího řádu reprezentovaný „3D maticí“ (jiná forma inicializace) https://github.com/tisnik/most-popular-python-libs/blob/master/PyTorch/ten­sor_constructor_3D2.py
       
10 tensor_constructor_scalar_zero.py vynulování prvků tenzoru nultého řádu https://github.com/tisnik/most-popular-python-libs/blob/master/PyTorch/ten­sor_constructor_scalar_ze­ro.py
11 tensor_constructor_vector_zero.py vynulování prvků tenzoru prvního řádu https://github.com/tisnik/most-popular-python-libs/blob/master/PyTorch/ten­sor_constructor_vector_ze­ro.py
12 tensor_constructor_matrix_zero.py vynulování prvků tenzoru druhého řádu https://github.com/tisnik/most-popular-python-libs/blob/master/PyTorch/ten­sor_constructor_matrix_ze­ro.py
13 tensor_constructor_3D_zero.py vynulování prvků tenzoru třetího řádu https://github.com/tisnik/most-popular-python-libs/blob/master/PyTorch/ten­sor_constructor_3D_zero.py
       
14 tensor_zeros_shape.py použití konstruktoru zeros pro tenzory různých řádů a tvarů https://github.com/tisnik/most-popular-python-libs/blob/master/PyTorch/ten­sor_zeros_shape.py
15 tensor_ones_shape.py použití konstruktoru ones pro tenzory různých řádů a tvarů https://github.com/tisnik/most-popular-python-libs/blob/master/PyTorch/ten­sor_ones_shape.py
16 tensor_eye.py konstrukce jednotkové matice https://github.com/tisnik/most-popular-python-libs/blob/master/PyTorch/tensor_eye.py
       
17 tensor_range.py využití konstruktoru range https://github.com/tisnik/most-popular-python-libs/blob/master/PyTorch/ten­sor_range.py
18 tensor_arange.py využití konstruktoru arange https://github.com/tisnik/most-popular-python-libs/blob/master/PyTorch/ten­sor_arange.py
       
19 tensor_shape.py zjištění tvaru tenzoru https://github.com/tisnik/most-popular-python-libs/blob/master/PyTorch/ten­sor_shape.py
20 tensor_zeros_shape.py zjištění tvaru tenzoru vytvořeného konstruktorem zeros https://github.com/tisnik/most-popular-python-libs/blob/master/PyTorch/ten­sor_zeros_shape.py
21 tensor_ones_shape.py zjištění tvaru tenzoru vytvořeného konstruktorem ones https://github.com/tisnik/most-popular-python-libs/blob/master/PyTorch/ten­sor_ones_shape.py
22 tensor_read_dtype.py zjištění, jakého typu jsou prvky tenzoru https://github.com/tisnik/most-popular-python-libs/blob/master/PyTorch/ten­sor_read_dtype.py
23 tensor_set_dtype.py nastavení či změna typu prvků tenzoru https://github.com/tisnik/most-popular-python-libs/blob/master/PyTorch/ten­sor_set_dtype.py
       
24 tensor_storage1.py získání datové struktury se zdrojem dat pro tenzor https://github.com/tisnik/most-popular-python-libs/blob/master/PyTorch/ten­sor_storage1.py
25 tensor_storage2.py získání datové struktury se zdrojem dat pro tenzor https://github.com/tisnik/most-popular-python-libs/blob/master/PyTorch/ten­sor_storage2.py
26 tensor_storage3.py získání datové struktury se zdrojem dat pro tenzor https://github.com/tisnik/most-popular-python-libs/blob/master/PyTorch/ten­sor_storage3.py
27 tensor_storage_casts.py přetypování datové struktury se zdrojem dat pro tenzor https://github.com/tisnik/most-popular-python-libs/blob/master/PyTorch/ten­sor_storage_casts.py
       
28 tensor_slice_operation1.py konstrukce řezu z tenzoru prvního řádu https://github.com/tisnik/most-popular-python-libs/blob/master/PyTorch/ten­sor_slice_operation1.py
29 tensor_slice_operation2.py konstrukce řezu z tenzoru druhého řádu (přes řádky a sloupce) https://github.com/tisnik/most-popular-python-libs/blob/master/PyTorch/ten­sor_slice_operation2.py
30 tensor_slice_operation3.py konstrukce řezu s jeho následnou modifikací https://github.com/tisnik/most-popular-python-libs/blob/master/PyTorch/ten­sor_slice_operation3.py
31 tensor_slice_operation4.py konstrukce řezu s jeho následnou modifikací (odlišné operace od předchozího příkladu) https://github.com/tisnik/most-popular-python-libs/blob/master/PyTorch/ten­sor_slice_operation4.py
32 tensor_is_slice.py test základních vlastností řezů https://github.com/tisnik/most-popular-python-libs/blob/master/PyTorch/ten­sor_is_slice.py
       
33 tensor_stride1.py význam atributů stride a storage_offset https://github.com/tisnik/most-popular-python-libs/blob/master/PyTorch/ten­sor_stride1.py
34 tensor_stride2.py význam atributů stride a storage_offset https://github.com/tisnik/most-popular-python-libs/blob/master/PyTorch/ten­sor_stride2.py
35 tensor_stride3.py význam atributů stride a storage_offset https://github.com/tisnik/most-popular-python-libs/blob/master/PyTorch/ten­sor_stride3.py
       
36 tensor_reshape.py změna tvaru tenzoru operací reshape https://github.com/tisnik/most-popular-python-libs/blob/master/PyTorch/ten­sor_reshape.py
37 tensor_reshape2.py změna tvaru tenzoru operací reshape https://github.com/tisnik/most-popular-python-libs/blob/master/PyTorch/ten­sor_reshape2.py
       
38 tensor_narrow_operation1.py operace nad celým tenzorem typu narrow, první ukázka https://github.com/tisnik/most-popular-python-libs/blob/master/PyTorch/ten­sor_narrow_operation1.py
39 tensor_narrow_operation1_B.py operace nad celým tenzorem typu narrow, první ukázka přepsaná do volání metody https://github.com/tisnik/most-popular-python-libs/blob/master/PyTorch/ten­sor_narrow_operation1_B.py
40 tensor_narrow_operation2.py operace nad celým tenzorem typu narrow, druhá ukázka https://github.com/tisnik/most-popular-python-libs/blob/master/PyTorch/ten­sor_narrow_operation2.py
41 tensor_narrow_operation2_B.py operace nad celým tenzorem typu narrow, druhá ukázka přepsaná do volání metody https://github.com/tisnik/most-popular-python-libs/blob/master/PyTorch/ten­sor_narrow_operation2_B.py
42 tensor_narrow_operation3.py operace nad celým tenzorem typu narrow, třetí ukázka https://github.com/tisnik/most-popular-python-libs/blob/master/PyTorch/ten­sor_narrow_operation3.py
43 tensor_narrow_operation3_B.py operace nad celým tenzorem typu narrow, třetí ukázka přepsaná do volání metody https://github.com/tisnik/most-popular-python-libs/blob/master/PyTorch/ten­sor_narrow_operation3_B.py
44 tensor_narrow_operation4.py přepis původní matice přes pohled na ni (view) https://github.com/tisnik/most-popular-python-libs/blob/master/PyTorch/ten­sor_narrow_operation4.py
45 tensor_narrow_operation5.py přepis původní matice přes pohled na ni (view)narrow, třetí ukázka https://github.com/tisnik/most-popular-python-libs/blob/master/PyTorch/ten­sor_narrow_operation5.py
       
46 tensor_operator_add.py součet dvou tenzorů prvek po prvku https://github.com/tisnik/most-popular-python-libs/blob/master/PyTorch/ten­sor_operator_add.py
47 tensor_operator_sub.py rozdíl dvou tenzorů prvek po prvku https://github.com/tisnik/most-popular-python-libs/blob/master/PyTorch/ten­sor_operator_sub.py
48 tensor_operator_mul.py součin dvou tenzorů prvek po prvku https://github.com/tisnik/most-popular-python-libs/blob/master/PyTorch/ten­sor_operator_mul.py
49 tensor_operator_div.py podíl dvou tenzorů prvek po prvku https://github.com/tisnik/most-popular-python-libs/blob/master/PyTorch/ten­sor_operator_div.py
50 tensor_dot_product.py skalární součin dvou tenzorů prvního řádu https://github.com/tisnik/most-popular-python-libs/blob/master/PyTorch/ten­sor_dot_product.py
50 tensor_operator_matmul.py maticové násobení (dvou tenzorů druhého řádu) https://github.com/tisnik/most-popular-python-libs/blob/master/PyTorch/ten­sor_operator_matmul.py
51 tensor_operator_matmul2.py maticové násobení (dvou tenzorů druhého řádu) https://github.com/tisnik/most-popular-python-libs/blob/master/PyTorch/ten­sor_operator_matmul2.py
52 tensor_operator_matmul3.py maticové násobení v případě nekompatibilních tvarů matic https://github.com/tisnik/most-popular-python-libs/blob/master/PyTorch/ten­sor_operator_matmul3.py
53 tensor_operator_matmul4.py maticové násobení s broadcastingem https://github.com/tisnik/most-popular-python-libs/blob/master/PyTorch/ten­sor_operator_matmul4.py
54 tensor_operator_matmul5.py násobení vektoru a matice https://github.com/tisnik/most-popular-python-libs/blob/master/PyTorch/ten­sor_operator_matmul5.py
       
55 tensor_broadcast1.py operace broadcast (součin každého prvku tenzoru se skalárem) https://github.com/tisnik/most-popular-python-libs/blob/master/PyTorch/ten­sor_broadcast1.py
56 tensor_broadcast2.py operace broadcast (součin tenzoru druhého řádu s vektorem) https://github.com/tisnik/most-popular-python-libs/blob/master/PyTorch/ten­sor_broadcast2.py
57 tensor_broadcast3.py operace broadcast (součin vektoru s tenzorem druhého řádu) https://github.com/tisnik/most-popular-python-libs/blob/master/PyTorch/ten­sor_broadcast3.py
58 tensor_broadcast4.py operace broadcast (součet tenzorů druhého a třetího řádu) https://github.com/tisnik/most-popular-python-libs/blob/master/PyTorch/ten­sor_broadcast4.py
       
59 tensor_sparse.py konstrukce řídkého tenzoru https://github.com/tisnik/most-popular-python-libs/blob/master/PyTorch/ten­sor_sparse.py

20. Odkazy na Internetu

  1. Seriál Programovací jazyk Lua na Rootu:
    https://www.root.cz/seria­ly/programovaci-jazyk-lua/
  2. PDM: moderní správce balíčků a virtuálních prostředí Pythonu:
    https://www.root.cz/clanky/pdm-moderni-spravce-balicku-a-virtualnich-prostredi-pythonu/
  3. 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/
  4. 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/
  5. 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/
  6. Stránky projektu PyTorch:
    https://pytorch.org/
  7. Informace o instalaci PyTorche:
    https://pytorch.org/get-started/locally/
  8. Tenzor (Wikipedia):
    https://cs.wikipedia.org/wiki/Tenzor
  9. Introduction to Tensors:
    https://www.youtube.com/wat­ch?v=uaQeXi4E7gA
  10. Introduction to Tensors: Transformation Rules:
    https://www.youtube.com/wat­ch?v=j6DazQDbEhQ
  11. Tensor Attributes:
    https://pytorch.org/docs/sta­ble/tensor_attributes.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/qu­estions/44371560/what-is-the-relationship-between-pytorch-and-torch
  14. What is a tensor anyway?? (from a mathematician):
    https://www.youtube.com/wat­ch?v=K7f2pCQ3p3U
  15. Visualization of tensors – part 1 :
    https://www.youtube.com/wat­ch?v=YxXyN2ifK8A
  16. Visualization of tensors – part 2A:
    https://www.youtube.com/wat­ch?v=A95jdIuUUW0
  17. Visualization of tensors – part 2B:
    https://www.youtube.com/wat­ch?v=A95jdIuUUW0
  18. What the HECK is a Tensor?!?:
    https://www.youtube.com/wat­ch?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.youtube.com/wat­ch?v=L35fFDpwIM4
  28. Tensor Processing Unit:
    https://en.wikipedia.org/wi­ki/Tensor_Processing_Unit
  29. Třída Storage:
    http://docs.pytorch.wiki/en/sto­rage.html
  30. Funkce torch.dot
    https://pytorch.org/docs/sta­ble/generated/torch.dot.html#tor­ch.dot
  31. Funkce torch.narrow
    https://pytorch.org/docs/sta­ble/generated/torch.narrow­.html
  32. Funkce torch.matmul
    https://pytorch.org/docs/sta­ble/generated/torch.matmul­.html
  33. Funkce torch.reshape
    https://pytorch.org/docs/sta­ble/generated/torch.resha­pe.html
  34. Funkce torch.arange
    https://pytorch.org/docs/sta­ble/generated/torch.arange­.html
  35. Funkce torch.range
    https://pytorch.org/docs/sta­ble/generated/torch.range­.html
  36. Třída torch.Tensor
    https://pytorch.org/docs/sta­ble/tensors.html
  37. Atributy tenzorů
    https://pytorch.org/docs/sta­ble/tensor_attributes.html
  38. Pohledy vytvořené nad tenzory
    https://pytorch.org/docs/sta­ble/tensor_view.html
  39. Broadcasting v knihovně NumPy
    https://numpy.org/doc/sta­ble/user/basics.broadcastin­g.html
  40. Broadcasting semantics (v knihovně PyTorch)
    https://pytorch.org/docs/sta­ble/notes/broadcasting.html
  41. 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/

Autor článku

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