рддреНрд╡рд░рд┐рдд рдбреНрд░рд╛ рдбреВрдбрд▓ рдкрд╣рдЪрд╛рди: рдЖрд░, рд╕реА++ рдФрд░ рддрдВрддреНрд░рд┐рдХрд╛ рдиреЗрдЯрд╡рд░реНрдХ рд╕реЗ рджреЛрд╕реНрддреА рдХреИрд╕реЗ рдХрд░реЗрдВ

рддреНрд╡рд░рд┐рдд рдбреНрд░рд╛ рдбреВрдбрд▓ рдкрд╣рдЪрд╛рди: рдЖрд░, рд╕реА++ рдФрд░ рддрдВрддреНрд░рд┐рдХрд╛ рдиреЗрдЯрд╡рд░реНрдХ рд╕реЗ рджреЛрд╕реНрддреА рдХреИрд╕реЗ рдХрд░реЗрдВ

рд╣реЗ рд╣рдмрд░!

рдкрд┐рдЫрд▓реА рдмрд╛рд░, рдХрд╛рдЧрд▓ рдиреЗ рд╣рд╛рде рд╕реЗ рдЦреАрдВрдЪреА рдЧрдИ рддрд╕реНрд╡реАрд░реЛрдВ рдХреЛ рд╡рд░реНрдЧреАрдХреГрдд рдХрд░рдиреЗ рдХреЗ рд▓рд┐рдП рдХреНрд╡рд┐рдХ рдбреНрд░реЙ рдбреВрдбрд▓ рд░рд┐рдХреЙрдЧреНрдирд┐рд╢рди рдирд╛рдордХ рдПрдХ рдкреНрд░рддрд┐рдпреЛрдЧрд┐рддрд╛ рдХреА рдореЗрдЬрдмрд╛рдиреА рдХреА рдереА, рдЬрд┐рд╕рдореЗрдВ рдЕрдиреНрдп рд▓реЛрдЧреЛрдВ рдХреЗ рдЕрд▓рд╛рд╡рд╛, рдЖрд░-рд╡реИрдЬреНрдЮрд╛рдирд┐рдХреЛрдВ рдХреА рдПрдХ рдЯреАрдо рдиреЗ рднрд╛рдЧ рд▓рд┐рдпрд╛ рдерд╛: рдЖрд░реНрдЯреЗрдо рдХреНрд▓реЗрд╡рддреНрд╕реЛрд╡рд╛, рдлрд╝рд┐рд▓рд┐рдкрд╛ рдкреНрд░рдмрдВрдзрдХ ╨╕ рдПрдВрдбреНрд░реА рдУрдЧреБрд░рддреНрд╕реЛрд╡. рд╣рдо рдкреНрд░рддрд┐рдпреЛрдЧрд┐рддрд╛ рдХрд╛ рд╡рд┐рд╕реНрддрд╛рд░ рд╕реЗ рд╡рд░реНрдгрди рдирд╣реАрдВ рдХрд░реЗрдВрдЧреЗ; рд╡рд╣ рдкрд╣рд▓реЗ рд╣реА рдХрд┐рдпрд╛ рдЬрд╛ рдЪреБрдХрд╛ рд╣реИ рд╣рд╛рд▓рд┐рдпрд╛ рдкреНрд░рдХрд╛рд╢рди.

рдЗрд╕ рдмрд╛рд░ рдкрджрдХ рдЦреЗрддреА рдХреЗ рд╕рд╛рде рдХрд╛рдо рдирд╣реАрдВ рд╣реБрдЖ, рд▓реЗрдХрд┐рди рдмрд╣реБрдд рдореВрд▓реНрдпрд╡рд╛рди рдЕрдиреБрднрд╡ рдкреНрд░рд╛рдкреНрдд рд╣реБрдЖ, рдЗрд╕рд▓рд┐рдП рдореИрдВ рд╕рдореБрджрд╛рдп рдХреЛ рдХрд╛рдЧрд▓реЗ рдФрд░ рд░реЛрдЬрдорд░реНрд░рд╛ рдХреЗ рдХрд╛рдо рдореЗрдВ рд╕рдмрд╕реЗ рджрд┐рд▓рдЪрд╕реНрдк рдФрд░ рдЙрдкрдпреЛрдЧреА рдЪреАрдЬреЛрдВ рдХреЗ рдмрд╛рд░реЗ рдореЗрдВ рдмрддрд╛рдирд╛ рдЪрд╛рд╣рддрд╛ рд╣реВрдВред рдЪрд░реНрдЪрд╛ рдХрд┐рдП рдЧрдП рд╡рд┐рд╖рдпреЛрдВ рдореЗрдВ: рдмрд┐рдирд╛ рдХрдард┐рди рдЬреАрд╡рди OpenCV, JSON рдкрд╛рд░реНрд╕рд┐рдВрдЧ (рдпреЗ рдЙрджрд╛рд╣рд░рдг R рдХрд╛ рдЙрдкрдпреЛрдЧ рдХрд░рдХреЗ рд╕реНрдХреНрд░рд┐рдкреНрдЯ рдпрд╛ рдкреИрдХреЗрдЬ рдореЗрдВ C++ рдХреЛрдб рдХреЗ рдПрдХреАрдХрд░рдг рдХреА рдЬрд╛рдВрдЪ рдХрд░рддреЗ рд╣реИрдВ) рдЖрд░рд╕реАрдкреАрдкреА), рд╕реНрдХреНрд░рд┐рдкреНрдЯ рдХрд╛ рдорд╛рдирдХреАрдХрд░рдг рдФрд░ рдЕрдВрддрд┐рдо рд╕рдорд╛рдзрд╛рди рдХрд╛ рдбреЙрдХрд░реАрдХрд░рдгред рд╕рдВрджреЗрд╢ рдХреЗ рд╕рднреА рдХреЛрдб рдирд┐рд╖реНрдкрд╛рджрди рдХреЗ рд▓рд┐рдП рдЙрдкрдпреБрдХреНрдд рд░реВрдк рдореЗрдВ рдЙрдкрд▓рдмреНрдз рд╣реИрдВ рдЦрдЬрд╛рдиреЗ.

рд╕рд╛рдордЧреНрд░реА:

  1. CSV рд╕реЗ MonetDB рдореЗрдВ рдбреЗрдЯрд╛ рдХреЛ рдХреБрд╢рд▓рддрд╛рдкреВрд░реНрд╡рдХ рд▓реЛрдб рдХрд░реЗрдВ
  2. рдмреИрдЪ рддреИрдпрд╛рд░ рдХрд░рдирд╛
  3. рдбреЗрдЯрд╛рдмреЗрд╕ рд╕реЗ рдмреИрдЪреЛрдВ рдХреЛ рдЕрдирд▓реЛрдб рдХрд░рдиреЗ рдХреЗ рд▓рд┐рдП рдЗрдЯрд░реЗрдЯрд░
  4. рдПрдХ рдореЙрдбрд▓ рдЖрд░реНрдХрд┐рдЯреЗрдХреНрдЪрд░ рдХрд╛ рдЪрдпрди рдХрд░рдирд╛
  5. рд╕реНрдХреНрд░рд┐рдкреНрдЯ рдорд╛рдирдХреАрдХрд░рдг
  6. рд╕реНрдХреНрд░рд┐рдкреНрдЯ рдХрд╛ рдбреЙрдХрд░реАрдХрд░рдг
  7. Google рдХреНрд▓рд╛рдЙрдб рдкрд░ рдПрдХрд╛рдзрд┐рдХ GPU рдХрд╛ рдЙрдкрдпреЛрдЧ рдХрд░рдирд╛
  8. рдЗрд╕рдХреЗ рдмрдЬрд╛рдп рдПрдХ рдирд┐рд╖реНрдХрд░реНрд╖ рдХреА

1. CSV рд╕реЗ MonetDB рдбреЗрдЯрд╛рдмреЗрд╕ рдореЗрдВ рдбреЗрдЯрд╛ рдХреЛ рдХреБрд╢рд▓рддрд╛рдкреВрд░реНрд╡рдХ рд▓реЛрдб рдХрд░реЗрдВ

рдЗрд╕ рдкреНрд░рддрд┐рдпреЛрдЧрд┐рддрд╛ рдореЗрдВ рдбреЗрдЯрд╛ рддреИрдпрд╛рд░ рдЫрд╡рд┐рдпреЛрдВ рдХреЗ рд░реВрдк рдореЗрдВ рдирд╣реАрдВ, рдмрд▓реНрдХрд┐ рдмрд┐рдВрджреБ рдирд┐рд░реНрджреЗрд╢рд╛рдВрдХ рдХреЗ рд╕рд╛рде JSON рдпреБрдХреНрдд 340 CSV рдлрд╝рд╛рдЗрд▓реЛрдВ (рдкреНрд░рддреНрдпреЗрдХ рд╡рд░реНрдЧ рдХреЗ рд▓рд┐рдП рдПрдХ рдлрд╝рд╛рдЗрд▓) рдХреЗ рд░реВрдк рдореЗрдВ рдкреНрд░рджрд╛рди рдХрд┐рдпрд╛ рдЬрд╛рддрд╛ рд╣реИред рдЗрди рдмрд┐рдВрджреБрдУрдВ рдХреЛ рд░реЗрдЦрд╛рдУрдВ рд╕реЗ рдЬреЛрдбрд╝рдиреЗ рдкрд░ рд╣рдореЗрдВ 256x256 рдкрд┐рдХреНрд╕реЗрд▓ рдХреА рдЕрдВрддрд┐рдо рдЫрд╡рд┐ рдкреНрд░рд╛рдкреНрдд рд╣реЛрддреА рд╣реИред рдЗрд╕рдХреЗ рдЕрд▓рд╛рд╡рд╛ рдкреНрд░рддреНрдпреЗрдХ рд░рд┐рдХреЙрд░реНрдб рдХреЗ рд▓рд┐рдП рдПрдХ рд▓реЗрдмрд▓ рд╣реЛрддрд╛ рд╣реИ рдЬреЛ рджрд░реНрд╢рд╛рддрд╛ рд╣реИ рдХрд┐ рдбреЗрдЯрд╛рд╕реЗрдЯ рдПрдХрддреНрд░ рдХрд░рдиреЗ рдХреЗ рд╕рдордп рдЗрд╕реНрддреЗрдорд╛рд▓ рдХрд┐рдП рдЧрдП рдХреНрд▓рд╛рд╕рд┐рдлрд╛рдпрд░ рджреНрд╡рд╛рд░рд╛ рдЪрд┐рддреНрд░ рдХреЛ рд╕рд╣реА рдврдВрдЧ рд╕реЗ рдкрд╣рдЪрд╛рдирд╛ рдЧрдпрд╛ рдерд╛ рдпрд╛ рдирд╣реАрдВ, рдЪрд┐рддреНрд░ рдХреЗ рд▓реЗрдЦрдХ рдХреЗ рдирд┐рд╡рд╛рд╕ рдХреЗ рджреЗрд╢ рдХрд╛ рджреЛ-рдЕрдХреНрд╖рд░ рдХреЛрдб, рдПрдХ рдЕрджреНрд╡рд┐рддреАрдп рдкрд╣рдЪрд╛рдирдХрд░реНрддрд╛, рдПрдХ рдЯрд╛рдЗрдорд╕реНрдЯреИрдореНрдк рдФрд░ рдПрдХ рд╡рд░реНрдЧ рдирд╛рдо рдЬреЛ рдлрд╝рд╛рдЗрд▓ рдирд╛рдо рд╕реЗ рдореЗрд▓ рдЦрд╛рддрд╛ рд╣реЛред рдореВрд▓ рдбреЗрдЯрд╛ рдХрд╛ рдПрдХ рд╕рд░рд▓реАрдХреГрдд рд╕рдВрд╕реНрдХрд░рдг рд╕рдВрдЧреНрд░рд╣ рдореЗрдВ 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"
    )
  )
}

рдбреЗрдЯрд╛рдмреЗрд╕ рдореЗрдВ рдбреЗрдЯрд╛ рд▓реЛрдб рдХрд░рдиреЗ рдХрд╛ рд╕рдмрд╕реЗ рддреЗрдЬрд╝ рддрд░реАрдХрд╛ SQL - рдХрдорд╛рдВрдб рдХрд╛ рдЙрдкрдпреЛрдЧ рдХрд░рдХреЗ рд╕реАрдзреЗ CSV рдлрд╝рд╛рдЗрд▓реЛрдВ рдХреЛ рдХреЙрдкреА рдХрд░рдирд╛ рдерд╛ 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. рдмрд┐рдВрджреБрдУрдВ рдХреЗ рдирд┐рд░реНрджреЗрд╢рд╛рдВрдХ рдХреЗ рд╕рд╛рде рд╕реНрдЯреНрд░рд┐рдВрдЧ рдХреЗ рд╡реИрдХреНрдЯрд░ рд╡рд╛рд▓реЗ рдХрдИ JSON рдХреЛ рдкрд╛рд░реНрд╕ рдХрд░рдирд╛ред
  2. рдЖрд╡рд╢реНрдпрдХ рдЖрдХрд╛рд░ рдХреА рдЫрд╡рд┐ рдкрд░ рдмрд┐рдВрджреБрдУрдВ рдХреЗ рдирд┐рд░реНрджреЗрд╢рд╛рдВрдХ рдХреЗ рдЖрдзрд╛рд░ рдкрд░ рд░рдВрдЧреАрди рд░реЗрдЦрд╛рдПрдБ рдЦреАрдВрдЪрдирд╛ (рдЙрджрд╛рд╣рд░рдг рдХреЗ рд▓рд┐рдП, 256├Ч256 рдпрд╛ 128├Ч128)ред
  3. рдкрд░рд┐рдгрд╛рдореА рдЫрд╡рд┐рдпреЛрдВ рдХреЛ рдЯреЗрдВрд╕рд░ рдореЗрдВ рдкрд░рд┐рд╡рд░реНрддрд┐рдд рдХрд░рдирд╛ред

рдкрд╛рдпрдерди рдХрд░реНрдиреЗрд▓ рдХреЗ рдмреАрдЪ рдкреНрд░рддрд┐рд╕реНрдкрд░реНрдзрд╛ рдХреЗ рднрд╛рдЧ рдХреЗ рд░реВрдк рдореЗрдВ, рд╕рдорд╕реНрдпрд╛ рдХреЛ рдореБрдЦреНрдп рд░реВрдк рд╕реЗ рдЙрдкрдпреЛрдЧ рдХрд░рдХреЗ рд╣рд▓ рдХрд┐рдпрд╛ рдЧрдпрд╛ рдерд╛ OpenCV. рдЖрд░ рдореЗрдВ рд╕рдмрд╕реЗ рд╕рд░рд▓ рдФрд░ рд╕рдмрд╕реЗ рд╕реНрдкрд╖реНрдЯ рдПрдирд╛рд▓реЙрдЧреНрд╕ рдореЗрдВ рд╕реЗ рдПрдХ рдЗрд╕ рддрд░рд╣ рджрд┐рдЦреЗрдЧрд╛:

R рдореЗрдВ JSON рд╕реЗ Tensor рд░реВрдкрд╛рдВрддрд░рдг рд▓рд╛рдЧреВ рдХрд░рдирд╛

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

рдпрд╣ рдХрд╛рд░реНрдпрд╛рдиреНрд╡рдпрди рд╣рдореЗрдВ рдЗрд╖реНрдЯрддрдо рдирд╣реАрдВ рд▓рдЧрд╛, рдХреНрдпреЛрдВрдХрд┐ рдмрдбрд╝реЗ рдмреИрдЪреЛрдВ рдХреЗ рдирд┐рд░реНрдорд╛рдг рдореЗрдВ рдмрд╣реБрдд рд▓рдВрдмрд╛ рд╕рдордп рд▓рдЧрддрд╛ рд╣реИ, рдФрд░ рд╣рдордиреЗ рдПрдХ рд╢рдХреНрддрд┐рд╢рд╛рд▓реА рдкреБрд╕реНрддрдХрд╛рд▓рдп рдХрд╛ рдЙрдкрдпреЛрдЧ рдХрд░рдХреЗ рдЕрдкрдиреЗ рд╕рд╣рдпреЛрдЧрд┐рдпреЛрдВ рдХреЗ рдЕрдиреБрднрд╡ рдХрд╛ рд▓рд╛рдн рдЙрдард╛рдиреЗ рдХрд╛ рдирд┐рд░реНрдгрдп рд▓рд┐рдпрд╛ред OpenCV. рдЙрд╕ рд╕рдордп рдЖрд░ рдХреЗ рд▓рд┐рдП рдХреЛрдИ рддреИрдпрд╛рд░ рдкреИрдХреЗрдЬ рдирд╣реАрдВ рдерд╛ (рдЕрдм рдХреЛрдИ рдирд╣реАрдВ рд╣реИ), рдЗрд╕рд▓рд┐рдП рдЖрд╡рд╢реНрдпрдХ рдХрд╛рд░реНрдпрдХреНрд╖рдорддрд╛ рдХрд╛ рдиреНрдпреВрдирддрдо рдХрд╛рд░реНрдпрд╛рдиреНрд╡рдпрди рд╕реА ++ рдореЗрдВ рдЖрд░ рдХреЛрдб рдореЗрдВ рдПрдХреАрдХрд░рдг рдХреЗ рд╕рд╛рде рд▓рд┐рдЦрд╛ рдЧрдпрд╛ рдерд╛ рдЖрд░рд╕реАрдкреАрдкреА.

рд╕рдорд╕реНрдпрд╛ рдХреЛ рд╣рд▓ рдХрд░рдиреЗ рдХреЗ рд▓рд┐рдП, рдирд┐рдореНрдирд▓рд┐рдЦрд┐рдд рдкреИрдХреЗрдЬ рдФрд░ рд▓рд╛рдЗрдмреНрд░реЗрд░реА рдХрд╛ рдЙрдкрдпреЛрдЧ рдХрд┐рдпрд╛ рдЧрдпрд╛:

  1. OpenCV рдЫрд╡рд┐рдпреЛрдВ рдФрд░ рд░реЗрдЦрд╛рдПрдБ рдЦреАрдВрдЪрдиреЗ рдХреЗ рд╕рд╛рде рдХрд╛рдо рдХрд░рдиреЗ рдХреЗ рд▓рд┐рдПред рдкреВрд░реНрд╡-рд╕реНрдерд╛рдкрд┐рдд рд╕рд┐рд╕реНрдЯрдо рд▓рд╛рдЗрдмреНрд░реЗрд░реАрдЬрд╝ рдФрд░ рд╣реЗрдбрд░ рдлрд╝рд╛рдЗрд▓реЛрдВ рдХреЗ рд╕рд╛рде-рд╕рд╛рде рдбрд╛рдпрдирд╛рдорд┐рдХ рд▓рд┐рдВрдХрд┐рдВрдЧ рдХрд╛ рдЙрдкрдпреЛрдЧ рдХрд┐рдпрд╛ рдЧрдпрд╛ред

  2. xtensor рдмрд╣реБрдЖрдпрд╛рдореА рд╕рд░рдгрд┐рдпреЛрдВ рдФрд░ рдЯреЗрдВрд╕рд░реЛрдВ рдХреЗ рд╕рд╛рде рдХрд╛рдо рдХрд░рдиреЗ рдХреЗ рд▓рд┐рдПред рд╣рдордиреЗ рдЗрд╕реА рдирд╛рдо рдХреЗ рдЖрд░ рдкреИрдХреЗрдЬ рдореЗрдВ рд╢рд╛рдорд┐рд▓ рд╣реЗрдбрд░ рдлрд╝рд╛рдЗрд▓реЛрдВ рдХрд╛ рдЙрдкрдпреЛрдЧ рдХрд┐рдпрд╛ред рд▓рд╛рдЗрдмреНрд░реЗрд░реА рдЖрдкрдХреЛ рдкрдВрдХреНрддрд┐ рдкреНрд░рдореБрдЦ рдФрд░ рд╕реНрддрдВрдн рдкреНрд░рдореБрдЦ рдХреНрд░рдо рджреЛрдиреЛрдВ рдореЗрдВ рдмрд╣реБрдЖрдпрд╛рдореА рд╕рд░рдгрд┐рдпреЛрдВ рдХреЗ рд╕рд╛рде рдХрд╛рдо рдХрд░рдиреЗ рдХреА рдЕрдиреБрдорддрд┐ рджреЗрддреА рд╣реИред

  3. ndjson JSON рдХреЛ рдкрд╛рд░реНрд╕ рдХрд░рдиреЗ рдХреЗ рд▓рд┐рдПред рдЗрд╕ рд▓рд╛рдЗрдмреНрд░реЗрд░реА рдХрд╛ рдЙрдкрдпреЛрдЧ рдХрд┐рдпрд╛ рдЬрд╛рддрд╛ рд╣реИ xtensor рдпрджрд┐ рдпрд╣ рдкреНрд░реЛрдЬреЗрдХреНрдЯ рдореЗрдВ рдореМрдЬреВрдж рд╣реИ рддреЛ рд╕реНрд╡рдЪрд╛рд▓рд┐рдд рд░реВрдк рд╕реЗред

  4. рдЖрд░рд╕реАрдкреАрдкреАрдереНрд░реЗрдб JSON рд╕реЗ рдПрдХ рд╡реЗрдХреНрдЯрд░ рдХреЗ рдмрд╣реБ-рдереНрд░реЗрдбреЗрдб рдкреНрд░рд╕рдВрд╕реНрдХрд░рдг рдХреЛ рд╡реНрдпрд╡рд╕реНрдерд┐рдд рдХрд░рдиреЗ рдХреЗ рд▓рд┐рдПред рдЗрд╕ рдкреИрдХреЗрдЬ рджреНрд╡рд╛рд░рд╛ рдкреНрд░рджрд╛рди рдХреА рдЧрдИ рд╣реЗрдбрд░ рдлрд╝рд╛рдЗрд▓реЛрдВ рдХрд╛ рдЙрдкрдпреЛрдЧ рдХрд┐рдпрд╛ рдЧрдпрд╛ред рдЕрдзрд┐рдХ рд▓реЛрдХрдкреНрд░рд┐рдп рд╕реЗ Rcppрд╕рдорд╛рдирд╛рдВрддрд░ рдкреИрдХреЗрдЬ рдореЗрдВ, рдЕрдиреНрдп рдмрд╛рддреЛрдВ рдХреЗ рдЕрд▓рд╛рд╡рд╛, рдПрдХ рдЕрдВрддрд░реНрдирд┐рд╣рд┐рдд рд▓реВрдк рдЗрдВрдЯрд░рдкреНрдЯ рддрдВрддреНрд░ рд╣реИред

рдпрд╣ рдзреНрдпрд╛рди рджрд┐рдпрд╛ рдЬрд╛рдирд╛ рдЪрд╛рд╣рд┐рдП рдХрд┐ xtensor рдпрд╣ рдПрдХ рд╡рд░рджрд╛рди рд╕рд╛рдмрд┐рдд рд╣реБрдЖ: рдЗрд╕ рддрдереНрдп рдХреЗ рдЕрд▓рд╛рд╡рд╛ рдХрд┐ рдЗрд╕рдореЗрдВ рд╡реНрдпрд╛рдкрдХ рдХрд╛рд░реНрдпрдХреНрд╖рдорддрд╛ рдФрд░ рдЙрдЪреНрдЪ рдкреНрд░рджрд░реНрд╢рди рд╣реИ, рдЗрд╕рдХреЗ рдбреЗрд╡рд▓рдкрд░реНрд╕ рдХрд╛рдлреА рд╕рдВрд╡реЗрджрдирд╢реАрд▓ рдирд┐рдХрд▓реЗ рдФрд░ рдЙрдиреНрд╣реЛрдВрдиреЗ рддреБрд░рдВрдд рдФрд░ рд╡рд┐рд╕реНрддрд╛рд░ рд╕реЗ рд╕рд╡рд╛рд▓реЛрдВ рдХреЗ рдЬрд╡рд╛рдм рджрд┐рдПред рдЙрдирдХреА рдорджрдж рд╕реЗ, рдУрдкрдирд╕реАрд╡реА рдореИрдЯреНрд░рд┐рд╕реЗрд╕ рдХреЗ 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

рд╕рд┐рд╕реНрдЯрдо рдлрд╝рд╛рдЗрд▓реЛрдВ рдХрд╛ рдЙрдкрдпреЛрдЧ рдХрд░рдиреЗ рд╡рд╛рд▓реА рдлрд╝рд╛рдЗрд▓реЛрдВ рдХреЛ рд╕рдВрдХрд▓рд┐рдд рдХрд░рдиреЗ рдФрд░ рд╕рд┐рд╕реНрдЯрдо рдкрд░ рд╕реНрдерд╛рдкрд┐рдд рдкреБрд╕реНрддрдХрд╛рд▓рдпреЛрдВ рдХреЗ рд╕рд╛рде рдЧрддрд┐рд╢реАрд▓ рд▓рд┐рдВрдХрд┐рдВрдЧ рдХреЗ рд▓рд┐рдП, рд╣рдордиреЗ рдкреИрдХреЗрдЬ рдореЗрдВ рд▓рд╛рдЧреВ рдкреНрд▓рдЧрдЗрди рддрдВрддреНрд░ рдХрд╛ рдЙрдкрдпреЛрдЧ рдХрд┐рдпрд╛ рдЖрд░рд╕реАрдкреАрдкреА. рдкрдереЛрдВ рдФрд░ рдЭрдВрдбреЛрдВ рдХреЛ рд╕реНрд╡рдЪрд╛рд▓рд┐рдд рд░реВрдк рд╕реЗ рдЦреЛрдЬрдиреЗ рдХреЗ рд▓рд┐рдП, рд╣рдордиреЗ рдПрдХ рд▓реЛрдХрдкреНрд░рд┐рдп рд▓рд┐рдирдХреНрд╕ рдЙрдкрдпреЛрдЧрд┐рддрд╛ рдХрд╛ рдЙрдкрдпреЛрдЧ рдХрд┐рдпрд╛ рдкреАрдХреЗрдЬреА-рдХреЙрдиреНрдлрд╝рд┐рдЧрд░реЗрд╢рди.

OpenCV рд▓рд╛рдЗрдмреНрд░реЗрд░реА рдХрд╛ рдЙрдкрдпреЛрдЧ рдХрд░рдиреЗ рдХреЗ рд▓рд┐рдП Rcpp рдкреНрд▓рдЧрдЗрди рдХрд╛ рдХрд╛рд░реНрдпрд╛рдиреНрд╡рдпрди

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 рдХреЛ рдкрд╛рд░реНрд╕ рдХрд░рдиреЗ рдФрд░ рдореЙрдбрд▓ рдореЗрдВ рдЯреНрд░рд╛рдВрд╕рдорд┐рд╢рди рдХреЗ рд▓рд┐рдП рдПрдХ рдмреИрдЪ рддреИрдпрд╛рд░ рдХрд░рдиреЗ рдХреЗ рд▓рд┐рдП рдХрд╛рд░реНрдпрд╛рдиреНрд╡рдпрди рдХреЛрдб рд╕реНрдкреЙрдЗрд▓рд░ рдХреЗ рдиреАрдЪреЗ рджрд┐рдпрд╛ рдЧрдпрд╛ рд╣реИред рд╕рдмрд╕реЗ рдкрд╣рд▓реЗ, рд╣реЗрдбрд░ рдлрд╝рд╛рдЗрд▓реЛрдВ рдХреА рдЦреЛрдЬ рдХреЗ рд▓рд┐рдП рдПрдХ рд╕реНрдерд╛рдиреАрдп рдкреНрд░реЛрдЬреЗрдХреНрдЯ рдирд┐рд░реНрджреЗрд╢рд┐рдХрд╛ рдЬреЛрдбрд╝реЗрдВ (рдПрдирдбреАрдЬреЗрд╕рди рдХреЗ рд▓рд┐рдП рдЖрд╡рд╢реНрдпрдХ):

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

C++ рдореЗрдВ JSON рд╕реЗ рдЯреЗрдВрд╕рд░ рд░реВрдкрд╛рдВрддрд░рдг рдХрд╛ рдХрд╛рд░реНрдпрд╛рдиреНрд╡рдпрди

// [[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, рдЬреЛ рдкрд░рд┐рдгрд╛рдо рдХреЛ рдЖрд░-рдСрдмреНрдЬреЗрдХреНрдЯ (рдмрд╣реБрдЖрдпрд╛рдореА рд╕рд░рдгреА) рдореЗрдВ рдирд┐рд░реНрдпрд╛рдд рдХрд░рддрд╛ рд╣реИ;

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

рддреНрд╡рд░рд┐рдд рдбреНрд░рд╛ рдбреВрдбрд▓ рдкрд╣рдЪрд╛рди: рдЖрд░, рд╕реА++ рдФрд░ рддрдВрддреНрд░рд┐рдХрд╛ рдиреЗрдЯрд╡рд░реНрдХ рд╕реЗ рджреЛрд╕реНрддреА рдХреИрд╕реЗ рдХрд░реЗрдВ
рдЖрд░ рдФрд░ рд╕реА++ рдореЗрдВ рдХрд╛рд░реНрдпрд╛рдиреНрд╡рдпрди рдХреА рдЧрддрд┐ рдХреА рддреБрд▓рдирд╛

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

рддреНрд╡рд░рд┐рдд рдбреНрд░рд╛ рдбреВрдбрд▓ рдкрд╣рдЪрд╛рди: рдЖрд░, рд╕реА++ рдФрд░ рддрдВрддреНрд░рд┐рдХрд╛ рдиреЗрдЯрд╡рд░реНрдХ рд╕реЗ рджреЛрд╕реНрддреА рдХреИрд╕реЗ рдХрд░реЗрдВ

рдЬреИрд╕рд╛ рдХрд┐ рдЖрдк рджреЗрдЦ рд╕рдХрддреЗ рд╣реИрдВ, рдЧрддрд┐ рдореЗрдВ рд╡реГрджреНрдзрд┐ рдмрд╣реБрдд рдорд╣рддреНрд╡рдкреВрд░реНрдг рд╣реЛ рдЧрдИ рд╣реИ, рдФрд░ рдЖрд░ рдХреЛрдб рдХреЛ рд╕рдорд╛рдирд╛рдВрддрд░ рдХрд░рдХреЗ C++ рдХреЛрдб рдХреЛ рдкрдХрдбрд╝рдирд╛ рд╕рдВрднрд╡ рдирд╣реАрдВ рд╣реИред

3. рдбреЗрдЯрд╛рдмреЗрд╕ рд╕реЗ рдмреИрдЪреЛрдВ рдХреЛ рдЕрдирд▓реЛрдб рдХрд░рдиреЗ рдХреЗ рд▓рд┐рдП рдЗрдЯрд░реЗрдЯрд░

рдЖрд░ рдХреЗ рдкрд╛рд╕ рд░реИрдо рдореЗрдВ рдлрд┐рдЯ рд╣реЛрдиреЗ рд╡рд╛рд▓реЗ рдбреЗрдЯрд╛ рдХреЛ рд╕рдВрд╕рд╛рдзрд┐рдд рдХрд░рдиреЗ рдХреЗ рд▓рд┐рдП рдПрдХ рдЕрдЪреНрдЫреА-рдЦрд╛рд╕реА рдкреНрд░рддрд┐рд╖реНрдард╛ рд╣реИ, рдЬрдмрдХрд┐ рдкрд╛рдпрдерди рдХреЛ рдкреБрдирд░рд╛рд╡реГрддреНрдд рдбреЗрдЯрд╛ рдкреНрд░реЛрд╕реЗрд╕рд┐рдВрдЧ рдХреА рдЕрдзрд┐рдХ рд╡рд┐рд╢реЗрд╖рддрд╛ рд╣реИ, рдЬреЛ рдЖрдкрдХреЛ рдЖрд╕рд╛рдиреА рд╕реЗ рдФрд░ рд╕реНрд╡рд╛рднрд╛рд╡рд┐рдХ рд░реВрдк рд╕реЗ рдЖрдЙрдЯ-рдСрдл-рдХреЛрд░ рдЧрдгрдирд╛ (рдмрд╛рд╣рд░реА рдореЗрдореЛрд░реА рдХрд╛ рдЙрдкрдпреЛрдЧ рдХрд░рдХреЗ рдЧрдгрдирд╛) рд▓рд╛рдЧреВ рдХрд░рдиреЗ рдХреА рдЕрдиреБрдорддрд┐ рджреЗрддрд╛ рд╣реИред рд╡рд░реНрдгрд┐рдд рд╕рдорд╕реНрдпрд╛ рдХреЗ рд╕рдВрджрд░реНрдн рдореЗрдВ рд╣рдорд╛рд░реЗ рд▓рд┐рдП рдПрдХ рдХреНрд▓рд╛рд╕рд┐рдХ рдФрд░ рдкреНрд░рд╛рд╕рдВрдЧрд┐рдХ рдЙрджрд╛рд╣рд░рдг рдЧреНрд░реЗрдбрд┐рдПрдВрдЯ рдбрд┐рд╕реЗрдВрдЯ рд╡рд┐рдзрд┐ рджреНрд╡рд╛рд░рд╛ рдкреНрд░рд╢рд┐рдХреНрд╖рд┐рдд рдЧрд╣рди рддрдВрддреНрд░рд┐рдХрд╛ рдиреЗрдЯрд╡рд░реНрдХ рд╣реИ, рдЬрд┐рд╕рдореЗрдВ рдкреНрд░рддреНрдпреЗрдХ рдЪрд░рдг рдореЗрдВ рдЕрд╡рд▓реЛрдХрди рдХреЗ рдПрдХ рдЫреЛрдЯреЗ рд╕реЗ рд╣рд┐рд╕реНрд╕реЗ рдпрд╛ рдорд┐рдиреА-рдмреИрдЪ рдХрд╛ рдЙрдкрдпреЛрдЧ рдХрд░рдХреЗ рдЧреНрд░реЗрдбрд┐рдПрдВрдЯ рдХрд╛ рдЕрдиреБрдорд╛рди рд▓рдЧрд╛рдпрд╛ рдЬрд╛рддрд╛ рд╣реИред

рдкрд╛рдпрдерди рдореЗрдВ рд▓рд┐рдЦреЗ рдЧрдП рдбреАрдк рд▓рд░реНрдирд┐рдВрдЧ рдлреНрд░реЗрдорд╡рд░реНрдХ рдореЗрдВ рд╡рд┐рд╢реЗрд╖ рдХрдХреНрд╖рд╛рдПрдВ рд╣реЛрддреА рд╣реИрдВ рдЬреЛ рдбреЗрдЯрд╛ рдХреЗ рдЖрдзрд╛рд░ рдкрд░ рдкреБрдирд░рд╛рд╡реГрддреНрддрд┐рдпреЛрдВ рдХреЛ рд▓рд╛рдЧреВ рдХрд░рддреА рд╣реИрдВ: рдЯреЗрдмрд▓, рдлрд╝реЛрд▓реНрдбрд░реЛрдВ рдореЗрдВ рдЪрд┐рддреНрд░, рдмрд╛рдЗрдирд░реА рдкреНрд░рд╛рд░реВрдк, рдЖрджрд┐ред рдЖрдк рд╡рд┐рд╢рд┐рд╖реНрдЯ рдХрд╛рд░реНрдпреЛрдВ рдХреЗ рд▓рд┐рдП рддреИрдпрд╛рд░ рд╡рд┐рдХрд▓реНрдкреЛрдВ рдХрд╛ рдЙрдкрдпреЛрдЧ рдХрд░ рд╕рдХрддреЗ рд╣реИрдВ рдпрд╛ рдЕрдкрдирд╛ рдЦреБрдж рдХрд╛ рд▓рд┐рдЦ тАЛтАЛрд╕рдХрддреЗ рд╣реИрдВред R рдореЗрдВ рд╣рдо Python рд▓рд╛рдЗрдмреНрд░реЗрд░реА рдХреА рд╕рднреА рд╕реБрд╡рд┐рдзрд╛рдУрдВ рдХрд╛ рд▓рд╛рдн рдЙрдард╛ рд╕рдХрддреЗ рд╣реИрдВ keras рдПрдХ рд╣реА рдирд╛рдо рдХреЗ рдкреИрдХреЗрдЬ рдХрд╛ рдЙрдкрдпреЛрдЧ рдХрд░рддреЗ рд╣реБрдП рдЗрд╕рдХреЗ рд╡рд┐рднрд┐рдиреНрди рдмреИрдХрдПрдВрдб рдХреЗ рд╕рд╛рде, рдЬреЛ рдмрджрд▓реЗ рдореЗрдВ рдкреИрдХреЗрдЬ рдХреЗ рд╢реАрд░реНрд╖ рдкрд░ рдХрд╛рдо рдХрд░рддрд╛ рд╣реИ рдЬрд╛рд▓ рд╕реЗ рдврдБрдХрдирд╛. рдЙрддреНрддрд░рд╛рд░реНрджреНрдз рдПрдХ рдЕрд▓рдЧ рд▓рдВрдмреЗ рд▓реЗрдЦ рдХрд╛ рд╣рдХрджрд╛рд░ рд╣реИ; рдпрд╣ рди рдХреЗрд╡рд▓ рдЖрдкрдХреЛ рдЖрд░ рд╕реЗ рдкрд╛рдпрдерди рдХреЛрдб рдЪрд▓рд╛рдиреЗ рдХреА рдЕрдиреБрдорддрд┐ рджреЗрддрд╛ рд╣реИ, рдмрд▓реНрдХрд┐ рдЖрдкрдХреЛ рд╕рднреА рдЖрд╡рд╢реНрдпрдХ рдкреНрд░рдХрд╛рд░ рдХреЗ рд░реВрдкрд╛рдВрддрд░рдгреЛрдВ рдХреЛ рд╕реНрд╡рдЪрд╛рд▓рд┐рдд рд░реВрдк рд╕реЗ рдирд┐рд╖реНрдкрд╛рджрд┐рдд рдХрд░рддреЗ рд╣реБрдП, рдЖрд░ рдФрд░ рдкрд╛рдпрдерди рд╕рддреНрд░реЛрдВ рдХреЗ рдмреАрдЪ рд╡рд╕реНрддреБрдУрдВ рдХреЛ рд╕реНрдерд╛рдирд╛рдВрддрд░рд┐рдд рдХрд░рдиреЗ рдХреА рднреА рдЕрдиреБрдорддрд┐ рджреЗрддрд╛ рд╣реИред

рд╣рдордиреЗ MonetDBLite рдХрд╛ рдЙрдкрдпреЛрдЧ рдХрд░рдХреЗ рд╕рднреА рдбреЗрдЯрд╛ рдХреЛ RAM рдореЗрдВ рд╕рдВрдЧреНрд░рд╣реАрдд рдХрд░рдиреЗ рдХреА рдЖрд╡рд╢реНрдпрдХрддрд╛ рд╕реЗ рдЫреБрдЯрдХрд╛рд░рд╛ рдкрд╛ рд▓рд┐рдпрд╛ рд╣реИ, рд╕рднреА "рдиреНрдпреВрд░рд▓ рдиреЗрдЯрд╡рд░реНрдХ" рдХрд╛рд░реНрдп рдкрд╛рдпрдерди рдореЗрдВ рдореВрд▓ рдХреЛрдб рджреНрд╡рд╛рд░рд╛ рдХрд┐рдП рдЬрд╛рдПрдВрдЧреЗ, рд╣рдореЗрдВ рдмрд╕ рдбреЗрдЯрд╛ рдкрд░ рдПрдХ рдЗрдЯрд░реЗрдЯрд░ рд▓рд┐рдЦрдирд╛ рд╣реЛрдЧрд╛, рдХреНрдпреЛрдВрдХрд┐ рдХреБрдЫ рднреА рддреИрдпрд╛рд░ рдирд╣реАрдВ рд╣реИ рдЖрд░ рдпрд╛ рдкрд╛рдпрдерди рдореЗрдВ рдРрд╕реА рд╕реНрдерд┐рддрд┐ рдХреЗ рд▓рд┐рдПред рдЗрд╕рдХреЗ рд▓рд┐рдП рдЕрдирд┐рд╡рд╛рд░реНрдп рд░реВрдк рд╕реЗ рдХреЗрд╡рд▓ рджреЛ рдЖрд╡рд╢реНрдпрдХрддрд╛рдПрдВ рд╣реИрдВ: рдЗрд╕реЗ рдмреИрдЪреЛрдВ рдХреЛ рдПрдХ рдЕрдВрддрд╣реАрди рд▓реВрдк рдореЗрдВ рд╡рд╛рдкрд╕ рдХрд░рдирд╛ рд╣реЛрдЧрд╛ рдФрд░ рдкреБрдирд░рд╛рд╡реГрддреНрддрд┐рдпреЛрдВ рдХреЗ рдмреАрдЪ рдЕрдкрдиреА рд╕реНрдерд┐рддрд┐ рдХреЛ рд╕рд╣реЗрдЬрдирд╛ рд╣реЛрдЧрд╛ (рдЖрд░ рдореЗрдВ рдЙрддреНрддрд░рд╛рд░реНрджреНрдз рдХреЛ рдХреНрд▓реЛрдЬрд░ рдХрд╛ рдЙрдкрдпреЛрдЧ рдХрд░рдХреЗ рд╕рдмрд╕реЗ рд╕рд░рд▓ рддрд░реАрдХреЗ рд╕реЗ рдХрд╛рд░реНрдпрд╛рдиреНрд╡рд┐рдд рдХрд┐рдпрд╛ рдЬрд╛рддрд╛ рд╣реИ)ред рдкрд╣рд▓реЗ, рдЗрдЯрд░реЗрдЯрд░ рдХреЗ рдЕрдВрджрд░ рдЖрд░ рд╕рд░рдгрд┐рдпреЛрдВ рдХреЛ рд╕реНрдкрд╖реНрдЯ рд░реВрдк рд╕реЗ рд╕рдВрдЦреНрдпрд╛рддреНрдордХ рд╕рд░рдгрд┐рдпреЛрдВ рдореЗрдВ рдкрд░рд┐рд╡рд░реНрддрд┐рдд рдХрд░рдирд╛ рдЖрд╡рд╢реНрдпрдХ рдерд╛, рд▓реЗрдХрд┐рди рдкреИрдХреЗрдЬ рдХрд╛ рд╡рд░реНрддрдорд╛рди рд╕рдВрд╕реНрдХрд░рдг keras рдпрд╣ рд╕реНрд╡рдпрдВ рдХрд░рддреА рд╣реИ.

рдкреНрд░рд╢рд┐рдХреНрд╖рдг рдФрд░ рд╕рддреНрдпрд╛рдкрди рдбреЗрдЯрд╛ рдХреЗ рд▓рд┐рдП рдкреБрдирд░рд╛рд╡рд░реНрддрдХ рдЗрд╕ рдкреНрд░рдХрд╛рд░ рдирд┐рдХрд▓рд╛:

рдкреНрд░рд╢рд┐рдХреНрд╖рдг рдФрд░ рд╕рддреНрдпрд╛рдкрди рдбреЗрдЯрд╛ рдХреЗ рд▓рд┐рдП рдЗрдЯрд░реЗрдЯрд░

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 рдкреНрд░рддреНрдпреЗрдХ рд╕реНрдЯреНрд░реЛрдХ рдХреЛ рдПрдХ рдирдП рд░рдВрдЧ рдореЗрдВ рдЦреАрдВрдЪрд╛ рдЬрд╛рддрд╛ рд╣реИ) рдФрд░ рдЗрдореЗрдЬрдиреЗрдЯ рдкрд░ рдкреВрд░реНрд╡-рдкреНрд░рд╢рд┐рдХреНрд╖рд┐рдд рдиреЗрдЯрд╡рд░реНрдХ рдХреЗ рд▓рд┐рдП рдПрдХ рдкреНрд░реАрдкреНрд░реЛрд╕реЗрд╕рд┐рдВрдЧ рд╕рдВрдХреЗрддрдХред рдЕрдВрддрд░рд╛рд▓ [0, 1] рд╕реЗ рдЕрдВрддрд░рд╛рд▓ [-1, 1] рддрдХ рдкрд┐рдХреНрд╕реЗрд▓ рдорд╛рдиреЛрдВ рдХреЛ рд╕реНрдХреЗрд▓ рдХрд░рдиреЗ рдХреЗ рд▓рд┐рдП рдЙрддреНрддрд░рд╛рд░реНрджреНрдз рдХреА рдЖрд╡рд╢реНрдпрдХрддрд╛ рд╣реЛрддреА рд╣реИ, рдЬрд┐рд╕рдХрд╛ рдЙрдкрдпреЛрдЧ рдЖрдкреВрд░реНрддрд┐ рдХреЛ рдкреНрд░рд╢рд┐рдХреНрд╖рд┐рдд рдХрд░рддреЗ рд╕рдордп рдХрд┐рдпрд╛ рдЬрд╛рддрд╛ рдерд╛ keras рдореЙрдбрд▓ред

рдмрд╛рд╣рд░реА рдлрд╝рдВрдХреНрд╢рди рдореЗрдВ рддрд░реНрдХ рдкреНрд░рдХрд╛рд░ рдХреА рдЬрд╛рдБрдЪ, рдПрдХ рддрд╛рд▓рд┐рдХрд╛ рд╢рд╛рдорд┐рд▓ рд╣реИ 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 рдФрд░ рд▓рд┐рдВрдХ рдХреЗ рдорд╛рдзреНрдпрдо рд╕реЗ рд╕рдВрд╢реЛрдзрди - рдЗрди рдкреИрдХреЗрдЬ "рдЪрд┐рдкреНрд╕" рдХреЗ рдмрд┐рдирд╛ рдбреЗрдЯрд╛ рддрд╛рд▓рд┐рдХрд╛ рдЖрд░ рдореЗрдВ рдХрд┐рд╕реА рднреА рдорд╣рддреНрд╡рдкреВрд░реНрдг рдорд╛рддреНрд░рд╛ рдореЗрдВ рдбреЗрдЯрд╛ рдХреЗ рд╕рд╛рде рдкреНрд░рднрд╛рд╡реА рдврдВрдЧ рд╕реЗ рдХрд╛рдо рдХрд░рдиреЗ рдХреА рдХрд▓реНрдкрдирд╛ рдХрд░рдирд╛ рдХрд╛рдлреА рдХрдард┐рди рд╣реИред

рдХреЛрд░ 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)

рддреНрд╡рд░рд┐рдд рдбреНрд░рд╛ рдбреВрдбрд▓ рдкрд╣рдЪрд╛рди: рдЖрд░, рд╕реА++ рдФрд░ рддрдВрддреНрд░рд┐рдХрд╛ рдиреЗрдЯрд╡рд░реНрдХ рд╕реЗ рджреЛрд╕реНрддреА рдХреИрд╕реЗ рдХрд░реЗрдВ

рдпрджрд┐ рдЖрдкрдХреЗ рдкрд╛рд╕ рдкрд░реНрдпрд╛рдкреНрдд рдорд╛рддреНрд░рд╛ рдореЗрдВ рд░реИрдо рд╣реИ, рддреЛ рдЖрдк рдЗрд╕реЗ рдЙрд╕реА рд░реИрдо рдореЗрдВ рд╕реНрдерд╛рдирд╛рдВрддрд░рд┐рдд рдХрд░рдХреЗ рдбреЗрдЯрд╛рдмреЗрд╕ рдХреЗ рд╕рдВрдЪрд╛рд▓рди рдХреЛ рдЧрдВрднреАрд░рддрд╛ рд╕реЗ рддреЗрдЬ рдХрд░ рд╕рдХрддреЗ рд╣реИрдВ (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. рдореЙрдбрд▓ рд╡рд╛рд╕реНрддреБрдХрд▓рд╛ рдХрд╛ рдЪрдпрди

рд╕рдмрд╕реЗ рдкрд╣рд▓реЗ рд╡рд╛рд╕реНрддреБрдХрд▓рд╛ рдХрд╛ рдкреНрд░рдпреЛрдЧ рдХрд┐рдпрд╛ рдЧрдпрд╛ рдерд╛ рдореЛрдмрд╛рдЗрд▓рдиреЗрдЯ v1, рдЬрд┐рдирдХреА рд╡рд┐рд╢реЗрд╖рддрд╛рдУрдВ рдкрд░ рдЪрд░реНрдЪрд╛ рдХреА рдЧрдИ рд╣реИ рдпрд╣ рд╕рдВрджреЗрд╢ред рдЗрд╕реЗ рдорд╛рдирдХ рдХреЗ рд░реВрдк рдореЗрдВ рд╢рд╛рдорд┐рд▓ рдХрд┐рдпрд╛ рдЧрдпрд╛ рд╣реИ keras рдФрд░, рддрджрдиреБрд╕рд╛рд░, рдЖрд░ рдХреЗ рд▓рд┐рдП рд╕рдорд╛рди рдирд╛рдо рдХреЗ рдкреИрдХреЗрдЬ рдореЗрдВ рдЙрдкрд▓рдмреНрдз рд╣реИред рд▓реЗрдХрд┐рди рдЬрдм рдПрдХрд▓-рдЪреИрдирд▓ рдЫрд╡рд┐рдпреЛрдВ рдХреЗ рд╕рд╛рде рдЗрд╕рдХрд╛ рдЙрдкрдпреЛрдЧ рдХрд░рдиреЗ рдХрд╛ рдкреНрд░рдпрд╛рд╕ рдХрд┐рдпрд╛ рдЧрдпрд╛, рддреЛ рдПрдХ рдЕрдЬреАрдм рдмрд╛рдд рд╕рд╛рдордиреЗ рдЖрдИ: рдЗрдирдкреБрдЯ рдЯреЗрдВрд╕рд░ рдореЗрдВ рд╣рдореЗрд╢рд╛ рдЖрдпрд╛рдо рд╣реЛрдирд╛ рдЪрд╛рд╣рд┐рдП (batch, height, width, 3)рдпрд╛рдиреА рдЪреИрдирд▓реЛрдВ рдХреА рд╕рдВрдЦреНрдпрд╛ рдирд╣реАрдВ рдмрджрд▓реА рдЬрд╛ рд╕рдХрддреА. рдкрд╛рдпрдерди рдореЗрдВ рдРрд╕реА рдХреЛрдИ рд╕реАрдорд╛ рдирд╣реАрдВ рд╣реИ, рдЗрд╕рд▓рд┐рдП рд╣рдордиреЗ рдореВрд▓ рд▓реЗрдЦ (рдХреЗрд░рд╕ рд╕рдВрд╕реНрдХрд░рдг рдореЗрдВ рдбреНрд░реЙрдкрдЖрдЙрдЯ рдХреЗ рдмрд┐рдирд╛) рдХрд╛ рдЕрдиреБрд╕рд░рдг рдХрд░рддреЗ рд╣реБрдП, рдЗрд╕ рд╡рд╛рд╕реНрддреБрдХрд▓рд╛ рдХрд╛ рдЕрдкрдирд╛ рд╕реНрд╡рдпрдВ рдХрд╛ рдХрд╛рд░реНрдпрд╛рдиреНрд╡рдпрди рд▓рд┐рдЦрд╛ рдФрд░ рд▓рд┐рдЦрд╛:

рдореЛрдмрд╛рдЗрд▓рдиреЗрдЯ 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)
}

рдЗрд╕ рджреГрд╖реНрдЯрд┐рдХреЛрдг рдХреЗ рдиреБрдХрд╕рд╛рди рд╕реНрдкрд╖реНрдЯ рд╣реИрдВ. рдореИрдВ рдмрд╣реБрдд рд╕рд╛рд░реЗ рдореЙрдбрд▓реЛрдВ рдХрд╛ рдкрд░реАрдХреНрд╖рдг рдХрд░рдирд╛ рдЪрд╛рд╣рддрд╛ рд╣реВрдВ, рд▓реЗрдХрд┐рди рдЗрд╕рдХреЗ рд╡рд┐рдкрд░реАрдд, рдореИрдВ рдкреНрд░рддреНрдпреЗрдХ рдЖрд░реНрдХрд┐рдЯреЗрдХреНрдЪрд░ рдХреЛ рдореИрдиреНрдпреБрдЕрд▓ рд░реВрдк рд╕реЗ рдлрд┐рд░ рд╕реЗ рд▓рд┐рдЦрдирд╛ рдирд╣реАрдВ рдЪрд╛рд╣рддрд╛ рд╣реВрдВред рд╣рдо рдЗрдореЗрдЬрдиреЗрдЯ рдкрд░ рдкреВрд░реНрд╡-рдкреНрд░рд╢рд┐рдХреНрд╖рд┐рдд рдореЙрдбрд▓реЛрдВ рдХреЗ рд╡рдЬрди рдХрд╛ рдЙрдкрдпреЛрдЧ рдХрд░рдиреЗ рдХреЗ рдЕрд╡рд╕рд░ рд╕реЗ рднреА рд╡рдВрдЪрд┐рдд рдереЗред рд╣рдореЗрд╢рд╛ рдХреА рддрд░рд╣, рджрд╕реНрддрд╛рд╡реЗрдЬрд╝реАрдХрд░рдг рдХрд╛ рдЕрдзреНрдпрдпрди рдХрд░рдиреЗ рд╕реЗ рдорджрдж рдорд┐рд▓реАред рд╕рдорд╛рд░реЛрд╣ 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)

рдЕрдм рдХрд┐рд╕реА рднреА рдЖрдкреВрд░реНрддрд┐ рдХреЛ рдкреНрд░рд╛рдкреНрдд рдХрд░рдиреЗ рдХреЗ рд▓рд┐рдП рдПрдХ рд╕рд╛рд░реНрд╡рднреМрдорд┐рдХ рдлрд╝рдВрдХреНрд╢рди рд▓рд┐рдЦрдирд╛ рдореБрд╢реНрдХрд┐рд▓ рдирд╣реАрдВ рд╣реИ keras рдЗрдореЗрдЬрдиреЗрдЯ рдкрд░ рдкреНрд░рд╢рд┐рдХреНрд╖рд┐рдд рд╡рдЬрди рд╡рд╛рд▓реЗ рдпрд╛ рдмрд┐рдирд╛ рд╡рдЬрди рд╡рд╛рд▓реЗ рдореЙрдбрд▓:

рддреИрдпрд╛рд░ рдЖрд░реНрдХрд┐рдЯреЗрдХреНрдЪрд░ рдХреЛ рд▓реЛрдб рдХрд░рдиреЗ рдХрд╛ рдХрд╛рд░реНрдп

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 рдХреЗ рд╕рд╛рде-рд╕рд╛рде resnet34 рдХрд╛ рдЙрдкрдпреЛрдЧ рдХрд░рдХреЗ рдХрд┐рдПред SE-ResNeXt рдЬреИрд╕реЗ рдЕрдзрд┐рдХ рдЖрдзреБрдирд┐рдХ рдЖрд░реНрдХрд┐рдЯреЗрдХреНрдЪрд░ рдиреЗ рдЗрд╕ рдкреНрд░рддрд┐рдпреЛрдЧрд┐рддрд╛ рдореЗрдВ рдЕрдЪреНрдЫрд╛ рдкреНрд░рджрд░реНрд╢рди рдХрд┐рдпрд╛ред рджреБрд░реНрднрд╛рдЧреНрдп рд╕реЗ, рд╣рдорд╛рд░реЗ рдкрд╛рд╕ рддреИрдпрд╛рд░ рдХрд╛рд░реНрдпрд╛рдиреНрд╡рдпрди рдирд╣реАрдВ рдереЗ, рдФрд░ рд╣рдордиреЗ рдЕрдкрдирд╛ рд╕реНрд╡рдпрдВ рдХрд╛ рдХрд╛рд░реНрдпрд╛рдиреНрд╡рдпрди рдирд╣реАрдВ рд▓рд┐рдЦрд╛ (рд▓реЗрдХрд┐рди рд╣рдо рдирд┐рд╢реНрдЪрд┐рдд рд░реВрдк рд╕реЗ рд▓рд┐рдЦреЗрдВрдЧреЗ)ред

5. рд▓рд┐рдкрд┐рдпреЛрдВ рдХрд╛ рдорд╛рдирдХреАрдХрд░рдг

рд╕реБрд╡рд┐рдзрд╛ рдХреЗ рд▓рд┐рдП, рдкреНрд░рд╢рд┐рдХреНрд╖рдг рд╢реБрд░реВ рдХрд░рдиреЗ рдХреЗ рд▓рд┐рдП рд╕рднреА рдХреЛрдб рдХреЛ рдПрдХ рдПрдХрд▓ рд╕реНрдХреНрд░рд┐рдкреНрдЯ рдХреЗ рд░реВрдк рдореЗрдВ рдбрд┐рдЬрд╝рд╛рдЗрди рдХрд┐рдпрд╛ рдЧрдпрд╛ рдерд╛, рдЬрд┐рд╕рдХрд╛ рдЙрдкрдпреЛрдЧ рдкреИрд░рд╛рдореАрдЯрд░рдпреБрдХреНрдд рдХрд┐рдпрд╛ рдЧрдпрд╛ рдерд╛ docpt рдирд┐рдореНрдирд╛рдиреБрд╕рд╛рд░ рд╣реИ:

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)

рдкреИрдХреЗрдЬ docpt рдХрд╛рд░реНрдпрд╛рдиреНрд╡рдпрди рдХрд╛ рдкреНрд░рддрд┐рдирд┐рдзрд┐рддреНрд╡ рдХрд░рддрд╛ рд╣реИ 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 128x128 рдкрд┐рдХреНрд╕реЗрд▓ рдорд╛рдкрдиреЗ рд╡рд╛рд▓реА рддреАрди-рд░рдВрдЧ рдХреА рдЫрд╡рд┐рдпреЛрдВ рдкрд░, рдбреЗрдЯрд╛рдмреЗрд╕ рдлрд╝реЛрд▓реНрдбрд░ рдореЗрдВ рд╕реНрдерд┐рдд рд╣реЛрдирд╛ рдЪрд╛рд╣рд┐рдП /home/andrey/doodle_db). рдЖрдк рд╕реВрдЪреА рдореЗрдВ рд╕реАрдЦрдиреЗ рдХреА рдЧрддрд┐, рдЕрдиреБрдХреВрд▓рдХ рдкреНрд░рдХрд╛рд░ рдФрд░ рдХреЛрдИ рдЕрдиреНрдп рдЕрдиреБрдХреВрд▓рди рдпреЛрдЧреНрдп рдкреИрд░рд╛рдореАрдЯрд░ рдЬреЛрдбрд╝ рд╕рдХрддреЗ рд╣реИрдВред рдкреНрд░рдХрд╛рд╢рди рдХреА рддреИрдпрд╛рд░реА рдХреА рдкреНрд░рдХреНрд░рд┐рдпрд╛ рдореЗрдВ, рдпрд╣ рдкрддрд╛ рдЪрд▓рд╛ рдХрд┐ рд╡рд╛рд╕реНрддреБрдХрд▓рд╛ mobilenet_v2 рд╡рд░реНрддрдорд╛рди рд╕рдВрд╕реНрдХрд░рдг рд╕реЗ keras рдЖрд░ рдЙрдкрдпреЛрдЧ рдореЗрдВ рдмрд┐рд▓рдХреБрд▓ рдордирд╛ рд╣реИ рдЖрд░ рдкреИрдХреЗрдЬ рдореЗрдВ рдкрд░рд┐рд╡рд░реНрддрдиреЛрдВ рдкрд░ рдзреНрдпрд╛рди рдирд╣реАрдВ рджрд┐рдП рдЬрд╛рдиреЗ рдХреЗ рдХрд╛рд░рдг, рд╣рдо рдЗрд╕реЗ рдареАрдХ рдХрд░рдиреЗ рдХреЗ рд▓рд┐рдП рдЙрдирдХреА рдкреНрд░рддреАрдХреНрд╖рд╛ рдХрд░ рд░рд╣реЗ рд╣реИрдВред

рдЗрд╕ рджреГрд╖реНрдЯрд┐рдХреЛрдг рдиреЗ RStudio рдореЗрдВ рд╕реНрдХреНрд░рд┐рдкреНрдЯ рдХреЗ рдЕрдзрд┐рдХ рдкрд╛рд░рдВрдкрд░рд┐рдХ рд▓реЙрдиреНрдЪ рдХреА рддреБрд▓рдирд╛ рдореЗрдВ рд╡рд┐рднрд┐рдиреНрди рдореЙрдбрд▓реЛрдВ рдХреЗ рд╕рд╛рде рдкреНрд░рдпреЛрдЧреЛрдВ рдХреЛ рддреЗрдЬ рдХрд░рдирд╛ рд╕рдВрднрд╡ рдмрдирд╛ рджрд┐рдпрд╛ (рд╣рдо рдкреИрдХреЗрдЬ рдХреЛ рд╕рдВрднрд╛рд╡рд┐рдд рд╡рд┐рдХрд▓реНрдк рдХреЗ рд░реВрдк рдореЗрдВ рдиреЛрдЯ рдХрд░рддреЗ рд╣реИрдВ) tfruns). рд▓реЗрдХрд┐рди рдореБрдЦреНрдп рд▓рд╛рдн рдбреЙрдХрд░ рдореЗрдВ рдпрд╛ рдмрд╕ рд╕рд░реНрд╡рд░ рдкрд░ рд╕реНрдХреНрд░рд┐рдкреНрдЯ рдХреЗ рд▓реЙрдиреНрдЪ рдХреЛ рдЖрд╕рд╛рдиреА рд╕реЗ рдкреНрд░рдмрдВрдзрд┐рдд рдХрд░рдиреЗ рдХреА рдХреНрд╖рдорддрд╛ рд╣реИ, рдЗрд╕рдХреЗ рд▓рд┐рдП RStudio рдЗрдВрд╕реНрдЯреЙрд▓ рдХрд┐рдП рдмрд┐рдирд╛ред

6. рд╕реНрдХреНрд░рд┐рдкреНрдЯ рдХрд╛ рдбреЙрдХрд░реАрдХрд░рдг

рд╣рдордиреЗ рдЯреАрдо рдХреЗ рд╕рджрд╕реНрдпреЛрдВ рдХреЗ рдмреАрдЪ рдкреНрд░рд╢рд┐рдХреНрд╖рдг рдореЙрдбрд▓ рдХреЗ рд▓рд┐рдП рдФрд░ рдХреНрд▓рд╛рдЙрдб рдореЗрдВ рддреЗрдЬреА рд╕реЗ рддреИрдирд╛рддреА рдХреЗ рд▓рд┐рдП рдкрд░реНрдпрд╛рд╡рд░рдг рдХреА рдкреЛрд░реНрдЯреЗрдмрд┐рд▓рд┐рдЯреА рд╕реБрдирд┐рд╢реНрдЪрд┐рдд рдХрд░рдиреЗ рдХреЗ рд▓рд┐рдП рдбреЙрдХрд░ рдХрд╛ рдЙрдкрдпреЛрдЧ рдХрд┐рдпрд╛ред рдЖрдк рдЗрд╕ рдЯреВрд▓ рд╕реЗ рдкрд░рд┐рдЪрд┐рдд рд╣реЛрдирд╛ рд╢реБрд░реВ рдХрд░ рд╕рдХрддреЗ рд╣реИрдВ, рдЬреЛ рдПрдХ рдЖрд░ рдкреНрд░реЛрдЧреНрд░рд╛рдорд░ рдХреЗ рд▓рд┐рдП рдЕрдкреЗрдХреНрд╖рд╛рдХреГрдд рдЕрд╕рд╛рдорд╛рдиреНрдп рд╣реИ рдпрд╣ рдкреНрд░рдХрд╛рд╢рдиреЛрдВ рдХреА рд╢реНрд░реГрдВрдЦрд▓рд╛ рдпрд╛ рд╡реАрдбрд┐рдпреЛ рдкрд╛рдареНрдпрдХреНрд░рдо.

рдбреЙрдХрд░ рдЖрдкрдХреЛ рд╕реНрдХреНрд░реИрдЪ рд╕реЗ рдЕрдкрдиреА рдЦреБрдж рдХреА рдЫрд╡рд┐рдпрд╛рдВ рдмрдирд╛рдиреЗ рдФрд░ рдЕрдкрдиреА рдЦреБрдж рдХреА рдЫрд╡рд┐рдпрд╛рдВ рдмрдирд╛рдиреЗ рдХреЗ рд▓рд┐рдП рдЖрдзрд╛рд░ рдХреЗ рд░реВрдк рдореЗрдВ рдЕрдиреНрдп рдЫрд╡рд┐рдпреЛрдВ рдХрд╛ рдЙрдкрдпреЛрдЧ рдХрд░рдиреЗ рдХреА рдЕрдиреБрдорддрд┐ рджреЗрддрд╛ рд╣реИред рдЙрдкрд▓рдмреНрдз рд╡рд┐рдХрд▓реНрдкреЛрдВ рдХрд╛ рд╡рд┐рд╢реНрд▓реЗрд╖рдг рдХрд░рддреЗ рд╕рдордп, рд╣рдо рдЗрд╕ рдирд┐рд╖реНрдХрд░реНрд╖ рдкрд░ рдкрд╣реБрдВрдЪреЗ рдХрд┐ NVIDIA, CUDA+cuDNN рдбреНрд░рд╛рдЗрд╡рд░ рдФрд░ рдкрд╛рдпрдерди рд▓рд╛рдЗрдмреНрд░реЗрд░реА рд╕реНрдерд╛рдкрд┐рдд рдХрд░рдирд╛ рдЫрд╡рд┐ рдХрд╛ рдХрд╛рдлреА рдмрдбрд╝рд╛ рд╣рд┐рд╕реНрд╕рд╛ рд╣реИ, рдФрд░ рд╣рдордиреЗ рдЖрдзрд┐рдХрд╛рд░рд┐рдХ рдЫрд╡рд┐ рдХреЛ рдЖрдзрд╛рд░ рдХреЗ рд░реВрдк рдореЗрдВ рд▓реЗрдиреЗ рдХрд╛ рдирд┐рд░реНрдгрдп рд▓рд┐рдпрд╛ tensorflow/tensorflow:1.12.0-gpu, рд╡рд╣рд╛рдВ рдЖрд╡рд╢реНрдпрдХ рдЖрд░ рдкреИрдХреЗрдЬ рдЬреЛрдбрд╝рдирд╛ред

рдЕрдВрддрд┐рдо рдбреЛрдХрд░ рдлрд╝рд╛рдЗрд▓ рдЗрд╕ рддрд░рд╣ рджрд┐рдЦреА:

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. рдЗрд╕рд╕реЗ рдХреЛрдб рдореЗрдВ OS рд╕рдВрд╕реНрдХрд░рдг рдирд┐рд░реНрджрд┐рд╖реНрдЯ рдХрд░рдиреЗ рдХреА рдЖрд╡рд╢реНрдпрдХрддрд╛ рд╕реЗ рдмрдЪрд╛ рдЬрд╛ рд╕рдХрд╛ред

рдЗрд╕рдХреЗ рдЕрддрд┐рд░рд┐рдХреНрдд, рдПрдХ рдЫреЛрдЯреА рдмреИрд╢ рд╕реНрдХреНрд░рд┐рдкреНрдЯ рд▓рд┐рдЦреА рдЧрдИ рдереА рдЬреЛ рдЖрдкрдХреЛ рд╡рд┐рднрд┐рдиреНрди рдХрдорд╛рдВрдб рдХреЗ рд╕рд╛рде рдПрдХ рдХрдВрдЯреЗрдирд░ рд▓реЙрдиреНрдЪ рдХрд░рдиреЗ рдХреА рдЕрдиреБрдорддрд┐ рджреЗрддреА рд╣реИред рдЙрджрд╛рд╣рд░рдг рдХреЗ рд▓рд┐рдП, рдпреЗ рддрдВрддреНрд░рд┐рдХрд╛ рдиреЗрдЯрд╡рд░реНрдХ рдХреЗ рдкреНрд░рд╢рд┐рдХреНрд╖рдг рдХреЗ рд▓рд┐рдП рд╕реНрдХреНрд░рд┐рдкреНрдЯ рд╣реЛ рд╕рдХрддреЗ рд╣реИрдВ рдЬреЛ рдкрд╣рд▓реЗ рдХрдВрдЯреЗрдирд░ рдХреЗ рдЕрдВрджрд░ рд░рдЦреЗ рдЧрдП рдереЗ, рдпрд╛ рдбрд┐рдмрдЧрд┐рдВрдЧ рдФрд░ рдХрдВрдЯреЗрдирд░ рдХреЗ рд╕рдВрдЪрд╛рд▓рди рдХреА рдирд┐рдЧрд░рд╛рдиреА рдХреЗ рд▓рд┐рдП рдПрдХ рдХрдорд╛рдВрдб рд╢реЗрд▓ рд╣реЛ рд╕рдХрддреЗ рд╣реИрдВ:

рдХрдВрдЯреЗрдирд░ рд▓реЙрдиреНрдЪ рдХрд░рдиреЗ рдХреЗ рд▓рд┐рдП рд╕реНрдХреНрд░рд┐рдкреНрдЯ

#!/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. Google рдХреНрд▓рд╛рдЙрдб рдкрд░ рдПрдХрд╛рдзрд┐рдХ GPU рдХрд╛ рдЙрдкрдпреЛрдЧ рдХрд░рдирд╛

рдкреНрд░рддрд┐рдпреЛрдЧрд┐рддрд╛ рдХреА рд╡рд┐рд╢реЗрд╖рддрд╛рдУрдВ рдореЗрдВ рд╕реЗ рдПрдХ рдмрд╣реБрдд рд╢реЛрд░ рд╡рд╛рд▓рд╛ рдбреЗрдЯрд╛ рдерд╛ (рд╢реАрд░реНрд╖рдХ рдЪрд┐рддреНрд░ рджреЗрдЦреЗрдВ, ODS рд╕реНрд▓реИрдХ рд╕реЗ @Leigh.plt рд╕реЗ рдЙрдзрд╛рд░ рд▓рд┐рдпрд╛ рдЧрдпрд╛)ред рдмрдбрд╝реЗ рдмреИрдЪ рдЗрд╕рд╕реЗ рдирд┐рдкрдЯрдиреЗ рдореЗрдВ рдорджрдж рдХрд░рддреЗ рд╣реИрдВ, рдФрд░ 1 рдЬреАрдкреАрдпреВ рд╡рд╛рд▓реЗ рдкреАрд╕реА рдкрд░ рдкреНрд░рдпреЛрдЧреЛрдВ рдХреЗ рдмрд╛рдж, рд╣рдордиреЗ рдХреНрд▓рд╛рдЙрдб рдореЗрдВ рдХрдИ рдЬреАрдкреАрдпреВ рдкрд░ рдкреНрд░рд╢рд┐рдХреНрд╖рдг рдореЙрдбрд▓ рдореЗрдВ рдорд╣рд╛рд░рдд рд╣рд╛рд╕рд┐рд▓ рдХрд░рдиреЗ рдХрд╛ рдлреИрд╕рд▓рд╛ рдХрд┐рдпрд╛ред рдкреНрд░рдпреБрдХреНрдд GoogleCloud (рдмреБрдирд┐рдпрд╛рджреА рдмрд╛рддреЛрдВ рдХреЗ рд▓рд┐рдП рдЕрдЪреНрдЫрд╛ рдорд╛рд░реНрдЧрджрд░реНрд╢рдХ) рдЙрдкрд▓рдмреНрдз рдХреЙрдиреНрдлрд╝рд┐рдЧрд░реЗрд╢рди рдХреЗ рдмрдбрд╝реЗ рдЪрдпрди, рдЙрдЪрд┐рдд рдХреАрдорддреЛрдВ рдФрд░ $300 рдмреЛрдирд╕ рдХреЗ рдХрд╛рд░рдгред рд▓рд╛рд▓рдЪ рдХреЗ рдХрд╛рд░рдг, рдореИрдВрдиреЗ рдПрдХ SSD рдФрд░ рдПрдХ рдЯрди RAM рдХреЗ рд╕рд╛рде 4xV100 рдЗрдВрд╕реНрдЯреЗрдВрд╕ рдХрд╛ рдСрд░реНрдбрд░ рджрд┐рдпрд╛, рдФрд░ рдпрд╣ рдПрдХ рдмрдбрд╝реА рдЧрд▓рддреА рдереАред рдРрд╕реА рдорд╢реАрди рдкреИрд╕рд╛ рдЬрд▓реНрджреА рдЦрд╛ рдЬрд╛рддреА рд╣реИ; рдЖрдк рдмрд┐рдирд╛ рд╕рд┐рджреНрдз рдкрд╛рдЗрдкрд▓рд╛рдЗрди рдХреЗ рдкреНрд░рдпреЛрдЧ рдореЗрдВ рдЕрд╕рдлрд▓ рд╣реЛ рд╕рдХрддреЗ рд╣реИрдВред рд╢реИрдХреНрд╖рд┐рдХ рдЙрджреНрджреЗрд╢реНрдпреЛрдВ рдХреЗ рд▓рд┐рдП, K80 рд▓реЗрдирд╛ рдмреЗрд╣рддрд░ рд╣реИред рд▓реЗрдХрд┐рди рдмрдбрд╝реА рдорд╛рддреНрд░рд╛ рдореЗрдВ рд░реИрдо рдХрд╛рдо рдЖрдИ - рдХреНрд▓рд╛рдЙрдб рдПрд╕рдПрд╕рдбреА рдиреЗ рдЕрдкрдиреЗ рдкреНрд░рджрд░реНрд╢рди рд╕реЗ рдкреНрд░рднрд╛рд╡рд┐рдд рдирд╣реАрдВ рдХрд┐рдпрд╛, рдЗрд╕рд▓рд┐рдП рдбреЗрдЯрд╛рдмреЗрд╕ рдХреЛ рд╕реНрдерд╛рдирд╛рдВрддрд░рд┐рдд рдХрд░ рджрд┐рдпрд╛ рдЧрдпрд╛ 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
  )
})

рдлрд┐рд░ рдЕрд╕рдВрдХрд▓рд┐рдд (рдпрд╣ рдорд╣рддреНрд╡рдкреВрд░реНрдг рд╣реИ) рдореЙрдбрд▓ рдХреЛ рдЙрдкрд▓рдмреНрдз GPU рдХреА рджреА рдЧрдИ рд╕рдВрдЦреНрдпрд╛ рдореЗрдВ рдХреЙрдкреА рдХрд┐рдпрд╛ рдЬрд╛рддрд╛ рд╣реИ, рдФрд░ рдЙрд╕рдХреЗ рдмрд╛рдж рд╣реА рдЗрд╕реЗ рд╕рдВрдХрд▓рд┐рдд рдХрд┐рдпрд╛ рдЬрд╛рддрд╛ рд╣реИ:

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. рдирд┐рд╖реНрдХрд░реНрд╖ рдХреЗ рдмрдЬрд╛рдп

рд╣рдордиреЗ рдЬрд┐рди рдХрдИ рд╕рдорд╕реНрдпрд╛рдУрдВ рдХрд╛ рд╕рд╛рдордирд╛ рдХрд┐рдпрд╛ рд╣реИ, рдЙрдиреНрд╣реЗрдВ рдЕрднреА рддрдХ рджреВрд░ рдирд╣реАрдВ рдХрд┐рдпрд╛ рдЬрд╛ рд╕рдХрд╛ рд╣реИ:

  • ╨▓ keras рдЗрд╖реНрдЯрддрдо рд╕реАрдЦрдиреЗ рдХреА рджрд░ (рдПрдирд╛рд▓реЙрдЧ) рдХреЗ рд▓рд┐рдП рд╕реНрд╡рдЪрд╛рд▓рд┐рдд рд░реВрдк рд╕реЗ рдЦреЛрдЬ рдХрд░рдиреЗ рдХреЗ рд▓рд┐рдП рдХреЛрдИ рддреИрдпрд╛рд░ рдлрд╝рдВрдХреНрд╢рди рдирд╣реАрдВ рд╣реИ lr_finder рдкреБрд╕реНрддрдХрд╛рд▓рдп рдореЗрдВ рддреЗрдЬреА рд╕реЗ); рдХреБрдЫ рдкреНрд░рдпрд╛рд╕реЛрдВ рд╕реЗ, рддреГрддреАрдп-рдкрдХреНрд╖ рдХрд╛рд░реНрдпрд╛рдиреНрд╡рдпрди рдХреЛ R рдореЗрдВ рдкреЛрд░реНрдЯ рдХрд░рдирд╛ рд╕рдВрднрд╡ рд╣реИ, рдЙрджрд╛рд╣рд░рдг рдХреЗ рд▓рд┐рдП, рдпрд╣;
  • рдкрд┐рдЫрд▓реЗ рдмрд┐рдВрджреБ рдХреЗ рдкрд░рд┐рдгрд╛рдорд╕реНрд╡рд░реВрдк, рдХрдИ рдЬреАрдкреАрдпреВ рдХрд╛ рдЙрдкрдпреЛрдЧ рдХрд░рддреЗ рд╕рдордп рд╕рд╣реА рдкреНрд░рд╢рд┐рдХреНрд╖рдг рдЧрддрд┐ рдХрд╛ рдЪрдпрди рдХрд░рдирд╛ рд╕рдВрднрд╡ рдирд╣реАрдВ рдерд╛;
  • рдЖрдзреБрдирд┐рдХ рддрдВрддреНрд░рд┐рдХрд╛ рдиреЗрдЯрд╡рд░реНрдХ рдЖрд░реНрдХрд┐рдЯреЗрдХреНрдЪрд░ рдХреА рдХрдореА рд╣реИ, рд╡рд┐рд╢реЗрд╖ рд░реВрдк рд╕реЗ рдЗрдореЗрдЬрдиреЗрдЯ рдкрд░ рдкреВрд░реНрд╡-рдкреНрд░рд╢рд┐рдХреНрд╖рд┐рдд;
  • рдХреЛрдИ рдПрдХ рдЪрдХреНрд░ рдиреАрддрд┐ рдФрд░ рднреЗрджрднрд╛рд╡рдкреВрд░реНрдг рд╕реАрдЦрдиреЗ рдХреА рджрд░ (рдХреЛрд╕рд╛рдЗрди рдПрдиреАрд▓рд┐рдВрдЧ рд╣рдорд╛рд░реЗ рдЕрдиреБрд░реЛрдз рдкрд░ рдирд╣реАрдВ рдереА рдХрд╛рд░реНрдпрд╛рдиреНрд╡рд┐рдд, рдзрдиреНрдпрд╡рд╛рдж рд╕реНрдХрд╛рдИрдбреИрди).

рдЗрд╕ рдкреНрд░рддрд┐рдпреЛрдЧрд┐рддрд╛ рд╕реЗ рдХреМрди рд╕реА рдЙрдкрдпреЛрдЧреА рдмрд╛рддреЗрдВ рд╕реАрдЦреАрдВ:

  • рдЕрдкреЗрдХреНрд╖рд╛рдХреГрдд рдХрдо-рд╢рдХреНрддрд┐ рд╡рд╛рд▓реЗ рд╣рд╛рд░реНрдбрд╡реЗрдпрд░ рдкрд░, рдЖрдк рдмрд┐рдирд╛ рдХрд┐рд╕реА рдкрд░реЗрд╢рд╛рдиреА рдХреЗ рдЕрдЪреНрдЫреА рдорд╛рддреНрд░рд╛ рдореЗрдВ (рд░реИрдо рдХреЗ рдЖрдХрд╛рд░ рд╕реЗ рдХрдИ рдЧреБрдирд╛ рдЕрдзрд┐рдХ) рдбреЗрдЯрд╛ рдХреЗ рд╕рд╛рде рдХрд╛рдо рдХрд░ рд╕рдХрддреЗ рд╣реИрдВред рдкреНрд▓рд╛рд╕реНрдЯрд┐рдХ рдмреИрдЧ рдбреЗрдЯрд╛ рддрд╛рд▓рд┐рдХрд╛ рддрд╛рд▓рд┐рдХрд╛рдУрдВ рдХреЗ рд╕реНрдерд╛рди-рд╕реНрдерд╛рди рдкрд░ рд╕рдВрд╢реЛрдзрди рдХреЗ рдХрд╛рд░рдг рдореЗрдореЛрд░реА рдХреА рдмрдЪрдд рд╣реЛрддреА рд╣реИ, рдЬрд┐рд╕рд╕реЗ рдЙрдиреНрд╣реЗрдВ рдХреЙрдкреА рдХрд░рдиреЗ рд╕реЗ рдмрдЪрд╛ рдЬрд╛рддрд╛ рд╣реИ, рдФрд░ рдЬрдм рд╕рд╣реА рдврдВрдЧ рд╕реЗ рдЙрдкрдпреЛрдЧ рдХрд┐рдпрд╛ рдЬрд╛рддрд╛ рд╣реИ, рддреЛ рдЗрд╕рдХреА рдХреНрд╖рдорддрд╛рдПрдВ рд▓рдЧрднрдЧ рд╣рдореЗрд╢рд╛ рд╕реНрдХреНрд░рд┐рдкреНрдЯрд┐рдВрдЧ рднрд╛рд╖рд╛рдУрдВ рдХреЗ рд▓рд┐рдП рдЬреНрдЮрд╛рдд рд╕рднреА рдЙрдкрдХрд░рдгреЛрдВ рдХреЗ рдмреАрдЪ рдЙрдЪреНрдЪрддрдо рдЧрддрд┐ рдкреНрд░рджрд░реНрд╢рд┐рдд рдХрд░рддреА рд╣реИрдВред рдбреЗрдЯрд╛рдмреЗрд╕ рдореЗрдВ рдбреЗрдЯрд╛ рд╕рд╣реЗрдЬрдиреЗ рд╕реЗ, рдХрдИ рдорд╛рдорд▓реЛрдВ рдореЗрдВ, рдЖрдкрдХреЛ рдкреВрд░реЗ рдбреЗрдЯрд╛рд╕реЗрдЯ рдХреЛ рд░реИрдо рдореЗрдВ рдирд┐рдЪреЛрдбрд╝рдиреЗ рдХреА рдЖрд╡рд╢реНрдпрдХрддрд╛ рдХреЗ рдмрд╛рд░реЗ рдореЗрдВ рдмрд┐рд▓реНрдХреБрд▓ рднреА рдирд╣реАрдВ рд╕реЛрдЪрдиреЗ рдХреА рдЕрдиреБрдорддрд┐ рдорд┐рд▓рддреА рд╣реИред
  • рдкреИрдХреЗрдЬ рдХрд╛ рдЙрдкрдпреЛрдЧ рдХрд░рдХреЗ R рдореЗрдВ рдзреАрдореЗ рдлрд╝рдВрдХреНрд╢рдВрд╕ рдХреЛ C++ рдореЗрдВ рддреЗрдЬрд╝ рдлрд╝рдВрдХреНрд╢рдВрд╕ рд╕реЗ рдмрджрд▓рд╛ рдЬрд╛ рд╕рдХрддрд╛ рд╣реИ рдЖрд░рд╕реАрдкреАрдкреА. рдпрджрд┐ рдЙрдкрдпреЛрдЧ рдХреЗ рдЕрддрд┐рд░рд┐рдХреНрдд рдЖрд░рд╕реАрдкреАрдкреАрдереНрд░реЗрдб рдпрд╛ Rcppрд╕рдорд╛рдирд╛рдВрддрд░, рд╣рдореЗрдВ рдХреНрд░реЙрд╕-рдкреНрд▓реЗрдЯрдлрд╝реЙрд░реНрдо рдорд▓реНрдЯреА-рдереНрд░реЗрдбреЗрдб рдХрд╛рд░реНрдпрд╛рдиреНрд╡рдпрди рдорд┐рд▓рддрд╛ рд╣реИ, рдЗрд╕рд▓рд┐рдП рдЖрд░ рд╕реНрддрд░ рдкрд░ рдХреЛрдб рдХреЛ рд╕рдорд╛рдирд╛рдВрддрд░ рдХрд░рдиреЗ рдХреА рдХреЛрдИ рдЖрд╡рд╢реНрдпрдХрддрд╛ рдирд╣реАрдВ рд╣реИред
  • рдкреИрдХреЗрдЬ рдЖрд░рд╕реАрдкреАрдкреА C++ рдХреЗ рдЧрдВрднреАрд░ рдЬреНрдЮрд╛рди рдХреЗ рдмрд┐рдирд╛ рдЙрдкрдпреЛрдЧ рдХрд┐рдпрд╛ рдЬрд╛ рд╕рдХрддрд╛ рд╣реИ, рдЖрд╡рд╢реНрдпрдХ рдиреНрдпреВрдирддрдо рд░реВрдкрд░реЗрдЦрд╛ рджреА рдЧрдИ рд╣реИ рдпрд╣рд╛рдВ. рдЬреИрд╕реЗ рдХрдИ рд╢рд╛рдирджрд╛рд░ рд╕реА-рд▓рд╛рдЗрдмреНрд░реЗрд░реА рдХреЗ рд▓рд┐рдП рд╣реЗрдбрд░ рдлрд╝рд╛рдЗрд▓реЗрдВ xtensor рд╕реАрдЖрд░рдПрдПрди рдкрд░ рдЙрдкрд▓рдмреНрдз рд╣реИ, рдпрд╛рдиреА, рдкрд░рд┐рдпреЛрдЬрдирд╛рдУрдВ рдХреЗ рдХрд╛рд░реНрдпрд╛рдиреНрд╡рдпрди рдХреЗ рд▓рд┐рдП рдПрдХ рдмреБрдирд┐рдпрд╛рджреА рдврд╛рдВрдЪрд╛ рддреИрдпрд╛рд░ рдХрд┐рдпрд╛ рдЬрд╛ рд░рд╣рд╛ рд╣реИ рдЬреЛ рддреИрдпрд╛рд░ рдЙрдЪреНрдЪ-рдкреНрд░рджрд░реНрд╢рди рд╕реА ++ рдХреЛрдб рдХреЛ рдЖрд░ рдореЗрдВ рдПрдХреАрдХреГрдд рдХрд░рддрд╛ рд╣реИред рдЕрддрд┐рд░рд┐рдХреНрдд рд╕реБрд╡рд┐рдзрд╛ рд╕рд┐рдВрдЯреИрдХреНрд╕ рд╣рд╛рдЗрд▓рд╛рдЗрдЯрд┐рдВрдЧ рдФрд░ RStudio рдореЗрдВ рдПрдХ рд╕реНрдерд┐рд░ C++ рдХреЛрдб рд╡рд┐рд╢реНрд▓реЗрд╖рдХ рд╣реИред
  • docpt рдЖрдкрдХреЛ рдорд╛рдкрджрдВрдбреЛрдВ рдХреЗ рд╕рд╛рде рд╕реНрд╡-рдирд┐рд╣рд┐рдд рд╕реНрдХреНрд░рд┐рдкреНрдЯ рдЪрд▓рд╛рдиреЗ рдХреА рдЕрдиреБрдорддрд┐ рджреЗрддрд╛ рд╣реИред рдпрд╣ рд░рд┐рдореЛрдЯ рд╕рд░реНрд╡рд░ рд╕рд╣рд┐рдд рдЕрдиреНрдп рдкрд░ рдЙрдкрдпреЛрдЧ рдХреЗ рд▓рд┐рдП рд╕реБрд╡рд┐рдзрд╛рдЬрдирдХ рд╣реИред рдбреЙрдХрд░ рдХреЗ рдЕрдВрддрд░реНрдЧрддред RStudio рдореЗрдВ, рддрдВрддреНрд░рд┐рдХрд╛ рдиреЗрдЯрд╡рд░реНрдХ рдХреЗ рдкреНрд░рд╢рд┐рдХреНрд╖рдг рдХреЗ рд╕рд╛рде рдХрдИ рдШрдВрдЯреЛрдВ рдХреЗ рдкреНрд░рдпреЛрдЧ рдХрд░рдирд╛ рдЕрд╕реБрд╡рд┐рдзрд╛рдЬрдирдХ рд╣реИ, рдФрд░ рд╕рд░реНрд╡рд░ рдкрд░ IDE рд╕реНрдерд╛рдкрд┐рдд рдХрд░рдирд╛ рд╣рдореЗрд╢рд╛ рдЙрдЪрд┐рдд рдирд╣реАрдВ рд╣реЛрддрд╛ рд╣реИред
  • рдбреЙрдХрд░ рдУрдПрд╕ рдФрд░ рд▓рд╛рдЗрдмреНрд░реЗрд░реА рдХреЗ рд╡рд┐рднрд┐рдиреНрди рд╕рдВрд╕реНрдХрд░рдгреЛрдВ рд╡рд╛рд▓реЗ рдбреЗрд╡рд▓рдкрд░реНрд╕ рдХреЗ рдмреАрдЪ рдХреЛрдб рдкреЛрд░реНрдЯреЗрдмрд┐рд▓рд┐рдЯреА рдФрд░ рдкрд░рд┐рдгрд╛рдореЛрдВ рдХреА рдкреНрд░рддрд┐рд▓рд┐рдкрд┐ рдкреНрд░рд╕реНрддреБрдд рдХрд░рдиреЗ рдпреЛрдЧреНрдпрддрд╛ рд╕реБрдирд┐рд╢реНрдЪрд┐рдд рдХрд░рддрд╛ рд╣реИ, рд╕рд╛рде рд╣реА рд╕рд░реНрд╡рд░ рдкрд░ рдирд┐рд╖реНрдкрд╛рджрди рдореЗрдВ рдЖрд╕рд╛рдиреА рднреА рд╕реБрдирд┐рд╢реНрдЪрд┐рдд рдХрд░рддрд╛ рд╣реИред рдЖрдк рдХреЗрд╡рд▓ рдПрдХ рдХрдорд╛рдВрдб рд╕реЗ рд╕рдВрдкреВрд░реНрдг рдкреНрд░рд╢рд┐рдХреНрд╖рдг рдкрд╛рдЗрдкрд▓рд╛рдЗрди рд▓реЙрдиреНрдЪ рдХрд░ рд╕рдХрддреЗ рд╣реИрдВред
  • Google рдХреНрд▓рд╛рдЙрдб рдорд╣рдВрдЧреЗ рд╣рд╛рд░реНрдбрд╡реЗрдпрд░ рдкрд░ рдкреНрд░рдпреЛрдЧ рдХрд░рдиреЗ рдХрд╛ рдПрдХ рдмрдЬрдЯ-рдЕрдиреБрдХреВрд▓ рддрд░реАрдХрд╛ рд╣реИ, рд▓реЗрдХрд┐рди рдЖрдкрдХреЛ рдХреЙрдиреНрдлрд╝рд┐рдЧрд░реЗрд╢рди рд╕рд╛рд╡рдзрд╛рдиреА рд╕реЗ рдЪреБрдирдиреЗ рдХреА рдЖрд╡рд╢реНрдпрдХрддрд╛ рд╣реИред
  • рдЕрд▓рдЧ-рдЕрд▓рдЧ рдХреЛрдб рдЕрдВрд╢реЛрдВ рдХреА рдЧрддрд┐ рдХреЛ рдорд╛рдкрдирд╛ рдмрд╣реБрдд рдЙрдкрдпреЛрдЧреА рд╣реИ, рдЦрд╛рд╕рдХрд░ рдЬрдм рдЖрд░ рдФрд░ рд╕реА++ рдФрд░ рдкреИрдХреЗрдЬ рдХреЗ рд╕рд╛рде рд╕рдВрдпреЛрдЬрди рдХрд░рддреЗ рд╕рдордп рдмреЗрдВрдЪ - рдмрд╣реБрдд рдЖрд╕рд╛рди рднреА.

рдХреБрд▓ рдорд┐рд▓рд╛рдХрд░ рдпрд╣ рдЕрдиреБрднрд╡ рдмрд╣реБрдд рдлрд╛рдпрджреЗрдордВрдж рд░рд╣рд╛ рдФрд░ рд╣рдо рдЙрдард╛рдП рдЧрдП рдХреБрдЫ рдореБрджреНрджреЛрдВ рдХреЛ рд╣рд▓ рдХрд░рдиреЗ рдХреЗ рд▓рд┐рдП рдХрд╛рдо рдХрд░рдирд╛ рдЬрд╛рд░реА рд░рдЦреЗрдВрдЧреЗред

рд╕реНрд░реЛрдд: www.habr.com

рдПрдХ рдЯрд┐рдкреНрдкрдгреА рдЬреЛрдбрд╝реЗрдВ