Om inzicht te krijgen in een VAE, starten we eerst vanuit een eenvoudig netwerk en voegen we stap voor stap onderdelen toe.

Een gebruikelijke manier om een neuraal netwerk te beschrijven is een benadering van een of andere functie die we willen modelleren. Echter, ze zullen zelfs worden gezien als een kennisstructuur die informatie bevat.

http://kvfrans.com/content/images/2016/08/dat.jpg

Laten we zeggen dat we een netwerk hadden dat bestond uit een paar deconvolutielagen. We hebben de input zo ingesteld dat het altijd een vector van die lagen is. Dan trainen we het netwerk om de gemiddelde kwadratuurfout tussen zichzelf en één doelafbeelding terug te schalen. De “data” voor die afbeelding zit nu in de parameters van het netwerk.

Laten we het nu proberen op meerdere afbeeldingen. Eerder dan een vector van één, zullen we een one-hot vector gebruiken voor de invoer. [1, 0, 0, 0] kan een katafbeelding betekenen, terwijl [0, 1, 0, 0] een hond kan betekenen. Dit werkt, maar we zullen slechts tot 4 afbeeldingen opslaan. Het gebruik van een langere vector betekent het toevoegen van extra en meer parameters waardoor het netwerk de verschillende afbeeldingen kan onthouden.

Om dit op te lossen gebruiken we een vector van reële getallen in plaats van een one-hot vector. We zullen dit beschouwen als een code voor een afbeelding, waar de termen codering/code vandaan komen. Bijvoorbeeld , [3.3, 4.5, 2.1, 9.8] zou de afbeelding van de kat kunnen weergeven, terwijl [3.4, 2.1, 6.7, 4.2] de hond zou kunnen weergeven. Deze eerste vector wordt begrepen als onze latente variabelen.

http://kvfrans.com/content/images/2016/08/autoenc.jpg

Het willekeurig kiezen van de latente variabelen, zoals ik hierboven heb gedaan, is duidelijk een vervelend idee. In een autoencoder voegen we een andere component toe die in de originele beelden opneemt en deze voor ons in vectoren codeert. De deconvolutionele lagen “decoderen” dan de vectoren terug naar de eerste beelden.

We zijn nu eindelijk in een fase gekomen waarin ons model een beetje praktisch nut heeft. We zullen ons netwerk trainen op zoveel afbeeldingen als we willen. Als we de gecodeerde vector van een beeld opslaan, zullen we het later reconstrueren door het door te geven aan het decodergedeelte. Wat we hebben is dat de standaard autoencoder.

We proberen hier echter een generatief model te maken, niet alleen een wazige opstelling die beelden “onthoudt”. We zullen nog niets genereren, aangezien we geen vaardigheden hebben om latente vectoren te maken, behalve het coderen van de beelden.

Er is hier een eenvoudige oplossing. We voegen een beperking toe aan het coderingsnetwerk, die het dwingt om latente vectoren te krijgen die ruwweg een eenheid normale distributie volgen. het is deze beperking die een variationele autoencoder scheidt van een typische autoencoder.

Het genereren van nieuwe beelden is nu eenvoudig: het enige wat we willen proberen is een latente vector uit de unit gaussian te bemonsteren en deze door te geven aan de decoder.

In de praktijk is er een wisselwerking tussen hoe nauwkeurig ons netwerk vaak is en de manier waarop de latente variabelen in de buurt van de normale verdeling van de eenheid kunnen komen.

We laten het netwerk dit zelf beslissen. Voor onze verliesperiode vatten we twee afzonderlijke verliezen samen: het generatieve verlies, dat een gemiddelde kwadratische fout kan zijn die meet hoe nauwkeurig het netwerk de beelden heeft gereconstrueerd, en een latent verlies, dat is dat de KL-afwijking die meet hoe dicht de latente variabelen bij een eenheidsmeter liggen.

generatie_verlies = gemiddelde(vierkant(gegenereerd_beeld – reëel_beeld))

latent_verlies = KL-Divergentie (latent_variabel, eenheid_gaussisch)

verlies = generatieverlies + latent verlies

http://kvfrans.com/content/images/2016/08/vae.jpg

Om de KL-divergentie te optimaliseren, willen we een eenvoudige herparametertruc gebruiken: in plaats van de encoder die een vector van echte waarden genereert, zal hij een vector van middelen en een vector van gewone afwijkingen genereren.

Dit laat ons toe om de KL divergentie als volgt te berekenen:

# z_mean en z_stddev zijn twee vectoren die gegenereerd worden door het encoder netwerk

latent_verlies = 0,5 * tf.reduce_sum(tf.square) + tf.square(z_stddev) – tf.log(tf.square(z_stddev)) – 1,1)

Bij het berekenen van het verlies voor het decodernetwerk zullen we gewoon een steekproef nemen van de kwaliteitsafwijkingen en het gemiddelde toevoegen, en dat gebruiken als onze latente vector:

samples = tf.random_normal([batch size,n_z],0,1,dtype=tf.float32)

sampled_z = z_mean + (z_stddev * monsters)

Naast de mogelijkheid om willekeurige latente variabelen te krijgen, verbetert deze beperking ook de veralgemening van ons netwerk.

Om dit te visualiseren zullen we de latente variabele beschouwen als een overdracht van kennis.

Laten we zeggen dat je een stel echte getallenparen hebt tussen [0, 10], naast een reputatie . bijvoorbeeld , 5,43 betekent appel, en 5,44 betekent banaan. Als iemand je het bedrag 5,43 geeft, herken je natuurlijk dat het om een appel gaat. We zullen op deze manier in wezen oneindig veel informatie coderen, omdat er geen limiet is op welk percentage verschillende reële getallen we zullen hebben tussen [0, 10].

Echter, wat als er een gaussian ruis van 1 toegevoegd was wanneer iemand je een getal probeerde te informeren? Als je nu eenmaal het getal 5,43 ontvangt, zou het eerste getal overal rond [4,4 ~ 6,4] kunnen liggen, dus de andere persoon had net zo goed banaan kunnen betekenen (5,44).

Hoe groter de variantie op de toegevoegde ruis, hoe minder informatie we zullen doorgeven met behulp van die ene variabele.

Nu zullen we dezelfde logica toepassen op de latente variabele die tussen de encoder en de decoder wordt doorgegeven. Hoe efficiënter we het eerste beeld zullen coderen, hoe hoger we de kwaliteitsafwijking op onze gaussian zullen verhogen tot het een niveau bereikt.

Deze beperking dwingt de encoder om zeer efficiënt te zijn, waardoor er informatie-rijke latente variabelen ontstaan. Dit verbetert de veralgemening, zodat latente variabelen die we ofwel willekeurig genereren, of we krijgen van het coderen van niet-trainende beelden, een mooier resultaat zullen opleveren wanneer ze gedecodeerd worden.

Hoe goed werkt het?

http://kvfrans.com/content/images/2016/08/mnist.jpg

Ik heb een paar tests gedaan om te bepalen hoe goed een variationele autoencoder zou werken op de MNIST-handschriftdataset.