Neural Artistic Style Transfer: Komplexní pohled

Jarní čtvrtletí mého prvního ročníku jsem absolvoval kurz Stanfordova CS 231n na Konvolučních neuronových sítích. Můj závěrečný projekt kurzu se zabýval super cool konceptem zvaným neuronový styl, ve kterém je styl uměleckého díla přenesen na obrázek. Zde je klasický příklad - obrázek Hoover Tower ve Stanfordu ve stylu Hvězdné noci:

Starry Stanford

První publikovaný článek o přenosu neuronového stylu použil optimalizační techniku ​​- to znamená, že začal s obrazem náhodného šumu a stal se čím dál více žádoucí při každé „tréninkové“ iteraci neuronové sítě. Tato technika byla popsána v několika tutoriálech po celém webu. Technika následného papíru, což je to, co ve skutečnosti způsobil, že došlo k propuknutí nervového stylu, nebyla tak důkladně pokryta. Tato technika je přímočará - naučte síť předem provádět stylizace daného obrazu, aby mohla okamžitě vytvářet stylizované obrázky.

V tomto tutoriálu se budeme zabývat oběma technikami, intuicemi a matematikou za tím, jak fungují a jak druhý staví první. Pokryjeme také další krok: špičkový výzkum, který jsem prozkoumal v mém projektu CS 231n, jakož i výzkumné týmy v Cornell a Google. Na konci budete moci trénovat své vlastní sítě k výrobě krásných uměleckých děl!

Metoda optimalizace

V této metodě nepoužíváme neuronovou síť v pravém slova smyslu. To znamená, že školíme síť, aby dělala cokoli. Jednoduše využíváme backpropagation pro minimalizaci dvou definovaných ztrátových hodnot. Tenzorem, do kterého se vracíme, je stylizovaný obraz, kterého chceme dosáhnout - a odtud se nazývá pastiche. Jako vstupy máme také kresbu, jejíž styl chceme přenést, známý jako obrázek stylu, a obrázek, na který chceme přenést styl, známý jako obrázek obsahu.

Pastiche je inicializován jako náhodný šum. Spolu s obrázky obsahu a stylu pak prochází několika vrstvami sítě, která je předběžně zařazena do klasifikace obrázků. Výstupy různých mezilehlých vrstev používáme pro výpočet dvou typů ztrát: ztráta stylu a ztráta obsahu - to je, jak blízko je pastiche stylu obrázku ve stylu a jak blízko je pastiche obsahu obsahu v obsahu. Tyto ztráty jsou pak minimalizovány přímou změnou našeho pastiche image. Na konci několika iterací má nyní obraz pastiche styl stylu a obsah obsahu - nebo, jinak řečeno, je to stylizovaná verze původního obsahu.

Ztráty

Než se ponoříme do matematiky a intuice za ztrátami, pojďme řešit problém, který můžete mít. Možná vás zajímá, proč používáme výstupy mezilehlých vrstev předpřipravené sítě pro klasifikaci obrázků pro výpočet našich ztrát stylu a obsahu. Důvodem je to, že aby síť mohla provést klasifikaci obrázků, musí obrázek pochopit. Takže mezi přijetím obrazu jako vstupu a výstupem jeho odhadu, co to je, dělá transformace, aby proměnil obrazové pixely v interní porozumění obsahu obrázku.

Tato interní porozumění můžeme interpretovat jako přechodné sémantické reprezentace původního obrazu a použít tyto reprezentace k „porovnání“ obsahu dvou obrazů. Například: pokud projdeme dva obrazy koček sítí pro klasifikaci obrázků, i když počáteční obrázky vypadají velmi odlišně, po průchodu mnoha vnitřními vrstvami budou jejich reprezentace velmi blízké v hrubé hodnotě. Toto je ztráta obsahu - projděte jak pastiche, tak i obsah pomocí některých vrstev sítě pro klasifikaci obrázků a najděte euklidovskou vzdálenost mezi prostředními reprezentacemi těchto obrázků. Zde je rovnice ztráty obsahu:

Rovnice ztráty obsahu

Sumační notace způsobuje, že koncept vypadá těžší, než ve skutečnosti je. V zásadě vytváříme seznam vrstev, ve kterých chceme vypočítat ztrátu obsahu. Předáváme obsah a pastiches obrazy sítí, dokud konkrétní vrstva v seznamu, vzít výstup této vrstvy, druhou mocninu rozdíl mezi každou odpovídající hodnotu ve výstupu, a sčítat je všechny dohromady. Děláme to pro každou vrstvu v seznamu a shrneme je. Je však třeba si uvědomit jednu věc: každou z reprezentací vynásobíme nějakou hodnotou alfa (nazývanou hmotnost obsahu), než najdeme jejich rozdíly a porovnáme ji, zatímco původní rovnice vyžaduje, aby byla hodnota po vyrovnání umocněna. V praxi jsem zjistil, že první z nich funguje mnohem lépe než druhý, protože to produkuje přitažlivé stylizace mnohem rychleji.

Ztráta stylu je velmi podobná, kromě toho, že místo srovnání surových výstupů stylu a pastiche obrazů v různých vrstvách porovnáváme Gramovy matice výstupů. Gramova matice je výsledkem násobení matice transpozicí samotné:

Gramova maticová rovnice

Protože je každý sloupec násoben každým řádkem v matici, můžeme si představit, že prostorové informace obsažené v původních reprezentacích byly „distribuovány“. Matice Gram místo toho obsahuje nealokalizované informace o obrázku, například texturu, tvary a hmotnosti - styl!

Nyní, když jsme definovali Gramovu matici jako informace o stylu, můžeme najít euklidovskou vzdálenost mezi Gramovými maticemi středních reprezentací pastiche a obrazu stylu, abychom zjistili, jak podobní jsou ve stylu:

Rovnice ztráty stylu

Podobně jako v případě výpočtu ztráty stylu, najdeme euklidovské vzdálenosti mezi každou odpovídající dvojicí hodnot v Gramových matricích vypočtených v každé vrstvě v předdefinovaném seznamu vrstev vynásobeném nějakou hodnotou beta (známou jako váha stylu).

Ztráta obsahu - která obsahuje informace o tom, jak blízko je pastiche obsahu obsahu - a ztráta stylu - která obsahuje informace o tom, jak blízko je pastiche ve stylu obrázku stylu. Nyní je můžeme přidat dohromady, abychom získali celkovou ztrátu. Pak jsme zpětné propagování v síti, abychom tuto ztrátu snížili, získáme přechod na pastiche a iterativně jej upravíme tak, aby vypadal stále více jako stylizovaný obraz obsahu. To vše je podrobněji popsáno v původním článku na toto téma od Gatys et al.

Implementace

Nyní, když víme, jak to funguje, vytvořme to. Budeme používat knihovnu PyTorch pro celý náš kód, takže se ujistěte, že máte nainstalovaný.

Nejprve implementujme maticovou vrstvu Gram:

Nyní definujme naši síť. Vytvořme třídu s inicializátorem, který nastaví některé důležité proměnné:

Proměnné, které inicializujeme, jsou: styl, obsah a obrázky pastiches; vrstvy, ve kterých počítáme ztrátu obsahu a stylu, a také váhy alfa a beta, které znásobíme reprezentace; předpřipravená síť, kterou používáme k získání přechodných reprezentací (používáme VGG-19); výpočet Gramovy matice; výpočet ztráty děláme (protože MSE je stejná jako euklidovská vzdálenost); a optimalizátor, který používáme. Chceme také využít GPU, pokud máme na našem počítači.

Nyní pro režim „školení“ sítě. Obrázky procházíme sítí po jedné vrstvě. Zkontrolujeme, zda se jedná o vrstvu, ve které provádíme výpočet ztráty obsahu nebo stylu. Pokud ano, vypočítáme příslušnou ztrátu v této vrstvě. Nakonec přidáme ztráty obsahu a stylu dohromady a na tuto ztrátu zavoláme zpět a provedeme krok aktualizace. Jak to vypadá:

(Chcete-li použít optimalizátor LBGFS, je nutné předat do krokové funkce uzavírací funkci, která „reevaluuje model a vrátí ztrátu“; to nemusíme dělat s žádným jiným optimalizátorem… jít obrázek)

Ještě jeden krok, než začneme převádět nějaký styl - musíme si napsat několik funkcí pohodlí:

Funkce image_loader otevře obraz na cestě a načte jej jako proměnnou velikosti PyTorch velikosti imsize; funkce save_image převede obrázek pastiches, což je proměnná PyTorch, do příslušného formátu PIL a uloží jej do souboru.

Nyní vyrábět krásné umění. Nejprve pojďme importovat nějaké věci, načíst naše obrázky a dát je na GPU, pokud je máme. Pak pojďme definovat a zavolat naši tréninkovou smyčku, abychom z naší původně náhodné pastiche udělali neuvěřitelné umění. Takto to vypadá:

A to je vše! Použili jsme optimalizační metodu k vytvoření stylizované verze obsahu. Nyní můžete libovolný obrázek vykreslit do stylu libovolného obrazu - i když pomalu, protože proces optimalizace je iterativní. Zde je příklad, který jsem vytvořil z našeho kódu - tanečnice ve stylu postavy Dans un Fauteuil od Picasso:

Picasso tanečnice

Zpětná metoda

Proč předchozí metoda trvá tolik času? Proč musíme čekat na optimalizační smyčku, abychom vytvořili pěkný obrázek? Nemůžeme říct síti: „Hej, naučte se styl Hvězdné noci tak dobře, že vám mohu poskytnout jakýkoli obrázek a okamžitě z něj uděláte verzi obrázku s Hvězdnou nocí“? Ve skutečnosti můžeme!

V zásadě vytváříme netrénovanou síť pro transformaci obrazu, která transformuje obsahový obsah do svého nejlepšího odhadu na přitažlivém obrazu pastiche. Poté to použijeme jako obraz pastiche, který je společně s obrázky obsahu a stylu procházen předpřipravenou sítí klasifikace obrázků (nyní nazývanou ztrátová síť) pro výpočet našeho ztráty obsahu a stylu. Nakonec, abychom minimalizovali ztrátu, jsme zpětně propracováni do parametrů Image Transormation Network, nikoli přímo do pastiche image. Děláme to s tuny náhodných příkladů obrázků obsahu, a tak školíme Image Transformation Network tak, aby transformoval jakýkoli daný obrázek do stylu nějakého předdefinovaného uměleckého díla.

Implementace

Nyní musíme do naší vícestupňové architektury sítě přidat síť Image Transformation Network a ujistit se, že optimalizátor je nastaven tak, aby optimalizoval parametry ITN. Budeme používat architekturu od Johnson et al. pro naše ITN. Nahraďte posledních 8 řádků inicializátoru StyleCNN tímto kódem:

Protože nyní chceme, aby náš tréninkový režim akceptoval dávku obsahu obsahu jako příklady školení, můžeme obrázek obsahu odstranit jako vstup do inicializátoru. Náš tréninkový režim přijímá šarži obrazového obsahu, transformuje ji na pastiche, vypočítává ztráty podle výše uvedeného postupu a zpětně vyzývá ke konečné ztrátě, aby aktualizoval parametry ITN. Tady je vše v kódu:

Úžasné! Změníme naši funkci save_image, abychom mohli uložit nejen jeden obrázek, ale i dávku obrázků:

def save_images (vstup, cesty): N = input.size () [0] images = input.data.clone (). cpu () pro n v rozsahu (N): image = images [n] image = image.view (3, imsize, imsize) image = unloader (image) scipy.misc.imsave (cesty [n], image)

Ještě jedna zakázka. Musíme mít k dispozici dataset obsahových obrázků jako příklady školení, které se předávají do naší sítě při každé iteraci školení. K tomu použijeme datový soubor Microsoft COCO. Předtím, než s tím v PyTorch budete moci dělat cokoli, musíte nainstalovat a nastavit rozhraní COCO API. API si můžete stáhnout ze zdroje zde. Po stažení jej nainstalujte spuštěním setup.py.

Po dokončení těchto kroků přidejte tyto importy:

import torch.utils.data import torchvision.datasets jako datové sady

Nakonec nahradíme naši hlavní funkci tímto kódem:

Woo! Nyní můžeme trénovat síť tak, aby transformovala jakýkoli obrázek na jeho stylizovanou verzi, založenou na stylu našeho předepsaného obrazu. Tohle je úžasné! V případě, že by vás zajímalo, tato technologie přesně funguje aplikace jako Prisma. Zde je několik příkladů výstupů ze tří předběžných sítí vycvičených na třech různých obrazech:

Příklady dopředných obrázků

Libovolný přenos stylu

Možná jste si všimli, že ačkoli naše dopředná implementace dokáže okamžitě vytvořit stylizované pastiches, může tak učinit pouze pro jeden daný obrázek stylu. Bylo by možné vyškolit síť, která kromě jakýchkoli obsahových obrázků dokáže pořídit i jakýkoli styl a vytvořit z těchto dvou obrazů pánev? Jinými slovy, můžeme vytvořit skutečně libovolnou síť pro přenos neurálních stylů?

Jak se to stává, velmi cool zjištění v tomto problému naznačovalo, že je to možné. Před několika lety bylo zjištěno, že vrstvy normalizace instance v sítích pro transformaci obrazu byly jedinými důležitými vrstvami, které představují styl. Jinými slovy, pokud zachováme všechny konvoluční parametry stejné a naučíme se pouze nové parametry normalizace instance, můžeme v jedné síti reprezentovat úplně jiné styly. Tady je papír s tímto nálezem. To naznačuje, že můžeme využít vrstvy standardů instance tím, že v těchto vrstvách použijeme parametry, které jsou specifické pro každý styl.

První pokus o to byl od týmu v Cornell. Jejich řešením bylo použití normalizace adaptivní instance, ve které byla pro generování parametrů instance Norm z obrazů stylů použita architektura kodér-dekodér. Tady je papír o tom. To mělo docela velký úspěch.

Dalším pokusem o libovolný přenos stylu byl můj vlastní projekt, ve kterém používám sekundární normalizační síť k transformaci obrazu stylu do instančních normalizačních parametrů, které mají používat Image Transformation Network, učení parametrů jak v normalizační síti, tak v ITN. najednou. Tady je můj papír o tom. Tato metoda byla schopna prokázat úspěch na malém souboru náhodných stylů, a proto nebyla skutečně libovolná; bylo to však teoreticky úspěšné.

Poslední pokus o dosažení libovolného přenosu stylu byl od týmu v Google Brain. Použili metodu, která je téměř totožná s mojí metodou, jak je popsáno výše, kromě toho, že používají předškolenou počáteční síť k transformaci obrazů stylů do parametrů instance Norm namísto použití netrénované sítě a jejich školení spolu s ITN, end-to-end. Tato metoda zaznamenala divoký úspěch a přinesla krásné výsledky a dosáhla skutečného přenosu libovolného nervového stylu. Tady je úžasný papír o tom.

I když jsem nebyl schopen problém plně vyřešit, cítil jsem poctu, že jsem byl schopen účastnit se výzkumné konverzace a být na špici řešení tak zajímavého problému. Bylo vzrušující vidět, jak Google konečně vyřešil problém s tak elegantním a krásným řešením.

Další čtení

K tomuto problému je docela dost literatury, takže další skvělé kroky by prošly skrz ně. Propojil jsem články v celém článku, ale myslel jsem, že je všechny zveřejním na jednom místě:

  • Zde je původní dokument o přenosu nervového stylu, který navrhl proces optimalizace
  • Tady je papír o dopředném přenosu stylu; její doplňkové materiály obsahují architekturu, kterou jsme použili v našem kódu.
  • Pokud jste přemýšleli, co je Normalizace instance vůbec, zde je papír, který ji popisuje.
  • Zde je Cornellův článek o normě adaptivní instance
  • Tady je můj článek o end-to-end libovolném tréninku přenosu sítí
  • Zde je dokument Google, který dosáhl libovolného přenosu stylu

Doufám, že jste zjistili, že tato vzrušující aplikace neuronových sítí je stejně fascinující a zábavná jako já. Šťastné učení!

Pokud se vám tento článek líbil, ujistěte se, že mi dáte tleskání a následujte mě, abyste viděli své budoucí články ve vašem zdroji! Podívejte se také na můj osobní blog a sledujte můj Twitter, kde najdete více mých úvah.