Masinõpe. Scikit-Learn ja TensorFlow.

Valter Kiisk
TÜ Füüsika Instituut
Viimati muudetud: 21.01.2022
$\renewcommand{\vec}[1]{{\bf #1}}$ $\newcommand{\aver}[1]{\langle #1 \rangle}$ $\newcommand{\eps}{\varepsilon}$

Sisukord

Sissejuhatus

Masinõpe tegeleb matemaatiliste (statistiliste) mudelitega, mida on võimalik treenida empiiriliste andmetega nii, et need mudelid suudavad teha piisavalt täpseid ennustusi või otsuseid ka sama tüüpi uute andmete korral. Masinõppe valdkondi võib klassifitseerida järgmiselt:

Objekti iseloomustab komplekt mõõdetavaid tunnuseid (features) ehk seletavaid muutujaid (explanatory variables). Need on masinõppe mudelile sisendiks. Juhendatud õppe korral lisandub ka väljundsuurus ehk märgend (label, target), mis regressiooni korral on pidev ehk reaalarvuline ja klassifitseerimise korral diskreetne ehk kategoriaalne. Viimasel juhul võib märgendit nimetada klassiks. Üks vaatlus ehk näidis ehk andmepunkt (sample) sisaldab tunnuste komplekti koos vastava märgendiga.

Seega juhendatud õppe korral peab masin õppima ennustama väljundit suvalise sisendi jaoks, tuginedes (inimese poolt) eelnevalt märgendatud treeningandmetele. Seevastu juhendamata õppe korral märgendid puuduvad ja algoritm ise peab tuvastama andmestikus leiduvad (varjatud) struktuurid, nt mitu erinevat objektitüüpi esineb või kui palju on tunnuste hulgas sõltumatuid muutujaid.

Et masinõppe mudel oleks õppimisvõimeline, sisaldab see vabu parameetreid, mida optimeeritakse treenimise käigus, püüdes minimeerida mõnesugust sihi- või kahjufunktsiooni (objective function, loss function). Samas võib mudeli või treenimisalgoritmi koosseisus olla ka nn hüperparameetreid, mis fikseeritakse enne treeningu algust ja mis mõjutavad õppe tulemust või kiirust.

Selles märkmeraamatus vaatame vaid juhendatud õpet. Sissejuhatava näitena vaatame sellist regressioonülesannet, kus on üksainus seletav muutuja $x$, mis määrab mõnesuguse tundmatu seose kaudu sõltuva muutuja $y$ väärtuse. See on piisavalt lihtne ülesanne, kus me masinõppe-spetsiifilisi Pythoni pakette veel ei vaja ja võime piirduda Numpy vahenditega. Impordime vajalikud vahendid:

Genereerime juhuslikud "katseandmed". Tegelikkuses andmed pärineksid tõenäoliselt mõnesugustest mõõtmistest.

Niisiis meie eesmärk on õpetada arvutile seos $x$ ja $y$ vahel, nii et etteantud $x$ väärtuse korral saaks mõnesuguse täpsusega ennustada $y$ väärtust. Seejuures tegelikku seost $x$ ja $y$ vahel me ei tea. Üks parajalt üldine ja paindlik matemaatiline funktsioon on polünoom: $$y=a_0x^n+a_1x^{n-1}+\ldots+a_{n-1}x+a_n.$$ Selle mudeli treenimine tähendab siis kordajate $a_i$ leidmist, nii et funktsioon kulgeks võimalikult katsepunktide lähedalt. Konkreetsemalt, võtame kahjufunktsiooniks ruutkeskmise erinevuse katselise $y$-väärtuse ja mudelfuktsiooni vastava ennustuse vahel. Vähimruutude meetodil polünoomi sobitamist teostabki numpy.polyfit.

Masinõppe korral on oluline, et treenitud mudel annaks adekvaatseid prognoose ka uute andmete korral, mida treenimise ajal ei kasutatud. Seega andmemassiivist mingi osa tuleb jätta hilisemaks testimiseks. Jätame näiteks pooled andmed mudeli treenimiseks ja ülejäänud testimiseks.

Esialgu me ei tea ka seda, milline võiks olla mõistlik polünoomi järk $n$. Viimane on seega mudeli hüperparameeter. Katsetame erinevate $n$ väärtustega. Mudeli sobivust kontrollime nii treening- kui ka testandmete peal, kasutades mõlemal juhul karakteristikuna ruutkeskmist viga.

Treeningandmete puhul funktsioon sobitub seda paremini, mida suurem on $n$, sest $n$ suurendamise teel on alati võimalik mudeli õppimisvõimet suurendada (ehk polünoomi aina täpsemalt antud katsepunktidest läbi juhtida). Esialgu ennustused paranevad ka testandmete jaoks kuni umbes $n=5$ juures hakkab ennustuste kvaliteet langema. Veel suuremate $n$ väärtuste kasutamine ei ole õigustatud ja tingib ületreeningu. Vaatame, kuidas variandid $n=1$ (liiga lihtne mudel), $n=5$ (optimaalne) ja $n=15$ (ületreening) graafiliselt välja näevad:

Nendest kolmest variandist $n=5$ on ilmselt kõige loomulikuma käitumisega ja sobivalt üldistub andmetele. Samas, kui me katsetaks näiteks mudeliga $$y=a_1e^{-k_1x} + a_2e^{-k_2x} + \ldots + a_ne^{-k_nx},$$ saaks tulemus veelgi parem.

Selles näites iseloomustas vaatlust üksainus tunnus, nii et kõik vaatlused sai esitada vektorina. Kui tunnuseid on rohkem, esitatakse andmed maatriksina $\vec X$, mille iga rida vastab ühele vaatlusele ja iga veerg ühele kindlale tunnusele. Märgendid tuleb samas järjestuses koondada vektorisse $\vec y$. $$\vec X=\stackrel{\Tiny\text{tunnused}\rightarrow}{\begin{bmatrix}x_{11} & x_{12} & \cdots & x_{1n}\\ x_{21} & x_{22} & \cdots & x_{2n}\\ \vdots & \vdots & \ddots & \vdots\\ x_{m1} & x_{m2} & \cdots & x_{mn}\end{bmatrix}} {\Tiny \begin{matrix}\text{vaatlused} \\ \downarrow\end{matrix}} \qquad \vec y=\begin{bmatrix}y_1\\y_2\\ \vdots \\ y_m\end{bmatrix}.$$ Näiteks Numpy andmestruktuure kasutades võiks maatriksit $\vec X$ esindada kahemõõtmeline massiiv, kus vaatlused kulgevad 1. telje sihis ja tunnused 2. telje sihis.

Regressioon (Scikit-Learn)

Scikit-Learn (sklearn) on üks vanimaid ja võrdlemisi üldotstarbeline Pythoni masinõppe teek. See sisaldab suure hulga lihtsasti kasutatavaid (valmiskujul) vahendeid ja algoritme, mis on koondatud vastavatesse klassidesse ja moodulitesse.

Reeglina masinõppeprobleemides tunnuseid/seletavaid muutujaid on rohkem kui üks. Et saaks regressiooni tulemust siiski veel graafiliselt esitada, piirdume kahe tunnusega. Simuleerime jälle andmed:

3D graafikute tegemiseks on tarvis veel mõningaid vahendeid: