Quick Draw Doodle Recognition: ΠΊΠ°ΠΊΠΎ Π΄Π° сС Π΄Ρ€ΡƒΠΆΠΈΡ‚Π΅ со R, C++ ΠΈ нСвронскитС ΠΌΡ€Π΅ΠΆΠΈ

Quick Draw Doodle Recognition: ΠΊΠ°ΠΊΠΎ Π΄Π° сС Π΄Ρ€ΡƒΠΆΠΈΡ‚Π΅ со R, C++ ΠΈ нСвронскитС ΠΌΡ€Π΅ΠΆΠΈ

Π•Ρ˜ Π₯Π°Π±Ρ€!

ΠœΠΈΠ½Π°Ρ‚Π°Ρ‚Π° СсСн, Kaggle бСшС домаќин Π½Π° Π½Π°Ρ‚ΠΏΡ€Π΅Π²Π°Ρ€ Π·Π° ΠΊΠ»Π°ΡΠΈΡ„ΠΈΠΊΠ°Ρ†ΠΈΡ˜Π° Π½Π° Ρ€Π°Ρ‡Π½ΠΎ Π½Π°Ρ†Ρ€Ρ‚Π°Π½ΠΈ слики, Quick Draw Doodle Recognition, Π²ΠΎ кој, ΠΌΠ΅Ρ“Ρƒ Π΄Ρ€ΡƒΠ³ΠΎΡ‚ΠΎ, ΡƒΡ‡Π΅ΡΡ‚Π²ΡƒΠ²Π°ΡˆΠ΅ ΠΈ Ρ‚ΠΈΠΌ ΠΎΠ΄ Π -Π½Π°ΡƒΡ‡Π½ΠΈΡ†ΠΈ: АртСм ΠšΠ»Π΅Π²Ρ†ΠΎΠ²Π°, ΠœΠ΅Π½Π°ΡŸΠ΅Ρ€ Π½Π° Π€ΠΈΠ»ΠΈΠΏΠ° ΠΈ ΠΠ½Π΄Ρ€Π΅Ρ˜ ΠžΠ³ΡƒΡ€Ρ†ΠΎΠ². НСма Π΄Π° Π³ΠΎ опишСмС Π½Π°Ρ‚ΠΏΡ€Π΅Π²Π°Ρ€ΠΎΡ‚ Π²ΠΎ Π΄Π΅Ρ‚Π°Π»ΠΈ, Ρ‚ΠΎΠ° Π΅ вСќС Π½Π°ΠΏΡ€Π°Π²Π΅Π½ΠΎ Π²ΠΎ нСодамнСшна ΠΏΡƒΠ±Π»ΠΈΠΊΠ°Ρ†ΠΈΡ˜Π°.

Овој ΠΏΠ°Ρ‚ Π½Π΅ успСа со ΠΎΠ΄Π³Π»Π΅Π΄ΡƒΠ²Π°ΡšΠ΅ ΠΌΠ΅Π΄Π°Π»ΠΈ, Π½ΠΎ сС стСкна ΠΌΠ½ΠΎΠ³Ρƒ Π΄Ρ€Π°Π³ΠΎΡ†Π΅Π½ΠΎ искуство, ΠΏΠ° Π±ΠΈ сакал Π΄Π° ΠΈ ΠΊΠ°ΠΆΠ°ΠΌ Π½Π° Π·Π°Π΅Π΄Π½ΠΈΡ†Π°Ρ‚Π° Π·Π° Π³ΠΎΠ»Π΅ΠΌ Π±Ρ€ΠΎΡ˜ ΠΎΠ΄ Π½Π°Ρ˜ΠΈΠ½Ρ‚Π΅Ρ€Π΅ΡΠ½ΠΈΡ‚Π΅ ΠΈ Π½Π°Ρ˜ΠΊΠΎΡ€ΠΈΡΠ½ΠΈΡ‚Π΅ Ρ€Π°Π±ΠΎΡ‚ΠΈ Π½Π° КаглС ΠΈ Π²ΠΎ ΡΠ΅ΠΊΠΎΡ˜Π΄Π½Π΅Π²Π½Π°Ρ‚Π° Ρ€Π°Π±ΠΎΡ‚Π°. ΠœΠ΅Ρ“Ρƒ Ρ‚Π΅ΠΌΠΈΡ‚Π΅ Π·Π° ΠΊΠΎΠΈ сС Π΄ΠΈΡΠΊΡƒΡ‚ΠΈΡ€Π°ΡˆΠ΅: Ρ‚Π΅ΠΆΠΎΠΊ ΠΆΠΈΠ²ΠΎΡ‚ Π±Π΅Π· OpenCV, JSON ΠΏΠ°Ρ€ΡΠΈΡ€Π°ΡšΠ΅ (ΠΎΠ²ΠΈΠ΅ ΠΏΡ€ΠΈΠΌΠ΅Ρ€ΠΈ ја испитуваат ΠΈΠ½Ρ‚Π΅Π³Ρ€Π°Ρ†ΠΈΡ˜Π°Ρ‚Π° Π½Π° C++ ΠΊΠΎΠ΄ΠΎΡ‚ Π²ΠΎ скрипти ΠΈΠ»ΠΈ ΠΏΠ°ΠΊΠ΅Ρ‚ΠΈ Π²ΠΎ R ΠΊΠΎΡ€ΠΈΡΡ‚Π΅Ρ˜ΡœΠΈ Rcpp), ΠΏΠ°Ρ€Π°ΠΌΠ΅Ρ‚Π°Ρ€ΠΈΠ·Π°Ρ†ΠΈΡ˜Π° Π½Π° скрипти ΠΈ Π΄ΠΎΠΊΠ΅Ρ€ΠΈΠ·Π°Ρ†ΠΈΡ˜Π° Π½Π° ΠΊΠΎΠ½Π΅Ρ‡Π½ΠΎΡ‚ΠΎ Ρ€Π΅ΡˆΠ΅Π½ΠΈΠ΅. Π¦Π΅Π»ΠΈΠΎΡ‚ ΠΊΠΎΠ΄ ΠΎΠ΄ ΠΏΠΎΡ€Π°ΠΊΠ°Ρ‚Π° Π²ΠΎ Ρ„ΠΎΡ€ΠΌΠ° ΠΏΠΎΠ³ΠΎΠ΄Π½Π° Π·Π° ΠΈΠ·Π²Ρ€ΡˆΡƒΠ²Π°ΡšΠ΅ Π΅ достапСн Π²ΠΎ ΡΠΊΠ»Π°Π΄ΠΈΡˆΡ‚Π°.

Π‘ΠΎΠ΄Ρ€ΠΆΠΈΠ½Π°:

  1. Ефикасно Π²Ρ‡ΠΈΡ‚Π°Ρ˜Ρ‚Π΅ ΠΏΠΎΠ΄Π°Ρ‚ΠΎΡ†ΠΈ ΠΎΠ΄ CSV Π²ΠΎ MonetDB
  2. ΠŸΠΎΠ΄Π³ΠΎΡ‚ΠΎΠ²ΠΊΠ° Π½Π° сСрии
  3. Π˜Ρ‚Π΅Ρ€Π°Ρ‚ΠΎΡ€ΠΈ Π·Π° истовар Π½Π° сСрии ΠΎΠ΄ Π±Π°Π·Π°Ρ‚Π° Π½Π° ΠΏΠΎΠ΄Π°Ρ‚ΠΎΡ†ΠΈ
  4. Π˜Π·Π±ΠΎΡ€ Π½Π° ΠΌΠΎΠ΄Π΅Π» Π½Π° Π°Ρ€Ρ…ΠΈΡ‚Π΅ΠΊΡ‚ΡƒΡ€Π°
  5. ΠŸΠ°Ρ€Π°ΠΌΠ΅Ρ‚Π°Ρ€ΠΈΠ·Π°Ρ†ΠΈΡ˜Π° Π½Π° скрипта
  6. Π”ΠΎΠΊΠ΅Ρ€ΠΈΠ·Π°Ρ†ΠΈΡ˜Π° Π½Π° скрипти
  7. ΠšΠΎΡ€ΠΈΡΡ‚Π΅ΡšΠ΅ Π½Π° повСќС Π³Ρ€Π°Ρ„ΠΈΡ‡ΠΊΠΈ процСсори Π½Π° Google Cloud
  8. НамСсто Π·Π°ΠΊΠ»ΡƒΡ‡ΠΎΠΊ

1. Ефикасно Π²Ρ‡ΠΈΡ‚Π°Ρ˜Ρ‚Π΅ ΠΏΠΎΠ΄Π°Ρ‚ΠΎΡ†ΠΈ ΠΎΠ΄ CSV Π²ΠΎ Π±Π°Π·Π°Ρ‚Π° Π½Π° ΠΏΠΎΠ΄Π°Ρ‚ΠΎΡ†ΠΈ Π½Π° MonetDB

ΠŸΠΎΠ΄Π°Ρ‚ΠΎΡ†ΠΈΡ‚Π΅ Π²ΠΎ овој Π½Π°Ρ‚ΠΏΡ€Π΅Π²Π°Ρ€ Π½Π΅ сС ΠΎΠ±Π΅Π·Π±Π΅Π΄Π΅Π½ΠΈ Π²ΠΎ Ρ„ΠΎΡ€ΠΌΠ° Π½Π° Π³ΠΎΡ‚ΠΎΠ²ΠΈ слики, Ρ‚ΡƒΠΊΡƒ Π²ΠΎ Ρ„ΠΎΡ€ΠΌΠ° Π½Π° 340 CSV Π΄Π°Ρ‚ΠΎΡ‚Π΅ΠΊΠΈ (ΠΏΠΎ Π΅Π΄Π½Π° Π΄Π°Ρ‚ΠΎΡ‚Π΅ΠΊΠ° Π·Π° сСкоја класа) ΠΊΠΎΠΈ содрТат JSON со ΠΊΠΎΠΎΡ€Π΄ΠΈΠ½Π°Ρ‚ΠΈ Π½Π° Ρ‚ΠΎΡ‡ΠΊΠΈ. Π‘ΠΎ ΠΏΠΎΠ²Ρ€Π·ΡƒΠ²Π°ΡšΠ΅ Π½Π° ΠΎΠ²ΠΈΠ΅ Ρ‚ΠΎΡ‡ΠΊΠΈ со Π»ΠΈΠ½ΠΈΠΈ, Π΄ΠΎΠ±ΠΈΠ²Π°ΠΌΠ΅ ΠΊΠΎΠ½Π΅Ρ‡Π½Π° слика со Π΄ΠΈΠΌΠ΅Π½Π·ΠΈΠΈ 256x256 пиксСли. Π˜ΡΡ‚ΠΎ Ρ‚Π°ΠΊΠ°, Π·Π° сСкој запис ΠΈΠΌΠ° Π΅Ρ‚ΠΈΠΊΠ΅Ρ‚Π° ΡˆΡ‚ΠΎ ΠΏΠΎΠΊΠ°ΠΆΡƒΠ²Π° Π΄Π°Π»ΠΈ сликата Π΅ ΠΏΡ€Π°Π²ΠΈΠ»Π½ΠΎ ΠΏΡ€Π΅ΠΏΠΎΠ·Π½Π°Π΅Π½Π° ΠΎΠ΄ класификаторот ΡˆΡ‚ΠΎ сС користСл Π²ΠΎ ΠΌΠΎΠΌΠ΅Π½Ρ‚ΠΎΡ‚ Π½Π° ΡΠΎΠ±ΠΈΡ€Π°ΡšΠ΅ Π½Π° Π±Π°Π·Π°Ρ‚Π°, ΡˆΠΈΡ„Ρ€Π° со Π΄Π²Π΅ Π±ΡƒΠΊΠ²ΠΈ Π½Π° Π·Π΅ΠΌΡ˜Π°Ρ‚Π° Π½Π° ТивССњС Π½Π° Π°Π²Ρ‚ΠΎΡ€ΠΎΡ‚ Π½Π° сликата, СдинствСн ΠΈΠ΄Π΅Π½Ρ‚ΠΈΡ„ΠΈΠΊΠ°Ρ‚ΠΎΡ€, врСмСнски ΠΏΠ΅Ρ‡Π°Ρ‚ ΠΈ ΠΈΠΌΠ΅ Π½Π° класа ΡˆΡ‚ΠΎ сС совпаѓа со ΠΈΠΌΠ΅Ρ‚ΠΎ Π½Π° Π΄Π°Ρ‚ΠΎΡ‚Π΅ΠΊΠ°Ρ‚Π°. ΠŸΠΎΠ΅Π΄Π½ΠΎΡΡ‚Π°Π²Π΅Π½Π°Ρ‚Π° Π²Π΅Ρ€Π·ΠΈΡ˜Π° Π½Π° ΠΎΡ€ΠΈΠ³ΠΈΠ½Π°Π»Π½ΠΈΡ‚Π΅ ΠΏΠΎΠ΄Π°Ρ‚ΠΎΡ†ΠΈ Ρ‚Π΅ΠΆΠΈ 7.4 GB Π²ΠΎ Π°Ρ€Ρ…ΠΈΠ²Π°Ρ‚Π° ΠΈ ΠΏΡ€ΠΈΠ±Π»ΠΈΠΆΠ½ΠΎ 20 GB ΠΏΠΎ Ρ€Π°ΡΠΏΠ°ΠΊΡƒΠ²Π°ΡšΠ΅Ρ‚ΠΎ, цСлоснитС ΠΏΠΎΠ΄Π°Ρ‚ΠΎΡ†ΠΈ ΠΏΠΎ Ρ€Π°ΡΠΏΠ°ΠΊΡƒΠ²Π°ΡšΠ΅Ρ‚ΠΎ Π·Π°Ρ„Π°ΡœΠ°Π°Ρ‚ 240 GB. ΠžΡ€Π³Π°Π½ΠΈΠ·Π°Ρ‚ΠΎΡ€ΠΈΡ‚Π΅ сС ΠΏΠΎΠ³Ρ€ΠΈΠΆΠΈΡ˜Π° Π΄Π²Π΅Ρ‚Π΅ Π²Π΅Ρ€Π·ΠΈΠΈ Π΄Π° Π³ΠΈ Ρ€Π΅ΠΏΡ€ΠΎΠ΄ΡƒΡ†ΠΈΡ€Π°Π°Ρ‚ иститС Ρ†Ρ€Ρ‚Π΅ΠΆΠΈ, ΡˆΡ‚ΠΎ Π·Π½Π°Ρ‡ΠΈ Π΄Π΅ΠΊΠ° цСлосната Π²Π΅Ρ€Π·ΠΈΡ˜Π° Π΅ излишна. Π’ΠΎ сСкој ΡΠ»ΡƒΡ‡Π°Ρ˜, ΡΠΊΠ»Π°Π΄ΠΈΡ€Π°ΡšΠ΅Ρ‚ΠΎ Π½Π° 50 ΠΌΠΈΠ»ΠΈΠΎΠ½ΠΈ слики Π²ΠΎ Π³Ρ€Π°Ρ„ΠΈΡ‡ΠΊΠΈ Π΄Π°Ρ‚ΠΎΡ‚Π΅ΠΊΠΈ ΠΈΠ»ΠΈ Π²ΠΎ Ρ„ΠΎΡ€ΠΌΠ° Π½Π° Π½ΠΈΠ·ΠΈ вСднаш сС ΡΠΌΠ΅Ρ‚Π°ΡˆΠ΅ Π·Π° Π½Π΅ΠΏΡ€ΠΎΡ„ΠΈΡ‚Π°Π±ΠΈΠ»Π½ΠΎ ΠΈ Ρ€Π΅ΡˆΠΈΠ²ΠΌΠ΅ Π΄Π° Π³ΠΈ споимС ситС CSV-Π΄Π°Ρ‚ΠΎΡ‚Π΅ΠΊΠΈ ΠΎΠ΄ Π°Ρ€Ρ…ΠΈΠ²Π°Ρ‚Π° train_simplified.zip Π²ΠΎ Π±Π°Π·Π°Ρ‚Π° Π½Π° ΠΏΠΎΠ΄Π°Ρ‚ΠΎΡ†ΠΈ со послСдоватСлно Π³Π΅Π½Π΅Ρ€ΠΈΡ€Π°ΡšΠ΅ Π½Π° слики со ΠΏΠΎΡ‚Ρ€Π΅Π±Π½Π°Ρ‚Π° Π³ΠΎΠ»Π΅ΠΌΠΈΠ½Π° β€žΠ²ΠΎ Π»Π΅Ρ‚β€œ Π·Π° сСкоја ΡΠ΅Ρ€ΠΈΡ˜Π°.

Π”ΠΎΠ±Ρ€ΠΎ Π΄ΠΎΠΊΠ°ΠΆΠ°Π½ систСм бСшС ΠΈΠ·Π±Ρ€Π°Π½ ΠΊΠ°ΠΊΠΎ DBMS MonetDB, ΠΈΠΌΠ΅Π½ΠΎ ΠΈΠΌΠΏΠ»Π΅ΠΌΠ΅Π½Ρ‚Π°Ρ†ΠΈΡ˜Π° Π·Π° R ΠΊΠ°ΠΊΠΎ ΠΏΠ°ΠΊΠ΅Ρ‚ MonetDBLite. ΠŸΠ°ΠΊΠ΅Ρ‚ΠΎΡ‚ Π²ΠΊΠ»ΡƒΡ‡ΡƒΠ²Π° Π²Π³Ρ€Π°Π΄Π΅Π½Π° Π²Π΅Ρ€Π·ΠΈΡ˜Π° Π½Π° сСрвСрот Π·Π° Π±Π°Π·Π° Π½Π° ΠΏΠΎΠ΄Π°Ρ‚ΠΎΡ†ΠΈ ΠΈ Π²ΠΈ ΠΎΠ²ΠΎΠ·ΠΌΠΎΠΆΡƒΠ²Π° Π΄Π° Π³ΠΎ Π·Π΅ΠΌΠ΅Ρ‚Π΅ сСрвСрот Π΄ΠΈΡ€Π΅ΠΊΡ‚Π½ΠΎ ΠΎΠ΄ R сСсија ΠΈ Π΄Π° Ρ€Π°Π±ΠΎΡ‚ΠΈΡ‚Π΅ со Π½Π΅Π³ΠΎ Ρ‚Π°ΠΌΡƒ. ΠšΡ€Π΅ΠΈΡ€Π°ΡšΠ΅Ρ‚ΠΎ Π±Π°Π·Π° Π½Π° ΠΏΠΎΠ΄Π°Ρ‚ΠΎΡ†ΠΈ ΠΈ ΠΏΠΎΠ²Ρ€Π·ΡƒΠ²Π°ΡšΠ΅Ρ‚ΠΎ со Π½Π΅Π° сС Π²Ρ€ΡˆΠΈ со Π΅Π΄Π½Π° ΠΊΠΎΠΌΠ°Π½Π΄Π°:

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"
    )
  )
}

ΠΠ°Ρ˜Π±Ρ€Π·ΠΈΠΎΡ‚ Π½Π°Ρ‡ΠΈΠ½ Π·Π° Π²Ρ‡ΠΈΡ‚ΡƒΠ²Π°ΡšΠ΅ ΠΏΠΎΠ΄Π°Ρ‚ΠΎΡ†ΠΈ Π²ΠΎ Π±Π°Π·Π°Ρ‚Π° Π½Π° ΠΏΠΎΠ΄Π°Ρ‚ΠΎΡ†ΠΈ бСшС Π΄ΠΈΡ€Π΅ΠΊΡ‚Π½ΠΎ ΠΊΠΎΠΏΠΈΡ€Π°ΡšΠ΅ Π½Π° CSV-Π΄Π°Ρ‚ΠΎΡ‚Π΅ΠΊΠΈ со помош Π½Π° ΠΊΠΎΠΌΠ°Π½Π΄Π°Ρ‚Π° SQL COPY OFFSET 2 INTO tablename FROM path USING DELIMITERS ',','n','"' NULL AS '' BEST EFFORTΠΊΠ°Π΄Π΅ tablename - ΠΈΠΌΠ΅ Π½Π° Ρ‚Π°Π±Π΅Π»Π°Ρ‚Π° ΠΈ path - ΠΏΠ°Ρ‚Π΅ΠΊΠ°Ρ‚Π° Π΄ΠΎ Π΄Π°Ρ‚ΠΎΡ‚Π΅ΠΊΠ°Ρ‚Π°. ΠŸΡ€ΠΈ Ρ€Π°Π±ΠΎΡ‚Π° со Π°Ρ€Ρ…ΠΈΠ²Π°Ρ‚Π°, ΠΎΡ‚ΠΊΡ€ΠΈΠ΅Π½ΠΎ Π΅ Π΄Π΅ΠΊΠ° Π²Π³Ρ€Π°Π΄Π΅Π½Π°Ρ‚Π° ΠΈΠΌΠΏΠ»Π΅ΠΌΠ΅Π½Ρ‚Π°Ρ†ΠΈΡ˜Π° unzip Π²ΠΎ R Π½Π΅ Ρ€Π°Π±ΠΎΡ‚ΠΈ ΠΏΡ€Π°Π²ΠΈΠ»Π½ΠΎ со Π³ΠΎΠ»Π΅ΠΌ Π±Ρ€ΠΎΡ˜ Π΄Π°Ρ‚ΠΎΡ‚Π΅ΠΊΠΈ ΠΎΠ΄ Π°Ρ€Ρ…ΠΈΠ²Π°Ρ‚Π°, ΠΏΠ° Π·Π°Ρ‚ΠΎΠ° Π³ΠΎ користСвмС систСмот 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

Π’Ρ€Π΅ΠΌΠ΅Ρ‚ΠΎ Π½Π° Π²Ρ‡ΠΈΡ‚ΡƒΠ²Π°ΡšΠ΅ Π½Π° ΠΏΠΎΠ΄Π°Ρ‚ΠΎΡ†ΠΈΡ‚Π΅ ΠΌΠΎΠΆΠ΅ Π΄Π° Π²Π°Ρ€ΠΈΡ€Π° Π²ΠΎ зависност ΠΎΠ΄ карактСристикитС Π½Π° Π±Ρ€Π·ΠΈΠ½Π°Ρ‚Π° Π½Π° користСниот ΠΏΠΎΠ³ΠΎΠ½. Π’ΠΎ Π½Π°ΡˆΠΈΠΎΡ‚ ΡΠ»ΡƒΡ‡Π°Ρ˜, Ρ‡ΠΈΡ‚Π°ΡšΠ΅Ρ‚ΠΎ ΠΈ ΠΏΠΈΡˆΡƒΠ²Π°ΡšΠ΅Ρ‚ΠΎ Π²ΠΎ Ρ€Π°ΠΌΠΊΠΈΡ‚Π΅ Π½Π° Π΅Π΄Π΅Π½ SSD ΠΈΠ»ΠΈ ΠΎΠ΄ Ρ„Π»Π΅Ρˆ-ΡƒΡ€Π΅Π΄ (ΠΈΠ·Π²ΠΎΡ€Π½Π° Π΄Π°Ρ‚ΠΎΡ‚Π΅ΠΊΠ°) Π½Π° SSD (DB) Ρ‚Ρ€Π°Π΅ ΠΏΠΎΠΌΠ°Π»ΠΊΡƒ ΠΎΠ΄ 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 Ρ‚Ρ€ΠΈΠΊΠΎΠ²ΠΈ. ΠŸΡ€Π²ΠΈΠΎΡ‚ бСшС Π΄Π° сС Π½Π°ΠΌΠ°Π»ΠΈ димСнзионалноста Π½Π° Ρ‚ΠΈΠΏΠΎΡ‚ ΡˆΡ‚ΠΎ Π³ΠΎ Ρ‡ΡƒΠ²Π° ID Π½Π° Π½Π°Π±Ρ™ΡƒΠ΄ΡƒΠ²Π°ΡšΠ΅. Π’ΠΎ ΠΎΡ€ΠΈΠ³ΠΈΠ½Π°Π»Π½ΠΈΠΎΡ‚ сСт Π½Π° ΠΏΠΎΠ΄Π°Ρ‚ΠΎΡ†ΠΈ, Ρ‚ΠΈΠΏΠΎΡ‚ ΠΏΠΎΡ‚Ρ€Π΅Π±Π΅Π½ Π·Π° ΡΠΊΠ»Π°Π΄ΠΈΡ€Π°ΡšΠ΅ Π½Π° Π»ΠΈΡ‡Π½Π°Ρ‚Π° ΠΊΠ°Ρ€Ρ‚Π° Π΅ bigint, Π½ΠΎ Π±Ρ€ΠΎΡ˜ΠΎΡ‚ Π½Π° Π½Π°Π±Ρ™ΡƒΠ΄ΡƒΠ²Π°ΡšΠ° ΠΎΠ²ΠΎΠ·ΠΌΠΎΠΆΡƒΠ²Π° Π΄Π° сС Π²ΠΊΠ»ΠΎΠΏΠ°Ρ‚ Π½ΠΈΠ²Π½ΠΈΡ‚Π΅ ΠΈΠ΄Π΅Π½Ρ‚ΠΈΡ„ΠΈΠΊΠ°Ρ‚ΠΎΡ€ΠΈ, Π΅Π΄Π½Π°ΠΊΠ²ΠΈ Π½Π° Ρ€Π΅Π΄Π½ΠΈΠΎΡ‚ Π±Ρ€ΠΎΡ˜, Π²ΠΎ Ρ‚ΠΈΠΏΠΎΡ‚ int. ΠŸΡ€Π΅Π±Π°Ρ€ΡƒΠ²Π°ΡšΠ΅Ρ‚ΠΎ Π΅ ΠΌΠ½ΠΎΠ³Ρƒ ΠΏΠΎΠ±Ρ€Π·ΠΎ Π²ΠΎ овој ΡΠ»ΡƒΡ‡Π°Ρ˜. Π’Ρ‚ΠΎΡ€ΠΈΠΎΡ‚ Ρ‚Ρ€ΠΈΠΊ бСшС Π΄Π° сС искористи ORDERED INDEX - Π”ΠΎΡ˜Π΄ΠΎΠ²ΠΌΠ΅ Π΄ΠΎ ΠΎΠ²Π°Π° ΠΎΠ΄Π»ΡƒΠΊΠ° Смпириски, ΠΎΡ‚ΠΊΠ°ΠΊΠΎ Π³ΠΈ ΠΏΠΎΠΌΠΈΠ½Π°Π²ΠΌΠ΅ ситС достапни ΠΎΠΏΡ†ΠΈΠΈ. Π’Ρ€Π΅Ρ‚ΠΈΠΎΡ‚ бСшС Π΄Π° сС користат ΠΏΠ°Ρ€Π°ΠΌΠ΅Ρ‚Ρ€ΠΈΠΈΠ·ΠΈΡ€Π°Π½ΠΈ ΠΏΡ€Π°ΡˆΠ°ΡšΠ°. Π‘ΡƒΡˆΡ‚ΠΈΠ½Π°Ρ‚Π° Π½Π° ΠΌΠ΅Ρ‚ΠΎΠ΄ΠΎΡ‚ Π΅ Π΄Π° сС ΠΈΠ·Π²Ρ€ΡˆΠΈ ΠΊΠΎΠΌΠ°Π½Π΄Π°Ρ‚Π° Сднаш PREPARE со послСдоватСлна ΡƒΠΏΠΎΡ‚Ρ€Π΅Π±Π° Π½Π° ΠΏΠΎΠ΄Π³ΠΎΡ‚Π²Π΅Π½ ΠΈΠ·Ρ€Π°Π· ΠΏΡ€ΠΈ ΠΊΡ€Π΅ΠΈΡ€Π°ΡšΠ΅ Π½Π° ΠΊΡƒΠΏ ΠΏΡ€Π°ΡˆΠ°ΡšΠ° ΠΎΠ΄ ист Ρ‚ΠΈΠΏ, Π½ΠΎ Π²ΡΡƒΡˆΠ½ΠΎΡΡ‚ ΠΈΠΌΠ° прСдност Π²ΠΎ спорСдба со Сдноставниот SELECT сС ΠΏΠΎΠΊΠ°ΠΆΠ° Π΄Π΅ΠΊΠ° Π΅ Π²ΠΎ опсСгот Π½Π° статистичка Π³Ρ€Π΅ΡˆΠΊΠ°.

ΠŸΡ€ΠΎΡ†Π΅ΡΠΎΡ‚ Π½Π° ΠΏΠΎΡΡ‚Π°Π²ΡƒΠ²Π°ΡšΠ΅ ΠΏΠΎΠ΄Π°Ρ‚ΠΎΡ†ΠΈ Ρ‚Ρ€ΠΎΡˆΠΈ Π½Π΅ повСќС ΠΎΠ΄ 450 MB RAM ΠΌΠ΅ΠΌΠΎΡ€ΠΈΡ˜Π°. Односно, ΠΎΠΏΠΈΡˆΠ°Π½ΠΈΠΎΡ‚ пристап Π²ΠΈ ΠΎΠ²ΠΎΠ·ΠΌΠΎΠΆΡƒΠ²Π° Π΄Π° прСмСститС Π·Π±ΠΈΡ€ΠΊΠΈ Π½Π° ΠΏΠΎΠ΄Π°Ρ‚ΠΎΡ†ΠΈ со Ρ‚Π΅ΠΆΠΈΠ½Π° ΠΎΠ΄ дСсСтици Π³ΠΈΠ³Π°Π±Π°Ρ˜Ρ‚ΠΈ Π½Π° рСчиси сСкој Π±ΡƒΡŸΠ΅Ρ‚ΡΠΊΠΈ Ρ…Π°Ρ€Π΄Π²Π΅Ρ€, Π²ΠΊΠ»ΡƒΡ‡ΠΈΡ‚Π΅Π»Π½ΠΎ ΠΈ Π½Π΅ΠΊΠΎΠΈ ΡƒΡ€Π΅Π΄ΠΈ со Π΅Π΄Π½Π° ΠΏΠ»ΠΎΡ‡Π°, ΡˆΡ‚ΠΎ Π΅ ΠΏΡ€ΠΈΠ»ΠΈΡ‡Π½ΠΎ ΠΊΡƒΠ».

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

Π Π΅ΠΏΠ΅Ρ€ Π·Π° Π±Π°Π·Π° Π½Π° ΠΏΠΎΠ΄Π°Ρ‚ΠΎΡ†ΠΈ

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)

Quick Draw Doodle Recognition: ΠΊΠ°ΠΊΠΎ Π΄Π° сС Π΄Ρ€ΡƒΠΆΠΈΡ‚Π΅ со R, C++ ΠΈ нСвронскитС ΠΌΡ€Π΅ΠΆΠΈ

2. ΠŸΠΎΠ΄Π³ΠΎΡ‚ΠΎΠ²ΠΊΠ° Π½Π° сСрии

Π¦Π΅Π»ΠΈΠΎΡ‚ процСс Π½Π° ΠΏΠΎΠ΄Π³ΠΎΡ‚ΠΎΠ²ΠΊΠ° Π½Π° ΡΠ΅Ρ€ΠΈΡ˜Π°Ρ‚Π° сС состои ΠΎΠ΄ слСднивС Ρ‡Π΅ΠΊΠΎΡ€ΠΈ:

  1. ΠŸΠ°Ρ€ΡΠΈΡ€Π°ΡšΠ΅ Π½Π° Π½Π΅ΠΊΠΎΠ»ΠΊΡƒ JSON ΠΊΠΎΠΈ содрТат Π²Π΅ΠΊΡ‚ΠΎΡ€ΠΈ Π½Π° Π½ΠΈΠ·ΠΈ со ΠΊΠΎΠΎΡ€Π΄ΠΈΠ½Π°Ρ‚ΠΈ Π½Π° Ρ‚ΠΎΡ‡ΠΊΠΈ.
  2. Π¦Ρ€Ρ‚Π°ΡšΠ΅ ΠΎΠ±ΠΎΠ΅Π½ΠΈ Π»ΠΈΠ½ΠΈΠΈ Π²Ρ€Π· основа Π½Π° ΠΊΠΎΠΎΡ€Π΄ΠΈΠ½Π°Ρ‚ΠΈΡ‚Π΅ Π½Π° Ρ‚ΠΎΡ‡ΠΊΠΈΡ‚Π΅ Π½Π° слика со ΠΏΠΎΡ‚Ρ€Π΅Π±Π½Π°Ρ‚Π° Π³ΠΎΠ»Π΅ΠΌΠΈΠ½Π° (Π½Π° ΠΏΡ€ΠΈΠΌΠ΅Ρ€, 256Γ—256 ΠΈΠ»ΠΈ 128Γ—128).
  3. ΠšΠΎΠ½Π²Π΅Ρ€Ρ‚ΠΈΡ€Π°ΡšΠ΅ Π½Π° Π΄ΠΎΠ±ΠΈΠ΅Π½ΠΈΡ‚Π΅ слики Π²ΠΎ Ρ‚Π΅Π½Π·ΠΎΡ€.

Како Π΄Π΅Π» ΠΎΠ΄ Π½Π°Ρ‚ΠΏΡ€Π΅Π²Π°Ρ€ΠΎΡ‚ ΠΌΠ΅Ρ“Ρƒ ΠΊΠ΅Ρ€Π½Π΅Π»ΠΈΡ‚Π΅ Π½Π° Python, ΠΏΡ€ΠΎΠ±Π»Π΅ΠΌΠΎΡ‚ бСшС Ρ€Π΅ΡˆΠ΅Π½ првСнствСно ΠΊΠΎΡ€ΠΈΡΡ‚Π΅Ρ˜ΡœΠΈ OpenCV. Π•Π΄Π΅Π½ ΠΎΠ΄ Π½Π°Ρ˜Π΅Π΄Π½ΠΎΡΡ‚Π°Π²Π½ΠΈΡ‚Π΅ ΠΈ Π½Π°Ρ˜ΠΎΡ‡ΠΈΠ³Π»Π΅Π΄Π½ΠΈΡ‚Π΅ Π°Π½Π°Π»ΠΎΠ·ΠΈ Π²ΠΎ R Π±ΠΈ ΠΈΠ·Π³Π»Π΅Π΄Π°Π» Π²Π°ΠΊΠ°:

Π‘ΠΏΡ€ΠΎΠ²Π΅Π΄ΡƒΠ²Π°ΡšΠ΅ Π½Π° ΠΊΠΎΠ½Π²Π΅Ρ€Π·ΠΈΡ˜Π° JSON Π²ΠΎ Ρ‚Π΅Π½Π·ΠΎΡ€ Π²ΠΎ Π 

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)
}

Π¦Ρ€Ρ‚Π΅ΠΆΠΎΡ‚ сС ΠΈΠ·Π²Π΅Π΄ΡƒΠ²Π° со помош Π½Π° стандардни R Π°Π»Π°Ρ‚ΠΊΠΈ ΠΈ сС Π·Π°Ρ‡ΡƒΠ²ΡƒΠ²Π° Π²ΠΎ ΠΏΡ€ΠΈΠ²Ρ€Π΅ΠΌΠ΅Π½ PNG складиран Π²ΠΎ RAM ΠΌΠ΅ΠΌΠΎΡ€ΠΈΡ˜Π° (Π½Π° Linux, ΠΏΡ€ΠΈΠ²Ρ€Π΅ΠΌΠ΅Π½ΠΈΡ‚Π΅ R Π΄ΠΈΡ€Π΅ΠΊΡ‚ΠΎΡ€ΠΈΡƒΠΌΠΈ сС Π½Π°ΠΎΡ“Π°Π°Ρ‚ Π²ΠΎ Π΄ΠΈΡ€Π΅ΠΊΡ‚ΠΎΡ€ΠΈΡƒΠΌΠΎΡ‚ /tmp, ΠΌΠΎΠ½Ρ‚ΠΈΡ€Π°Π½ Π²ΠΎ RAM ΠΌΠ΅ΠΌΠΎΡ€ΠΈΡ˜Π°). Оваа Π΄Π°Ρ‚ΠΎΡ‚Π΅ΠΊΠ° ΠΏΠΎΡ‚ΠΎΠ° сС Ρ‡ΠΈΡ‚Π° ΠΊΠ°ΠΊΠΎ Ρ‚Ρ€ΠΎΠ΄ΠΈΠΌΠ΅Π½Π·ΠΈΠΎΠ½Π°Π»Π½Π° Π½ΠΈΠ·Π° со Π±Ρ€ΠΎΠ΅Π²ΠΈ ΠΊΠΎΠΈ сС Π΄Π²ΠΈΠΆΠ°Ρ‚ ΠΎΠ΄ 0 Π΄ΠΎ 1. Ова Π΅ Π²Π°ΠΆΠ½ΠΎ Π·Π°Ρ‚ΠΎΠ° ΡˆΡ‚ΠΎ ΠΏΠΎΠΊΠΎΠ½Π²Π΅Π½Ρ†ΠΈΠΎΠ½Π°Π»Π΅Π½ BMP Π±ΠΈ сС Ρ‡ΠΈΡ‚Π°Π» Π²ΠΎ Π½Π΅ΠΎΠ±Ρ€Π°Π±ΠΎΡ‚Π΅Π½Π° Π½ΠΈΠ·Π° со хСксадСцимални ΡˆΠΈΡ„Ρ€ΠΈ Π½Π° Π±ΠΎΠΈ.

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

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))

Quick Draw Doodle Recognition: ΠΊΠ°ΠΊΠΎ Π΄Π° сС Π΄Ρ€ΡƒΠΆΠΈΡ‚Π΅ со R, C++ ΠΈ нСвронскитС ΠΌΡ€Π΅ΠΆΠΈ

Π‘Π°ΠΌΠ°Ρ‚Π° ΡΠ΅Ρ€ΠΈΡ˜Π° ќС сС Ρ„ΠΎΡ€ΠΌΠΈΡ€Π° Π½Π° слСдниов Π½Π°Ρ‡ΠΈΠ½:

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

Оваа ΠΈΠΌΠΏΠ»Π΅ΠΌΠ΅Π½Ρ‚Π°Ρ†ΠΈΡ˜Π° Π½ΠΈ сС Ρ‡ΠΈΠ½Π΅ΡˆΠ΅ Π½Π΅ΠΎΠΏΡ‚ΠΈΠΌΠ°Π»Π½Π°, бидСјќи Ρ„ΠΎΡ€ΠΌΠΈΡ€Π°ΡšΠ΅Ρ‚ΠΎ Π½Π° Π³ΠΎΠ»Π΅ΠΌΠΈ сСрии Ρ‚Ρ€Π°Π΅ Π½Π΅ΠΏΡ€ΠΈΡΡ‚ΠΎΡ˜Π½ΠΎ Π΄ΠΎΠ»Π³ΠΎ Π²Ρ€Π΅ΠΌΠ΅, ΠΈ Ρ€Π΅ΡˆΠΈΠ²ΠΌΠ΅ Π΄Π° Π³ΠΎ искористимС искуството Π½Π° Π½Π°ΡˆΠΈΡ‚Π΅ ΠΊΠΎΠ»Π΅Π³ΠΈ ΠΊΠΎΡ€ΠΈΡΡ‚Π΅Ρ˜ΡœΠΈ моќна Π±ΠΈΠ±Π»ΠΈΠΎΡ‚Π΅ΠΊΠ° OpenCV. Π’ΠΎ Ρ‚ΠΎΠ° Π²Ρ€Π΅ΠΌΠ΅ нСмашС Π³ΠΎΡ‚ΠΎΠ² ΠΏΠ°ΠΊΠ΅Ρ‚ Π·Π° R (сСга Π½Π΅ΠΌΠ°), ΠΏΠ° ΠΌΠΈΠ½ΠΈΠΌΠ°Π»Π½Π° ΠΈΠΌΠΏΠ»Π΅ΠΌΠ΅Π½Ρ‚Π°Ρ†ΠΈΡ˜Π° Π½Π° ΠΏΠΎΡ‚Ρ€Π΅Π±Π½Π°Ρ‚Π° функционалност бСшС напишана Π²ΠΎ C++ со ΠΈΠ½Ρ‚Π΅Π³Ρ€Π°Ρ†ΠΈΡ˜Π° Π²ΠΎ R ΠΊΠΎΠ΄ ΠΊΠΎΡ€ΠΈΡΡ‚Π΅Ρ˜ΡœΠΈ Rcpp.

Π—Π° Π΄Π° сС Ρ€Π΅ΡˆΠΈ ΠΏΡ€ΠΎΠ±Π»Π΅ΠΌΠΎΡ‚, Π±Π΅Π° користСни слСднитС ΠΏΠ°ΠΊΠ΅Ρ‚ΠΈ ΠΈ Π±ΠΈΠ±Π»ΠΈΠΎΡ‚Π΅ΠΊΠΈ:

  1. OpenCV Π·Π° Ρ€Π°Π±ΠΎΡ‚Π° со слики ΠΈ Ρ†Ρ€Ρ‚Π°ΡšΠ΅ Π»ΠΈΠ½ΠΈΠΈ. ΠšΠΎΡ€ΠΈΡΡ‚Π΅Π½ΠΈ ΠΏΡ€Π΅Ρ‚Ρ…ΠΎΠ΄Π½ΠΎ инсталирани систСмски Π±ΠΈΠ±Π»ΠΈΠΎΡ‚Π΅ΠΊΠΈ ΠΈ Π΄Π°Ρ‚ΠΎΡ‚Π΅ΠΊΠΈ со заглавија, ΠΊΠ°ΠΊΠΎ ΠΈ Π΄ΠΈΠ½Π°ΠΌΠΈΡ‡Π½ΠΎ ΠΏΠΎΠ²Ρ€Π·ΡƒΠ²Π°ΡšΠ΅.

  2. xtensor Π·Π° Ρ€Π°Π±ΠΎΡ‚Π° со повСќСдимСнзионални Π½ΠΈΠ·ΠΈ ΠΈ Ρ‚Π΅Π½Π·ΠΎΡ€ΠΈ. ΠšΠΎΡ€ΠΈΡΡ‚ΠΈΠ²ΠΌΠ΅ Π΄Π°Ρ‚ΠΎΡ‚Π΅ΠΊΠΈ со заглавија Π²ΠΊΠ»ΡƒΡ‡Π΅Π½ΠΈ Π²ΠΎ истоимСниот ΠΏΠ°ΠΊΠ΅Ρ‚ R. Π‘ΠΈΠ±Π»ΠΈΠΎΡ‚Π΅ΠΊΠ°Ρ‚Π° Π²ΠΈ ΠΎΠ²ΠΎΠ·ΠΌΠΎΠΆΡƒΠ²Π° Π΄Π° Ρ€Π°Π±ΠΎΡ‚ΠΈΡ‚Π΅ со повСќСдимСнзионални Π½ΠΈΠ·ΠΈ, ΠΈ ΠΏΠΎ Ρ€Π΅Π΄ ΠΈ Π³Π»Π°Π²Π΅Π½ рСдослСд Π½Π° ΠΊΠΎΠ»ΠΎΠ½ΠΈ.

  3. нјсон Π·Π° ΠΏΠ°Ρ€ΡΠΈΡ€Π°ΡšΠ΅ Π½Π° JSON. Оваа Π±ΠΈΠ±Π»ΠΈΠΎΡ‚Π΅ΠΊΠ° сС користи Π²ΠΎ xtensor автоматски Π΄ΠΎΠΊΠΎΠ»ΠΊΡƒ Π΅ присутСн Π²ΠΎ ΠΏΡ€ΠΎΠ΅ΠΊΡ‚ΠΎΡ‚.

  4. RcppThread Π·Π° ΠΎΡ€Π³Π°Π½ΠΈΠ·ΠΈΡ€Π°ΡšΠ΅ Π½Π° повСќСнишка ΠΎΠ±Ρ€Π°Π±ΠΎΡ‚ΠΊΠ° Π½Π° Π²Π΅ΠΊΡ‚ΠΎΡ€ ΠΎΠ΄ JSON. Π“ΠΈ ΠΊΠΎΡ€ΠΈΡΡ‚Π΅ΡˆΠ΅ Π΄Π°Ρ‚ΠΎΡ‚Π΅ΠΊΠΈΡ‚Π΅ Π·Π° заглавија ΠΎΠ±Π΅Π·Π±Π΅Π΄Π΅Π½ΠΈ ΠΎΠ΄ овој ΠΏΠ°ΠΊΠ΅Ρ‚. Од повСќС ΠΏΠΎΠΏΡƒΠ»Π°Ρ€Π½ΠΈ RcppΠŸΠ°Ρ€Π°Π»Π΅Π»Π½ΠΎ ΠŸΠ°ΠΊΠ΅Ρ‚ΠΎΡ‚, ΠΌΠ΅Ρ“Ρƒ Π΄Ρ€ΡƒΠ³ΠΎΡ‚ΠΎ, ΠΈΠΌΠ° Π²Π³Ρ€Π°Π΄Π΅Π½ ΠΌΠ΅Ρ…Π°Π½ΠΈΠ·Π°ΠΌ Π·Π° ΠΏΡ€Π΅ΠΊΠΈΠ½ Π½Π° Ρ˜Π°ΠΌΠΊΠ°Ρ‚Π°.

Π’Ρ€Π΅Π±Π° Π΄Π° сС Π½Π°ΠΏΠΎΠΌΠ΅Π½Π΅ Π΄Π΅ΠΊΠ° xtensor сС ΠΏΠΎΠΊΠ°ΠΆΠ° ΠΊΠ°ΠΊΠΎ Π‘ΠΎΠΆΡ˜ΠΈ Π΄Π°Ρ€: ΠΏΠΎΠΊΡ€Π°Ρ˜ Ρ„Π°ΠΊΡ‚ΠΎΡ‚ ΡˆΡ‚ΠΎ ΠΈΠΌΠ° ΠΎΠ±Π΅ΠΌΠ½Π° функционалност ΠΈ високи пСрформанси, Π½Π΅Π³ΠΎΠ²ΠΈΡ‚Π΅ ΠΏΡ€ΠΎΠ³Ρ€Π°ΠΌΠ΅Ρ€ΠΈ сС ΠΏΠΎΠΊΠ°ΠΆΠ°Π° ΠΊΠ°ΠΊΠΎ доста ΠΎΠ΄Π³ΠΎΠ²ΠΎΡ€Π½ΠΈ ΠΈ ΠΎΠ΄Π³ΠΎΠ²ΠΎΡ€ΠΈΡ˜Π° Π½Π° ΠΏΡ€Π°ΡˆΠ°ΡšΠ° Π±Ρ€Π·ΠΎ ΠΈ Π΄Π΅Ρ‚Π°Π»Π½ΠΎ. Π‘ΠΎ Π½ΠΈΠ²Π½Π° помош, бСшС ΠΌΠΎΠΆΠ½ΠΎ Π΄Π° сС ΠΈΠΌΠΏΠ»Π΅ΠΌΠ΅Π½Ρ‚ΠΈΡ€Π°Π°Ρ‚ трансформации Π½Π° OpenCV ΠΌΠ°Ρ‚Ρ€ΠΈΡ†ΠΈ Π²ΠΎ xtensor Ρ‚Π΅Π½Π·ΠΎΡ€ΠΈ, ΠΊΠ°ΠΊΠΎ ΠΈ Π½Π°Ρ‡ΠΈΠ½ Π·Π° ΠΊΠΎΠΌΠ±ΠΈΠ½ΠΈΡ€Π°ΡšΠ΅ Π½Π° 3-Π΄ΠΈΠΌΠ΅Π½Π·ΠΈΠΎΠ½Π°Π»Π½ΠΈ Ρ‚Π΅Π½Π·ΠΎΡ€ΠΈ Π½Π° слика Π²ΠΎ 4-Π΄ΠΈΠΌΠ΅Π½Π·ΠΈΠΎΠ½Π°Π»Π΅Π½ Ρ‚Π΅Π½Π·ΠΎΡ€ со ΠΏΡ€Π°Π²ΠΈΠ»Π½Π° димСнзија (самата ΡΠ΅Ρ€ΠΈΡ˜Π°).

ΠœΠ°Ρ‚Π΅Ρ€ΠΈΡ˜Π°Π»ΠΈ Π·Π° ΡƒΡ‡Π΅ΡšΠ΅ Rcpp, xtensor ΠΈ RcppThread

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. Π—Π° автоматско Π½Π°ΠΎΡ“Π°ΡšΠ΅ ΠΏΠ°Ρ‚Π΅ΠΊΠΈ ΠΈ знамиња, користСвмС ΠΏΠΎΠΏΡƒΠ»Π°Ρ€Π½Π° Π°Π»Π°Ρ‚ΠΊΠ° Π·Π° Linux pkg-ΠΊΠΎΠ½Ρ„ΠΈΠ³ΡƒΡ€Π°Ρ†ΠΈΡ˜Π°.

Π˜ΠΌΠΏΠ»Π΅ΠΌΠ΅Π½Ρ‚Π°Ρ†ΠΈΡ˜Π° Π½Π° ΠΏΡ€ΠΈΠΊΠ»ΡƒΡ‡ΠΎΠΊΠΎΡ‚ Rcpp Π·Π° ΠΊΠΎΡ€ΠΈΡΡ‚Π΅ΡšΠ΅ Π½Π° Π±ΠΈΠ±Π»ΠΈΠΎΡ‚Π΅ΠΊΠ°Ρ‚Π° OpenCV

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"

Под ΡΠΏΠΎΡ˜Π»Π΅Ρ€ΠΎΡ‚ Π΅ Π΄Π°Π΄Π΅Π½ ΠΊΠΎΠ΄ΠΎΡ‚ Π·Π° ΠΈΠΌΠΏΠ»Π΅ΠΌΠ΅Π½Ρ‚Π°Ρ†ΠΈΡ˜Π° Π·Π° ΠΏΠ°Ρ€ΡΠΈΡ€Π°ΡšΠ΅ Π½Π° JSON ΠΈ Π³Π΅Π½Π΅Ρ€ΠΈΡ€Π°ΡšΠ΅ ΡΠ΅Ρ€ΠΈΡ˜Π° Π·Π° прСнос Π΄ΠΎ ΠΌΠΎΠ΄Π΅Π»ΠΎΡ‚. ΠŸΡ€Π²ΠΎ, Π΄ΠΎΠ΄Π°Π΄Π΅Ρ‚Π΅ Π»ΠΎΠΊΠ°Π»Π΅Π½ ΠΏΡ€ΠΎΠ΅ΠΊΡ‚Π΅Π½ Π΄ΠΈΡ€Π΅ΠΊΡ‚ΠΎΡ€ΠΈΡƒΠΌ Π·Π° ΠΏΡ€Π΅Π±Π°Ρ€ΡƒΠ²Π°ΡšΠ΅ Π½Π° Π΄Π°Ρ‚ΠΎΡ‚Π΅ΠΊΠΈ со заглавија (ΠΏΠΎΡ‚Ρ€Π΅Π±Π½ΠΈ Π·Π° ndjson):

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

Π˜ΠΌΠΏΠ»Π΅ΠΌΠ΅Π½Ρ‚Π°Ρ†ΠΈΡ˜Π° Π½Π° ΠΊΠΎΠ½Π²Π΅Ρ€Π·ΠΈΡ˜Π° Π½Π° JSON Π²ΠΎ Ρ‚Π΅Π½Π·ΠΎΡ€ Π²ΠΎ C++

// [[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 β€” Ρ„ΡƒΠ½ΠΊΡ†ΠΈΡ˜Π°Ρ‚Π° Π°Π½Π°Π»ΠΈΠ·ΠΈΡ€Π° Π½ΠΈΠ·Π° JSON, Π³ΠΈ ΠΈΠ·Π²Π»Π΅ΠΊΡƒΠ²Π° ΠΊΠΎΠΎΡ€Π΄ΠΈΠ½Π°Ρ‚ΠΈΡ‚Π΅ Π½Π° Ρ‚ΠΎΡ‡ΠΊΠΈΡ‚Π΅, ΠΏΠ°ΠΊΡƒΠ²Π°Ρ˜ΡœΠΈ Π³ΠΈ Π²ΠΎ Π²Π΅ΠΊΡ‚ΠΎΡ€;

  • ocv_draw_lines β€” ΠΎΠ΄ Π΄ΠΎΠ±ΠΈΠ΅Π½ΠΈΠΎΡ‚ Π²Π΅ΠΊΡ‚ΠΎΡ€ Π½Π° Ρ‚ΠΎΡ‡ΠΊΠΈ, Ρ†Ρ€Ρ‚Π° повСќСбојни Π»ΠΈΠ½ΠΈΠΈ;

  • process β€” Π³ΠΈ ΠΊΠΎΠΌΠ±ΠΈΠ½ΠΈΡ€Π° Π³ΠΎΡ€Π΅Π½Π°Π²Π΅Π΄Π΅Π½ΠΈΡ‚Π΅ Ρ„ΡƒΠ½ΠΊΡ†ΠΈΠΈ ΠΈ исто Ρ‚Π°ΠΊΠ° Π΄ΠΎΠ΄Π°Π²Π° моТност Π·Π° ΡΠΊΠ°Π»ΠΈΡ€Π°ΡšΠ΅ Π½Π° Π΄ΠΎΠ±ΠΈΠ΅Π½Π°Ρ‚Π° слика;

  • cpp_process_json_str - ΠΎΠ±Π²ΠΈΠ²ΠΊΠ° Π½Π°Π΄ Ρ„ΡƒΠ½ΠΊΡ†ΠΈΡ˜Π°Ρ‚Π° process, кој Π³ΠΎ ΠΈΠ·Π²Π΅Π·ΡƒΠ²Π° Ρ€Π΅Π·ΡƒΠ»Ρ‚Π°Ρ‚ΠΎΡ‚ Π²ΠΎ R-ΠΎΠ±Ρ˜Π΅ΠΊΡ‚ (ΠΌΡƒΠ»Ρ‚ΠΈΠ΄ΠΈΠΌΠ΅Π½Π·ΠΈΠΎΠ½Π°Π»Π½Π° Π½ΠΈΠ·Π°);

  • cpp_process_json_vector - ΠΎΠ±Π²ΠΈΠ²ΠΊΠ° Π½Π°Π΄ Ρ„ΡƒΠ½ΠΊΡ†ΠΈΡ˜Π°Ρ‚Π° cpp_process_json_str, кој Π²ΠΈ ΠΎΠ²ΠΎΠ·ΠΌΠΎΠΆΡƒΠ²Π° Π΄Π° ΠΎΠ±Ρ€Π°Π±ΠΎΡ‚ΠΈΡ‚Π΅ стринг Π²Π΅ΠΊΡ‚ΠΎΡ€ Π²ΠΎ Ρ€Π΅ΠΆΠΈΠΌ со повСќС нишки.

Π—Π° Ρ†Ρ€Ρ‚Π°ΡšΠ΅ Π»ΠΈΠ½ΠΈΠΈ Π²ΠΎ повСќС Π±ΠΎΠΈ, користСн Π΅ ΠΌΠΎΠ΄Π΅Π»ΠΎΡ‚ Π½Π° боја HSV, прослСдСн со ΠΊΠΎΠ½Π²Π΅Ρ€Π·ΠΈΡ˜Π° Π²ΠΎ RGB. АјдС Π΄Π° Π³ΠΎ тСстирамС Ρ€Π΅Π·ΡƒΠ»Ρ‚Π°Ρ‚ΠΎΡ‚:

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

Quick Draw Doodle Recognition: ΠΊΠ°ΠΊΠΎ Π΄Π° сС Π΄Ρ€ΡƒΠΆΠΈΡ‚Π΅ со R, C++ ΠΈ нСвронскитС ΠΌΡ€Π΅ΠΆΠΈ
Π‘ΠΏΠΎΡ€Π΅Π΄Π±Π° Π½Π° Π±Ρ€Π·ΠΈΠ½Π°Ρ‚Π° Π½Π° ΠΈΠΌΠΏΠ»Π΅ΠΌΠ΅Π½Ρ‚Π°Ρ†ΠΈΠΈ Π²ΠΎ R ΠΈ C++

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") 

Quick Draw Doodle Recognition: ΠΊΠ°ΠΊΠΎ Π΄Π° сС Π΄Ρ€ΡƒΠΆΠΈΡ‚Π΅ со R, C++ ΠΈ нСвронскитС ΠΌΡ€Π΅ΠΆΠΈ

Како ΡˆΡ‚ΠΎ ΠΌΠΎΠΆΠ΅Ρ‚Π΅ Π΄Π° Π²ΠΈΠ΄ΠΈΡ‚Π΅, Π·Π³ΠΎΠ»Π΅ΠΌΡƒΠ²Π°ΡšΠ΅Ρ‚ΠΎ Π½Π° Π±Ρ€Π·ΠΈΠ½Π°Ρ‚Π° сС ΠΏΠΎΠΊΠ°ΠΆΠ° ΠΊΠ°ΠΊΠΎ ΠΌΠ½ΠΎΠ³Ρƒ Π·Π½Π°Ρ‡Π°Ρ˜Π½ΠΎ ΠΈ Π½Π΅ Π΅ ΠΌΠΎΠΆΠ½ΠΎ Π΄Π° сС стигнС Π΄ΠΎ C++ ΠΊΠΎΠ΄ΠΎΡ‚ со ΠΏΠ°Ρ€Π°Π»Π΅Π»ΠΈΠ·ΠΈΡ€Π°ΡšΠ΅ Π½Π° R-ΠΊΠΎΠ΄ΠΎΡ‚.

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

R ΠΈΠΌΠ° заслуТСна Ρ€Π΅ΠΏΡƒΡ‚Π°Ρ†ΠΈΡ˜Π° Π·Π° ΠΎΠ±Ρ€Π°Π±ΠΎΡ‚ΠΊΠ° Π½Π° ΠΏΠΎΠ΄Π°Ρ‚ΠΎΡ†ΠΈ ΡˆΡ‚ΠΎ сС Π²ΠΊΠ»ΠΎΠΏΡƒΠ²Π°Π°Ρ‚ Π²ΠΎ RAM ΠΌΠ΅ΠΌΠΎΡ€ΠΈΡ˜Π°Ρ‚Π°, Π΄ΠΎΠ΄Π΅ΠΊΠ° Python повСќС сС ΠΊΠ°Ρ€Π°ΠΊΡ‚Π΅Ρ€ΠΈΠ·ΠΈΡ€Π° со ΠΈΡ‚Π΅Ρ€Π°Ρ‚ΠΈΠ²Π½Π° ΠΎΠ±Ρ€Π°Π±ΠΎΡ‚ΠΊΠ° Π½Π° ΠΏΠΎΠ΄Π°Ρ‚ΠΎΡ†ΠΈ, ΡˆΡ‚ΠΎ Π²ΠΈ ΠΎΠ²ΠΎΠ·ΠΌΠΎΠΆΡƒΠ²Π° лСсно ΠΈ ΠΏΡ€ΠΈΡ€ΠΎΠ΄Π½ΠΎ Π΄Π° спровСдуватС прСсмСтки Π½Π°Π΄Π²ΠΎΡ€ ΠΎΠ΄ Ρ˜Π°Π΄Ρ€ΠΎΡ‚ΠΎ (прСсмСтки со помош Π½Π° Π½Π°Π΄Π²ΠΎΡ€Π΅ΡˆΠ½Π° ΠΌΠ΅ΠΌΠΎΡ€ΠΈΡ˜Π°). ΠšΠ»Π°ΡΠΈΡ‡Π΅Π½ ΠΈ Ρ€Π΅Π»Π΅Π²Π°Π½Ρ‚Π΅Π½ ΠΏΡ€ΠΈΠΌΠ΅Ρ€ Π·Π° нас Π²ΠΎ контСкст Π½Π° ΠΎΠΏΠΈΡˆΠ°Π½ΠΈΠΎΡ‚ ΠΏΡ€ΠΎΠ±Π»Π΅ΠΌ сС Π΄Π»Π°Π±ΠΎΠΊΠΈΡ‚Π΅ нСвронски ΠΌΡ€Π΅ΠΆΠΈ ΠΎΠ±ΡƒΡ‡Π΅Π½ΠΈ со ΠΌΠ΅Ρ‚ΠΎΠ΄ΠΎΡ‚ Π½Π° ΡΠΏΡƒΡˆΡ‚Π°ΡšΠ΅ Π½Π° Π³Ρ€Π°Π΄ΠΈΠ΅Π½Ρ‚ со ΠΏΡ€ΠΈΠ±Π»ΠΈΠΆΡƒΠ²Π°ΡšΠ΅ Π½Π° Π³Ρ€Π°Π΄ΠΈΠ΅Π½Ρ‚ΠΎΡ‚ Π½Π° сСкој Ρ‡Π΅ΠΊΠΎΡ€ ΠΊΠΎΡ€ΠΈΡΡ‚Π΅Ρ˜ΡœΠΈ ΠΌΠ°Π» Π΄Π΅Π» ΠΎΠ΄ Π½Π°Π±Ρ™ΡƒΠ΄ΡƒΠ²Π°ΡšΠ°, ΠΈΠ»ΠΈ ΠΌΠΈΠ½ΠΈ-ΡΠ΅Ρ€ΠΈΡ˜Π°.

Π Π°ΠΌΠΊΠΈΡ‚Π΅ Π·Π° Π΄Π»Π°Π±ΠΎΠΊΠΎ ΡƒΡ‡Π΅ΡšΠ΅ напишани Π²ΠΎ Python ΠΈΠΌΠ°Π°Ρ‚ посСбни класи ΠΊΠΎΠΈ ΠΈΠΌΠΏΠ»Π΅ΠΌΠ΅Π½Ρ‚ΠΈΡ€Π°Π°Ρ‚ ΠΈΡ‚Π΅Ρ€Π°Ρ‚ΠΎΡ€ΠΈ Π±Π°Π·ΠΈΡ€Π°Π½ΠΈ Π½Π° ΠΏΠΎΠ΄Π°Ρ‚ΠΎΡ†ΠΈ: Ρ‚Π°Π±Π΅Π»ΠΈ, слики Π²ΠΎ ΠΏΠ°ΠΏΠΊΠΈ, Π±ΠΈΠ½Π°Ρ€Π½ΠΈ Ρ„ΠΎΡ€ΠΌΠ°Ρ‚ΠΈ ΠΈΡ‚Π½. ΠœΠΎΠΆΠ΅Ρ‚Π΅ Π΄Π° користитС Π³ΠΎΡ‚ΠΎΠ²ΠΈ ΠΎΠΏΡ†ΠΈΠΈ ΠΈΠ»ΠΈ Π΄Π° Π½Π°ΠΏΠΈΡˆΠ΅Ρ‚Π΅ свои Π·Π° ΠΊΠΎΠ½ΠΊΡ€Π΅Ρ‚Π½ΠΈ Π·Π°Π΄Π°Ρ‡ΠΈ. Π’ΠΎ R ΠΌΠΎΠΆΠ΅ΠΌΠ΅ Π΄Π° Π³ΠΈ искористимС ситС карактСристики Π½Π° Π±ΠΈΠ±Π»ΠΈΠΎΡ‚Π΅ΠΊΠ°Ρ‚Π° Π½Π° Python кСрас со Π½Π΅Π³ΠΎΠ²ΠΈΡ‚Π΅ Ρ€Π°Π·Π»ΠΈΡ‡Π½ΠΈ Π·Π°Π΄Π½ΠΈ Π΄Π΅Π»ΠΎΠ²ΠΈ ΠΊΠΎΡ€ΠΈΡΡ‚Π΅Ρ˜ΡœΠΈ Π³ΠΎ истоимСниот ΠΏΠ°ΠΊΠ΅Ρ‚, кој ΠΏΠ°ΠΊ Ρ€Π°Π±ΠΎΡ‚ΠΈ Π½Π° Π²Ρ€Π²ΠΎΡ‚ Π½Π° ΠΏΠ°ΠΊΠ΅Ρ‚ΠΎΡ‚ мрСТСсти. Π’Ρ‚ΠΎΡ€ΠΈΠΎΡ‚ заслуТува посСбна Π΄ΠΎΠ»Π³Π° ΡΡ‚Π°Ρ‚ΠΈΡ˜Π°; Π½Π΅ само ΡˆΡ‚ΠΎ Π²ΠΈ ΠΎΠ²ΠΎΠ·ΠΌΠΎΠΆΡƒΠ²Π° Π΄Π° ΠΈΠ·Π²Ρ€ΡˆΠΈΡ‚Π΅ Python ΠΊΠΎΠ΄ ΠΎΠ΄ R, Ρ‚ΡƒΠΊΡƒ исто Ρ‚Π°ΠΊΠ° Π²ΠΈ ΠΎΠ²ΠΎΠ·ΠΌΠΎΠΆΡƒΠ²Π° Π΄Π° прСнСсуватС ΠΎΠ±Ρ˜Π΅ΠΊΡ‚ΠΈ ΠΏΠΎΠΌΠ΅Ρ“Ρƒ R ΠΈ Python сСсии, автоматски ΠΈΠ·Π²Ρ€ΡˆΡƒΠ²Π°Ρ˜ΡœΠΈ Π³ΠΈ ситС ΠΏΠΎΡ‚Ρ€Π΅Π±Π½ΠΈ ΠΊΠΎΠ½Π²Π΅Ρ€Π·ΠΈΠΈ Π½Π° Ρ‚ΠΈΠΏΠΎΠ²ΠΈ.

Π‘Π΅ ослободивмС ΠΎΠ΄ ΠΏΠΎΡ‚Ρ€Π΅Π±Π°Ρ‚Π° Π΄Π° Π³ΠΈ складирамС ситС ΠΏΠΎΠ΄Π°Ρ‚ΠΎΡ†ΠΈ Π²ΠΎ RAM ΠΌΠ΅ΠΌΠΎΡ€ΠΈΡ˜Π°Ρ‚Π° со помош Π½Π° MonetDBLite, Ρ†Π΅Π»Π°Ρ‚Π° Ρ€Π°Π±ΠΎΡ‚Π° Π½Π° β€žΠ½Π΅Π²Ρ€ΠΎΠ½ΡΠΊΠ°Ρ‚Π° ΠΌΡ€Π΅ΠΆΠ°β€œ ќС ја Π²Ρ€ΡˆΠΈ ΠΎΡ€ΠΈΠ³ΠΈΠ½Π°Π»Π½ΠΈΠΎΡ‚ ΠΊΠΎΠ΄ Π²ΠΎ Python, само Ρ‚Ρ€Π΅Π±Π° Π΄Π° напишСмС ΠΈΡ‚Π΅Ρ€Π°Ρ‚ΠΎΡ€ Π½Π°Π΄ ΠΏΠΎΠ΄Π°Ρ‚ΠΎΡ†ΠΈΡ‚Π΅, бидСјќи Π½Π΅ΠΌΠ° Π½ΠΈΡˆΡ‚ΠΎ ΠΏΠΎΠ΄Π³ΠΎΡ‚Π²Π΅Π½ΠΎ Π·Π° Ρ‚Π°ΠΊΠ²Π° ΡΠΈΡ‚ΡƒΠ°Ρ†ΠΈΡ˜Π° ΠΈΠ»ΠΈ Π²ΠΎ R ΠΈΠ»ΠΈ Π²ΠΎ Python. Π’ΠΎ ΡΡƒΡˆΡ‚ΠΈΠ½Π° ΠΈΠΌΠ° само Π΄Π²Π΅ Π±Π°Ρ€Π°ΡšΠ° Π·Π° Π½Π΅Π³ΠΎ: ΠΌΠΎΡ€Π° Π΄Π° Π³ΠΈ Π²Ρ€Π°Ρ‚ΠΈ сСриитС Π²ΠΎ Π±Π΅ΡΠΊΡ€Π°Ρ˜Π½Π° јамка ΠΈ Π΄Π° ја Π·Π°Ρ‡ΡƒΠ²Π° ΡΠ²ΠΎΡ˜Π°Ρ‚Π° ΡΠΎΡΡ‚ΠΎΡ˜Π±Π° ΠΏΠΎΠΌΠ΅Ρ“Ρƒ ΠΏΠΎΠ²Ρ‚ΠΎΡ€ΡƒΠ²Π°ΡšΠ°Ρ‚Π° (Π²Ρ‚ΠΎΡ€ΠΎΡ‚ΠΎ Π²ΠΎ R сС ΠΈΠΌΠΏΠ»Π΅ΠΌΠ΅Π½Ρ‚ΠΈΡ€Π° Π½Π° Π½Π°Ρ˜Π΅Π΄Π½ΠΎΡΡ‚Π°Π²Π΅Π½ Π½Π°Ρ‡ΠΈΠ½ ΠΊΠΎΡ€ΠΈΡΡ‚Π΅Ρ˜ΡœΠΈ Π·Π°Ρ‚Π²ΠΎΡ€Π°Ρ‡ΠΈ). ΠŸΡ€Π΅Ρ‚Ρ…ΠΎΠ΄Π½ΠΎ, бСшС ΠΏΠΎΡ‚Ρ€Π΅Π±Π½ΠΎ Сксплицитно Π΄Π° сС ΠΊΠΎΠ½Π²Π΅Ρ€Ρ‚ΠΈΡ€Π°Π°Ρ‚ R-Π½ΠΈΠ·ΠΈΡ‚Π΅ Π²ΠΎ numpy Π½ΠΈΠ·ΠΈ Π²Π½Π°Ρ‚Ρ€Π΅ Π²ΠΎ ΠΈΡ‚Π΅Ρ€Π°Ρ‚ΠΎΡ€ΠΎΡ‚, Π½ΠΎ Ρ‚Π΅ΠΊΠΎΠ²Π½Π°Ρ‚Π° Π²Π΅Ρ€Π·ΠΈΡ˜Π° Π½Π° ΠΏΠ°ΠΊΠ΅Ρ‚ΠΎΡ‚ кСрас Π³ΠΎ ΠΏΡ€Π°Π²ΠΈ Ρ‚ΠΎΠ° сама.

Π˜Ρ‚Π΅Ρ€Π°Ρ‚ΠΎΡ€ΠΎΡ‚ Π·Π° ΠΏΠΎΠ΄Π°Ρ‚ΠΎΡ†ΠΈ Π·Π° ΠΎΠ±ΡƒΠΊΠ° ΠΈ Π²Π°Π»ΠΈΠ΄Π°Ρ†ΠΈΡ˜Π° сС ΠΏΠΎΠΊΠ°ΠΆΠ° ΠΊΠ°ΠΊΠΎ ΡˆΡ‚ΠΎ слСдува:

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

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 ΠΎΠ΄Π³ΠΎΠ²Π°Ρ€Π° Π½Π° ΠΏΡ€ΠΈΠΊΠ°ΠΆΡƒΠ²Π°ΡšΠ΅ слики ΠΎΠ΄ 256x256 пиксСли, scale = 0.5 β€” 128x128 пиксСли), ΠΈΠ½Π΄ΠΈΠΊΠ°Ρ‚ΠΎΡ€ Π·Π° боја (color = FALSE ΠΎΠ΄Ρ€Π΅Π΄ΡƒΠ²Π° Ρ€Π΅Π½Π΄Π΅Ρ€ΠΈΡ€Π°ΡšΠ΅ Π²ΠΎ сиви Ρ‚ΠΎΠ½ΠΎΠ²ΠΈ ΠΊΠΎΠ³Π° сС користи color = TRUE сСкој ΠΏΠΎΡ‚Π΅Π³ Π΅ Π½Π°Ρ†Ρ€Ρ‚Π°Π½ Π²ΠΎ Π½ΠΎΠ²Π° боја) ΠΈ ΠΈΠ½Π΄ΠΈΠΊΠ°Ρ‚ΠΎΡ€ Π·Π° ΠΏΡ€Π΅Ρ‚ΠΏΡ€ΠΎΡ†Π΅ΡΠΈΡ€Π°ΡšΠ΅ Π·Π° ΠΌΡ€Π΅ΠΆΠΈ ΠΏΡ€Π΅Ρ‚Ρ…ΠΎΠ΄Π½ΠΎ ΠΎΠ±ΡƒΡ‡Π΅Π½ΠΈ Π½Π° imagenet. ПослСдново Π΅ ΠΏΠΎΡ‚Ρ€Π΅Π±Π½ΠΎ Π·Π° Π΄Π° сС Π½Π°ΠΌΠ°Π»Π°Ρ‚ врСдноститС Π½Π° пиксСлитС ΠΎΠ΄ ΠΈΠ½Ρ‚Π΅Ρ€Π²Π°Π»ΠΎΡ‚ [0, 1] Π΄ΠΎ ΠΈΠ½Ρ‚Π΅Ρ€Π²Π°Π»ΠΎΡ‚ [-1, 1], ΡˆΡ‚ΠΎ сС ΠΊΠΎΡ€ΠΈΡΡ‚Π΅ΡˆΠ΅ ΠΏΡ€ΠΈ ΠΎΠ±ΡƒΠΊΠ° Π½Π° испорачанитС кСрас ΠΌΠΎΠ΄Π΅Π»ΠΈ.

ΠΠ°Π΄Π²ΠΎΡ€Π΅ΡˆΠ½Π°Ρ‚Π° Ρ„ΡƒΠ½ΠΊΡ†ΠΈΡ˜Π° содрТи ΠΏΡ€ΠΎΠ²Π΅Ρ€ΠΊΠ° Π½Π° Ρ‚ΠΈΠΏΠΎΡ‚ Π½Π° Π°Ρ€Π³ΡƒΠΌΠ΅Π½Ρ‚ΠΈ, Ρ‚Π°Π±Π΅Π»Π° data.table со ΡΠ»ΡƒΡ‡Π°Ρ˜Π½ΠΎ измСшани Π»ΠΈΠ½ΠΈΠΈ ΠΎΠ΄ samples_index ΠΈ Π±Ρ€ΠΎΠ΅Π²ΠΈ Π½Π° сСрии, Π±Ρ€ΠΎΡ˜Π°Ρ‡ ΠΈ максималСн Π±Ρ€ΠΎΡ˜ Π½Π° сСрии, ΠΊΠ°ΠΊΠΎ ΠΈ SQL ΠΈΠ·Ρ€Π°Π· Π·Π° истовар Π½Π° ΠΏΠΎΠ΄Π°Ρ‚ΠΎΡ†ΠΈ ΠΎΠ΄ Π±Π°Π·Π°Ρ‚Π° Π½Π° ΠΏΠΎΠ΄Π°Ρ‚ΠΎΡ†ΠΈ. Π”ΠΎΠΏΠΎΠ»Π½ΠΈΡ‚Π΅Π»Π½ΠΎ, Π΄Π΅Ρ„ΠΈΠ½ΠΈΡ€Π°Π²ΠΌΠ΅ Π±Ρ€Π· Π°Π½Π°Π»ΠΎΠ³ Π½Π° Ρ„ΡƒΠ½ΠΊΡ†ΠΈΡ˜Π°Ρ‚Π° Π²Π½Π°Ρ‚Ρ€Π΅ keras::to_categorical(). Π“ΠΈ искористивмС скоро ситС ΠΏΠΎΠ΄Π°Ρ‚ΠΎΡ†ΠΈ Π·Π° ΠΎΠ±ΡƒΠΊΠ°, ΠΎΡΡ‚Π°Π²Π°Ρ˜ΡœΠΈ ΠΏΠΎΠ»ΠΎΠ²ΠΈΠ½Π° ΠΏΡ€ΠΎΡ†Π΅Π½Ρ‚ Π·Π° Π²Π°Π»ΠΈΠ΄Π°Ρ†ΠΈΡ˜Π°, Ρ‚Π°ΠΊΠ° ΡˆΡ‚ΠΎ Π³ΠΎΠ»Π΅ΠΌΠΈΠ½Π°Ρ‚Π° Π½Π° Π΅ΠΏΠΎΡ…Π°Ρ‚Π° бСшС ΠΎΠ³Ρ€Π°Π½ΠΈΡ‡Π΅Π½Π° со ΠΏΠ°Ρ€Π°ΠΌΠ΅Ρ‚Π°Ρ€ΠΎΡ‚ steps_per_epoch ΠΊΠΎΠ³Π° ќС сС ΠΏΠΎΠ²ΠΈΠΊΠ°Π°Ρ‚ keras::fit_generator(), ΠΈ ΡΠΎΡΡ‚ΠΎΡ˜Π±Π°Ρ‚Π° if (i > max_i) Ρ€Π°Π±ΠΎΡ‚Π΅ΡˆΠ΅ само Π·Π° ΠΈΡ‚Π΅Ρ€Π°Ρ‚ΠΎΡ€ Π·Π° Π²Π°Π»ΠΈΠ΄Π°Ρ†ΠΈΡ˜Π°.

Π’ΠΎ Π²Π½Π°Ρ‚Ρ€Π΅ΡˆΠ½Π°Ρ‚Π° Ρ„ΡƒΠ½ΠΊΡ†ΠΈΡ˜Π°, индСкситС Π½Π° Ρ€Π΅Π΄ΠΎΠ²ΠΈ сС ΠΏΡ€Π΅Π·Π΅ΠΌΠ°Π°Ρ‚ Π·Π° слСдната ΡΠ΅Ρ€ΠΈΡ˜Π°, записитС сС истоваруваат ΠΎΠ΄ Π±Π°Π·Π°Ρ‚Π° Π½Π° ΠΏΠΎΠ΄Π°Ρ‚ΠΎΡ†ΠΈ со Π·Π³ΠΎΠ»Π΅ΠΌΡƒΠ²Π°ΡšΠ΅ Π½Π° Π±Ρ€ΠΎΡ˜Π°Ρ‡ΠΎΡ‚ Π½Π° ΡΠ΅Ρ€ΠΈΡ˜Π°, ΠΏΠ°Ρ€ΡΠΈΡ€Π°ΡšΠ΅ JSON (Ρ„ΡƒΠ½ΠΊΡ†ΠΈΡ˜Π° cpp_process_json_vector(), напишано Π²ΠΎ C++) ΠΈ создавањС Π½ΠΈΠ·ΠΈ ΡˆΡ‚ΠΎ ΠΎΠ΄Π³ΠΎΠ²Π°Ρ€Π°Π°Ρ‚ Π½Π° слики. ΠŸΠΎΡ‚ΠΎΠ° сС создаваат Π΅Π΄Π½ΠΎ-ТСшки Π²Π΅ΠΊΡ‚ΠΎΡ€ΠΈ со ΠΎΠ·Π½Π°ΠΊΠΈ Π·Π° класи, Π½ΠΈΠ·ΠΈ со врСдности Π½Π° пиксСли ΠΈ Π΅Ρ‚ΠΈΠΊΠ΅Ρ‚ΠΈ сС ΠΊΠΎΠΌΠ±ΠΈΠ½ΠΈΡ€Π°Π°Ρ‚ Π²ΠΎ листа, ΡˆΡ‚ΠΎ Π΅ ΠΏΠΎΠ²Ρ€Π°Ρ‚Π½Π°Ρ‚Π° врСдност. Π—Π° Π΄Π° ја Π·Π°Π±Ρ€Π·Π°ΠΌΠ΅ Ρ€Π°Π±ΠΎΡ‚Π°Ρ‚Π°, користСвмС создавањС Π½Π° индСкси Π²ΠΎ Ρ‚Π°Π±Π΅Π»ΠΈ data.table ΠΈ ΠΌΠΎΠ΄ΠΈΡ„ΠΈΠΊΠ°Ρ†ΠΈΡ˜Π° ΠΏΡ€Π΅ΠΊΡƒ врската - Π±Π΅Π· ΠΎΠ²ΠΈΠ΅ ΠΏΠ°ΠΊΠ΅Ρ‚ΠΈ β€žΡ‡ΠΈΠΏΠΎΠ²ΠΈβ€œ ΠΏΠΎΠ΄Π°Ρ‚ΠΎΡ†ΠΈ. Ρ‚Π°Π±Π΅Π»Π° ΠŸΡ€ΠΈΠ»ΠΈΡ‡Π½ΠΎ Π΅ Ρ‚Π΅ΡˆΠΊΠΎ Π΄Π° сС замисли Π΄Π° сС Ρ€Π°Π±ΠΎΡ‚ΠΈ Π΅Ρ„Π΅ΠΊΡ‚ΠΈΠ²Π½ΠΎ со која Π±ΠΈΠ»ΠΎ Π·Π½Π°Ρ‡ΠΈΡ‚Π΅Π»Π½Π° ΠΊΠΎΠ»ΠΈΡ‡ΠΈΠ½Π° Π½Π° ΠΏΠΎΠ΄Π°Ρ‚ΠΎΡ†ΠΈ Π²ΠΎ Π .

Π Π΅Π·ΡƒΠ»Ρ‚Π°Ρ‚ΠΈΡ‚Π΅ ΠΎΠ΄ ΠΌΠ΅Ρ€Π΅ΡšΠ΅Ρ‚ΠΎ Π½Π° Π±Ρ€Π·ΠΈΠ½Π°Ρ‚Π° Π½Π° Π»Π°ΠΏΡ‚ΠΎΠΏΠΎΡ‚ Core i5 сС ΠΊΠ°ΠΊΠΎ ΡˆΡ‚ΠΎ слСдува:

Π˜Ρ‚Π΅Ρ€Π°Ρ‚ΠΎΡ€ Ρ€Π΅ΠΏΠ΅Ρ€

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)

Quick Draw Doodle Recognition: ΠΊΠ°ΠΊΠΎ Π΄Π° сС Π΄Ρ€ΡƒΠΆΠΈΡ‚Π΅ со R, C++ ΠΈ нСвронскитС ΠΌΡ€Π΅ΠΆΠΈ

Ако ΠΈΠΌΠ°Ρ‚Π΅ Π΄ΠΎΠ²ΠΎΠ»Π½ΠΎ количСство RAM ΠΌΠ΅ΠΌΠΎΡ€ΠΈΡ˜Π°, ΠΌΠΎΠΆΠ΅Ρ‚Π΅ сСриозно Π΄Π° ја Π·Π°Π±Ρ€Π·Π°Ρ‚Π΅ Ρ€Π°Π±ΠΎΡ‚Π°Ρ‚Π° Π½Π° Π±Π°Π·Π°Ρ‚Π° со ΠΏΡ€Π΅Ρ„Ρ€Π»Π°ΡšΠ΅ Π½Π° истата RAM ΠΌΠ΅ΠΌΠΎΡ€ΠΈΡ˜Π° (32 GB сС Π΄ΠΎΠ²ΠΎΠ»Π½ΠΈ Π·Π° Π½Π°ΡˆΠ°Ρ‚Π° Π·Π°Π΄Π°Ρ‡Π°). Π’ΠΎ Linux, ΠΏΠ°Ρ€Ρ‚ΠΈΡ†ΠΈΡ˜Π°Ρ‚Π° Π΅ стандардно ΠΌΠΎΠ½Ρ‚ΠΈΡ€Π°Π½Π° /dev/shm, Π·Π°Ρ„Π°ΡœΠ°Ρ˜ΡœΠΈ Π΄ΠΎ ΠΏΠΎΠ»ΠΎΠ²ΠΈΠ½Π° ΠΎΠ΄ ΠΊΠ°ΠΏΠ°Ρ†ΠΈΡ‚Π΅Ρ‚ΠΎΡ‚ Π½Π° RAM ΠΌΠ΅ΠΌΠΎΡ€ΠΈΡ˜Π°Ρ‚Π°. ΠœΠΎΠΆΠ΅Ρ‚Π΅ Π΄Π° истакнСтС повСќС со ΡƒΡ€Π΅Π΄ΡƒΠ²Π°ΡšΠ΅ /etc/fstabΠ΄Π° сС Π΄ΠΎΠ±ΠΈΠ΅ Ρ€Π΅ΠΊΠΎΡ€Π΄ ΠΊΠ°ΠΊΠΎ tmpfs /dev/shm tmpfs defaults,size=25g 0 0. Π‘ΠΈΠ΄Π΅Ρ‚Π΅ сигурни Π΄Π° сС рСстартиратС ΠΈ ΠΏΡ€ΠΎΠ²Π΅Ρ€Π΅Ρ‚Π΅ Π³ΠΎ Ρ€Π΅Π·ΡƒΠ»Ρ‚Π°Ρ‚ΠΎΡ‚ со ΠΈΠ·Π²Ρ€ΡˆΡƒΠ²Π°ΡšΠ΅ Π½Π° ΠΊΠΎΠΌΠ°Π½Π΄Π°Ρ‚Π° df -h.

Π˜Ρ‚Π΅Ρ€Π°Ρ‚ΠΎΡ€ΠΎΡ‚ Π·Π° тСст-ΠΏΠΎΠ΄Π°Ρ‚ΠΎΡ†ΠΈ ΠΈΠ·Π³Π»Π΅Π΄Π° ΠΌΠ½ΠΎΠ³Ρƒ поСдноставСн, бидСјќи сСтот Π·Π° Ρ‚Π΅ΡΡ‚ΠΈΡ€Π°ΡšΠ΅ цСлосно сС Π²ΠΊΠ»ΠΎΠΏΡƒΠ²Π° Π²ΠΎ RAM-ΠΎΡ‚:

Π˜Ρ‚Π΅Ρ€Π°Ρ‚ΠΎΡ€ Π·Π° тСст ΠΏΠΎΠ΄Π°Ρ‚ΠΎΡ†ΠΈ

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. Π˜Π·Π±ΠΎΡ€ Π½Π° ΠΌΠΎΠ΄Π΅Π» Π°Ρ€Ρ…ΠΈΡ‚Π΅ΠΊΡ‚ΡƒΡ€Π°

ΠŸΡ€Π²Π°Ρ‚Π° користСна Π°Ρ€Ρ…ΠΈΡ‚Π΅ΠΊΡ‚ΡƒΡ€Π° Π±ΠΈΠ»Π° mobilenet v1, Ρ‡ΠΈΠΈ карактСристики сС дискутирани Π²ΠΎ ΠΎΠ²Π° ΠΏΠΎΡ€Π°ΠΊΠ°. Π‘Ρ‚Π°Π½Π΄Π°Ρ€Π΄Π½ΠΎ Π΅ Π²ΠΊΠ»ΡƒΡ‡Π΅Π½ΠΎ кСрас ΠΈ, соодвСтно, Π΅ достапСн Π²ΠΎ истоимСниот ΠΏΠ°ΠΊΠ΅Ρ‚ Π·Π° R. Но, ΠΊΠΎΠ³Π° сС ΠΎΠ±ΠΈΠ΄ΡƒΠ²Π°Ρ‚Π΅ Π΄Π° Π³ΠΎ користитС со Π΅Π΄Π½ΠΎΠΊΠ°Π½Π°Π»Π½ΠΈ слики, сС ΠΏΠΎΠΊΠ°ΠΆΠ° Ρ‡ΡƒΠ΄Π½Π° Ρ€Π°Π±ΠΎΡ‚Π°: Π²Π»Π΅Π·Π½ΠΈΠΎΡ‚ Ρ‚Π΅Π½Π·ΠΎΡ€ сСкогаш ΠΌΠΎΡ€Π° Π΄Π° ја ΠΈΠΌΠ° Π΄ΠΈΠΌΠ΅Π½Π·ΠΈΡ˜Π°Ρ‚Π° (batch, height, width, 3), односно Π±Ρ€ΠΎΡ˜ΠΎΡ‚ Π½Π° ΠΊΠ°Π½Π°Π»ΠΈ Π½Π΅ ΠΌΠΎΠΆΠ΅ Π΄Π° сС ΠΏΡ€ΠΎΠΌΠ΅Π½ΠΈ. НСма Ρ‚Π°ΠΊΠ²ΠΎ ΠΎΠ³Ρ€Π°Π½ΠΈΡ‡ΡƒΠ²Π°ΡšΠ΅ Π²ΠΎ Python, ΠΏΠ° Π·Π°Ρ‚ΠΎΠ° ΠΏΠΎΠ±Ρ€Π·Π°Π²ΠΌΠ΅ ΠΈ напишавмС сопствСна ΠΈΠΌΠΏΠ»Π΅ΠΌΠ΅Π½Ρ‚Π°Ρ†ΠΈΡ˜Π° Π½Π° ΠΎΠ²Π°Π° Π°Ρ€Ρ…ΠΈΡ‚Π΅ΠΊΡ‚ΡƒΡ€Π°, слСдСјќи ја ΠΎΡ€ΠΈΠ³ΠΈΠ½Π°Π»Π½Π°Ρ‚Π° ΡΡ‚Π°Ρ‚ΠΈΡ˜Π° (Π±Π΅Π· ΠΎΡ‚ΠΏΠΈΡˆΡƒΠ²Π°ΡšΠ΅Ρ‚ΠΎ ΡˆΡ‚ΠΎ Π΅ Π²ΠΎ Π²Π΅Ρ€Π·ΠΈΡ˜Π°Ρ‚Π° keras):

АрхитСктура Π½Π° Mobilenet v1

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)
}

НСдостатоцитС Π½Π° овој пристап сС ΠΎΡ‡ΠΈΠ³Π»Π΅Π΄Π½ΠΈ. Π‘Π°ΠΊΠ°ΠΌ Π΄Π° тСстирам ΠΌΠ½ΠΎΠ³Ρƒ ΠΌΠΎΠ΄Π΅Π»ΠΈ, Π½ΠΎ Π½Π°ΠΏΡ€ΠΎΡ‚ΠΈΠ², Π½Π΅ сакам Π΄Π° ја ΠΏΡ€Π΅ΠΏΠΈΡˆΡƒΠ²Π°ΠΌ сСкоја Π°Ρ€Ρ…ΠΈΡ‚Π΅ΠΊΡ‚ΡƒΡ€Π° Ρ€Π°Ρ‡Π½ΠΎ. Π‘Π΅Π²ΠΌΠ΅ лишСни ΠΎΠ΄ моТноста Π΄Π° Π³ΠΈ користимС Ρ‚Π΅ΠΆΠΈΠ½ΠΈΡ‚Π΅ Π½Π° ΠΌΠΎΠ΄Π΅Π»ΠΈΡ‚Π΅ ΠΏΡ€Π΅Ρ‚Ρ…ΠΎΠ΄Π½ΠΎ ΠΎΠ±ΡƒΡ‡Π΅Π½ΠΈ Π½Π° imagenet. Како ΠΈ ΠΎΠ±ΠΈΡ‡Π½ΠΎ, ΠΏΡ€ΠΎΡƒΡ‡ΡƒΠ²Π°ΡšΠ΅Ρ‚ΠΎ Π½Π° Π΄ΠΎΠΊΡƒΠΌΠ΅Π½Ρ‚Π°Ρ†ΠΈΡ˜Π°Ρ‚Π° ΠΏΠΎΠΌΠΎΠ³Π½Π°. Π€ΡƒΠ½ΠΊΡ†ΠΈΡ˜Π° get_config() Π²ΠΈ ΠΎΠ²ΠΎΠ·ΠΌΠΎΠΆΡƒΠ²Π° Π΄Π° Π΄ΠΎΠ±ΠΈΠ΅Ρ‚Π΅ опис Π½Π° ΠΌΠΎΠ΄Π΅Π»ΠΎΡ‚ Π²ΠΎ Ρ„ΠΎΡ€ΠΌΠ° ΠΏΠΎΠ³ΠΎΠ΄Π½Π° Π·Π° ΡƒΡ€Π΅Π΄ΡƒΠ²Π°ΡšΠ΅ (base_model_conf$layers - Ρ€Π΅Π΄ΠΎΠ²Π½Π° листа R), ΠΈ Ρ„ΡƒΠ½ΠΊΡ†ΠΈΡ˜Π°Ρ‚Π° 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)

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

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

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() Π·Π΅ΠΌΠ΅Ρ‚Π΅ Π³ΠΈ Ρ‚Π΅ΠΆΠΈΠ½ΠΈΡ‚Π΅ Π½Π° ΠΌΠΎΠ΄Π΅Π»ΠΎΡ‚ Π²ΠΎ Ρ„ΠΎΡ€ΠΌΠ° Π½Π° листа Π½Π° R Π½ΠΈΠ·ΠΈ, ΠΏΡ€ΠΎΠΌΠ΅Π½Π΅Ρ‚Π΅ ја Π΄ΠΈΠΌΠ΅Π½Π·ΠΈΡ˜Π°Ρ‚Π° Π½Π° ΠΏΡ€Π²ΠΈΠΎΡ‚ Π΅Π»Π΅ΠΌΠ΅Π½Ρ‚ ΠΎΠ΄ ΠΎΠ²Π°Π° листа (со ΠΏΡ€Π΅Π·Π΅ΠΌΠ°ΡšΠ΅ Π½Π° Π΅Π΄Π΅Π½ ΠΊΠ°Π½Π°Π» Π²ΠΎ боја ΠΈΠ»ΠΈ просСк Π½Π° ситС Ρ‚Ρ€ΠΈ), Π° ΠΏΠΎΡ‚ΠΎΠ° Π²Ρ‡ΠΈΡ‚Π°Ρ˜Ρ‚Π΅ Π³ΠΈ Ρ‚Π΅ΠΆΠΈΠ½ΠΈΡ‚Π΅ Π½Π°Π·Π°Π΄ Π²ΠΎ ΠΌΠΎΠ΄Π΅Π»ΠΎΡ‚ со Ρ„ΡƒΠ½ΠΊΡ†ΠΈΡ˜Π°Ρ‚Π° set_weights(). Никогаш Π½Π΅ ја Π΄ΠΎΠ΄Π°Π΄ΠΎΠ²ΠΌΠ΅ ΠΎΠ²Π°Π° функционалност, бидСјќи Π²ΠΎ ΠΎΠ²Π°Π° Ρ„Π°Π·Π° вСќС бСшС јасно Π΄Π΅ΠΊΠ° Π΅ ΠΏΠΎΠΏΡ€ΠΎΠ΄ΡƒΠΊΡ‚ΠΈΠ²Π½ΠΎ Π΄Π° сС Ρ€Π°Π±ΠΎΡ‚ΠΈ со слики Π²ΠΎ боја.

НиС Π³ΠΈ спровСдовмС ΠΏΠΎΠ²Π΅ΡœΠ΅Ρ‚ΠΎ СкспСримСнти ΠΊΠΎΡ€ΠΈΡΡ‚Π΅Ρ˜ΡœΠΈ Π³ΠΈ ΠΌΠΎΠ±ΠΈΠ»Π½ΠΈΡ‚Π΅ Π²Π΅Ρ€Π·ΠΈΠΈ 1 ΠΈ 2, ΠΊΠ°ΠΊΠΎ ΠΈ resnet34. ΠŸΠΎΠΌΠΎΠ΄Π΅Ρ€Π½ΠΈΡ‚Π΅ Π°Ρ€Ρ…ΠΈΡ‚Π΅ΠΊΡ‚ΡƒΡ€ΠΈ ΠΊΠ°ΠΊΠΎ SE-ResNeXt сС ΠΏΡ€Π΅Ρ‚ΡΡ‚Π°Π²ΠΈΡ˜Π° Π΄ΠΎΠ±Ρ€ΠΎ Π½Π° овој Π½Π°Ρ‚ΠΏΡ€Π΅Π²Π°Ρ€. Π—Π° ΠΆΠ°Π», Π½Π΅ΠΌΠ°Π²ΠΌΠ΅ Π³ΠΎΡ‚ΠΎΠ²ΠΈ ΠΈΠΌΠΏΠ»Π΅ΠΌΠ΅Π½Ρ‚Π°Ρ†ΠΈΠΈ Π½Π° Ρ€Π°ΡΠΏΠΎΠ»Π°Π³Π°ΡšΠ΅, Π° Π½Π΅ напишавмС наши (Π½ΠΎ Π΄Π΅Ρ„ΠΈΠ½ΠΈΡ‚ΠΈΠ²Π½ΠΎ ќС ΠΏΠΈΡˆΡƒΠ²Π°ΠΌΠ΅).

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/ Π·Π° R. Π‘ΠΎ Π½Π΅Π³ΠΎΠ²Π° помош сС лансираат скрипти со Сдноставни ΠΊΠΎΠΌΠ°Π½Π΄ΠΈ ΠΊΠ°ΠΊΠΎ 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 Π½Π° слики со Ρ‚Ρ€ΠΈ Π±ΠΎΠΈ со Π΄ΠΈΠΌΠ΅Π½Π·ΠΈΠΈ 128x128 пиксСли, Π±Π°Π·Π°Ρ‚Π° Π½Π° ΠΏΠΎΠ΄Π°Ρ‚ΠΎΡ†ΠΈ ΠΌΠΎΡ€Π° Π΄Π° сС Π½Π°ΠΎΡ“Π° Π²ΠΎ ΠΏΠ°ΠΏΠΊΠ°Ρ‚Π° /home/andrey/doodle_db). ΠœΠΎΠΆΠ΅Ρ‚Π΅ Π΄Π° Π΄ΠΎΠ΄Π°Π΄Π΅Ρ‚Π΅ Π±Ρ€Π·ΠΈΠ½Π° Π½Π° ΡƒΡ‡Π΅ΡšΠ΅, Ρ‚ΠΈΠΏ Π½Π° ΠΎΠΏΡ‚ΠΈΠΌΠΈΠ·Π°Ρ‚ΠΎΡ€ ΠΈ ΠΊΠ°ΠΊΠ²ΠΈ Π±ΠΈΠ»ΠΎ Π΄Ρ€ΡƒΠ³ΠΈ приспособливи ΠΏΠ°Ρ€Π°ΠΌΠ΅Ρ‚Ρ€ΠΈ Π½Π° списокот. Π’ΠΎ процСсот Π½Π° ΠΏΠΎΠ΄Π³ΠΎΡ‚ΠΎΠ²ΠΊΠ° Π½Π° ΠΏΡƒΠ±Π»ΠΈΠΊΠ°Ρ†ΠΈΡ˜Π°Ρ‚Π°, сС ΠΏΠΎΠΊΠ°ΠΆΠ° Π΄Π΅ΠΊΠ° Π°Ρ€Ρ…ΠΈΡ‚Π΅ΠΊΡ‚ΡƒΡ€Π°Ρ‚Π° mobilenet_v2 ΠΎΠ΄ Ρ‚Π΅ΠΊΠΎΠ²Π½Π°Ρ‚Π° Π²Π΅Ρ€Π·ΠΈΡ˜Π° кСрас Π²ΠΎ Π  ΡƒΠΏΠΎΡ‚Ρ€Π΅Π±Π° Π½Π΅ ΠΌΠΎΡ€Π° Π΄Π° ΠΏΠΎΡ€Π°Π΄ΠΈ ΠΏΡ€ΠΎΠΌΠ΅Π½ΠΈΡ‚Π΅ ΠΊΠΎΠΈ Π½Π΅ сС Π·Π΅ΠΌΠ΅Π½ΠΈ ΠΏΡ€Π΅Π΄Π²ΠΈΠ΄ Π²ΠΎ ΠΏΠ°ΠΊΠ΅Ρ‚ΠΎΡ‚ R, Ρ‡Π΅ΠΊΠ°ΠΌΠ΅ Π΄Π° Π³ΠΎ ΠΏΠΎΠΏΡ€Π°Π²Π°Ρ‚.

Овој пристап ΠΎΠ²ΠΎΠ·ΠΌΠΎΠΆΠΈ Π·Π½Π°Ρ‡ΠΈΡ‚Π΅Π»Π½ΠΎ Π΄Π° сС Π·Π°Π±Ρ€Π·Π°Π°Ρ‚ СкспСримСнтитС со Ρ€Π°Π·Π»ΠΈΡ‡Π½ΠΈ ΠΌΠΎΠ΄Π΅Π»ΠΈ Π²ΠΎ спорСдба со ΠΏΠΎΡ‚Ρ€Π°Π΄ΠΈΡ†ΠΈΠΎΠ½Π°Π»Π½ΠΎΡ‚ΠΎ Π»Π°Π½ΡΠΈΡ€Π°ΡšΠ΅ Π½Π° скрипти Π²ΠΎ RStudio (Π³ΠΎ Π·Π°Π±Π΅Π»Π΅ΠΆΡƒΠ²Π°ΠΌΠ΅ ΠΏΠ°ΠΊΠ΅Ρ‚ΠΎΡ‚ ΠΊΠ°ΠΊΠΎ ΠΌΠΎΠΆΠ½Π° Π°Π»Ρ‚Π΅Ρ€Π½Π°Ρ‚ΠΈΠ²Π° тфрунс). Но, Π³Π»Π°Π²Π½Π°Ρ‚Π° прСдност Π΅ способноста лСсно Π΄Π° сС ΡƒΠΏΡ€Π°Π²ΡƒΠ²Π° со Π»Π°Π½ΡΠΈΡ€Π°ΡšΠ΅Ρ‚ΠΎ Π½Π° скрипти Π²ΠΎ Docker ΠΈΠ»ΠΈ Сдноставно Π½Π° сСрвСрот, Π±Π΅Π· Π΄Π° сС инсталира RStudio Π·Π° ΠΎΠ²Π°.

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

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

Docker Π²ΠΈ ΠΎΠ²ΠΎΠ·ΠΌΠΎΠΆΡƒΠ²Π° Π΄Π° ΠΊΡ€Π΅ΠΈΡ€Π°Ρ‚Π΅ свои слики ΠΎΠ΄ Π½ΡƒΠ»Π° ΠΈ Π΄Π° користитС Π΄Ρ€ΡƒΠ³ΠΈ слики ΠΊΠ°ΠΊΠΎ основа Π·Π° создавањС Π½Π° свои. Кога Π³ΠΈ Π°Π½Π°Π»ΠΈΠ·ΠΈΡ€Π°Π²ΠΌΠ΅ достапнитС ΠΎΠΏΡ†ΠΈΠΈ, дојдовмС Π΄ΠΎ Π·Π°ΠΊΠ»ΡƒΡ‡ΠΎΠΊ Π΄Π΅ΠΊΠ° ΠΈΠ½ΡΡ‚Π°Π»ΠΈΡ€Π°ΡšΠ΅Ρ‚ΠΎ Π½Π° NVIDIA, CUDA+cuDNN Π΄Ρ€Π°Ρ˜Π²Π΅Ρ€ΠΈΡ‚Π΅ ΠΈ Π±ΠΈΠ±Π»ΠΈΠΎΡ‚Π΅ΠΊΠΈΡ‚Π΅ Π½Π° Python Π΅ ΠΏΡ€ΠΈΠ»ΠΈΡ‡Π½ΠΎ ΠΎΠ±Π΅ΠΌΠ΅Π½ Π΄Π΅Π» ΠΎΠ΄ сликата ΠΈ Ρ€Π΅ΡˆΠΈΠ²ΠΌΠ΅ Π΄Π° ја Π·Π΅ΠΌΠ΅ΠΌΠ΅ ΠΎΡ„ΠΈΡ†ΠΈΡ˜Π°Π»Π½Π°Ρ‚Π° слика ΠΊΠ°ΠΊΠΎ основа tensorflow/tensorflow:1.12.0-gpu, додавајќи Π³ΠΈ ΠΏΠΎΡ‚Ρ€Π΅Π±Π½ΠΈΡ‚Π΅ R ΠΏΠ°ΠΊΠ΅Ρ‚ΠΈ Ρ‚Π°ΠΌΡƒ.

ΠšΠΎΠ½Π΅Ρ‡Π½Π°Ρ‚Π° Π΄ΠΎΠΊΠ΅Ρ€-Π΄Π°Ρ‚ΠΎΡ‚Π΅ΠΊΠ° изглСдашС Π²Π°ΠΊΠ°:

dockerfile

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 со стандардни врСдности; Π°ΠΊΠΎ ΠΏΡ€Π²ΠΈΠΎΡ‚ ΠΏΠΎΠ·ΠΈΡ†ΠΈΠΎΠ½Π΅Π½ Π°Ρ€Π³ΡƒΠΌΠ΅Π½Ρ‚ Π΅ β€žbashβ€œ, Ρ‚ΠΎΠ³Π°Ρˆ ΠΊΠΎΠ½Ρ‚Π΅Ρ˜Π½Π΅Ρ€ΠΎΡ‚ ќС Π·Π°ΠΏΠΎΡ‡Π½Π΅ ΠΈΠ½Ρ‚Π΅Ρ€Π°ΠΊΡ‚ΠΈΠ²Π½ΠΎ со ΠΊΠΎΠΌΠ°Π½Π΄Π½Π° школка. Π’ΠΎ ситС Π΄Ρ€ΡƒΠ³ΠΈ случаи, врСдноститС Π½Π° позицискитС Π°Ρ€Π³ΡƒΠΌΠ΅Π½Ρ‚ΠΈ сС Π·Π°ΠΌΠ΅Π½ΡƒΠ²Π°Π°Ρ‚: CMD="Rscript /app/train_nn.R $@".

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

7. ΠšΠΎΡ€ΠΈΡΡ‚Π΅ΡšΠ΅ Π½Π° повСќС Π³Ρ€Π°Ρ„ΠΈΡ‡ΠΊΠΈ процСсори Π½Π° Google Cloud

Π•Π΄Π½Π° ΠΎΠ΄ карактСристикитС Π½Π° Π½Π°Ρ‚ΠΏΡ€Π΅Π²Π°Ρ€ΠΎΡ‚ Π±Π΅Π° ΠΌΠ½ΠΎΠ³Ρƒ Π±ΡƒΡ‡Π½ΠΈΡ‚Π΅ ΠΏΠΎΠ΄Π°Ρ‚ΠΎΡ†ΠΈ (Π²ΠΈΠ΄Π΅Ρ‚Π΅ ја насловната слика, позајмСна ΠΎΠ΄ @Leigh.plt ΠΎΠ΄ ODS slack). Π“ΠΎΠ»Π΅ΠΌΠΈΡ‚Π΅ сСрии ΠΏΠΎΠΌΠ°Π³Π°Π°Ρ‚ Π²ΠΎ Π±ΠΎΡ€Π±Π°Ρ‚Π° ΠΏΡ€ΠΎΡ‚ΠΈΠ² ΠΎΠ²Π°, ΠΈ ΠΏΠΎ СкспСримСнтитС Π½Π° ΠΊΠΎΠΌΠΏΡ˜ΡƒΡ‚Π΅Ρ€ со 1 Π³Ρ€Π°Ρ„ΠΈΡ‡ΠΊΠΈ процСсор, Ρ€Π΅ΡˆΠΈΠ²ΠΌΠ΅ Π΄Π° Π³ΠΈ совладамС ΠΌΠΎΠ΄Π΅Π»ΠΈΡ‚Π΅ Π·Π° ΠΎΠ±ΡƒΠΊΠ° Π½Π° Π½Π΅ΠΊΠΎΠ»ΠΊΡƒ Π³Ρ€Π°Ρ„ΠΈΡ‡ΠΊΠΈ процСсори Π²ΠΎ ΠΎΠ±Π»Π°ΠΊΠΎΡ‚. ΠšΠΎΡ€ΠΈΡΡ‚Π΅Π² GoogleCloud (Π΄ΠΎΠ±Π°Ρ€ Π²ΠΎΠ΄ΠΈΡ‡ Π·Π° основитС) ΠΏΠΎΡ€Π°Π΄ΠΈ Π³ΠΎΠ»Π΅ΠΌΠΈΠΎΡ‚ ΠΈΠ·Π±ΠΎΡ€ Π½Π° достапни ΠΊΠΎΠ½Ρ„ΠΈΠ³ΡƒΡ€Π°Ρ†ΠΈΠΈ, Ρ€Π°Π·ΡƒΠΌΠ½ΠΈ Ρ†Π΅Π½ΠΈ ΠΈ бонус ΠΎΠ΄ 300 Π΄ΠΎΠ»Π°Ρ€ΠΈ. Од алчност, Π½Π°Ρ€Π°Ρ‡Π°Π² ΠΏΡ€ΠΈΠΌΠ΅Ρ€ΠΎΠΊ 4xV100 со SSD ΠΈ Π΅Π΄Π΅Π½ Ρ‚ΠΎΠ½ RAM ΠΈ Ρ‚ΠΎΠ° бСшС Π³ΠΎΠ»Π΅ΠΌΠ° Π³Ρ€Π΅ΡˆΠΊΠ°. Π’Π°ΠΊΠ²Π°Ρ‚Π° машина Π±Ρ€Π·ΠΎ Π³ΠΈ јадС ΠΏΠ°Ρ€ΠΈΡ‚Π΅; ΠΌΠΎΠΆΠ΅Ρ‚Π΅ Π΄Π° ΠΏΡ€ΠΎΠΏΠ°Π΄Π½Π΅Ρ‚Π΅ Π΄Π° СкспСримСнтиратС Π±Π΅Π· Π΄ΠΎΠΊΠ°ΠΆΠ°Π½ гасовод. Π—Π° Π΅Π΄ΡƒΠΊΠ°Ρ‚ΠΈΠ²Π½ΠΈ Ρ†Π΅Π»ΠΈ, ΠΏΠΎΠ΄ΠΎΠ±Ρ€ΠΎ Π΅ Π΄Π° сС Π·Π΅ΠΌΠ΅ K80. Но, Π³ΠΎΠ»Π΅ΠΌΠ°Ρ‚Π° ΠΊΠΎΠ»ΠΈΡ‡ΠΈΠ½Π° Π½Π° RAM ΠΌΠ΅ΠΌΠΎΡ€ΠΈΡ˜Π° Π½ΠΈ дојдС Π΄ΠΎΠ±Ρ€ΠΎ - ΠΎΠ±Π»Π°ΠΊ SSD Π½Π΅ ΠΈΠΌΠΏΡ€Π΅ΡΠΈΠΎΠ½ΠΈΡ€Π°ΡˆΠ΅ со своитС пСрформанси, ΠΏΠ° Π±Π°Π·Π°Ρ‚Π° Π½Π° ΠΏΠΎΠ΄Π°Ρ‚ΠΎΡ†ΠΈ бСшС ΠΏΡ€Π΅Ρ„Ρ€Π»Π΅Π½Π° Π½Π° dev/shm.

Од најголСм интСрСс Π΅ Ρ„Ρ€Π°Π³ΠΌΠ΅Π½Ρ‚ΠΎΡ‚ Π½Π° ΠΊΠΎΠ΄ΠΎΡ‚ ΠΎΠ΄Π³ΠΎΠ²ΠΎΡ€Π΅Π½ Π·Π° ΠΊΠΎΡ€ΠΈΡΡ‚Π΅ΡšΠ΅ Π½Π° повСќС Π³Ρ€Π°Ρ„ΠΈΡ‡ΠΊΠΈ процСсори. ΠŸΡ€Π²ΠΎ, ΠΌΠΎΠ΄Π΅Π»ΠΎΡ‚ сС ΠΊΡ€Π΅ΠΈΡ€Π° Π½Π° процСсорот со помош Π½Π° контСкстуалСн ΠΌΠ΅Π½Π°ΡŸΠ΅Ρ€, исто ΠΊΠ°ΠΊΠΎ Π²ΠΎ Python:

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 Π²ΠΎ Π±ΠΈΠ±Π»ΠΈΠΎΡ‚Π΅ΠΊΠ°Ρ‚Π° Π±Ρ€Π·ΠΎ.ai); Π‘ΠΎ ΠΎΠ΄Ρ€Π΅Π΄Π΅Π½ Π½Π°ΠΏΠΎΡ€, ΠΌΠΎΠΆΠ½ΠΎ Π΅ Π΄Π° сС ΠΏΡ€Π΅Ρ„Ρ€Π»Π°Ρ‚ ΠΈΠΌΠΏΠ»Π΅ΠΌΠ΅Π½Ρ‚Π°Ρ†ΠΈΠΈ ΠΎΠ΄ Ρ‚Ρ€Π΅Ρ‚ΠΈ страни Π½Π° R, Π½Π° ΠΏΡ€ΠΈΠΌΠ΅Ρ€, ΠΎΠ²Π°;
  • ΠΊΠ°ΠΊΠΎ послСдица Π½Π° ΠΏΡ€Π΅Ρ‚Ρ…ΠΎΠ΄Π½Π°Ρ‚Π° Ρ‚ΠΎΡ‡ΠΊΠ°, Π½Π΅ бСшС ΠΌΠΎΠΆΠ½ΠΎ Π΄Π° сС ΠΈΠ·Π±Π΅Ρ€Π΅ Ρ‚ΠΎΡ‡Π½Π°Ρ‚Π° Π±Ρ€Π·ΠΈΠ½Π° Π½Π° ΠΎΠ±ΡƒΠΊΠ° ΠΏΡ€ΠΈ ΠΊΠΎΡ€ΠΈΡΡ‚Π΅ΡšΠ΅ Π½Π° Π½Π΅ΠΊΠΎΠ»ΠΊΡƒ Π³Ρ€Π°Ρ„ΠΈΡ‡ΠΊΠΈ процСсори;
  • нСдостигаат ΠΌΠΎΠ΄Π΅Ρ€Π½ΠΈ Π°Ρ€Ρ…ΠΈΡ‚Π΅ΠΊΡ‚ΡƒΡ€ΠΈ Π½Π° нСвронски ΠΌΡ€Π΅ΠΆΠΈ, особСно ΠΎΠ½ΠΈΠ΅ ΠΊΠΎΠΈ сС ΠΏΡ€Π΅Ρ‚Ρ…ΠΎΠ΄Π½ΠΎ ΠΎΠ±ΡƒΡ‡Π΅Π½ΠΈ Π½Π° ΠΈΠΌΠΈΡŸΠ½Π΅Ρ‚;
  • Никој циклус ΠΏΠΎΠ»ΠΈΡ‚ΠΈΠΊΠ° ΠΈ дискриминативни стапки Π½Π° ΡƒΡ‡Π΅ΡšΠ΅ (косинусната ΠΆΠ°Ρ€Π΅ΡšΠ΅ бСшС Π½Π° нашС Π±Π°Ρ€Π°ΡšΠ΅ ΠΈΠΌΠΏΠ»Π΅ΠΌΠ΅Π½Ρ‚ΠΈΡ€Π°Π½ΠΈ, Π’ΠΈ Π±Π»Π°Π³ΠΎΠ΄Π°Ρ€Π°ΠΌ скСјдан).

Кои корисни Ρ€Π°Π±ΠΎΡ‚ΠΈ сС Π½Π°ΡƒΡ‡ΠΈΡ˜Π° ΠΎΠ΄ овој Π½Π°Ρ‚ΠΏΡ€Π΅Π²Π°Ρ€:

  • На Ρ…Π°Ρ€Π΄Π²Π΅Ρ€ со Ρ€Π΅Π»Π°Ρ‚ΠΈΠ²Π½ΠΎ ΠΌΠ°Π»Π° ΠΌΠΎΡœΠ½ΠΎΡΡ‚, ΠΌΠΎΠΆΠ΅Ρ‚Π΅ Π΄Π° Ρ€Π°Π±ΠΎΡ‚ΠΈΡ‚Π΅ со ΠΏΡ€ΠΈΡΡ‚ΠΎΡ˜Π½ΠΈ (ΠΌΠ½ΠΎΠ³Ρƒ ΠΏΠ°Ρ‚ΠΈ ΠΏΠΎΠ³ΠΎΠ»Π΅ΠΌΠΈ ΠΎΠ΄ RAM ΠΌΠ΅ΠΌΠΎΡ€ΠΈΡ˜Π°Ρ‚Π°) Π²ΠΎΠ»ΡƒΠΌΠ΅Π½ΠΈ Π½Π° ΠΏΠΎΠ΄Π°Ρ‚ΠΎΡ†ΠΈ Π±Π΅Π· Π±ΠΎΠ»ΠΊΠ°. ΠŸΠ»Π°ΡΡ‚ΠΈΡ‡Π½Π° кСса ΠΏΠΎΠ΄Π°Ρ‚ΠΎΡ†ΠΈ. Ρ‚Π°Π±Π΅Π»Π° Π·Π°ΡˆΡ‚Π΅Π΄ΡƒΠ²Π° ΠΌΠ΅ΠΌΠΎΡ€ΠΈΡ˜Π° ΠΏΠΎΡ€Π°Π΄ΠΈ намСстСната ΠΌΠΎΠ΄ΠΈΡ„ΠΈΠΊΠ°Ρ†ΠΈΡ˜Π° Π½Π° Ρ‚Π°Π±Π΅Π»ΠΈΡ‚Π΅, со ΡˆΡ‚ΠΎ сС ΠΈΠ·Π±Π΅Π³Π½ΡƒΠ²Π° Π½ΠΈΠ²Π½ΠΎ ΠΊΠΎΠΏΠΈΡ€Π°ΡšΠ΅, Π° ΠΊΠΎΠ³Π° сС користи ΠΏΡ€Π°Π²ΠΈΠ»Π½ΠΎ, Π½Π΅Π³ΠΎΠ²ΠΈΡ‚Π΅ способности рСчиси сСкогаш ΠΏΠΎΠΊΠ°ΠΆΡƒΠ²Π°Π°Ρ‚ најголСма Π±Ρ€Π·ΠΈΠ½Π° ΠΌΠ΅Ρ“Ρƒ ситС Π°Π»Π°Ρ‚ΠΊΠΈ ΠΊΠΎΠΈ Π½ΠΈ сС ΠΏΠΎΠ·Π½Π°Ρ‚ΠΈ Π·Π° Ρ˜Π°Π·ΠΈΡ†ΠΈΡ‚Π΅ Π·Π° ΡΠΊΡ€ΠΈΠΏΡ‚ΠΈΡ€Π°ΡšΠ΅. Π—Π°Ρ‡ΡƒΠ²ΡƒΠ²Π°ΡšΠ΅Ρ‚ΠΎ Π½Π° ΠΏΠΎΠ΄Π°Ρ‚ΠΎΡ†ΠΈΡ‚Π΅ Π²ΠΎ Π±Π°Π·Π°Ρ‚Π° Π½Π° ΠΏΠΎΠ΄Π°Ρ‚ΠΎΡ†ΠΈ Π²ΠΈ ΠΎΠ²ΠΎΠ·ΠΌΠΎΠΆΡƒΠ²Π°, Π²ΠΎ ΠΌΠ½ΠΎΠ³Ρƒ случаи, Π²ΠΎΠΎΠΏΡˆΡ‚ΠΎ Π΄Π° Π½Π΅ размислуватС Π·Π° ΠΏΠΎΡ‚Ρ€Π΅Π±Π°Ρ‚Π° Π΄Π° сС притиснС Ρ†Π΅Π»Π°Ρ‚Π° Π±Π°Π·Π° Π½Π° ΠΏΠΎΠ΄Π°Ρ‚ΠΎΡ†ΠΈ Π²ΠΎ RAM ΠΌΠ΅ΠΌΠΎΡ€ΠΈΡ˜Π°Ρ‚Π°.
  • Π‘Π°Π²Π½ΠΈΡ‚Π΅ Ρ„ΡƒΠ½ΠΊΡ†ΠΈΠΈ Π²ΠΎ R ΠΌΠΎΠΆΠ΅ Π΄Π° сС Π·Π°ΠΌΠ΅Π½Π°Ρ‚ со Π±Ρ€Π·ΠΈ Π²ΠΎ C++ ΠΊΠΎΡ€ΠΈΡΡ‚Π΅Ρ˜ΡœΠΈ Π³ΠΎ ΠΏΠ°ΠΊΠ΅Ρ‚ΠΎΡ‚ Rcpp. Π”ΠΎΠΊΠΎΠ»ΠΊΡƒ ΠΏΠΎΠΊΡ€Π°Ρ˜ ΡƒΠΏΠΎΡ‚Ρ€Π΅Π±Π°Ρ‚Π° RcppThread ΠΈΠ»ΠΈ RcppΠŸΠ°Ρ€Π°Π»Π΅Π»Π½ΠΎ, Π΄ΠΎΠ±ΠΈΠ²Π°ΠΌΠ΅ ΠΈΠΌΠΏΠ»Π΅ΠΌΠ΅Π½Ρ‚Π°Ρ†ΠΈΠΈ со повСќС нишки ΠΌΠ΅Ρ“Ρƒ ΠΏΠ»Π°Ρ‚Ρ„ΠΎΡ€ΠΌΠΈ, Ρ‚Π°ΠΊΠ° ΡˆΡ‚ΠΎ Π½Π΅ΠΌΠ° ΠΏΠΎΡ‚Ρ€Π΅Π±Π° Π΄Π° сС ΠΏΠ°Ρ€Π°Π»Π΅Π»ΠΈΠ·ΠΈΡ€Π° ΠΊΠΎΠ΄ΠΎΡ‚ Π½Π° Π½ΠΈΠ²ΠΎ R.
  • ΠŸΠ°ΠΊΠ΅Ρ‚ Rcpp ΠΌΠΎΠΆΠ΅ Π΄Π° сС користи Π±Π΅Π· сСриозно познавањС Π½Π° C++, Π½Π°Π²Π΅Π΄Π΅Π½ Π΅ ΠΏΠΎΡ‚Ρ€Π΅Π±Π½ΠΈΠΎΡ‚ ΠΌΠΈΠ½ΠΈΠΌΡƒΠΌ Ρ‚ΡƒΠΊΠ°. Π—Π°Π³Π»Π°Π²ΠΈΠ΅ Π΄Π°Ρ‚ΠΎΡ‚Π΅ΠΊΠΈ Π·Π° Π³ΠΎΠ»Π΅ΠΌ Π±Ρ€ΠΎΡ˜ Π½Π° ΠΊΡƒΠ» C-Π±ΠΈΠ±Π»ΠΈΠΎΡ‚Π΅ΠΊΠΈ ΠΊΠ°ΠΊΠΎ xtensor достапСн Π½Π° CRAN, односно сС Ρ„ΠΎΡ€ΠΌΠΈΡ€Π° инфраструктура Π·Π° ΠΈΠΌΠΏΠ»Π΅ΠΌΠ΅Π½Ρ‚Π°Ρ†ΠΈΡ˜Π° Π½Π° ΠΏΡ€ΠΎΠ΅ΠΊΡ‚ΠΈ ΠΊΠΎΠΈ ΠΈΠ½Ρ‚Π΅Π³Ρ€ΠΈΡ€Π°Π°Ρ‚ Π³ΠΎΡ‚ΠΎΠ² C++ ΠΊΠΎΠ΄ со високи пСрформанси Π²ΠΎ Π . Π”ΠΎΠΏΠΎΠ»Π½ΠΈΡ‚Π΅Π»Π½Π° погодност Π΅ ΠΈΡΡ‚Π°ΠΊΠ½ΡƒΠ²Π°ΡšΠ΅Ρ‚ΠΎ Π½Π° синтаксата ΠΈ статичниот C++ Π°Π½Π°Π»ΠΈΠ·Π°Ρ‚ΠΎΡ€ Π½Π° ΠΊΠΎΠ΄ΠΎΠ²ΠΈ Π²ΠΎ RStudio.
  • Π΄ΠΎΠΊΠΎΠΏΡ‚ Π²ΠΈ ΠΎΠ²ΠΎΠ·ΠΌΠΎΠΆΡƒΠ²Π° Π΄Π° ΠΈΠ·Π²Ρ€ΡˆΡƒΠ²Π°Ρ‚Π΅ ΡΠ°ΠΌΠΎΡΡ‚ΠΎΡ˜Π½ΠΈ скрипти со ΠΏΠ°Ρ€Π°ΠΌΠ΅Ρ‚Ρ€ΠΈ. Ова Π΅ ΠΏΠΎΠ³ΠΎΠ΄Π½ΠΎ Π·Π° ΡƒΠΏΠΎΡ‚Ρ€Π΅Π±Π° Π½Π° ΠΎΠ΄Π΄Π°Π»Π΅Ρ‡Π΅Π½ сСрвСр, Π²ΠΊΠ». ΠΏΠΎΠ΄ Π΄ΠΎΠΊΠ΅Ρ€. Π’ΠΎ RStudio, Π½Π΅Π·Π³ΠΎΠ΄Π½ΠΎ Π΅ Π΄Π° сС спровСдуваат ΠΌΠ½ΠΎΠ³Ρƒ часови СкспСримСнти со ΠΎΠ±ΡƒΠΊΠ° Π½Π° нСвронски ΠΌΡ€Π΅ΠΆΠΈ, Π° ΠΈΠ½ΡΡ‚Π°Π»ΠΈΡ€Π°ΡšΠ΅Ρ‚ΠΎ Π½Π° IDE Π½Π° самиот сСрвСр Π½Π΅ Π΅ сСкогаш ΠΎΠΏΡ€Π°Π²Π΄Π°Π½ΠΎ.
  • Docker ΠΎΠ±Π΅Π·Π±Π΅Π΄ΡƒΠ²Π° прСносливост Π½Π° ΠΊΠΎΠ΄ΠΎΡ‚ ΠΈ рСпродуктивност Π½Π° Ρ€Π΅Π·ΡƒΠ»Ρ‚Π°Ρ‚ΠΈΡ‚Π΅ ΠΏΠΎΠΌΠ΅Ρ“Ρƒ ΠΏΡ€ΠΎΠ³Ρ€Π°ΠΌΠ΅Ρ€ΠΈΡ‚Π΅ со Ρ€Π°Π·Π»ΠΈΡ‡Π½ΠΈ Π²Π΅Ρ€Π·ΠΈΠΈ Π½Π° ОБ ΠΈ Π±ΠΈΠ±Π»ΠΈΠΎΡ‚Π΅ΠΊΠΈ, ΠΊΠ°ΠΊΠΎ ΠΈ Π»Π΅ΡΠ½ΠΎΡ‚ΠΈΡ˜Π° Π½Π° ΠΈΠ·Π²Ρ€ΡˆΡƒΠ²Π°ΡšΠ΅ Π½Π° сСрвСритС. ΠœΠΎΠΆΠ΅Ρ‚Π΅ Π΄Π° Π³ΠΎ стартуватС Ρ†Π΅Π»ΠΈΠΎΡ‚ Ρ†Π΅Π²ΠΊΠΎΠ²ΠΎΠ΄ Π·Π° ΠΎΠ±ΡƒΠΊΠ° со само Π΅Π΄Π½Π° ΠΊΠΎΠΌΠ°Π½Π΄Π°.
  • Google Cloud Π΅ Π±ΡƒΡŸΠ΅Ρ‚ΡΠΊΠΈ Π½Π°Ρ‡ΠΈΠ½ Π·Π° Π΅ΠΊΡΠΏΠ΅Ρ€ΠΈΠΌΠ΅Π½Ρ‚ΠΈΡ€Π°ΡšΠ΅ Π½Π° скап Ρ…Π°Ρ€Π΄Π²Π΅Ρ€, Π½ΠΎ Ρ‚Ρ€Π΅Π±Π° Π²Π½ΠΈΠΌΠ°Ρ‚Π΅Π»Π½ΠΎ Π΄Π° Π³ΠΈ ΠΈΠ·Π±ΠΈΡ€Π°Ρ‚Π΅ ΠΊΠΎΠ½Ρ„ΠΈΠ³ΡƒΡ€Π°Ρ†ΠΈΠΈΡ‚Π΅.
  • ΠœΠ΅Ρ€Π΅ΡšΠ΅Ρ‚ΠΎ Π½Π° Π±Ρ€Π·ΠΈΠ½Π°Ρ‚Π° Π½Π° ΠΏΠΎΠ΅Π΄ΠΈΠ½Π΅Ρ‡Π½ΠΈΡ‚Π΅ Ρ„Ρ€Π°Π³ΠΌΠ΅Π½Ρ‚ΠΈ ΠΎΠ΄ ΠΊΠΎΠ΄ΠΎΡ‚ Π΅ ΠΌΠ½ΠΎΠ³Ρƒ корисно, особСно ΠΊΠΎΠ³Π° сС ΠΊΠΎΠΌΠ±ΠΈΠ½ΠΈΡ€Π°Π°Ρ‚ R ΠΈ C++ ΠΈ со ΠΏΠ°ΠΊΠ΅Ρ‚ΠΎΡ‚ ΠΊΠ»ΡƒΠΏΠ°Ρ‚Π° - исто Ρ‚Π°ΠΊΠ° ΠΌΠ½ΠΎΠ³Ρƒ лСсно.

Π“Π΅Π½Π΅Ρ€Π°Π»Π½ΠΎ, ΠΎΠ²Π° искуство бСшС ΠΌΠ½ΠΎΠ³Ρƒ Π½Π°Π³Ρ€Π°Π΄ΡƒΠ²Π°Ρ‡ΠΊΠΎ ΠΈ Π½ΠΈΠ΅ ΠΏΡ€ΠΎΠ΄ΠΎΠ»ΠΆΡƒΠ²Π°ΠΌΠ΅ Π΄Π° Ρ€Π°Π±ΠΎΡ‚ΠΈΠΌΠ΅ Π½Π° Ρ€Π΅ΡˆΠ°Π²Π°ΡšΠ΅ Π½Π° Π½Π΅ΠΊΠΎΠΈ ΠΎΠ΄ ΠΏΠΎΠΊΡ€Π΅Π½Π°Ρ‚ΠΈΡ‚Π΅ ΠΏΡ€Π°ΡˆΠ°ΡšΠ°.

Π˜Π·Π²ΠΎΡ€: www.habr.com

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