Flere eksperimenter med generative modeller

En av fordelene med å være en halvstudert røver innen maskinlæring, er at når man kommer over en forskningsartikkel på arxiv som man for en gangs skyld kan følge sånn noenlunde, så blir man behagelig overivrig. Man får den følelsen av at dette er helt fantastisk, selv når resten av maskinlæringsmiljøet ikke ser ut til å dele din begeistring.

En artikkel som inspirerte meg på den måten, var denne:  How (not) to Train your Generative Model av Ferenc Huszár (http://arxiv.org/abs/1511.05101). Jeg skal prøve å forklare.

Når jeg trener en generativ modell, slik som den jeg trente for å lage vakre blomsterbilder, er det egentlig en sannsynlighetsfordeling jeg er ute etter. (Dette er selvfølgelig for maskinlæringsfolk, jeg har også forstått det etterhvert – men det er ikke helt selvinnlysende heller.)

Det jeg vil, er å fange opp variasjonen i treningsmaterialet. Ideelt sett skulle det være slik at modellen min kunne generere alle mulige blomsterbilder, og ikke noe bilde modellen min kunne generere var noe annet enn en blomst.

Fordelingen som kommer ut av min modell, vil ikke være perfekt. Det vil si, det vil være en “avstand” mellom den ideelle sannsynlighetsfordelingen, og den jeg faktisk har. Jeg putter avstand i gåseøyne, for det merkelige med sannsynlighetsfordelinger, er at man kan ikke egentlig kalle det en avstand. Avstander skal helst følge regelen at att og fram er like langt, men slik er det ikke med sannsynlighetsfordelinger! Det tekniske order for noe som ligner litt på en avstand, men bryter den regelen, er en divergens. I sannsynlighetsregning måler man avstanden mellom to fordelinger med noe som kalles Kullback-Leibler-divergens, eller KL-divergens.

La oss kalle fordelingen av bilder som virkeligheten lager for P. La oss kalle distribusjonen av bilder min modell kan lage for Q. Hva vil det si at det er en stor “avstand” fra P til Q? Det betyr at virkeligheten ganske ofte kan produsere bilder som det er usannsynlig at min modell vil produsere. Og hva betyr en stor avstand andre veien? At noen bilder min modell produserer, ikke er særlig sannsynlig at skal finnes i virkeligheten.

Når man lager en generativ modell, hva er verst? At vi ikke kan generere alle mulige blomster, eller at vi noen ganger lager skrot som ikke ser ut som blomster i det hele tatt? Svaret virker åpenbart. Vi klarer aldri å gjenskape all naturlig variasjon uansett, og det er blomster vi vil ha, ikke skrot. Vi vil minimere avstander fra virkeligheten til vår modell, ikke motsatt, eller hva?

Det er det Ferenc Huszár påstår, og det virker rimelig. Men det er et problem (som han også forklarer): Å trene en generator til å minimere avstanden fra modellen til virkeligheten er vanskelig nok. Andre veien er enda vanskeligere. Det virker umulig å ta sikte på dette målet direkte.

Men det er her GAN kommer inn i bildet. De virker da som de gjør det ganske bra, ikke sant? Hvordan kan det ha seg? Ferenc Huszár hevder (og jeg kan ikke følge all matematikken, men jeg tror han vet hva han gjør!) at et GAN sikter på noe midt i mellom divergensen fra P til Q og fra Q til P. Og han mener at det bør gå an å forskyve det i den ene eller andre retningen, ved ganske enkelt å justere antallet treningseksempler av hver type.

For å repetere fra forrige post: et GAN har to deler, en generator som lager kunstige bilder, og en diskriminator som prøver å se forskjell på ekte og kunstige. Kan det være så enkelt? Kan vi få en mer realistisk generator ganske enkelt ved å gi diskriminatoren flere eksempler på ekte bilder enn kunstige?

Ferenc Huszár advarer om at “denne endringen kan ha negative konsekvenser for algoritmens konvergensegenskaper”. Med enkle ord, vi vet ikke hvor bra det virker i praksis. Å få et GAN til å konvergere kan være utfordrende nok i første omgang, og denne endringen gjør det nok ikke enklere.

Jeg så ham på reddit, og spurte hvorfor han ikke bare hadde prøvd det. (Det er en av de flotte tingene med maskinlæring: man møter på masse veldig dyktige folk, som man kan spørre! Jeg prøver å bruke denne muligheten med ansvar, så vi ikke skremmer dem vekk! Men dette spørsmålet virket uskyldig nok.)

Han sa at han planla å prøve noen av ideene i praksis, men at han stort sett ikke kunne rettferdiggjøre å bruke mye tid på det. Og så, sa han, er det ofte slik at noen andre allerede har gjort noe lignende.

Men jeg er en halvstudert røver, utrustet med Soumith Chintalas DCGAN-kode, og jeg har nok av tid (samt et uansvarlig dyrt grafikkort). Chintalas kode virket som om den hadde få problemer med å konvergere i utgangspunktet, så den tåler sikkert litt utfordringer også. La oss prøve!

For å ha et sammenligningsgrunnlag, brukte jeg samme blomsterdatasett som forrige gang. Det første jeg prøvde var å doble antallet ekte bilder i hver treningsbatch. Etter 250 epoker, ble det slik:

cyjzyiiwmaemsjc

Vel, det ser ikke så verst ut, men ikke så imponerende heller. Var 250 epoker virkelig ikke nok? Uansett må vi prøve andre veien, med dobbelt så mange kunstige bilder. Enda et par timer senere, ble det slik:
cyk0eojwmaapcgw

Vent litt, dette ser da bedre ut? Det skulle vel være verre? Gjør jeg noe galt her?

Her finner jeg feil nummer en. Funksjonen som skal evaluere hvor bra diskriminatoren gjør det, viser seg å dele på antall eksempler. Bidraget fra positive og negative eksempler var fortsatt 50-50, det var bare at i første eksperiment brukte den færre eksempler for å estimere hvordan ekte bilder skulle se ut, og i det andre brukte den flere bilder for å få et bedre estimat av hvordan kunstige bilder så ut. Ikke rart den gjorde det bedre

Jeg tok et eksperiment til. Denne gangen delte jeg ganske enkelt bidraget fra negative eksempler med to:

cynoatoueaa-bie

Nå begynner det å ligne på noe! Det virker som den lager mer plausible og interessante bilder, gjør det ikke? Denne modellen virker for meg som den beste så langt, selv bedre enn den som trenet fire ganger så lenge.

Men så tenkte jeg: la oss se hvor langt vi kan presse det. Jeg kan jo egentlig trene på så mange kunstige bilder jeg vil – det gir bare et bedre estimat på hvordan kunstige bilder ser ut. Bidraget fra dem kan jeg skalere opp og ned uavhengig av hvor mange det er.

Så jeg kjørte et siste eksperiment, hvor jeg firedoblet antallet kunstige bilder, men skalerte ned bidraget fra dem til en åttendedel i forhold til de ekte. Den tok veldig lang tid å trene. I det jeg gikk til sengs, var jeg litt bekymret, for det så ut som om bildene gikk frem og tilbake i kvalitet en god del, uten å bli så mye bedre i det lange løp.

Når jeg tenkte over det etterpå, så var det antagelig ikke helt harmløst å legge til masse kunstige bilder. En ting var at det forlenget treningstiden kraftig, men jeg glemte også at generatoren bare trener på kunstige bilder. Med dette oppsettet, ble den antagelig litt for sterk, så diskriminatoren ikke klarte å holde følge særlig bra. Kanskje det var grunnen til svingningene i kvalitet også. Den sluttet på en generasjon der ting så noenlunde OK ut:

czcmtjnwaaaadkp

Men det er fortsatt ikke bedre enn den forrige.

Advertisements

Kunstige blomster

 

Soumith Chintalas DCGAN-kode er om mulig enda enklere å installere enn char-rnn: en trenger bare torch, nn (luarocks install nn) og display (luarocks install display). For å trene nettene trenger en som vanlig et kraftig nvidia-kort, men for å generere bildene et trenet nett har lært å lage, kreves det ikke.

 

Jeg måtte gjøre noen endringer i koden for å få det til å virke. Under trening av modellen, blir kopier av modellen lagret med jevne mellomrom, som i char-rnn – men jeg fant ut at denne lagringen forårsaket at modellen sluttet å trene. Siden jeg ikke så øyeblikkelig hvordan denne feilen kunne oppstå, løste jeg like godt problemet ved å flytte lagringen til etter at treningen er fullført. Litt kjedelig å ikke kunne avbryte treningen underveis, men det var raskeste og enkleste løsning.

 

Som datasett benyttet jeg Oxford 102-category flower dataset. Merkelappene med artsinformasjon brukte jeg ikke. Det var bare å lage en katalog, kopiere inn de ca. 9000 blomsterbildene, og sette i gang treningen.

 

Dette er et ganske lite datasett med blomster – ideelt sett skulle det vært hundre ganger så mange. Når man har få treningseksempler i maskinlæring, er det en fare for overfitting – at systemet lærer seg treningseksemplene utenat, så å si. Som for mennesker, er det av tvilsom verdi å lære seg ting utenat, det kan gå på bekostning av forståelsen og evnen til å generalisere. I en DCGAN, er faren først og fremst at diskriminatoren lærer seg treningseksemplene utenat. For å unngå det, prøvde jeg å gi generatoren en liten fordel: den har dobbelt så mange parametre som diskriminatoren, den kan med andre ord lage seg en betydelig mer komplisert modell.

 

Etter kanskje ti minutters trening, lagde den slike blomster:

 

Ikke verst! Men hva skjer om jeg lar den stå over natten? Da blir det vel overfitting? Men hvordan ser overfitting egentlig ut i en DCGAN? Og jeg tenker: modellen er bare 40 megabyte, mye mindre enn treningsdatasettet på 348 megabyte. Og treningssettet er JPEG-komprimert også… det virker lite sannsynlig at diskriminatoren skal lære seg bildene utenat. La oss prøve!

 

Resultatet ble slik:

 

 

Dette er altså tilfeldige punkter i “blomsterrommet” som generatoren har utviklet. Og som man ser: det ser mer eller mindre ut som blomster alt sammen!

 

Chintalas kode har en stilig funksjon der man istedet for tilfeldige punkter i vektorrommet, får punkter som ligger på en linje:

 


At det skjer en gradvis overgang her, og at bildene inn i mellom også ser ut som blomster, tyder på at vi ikke har overtrent alt for mye.

 

Modellen jeg trente har jeg lagt ut på google drive.

Det er ganske lettvint å generere bilder med den, selv uten en kraftig GPU tar det bare noen sekunder. Bare last ned og prøv, om du tør!

DCGAN

Dype nevrale nettverk er blitt imponerende gode på klassifisering. Når det gjelder å klassifisere et bilde i en av mange mulige kategorier fastsatt på forhånd, er de beste programmene nå på linje med mennesker, om ikke bedre.

Men det betyr ikke akkurat at programmet “forstår” hva et fly, en fjellrev eller en border-collie ser ut som. Selv om det er svært bra til å skille dem, kan en ikke uten videre bruke nettverket til å tegne en border-collie, for eksempel. Selv om gjenkjenning og generering er nært beslektet, er generering grunnleggende vanskeligere.

I helgen eksperimenterte jeg med en rykende fersk teknikk for å angripe problemet med generering: Deep Convolutional Generative Adversarial Nets, eller DCGAN.

For å forklare hvordan den virker, tenk deg at du skal tegne personer fra fantasien, med målet å lure folk til å tro at det er portretter av tilfeldige mennesker. Da må man passe på å ikke falle i beregnelige mønstre. Om en alltid tegner folk med stor nese, eller alltid menn, blir det lett å gjennomskue. Så kanskje du lager deg en liste:

Kjønn, 0 for mann, 1 for kvinne (og kanskje noen tall inni mellom også, hvorfor ikke?)
Alder, fra 0 (nyfødt) til 1 (100+ år)
Hårlengde, fra 0 (glattbarbert) til 1 (hår til livet)
Nesestørrelse, fra 0 (ingen nese) til 1 (nesen fyller hele ansiktet)

osv. osv. Du vil at alle disse skal variere akkurat slik de varierer i gruppen du liksom lager “portretter” av.

En autoenkoder er en type nevralt nettverk som prøver å finne en slik liste. Du gir den et eksempel (dvs. et bilde), og den forsøker å koke det ned, forenkle det til en vektor, på en slik måte at mest mulig av bildet kan rekonstrueres fra vektoren.

Hvis noen av mine lesere har lært om lineær algebra på universitet/høyskole, og husker egenvektorer og egenverdier: Det er en lineær tilnærming til det samme problemet. Autoenkodere er laget for å gjøre en god jobb på problemer der

* man har flere dimensjoner
* man har veldig mye data (å finne egenvektorer for store matriser blir fort uhåndterlig)
* Mønstrene ikke så lett lar seg uttrykke som en lineær kombinasjon av vektorer

Når man har en autoenkoder, har man jo en slags generator: man kan bare gi den en tilfeldig vektor (nesestørrelse 6! mann! alder 24! hårlengde 2!) og be dem “rekonstruere” bildet som tilsvarer det.

Desverre lager dette ikke særlig gode bilder med en vanlig autoenkoder. Autoenkoderen prøver å optimalisere rekonstruksjonen, men det er ikke dermed sagt at den klarer å utnytte hele vektorrommet den har til rådighet til å representere den. Det er heller ikke sikkert at elementene i vektoren svarer til noe særlig meningsfullt (neselenge osv.)

Det er her DCGAN kommer inn. I DCGAN er det to nevrale nettverk som konkurrerer: En diskriminator som prøver å skille ekte bilder fra genererte, og en autoenkoder som generator. Istedet for å optimalisere rekonstruksjon av eksempelbilder, får generatoren “poeng” for å lure diskriminatoren. Dette lar begge nettverkene lære i takt. Først lærer diskriminatoren de groveste tingene som skiller et ekte bilde fra støy, men så lærer generatoren det også – og så er kappløpet i gang.

Du kan tenke deg at du som portrettmaler begynner med en veldig dårlig kritiker, som knapt kan se forskjell på en strektegning og et ekte portrett. Men i tråd med at du blir flinkere, blir han flinkere til å kritisere også. Høres det ikke enklere ut å lære på den måten, enn ved å starte med en kritiker som krever 100% perfeksjon fra starten av?

Prinsippet er enkelt og genialt, men det har tatt tid å få det til å virke. Nylig kom det ut en forskningsartikkel fra Alec Radford, Luke Metz og Soumith Chintala (maskinlæringsforskere ansatt av Facebook) der de forklarer noen imponerende resultater – og som vanlig i maskinlæring, la de ut kode på github like etter.

I neste post tenker jeg å forklare litt hva jeg har fått til med denne koden.

Introprosjekt: char-rnn

Andrej Karpathy er en doktorgradsstudent fra Stanford, som er helt i front på det som skjer i forskningen. I tillegg har han et skjeldent talent for formidling. Bloggen hans anbefales sterkt. I denne posten tenker jeg forklare hvordan en installerer char-rnn.

Hva char-rnn gjør rent teknisk, forklarer han best på sin egen blog, med det forutsetter kanskje litt mer kunnskap om emnet enn det jeg har tenkt å anta akkurat nå. Jeg vil bare vise hvor lett det er å komme i gang med denne teknologien, og kjøre sine egne eksempler.

Det første man trenger, er Mac eller Linux. Beklager, Windowsbrukere, men Torch7-rammeverket som char-rnn er basert på fungerer ikke på Windows – i alle fall ikke uten atskillig mer blod, svette og tårer enn det er verd. Slik er det også med en god del andre maskinlæringsverktøy. Det er greiest å bare installere Linux på en egen partisjon, eller i en virtuell maskin, om en er på Windows og vil drive med maskinlæring.

Det andre man helst trenger, er et skjermkort. Aller helst et nyere NVidia-kort. Uten det er det mye som ikke er tilgjengelig av maskinlæringsverktøy, og det som finnes vil gå smertefullt tregt. Men akkurat char-rnn er greiere enn de fleste tilsvarende prosjekter på den måten – her kan man klare seg med et eldre NVidia-kort, et AMD-grafikkort eller bare prosessoren. Og siden det er et ganske enkelt prosjekt, kan man få morsomme resultater selv med bare CPU.

Aller først må vi ha versjonshåndteringssystemet git. En beskrivelse på hvordan en gjør det på Mac finnes her. På Ubuntu er det bare den vanlige

sudo apt-get install git

Så må vi installere Torch7-rammeverket som char-rnn er skrevet i. Det gjør en slik, fra et kommandolinjeskall på Linux eller Mac:

curl -s https://raw.githubusercontent.com/torch/ezinstall/master/install-deps | bash
git clone https://github.com/torch/distro.git ~/torch --recursive
cd ~/torch; ./install.sh

Dette vil forhåpentligvis laste ned og installere alt. En trenger ikke administratorprivilegier.

Med Torch kommer også Torch sitt eget pakkesystem, som nå er blitt et slags pakkesystem for hele programmeringsspråket Torch er skrevet i (Lua). Det heter luarocks. char-rnn trenger et par ting til:

luarocks install nngraph
luarocks install optim
luarocks install nn

Dersom man har et nyere NVidia-skjermkort, bør en i tillegg kjøre disse to:

luarocks install cutorch
luarocks install cunn

Dersom man har et eldre NVidia-kort eller et AMD-kort, kan en istedet kjøre disse:

luarocks install cltorch
luarocks install clnn

Nå er vi klar til å installere selve char-rnn! Det gjør en slik:

git clone https://github.com/karpathy/char-rnn.git

Nå til forklaringen, og selve moroa. Det char-rnn gjør, er å generere tekster, en bokstav av gangen. Den ser på de foregående bokstavene, og basert på tekstmaterialet den er blitt trenet på, spår den hva neste bokstav vil bli. Så skriver det denne bokstaven, og spår på nytt, og på nytt. Selv om den bare gjetter en bokstav av gangen, kan den med nok trening bli riktig flink til å dikte opp grammatisk korrekte setninger – gjerne med stor underholdningsverdi. Karpathy har mange artige eksempler på sin blog, men vi vil jo gjerne la char-rnn lære norsk! Så la oss finne en tekst å trene den på.

Jeg gikk til prosjekt Gutenberg, og lastet ned “Markens grøde” og “Sult” av Hamsun. Så klipte jeg av delene som ikke er en del av selve teksten (så som lisensen – men det er lov!) og kombinerte den til en fil med navn “input.txt”. Denne la jeg under katalogen “data” i char-rnn, i en underkatalog jeg hadde opprettet som het “Hamsun”. Så satte jeg i gang treningen med følgende kommando:

th train.lua -data_dir data/hamsun/

Dette er hvis en har et NVidia-kort. Alle innstillinger på standard – det burde fungere bra for et så lite prosjekt. Dersom en ikke har NVidia-kort, kan en heller kjøre

th train.lua -opencl 1 -data_dir data/hamsun/

Nå er treningen i gang! Med jevne mellomrom vil den skrive ut en modellfil til katalogen “cv”. Disse filene vil se noe slikt ut:

lm_lstm_epoch15.67_1.3499.t7

Det er ett tall som vi trenger å følge med på her: det aller siste, som står bak understreken men foran “.t7”. I dette tilfellet 1,3499. Det sier noe om hvor bra modellen er – hvor ofte den klarte å gjette riktig bokstav når den fikk servert en bit Hamsun den ikke hadde sett før. Jo lavere tall, jo bedre. Det er ikke alltid at den siste modellen er best, noen ganger kan modellen bli “overtrent” på akkurat de setningene den har sett, slik at den lærer seg svarene på dem utenat så å si. Da gjetter den ikke bra på setninger den aldri har sett.

Når den har trent ferdig, eller før, kan en generere tekst fra modellen med følgende kommando

th sample.lua cv/[navnet på modellfilen]

Dersom en trenet med -opencl 1, må en gi denne parameteren her også:

th sample.lua -opencl 1 cv/[navnet på modellfilen]

Resultatet bør bli noe slikt:

Jeg blev alt tilktændt, at jeg ikke træder på ret og lagt snød af forbi, den slittige Punkt i Knæl og Bryggenisk Morvet, skulde aldeles om Gjærlighed av Hesten og loded af en halv Livstræn forsom alden, hvad det var det, og Inger blåd forvere. Hun havde det mig ikke to vare.

»Så værre du et Væs, om Der . . . .«

»Å, en Myr som tænkt henrvis ikke!«

»Vil Mommeren, for slyste?« miger jeg, jeg siger i Indskyelighed og stirred og videre og grytted bedt mig om i de na, Politier og Jegn gør forbi! Da jeg kunde hevles gøe at gå nedoper over at lige en fejl Gas af mit Hoved!

»Nej, Såljord?«

»Godt!« sagde han.

Så enkelt kan en lage en modell av Hamsundsk språk! Siden jeg oppdaget char-rnn, har jeg bl.a laget modeller for norske stedsnavn, amerikanske stedsnavn og norske bedriftsnavn fra Brønnøysundregisteret. char-rnn er bare et moroprosjekt, men jeg har hatt mye moro med det!

Om villmenn og introprosjekter

Det er som jeg sa mye spennende som skjer i maskinlæring for tiden. Men først en liten digresjon.

Det er et gammelt sagn fra Setesdal, om en mann som het Harde-Aslak. Han ble visstnok bergtatt da han var bare barnet, og var borte i sju uker. I de ukene vokste han mer enn han hadde gjort i de foregående sju år, og han ble en “utifraa Vaae”, vill og mektig. Eplemøya Songlag har en flott sang om ham, her er den på Spotify og her på Beat. Den anbefales.

Og nå til poenget: Det er en maskinlæringsteknikk som er mye som Harde-Aslak, nemlig såkalte nevrale nettverk. Liten og svakelig i lange tider. Selv da jeg tok Andrew Ng sitt kurs (og det er ikke så lenge siden), så var det bare ett kapittel om nevrale nettverk. Hovedbudskapet var vel mest at de tar lang tid å trene, men de kan gjøre det riktig bra i noen beskjedne områder, og det er noen som mener de har potensiale ut over det.

Og så over natta er den plutselig blitt uregjerlig, mektig, enorm og ikke så rent lite skremmende. Det er en av de spennende tingene.

Den andre tingen som er spennende, er hvor fort ting går. Forskningsartiklene på dette området blir gjerne publisert bare på arxiv, og tilbakemeldingen fra andre forskere skjer lynraskt. Store organisasjoner som Facebook og Google sitter ikke på hemmelighetene sine, de lar forskerne som jobber for dem publisere i et heseblesende tempo.

Den tredje tingen, best av alt, er at man faktisk kan prøve ut det meste av det med en gang. De publiserer nemlig skjelden artikler uten vedlagt kildekode. Med noen få kommandoer, kan en laste det ned og kjøre det på sitt eget system.

For å illustrere hvor lett det er, tenkte jeg at jeg i neste post skulle gå gjennom hvordan en installerer og bruker char-rnn av Andrej Karpathy. (Han forklarer det riktignok temmelig bra på sin egen blog, men litt av poenget med denne bloggen er jo å forklare ting på norsk, så vi tåler litt repetisjon!).

En blogg på norsk om maskinlæring og musikk

Det er det planen at dette skal være.

Mitt navn er Harald Korneliussen. Til daglig jobber jeg som programvareutvikler for et internasjonalt telekomselskap. Jeg vet ikke hvor mye jeg bør si om det, annet enn at jeg ikke jobber med maskinlæring der, og at alt jeg måtte skrive på denne bloggen selvsagt står for egen regning.

Hvorfor dette, hvorfor nå? Vel, innen maskinlæring er jeg en entusiastisk men halvstudert røver. Jeg tok Andrew Ng sitt maskinlæringskurs på Coursera for noen år siden. Som kjent har slike onlinekurs en svært høy frafallsprosent, og jeg er slett ikke noe heroisk unntak, brorparten av onlinekurs jeg har hoppet på de siste årenen har jeg hoppet av igjen. Som regel ganske raskt. Men ikke Ng sitt. Det var såpass engasjerende og såpass bra lagt opp, at jeg fikk gjennomført det. Siden har jeg prøvd å følge hva som skjer på feltet.

Og hva som skjer! De siste årene har det skjedd fantastiske ting. Det er det jeg tenker å skrive om her. Forhåpentligvis kan jeg være nyttig for deg, du som også er norskspråklig og interessert i moderne maskinlæring.

Og så var det musikk, da. Den underliggende årsaken til at jeg skriver, er som sagt interessen for maskinlæring. Men den direkte og utløsende årsaken er begeistring for hva et visst svensk streamingselskap har klart å få til med maskinlæring.

Det minner meg på en annen ting, som jeg har litt dårlig samvittighet for. Ut av det blå ble jeg faktisk tilbudt et digert datasett av lyttevaner fra et noe mindre norsk streamingselskap. Og jeg takket ja, ryddet litt i datasettet i forberedning til å kjøre en standardalgoritme på det – og så glemte jeg hele greia. Det har gått en del måneder nå. Å gjøre noe kult med det datasettet, og beskrive det her, er en av ambisjonene for bloggen.

Velkommen!