Hlavní navigace

Torch: framework pro strojové učení i pro zpracování vektorů a tenzorů

Pavel Tišnovský

Dnes se seznámíme s vlastnostmi frameworku Torch, který je používaný v oboru strojového učení, ale i pro „obyčejné“ zpracování vektorů a tenzorů. Pro psaní skriptů se používá Lua, interně je ovšem postavený na C.

Obsah

1. Torch: framework pro strojové učení i pro zpracování vektorů a tenzorů

2. Instalace frameworku Torch

3. První spuštění interaktivního prostředí

4. Základní datová struktura, s níž se ve frameworku Torch pracuje

5. Základní konstruktory tenzorů

6. Použití konstruktoru zeros

7. Použití konstruktoru ones

8. Použití konstruktoru range

9. Způsob uložení tenzorů v paměti počítače

10. Manipulace s objektem typu Storage

11. Operace sub aplikovaná na vektory

12. Operace sub aplikovaná na matice a tenzory vyšších řádů

13. Operace narrow aplikovaná na vektory

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

15. Operace sub a narrow ve funkci zapisovatelných pohledů

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

17. Odkazy na Internetu

1. Torch: framework pro strojové učení i pro zpracování vektorů 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í 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 SSE, původně též MMX či 3DNow!, viz též článek na toto téma), tak i programovatelné grafické akcelerátory (GPU, v současnosti je lídrem v tomto oboru NVidia s GPU Tesla).

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 Torch je primárně určen pro zpracování vektorů, matic i tenzorů (tj. zobecnění vektorů), a to s využitím programovacího jazyka Lua namísto specializovaného jazyka (Julia, Matlab, R). Interně se prakticky všechny výpočty provádí v nativních céčkových knihovnách a popř. se využívá i CUDA, tj. možnosti grafických akcelerátorů. Možnosti frameworku 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.

2. Instalace frameworku Torch

Před čtením dalšího textu je vhodné si framework Torch nainstalovat. Není to nic složitého, protože postačuje dodržet instrukce, které naleznete na stránce http://torch.ch/docs/getting-started.html. Postačovat by mělo pouze těchto několik příkazů, které spustíte pod svým účtem (otestováno na Fedoře 26 a Linux Mintu, tedy na distribucích založených na odlišném systému balíčků):

git clone https://github.com/torch/distro.git ~/torch --recursive
cd ~/torch
bash install-deps
./install.sh
source ~/.bashrc

Ve skutečnosti může nastat několik problémů:

  1. Nezapomeňte na volbu –recursive u prvního příkazu. Torch totiž používá submoduly.
  2. Uživatel musí získat práva superuživatele pro instalaci doplňkových balíčků (kterých je poměrně velké množství).
  3. Skript install-deps nepočítá s některými novějšími verzemi distribucí. Snadnou úpravou je ale možné docílit instalace na Fedoru 26 (změnou jedné podmínky) či novějším Linux Mintu.

3. První spuštění interaktivního prostředí

Po (doufejme) úspěšné instalaci si můžete vyzkoušet spustit interaktivní prostředí Torche. Je to snadné – postačuje spustit th (tento spustitelný soubor by se již měl nacházet na PATH):

$ th
  ______             __   |  Torch7
 /_  __/__  ________/ /   |  Scientific computing for Lua.
  / / / _ \/ __/ __/ _ \  |  Type ? for help
 /_/  \___/_/  \__/_//_/  |  https://github.com/torch
                          |  http://torch.ch

Alternativně lze přímo spustit skript uložený v externím souboru. Po dokončení skriptu se prostředí Torche ukončí:

$ th constructors.lua

Pokud budete chtít spustit nějaký skript a poté zůstat v interaktivním prostředí Torche, použijte tento příkaz:

$ th -i constructors.lua

Uživatelé textového editoru Vim mohou skripty postupně vytvářet ve svém oblíbeném vimovském prostředí a posléze je spouštět například klávesovou zkratkou F5 s využitím následujícího mapování:

:map <F5> :!th %<cr>

4. Základní datová struktura, s níž se ve frameworku Torch pracuje

Ve frameworku Torch 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). Samotné interní pole objektů typu Tensor je vždy homogenní, tj. 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
ByteTensor tenzor s prvky typu unsigned char
CharTensor tenzor s prvky typu char
ShortTensor tenzor s prvky typu short (16bitové celé číslo)
IntTensor tenzor s prvky typu int (32bitové celé číslo)
LongTensor tenzor s prvky typu long (64bitové celé číslo)
FloatTensor tenzor s prvky typu float (32bitová FP hodnota)
DoubleTensor tenzor s prvky typu double (64bitová FP hodnota)

5. Základní konstruktory tenzorů

Již v úvodních kapitolách jsme si řekli, že základní datovou strukturou frameworku Torch 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:

th> s1=torch.Tensor(1)
                                                                      [0.0002s]
th> s1[1]=42
                                                                      [0.0001s]

Výsledek (povšimněte si typu – nejedná se o běžné číslo):

th> s1
 42
[torch.DoubleTensor of size 1]

Vytvoření vektoru, neboli tenzoru prvního řádu. V tomto konkrétním případě se jedná o tříprvkový vektor:

th> v1 = torch.Tensor(3)
                                                                      [0.0001s]

Inicializace komponent:

th> v1[1]=10
                                                                      [0.0001s]
th> v1[2]=20
                                                                      [0.0001s]
th> v1[3]=40
                                                                      [0.0001s]

Výsledek:

th> v1
 10
 20
 40
[torch.DoubleTensor of size 3]
                                                                      [0.0001s]

Alternativně lze vektor (tenzor prvního řádu) vytvořit a současně inicializovat jeho komponenty. Použije se přitom běžné pole tak, jak ho známe z programovacího jazyka Lua:

th> v2=torch.Tensor({10,20,30})
                                                                      [0.0001s]
th> v2
 10
 20
 30
[torch.DoubleTensor of size 3]

Vytvoření tenzoru druhého řádu:

th> m1 = torch.Tensor(3,3)

Vytvoření a inicializace tenzoru druhého řádu, který může být reprezentován maticí:

th> m2=torch.Tensor({{1,2,3}, {4,5,6}, {7,8,9}})
                                                                      [0.0002s]

Výsledek:

th> m2
 1  2  3
 4  5  6
 7  8  9
[torch.DoubleTensor of size 3x3]

A konečně tenzor třetího řádu reprezentovaný „3D maticí“:

th> q = torch.Tensor({{{1,2,3}, {4,5,6}, {7,8,9}},
                      {{9,8,7}, {6,5,4}, {3,2,1}}})

Výsledek se na 2D obrazovce zobrazí takto:

(1,.,.) =
  1  2  3
  4  5  6
  7  8  9
 
(2,.,.) =
  9  8  7
  6  5  4
  3  2  1
[torch.DoubleTensor of size 2x3x3]

6. Použití konstruktoru zeros

V knihovně Torch existují i další konstruktory. V mnoha případech potřebujeme vytvořit vektor, matici atd. vyplněný nulami. V tomto případě můžeme použít metodu (nikoli konstruktor) zero(), která se ovšem aplikuje na již vytvořený objekt:

th> x1 = torch.Tensor(10):zero()
                                                                      [0.0002s]
th> x1
 0
 0
 0
 0
 0
 0
 0
 0
 0
 0
[torch.DoubleTensor of size 10]
                                                                      [0.0002s]

Podobný postup lze použít i u 2D matice:

th> x2 = torch.Tensor(4,4):zero()
                                                                      [0.0001s]
th> x2
 0  0  0  0
 0  0  0  0
 0  0  0  0
 0  0  0  0
[torch.DoubleTensor of size 4x4]

Výhodnější a rychlejší je však 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:

Tenzor nultého řádu (skalár):

th> z0 = torch.zeros(1)
                                                                      [0.0003s]
th> print(z0)
 0
[torch.DoubleTensor of size 1]
                                                                      [0.0003s]

Tenzor prvního řádu (vektor):

th> z1 = torch.zeros(10)
                                                                      [0.0001s]
th> print(z1)
 0
 0
 0
 0
 0
 0
 0
 0
 0
 0
[torch.DoubleTensor of size 10]
                                                                      [0.0002s]

Tenzor druhého řádu:

th> z2 = torch.zeros(3,4)
                                                                      [0.0000s]
th> print(z2)
 0  0  0  0
 0  0  0  0
 0  0  0  0
[torch.DoubleTensor of size 3x4]

Tenzor třetího řádu:

th> z3 = torch.zeros(2,3,4)
                                                                      [0.0001s]
th> z3
(1,.,.) =
  0  0  0  0
  0  0  0  0
  0  0  0  0
 
(2,.,.) =
  0  0  0  0
  0  0  0  0
  0  0  0  0
[torch.DoubleTensor of size 2x3x4]

7. Použití konstruktoru ones

Způsob reprezentace tenzorů druhého řádu sice připomíná matice, ovšem zde se nesmíme nechat zmýlit – další konstruktor 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:

Skalár s hodnotou 1:

th> o0 = torch.ones(1)
                                                                      [0.0003s]
th> print(o0)
 1
[torch.DoubleTensor of size 1]
                                                                      [0.0003s]

Tenzor prvního řádu (zde vektor o deseti prvcích):

th> o1 = torch.ones(10)
                                                                      [0.0001s]
th> print(o1)
 1
 1
 1
 1
 1
 1
 1
 1
 1
 1
[torch.DoubleTensor of size 10]

Tenzor druhého řádu:

th> o2 = torch.ones(3,4)
                                                                      [0.0001s]
th> print(o2)
 1  1  1  1
 1  1  1  1
 1  1  1  1
[torch.DoubleTensor of size 3x4]
                                                                      [0.0003s]

Tenzor třetího řádu:

th> o3 = torch.ones(2,3,4)
                                                                      [0.0001s]
th> print(o3)
(1,.,.) =
  1  1  1  1
  1  1  1  1
  1  1  1  1
 
(2,.,.) =
  1  1  1  1
  1  1  1  1
  1  1  1  1
[torch.DoubleTensor of size 2x3x4]

8. 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 Torch 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ů:

Použití implicitního kroku jedna (hodnota prvního a posledního prvku je reprezentována celými čísly, není to však nutnost):

th> r1 = torch.range(1, 10)
                                                                      [0.0002s]
th> print(r1)
  1
  2
  3
  4
  5
  6
  7
  8
  9
 10
[torch.DoubleTensor of size 10]
                                                                      [0.0003s]

Explicitní specifikace kroku (opět pro jednoduchost používáme celá čísla):

th> r2 = torch.range(1, 10, 2)
                                                                      [0.0001s]
th> print(r2)
 1
 3
 5
 7
 9
[torch.DoubleTensor of size 5]
                                                                      [0.0001s]

Můžeme zadat i záporný krok:

th> r3 = torch.range(10, 0, -2)
                                                                      [0.0001s]
th> print(r3)
 10
  8
  6
  4
  2
  0
[torch.DoubleTensor of size 6]
                                                                      [0.0001s]

Knihovna Torch samozřejmě hlídá, aby nebyl použit krok s hodnotou nula. Toto chování si můžeme snadno ověřit:

th> r4 = torch.range(10, 0, 0)
bad argument #3 to '?' (step must be a non-null number at /home/tester/torch/pkg/torch/lib/TH/generic/THTensorMath.c:2003)
stack traceback:
        [C]: at 0x7f3ff7194840
        [C]: in function 'range'
        [string "r4 = torch.range(10, 0, 0)"]:1: in main chunk
        [C]: in function 'xpcall'
        /home/tester/torch/install/share/lua/5.1/trepl/init.lua:679: in function 'repl'
        ...novs/torch/install/lib/luarocks/rocks/trepl/scm-1/bin/th:204: in main chunk
        [C]: at 0x00405780

9. Způsob uložení tenzorů v paměti počítače

Ve čtvrté kapitole jsme si řekli, že objekty typu Tensor pro uložení svých komponent (prvků) interně používají jednorozměrná pole. To, že se tenzory uživateli jeví jako 1D, 2D, 3D atd. struktury je záležitostí pohledů (views) na zmíněná jednorozměrná pole (jedná se vlastně o běžná céčková pole). Pro některé nízkoúrovňové operace může být výhodné přistupovat přímo k internímu poli, což nám knihovna Torch umožňuje, protože nabízí objekty typu Storage. Existuje několik konkrétních typů Storage, protože interní (céčková) pole taktéž mohou obsahovat prvky různých typů. Implicitně se používá DoubleStorage:

Typ Storage Význam
ByteStorage pole s prvky typu unsigned char
CharStorage pole s prvky typu char
ShortStorage pole s prvky typu short (16bitové celé číslo)
IntStorage pole s prvky typu int (32bitové celé číslo)
LongStorage pole s prvky typu long (64bitové celé číslo)
FloatStorage pole s prvky typu float (32bitová FP hodnota)
DoubleStorage pole s prvky typu double (64bitová FP hodnota)

10. Manipulace s objektem typu Storage

Ukažme si nyní, jak je možné pro existující tenzor získat objekt typu Storage a jak se dá tento objekt využít pro změnu hodnot komponent tenzoru. Nejprve vytvoříme běžný vektor s deseti prvky:

th> vector=torch.Tensor(10)
                                                                      [0.0001s]

Následně pro tento vektor získáme objekt typu Storage. Povšimněte si, že se při volání metody objektu používá dvojtečka a nikoli tečka! Jedná se o vlastnost programovacího jazyka Lua, díky níž nemusíme explicitně specifikovat parametr this:

th> storage=vector:storage()
                                                                      [0.0001s]

Objekt typu Storage se chová podobně jako běžné pole jazyka Lua. Musíme si jen dát pozor na to, že se prvky indexují od jedničky a nikoli od nuly (ovšem to je v matematice běžné). V následující smyčce do interního pole prvků typu double vložíme hodnoty 1/1, 1/2, 1/3 až 1/10:

th> for i=1,storage:size() do
..>     storage[i] = 1.0/i
..> end

Pro jistotu se můžeme na prvky v poli podívat. Povšimněte si zejména typu vypsaného na předposledním řádku):

th> storage
 1.0000
 0.5000
 0.3333
 0.2500
 0.2000
 0.1667
 0.1429
 0.1250
 0.1111
 0.1000
[torch.DoubleStorage of size 10]
                                                                      [0.0002s]

Přes objekt typu Storage se ovšem změnil i vlastní vektor (tedy „pohled“ na Storage), o čemž se opět můžeme snadno přesvědčit:

th> vector
 1.0000
 0.5000
 0.3333
 0.2500
 0.2000
 0.1667
 0.1429
 0.1250
 0.1111
 0.1000
[torch.DoubleTensor of size 10]
                                                                      [0.0002s]

Podobně můžeme postupovat při naplnění složitější struktury s 2×3×4 prvky:

th> t=torch.Tensor(2,3,4)
                                                                      [0.0001s]
th> s=t:storage()
                                                                      [0.0001s]
th> s:size()
24

Vidíme, že se interně vytvořilo jednorozměrné pole s 24 prvky, které můžeme naplnit:

th> for i=1,s:size() do
..>     s[i] = i
..> end

Současně se změnil i samotný tenzor:

th> t
(1,.,.) =
   1   2   3   4
   5   6   7   8
   9  10  11  12
 
(2,.,.) =
  13  14  15  16
  17  18  19  20
  21  22  23  24
[torch.DoubleTensor of size 2x3x4]

11. Operace sub aplikovaná na vektory

Další zajímavou operací, která produkuje pohled (view) nad tenzorem, je operace nazvaná sub. Nejprve se podíváme na nejjednodušší použití této operace při práci s vektory. Vytvoříme si vektor s deseti prvky od 1/1 do 1/10:

th> vector=torch.Tensor(10)
th> storage=vector:storage()
th> for i=1,storage:size() do
..>     storage[i] = 1.0/i
..> end

Vektor skutečně obsahuje deset prvků:

th> vector
 1.0000
 0.5000
 0.3333
 0.2500
 0.2000
 0.1667
 0.1429
 0.1250
 0.1111
 0.1000
[torch.DoubleTensor of size 10]

Pomocí operace sub můžeme získat pohled na prvky ležícími mezi specifikovaným dolním a horním indexem. Druhý až osmý prvek se tedy přečte takto:

th> vector:sub(2,9)
 0.5000
 0.3333
 0.2500
 0.2000
 0.1667
 0.1429
 0.1250
 0.1111
[torch.DoubleTensor of size 8]

Povšimněte si, že výsledkem operace sub je opět plnohodnotný tenzor.

Při zadávání indexů prvků je možné použít i záporné hodnoty. Jak je zvykem, jsou tyto hodnoty chápány jako indexy od konce vektoru. Další příklad nám tedy dá stejný výsledek, jako příklad předchozí (druhý prvek od začátku až druhý prvek od konce; povšimněte si, proč je konzistentní pracovat s indexy začínajícími od 1 a nikoli od 0):

th> vector:sub(2,-2)
 0.5000
 0.3333
 0.2500
 0.2000
 0.1667
 0.1429
 0.1250
 0.1111
[torch.DoubleTensor of size 8]

Můžeme samozřejmě vybrat i jediný prvek:

th> vector:sub(10,10)
 0.1000
[torch.DoubleTensor of size 1]

Totožný výsledek s použitím záporných indexů:

th> vector:sub(-1,-1)
 0.1000
[torch.DoubleTensor of size 1]

12. Operace sub aplikovaná na matice a tenzory vyšších řádů

Operaci sub je samozřejmě možné aplikovat i na matice a tenzory vyšších řádů; výsledkem je vždy opět tenzor. Nejprve si pro ukázku vytvoříme 2D matici a naplníme ji prvky s hodnotami 1 až 20:

th> x=torch.Tensor(4,5)
                                                                      [0.0001s]
th> s=x:storage()
                                                                      [0.0001s]
th> for i=1,s:size() do
..>     s[i] = i
..> end

Matice se skutečně vytvořila:

th> x
  1   2   3   4   5
  6   7   8   9  10
 11  12  13  14  15
 16  17  18  19  20
[torch.DoubleTensor of size 4x5]

Voláním x:sub(1,4) získáme pohled obsahující řádky 1 až 4 (včetně), tedy celou původní matici:

th> x:sub(1,4)
  1   2   3   4   5
  6   7   8   9  10
 11  12  13  14  15
 16  17  18  19  20
[torch.DoubleTensor of size 4x5]

Pohled můžeme snadno omezit na první tři řádky:

th> x:sub(1,3)
  1   2   3   4   5
  6   7   8   9  10
 11  12  13  14  15
[torch.DoubleTensor of size 3x5]

Popř. na řádek druhý a třetí:

th> x:sub(2,3)
  6   7   8   9  10
 11  12  13  14  15
[torch.DoubleTensor of size 2x5]

I u operace sub je možné používat záporné indexy. Následující příkaz vrátí předposlední a poslední řádek původní matice:

th> x:sub(-2,-1)
 11  12  13  14  15
 16  17  18  19  20

To ovšem není zdaleka vše, protože je možné specifikovat indexy i ve druhé dimenzi. Následující příkaz tedy získá submatici 2×2 prvky:

th> x:sub(2,3,2,3)
  7   8
 12  13
[torch.DoubleTensor of size 2x2]

Další příkaz vrátí submatici 2×2 prvků, která leží v pravém dolním rohu původní matice:

th> x:sub(-2,-1,-2,-1)
 14  15
 19  20

13. Operace narrow aplikovaná na vektory

S operací sub do značné míry souvisí i operace narrow, která taktéž získá pohled na zvolený tenzor. Této operaci se předávají tři parametry: dimenze (resp. její index), první prvek v dané dimenzi a počet prvků. Podívejme se opět na ten nejjednodušší případ, tedy na získání pohledu do jednorozměrného vektoru. Ten má jen jednu dimenzi (=1) a budeme chtít získat čtyři prvky začínající druhým prvkem:

th> vector:narrow(1,2,4)
 0.5000
 0.3333
 0.2500
 0.2000
[torch.DoubleTensor of size 4]

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

Mnohem užitečnější je použití operace narrow na matice a tenzory vyšších řádů. Vraťme se k naší matici 4×5 prvků:

th> x
  1   2   3   4   5
  6   7   8   9  10
 11  12  13  14  15
 16  17  18  19  20
[torch.DoubleTensor of size 4x5]
                                                                      [0.0003s]

Další příkaz získá první dva řádky matice (pohybujeme se tedy po řádcích, neboť jsme zvolili první dimenzi):

th> x:narrow(1,1,2)
  1   2   3   4   5
  6   7   8   9  10
[torch.DoubleTensor of size 2x5]
                                                                      [0.0004s]

Můžeme ovšem získat i první dva sloupce, tj. pohybovat se po dimenzi druhé:

th> x:narrow(2,1,2)
  1   2
  6   7
 11  12
 16  17
[torch.DoubleTensor of size 4x2]

15. Operace sub a narrow ve funkci zapisovatelných pohledů

Vzhledem k tomu, že pohled na tenzory může být použit i pro zápis, můžeme s operacemi sub a narrow provádět i poměrně složité operace, a to opět bez nutnosti explicitně zapisovat programové smyčky při přístupu k prvkům tenzoru.

Zkusme si například vytvořit matici 5×5 prvků, která bude ve svém středu obsahovat submatici 3×3 prvky naplněné jedničkami (zbylé prvky budou nulové). Pro výplň tenzoru (či pohledu na něj) nějakou hodnotou se používá metoda fill(hodnota):

th> x=torch.zeros(5,5)
                                                                      [0.0002s]
th> x
 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
[torch.DoubleTensor of size 5x5]

Matici máme vytvořenou, takže získáme submatici 3×3 prvky a vyplníme ji jedničkami (povšimněte si, že se tato submatice vrátí jako výsledek, ten ovšem zahodíme):

th> x:sub(2,4,2,4):fill(1)
 1  1  1
 1  1  1
 1  1  1
[torch.DoubleTensor of size 3x3]
                                                                      [0.0003s]

Současně se změnila i původní matice:

th> x
 0  0  0  0  0
 0  1  1  1  0
 0  1  1  1  0
 0  1  1  1  0
 0  0  0  0  0
[torch.DoubleTensor of size 5x5]

Nyní si zkusme naplnění prostředního řádku nové nulové matice devítkami:

th> x=torch.zeros(5,5)
                                                                      [0.0001s]
th> x
 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
[torch.DoubleTensor of size 5x5]
                                                                      [0.0003s]

Volání narrow(1,3,1) nám vrátí celý třetí řádek matice:

th> x:narrow(1,3,1):fill(9)
 9  9  9  9  9
[torch.DoubleTensor of size 1x5]

                                                                      [0.0002s]
th> x
 0  0  0  0  0
 0  0  0  0  0
 9  9  9  9  9
 0  0  0  0  0
 0  0  0  0  0
[torch.DoubleTensor of size 5x5]

Doplnění trojek do posledního sloupce (dimenze=2):

th> x:narrow(2,5,1):fill(3)
 3
 3
 3
 3
 3
[torch.DoubleTensor of size 5x1]

                                                                      [0.0004s]
th> x
 0  0  0  0  3
 0  0  0  0  3
 9  9  9  9  3
 0  0  0  0  3
 0  0  0  0  3
[torch.DoubleTensor of size 5x5]

Pohledy je možné získávat i pro již existující pohledy, takže:

th> x=torch.zeros(7,7)
                                                                      [0.0001s]
th> x:narrow(1,3,4):narrow(2,2,2):fill(1)
 1  1
 1  1
 1  1
 1  1
[torch.DoubleTensor of size 4x2]
                                                                      [0.0001s]

th> x
 0  0  0  0  0  0  0
 0  0  0  0  0  0  0
 0  1  1  0  0  0  0
 0  1  1  0  0  0  0
 0  1  1  0  0  0  0
 0  1  1  0  0  0  0
 0  0  0  0  0  0  0
[torch.DoubleTensor of size 7x7]
                                                                      [0.0002s]

Další komplikovanější operace s tenzory, například získání řezu, změny tvaru atd., si popíšeme příště.

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

Všechny demonstrační příklady, které jsme si popsali v předchozích kapitolách, najdete v GIT repositáři dostupném na adrese https://github.com/tisnik/torch-examples.git. Následují odkazy na zdrojové kódy jednotlivých příkladů:

17. Odkazy na Internetu

  1. Stránka projektu Torch
    http://torch.ch/
  2. Torch na GitHubu (několik repositářů)
    https://github.com/torch
  3. Torch (machine learning), Wikipedia
    https://en.wikipedia.org/wi­ki/Torch_%28machine_learnin­g%29
  4. Torch Package Reference Manual
    https://github.com/torch/tor­ch7/blob/master/README.md
  5. Torch Cheatsheet
    https://github.com/torch/tor­ch7/wiki/Cheatsheet
  6. An Introduction to Tensors
    https://math.stackexchange­.com/questions/10282/an-introduction-to-tensors
  7. Differences between a matrix and a tensor
    https://math.stackexchange­.com/questions/412423/dif­ferences-between-a-matrix-and-a-tensor
  8. 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?
  9. BLAS (Basic Linear Algebra Subprograms)
    http://www.netlib.org/blas/
  10. Basic Linear Algebra Subprograms (Wikipedia)
    https://en.wikipedia.org/wi­ki/Basic_Linear_Algebra_Sub­programs
  11. Comparison of deep learning software
    https://en.wikipedia.org/wi­ki/Comparison_of_deep_lear­ning_software
  12. TensorFlow
    https://www.tensorflow.org/
  13. Caffe2 (A New Lightweight, Modular, and Scalable Deep Learning Framework)
    https://caffe2.ai/
  14. PyTorch
    http://pytorch.org/
  15. Seriál o programovacím jazyku Lua
    http://www.root.cz/serialy/pro­gramovaci-jazyk-lua/
  16. LuaJIT – Just in Time překladač pro programovací jazyk Lua
    http://www.root.cz/clanky/luajit-just-in-time-prekladac-pro-programovaci-jazyk-lua/
  17. LuaJIT – Just in Time překladač pro programovací jazyk Lua (2)
    http://www.root.cz/clanky/luajit-just-in-time-prekladac-pro-programovaci-jazyk-lua-2/
  18. LuaJIT – Just in Time překladač pro programovací jazyk Lua (3)
    http://www.root.cz/clanky/luajit-just-in-time-prekladac-pro-programovaci-jazyk-lua-3/
  19. LuaJIT – Just in Time překladač pro programovací jazyk Lua (4)
    http://www.root.cz/clanky/luajit-just-in-time-prekladac-pro-programovaci-jazyk-lua-4/
  20. LuaJIT – Just in Time překladač pro programovací jazyk Lua (5 – tabulky a pole)
    http://www.root.cz/clanky/luajit-just-in-time-prekladac-pro-programovaci-jazyk-lua-5-tabulky-a-pole/
  21. LuaJIT – Just in Time překladač pro programovací jazyk Lua (6 – překlad programových smyček do mezijazyka LuaJITu)
    http://www.root.cz/clanky/luajit-just-in-time-prekladac-pro-programovaci-jazyk-lua-6-preklad-programovych-smycek-do-mezijazyka-luajitu/
  22. LuaJIT – Just in Time překladač pro programovací jazyk Lua (7 – dokončení popisu mezijazyka LuaJITu)
    http://www.root.cz/clanky/luajit-just-in-time-prekladac-pro-programovaci-jazyk-lua-7-dokonceni-popisu-mezijazyka-luajitu/
  23. LuaJIT – Just in Time překladač pro programovací jazyk Lua (8 – základní vlastnosti trasovacího JITu)
    http://www.root.cz/clanky/luajit-just-in-time-prekladac-pro-programovaci-jazyk-lua-8-zakladni-vlastnosti-trasovaciho-jitu/
  24. LuaJIT – Just in Time překladač pro programovací jazyk Lua (9 – další vlastnosti trasovacího JITu)
    http://www.root.cz/clanky/luajit-just-in-time-prekladac-pro-programovaci-jazyk-lua-9-dalsi-vlastnosti-trasovaciho-jitu/
  25. LuaJIT – Just in Time překladač pro programovací jazyk Lua (10 – JIT překlad do nativního kódu)
    http://www.root.cz/clanky/luajit-just-in-time-prekladac-pro-programovaci-jazyk-lua-10-jit-preklad-do-nativniho-kodu/
  26. LuaJIT – Just in Time překladač pro programovací jazyk Lua (11 – JIT překlad do nativního kódu procesorů s architekturami x86 a ARM)
    http://www.root.cz/clanky/luajit-just-in-time-prekladac-pro-programovaci-jazyk-lua-11-jit-preklad-do-nativniho-kodu-procesoru-s-architekturami-x86-a-arm/
  27. LuaJIT – Just in Time překladač pro programovací jazyk Lua (12 – překlad operací s reálnými čísly)
    http://www.root.cz/clanky/luajit-just-in-time-prekladac-pro-programovaci-jazyk-lua-12-preklad-operaci-s-realnymi-cisly/
  28. Lua Profiler (GitHub)
    https://github.com/luafor­ge/luaprofiler
  29. Lua Profiler (LuaForge)
    http://luaforge.net/projec­ts/luaprofiler/
  30. ctrace
    http://webserver2.tecgraf.puc-rio.br/~lhf/ftp/lua/
  31. The Lua VM, on the Web
    https://kripken.github.io/lu­a.vm.js/lua.vm.js.html
  32. Lua.vm.js REPL
    https://kripken.github.io/lu­a.vm.js/repl.html
  33. lua2js
    https://www.npmjs.com/package/lua2js
  34. lua2js na GitHubu
    https://github.com/basicer/lua2js-dist
  35. Lua (programming language)
    http://en.wikipedia.org/wi­ki/Lua_(programming_langu­age)
  36. LuaJIT 2.0 SSA IRhttp://wiki.luajit.org/SSA-IR-2.0
  37. The LuaJIT Project
    http://luajit.org/index.html
  38. LuaJIT FAQ
    http://luajit.org/faq.html
  39. LuaJIT Performance Comparison
    http://luajit.org/performance.html
  40. LuaJIT 2.0 intellectual property disclosure and research opportunities
    http://article.gmane.org/gma­ne.comp.lang.lua.general/58908
  41. LuaJIT Wiki
    http://wiki.luajit.org/Home
  42. LuaJIT 2.0 Bytecode Instructions
    http://wiki.luajit.org/Bytecode-2.0
  43. Programming in Lua (first edition)
    http://www.lua.org/pil/contents.html
  44. Lua 5.2 sources
    http://www.lua.org/source/5.2/
  45. REPL
    https://en.wikipedia.org/wi­ki/Read%E2%80%93eval%E2%80%93prin­t_loop
  46. The LLVM Compiler Infrastructure
    http://llvm.org/ProjectsWithLLVM/
  47. clang: a C language family frontend for LLVM
    http://clang.llvm.org/
  48. LLVM Backend („Fastcomp“)
    http://kripken.github.io/emscripten-site/docs/building_from_source/LLVM-Backend.html#llvm-backend
  49. Lambda the Ultimate: Coroutines in Lua,
    http://lambda-the-ultimate.org/node/438
  50. Coroutines Tutorial,
    http://lua-users.org/wiki/CoroutinesTutorial
  51. Lua Coroutines Versus Python Generators,
    http://lua-users.org/wiki/LuaCorouti­nesVersusPythonGenerators
Našli jste v článku chybu?