ΠšΡƒΠΈΡ†ΠΊ Π”Ρ€Π°Π² Π”ΠΎΠΎΠ΄Π»Π΅ Π Π΅Ρ†ΠΎΠ³Π½ΠΈΡ‚ΠΈΠΎΠ½: ΠΊΠ°ΠΊΠΎ сС ΡΠΏΡ€ΠΈΡ˜Π°Ρ‚Π΅Ρ™ΠΈΡ‚ΠΈ са Π , Π¦++ ΠΈ нСуронским ΠΌΡ€Π΅ΠΆΠ°ΠΌΠ°

ΠšΡƒΠΈΡ†ΠΊ Π”Ρ€Π°Π² Π”ΠΎΠΎΠ΄Π»Π΅ Π Π΅Ρ†ΠΎΠ³Π½ΠΈΡ‚ΠΈΠΎΠ½: ΠΊΠ°ΠΊΠΎ сС ΡΠΏΡ€ΠΈΡ˜Π°Ρ‚Π΅Ρ™ΠΈΡ‚ΠΈ са Π , Π¦++ ΠΈ нСуронским ΠΌΡ€Π΅ΠΆΠ°ΠΌΠ°

Π₯Сј Π₯Π°Π±Ρ€!

ΠŸΡ€ΠΎΡˆΠ»Π΅ јСсСни, КагглС јС Π±ΠΈΠΎ Π΄ΠΎΠΌΠ°Ρ›ΠΈΠ½ Ρ‚Π°ΠΊΠΌΠΈΡ‡Π΅ΡšΠ° Π·Π° ΠΊΠ»Π°ΡΠΈΡ„ΠΈΠΊΠ°Ρ†ΠΈΡ˜Ρƒ Ρ€ΡƒΡ‡Π½ΠΎ Π½Π°Ρ†Ρ€Ρ‚Π°Π½ΠΈΡ… слика, ΠšΡƒΠΈΡ†ΠΊ Π”Ρ€Π°Π² Π”ΠΎΠΎΠ΄Π»Π΅ Π Π΅Ρ†ΠΎΠ³Π½ΠΈΡ‚ΠΈΠΎΠ½, Ρƒ којСм јС, ΠΈΠ·ΠΌΠ΅Ρ’Ρƒ осталих, учСствовао ΠΈ Ρ‚ΠΈΠΌ Π -Π½Π°ΡƒΡ‡Π½ΠΈΠΊΠ°: АртСм ΠšΠ»Π΅Π²Ρ‚ΡΠΎΠ²Π°, ΠŸΡ…ΠΈΠ»ΠΈΠΏΠΏΠ° ΠœΠ°Π½Π°Π³Π΅Ρ€ ΠΈ ΠΠ½Π΄Ρ€Π΅Ρ˜ ΠžΠ³ΡƒΡ€Ρ†ΠΎΠ². НСћСмо Π΄Π΅Ρ‚Π°Ρ™Π½ΠΎ описивати Ρ‚Π°ΠΊΠΌΠΈΡ‡Π΅ΡšΠ΅, Ρ‚ΠΎ јС Π²Π΅Ρ› ΡƒΡ€Π°Ρ’Π΅Π½ΠΎ Π½Π΅Π΄Π°Π²Π½Π° ΠΏΡƒΠ±Π»ΠΈΠΊΠ°Ρ†ΠΈΡ˜Π°.

Овога ΠΏΡƒΡ‚Π° нијС ишло са ΡƒΠ·Π³ΠΎΡ˜Π΅ΠΌ ΠΌΠ΅Π΄Π°Ρ™Π°, Π°Π»ΠΈ јС стСчСно ΠΌΠ½ΠΎΠ³ΠΎ Π΄Ρ€Π°Π³ΠΎΡ†Π΅Π½ΠΎΠ³ искуства, ΠΏΠ° Π±ΠΈΡ… ΠΆΠ΅Π»Π΅ΠΎ Π΄Π° испричам Π·Π°Ρ˜Π΅Π΄Π½ΠΈΡ†ΠΈ Π½Π΅ΠΊΠΎΠ»ΠΈΠΊΠΎ Π½Π°Ρ˜Π·Π°Π½ΠΈΠΌΡ™ΠΈΠ²ΠΈΡ˜ΠΈΡ… ΠΈ Π½Π°Ρ˜ΠΊΠΎΡ€ΠΈΡΠ½ΠΈΡ˜ΠΈΡ… ствари Π½Π° ΠšΠ°Π³Π»Π΅Ρƒ ΠΈ Ρƒ свакоднСвном Ρ€Π°Π΄Ρƒ. ΠœΠ΅Ρ’Ρƒ Ρ‚Π΅ΠΌΠ°ΠΌΠ° ΠΎ којима сС Ρ€Π°Π·Π³ΠΎΠ²Π°Ρ€Π°Π»ΠΎ: Ρ‚Π΅ΠΆΠ°ΠΊ ΠΆΠΈΠ²ΠΎΡ‚ Π±Π΅Π· ΠžΠΏΠ΅Π½Π¦Π’, ЈБОН Ρ€Π°ΡˆΡ‡Π»Π°ΡšΠΈΠ²Π°ΡšΠ΅ (ΠΎΠ²ΠΈ ΠΏΡ€ΠΈΠΌΠ΅Ρ€ΠΈ ΠΈΡΠΏΠΈΡ‚ΡƒΡ˜Ρƒ ΠΈΠ½Ρ‚Π΅Π³Ρ€Π°Ρ†ΠΈΡ˜Ρƒ Π¦++ ΠΊΠΎΠ΄Π° Ρƒ скриптС ΠΈΠ»ΠΈ ΠΏΠ°ΠΊΠ΅Ρ‚Π΅ Ρƒ Π  користСћи Π Ρ†ΠΏΠΏ), ΠΏΠ°Ρ€Π°ΠΌΠ΅Ρ‚Ρ€ΠΈΠ·Π°Ρ†ΠΈΡ˜Π° скрипти ΠΈ Π΄ΠΎΠΊΠ΅Ρ€ΠΈΠ·Π°Ρ†ΠΈΡ˜Π° ΠΊΠΎΠ½Π°Ρ‡Π½ΠΎΠ³ Ρ€Π΅ΡˆΠ΅ΡšΠ°. Π‘Π°Π² ΠΊΠΎΠ΄ ΠΈΠ· ΠΏΠΎΡ€ΡƒΠΊΠ΅ Ρƒ ΠΎΠ±Π»ΠΈΠΊΡƒ ΠΏΠΎΠ³ΠΎΠ΄Π½ΠΎΠΌ Π·Π° ΠΈΠ·Π²Ρ€ΡˆΠ΅ΡšΠ΅ јС доступан Ρƒ ΡΠΏΡ€Π΅ΠΌΠΈΡˆΡ‚Π°.

Π‘Π°Π΄Ρ€ΠΆΠ°Ρ˜:

  1. Ефикасно ΡƒΡ‡ΠΈΡ‚Π°Ρ˜Ρ‚Π΅ ΠΏΠΎΠ΄Π°Ρ‚ΠΊΠ΅ ΠΈΠ· Π¦Π‘Π’-Π° Ρƒ ΠœΠΎΠ½Π΅Ρ‚Π”Π‘
  2. ΠŸΡ€ΠΈΠΏΡ€Π΅ΠΌΠ° ΡΠ΅Ρ€ΠΈΡ˜Π°
  3. Π˜Ρ‚Π΅Ρ€Π°Ρ‚ΠΎΡ€ΠΈ Π·Π° истовар ΠΏΠ°ΠΊΠ΅Ρ‚Π° ΠΈΠ· Π±Π°Π·Π΅ ΠΏΠΎΠ΄Π°Ρ‚Π°ΠΊΠ°
  4. Π˜Π·Π±ΠΎΡ€ Π°Ρ€Ρ…ΠΈΡ‚Π΅ΠΊΡ‚ΡƒΡ€Π΅ ΠΌΠΎΠ΄Π΅Π»Π°
  5. ΠŸΠ°Ρ€Π°ΠΌΠ΅Ρ‚Π΅Ρ€ΠΈΠ·Π°Ρ†ΠΈΡ˜Π° скриптС
  6. Π”ΠΎΠΊΠ΅Ρ€ΠΈΠ·Π°Ρ†ΠΈΡ˜Π° скрипти
  7. ΠšΠΎΡ€ΠΈΡˆΡ›Π΅ΡšΠ΅ вишС Π“ΠŸΠ£-Π° Π½Π° Π“ΠΎΠΎΠ³Π»Π΅ Π¦Π»ΠΎΡƒΠ΄-Ρƒ
  8. УмСсто Π·Π°ΠΊΡ™ΡƒΡ‡ΠΊΠ°

1. Ефикасно ΡƒΡ‡ΠΈΡ‚Π°Ρ˜Ρ‚Π΅ ΠΏΠΎΠ΄Π°Ρ‚ΠΊΠ΅ ΠΈΠ· Π¦Π‘Π’-Π° Ρƒ ΠœΠΎΠ½Π΅Ρ‚Π”Π‘ Π±Π°Π·Ρƒ ΠΏΠΎΠ΄Π°Ρ‚Π°ΠΊΠ°

ΠŸΠΎΠ΄Π°Ρ†ΠΈ Ρƒ ΠΎΠ²ΠΎΠΌ конкурсу нису Π΄Π°Ρ‚ΠΈ Ρƒ ΠΎΠ±Π»ΠΈΠΊΡƒ Π³ΠΎΡ‚ΠΎΠ²ΠΈΡ… слика, Π²Π΅Ρ› Ρƒ ΠΎΠ±Π»ΠΈΠΊΡƒ 340 Π¦Π‘Π’ Ρ„Π°Ρ˜Π»ΠΎΠ²Π° (ΠΏΠΎ јСдан Ρ„Π°Ρ˜Π» Π·Π° сваку класу) који садрТС ЈБОН са ΠΊΠΎΠΎΡ€Π΄ΠΈΠ½Π°Ρ‚Π°ΠΌΠ° Ρ‚Π°Ρ‡Π°ΠΊΠ°. ПовСзивањСм ΠΎΠ²ΠΈΡ… Ρ‚Π°Ρ‡Π°ΠΊΠ° линијама добијамо ΠΊΠΎΠ½Π°Ρ‡Π½Ρƒ слику димСнзија 256ΠΊ256 пиксСла. Π’Π°ΠΊΠΎΡ’Π΅ Π·Π° сваки запис ΠΏΠΎΡΡ‚ΠΎΡ˜ΠΈ ΠΎΠ·Π½Π°ΠΊΠ° која ΠΏΠΎΠΊΠ°Π·ΡƒΡ˜Π΅ Π΄Π° Π»ΠΈ јС слику исправно ΠΏΡ€Π΅ΠΏΠΎΠ·Π½Π°ΠΎ класификатор који јС ΠΊΠΎΡ€ΠΈΡˆΡ›Π΅Π½ Ρƒ Π²Ρ€Π΅ΠΌΠ΅ ΠΏΡ€ΠΈΠΊΡƒΠΏΡ™Π°ΡšΠ° скупа ΠΏΠΎΠ΄Π°Ρ‚Π°ΠΊΠ°, двословни ΠΊΠΎΠ΄ Π·Π΅ΠΌΡ™Π΅ ΠΏΡ€Π΅Π±ΠΈΠ²Π°Π»ΠΈΡˆΡ‚Π° Π°ΡƒΡ‚ΠΎΡ€Π° сликС, Ρ˜Π΅Π΄ΠΈΠ½ΡΡ‚Π²Π΅Π½ΠΈ ΠΈΠ΄Π΅Π½Ρ‚ΠΈΡ„ΠΈΠΊΠ°Ρ‚ΠΎΡ€, врСмСнска ΠΎΠ·Π½Π°ΠΊΠ° ΠΈ ΠΈΠΌΠ΅ класС којС ΠΎΠ΄Π³ΠΎΠ²Π°Ρ€Π° ΠΈΠΌΠ΅Π½Ρƒ Π΄Π°Ρ‚ΠΎΡ‚Π΅ΠΊΠ΅. ΠŸΠΎΡ˜Π΅Π΄Π½ΠΎΡΡ‚Π°Π²Ρ™Π΅Π½Π° Π²Π΅Ρ€Π·ΠΈΡ˜Π° ΠΎΡ€ΠΈΠ³ΠΈΠ½Π°Π»Π½ΠΈΡ… ΠΏΠΎΠ΄Π°Ρ‚Π°ΠΊΠ° Ρ‚Π΅ΠΆΠΈ 7.4 Π“Π‘ Ρƒ Π°Ρ€Ρ…ΠΈΠ²ΠΈ ΠΈ ΠΏΡ€ΠΈΠ±Π»ΠΈΠΆΠ½ΠΎ 20 Π“Π‘ Π½Π°ΠΊΠΎΠ½ Ρ€Π°ΡΠΏΠ°ΠΊΠΈΠ²Π°ΡšΠ°, ΠΏΡƒΠ½ΠΈ ΠΏΠΎΠ΄Π°Ρ†ΠΈ Π½Π°ΠΊΠΎΠ½ Ρ€Π°ΡΠΏΠ°ΠΊΠΈΠ²Π°ΡšΠ° Π·Π°ΡƒΠ·ΠΈΠΌΠ°Ρ˜Ρƒ 240 Π“Π‘. ΠžΡ€Π³Π°Π½ΠΈΠ·Π°Ρ‚ΠΎΡ€ΠΈ су ΠΎΠ±Π΅Π·Π±Π΅Π΄ΠΈΠ»ΠΈ Π΄Π° ΠΎΠ±Π΅ Π²Π΅Ρ€Π·ΠΈΡ˜Π΅ Ρ€Π΅ΠΏΡ€ΠΎΠ΄ΡƒΠΊΡƒΡ˜Ρƒ истС Ρ†Ρ€Ρ‚Π΅ΠΆΠ΅, ΡˆΡ‚ΠΎ Π·Π½Π°Ρ‡ΠΈ Π΄Π° јС ΠΏΡƒΠ½Π° Π²Π΅Ρ€Π·ΠΈΡ˜Π° ΡΡƒΠ²ΠΈΡˆΠ½Π°. Π£ сваком ΡΠ»ΡƒΡ‡Π°Ρ˜Ρƒ, ΡΠΊΠ»Π°Π΄ΠΈΡˆΡ‚Π΅ΡšΠ΅ 50 ΠΌΠΈΠ»ΠΈΠΎΠ½Π° слика Ρƒ Π³Ρ€Π°Ρ„ΠΈΡ‡ΠΊΠΈΠΌ Π΄Π°Ρ‚ΠΎΡ‚Π΅ΠΊΠ°ΠΌΠ° ΠΈΠ»ΠΈ Ρƒ ΠΎΠ±Π»ΠΈΠΊΡƒ Π½ΠΈΠ·ΠΎΠ²Π° ΠΎΠ΄ΠΌΠ°Ρ… јС сматрано нСисплативим, ΠΏΠ° смо ΠΎΠ΄Π»ΡƒΡ‡ΠΈΠ»ΠΈ Π΄Π° спојимо свС Π¦Π‘Π’ Π΄Π°Ρ‚ΠΎΡ‚Π΅ΠΊΠ΅ ΠΈΠ· Π°Ρ€Ρ…ΠΈΠ²Π΅ Ρ‚Ρ€Π°ΠΈΠ½_симплифиСд.Π·ΠΈΠΏ Ρƒ Π±Π°Π·Ρƒ ΠΏΠΎΠ΄Π°Ρ‚Π°ΠΊΠ° са Π½Π°ΠΊΠ½Π°Π΄Π½ΠΈΠΌ Π³Π΅Π½Π΅Ρ€ΠΈΡΠ°ΡšΠ΅ΠΌ слика ΠΏΠΎΡ‚Ρ€Π΅Π±Π½Π΅ Π²Π΅Π»ΠΈΡ‡ΠΈΠ½Π΅ β€žΡƒ Ρ…ΠΎΠ΄Ρƒβ€œ Π·Π° сваку ΡΠ΅Ρ€ΠΈΡ˜Ρƒ.

Као Π”Π‘ΠœΠ‘ ΠΈΠ·Π°Π±Ρ€Π°Π½ јС Π΄ΠΎΠ±Ρ€ΠΎ Π΄ΠΎΠΊΠ°Π·Π°Π½ систСм ΠœΠΎΠ½Π΅Ρ‚Π”Π‘, односно ΠΈΠΌΠΏΠ»Π΅ΠΌΠ΅Π½Ρ‚Π°Ρ†ΠΈΡ˜Π° Π·Π° Π  ΠΊΠ°ΠΎ ΠΏΠ°ΠΊΠ΅Ρ‚ ΠœΠΎΠ½Π΅Ρ‚Π”Π‘Π›ΠΈΡ‚Π΅. ΠŸΠ°ΠΊΠ΅Ρ‚ ΡƒΠΊΡ™ΡƒΡ‡ΡƒΡ˜Π΅ ΡƒΠ³Ρ€Π°Ρ’Π΅Π½Ρƒ Π²Π΅Ρ€Π·ΠΈΡ˜Ρƒ сСрвСра Π±Π°Π·Π΅ ΠΏΠΎΠ΄Π°Ρ‚Π°ΠΊΠ° ΠΈ ΠΎΠΌΠΎΠ³ΡƒΡ›Π°Π²Π° Π²Π°ΠΌ Π΄Π° ΠΏΡ€Π΅ΡƒΠ·ΠΌΠ΅Ρ‚Π΅ сСрвСр Π΄ΠΈΡ€Π΅ΠΊΡ‚Π½ΠΎ ΠΈΠ· Π  сСсијС ΠΈ Ρ‚Π°ΠΌΠΎ Ρ€Π°Π΄ΠΈΡ‚Π΅ са њим. ΠšΡ€Π΅ΠΈΡ€Π°ΡšΠ΅ Π±Π°Π·Π΅ ΠΏΠΎΠ΄Π°Ρ‚Π°ΠΊΠ° ΠΈ повСзивањС са њом Π²Ρ€ΡˆΠΈ сС јСдном ΠΊΠΎΠΌΠ°Π½Π΄ΠΎΠΌ:

con <- DBI::dbConnect(drv = MonetDBLite::MonetDBLite(), Sys.getenv("DBDIR"))

ΠœΠΎΡ€Π°Ρ›Π΅ΠΌΠΎ Π΄Π° Π½Π°ΠΏΡ€Π°Π²ΠΈΠΌΠΎ Π΄Π²Π΅ Ρ‚Π°Π±Π΅Π»Π΅: Ρ˜Π΅Π΄Π½Ρƒ Π·Π° свС ΠΏΠΎΠ΄Π°Ρ‚ΠΊΠ΅, Π΄Ρ€ΡƒΠ³Ρƒ Π·Π° сСрвиснС ΠΈΠ½Ρ„ΠΎΡ€ΠΌΠ°Ρ†ΠΈΡ˜Π΅ ΠΎ ΠΏΡ€Π΅ΡƒΠ·Π΅Ρ‚ΠΈΠΌ Π΄Π°Ρ‚ΠΎΡ‚Π΅ΠΊΠ°ΠΌΠ° (корисно Π°ΠΊΠΎ Π½Π΅ΡˆΡ‚ΠΎ ΠΊΡ€Π΅Π½Π΅ Π½Π°ΠΎΠΏΠ°ΠΊΠΎ ΠΈ процСс ΠΌΠΎΡ€Π° Π΄Π° сС настави Π½Π°ΠΊΠΎΠ½ ΠΏΡ€Π΅ΡƒΠ·ΠΈΠΌΠ°ΡšΠ° Π½Π΅ΠΊΠΎΠ»ΠΈΠΊΠΎ Π΄Π°Ρ‚ΠΎΡ‚Π΅ΠΊΠ°):

ΠšΡ€Π΅ΠΈΡ€Π°ΡšΠ΅ Ρ‚Π°Π±Π΅Π»Π°

if (!DBI::dbExistsTable(con, "doodles")) {
  DBI::dbCreateTable(
    con = con,
    name = "doodles",
    fields = c(
      "countrycode" = "char(2)",
      "drawing" = "text",
      "key_id" = "bigint",
      "recognized" = "bool",
      "timestamp" = "timestamp",
      "word" = "text"
    )
  )
}

if (!DBI::dbExistsTable(con, "upload_log")) {
  DBI::dbCreateTable(
    con = con,
    name = "upload_log",
    fields = c(
      "id" = "serial",
      "file_name" = "text UNIQUE",
      "uploaded" = "bool DEFAULT false"
    )
  )
}

ΠΠ°Ρ˜Π±Ρ€ΠΆΠΈ Π½Π°Ρ‡ΠΈΠ½ Π·Π° ΡƒΡ‡ΠΈΡ‚Π°Π²Π°ΡšΠ΅ ΠΏΠΎΠ΄Π°Ρ‚Π°ΠΊΠ° Ρƒ Π±Π°Π·Ρƒ ΠΏΠΎΠ΄Π°Ρ‚Π°ΠΊΠ° Π±ΠΈΠΎ јС Π΄ΠΈΡ€Π΅ΠΊΡ‚Π½ΠΎ ΠΊΠΎΠΏΠΈΡ€Π°ΡšΠ΅ Π¦Π‘Π’ Π΄Π°Ρ‚ΠΎΡ‚Π΅ΠΊΠ° ΠΏΠΎΠΌΠΎΡ›Ρƒ Π‘ΠšΠ› - ΠΊΠΎΠΌΠ°Π½Π΄Π΅ COPY OFFSET 2 INTO tablename FROM path USING DELIMITERS ',','n','"' NULL AS '' BEST EFFORTΠ“Π΄Π΅ tablename - Π½Π°Π·ΠΈΠ² Ρ‚Π°Π±Π΅Π»Π΅ ΠΈ path - ΠΏΡƒΡ‚Π°ΡšΠ° Π΄ΠΎ Π΄Π°Ρ‚ΠΎΡ‚Π΅ΠΊΠ΅. Π’ΠΎΠΊΠΎΠΌ Ρ€Π°Π΄Π° са Π°Ρ€Ρ…ΠΈΠ²ΠΎΠΌ ΠΎΡ‚ΠΊΡ€ΠΈΠ²Π΅Π½ΠΎ јС Π΄Π° јС ΡƒΠ³Ρ€Π°Ρ’Π΅Π½Π° ΠΈΠΌΠΏΠ»Π΅ΠΌΠ΅Π½Ρ‚Π°Ρ†ΠΈΡ˜Π° unzip Ρƒ Π  Π½Π΅ Ρ€Π°Π΄ΠΈ исправно са Π²Π΅Ρ›ΠΈΠΌ Π±Ρ€ΠΎΡ˜Π΅ΠΌ Π΄Π°Ρ‚ΠΎΡ‚Π΅ΠΊΠ° ΠΈΠ· Π°Ρ€Ρ…ΠΈΠ²Π΅, ΠΏΠ° смо користили систСм unzip (користСћи ΠΏΠ°Ρ€Π°ΠΌΠ΅Ρ‚Π°Ρ€ getOption("unzip")).

Π€ΡƒΠ½ΠΊΡ†ΠΈΡ˜Π° Π·Π° упис Ρƒ Π±Π°Π·Ρƒ ΠΏΠΎΠ΄Π°Ρ‚Π°ΠΊΠ°

#' @title Π˜Π·Π²Π»Π΅Ρ‡Π΅Π½ΠΈΠ΅ ΠΈ Π·Π°Π³Ρ€ΡƒΠ·ΠΊΠ° Ρ„Π°ΠΉΠ»ΠΎΠ²
#'
#' @description
#' Π˜Π·Π²Π»Π΅Ρ‡Π΅Π½ΠΈΠ΅ CSV-Ρ„Π°ΠΉΠ»ΠΎΠ² ΠΈΠ· ZIP-Π°Ρ€Ρ…ΠΈΠ²Π° ΠΈ Π·Π°Π³Ρ€ΡƒΠ·ΠΊΠ° ΠΈΡ… Π² Π±Π°Π·Ρƒ Π΄Π°Π½Π½Ρ‹Ρ…
#'
#' @param con ΠžΠ±ΡŠΠ΅ΠΊΡ‚ ΠΏΠΎΠ΄ΠΊΠ»ΡŽΡ‡Π΅Π½ΠΈΡ ΠΊ Π±Π°Π·Π΅ Π΄Π°Π½Π½Ρ‹Ρ… (класс `MonetDBEmbeddedConnection`).
#' @param tablename НазваниС Ρ‚Π°Π±Π»ΠΈΡ†Ρ‹ Π² Π±Π°Π·Π΅ Π΄Π°Π½Π½Ρ‹Ρ….
#' @oaram zipfile ΠŸΡƒΡ‚ΡŒ ΠΊ ZIP-Π°Ρ€Ρ…ΠΈΠ²Ρƒ.
#' @oaram filename Имя Ρ„Π°ΠΉΠ»Π° Π²Π½ΡƒΡ€ΠΈ ZIP-Π°Ρ€Ρ…ΠΈΠ²Π°.
#' @param preprocess Ѐункция ΠΏΡ€Π΅Π΄ΠΎΠ±Ρ€Π°Π±ΠΎΡ‚ΠΊΠΈ, которая Π±ΡƒΠ΄Π΅Ρ‚ ΠΏΡ€ΠΈΠΌΠ΅Π½Π΅Π½Π° ΠΈΠ·Π²Π»Π΅Ρ‡Ρ‘Π½Π½ΠΎΠΌΡƒ Ρ„Π°ΠΉΠ»Ρƒ.
#'   Π”ΠΎΠ»ΠΆΠ½Π° ΠΏΡ€ΠΈΠ½ΠΈΠΌΠ°Ρ‚ΡŒ ΠΎΠ΄ΠΈΠ½ Π°Ρ€Π³ΡƒΠΌΠ΅Π½Ρ‚ `data` (ΠΎΠ±ΡŠΠ΅ΠΊΡ‚ `data.table`).
#'
#' @return `TRUE`.
#'
upload_file <- function(con, tablename, zipfile, filename, preprocess = NULL) {
  # ΠŸΡ€ΠΎΠ²Π΅Ρ€ΠΊΠ° Π°Ρ€Π³ΡƒΠΌΠ΅Π½Ρ‚ΠΎΠ²
  checkmate::assert_class(con, "MonetDBEmbeddedConnection")
  checkmate::assert_string(tablename)
  checkmate::assert_string(filename)
  checkmate::assert_true(DBI::dbExistsTable(con, tablename))
  checkmate::assert_file_exists(zipfile, access = "r", extension = "zip")
  checkmate::assert_function(preprocess, args = c("data"), null.ok = TRUE)

  # Π˜Π·Π²Π»Π΅Ρ‡Π΅Π½ΠΈΠ΅ Ρ„Π°ΠΉΠ»Π°
  path <- file.path(tempdir(), filename)
  unzip(zipfile, files = filename, exdir = tempdir(), 
        junkpaths = TRUE, unzip = getOption("unzip"))
  on.exit(unlink(file.path(path)))

  # ΠŸΡ€ΠΈΠΌΠ΅Π½ΡΠ΅ΠΌ функция ΠΏΡ€Π΅Π΄ΠΎΠ±Ρ€Π°Π±ΠΎΡ‚ΠΊΠΈ
  if (!is.null(preprocess)) {
    .data <- data.table::fread(file = path)
    .data <- preprocess(data = .data)
    data.table::fwrite(x = .data, file = path, append = FALSE)
    rm(.data)
  }

  # Запрос ΠΊ Π‘Π” Π½Π° ΠΈΠΌΠΏΠΎΡ€Ρ‚ CSV
  sql <- sprintf(
    "COPY OFFSET 2 INTO %s FROM '%s' USING DELIMITERS ',','n','"' NULL AS '' BEST EFFORT",
    tablename, path
  )
  # Π’Ρ‹ΠΏΠΎΠ»Π½Π΅Π½ΠΈΠ΅ запроса ΠΊ Π‘Π”
  DBI::dbExecute(con, sql)

  # Π”ΠΎΠ±Π°Π²Π»Π΅Π½ΠΈΠ΅ записи ΠΎΠ± ΡƒΡΠΏΠ΅ΡˆΠ½ΠΎΠΉ Π·Π°Π³Ρ€ΡƒΠ·ΠΊΠ΅ Π² ΡΠ»ΡƒΠΆΠ΅Π±Π½ΡƒΡŽ Ρ‚Π°Π±Π»ΠΈΡ†Ρƒ
  DBI::dbExecute(con, sprintf("INSERT INTO upload_log(file_name, uploaded) VALUES('%s', true)",
                              filename))

  return(invisible(TRUE))
}

Ако Ρ‚Ρ€Π΅Π±Π° Π΄Π° Ρ‚Ρ€Π°Π½ΡΡ„ΠΎΡ€ΠΌΠΈΡˆΠ΅Ρ‚Π΅ Ρ‚Π°Π±Π΅Π»Ρƒ ΠΏΡ€Π΅ Π½Π΅Π³ΠΎ ΡˆΡ‚ΠΎ јС ΡƒΠΏΠΈΡˆΠ΅Ρ‚Π΅ Ρƒ Π±Π°Π·Ρƒ ΠΏΠΎΠ΄Π°Ρ‚Π°ΠΊΠ°, Π΄ΠΎΠ²ΠΎΡ™Π½ΠΎ јС Π΄Π° прослСдитС Π°Ρ€Π³ΡƒΠΌΠ΅Π½Ρ‚ preprocess Ρ„ΡƒΠ½ΠΊΡ†ΠΈΡ˜Π° која Ρ›Π΅ трансформисати ΠΏΠΎΠ΄Π°Ρ‚ΠΊΠ΅.

Код Π·Π° ΡΠ΅ΠΊΠ²Π΅Π½Ρ†ΠΈΡ˜Π°Π»Π½ΠΎ ΡƒΡ‡ΠΈΡ‚Π°Π²Π°ΡšΠ΅ ΠΏΠΎΠ΄Π°Ρ‚Π°ΠΊΠ° Ρƒ Π±Π°Π·Ρƒ ΠΏΠΎΠ΄Π°Ρ‚Π°ΠΊΠ°:

УписивањС ΠΏΠΎΠ΄Π°Ρ‚Π°ΠΊΠ° Ρƒ Π±Π°Π·Ρƒ ΠΏΠΎΠ΄Π°Ρ‚Π°ΠΊΠ°

# Бписок Ρ„Π°ΠΉΠ»ΠΎΠ² для записи
files <- unzip(zipfile, list = TRUE)$Name

# Бписок ΠΈΡΠΊΠ»ΡŽΡ‡Π΅Π½ΠΈΠΉ, Ссли Ρ‡Π°ΡΡ‚ΡŒ Ρ„Π°ΠΉΠ»ΠΎΠ² ΡƒΠΆΠ΅ Π±Ρ‹Π»Π° Π·Π°Π³Ρ€ΡƒΠΆΠ΅Π½Π°
to_skip <- DBI::dbGetQuery(con, "SELECT file_name FROM upload_log")[[1L]]
files <- setdiff(files, to_skip)

if (length(files) > 0L) {
  # ЗапускаСм Ρ‚Π°ΠΉΠΌΠ΅Ρ€
  tictoc::tic()
  # ΠŸΡ€ΠΎΠ³Ρ€Π΅ΡΡ Π±Π°Ρ€
  pb <- txtProgressBar(min = 0L, max = length(files), style = 3)
  for (i in seq_along(files)) {
    upload_file(con = con, tablename = "doodles", 
                zipfile = zipfile, filename = files[i])
    setTxtProgressBar(pb, i)
  }
  close(pb)
  # ΠžΡΡ‚Π°Π½Π°Π²Π»ΠΈΠ²Π°Π΅ΠΌ Ρ‚Π°ΠΉΠΌΠ΅Ρ€
  tictoc::toc()
}

# 526.141 sec elapsed - ΠΊΠΎΠΏΠΈΡ€ΠΎΠ²Π°Π½ΠΈΠ΅ SSD->SSD
# 558.879 sec elapsed - ΠΊΠΎΠΏΠΈΡ€ΠΎΠ²Π°Π½ΠΈΠ΅ USB->SSD

Π’Ρ€Π΅ΠΌΠ΅ ΡƒΡ‡ΠΈΡ‚Π°Π²Π°ΡšΠ° ΠΏΠΎΠ΄Π°Ρ‚Π°ΠΊΠ° ΠΌΠΎΠΆΠ΅ Π΄Π° Π²Π°Ρ€ΠΈΡ€Π° Ρƒ зависности ΠΎΠ΄ карактСристика Π±Ρ€Π·ΠΈΠ½Π΅ ΠΊΠΎΡ€ΠΈΡˆΡ›Π΅Π½ΠΎΠ³ Π΄Ρ€Π°Ρ˜Π²Π°. Π£ нашСм ΡΠ»ΡƒΡ‡Π°Ρ˜Ρƒ, Ρ‡ΠΈΡ‚Π°ΡšΠ΅ ΠΈ писањС ΡƒΠ½ΡƒΡ‚Π°Ρ€ јСдног Π‘Π‘Π”-Π° ΠΈΠ»ΠΈ са Ρ„Π»Π΅Ρˆ диска (ΠΈΠ·Π²ΠΎΡ€Π½Π΅ Π΄Π°Ρ‚ΠΎΡ‚Π΅ΠΊΠ΅) Π½Π° Π‘Π‘Π” (Π”Π‘) Ρ‚Ρ€Π°Ρ˜Π΅ мањС ΠΎΠ΄ 10 ΠΌΠΈΠ½ΡƒΡ‚Π°.

ΠŸΠΎΡ‚Ρ€Π΅Π±Π½ΠΎ јС још Π½Π΅ΠΊΠΎΠ»ΠΈΠΊΠΎ сСкунди Π΄Π° сС Π½Π°ΠΏΡ€Π°Π²ΠΈ ΠΊΠΎΠ»ΠΎΠ½Π° са Ρ†Π΅Π»ΠΎΠ±Ρ€ΠΎΡ˜Π½ΠΎΠΌ ΠΎΠ·Π½Π°ΠΊΠΎΠΌ класС ΠΈ ΠΊΠΎΠ»ΠΎΠ½ΠΎΠΌ индСкса (ORDERED INDEX) са Π±Ρ€ΠΎΡ˜Π΅Π²ΠΈΠΌΠ° Ρ€Π΅Π΄ΠΎΠ²Π° ΠΏΠΎΠΌΠΎΡ›Ρƒ ΠΊΠΎΡ˜ΠΈΡ… Ρ›Π΅ сС ΡƒΠ·ΠΎΡ€ΠΊΠΎΠ²Π°Ρ‚ΠΈ запаТања ΠΏΡ€ΠΈΠ»ΠΈΠΊΠΎΠΌ ΠΊΡ€Π΅ΠΈΡ€Π°ΡšΠ° ΡΠ΅Ρ€ΠΈΡ˜Π°:

ΠšΡ€Π΅ΠΈΡ€Π°ΡšΠ΅ Π΄ΠΎΠ΄Π°Ρ‚Π½ΠΈΡ… ΠΊΠΎΠ»ΠΎΠ½Π° ΠΈ индСкса

message("Generate lables")
invisible(DBI::dbExecute(con, "ALTER TABLE doodles ADD label_int int"))
invisible(DBI::dbExecute(con, "UPDATE doodles SET label_int = dense_rank() OVER (ORDER BY word) - 1"))

message("Generate row numbers")
invisible(DBI::dbExecute(con, "ALTER TABLE doodles ADD id serial"))
invisible(DBI::dbExecute(con, "CREATE ORDERED INDEX doodles_id_ord_idx ON doodles(id)"))

Π”Π° бисмо Ρ€Π΅ΡˆΠΈΠ»ΠΈ ΠΏΡ€ΠΎΠ±Π»Π΅ΠΌ ΠΊΡ€Π΅ΠΈΡ€Π°ΡšΠ° ΡΠ΅Ρ€ΠΈΡ˜Π΅ Ρƒ Ρ…ΠΎΠ΄Ρƒ, ΠΌΠΎΡ€Π°Π»ΠΈ смо Π΄Π° постигнСмо максималну Π±Ρ€Π·ΠΈΠ½Ρƒ издвајања насумичних Ρ€Π΅Π΄ΠΎΠ²Π° ΠΈΠ· Ρ‚Π°Π±Π΅Π»Π΅ doodles. Π—Π° ΠΎΠ²ΠΎ смо користили 3 Ρ‚Ρ€ΠΈΠΊΠ°. ΠŸΡ€Π²ΠΈ јС Π±ΠΈΠΎ Π΄Π° сС смањи димСнзионалност Ρ‚ΠΈΠΏΠ° који Ρ‡ΡƒΠ²Π° Π˜Π” ΠΏΠΎΡΠΌΠ°Ρ‚Ρ€Π°ΡšΠ°. Π£ ΠΎΡ€ΠΈΠ³ΠΈΠ½Π°Π»Π½ΠΎΠΌ скупу ΠΏΠΎΠ΄Π°Ρ‚Π°ΠΊΠ°, Ρ‚ΠΈΠΏ који јС ΠΏΠΎΡ‚Ρ€Π΅Π±Π°Π½ Π·Π° Ρ‡ΡƒΠ²Π°ΡšΠ΅ Π˜Π”-Π° јС bigint, Π°Π»ΠΈ Π±Ρ€ΠΎΡ˜ запаТања ΠΎΠΌΠΎΠ³ΡƒΡ›Π°Π²Π° Π΄Π° сС ΡšΠΈΡ…ΠΎΠ²ΠΈ ΠΈΠ΄Π΅Π½Ρ‚ΠΈΡ„ΠΈΠΊΠ°Ρ‚ΠΎΡ€ΠΈ, јСднаки Ρ€Π΅Π΄Π½ΠΎΠΌ Π±Ρ€ΠΎΡ˜Ρƒ, ΡƒΠΊΠ»ΠΎΠΏΠ΅ Ρƒ Ρ‚ΠΈΠΏ int. ΠŸΡ€Π΅Ρ‚Ρ€Π°Π³Π° јС Ρƒ ΠΎΠ²ΠΎΠΌ ΡΠ»ΡƒΡ‡Π°Ρ˜Ρƒ ΠΌΠ½ΠΎΠ³ΠΎ Π±Ρ€ΠΆΠ°. Π”Ρ€ΡƒΠ³ΠΈ Ρ‚Ρ€ΠΈΠΊ јС Π±ΠΈΠΎ ΠΊΠΎΡ€ΠΈΡˆΡ›Π΅ΡšΠ΅ ORDERED INDEX β€” Π΄ΠΎ ΠΎΠ²Π΅ ΠΎΠ΄Π»ΡƒΠΊΠ΅ смо дошли Π΅ΠΌΠΏΠΈΡ€ΠΈΡ˜ΡΠΊΠΈ, ΠΏΡ€ΠΎΡˆΠ°Π²ΡˆΠΈ свС располоТивС ΠΎΠΏΡ†ΠΈΡ˜Π΅. Π’Ρ€Π΅Ρ›ΠΈ јС Π±ΠΈΠΎ ΠΊΠΎΡ€ΠΈΡˆΡ›Π΅ΡšΠ΅ ΠΏΠ°Ρ€Π°ΠΌΠ΅Ρ‚Ρ€ΠΈΠ·ΠΎΠ²Π°Π½ΠΈΡ… ΡƒΠΏΠΈΡ‚Π°. Π‘ΡƒΡˆΡ‚ΠΈΠ½Π° ΠΌΠ΅Ρ‚ΠΎΠ΄Π΅ јС Π΄Π° сС Π½Π°Ρ€Π΅Π΄Π±Π° ΠΈΠ·Π²Ρ€ΡˆΠΈ јСдном PREPARE ΡƒΠ· Π½Π°ΠΊΠ½Π°Π΄Π½Ρƒ ΡƒΠΏΠΎΡ‚Ρ€Π΅Π±Ρƒ ΠΏΡ€ΠΈΠΏΡ€Π΅ΠΌΡ™Π΅Π½ΠΎΠ³ ΠΈΠ·Ρ€Π°Π·Π° ΠΏΡ€ΠΈ ΠΊΡ€Π΅ΠΈΡ€Π°ΡšΡƒ Π³ΠΎΠΌΠΈΠ»Π΅ ΡƒΠΏΠΈΡ‚Π° истог Ρ‚ΠΈΠΏΠ°, Π°Π»ΠΈ Ρƒ ствари ΠΏΠΎΡΡ‚ΠΎΡ˜ΠΈ прСдност Ρƒ ΠΏΠΎΡ€Π΅Ρ’Π΅ΡšΡƒ са Ρ˜Π΅Π΄Π½ΠΎΡΡ‚Π°Π²Π½ΠΈΠΌ SELECT испоставило сС Π΄Π° јС Ρƒ опсСгу статистичкС Π³Ρ€Π΅ΡˆΠΊΠ΅.

ΠŸΡ€ΠΎΡ†Π΅Ρ ΡƒΡ‡ΠΈΡ‚Π°Π²Π°ΡšΠ° ΠΏΠΎΠ΄Π°Ρ‚Π°ΠΊΠ° Π½Π΅ Ρ‚Ρ€ΠΎΡˆΠΈ вишС ΠΎΠ΄ 450 ΠœΠ‘ РАМ-Π°. Π’ΠΎ Ρ˜Π΅ΡΡ‚, описани приступ Π²Π°ΠΌ ΠΎΠΌΠΎΠ³ΡƒΡ›Π°Π²Π° Π΄Π° ΠΏΡ€Π΅ΠΌΠ΅ΡˆΡ‚Π°Ρ‚Π΅ скуповС ΠΏΠΎΠ΄Π°Ρ‚Π°ΠΊΠ° Ρ‚Π΅ΠΆΠΈΠ½Π΅ дСсСтинС Π³ΠΈΠ³Π°Π±Π°Ρ˜Ρ‚Π° Π½Π° скоро сваки Π±ΡƒΡŸΠ΅Ρ‚ΡΠΊΠΈ Ρ…Π°Ρ€Π΄Π²Π΅Ρ€, ΡƒΠΊΡ™ΡƒΡ‡ΡƒΡ˜ΡƒΡ›ΠΈ ΠΈ Π½Π΅ΠΊΠ΅ ΡƒΡ€Π΅Ρ’Π°Ρ˜Π΅ са јСдном ΠΏΠ»ΠΎΡ‡ΠΎΠΌ, ΡˆΡ‚ΠΎ јС ΠΏΡ€ΠΈΠ»ΠΈΡ‡Π½ΠΎ Ρ†ΠΎΠΎΠ».

ΠžΡΡ‚Π°Ρ˜Π΅ само Π΄Π° ΠΈΠ·ΠΌΠ΅Ρ€ΠΈΠΌΠΎ Π±Ρ€Π·ΠΈΠ½Ρƒ ΠΏΡ€Π΅ΡƒΠ·ΠΈΠΌΠ°ΡšΠ° (ΡΠ»ΡƒΡ‡Π°Ρ˜Π½ΠΈΡ…) ΠΏΠΎΠ΄Π°Ρ‚Π°ΠΊΠ° ΠΈ ΠΏΡ€ΠΎΡ†Π΅Π½ΠΈΠΌΠΎ ΡΠΊΠ°Π»ΠΈΡ€Π°ΡšΠ΅ ΠΏΡ€ΠΈΠ»ΠΈΠΊΠΎΠΌ ΡƒΠ·ΠΎΡ€ΠΊΠΎΠ²Π°ΡšΠ° ΡΠ΅Ρ€ΠΈΡ˜Π° Ρ€Π°Π·Π»ΠΈΡ‡ΠΈΡ‚ΠΈΡ… Π²Π΅Π»ΠΈΡ‡ΠΈΠ½Π°:

Π Π΅ΠΏΠ΅Ρ€ Π±Π°Π·Π΅ ΠΏΠΎΠ΄Π°Ρ‚Π°ΠΊΠ°

library(ggplot2)

set.seed(0)
# ΠŸΠΎΠ΄ΠΊΠ»ΡŽΡ‡Π΅Π½ΠΈΠ΅ ΠΊ Π±Π°Π·Π΅ Π΄Π°Π½Π½Ρ‹Ρ…
con <- DBI::dbConnect(MonetDBLite::MonetDBLite(), Sys.getenv("DBDIR"))

# Ѐункция для ΠΏΠΎΠ΄Π³ΠΎΡ‚ΠΎΠ²ΠΊΠΈ запроса Π½Π° сторонС сСрвСра
prep_sql <- function(batch_size) {
  sql <- sprintf("PREPARE SELECT id FROM doodles WHERE id IN (%s)",
                 paste(rep("?", batch_size), collapse = ","))
  res <- DBI::dbSendQuery(con, sql)
  return(res)
}

# Ѐункция для извлСчСния Π΄Π°Π½Π½Ρ‹Ρ…
fetch_data <- function(rs, batch_size) {
  ids <- sample(seq_len(n), batch_size)
  res <- DBI::dbFetch(DBI::dbBind(rs, as.list(ids)))
  return(res)
}

# ΠŸΡ€ΠΎΠ²Π΅Π΄Π΅Π½ΠΈΠ΅ Π·Π°ΠΌΠ΅Ρ€Π°
res_bench <- bench::press(
  batch_size = 2^(4:10),
  {
    rs <- prep_sql(batch_size)
    bench::mark(
      fetch_data(rs, batch_size),
      min_iterations = 50L
    )
  }
)
# ΠŸΠ°Ρ€Π°ΠΌΠ΅Ρ‚Ρ€Ρ‹ Π±Π΅Π½Ρ‡ΠΌΠ°Ρ€ΠΊΠ°
cols <- c("batch_size", "min", "median", "max", "itr/sec", "total_time", "n_itr")
res_bench[, cols]

#   batch_size      min   median      max `itr/sec` total_time n_itr
#        <dbl> <bch:tm> <bch:tm> <bch:tm>     <dbl>   <bch:tm> <int>
# 1         16   23.6ms  54.02ms  93.43ms     18.8        2.6s    49
# 2         32     38ms  84.83ms 151.55ms     11.4       4.29s    49
# 3         64   63.3ms 175.54ms 248.94ms     5.85       8.54s    50
# 4        128   83.2ms 341.52ms 496.24ms     3.00      16.69s    50
# 5        256  232.8ms 653.21ms 847.44ms     1.58      31.66s    50
# 6        512  784.6ms    1.41s    1.98s     0.740       1.1m    49
# 7       1024  681.7ms    2.72s    4.06s     0.377      2.16m    49

ggplot(res_bench, aes(x = factor(batch_size), y = median, group = 1)) +
  geom_point() +
  geom_line() +
  ylab("median time, s") +
  theme_minimal()

DBI::dbDisconnect(con, shutdown = TRUE)

ΠšΡƒΠΈΡ†ΠΊ Π”Ρ€Π°Π² Π”ΠΎΠΎΠ΄Π»Π΅ Π Π΅Ρ†ΠΎΠ³Π½ΠΈΡ‚ΠΈΠΎΠ½: ΠΊΠ°ΠΊΠΎ сС ΡΠΏΡ€ΠΈΡ˜Π°Ρ‚Π΅Ρ™ΠΈΡ‚ΠΈ са Π , Π¦++ ΠΈ нСуронским ΠΌΡ€Π΅ΠΆΠ°ΠΌΠ°

2. ΠŸΡ€ΠΈΠΏΡ€Π΅ΠΌΠ° ΡΠ΅Ρ€ΠΈΡ˜Π°

Π¦Π΅ΠΎ процСс ΠΏΡ€ΠΈΠΏΡ€Π΅ΠΌΠ΅ ΡΠ΅Ρ€ΠΈΡ˜Π΅ ΡΠ°ΡΡ‚ΠΎΡ˜ΠΈ сС ΠΎΠ΄ слСдСћих ΠΊΠΎΡ€Π°ΠΊΠ°:

  1. ΠŸΠ°Ρ€ΡΠΈΡ€Π°ΡšΠ΅ Π½Π΅ΠΊΠΎΠ»ΠΈΠΊΠΎ ЈБОН-ΠΎΠ²Π° који садрТС Π²Π΅ΠΊΡ‚ΠΎΡ€Π΅ Π½ΠΈΠ·ΠΎΠ²Π° са ΠΊΠΎΠΎΡ€Π΄ΠΈΠ½Π°Ρ‚Π°ΠΌΠ° Ρ‚Π°Ρ‡Π°ΠΊΠ°.
  2. Π¦Ρ€Ρ‚Π°ΡšΠ΅ линија Ρƒ боји Π½Π° основу ΠΊΠΎΠΎΡ€Π΄ΠΈΠ½Π°Ρ‚Π° Ρ‚Π°Ρ‡Π°ΠΊΠ° Π½Π° слици ΠΏΠΎΡ‚Ρ€Π΅Π±Π½Π΅ Π²Π΅Π»ΠΈΡ‡ΠΈΠ½Π΅ (Π½Π° ΠΏΡ€ΠΈΠΌΠ΅Ρ€, 256Γ—256 ΠΈΠ»ΠΈ 128Γ—128).
  3. ΠŸΡ€Π΅Ρ‚Π²Π°Ρ€Π°ΡšΠ΅ Π΄ΠΎΠ±ΠΈΡ˜Π΅Π½ΠΈΡ… слика Ρƒ Ρ‚Π΅Π½Π·ΠΎΡ€.

Π£ ΠΎΠΊΠ²ΠΈΡ€Ρƒ Ρ‚Π°ΠΊΠΌΠΈΡ‡Π΅ΡšΠ° ΠΌΠ΅Ρ’Ρƒ ΠŸΠΈΡ‚Ρ…ΠΎΠ½ ΠΊΠ΅Ρ€Π½Π΅Π»ΠΈΠΌΠ°, ΠΏΡ€ΠΎΠ±Π»Π΅ΠΌ јС првСнствСно Ρ€Π΅ΡˆΠ΅Π½ ΠΊΠΎΡ€ΠΈΡˆΡ›Π΅ΡšΠ΅ΠΌ ΠžΠΏΠ΅Π½Π¦Π’. ЈСдан ΠΎΠ΄ Π½Π°Ρ˜Ρ˜Π΅Π΄Π½ΠΎΡΡ‚Π°Π²Π½ΠΈΡ˜ΠΈΡ… ΠΈ Π½Π°Ρ˜ΠΎΡ‡ΠΈΠ³Π»Π΅Π΄Π½ΠΈΡ˜ΠΈΡ… Π°Π½Π°Π»ΠΎΠ³Π° Ρƒ Π  Π±ΠΈ ΠΈΠ·Π³Π»Π΅Π΄Π°ΠΎ ΠΎΠ²Π°ΠΊΠΎ:

Π˜ΠΌΠΏΠ»Π΅ΠΌΠ΅Π½Ρ‚Π°Ρ†ΠΈΡ˜Π° ΠΊΠΎΠ½Π²Π΅Ρ€Π·ΠΈΡ˜Π΅ ЈБОН Ρƒ Ρ‚Π΅Π½Π·ΠΎΡ€ Ρƒ Π 

r_process_json_str <- function(json, line.width = 3, 
                               color = TRUE, scale = 1) {
  # ΠŸΠ°Ρ€ΡΠΈΠ½Π³ JSON
  coords <- jsonlite::fromJSON(json, simplifyMatrix = FALSE)
  tmp <- tempfile()
  # УдаляСм Π²Ρ€Π΅ΠΌΠ΅Π½Π½Ρ‹ΠΉ Ρ„Π°ΠΉΠ» ΠΏΠΎ Π·Π°Π²Π΅Ρ€ΡˆΠ΅Π½ΠΈΡŽ Ρ„ΡƒΠ½ΠΊΡ†ΠΈΠΈ
  on.exit(unlink(tmp))
  png(filename = tmp, width = 256 * scale, height = 256 * scale, pointsize = 1)
  # ΠŸΡƒΡΡ‚ΠΎΠΉ Π³Ρ€Π°Ρ„ΠΈΠΊ
  plot.new()
  # Π Π°Π·ΠΌΠ΅Ρ€ ΠΎΠΊΠ½Π° Π³Ρ€Π°Ρ„ΠΈΠΊΠ°
  plot.window(xlim = c(256 * scale, 0), ylim = c(256 * scale, 0))
  # Π¦Π²Π΅Ρ‚Π° Π»ΠΈΠ½ΠΈΠΉ
  cols <- if (color) rainbow(length(coords)) else "#000000"
  for (i in seq_along(coords)) {
    lines(x = coords[[i]][[1]] * scale, y = coords[[i]][[2]] * scale, 
          col = cols[i], lwd = line.width)
  }
  dev.off()
  # ΠŸΡ€Π΅ΠΎΠ±Ρ€Π°Π·ΠΎΠ²Π°Π½ΠΈΠ΅ изобраТСния Π² 3-Ρ… ΠΌΠ΅Ρ€Π½Ρ‹ΠΉ массив
  res <- png::readPNG(tmp)
  return(res)
}

r_process_json_vector <- function(x, ...) {
  res <- lapply(x, r_process_json_str, ...)
  # ОбъСдинСниС 3-Ρ… ΠΌΠ΅Ρ€Π½Ρ‹Ρ… массивов ΠΊΠ°Ρ€Ρ‚ΠΈΠ½ΠΎΠΊ Π² 4-Ρ… ΠΌΠ΅Ρ€Π½Ρ‹ΠΉ Π² Ρ‚Π΅Π½Π·ΠΎΡ€
  res <- do.call(abind::abind, c(res, along = 0))
  return(res)
}

Π¦Ρ€Ρ‚Π°ΡšΠ΅ сС ΠΈΠ·Π²ΠΎΠ΄ΠΈ ΠΏΠΎΠΌΠΎΡ›Ρƒ стандардних Π  Π°Π»Π°Ρ‚Π° ΠΈ Ρ‡ΡƒΠ²Π° Ρƒ ΠΏΡ€ΠΈΠ²Ρ€Π΅ΠΌΠ΅Π½ΠΎΠΌ ΠŸΠΠ“ Ρ„ΠΎΡ€ΠΌΠ°Ρ‚Ρƒ који сС Ρ‡ΡƒΠ²Π° Ρƒ РАМ-Ρƒ (Π½Π° Π›ΠΈΠ½ΡƒΠΊ-Ρƒ, ΠΏΡ€ΠΈΠ²Ρ€Π΅ΠΌΠ΅Π½ΠΈ Π  Π΄ΠΈΡ€Π΅ΠΊΡ‚ΠΎΡ€ΠΈΡ˜ΡƒΠΌΠΈ сС Π½Π°Π»Π°Π·Π΅ Ρƒ Π΄ΠΈΡ€Π΅ΠΊΡ‚ΠΎΡ€ΠΈΡ˜ΡƒΠΌΡƒ /tmp, ΠΌΠΎΠ½Ρ‚ΠΈΡ€Π°Π½ Ρƒ РАМ). Ова Π΄Π°Ρ‚ΠΎΡ‚Π΅ΠΊΠ° сС Π·Π°Ρ‚ΠΈΠΌ Ρ‡ΠΈΡ‚Π° ΠΊΠ°ΠΎ Ρ‚Ρ€ΠΎΠ΄ΠΈΠΌΠ΅Π½Π·ΠΈΠΎΠ½Π°Π»Π½ΠΈ Π½ΠΈΠ· са Π±Ρ€ΠΎΡ˜Π΅Π²ΠΈΠΌΠ° Ρƒ распону ΠΎΠ΄ 0 Π΄ΠΎ 1. Ово јС Π²Π°ΠΆΠ½ΠΎ Ρ˜Π΅Ρ€ Π±ΠΈ ΠΊΠΎΠ½Π²Π΅Π½Ρ†ΠΈΠΎΠ½Π°Π»Π½ΠΈΡ˜ΠΈ Π‘ΠœΠŸ Π±ΠΈΠΎ ΠΏΡ€ΠΎΡ‡ΠΈΡ‚Π°Π½ Ρƒ сирови Π½ΠΈΠ· са хСксадСцималним ΠΊΠΎΠ΄ΠΎΠ²ΠΈΠΌΠ° боја.

Π₯ајдС Π΄Π° тСстирамо Ρ€Π΅Π·ΡƒΠ»Ρ‚Π°Ρ‚:

zip_file <- file.path("data", "train_simplified.zip")
csv_file <- "cat.csv"
unzip(zip_file, files = csv_file, exdir = tempdir(), 
      junkpaths = TRUE, unzip = getOption("unzip"))
tmp_data <- data.table::fread(file.path(tempdir(), csv_file), sep = ",", 
                              select = "drawing", nrows = 10000)
arr <- r_process_json_str(tmp_data[4, drawing])
dim(arr)
# [1] 256 256   3
plot(magick::image_read(arr))

ΠšΡƒΠΈΡ†ΠΊ Π”Ρ€Π°Π² Π”ΠΎΠΎΠ΄Π»Π΅ Π Π΅Ρ†ΠΎΠ³Π½ΠΈΡ‚ΠΈΠΎΠ½: ΠΊΠ°ΠΊΠΎ сС ΡΠΏΡ€ΠΈΡ˜Π°Ρ‚Π΅Ρ™ΠΈΡ‚ΠΈ са Π , Π¦++ ΠΈ нСуронским ΠΌΡ€Π΅ΠΆΠ°ΠΌΠ°

Π‘Π°ΠΌΠ° Π³Ρ€ΡƒΠΏΠ° Ρ›Π΅ сС Ρ„ΠΎΡ€ΠΌΠΈΡ€Π°Ρ‚ΠΈ Π½Π° слСдСћи Π½Π°Ρ‡ΠΈΠ½:

res <- r_process_json_vector(tmp_data[1:4, drawing], scale = 0.5)
str(res)
 # num [1:4, 1:128, 1:128, 1:3] 1 1 1 1 1 1 1 1 1 1 ...
 # - attr(*, "dimnames")=List of 4
 #  ..$ : NULL
 #  ..$ : NULL
 #  ..$ : NULL
 #  ..$ : NULL

Ова ΠΈΠΌΠΏΠ»Π΅ΠΌΠ΅Π½Ρ‚Π°Ρ†ΠΈΡ˜Π° Π½Π°ΠΌ сС Ρ‡ΠΈΠ½ΠΈΠ»Π° Π½Π΅ΠΎΠΏΡ‚ΠΈΠΌΠ°Π»Π½Π°, ΠΏΠΎΡˆΡ‚ΠΎ Ρ„ΠΎΡ€ΠΌΠΈΡ€Π°ΡšΠ΅ Π²Π΅Π»ΠΈΠΊΠΈΡ… ΡΠ΅Ρ€ΠΈΡ˜Π° Ρ‚Ρ€Π°Ρ˜Π΅ Π½Π΅ΠΏΡ€ΠΈΡΡ‚ΠΎΡ˜Π½ΠΎ Π΄ΡƒΠ³ΠΎ, ΠΏΠ° смо ΠΎΠ΄Π»ΡƒΡ‡ΠΈΠ»ΠΈ Π΄Π° искористимо искуство Π½Π°ΡˆΠΈΡ… ΠΊΠΎΠ»Π΅Π³Π° ΠΊΠΎΡ€ΠΈΡˆΡ›Π΅ΡšΠ΅ΠΌ ΠΌΠΎΡ›Π½Π΅ Π±ΠΈΠ±Π»ΠΈΠΎΡ‚Π΅ΠΊΠ΅ ΠžΠΏΠ΅Π½Π¦Π’. Π£ Ρ‚ΠΎ Π²Ρ€Π΅ΠΌΠ΅ нијС ΠΏΠΎΡΡ‚ΠΎΡ˜Π°ΠΎ Π³ΠΎΡ‚ΠΎΠ² ΠΏΠ°ΠΊΠ΅Ρ‚ Π·Π° Π  (сада Π³Π° Π½Π΅ΠΌΠ°), ΠΏΠ° јС ΠΌΠΈΠ½ΠΈΠΌΠ°Π»Π½Π° ΠΈΠΌΠΏΠ»Π΅ΠΌΠ΅Π½Ρ‚Π°Ρ†ΠΈΡ˜Π° ΠΏΠΎΡ‚Ρ€Π΅Π±Π½Π΅ функционалности написана Ρƒ Π¦++ са ΠΈΠ½Ρ‚Π΅Π³Ρ€Π°Ρ†ΠΈΡ˜ΠΎΠΌ Ρƒ Π  ΠΊΠΎΠ΄ ΠΊΠΎΡ€ΠΈΡˆΡ›Π΅ΡšΠ΅ΠΌ Π Ρ†ΠΏΠΏ.

Π”Π° Π±ΠΈ сС Ρ€Π΅ΡˆΠΈΠΎ ΠΏΡ€ΠΎΠ±Π»Π΅ΠΌ, ΠΊΠΎΡ€ΠΈΡˆΡ›Π΅Π½ΠΈ су слСдСћи ΠΏΠ°ΠΊΠ΅Ρ‚ΠΈ ΠΈ Π±ΠΈΠ±Π»ΠΈΠΎΡ‚Π΅ΠΊΠ΅:

  1. ΠžΠΏΠ΅Π½Π¦Π’ Π·Π° Ρ€Π°Π΄ са сликама ΠΈ Ρ†Ρ€Ρ‚Π°ΡšΠ΅ линија. ΠšΠΎΡ€ΠΈΡˆΡ›Π΅Π½Π΅ су ΡƒΠ½Π°ΠΏΡ€Π΅Π΄ инсталиранС систСмскС Π±ΠΈΠ±Π»ΠΈΠΎΡ‚Π΅ΠΊΠ΅ ΠΈ Π΄Π°Ρ‚ΠΎΡ‚Π΅ΠΊΠ΅ Π·Π°Π³Π»Π°Π²Ρ™Π°, ΠΊΠ°ΠΎ ΠΈ Π΄ΠΈΠ½Π°ΠΌΠΈΡ‡ΠΊΠΎ повСзивањС.

  2. ктСнсор Π·Π° Ρ€Π°Π΄ са вишСдимСнзионалним Π½ΠΈΠ·ΠΎΠ²ΠΈΠΌΠ° ΠΈ Ρ‚Π΅Π½Π·ΠΎΡ€ΠΈΠΌΠ°. ΠšΠΎΡ€ΠΈΡΡ‚ΠΈΠ»ΠΈ смо Π΄Π°Ρ‚ΠΎΡ‚Π΅ΠΊΠ΅ Π·Π°Π³Π»Π°Π²Ρ™Π° ΡƒΠΊΡ™ΡƒΡ‡Π΅Π½Π΅ Ρƒ истоимСни Π  ΠΏΠ°ΠΊΠ΅Ρ‚. Π‘ΠΈΠ±Π»ΠΈΠΎΡ‚Π΅ΠΊΠ° Π²Π°ΠΌ ΠΎΠΌΠΎΠ³ΡƒΡ›Π°Π²Π° Π΄Π° Ρ€Π°Π΄ΠΈΡ‚Π΅ са вишСдимСнзионалним Π½ΠΈΠ·ΠΎΠ²ΠΈΠΌΠ°, ΠΊΠ°ΠΊΠΎ Ρƒ Ρ€Π΅Π΄ΠΎΠ²ΠΈΠΌΠ°, Ρ‚Π°ΠΊΠΎ ΠΈ Ρƒ Π³Π»Π°Π²Π½ΠΎΠΌ рСдослСду ΠΊΠΎΠ»ΠΎΠ½Π°.

  3. ндјсон Π·Π° Ρ€Π°ΡˆΡ‡Π»Π°ΡšΠΈΠ²Π°ΡšΠ΅ ЈБОН-Π°. Ова Π±ΠΈΠ±Π»ΠΈΠΎΡ‚Π΅ΠΊΠ° сС користи Ρƒ ктСнсор аутоматски Π°ΠΊΠΎ јС присутан Ρƒ ΠΏΡ€ΠΎΡ˜Π΅ΠΊΡ‚Ρƒ.

  4. Π Ρ†ΠΏΠΏΠ’Ρ…Ρ€Π΅Π°Π΄ Π·Π° ΠΎΡ€Π³Π°Π½ΠΈΠ·ΠΎΠ²Π°ΡšΠ΅ Π²ΠΈΡˆΠ΅Π½ΠΈΡ‚Π½Π΅ ΠΎΠ±Ρ€Π°Π΄Π΅ Π²Π΅ΠΊΡ‚ΠΎΡ€Π° ΠΈΠ· ЈБОН-Π°. ΠšΠΎΡ€ΠΈΡΡ‚ΠΈΠΎ јС Π΄Π°Ρ‚ΠΎΡ‚Π΅ΠΊΠ΅ Π·Π°Π³Π»Π°Π²Ρ™Π° којС ΠΎΠ±Π΅Π·Π±Π΅Ρ’ΡƒΡ˜Π΅ овај ΠΏΠ°ΠΊΠ΅Ρ‚. Од ΠΏΠΎΠΏΡƒΠ»Π°Ρ€Π½ΠΈΡ˜ΠΈΡ… Π Ρ†ΠΏΠΏΠŸΠ°Ρ€Π°Π»Π»Π΅Π» ΠŸΠ°ΠΊΠ΅Ρ‚, ΠΈΠ·ΠΌΠ΅Ρ’Ρƒ осталог, ΠΈΠΌΠ° ΡƒΠ³Ρ€Π°Ρ’Π΅Π½ ΠΌΠ΅Ρ…Π°Π½ΠΈΠ·Π°ΠΌ Π·Π° ΠΏΡ€Π΅ΠΊΠΈΠ΄ ΠΏΠ΅Ρ‚Ρ™Π΅.

Π’Ρ€Π΅Π±Π° Π½Π°ΠΏΠΎΠΌΠ΅Π½ΡƒΡ‚ΠΈ Π΄Π° ктСнсор испоставило сС Π΄Π° јС боТји Π΄Π°Ρ€: ΠΏΠΎΡ€Π΅Π΄ Ρ‡ΠΈΡšΠ΅Π½ΠΈΡ†Π΅ Π΄Π° ΠΈΠΌΠ° ΡˆΠΈΡ€ΠΎΠΊΡƒ функционалност ΠΈ високС пСрформансС, испоставило сС Π΄Π° су њСгови ΠΏΡ€ΠΎΠ³Ρ€Π°ΠΌΠ΅Ρ€ΠΈ ΠΏΡ€ΠΈΠ»ΠΈΡ‡Π½ΠΎ Ρ€Π΅Π°Π³ΠΎΠ²Π°Π»ΠΈ ΠΈ ΠΎΠ΄Π³ΠΎΠ²ΠΎΡ€ΠΈΠ»ΠΈ Π½Π° ΠΏΠΈΡ‚Π°ΡšΠ° Π±Ρ€Π·ΠΎ ΠΈ Π΄Π΅Ρ‚Π°Ρ™Π½ΠΎ. Π£Π· ΡšΠΈΡ…ΠΎΠ²Ρƒ ΠΏΠΎΠΌΠΎΡ›, Π±ΠΈΠ»ΠΎ јС ΠΌΠΎΠ³ΡƒΡ›Π΅ Ρ€Π΅Π°Π»ΠΈΠ·ΠΎΠ²Π°Ρ‚ΠΈ Ρ‚Ρ€Π°Π½ΡΡ„ΠΎΡ€ΠΌΠ°Ρ†ΠΈΡ˜Π΅ ΠžΠΏΠ΅Π½Π¦Π’ ΠΌΠ°Ρ‚Ρ€ΠΈΡ†Π° Ρƒ ΠΊΡ‚Π΅Π½Π·ΠΎΡ€ Ρ‚Π΅Π½Π·ΠΎΡ€Π°, ΠΊΠ°ΠΎ ΠΈ Π½Π°Ρ‡ΠΈΠ½ комбиновања 3-Π΄ΠΈΠΌΠ΅Π½Π·ΠΈΠΎΠ½Π°Π»Π½ΠΈΡ… Ρ‚Π΅Π½Π·ΠΎΡ€Π° сликС Ρƒ 4-Π΄ΠΈΠΌΠ΅Π½Π·ΠΈΠΎΠ½Π°Π»Π½ΠΈ Ρ‚Π΅Π½Π·ΠΎΡ€ исправнС димСнзијС (сама ΡΠ΅Ρ€ΠΈΡ˜Π°).

ΠœΠ°Ρ‚Π΅Ρ€ΠΈΡ˜Π°Π»ΠΈ Π·Π° ΡƒΡ‡Π΅ΡšΠ΅ Π Ρ†ΠΏΠΏ, ктСнсор ΠΈ Π Ρ†ΠΏΠΏΠ’Ρ…Ρ€Π΅Π°Π΄

https://thecoatlessprofessor.com/programming/unofficial-rcpp-api-documentation

https://docs.opencv.org/4.0.1/d7/dbd/group__imgproc.html

https://xtensor.readthedocs.io/en/latest/

https://xtensor.readthedocs.io/en/latest/file_loading.html#loading-json-data-into-xtensor

https://cran.r-project.org/web/packages/RcppThread/vignettes/RcppThread-vignette.pdf

Π—Π° ΠΊΠΎΠΌΠΏΠ°Ρ˜Π»ΠΈΡ€Π°ΡšΠ΅ Π΄Π°Ρ‚ΠΎΡ‚Π΅ΠΊΠ° којС користС систСмскС Π΄Π°Ρ‚ΠΎΡ‚Π΅ΠΊΠ΅ ΠΈ Π΄ΠΈΠ½Π°ΠΌΠΈΡ‡ΠΊΠΎ повСзивањС са Π±ΠΈΠ±Π»ΠΈΠΎΡ‚Π΅ΠΊΠ°ΠΌΠ° инсталираним Π½Π° систСму, користили смо ΠΌΠ΅Ρ…Π°Π½ΠΈΠ·Π°ΠΌ Π΄ΠΎΠ΄Π°Ρ‚Π°ΠΊΠ° ΠΈΠΌΠΏΠ»Π΅ΠΌΠ΅Π½Ρ‚ΠΈΡ€Π°Π½ Ρƒ ΠΏΠ°ΠΊΠ΅Ρ‚Ρƒ Π Ρ†ΠΏΠΏ. Π”Π° бисмо аутоматски ΠΏΡ€ΠΎΠ½Π°ΡˆΠ»ΠΈ ΠΏΡƒΡ‚Π°ΡšΠ΅ ΠΈ заставицС, користили смо ΠΏΠΎΠΏΡƒΠ»Π°Ρ€Π½ΠΈ Π›ΠΈΠ½ΡƒΠΊ услуТни ΠΏΡ€ΠΎΠ³Ρ€Π°ΠΌ ΠΏΠΊΠ³-Ρ†ΠΎΠ½Ρ„ΠΈΠ³.

Π˜ΠΌΠΏΠ»Π΅ΠΌΠ΅Π½Ρ‚Π°Ρ†ΠΈΡ˜Π° Π Ρ†ΠΏΠΏ Π΄ΠΎΠ΄Π°Ρ‚ΠΊΠ° Π·Π° ΠΊΠΎΡ€ΠΈΡˆΡ›Π΅ΡšΠ΅ ΠžΠΏΠ΅Π½Π¦Π’ Π±ΠΈΠ±Π»ΠΈΠΎΡ‚Π΅ΠΊΠ΅

Rcpp::registerPlugin("opencv", function() {
  # Π’ΠΎΠ·ΠΌΠΎΠΆΠ½Ρ‹Π΅ названия ΠΏΠ°ΠΊΠ΅Ρ‚Π°
  pkg_config_name <- c("opencv", "opencv4")
  # Π‘ΠΈΠ½Π°Ρ€Π½Ρ‹ΠΉ Ρ„Π°ΠΉΠ» ΡƒΡ‚ΠΈΠ»ΠΈΡ‚Ρ‹ pkg-config
  pkg_config_bin <- Sys.which("pkg-config")
  # ΠŸΡ€ΠΎΠ²Ρ€Π΅ΠΊΠ° наличия ΡƒΡ‚ΠΈΠ»ΠΈΡ‚Ρ‹ Π² систСмС
  checkmate::assert_file_exists(pkg_config_bin, access = "x")
  # ΠŸΡ€ΠΎΠ²Π΅Ρ€ΠΊΠ° наличия Ρ„Π°ΠΉΠ»Π° настроСк OpenCV для pkg-config
  check <- sapply(pkg_config_name, 
                  function(pkg) system(paste(pkg_config_bin, pkg)))
  if (all(check != 0)) {
    stop("OpenCV config for the pkg-config not found", call. = FALSE)
  }

  pkg_config_name <- pkg_config_name[check == 0]
  list(env = list(
    PKG_CXXFLAGS = system(paste(pkg_config_bin, "--cflags", pkg_config_name), 
                          intern = TRUE),
    PKG_LIBS = system(paste(pkg_config_bin, "--libs", pkg_config_name), 
                      intern = TRUE)
  ))
})

Као Ρ€Π΅Π·ΡƒΠ»Ρ‚Π°Ρ‚ Ρ€Π°Π΄Π° Π΄ΠΎΠ΄Π°Ρ‚ΠΊΠ°, слСдСћС врСдности Ρ›Π΅ Π±ΠΈΡ‚ΠΈ замСњСнС Ρ‚ΠΎΠΊΠΎΠΌ процСса ΠΊΠΎΠΌΠΏΠΈΠ»Π°Ρ†ΠΈΡ˜Π΅:

Rcpp:::.plugins$opencv()$env

# $PKG_CXXFLAGS
# [1] "-I/usr/include/opencv"
#
# $PKG_LIBS
# [1] "-lopencv_shape -lopencv_stitching -lopencv_superres -lopencv_videostab -lopencv_aruco -lopencv_bgsegm -lopencv_bioinspired -lopencv_ccalib -lopencv_datasets -lopencv_dpm -lopencv_face -lopencv_freetype -lopencv_fuzzy -lopencv_hdf -lopencv_line_descriptor -lopencv_optflow -lopencv_video -lopencv_plot -lopencv_reg -lopencv_saliency -lopencv_stereo -lopencv_structured_light -lopencv_phase_unwrapping -lopencv_rgbd -lopencv_viz -lopencv_surface_matching -lopencv_text -lopencv_ximgproc -lopencv_calib3d -lopencv_features2d -lopencv_flann -lopencv_xobjdetect -lopencv_objdetect -lopencv_ml -lopencv_xphoto -lopencv_highgui -lopencv_videoio -lopencv_imgcodecs -lopencv_photo -lopencv_imgproc -lopencv_core"

Π˜ΠΌΠΏΠ»Π΅ΠΌΠ΅Π½Ρ‚Π°Ρ†ΠΈΠΎΠ½ΠΈ ΠΊΠΎΠ΄ Π·Π° Ρ€Π°ΡˆΡ‡Π»Π°ΡšΠΈΠ²Π°ΡšΠ΅ ЈБОН-Π° ΠΈ Π³Π΅Π½Π΅Ρ€ΠΈΡΠ°ΡšΠ΅ Π³Ρ€ΡƒΠΏΠ΅ Π·Π° прСнос Ρƒ ΠΌΠΎΠ΄Π΅Π» јС Π΄Π°Ρ‚ испод ΡΠΏΠΎΡ˜Π»Π΅Ρ€Π°. ΠŸΡ€Π²ΠΎ Π΄ΠΎΠ΄Π°Ρ˜Ρ‚Π΅ Π»ΠΎΠΊΠ°Π»Π½ΠΈ Π΄ΠΈΡ€Π΅ΠΊΡ‚ΠΎΡ€ΠΈΡ˜ΡƒΠΌ ΠΏΡ€ΠΎΡ˜Π΅ΠΊΡ‚Π° Π΄Π° бистС Ρ‚Ρ€Π°ΠΆΠΈΠ»ΠΈ Π΄Π°Ρ‚ΠΎΡ‚Π΅ΠΊΠ΅ Π·Π°Π³Π»Π°Π²Ρ™Π° (ΠΏΠΎΡ‚Ρ€Π΅Π±Π½ΠΎ Π·Π° ндјсон):

Sys.setenv("PKG_CXXFLAGS" = paste0("-I", normalizePath(file.path("src"))))

Π˜ΠΌΠΏΠ»Π΅ΠΌΠ΅Π½Ρ‚Π°Ρ†ΠΈΡ˜Π° ΠΊΠΎΠ½Π²Π΅Ρ€Π·ΠΈΡ˜Π΅ ЈБОН Ρƒ Ρ‚Π΅Π½Π·ΠΎΡ€ Ρƒ Π¦++

// [[Rcpp::plugins(cpp14)]]
// [[Rcpp::plugins(opencv)]]
// [[Rcpp::depends(xtensor)]]
// [[Rcpp::depends(RcppThread)]]

#include <xtensor/xjson.hpp>
#include <xtensor/xadapt.hpp>
#include <xtensor/xview.hpp>
#include <xtensor-r/rtensor.hpp>
#include <opencv2/core/core.hpp>
#include <opencv2/highgui/highgui.hpp>
#include <opencv2/imgproc/imgproc.hpp>
#include <Rcpp.h>
#include <RcppThread.h>

// Π‘ΠΈΠ½ΠΎΠ½ΠΈΠΌΡ‹ для Ρ‚ΠΈΠΏΠΎΠ²
using RcppThread::parallelFor;
using json = nlohmann::json;
using points = xt::xtensor<double,2>;     // Π˜Π·Π²Π»Π΅Ρ‡Ρ‘Π½Π½Ρ‹Π΅ ΠΈΠ· JSON ΠΊΠΎΠΎΡ€Π΄ΠΈΠ½Π°Ρ‚Ρ‹ Ρ‚ΠΎΡ‡Π΅ΠΊ
using strokes = std::vector<points>;      // Π˜Π·Π²Π»Π΅Ρ‡Ρ‘Π½Π½Ρ‹Π΅ ΠΈΠ· JSON ΠΊΠΎΠΎΡ€Π΄ΠΈΠ½Π°Ρ‚Ρ‹ Ρ‚ΠΎΡ‡Π΅ΠΊ
using xtensor3d = xt::xtensor<double, 3>; // Π’Π΅Π½Π·ΠΎΡ€ для хранСния ΠΌΠ°Ρ‚Ρ€ΠΈΡ†Ρ‹ изообраТСния
using xtensor4d = xt::xtensor<double, 4>; // Π’Π΅Π½Π·ΠΎΡ€ для хранСния мноТСства ΠΈΠ·ΠΎΠ±Ρ€Π°ΠΆΠ΅Π½ΠΈΠΉ
using rtensor3d = xt::rtensor<double, 3>; // ΠžΠ±Ρ‘Ρ€Ρ‚ΠΊΠ° для экспорта Π² R
using rtensor4d = xt::rtensor<double, 4>; // ΠžΠ±Ρ‘Ρ€Ρ‚ΠΊΠ° для экспорта Π² R

// БтатичСскиС константы
// Π Π°Π·ΠΌΠ΅Ρ€ изобраТСния Π² пиксСлях
const static int SIZE = 256;
// Π’ΠΈΠΏ Π»ΠΈΠ½ΠΈΠΈ
// Π‘ΠΌ. https://en.wikipedia.org/wiki/Pixel_connectivity#2-dimensional
const static int LINE_TYPE = cv::LINE_4;
// Π’ΠΎΠ»Ρ‰ΠΈΠ½Π° Π»ΠΈΠ½ΠΈΠΈ Π² пиксСлях
const static int LINE_WIDTH = 3;
// Алгоритм рСсайза
// https://docs.opencv.org/3.1.0/da/d54/group__imgproc__transform.html#ga5bb5a1fea74ea38e1a5445ca803ff121
const static int RESIZE_TYPE = cv::INTER_LINEAR;

// Π¨Π°Π±Π»ΠΎΠ½ для конвСртирования OpenCV-ΠΌΠ°Ρ‚Ρ€ΠΈΡ†Ρ‹ Π² Ρ‚Π΅Π½Π·ΠΎΡ€
template <typename T, int NCH, typename XT=xt::xtensor<T,3,xt::layout_type::column_major>>
XT to_xt(const cv::Mat_<cv::Vec<T, NCH>>& src) {
  // Π Π°Π·ΠΌΠ΅Ρ€Π½ΠΎΡΡ‚ΡŒ Ρ†Π΅Π»Π΅Π²ΠΎΠ³ΠΎ Ρ‚Π΅Π½Π·ΠΎΡ€Π°
  std::vector<int> shape = {src.rows, src.cols, NCH};
  // ΠžΠ±Ρ‰Π΅Π΅ количСство элСмСнтов Π² массивС
  size_t size = src.total() * NCH;
  // ΠŸΡ€Π΅ΠΎΠ±Ρ€Π°Π·ΠΎΠ²Π°Π½ΠΈΠ΅ cv::Mat Π² xt::xtensor
  XT res = xt::adapt((T*) src.data, size, xt::no_ownership(), shape);
  return res;
}

// ΠŸΡ€Π΅ΠΎΠ±Ρ€Π°Π·ΠΎΠ²Π°Π½ΠΈΠ΅ JSON Π² список ΠΊΠΎΠΎΡ€Π΄ΠΈΠ½Π°Ρ‚ Ρ‚ΠΎΡ‡Π΅ΠΊ
strokes parse_json(const std::string& x) {
  auto j = json::parse(x);
  // Π Π΅Π·ΡƒΠ»ΡŒΡ‚Π°Ρ‚ парсинга Π΄ΠΎΠ»ΠΆΠ΅Π½ Π±Ρ‹Ρ‚ΡŒ массивом
  if (!j.is_array()) {
    throw std::runtime_error("'x' must be JSON array.");
  }
  strokes res;
  res.reserve(j.size());
  for (const auto& a: j) {
    // ΠšΠ°ΠΆΠ΄Ρ‹ΠΉ элСмСнт массива Π΄ΠΎΠ»ΠΆΠ΅Π½ Π±Ρ‹Ρ‚ΡŒ 2-ΠΌΠ΅Ρ€Π½Ρ‹ΠΌ массивом
    if (!a.is_array() || a.size() != 2) {
      throw std::runtime_error("'x' must include only 2d arrays.");
    }
    // Π˜Π·Π²Π»Π΅Ρ‡Π΅Π½ΠΈΠ΅ Π²Π΅ΠΊΡ‚ΠΎΡ€Π° Ρ‚ΠΎΡ‡Π΅ΠΊ
    auto p = a.get<points>();
    res.push_back(p);
  }
  return res;
}

// ΠžΡ‚Ρ€ΠΈΡΠΎΠ²ΠΊΠ° Π»ΠΈΠ½ΠΈΠΉ
// Π¦Π²Π΅Ρ‚Π° HSV
cv::Mat ocv_draw_lines(const strokes& x, bool color = true) {
  // Π˜ΡΡ…ΠΎΠ΄Π½Ρ‹ΠΉ Ρ‚ΠΈΠΏ ΠΌΠ°Ρ‚Ρ€ΠΈΡ†Ρ‹
  auto stype = color ? CV_8UC3 : CV_8UC1;
  // Π˜Ρ‚ΠΎΠ³ΠΎΠ²Ρ‹ΠΉ Ρ‚ΠΈΠΏ ΠΌΠ°Ρ‚Ρ€ΠΈΡ†Ρ‹
  auto dtype = color ? CV_32FC3 : CV_32FC1;
  auto bg = color ? cv::Scalar(0, 0, 255) : cv::Scalar(255);
  auto col = color ? cv::Scalar(0, 255, 220) : cv::Scalar(0);
  cv::Mat img = cv::Mat(SIZE, SIZE, stype, bg);
  // ΠšΠΎΠ»ΠΈΡ‡Π΅ΡΡ‚Π²ΠΎ Π»ΠΈΠ½ΠΈΠΉ
  size_t n = x.size();
  for (const auto& s: x) {
    // ΠšΠΎΠ»ΠΈΡ‡Π΅ΡΡ‚Π²ΠΎ Ρ‚ΠΎΡ‡Π΅ΠΊ Π² Π»ΠΈΠ½ΠΈΠΈ
    size_t n_points = s.shape()[1];
    for (size_t i = 0; i < n_points - 1; ++i) {
      // Π’ΠΎΡ‡ΠΊΠ° Π½Π°Ρ‡Π°Π»Π° ΡˆΡ‚Ρ€ΠΈΡ…Π°
      cv::Point from(s(0, i), s(1, i));
      // Π’ΠΎΡ‡ΠΊΠ° окончания ΡˆΡ‚Ρ€ΠΈΡ…Π°
      cv::Point to(s(0, i + 1), s(1, i + 1));
      // ΠžΡ‚Ρ€ΠΈΡΠΎΠ²ΠΊΠ° Π»ΠΈΠ½ΠΈΠΈ
      cv::line(img, from, to, col, LINE_WIDTH, LINE_TYPE);
    }
    if (color) {
      // МСняСм Ρ†Π²Π΅Ρ‚ Π»ΠΈΠ½ΠΈΠΈ
      col[0] += 180 / n;
    }
  }
  if (color) {
    // МСняСм Ρ†Π²Π΅Ρ‚ΠΎΠ²ΠΎΠ΅ прСдставлСниС Π½Π° RGB
    cv::cvtColor(img, img, cv::COLOR_HSV2RGB);
  }
  // МСняСм Ρ„ΠΎΡ€ΠΌΠ°Ρ‚ прСдставлСния Π½Π° float32 с Π΄ΠΈΠ°ΠΏΠ°Π·ΠΎΠ½ΠΎΠΌ [0, 1]
  img.convertTo(img, dtype, 1 / 255.0);
  return img;
}

// ΠžΠ±Ρ€Π°Π±ΠΎΡ‚ΠΊΠ° JSON ΠΈ ΠΏΠΎΠ»ΡƒΡ‡Π΅Π½ΠΈΠ΅ Ρ‚Π΅Π½Π·ΠΎΡ€Π° с Π΄Π°Π½Π½Ρ‹ΠΌΠΈ изобраТСния
xtensor3d process(const std::string& x, double scale = 1.0, bool color = true) {
  auto p = parse_json(x);
  auto img = ocv_draw_lines(p, color);
  if (scale != 1) {
    cv::Mat out;
    cv::resize(img, out, cv::Size(), scale, scale, RESIZE_TYPE);
    cv::swap(img, out);
    out.release();
  }
  xtensor3d arr = color ? to_xt<double,3>(img) : to_xt<double,1>(img);
  return arr;
}

// [[Rcpp::export]]
rtensor3d cpp_process_json_str(const std::string& x, 
                               double scale = 1.0, 
                               bool color = true) {
  xtensor3d res = process(x, scale, color);
  return res;
}

// [[Rcpp::export]]
rtensor4d cpp_process_json_vector(const std::vector<std::string>& x, 
                                  double scale = 1.0, 
                                  bool color = false) {
  size_t n = x.size();
  size_t dim = floor(SIZE * scale);
  size_t channels = color ? 3 : 1;
  xtensor4d res({n, dim, dim, channels});
  parallelFor(0, n, [&x, &res, scale, color](int i) {
    xtensor3d tmp = process(x[i], scale, color);
    auto view = xt::view(res, i, xt::all(), xt::all(), xt::all());
    view = tmp;
  });
  return res;
}

Овај ΠΊΠΎΠ΄ Ρ‚Ρ€Π΅Π±Π° ставити Ρƒ Π΄Π°Ρ‚ΠΎΡ‚Π΅ΠΊΡƒ src/cv_xt.cpp ΠΈ ΠΊΠΎΠΌΠΏΠ°Ρ˜Π»ΠΈΡ€Π°Ρ˜Ρ‚Π΅ са ΠΊΠΎΠΌΠ°Π½Π΄ΠΎΠΌ Rcpp::sourceCpp(file = "src/cv_xt.cpp", env = .GlobalEnv); Ρ‚Π°ΠΊΠΎΡ’Π΅ ΠΏΠΎΡ‚Ρ€Π΅Π±Π°Π½ Π·Π° Ρ€Π°Π΄ nlohmann/json.hpp ΠΎΠ΄ Ρ€Π΅ΠΏΠΎΠ·ΠΈΡ‚ΠΎΡ€ΠΈΠ°. Код јС ΠΏΠΎΠ΄Π΅Ρ™Π΅Π½ Π½Π° Π½Π΅ΠΊΠΎΠ»ΠΈΠΊΠΎ Ρ„ΡƒΠ½ΠΊΡ†ΠΈΡ˜Π°:

  • to_xt β€” шаблонска Ρ„ΡƒΠ½ΠΊΡ†ΠΈΡ˜Π° Π·Π° Ρ‚Ρ€Π°Π½ΡΡ„ΠΎΡ€ΠΌΠ°Ρ†ΠΈΡ˜Ρƒ ΠΌΠ°Ρ‚Ρ€ΠΈΡ†Π΅ сликС (cv::Mat) Π½Π° Ρ‚Π΅Π½Π·ΠΎΡ€ xt::xtensor;

  • parse_json β€” Ρ„ΡƒΠ½ΠΊΡ†ΠΈΡ˜Π° Π°Π½Π°Π»ΠΈΠ·ΠΈΡ€Π° ЈБОН стринг, издваја ΠΊΠΎΠΎΡ€Π΄ΠΈΠ½Π°Ρ‚Π΅ Ρ‚Π°Ρ‡Π°ΠΊΠ°, ΠΏΠ°ΠΊΡƒΡ˜Π΅ ΠΈΡ… Ρƒ Π²Π΅ΠΊΡ‚ΠΎΡ€;

  • ocv_draw_lines β€” ΠΈΠ· Ρ€Π΅Π·ΡƒΠ»Ρ‚ΡƒΡ˜ΡƒΡ›Π΅Π³ Π²Π΅ΠΊΡ‚ΠΎΡ€Π° Ρ‚Π°Ρ‡Π°ΠΊΠ°, Ρ†Ρ€Ρ‚Π° вишСбојнС линијС;

  • process β€” ΠΊΠΎΠΌΠ±ΠΈΠ½ΡƒΡ˜Π΅ Π³ΠΎΡ€Π΅ Π½Π°Π²Π΅Π΄Π΅Π½Π΅ Ρ„ΡƒΠ½ΠΊΡ†ΠΈΡ˜Π΅ ΠΈ Ρ‚Π°ΠΊΠΎΡ’Π΅ додајС могућност ΡΠΊΠ°Π»ΠΈΡ€Π°ΡšΠ° Ρ€Π΅Π·ΡƒΠ»Ρ‚ΠΈΡ€Π°Ρ˜ΡƒΡ›Π΅ сликС;

  • cpp_process_json_str - ΠΎΠΌΠΎΡ‚Π°Ρ‡ ΠΏΡ€Π΅ΠΊΠΎ Ρ„ΡƒΠ½ΠΊΡ†ΠΈΡ˜Π΅ process, који ΠΈΠ·Π²ΠΎΠ·ΠΈ Ρ€Π΅Π·ΡƒΠ»Ρ‚Π°Ρ‚ Ρƒ Π -ΠΎΠ±Ρ˜Π΅ΠΊΠ°Ρ‚ (вишСдимСнзионални Π½ΠΈΠ·);

  • cpp_process_json_vector - ΠΎΠΌΠΎΡ‚Π°Ρ‡ ΠΏΡ€Π΅ΠΊΠΎ Ρ„ΡƒΠ½ΠΊΡ†ΠΈΡ˜Π΅ cpp_process_json_str, који Π²Π°ΠΌ ΠΎΠΌΠΎΠ³ΡƒΡ›Π°Π²Π° Π΄Π° ΠΎΠ±Ρ€Π°Ρ’ΡƒΡ˜Π΅Ρ‚Π΅ Π²Π΅ΠΊΡ‚ΠΎΡ€ Π½ΠΈΠ·Π° Ρƒ Π²ΠΈΡˆΠ΅Π½ΠΈΡ‚Π½ΠΎΠΌ Ρ€Π΅ΠΆΠΈΠΌΡƒ.

Π—Π° Ρ†Ρ€Ρ‚Π°ΡšΠ΅ Π²ΠΈΡˆΠ΅Π±ΠΎΡ˜Π½ΠΈΡ… линија ΠΊΠΎΡ€ΠΈΡˆΡ›Π΅Π½ јС Π₯Π‘Π’ ΠΌΠΎΠ΄Π΅Π» боја, Π½Π°ΠΊΠΎΠ½ Ρ‡Π΅Π³Π° јС услСдила ΠΊΠΎΠ½Π²Π΅Ρ€Π·ΠΈΡ˜Π° Ρƒ Π Π“Π‘. Π₯ајдС Π΄Π° тСстирамо Ρ€Π΅Π·ΡƒΠ»Ρ‚Π°Ρ‚:

arr <- cpp_process_json_str(tmp_data[4, drawing])
dim(arr)
# [1] 256 256   3
plot(magick::image_read(arr))

ΠšΡƒΠΈΡ†ΠΊ Π”Ρ€Π°Π² Π”ΠΎΠΎΠ΄Π»Π΅ Π Π΅Ρ†ΠΎΠ³Π½ΠΈΡ‚ΠΈΠΎΠ½: ΠΊΠ°ΠΊΠΎ сС ΡΠΏΡ€ΠΈΡ˜Π°Ρ‚Π΅Ρ™ΠΈΡ‚ΠΈ са Π , Π¦++ ΠΈ нСуронским ΠΌΡ€Π΅ΠΆΠ°ΠΌΠ°
ΠŸΠΎΡ€Π΅Ρ’Π΅ΡšΠ΅ Π±Ρ€Π·ΠΈΠ½Π΅ ΠΈΠΌΠΏΠ»Π΅ΠΌΠ΅Π½Ρ‚Π°Ρ†ΠΈΡ˜Π° Ρƒ Π  ΠΈ Π¦++

res_bench <- bench::mark(
  r_process_json_str(tmp_data[4, drawing], scale = 0.5),
  cpp_process_json_str(tmp_data[4, drawing], scale = 0.5),
  check = FALSE,
  min_iterations = 100
)
# ΠŸΠ°Ρ€Π°ΠΌΠ΅Ρ‚Ρ€Ρ‹ Π±Π΅Π½Ρ‡ΠΌΠ°Ρ€ΠΊΠ°
cols <- c("expression", "min", "median", "max", "itr/sec", "total_time", "n_itr")
res_bench[, cols]

#   expression                min     median       max `itr/sec` total_time  n_itr
#   <chr>                <bch:tm>   <bch:tm>  <bch:tm>     <dbl>   <bch:tm>  <int>
# 1 r_process_json_str     3.49ms     3.55ms    4.47ms      273.      490ms    134
# 2 cpp_process_json_str   1.94ms     2.02ms    5.32ms      489.      497ms    243

library(ggplot2)
# ΠŸΡ€ΠΎΠ²Π΅Π΄Π΅Π½ΠΈΠ΅ Π·Π°ΠΌΠ΅Ρ€Π°
res_bench <- bench::press(
  batch_size = 2^(4:10),
  {
    .data <- tmp_data[sample(seq_len(.N), batch_size), drawing]
    bench::mark(
      r_process_json_vector(.data, scale = 0.5),
      cpp_process_json_vector(.data,  scale = 0.5),
      min_iterations = 50,
      check = FALSE
    )
  }
)

res_bench[, cols]

#    expression   batch_size      min   median      max `itr/sec` total_time n_itr
#    <chr>             <dbl> <bch:tm> <bch:tm> <bch:tm>     <dbl>   <bch:tm> <int>
#  1 r                   16   50.61ms  53.34ms  54.82ms    19.1     471.13ms     9
#  2 cpp                 16    4.46ms   5.39ms   7.78ms   192.      474.09ms    91
#  3 r                   32   105.7ms 109.74ms 212.26ms     7.69        6.5s    50
#  4 cpp                 32    7.76ms  10.97ms  15.23ms    95.6     522.78ms    50
#  5 r                   64  211.41ms 226.18ms 332.65ms     3.85      12.99s    50
#  6 cpp                 64   25.09ms  27.34ms  32.04ms    36.0        1.39s    50
#  7 r                  128   534.5ms 627.92ms 659.08ms     1.61      31.03s    50
#  8 cpp                128   56.37ms  58.46ms  66.03ms    16.9        2.95s    50
#  9 r                  256     1.15s    1.18s    1.29s     0.851     58.78s    50
# 10 cpp                256  114.97ms 117.39ms 130.09ms     8.45       5.92s    50
# 11 r                  512     2.09s    2.15s    2.32s     0.463       1.8m    50
# 12 cpp                512  230.81ms  235.6ms 261.99ms     4.18      11.97s    50
# 13 r                 1024        4s    4.22s     4.4s     0.238       3.5m    50
# 14 cpp               1024  410.48ms 431.43ms 462.44ms     2.33      21.45s    50

ggplot(res_bench, aes(x = factor(batch_size), y = median, 
                      group =  expression, color = expression)) +
  geom_point() +
  geom_line() +
  ylab("median time, s") +
  theme_minimal() +
  scale_color_discrete(name = "", labels = c("cpp", "r")) +
  theme(legend.position = "bottom") 

ΠšΡƒΠΈΡ†ΠΊ Π”Ρ€Π°Π² Π”ΠΎΠΎΠ΄Π»Π΅ Π Π΅Ρ†ΠΎΠ³Π½ΠΈΡ‚ΠΈΠΎΠ½: ΠΊΠ°ΠΊΠΎ сС ΡΠΏΡ€ΠΈΡ˜Π°Ρ‚Π΅Ρ™ΠΈΡ‚ΠΈ са Π , Π¦++ ΠΈ нСуронским ΠΌΡ€Π΅ΠΆΠ°ΠΌΠ°

Као ΡˆΡ‚ΠΎ Π²ΠΈΠ΄ΠΈΡ‚Π΅, ΠΏΠΎΠ²Π΅Ρ›Π°ΡšΠ΅ Π±Ρ€Π·ΠΈΠ½Π΅ сС ΠΏΠΎΠΊΠ°Π·Π°Π»ΠΎ Π²Π΅ΠΎΠΌΠ° Π·Π½Π°Ρ‡Π°Ρ˜Π½ΠΈΠΌ ΠΈ нијС ΠΌΠΎΠ³ΡƒΡ›Π΅ сустићи Π¦++ ΠΊΠΎΠ΄ ΠΏΠ°Ρ€Π°Π»Π΅Π»ΠΈΠ·Π°Ρ†ΠΈΡ˜ΠΎΠΌ Π  ΠΊΠΎΠ΄Π°.

3. Π˜Ρ‚Π΅Ρ€Π°Ρ‚ΠΎΡ€ΠΈ Π·Π° истовар ΠΏΠ°Ρ€Ρ‚ΠΈΡ˜Π° ΠΈΠ· Π±Π°Π·Π΅ ΠΏΠΎΠ΄Π°Ρ‚Π°ΠΊΠ°

Π  ΠΈΠΌΠ° заслуТСну Ρ€Π΅ΠΏΡƒΡ‚Π°Ρ†ΠΈΡ˜Ρƒ Π·Π° ΠΎΠ±Ρ€Π°Π΄Ρƒ ΠΏΠΎΠ΄Π°Ρ‚Π°ΠΊΠ° који сС ΡƒΠΊΠ»Π°ΠΏΠ°Ρ˜Ρƒ Ρƒ РАМ, Π΄ΠΎΠΊ ΠŸΠΈΡ‚Ρ…ΠΎΠ½ вишС ΠΊΠ°Ρ€Π°ΠΊΡ‚Π΅Ρ€ΠΈΡˆΠ΅ ΠΈΡ‚Π΅Ρ€Π°Ρ‚ΠΈΠ²Π½Π° ΠΎΠ±Ρ€Π°Π΄Π° ΠΏΠΎΠ΄Π°Ρ‚Π°ΠΊΠ°, ΡˆΡ‚ΠΎ Π²Π°ΠΌ ΠΎΠΌΠΎΠ³ΡƒΡ›Π°Π²Π° Π΄Π° Π»Π°ΠΊΠΎ ΠΈ ΠΏΡ€ΠΈΡ€ΠΎΠ΄Π½ΠΎ ΠΈΠΌΠΏΠ»Π΅ΠΌΠ΅Π½Ρ‚ΠΈΡ€Π°Ρ‚Π΅ ΠΏΡ€ΠΎΡ€Π°Ρ‡ΡƒΠ½Π΅ Π²Π°Π½ Ρ˜Π΅Π·Π³Ρ€Π° (ΠΏΡ€ΠΎΡ€Π°Ρ‡ΡƒΠ½ΠΈ ΠΏΠΎΠΌΠΎΡ›Ρƒ СкстСрнС ΠΌΠ΅ΠΌΠΎΡ€ΠΈΡ˜Π΅). ΠšΠ»Π°ΡΠΈΡ‡Π°Π½ ΠΈ Ρ€Π΅Π»Π΅Π²Π°Π½Ρ‚Π°Π½ ΠΏΡ€ΠΈΠΌΠ΅Ρ€ Π·Π° нас Ρƒ контСксту описаног ΠΏΡ€ΠΎΠ±Π»Π΅ΠΌΠ° су Π΄ΡƒΠ±ΠΎΠΊΠ΅ нСуронскС ΠΌΡ€Π΅ΠΆΠ΅ ΠΎΠ±ΡƒΡ‡Π΅Π½Π΅ ΠΌΠ΅Ρ‚ΠΎΠ΄ΠΎΠΌ Π³Ρ€Π°Π΄ΠΈΡ˜Π΅Π½Ρ‚Π° ΡΠΏΡƒΡˆΡ‚Π°ΡšΠ° са Π°ΠΏΡ€ΠΎΠΊΡΠΈΠΌΠ°Ρ†ΠΈΡ˜ΠΎΠΌ Π³Ρ€Π°Π΄ΠΈΡ˜Π΅Π½Ρ‚Π° Π½Π° сваком ΠΊΠΎΡ€Π°ΠΊΡƒ користСћи ΠΌΠ°Π»ΠΈ Π΄Π΅ΠΎ ΠΏΠΎΡΠΌΠ°Ρ‚Ρ€Π°ΡšΠ°, ΠΈΠ»ΠΈ ΠΌΠΈΠ½ΠΈ-Π±Π°Ρ‚Ρ†Ρ….

ΠžΠΊΠ²ΠΈΡ€ΠΈ Π·Π° Π΄ΡƒΠ±ΠΎΠΊΠΎ ΡƒΡ‡Π΅ΡšΠ΅ написани Ρƒ ΠŸΠΈΡ‚Ρ…ΠΎΠ½-Ρƒ ΠΈΠΌΠ°Ρ˜Ρƒ посСбнС класС којС ΠΈΠΌΠΏΠ»Π΅ΠΌΠ΅Π½Ρ‚ΠΈΡ€Π°Ρ˜Ρƒ ΠΈΡ‚Π΅Ρ€Π°Ρ‚ΠΎΡ€Π΅ Π½Π° основу ΠΏΠΎΠ΄Π°Ρ‚Π°ΠΊΠ°: Ρ‚Π°Π±Π΅Π»Π΅, сликС Ρƒ фасциклама, Π±ΠΈΠ½Π°Ρ€Π½ΠΈ Ρ„ΠΎΡ€ΠΌΠ°Ρ‚ΠΈ, ΠΈΡ‚Π΄. ΠœΠΎΠΆΠ΅Ρ‚Π΅ користити Π³ΠΎΡ‚ΠΎΠ²Π΅ ΠΎΠΏΡ†ΠΈΡ˜Π΅ ΠΈΠ»ΠΈ написати својС Π·Π° ΠΎΠ΄Ρ€Π΅Ρ’Π΅Π½Π΅ Π·Π°Π΄Π°Ρ‚ΠΊΠ΅. Π£ Π  ΠΌΠΎΠΆΠ΅ΠΌΠΎ искористити свС карактСристикС ΠŸΠΈΡ‚Ρ…ΠΎΠ½ Π±ΠΈΠ±Π»ΠΈΠΎΡ‚Π΅ΠΊΠ΅ кСрас са својим Ρ€Π°Π·Π»ΠΈΡ‡ΠΈΡ‚ΠΈΠΌ ΠΏΠΎΠ·Π°Π΄ΠΈΠ½Π°ΠΌΠ° користСћи истоимСни ΠΏΠ°ΠΊΠ΅Ρ‚, који Π·Π°ΡƒΠ·Π²Ρ€Π°Ρ‚ Ρ€Π°Π΄ΠΈ Π½Π° Π²Ρ€Ρ…Ρƒ ΠΏΠ°ΠΊΠ΅Ρ‚Π° мрСТасти. Ово послСдњС Π·Π°ΡΠ»ΡƒΠΆΡƒΡ˜Π΅ посСбан Π΄ΡƒΠ³ Ρ‡Π»Π°Π½Π°ΠΊ; Π½Π΅ само Π΄Π° Π²Π°ΠΌ ΠΎΠΌΠΎΠ³ΡƒΡ›Π°Π²Π° Π΄Π° ΠΏΠΎΠΊΡ€Π΅Π½Π΅Ρ‚Π΅ ΠŸΠΈΡ‚Ρ…ΠΎΠ½ ΠΊΠΎΠ΄ ΠΈΠ· Π , Π²Π΅Ρ› Π²Π°ΠΌ Ρ‚Π°ΠΊΠΎΡ’Π΅ ΠΎΠΌΠΎΠ³ΡƒΡ›Π°Π²Π° Π΄Π° прСноситС ΠΎΠ±Ρ˜Π΅ΠΊΡ‚Π΅ ΠΈΠ·ΠΌΠ΅Ρ’Ρƒ Π  ΠΈ ΠŸΠΈΡ‚Ρ…ΠΎΠ½ сСсија, аутоматски ΠΎΠ±Π°Π²Ρ™Π°Ρ˜ΡƒΡ›ΠΈ свС ΠΏΠΎΡ‚Ρ€Π΅Π±Π½Π΅ ΠΊΠΎΠ½Π²Π΅Ρ€Π·ΠΈΡ˜Π΅ Ρ‚ΠΈΠΏΠΎΠ²Π°.

РСшили смо сС ΠΏΠΎΡ‚Ρ€Π΅Π±Π΅ Π΄Π° Ρ‡ΡƒΠ²Π°ΠΌΠΎ свС ΠΏΠΎΠ΄Π°Ρ‚ΠΊΠ΅ Ρƒ РАМ-Ρƒ ΠΊΠΎΡ€ΠΈΡˆΡ›Π΅ΡšΠ΅ΠΌ ΠœΠΎΠ½Π΅Ρ‚Π”Π‘Π›ΠΈΡ‚Π΅-Π°, сав посао Π½Π° β€žΠ½Π΅ΡƒΡ€Π°Π»Π½ΠΎΡ˜ ΠΌΡ€Π΅ΠΆΠΈβ€œ Ρ›Π΅ ΠΎΠ±Π°Π²Ρ™Π°Ρ‚ΠΈ ΠΎΡ€ΠΈΠ³ΠΈΠ½Π°Π»Π½ΠΈ ΠΊΠΎΠ΄ Ρƒ ΠŸΠΈΡ‚Ρ…ΠΎΠ½-Ρƒ, само ΠΌΠΎΡ€Π°ΠΌΠΎ Π΄Π° напишСмо ΠΈΡ‚Π΅Ρ€Π°Ρ‚ΠΎΡ€ ΠΏΡ€Π΅ΠΊΠΎ ΠΏΠΎΠ΄Π°Ρ‚Π°ΠΊΠ°, ΠΏΠΎΡˆΡ‚ΠΎ Π½ΠΈΡˆΡ‚Π° нијС спрСмно Π·Π° Ρ‚Π°ΠΊΠ²Ρƒ ΡΠΈΡ‚ΡƒΠ°Ρ†ΠΈΡ˜Ρƒ Ρƒ Π  ΠΈΠ»ΠΈ ΠŸΠΈΡ‚Ρ…ΠΎΠ½-Ρƒ. Π£ ΡΡƒΡˆΡ‚ΠΈΠ½ΠΈ ΠΏΠΎΡΡ‚ΠΎΡ˜Π΅ само Π΄Π²Π° Π·Π°Ρ…Ρ‚Π΅Π²Π° Π·Π° њСга: ΠΌΠΎΡ€Π° Π΄Π° Π²Ρ€Π°Ρ›Π° ΠΏΠ°ΠΊΠ΅Ρ‚Π΅ Ρƒ Π±Π΅ΡΠΊΠΎΠ½Π°Ρ‡Π½ΠΎΡ˜ ΠΏΠ΅Ρ‚Ρ™ΠΈ ΠΈ Π΄Π° сачува својС ΡΡ‚Π°ΡšΠ΅ ΠΈΠ·ΠΌΠ΅Ρ’Ρƒ ΠΈΡ‚Π΅Ρ€Π°Ρ†ΠΈΡ˜Π° (ΠΎΠ²ΠΎ послСдњС Ρƒ Π  сС ΠΈΠΌΠΏΠ»Π΅ΠΌΠ΅Π½Ρ‚ΠΈΡ€Π° Π½Π° Π½Π°Ρ˜Ρ˜Π΅Π΄Π½ΠΎΡΡ‚Π°Π²Π½ΠΈΡ˜ΠΈ Π½Π°Ρ‡ΠΈΠ½ ΠΊΠΎΡ€ΠΈΡˆΡ›Π΅ΡšΠ΅ΠΌ Π·Π°Ρ‚Π²Π°Ρ€Π°ΡšΠ°). РанијС јС Π±ΠΈΠ»ΠΎ ΠΏΠΎΡ‚Ρ€Π΅Π±Π½ΠΎ Сксплицитно ΠΊΠΎΠ½Π²Π΅Ρ€Ρ‚ΠΎΠ²Π°Ρ‚ΠΈ Π  Π½ΠΈΠ·ΠΎΠ²Π΅ Ρƒ Π½ΡƒΠΌΠΏΠΈ Π½ΠΈΠ·ΠΎΠ²Π΅ ΡƒΠ½ΡƒΡ‚Π°Ρ€ ΠΈΡ‚Π΅Ρ€Π°Ρ‚ΠΎΡ€Π°, Π°Π»ΠΈ Ρ‚Ρ€Π΅Π½ΡƒΡ‚Π½Π° Π²Π΅Ρ€Π·ΠΈΡ˜Π° ΠΏΠ°ΠΊΠ΅Ρ‚Π° кСрас сама Ρ‚ΠΎ Ρ€Π°Π΄ΠΈ.

Показало сС Π΄Π° јС ΠΈΡ‚Π΅Ρ€Π°Ρ‚ΠΎΡ€ Π·Π° ΠΏΠΎΠ΄Π°Ρ‚ΠΊΠ΅ ΠΎ ΠΎΠ±ΡƒΡ†ΠΈ ΠΈ Π²Π°Π»ΠΈΠ΄Π°Ρ†ΠΈΡ˜ΠΈ слСдСћи:

Π˜Ρ‚Π΅Ρ€Π°Ρ‚ΠΎΡ€ Π·Π° ΠΎΠ±ΡƒΠΊΡƒ ΠΈ Π²Π°Π»ΠΈΠ΄Π°Ρ†ΠΈΡ˜Ρƒ ΠΏΠΎΠ΄Π°Ρ‚Π°ΠΊΠ°

train_generator <- function(db_connection = con,
                            samples_index,
                            num_classes = 340,
                            batch_size = 32,
                            scale = 1,
                            color = FALSE,
                            imagenet_preproc = FALSE) {
  # ΠŸΡ€ΠΎΠ²Π΅Ρ€ΠΊΠ° Π°Ρ€Π³ΡƒΠΌΠ΅Π½Ρ‚ΠΎΠ²
  checkmate::assert_class(con, "DBIConnection")
  checkmate::assert_integerish(samples_index)
  checkmate::assert_count(num_classes)
  checkmate::assert_count(batch_size)
  checkmate::assert_number(scale, lower = 0.001, upper = 5)
  checkmate::assert_flag(color)
  checkmate::assert_flag(imagenet_preproc)

  # ΠŸΠ΅Ρ€Π΅ΠΌΠ΅ΡˆΠΈΠ²Π°Π΅ΠΌ, Ρ‡Ρ‚ΠΎΠ±Ρ‹ Π±Ρ€Π°Ρ‚ΡŒ ΠΈ ΡƒΠ΄Π°Π»ΡΡ‚ΡŒ ΠΈΡΠΏΠΎΠ»ΡŒΠ·ΠΎΠ²Π°Π½Π½Ρ‹Π΅ индСксы Π±Π°Ρ‚Ρ‡Π΅ΠΉ ΠΏΠΎ порядку
  dt <- data.table::data.table(id = sample(samples_index))
  # ΠŸΡ€ΠΎΡΡ‚Π°Π²Π»ΡΠ΅ΠΌ Π½ΠΎΠΌΠ΅Ρ€Π° Π±Π°Ρ‚Ρ‡Π΅ΠΉ
  dt[, batch := (.I - 1L) %/% batch_size + 1L]
  # ΠžΡΡ‚Π°Π²Π»ΡΠ΅ΠΌ Ρ‚ΠΎΠ»ΡŒΠΊΠΎ ΠΏΠΎΠ»Π½Ρ‹Π΅ Π±Π°Ρ‚Ρ‡ΠΈ ΠΈ индСксируСм
  dt <- dt[, if (.N == batch_size) .SD, keyby = batch]
  # УстанавливаСм счётчик
  i <- 1
  # ΠšΠΎΠ»ΠΈΡ‡Π΅ΡΡ‚Π²ΠΎ Π±Π°Ρ‚Ρ‡Π΅ΠΉ
  max_i <- dt[, max(batch)]

  # ΠŸΠΎΠ΄Π³ΠΎΡ‚ΠΎΠ²ΠΊΠ° выраТСния для Π²Ρ‹Π³Ρ€ΡƒΠ·ΠΊΠΈ
  sql <- sprintf(
    "PREPARE SELECT drawing, label_int FROM doodles WHERE id IN (%s)",
    paste(rep("?", batch_size), collapse = ",")
  )
  res <- DBI::dbSendQuery(con, sql)

  # Аналог keras::to_categorical
  to_categorical <- function(x, num) {
    n <- length(x)
    m <- numeric(n * num)
    m[x * n + seq_len(n)] <- 1
    dim(m) <- c(n, num)
    return(m)
  }

  # Π—Π°ΠΌΡ‹ΠΊΠ°Π½ΠΈΠ΅
  function() {
    # НачинаСм Π½ΠΎΠ²ΡƒΡŽ эпоху
    if (i > max_i) {
      dt[, id := sample(id)]
      data.table::setkey(dt, batch)
      # БбрасываСм счётчик
      i <<- 1
      max_i <<- dt[, max(batch)]
    }

    # ID для Π²Ρ‹Π³Ρ€ΡƒΠ·ΠΊΠΈ Π΄Π°Π½Π½Ρ‹Ρ…
    batch_ind <- dt[batch == i, id]
    # Π’Ρ‹Π³Ρ€ΡƒΠ·ΠΊΠ° Π΄Π°Π½Π½Ρ‹Ρ…
    batch <- DBI::dbFetch(DBI::dbBind(res, as.list(batch_ind)), n = -1)

    # Π£Π²Π΅Π»ΠΈΡ‡ΠΈΠ²Π°Π΅ΠΌ счётчик
    i <<- i + 1

    # ΠŸΠ°Ρ€ΡΠΈΠ½Π³ JSON ΠΈ ΠΏΠΎΠ΄Π³ΠΎΡ‚ΠΎΠ²ΠΊΠ° массива
    batch_x <- cpp_process_json_vector(batch$drawing, scale = scale, color = color)
    if (imagenet_preproc) {
      # Π¨ΠΊΠ°Π»ΠΈΡ€ΠΎΠ²Π°Π½ΠΈΠ΅ c ΠΈΠ½Ρ‚Π΅Ρ€Π²Π°Π»Π° [0, 1] Π½Π° ΠΈΠ½Ρ‚Π΅Ρ€Π²Π°Π» [-1, 1]
      batch_x <- (batch_x - 0.5) * 2
    }

    batch_y <- to_categorical(batch$label_int, num_classes)
    result <- list(batch_x, batch_y)
    return(result)
  }
}

Π€ΡƒΠ½ΠΊΡ†ΠΈΡ˜Π° ΡƒΠ·ΠΈΠΌΠ° ΠΊΠ°ΠΎ ΡƒΠ»Π°Π· ΠΏΡ€ΠΎΠΌΠ΅Π½Ρ™ΠΈΠ²Ρƒ са Π²Π΅Π·ΠΎΠΌ са Π±Π°Π·ΠΎΠΌ ΠΏΠΎΠ΄Π°Ρ‚Π°ΠΊΠ°, Π±Ρ€ΠΎΡ˜Π΅Π²ΠΈΠΌΠ° ΠΊΠΎΡ€ΠΈΡˆΡ›Π΅Π½ΠΈΡ… линија, Π±Ρ€ΠΎΡ˜Π΅ΠΌ класа, Π²Π΅Π»ΠΈΡ‡ΠΈΠ½ΠΎΠΌ ΡΠ΅Ρ€ΠΈΡ˜Π΅, Ρ€Π°Π·ΠΌΠ΅Ρ€ΠΎΠΌ (scale = 1 ΠΎΠ΄Π³ΠΎΠ²Π°Ρ€Π° ΠΏΡ€ΠΈΠΊΠ°Π·ΠΈΠ²Π°ΡšΡƒ слика ΠΎΠ΄ 256ΠΊ256 пиксСла, scale = 0.5 β€” 128ΠΊ128 пиксСла), ΠΈΠ½Π΄ΠΈΠΊΠ°Ρ‚ΠΎΡ€ боја (color = FALSE ΠΎΠ΄Ρ€Π΅Ρ’ΡƒΡ˜Π΅ ΠΏΡ€ΠΈΠΊΠ°Π·ΠΈΠ²Π°ΡšΠ΅ Ρƒ сивим Ρ‚ΠΎΠ½ΠΎΠ²ΠΈΠΌΠ° ΠΊΠ°Π΄Π° сС користи color = TRUE сваки ΠΏΠΎΡ‚Π΅Π· јС Π½Π°Ρ†Ρ€Ρ‚Π°Π½ Ρƒ новој боји) ΠΈ ΠΈΠ½Π΄ΠΈΠΊΠ°Ρ‚ΠΎΡ€ Π·Π° ΠΏΡ€Π΅Ρ‚Ρ…ΠΎΠ΄Π½Ρƒ ΠΎΠ±Ρ€Π°Π΄Ρƒ Π·Π° ΠΌΡ€Π΅ΠΆΠ΅ ΠΏΡ€Π΅Ρ‚Ρ…ΠΎΠ΄Π½ΠΎ ΠΎΠ±ΡƒΡ‡Π΅Π½Π΅ Π½Π° ΠΈΠΌΠ°Π³Π΅Π½Π΅Ρ‚-Ρƒ. Ово послСдњС јС ΠΏΠΎΡ‚Ρ€Π΅Π±Π½ΠΎ Π΄Π° Π±ΠΈ сС скалирали врСдности пиксСла ΠΎΠ΄ ΠΈΠ½Ρ‚Π΅Ρ€Π²Π°Π»Π° [0, 1] Π΄ΠΎ ΠΈΠ½Ρ‚Π΅Ρ€Π²Π°Π»Π° [-1, 1], који јС ΠΊΠΎΡ€ΠΈΡˆΡ›Π΅Π½ ΠΏΡ€ΠΈ ΠΎΠ±ΡƒΡ‡Π°Π²Π°ΡšΡƒ испоручСних кСрас ΠΌΠΎΠ΄Π΅Π»ΠΈ.

ЕкстСрна Ρ„ΡƒΠ½ΠΊΡ†ΠΈΡ˜Π° садрТи ΠΏΡ€ΠΎΠ²Π΅Ρ€Ρƒ Ρ‚ΠΈΠΏΠ° Π°Ρ€Π³ΡƒΠΌΠ΅Π½Ρ‚Π°, Ρ‚Π°Π±Π΅Π»Ρƒ data.table са насумично помСшаним Π±Ρ€ΠΎΡ˜Π΅Π²ΠΈΠΌΠ° линија ΠΈΠ· samples_index ΠΈ Π±Ρ€ΠΎΡ˜Π΅Π²ΠΈ ΡΠ΅Ρ€ΠΈΡ˜Π°, Π±Ρ€ΠΎΡ˜Π°Ρ‡ ΠΈ максималан Π±Ρ€ΠΎΡ˜ ΡΠ΅Ρ€ΠΈΡ˜Π°, ΠΊΠ°ΠΎ ΠΈ Π‘ΠšΠ› ΠΈΠ·Ρ€Π°Π· Π·Π° истовар ΠΏΠΎΠ΄Π°Ρ‚Π°ΠΊΠ° ΠΈΠ· Π±Π°Π·Π΅ ΠΏΠΎΠ΄Π°Ρ‚Π°ΠΊΠ°. Π”ΠΎΠ΄Π°Ρ‚Π½ΠΎ, дСфинисали смо Π±Ρ€Π·ΠΈ Π°Π½Π°Π»ΠΎΠ³ Ρ„ΡƒΠ½ΠΊΡ†ΠΈΡ˜Π΅ ΡƒΠ½ΡƒΡ‚Ρ€Π° keras::to_categorical(). ΠšΠΎΡ€ΠΈΡΡ‚ΠΈΠ»ΠΈ смо скоро свС ΠΏΠΎΠ΄Π°Ρ‚ΠΊΠ΅ Π·Π° ΠΎΠ±ΡƒΠΊΡƒ, ΠΎΡΡ‚Π°Π²Ρ™Π°Ρ˜ΡƒΡ›ΠΈ ΠΏΠΎΠ»Π° ΠΏΡ€ΠΎΡ†Π΅Π½Ρ‚Π° Π·Π° Π²Π°Π»ΠΈΠ΄Π°Ρ†ΠΈΡ˜Ρƒ, Ρ‚Π°ΠΊΠΎ Π΄Π° јС Π²Π΅Π»ΠΈΡ‡ΠΈΠ½Π° Π΅ΠΏΠΎΡ…Π΅ Π±ΠΈΠ»Π° ΠΎΠ³Ρ€Π°Π½ΠΈΡ‡Π΅Π½Π° ΠΏΠ°Ρ€Π°ΠΌΠ΅Ρ‚Ρ€ΠΎΠΌ steps_per_epoch ΠΏΡ€ΠΈΠ»ΠΈΠΊΠΎΠΌ позивања keras::fit_generator(), ΠΈ ΡΡ‚Π°ΡšΠ΅ if (i > max_i) Ρ€Π°Π΄ΠΈΠΎ само Π·Π° ΠΈΡ‚Π΅Ρ€Π°Ρ‚ΠΎΡ€ Π²Π°Π»ΠΈΠ΄Π°Ρ†ΠΈΡ˜Π΅.

Π£ ΠΈΠ½Ρ‚Π΅Ρ€Π½ΠΎΡ˜ Ρ„ΡƒΠ½ΠΊΡ†ΠΈΡ˜ΠΈ, индСкси Ρ€Π΅Π΄ΠΎΠ²Π° сС ΠΏΡ€Π΅ΡƒΠ·ΠΈΠΌΠ°Ρ˜Ρƒ Π·Π° слСдСћу Π³Ρ€ΡƒΠΏΡƒ, записи сС ΡƒΡ‡ΠΈΡ‚Π°Π²Π°Ρ˜Ρƒ ΠΈΠ· Π±Π°Π·Π΅ ΠΏΠΎΠ΄Π°Ρ‚Π°ΠΊΠ° са ΠΏΠΎΠ²Π΅Ρ›Π°ΡšΠ΅ΠΌ Π±Ρ€ΠΎΡ˜Π°Ρ‡Π° Π³Ρ€ΡƒΠΏΠ΅, ЈБОН Ρ€Π°ΡˆΡ‡Π»Π°ΡšΠΈΠ²Π°ΡšΠ΅ΠΌ (Ρ„ΡƒΠ½ΠΊΡ†ΠΈΡ˜Π° cpp_process_json_vector(), написан Ρƒ Π¦++) ΠΈ ΠΊΡ€Π΅ΠΈΡ€Π°ΡšΠ΅ Π½ΠΈΠ·ΠΎΠ²Π° који ΠΎΠ΄Π³ΠΎΠ²Π°Ρ€Π°Ρ˜Ρƒ сликама. Π—Π°Ρ‚ΠΈΠΌ сС ΠΊΡ€Π΅ΠΈΡ€Π°Ρ˜Ρƒ Ρ˜Π΅Π΄Π½ΠΎΠΊΡ€Π°Ρ‚Π½ΠΈ Π²Π΅ΠΊΡ‚ΠΎΡ€ΠΈ са ΠΎΠ·Π½Π°ΠΊΠ°ΠΌΠ° класа, Π½ΠΈΠ·ΠΎΠ²ΠΈ са врСдностима пиксСла ΠΈ ΠΎΠ·Π½Π°ΠΊΠ°ΠΌΠ° сС ΠΊΠΎΠΌΠ±ΠΈΠ½ΡƒΡ˜Ρƒ Ρƒ листу, ΡˆΡ‚ΠΎ јС ΠΏΠΎΠ²Ρ€Π°Ρ‚Π½Π° врСдност. Π”Π° бисмо ΡƒΠ±Ρ€Π·Π°Π»ΠΈ Ρ€Π°Π΄, користили смо ΠΊΡ€Π΅ΠΈΡ€Π°ΡšΠ΅ индСкса Ρƒ Ρ‚Π°Π±Π΅Π»Π°ΠΌΠ° data.table ΠΈ ΠΌΠΎΠ΄ΠΈΡ„ΠΈΠΊΠ°Ρ†ΠΈΡ˜Π° ΠΏΡ€Π΅ΠΊΠΎ Π²Π΅Π·Π΅ - Π±Π΅Π· ΠΎΠ²ΠΈΡ… ΠΏΠ°ΠΊΠ΅Ρ‚Π° β€žΡ‡ΠΈΠΏΠΎΠ²Π°β€œ ΠΏΠΎΠ΄Π°Ρ†ΠΈ.Ρ‚Π°Π±Π΅Π»Π° ΠŸΡ€ΠΈΠ»ΠΈΡ‡Π½ΠΎ јС Ρ‚Π΅ΡˆΠΊΠΎ замислити Сфикасан Ρ€Π°Π΄ са Π±ΠΈΠ»ΠΎ којом Π·Π½Π°Ρ‡Π°Ρ˜Π½ΠΎΠΌ ΠΊΠΎΠ»ΠΈΡ‡ΠΈΠ½ΠΎΠΌ ΠΏΠΎΠ΄Π°Ρ‚Π°ΠΊΠ° Ρƒ Π .

Π Π΅Π·ΡƒΠ»Ρ‚Π°Ρ‚ΠΈ ΠΌΠ΅Ρ€Π΅ΡšΠ° Π±Ρ€Π·ΠΈΠ½Π΅ Π½Π° Π¦ΠΎΡ€Π΅ ΠΈ5 Π»Π°ΠΏΡ‚ΠΎΠΏΡƒ су слСдСћи:

Π‘Π΅Π½Ρ†Ρ…ΠΌΠ°Ρ€ΠΊ ΠΈΡ‚Π΅Ρ€Π°Ρ‚ΠΎΡ€Π°

library(Rcpp)
library(keras)
library(ggplot2)

source("utils/rcpp.R")
source("utils/keras_iterator.R")

con <- DBI::dbConnect(drv = MonetDBLite::MonetDBLite(), Sys.getenv("DBDIR"))

ind <- seq_len(DBI::dbGetQuery(con, "SELECT count(*) FROM doodles")[[1L]])
num_classes <- DBI::dbGetQuery(con, "SELECT max(label_int) + 1 FROM doodles")[[1L]]

# Π˜Π½Π΄Π΅ΠΊΡΡ‹ для ΠΎΠ±ΡƒΡ‡Π°ΡŽΡ‰Π΅ΠΉ Π²Ρ‹Π±ΠΎΡ€ΠΊΠΈ
train_ind <- sample(ind, floor(length(ind) * 0.995))
# Π˜Π½Π΄Π΅ΠΊΡΡ‹ для ΠΏΡ€ΠΎΠ²Π΅Ρ€ΠΎΡ‡Π½ΠΎΠΉ Π²Ρ‹Π±ΠΎΡ€ΠΊΠΈ
val_ind <- ind[-train_ind]
rm(ind)
# ΠšΠΎΡΡ„Ρ„ΠΈΡ†ΠΈΠ΅Π½Ρ‚ ΠΌΠ°ΡΡˆΡ‚Π°Π±Π°
scale <- 0.5

# ΠŸΡ€ΠΎΠ²Π΅Π΄Π΅Π½ΠΈΠ΅ Π·Π°ΠΌΠ΅Ρ€Π°
res_bench <- bench::press(
  batch_size = 2^(4:10),
  {
    it1 <- train_generator(
      db_connection = con,
      samples_index = train_ind,
      num_classes = num_classes,
      batch_size = batch_size,
      scale = scale
    )
    bench::mark(
      it1(),
      min_iterations = 50L
    )
  }
)
# ΠŸΠ°Ρ€Π°ΠΌΠ΅Ρ‚Ρ€Ρ‹ Π±Π΅Π½Ρ‡ΠΌΠ°Ρ€ΠΊΠ°
cols <- c("batch_size", "min", "median", "max", "itr/sec", "total_time", "n_itr")
res_bench[, cols]

#   batch_size      min   median      max `itr/sec` total_time n_itr
#        <dbl> <bch:tm> <bch:tm> <bch:tm>     <dbl>   <bch:tm> <int>
# 1         16     25ms  64.36ms   92.2ms     15.9       3.09s    49
# 2         32   48.4ms 118.13ms 197.24ms     8.17       5.88s    48
# 3         64   69.3ms 117.93ms 181.14ms     8.57       5.83s    50
# 4        128  157.2ms 240.74ms 503.87ms     3.85      12.71s    49
# 5        256  359.3ms 613.52ms 988.73ms     1.54       30.5s    47
# 6        512  884.7ms    1.53s    2.07s     0.674      1.11m    45
# 7       1024     2.7s    3.83s    5.47s     0.261      2.81m    44

ggplot(res_bench, aes(x = factor(batch_size), y = median, group = 1)) +
    geom_point() +
    geom_line() +
    ylab("median time, s") +
    theme_minimal()

DBI::dbDisconnect(con, shutdown = TRUE)

ΠšΡƒΠΈΡ†ΠΊ Π”Ρ€Π°Π² Π”ΠΎΠΎΠ΄Π»Π΅ Π Π΅Ρ†ΠΎΠ³Π½ΠΈΡ‚ΠΈΠΎΠ½: ΠΊΠ°ΠΊΠΎ сС ΡΠΏΡ€ΠΈΡ˜Π°Ρ‚Π΅Ρ™ΠΈΡ‚ΠΈ са Π , Π¦++ ΠΈ нСуронским ΠΌΡ€Π΅ΠΆΠ°ΠΌΠ°

Ако ΠΈΠΌΠ°Ρ‚Π΅ Π΄ΠΎΠ²ΠΎΡ™Π½Ρƒ ΠΊΠΎΠ»ΠΈΡ‡ΠΈΠ½Ρƒ РАМ-Π°, ΠΌΠΎΠΆΠ΅Ρ‚Π΅ ΠΎΠ·Π±ΠΈΡ™Π½ΠΎ ΡƒΠ±Ρ€Π·Π°Ρ‚ΠΈ Ρ€Π°Π΄ Π±Π°Π·Π΅ ΠΏΠΎΠ΄Π°Ρ‚Π°ΠΊΠ° Ρ‚Π°ΠΊΠΎ ΡˆΡ‚ΠΎ Ρ›Π΅Ρ‚Π΅ јС ΠΏΡ€Π΅Π½Π΅Ρ‚ΠΈ Ρƒ ΠΎΠ²Ρƒ исту РАМ ΠΌΠ΅ΠΌΠΎΡ€ΠΈΡ˜Ρƒ (Π·Π° наш Π·Π°Π΄Π°Ρ‚Π°ΠΊ јС Π΄ΠΎΠ²ΠΎΡ™Π½ΠΎ 32 Π“Π‘). Π£ Π›ΠΈΠ½ΡƒΠΊ-Ρƒ, ΠΏΠ°Ρ€Ρ‚ΠΈΡ†ΠΈΡ˜Π° јС ΠΏΠΎΠ΄Ρ€Π°Π·ΡƒΠΌΠ΅Π²Π°Π½ΠΎ ΠΌΠΎΠ½Ρ‚ΠΈΡ€Π°Π½Π° /dev/shm, који Π·Π°ΡƒΠ·ΠΈΠΌΠ°Ρ˜Ρƒ Π΄ΠΎ ΠΏΠΎΠ»ΠΎΠ²ΠΈΠ½Π΅ ΠΊΠ°ΠΏΠ°Ρ†ΠΈΡ‚Π΅Ρ‚Π° РАМ-Π°. ΠœΠΎΠΆΠ΅Ρ‚Π΅ Π΄Π° истакнСтС вишС ΡƒΡ€Π΅Ρ’ΠΈΠ²Π°ΡšΠ΅ΠΌ /etc/fstabΠ΄Π° Π΄ΠΎΠ±ΠΈΡ˜Π΅Ρ‚Π΅ запис ΠΊΠ°ΠΎ tmpfs /dev/shm tmpfs defaults,size=25g 0 0. ОбавСзно ΠΏΠΎΠ½ΠΎΠ²ΠΎ ΠΏΠΎΠΊΡ€Π΅Π½ΠΈΡ‚Π΅ систСм ΠΈ ΠΏΡ€ΠΎΠ²Π΅Ρ€ΠΈΡ‚Π΅ Ρ€Π΅Π·ΡƒΠ»Ρ‚Π°Ρ‚ ΠΏΠΎΠΊΡ€Π΅Ρ‚Π°ΡšΠ΅ΠΌ ΠΊΠΎΠΌΠ°Π½Π΄Π΅ df -h.

Π˜Ρ‚Π΅Ρ€Π°Ρ‚ΠΎΡ€ Π·Π° тСстнС ΠΏΠΎΠ΄Π°Ρ‚ΠΊΠ΅ ΠΈΠ·Π³Π»Π΅Π΄Π° ΠΌΠ½ΠΎΠ³ΠΎ Ρ˜Π΅Π΄Π½ΠΎΡΡ‚Π°Π²Π½ΠΈΡ˜Π΅, ΠΏΠΎΡˆΡ‚ΠΎ сС тСстни скуп ΠΏΠΎΠ΄Π°Ρ‚Π°ΠΊΠ° Ρƒ потпуности ΡƒΠΊΠ»Π°ΠΏΠ° Ρƒ РАМ:

Π˜Ρ‚Π΅Ρ€Π°Ρ‚ΠΎΡ€ Π·Π° тСстнС ΠΏΠΎΠ΄Π°Ρ‚ΠΊΠ΅

test_generator <- function(dt,
                           batch_size = 32,
                           scale = 1,
                           color = FALSE,
                           imagenet_preproc = FALSE) {

  # ΠŸΡ€ΠΎΠ²Π΅Ρ€ΠΊΠ° Π°Ρ€Π³ΡƒΠΌΠ΅Π½Ρ‚ΠΎΠ²
  checkmate::assert_data_table(dt)
  checkmate::assert_count(batch_size)
  checkmate::assert_number(scale, lower = 0.001, upper = 5)
  checkmate::assert_flag(color)
  checkmate::assert_flag(imagenet_preproc)

  # ΠŸΡ€ΠΎΡΡ‚Π°Π²Π»ΡΠ΅ΠΌ Π½ΠΎΠΌΠ΅Ρ€Π° Π±Π°Ρ‚Ρ‡Π΅ΠΉ
  dt[, batch := (.I - 1L) %/% batch_size + 1L]
  data.table::setkey(dt, batch)
  i <- 1
  max_i <- dt[, max(batch)]

  # Π—Π°ΠΌΡ‹ΠΊΠ°Π½ΠΈΠ΅
  function() {
    batch_x <- cpp_process_json_vector(dt[batch == i, drawing], 
                                       scale = scale, color = color)
    if (imagenet_preproc) {
      # Π¨ΠΊΠ°Π»ΠΈΡ€ΠΎΠ²Π°Π½ΠΈΠ΅ c ΠΈΠ½Ρ‚Π΅Ρ€Π²Π°Π»Π° [0, 1] Π½Π° ΠΈΠ½Ρ‚Π΅Ρ€Π²Π°Π» [-1, 1]
      batch_x <- (batch_x - 0.5) * 2
    }
    result <- list(batch_x)
    i <<- i + 1
    return(result)
  }
}

4. Π˜Π·Π±ΠΎΡ€ Π°Ρ€Ρ…ΠΈΡ‚Π΅ΠΊΡ‚ΡƒΡ€Π΅ ΠΌΠΎΠ΄Π΅Π»Π°

ΠŸΡ€Π²Π° ΠΊΠΎΡ€ΠΈΡˆΡ›Π΅Π½Π° Π°Ρ€Ρ…ΠΈΡ‚Π΅ΠΊΡ‚ΡƒΡ€Π° Π±ΠΈΠ»Π° јС ΠΌΠΎΠ±ΠΈΠ»Π΅Π½Π΅Ρ‚ Π²1, ΠΎ Ρ‡ΠΈΡ˜ΠΈΠΌ карактСристикама сС Π³ΠΎΠ²ΠΎΡ€ΠΈ Ρƒ ΠΎΠ²ΠΎ ΠΏΠΎΡ€ΡƒΠΊΠ°. Π£ΠΊΡ™ΡƒΡ‡Π΅Π½ јС ΠΊΠ°ΠΎ стандард кСрас ΠΈ, сходно Ρ‚ΠΎΠΌΠ΅, доступан јС Ρƒ истоимСном ΠΏΠ°ΠΊΠ΅Ρ‚Ρƒ Π·Π° Π . Али ΠΊΠ°Π΄Π° ΠΏΠΎΠΊΡƒΡˆΠ°Ρ‚Π΅ Π΄Π° Π³Π° користитС са јСдноканалним сликама, испоставило сС Ρ‡ΡƒΠ΄Π½ΠΎ: ΡƒΠ»Π°Π·Π½ΠΈ Ρ‚Π΅Π½Π·ΠΎΡ€ ΡƒΠ²Π΅ΠΊ ΠΌΠΎΡ€Π° ΠΈΠΌΠ°Ρ‚ΠΈ Π΄ΠΈΠΌΠ΅Π½Π·ΠΈΡ˜Ρƒ (batch, height, width, 3), односно Π±Ρ€ΠΎΡ˜ ΠΊΠ°Π½Π°Π»Π° сС Π½Π΅ ΠΌΠΎΠΆΠ΅ ΠΌΠ΅ΡšΠ°Ρ‚ΠΈ. Π£ ΠŸΠΈΡ‚Ρ…ΠΎΠ½-Ρƒ Π½Π΅ΠΌΠ° Ρ‚Π°ΠΊΠ²ΠΎΠ³ ΠΎΠ³Ρ€Π°Π½ΠΈΡ‡Π΅ΡšΠ°, ΠΏΠ° смо ΠΏΠΎΠΆΡƒΡ€ΠΈΠ»ΠΈ ΠΈ написали сопствСну ΠΈΠΌΠΏΠ»Π΅ΠΌΠ΅Π½Ρ‚Π°Ρ†ΠΈΡ˜Ρƒ ΠΎΠ²Π΅ Π°Ρ€Ρ…ΠΈΡ‚Π΅ΠΊΡ‚ΡƒΡ€Π΅, ΠΏΡ€Π°Ρ‚Π΅Ρ›ΠΈ ΠΎΡ€ΠΈΠ³ΠΈΠ½Π°Π»Π½ΠΈ Ρ‡Π»Π°Π½Π°ΠΊ (Π±Π΅Π· испадања који јС Ρƒ кСрас Π²Π΅Ρ€Π·ΠΈΡ˜ΠΈ):

ΠœΠΎΠ±ΠΈΠ»Π΅Π½Π΅Ρ‚ Π²1 Π°Ρ€Ρ…ΠΈΡ‚Π΅ΠΊΡ‚ΡƒΡ€Π°

library(keras)

top_3_categorical_accuracy <- custom_metric(
    name = "top_3_categorical_accuracy",
    metric_fn = function(y_true, y_pred) {
         metric_top_k_categorical_accuracy(y_true, y_pred, k = 3)
    }
)

layer_sep_conv_bn <- function(object, 
                              filters,
                              alpha = 1,
                              depth_multiplier = 1,
                              strides = c(2, 2)) {

  # NB! depth_multiplier !=  resolution multiplier
  # https://github.com/keras-team/keras/issues/10349

  layer_depthwise_conv_2d(
    object = object,
    kernel_size = c(3, 3), 
    strides = strides,
    padding = "same",
    depth_multiplier = depth_multiplier
  ) %>%
  layer_batch_normalization() %>% 
  layer_activation_relu() %>%
  layer_conv_2d(
    filters = filters * alpha,
    kernel_size = c(1, 1), 
    strides = c(1, 1)
  ) %>%
  layer_batch_normalization() %>% 
  layer_activation_relu() 
}

get_mobilenet_v1 <- function(input_shape = c(224, 224, 1),
                             num_classes = 340,
                             alpha = 1,
                             depth_multiplier = 1,
                             optimizer = optimizer_adam(lr = 0.002),
                             loss = "categorical_crossentropy",
                             metrics = c("categorical_crossentropy",
                                         top_3_categorical_accuracy)) {

  inputs <- layer_input(shape = input_shape)

  outputs <- inputs %>%
    layer_conv_2d(filters = 32, kernel_size = c(3, 3), strides = c(2, 2), padding = "same") %>%
    layer_batch_normalization() %>% 
    layer_activation_relu() %>%
    layer_sep_conv_bn(filters = 64, strides = c(1, 1)) %>%
    layer_sep_conv_bn(filters = 128, strides = c(2, 2)) %>%
    layer_sep_conv_bn(filters = 128, strides = c(1, 1)) %>%
    layer_sep_conv_bn(filters = 256, strides = c(2, 2)) %>%
    layer_sep_conv_bn(filters = 256, strides = c(1, 1)) %>%
    layer_sep_conv_bn(filters = 512, strides = c(2, 2)) %>%
    layer_sep_conv_bn(filters = 512, strides = c(1, 1)) %>%
    layer_sep_conv_bn(filters = 512, strides = c(1, 1)) %>%
    layer_sep_conv_bn(filters = 512, strides = c(1, 1)) %>%
    layer_sep_conv_bn(filters = 512, strides = c(1, 1)) %>%
    layer_sep_conv_bn(filters = 512, strides = c(1, 1)) %>%
    layer_sep_conv_bn(filters = 1024, strides = c(2, 2)) %>%
    layer_sep_conv_bn(filters = 1024, strides = c(1, 1)) %>%
    layer_global_average_pooling_2d() %>%
    layer_dense(units = num_classes) %>%
    layer_activation_softmax()

    model <- keras_model(
      inputs = inputs,
      outputs = outputs
    )

    model %>% compile(
      optimizer = optimizer,
      loss = loss,
      metrics = metrics
    )

    return(model)
}

НСдостаци ΠΎΠ²ΠΎΠ³ приступа су ΠΎΡ‡ΠΈΠ³Π»Π΅Π΄Π½ΠΈ. Π–Π΅Π»ΠΈΠΌ Π΄Π° тСстирам ΠΌΠ½ΠΎΠ³ΠΎ ΠΌΠΎΠ΄Π΅Π»Π°, Π°Π»ΠΈ Π½Π°ΠΏΡ€ΠΎΡ‚ΠΈΠ², Π½Π΅ ΠΆΠ΅Π»ΠΈΠΌ Π΄Π° ΠΏΡ€Π΅ΠΏΠΈΡΡƒΡ˜Π΅ΠΌ сваку Π°Ρ€Ρ…ΠΈΡ‚Π΅ΠΊΡ‚ΡƒΡ€Ρƒ Ρ€ΡƒΡ‡Π½ΠΎ. Π’Π°ΠΊΠΎΡ’Π΅ смо Π±ΠΈΠ»ΠΈ лишСни могућности Π΄Π° користимо Ρ‚Π΅ΠΆΠΈΠ½Π΅ ΠΌΠΎΠ΄Π΅Π»Π° ΡƒΠ½Π°ΠΏΡ€Π΅Π΄ ΠΎΠ±ΡƒΡ‡Π΅Π½ΠΈΡ… Π½Π° ΠΈΠΌΠ°Π³Π΅Π½Π΅Ρ‚-Ρƒ. Као ΠΈ ΠΎΠ±ΠΈΡ‡Π½ΠΎ, ΠΏΠΎΠΌΠΎΠ³Π»ΠΎ јС ΠΏΡ€ΠΎΡƒΡ‡Π°Π²Π°ΡšΠ΅ Π΄ΠΎΠΊΡƒΠΌΠ΅Π½Ρ‚Π°Ρ†ΠΈΡ˜Π΅. Π€ΡƒΠ½ΠΊΡ†ΠΈΡ˜Π° get_config() ΠΎΠΌΠΎΠ³ΡƒΡ›Π°Π²Π° Π²Π°ΠΌ Π΄Π° Π΄ΠΎΠ±ΠΈΡ˜Π΅Ρ‚Π΅ опис ΠΌΠΎΠ΄Π΅Π»Π° Ρƒ ΠΎΠ±Π»ΠΈΠΊΡƒ ΠΏΠΎΠ³ΠΎΠ΄Π½ΠΎΠΌ Π·Π° ΡƒΡ€Π΅Ρ’ΠΈΠ²Π°ΡšΠ΅ (base_model_conf$layers - Ρ€Π΅Π³ΡƒΠ»Π°Ρ€Π½Π° Π  листа) ΠΈ Ρ„ΡƒΠ½ΠΊΡ†ΠΈΡ˜Π° from_config() Π²Ρ€ΡˆΠΈ ΠΎΠ±Ρ€Π½ΡƒΡ‚Ρƒ ΠΊΠΎΠ½Π²Π΅Ρ€Π·ΠΈΡ˜Ρƒ Ρƒ ΠΎΠ±Ρ˜Π΅ΠΊΠ°Ρ‚ ΠΌΠΎΠ΄Π΅Π»Π°:

base_model_conf <- get_config(base_model)
base_model_conf$layers[[1]]$config$batch_input_shape[[4]] <- 1L
base_model <- from_config(base_model_conf)

Π‘Π°Π΄Π° нијС Ρ‚Π΅ΡˆΠΊΠΎ написати ΡƒΠ½ΠΈΠ²Π΅Ρ€Π·Π°Π»Π½Ρƒ Ρ„ΡƒΠ½ΠΊΡ†ΠΈΡ˜Ρƒ Π·Π° добијањС Π±ΠΈΠ»ΠΎ којС ΠΎΠ΄ испоручСних кСрас ΠΌΠΎΠ΄Π΅Π»ΠΈ са ΠΈΠ»ΠΈ Π±Π΅Π· Ρ‚Π΅Π³ΠΎΠ²Π° ΠΎΠ±ΡƒΡ‡Π΅Π½ΠΈ Π½Π° ΠΈΠΌΠ°Π³Π΅Π½Π΅Ρ‚-Ρƒ:

Π€ΡƒΠ½ΠΊΡ†ΠΈΡ˜Π° Π·Π° ΡƒΡ‡ΠΈΡ‚Π°Π²Π°ΡšΠ΅ Π³ΠΎΡ‚ΠΎΠ²ΠΈΡ… Π°Ρ€Ρ…ΠΈΡ‚Π΅ΠΊΡ‚ΡƒΡ€Π°

get_model <- function(name = "mobilenet_v2",
                      input_shape = NULL,
                      weights = "imagenet",
                      pooling = "avg",
                      num_classes = NULL,
                      optimizer = keras::optimizer_adam(lr = 0.002),
                      loss = "categorical_crossentropy",
                      metrics = NULL,
                      color = TRUE,
                      compile = FALSE) {
  # ΠŸΡ€ΠΎΠ²Π΅Ρ€ΠΊΠ° Π°Ρ€Π³ΡƒΠΌΠ΅Π½Ρ‚ΠΎΠ²
  checkmate::assert_string(name)
  checkmate::assert_integerish(input_shape, lower = 1, upper = 256, len = 3)
  checkmate::assert_count(num_classes)
  checkmate::assert_flag(color)
  checkmate::assert_flag(compile)

  # ΠŸΠΎΠ»ΡƒΡ‡Π°Π΅ΠΌ ΠΎΠ±ΡŠΠ΅ΠΊΡ‚ ΠΈΠ· ΠΏΠ°ΠΊΠ΅Ρ‚Π° keras
  model_fun <- get0(paste0("application_", name), envir = asNamespace("keras"))
  # ΠŸΡ€ΠΎΠ²Π΅Ρ€ΠΊΠ° наличия ΠΎΠ±ΡŠΠ΅ΠΊΡ‚Π° Π² ΠΏΠ°ΠΊΠ΅Ρ‚Π΅
  if (is.null(model_fun)) {
    stop("Model ", shQuote(name), " not found.", call. = FALSE)
  }

  base_model <- model_fun(
    input_shape = input_shape,
    include_top = FALSE,
    weights = weights,
    pooling = pooling
  )

  # Если ΠΈΠ·ΠΎΠ±Ρ€Π°ΠΆΠ΅Π½ΠΈΠ΅ Π½Π΅ Ρ†Π²Π΅Ρ‚Π½ΠΎΠ΅, мСняСм Ρ€Π°Π·ΠΌΠ΅Ρ€Π½ΠΎΡΡ‚ΡŒ Π²Ρ…ΠΎΠ΄Π°
  if (!color) {
    base_model_conf <- keras::get_config(base_model)
    base_model_conf$layers[[1]]$config$batch_input_shape[[4]] <- 1L
    base_model <- keras::from_config(base_model_conf)
  }

  predictions <- keras::get_layer(base_model, "global_average_pooling2d_1")$output
  predictions <- keras::layer_dense(predictions, units = num_classes, activation = "softmax")
  model <- keras::keras_model(
    inputs = base_model$input,
    outputs = predictions
  )

  if (compile) {
    keras::compile(
      object = model,
      optimizer = optimizer,
      loss = loss,
      metrics = metrics
    )
  }

  return(model)
}

Када користитС јСдноканалнС сликС, Π½Π΅ користС сС ΡƒΠ½Π°ΠΏΡ€Π΅Π΄ ΠΎΠ±ΡƒΡ‡Π΅Π½Π΅ Ρ‚Π΅ΠΆΠΈΠ½Π΅. Ово Π±ΠΈ сС ΠΌΠΎΠ³Π»ΠΎ ΠΏΠΎΠΏΡ€Π°Π²ΠΈΡ‚ΠΈ: ΠΊΠΎΡ€ΠΈΡˆΡ›Π΅ΡšΠ΅ΠΌ Ρ„ΡƒΠ½ΠΊΡ†ΠΈΡ˜Π΅ get_weights() Π΄ΠΎΠ±ΠΈΡ˜Ρ‚Π΅ Ρ‚Π΅ΠΆΠΈΠ½Π΅ ΠΌΠΎΠ΄Π΅Π»Π° Ρƒ ΠΎΠ±Π»ΠΈΠΊΡƒ листС Π  Π½ΠΈΠ·ΠΎΠ²Π°, ΠΏΡ€ΠΎΠΌΠ΅Π½ΠΈΡ‚Π΅ Π΄ΠΈΠΌΠ΅Π½Π·ΠΈΡ˜Ρƒ ΠΏΡ€Π²ΠΎΠ³ Π΅Π»Π΅ΠΌΠ΅Π½Ρ‚Π° ΠΎΠ²Π΅ листС (ΡƒΠ·ΠΈΠΌΠ°ΡšΠ΅ΠΌ јСдног ΠΊΠ°Π½Π°Π»Π° бојС ΠΈΠ»ΠΈ ΡƒΡΡ€Π΅Π΄ΡšΠ°Π²Π°ΡšΠ΅ΠΌ сва Ρ‚Ρ€ΠΈ), Π° Π·Π°Ρ‚ΠΈΠΌ ΡƒΡ‡ΠΈΡ‚Π°Ρ˜Ρ‚Π΅ Ρ‚Π΅ΠΆΠΈΠ½Π΅ Π½Π°Π·Π°Π΄ Ρƒ ΠΌΠΎΠ΄Π΅Π» ΠΏΠΎΠΌΠΎΡ›Ρƒ Ρ„ΡƒΠ½ΠΊΡ†ΠΈΡ˜Π΅ set_weights(). Никада нисмо Π΄ΠΎΠ΄Π°Π»ΠΈ ΠΎΠ²Ρƒ функционалност, Ρ˜Π΅Ρ€ јС Ρƒ овој Ρ„Π°Π·ΠΈ Π²Π΅Ρ› Π±ΠΈΠ»ΠΎ јасно Π΄Π° јС ΠΏΡ€ΠΎΠ΄ΡƒΠΊΡ‚ΠΈΠ²Π½ΠΈΡ˜Π΅ Ρ€Π°Π΄ΠΈΡ‚ΠΈ са сликама Ρƒ боји.

ИзвСли смо Π²Π΅Ρ›ΠΈΠ½Ρƒ СкспСримСната користСћи ΠΌΠΎΠ±ΠΈΠ»Π½Π΅ ΠΌΡ€Π΅ΠΆΠ΅ Π²Π΅Ρ€Π·ΠΈΡ˜Π΅ 1 ΠΈ 2, ΠΊΠ°ΠΎ ΠΈ рСснСт34. ΠœΠΎΠ΄Π΅Ρ€Π½ΠΈΡ˜Π΅ Π°Ρ€Ρ…ΠΈΡ‚Π΅ΠΊΡ‚ΡƒΡ€Π΅ ΠΊΠ°ΠΎ ΡˆΡ‚ΠΎ јС Π‘Π•-Π Π΅ΡΠΠ΅ΠšΡΡ‚ су сС Π΄ΠΎΠ±Ρ€ΠΎ ΠΏΠΎΠΊΠ°Π·Π°Π»Π΅ Π½Π° ΠΎΠ²ΠΎΠΌ Ρ‚Π°ΠΊΠΌΠΈΡ‡Π΅ΡšΡƒ. НаТалост, нисмо ΠΈΠΌΠ°Π»ΠΈ Π³ΠΎΡ‚ΠΎΠ²Π΅ ΠΈΠΌΠΏΠ»Π΅ΠΌΠ΅Π½Ρ‚Π°Ρ†ΠΈΡ˜Π΅ Π½Π° Ρ€Π°ΡΠΏΠΎΠ»Π°Π³Π°ΡšΡƒ, Π° нисмо Π½ΠΈ писали својС (Π°Π»ΠΈ Ρ›Π΅ΠΌΠΎ свакако писати).

5. ΠŸΠ°Ρ€Π°ΠΌΠ΅Ρ‚Π°Ρ€ΠΈΠ·Π°Ρ†ΠΈΡ˜Π° скрипти

Π Π°Π΄ΠΈ практичности, сав ΠΊΠΎΠ΄ Π·Π° ΠΏΠΎΡ‡Π΅Ρ‚Π°ΠΊ ΠΎΠ±ΡƒΠΊΠ΅ јС Π΄ΠΈΠ·Π°Ρ˜Π½ΠΈΡ€Π°Π½ ΠΊΠ°ΠΎ јСдна скрипта, ΠΏΠ°Ρ€Π°ΠΌΠ΅Ρ‚Ρ€ΠΈΠ·ΠΎΠ²Π°Π½Π° ΠΊΠΎΡ€ΠΈΡˆΡ›Π΅ΡšΠ΅ΠΌ Π΄ΠΎΡ†ΠΎΠΏΡ‚ ΠΊΠ°ΠΊΠΎ слијСди:

doc <- '
Usage:
  train_nn.R --help
  train_nn.R --list-models
  train_nn.R [options]

Options:
  -h --help                   Show this message.
  -l --list-models            List available models.
  -m --model=<model>          Neural network model name [default: mobilenet_v2].
  -b --batch-size=<size>      Batch size [default: 32].
  -s --scale-factor=<ratio>   Scale factor [default: 0.5].
  -c --color                  Use color lines [default: FALSE].
  -d --db-dir=<path>          Path to database directory [default: Sys.getenv("db_dir")].
  -r --validate-ratio=<ratio> Validate sample ratio [default: 0.995].
  -n --n-gpu=<number>         Number of GPUs [default: 1].
'
args <- docopt::docopt(doc)

ΠŸΠ»Π°ΡΡ‚ΠΈΡ‡Π½Π° кСса Π΄ΠΎΡ†ΠΎΠΏΡ‚ прСдставља ΠΈΠΌΠΏΠ»Π΅ΠΌΠ΅Π½Ρ‚Π°Ρ†ΠΈΡ˜Ρƒ http://docopt.org/ Π·Π° Π . Π£Π· ΡšΠ΅Π³ΠΎΠ²Ρƒ ΠΏΠΎΠΌΠΎΡ›, скриптС сС ΠΏΠΎΠΊΡ€Π΅Ρ›Ρƒ Ρ˜Π΅Π΄Π½ΠΎΡΡ‚Π°Π²Π½ΠΈΠΌ ΠΊΠΎΠΌΠ°Π½Π΄Π°ΠΌΠ° ΠΏΠΎΠΏΡƒΡ‚ Rscript bin/train_nn.R -m resnet50 -c -d /home/andrey/doodle_db ΠΈΠ»ΠΈ ./bin/train_nn.R -m resnet50 -c -d /home/andrey/doodle_db, Π°ΠΊΠΎ Ρ„Π°Ρ˜Π» train_nn.R јС ΠΈΠ·Π²Ρ€ΡˆΠ½Π° (ΠΎΠ²Π° ΠΊΠΎΠΌΠ°Π½Π΄Π° Ρ›Π΅ Π·Π°ΠΏΠΎΡ‡Π΅Ρ‚ΠΈ ΠΎΠ±ΡƒΠΊΡƒ ΠΌΠΎΠ΄Π΅Π»Π° resnet50 Π½Π° Ρ‚Ρ€ΠΎΠ±ΠΎΡ˜Π½ΠΈΠΌ сликама димСнзија 128ΠΊ128 пиксСла, Π±Π°Π·Π° ΠΏΠΎΠ΄Π°Ρ‚Π°ΠΊΠ° ΠΌΠΎΡ€Π° Π΄Π° сС Π½Π°Π»Π°Π·ΠΈ Ρƒ фасцикли /home/andrey/doodle_db). ΠœΠΎΠΆΠ΅Ρ‚Π΅ Π΄ΠΎΠ΄Π°Ρ‚ΠΈ Π±Ρ€Π·ΠΈΠ½Ρƒ ΡƒΡ‡Π΅ΡšΠ°, Ρ‚ΠΈΠΏ ΠΎΠΏΡ‚ΠΈΠΌΠΈΠ·Π°Ρ‚ΠΎΡ€Π° ΠΈ свС Π΄Ρ€ΡƒΠ³Π΅ ΠΏΡ€ΠΈΠ»Π°Π³ΠΎΠ΄Ρ™ΠΈΠ²Π΅ ΠΏΠ°Ρ€Π°ΠΌΠ΅Ρ‚Ρ€Π΅ Π½Π° листу. Π£ процСсу ΠΏΡ€ΠΈΠΏΡ€Π΅ΠΌΠ΅ ΠΏΡƒΠ±Π»ΠΈΠΊΠ°Ρ†ΠΈΡ˜Π΅ испоставило сС Π΄Π° Π°Ρ€Ρ…ΠΈΡ‚Π΅ΠΊΡ‚ΡƒΡ€Π° mobilenet_v2 ΠΈΠ· Ρ‚Ρ€Π΅Π½ΡƒΡ‚Π½Π΅ Π²Π΅Ρ€Π·ΠΈΡ˜Π΅ кСрас Ρƒ ΡƒΠΏΠΎΡ‚Ρ€Π΅Π±ΠΈ Π  Π½Π΅ ΠΌΠΎΠ³Ρƒ Π·Π±ΠΎΠ³ ΠΏΡ€ΠΎΠΌΠ΅Π½Π° којС нису ΡƒΠ·Π΅Ρ‚Π΅ Ρƒ ΠΎΠ±Π·ΠΈΡ€ Ρƒ Π  ΠΏΠ°ΠΊΠ΅Ρ‚Ρƒ, Ρ‡Π΅ΠΊΠ°ΠΌΠΎ Π΄Π° Ρ‚ΠΎ ΠΏΠΎΠΏΡ€Π°Π²Π΅.

Овај приступ јС ΠΎΠΌΠΎΠ³ΡƒΡ›ΠΈΠΎ Π΄Π° сС Π·Π½Π°Ρ‡Π°Ρ˜Π½ΠΎ ΡƒΠ±Ρ€Π·Π°Ρ˜Ρƒ СкспСримСнти са Ρ€Π°Π·Π»ΠΈΡ‡ΠΈΡ‚ΠΈΠΌ ΠΌΠΎΠ΄Π΅Π»ΠΈΠΌΠ° Ρƒ ΠΏΠΎΡ€Π΅Ρ’Π΅ΡšΡƒ са Ρ‚Ρ€Π°Π΄ΠΈΡ†ΠΈΠΎΠ½Π°Π»Π½ΠΈΡ˜ΠΈΠΌ ΠΏΠΎΠΊΡ€Π΅Ρ‚Π°ΡšΠ΅ΠΌ скрипти Ρƒ Π Π‘Ρ‚ΡƒΠ΄ΠΈΡƒ (ΠΏΠ°ΠΊΠ΅Ρ‚ Π½Π°Π²ΠΎΠ΄ΠΈΠΌΠΎ ΠΊΠ°ΠΎ ΠΌΠΎΠ³ΡƒΡ›Ρƒ Π°Π»Ρ‚Π΅Ρ€Π½Π°Ρ‚ΠΈΠ²Ρƒ тфрунс). Али Π³Π»Π°Π²Π½Π° прСдност јС могућност Π»Π°ΠΊΠΎΠ³ ΡƒΠΏΡ€Π°Π²Ρ™Π°ΡšΠ° ΠΏΠΎΠΊΡ€Π΅Ρ‚Π°ΡšΠ΅ΠΌ скрипти Ρƒ Π”ΠΎΡ†ΠΊΠ΅Ρ€-Ρƒ ΠΈΠ»ΠΈ Ρ˜Π΅Π΄Π½ΠΎΡΡ‚Π°Π²Π½ΠΎ Π½Π° сСрвСру, Π±Π΅Π· ΠΈΠ½ΡΡ‚Π°Π»ΠΈΡ€Π°ΡšΠ° Π Π‘Ρ‚ΡƒΠ΄ΠΈΠ° Π·Π° ΠΎΠ²ΠΎ.

6. Π”ΠΎΠΊΠ΅Ρ€ΠΈΠ·Π°Ρ†ΠΈΡ˜Π° скрипти

ΠšΠΎΡ€ΠΈΡΡ‚ΠΈΠ»ΠΈ смо Π”ΠΎΡ†ΠΊΠ΅Ρ€ Π΄Π° ΠΎΠ±Π΅Π·Π±Π΅Π΄ΠΈΠΌΠΎ прСносивост ΠΎΠΊΡ€ΡƒΠΆΠ΅ΡšΠ° Π·Π° ΠΌΠΎΠ΄Π΅Π»Π΅ ΠΎΠ±ΡƒΠΊΠ΅ ΠΈΠ·ΠΌΠ΅Ρ’Ρƒ Ρ‡Π»Π°Π½ΠΎΠ²Π° Ρ‚ΠΈΠΌΠ° ΠΈ Π·Π° Π±Ρ€Π·Ρƒ ΠΏΡ€ΠΈΠΌΠ΅Π½Ρƒ Ρƒ ΠΎΠ±Π»Π°ΠΊΡƒ. ΠœΠΎΠΆΠ΅Ρ‚Π΅ ΠΏΠΎΡ‡Π΅Ρ‚ΠΈ Π΄Π° сС ΡƒΠΏΠΎΠ·Π½Π°Ρ‚Π΅ са ΠΎΠ²ΠΈΠΌ Π°Π»Π°Ρ‚ΠΎΠΌ, који јС Ρ€Π΅Π»Π°Ρ‚ΠΈΠ²Π½ΠΎ Π½Π΅ΠΎΠ±ΠΈΡ‡Π°Π½ Π·Π° Π  ΠΏΡ€ΠΎΠ³Ρ€Π°ΠΌΠ΅Ρ€Π° ΠΎΠ²ΠΎ ΡΠ΅Ρ€ΠΈΡ˜Π° ΠΏΡƒΠ±Π»ΠΈΠΊΠ°Ρ†ΠΈΡ˜Π° ΠΈΠ»ΠΈ Π²ΠΈΠ΄Π΅ΠΎ курс.

Π”ΠΎΡ†ΠΊΠ΅Ρ€ Π²Π°ΠΌ ΠΎΠΌΠΎΠ³ΡƒΡ›Π°Π²Π° Π΄Π° ΠΊΡ€Π΅ΠΈΡ€Π°Ρ‚Π΅ сопствСнС сликС ΠΎΠ΄ Π½ΡƒΠ»Π΅ ΠΈ Π΄Π° користитС Π΄Ρ€ΡƒΠ³Π΅ сликС ΠΊΠ°ΠΎ основу Π·Π° ΠΊΡ€Π΅ΠΈΡ€Π°ΡšΠ΅ сопствСних. ΠΠ½Π°Π»ΠΈΠ·ΠΈΡ€Π°Ρ˜ΡƒΡ›ΠΈ доступнС ΠΎΠΏΡ†ΠΈΡ˜Π΅, дошли смо Π΄ΠΎ Π·Π°ΠΊΡ™ΡƒΡ‡ΠΊΠ° Π΄Π° јС ΠΈΠ½ΡΡ‚Π°Π»ΠΈΡ€Π°ΡšΠ΅ ΠΠ’Π˜Π”Π˜Π, ЦУДА+цуДНН Π΄Ρ€Π°Ρ˜Π²Π΅Ρ€Π° ΠΈ ΠŸΠΈΡ‚Ρ…ΠΎΠ½ Π±ΠΈΠ±Π»ΠΈΠΎΡ‚Π΅ΠΊΠ° ΠΏΡ€ΠΈΠ»ΠΈΡ‡Π½ΠΎ ΠΎΠ±ΠΈΠΌΠ½ΠΈ Π΄Π΅ΠΎ сликС ΠΈ ΠΎΠ΄Π»ΡƒΡ‡ΠΈΠ»ΠΈ смо Π΄Π° Π·Π° основу ΡƒΠ·ΠΌΠ΅ΠΌΠΎ Π·Π²Π°Π½ΠΈΡ‡Π½Ρƒ слику tensorflow/tensorflow:1.12.0-gpu, Π΄ΠΎΠ΄Π°Ρ˜ΡƒΡ›ΠΈ Ρ‚Π°ΠΌΠΎ ΠΏΠΎΡ‚Ρ€Π΅Π±Π½Π΅ Π  ΠΏΠ°ΠΊΠ΅Ρ‚Π΅.

ΠšΠΎΠ½Π°Ρ‡Π½Π° Π΄ΠΎΡ†ΠΊΠ΅Ρ€ Π΄Π°Ρ‚ΠΎΡ‚Π΅ΠΊΠ° јС ΠΈΠ·Π³Π»Π΅Π΄Π°Π»Π° ΠΎΠ²Π°ΠΊΠΎ:

Π”ΠΎΡ†ΠΊΠ΅Ρ€Ρ„ΠΈΠ»Π΅

FROM tensorflow/tensorflow:1.12.0-gpu

MAINTAINER Artem Klevtsov <[email protected]>

SHELL ["/bin/bash", "-c"]

ARG LOCALE="en_US.UTF-8"
ARG APT_PKG="libopencv-dev r-base r-base-dev littler"
ARG R_BIN_PKG="futile.logger checkmate data.table rcpp rapidjsonr dbi keras jsonlite curl digest remotes"
ARG R_SRC_PKG="xtensor RcppThread docopt MonetDBLite"
ARG PY_PIP_PKG="keras"
ARG DIRS="/db /app /app/data /app/models /app/logs"

RUN source /etc/os-release && 
    echo "deb https://cloud.r-project.org/bin/linux/ubuntu ${UBUNTU_CODENAME}-cran35/" > /etc/apt/sources.list.d/cran35.list && 
    apt-key adv --keyserver keyserver.ubuntu.com --recv-keys E084DAB9 && 
    add-apt-repository -y ppa:marutter/c2d4u3.5 && 
    add-apt-repository -y ppa:timsc/opencv-3.4 && 
    apt-get update && 
    apt-get install -y locales && 
    locale-gen ${LOCALE} && 
    apt-get install -y --no-install-recommends ${APT_PKG} && 
    ln -s /usr/lib/R/site-library/littler/examples/install.r /usr/local/bin/install.r && 
    ln -s /usr/lib/R/site-library/littler/examples/install2.r /usr/local/bin/install2.r && 
    ln -s /usr/lib/R/site-library/littler/examples/installGithub.r /usr/local/bin/installGithub.r && 
    echo 'options(Ncpus = parallel::detectCores())' >> /etc/R/Rprofile.site && 
    echo 'options(repos = c(CRAN = "https://cloud.r-project.org"))' >> /etc/R/Rprofile.site && 
    apt-get install -y $(printf "r-cran-%s " ${R_BIN_PKG}) && 
    install.r ${R_SRC_PKG} && 
    pip install ${PY_PIP_PKG} && 
    mkdir -p ${DIRS} && 
    chmod 777 ${DIRS} && 
    rm -rf /tmp/downloaded_packages/ /tmp/*.rds && 
    rm -rf /var/lib/apt/lists/*

COPY utils /app/utils
COPY src /app/src
COPY tests /app/tests
COPY bin/*.R /app/

ENV DBDIR="/db"
ENV CUDA_HOME="/usr/local/cuda"
ENV PATH="/app:${PATH}"

WORKDIR /app

VOLUME /db
VOLUME /app

CMD bash

Π Π°Π΄ΠΈ погодности, ΠΊΠΎΡ€ΠΈΡˆΡ›Π΅Π½ΠΈ ΠΏΠ°ΠΊΠ΅Ρ‚ΠΈ су стављСни Ρƒ Π²Π°Ρ€ΠΈΡ˜Π°Π±Π»Π΅; Π²Π΅Ρ›ΠΈΠ½Π° написаних скрипти сС ΠΊΠΎΠΏΠΈΡ€Π° ΡƒΠ½ΡƒΡ‚Π°Ρ€ ΠΊΠΎΠ½Ρ‚Π΅Ρ˜Π½Π΅Ρ€Π° Ρ‚ΠΎΠΊΠΎΠΌ склапања. Π’Π°ΠΊΠΎΡ’Π΅ смо ΠΏΡ€ΠΎΠΌΠ΅Π½ΠΈΠ»ΠΈ ΠΊΠΎΠΌΠ°Π½Π΄Π½Ρƒ ΡˆΠΊΠΎΡ™ΠΊΡƒ Ρƒ /bin/bash Ρ€Π°Π΄ΠΈ лакшСг ΠΊΠΎΡ€ΠΈΡˆΡ›Π΅ΡšΠ° ΡΠ°Π΄Ρ€ΠΆΠ°Ρ˜Π° /etc/os-release. Π’ΠΈΠΌΠ΅ јС ΠΈΠ·Π±Π΅Π³Π½ΡƒΡ‚Π° ΠΏΠΎΡ‚Ρ€Π΅Π±Π° Π΄Π° сС Ρƒ ΠΊΠΎΠ΄Ρƒ Π½Π°Π²Π΅Π΄Π΅ Π²Π΅Ρ€Π·ΠΈΡ˜Π° ОБ-Π°.

ΠŸΠΎΡ€Π΅Π΄ Ρ‚ΠΎΠ³Π°, написана јС ΠΌΠ°Π»Π° басх скрипта која Π²Π°ΠΌ ΠΎΠΌΠΎΠ³ΡƒΡ›Π°Π²Π° Π΄Π° ΠΏΠΎΠΊΡ€Π΅Π½Π΅Ρ‚Π΅ ΠΊΠΎΠ½Ρ‚Π΅Ρ˜Π½Π΅Ρ€ са Ρ€Π°Π·Π»ΠΈΡ‡ΠΈΡ‚ΠΈΠΌ ΠΊΠΎΠΌΠ°Π½Π΄Π°ΠΌΠ°. На ΠΏΡ€ΠΈΠΌΠ΅Ρ€, Ρ‚ΠΎ ΠΌΠΎΠ³Ρƒ Π±ΠΈΡ‚ΠΈ скриптС Π·Π° ΠΎΠ±ΡƒΠΊΡƒ нСуронских ΠΌΡ€Π΅ΠΆΠ° којС су ΠΏΡ€Π΅Ρ‚Ρ…ΠΎΠ΄Π½ΠΎ Π±ΠΈΠ»Π΅ ΡΠΌΠ΅ΡˆΡ‚Π΅Π½Π΅ ΡƒΠ½ΡƒΡ‚Π°Ρ€ ΠΊΠΎΠ½Ρ‚Π΅Ρ˜Π½Π΅Ρ€Π°, ΠΈΠ»ΠΈ ΠΊΠΎΠΌΠ°Π½Π΄Π½Π° ΡˆΠΊΠΎΡ™ΠΊΠ° Π·Π° ΠΎΡ‚ΠΊΠ»Π°ΡšΠ°ΡšΠ΅ Π³Ρ€Π΅ΡˆΠ°ΠΊΠ° ΠΈ надглСдањС Ρ€Π°Π΄Π° ΠΊΠΎΠ½Ρ‚Π΅Ρ˜Π½Π΅Ρ€Π°:

Π‘ΠΊΡ€ΠΈΠΏΡ‚Π° Π·Π° ΠΏΠΎΠΊΡ€Π΅Ρ‚Π°ΡšΠ΅ ΠΊΠΎΠ½Ρ‚Π΅Ρ˜Π½Π΅Ρ€Π°

#!/bin/sh

DBDIR=${PWD}/db
LOGSDIR=${PWD}/logs
MODELDIR=${PWD}/models
DATADIR=${PWD}/data
ARGS="--runtime=nvidia --rm -v ${DBDIR}:/db -v ${LOGSDIR}:/app/logs -v ${MODELDIR}:/app/models -v ${DATADIR}:/app/data"

if [ -z "$1" ]; then
    CMD="Rscript /app/train_nn.R"
elif [ "$1" = "bash" ]; then
    ARGS="${ARGS} -ti"
else
    CMD="Rscript /app/train_nn.R $@"
fi

docker run ${ARGS} doodles-tf ${CMD}

Ако сС ΠΎΠ²Π° басх скрипта ΠΏΠΎΠΊΡ€Π΅Π½Π΅ Π±Π΅Π· ΠΏΠ°Ρ€Π°ΠΌΠ΅Ρ‚Π°Ρ€Π°, скрипта Ρ›Π΅ Π±ΠΈΡ‚ΠΈ ΠΏΠΎΠ·Π²Π°Π½Π° ΡƒΠ½ΡƒΡ‚Π°Ρ€ ΠΊΠΎΠ½Ρ‚Π΅Ρ˜Π½Π΅Ρ€Π° train_nn.R са ΠΏΠΎΠ΄Ρ€Π°Π·ΡƒΠΌΠ΅Π²Π°Π½ΠΈΠΌ врСдностима; Π°ΠΊΠΎ јС ΠΏΡ€Π²ΠΈ ΠΏΠΎΠ·ΠΈΡ†ΠΈΠΎΠ½ΠΈ Π°Ρ€Π³ΡƒΠΌΠ΅Π½Ρ‚ "басх", ΠΎΠ½Π΄Π° Ρ›Π΅ ΠΊΠΎΠ½Ρ‚Π΅Ρ˜Π½Π΅Ρ€ Π·Π°ΠΏΠΎΡ‡Π΅Ρ‚ΠΈ ΠΈΠ½Ρ‚Π΅Ρ€Π°ΠΊΡ‚ΠΈΠ²Π½ΠΎ са ΠΊΠΎΠΌΠ°Π½Π΄Π½ΠΎΠΌ ΡˆΠΊΠΎΡ™ΠΊΠΎΠΌ. Π£ свим осталим ΡΠ»ΡƒΡ‡Π°Ρ˜Π΅Π²ΠΈΠΌΠ°, врСдности ΠΏΠΎΠ·ΠΈΡ†ΠΈΠΎΠ½ΠΈΡ… Π°Ρ€Π³ΡƒΠΌΠ΅Π½Π°Ρ‚Π° сС Π·Π°ΠΌΠ΅ΡšΡƒΡ˜Ρƒ: CMD="Rscript /app/train_nn.R $@".

Π’Ρ€Π΅Π΄ΠΈ Π½Π°ΠΏΠΎΠΌΠ΅Π½ΡƒΡ‚ΠΈ Π΄Π° сС Π΄ΠΈΡ€Π΅ΠΊΡ‚ΠΎΡ€ΠΈΡ˜ΡƒΠΌΠΈ са ΠΈΠ·Π²ΠΎΡ€Π½ΠΈΠΌ ΠΏΠΎΠ΄Π°Ρ†ΠΈΠΌΠ° ΠΈ Π±Π°Π·ΠΎΠΌ ΠΏΠΎΠ΄Π°Ρ‚Π°ΠΊΠ°, ΠΊΠ°ΠΎ ΠΈ Π΄ΠΈΡ€Π΅ΠΊΡ‚ΠΎΡ€ΠΈΡ˜ΡƒΠΌ Π·Π° Ρ‡ΡƒΠ²Π°ΡšΠ΅ ΠΎΠ±ΡƒΡ‡Π΅Π½ΠΈΡ… ΠΌΠΎΠ΄Π΅Π»Π°, ΠΌΠΎΠ½Ρ‚ΠΈΡ€Π°Ρ˜Ρƒ ΡƒΠ½ΡƒΡ‚Π°Ρ€ ΠΊΠΎΠ½Ρ‚Π΅Ρ˜Π½Π΅Ρ€Π° ΠΈΠ· хост систСма, ΡˆΡ‚ΠΎ Π²Π°ΠΌ ΠΎΠΌΠΎΠ³ΡƒΡ›Π°Π²Π° Π΄Π° приступитС Ρ€Π΅Π·ΡƒΠ»Ρ‚Π°Ρ‚ΠΈΠΌΠ° скрипти Π±Π΅Π· Π½Π΅ΠΏΠΎΡ‚Ρ€Π΅Π±Π½ΠΈΡ… ΠΌΠ°Π½ΠΈΠΏΡƒΠ»Π°Ρ†ΠΈΡ˜Π°.

7. ΠšΠΎΡ€ΠΈΡˆΡ›Π΅ΡšΠ΅ вишС Π“ΠŸΠ£-Π° Π½Π° Π“ΠΎΠΎΠ³Π»Π΅ Π¦Π»ΠΎΡƒΠ΄-Ρƒ

ЈСдна ΠΎΠ΄ карактСристика Ρ‚Π°ΠΊΠΌΠΈΡ‡Π΅ΡšΠ° су Π±ΠΈΠ»ΠΈ Π²Π΅ΠΎΠΌΠ° Π±ΡƒΡ‡Π½ΠΈ ΠΏΠΎΠ΄Π°Ρ†ΠΈ (ΠΏΠΎΠ³Π»Π΅Π΄Π°Ρ˜Ρ‚Π΅ насловну слику, ΠΏΠΎΠ·Π°Ρ˜ΠΌΡ™Π΅Π½Ρƒ са @Π›Π΅ΠΈΠ³Ρ….ΠΏΠ»Ρ‚ ΠΈΠ· ΠžΠ”Π‘ слацк-Π°). Π’Π΅Π»ΠΈΠΊΠ΅ ΡΠ΅Ρ€ΠΈΡ˜Π΅ ΠΏΠΎΠΌΠ°ΠΆΡƒ Ρƒ Π±ΠΎΡ€Π±ΠΈ ΠΏΡ€ΠΎΡ‚ΠΈΠ² ΠΎΠ²ΠΎΠ³Π°, ΠΈ Π½Π°ΠΊΠΎΠ½ СкспСримСната Π½Π° Ρ€Π°Ρ‡ΡƒΠ½Π°Ρ€Ρƒ са 1 Π“ΠŸΠ£-ΠΎΠΌ, ΠΎΠ΄Π»ΡƒΡ‡ΠΈΠ»ΠΈ смо Π΄Π° савладамо ΠΌΠΎΠ΄Π΅Π»Π΅ ΠΎΠ±ΡƒΠΊΠ΅ Π½Π° Π½Π΅ΠΊΠΎΠ»ΠΈΠΊΠΎ Π“ΠŸΠ£-Π° Ρƒ ΠΎΠ±Π»Π°ΠΊΡƒ. ΠšΠΎΡ€ΠΈΡΡ‚ΠΈ Π“ΠΎΠΎΠ³Π»Π΅Π¦Π»ΠΎΡƒΠ΄ (Π΄ΠΎΠ±Π°Ρ€ Π²ΠΎΠ΄ΠΈΡ‡ Π·Π° основС) Π·Π±ΠΎΠ³ Π²Π΅Π»ΠΈΠΊΠΎΠ³ ΠΈΠ·Π±ΠΎΡ€Π° доступних ΠΊΠΎΠ½Ρ„ΠΈΠ³ΡƒΡ€Π°Ρ†ΠΈΡ˜Π°, Ρ€Π°Π·ΡƒΠΌΠ½ΠΈΡ… Ρ†Π΅Π½Π° ΠΈ бонуса ΠΎΠ΄ 300 Π£Π‘Π”. Из ΠΏΠΎΡ…Π»Π΅ΠΏΠ΅, Π½Π°Ρ€ΡƒΡ‡ΠΈΠΎ сам 4ΠΊΠ’100 инстанцу са Π‘Π‘Π”-ΠΎΠΌ ΠΈ Ρ‚ΠΎΠ½ΠΎΠΌ РАМ-Π°, ΠΈ Ρ‚ΠΎ јС Π±ΠΈΠ»Π° Π²Π΅Π»ΠΈΠΊΠ° Π³Ρ€Π΅ΡˆΠΊΠ°. Π’Π°ΠΊΠ²Π° машина Π±Ρ€Π·ΠΎ појСдС Π½ΠΎΠ²Π°Ρ†; ΠΌΠΎΠΆΠ΅Ρ‚Π΅ пропасти Π΅ΠΊΡΠΏΠ΅Ρ€ΠΈΠΌΠ΅Π½Ρ‚ΠΈΡˆΡƒΡ›ΠΈ Π±Π΅Π· Π΄ΠΎΠΊΠ°Π·Π°Π½ΠΎΠ³ Ρ†Π΅Π²ΠΎΠ²ΠΎΠ΄Π°. Π£ ΠΎΠ±Ρ€Π°Π·ΠΎΠ²Π½Π΅ сврхС, Π±ΠΎΡ™Π΅ јС ΡƒΠ·Π΅Ρ‚ΠΈ К80. Али Π²Π΅Π»ΠΈΠΊΠ° ΠΊΠΎΠ»ΠΈΡ‡ΠΈΠ½Π° РАМ-Π° јС Π΄ΠΎΠ±Ρ€ΠΎ дошла - Ρ†Π»ΠΎΡƒΠ΄ Π‘Π‘Π” нијС импрСсионирао својим пСрформансама, ΠΏΠ° јС Π±Π°Π·Π° ΠΏΠΎΠ΄Π°Ρ‚Π°ΠΊΠ° ΠΏΡ€Π΅Π±Π°Ρ‡Π΅Π½Π° Π½Π° dev/shm.

ΠΠ°Ρ˜Π²Π΅Ρ›ΠΈ интСрСс јС Ρ„Ρ€Π°Π³ΠΌΠ΅Π½Ρ‚ ΠΊΠΎΠ΄Π° ΠΎΠ΄Π³ΠΎΠ²ΠΎΡ€Π°Π½ Π·Π° ΠΊΠΎΡ€ΠΈΡˆΡ›Π΅ΡšΠ΅ вишС Π“ΠŸΠ£-ΠΎΠ²Π°. ΠŸΡ€Π²ΠΎ, ΠΌΠΎΠ΄Π΅Π» сС ΠΊΡ€Π΅ΠΈΡ€Π° Π½Π° ЦПУ-Ρƒ ΠΏΠΎΠΌΠΎΡ›Ρƒ ΠΌΠ΅Π½Π°ΡŸΠ΅Ρ€Π° контСкста, баш ΠΊΠ°ΠΎ Ρƒ ΠŸΠΈΡ‚Ρ…ΠΎΠ½-Ρƒ:

with(tensorflow::tf$device("/cpu:0"), {
  model_cpu <- get_model(
    name = model_name,
    input_shape = input_shape,
    weights = weights,
    metrics =(top_3_categorical_accuracy,
    compile = FALSE
  )
})

Π—Π°Ρ‚ΠΈΠΌ сС Π½Π΅ΠΏΡ€Π΅Π²Π΅Π΄Π΅Π½ΠΈ (ΠΎΠ²ΠΎ јС Π²Π°ΠΆΠ½ΠΎ) ΠΌΠΎΠ΄Π΅Π» ΠΊΠΎΠΏΠΈΡ€Π° Π½Π° Π΄Π°Ρ‚ΠΈ Π±Ρ€ΠΎΡ˜ доступних Π“ΠŸΠ£-Π° ΠΈ Ρ‚Π΅ΠΊ Π½Π°ΠΊΠΎΠ½ Ρ‚ΠΎΠ³Π° сС ΠΊΠΎΠΌΠΏΠ°Ρ˜Π»ΠΈΡ€Π°:

model <- keras::multi_gpu_model(model_cpu, gpus = n_gpu)
keras::compile(
  object = model,
  optimizer = keras::optimizer_adam(lr = 0.0004),
  loss = "categorical_crossentropy",
  metrics = c(top_3_categorical_accuracy)
)

ΠšΠ»Π°ΡΠΈΡ‡Π½Π° Ρ‚Π΅Ρ…Π½ΠΈΠΊΠ° Π·Π°ΠΌΡ€Π·Π°Π²Π°ΡšΠ° свих слојСва осим послСдњСг, ΠΎΠ±ΡƒΡ‡Π°Π²Π°ΡšΠ° послСдњСг слоја, ΠΎΠ΄ΠΌΡ€Π·Π°Π²Π°ΡšΠ° ΠΈ ΠΏΡ€Π΅ΠΎΠ±ΡƒΠΊΠ΅ Ρ†Π΅Π»ΠΎΠ³ ΠΌΠΎΠ΄Π΅Π»Π° Π·Π° Π½Π΅ΠΊΠΎΠ»ΠΈΠΊΠΎ Π“ΠŸΠ£-Π° нијС ΠΌΠΎΠ³Π»Π° Π΄Π° сС ΠΏΡ€ΠΈΠΌΠ΅Π½ΠΈ.

ΠžΠ±ΡƒΠΊΠ° јС ΠΏΡ€Π°Ρ›Π΅Π½Π° Π±Π΅Π· ΡƒΠΏΠΎΡ‚Ρ€Π΅Π±Π΅. тСнсорбоард, ΠΎΠ³Ρ€Π°Π½ΠΈΡ‡Π°Π²Π°Ρ˜ΡƒΡ›ΠΈ сС Π½Π° снимањС Π΄Π½Π΅Π²Π½ΠΈΠΊΠ° ΠΈ Ρ‡ΡƒΠ²Π°ΡšΠ΅ ΠΌΠΎΠ΄Π΅Π»Π° са ΠΈΠ½Ρ„ΠΎΡ€ΠΌΠ°Ρ‚ΠΈΠ²Π½ΠΈΠΌ Π½Π°Π·ΠΈΠ²ΠΈΠΌΠ° Π½Π°ΠΊΠΎΠ½ свакС Π΅ΠΏΠΎΡ…Π΅:

ΠŸΠΎΠ²Ρ€Π°Ρ‚Π½ΠΈ ΠΏΠΎΠ·ΠΈΠ²ΠΈ

# Π¨Π°Π±Π»ΠΎΠ½ ΠΈΠΌΠ΅Π½ΠΈ Ρ„Π°ΠΉΠ»Π° Π»ΠΎΠ³Π°
log_file_tmpl <- file.path("logs", sprintf(
  "%s_%d_%dch_%s.csv",
  model_name,
  dim_size,
  channels,
  format(Sys.time(), "%Y%m%d%H%M%OS")
))
# Π¨Π°Π±Π»ΠΎΠ½ ΠΈΠΌΠ΅Π½ΠΈ Ρ„Π°ΠΉΠ»Π° ΠΌΠΎΠ΄Π΅Π»ΠΈ
model_file_tmpl <- file.path("models", sprintf(
  "%s_%d_%dch_{epoch:02d}_{val_loss:.2f}.h5",
  model_name,
  dim_size,
  channels
))

callbacks_list <- list(
  keras::callback_csv_logger(
    filename = log_file_tmpl
  ),
  keras::callback_early_stopping(
    monitor = "val_loss",
    min_delta = 1e-4,
    patience = 8,
    verbose = 1,
    mode = "min"
  ),
  keras::callback_reduce_lr_on_plateau(
    monitor = "val_loss",
    factor = 0.5, # ΡƒΠΌΠ΅Π½ΡŒΡˆΠ°Π΅ΠΌ lr Π² 2 Ρ€Π°Π·Π°
    patience = 4,
    verbose = 1,
    min_delta = 1e-4,
    mode = "min"
  ),
  keras::callback_model_checkpoint(
    filepath = model_file_tmpl,
    monitor = "val_loss",
    save_best_only = FALSE,
    save_weights_only = FALSE,
    mode = "min"
  )
)

8. УмСсто Π·Π°ΠΊΡ™ΡƒΡ‡ΠΊΠ°

Π‘Ρ€ΠΎΡ˜Π½ΠΈ ΠΏΡ€ΠΎΠ±Π»Π΅ΠΌΠΈ са којима смо сС сусрСли још ΡƒΠ²Π΅ΠΊ нису ΠΏΡ€Π΅Π²Π°Π·ΠΈΡ’Π΅Π½ΠΈ:

  • Π² кСрас Π½Π΅ ΠΏΠΎΡΡ‚ΠΎΡ˜ΠΈ Π³ΠΎΡ‚ΠΎΠ²Π° Ρ„ΡƒΠ½ΠΊΡ†ΠΈΡ˜Π° Π·Π° аутоматско Ρ‚Ρ€Π°ΠΆΠ΅ΡšΠ΅ ΠΎΠΏΡ‚ΠΈΠΌΠ°Π»Π½Π΅ Π±Ρ€Π·ΠΈΠ½Π΅ ΡƒΡ‡Π΅ΡšΠ° (Π°Π½Π°Π»ΠΎΠ³Π½ΠΎ lr_finder Ρƒ Π±ΠΈΠ±Π»ΠΈΠΎΡ‚Π΅Ρ†ΠΈ Π±Ρ€Π·ΠΎ.Π°ΠΈ); Π£Π· ΠΎΠ΄Ρ€Π΅Ρ’Π΅Π½ΠΈ Π½Π°ΠΏΠΎΡ€, ΠΌΠΎΠ³ΡƒΡ›Π΅ јС ΠΏΡ€Π΅Π½Π΅Ρ‚ΠΈ ΠΈΠΌΠΏΠ»Π΅ΠΌΠ΅Π½Ρ‚Π°Ρ†ΠΈΡ˜Π΅ Ρ‚Ρ€Π΅Ρ›Π΅ странС Π½Π° Π , Π½Π° ΠΏΡ€ΠΈΠΌΠ΅Ρ€, ΠΎΠ²ΠΎ;
  • ΠΊΠ°ΠΎ послСдица ΠΏΡ€Π΅Ρ‚Ρ…ΠΎΠ΄Π½Π΅ Ρ‚Π°Ρ‡ΠΊΠ΅, нијС Π±ΠΈΠ»ΠΎ ΠΌΠΎΠ³ΡƒΡ›Π΅ ΠΈΠ·Π°Π±Ρ€Π°Ρ‚ΠΈ исправну Π±Ρ€Π·ΠΈΠ½Ρƒ Ρ‚Ρ€Π΅Π½ΠΈΠ½Π³Π° ΠΊΠ°Π΄Π° сС користи Π½Π΅ΠΊΠΎΠ»ΠΈΠΊΠΎ Π“ΠŸΠ£-Π°;
  • ΠΏΠΎΡΡ‚ΠΎΡ˜ΠΈ нСдостатак ΠΌΠΎΠ΄Π΅Ρ€Π½ΠΈΡ… Π°Ρ€Ρ…ΠΈΡ‚Π΅ΠΊΡ‚ΡƒΡ€Π° нСуронских ΠΌΡ€Π΅ΠΆΠ°, посСбно ΠΎΠ½ΠΈΡ… ΠΏΡ€Π΅Ρ‚Ρ…ΠΎΠ΄Π½ΠΎ ΠΎΠ±ΡƒΡ‡Π΅Π½ΠΈΡ… Π½Π° ΠΈΠΌΠ°Π³Π΅Π½Π΅Ρ‚-Ρƒ;
  • ΠΏΠΎΠ»ΠΈΡ‚ΠΈΠΊΠ° јСдног циклуса ΠΈ дискриминативнС стопС ΡƒΡ‡Π΅ΡšΠ° (косинусно ΠΆΠ°Ρ€Π΅ΡšΠ΅ јС Π±ΠΈΠ»ΠΎ Π½Π° наш Π·Π°Ρ…Ρ‚Π΅Π² ΠΈΠΌΠΏΠ»Π΅ΠΌΠ΅Π½Ρ‚ΠΈΡ€Π°Π½, Π₯Π²Π°Π»Π° скСидан).

Π¨Ρ‚Π° сС корисно Π½Π°ΡƒΡ‡ΠΈΠ»ΠΎ са ΠΎΠ²ΠΎΠ³ Ρ‚Π°ΠΊΠΌΠΈΡ‡Π΅ΡšΠ°:

  • На Ρ…Π°Ρ€Π΄Π²Π΅Ρ€Ρƒ са Ρ€Π΅Π»Π°Ρ‚ΠΈΠ²Π½ΠΎ ΠΌΠ°Π»ΠΎΠΌ ΠΏΠΎΡ‚Ρ€ΠΎΡˆΡšΠΎΠΌ, ΠΌΠΎΠΆΠ΅Ρ‚Π΅ Π΄Π° Ρ€Π°Π΄ΠΈΡ‚Π΅ са ΠΏΡ€ΠΈΡΡ‚ΠΎΡ˜Π½ΠΈΠΌ (Π²ΠΈΡˆΠ΅ΡΡ‚Ρ€ΡƒΠΊΠΎ Π²Π΅Ρ›ΠΈΠΌ ΠΎΠ΄ РАМ-Π°) ΠΎΠ±ΠΈΠΌΠΈΠΌΠ° ΠΏΠΎΠ΄Π°Ρ‚Π°ΠΊΠ° Π±Π΅Π· ΠΌΡƒΠΊΠ΅. ΠŸΠ»Π°ΡΡ‚ΠΈΡ‡Π½Π° кСса ΠΏΠΎΠ΄Π°Ρ†ΠΈ.Ρ‚Π°Π±Π΅Π»Π° ΡˆΡ‚Π΅Π΄ΠΈ ΠΌΠ΅ΠΌΠΎΡ€ΠΈΡ˜Ρƒ Π·Π°Ρ…Π²Π°Ρ™ΡƒΡ˜ΡƒΡ›ΠΈ ΠΌΠΎΠ΄ΠΈΡ„ΠΈΠΊΠ°Ρ†ΠΈΡ˜ΠΈ Ρ‚Π°Π±Π΅Π»Π° Π½Π° мСсту, Ρ‡ΠΈΠΌΠ΅ сС ΠΈΠ·Π±Π΅Π³Π°Π²Π° ΡšΠΈΡ…ΠΎΠ²ΠΎ ΠΊΠΎΠΏΠΈΡ€Π°ΡšΠ΅, Π° ΠΊΠ°Π΄Π° сС ΠΏΡ€Π°Π²ΠΈΠ»Π½ΠΎ користС, њСговС могућности скоро ΡƒΠ²Π΅ΠΊ ΠΏΠΎΠΊΠ°Π·ΡƒΡ˜Ρƒ Π½Π°Ρ˜Π²Π΅Ρ›Ρƒ Π±Ρ€Π·ΠΈΠ½Ρƒ ΠΌΠ΅Ρ’Ρƒ свим Π½Π°ΠΌΠ° ΠΏΠΎΠ·Π½Π°Ρ‚ΠΈΠΌ Π°Π»Π°Ρ‚ΠΈΠΌΠ° Π·Π° скриптнС јСзикС. Π§ΡƒΠ²Π°ΡšΠ΅ ΠΏΠΎΠ΄Π°Ρ‚Π°ΠΊΠ° Ρƒ Π±Π°Π·ΠΈ ΠΏΠΎΠ΄Π°Ρ‚Π°ΠΊΠ° Π²Π°ΠΌ ΠΎΠΌΠΎΠ³ΡƒΡ›Π°Π²Π°, Ρƒ ΠΌΠ½ΠΎΠ³ΠΈΠΌ ΡΠ»ΡƒΡ‡Π°Ρ˜Π΅Π²ΠΈΠΌΠ°, Π΄Π° ΡƒΠΎΠΏΡˆΡ‚Π΅ Π½Π΅ Ρ€Π°Π·ΠΌΠΈΡˆΡ™Π°Ρ‚Π΅ ΠΎ ΠΏΠΎΡ‚Ρ€Π΅Π±ΠΈ Π΄Π° сС Ρ†Π΅ΠΎ скуп ΠΏΠΎΠ΄Π°Ρ‚Π°ΠΊΠ° ΡƒΠ³ΡƒΡ€Π° Ρƒ РАМ.
  • Π‘ΠΏΠΎΡ€Π΅ Ρ„ΡƒΠ½ΠΊΡ†ΠΈΡ˜Π΅ Ρƒ Π  ΠΌΠΎΠ³Ρƒ сС Π·Π°ΠΌΠ΅Π½ΠΈΡ‚ΠΈ Π±Ρ€Π·ΠΈΠΌ Ρƒ Π¦++ ΠΏΠΎΠΌΠΎΡ›Ρƒ ΠΏΠ°ΠΊΠ΅Ρ‚Π° Π Ρ†ΠΏΠΏ. Ако ΠΏΠΎΡ€Π΅Π΄ ΡƒΠΏΠΎΡ‚Ρ€Π΅Π±Π΅ Π Ρ†ΠΏΠΏΠ’Ρ…Ρ€Π΅Π°Π΄ ΠΈΠ»ΠΈ Π Ρ†ΠΏΠΏΠŸΠ°Ρ€Π°Π»Π»Π΅Π», добијамо Π²ΠΈΡˆΠ΅ΠΏΠ»Π°Ρ‚Ρ„ΠΎΡ€ΠΌΡΠΊΠ΅ ΠΈΠΌΠΏΠ»Π΅ΠΌΠ΅Π½Ρ‚Π°Ρ†ΠΈΡ˜Π΅ са вишС Π½ΠΈΡ‚ΠΈ, Ρ‚Π°ΠΊΠΎ Π΄Π° Π½Π΅ΠΌΠ° ΠΏΠΎΡ‚Ρ€Π΅Π±Π΅ Π·Π° ΠΏΠ°Ρ€Π°Π»Π΅Π»ΠΈΠ·Π°Ρ†ΠΈΡ˜ΠΎΠΌ ΠΊΠΎΠ΄Π° Π½Π° Π½ΠΈΠ²ΠΎΡƒ Π .
  • ΠŸΠ°ΠΊΠ΅Ρ‚ Π Ρ†ΠΏΠΏ ΠΌΠΎΠΆΠ΅ сС користити Π±Π΅Π· ΠΎΠ·Π±ΠΈΡ™Π½ΠΎΠ³ познавања Π¦++-Π°, Π½Π°Π²Π΅Π΄Π΅Π½ јС ΠΏΠΎΡ‚Ρ€Π΅Π±Π°Π½ ΠΌΠΈΠ½ΠΈΠΌΡƒΠΌ ΠΎΠ²Π΄Π΅. Π”Π°Ρ‚ΠΎΡ‚Π΅ΠΊΠ΅ Π·Π°Π³Π»Π°Π²Ρ™Π° Π·Π° Π±Ρ€ΠΎΡ˜Π½Π΅ Ρ†ΠΎΠΎΠ» Π¦-Π±ΠΈΠ±Π»ΠΈΠΎΡ‚Π΅ΠΊΠ΅ ΠΊΠ°ΠΎ ΡˆΡ‚ΠΎ су ктСнсор доступно Π½Π° ЦРАН-Ρƒ, односно Ρ„ΠΎΡ€ΠΌΠΈΡ€Π° сС инфраструктура Π·Π° ΠΈΠΌΠΏΠ»Π΅ΠΌΠ΅Π½Ρ‚Π°Ρ†ΠΈΡ˜Ρƒ ΠΏΡ€ΠΎΡ˜Π΅ΠΊΠ°Ρ‚Π° који ΠΈΠ½Ρ‚Π΅Π³Ρ€ΠΈΡˆΡƒ Π³ΠΎΡ‚ΠΎΠ² Π¦++ ΠΊΠΎΠ΄ високих пСрформанси Ρƒ Π . Π”ΠΎΠ΄Π°Ρ‚Π½Π° погодност јС ΠΈΡΡ‚ΠΈΡ†Π°ΡšΠ΅ синтаксС ΠΈ статички Π¦++ Π°Π½Π°Π»ΠΈΠ·Π°Ρ‚ΠΎΡ€ ΠΊΠΎΠ΄Π° Ρƒ Π Π‘Ρ‚ΡƒΠ΄ΠΈΡƒ.
  • Π΄ΠΎΡ†ΠΎΠΏΡ‚ ΠΎΠΌΠΎΠ³ΡƒΡ›Π°Π²Π° Π²Π°ΠΌ Π΄Π° ΠΏΠΎΠΊΡ€Π΅Π½Π΅Ρ‚Π΅ самосталнС скриптС са ΠΏΠ°Ρ€Π°ΠΌΠ΅Ρ‚Ρ€ΠΈΠΌΠ°. Ово јС Π·Π³ΠΎΠ΄Π½ΠΎ Π·Π° ΡƒΠΏΠΎΡ‚Ρ€Π΅Π±Ρƒ Π½Π° ΡƒΠ΄Π°Ρ™Π΅Π½ΠΎΠΌ сСрвСру, ΡƒΠΊΡ™. ΠΏΠΎΠ΄ Π΄ΠΎΡ†ΠΊΠ΅Ρ€. Π£ Π Π‘Ρ‚ΡƒΠ΄ΠΈΡƒ јС Π½Π΅Π·Π³ΠΎΠ΄Π½ΠΎ ΠΈΠ·Π²ΠΎΠ΄ΠΈΡ‚ΠΈ ΠΌΠ½ΠΎΠ³ΠΎ сати СкспСримСната са ΠΎΠ±ΡƒΡ‡Π°Π²Π°ΡšΠ΅ΠΌ нСуронских ΠΌΡ€Π΅ΠΆΠ°, Π° ΠΈΠ½ΡΡ‚Π°Π»ΠΈΡ€Π°ΡšΠ΅ Π˜Π”Π•-Π° Π½Π° самом сСрвСру нијС ΡƒΠ²Π΅ΠΊ ΠΎΠΏΡ€Π°Π²Π΄Π°Π½ΠΎ.
  • Π”ΠΎΡ†ΠΊΠ΅Ρ€ ΠΎΠ±Π΅Π·Π±Π΅Ρ’ΡƒΡ˜Π΅ прСносивост ΠΊΠΎΠ΄Π° ΠΈ поновљивост Ρ€Π΅Π·ΡƒΠ»Ρ‚Π°Ρ‚Π° ΠΈΠ·ΠΌΠ΅Ρ’Ρƒ ΠΏΡ€ΠΎΠ³Ρ€Π°ΠΌΠ΅Ρ€Π° са Ρ€Π°Π·Π»ΠΈΡ‡ΠΈΡ‚ΠΈΠΌ Π²Π΅Ρ€Π·ΠΈΡ˜Π°ΠΌΠ° ОБ-Π° ΠΈ Π±ΠΈΠ±Π»ΠΈΠΎΡ‚Π΅ΠΊΠ°, ΠΊΠ°ΠΎ ΠΈ Π»Π°ΠΊΠΎΡ›Ρƒ ΠΈΠ·Π²Ρ€ΡˆΠ°Π²Π°ΡšΠ° Π½Π° сСрвСрима. ΠœΠΎΠΆΠ΅Ρ‚Π΅ ΠΏΠΎΠΊΡ€Π΅Π½ΡƒΡ‚ΠΈ Ρ†Π΅ΠΎ Ρ†Π΅Π²ΠΎΠ²ΠΎΠ΄ ΠΎΠ±ΡƒΠΊΠ΅ са само јСдном ΠΊΠΎΠΌΠ°Π½Π΄ΠΎΠΌ.
  • Π“ΠΎΠΎΠ³Π»Π΅ Π¦Π»ΠΎΡƒΠ΄ јС Ρ˜Π΅Ρ„Ρ‚ΠΈΠ½ Π½Π°Ρ‡ΠΈΠ½ Π·Π° Π΅ΠΊΡΠΏΠ΅Ρ€ΠΈΠΌΠ΅Π½Ρ‚ΠΈΡΠ°ΡšΠ΅ Π½Π° скупом Ρ…Π°Ρ€Π΄Π²Π΅Ρ€Ρƒ, Π°Π»ΠΈ ΠΌΠΎΡ€Π°Ρ‚Π΅ ΠΏΠ°ΠΆΡ™ΠΈΠ²ΠΎ Π΄Π° ΠΈΠ·Π°Π±Π΅Ρ€Π΅Ρ‚Π΅ ΠΊΠΎΠ½Ρ„ΠΈΠ³ΡƒΡ€Π°Ρ†ΠΈΡ˜Π΅.
  • ΠœΠ΅Ρ€Π΅ΡšΠ΅ Π±Ρ€Π·ΠΈΠ½Π΅ ΠΏΠΎΡ˜Π΅Π΄ΠΈΠ½Π°Ρ‡Π½ΠΈΡ… Ρ„Ρ€Π°Π³ΠΌΠ΅Π½Π°Ρ‚Π° ΠΊΠΎΠ΄Π° јС Π²Π΅ΠΎΠΌΠ° корисно, посСбно ΠΊΠ°Π΄Π° сС ΠΊΠΎΠΌΠ±ΠΈΠ½ΡƒΡ˜Ρƒ Π  ΠΈ Π¦++, ΠΈ са ΠΏΠ°ΠΊΠ΅Ρ‚ΠΎΠΌ ΠΊΠ»ΡƒΠΏΠ° - Ρ‚Π°ΠΊΠΎΡ’Π΅ Π²Ρ€Π»ΠΎ Π»Π°ΠΊΠΎ.

Π‘Π²Π΅ Ρƒ свСму, ΠΎΠ²ΠΎ искуство јС Π±ΠΈΠ»ΠΎ Π²Π΅ΠΎΠΌΠ° корисно ΠΈ настављамо Π΄Π° Ρ€Π°Π΄ΠΈΠΌΠΎ Π½Π° Ρ€Π΅ΡˆΠ°Π²Π°ΡšΡƒ Π½Π΅ΠΊΠΈΡ… ΠΎΠ΄ постављСних ΠΏΠΈΡ‚Π°ΡšΠ°.

Π˜Π·Π²ΠΎΡ€: Π²Π²Π².Ρ…Π°Π±Ρ€.Ρ†ΠΎΠΌ

Π”ΠΎΠ΄Π°Ρ˜ ΠΊΠΎΠΌΠ΅Π½Ρ‚Π°Ρ€