Plačiau apie lietuviškų žodžių generatorių
Dar nepradėjus rašyti, jaučiu, kad šis skaitalas bus iš dalies apie viską ir iš dalies apie nieką, bet stengsiuos išlaikyti dirbtinio intelekto tematiką naudodamas šį projektą/programą, kaip pavyzdį. Taip pat iš anksto atsiprašau už savo lietuvių kalbos sugebėjimus. Tiesiog programuotojo darbas reikalauja daug dėmesio skirti anglų kalbai - kodas rašomas anglų kalba, dokumentacija skaitoma taip pat agliška. Negana to, namie medijos šaltinius taip pat žiūriu ir klausau anglų kalba. Todėl iš dalies ir nusprendžiau paleisti šį, kad ir nediduką, projektėlį į pasaulį. Aplink gana daug informacijos ir projektų susijusių su populiariausiomis pasaulio kalbomis, mažesnes paliekant nuošalyje.
Santraukoje minėjau, jog šis projektas parašytas pasitelkiant neuroninius tinklus (Neural Networks), arba dar tiksliau - dirbtinius neuroninius tinklus (Artificial Neural Networks). Neuroniniai tinklai priklauso didesnei - komputerių mokymosi (Machine Learning) - grupei, kuri priklauso dirbtinio intelekto (Artificial Intelligence arba trumpiau - AI) grupei. O jeigu jau pasisuko kalba apie dirbtinį intelektą, tai kaip gi neprisiminti pasaulio užvaldymo problemos ir terminatoriaus...
Kol bijom pasaulio pabaigos dėl AI, net nepastebėjpm, jog pasaulio pabaiga jau atėjo...
Na gerai, gal šiek tiek perdedu, bet tik dėl sąvokų nesusipratimo. Iš esmės dirbtinis intelektas (AI), jau naudojamas mūsų kasdienybėje daug metų. Tarp akademikų ir AI srityje dirbančių žmonių ši sąvoka būtent ir reiškia specifinę dirbtinio intelekto variaciją, implementaciją spręsti konkrečiai problemai. Tai ką eiliniai žmonės vadina dirbtiniu intelektu, tokiu kaip terminatorius, iš tiesų yra dirbtinis bendrasis intelektas (Artificial General Inteligence) arba tiesiog AGI. Tai galima sakyti, jog AI mus jau užvaldė, čia jau pavėlavom bijoti, o AGI dar teks palaukti, nes kol kas nėra žinoma kaip tai pasiekti. Tarp programuotojų yra juokaujama:
"Ką vienas programuotojas gali padaryti per mėnesį, du programuotojai padarys per du mėnesius."
Panašiai yra ir su AI - šiuo metu yra sugalvota daug atskirų specializuotų algoritmų ir programų - veidų atpažinimas, vaizdų klasifikavimas, teksto vertimas, anotavimas, garso sintezavimas, pokalbių robotai (chat bots). Deja, visa tai apjungus vis tiek nesigauna AGI. Nes net ir sudėjus viską ką turime į vieną krūva dar labai daug ko trūksta. AGI teks dar palaukti, bet grįžkime į tai ką galima padaryti ir panaudoti dabar.
Nesiplėsiu apie tai kas šiuo metu yra sukurta ar kuriama, nes pastaruoju metu iš ties daug dėmesio yra skiriama AI ir ypač giliems neuroniniams tinklams (Deep Neutal Networks), bet keletą galimybių gali pažiūrėti čia (autonominių automobilių net neminėsiu :) ):
- Google asistentas
- Stiliaus pritaikymas nuotraukai ar video medžiagai
- Lupų sinchronizavimas pagal kalbą
- Muzikos kūrinių sintezavimas (kurimas)
Iš tiesų net sunku buvo išrinkti sritis ir projektus, kaip pavyzdžius, nes jų labai daug. Kiti mūsų kasdienybėje naudojami įrankiai jau tapę kasdienybe - nuotraukų paieška pagal tekstą Google Photos platformoje, Netflix rekomendacijos, Google paieškos rekomendacijos, judesių perkėlimas ant animacinio veikėjo iPhone telefone ir t.t..
Kol kas neblogai sekėsi kalbėti apie nieką, tad grįžkime prie generatoriaus.
Kur gi problema ir kam išvis reikėjo visą šį keistą žaidimą daryti ?
Eiliniams, nieko bendro su programavimo vargais neturintiems, žmonėms tai gali atrodyti paprasta problema su paprastu sprendimu. Bet taip atrodo todėl, kad eilinis žmogus į problemas žiūri iš žmogaus perspektyvos. Programuotojui tenka į problemas žiūrėti iš kompiuterio perspektyvos. Ne programuotojas atlieka darbą, darbą atlieka kompiuteris. Programuotojas tik užrašo taisykles, kuriomis vadovaudamasis kompiuteris atlieka veiksmus - sprendžia užduotį ar problemą. Žmogui puikiai sekasi atlikti kūrybines užduotis, užduotis kur reikalingas samprotavimas, argumentavimas. Tuo tarpu kompiuteriui puikiai sekasi dirbti su skaičiais.
Pavyzdžiui, norime parašyti programą, kuri duotą skaičių padidina dvejetu. Susitariame, kad x - tai bet koks mūsų sugalvotas skaičius. Tuomet programą, atliekančią šį veiksmą, galime užrašyti taip:
rezultatas = x + 2
Duodami programai bet kokį skaičių, ji visuomet gražins tą patį skaičių tik padidintą dvejetu:
jei x = 2, tai rezultatas = 2 + 2 = 4
jei x = 10, tai rezultatas = 10 + 2 = 12
Daugelį problemų galima suskaidyti į smulkias dalis ir aprašyti jas taisyklėmis. Ir programuotojai tą puikiai įvaldę - imi problemą, skaldai ją į dalis, ir užrašai taisyklėmis.
Dabar pabandom įsivaizduoti kaip reikėtų parašyti taisykles lietuviškų žodžių generatoriui naudojant programavimo būdą kurį čia aptarėme - problemą skaldom į mažesnes, lengvai apčiuopiamas dalis, kurioms galime užrašyti taisykles. Tada tas taisykles apjungiame į visumą - štai ir turime lietuviškų žodžių generatoriaus programą.
- Visų pirma, žinom, jog žodis turi būti sudarytas iš raidžių (tikiuosi, kad visi skaitantys tą žino, nes bus sunku suprasti kas bus parašyta toliau. Nors abejoju, jog iki čia pavyko perskaityt, jei to nežinojai). Lietuviškoje abėcėlėje yra 32 raidės. Jeigu jas bandysim dėlioti bet kaip, gausim ką nors panašaus į:
fsjlakėįęįnhjlk
Kitaip sakant, generatorius bus maždaug "katinas perbėgo per klaviatūra" lygio. Bus greičiau ir paprasčiau įsigyti katiną. Negrynaveislis šiuo atveju net rekomenduojamas, o jei dar turi kokią negalią, tai išvis bus idealus generatorius. Jei sunku įtikint savo antrąją pusę, jog jums reikia katino, tai iš šio skaitalo gali pasiimti puikų argumentą (tinka ir slaptažodžių generavimui).
Katinas tegu toliau miega... o mums norėtųsi patobulinti savo programą (katino tolesniais žingsniais patobulint nepavyks, patikėk, bandžiau). Galima būtų suskirstyti raides į balses ir priebalses, dvibalsius ir kombinuoti juos. Pvz., priebalsiai lietuvių kalboje, retai pasitaiko, kad eina vienas po kito, patobuliname programą tokia taisykle, gauname kažką tokio:
karobūrit
Jau arčiau. Trūksta galūnės... Surašom visas lietuvių kalboje aptinkamas galūnes ir pridedam taisyklę užbaigti žodį su viena iš jų:
karobūritė
Gal ir panašu į lietuvišką žodį, gal ir nelabai. Bet sugeneravus keletą žodžių matytųsi jų mechaniškumas ir panašumas vieno į kitą. Galų gale, tikimybė, jog pavyks sugeneruoti tikrą žodį gana nedidelė. Galima būtų taisykles galvoti toliau ir gal net pavyktų sukurti pakankamai neblogą algoritmą, nes kalba visgi turi sandaros taisykles, bet teks praleisti nemažai laiko mokinantis ir analizuojant jas.
Kaip jau minėjau, kai kurios problemos yra intuityvios žmogui, bet ne kompiuteriui. Kitos problemos yra lengvos kompiuteriui, bet ne žmogui. Kompiuteris puikiai susidoroja su matematika, skaičiavimais, bet jam sunku atpažinti šunį nuotraukoje, nes aprašyti konkrečias taisykles kas yra šuo ir kaip jį rasti nuotraukoje yra labai sunki užduotis. Ilgą laiką matematines ir logines užduotis mes atiduodavom kompiuteriui, o kūrybines problemas pasilikdavom spręsti sau, bet jau yra nemažai pavyzdžių kaip AI puikiai sugeba susidoroti ir su kūrybinėmis užduotimis.
Čia ateina AI ir apverčia viską aukštyn kojomis, tame tarpe ir skaitalo minčių eigą :)... Vietoje to, kad užrašytume taisyklę kaip gauti norimą rezultatą iš pradinių duomenų, kodėl negalim duoti pradinių duomenų su rezultatais ir tegu kompiuteris pats sugalvoja taisykles kaip gauti vieną iš kito. Būtent tai neuroniniai tinklai (ir apskritai visa kompiuterių mokymosi (Machine Learning) algoritmų grupė) įgalina mus padaryti. Darbą su dirbtiniu neuroniniu tinklu galima išskirti į 3 etapus:
- Tinklo modelio sudarymas
- Tinklo apmokymas
- Tinklo naudojimas (spėjimo generavimas)
Turint neuroninio tinklo modelį, jis apmokomas paduodant modeliui pradinių duomenų ir rezultatų poras, tam, kad surasti optimaliausią funkciją tarp jų. Kaip optimaliausią funkciją rasti, gana plati tema su nemažai matematikos, todėl per daug apie tai nesiplėsiu, bet jo esmė: modeliui paduodamas pradinis dėmuo, pavyzdžiui skaičius - 2. Tuomet prašom, kad jis spėtų koks yra rezultatas. Pirmą kartą tinklas spėja bet ką, pvz., 1564. Mes žinom, kad iš tiesų rezultatas turėjo būti 4. Sakom modeliui, kad prašovei per 1560 (1560 = 1564 - 4). Neuroninis tinklas sužinojęs, jog taip baisiai prašovė, gėdingai patyliukais pakoreguoja savo varžtelius, kad kitą kartą spėjimas būtų mažesnis. Tada kartojam tą patį su kitu deriniu: Duodam tinklui 6 ir prašom spėt (patys žinom, jog rezultatas turi būti 8). Modelis, vis dar persigandęs, spėja skaičių 16. Mes šį kartą šiek tiek padrąsinam modelį, bet pasakom kad šį kartą prašovė per 8 (8 = 16 - 8). Ir taip iteracija kartojama, kol tinklas suranda optimaliausią funkciją - šiuo atveju, kol tinklas išmoksta, jog prie pradinio skaičiaus reikia pridėti 2. Ir taip! neuroninį tinklą galima auginti kaip naminį gyvūną, to draudžiančių įstatymų kol kas nėra, tad paskubėkite!
Čia aprašiau tik vieną iš būdų kaip galima mokyti neuroninius tinklus, vadinamą Supervised learning. Šis metodas yra populiariausias būdas mokyti tinklus komercijoje. Jis naudotas iš kuriant šį generatorių, bet jo kokybė priklauso nuo duomenų kiekio kuriuo apmokomas modelis. Kai kurios problemos reikalauja šimtų tūkstančių, milijonų ar net milijardų derinių tam, kad būtų pasiektas tinkamas rezultatas.
Galutinis etapas yra spėjimas. Jei dar neužmigai, tai pastebėjai, jog šis etapas buvo naudojamas ir mokymo metu, bet tada modeliui padarius spėjimą, jis būdavo koreguojamas, kad kitą kartą spėtų geriau. Spėjimo etape, po spėjimo, mes modelio nebekoreguojame. Šio etapo metu modelis žino kiek žino, belieka tik atsakyti į mūsų užduotus klausimus. Beveik kaip studentas - spėlioja mokydamasis, koreguoja savo spėjimus, o tada ateina atsiskaitymo diena ir tenka spėti pagal tai ką išmokai, bet jau nebegali pasitaisyti. Jei spėjimai neteisingi, tenka pakeisti kitu arba tvarkyti... modelį, be abejo...
Lietuviškų žodžių generatoriaus atveju buvo panadotas pasikartojančio neuroninio tinklo (Recurrent Neural Network) modelis. Šis modelis buvo apmokytas panaudojus ~83,000 žodžių žodyną gautą iš čia. Kaip minėjau, neuroniniai tinklai yra gana jautrūs duomenims. Jeigu bandydamas programą pastebėjai keistų žodžių, kurie tavo manymu, tikrai nėra lietuviški žodžiai, nors programa sako, jog yra, arba atvirkščiai. Tai, taip, žodynas nėra pats geriausias ir turi savyje įtartinų žodžių, o kai ko neturi, ko reiktų, bet tik tokį radau. Jei turi geresnį, brūkštelk man per LinkedIn...
Mokymo metu imamas kiekvienas žodis iš žodyno ir suskaidomas paraidžiui:
Rezultatui naudojamas tas pats žodis tik perstūmus per vieną raidę. Be įprastų raidžių reikalingas ir specialus simbolis, kuris rodytų, kada žodis baigėsi, kitu atveju tinklas generuos begalinio ilgio žodžius. Paveiksle žodžio pabaigą simbolizuoja tuščias laukelis:
Taip pat reikia atkreipti dėmesį, jog pasikartojantys neuroniniai tinklai turi savybę perduoti informaciją iš praeitų iteracijų. Jeigu žodį apsibrėšime kaip iteracijos ribą, tai gausime, jog pirmo spėjimo metu modeliui davus raidę "a", modelis turi atspėti, jog kita raidė yra "g", kas nėra labai lengva, nes žodžių prasidedančių a raide yra gana daug. Kitos iteracijos metu modelis gavęs raidę "g", jau turės informaciją ir iš praeitos iteracijos, tai galima teigti, jog "u" raidę atspėti jam reikės turint "ag", kas jau yra šiek tiek lengviau. Toliau gavęs "agu", turės atspėti, jog kita raidė "r". Gavęs "agur", turės atspėti, jog kita raidė yra "k" ir t.t., kol turės atspėti, jog žodis baigėsi, atspėdamas žodžio pabaigos simbolį.
Taip modelis spėlioja kiekvieną žodį žodyne, kiekvieno spėjimo metu koreguodamas savo vidinį spėjimo mechanizmą - mokydamasis. Perėjęs per visus žodžius išmoksta kokios raidės duotu atveju turi didelę tikimybę pasirodyti, o kurios mažą. Pavyzdžiui, pamatęs visus žodžius, modelis išmoks, jog po "a" raidės, tikėtina, jog gali būti raidė "k", "l", "r" ir pan., bet nebus raidės "į", "ų" ar "ą". Kai modelis išmoksta daug tokių sandaros taisyklių, sugeba sudaryti pakankamai realų lietuvišką žodį.
Jei pakankamai ilgai žaidei, gali būti, jog užtikai keistus žodžius prasidedančius "Ę" arba "Ų" raide. Keistus, todėl, kad lietuvių kalboje žodžių prasidedančių šiomis raidėmis nėra. Būtų naudinga šias raides išmest iš spėjimų, bet jas palikau specialiai, kad parodyti kas bus, jei modelis turės sugeneruoti žodį iš to ko jis niekada nebuvo matęs. Man modelis sugeneravo tokius žodžius:
Tikėtina, jog "Ęstinis" buvo geriausias spėjimas panaudojant matytą žodį "Tęstinis". o "Ųdviejų", gali būti, jog kilo iš žodžio "Jųdviejų". Kaip matome, modelis, nors ir akivaizdžiai prašovė, bet tikrai įdėjo pastangų galvojant žodį pagal mūsų nerealią užgaidą. Ir net valgyt neprašo!
Dar reikėtų paminėti, kad nors visi žodžiai generuojami modelio, bet jie generuojami atsitiktine tvarka parenkant raides pagal jų tikimybę. Jeigu visuomet imtume didžiausią tikimybę turinčias raides, tai modelio paprašius sugeneruoti žodį iš raidės "D", jis visuomet sugeneruotų žodį "Daugiakojis". Taip yra todėl, kad jis išmokęs, jog po raidės "d" didžiausia tikimybė, jog eis raidė "a". Po raidžių "da", didžiausia tikimybė, jog bus raidė "u" ir t.t., kol gaunam žodį "Daugiakojis". Tai yra tiesiog lietuviškų žodžių sandaros pasikarojamumo padarinys. Jei duotume raidę "a", visuomet būtų generuojamas žodis "Antaninava". Turbūt ne pats populiariausias žodis kasdienėje kalboje, bet, tikėtina, jog atskiros jo dalys gana populiaros tarp lietuviškų žodžių. Kad nebūtų generuojami visuomet tik struktūriškai populiariausi žodžiai, kiekviena kita raidė parenkama pagal modelio gražintą tikimybę, bet atsitiktine tvarka.
Paanalizuokime vieną įdomų variantą, kurį sugeneravo modelis:
Ne, tokio žodžio lietuvių kalboje nėra. Tai kodėl generatorius jį sugeneravo? Galima būtų spėti, jog kol buvo generuojama pradžia "Stačia", modeliui buvo viskas aišku ir paprasta, bet jo nelaimei kita raidė buvo parinkta "ž". Jei aš tokią raidę ištraukčiau žaisdamas panašų stalo žaidimą, nelabai apsidžiaugčiau. Turiu rankose "Stačiaž"... Visgi reikia kažkaip suktis... Laikas bėga... Žinau, Stačiatikis!! ne, ne "t" raidė, o "ž", laikas baigėsi...
O išsisukt pasirodo įmanoma su žodžiu "Stačiaženklis". Nors tokio žodžio lietuvių kalboje nėra, bet užtat yra krūva kitų žodžių kurie baigiasi "-ženklis", tai kodėl gi ne "Stačiaženklis"? :)
Pabaigai dar apžvelgsim mokymo epochas. Iki šiol minėjau, jog modelis apmokytas pereinant visus žodyno žodžius. Bet realybėje visus žodžius galima pereiti ne vieną kartą. Vienas pilnas apmokymas visais žodžiais vadinamas viena epocha. Apmokant modelį tik viena epocha, tikėtina, jog nebus surasta pati optimaliausia funkcija, kadangi mokymas vykdomas palaipsniui.
Galima būtų palyginti 1 epochą ir 200 epochų mokyto modelio rezultatus. Lentelėje pateikti didžiausią tikimybę turintys žodžiai.
| Pradinė raidė | 1 epochos modelis | 200 epochų modelis |
|---|---|---|
| c | Ciptelėjo | Cingsi |
| p | Pasieninis | Pasiklydėlis |
| b | Baltakalnis | Baltakis |
| t | Trampinis | Tarpusienis |
| i | Ištaras | Iškalba |
| u | Užininkas | Užuomarša |
| š | Šlaidinti | Šiurpiškiai |
Net ir vieną epochą mokytas modelis generuoja neblogus rezultatus, bet žodžiuose dažnai kartojasi "in", "inis" ir "inin". Sugeneruoti žodžiai labai panašūs tarpusavyje ir "sausoki". Baigiasi dažniausiai raide "s". Iš pateiktų 1 epochos modelio sugeneruotų žodžių tik 2 žodžiai yra žodyne, tuo tarpu visi pateikti 200 epochų apmokyto modelio žodžiai žodyne yra. Apmokant neuroninius tinklus galima ir persistengti - išmokyti tinklą puikiai spėlioti tai, ką jis matė apmokymo metu. Tik šiuo atveju modeliui sunkiai seksis spėlioti pagal anksčiau nematytus duomenis. Šios programos užduotis gana specifinė ir labai sunku pasakyti, kokia yra riba tarp to kas yra teisinga, o kas ne. Mano noras buvo, kad šis generatorius gana dažnai gamintų tikrus žodžius su kartais pasitaikančiomis kliurkomis, kurių žmogus nesitiki. O kai vieną kartą suklysti, pradedi dvejot savo lietuvių kalbos subegėjimais :) Visgi, jei tikslas būtų dažniau generuoti netikrus žodžius, vienas iš būdų šiuo atveju - sumažinti apmokymo epochų skaičių.
Liko dar daug neaptartų niuansų, o ir tuos kuriuos aprašiau, aprašiau gana paviršutiniškai. Bet jeigu nebaigsiu dabar, tai prirašysiu pusę knygos, nes tema gana plati. Vienu metu jau buvau pradėjęs pasakoti matematinėmis formulėmis, bet supratau, kad šiek tiek per toli nukrypau :D Jei buvo įdomu, ar nuliūdai, jog neradai čia matematikos, siūlau panaršyti apie dirbtinius neuroninius tinklus interneto platybėse. Nors neuroninių tinklų įdėja užgimė dar penktame dešimtmetyje, bet paskutinius keletą metų labai išpopuliarėjo. Tyrimai vyksta vis didesniu mąstu, galimybės ir naujos metodikos atrandamos vos ne kasdien...