# ML 5. Umělá inteligence ve zpracování obrazu Formování obrazu (PSF, OTF, vzorkování). Klasifikace obrazu (VGGNet, GoogLeNet, ResNet, SENet). Detekce objektů (R-CNN, Fast R-CNN, Faster R-CNN, YOLO). Segmentace obrazu (FCN, UNet, Mask R-CNN). Podmíněné a nepodmíněné generativní modely (autoregresivní modely, VAEs, GANs). Modely založené na konvolučních sítích a transformerech (attention, CNN vs. ViT) ## Formování obrazu Obraz = funkce ze souřadnic do intenzit * spojitý obraz: $ℝ^m → ℝ^c$ * diskrétní obraz: $ℤ^𝑚 → ℝ^c$ * digitální obraz: $ℤ^𝑚 → ℤ^c$ m je počet dimenzí, například 1 pro audio signál, 2 pro obrázek c je počet kanálů, např. 3 pro RGB, 1 pro grayscale Zobrazovací systém (mikroskop, kamera, rentgen, …) zachycuje scénu do digitálního obrazu Prvně se scéna zobrazí na “Image plane”, poté se vzorkováním a kvantizací převede na digitální obraz ### PSF - Point Spread Function (Rozptylová funkce) Rozptylová funkce popisuje, jak zobrazovací systém (kamera, …) zobrazí bodový zdroj světla na vstupu do obrazu na výstup (**impulse response**). Samotnou scénou se už nebudeme zabývat a zobrazovací systém budeme brát že bere na vstup obraz (tzn. funkci) a jiný obraz dává na výstup (jinou funkci). Rozptylová funkce může být obecně komplikovaná, ale velké množství zobrazovacích systémů lze dostatečně přesně modelovat jako **linear shift-invariant system (LSI)**, tzn: * rozptylová funkce nezávisí na poloze (shift invariant), tzn: $LSI(T(g)) = T(LSI(g))$ * rozptylová funkce je lineární, tzn: * kombinace dvou obrazů na vstupu a poté zobrazit je jako zobrazit každý zvlášť a pak je zkombinovat: \ $LSI(g1 + g2) = LSI(g1) + LSI(g2)$ * zesílení signálu na vstupu zesílí signál na výstupu \ $LSI(n * g) = n * LSI(g)$ $g, g1, g2$ jsou obrazy, $n$ je skalár a $T$ je translation operátor (posunutí) Pro LSI je rozptylová funkce jednodušší (protože odpadá hromada parametrů?) a celý zobrazovací systém lze vyjádřit jako **konvoluci** Klasický příklad rozptylové funkce (PSF) je gaussovský noise (rozostření): <table> <tr> <td> ![image36](https://hackmd.io/_uploads/BJVbUxoE0.png) kernel pro gaussovské rozostření </td> <td> ![image20](https://hackmd.io/_uploads/Sk6fUgoV0.png) příklad </td> </tr> </table> Ukázka ze slidů, kde zobrazovací systém každý bod na vstupu zobrazí na “šmouhu” ve tvaru PSF ![image37](https://hackmd.io/_uploads/HyJHUxoV0.png) ### Konvoluce, Vzájemná korelace (Cross-corelation) není přímo v otázce, ale bez toho zbytek nepůjde :D ![image35](https://hackmd.io/_uploads/ry0D8gjVC.png) Spojitá varianta je prakticky stejná, ale má tam integrály místo sum Konvoluce je operátor: * lineární * => zvýšení intenzity obrazu na vstupu přímo zvýší intenzitu na výstupu * => 2 obrazy můžeme sečíst a pak konvolutit, nebo prvně konvolutit a pak sečíst a dostaneme stejný výsledek * ekvivariantní k posunu (translation equivariance) * => pokud posuneme něco na vstupu tak se posune zobrazení té věci na výstupu Využití: * hledání vzorů * detekce hran, blobů, rohů, textur * rozmázání, low-pass filter (denoising) * CNN ### OTF - Optical Transfer Function = Fourierova transformace rozptylové funkce (point spread funkce) * charakterizuje frekvence, které se skrz zobrazovací systém přenesou * ve skutečných zobrazovacích systémech je konečná * nejvyšší přenesená frekvence se nazývá cut-off frekvence Convolution theorem: ![image18](https://hackmd.io/_uploads/HJ5Y8giNA.png) ### Vzorkování = diskretizace vstupního signálu (osa x pro 1D signál) fundamentální teorie: **Nyquistův–Shannonův vzorkovací teorém** * dává do spojitosti signály se spojitým časem a diskrétním časem * v audiu mluvíme o diskretizaci na časové ose, v obrazu jde o 2 prostorové souřadnice x, y * pro jednoduchost tu mluvíme o 1D signálu a časové ose Pokud je spojitá funkce f(x) složená pouze z frekvencí nižších než B, potom je bezeztrátově a jednoznačně určena funkčními hodnotami vzorkovanými pravidelně v kratším intervalu než 1/(2B). Pozorování: * vysoké frekvence v signálu jsou obvykle šum a nemají význam * senzory (příp. lidské ucho, atd.) mívají maximální frekvenci (cut-off frekvenci) a vyšší neumí rozlišit Důsledky a význam **Nyquistova-Shannonova vzorkovacího teorému**: * signál (audio, obraz,…) se spojitou časovou umíme “dokonale” zrekonstruovat pokud ho navzorkujeme dostatečně časo * “dokonale” = do libovolné přesnosti, tzn. libovolně vysoké frekvence \ zejména do cut-off frekcence zobrazovacího systému (např. lidského ucha) \ nebo do frekvence, od které se dá všechno v signálu považovat za šum Omezení: * Nyquistův–Shannonův vzorkovací teorém mluví o diskretizaci časové osy, ne o amplitudě * diskretizace amplitudy se nazývá kvantizace a podobný teorém nemá? ## Klasifikace obrazu * dnes obvykle pomocí strojového učení * hluboké neuronové sítě ### VGGNet Hlavní nápad: * několik po sobě jdoucích 3x3 konvolucí (a aktivačních fcí) má méně parametrů a více nelinearity než jedna velká konvoluce (např. 7x7) při stejném efektivním receptivním fieldu * => nahradíme všechny konvoluce více 3x3 konvolucema ![image23](https://hackmd.io/_uploads/Syka8xjVC.png) ### GoogLeNet Hlavní nápady: * Zpochybnění toho, že 3x3 konvoluce jsou optimální, nebo že kterákoli jiná konkrétní velikost je optimální * Můžeme nechat v neuronce víc velikostí naráz paralelně * => inception blok - obrázek níže * velké konvoluční filtry na hodně kanálech potřebují velké množství parametrů * můžeme redukovat počet vstupních kanálu pomocí 1x1 konvoluce * GoogLeNet 1x1 konvoluce zpopularizoval * Odstraníme finální FC vrstvy na konci, protože mají velkou dimenzi: * (WxHxC) x FC_dim, například 7x7x512 x 4096 = 100M parametrů * většina parametrů je tam, což intuitivně nedává moc smysl * nahradíme je za globální avg pooling který srazí (WxHxC) -> (1x1xC) * snaha o vyřešení vanishing gradientu * do třetiny a dvou třetin celé CNN přidáme pomocné vedlejší klasifikační hlavy * při tréningu počítáme loss na všech 3 klasifikačních hlavách * po tréningu pomocné hlavy odstřihneme ![image32](https://hackmd.io/_uploads/S1RcPgsNC.png) žluté bloky jsou bottlenecky, které snižují dimenzi a tím snižují počet parametrů které jsou potřeba ve vrstvě která na ně navazuje Celková architektura: ![image28](https://hackmd.io/_uploads/S1RUvls40.png) ### ResNet Hlavní myšlenky: * Hluboké sítě se nechtějí učit a jsou horší než mělké * kvůli vanishing gradientu * potřebujeme vyřešit * řešení: * Residuální bloky jsou all you need! ![image9](https://hackmd.io/_uploads/ryDTves4R.png) ResNet je potom jednoduchá architektura: * za sebou naskládané residuální bloky s 3x3 konvolucí, ReLU * buď se počet kanálů a velikost featur map nemění * nebo se zdvojnásobí počet kanálů a redukuje výška a šířka na polovinu * na konci global pooling a 1 FC vrstva pro klasifikaci * basically gigachad v roce 2016 ### SENet * snaží se potlačit nepodstatné feature mapy a vyzdvihnout ty důležité * kompatibilní s jinými architekturami * stači do architektury vložit squeeze-and-excitation blok (SE blok): ![image29](https://hackmd.io/_uploads/rJMADgsEA.png) - SENet dynamicky zesiluje/zeslabuje feature mapy ## Detekce Objektů ### R-CNN * historický a naivní přístup k detekci objektů * algoritmicky generujeme kandidáty (region proposals) na vstupním obrázku * CNN potom pro každý region proposal: * klasifikuje třídu - jaká třída nebo NIC * predikuje regresí t_x, t_y, t_h, t_w - korekce bounding boxu ![image30](https://hackmd.io/_uploads/Sysedei40.png) Problém R-CNN je ve výpočetní náročnosti - pro 2k region proposalů potřebujeme 2k forward průchodů CNN ### Fast R-CNN * zefektivnění R-CNN * Používáme stejný region proposal algoritmus * ale vyřezáváme regiony až na výstupu backbone CNN: ![image10](https://hackmd.io/_uploads/Skx7_xsER.png) Drobný problém: * feature mapy mají nižší rozlišení než originální obraz * takže proposal region je potřeba rozumně namapovat na feature mapy * řešení: * ROI Pool - snap to closest pixels in feature maps * ROI Align - bilineární interpolací zarovnat * skrz obě operace se dá backpropagovat <table> <tr> <td> ![image3](https://hackmd.io/_uploads/H14wOxoVA.png) ROI Pool </td> <td> ![image17](https://hackmd.io/_uploads/r1frdxiNR.png) ROI Align </td> </tr> </table> ### Faster R-CNN Motivace: * hand-coded region proposal metody: * nejsou kvalitní * jsou pomalý (běží na CPU) * chceme je naučit a mít součástí NN architektury Architektura: * na začátku je backbone steně jako Fast R-CNN * potom následuje region proposal network (RPN) * předdefinujeme si několik tvarů a velikostí (templaty) anchor boxů * RPN predikuje pro každý pixel pro všech K templaty anchor boxů * odpovídá tento pixel středu a tento anchor boxem ohraničení nějakého objektu? = pro každá píxel K binárních klasifikací * jak by se musel upravit anchor box template aby přesně ohraničil objekt? \ = pro každý pixel K regresí 4 floaty * pro HxWxC feature mapu a K anchor box template má výstup shape \ HxWx(K+4K) * top kandidáti se potom pošlou do per-region CNN která je stejná jako v Fast R-CNN ![image12](https://hackmd.io/_uploads/SJzaOls4R.png) ### YOLO (You Only Look Once) pozorování: * region propsal network a per-region network působí duplicitně (říká se tomu two-stage detector) řešení: * zjednoduššíme architekturu * spojíme region proposal network a per-region network (single stage detector) * proženeme vstup skrz backbone a pak * 1 CNN která pro každý pixel a K anchor box šablon predikuje: * odpovídá tento pixel středu a tento anchor boxem ohraničení nějakého objektu, a jakého? * jak se tento anchor box template musí upravit? * vstupní dimenze po backbone: * HxWxC * výstupní dimenze: * klasifikační hlava: H x W x K x (N+1) * regresní hlava: H x W x 4K x N ## Segmentace obrazu * rozdělení obrazů do regionů odpovídající (sémantickým) třídám, jako obloha, pes, tráva * lze přeformulovat jako klasifikace každého pixelu do N tříd * přirozeně lze řešit konvolučníma sítěma ### FCN - Fully Convolutional Network * naivní CNN architektura * Konvoluční vrstvy které nemění spatial dimenze ![image31](https://hackmd.io/_uploads/Hyyktei4C.png) Problém: * výpočetně náročné pro jakékoli netriviální množství latentních feature map protože konvoluce na plném rozlišení jsou drahé Zefektivnění: * snižovat rozlišení se zvyšujícím počtem kanálů * symetricky potom zrekonstruovat stejnou dimenzi jako originální input ![image25](https://hackmd.io/_uploads/SyX-tgo4C.png) Potřebujeme způsob jak zvýšit spatial dimenzi feature map Příklady upsampling vrstev bez učených parametrů: <table> <tr> <td> ![image33](https://hackmd.io/_uploads/ByRzYgjNC.png) </td> <td> ![image11](https://hackmd.io/_uploads/HyFmFxsN0.png) </td> </tr> <tr> <td colspan="2" > ![image2](https://hackmd.io/_uploads/BJ5SYxjNR.png) </td> </tr> </table> Učenou verze upsamplingu lze naimplementovat pomocí transposed konvoluce Intuitivní představa je že Transposed konvoluce “rozkopírovává” input pronásobený kernelem. Nejlépe je to vidět na variantě kde stride = velikost kernelu: ![image24](https://hackmd.io/_uploads/r1dnteo4C.png) transposed konvoluce s 2x2 maticí plnou jedniček a stridem 2 odpovídá nearest-neighbor upsamplingu Takhle vypadá varianta se stridem 1: ![image7](https://hackmd.io/_uploads/BkmiFli4C.png) ### UNet Problémy, které chceme vyřešit: * FCN která zachovává spacial dimenzi je neefektivní * FCN která má uprostřed malou spacial dimenzi má “informační bottleneck” * = hodně informace se může ztratit v prostřední reprezentaci Řešení: * přidáme skip connections mezi vrstvami se stejnou spatial dimenzí ![image34](https://hackmd.io/_uploads/S1IpFeiE0.png) ### Mask R-CNN = adaptace Faster R-CNN pro instance segmentaci * kromě bounding boxu chceme masky pro každý objekt * úprava achitektury je jednoduchá * kromě klasifikace třídy a regrese pro korekci bounding boxu se na konci per-region CNN predikuje i binární maska ![image15](https://hackmd.io/_uploads/HyW19liVR.png) ## Podmíněné a nepodmíněné generativní modely Intuitivně: * X jsou komplikovaná data * Y jsou primitivní data (labely) * P(Y) je prior na labelech (snadno aproximujeme z četností výskytu) * P(Y | X) aproximují diskriminativní modely (klasifikátory) * P(X) aproximují nepodmíněné generativní modely * P(X | Y) aproximují podmíněné generativní model Bayes rule je dává do souvislosti: ![image6](https://hackmd.io/_uploads/Bk91cxi4A.png) ### Autoregresivní modely * explicitně modelují hustotu p(x) * tzn model nám na vstup x umí vrátit skalár který odhaduje jak je x pravděpodobný * cíl je natrénovat model (odhadnout parametry w), který maximalizuje likelihood dat: ![image21](https://hackmd.io/_uploads/Hkvh5xsER.png) Autoregrese: * předpokládáme že x se skládá z “částí” x_i * pomocí chain rule vyjádříme p(X) = p(X_1) * p(X_2 | X_1) * p(X_3 | X_1, X_2) * … * autoregresivní model potom modeluje p(X_i | X_0 … X_i-1) * při generování x postupujeme od x_1 po x_n * každý predikovaný prvek x_i strčíme zpět do modelu a predikujeme následující Pixel RNN: * u grayscale by části x_i byly jednotlivé pixely * u RGB má máme tři části pro každý pixel * generování každého pixelu je podmíněné všemi pixely nalevo a nahoře pomocí hidden statu RNN * predikce pixelu je natřikrát, pro každý kanál softmax 0 - 256 ![image26](https://hackmd.io/_uploads/HJ9RqxsN0.png) Pixel CNN: * podobné Pixel RNN, ale používá konvoluce na lokálním okolí místo RNN hidden stavu, který se musí počítat při tréningu úplně sekvenčně * generování je pořád extrémně pomalé ![image1](https://hackmd.io/_uploads/rJ2Jsei4A.png) ### VAE - Variational Autoencoder klasické autoencoder: * 2 části, encoder a decoder * trénujeme: * z = enc(x) * x’ = dec(z) * minimize loss(x, x’) * **z** se nazývá latentní vektor * dim z &lt; dim x, jinak by se encoder mohl naučit prostě kopírovat **x** do **x’** * jak generovat? * a pak vyrobit nová data jako: x’ = dec(random z) * ale my nevíme nic o tom jakou distribuci má **z** * takže jsme namydlení Variační autoencoder: * snaží se vynutit konkrétní distribuci na **z** * potom z ní můžeme samplovat a generovat nová data pomocí decoderu * enc(x) nově predikuje distribuci p(z | x) * rodinu distribucí si vybereme předem * a encoder predikuje pouze parametry * obvyklá volba je gausián s diagonální kovarianční maticí * pak encoder predikuje pouze n průměrů a n rozptylů (nebo std) * z se potom nasampluje z téhle distribuce z ~ enc(x) * analogicky, decoder predikuje distribuci p(x’ | z) * ale někde se používá i deterministický encoder, který přímo predikuje jedno konkrétní x’ * obvyklá volba je opět gausián s diagonální kovarianční maticí Loss funkce pro VAE: * skládá se ze 2 částí: reconstruction loss - regularizace * reconstruction loss: * snaží se o aby VAE přiřazoval velkou pravděpodobnost examplum z datasetu * regularizace: * snaží se vynutit, aby encoder predikoval distribuce pro z blízké **prior distribuci** * pro gaussiány s kovarianční maticí bude prior, že průměry = 1 a rozptyly = 1 * díky tomu můžeme pak generovat nová data: * samplovat z ~ prior * nová data x’ ~ dec(z) Formálně: * enc(x) … predikovaná distribuce přes **z** * dec(z) … predikovaná distribuce přes **x’** * dec(x | z) … predikovaná pravděpodobnost x za podmínky **z** * Celková loss: $$ \mathbb{E}_{x \sim D, z \sim \text{enc}(x)} \log \text{dec}(x \mid z) - \mathbb{E}_{x \sim D} \text{KL} \left( \text{enc}(x) \parallel Z_{\text{prior}} \right) $$ * první části taky říkáme Variational Lower Bound (ELBO) * není to přímo pravděpodobnost kterou autoencoder přiřazuje x protože místo toho abychom integrovali (sumovali) přes všechny možný z, prostě náhodně samplujeme * jenže integrovat přes všechny **z** je drahé, samplovat ze **z** je levné * probabilita **x** given jedno **z** je je nižší než suma probabilit pro **x** given z přes všechny **z** * => to je ta “lower bound” * předpoklad je, že když maximalizujeme lower bound funkce F, tak tím nakonec maximalizujeme i funkci F, protože jí “zespodu vytláčíme” :D V případě, že omezujeme Z~enc(x) a X’~dec(x) na gausiány s kovarianční maticí, tak: * KL(z || Z_prior) má closed-form řešení (vzoreček) * dec(x | z) je dosazení **x** do hustoty gausiánu, kterou decoder predikuje: dec(z) Repametrizační trik * my samplujeme latentní vektory **z** uprostřed forward průchodu VAE * potřebujeme zajistit aby skrz samplování šlo backpropagovat * → reperametrizační trik: * přeformulujeme jak vzniká latentní vektor z * místo originálního: * z ~ enc(x) * použijeme: * means, variances := enc(x) * eps ~ N(0, 1) * z = means + variances * eps * díky tomu je **z** diferencovatelné vzhledem k **means** a **variances**, a tím k params encoderu ![image16](https://hackmd.io/_uploads/HkNVixiVR.png) ### GAN - Generativní Adversariální Síť ![image4](https://hackmd.io/_uploads/SyiIsljNC.png) * GAN modeluje p(x) implicitně * můžeme samplovat z aproximace datové distribuce * ale neodhadujeme p(x) * D(x) není aproximace p(x) !!! * D(x) nemodeluje hustotu (nebo pravděpodobnost) x * a rozhodně se neitegruje (nesčítá) do 1 přes všechny možné vstupy * G a D hrají adversariální hru * D se snaží rozpoznat fake data * G se snaží oblafnout D * Účelová funkce je založená na binární cross-entropii * vysvětlení z formely: [Binary Cross-entropy](https://www.notion.so/GAN-formela-7bbfd09528a343dcb429a8f150dce7e0?pvs=4#10c2504b25fe46e899b5014d064ef83a) GAN účelová funkce: ![image13](https://hackmd.io/_uploads/H1GdjljNC.png) Řešení hry: * (předpokládáme bezmeznou expresivní sílu D i G) * pro fixní G, existuje unikátní globálně optimální D * za předpokladu, že D bude optimální protihráč, existuje globálně optimální G * → tzn, existuje globální a unikátní Nashovo ekvilibrium * v ekvilibriu: * G dokonale modeluje datovou distribuci * D neumí rozpoznat fakes a reaálné data * ani jeden si sám nemůže přilepšit (z definice ekvilibria) tréning konverguje do ekvilibria, za divokých teorietických předpokladů * NNs mají nekonečnou expresivní sílu * máme nekonečně dat * po každým updatu G, děláme nekonečně mnoho updatů pro D * … Praktické problémy: * nedostatečné gradienty * pro D je snadné poznat fakes, takže posílá do G malý grady * (= G neumí žádnou malou změnou rozumě ovlivnit výstup D) * Mode collapse: * G najde slabinu v D and exploituje ho * ⇒ G produkuje nediverzní popřípadě degenerovaný samply * oscilace: * tréning mode-collapsne * D se naučí rozpoznávat fakes z toho kolapsu, ale zapomene něco z dřívějšího tréningu * G najde novou slabinu → nový mode collapse → opakuje se dokola ## Transformer ### Self-Attention parametry: * query matice W_Q: D x D_q * key matice W_K: D x D_q * value matice W_V: D x D_v vstup = posloupnost vektorů * coby matice X: N x D * může být třeba: * posloupnost slov * patche obrázku výstup = posloupnost vektorů: * coby matice Y: N x D_v Výpočet: * Q = X @ W_Q shape N x D_q * K = X @ W_K shape N x D_q * V = X @ W_V shape N x D_v * E = Q @ K.T / sqrt(D_q) shape N x N * A = softmax(E, row-wise) shape N x N, každý řádek se sčítá do jedné * Y = A @ V shape N x D_v Y jsou nové reprezentace vstupu X, ve kterém se jednotlivé vektory “vzájemně obohatili” o kontext Vizualizace výpočtu (ale nesedí tu pořadí řádky/sloupce s formální notací) ![image5](https://hackmd.io/_uploads/Bk6KoxiNC.png) ### Cross-Attention = rozšíření self-attention Nově máme 2 vstupy: * jeden, který obohacujeme - Src * druhý, pomocí kterého obohacujeme - Tgt * Src a Tgt mohou mít různé dimenze, matice W_* nám to “zarovnají” Změny: * queries se počítají ze Src * keys a values se počítají z Tgt * Y jsou na konci výpočtu nové reprezentace pro Tgt Využití: * flexibilní varianta attention * umožňuje kombinovat více vstupů nebo dokonce modalit * příklady: * similarita textu a obrázku * popisování obrázku * audio transkript * strojový překlad * … ### Multi-Head Attention = zapojení několika paralelních attention vrstev vedle sebe Výstupy se concatenují a pak pomocí jedné učené lineární vrstvy zobrazí na požadovanou dimenzi ### Poziční kódování Není součástí otázky explicitně, ale byla by asi chyba o něm nic nevědet, když je v otázce transformer Pozorování: * attention vrstva je “permutation equivariant” * tzn, pokud přemícháme pořadí vektorů na vstupu: * přemíchá se pořadí vektorů na výstupu * ale jejich obsah bude stejný * → attention vrstvy nemají (a teedy ani nepoužívají) informaci o tom: * kde ve vstupu se vektor nachází * jak jsou od sebe ve vstupu daleko * to je důležité protože na pořadí a relativních vzdálenostech ve vstupu záleží * například pořadí slov ve větě mění význam * pokud máme patch v obrázku obsahující červené kalhoty, patch nad ním má modré tričko a patch 10 bloků daleko obsahuje zelené triko, lze usoudit že osoba s červenými kalhotami má modré tričko a patch se zeleným je irelevantní Poziční kódování přidává do vstupu informaci o tom, kde se jednotlivé části vstupu nachází Populární typy: * naučené * máme učitelnou embedding matici E dimenze (N x D_model) * k i-té části vstupu se přičte (popř. concatenuje) poziční kódování E[i] * parametry E se trénují souběžně s ostatními parametry modelu * relativní * nemění reprezentace vektorů * ovlivňuje pouze výpočet attention * předpokládá že je důležitá relativní vzdálenost částí a ne jejich absolutní pozice ve vstupu ![image27](https://hackmd.io/_uploads/Hy7hsxoEC.png) * sinusoidní * používá stejnou matici E jako naučené, ale nemá trénovatelné parametry * má dobré vlastnosti, například: * attention hlava se může naučit attendovat o n pozic dopředu a dozadu * matice E vypadá asi takhle: ![image22](https://hackmd.io/_uploads/BJxaogiE0.png) ### Transformer Encoder = model, který využívá: * poziční kódování * Bloky složené z: * attention * MLP * residuálních spojení * normalizace ![image19](https://hackmd.io/_uploads/H1oPqxiE0.png) ### Vision Transformer ![image14](https://hackmd.io/_uploads/SybU9xjN0.png) Lineární vrstvy v transformer MLP části lze chápat jako konvoluce se kernelem velikost 1: * protože jde o lineární vrstvu, která se aplikuje na každou pozici samostatně