{"id":102,"date":"2017-05-12T11:48:22","date_gmt":"2017-05-12T11:48:22","guid":{"rendered":"http:\/\/liipetti.net\/retkia\/?p=102"},"modified":"2017-05-12T14:19:13","modified_gmt":"2017-05-12T14:19:13","slug":"neuroverkot-kaytannon-johdanto-3","status":"publish","type":"post","link":"https:\/\/liipetti.net\/retkia\/neuroverkot-kaytannon-johdanto-3\/","title":{"rendered":"Neuroverkot -k\u00e4yt\u00e4nn\u00f6n johdanto 3"},"content":{"rendered":"<p>Edellisess\u00e4 osassa n\u00e4imme kuinka yksitt\u00e4inen neuroverkon solu k\u00e4sittelee numeerista tietoa ja kuinka n\u00e4ist\u00e4 soluista voidaan koota kerroksia ja n\u00e4ist\u00e4 monikerroksisia neuroverkkoja. Katsotaan seuraavaksi miten neuroverkolla voidaan k\u00e4sitell\u00e4 kuvia.<\/p>\n<p>Mustavalkoinen kuva voidaan esitt\u00e4\u00e4 kaksiulotteisena taulukkona, jossa kuvat pikselit on esitetty numeerisesti, esim. lukuina nollasta yhteen, jossa nolla vastaa mustaa ja yksi kirkkaan valkoista. Toinen yleisesti k\u00e4ytetty esitystapa on tallettaa pikselit kokonaislukuina 0..255, t\u00e4ss\u00e4kin nolla vastaa mustaa.<\/p>\n<p>Otetaan sitten keinotekoinen neurosolu, johon sy\u00f6tet\u00e4\u00e4n yksi pikseli ja kaikki sen viereiset kahdeksan pikseli\u00e4.<\/p>\n<p><img loading=\"lazy\" decoding=\"async\" class=\"alignnone size-medium wp-image-104\" src=\"https:\/\/liipetti.net\/retkia\/wp-content\/uploads\/2017\/05\/imgconvr-300x233.png\" alt=\"imgconvr\" width=\"300\" height=\"233\" srcset=\"https:\/\/liipetti.net\/retkia\/wp-content\/uploads\/2017\/05\/imgconvr-300x233.png 300w, https:\/\/liipetti.net\/retkia\/wp-content\/uploads\/2017\/05\/imgconvr-768x597.png 768w, https:\/\/liipetti.net\/retkia\/wp-content\/uploads\/2017\/05\/imgconvr-1024x795.png 1024w, https:\/\/liipetti.net\/retkia\/wp-content\/uploads\/2017\/05\/imgconvr-193x150.png 193w, https:\/\/liipetti.net\/retkia\/wp-content\/uploads\/2017\/05\/imgconvr-150x117.png 150w, https:\/\/liipetti.net\/retkia\/wp-content\/uploads\/2017\/05\/imgconvr.png 1201w\" sizes=\"auto, (max-width: 300px) 100vw, 300px\" \/><\/p>\n<p>T\u00e4llainen solu voidaan\u00a0opettaa havaitsemaan yksinkertaisia vierekk\u00e4isten pisteiden muodostamia kuvioita.\u00a0Jos viel\u00e4 ajattellaan ett\u00e4 solua liu&#8217;utetaan kuvan p\u00e4\u00e4ll\u00e4, voidaan n\u00e4it\u00e4 havaintoja tehd\u00e4 koko kuvan alueella. Matemaattisesti puhutaan konvoluutiosta, jota on ennen neuroverkkojakin sovellettu kuvank\u00e4sittelyss\u00e4 esim. kuvan sumentamiseen, tarkentamiseen ja reunojen havaitsemiseen. Perinteisess\u00e4 konvoluutiossa liikkuvan ikkunan painokertoimet on asetettu ennalta halutun k\u00e4ytt\u00f6tarkoituksen mukaan, neuroverkossa taas solut oppivat itse painokertoimet koulutusaineiston perusteella.<\/p>\n<p>T\u00e4mm\u00f6ist\u00e4 kaksiulotteista solua ja varsinkin sen painokertoimia kutsutaan\u00a0<em>kerneliksi<\/em>. Kerneli\u00e4 ei kuitenkaan k\u00e4yt\u00e4nn\u00f6ss\u00e4 liu&#8217;uteta kuvan p\u00e4\u00e4ll\u00e4, vaan solua monistetaan tarvittava m\u00e4\u00e4r\u00e4 niin ett\u00e4 lopputulos on sama kuin jos kernel liukuisi kuvan p\u00e4\u00e4ll\u00e4. Muistia kuluu enemm\u00e4n, mutta toiminta saadaan nopeammaksi kun voidaan hy\u00f6dynt\u00e4\u00e4 rinnakkaista laskentaa.<\/p>\n<p>Yll\u00e4olevassa kuvassa on 3&#215;3 kernel, mutta muunkinkokoisia kerneleit\u00e4 k\u00e4ytet\u00e4\u00e4n, yleens\u00e4 ei kuitenkaan kovin isoja. Voisi toki ajatella, ett\u00e4 isompi kernel pystyy tunnistamaan kuvasta mutkikkaampia piirteit\u00e4, mutta k\u00e4yt\u00e4nn\u00f6ss\u00e4 toimii paljon paremmin ett\u00e4 k\u00e4ytet\u00e4\u00e4n pient\u00e4 kerneli\u00e4, 3&#215;3 tai 4&#215;4, ja kootaan n\u00e4ist\u00e4 konvoluutiokerroksia joita sitten kasataan useita p\u00e4\u00e4llekk\u00e4in. T\u00e4llaisessa verkossa alemmat kerrokset havaitsevat yksinkertaisia piirteit\u00e4, esim. v\u00e4rej\u00e4 ja reunoja, ylemm\u00e4t sitten viivoja ja k\u00e4yri\u00e4, edelleen ylemm\u00e4t erilaisia muotoja ja hahmoja, kunnes pystyt\u00e4\u00e4n tunnistamaan kuvista olentoja ja esineit\u00e4. Kukin kerros sis\u00e4lt\u00e4\u00e4 viel\u00e4 lukuisia rinnakkaisia osakerroksia (channels, feature maps) joista kukin reagoi eri piirteisiin.<\/p>\n<p>T\u00e4ss\u00e4 olen tutkinut kahden eri kerroksen reagointia valokuvaan. Vasemmanpuolinen osakerros n\u00e4ytt\u00e4\u00e4 reagoivan vaakaviivoihin, oikeapuoleinen johonkin mutkikkaampaan kokonaisuuteen.<\/p>\n<p><img loading=\"lazy\" decoding=\"async\" class=\"alignnone\" src=\"http:\/\/liipetti.net\/erratic\/wp-content\/uploads\/2016\/05\/7df7b6fc-1520-11e6-9df6-1c15f0652f18.png\" alt=\"\" width=\"295\" height=\"221\" \/>\u00a0\u00a0<img loading=\"lazy\" decoding=\"async\" class=\"alignnone\" src=\"http:\/\/liipetti.net\/erratic\/wp-content\/uploads\/2016\/05\/583d4f74-1522-11e6-90ed-85a6bd4aa812.png\" alt=\"\" width=\"295\" height=\"221\" \/><\/p>\n<p>T\u00e4ss\u00e4 sitten kaavakuva verkosta, jolla pystyt\u00e4\u00e4n tunnistamaan ja luokittelemaan kuvan sis\u00e4lt\u00f6\u00e4.<\/p>\n<p><img loading=\"lazy\" decoding=\"async\" class=\"alignnone\" src=\"http:\/\/liipetti.net\/erratic\/wp-content\/uploads\/2016\/05\/convnet2.png\" alt=\"\" width=\"3463\" height=\"1237\" \/><\/p>\n<p>Vasemmalla on kuva josta l\u00e4hdet\u00e4\u00e4n liikkeelle, v\u00e4rikuvan tapauksessa esim. 3 v\u00e4ri\u00e4 x \u00a0256 x 256 matriisi. T\u00e4st\u00e4 menn\u00e4\u00e4n konvoluutiokerroksella muotoon vaikkapa 64 osakerrosta x 256 x 256, t\u00e4m\u00e4n per\u00e4ss\u00e4 viel\u00e4 yksi tai useampi konvoluutiokerros samoilla mitoilla. Sitten pudotetaan kokoa puoleen ja samalla lis\u00e4t\u00e4\u00e4n osakerrosten m\u00e4\u00e4r\u00e4\u00e4: 128 osakerrosta x 128 x 128 ja jatketaan. Ja taas koko puoleen mutta osakerroksia lis\u00e4\u00e4: 256 osakerrosta x 64 x 64. Sit\u00e4 mukaan kuin abstraktiotaso kasvaa, havaitaan isompia kokonaisuuksia ja siksi tilallisen tarkkuuden tarve v\u00e4henee: on t\u00e4rke\u00e4mp\u00e4\u00e4 ett\u00e4 kukin solu kattaa suuremman osan kuvasta.<\/p>\n<p>Viimeisen (sinisen) konvoluutiokerroksen j\u00e4lkeen muutetaan kaksiulotteinen l\u00e4ht\u00f6 yksiulotteiseksi vektoriksi ja sy\u00f6tet\u00e4\u00e4n se muutaman tavallisen neuroverkkokerroksen l\u00e4pi jotta lopulta saadaan arvio siit\u00e4 mit\u00e4 verkon mukaan\u00a0n\u00e4kyy. N\u00e4m\u00e4 kerrokset k\u00e4yt\u00e4nn\u00f6ss\u00e4 tekev\u00e4t p\u00e4\u00e4telmi\u00e4 alempien kerrosten havaitsemien piirteiden perusteella, nyt ei siis en\u00e4\u00e4 k\u00e4sitell\u00e4 kuvaa vaan tehd\u00e4\u00e4n loogisia tai matemaattisia johtop\u00e4\u00e4t\u00f6ksi\u00e4. Oikeapuoleisimman verkon l\u00e4hd\u00f6st\u00e4 saadaan esimerkiksi 1000 todenn\u00e4k\u00f6isyytt\u00e4, yksi kutakin havaittavissa olevaa kohdetta kohti.<\/p>\n<p>Kokeillaan sitten k\u00e4yt\u00e4nn\u00f6ss\u00e4. Nyt tarvitaan edelleen Torch, joten jos et asentanut sit\u00e4 viime kerralla, niin se pit\u00e4\u00e4 asentaa ensimm\u00e4isen\u00e4. Torchin lis\u00e4ksi tarvitaan nn, joka toteuttaa neuroverkkotoiminnallisuuden. Se asennetaan luarocks-komennolla, joka tulee Torchin asennuksen mukana: kirjoita komentorivill\u00e4 &#8221;luarocks install nn&#8221;. Tarvitset my\u00f6s muita paketteja: &#8221;luarocks install image&#8221; kuvien lukemiseksi ohjelmaan, ja &#8221;luarocks install loadcaffe&#8221; valmiiksi koulutetun neuroverkon lataamiseksi ohjelmaan.<\/p>\n<p>Ohjelman, neuroverkon ja muut tarvittavat tiedostot saat n\u00e4ill\u00e4 komennoilla:<\/p>\n<p style=\"font-size: 80%;\"># haetaan ohjelma<br \/>\nwget liipetti.net\/htoyryla\/share\/predict.lua<br \/>\n# haetaan valmiiksi koulutettu paikkoja ymm\u00e4rt\u00e4v\u00e4 neuroverkko<br \/>\nwget http:\/\/places2.csail.mit.edu\/models_places365\/vgg16_places365.caffemodel<br \/>\nwget https:\/\/raw.githubusercontent.com\/metalbubble\/places365\/master\/deploy_vgg16_places365.prototxt<br \/>\n# haetaan lista jolla tulokset muutetaan selv\u00e4kielisiksi<br \/>\nwget https:\/\/raw.githubusercontent.com\/metalbubble\/places365\/master\/categories_places365.txt<br \/>\n# haetaan kaksi esimerkkikuvaa wget liipetti.net\/htoyryla\/share\/viktualien.jpg<br \/>\nwget https:\/\/github.com\/jcjohnson\/neural-style\/raw\/master\/examples\/inputs\/tubingen.jpg<\/p>\n<p>Nyt, jos kaikki meni oikein, voit kokeilla komentoa:<\/p>\n<p>th predict.lua viktualien.jpg<\/p>\n<p>Ohjelma tulostaa ensin tietoa neuroverkon lataamisesta ja rakenteesta, mutta lopuksi saadaan tulokset:<\/p>\n<p>0.36294424533844 \/b\/beer_hall 54<br \/>\n0.20446613430977 \/c\/cafeteria 75<br \/>\n0.13476124405861 \/f\/food_court 148<br \/>\n0.063512079417706 \/p\/pub\/indoor 274<\/p>\n<p>Nyt voit kokeilla kuvalla tubingen.jpg ja sen j\u00e4lkeen omilla kuvillasi. Voit my\u00f6s tutustua itse ohjelmakoodiin, se ei ole mitenk\u00e4\u00e4n mutkikas.<\/p>\n<pre style=\"font-size: 88%;\">require 'torch'\r\nrequire 'nn'\r\nrequire 'image'\r\nrequire 'loadcaffe' \r\n\r\n-- kuvan esiprosessointi\r\n-- mm. v\u00e4hennet\u00e4\u00e4n keskiarvo jotta saadaan pikseliarvot samalle alueelle kuin koulutettaessa \r\nfunction preprocess(img)\r\n   local mean_pixel = torch.DoubleTensor({103.939, 116.779, 123.68})\r\n   local perm = torch.LongTensor{3, 2, 1}\r\n   img = img:index(1, perm):mul(256.0)\r\n   mean_pixel = mean_pixel:view(3, 1, 1):expandAs(img)\r\n   img:add(-1, mean_pixel)\r\n   return img\r\nend\r\n\r\n-- haetaan kategorioiden nimet\r\n-- jotta tulokset voidaan n\u00e4ytt\u00e4\u00e4 selv\u00e4kielisen\u00e4\r\nf = io.open(\"categories_places365.txt\")\r\nlabels = {}\r\nfor line in f:lines() do\r\n  table.insert(labels, line)\r\nend\r\n\r\nlocal imgf = \"tubingen.jpg\"\r\nif arg[1] then\r\n  imgf = arg[1]\r\nend\r\n\r\n-- ladataan kuva muistiin ja skaalataan siihen kokoon jolla verkko on koulutettu\r\ncontent_image = image.load(imgf, 3)\r\ncontent_image = image.scale(content_image, 224, 224, 'bilinear')\r\ncontent_image_caffe = preprocess(content_image):float()\r\nimg = content_image_caffe:clone():float()\r\n\r\n-- ladataan valmis neuroverkko muistiin \r\ncnn = loadcaffe.load(\"deploy_vgg16_places365.prototxt\", \"vgg16_places365.caffemodel\", \"nn\"):float()\r\n\r\n-- lis\u00e4t\u00e4\u00e4n verkon per\u00e4\u00e4n SoftMax-kerros \r\nprob = nn.SoftMax():float()\r\ncnn:add(prob)\r\n\r\n-- sitten vain kuva sis\u00e4\u00e4n verkkoon ja katsotaan mit\u00e4 saadaan ulos\r\ny = cnn:forward(img)\r\n\r\n-- k\u00e4yd\u00e4\u00e4n tulokset yksitellen l\u00e4pi\r\n-- ja tulostetaan luokat joiden todenn\u00e4k\u00f6isyys ylitt\u00e4\u00e4 0.05\r\nfor i=1, 365 do\r\n  if y[i] &gt; 0.05 then\r\n    print(y[i], labels[i])\r\n  end\r\nend \r\n\r\n<\/pre>\n<p>&nbsp;<\/p>\n","protected":false},"excerpt":{"rendered":"<p>Edellisess\u00e4 osassa n\u00e4imme kuinka yksitt\u00e4inen neuroverkon solu k\u00e4sittelee numeerista tietoa ja kuinka n\u00e4ist\u00e4 soluista voidaan koota kerroksia ja n\u00e4ist\u00e4 monikerroksisia neuroverkkoja. Katsotaan seuraavaksi miten neuroverkolla voidaan k\u00e4sitell\u00e4 kuvia. Mustavalkoinen kuva voidaan esitt\u00e4\u00e4 kaksiulotteisena taulukkona, jossa kuvat pikselit on esitetty numeerisesti, esim. lukuina nollasta yhteen, jossa nolla vastaa mustaa ja yksi\u2026<\/p>\n<p class=\"continue-reading-button\"> <a class=\"continue-reading-link\" href=\"https:\/\/liipetti.net\/retkia\/neuroverkot-kaytannon-johdanto-3\/\">Continue reading<i class=\"crycon-right-dir\"><\/i><\/a><\/p>\n","protected":false},"author":1,"featured_media":0,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[4,2],"tags":[],"class_list":["post-102","post","type-post","status-publish","format-standard","hentry","category-kuvankasittely","category-neuroverkot"],"_links":{"self":[{"href":"https:\/\/liipetti.net\/retkia\/wp-json\/wp\/v2\/posts\/102","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/liipetti.net\/retkia\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/liipetti.net\/retkia\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/liipetti.net\/retkia\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/liipetti.net\/retkia\/wp-json\/wp\/v2\/comments?post=102"}],"version-history":[{"count":16,"href":"https:\/\/liipetti.net\/retkia\/wp-json\/wp\/v2\/posts\/102\/revisions"}],"predecessor-version":[{"id":120,"href":"https:\/\/liipetti.net\/retkia\/wp-json\/wp\/v2\/posts\/102\/revisions\/120"}],"wp:attachment":[{"href":"https:\/\/liipetti.net\/retkia\/wp-json\/wp\/v2\/media?parent=102"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/liipetti.net\/retkia\/wp-json\/wp\/v2\/categories?post=102"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/liipetti.net\/retkia\/wp-json\/wp\/v2\/tags?post=102"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}