velkommen til Del 3 af Applied Deep Learning series. Del 1 var en praktisk introduktion til kunstige neurale netværk, der dækker både teori og anvendelse med mange kodeeksempler og visualisering. I Del 2 anvendte vi dyb læring til virkelige datasæt, der dækker de 3 mest almindelige problemer som casestudier: binær klassificering, multiklasseklassificering og regression.
nu begynder vi at dykke ned i specifikke dybe læringsarkitekturer, der starter med de enkleste: Autoencoders.
- introduktion
- arkitektur
- implementering
- denoising Autoencoders
- sparsomme Autoencoders
- Use Cases
- konklusion
koden til denne artikel er tilgængelig her som en jupyter notesbog, er du velkommen til at hente og prøve det selv.
introduktion
Autoencoders er en bestemt type fremadgående neurale netværk, hvor input er det samme som output. De komprimerer input til en lavere dimensionel kode og rekonstruerer derefter output fra denne repræsentation. Koden er en kompakt “oversigt” eller “komprimering” af input, også kaldet latent-rumrepræsentation.
en autoencoder består af 3 komponenter: encoder, kode og dekoder. Koderen komprimerer indgangen og producerer koden, dekoderen rekonstruerer derefter kun indgangen ved hjælp af denne kode.
for at opbygge en autoencoder har vi brug for 3 ting: en kodningsmetode, afkodningsmetode og en tabsfunktion for at sammenligne output med målet. Vi vil undersøge disse i næste afsnit.
Autoencoders er hovedsageligt en dimensionalitetsreduktionsalgoritme (eller komprimeringsalgoritme) med et par vigtige egenskaber:
- Dataspecifik: Autoencodere er kun i stand til meningsfuldt at komprimere data svarende til det, de er blevet trænet på. Da de lærer funktioner, der er specifikke for de givne træningsdata, er de forskellige fra en standard datakomprimeringsalgoritme som f.eks. Så vi kan ikke forvente, at en autoencoder, der er trænet på håndskrevne cifre, komprimerer landskabsbilleder.
- Lossy: Udgangen af autoencoderen vil ikke være nøjagtig den samme som input, det vil være en tæt, men forringet repræsentation. Hvis du vil have tabsfri kompression, er de ikke vejen at gå.
- uden opsyn: for at træne en autoencoder behøver vi ikke gøre noget fancy, bare kast de rå inputdata på det. Autoencoders betragtes som en uovervåget læringsteknik, da de ikke har brug for eksplicitte etiketter at træne på. Men for at være mere præcis overvåges de selv, fordi de genererer deres egne etiketter fra træningsdataene.
arkitektur
lad os udforske detaljerne i encoder, kode og dekoder. Både koderen og dekoderen er fuldt tilsluttede fremadgående neurale netværk, i det væsentlige De Ann ‘ er, vi dækkede i Del 1. Kode er et enkelt lag af en ANN med den dimensionalitet, vi vælger. Antallet af noder i kodelaget (kodestørrelse) er et hyperparameter, som vi indstiller, før vi træner autoencoderen.
dette er en mere detaljeret visualisering af en autoencoder. Først passerer indgangen gennem koderen, som er en fuldt tilsluttet ANN, for at producere koden. Dekoderen, som har den tilsvarende ANN-struktur, producerer derefter output kun ved hjælp af koden. Målet er at få et output identisk med input. Bemærk, at dekoderarkitekturen er spejlbilledet af koderen. Dette er ikke et krav, men det er typisk tilfældet. Det eneste krav er dimensionalitet input og output skal være den samme. Alt i midten kan spilles med.
der er 4 hyperparametre, som vi skal indstille, før vi træner en autoencoder:
- Kodestørrelse: antal noder i mellemlaget. Mindre størrelse resulterer i mere kompression.
- antal lag: autoencoderen kan være så dyb som vi vil. I figuren ovenfor har vi 2 lag i både koderen og dekoderen uden at overveje input og output.
- antal noder pr.lag: den autoencoder-arkitektur, vi arbejder på, kaldes en stablet autoencoder, da lagene er stablet efter hinanden. Normalt ser stablede autoencodere ud som en “sandbryder”. Lag falder med hvert efterfølgende lag af koderen og stiger tilbage i dekoderen. Dekoderen er også symmetrisk til koderen med hensyn til lagstruktur. Som nævnt ovenfor er dette ikke nødvendigt, og vi har total kontrol over disse parametre.
- tabsfunktion: vi bruger enten gennemsnitlig kvadreret fejl (mse) eller binær crossentropi. Hvis inputværdierne er i området, bruger vi typisk crossentropi, ellers bruger vi den gennemsnitlige kvadrerede fejl. For flere detaljer tjek denne video.
Autoencoders trænes på samme måde som ANNs via backpropagation. Tjek introduktionen af Del 1 For flere detaljer om, hvordan neurale netværk trænes, det gælder direkte for autoencodere.
implementering
lad os nu implementere en autoencoder til følgende arkitektur, 1 skjult lag i koderen og dekoderen.
vi bruger det ekstremt populære MNIST-datasæt som input. Den indeholder sort-hvide billeder af håndskrevne cifre.
de er af størrelse 28h28, og vi bruger dem som en vektor af 784 tal mellem . Tjek jupyter notebook for detaljerne.
vi implementerer nu autoencoderen med Keras. Hyperparametrene er: 128 noder i det skjulte lag, kodestørrelse er 32, og binær crossentropi er tabsfunktionen.
dette ligner meget de ANNs, vi arbejdede på, men nu bruger vi Keras funktionelle API. Se denne vejledning for detaljer, men her er en hurtig sammenligning. Før vi plejede at tilføje lag ved hjælp af den sekventielle API som følger:
model.add(Dense(16, activation='relu'))
model.add(Dense(8, activation='relu'))
med den funktionelle API gør vi dette:
layer_1 = Dense(16, activation='relu')(input)
layer_2 = Dense(8, activation='relu')(layer_1)
det er mere detaljeret, men en mere fleksibel måde at definere komplekse modeller på. Vi kan nemt få fat i dele af vores model, for eksempel kun dekoderen, og arbejde med det. Udgangen af tæt metode er et konverterbart lag, ved hjælp af den funktionelle API giver vi den input og gemmer output. Udgangen af et lag bliver indgangen til det næste lag. Med den sekventielle API håndterede add-metoden implicit dette for os.
Bemærk, at alle lagene bruger relu-aktiveringsfunktionen, da det er standarden med dybe neurale netværk. Det sidste lag bruger sigmoid aktivering, fordi vi har brug for udgangene til at være mellem . Indgangen er også i samme rækkevidde.
Bemærk også funktionen call to fit, før vi plejede at gøre med ANNs:
model.fit(x_train, y_train)
men nu gør vi det:
model.fit(x_train, x_train)
Husk, at målene for autoencoderen er de samme som input. Derfor leverer vi træningsdataene som mål.
visualisering
lad os nu visualisere, hvor godt vores autoencoder rekonstruerer sit input.
vi kører autoencoderen på testsættet ved blot at bruge predict-funktionen af Keras. For hvert billede i testsættet får vi output fra autoencoderen. Vi forventer, at output vil være meget lig input.
de er faktisk temmelig ens, men ikke nøjagtigt de samme. Vi kan bemærke det tydeligere i det sidste ciffer “4”. Da dette var en simpel opgave vores autoencoder udført temmelig godt.
rådgivning
vi har total kontrol over autoencoderens arkitektur. Vi kan gøre det meget kraftfuldt ved at øge antallet af lag, noder pr. Forøgelse af disse hyperparametre vil lade autoencoderen lære mere komplekse kodninger. Men vi skal være forsigtige med ikke at gøre det for magtfuldt. Ellers lærer autoencoderen simpelthen at kopiere sine input til output uden at lære nogen meningsfuld repræsentation. Det vil bare efterligne identitetsfunktionen. Autoencoderen rekonstruerer træningsdataene perfekt, men det vil være overmontering uden at være i stand til at generalisere til nye tilfælde, hvilket ikke er det, vi ønsker.
derfor foretrækker vi en “sandbryder” – arkitektur og holder bevidst kodestørrelsen lille. Da kodningslaget har en lavere dimensionalitet end inputdataene, siges autoencoderen at være underkomplet. Det vil ikke være i stand til direkte at kopiere sine input til output, og vil blive tvunget til at lære intelligente funktioner. Hvis inputdataene har et mønster, for eksempel indeholder cifferet “1” normalt en noget lige linje, og cifferet “0” er cirkulært, vil det lære denne kendsgerning og kode det i en mere kompakt form. Hvis inputdataene var helt tilfældige uden nogen intern korrelation eller afhængighed, vil en undercomplete autoencoder ikke være i stand til at gendanne dem perfekt. Men heldigvis i den virkelige verden er der en masse afhængighed.
Denoising Autoencoders
at holde kodelaget lille tvang vores autoencoder til at lære en intelligent repræsentation af dataene. Der er en anden måde at tvinge autoencoderen til at lære nyttige funktioner, som tilføjer tilfældig støj til dens input og får den til at gendanne de originale støjfrie data. På denne måde kan autoencoderen ikke blot kopiere input til dets output, fordi input også indeholder tilfældig støj. Vi beder den om at trække støj fra og producere de underliggende meningsfulde data. Dette kaldes en denoising autoencoder.
den øverste række indeholder de originale billeder. Vi tilføjer tilfældig Gaussisk støj til dem, og de støjende data bliver input til autoencoderen. Autoencoderen ser slet ikke det originale billede. Men så forventer vi, at autoencoderen regenererer det støjfrie originale billede.
der er kun en lille forskel mellem implementeringen af denoising autoencoder og den almindelige. Arkitekturen ændrer sig slet ikke, kun fit-funktionen. Vi trænede den almindelige autoencoder som følger:
autoencoder.fit(x_train, x_train)
denoising autoencoder er uddannet som:
autoencoder.fit(x_train_noisy, x_train)
simpelt er det, alt andet er nøjagtigt det samme. Indgangen til autoencoderen er det støjende billede, og det forventede mål er det originale støjfrie.
visualisering
lad os nu visualisere, om vi er i stand til at gendanne de støjfrie billeder.
det ser godt ud. Den nederste række er autoencoder output. Vi kan gøre det bedre ved at bruge mere kompleks autoencoder arkitektur, såsom convolutional autoencoders. Vi vil dække konvolutter i den kommende artikel.
sparsomme Autoencodere
vi introducerede to måder at tvinge autoencoderen til at lære nyttige funktioner: at holde kodestørrelsen lille og denoising autoencodere. Den tredje metode bruger regulering. Vi kan regulere autoencoderen ved hjælp af en sparsity-begrænsning, således at kun en brøkdel af knudepunkterne ville have ikke-nulværdier, kaldet aktive noder.
især tilføjer vi en strafperiode til tabsfunktionen, således at kun en brøkdel af knudepunkterne bliver aktive. Dette tvinger autoencoderen til at repræsentere hvert input som en kombination af et lille antal noder og kræver, at den opdager interessant struktur i dataene. Denne metode fungerer, selvom kodestørrelsen er stor, da kun en lille delmængde af knudepunkterne til enhver tid vil være aktive.
det er ret nemt at gøre dette i Keras med kun en parameter. Som en påmindelse oprettede vi tidligere kodelaget som følger:
code = Dense(code_size, activation='relu')(input_img)
vi tilføjer nu en anden parameter kaldet activity_regularisator ved at specificere reguleringsstyrken. Dette er typisk en værdi i området . Her valgte vi 10e-6.
code = Dense(code_size, activation='relu', activity_regularizer=l1(10e-6))(input_img)
det endelige tab af den sparsomme model er 0,01 højere end standardmodellen på grund af den tilføjede reguleringstid.
lad os demonstrere, at kodningerne genereret af den regulerede model faktisk er sparsomme. Hvis vi ser på histogrammet af kodeværdier for billederne i testsættet, er fordelingen som følger:
gennemsnittet for standardmodellen er 6,6, men for den regulerede model er det 0,8, en ret stor reduktion. Vi kan se, at en stor del af kodeværdier i den regulerede model faktisk er 0, hvilket er det, vi ønskede. Variansen af den regulerede model er også ret lav.
Use Cases
nu kan vi stille følgende spørgsmål. Hvor gode er autoencoders til at komprimere input? Og er de en almindeligt anvendt dyb læringsteknik?
desværre er autoencodere ikke meget udbredt i virkelige applikationer. Som en komprimeringsmetode fungerer de ikke bedre end dens alternativer, for eksempel gør jpeg fotokomprimering bedre end en autoencoder. Og det faktum, at autoencodere er dataspecifikke, gør dem upraktiske som en generel teknik. De har dog 3 almindelige brugssager:
- Data denoising: vi har set et eksempel på dette på billeder.
- Dimensionalitetsreduktion: visualisering af højdimensionelle data er udfordrende. t-SNE er den mest anvendte metode, men kæmper med et stort antal dimensioner (typisk over 32). Så autoencodere bruges som et forbehandlingstrin for at reducere dimensionaliteten, og denne komprimerede repræsentation bruges af t-SNE til at visualisere dataene i 2D-rum. For gode artikler om t-SNE henvises her og her.
- Variational Autoencoders (VAE): dette er et mere moderne og komplekst brugstilfælde af autoencoders, og vi vil dække dem i en anden artikel. Men som et hurtigt resume lærer VAE parametrene for sandsynlighedsfordelingen, der modellerer inputdataene, i stedet for at lære en vilkårlig funktion i tilfælde af vanilla autoencoders. Ved prøveudtagningspunkter fra denne distribution kan vi også bruge VAE som en generativ model. Her er en god reference.
konklusion
Autoencoders er en meget nyttig dimensionalitetsreduktionsteknik. De er meget populære som undervisningsmateriale i indledende dybe læringskurser, sandsynligvis på grund af deres enkelhed. I denne artikel dækkede vi dem i detaljer, og jeg håber du nød det.
hele koden til denne artikel er tilgængelig her, hvis du selv vil hacke den. Hvis du har nogen feedback velkommen til at nå ud til mig på kvidre.