mudel.html
21,970 bytes
| 1 | <!DOCTYPE html> |
|---|---|
| 2 | <html lang="et"> |
| 3 | <head> |
| 4 | <meta charset="utf-8"> |
| 5 | <meta name="viewport" content="width=device-width, initial-scale=1"> |
| 6 | <title>CountrySense: kuidas mudel töötab</title> |
| 7 | <style> |
| 8 | :root { |
| 9 | --ink: #1d2733; |
| 10 | --muted: #5b6b7c; |
| 11 | --line: #d9e1ea; |
| 12 | --accent: #1a6feb; |
| 13 | --accent-soft: #eaf2ff; |
| 14 | --bg: #fbfcfe; |
| 15 | --code-bg: #f2f5f9; |
| 16 | } |
| 17 | * { box-sizing: border-box; } |
| 18 | body { |
| 19 | margin: 0; |
| 20 | font-family: Georgia, "Times New Roman", serif; |
| 21 | color: var(--ink); |
| 22 | background: var(--bg); |
| 23 | line-height: 1.65; |
| 24 | } |
| 25 | header { |
| 26 | background: var(--ink); |
| 27 | color: #fff; |
| 28 | padding: 3rem 1.5rem 2.5rem; |
| 29 | text-align: center; |
| 30 | } |
| 31 | header h1 { margin: 0 0 0.4rem; font-size: 2.2rem; } |
| 32 | header p { margin: 0; color: #b9c6d4; font-size: 1.05rem; } |
| 33 | main { max-width: 860px; margin: 0 auto; padding: 1.5rem; } |
| 34 | nav.toc { |
| 35 | background: #fff; |
| 36 | border: 1px solid var(--line); |
| 37 | border-radius: 8px; |
| 38 | padding: 1rem 1.5rem; |
| 39 | margin: 1.5rem 0; |
| 40 | font-family: system-ui, sans-serif; |
| 41 | font-size: 0.92rem; |
| 42 | } |
| 43 | nav.toc ol { margin: 0.3rem 0 0; padding-left: 1.3rem; columns: 2; } |
| 44 | nav.toc a { color: var(--accent); text-decoration: none; } |
| 45 | nav.toc a:hover { text-decoration: underline; } |
| 46 | h2 { |
| 47 | margin-top: 2.6rem; |
| 48 | padding-bottom: 0.3rem; |
| 49 | border-bottom: 2px solid var(--line); |
| 50 | font-size: 1.5rem; |
| 51 | } |
| 52 | h3 { margin-top: 1.8rem; font-size: 1.15rem; } |
| 53 | code, pre { |
| 54 | font-family: Consolas, "Courier New", monospace; |
| 55 | background: var(--code-bg); |
| 56 | border-radius: 4px; |
| 57 | } |
| 58 | code { padding: 0.1em 0.35em; font-size: 0.9em; } |
| 59 | pre { padding: 0.9rem 1.1rem; overflow-x: auto; border: 1px solid var(--line); } |
| 60 | pre code { background: none; padding: 0; } |
| 61 | table { |
| 62 | border-collapse: collapse; |
| 63 | width: 100%; |
| 64 | margin: 1rem 0; |
| 65 | font-family: system-ui, sans-serif; |
| 66 | font-size: 0.9rem; |
| 67 | background: #fff; |
| 68 | } |
| 69 | th, td { border: 1px solid var(--line); padding: 0.5rem 0.7rem; text-align: left; vertical-align: top; } |
| 70 | th { background: var(--accent-soft); } |
| 71 | .note { |
| 72 | background: var(--accent-soft); |
| 73 | border-left: 4px solid var(--accent); |
| 74 | padding: 0.8rem 1.1rem; |
| 75 | border-radius: 0 6px 6px 0; |
| 76 | margin: 1.2rem 0; |
| 77 | } |
| 78 | .warn { |
| 79 | background: #fff6ec; |
| 80 | border-left: 4px solid #e08a2e; |
| 81 | padding: 0.8rem 1.1rem; |
| 82 | border-radius: 0 6px 6px 0; |
| 83 | margin: 1.2rem 0; |
| 84 | } |
| 85 | .pipeline { |
| 86 | display: flex; |
| 87 | flex-wrap: wrap; |
| 88 | align-items: center; |
| 89 | justify-content: center; |
| 90 | gap: 0.4rem; |
| 91 | margin: 1.5rem 0; |
| 92 | font-family: system-ui, sans-serif; |
| 93 | font-size: 0.82rem; |
| 94 | } |
| 95 | .pipeline .box { |
| 96 | background: #fff; |
| 97 | border: 1.5px solid var(--ink); |
| 98 | border-radius: 6px; |
| 99 | padding: 0.55rem 0.8rem; |
| 100 | text-align: center; |
| 101 | min-width: 105px; |
| 102 | } |
| 103 | .pipeline .box small { display: block; color: var(--muted); } |
| 104 | .pipeline .arrow { font-size: 1.2rem; color: var(--muted); } |
| 105 | .pipeline .box.hot { background: var(--accent-soft); border-color: var(--accent); } |
| 106 | .block-diagram { |
| 107 | background: #fff; |
| 108 | border: 1px dashed var(--muted); |
| 109 | border-radius: 8px; |
| 110 | padding: 1rem 1.3rem; |
| 111 | font-family: Consolas, monospace; |
| 112 | font-size: 0.85rem; |
| 113 | white-space: pre; |
| 114 | overflow-x: auto; |
| 115 | margin: 1.2rem 0; |
| 116 | } |
| 117 | .formula { |
| 118 | text-align: center; |
| 119 | font-size: 1.1rem; |
| 120 | margin: 1.2rem 0; |
| 121 | font-style: italic; |
| 122 | } |
| 123 | footer { |
| 124 | margin-top: 3rem; |
| 125 | padding: 1.5rem; |
| 126 | text-align: center; |
| 127 | color: var(--muted); |
| 128 | font-size: 0.85rem; |
| 129 | border-top: 1px solid var(--line); |
| 130 | font-family: system-ui, sans-serif; |
| 131 | } |
| 132 | </style> |
| 133 | </head> |
| 134 | <body> |
| 135 | |
| 136 | <header> |
| 137 | <h1>CountrySense</h1> |
| 138 | <p>Kuidas nägemistransformer tänavapildi järgi riigi ära arvab: arhitektuur, andmed ja kõik valikud lahti seletatuna</p> |
| 139 | </header> |
| 140 | |
| 141 | <main> |
| 142 | |
| 143 | <nav class="toc"> |
| 144 | <strong>Sisukord</strong> |
| 145 | <ol> |
| 146 | <li><a href="#skoop">Ülesanne ja skoop</a></li> |
| 147 | <li><a href="#andmed">Andmestik ja valikukriteeriumid</a></li> |
| 148 | <li><a href="#puhastus">Andmete puhastamine</a></li> |
| 149 | <li><a href="#mudelivalik">Mudeli valik</a></li> |
| 150 | <li><a href="#vit">ViT samm-sammult</a></li> |
| 151 | <li><a href="#dense">Dense-kihid transformeri sees</a></li> |
| 152 | <li><a href="#pea">Klassifitseerimispea ja softmax</a></li> |
| 153 | <li><a href="#kadu">Kadufunktsioon</a></li> |
| 154 | <li><a href="#treening">Treening kahes faasis</a></li> |
| 155 | <li><a href="#augment">Augmentatsioonid</a></li> |
| 156 | <li><a href="#tasakaal">Klasside tasakaal</a></li> |
| 157 | <li><a href="#moodikud">Mõõdikud</a></li> |
| 158 | <li><a href="#piirangud">Piirangud ja teekaart</a></li> |
| 159 | </ol> |
| 160 | </nav> |
| 161 | |
| 162 | <h2 id="skoop">1. Ülesanne ja skoop</h2> |
| 163 | <p> |
| 164 | Sisend on üks tänavapilt, väljund on riigi nimi ja tõenäosused. Kogu toru näeb välja nii: |
| 165 | </p> |
| 166 | |
| 167 | <div class="pipeline"> |
| 168 | <div class="box">Pilt<small>224 × 224 × 3</small></div> |
| 169 | <div class="arrow">→</div> |
| 170 | <div class="box">Patch embedding<small>196 + 1 tokenit</small></div> |
| 171 | <div class="arrow">→</div> |
| 172 | <div class="box hot">12 × Transformeri plokk<small>attention + MLP</small></div> |
| 173 | <div class="arrow">→</div> |
| 174 | <div class="box">CLS-vektor<small>768 arvu</small></div> |
| 175 | <div class="arrow">→</div> |
| 176 | <div class="box hot">Dropout + Linear<small>768 → N riiki</small></div> |
| 177 | <div class="arrow">→</div> |
| 178 | <div class="box">Softmax<small>tõenäosused</small></div> |
| 179 | </div> |
| 180 | |
| 181 | <p> |
| 182 | Miks just riigi tase? Täpne geolokatsioon (koordinaatide ennustamine) on teadusartikli mõõtu ettevõtmine: miljonid pildid, suured mudelid, nädalad GPU-aega. Riigi klassifitseerimine saja klassi vahel on tavaline juhendatud õppe ülesanne, mis mahub tasuta Colabi GPU peale. Järgmine aus samm oleks regioon riigi sees, koordinaadid ei ole plaanis. |
| 183 | </p> |
| 184 | |
| 185 | <h2 id="andmed">2. Andmestik ja valikukriteeriumid</h2> |
| 186 | <p> |
| 187 | Vaikimisi andmestik on Kaggle'i <em>GeoLocation, Geoguessr Images 50K</em>: umbes 50 000 Street View pilti, iga riik oma kaustas. Valik tehti nelja kriteeriumi järgi: |
| 188 | </p> |
| 189 | <table> |
| 190 | <tr><th>Kriteerium</th><th>Miks oluline</th></tr> |
| 191 | <tr><td>Sildid kaustastruktuuris</td><td>Käsitsi märgendamine oleks nädalate töö. Kausta nimi ongi klassi silt.</td></tr> |
| 192 | <tr><td>~150 riiki, ~50k pilti</td><td>Piisavalt suur, et ülesanne oleks päris, ja piisavalt väike, et tasuta GPU jaksaks.</td></tr> |
| 193 | <tr><td>Maht mõni gigabait</td><td>Mahub Colabi kettale, allalaadimine minutites, mitte tundides.</td></tr> |
| 194 | <tr><td>Vaba juurdepääs</td><td>kagglehub laadib ilma API võtmeta, notebook töötab igaühel.</td></tr> |
| 195 | </table> |
| 196 | <p> |
| 197 | Kood ei sõltu sellest konkreetsest andmestikust: iga kaust paigutusega <code>root/<riik>/<pilt></code> sobib. Skaleerimiseks on hea kandidaat OpenStreetView-5M alamhulk. |
| 198 | </p> |
| 199 | <div class="warn"> |
| 200 | <strong>Ausalt biasest.</strong> Street View katvus on kaldu jõukamate riikide poole ja eri riikides on pildistatud eri kaamerapõlvkondadega. Mudel õpib paratamatult ka kaamera artefakte (värvitoon, teravus, resolutsioon), mitte ainult maastikku ja arhitektuuri. GeoGuessri profimängijad kasutavad täpselt sama vihjet. |
| 201 | </div> |
| 202 | |
| 203 | <h2 id="puhastus">3. Andmete puhastamine</h2> |
| 204 | <p> |
| 205 | Toorandmestikus on katkiseid faile, praktiliselt musti kaadreid (tunnelid, öö), uduseid pilte ja duplikaate. <code>clean.py</code> käib kõik pildid läbi ja kirjutab iga välja jäetud pildi kohta raporti reaga põhjuse. |
| 206 | </p> |
| 207 | <table> |
| 208 | <tr><th>Samm</th><th>Reegel</th><th>Miks</th></tr> |
| 209 | <tr><td>Rikutud failid</td><td>PIL ei suuda avada</td><td>Katkine fail kukutaks treeningu keset epohhi.</td></tr> |
| 210 | <tr><td>Suurus</td><td>lühem külg < 128 px</td><td>Alla selle pole piisavalt detaili, ViT sisend on 224 px.</td></tr> |
| 211 | <tr><td>Heledus</td><td>halltoonide keskmine < 20 või > 235</td><td>Peaaegu mustad või läbipõlenud kaadrid ei kanna infot, aga kannavad silti, st ainult müra.</td></tr> |
| 212 | <tr><td>Teravus</td><td>gradiendi energia keskmine < 25</td><td>Udune kaader (liikumine, vihmapiisk objektiivil). Gradiendi energia on lihtne teravuse mõõt: udusel pildil muutuvad naaberpikslid vähe.</td></tr> |
| 213 | <tr><td>Duplikaadid</td><td>korduv phash</td><td>Perceptual hash annab visuaalselt identsetele piltidele sama koodi. Kriitiline: kui sama koht satub nii treening- kui testihulka, on testitulemus petlikult hea. See on andmeleke, kõige levinum viga sedasorti projektides.</td></tr> |
| 214 | <tr><td>Väikesed klassid</td><td>riigil < 100 pilti</td><td>Paarikümne pildiga ei saa õppida ega usaldusväärselt mõõta.</td></tr> |
| 215 | <tr><td>Suured klassid</td><td>lagi 2000 pilti riigi kohta</td><td>Vähendab tasakaalustamatust juba andmete tasandil, ülejäänu teeb sampler (ptk 11).</td></tr> |
| 216 | </table> |
| 217 | |
| 218 | <h2 id="mudelivalik">4. Mudeli valik</h2> |
| 219 | <p> |
| 220 | Otsustuskriteeriumid: eeltreeningu kvaliteet geograafia jaoks, parameetrite maht (peab mahtuma tasuta T4 GPU 16 GB mällu koos peenhäälestusega) ja teegi tugi. |
| 221 | </p> |
| 222 | <table> |
| 223 | <tr><th>Kandidaat</th><th>Hinnang</th></tr> |
| 224 | <tr><td><strong>CLIP ViT-B/16 (valitud)</strong></td><td>OpenAI treenis seda 400 miljoni pilt-tekst paari peal. Kuna tekstid kirjeldasid ka kohti ("a street in Lisbon"), kodeerivad tunnused juba silte, taimestikku, arhitektuuri, teekattemärgistust. Lineaarne pea CLIP-i tunnuste otsas on teadaolevalt tugev geolokatsiooni baastase. 86M parameetrit mahub T4 peale.</td></tr> |
| 225 | <tr><td>ImageNet ViT / ConvNeXt</td><td>Töötaks, aga ImageNeti 1000 klassi (koeratõud, esemed) on geograafiast kaugel, transfer on mõõdetavalt nõrgem.</td></tr> |
| 226 | <tr><td>StreetCLIP (ViT-L/14)</td><td>Juba geolokatsiooniks häälestatud CLIP, aga kolm korda suurem. Peenhäälestus T4 peal on kitsas. Hea järgmine samm parema riistvaraga.</td></tr> |
| 227 | <tr><td>CNN nullist</td><td>50k pildiga lootusetu. Eeltreening on kogu projekti võimaldaja: keegi teine on juba kulutanud tuhanded GPU-tunnid üldiste visuaalsete tunnuste õppimisele.</td></tr> |
| 228 | </table> |
| 229 | |
| 230 | <h3>ViT-B/16 numbrid</h3> |
| 231 | <table> |
| 232 | <tr><th>Omadus</th><th>Väärtus</th></tr> |
| 233 | <tr><td>Parameetreid</td><td>~86 miljonit</td></tr> |
| 234 | <tr><td>Transformeri plokke</td><td>12</td></tr> |
| 235 | <tr><td>Peidetud dimensioon</td><td>768</td></tr> |
| 236 | <tr><td>Attention-päid ploki kohta</td><td>12</td></tr> |
| 237 | <tr><td>MLP vahekihi laius</td><td>3072</td></tr> |
| 238 | <tr><td>Patchi suurus</td><td>16 × 16 px</td></tr> |
| 239 | <tr><td>Tokeneid 224 px pildi kohta</td><td>196 patchi + 1 CLS = 197</td></tr> |
| 240 | </table> |
| 241 | |
| 242 | <h2 id="vit">5. ViT samm-sammult</h2> |
| 243 | |
| 244 | <h3>5.1 Patch embedding: pilt muutub jadaks</h3> |
| 245 | <p> |
| 246 | Transformer töötab tokenite jadaga, mitte pikslivõrega. Seepärast lõigatakse 224 × 224 pilt 16 × 16 piksliseks ruudustikuks: 14 × 14 = 196 patchi. Iga patch on 16 × 16 × 3 = 768 arvu, mis lastakse läbi <em>ühe lineaarse kihi</em> (see on esimene dense-kiht kogu mudelis) ja saadakse 768-mõõtmeline vektor. Pilt on nüüd 196 "sõnast" koosnev lause. |
| 247 | </p> |
| 248 | <h3>5.2 CLS-token ja positsioonivektorid</h3> |
| 249 | <p> |
| 250 | Jada ette lisatakse üks õpitav lisatoken, <strong>CLS</strong> (classification). Tal pole pildisisu, tema ülesanne on plokkide läbimise käigus koguda attention'i kaudu kokku terve pildi kokkuvõte. Lõpus loetakse ennustus just tema pealt. |
| 251 | </p> |
| 252 | <p> |
| 253 | Kuna attention ise on järjekorra suhtes ükskõikne, liidetakse igale tokenile <strong>positsioonivektor</strong>: õpitav vektor, mis ütleb "sina oled rea 3, veeru 7 patch". Ilma selleta ei teaks mudel, kas taevas on üleval või all. |
| 254 | </p> |
| 255 | |
| 256 | <h3>5.3 Transformeri plokk</h3> |
| 257 | <p>Kõik 12 plokki on identse ehitusega:</p> |
| 258 | <div class="block-diagram">sisend (197 × 768) |
| 259 | │ |
| 260 | ├──────────────────────────────┐ |
| 261 | ▼ │ |
| 262 | LayerNorm │ |
| 263 | ▼ │ |
| 264 | Multi-head self-attention │ (12 pead) |
| 265 | ▼ │ |
| 266 | + ◄───────────────────────────┘ residuaalühendus |
| 267 | │ |
| 268 | ├──────────────────────────────┐ |
| 269 | ▼ │ |
| 270 | LayerNorm │ |
| 271 | ▼ │ |
| 272 | MLP: Linear 768 → 3072 │ (dense-kihid) |
| 273 | GELU │ |
| 274 | Linear 3072 → 768 │ |
| 275 | ▼ │ |
| 276 | + ◄───────────────────────────┘ residuaalühendus |
| 277 | │ |
| 278 | väljund (197 × 768)</div> |
| 279 | |
| 280 | <h3>5.4 Self-attention: info liigub patchide vahel</h3> |
| 281 | <p> |
| 282 | Igast tokenist arvutatakse kolm projektsiooni: päring <strong>Q</strong> (query), võti <strong>K</strong> (key) ja väärtus <strong>V</strong> (value). Iga token "küsib" kõigilt teistelt, kui asjakohased nad talle on, ja korjab nende väärtused kokku kaalutult: |
| 283 | </p> |
| 284 | <p class="formula">Attention(Q, K, V) = softmax(Q·K<sup>T</sup> / √d) · V</p> |
| 285 | <p> |
| 286 | Jagamine √d-ga hoiab korrutised mõistlikus vahemikus, et softmax ei küllastuks. "Multi-head" tähendab, et see arvutus tehakse 12 korda paralleelselt väiksemates alamruumides (768 / 12 = 64 mõõdet pea kohta): üks pea võib jälgida värve, teine geomeetriat, kolmas teksti silmapiiril. Just attention lubab CLS-tokenil siduda kokku liiklusmärgi paremal, taimestiku vasakul ja teekattemärgistuse all, ükskõik kui kaugel need üksteisest on. CNN-il kuluks sama kaugete seoste jaoks palju kihte. |
| 287 | </p> |
| 288 | |
| 289 | <h2 id="dense">6. Dense-kihid transformeri sees</h2> |
| 290 | <p> |
| 291 | Iga ploki teine pool on MLP (multi-layer perceptron), kaks dense- ehk täisühendatud kihti: |
| 292 | </p> |
| 293 | <pre><code>Linear(768 → 3072) # laiendus 4× |
| 294 | GELU # sujuv mittelineaarsus |
| 295 | Linear(3072 → 768) # tagasi kokku</code></pre> |
| 296 | <p> |
| 297 | Tööjaotus ploki sees on selge: <strong>attention liigutab infot tokenite vahel, MLP töötleb iga tokenit eraldi</strong>. MLP-s toimub tegelik tunnuste teisendamine: laiendus 3072 mõõtmesse annab ruumi vahepealsete kombinatsioonide jaoks ("kollane + ristkülik + posti otsas"), GELU teeb teisenduse mittelineaarseks (ilma selleta oleks kogu võrk üks suur maatrikskorrutis) ja tagasiprojektsioon surub tulemuse standardsesse 768-mõõtmelisse esitusse, mida järgmine plokk ootab. |
| 298 | </p> |
| 299 | <p> |
| 300 | Mahult on MLP-d mudeli põhiosa: umbes kaks kolmandikku kõigist parameetritest elab just neis dense-kihtides. |
| 301 | </p> |
| 302 | <p> |
| 303 | Kaks tugistruktuuri teevad 12 ploki virna treenitavaks: <strong>LayerNorm</strong> normaliseerib iga tokeni vektori enne igat alamosa (stabiilsed suurusjärgud), <strong>residuaalühendused</strong> (x + f(x)) lasevad gradiendil voolata otse läbi kogu virna, nii et sügav võrk ei "unusta" sisendit ega lämmata gradienti. |
| 304 | </p> |
| 305 | |
| 306 | <h2 id="pea">7. Klassifitseerimispea ja softmax</h2> |
| 307 | <p> |
| 308 | Pärast 12. plokki ja lõpu LayerNorm'i võetakse CLS-tokeni 768-mõõtmeline vektor. See on kogu pildi kokkuvõte. Pea on tahtlikult minimaalne: |
| 309 | </p> |
| 310 | <pre><code>nn.Sequential( |
| 311 | nn.Dropout(0.2), # treeningul nullitakse juhuslikult 20% tunnustest |
| 312 | nn.Linear(768, N_riiki), # üks dense-kiht: 768 sisendit → N logitit |
| 313 | )</code></pre> |
| 314 | <p> |
| 315 | <strong>Dropout</strong> takistab peal toetumast üksikutele tunnustele (näiteks ainult ühe kaamerapõlvkonna värvitoonile): kui iga tunnus võib treeningul kaduda, peab otsus toetuma laiemale mustrile. |
| 316 | </p> |
| 317 | <p> |
| 318 | <strong>Linear</strong> annab igale riigile ühe reaalarvu, logiti. Sisuliselt on igal riigil 768 kaalu, mis ütlevad, millised tunnusekombinatsioonid tema poolt räägivad. <strong>Softmax</strong> teisendab logitid tõenäosusteks: e astmes iga logit, jagatud summaga, nii et tulemused on positiivsed ja annavad kokku 1. |
| 319 | </p> |
| 320 | <div class="note"> |
| 321 | <strong>Miks ainult üks kiht, mitte sügavam pea?</strong> CLIP-i tunnused on juba suures osas lineaarselt eraldatavad, seda mõõdab nn linear probe. Sügavam pea lisaks selle andmemahu (~40k treeningpilti) juures peamiselt ülesobitumise riski. Kui tunnused vajavad painutamist, on parem avada backbone'i viimased plokid, mida faasis 2 teemegi. |
| 322 | </div> |
| 323 | |
| 324 | <h2 id="kadu">8. Kadufunktsioon</h2> |
| 325 | <p> |
| 326 | Cross-entropy võrdleb softmax'i tõenäosusjaotust õige vastusega ja karistab logaritmiliselt: kindel vale vastus on väga kallis. Lisaks kasutame <strong>label smoothing</strong> väärtusega 0.1: sihtmärk pole "Eesti = 1.0, kõik muu = 0.0", vaid "Eesti = 0.9, ülejäänu jagab 0.1". |
| 327 | </p> |
| 328 | <p> |
| 329 | Põhjus on geograafiline: sildid on piirialadel loomupäraselt mürarikkad. Pilt Valgast näeb välja nagu Valka, ja Street View asukohaviga võib panna pildi sõna otseses mõttes vale riigi kausta. Smoothing hoiab mudelit sellistel juhtudel ülekindlaks muutumast ja parandab kalibratsiooni. |
| 330 | </p> |
| 331 | |
| 332 | <h2 id="treening">9. Treening kahes faasis</h2> |
| 333 | <table> |
| 334 | <tr><th></th><th>Faas 1: lineaarne sondeerimine</th><th>Faas 2: osaline peenhäälestus</th></tr> |
| 335 | <tr><td>Mis treenib</td><td>ainult pea (Dropout + Linear)</td><td>viimased 4 plokki + lõpu norm + pea</td></tr> |
| 336 | <tr><td>Epohhe</td><td>3</td><td>8</td></tr> |
| 337 | <tr><td>Õppemäär</td><td>1e-3</td><td>2e-5 backbone, 1e-4 pea, koosinusgraafik</td></tr> |
| 338 | </table> |
| 339 | <p> |
| 340 | <strong>Miks mitte kohe kõike treenida?</strong> Pea alustab juhuslikest kaaludest ja tema esimesed gradiendid on suured ja suvalises suunas. Kui backbone oleks lahti, lammutaksid need gradiendid eeltreenitud kaale enne, kui pea üldse midagi mõistlikku nõuab. Seepärast laseme peal esmalt külmutatud tunnuste otsas paika loksuda. |
| 341 | </p> |
| 342 | <p> |
| 343 | <strong>Miks ainult viimased 4 plokki, mitte kõik 12?</strong> Alumised plokid õpivad üldisi asju (servad, tekstuurid, värvilaigud), mis on igasuguse pildiülesande jaoks niigi head. Ülemised plokid kannavad semantikat, mida tasub geograafiale kohandada. Vähem avatud plokke tähendab kolme asja korraga: väiksem mälukulu (mahume T4 peale), väiksem ülesobitumise risk ja väiksem katastroofilise unustamise risk (et mudel ei kaotaks CLIP-i üldteadmisi). |
| 344 | </p> |
| 345 | <p> |
| 346 | Tehnilised valikud: AdamW (weight decay 0.01 hoiab kaalud väiksed), AMP ehk poolttäpsusega arvutus (ligi 2× kiirem ja poole väiksem mälukulu), gradientide kärpimine normini 1.0 (üksik halb batch ei löö treeningut rööpast), koosinusgraafik faasis 2 (õppemäär langeb sujuvalt, lõpus tehakse peeneid samme). |
| 347 | </p> |
| 348 | |
| 349 | <h2 id="augment">10. Augmentatsioonid</h2> |
| 350 | <table> |
| 351 | <tr><th>Teisendus</th><th>Kasutusel?</th><th>Põhjendus</th></tr> |
| 352 | <tr><td>RandomResizedCrop (50 kuni 100% pindalast)</td><td>Jah</td><td>Kaugus ja kadreering varieeruvad päriselt: sama koht näeb eri suumiga erinev välja.</td></tr> |
| 353 | <tr><td>ColorJitter (kerge)</td><td>Jah</td><td>Valgustus, aastaaeg ja kaamera värvitoon varieeruvad päriselt.</td></tr> |
| 354 | <tr><td>Horisontaalne peegeldus</td><td><strong>Ei</strong></td><td>Vasak- või parempoolne liiklus on päris geograafiline tunnus. Peegeldatud Suurbritannia näeb välja nagu Prantsusmaa, silt jääb "Suurbritannia": õpetaksime mudelile otseselt valet.</td></tr> |
| 355 | <tr><td>Pööramine</td><td>Ei</td><td>Horisont on tänavapildil alati enam-vähem loodis, kaldus pilte päriselt ei tule. Horisondi asend on info.</td></tr> |
| 356 | </table> |
| 357 | <div class="note"> |
| 358 | Hea augmentatsiooni reegel: simuleeri variatsiooni, mis päris andmetes olemas on, ja mitte kunagi sellist, mis silti muudaks. |
| 359 | </div> |
| 360 | |
| 361 | <h2 id="tasakaal">11. Klasside tasakaal</h2> |
| 362 | <p> |
| 363 | Pärast puhastust on riikide vahel ikkagi suurusjärguline vahe: mõnel riigil 2000 pilti, mõnel 100. Ilma sekkumiseta õpiks mudel "kahtluse korral paku suurt riiki" ja väikesed riigid jääksid nulli. |
| 364 | </p> |
| 365 | <p> |
| 366 | Lahendus on <code>WeightedRandomSampler</code>: iga pildi valikutõenäosus on pöördvõrdeline tema riigi piltide arvuga, nii et iga batch sisaldab kõiki riike ligikaudu võrdselt. Väikeste riikide pilte näidatakse lihtsalt sagedamini (tagasipanekuga valik). Alternatiiv oleks klassikaalud kadufunktsioonis; sampler annab ühtlasemad batchid ja stabiilsema treeningu, seepärast valisime tema. |
| 367 | </p> |
| 368 | |
| 369 | <h2 id="moodikud">12. Mõõdikud</h2> |
| 370 | <table> |
| 371 | <tr><th>Mõõdik</th><th>Mida mõõdab</th><th>Miks siin oluline</th></tr> |
| 372 | <tr><td>Top-1</td><td>esimene pakkumine õige</td><td>Põhinäitaja. Juhuslik pakkumine ~100 riigiga oleks 1%.</td></tr> |
| 373 | <tr><td>Top-5</td><td>õige riik viie parima seas</td><td>Geograafias aus: Eesti-Läti segiajamine on väike viga, Eesti-Brasiilia suur. Vigade seas domineerivad naabrid.</td></tr> |
| 374 | <tr><td>Makro-F1</td><td>klasside keskmine F1, kõik riigid võrdse kaaluga</td><td>Paljastab, kui mudel ohverdab väikesed riigid. Top-1 üksi seda ei näita.</td></tr> |
| 375 | <tr><td>Riigipõhine tabel</td><td>täpsus ja tugi riigi kaupa</td><td>Näitab, kus mudel on nõrk ja kuhu andmeid juurde vaja.</td></tr> |
| 376 | <tr><td>Confusion matrix</td><td>mida millega segi aetakse</td><td>Tüüpilised klastrid: Balti riigid, Skandinaavia, hispaaniakeelne Ladina-Ameerika. Kui segadused on geograafiliselt loogilised, õpib mudel õigeid tunnuseid.</td></tr> |
| 377 | </table> |
| 378 | <p> |
| 379 | Testihulk on treeningust rangelt lahus (stratifitseeritud 80/10/10 jaotus, iga riigi sees eraldi) ja duplikaadid eemaldati enne jaotust, et sama koht ei satuks mõlemale poole. |
| 380 | </p> |
| 381 | |
| 382 | <h2 id="piirangud">13. Piirangud ja teekaart</h2> |
| 383 | <p> |
| 384 | Mudel õpib osalt kaamerat, mitte maastikku (Street View põlvkondade bias). Riigid, mida andmestikus pole, saavad paratamatult mõne naabri sildi. Sisepildid ja inimesed pole selle mudeli teema, ta on tänavavaadete klassifitseerija. |
| 385 | </p> |
| 386 | <p> |
| 387 | Teekaart, ausas järjekorras: |
| 388 | </p> |
| 389 | <ol> |
| 390 | <li>Regioonitase riigi sees: hierarhiline pea, mis ennustab enne riigi ja siis regiooni. Sama retsept, rohkem klasse, rohkem andmeid.</li> |
| 391 | <li>Suurem andmestik (OpenStreetView-5M alamhulk) ja suurem backbone (StreetCLIP), kui riistvara lubab.</li> |
| 392 | <li>Kalibratsioon ja keeldumine: kui top-1 tõenäosus on madal, on ausam öelda "ei tea".</li> |
| 393 | <li><strong>Mitte plaanis:</strong> täpsed koordinaadid. See on teadustöö territoorium (PIGEON, GeoCLIP) ja nõuab arvutusmahtu, mida see projekt teadlikult väldib.</li> |
| 394 | </ol> |
| 395 | |
| 396 | </main> |
| 397 | |
| 398 | <footer> |
| 399 | CountrySense · CLIP ViT-B/16 peenhäälestus riigi klassifitseerimiseks · vt ka README.et.md |
| 400 | </footer> |
| 401 | |
| 402 | </body> |
| 403 | </html> |
| 404 | |