ΠΡ Π₯Π°Π±Ρ!
ΠΠΈΠ½Π°ΡΠ°ΡΠ° Π΅ΡΠ΅Π½, Kaggle Π±Π΅ΡΠ΅ Π΄ΠΎΠΌΠ°ΡΠΈΠ½ Π½Π° Π½Π°ΡΠΏΡΠ΅Π²Π°Ρ Π·Π° ΠΊΠ»Π°ΡΠΈΡΠΈΠΊΠ°ΡΠΈΡΠ° Π½Π° ΡΠ°ΡΠ½ΠΎ Π½Π°ΡΡΡΠ°Π½ΠΈ ΡΠ»ΠΈΠΊΠΈ, Quick Draw Doodle Recognition, Π²ΠΎ ΠΊΠΎΡ, ΠΌΠ΅ΡΡ Π΄ΡΡΠ³ΠΎΡΠΎ, ΡΡΠ΅ΡΡΠ²ΡΠ²Π°ΡΠ΅ ΠΈ ΡΠΈΠΌ ΠΎΠ΄ Π -Π½Π°ΡΡΠ½ΠΈΡΠΈ:
ΠΠ²ΠΎΡ ΠΏΠ°Ρ Π½Π΅ ΡΡΠΏΠ΅Π° ΡΠΎ ΠΎΠ΄Π³Π»Π΅Π΄ΡΠ²Π°ΡΠ΅ ΠΌΠ΅Π΄Π°Π»ΠΈ, Π½ΠΎ ΡΠ΅ ΡΡΠ΅ΠΊΠ½Π° ΠΌΠ½ΠΎΠ³Ρ Π΄ΡΠ°Π³ΠΎΡΠ΅Π½ΠΎ ΠΈΡΠΊΡΡΡΠ²ΠΎ, ΠΏΠ° Π±ΠΈ ΡΠ°ΠΊΠ°Π» Π΄Π° ΠΈ ΠΊΠ°ΠΆΠ°ΠΌ Π½Π° Π·Π°Π΅Π΄Π½ΠΈΡΠ°ΡΠ° Π·Π° Π³ΠΎΠ»Π΅ΠΌ Π±ΡΠΎΡ ΠΎΠ΄ Π½Π°ΡΠΈΠ½ΡΠ΅ΡΠ΅ΡΠ½ΠΈΡΠ΅ ΠΈ Π½Π°ΡΠΊΠΎΡΠΈΡΠ½ΠΈΡΠ΅ ΡΠ°Π±ΠΎΡΠΈ Π½Π° ΠΠ°Π³Π»Π΅ ΠΈ Π²ΠΎ ΡΠ΅ΠΊΠΎΡΠ΄Π½Π΅Π²Π½Π°ΡΠ° ΡΠ°Π±ΠΎΡΠ°. ΠΠ΅ΡΡ ΡΠ΅ΠΌΠΈΡΠ΅ Π·Π° ΠΊΠΎΠΈ ΡΠ΅ Π΄ΠΈΡΠΊΡΡΠΈΡΠ°ΡΠ΅: ΡΠ΅ΠΆΠΎΠΊ ΠΆΠΈΠ²ΠΎΡ Π±Π΅Π· OpenCV, JSON ΠΏΠ°ΡΡΠΈΡΠ°ΡΠ΅ (ΠΎΠ²ΠΈΠ΅ ΠΏΡΠΈΠΌΠ΅ΡΠΈ ΡΠ° ΠΈΡΠΏΠΈΡΡΠ²Π°Π°Ρ ΠΈΠ½ΡΠ΅Π³ΡΠ°ΡΠΈΡΠ°ΡΠ° Π½Π° C++ ΠΊΠΎΠ΄ΠΎΡ Π²ΠΎ ΡΠΊΡΠΈΠΏΡΠΈ ΠΈΠ»ΠΈ ΠΏΠ°ΠΊΠ΅ΡΠΈ Π²ΠΎ R ΠΊΠΎΡΠΈΡΡΠ΅ΡΡΠΈ Rcpp), ΠΏΠ°ΡΠ°ΠΌΠ΅ΡΠ°ΡΠΈΠ·Π°ΡΠΈΡΠ° Π½Π° ΡΠΊΡΠΈΠΏΡΠΈ ΠΈ Π΄ΠΎΠΊΠ΅ΡΠΈΠ·Π°ΡΠΈΡΠ° Π½Π° ΠΊΠΎΠ½Π΅ΡΠ½ΠΎΡΠΎ ΡΠ΅ΡΠ΅Π½ΠΈΠ΅. Π¦Π΅Π»ΠΈΠΎΡ ΠΊΠΎΠ΄ ΠΎΠ΄ ΠΏΠΎΡΠ°ΠΊΠ°ΡΠ° Π²ΠΎ ΡΠΎΡΠΌΠ° ΠΏΠΎΠ³ΠΎΠ΄Π½Π° Π·Π° ΠΈΠ·Π²ΡΡΡΠ²Π°ΡΠ΅ Π΅ Π΄ΠΎΡΡΠ°ΠΏΠ΅Π½ Π²ΠΎ
Π‘ΠΎΠ΄ΡΠΆΠΈΠ½Π°:
ΠΡΠΈΠΊΠ°ΡΠ½ΠΎ Π²ΡΠΈΡΠ°ΡΡΠ΅ ΠΏΠΎΠ΄Π°ΡΠΎΡΠΈ ΠΎΠ΄ CSV Π²ΠΎ MonetDB ΠΠΎΠ΄Π³ΠΎΡΠΎΠ²ΠΊΠ° Π½Π° ΡΠ΅ΡΠΈΠΈ ΠΡΠ΅ΡΠ°ΡΠΎΡΠΈ Π·Π° ΠΈΡΡΠΎΠ²Π°Ρ Π½Π° ΡΠ΅ΡΠΈΠΈ ΠΎΠ΄ Π±Π°Π·Π°ΡΠ° Π½Π° ΠΏΠΎΠ΄Π°ΡΠΎΡΠΈ ΠΠ·Π±ΠΎΡ Π½Π° ΠΌΠΎΠ΄Π΅Π» Π½Π° Π°ΡΡ ΠΈΡΠ΅ΠΊΡΡΡΠ° ΠΠ°ΡΠ°ΠΌΠ΅ΡΠ°ΡΠΈΠ·Π°ΡΠΈΡΠ° Π½Π° ΡΠΊΡΠΈΠΏΡΠ° ΠΠΎΠΊΠ΅ΡΠΈΠ·Π°ΡΠΈΡΠ° Π½Π° ΡΠΊΡΠΈΠΏΡΠΈ ΠΠΎΡΠΈΡΡΠ΅ΡΠ΅ Π½Π° ΠΏΠΎΠ²Π΅ΡΠ΅ Π³ΡΠ°ΡΠΈΡΠΊΠΈ ΠΏΡΠΎΡΠ΅ΡΠΎΡΠΈ Π½Π° Google Cloud ΠΠ°ΠΌΠ΅ΡΡΠΎ Π·Π°ΠΊΠ»ΡΡΠΎΠΊ
1. ΠΡΠΈΠΊΠ°ΡΠ½ΠΎ Π²ΡΠΈΡΠ°ΡΡΠ΅ ΠΏΠΎΠ΄Π°ΡΠΎΡΠΈ ΠΎΠ΄ CSV Π²ΠΎ Π±Π°Π·Π°ΡΠ° Π½Π° ΠΏΠΎΠ΄Π°ΡΠΎΡΠΈ Π½Π° MonetDB
ΠΠΎΠ΄Π°ΡΠΎΡΠΈΡΠ΅ Π²ΠΎ ΠΎΠ²ΠΎΡ Π½Π°ΡΠΏΡΠ΅Π²Π°Ρ Π½Π΅ ΡΠ΅ ΠΎΠ±Π΅Π·Π±Π΅Π΄Π΅Π½ΠΈ Π²ΠΎ ΡΠΎΡΠΌΠ° Π½Π° Π³ΠΎΡΠΎΠ²ΠΈ ΡΠ»ΠΈΠΊΠΈ, ΡΡΠΊΡ Π²ΠΎ ΡΠΎΡΠΌΠ° Π½Π° 340 CSV Π΄Π°ΡΠΎΡΠ΅ΠΊΠΈ (ΠΏΠΎ Π΅Π΄Π½Π° Π΄Π°ΡΠΎΡΠ΅ΠΊΠ° Π·Π° ΡΠ΅ΠΊΠΎΡΠ° ΠΊΠ»Π°ΡΠ°) ΠΊΠΎΠΈ ΡΠΎΠ΄ΡΠΆΠ°Ρ JSON ΡΠΎ ΠΊΠΎΠΎΡΠ΄ΠΈΠ½Π°ΡΠΈ Π½Π° ΡΠΎΡΠΊΠΈ. Π‘ΠΎ ΠΏΠΎΠ²ΡΠ·ΡΠ²Π°ΡΠ΅ Π½Π° ΠΎΠ²ΠΈΠ΅ ΡΠΎΡΠΊΠΈ ΡΠΎ Π»ΠΈΠ½ΠΈΠΈ, Π΄ΠΎΠ±ΠΈΠ²Π°ΠΌΠ΅ ΠΊΠΎΠ½Π΅ΡΠ½Π° ΡΠ»ΠΈΠΊΠ° ΡΠΎ Π΄ΠΈΠΌΠ΅Π½Π·ΠΈΠΈ 256x256 ΠΏΠΈΠΊΡΠ΅Π»ΠΈ. ΠΡΡΠΎ ΡΠ°ΠΊΠ°, Π·Π° ΡΠ΅ΠΊΠΎΡ Π·Π°ΠΏΠΈΡ ΠΈΠΌΠ° Π΅ΡΠΈΠΊΠ΅ΡΠ° ΡΡΠΎ ΠΏΠΎΠΊΠ°ΠΆΡΠ²Π° Π΄Π°Π»ΠΈ ΡΠ»ΠΈΠΊΠ°ΡΠ° Π΅ ΠΏΡΠ°Π²ΠΈΠ»Π½ΠΎ ΠΏΡΠ΅ΠΏΠΎΠ·Π½Π°Π΅Π½Π° ΠΎΠ΄ ΠΊΠ»Π°ΡΠΈΡΠΈΠΊΠ°ΡΠΎΡΠΎΡ ΡΡΠΎ ΡΠ΅ ΠΊΠΎΡΠΈΡΡΠ΅Π» Π²ΠΎ ΠΌΠΎΠΌΠ΅Π½ΡΠΎΡ Π½Π° ΡΠΎΠ±ΠΈΡΠ°ΡΠ΅ Π½Π° Π±Π°Π·Π°ΡΠ°, ΡΠΈΡΡΠ° ΡΠΎ Π΄Π²Π΅ Π±ΡΠΊΠ²ΠΈ Π½Π° Π·Π΅ΠΌΡΠ°ΡΠ° Π½Π° ΠΆΠΈΠ²Π΅Π΅ΡΠ΅ Π½Π° Π°Π²ΡΠΎΡΠΎΡ Π½Π° ΡΠ»ΠΈΠΊΠ°ΡΠ°, Π΅Π΄ΠΈΠ½ΡΡΠ²Π΅Π½ ΠΈΠ΄Π΅Π½ΡΠΈΡΠΈΠΊΠ°ΡΠΎΡ, Π²ΡΠ΅ΠΌΠ΅Π½ΡΠΊΠΈ ΠΏΠ΅ΡΠ°Ρ ΠΈ ΠΈΠΌΠ΅ Π½Π° ΠΊΠ»Π°ΡΠ° ΡΡΠΎ ΡΠ΅ ΡΠΎΠ²ΠΏΠ°ΡΠ° ΡΠΎ ΠΈΠΌΠ΅ΡΠΎ Π½Π° Π΄Π°ΡΠΎΡΠ΅ΠΊΠ°ΡΠ°. ΠΠΎΠ΅Π΄Π½ΠΎΡΡΠ°Π²Π΅Π½Π°ΡΠ° Π²Π΅ΡΠ·ΠΈΡΠ° Π½Π° ΠΎΡΠΈΠ³ΠΈΠ½Π°Π»Π½ΠΈΡΠ΅ ΠΏΠΎΠ΄Π°ΡΠΎΡΠΈ ΡΠ΅ΠΆΠΈ 7.4 GB Π²ΠΎ Π°ΡΡ ΠΈΠ²Π°ΡΠ° ΠΈ ΠΏΡΠΈΠ±Π»ΠΈΠΆΠ½ΠΎ 20 GB ΠΏΠΎ ΡΠ°ΡΠΏΠ°ΠΊΡΠ²Π°ΡΠ΅ΡΠΎ, ΡΠ΅Π»ΠΎΡΠ½ΠΈΡΠ΅ ΠΏΠΎΠ΄Π°ΡΠΎΡΠΈ ΠΏΠΎ ΡΠ°ΡΠΏΠ°ΠΊΡΠ²Π°ΡΠ΅ΡΠΎ Π·Π°ΡΠ°ΡΠ°Π°Ρ 240 GB. ΠΡΠ³Π°Π½ΠΈΠ·Π°ΡΠΎΡΠΈΡΠ΅ ΡΠ΅ ΠΏΠΎΠ³ΡΠΈΠΆΠΈΡΠ° Π΄Π²Π΅ΡΠ΅ Π²Π΅ΡΠ·ΠΈΠΈ Π΄Π° Π³ΠΈ ΡΠ΅ΠΏΡΠΎΠ΄ΡΡΠΈΡΠ°Π°Ρ ΠΈΡΡΠΈΡΠ΅ ΡΡΡΠ΅ΠΆΠΈ, ΡΡΠΎ Π·Π½Π°ΡΠΈ Π΄Π΅ΠΊΠ° ΡΠ΅Π»ΠΎΡΠ½Π°ΡΠ° Π²Π΅ΡΠ·ΠΈΡΠ° Π΅ ΠΈΠ·Π»ΠΈΡΠ½Π°. ΠΠΎ ΡΠ΅ΠΊΠΎΡ ΡΠ»ΡΡΠ°Ρ, ΡΠΊΠ»Π°Π΄ΠΈΡΠ°ΡΠ΅ΡΠΎ Π½Π° 50 ΠΌΠΈΠ»ΠΈΠΎΠ½ΠΈ ΡΠ»ΠΈΠΊΠΈ Π²ΠΎ Π³ΡΠ°ΡΠΈΡΠΊΠΈ Π΄Π°ΡΠΎΡΠ΅ΠΊΠΈ ΠΈΠ»ΠΈ Π²ΠΎ ΡΠΎΡΠΌΠ° Π½Π° Π½ΠΈΠ·ΠΈ Π²Π΅Π΄Π½Π°Ρ ΡΠ΅ ΡΠΌΠ΅ΡΠ°ΡΠ΅ Π·Π° Π½Π΅ΠΏΡΠΎΡΠΈΡΠ°Π±ΠΈΠ»Π½ΠΎ ΠΈ ΡΠ΅ΡΠΈΠ²ΠΌΠ΅ Π΄Π° Π³ΠΈ ΡΠΏΠΎΠΈΠΌΠ΅ ΡΠΈΡΠ΅ CSV-Π΄Π°ΡΠΎΡΠ΅ΠΊΠΈ ΠΎΠ΄ Π°ΡΡ ΠΈΠ²Π°ΡΠ° train_simplified.zip Π²ΠΎ Π±Π°Π·Π°ΡΠ° Π½Π° ΠΏΠΎΠ΄Π°ΡΠΎΡΠΈ ΡΠΎ ΠΏΠΎΡΠ»Π΅Π΄ΠΎΠ²Π°ΡΠ΅Π»Π½ΠΎ Π³Π΅Π½Π΅ΡΠΈΡΠ°ΡΠ΅ Π½Π° ΡΠ»ΠΈΠΊΠΈ ΡΠΎ ΠΏΠΎΡΡΠ΅Π±Π½Π°ΡΠ° Π³ΠΎΠ»Π΅ΠΌΠΈΠ½Π° βΠ²ΠΎ Π»Π΅Ρβ Π·Π° ΡΠ΅ΠΊΠΎΡΠ° ΡΠ΅ΡΠΈΡΠ°.
ΠΠΎΠ±ΡΠΎ Π΄ΠΎΠΊΠ°ΠΆΠ°Π½ ΡΠΈΡΡΠ΅ΠΌ Π±Π΅ΡΠ΅ ΠΈΠ·Π±ΡΠ°Π½ ΠΊΠ°ΠΊΠΎ DBMS MonetDB, ΠΈΠΌΠ΅Π½ΠΎ ΠΈΠΌΠΏΠ»Π΅ΠΌΠ΅Π½ΡΠ°ΡΠΈΡΠ° Π·Π° R ΠΊΠ°ΠΊΠΎ ΠΏΠ°ΠΊΠ΅Ρ
con <- DBI::dbConnect(drv = MonetDBLite::MonetDBLite(), Sys.getenv("DBDIR"))
ΠΠ΅ ΡΡΠ΅Π±Π° Π΄Π° ΡΠΎΠ·Π΄Π°Π΄Π΅ΠΌΠ΅ Π΄Π²Π΅ ΡΠ°Π±Π΅Π»ΠΈ: Π΅Π΄Π½Π°ΡΠ° Π·Π° ΡΠΈΡΠ΅ ΠΏΠΎΠ΄Π°ΡΠΎΡΠΈ, Π΄ΡΡΠ³Π°ΡΠ° Π·Π° ΡΠ΅ΡΠ²ΠΈΡΠ½ΠΈ ΠΈΠ½ΡΠΎΡΠΌΠ°ΡΠΈΠΈ Π·Π° ΠΏΡΠ΅Π·Π΅ΠΌΠ΅Π½ΠΈΡΠ΅ Π΄Π°ΡΠΎΡΠ΅ΠΊΠΈ (ΠΊΠΎΡΠΈΡΠ½ΠΎ Π°ΠΊΠΎ Π½Π΅ΡΡΠΎ ΡΡΠ³Π½Π΅ Π½Π°ΠΎΠΏΠ°ΠΊΡ ΠΈ ΠΏΡΠΎΡΠ΅ΡΠΎΡ ΡΡΠ΅Π±Π° Π΄Π° ΠΏΡΠΎΠ΄ΠΎΠ»ΠΆΠΈ ΠΏΠΎ ΠΏΡΠ΅Π·Π΅ΠΌΠ°ΡΠ΅ΡΠΎ Π½Π΅ΠΊΠΎΠ»ΠΊΡ Π΄Π°ΡΠΎΡΠ΅ΠΊΠΈ):
ΠΡΠ΅ΠΈΡΠ°ΡΠ΅ ΡΠ°Π±Π΅Π»ΠΈ
if (!DBI::dbExistsTable(con, "doodles")) {
DBI::dbCreateTable(
con = con,
name = "doodles",
fields = c(
"countrycode" = "char(2)",
"drawing" = "text",
"key_id" = "bigint",
"recognized" = "bool",
"timestamp" = "timestamp",
"word" = "text"
)
)
}
if (!DBI::dbExistsTable(con, "upload_log")) {
DBI::dbCreateTable(
con = con,
name = "upload_log",
fields = c(
"id" = "serial",
"file_name" = "text UNIQUE",
"uploaded" = "bool DEFAULT false"
)
)
}
ΠΠ°ΡΠ±ΡΠ·ΠΈΠΎΡ Π½Π°ΡΠΈΠ½ Π·Π° Π²ΡΠΈΡΡΠ²Π°ΡΠ΅ ΠΏΠΎΠ΄Π°ΡΠΎΡΠΈ Π²ΠΎ Π±Π°Π·Π°ΡΠ° Π½Π° ΠΏΠΎΠ΄Π°ΡΠΎΡΠΈ Π±Π΅ΡΠ΅ Π΄ΠΈΡΠ΅ΠΊΡΠ½ΠΎ ΠΊΠΎΠΏΠΈΡΠ°ΡΠ΅ Π½Π° CSV-Π΄Π°ΡΠΎΡΠ΅ΠΊΠΈ ΡΠΎ ΠΏΠΎΠΌΠΎΡ Π½Π° ΠΊΠΎΠΌΠ°Π½Π΄Π°ΡΠ° SQL COPY OFFSET 2 INTO tablename FROM path USING DELIMITERS ',','n','"' NULL AS '' BEST EFFORT
ΠΊΠ°Π΄Π΅ tablename
- ΠΈΠΌΠ΅ Π½Π° ΡΠ°Π±Π΅Π»Π°ΡΠ° ΠΈ path
- ΠΏΠ°ΡΠ΅ΠΊΠ°ΡΠ° Π΄ΠΎ Π΄Π°ΡΠΎΡΠ΅ΠΊΠ°ΡΠ°. ΠΡΠΈ ΡΠ°Π±ΠΎΡΠ° ΡΠΎ Π°ΡΡ
ΠΈΠ²Π°ΡΠ°, ΠΎΡΠΊΡΠΈΠ΅Π½ΠΎ Π΅ Π΄Π΅ΠΊΠ° Π²Π³ΡΠ°Π΄Π΅Π½Π°ΡΠ° ΠΈΠΌΠΏΠ»Π΅ΠΌΠ΅Π½ΡΠ°ΡΠΈΡΠ° unzip
Π²ΠΎ R Π½Π΅ ΡΠ°Π±ΠΎΡΠΈ ΠΏΡΠ°Π²ΠΈΠ»Π½ΠΎ ΡΠΎ Π³ΠΎΠ»Π΅ΠΌ Π±ΡΠΎΡ Π΄Π°ΡΠΎΡΠ΅ΠΊΠΈ ΠΎΠ΄ Π°ΡΡ
ΠΈΠ²Π°ΡΠ°, ΠΏΠ° Π·Π°ΡΠΎΠ° Π³ΠΎ ΠΊΠΎΡΠΈΡΡΠ΅Π²ΠΌΠ΅ ΡΠΈΡΡΠ΅ΠΌΠΎΡ unzip
(ΠΊΠΎΡΠΈΡΡΠ΅ΡΡΠΈ Π³ΠΎ ΠΏΠ°ΡΠ°ΠΌΠ΅ΡΠ°ΡΠΎΡ getOption("unzip")
).
Π€ΡΠ½ΠΊΡΠΈΡΠ° Π·Π° ΠΏΠΈΡΡΠ²Π°ΡΠ΅ Π²ΠΎ Π±Π°Π·Π°ΡΠ° Π½Π° ΠΏΠΎΠ΄Π°ΡΠΎΡΠΈ
#' @title ΠΠ·Π²Π»Π΅ΡΠ΅Π½ΠΈΠ΅ ΠΈ Π·Π°Π³ΡΡΠ·ΠΊΠ° ΡΠ°ΠΉΠ»ΠΎΠ²
#'
#' @description
#' ΠΠ·Π²Π»Π΅ΡΠ΅Π½ΠΈΠ΅ CSV-ΡΠ°ΠΉΠ»ΠΎΠ² ΠΈΠ· ZIP-Π°ΡΡ
ΠΈΠ²Π° ΠΈ Π·Π°Π³ΡΡΠ·ΠΊΠ° ΠΈΡ
Π² Π±Π°Π·Ρ Π΄Π°Π½Π½ΡΡ
#'
#' @param con ΠΠ±ΡΠ΅ΠΊΡ ΠΏΠΎΠ΄ΠΊΠ»ΡΡΠ΅Π½ΠΈΡ ΠΊ Π±Π°Π·Π΅ Π΄Π°Π½Π½ΡΡ
(ΠΊΠ»Π°ΡΡ `MonetDBEmbeddedConnection`).
#' @param tablename ΠΠ°Π·Π²Π°Π½ΠΈΠ΅ ΡΠ°Π±Π»ΠΈΡΡ Π² Π±Π°Π·Π΅ Π΄Π°Π½Π½ΡΡ
.
#' @oaram zipfile ΠΡΡΡ ΠΊ ZIP-Π°ΡΡ
ΠΈΠ²Ρ.
#' @oaram filename ΠΠΌΡ ΡΠ°ΠΉΠ»Π° Π²Π½ΡΡΠΈ ZIP-Π°ΡΡ
ΠΈΠ²Π°.
#' @param preprocess Π€ΡΠ½ΠΊΡΠΈΡ ΠΏΡΠ΅Π΄ΠΎΠ±ΡΠ°Π±ΠΎΡΠΊΠΈ, ΠΊΠΎΡΠΎΡΠ°Ρ Π±ΡΠ΄Π΅Ρ ΠΏΡΠΈΠΌΠ΅Π½Π΅Π½Π° ΠΈΠ·Π²Π»Π΅ΡΡΠ½Π½ΠΎΠΌΡ ΡΠ°ΠΉΠ»Ρ.
#' ΠΠΎΠ»ΠΆΠ½Π° ΠΏΡΠΈΠ½ΠΈΠΌΠ°ΡΡ ΠΎΠ΄ΠΈΠ½ Π°ΡΠ³ΡΠΌΠ΅Π½Ρ `data` (ΠΎΠ±ΡΠ΅ΠΊΡ `data.table`).
#'
#' @return `TRUE`.
#'
upload_file <- function(con, tablename, zipfile, filename, preprocess = NULL) {
# ΠΡΠΎΠ²Π΅ΡΠΊΠ° Π°ΡΠ³ΡΠΌΠ΅Π½ΡΠΎΠ²
checkmate::assert_class(con, "MonetDBEmbeddedConnection")
checkmate::assert_string(tablename)
checkmate::assert_string(filename)
checkmate::assert_true(DBI::dbExistsTable(con, tablename))
checkmate::assert_file_exists(zipfile, access = "r", extension = "zip")
checkmate::assert_function(preprocess, args = c("data"), null.ok = TRUE)
# ΠΠ·Π²Π»Π΅ΡΠ΅Π½ΠΈΠ΅ ΡΠ°ΠΉΠ»Π°
path <- file.path(tempdir(), filename)
unzip(zipfile, files = filename, exdir = tempdir(),
junkpaths = TRUE, unzip = getOption("unzip"))
on.exit(unlink(file.path(path)))
# ΠΡΠΈΠΌΠ΅Π½ΡΠ΅ΠΌ ΡΡΠ½ΠΊΡΠΈΡ ΠΏΡΠ΅Π΄ΠΎΠ±ΡΠ°Π±ΠΎΡΠΊΠΈ
if (!is.null(preprocess)) {
.data <- data.table::fread(file = path)
.data <- preprocess(data = .data)
data.table::fwrite(x = .data, file = path, append = FALSE)
rm(.data)
}
# ΠΠ°ΠΏΡΠΎΡ ΠΊ ΠΠ Π½Π° ΠΈΠΌΠΏΠΎΡΡ CSV
sql <- sprintf(
"COPY OFFSET 2 INTO %s FROM '%s' USING DELIMITERS ',','n','"' NULL AS '' BEST EFFORT",
tablename, path
)
# ΠΡΠΏΠΎΠ»Π½Π΅Π½ΠΈΠ΅ Π·Π°ΠΏΡΠΎΡΠ° ΠΊ ΠΠ
DBI::dbExecute(con, sql)
# ΠΠΎΠ±Π°Π²Π»Π΅Π½ΠΈΠ΅ Π·Π°ΠΏΠΈΡΠΈ ΠΎΠ± ΡΡΠΏΠ΅ΡΠ½ΠΎΠΉ Π·Π°Π³ΡΡΠ·ΠΊΠ΅ Π² ΡΠ»ΡΠΆΠ΅Π±Π½ΡΡ ΡΠ°Π±Π»ΠΈΡΡ
DBI::dbExecute(con, sprintf("INSERT INTO upload_log(file_name, uploaded) VALUES('%s', true)",
filename))
return(invisible(TRUE))
}
ΠΠΊΠΎ ΡΡΠ΅Π±Π° Π΄Π° ΡΠ° ΡΡΠ°Π½ΡΡΠΎΡΠΌΠΈΡΠ°ΡΠ΅ ΡΠ°Π±Π΅Π»Π°ΡΠ° ΠΏΡΠ΅Π΄ Π΄Π° ΡΠ° Π·Π°ΠΏΠΈΡΠ΅ΡΠ΅ Π²ΠΎ Π±Π°Π·Π°ΡΠ° Π½Π° ΠΏΠΎΠ΄Π°ΡΠΎΡΠΈ, Π΄ΠΎΠ²ΠΎΠ»Π½ΠΎ Π΅ Π΄Π° ΠΏΠΎΠΌΠΈΠ½Π΅ΡΠ΅ Π²ΠΎ Π°ΡΠ³ΡΠΌΠ΅Π½ΡΠΎΡ preprocess
ΡΡΠ½ΠΊΡΠΈΡΠ° ΠΊΠΎΡΠ° ΡΠ΅ Π³ΠΈ ΡΡΠ°Π½ΡΡΠΎΡΠΌΠΈΡΠ° ΠΏΠΎΠ΄Π°ΡΠΎΡΠΈΡΠ΅.
ΠΠΎΠ΄ Π·Π° ΡΠ΅ΠΊΠ²Π΅Π½ΡΠΈΡΠ°Π»Π½ΠΎ Π²ΡΠΈΡΡΠ²Π°ΡΠ΅ ΠΏΠΎΠ΄Π°ΡΠΎΡΠΈ Π²ΠΎ Π±Π°Π·Π°ΡΠ° Π½Π° ΠΏΠΎΠ΄Π°ΡΠΎΡΠΈ:
ΠΠ°ΠΏΠΈΡΡΠ²Π°ΡΠ΅ ΠΏΠΎΠ΄Π°ΡΠΎΡΠΈ Π²ΠΎ Π±Π°Π·Π°ΡΠ° Π½Π° ΠΏΠΎΠ΄Π°ΡΠΎΡΠΈ
# Π‘ΠΏΠΈΡΠΎΠΊ ΡΠ°ΠΉΠ»ΠΎΠ² Π΄Π»Ρ Π·Π°ΠΏΠΈΡΠΈ
files <- unzip(zipfile, list = TRUE)$Name
# Π‘ΠΏΠΈΡΠΎΠΊ ΠΈΡΠΊΠ»ΡΡΠ΅Π½ΠΈΠΉ, Π΅ΡΠ»ΠΈ ΡΠ°ΡΡΡ ΡΠ°ΠΉΠ»ΠΎΠ² ΡΠΆΠ΅ Π±ΡΠ»Π° Π·Π°Π³ΡΡΠΆΠ΅Π½Π°
to_skip <- DBI::dbGetQuery(con, "SELECT file_name FROM upload_log")[[1L]]
files <- setdiff(files, to_skip)
if (length(files) > 0L) {
# ΠΠ°ΠΏΡΡΠΊΠ°Π΅ΠΌ ΡΠ°ΠΉΠΌΠ΅Ρ
tictoc::tic()
# ΠΡΠΎΠ³ΡΠ΅ΡΡ Π±Π°Ρ
pb <- txtProgressBar(min = 0L, max = length(files), style = 3)
for (i in seq_along(files)) {
upload_file(con = con, tablename = "doodles",
zipfile = zipfile, filename = files[i])
setTxtProgressBar(pb, i)
}
close(pb)
# ΠΡΡΠ°Π½Π°Π²Π»ΠΈΠ²Π°Π΅ΠΌ ΡΠ°ΠΉΠΌΠ΅Ρ
tictoc::toc()
}
# 526.141 sec elapsed - ΠΊΠΎΠΏΠΈΡΠΎΠ²Π°Π½ΠΈΠ΅ SSD->SSD
# 558.879 sec elapsed - ΠΊΠΎΠΏΠΈΡΠΎΠ²Π°Π½ΠΈΠ΅ USB->SSD
ΠΡΠ΅ΠΌΠ΅ΡΠΎ Π½Π° Π²ΡΠΈΡΡΠ²Π°ΡΠ΅ Π½Π° ΠΏΠΎΠ΄Π°ΡΠΎΡΠΈΡΠ΅ ΠΌΠΎΠΆΠ΅ Π΄Π° Π²Π°ΡΠΈΡΠ° Π²ΠΎ Π·Π°Π²ΠΈΡΠ½ΠΎΡΡ ΠΎΠ΄ ΠΊΠ°ΡΠ°ΠΊΡΠ΅ΡΠΈΡΡΠΈΠΊΠΈΡΠ΅ Π½Π° Π±ΡΠ·ΠΈΠ½Π°ΡΠ° Π½Π° ΠΊΠΎΡΠΈΡΡΠ΅Π½ΠΈΠΎΡ ΠΏΠΎΠ³ΠΎΠ½. ΠΠΎ Π½Π°ΡΠΈΠΎΡ ΡΠ»ΡΡΠ°Ρ, ΡΠΈΡΠ°ΡΠ΅ΡΠΎ ΠΈ ΠΏΠΈΡΡΠ²Π°ΡΠ΅ΡΠΎ Π²ΠΎ ΡΠ°ΠΌΠΊΠΈΡΠ΅ Π½Π° Π΅Π΄Π΅Π½ SSD ΠΈΠ»ΠΈ ΠΎΠ΄ ΡΠ»Π΅Ρ-ΡΡΠ΅Π΄ (ΠΈΠ·Π²ΠΎΡΠ½Π° Π΄Π°ΡΠΎΡΠ΅ΠΊΠ°) Π½Π° SSD (DB) ΡΡΠ°Π΅ ΠΏΠΎΠΌΠ°Π»ΠΊΡ ΠΎΠ΄ 10 ΠΌΠΈΠ½ΡΡΠΈ.
ΠΠΎΡΡΠ΅Π±Π½ΠΈ ΡΠ΅ ΡΡΡΠ΅ Π½Π΅ΠΊΠΎΠ»ΠΊΡ ΡΠ΅ΠΊΡΠ½Π΄ΠΈ Π·Π° Π΄Π° ΡΠ΅ ΡΠΎΠ·Π΄Π°Π΄Π΅ ΠΊΠΎΠ»ΠΎΠ½Π° ΡΠΎ ΠΎΠ·Π½Π°ΠΊΠ° Π½Π° ΠΊΠ»Π°ΡΠ° ΡΠΎ ΡΠ΅Π» Π±ΡΠΎΡ ΠΈ ΠΊΠΎΠ»ΠΎΠ½Π° ΠΈΠ½Π΄Π΅ΠΊΡ (ORDERED INDEX
) ΡΠΎ Π±ΡΠΎΠ΅Π²ΠΈ Π½Π° Π»ΠΈΠ½ΠΈΠΈ ΡΠΎ ΠΊΠΎΠΈ ΡΠ΅ ΡΠ΅ Π·Π΅ΠΌΠ°Π°Ρ ΠΏΡΠΈΠΌΠ΅ΡΠΎΡΠΈ ΠΎΠ΄ Π½Π°Π±ΡΡΠ΄ΡΠ²Π°ΡΠ°ΡΠ° ΠΏΡΠΈ ΠΊΡΠ΅ΠΈΡΠ°ΡΠ΅ Π½Π° ΡΠ΅ΡΠΈΠΈ:
ΠΡΠ΅ΠΈΡΠ°ΡΠ΅ Π½Π° Π΄ΠΎΠΏΠΎΠ»Π½ΠΈΡΠ΅Π»Π½ΠΈ ΠΊΠΎΠ»ΠΎΠ½ΠΈ ΠΈ ΠΈΠ½Π΄Π΅ΠΊΡ
message("Generate lables")
invisible(DBI::dbExecute(con, "ALTER TABLE doodles ADD label_int int"))
invisible(DBI::dbExecute(con, "UPDATE doodles SET label_int = dense_rank() OVER (ORDER BY word) - 1"))
message("Generate row numbers")
invisible(DBI::dbExecute(con, "ALTER TABLE doodles ADD id serial"))
invisible(DBI::dbExecute(con, "CREATE ORDERED INDEX doodles_id_ord_idx ON doodles(id)"))
ΠΠ° Π΄Π° Π³ΠΎ ΡΠ΅ΡΠΈΠΌΠ΅ ΠΏΡΠΎΠ±Π»Π΅ΠΌΠΎΡ ΡΠΎ ΡΠΎΠ·Π΄Π°Π²Π°ΡΠ΅ ΡΠ΅ΡΠΈΡΠ° Π²ΠΎ Π»Π΅Ρ, ΡΡΠ΅Π±Π°ΡΠ΅ Π΄Π° ΠΏΠΎΡΡΠΈΠ³Π½Π΅ΠΌΠ΅ ΠΌΠ°ΠΊΡΠΈΠΌΠ°Π»Π½Π° Π±ΡΠ·ΠΈΠ½Π° Π½Π° ΠΈΠ·Π²Π»Π΅ΠΊΡΠ²Π°ΡΠ΅ ΡΠ»ΡΡΠ°ΡΠ½ΠΈ ΡΠ΅Π΄ΠΎΠ²ΠΈ ΠΎΠ΄ ΡΠ°Π±Π΅Π»Π°ΡΠ° doodles
. ΠΠ° ΠΎΠ²Π° ΠΊΠΎΡΠΈΡΡΠ΅Π²ΠΌΠ΅ 3 ΡΡΠΈΠΊΠΎΠ²ΠΈ. ΠΡΠ²ΠΈΠΎΡ Π±Π΅ΡΠ΅ Π΄Π° ΡΠ΅ Π½Π°ΠΌΠ°Π»ΠΈ Π΄ΠΈΠΌΠ΅Π½Π·ΠΈΠΎΠ½Π°Π»Π½ΠΎΡΡΠ° Π½Π° ΡΠΈΠΏΠΎΡ ΡΡΠΎ Π³ΠΎ ΡΡΠ²Π° ID Π½Π° Π½Π°Π±ΡΡΠ΄ΡΠ²Π°ΡΠ΅. ΠΠΎ ΠΎΡΠΈΠ³ΠΈΠ½Π°Π»Π½ΠΈΠΎΡ ΡΠ΅Ρ Π½Π° ΠΏΠΎΠ΄Π°ΡΠΎΡΠΈ, ΡΠΈΠΏΠΎΡ ΠΏΠΎΡΡΠ΅Π±Π΅Π½ Π·Π° ΡΠΊΠ»Π°Π΄ΠΈΡΠ°ΡΠ΅ Π½Π° Π»ΠΈΡΠ½Π°ΡΠ° ΠΊΠ°ΡΡΠ° Π΅ bigint
, Π½ΠΎ Π±ΡΠΎΡΠΎΡ Π½Π° Π½Π°Π±ΡΡΠ΄ΡΠ²Π°ΡΠ° ΠΎΠ²ΠΎΠ·ΠΌΠΎΠΆΡΠ²Π° Π΄Π° ΡΠ΅ Π²ΠΊΠ»ΠΎΠΏΠ°Ρ Π½ΠΈΠ²Π½ΠΈΡΠ΅ ΠΈΠ΄Π΅Π½ΡΠΈΡΠΈΠΊΠ°ΡΠΎΡΠΈ, Π΅Π΄Π½Π°ΠΊΠ²ΠΈ Π½Π° ΡΠ΅Π΄Π½ΠΈΠΎΡ Π±ΡΠΎΡ, Π²ΠΎ ΡΠΈΠΏΠΎΡ int
. ΠΡΠ΅Π±Π°ΡΡΠ²Π°ΡΠ΅ΡΠΎ Π΅ ΠΌΠ½ΠΎΠ³Ρ ΠΏΠΎΠ±ΡΠ·ΠΎ Π²ΠΎ ΠΎΠ²ΠΎΡ ΡΠ»ΡΡΠ°Ρ. ΠΡΠΎΡΠΈΠΎΡ ΡΡΠΈΠΊ Π±Π΅ΡΠ΅ Π΄Π° ΡΠ΅ ΠΈΡΠΊΠΎΡΠΈΡΡΠΈ ORDERED INDEX
- ΠΠΎΡΠ΄ΠΎΠ²ΠΌΠ΅ Π΄ΠΎ ΠΎΠ²Π°Π° ΠΎΠ΄Π»ΡΠΊΠ° Π΅ΠΌΠΏΠΈΡΠΈΡΠΊΠΈ, ΠΎΡΠΊΠ°ΠΊΠΎ Π³ΠΈ ΠΏΠΎΠΌΠΈΠ½Π°Π²ΠΌΠ΅ ΡΠΈΡΠ΅ Π΄ΠΎΡΡΠ°ΠΏΠ½ΠΈ PREPARE
ΡΠΎ ΠΏΠΎΡΠ»Π΅Π΄ΠΎΠ²Π°ΡΠ΅Π»Π½Π° ΡΠΏΠΎΡΡΠ΅Π±Π° Π½Π° ΠΏΠΎΠ΄Π³ΠΎΡΠ²Π΅Π½ ΠΈΠ·ΡΠ°Π· ΠΏΡΠΈ ΠΊΡΠ΅ΠΈΡΠ°ΡΠ΅ Π½Π° ΠΊΡΠΏ ΠΏΡΠ°ΡΠ°ΡΠ° ΠΎΠ΄ ΠΈΡΡ ΡΠΈΠΏ, Π½ΠΎ Π²ΡΡΡΠ½ΠΎΡΡ ΠΈΠΌΠ° ΠΏΡΠ΅Π΄Π½ΠΎΡΡ Π²ΠΎ ΡΠΏΠΎΡΠ΅Π΄Π±Π° ΡΠΎ Π΅Π΄Π½ΠΎΡΡΠ°Π²Π½ΠΈΠΎΡ SELECT
ΡΠ΅ ΠΏΠΎΠΊΠ°ΠΆΠ° Π΄Π΅ΠΊΠ° Π΅ Π²ΠΎ ΠΎΠΏΡΠ΅Π³ΠΎΡ Π½Π° ΡΡΠ°ΡΠΈΡΡΠΈΡΠΊΠ° Π³ΡΠ΅ΡΠΊΠ°.
ΠΡΠΎΡΠ΅ΡΠΎΡ Π½Π° ΠΏΠΎΡΡΠ°Π²ΡΠ²Π°ΡΠ΅ ΠΏΠΎΠ΄Π°ΡΠΎΡΠΈ ΡΡΠΎΡΠΈ Π½Π΅ ΠΏΠΎΠ²Π΅ΡΠ΅ ΠΎΠ΄ 450 MB RAM ΠΌΠ΅ΠΌΠΎΡΠΈΡΠ°. ΠΠ΄Π½ΠΎΡΠ½ΠΎ, ΠΎΠΏΠΈΡΠ°Π½ΠΈΠΎΡ ΠΏΡΠΈΡΡΠ°ΠΏ Π²ΠΈ ΠΎΠ²ΠΎΠ·ΠΌΠΎΠΆΡΠ²Π° Π΄Π° ΠΏΡΠ΅ΠΌΠ΅ΡΡΠΈΡΠ΅ Π·Π±ΠΈΡΠΊΠΈ Π½Π° ΠΏΠΎΠ΄Π°ΡΠΎΡΠΈ ΡΠΎ ΡΠ΅ΠΆΠΈΠ½Π° ΠΎΠ΄ Π΄Π΅ΡΠ΅ΡΠΈΡΠΈ Π³ΠΈΠ³Π°Π±Π°ΡΡΠΈ Π½Π° ΡΠ΅ΡΠΈΡΠΈ ΡΠ΅ΠΊΠΎΡ Π±ΡΡΠ΅ΡΡΠΊΠΈ Ρ Π°ΡΠ΄Π²Π΅Ρ, Π²ΠΊΠ»ΡΡΠΈΡΠ΅Π»Π½ΠΎ ΠΈ Π½Π΅ΠΊΠΎΠΈ ΡΡΠ΅Π΄ΠΈ ΡΠΎ Π΅Π΄Π½Π° ΠΏΠ»ΠΎΡΠ°, ΡΡΠΎ Π΅ ΠΏΡΠΈΠ»ΠΈΡΠ½ΠΎ ΠΊΡΠ».
ΠΡΡΠ°Π½ΡΠ²Π° ΡΠ°ΠΌΠΎ Π΄Π° ΡΠ΅ ΠΈΠ·ΠΌΠ΅ΡΠΈ Π±ΡΠ·ΠΈΠ½Π°ΡΠ° Π½Π° ΠΏΡΠ΅Π·Π΅ΠΌΠ°ΡΠ΅ (ΡΠ»ΡΡΠ°ΡΠ½ΠΈ) ΠΏΠΎΠ΄Π°ΡΠΎΡΠΈ ΠΈ Π΄Π° ΡΠ΅ ΠΎΡΠ΅Π½ΠΈ ΡΠΊΠ°Π»ΠΈΡΠ°ΡΠ΅ΡΠΎ ΠΏΡΠΈ Π·Π΅ΠΌΠ°ΡΠ΅ ΠΏΡΠΈΠΌΠ΅ΡΠΎΡΠΈ Π½Π° ΡΠ΅ΡΠΈΠΈ ΡΠΎ ΡΠ°Π·Π»ΠΈΡΠ½ΠΈ Π³ΠΎΠ»Π΅ΠΌΠΈΠ½ΠΈ:
Π Π΅ΠΏΠ΅Ρ Π·Π° Π±Π°Π·Π° Π½Π° ΠΏΠΎΠ΄Π°ΡΠΎΡΠΈ
library(ggplot2)
set.seed(0)
# ΠΠΎΠ΄ΠΊΠ»ΡΡΠ΅Π½ΠΈΠ΅ ΠΊ Π±Π°Π·Π΅ Π΄Π°Π½Π½ΡΡ
con <- DBI::dbConnect(MonetDBLite::MonetDBLite(), Sys.getenv("DBDIR"))
# Π€ΡΠ½ΠΊΡΠΈΡ Π΄Π»Ρ ΠΏΠΎΠ΄Π³ΠΎΡΠΎΠ²ΠΊΠΈ Π·Π°ΠΏΡΠΎΡΠ° Π½Π° ΡΡΠΎΡΠΎΠ½Π΅ ΡΠ΅ΡΠ²Π΅ΡΠ°
prep_sql <- function(batch_size) {
sql <- sprintf("PREPARE SELECT id FROM doodles WHERE id IN (%s)",
paste(rep("?", batch_size), collapse = ","))
res <- DBI::dbSendQuery(con, sql)
return(res)
}
# Π€ΡΠ½ΠΊΡΠΈΡ Π΄Π»Ρ ΠΈΠ·Π²Π»Π΅ΡΠ΅Π½ΠΈΡ Π΄Π°Π½Π½ΡΡ
fetch_data <- function(rs, batch_size) {
ids <- sample(seq_len(n), batch_size)
res <- DBI::dbFetch(DBI::dbBind(rs, as.list(ids)))
return(res)
}
# ΠΡΠΎΠ²Π΅Π΄Π΅Π½ΠΈΠ΅ Π·Π°ΠΌΠ΅ΡΠ°
res_bench <- bench::press(
batch_size = 2^(4:10),
{
rs <- prep_sql(batch_size)
bench::mark(
fetch_data(rs, batch_size),
min_iterations = 50L
)
}
)
# ΠΠ°ΡΠ°ΠΌΠ΅ΡΡΡ Π±Π΅Π½ΡΠΌΠ°ΡΠΊΠ°
cols <- c("batch_size", "min", "median", "max", "itr/sec", "total_time", "n_itr")
res_bench[, cols]
# batch_size min median max `itr/sec` total_time n_itr
# <dbl> <bch:tm> <bch:tm> <bch:tm> <dbl> <bch:tm> <int>
# 1 16 23.6ms 54.02ms 93.43ms 18.8 2.6s 49
# 2 32 38ms 84.83ms 151.55ms 11.4 4.29s 49
# 3 64 63.3ms 175.54ms 248.94ms 5.85 8.54s 50
# 4 128 83.2ms 341.52ms 496.24ms 3.00 16.69s 50
# 5 256 232.8ms 653.21ms 847.44ms 1.58 31.66s 50
# 6 512 784.6ms 1.41s 1.98s 0.740 1.1m 49
# 7 1024 681.7ms 2.72s 4.06s 0.377 2.16m 49
ggplot(res_bench, aes(x = factor(batch_size), y = median, group = 1)) +
geom_point() +
geom_line() +
ylab("median time, s") +
theme_minimal()
DBI::dbDisconnect(con, shutdown = TRUE)
2. ΠΠΎΠ΄Π³ΠΎΡΠΎΠ²ΠΊΠ° Π½Π° ΡΠ΅ΡΠΈΠΈ
Π¦Π΅Π»ΠΈΠΎΡ ΠΏΡΠΎΡΠ΅Ρ Π½Π° ΠΏΠΎΠ΄Π³ΠΎΡΠΎΠ²ΠΊΠ° Π½Π° ΡΠ΅ΡΠΈΡΠ°ΡΠ° ΡΠ΅ ΡΠΎΡΡΠΎΠΈ ΠΎΠ΄ ΡΠ»Π΅Π΄Π½ΠΈΠ²Π΅ ΡΠ΅ΠΊΠΎΡΠΈ:
- ΠΠ°ΡΡΠΈΡΠ°ΡΠ΅ Π½Π° Π½Π΅ΠΊΠΎΠ»ΠΊΡ JSON ΠΊΠΎΠΈ ΡΠΎΠ΄ΡΠΆΠ°Ρ Π²Π΅ΠΊΡΠΎΡΠΈ Π½Π° Π½ΠΈΠ·ΠΈ ΡΠΎ ΠΊΠΎΠΎΡΠ΄ΠΈΠ½Π°ΡΠΈ Π½Π° ΡΠΎΡΠΊΠΈ.
- Π¦ΡΡΠ°ΡΠ΅ ΠΎΠ±ΠΎΠ΅Π½ΠΈ Π»ΠΈΠ½ΠΈΠΈ Π²ΡΠ· ΠΎΡΠ½ΠΎΠ²Π° Π½Π° ΠΊΠΎΠΎΡΠ΄ΠΈΠ½Π°ΡΠΈΡΠ΅ Π½Π° ΡΠΎΡΠΊΠΈΡΠ΅ Π½Π° ΡΠ»ΠΈΠΊΠ° ΡΠΎ ΠΏΠΎΡΡΠ΅Π±Π½Π°ΡΠ° Π³ΠΎΠ»Π΅ΠΌΠΈΠ½Π° (Π½Π° ΠΏΡΠΈΠΌΠ΅Ρ, 256Γ256 ΠΈΠ»ΠΈ 128Γ128).
- ΠΠΎΠ½Π²Π΅ΡΡΠΈΡΠ°ΡΠ΅ Π½Π° Π΄ΠΎΠ±ΠΈΠ΅Π½ΠΈΡΠ΅ ΡΠ»ΠΈΠΊΠΈ Π²ΠΎ ΡΠ΅Π½Π·ΠΎΡ.
ΠΠ°ΠΊΠΎ Π΄Π΅Π» ΠΎΠ΄ Π½Π°ΡΠΏΡΠ΅Π²Π°ΡΠΎΡ ΠΌΠ΅ΡΡ ΠΊΠ΅ΡΠ½Π΅Π»ΠΈΡΠ΅ Π½Π° Python, ΠΏΡΠΎΠ±Π»Π΅ΠΌΠΎΡ Π±Π΅ΡΠ΅ ΡΠ΅ΡΠ΅Π½ ΠΏΡΠ²Π΅Π½ΡΡΠ²Π΅Π½ΠΎ ΠΊΠΎΡΠΈΡΡΠ΅ΡΡΠΈ OpenCV. ΠΠ΄Π΅Π½ ΠΎΠ΄ Π½Π°ΡΠ΅Π΄Π½ΠΎΡΡΠ°Π²Π½ΠΈΡΠ΅ ΠΈ Π½Π°ΡΠΎΡΠΈΠ³Π»Π΅Π΄Π½ΠΈΡΠ΅ Π°Π½Π°Π»ΠΎΠ·ΠΈ Π²ΠΎ R Π±ΠΈ ΠΈΠ·Π³Π»Π΅Π΄Π°Π» Π²Π°ΠΊΠ°:
Π‘ΠΏΡΠΎΠ²Π΅Π΄ΡΠ²Π°ΡΠ΅ Π½Π° ΠΊΠΎΠ½Π²Π΅ΡΠ·ΠΈΡΠ° JSON Π²ΠΎ ΡΠ΅Π½Π·ΠΎΡ Π²ΠΎ Π
r_process_json_str <- function(json, line.width = 3,
color = TRUE, scale = 1) {
# ΠΠ°ΡΡΠΈΠ½Π³ JSON
coords <- jsonlite::fromJSON(json, simplifyMatrix = FALSE)
tmp <- tempfile()
# Π£Π΄Π°Π»ΡΠ΅ΠΌ Π²ΡΠ΅ΠΌΠ΅Π½Π½ΡΠΉ ΡΠ°ΠΉΠ» ΠΏΠΎ Π·Π°Π²Π΅ΡΡΠ΅Π½ΠΈΡ ΡΡΠ½ΠΊΡΠΈΠΈ
on.exit(unlink(tmp))
png(filename = tmp, width = 256 * scale, height = 256 * scale, pointsize = 1)
# ΠΡΡΡΠΎΠΉ Π³ΡΠ°ΡΠΈΠΊ
plot.new()
# Π Π°Π·ΠΌΠ΅Ρ ΠΎΠΊΠ½Π° Π³ΡΠ°ΡΠΈΠΊΠ°
plot.window(xlim = c(256 * scale, 0), ylim = c(256 * scale, 0))
# Π¦Π²Π΅ΡΠ° Π»ΠΈΠ½ΠΈΠΉ
cols <- if (color) rainbow(length(coords)) else "#000000"
for (i in seq_along(coords)) {
lines(x = coords[[i]][[1]] * scale, y = coords[[i]][[2]] * scale,
col = cols[i], lwd = line.width)
}
dev.off()
# ΠΡΠ΅ΠΎΠ±ΡΠ°Π·ΠΎΠ²Π°Π½ΠΈΠ΅ ΠΈΠ·ΠΎΠ±ΡΠ°ΠΆΠ΅Π½ΠΈΡ Π² 3-Ρ
ΠΌΠ΅ΡΠ½ΡΠΉ ΠΌΠ°ΡΡΠΈΠ²
res <- png::readPNG(tmp)
return(res)
}
r_process_json_vector <- function(x, ...) {
res <- lapply(x, r_process_json_str, ...)
# ΠΠ±ΡΠ΅Π΄ΠΈΠ½Π΅Π½ΠΈΠ΅ 3-Ρ
ΠΌΠ΅ΡΠ½ΡΡ
ΠΌΠ°ΡΡΠΈΠ²ΠΎΠ² ΠΊΠ°ΡΡΠΈΠ½ΠΎΠΊ Π² 4-Ρ
ΠΌΠ΅ΡΠ½ΡΠΉ Π² ΡΠ΅Π½Π·ΠΎΡ
res <- do.call(abind::abind, c(res, along = 0))
return(res)
}
Π¦ΡΡΠ΅ΠΆΠΎΡ ΡΠ΅ ΠΈΠ·Π²Π΅Π΄ΡΠ²Π° ΡΠΎ ΠΏΠΎΠΌΠΎΡ Π½Π° ΡΡΠ°Π½Π΄Π°ΡΠ΄Π½ΠΈ R Π°Π»Π°ΡΠΊΠΈ ΠΈ ΡΠ΅ Π·Π°ΡΡΠ²ΡΠ²Π° Π²ΠΎ ΠΏΡΠΈΠ²ΡΠ΅ΠΌΠ΅Π½ PNG ΡΠΊΠ»Π°Π΄ΠΈΡΠ°Π½ Π²ΠΎ RAM ΠΌΠ΅ΠΌΠΎΡΠΈΡΠ° (Π½Π° Linux, ΠΏΡΠΈΠ²ΡΠ΅ΠΌΠ΅Π½ΠΈΡΠ΅ R Π΄ΠΈΡΠ΅ΠΊΡΠΎΡΠΈΡΠΌΠΈ ΡΠ΅ Π½Π°ΠΎΡΠ°Π°Ρ Π²ΠΎ Π΄ΠΈΡΠ΅ΠΊΡΠΎΡΠΈΡΠΌΠΎΡ /tmp
, ΠΌΠΎΠ½ΡΠΈΡΠ°Π½ Π²ΠΎ RAM ΠΌΠ΅ΠΌΠΎΡΠΈΡΠ°). ΠΠ²Π°Π° Π΄Π°ΡΠΎΡΠ΅ΠΊΠ° ΠΏΠΎΡΠΎΠ° ΡΠ΅ ΡΠΈΡΠ° ΠΊΠ°ΠΊΠΎ ΡΡΠΎΠ΄ΠΈΠΌΠ΅Π½Π·ΠΈΠΎΠ½Π°Π»Π½Π° Π½ΠΈΠ·Π° ΡΠΎ Π±ΡΠΎΠ΅Π²ΠΈ ΠΊΠΎΠΈ ΡΠ΅ Π΄Π²ΠΈΠΆΠ°Ρ ΠΎΠ΄ 0 Π΄ΠΎ 1. ΠΠ²Π° Π΅ Π²Π°ΠΆΠ½ΠΎ Π·Π°ΡΠΎΠ° ΡΡΠΎ ΠΏΠΎΠΊΠΎΠ½Π²Π΅Π½ΡΠΈΠΎΠ½Π°Π»Π΅Π½ BMP Π±ΠΈ ΡΠ΅ ΡΠΈΡΠ°Π» Π²ΠΎ Π½Π΅ΠΎΠ±ΡΠ°Π±ΠΎΡΠ΅Π½Π° Π½ΠΈΠ·Π° ΡΠΎ Ρ
Π΅ΠΊΡΠ°Π΄Π΅ΡΠΈΠΌΠ°Π»Π½ΠΈ ΡΠΈΡΡΠΈ Π½Π° Π±ΠΎΠΈ.
ΠΡΠ΄Π΅ Π΄Π° Π³ΠΎ ΡΠ΅ΡΡΠΈΡΠ°ΠΌΠ΅ ΡΠ΅Π·ΡΠ»ΡΠ°ΡΠΎΡ:
zip_file <- file.path("data", "train_simplified.zip")
csv_file <- "cat.csv"
unzip(zip_file, files = csv_file, exdir = tempdir(),
junkpaths = TRUE, unzip = getOption("unzip"))
tmp_data <- data.table::fread(file.path(tempdir(), csv_file), sep = ",",
select = "drawing", nrows = 10000)
arr <- r_process_json_str(tmp_data[4, drawing])
dim(arr)
# [1] 256 256 3
plot(magick::image_read(arr))
Π‘Π°ΠΌΠ°ΡΠ° ΡΠ΅ΡΠΈΡΠ° ΡΠ΅ ΡΠ΅ ΡΠΎΡΠΌΠΈΡΠ° Π½Π° ΡΠ»Π΅Π΄Π½ΠΈΠΎΠ² Π½Π°ΡΠΈΠ½:
res <- r_process_json_vector(tmp_data[1:4, drawing], scale = 0.5)
str(res)
# num [1:4, 1:128, 1:128, 1:3] 1 1 1 1 1 1 1 1 1 1 ...
# - attr(*, "dimnames")=List of 4
# ..$ : NULL
# ..$ : NULL
# ..$ : NULL
# ..$ : NULL
ΠΠ²Π°Π° ΠΈΠΌΠΏΠ»Π΅ΠΌΠ΅Π½ΡΠ°ΡΠΈΡΠ° Π½ΠΈ ΡΠ΅ ΡΠΈΠ½Π΅ΡΠ΅ Π½Π΅ΠΎΠΏΡΠΈΠΌΠ°Π»Π½Π°, Π±ΠΈΠ΄Π΅ΡΡΠΈ ΡΠΎΡΠΌΠΈΡΠ°ΡΠ΅ΡΠΎ Π½Π° Π³ΠΎΠ»Π΅ΠΌΠΈ ΡΠ΅ΡΠΈΠΈ ΡΡΠ°Π΅ Π½Π΅ΠΏΡΠΈΡΡΠΎΡΠ½ΠΎ Π΄ΠΎΠ»Π³ΠΎ Π²ΡΠ΅ΠΌΠ΅, ΠΈ ΡΠ΅ΡΠΈΠ²ΠΌΠ΅ Π΄Π° Π³ΠΎ ΠΈΡΠΊΠΎΡΠΈΡΡΠΈΠΌΠ΅ ΠΈΡΠΊΡΡΡΠ²ΠΎΡΠΎ Π½Π° Π½Π°ΡΠΈΡΠ΅ ΠΊΠΎΠ»Π΅Π³ΠΈ ΠΊΠΎΡΠΈΡΡΠ΅ΡΡΠΈ ΠΌΠΎΡΠ½Π° Π±ΠΈΠ±Π»ΠΈΠΎΡΠ΅ΠΊΠ° OpenCV. ΠΠΎ ΡΠΎΠ° Π²ΡΠ΅ΠΌΠ΅ Π½Π΅ΠΌΠ°ΡΠ΅ Π³ΠΎΡΠΎΠ² ΠΏΠ°ΠΊΠ΅Ρ Π·Π° R (ΡΠ΅Π³Π° Π½Π΅ΠΌΠ°), ΠΏΠ° ΠΌΠΈΠ½ΠΈΠΌΠ°Π»Π½Π° ΠΈΠΌΠΏΠ»Π΅ΠΌΠ΅Π½ΡΠ°ΡΠΈΡΠ° Π½Π° ΠΏΠΎΡΡΠ΅Π±Π½Π°ΡΠ° ΡΡΠ½ΠΊΡΠΈΠΎΠ½Π°Π»Π½ΠΎΡΡ Π±Π΅ΡΠ΅ Π½Π°ΠΏΠΈΡΠ°Π½Π° Π²ΠΎ C++ ΡΠΎ ΠΈΠ½ΡΠ΅Π³ΡΠ°ΡΠΈΡΠ° Π²ΠΎ R ΠΊΠΎΠ΄ ΠΊΠΎΡΠΈΡΡΠ΅ΡΡΠΈ Rcpp.
ΠΠ° Π΄Π° ΡΠ΅ ΡΠ΅ΡΠΈ ΠΏΡΠΎΠ±Π»Π΅ΠΌΠΎΡ, Π±Π΅Π° ΠΊΠΎΡΠΈΡΡΠ΅Π½ΠΈ ΡΠ»Π΅Π΄Π½ΠΈΡΠ΅ ΠΏΠ°ΠΊΠ΅ΡΠΈ ΠΈ Π±ΠΈΠ±Π»ΠΈΠΎΡΠ΅ΠΊΠΈ:
-
OpenCV Π·Π° ΡΠ°Π±ΠΎΡΠ° ΡΠΎ ΡΠ»ΠΈΠΊΠΈ ΠΈ ΡΡΡΠ°ΡΠ΅ Π»ΠΈΠ½ΠΈΠΈ. ΠΠΎΡΠΈΡΡΠ΅Π½ΠΈ ΠΏΡΠ΅ΡΡ ΠΎΠ΄Π½ΠΎ ΠΈΠ½ΡΡΠ°Π»ΠΈΡΠ°Π½ΠΈ ΡΠΈΡΡΠ΅ΠΌΡΠΊΠΈ Π±ΠΈΠ±Π»ΠΈΠΎΡΠ΅ΠΊΠΈ ΠΈ Π΄Π°ΡΠΎΡΠ΅ΠΊΠΈ ΡΠΎ Π·Π°Π³Π»Π°Π²ΠΈΡΠ°, ΠΊΠ°ΠΊΠΎ ΠΈ Π΄ΠΈΠ½Π°ΠΌΠΈΡΠ½ΠΎ ΠΏΠΎΠ²ΡΠ·ΡΠ²Π°ΡΠ΅.
-
xtensor Π·Π° ΡΠ°Π±ΠΎΡΠ° ΡΠΎ ΠΏΠΎΠ²Π΅ΡΠ΅Π΄ΠΈΠΌΠ΅Π½Π·ΠΈΠΎΠ½Π°Π»Π½ΠΈ Π½ΠΈΠ·ΠΈ ΠΈ ΡΠ΅Π½Π·ΠΎΡΠΈ. ΠΠΎΡΠΈΡΡΠΈΠ²ΠΌΠ΅ Π΄Π°ΡΠΎΡΠ΅ΠΊΠΈ ΡΠΎ Π·Π°Π³Π»Π°Π²ΠΈΡΠ° Π²ΠΊΠ»ΡΡΠ΅Π½ΠΈ Π²ΠΎ ΠΈΡΡΠΎΠΈΠΌΠ΅Π½ΠΈΠΎΡ ΠΏΠ°ΠΊΠ΅Ρ R. ΠΠΈΠ±Π»ΠΈΠΎΡΠ΅ΠΊΠ°ΡΠ° Π²ΠΈ ΠΎΠ²ΠΎΠ·ΠΌΠΎΠΆΡΠ²Π° Π΄Π° ΡΠ°Π±ΠΎΡΠΈΡΠ΅ ΡΠΎ ΠΏΠΎΠ²Π΅ΡΠ΅Π΄ΠΈΠΌΠ΅Π½Π·ΠΈΠΎΠ½Π°Π»Π½ΠΈ Π½ΠΈΠ·ΠΈ, ΠΈ ΠΏΠΎ ΡΠ΅Π΄ ΠΈ Π³Π»Π°Π²Π΅Π½ ΡΠ΅Π΄ΠΎΡΠ»Π΅Π΄ Π½Π° ΠΊΠΎΠ»ΠΎΠ½ΠΈ.
-
Π½ΡΡΠΎΠ½ Π·Π° ΠΏΠ°ΡΡΠΈΡΠ°ΡΠ΅ Π½Π° JSON. ΠΠ²Π°Π° Π±ΠΈΠ±Π»ΠΈΠΎΡΠ΅ΠΊΠ° ΡΠ΅ ΠΊΠΎΡΠΈΡΡΠΈ Π²ΠΎ xtensor Π°Π²ΡΠΎΠΌΠ°ΡΡΠΊΠΈ Π΄ΠΎΠΊΠΎΠ»ΠΊΡ Π΅ ΠΏΡΠΈΡΡΡΠ΅Π½ Π²ΠΎ ΠΏΡΠΎΠ΅ΠΊΡΠΎΡ.
-
RcppThread Π·Π° ΠΎΡΠ³Π°Π½ΠΈΠ·ΠΈΡΠ°ΡΠ΅ Π½Π° ΠΏΠΎΠ²Π΅ΡΠ΅Π½ΠΈΡΠΊΠ° ΠΎΠ±ΡΠ°Π±ΠΎΡΠΊΠ° Π½Π° Π²Π΅ΠΊΡΠΎΡ ΠΎΠ΄ JSON. ΠΠΈ ΠΊΠΎΡΠΈΡΡΠ΅ΡΠ΅ Π΄Π°ΡΠΎΡΠ΅ΠΊΠΈΡΠ΅ Π·Π° Π·Π°Π³Π»Π°Π²ΠΈΡΠ° ΠΎΠ±Π΅Π·Π±Π΅Π΄Π΅Π½ΠΈ ΠΎΠ΄ ΠΎΠ²ΠΎΡ ΠΏΠ°ΠΊΠ΅Ρ. ΠΠ΄ ΠΏΠΎΠ²Π΅ΡΠ΅ ΠΏΠΎΠΏΡΠ»Π°ΡΠ½ΠΈ RcppΠΠ°ΡΠ°Π»Π΅Π»Π½ΠΎ ΠΠ°ΠΊΠ΅ΡΠΎΡ, ΠΌΠ΅ΡΡ Π΄ΡΡΠ³ΠΎΡΠΎ, ΠΈΠΌΠ° Π²Π³ΡΠ°Π΄Π΅Π½ ΠΌΠ΅Ρ Π°Π½ΠΈΠ·Π°ΠΌ Π·Π° ΠΏΡΠ΅ΠΊΠΈΠ½ Π½Π° ΡΠ°ΠΌΠΊΠ°ΡΠ°.
Π’ΡΠ΅Π±Π° Π΄Π° ΡΠ΅ Π½Π°ΠΏΠΎΠΌΠ΅Π½Π΅ Π΄Π΅ΠΊΠ° xtensor ΡΠ΅ ΠΏΠΎΠΊΠ°ΠΆΠ° ΠΊΠ°ΠΊΠΎ ΠΠΎΠΆΡΠΈ Π΄Π°Ρ: ΠΏΠΎΠΊΡΠ°Ρ ΡΠ°ΠΊΡΠΎΡ ΡΡΠΎ ΠΈΠΌΠ° ΠΎΠ±Π΅ΠΌΠ½Π° ΡΡΠ½ΠΊΡΠΈΠΎΠ½Π°Π»Π½ΠΎΡΡ ΠΈ Π²ΠΈΡΠΎΠΊΠΈ ΠΏΠ΅ΡΡΠΎΡΠΌΠ°Π½ΡΠΈ, Π½Π΅Π³ΠΎΠ²ΠΈΡΠ΅ ΠΏΡΠΎΠ³ΡΠ°ΠΌΠ΅ΡΠΈ ΡΠ΅ ΠΏΠΎΠΊΠ°ΠΆΠ°Π° ΠΊΠ°ΠΊΠΎ Π΄ΠΎΡΡΠ° ΠΎΠ΄Π³ΠΎΠ²ΠΎΡΠ½ΠΈ ΠΈ ΠΎΠ΄Π³ΠΎΠ²ΠΎΡΠΈΡΠ° Π½Π° ΠΏΡΠ°ΡΠ°ΡΠ° Π±ΡΠ·ΠΎ ΠΈ Π΄Π΅ΡΠ°Π»Π½ΠΎ. Π‘ΠΎ Π½ΠΈΠ²Π½Π° ΠΏΠΎΠΌΠΎΡ, Π±Π΅ΡΠ΅ ΠΌΠΎΠΆΠ½ΠΎ Π΄Π° ΡΠ΅ ΠΈΠΌΠΏΠ»Π΅ΠΌΠ΅Π½ΡΠΈΡΠ°Π°Ρ ΡΡΠ°Π½ΡΡΠΎΡΠΌΠ°ΡΠΈΠΈ Π½Π° OpenCV ΠΌΠ°ΡΡΠΈΡΠΈ Π²ΠΎ xtensor ΡΠ΅Π½Π·ΠΎΡΠΈ, ΠΊΠ°ΠΊΠΎ ΠΈ Π½Π°ΡΠΈΠ½ Π·Π° ΠΊΠΎΠΌΠ±ΠΈΠ½ΠΈΡΠ°ΡΠ΅ Π½Π° 3-Π΄ΠΈΠΌΠ΅Π½Π·ΠΈΠΎΠ½Π°Π»Π½ΠΈ ΡΠ΅Π½Π·ΠΎΡΠΈ Π½Π° ΡΠ»ΠΈΠΊΠ° Π²ΠΎ 4-Π΄ΠΈΠΌΠ΅Π½Π·ΠΈΠΎΠ½Π°Π»Π΅Π½ ΡΠ΅Π½Π·ΠΎΡ ΡΠΎ ΠΏΡΠ°Π²ΠΈΠ»Π½Π° Π΄ΠΈΠΌΠ΅Π½Π·ΠΈΡΠ° (ΡΠ°ΠΌΠ°ΡΠ° ΡΠ΅ΡΠΈΡΠ°).
ΠΠ°ΡΠ΅ΡΠΈΡΠ°Π»ΠΈ Π·Π° ΡΡΠ΅ΡΠ΅ Rcpp, xtensor ΠΈ RcppThread
ΠΠ° Π΄Π° ΡΠΎΡΡΠ°Π²ΠΈΠΌΠ΅ Π΄Π°ΡΠΎΡΠ΅ΠΊΠΈ ΡΡΠΎ ΠΊΠΎΡΠΈΡΡΠ°Ρ ΡΠΈΡΡΠ΅ΠΌΡΠΊΠΈ Π΄Π°ΡΠΎΡΠ΅ΠΊΠΈ ΠΈ Π΄ΠΈΠ½Π°ΠΌΠΈΡΠ½ΠΎ ΠΏΠΎΠ²ΡΠ·ΡΠ²Π°ΡΠ΅ ΡΠΎ Π±ΠΈΠ±Π»ΠΈΠΎΡΠ΅ΠΊΠΈ ΠΈΠ½ΡΡΠ°Π»ΠΈΡΠ°Π½ΠΈ Π½Π° ΡΠΈΡΡΠ΅ΠΌΠΎΡ, Π³ΠΎ ΠΊΠΎΡΠΈΡΡΠ΅Π²ΠΌΠ΅ ΠΌΠ΅Ρ Π°Π½ΠΈΠ·ΠΌΠΎΡ Π·Π° ΠΏΡΠΈΠΊΠ»ΡΡΠΎΡΠΈ ΠΈΠΌΠΏΠ»Π΅ΠΌΠ΅Π½ΡΠΈΡΠ°Π½ Π²ΠΎ ΠΏΠ°ΠΊΠ΅ΡΠΎΡ Rcpp. ΠΠ° Π°Π²ΡΠΎΠΌΠ°ΡΡΠΊΠΎ Π½Π°ΠΎΡΠ°ΡΠ΅ ΠΏΠ°ΡΠ΅ΠΊΠΈ ΠΈ Π·Π½Π°ΠΌΠΈΡΠ°, ΠΊΠΎΡΠΈΡΡΠ΅Π²ΠΌΠ΅ ΠΏΠΎΠΏΡΠ»Π°ΡΠ½Π° Π°Π»Π°ΡΠΊΠ° Π·Π° Linux pkg-ΠΊΠΎΠ½ΡΠΈΠ³ΡΡΠ°ΡΠΈΡΠ°.
ΠΠΌΠΏΠ»Π΅ΠΌΠ΅Π½ΡΠ°ΡΠΈΡΠ° Π½Π° ΠΏΡΠΈΠΊΠ»ΡΡΠΎΠΊΠΎΡ Rcpp Π·Π° ΠΊΠΎΡΠΈΡΡΠ΅ΡΠ΅ Π½Π° Π±ΠΈΠ±Π»ΠΈΠΎΡΠ΅ΠΊΠ°ΡΠ° OpenCV
Rcpp::registerPlugin("opencv", function() {
# ΠΠΎΠ·ΠΌΠΎΠΆΠ½ΡΠ΅ Π½Π°Π·Π²Π°Π½ΠΈΡ ΠΏΠ°ΠΊΠ΅ΡΠ°
pkg_config_name <- c("opencv", "opencv4")
# ΠΠΈΠ½Π°ΡΠ½ΡΠΉ ΡΠ°ΠΉΠ» ΡΡΠΈΠ»ΠΈΡΡ pkg-config
pkg_config_bin <- Sys.which("pkg-config")
# ΠΡΠΎΠ²ΡΠ΅ΠΊΠ° Π½Π°Π»ΠΈΡΠΈΡ ΡΡΠΈΠ»ΠΈΡΡ Π² ΡΠΈΡΡΠ΅ΠΌΠ΅
checkmate::assert_file_exists(pkg_config_bin, access = "x")
# ΠΡΠΎΠ²Π΅ΡΠΊΠ° Π½Π°Π»ΠΈΡΠΈΡ ΡΠ°ΠΉΠ»Π° Π½Π°ΡΡΡΠΎΠ΅ΠΊ OpenCV Π΄Π»Ρ pkg-config
check <- sapply(pkg_config_name,
function(pkg) system(paste(pkg_config_bin, pkg)))
if (all(check != 0)) {
stop("OpenCV config for the pkg-config not found", call. = FALSE)
}
pkg_config_name <- pkg_config_name[check == 0]
list(env = list(
PKG_CXXFLAGS = system(paste(pkg_config_bin, "--cflags", pkg_config_name),
intern = TRUE),
PKG_LIBS = system(paste(pkg_config_bin, "--libs", pkg_config_name),
intern = TRUE)
))
})
ΠΠ°ΠΊΠΎ ΡΠ΅Π·ΡΠ»ΡΠ°Ρ Π½Π° ΡΠ°Π±ΠΎΡΠ°ΡΠ° Π½Π° ΠΏΡΠΈΠΊΠ»ΡΡΠΎΠΊΠΎΡ, ΡΠ»Π΅Π΄Π½ΠΈΡΠ΅ Π²ΡΠ΅Π΄Π½ΠΎΡΡΠΈ ΡΠ΅ Π±ΠΈΠ΄Π°Ρ Π·Π°ΠΌΠ΅Π½Π΅ΡΠΈ Π·Π° Π²ΡΠ΅ΠΌΠ΅ Π½Π° ΠΏΡΠΎΡΠ΅ΡΠΎΡ Π½Π° ΠΊΠΎΠΌΠΏΠΈΠ»Π°ΡΠΈΡΠ°:
Rcpp:::.plugins$opencv()$env
# $PKG_CXXFLAGS
# [1] "-I/usr/include/opencv"
#
# $PKG_LIBS
# [1] "-lopencv_shape -lopencv_stitching -lopencv_superres -lopencv_videostab -lopencv_aruco -lopencv_bgsegm -lopencv_bioinspired -lopencv_ccalib -lopencv_datasets -lopencv_dpm -lopencv_face -lopencv_freetype -lopencv_fuzzy -lopencv_hdf -lopencv_line_descriptor -lopencv_optflow -lopencv_video -lopencv_plot -lopencv_reg -lopencv_saliency -lopencv_stereo -lopencv_structured_light -lopencv_phase_unwrapping -lopencv_rgbd -lopencv_viz -lopencv_surface_matching -lopencv_text -lopencv_ximgproc -lopencv_calib3d -lopencv_features2d -lopencv_flann -lopencv_xobjdetect -lopencv_objdetect -lopencv_ml -lopencv_xphoto -lopencv_highgui -lopencv_videoio -lopencv_imgcodecs -lopencv_photo -lopencv_imgproc -lopencv_core"
ΠΠΎΠ΄ ΡΠΏΠΎΡΠ»Π΅ΡΠΎΡ Π΅ Π΄Π°Π΄Π΅Π½ ΠΊΠΎΠ΄ΠΎΡ Π·Π° ΠΈΠΌΠΏΠ»Π΅ΠΌΠ΅Π½ΡΠ°ΡΠΈΡΠ° Π·Π° ΠΏΠ°ΡΡΠΈΡΠ°ΡΠ΅ Π½Π° JSON ΠΈ Π³Π΅Π½Π΅ΡΠΈΡΠ°ΡΠ΅ ΡΠ΅ΡΠΈΡΠ° Π·Π° ΠΏΡΠ΅Π½ΠΎΡ Π΄ΠΎ ΠΌΠΎΠ΄Π΅Π»ΠΎΡ. ΠΡΠ²ΠΎ, Π΄ΠΎΠ΄Π°Π΄Π΅ΡΠ΅ Π»ΠΎΠΊΠ°Π»Π΅Π½ ΠΏΡΠΎΠ΅ΠΊΡΠ΅Π½ Π΄ΠΈΡΠ΅ΠΊΡΠΎΡΠΈΡΠΌ Π·Π° ΠΏΡΠ΅Π±Π°ΡΡΠ²Π°ΡΠ΅ Π½Π° Π΄Π°ΡΠΎΡΠ΅ΠΊΠΈ ΡΠΎ Π·Π°Π³Π»Π°Π²ΠΈΡΠ° (ΠΏΠΎΡΡΠ΅Π±Π½ΠΈ Π·Π° ndjson):
Sys.setenv("PKG_CXXFLAGS" = paste0("-I", normalizePath(file.path("src"))))
ΠΠΌΠΏΠ»Π΅ΠΌΠ΅Π½ΡΠ°ΡΠΈΡΠ° Π½Π° ΠΊΠΎΠ½Π²Π΅ΡΠ·ΠΈΡΠ° Π½Π° JSON Π²ΠΎ ΡΠ΅Π½Π·ΠΎΡ Π²ΠΎ C++
// [[Rcpp::plugins(cpp14)]]
// [[Rcpp::plugins(opencv)]]
// [[Rcpp::depends(xtensor)]]
// [[Rcpp::depends(RcppThread)]]
#include <xtensor/xjson.hpp>
#include <xtensor/xadapt.hpp>
#include <xtensor/xview.hpp>
#include <xtensor-r/rtensor.hpp>
#include <opencv2/core/core.hpp>
#include <opencv2/highgui/highgui.hpp>
#include <opencv2/imgproc/imgproc.hpp>
#include <Rcpp.h>
#include <RcppThread.h>
// Π‘ΠΈΠ½ΠΎΠ½ΠΈΠΌΡ Π΄Π»Ρ ΡΠΈΠΏΠΎΠ²
using RcppThread::parallelFor;
using json = nlohmann::json;
using points = xt::xtensor<double,2>; // ΠΠ·Π²Π»Π΅ΡΡΠ½Π½ΡΠ΅ ΠΈΠ· JSON ΠΊΠΎΠΎΡΠ΄ΠΈΠ½Π°ΡΡ ΡΠΎΡΠ΅ΠΊ
using strokes = std::vector<points>; // ΠΠ·Π²Π»Π΅ΡΡΠ½Π½ΡΠ΅ ΠΈΠ· JSON ΠΊΠΎΠΎΡΠ΄ΠΈΠ½Π°ΡΡ ΡΠΎΡΠ΅ΠΊ
using xtensor3d = xt::xtensor<double, 3>; // Π’Π΅Π½Π·ΠΎΡ Π΄Π»Ρ Ρ
ΡΠ°Π½Π΅Π½ΠΈΡ ΠΌΠ°ΡΡΠΈΡΡ ΠΈΠ·ΠΎΠΎΠ±ΡΠ°ΠΆΠ΅Π½ΠΈΡ
using xtensor4d = xt::xtensor<double, 4>; // Π’Π΅Π½Π·ΠΎΡ Π΄Π»Ρ Ρ
ΡΠ°Π½Π΅Π½ΠΈΡ ΠΌΠ½ΠΎΠΆΠ΅ΡΡΠ²Π° ΠΈΠ·ΠΎΠ±ΡΠ°ΠΆΠ΅Π½ΠΈΠΉ
using rtensor3d = xt::rtensor<double, 3>; // ΠΠ±ΡΡΡΠΊΠ° Π΄Π»Ρ ΡΠΊΡΠΏΠΎΡΡΠ° Π² R
using rtensor4d = xt::rtensor<double, 4>; // ΠΠ±ΡΡΡΠΊΠ° Π΄Π»Ρ ΡΠΊΡΠΏΠΎΡΡΠ° Π² R
// Π‘ΡΠ°ΡΠΈΡΠ΅ΡΠΊΠΈΠ΅ ΠΊΠΎΠ½ΡΡΠ°Π½ΡΡ
// Π Π°Π·ΠΌΠ΅Ρ ΠΈΠ·ΠΎΠ±ΡΠ°ΠΆΠ΅Π½ΠΈΡ Π² ΠΏΠΈΠΊΡΠ΅Π»ΡΡ
const static int SIZE = 256;
// Π’ΠΈΠΏ Π»ΠΈΠ½ΠΈΠΈ
// Π‘ΠΌ. https://en.wikipedia.org/wiki/Pixel_connectivity#2-dimensional
const static int LINE_TYPE = cv::LINE_4;
// Π’ΠΎΠ»ΡΠΈΠ½Π° Π»ΠΈΠ½ΠΈΠΈ Π² ΠΏΠΈΠΊΡΠ΅Π»ΡΡ
const static int LINE_WIDTH = 3;
// ΠΠ»Π³ΠΎΡΠΈΡΠΌ ΡΠ΅ΡΠ°ΠΉΠ·Π°
// https://docs.opencv.org/3.1.0/da/d54/group__imgproc__transform.html#ga5bb5a1fea74ea38e1a5445ca803ff121
const static int RESIZE_TYPE = cv::INTER_LINEAR;
// Π¨Π°Π±Π»ΠΎΠ½ Π΄Π»Ρ ΠΊΠΎΠ½Π²Π΅ΡΡΠΈΡΠΎΠ²Π°Π½ΠΈΡ OpenCV-ΠΌΠ°ΡΡΠΈΡΡ Π² ΡΠ΅Π½Π·ΠΎΡ
template <typename T, int NCH, typename XT=xt::xtensor<T,3,xt::layout_type::column_major>>
XT to_xt(const cv::Mat_<cv::Vec<T, NCH>>& src) {
// Π Π°Π·ΠΌΠ΅ΡΠ½ΠΎΡΡΡ ΡΠ΅Π»Π΅Π²ΠΎΠ³ΠΎ ΡΠ΅Π½Π·ΠΎΡΠ°
std::vector<int> shape = {src.rows, src.cols, NCH};
// ΠΠ±ΡΠ΅Π΅ ΠΊΠΎΠ»ΠΈΡΠ΅ΡΡΠ²ΠΎ ΡΠ»Π΅ΠΌΠ΅Π½ΡΠΎΠ² Π² ΠΌΠ°ΡΡΠΈΠ²Π΅
size_t size = src.total() * NCH;
// ΠΡΠ΅ΠΎΠ±ΡΠ°Π·ΠΎΠ²Π°Π½ΠΈΠ΅ cv::Mat Π² xt::xtensor
XT res = xt::adapt((T*) src.data, size, xt::no_ownership(), shape);
return res;
}
// ΠΡΠ΅ΠΎΠ±ΡΠ°Π·ΠΎΠ²Π°Π½ΠΈΠ΅ JSON Π² ΡΠΏΠΈΡΠΎΠΊ ΠΊΠΎΠΎΡΠ΄ΠΈΠ½Π°Ρ ΡΠΎΡΠ΅ΠΊ
strokes parse_json(const std::string& x) {
auto j = json::parse(x);
// Π Π΅Π·ΡΠ»ΡΡΠ°Ρ ΠΏΠ°ΡΡΠΈΠ½Π³Π° Π΄ΠΎΠ»ΠΆΠ΅Π½ Π±ΡΡΡ ΠΌΠ°ΡΡΠΈΠ²ΠΎΠΌ
if (!j.is_array()) {
throw std::runtime_error("'x' must be JSON array.");
}
strokes res;
res.reserve(j.size());
for (const auto& a: j) {
// ΠΠ°ΠΆΠ΄ΡΠΉ ΡΠ»Π΅ΠΌΠ΅Π½Ρ ΠΌΠ°ΡΡΠΈΠ²Π° Π΄ΠΎΠ»ΠΆΠ΅Π½ Π±ΡΡΡ 2-ΠΌΠ΅ΡΠ½ΡΠΌ ΠΌΠ°ΡΡΠΈΠ²ΠΎΠΌ
if (!a.is_array() || a.size() != 2) {
throw std::runtime_error("'x' must include only 2d arrays.");
}
// ΠΠ·Π²Π»Π΅ΡΠ΅Π½ΠΈΠ΅ Π²Π΅ΠΊΡΠΎΡΠ° ΡΠΎΡΠ΅ΠΊ
auto p = a.get<points>();
res.push_back(p);
}
return res;
}
// ΠΡΡΠΈΡΠΎΠ²ΠΊΠ° Π»ΠΈΠ½ΠΈΠΉ
// Π¦Π²Π΅ΡΠ° HSV
cv::Mat ocv_draw_lines(const strokes& x, bool color = true) {
// ΠΡΡ
ΠΎΠ΄Π½ΡΠΉ ΡΠΈΠΏ ΠΌΠ°ΡΡΠΈΡΡ
auto stype = color ? CV_8UC3 : CV_8UC1;
// ΠΡΠΎΠ³ΠΎΠ²ΡΠΉ ΡΠΈΠΏ ΠΌΠ°ΡΡΠΈΡΡ
auto dtype = color ? CV_32FC3 : CV_32FC1;
auto bg = color ? cv::Scalar(0, 0, 255) : cv::Scalar(255);
auto col = color ? cv::Scalar(0, 255, 220) : cv::Scalar(0);
cv::Mat img = cv::Mat(SIZE, SIZE, stype, bg);
// ΠΠΎΠ»ΠΈΡΠ΅ΡΡΠ²ΠΎ Π»ΠΈΠ½ΠΈΠΉ
size_t n = x.size();
for (const auto& s: x) {
// ΠΠΎΠ»ΠΈΡΠ΅ΡΡΠ²ΠΎ ΡΠΎΡΠ΅ΠΊ Π² Π»ΠΈΠ½ΠΈΠΈ
size_t n_points = s.shape()[1];
for (size_t i = 0; i < n_points - 1; ++i) {
// Π’ΠΎΡΠΊΠ° Π½Π°ΡΠ°Π»Π° ΡΡΡΠΈΡ
Π°
cv::Point from(s(0, i), s(1, i));
// Π’ΠΎΡΠΊΠ° ΠΎΠΊΠΎΠ½ΡΠ°Π½ΠΈΡ ΡΡΡΠΈΡ
Π°
cv::Point to(s(0, i + 1), s(1, i + 1));
// ΠΡΡΠΈΡΠΎΠ²ΠΊΠ° Π»ΠΈΠ½ΠΈΠΈ
cv::line(img, from, to, col, LINE_WIDTH, LINE_TYPE);
}
if (color) {
// ΠΠ΅Π½ΡΠ΅ΠΌ ΡΠ²Π΅Ρ Π»ΠΈΠ½ΠΈΠΈ
col[0] += 180 / n;
}
}
if (color) {
// ΠΠ΅Π½ΡΠ΅ΠΌ ΡΠ²Π΅ΡΠΎΠ²ΠΎΠ΅ ΠΏΡΠ΅Π΄ΡΡΠ°Π²Π»Π΅Π½ΠΈΠ΅ Π½Π° RGB
cv::cvtColor(img, img, cv::COLOR_HSV2RGB);
}
// ΠΠ΅Π½ΡΠ΅ΠΌ ΡΠΎΡΠΌΠ°Ρ ΠΏΡΠ΅Π΄ΡΡΠ°Π²Π»Π΅Π½ΠΈΡ Π½Π° float32 Ρ Π΄ΠΈΠ°ΠΏΠ°Π·ΠΎΠ½ΠΎΠΌ [0, 1]
img.convertTo(img, dtype, 1 / 255.0);
return img;
}
// ΠΠ±ΡΠ°Π±ΠΎΡΠΊΠ° JSON ΠΈ ΠΏΠΎΠ»ΡΡΠ΅Π½ΠΈΠ΅ ΡΠ΅Π½Π·ΠΎΡΠ° Ρ Π΄Π°Π½Π½ΡΠΌΠΈ ΠΈΠ·ΠΎΠ±ΡΠ°ΠΆΠ΅Π½ΠΈΡ
xtensor3d process(const std::string& x, double scale = 1.0, bool color = true) {
auto p = parse_json(x);
auto img = ocv_draw_lines(p, color);
if (scale != 1) {
cv::Mat out;
cv::resize(img, out, cv::Size(), scale, scale, RESIZE_TYPE);
cv::swap(img, out);
out.release();
}
xtensor3d arr = color ? to_xt<double,3>(img) : to_xt<double,1>(img);
return arr;
}
// [[Rcpp::export]]
rtensor3d cpp_process_json_str(const std::string& x,
double scale = 1.0,
bool color = true) {
xtensor3d res = process(x, scale, color);
return res;
}
// [[Rcpp::export]]
rtensor4d cpp_process_json_vector(const std::vector<std::string>& x,
double scale = 1.0,
bool color = false) {
size_t n = x.size();
size_t dim = floor(SIZE * scale);
size_t channels = color ? 3 : 1;
xtensor4d res({n, dim, dim, channels});
parallelFor(0, n, [&x, &res, scale, color](int i) {
xtensor3d tmp = process(x[i], scale, color);
auto view = xt::view(res, i, xt::all(), xt::all(), xt::all());
view = tmp;
});
return res;
}
ΠΠ²ΠΎΡ ΠΊΠΎΠ΄ ΡΡΠ΅Π±Π° Π΄Π° ΡΠ΅ ΡΡΠ°Π²ΠΈ Π²ΠΎ Π΄Π°ΡΠΎΡΠ΅ΠΊΠ°ΡΠ° src/cv_xt.cpp
ΠΈ ΠΊΠΎΠΌΠΏΠ°ΡΠ»ΠΈΡΠ°ΡΡΠ΅ ΡΠΎ ΠΊΠΎΠΌΠ°Π½Π΄Π°ΡΠ° Rcpp::sourceCpp(file = "src/cv_xt.cpp", env = .GlobalEnv)
; ΠΈΡΡΠΎ ΡΠ°ΠΊΠ° ΠΏΠΎΡΡΠ΅Π±Π½ΠΈ Π·Π° ΡΠ°Π±ΠΎΡΠ° nlohmann/json.hpp
Π½Π°
-
to_xt
β ΡΠ°Π±Π»ΠΎΠ½ΡΠΊΠ° ΡΡΠ½ΠΊΡΠΈΡΠ° Π·Π° ΡΡΠ°Π½ΡΡΠΎΡΠΌΠΈΡΠ°ΡΠ΅ ΠΌΠ°ΡΡΠΈΡΠ° Π½Π° ΡΠ»ΠΈΠΊΠ° (cv::Mat
) Π½Π° ΡΠ΅Π½Π·ΠΎΡxt::xtensor
; -
parse_json
β ΡΡΠ½ΠΊΡΠΈΡΠ°ΡΠ° Π°Π½Π°Π»ΠΈΠ·ΠΈΡΠ° Π½ΠΈΠ·Π° JSON, Π³ΠΈ ΠΈΠ·Π²Π»Π΅ΠΊΡΠ²Π° ΠΊΠΎΠΎΡΠ΄ΠΈΠ½Π°ΡΠΈΡΠ΅ Π½Π° ΡΠΎΡΠΊΠΈΡΠ΅, ΠΏΠ°ΠΊΡΠ²Π°ΡΡΠΈ Π³ΠΈ Π²ΠΎ Π²Π΅ΠΊΡΠΎΡ; -
ocv_draw_lines
β ΠΎΠ΄ Π΄ΠΎΠ±ΠΈΠ΅Π½ΠΈΠΎΡ Π²Π΅ΠΊΡΠΎΡ Π½Π° ΡΠΎΡΠΊΠΈ, ΡΡΡΠ° ΠΏΠΎΠ²Π΅ΡΠ΅Π±ΠΎΡΠ½ΠΈ Π»ΠΈΠ½ΠΈΠΈ; -
process
β Π³ΠΈ ΠΊΠΎΠΌΠ±ΠΈΠ½ΠΈΡΠ° Π³ΠΎΡΠ΅Π½Π°Π²Π΅Π΄Π΅Π½ΠΈΡΠ΅ ΡΡΠ½ΠΊΡΠΈΠΈ ΠΈ ΠΈΡΡΠΎ ΡΠ°ΠΊΠ° Π΄ΠΎΠ΄Π°Π²Π° ΠΌΠΎΠΆΠ½ΠΎΡΡ Π·Π° ΡΠΊΠ°Π»ΠΈΡΠ°ΡΠ΅ Π½Π° Π΄ΠΎΠ±ΠΈΠ΅Π½Π°ΡΠ° ΡΠ»ΠΈΠΊΠ°; -
cpp_process_json_str
- ΠΎΠ±Π²ΠΈΠ²ΠΊΠ° Π½Π°Π΄ ΡΡΠ½ΠΊΡΠΈΡΠ°ΡΠ°process
, ΠΊΠΎΡ Π³ΠΎ ΠΈΠ·Π²Π΅Π·ΡΠ²Π° ΡΠ΅Π·ΡΠ»ΡΠ°ΡΠΎΡ Π²ΠΎ R-ΠΎΠ±ΡΠ΅ΠΊΡ (ΠΌΡΠ»ΡΠΈΠ΄ΠΈΠΌΠ΅Π½Π·ΠΈΠΎΠ½Π°Π»Π½Π° Π½ΠΈΠ·Π°); -
cpp_process_json_vector
- ΠΎΠ±Π²ΠΈΠ²ΠΊΠ° Π½Π°Π΄ ΡΡΠ½ΠΊΡΠΈΡΠ°ΡΠ°cpp_process_json_str
, ΠΊΠΎΡ Π²ΠΈ ΠΎΠ²ΠΎΠ·ΠΌΠΎΠΆΡΠ²Π° Π΄Π° ΠΎΠ±ΡΠ°Π±ΠΎΡΠΈΡΠ΅ ΡΡΡΠΈΠ½Π³ Π²Π΅ΠΊΡΠΎΡ Π²ΠΎ ΡΠ΅ΠΆΠΈΠΌ ΡΠΎ ΠΏΠΎΠ²Π΅ΡΠ΅ Π½ΠΈΡΠΊΠΈ.
ΠΠ° ΡΡΡΠ°ΡΠ΅ Π»ΠΈΠ½ΠΈΠΈ Π²ΠΎ ΠΏΠΎΠ²Π΅ΡΠ΅ Π±ΠΎΠΈ, ΠΊΠΎΡΠΈΡΡΠ΅Π½ Π΅ ΠΌΠΎΠ΄Π΅Π»ΠΎΡ Π½Π° Π±ΠΎΡΠ° HSV, ΠΏΡΠΎΡΠ»Π΅Π΄Π΅Π½ ΡΠΎ ΠΊΠΎΠ½Π²Π΅ΡΠ·ΠΈΡΠ° Π²ΠΎ RGB. ΠΡΠ΄Π΅ Π΄Π° Π³ΠΎ ΡΠ΅ΡΡΠΈΡΠ°ΠΌΠ΅ ΡΠ΅Π·ΡΠ»ΡΠ°ΡΠΎΡ:
arr <- cpp_process_json_str(tmp_data[4, drawing])
dim(arr)
# [1] 256 256 3
plot(magick::image_read(arr))
Π‘ΠΏΠΎΡΠ΅Π΄Π±Π° Π½Π° Π±ΡΠ·ΠΈΠ½Π°ΡΠ° Π½Π° ΠΈΠΌΠΏΠ»Π΅ΠΌΠ΅Π½ΡΠ°ΡΠΈΠΈ Π²ΠΎ R ΠΈ C++
res_bench <- bench::mark(
r_process_json_str(tmp_data[4, drawing], scale = 0.5),
cpp_process_json_str(tmp_data[4, drawing], scale = 0.5),
check = FALSE,
min_iterations = 100
)
# ΠΠ°ΡΠ°ΠΌΠ΅ΡΡΡ Π±Π΅Π½ΡΠΌΠ°ΡΠΊΠ°
cols <- c("expression", "min", "median", "max", "itr/sec", "total_time", "n_itr")
res_bench[, cols]
# expression min median max `itr/sec` total_time n_itr
# <chr> <bch:tm> <bch:tm> <bch:tm> <dbl> <bch:tm> <int>
# 1 r_process_json_str 3.49ms 3.55ms 4.47ms 273. 490ms 134
# 2 cpp_process_json_str 1.94ms 2.02ms 5.32ms 489. 497ms 243
library(ggplot2)
# ΠΡΠΎΠ²Π΅Π΄Π΅Π½ΠΈΠ΅ Π·Π°ΠΌΠ΅ΡΠ°
res_bench <- bench::press(
batch_size = 2^(4:10),
{
.data <- tmp_data[sample(seq_len(.N), batch_size), drawing]
bench::mark(
r_process_json_vector(.data, scale = 0.5),
cpp_process_json_vector(.data, scale = 0.5),
min_iterations = 50,
check = FALSE
)
}
)
res_bench[, cols]
# expression batch_size min median max `itr/sec` total_time n_itr
# <chr> <dbl> <bch:tm> <bch:tm> <bch:tm> <dbl> <bch:tm> <int>
# 1 r 16 50.61ms 53.34ms 54.82ms 19.1 471.13ms 9
# 2 cpp 16 4.46ms 5.39ms 7.78ms 192. 474.09ms 91
# 3 r 32 105.7ms 109.74ms 212.26ms 7.69 6.5s 50
# 4 cpp 32 7.76ms 10.97ms 15.23ms 95.6 522.78ms 50
# 5 r 64 211.41ms 226.18ms 332.65ms 3.85 12.99s 50
# 6 cpp 64 25.09ms 27.34ms 32.04ms 36.0 1.39s 50
# 7 r 128 534.5ms 627.92ms 659.08ms 1.61 31.03s 50
# 8 cpp 128 56.37ms 58.46ms 66.03ms 16.9 2.95s 50
# 9 r 256 1.15s 1.18s 1.29s 0.851 58.78s 50
# 10 cpp 256 114.97ms 117.39ms 130.09ms 8.45 5.92s 50
# 11 r 512 2.09s 2.15s 2.32s 0.463 1.8m 50
# 12 cpp 512 230.81ms 235.6ms 261.99ms 4.18 11.97s 50
# 13 r 1024 4s 4.22s 4.4s 0.238 3.5m 50
# 14 cpp 1024 410.48ms 431.43ms 462.44ms 2.33 21.45s 50
ggplot(res_bench, aes(x = factor(batch_size), y = median,
group = expression, color = expression)) +
geom_point() +
geom_line() +
ylab("median time, s") +
theme_minimal() +
scale_color_discrete(name = "", labels = c("cpp", "r")) +
theme(legend.position = "bottom")
ΠΠ°ΠΊΠΎ ΡΡΠΎ ΠΌΠΎΠΆΠ΅ΡΠ΅ Π΄Π° Π²ΠΈΠ΄ΠΈΡΠ΅, Π·Π³ΠΎΠ»Π΅ΠΌΡΠ²Π°ΡΠ΅ΡΠΎ Π½Π° Π±ΡΠ·ΠΈΠ½Π°ΡΠ° ΡΠ΅ ΠΏΠΎΠΊΠ°ΠΆΠ° ΠΊΠ°ΠΊΠΎ ΠΌΠ½ΠΎΠ³Ρ Π·Π½Π°ΡΠ°ΡΠ½ΠΎ ΠΈ Π½Π΅ Π΅ ΠΌΠΎΠΆΠ½ΠΎ Π΄Π° ΡΠ΅ ΡΡΠΈΠ³Π½Π΅ Π΄ΠΎ C++ ΠΊΠΎΠ΄ΠΎΡ ΡΠΎ ΠΏΠ°ΡΠ°Π»Π΅Π»ΠΈΠ·ΠΈΡΠ°ΡΠ΅ Π½Π° R-ΠΊΠΎΠ΄ΠΎΡ.
3. ΠΡΠ΅ΡΠ°ΡΠΎΡΠΈ Π·Π° ΠΈΡΡΠΎΠ²Π°Ρ Π½Π° ΡΠ΅ΡΠΈΠΈ ΠΎΠ΄ Π±Π°Π·Π°ΡΠ° Π½Π° ΠΏΠΎΠ΄Π°ΡΠΎΡΠΈ
R ΠΈΠΌΠ° Π·Π°ΡΠ»ΡΠΆΠ΅Π½Π° ΡΠ΅ΠΏΡΡΠ°ΡΠΈΡΠ° Π·Π° ΠΎΠ±ΡΠ°Π±ΠΎΡΠΊΠ° Π½Π° ΠΏΠΎΠ΄Π°ΡΠΎΡΠΈ ΡΡΠΎ ΡΠ΅ Π²ΠΊΠ»ΠΎΠΏΡΠ²Π°Π°Ρ Π²ΠΎ RAM ΠΌΠ΅ΠΌΠΎΡΠΈΡΠ°ΡΠ°, Π΄ΠΎΠ΄Π΅ΠΊΠ° Python ΠΏΠΎΠ²Π΅ΡΠ΅ ΡΠ΅ ΠΊΠ°ΡΠ°ΠΊΡΠ΅ΡΠΈΠ·ΠΈΡΠ° ΡΠΎ ΠΈΡΠ΅ΡΠ°ΡΠΈΠ²Π½Π° ΠΎΠ±ΡΠ°Π±ΠΎΡΠΊΠ° Π½Π° ΠΏΠΎΠ΄Π°ΡΠΎΡΠΈ, ΡΡΠΎ Π²ΠΈ ΠΎΠ²ΠΎΠ·ΠΌΠΎΠΆΡΠ²Π° Π»Π΅ΡΠ½ΠΎ ΠΈ ΠΏΡΠΈΡΠΎΠ΄Π½ΠΎ Π΄Π° ΡΠΏΡΠΎΠ²Π΅Π΄ΡΠ²Π°ΡΠ΅ ΠΏΡΠ΅ΡΠΌΠ΅ΡΠΊΠΈ Π½Π°Π΄Π²ΠΎΡ ΠΎΠ΄ ΡΠ°Π΄ΡΠΎΡΠΎ (ΠΏΡΠ΅ΡΠΌΠ΅ΡΠΊΠΈ ΡΠΎ ΠΏΠΎΠΌΠΎΡ Π½Π° Π½Π°Π΄Π²ΠΎΡΠ΅ΡΠ½Π° ΠΌΠ΅ΠΌΠΎΡΠΈΡΠ°). ΠΠ»Π°ΡΠΈΡΠ΅Π½ ΠΈ ΡΠ΅Π»Π΅Π²Π°Π½ΡΠ΅Π½ ΠΏΡΠΈΠΌΠ΅Ρ Π·Π° Π½Π°Ρ Π²ΠΎ ΠΊΠΎΠ½ΡΠ΅ΠΊΡΡ Π½Π° ΠΎΠΏΠΈΡΠ°Π½ΠΈΠΎΡ ΠΏΡΠΎΠ±Π»Π΅ΠΌ ΡΠ΅ Π΄Π»Π°Π±ΠΎΠΊΠΈΡΠ΅ Π½Π΅Π²ΡΠΎΠ½ΡΠΊΠΈ ΠΌΡΠ΅ΠΆΠΈ ΠΎΠ±ΡΡΠ΅Π½ΠΈ ΡΠΎ ΠΌΠ΅ΡΠΎΠ΄ΠΎΡ Π½Π° ΡΠΏΡΡΡΠ°ΡΠ΅ Π½Π° Π³ΡΠ°Π΄ΠΈΠ΅Π½Ρ ΡΠΎ ΠΏΡΠΈΠ±Π»ΠΈΠΆΡΠ²Π°ΡΠ΅ Π½Π° Π³ΡΠ°Π΄ΠΈΠ΅Π½ΡΠΎΡ Π½Π° ΡΠ΅ΠΊΠΎΡ ΡΠ΅ΠΊΠΎΡ ΠΊΠΎΡΠΈΡΡΠ΅ΡΡΠΈ ΠΌΠ°Π» Π΄Π΅Π» ΠΎΠ΄ Π½Π°Π±ΡΡΠ΄ΡΠ²Π°ΡΠ°, ΠΈΠ»ΠΈ ΠΌΠΈΠ½ΠΈ-ΡΠ΅ΡΠΈΡΠ°.
Π Π°ΠΌΠΊΠΈΡΠ΅ Π·Π° Π΄Π»Π°Π±ΠΎΠΊΠΎ ΡΡΠ΅ΡΠ΅ Π½Π°ΠΏΠΈΡΠ°Π½ΠΈ Π²ΠΎ Python ΠΈΠΌΠ°Π°Ρ ΠΏΠΎΡΠ΅Π±Π½ΠΈ ΠΊΠ»Π°ΡΠΈ ΠΊΠΎΠΈ ΠΈΠΌΠΏΠ»Π΅ΠΌΠ΅Π½ΡΠΈΡΠ°Π°Ρ ΠΈΡΠ΅ΡΠ°ΡΠΎΡΠΈ Π±Π°Π·ΠΈΡΠ°Π½ΠΈ Π½Π° ΠΏΠΎΠ΄Π°ΡΠΎΡΠΈ: ΡΠ°Π±Π΅Π»ΠΈ, ΡΠ»ΠΈΠΊΠΈ Π²ΠΎ ΠΏΠ°ΠΏΠΊΠΈ, Π±ΠΈΠ½Π°ΡΠ½ΠΈ ΡΠΎΡΠΌΠ°ΡΠΈ ΠΈΡΠ½. ΠΠΎΠΆΠ΅ΡΠ΅ Π΄Π° ΠΊΠΎΡΠΈΡΡΠΈΡΠ΅ Π³ΠΎΡΠΎΠ²ΠΈ ΠΎΠΏΡΠΈΠΈ ΠΈΠ»ΠΈ Π΄Π° Π½Π°ΠΏΠΈΡΠ΅ΡΠ΅ ΡΠ²ΠΎΠΈ Π·Π° ΠΊΠΎΠ½ΠΊΡΠ΅ΡΠ½ΠΈ Π·Π°Π΄Π°ΡΠΈ. ΠΠΎ R ΠΌΠΎΠΆΠ΅ΠΌΠ΅ Π΄Π° Π³ΠΈ ΠΈΡΠΊΠΎΡΠΈΡΡΠΈΠΌΠ΅ ΡΠΈΡΠ΅ ΠΊΠ°ΡΠ°ΠΊΡΠ΅ΡΠΈΡΡΠΈΠΊΠΈ Π½Π° Π±ΠΈΠ±Π»ΠΈΠΎΡΠ΅ΠΊΠ°ΡΠ° Π½Π° Python ΠΊΠ΅ΡΠ°Ρ ΡΠΎ Π½Π΅Π³ΠΎΠ²ΠΈΡΠ΅ ΡΠ°Π·Π»ΠΈΡΠ½ΠΈ Π·Π°Π΄Π½ΠΈ Π΄Π΅Π»ΠΎΠ²ΠΈ ΠΊΠΎΡΠΈΡΡΠ΅ΡΡΠΈ Π³ΠΎ ΠΈΡΡΠΎΠΈΠΌΠ΅Π½ΠΈΠΎΡ ΠΏΠ°ΠΊΠ΅Ρ, ΠΊΠΎΡ ΠΏΠ°ΠΊ ΡΠ°Π±ΠΎΡΠΈ Π½Π° Π²ΡΠ²ΠΎΡ Π½Π° ΠΏΠ°ΠΊΠ΅ΡΠΎΡ ΠΌΡΠ΅ΠΆΠ΅ΡΡΠΈ. ΠΡΠΎΡΠΈΠΎΡ Π·Π°ΡΠ»ΡΠΆΡΠ²Π° ΠΏΠΎΡΠ΅Π±Π½Π° Π΄ΠΎΠ»Π³Π° ΡΡΠ°ΡΠΈΡΠ°; Π½Π΅ ΡΠ°ΠΌΠΎ ΡΡΠΎ Π²ΠΈ ΠΎΠ²ΠΎΠ·ΠΌΠΎΠΆΡΠ²Π° Π΄Π° ΠΈΠ·Π²ΡΡΠΈΡΠ΅ Python ΠΊΠΎΠ΄ ΠΎΠ΄ R, ΡΡΠΊΡ ΠΈΡΡΠΎ ΡΠ°ΠΊΠ° Π²ΠΈ ΠΎΠ²ΠΎΠ·ΠΌΠΎΠΆΡΠ²Π° Π΄Π° ΠΏΡΠ΅Π½Π΅ΡΡΠ²Π°ΡΠ΅ ΠΎΠ±ΡΠ΅ΠΊΡΠΈ ΠΏΠΎΠΌΠ΅ΡΡ R ΠΈ Python ΡΠ΅ΡΠΈΠΈ, Π°Π²ΡΠΎΠΌΠ°ΡΡΠΊΠΈ ΠΈΠ·Π²ΡΡΡΠ²Π°ΡΡΠΈ Π³ΠΈ ΡΠΈΡΠ΅ ΠΏΠΎΡΡΠ΅Π±Π½ΠΈ ΠΊΠΎΠ½Π²Π΅ΡΠ·ΠΈΠΈ Π½Π° ΡΠΈΠΏΠΎΠ²ΠΈ.
Π‘Π΅ ΠΎΡΠ»ΠΎΠ±ΠΎΠ΄ΠΈΠ²ΠΌΠ΅ ΠΎΠ΄ ΠΏΠΎΡΡΠ΅Π±Π°ΡΠ° Π΄Π° Π³ΠΈ ΡΠΊΠ»Π°Π΄ΠΈΡΠ°ΠΌΠ΅ ΡΠΈΡΠ΅ ΠΏΠΎΠ΄Π°ΡΠΎΡΠΈ Π²ΠΎ RAM ΠΌΠ΅ΠΌΠΎΡΠΈΡΠ°ΡΠ° ΡΠΎ ΠΏΠΎΠΌΠΎΡ Π½Π° MonetDBLite, ΡΠ΅Π»Π°ΡΠ° ΡΠ°Π±ΠΎΡΠ° Π½Π° βΠ½Π΅Π²ΡΠΎΠ½ΡΠΊΠ°ΡΠ° ΠΌΡΠ΅ΠΆΠ°β ΡΠ΅ ΡΠ° Π²ΡΡΠΈ ΠΎΡΠΈΠ³ΠΈΠ½Π°Π»Π½ΠΈΠΎΡ ΠΊΠΎΠ΄ Π²ΠΎ Python, ΡΠ°ΠΌΠΎ ΡΡΠ΅Π±Π° Π΄Π° Π½Π°ΠΏΠΈΡΠ΅ΠΌΠ΅ ΠΈΡΠ΅ΡΠ°ΡΠΎΡ Π½Π°Π΄ ΠΏΠΎΠ΄Π°ΡΠΎΡΠΈΡΠ΅, Π±ΠΈΠ΄Π΅ΡΡΠΈ Π½Π΅ΠΌΠ° Π½ΠΈΡΡΠΎ ΠΏΠΎΠ΄Π³ΠΎΡΠ²Π΅Π½ΠΎ Π·Π° ΡΠ°ΠΊΠ²Π° ΡΠΈΡΡΠ°ΡΠΈΡΠ° ΠΈΠ»ΠΈ Π²ΠΎ R ΠΈΠ»ΠΈ Π²ΠΎ Python. ΠΠΎ ΡΡΡΡΠΈΠ½Π° ΠΈΠΌΠ° ΡΠ°ΠΌΠΎ Π΄Π²Π΅ Π±Π°ΡΠ°ΡΠ° Π·Π° Π½Π΅Π³ΠΎ: ΠΌΠΎΡΠ° Π΄Π° Π³ΠΈ Π²ΡΠ°ΡΠΈ ΡΠ΅ΡΠΈΠΈΡΠ΅ Π²ΠΎ Π±Π΅ΡΠΊΡΠ°ΡΠ½Π° ΡΠ°ΠΌΠΊΠ° ΠΈ Π΄Π° ΡΠ° Π·Π°ΡΡΠ²Π° ΡΠ²ΠΎΡΠ°ΡΠ° ΡΠΎΡΡΠΎΡΠ±Π° ΠΏΠΎΠΌΠ΅ΡΡ ΠΏΠΎΠ²ΡΠΎΡΡΠ²Π°ΡΠ°ΡΠ° (Π²ΡΠΎΡΠΎΡΠΎ Π²ΠΎ R ΡΠ΅ ΠΈΠΌΠΏΠ»Π΅ΠΌΠ΅Π½ΡΠΈΡΠ° Π½Π° Π½Π°ΡΠ΅Π΄Π½ΠΎΡΡΠ°Π²Π΅Π½ Π½Π°ΡΠΈΠ½ ΠΊΠΎΡΠΈΡΡΠ΅ΡΡΠΈ Π·Π°ΡΠ²ΠΎΡΠ°ΡΠΈ). ΠΡΠ΅ΡΡ ΠΎΠ΄Π½ΠΎ, Π±Π΅ΡΠ΅ ΠΏΠΎΡΡΠ΅Π±Π½ΠΎ Π΅ΠΊΡΠΏΠ»ΠΈΡΠΈΡΠ½ΠΎ Π΄Π° ΡΠ΅ ΠΊΠΎΠ½Π²Π΅ΡΡΠΈΡΠ°Π°Ρ R-Π½ΠΈΠ·ΠΈΡΠ΅ Π²ΠΎ numpy Π½ΠΈΠ·ΠΈ Π²Π½Π°ΡΡΠ΅ Π²ΠΎ ΠΈΡΠ΅ΡΠ°ΡΠΎΡΠΎΡ, Π½ΠΎ ΡΠ΅ΠΊΠΎΠ²Π½Π°ΡΠ° Π²Π΅ΡΠ·ΠΈΡΠ° Π½Π° ΠΏΠ°ΠΊΠ΅ΡΠΎΡ ΠΊΠ΅ΡΠ°Ρ Π³ΠΎ ΠΏΡΠ°Π²ΠΈ ΡΠΎΠ° ΡΠ°ΠΌΠ°.
ΠΡΠ΅ΡΠ°ΡΠΎΡΠΎΡ Π·Π° ΠΏΠΎΠ΄Π°ΡΠΎΡΠΈ Π·Π° ΠΎΠ±ΡΠΊΠ° ΠΈ Π²Π°Π»ΠΈΠ΄Π°ΡΠΈΡΠ° ΡΠ΅ ΠΏΠΎΠΊΠ°ΠΆΠ° ΠΊΠ°ΠΊΠΎ ΡΡΠΎ ΡΠ»Π΅Π΄ΡΠ²Π°:
ΠΡΠ΅ΡΠ°ΡΠΎΡ Π·Π° ΠΎΠ±ΡΠΊΠ° ΠΈ ΠΏΠΎΠ΄Π°ΡΠΎΡΠΈ Π·Π° Π²Π°Π»ΠΈΠ΄Π°ΡΠΈΡΠ°
train_generator <- function(db_connection = con,
samples_index,
num_classes = 340,
batch_size = 32,
scale = 1,
color = FALSE,
imagenet_preproc = FALSE) {
# ΠΡΠΎΠ²Π΅ΡΠΊΠ° Π°ΡΠ³ΡΠΌΠ΅Π½ΡΠΎΠ²
checkmate::assert_class(con, "DBIConnection")
checkmate::assert_integerish(samples_index)
checkmate::assert_count(num_classes)
checkmate::assert_count(batch_size)
checkmate::assert_number(scale, lower = 0.001, upper = 5)
checkmate::assert_flag(color)
checkmate::assert_flag(imagenet_preproc)
# ΠΠ΅ΡΠ΅ΠΌΠ΅ΡΠΈΠ²Π°Π΅ΠΌ, ΡΡΠΎΠ±Ρ Π±ΡΠ°ΡΡ ΠΈ ΡΠ΄Π°Π»ΡΡΡ ΠΈΡΠΏΠΎΠ»ΡΠ·ΠΎΠ²Π°Π½Π½ΡΠ΅ ΠΈΠ½Π΄Π΅ΠΊΡΡ Π±Π°ΡΡΠ΅ΠΉ ΠΏΠΎ ΠΏΠΎΡΡΠ΄ΠΊΡ
dt <- data.table::data.table(id = sample(samples_index))
# ΠΡΠΎΡΡΠ°Π²Π»ΡΠ΅ΠΌ Π½ΠΎΠΌΠ΅ΡΠ° Π±Π°ΡΡΠ΅ΠΉ
dt[, batch := (.I - 1L) %/% batch_size + 1L]
# ΠΡΡΠ°Π²Π»ΡΠ΅ΠΌ ΡΠΎΠ»ΡΠΊΠΎ ΠΏΠΎΠ»Π½ΡΠ΅ Π±Π°ΡΡΠΈ ΠΈ ΠΈΠ½Π΄Π΅ΠΊΡΠΈΡΡΠ΅ΠΌ
dt <- dt[, if (.N == batch_size) .SD, keyby = batch]
# Π£ΡΡΠ°Π½Π°Π²Π»ΠΈΠ²Π°Π΅ΠΌ ΡΡΡΡΡΠΈΠΊ
i <- 1
# ΠΠΎΠ»ΠΈΡΠ΅ΡΡΠ²ΠΎ Π±Π°ΡΡΠ΅ΠΉ
max_i <- dt[, max(batch)]
# ΠΠΎΠ΄Π³ΠΎΡΠΎΠ²ΠΊΠ° Π²ΡΡΠ°ΠΆΠ΅Π½ΠΈΡ Π΄Π»Ρ Π²ΡΠ³ΡΡΠ·ΠΊΠΈ
sql <- sprintf(
"PREPARE SELECT drawing, label_int FROM doodles WHERE id IN (%s)",
paste(rep("?", batch_size), collapse = ",")
)
res <- DBI::dbSendQuery(con, sql)
# ΠΠ½Π°Π»ΠΎΠ³ keras::to_categorical
to_categorical <- function(x, num) {
n <- length(x)
m <- numeric(n * num)
m[x * n + seq_len(n)] <- 1
dim(m) <- c(n, num)
return(m)
}
# ΠΠ°ΠΌΡΠΊΠ°Π½ΠΈΠ΅
function() {
# ΠΠ°ΡΠΈΠ½Π°Π΅ΠΌ Π½ΠΎΠ²ΡΡ ΡΠΏΠΎΡ
Ρ
if (i > max_i) {
dt[, id := sample(id)]
data.table::setkey(dt, batch)
# Π‘Π±ΡΠ°ΡΡΠ²Π°Π΅ΠΌ ΡΡΡΡΡΠΈΠΊ
i <<- 1
max_i <<- dt[, max(batch)]
}
# ID Π΄Π»Ρ Π²ΡΠ³ΡΡΠ·ΠΊΠΈ Π΄Π°Π½Π½ΡΡ
batch_ind <- dt[batch == i, id]
# ΠΡΠ³ΡΡΠ·ΠΊΠ° Π΄Π°Π½Π½ΡΡ
batch <- DBI::dbFetch(DBI::dbBind(res, as.list(batch_ind)), n = -1)
# Π£Π²Π΅Π»ΠΈΡΠΈΠ²Π°Π΅ΠΌ ΡΡΡΡΡΠΈΠΊ
i <<- i + 1
# ΠΠ°ΡΡΠΈΠ½Π³ JSON ΠΈ ΠΏΠΎΠ΄Π³ΠΎΡΠΎΠ²ΠΊΠ° ΠΌΠ°ΡΡΠΈΠ²Π°
batch_x <- cpp_process_json_vector(batch$drawing, scale = scale, color = color)
if (imagenet_preproc) {
# Π¨ΠΊΠ°Π»ΠΈΡΠΎΠ²Π°Π½ΠΈΠ΅ c ΠΈΠ½ΡΠ΅ΡΠ²Π°Π»Π° [0, 1] Π½Π° ΠΈΠ½ΡΠ΅ΡΠ²Π°Π» [-1, 1]
batch_x <- (batch_x - 0.5) * 2
}
batch_y <- to_categorical(batch$label_int, num_classes)
result <- list(batch_x, batch_y)
return(result)
}
}
Π€ΡΠ½ΠΊΡΠΈΡΠ°ΡΠ° Π·Π΅ΠΌΠ° ΠΊΠ°ΠΊΠΎ Π²Π»Π΅Π· ΠΏΡΠΎΠΌΠ΅Π½Π»ΠΈΠ²Π° ΡΠΎ ΠΏΠΎΠ²ΡΠ·ΡΠ²Π°ΡΠ΅ ΡΠΎ Π±Π°Π·Π°ΡΠ° Π½Π° ΠΏΠΎΠ΄Π°ΡΠΎΡΠΈ, Π±ΡΠΎΡΠΎΡ Π½Π° ΠΊΠΎΡΠΈΡΡΠ΅Π½ΠΈ Π»ΠΈΠ½ΠΈΠΈ, Π±ΡΠΎΡΠΎΡ Π½Π° ΠΊΠ»Π°ΡΠΈ, Π³ΠΎΠ»Π΅ΠΌΠΈΠ½Π°ΡΠ° Π½Π° ΡΠ΅ΡΠΈΡΠ°ΡΠ°, ΡΠΊΠ°Π»Π°ΡΠ° (scale = 1
ΠΎΠ΄Π³ΠΎΠ²Π°ΡΠ° Π½Π° ΠΏΡΠΈΠΊΠ°ΠΆΡΠ²Π°ΡΠ΅ ΡΠ»ΠΈΠΊΠΈ ΠΎΠ΄ 256x256 ΠΏΠΈΠΊΡΠ΅Π»ΠΈ, scale = 0.5
β 128x128 ΠΏΠΈΠΊΡΠ΅Π»ΠΈ), ΠΈΠ½Π΄ΠΈΠΊΠ°ΡΠΎΡ Π·Π° Π±ΠΎΡΠ° (color = FALSE
ΠΎΠ΄ΡΠ΅Π΄ΡΠ²Π° ΡΠ΅Π½Π΄Π΅ΡΠΈΡΠ°ΡΠ΅ Π²ΠΎ ΡΠΈΠ²ΠΈ ΡΠΎΠ½ΠΎΠ²ΠΈ ΠΊΠΎΠ³Π° ΡΠ΅ ΠΊΠΎΡΠΈΡΡΠΈ color = TRUE
ΡΠ΅ΠΊΠΎΡ ΠΏΠΎΡΠ΅Π³ Π΅ Π½Π°ΡΡΡΠ°Π½ Π²ΠΎ Π½ΠΎΠ²Π° Π±ΠΎΡΠ°) ΠΈ ΠΈΠ½Π΄ΠΈΠΊΠ°ΡΠΎΡ Π·Π° ΠΏΡΠ΅ΡΠΏΡΠΎΡΠ΅ΡΠΈΡΠ°ΡΠ΅ Π·Π° ΠΌΡΠ΅ΠΆΠΈ ΠΏΡΠ΅ΡΡ
ΠΎΠ΄Π½ΠΎ ΠΎΠ±ΡΡΠ΅Π½ΠΈ Π½Π° imagenet. ΠΠΎΡΠ»Π΅Π΄Π½ΠΎΠ²ΠΎ Π΅ ΠΏΠΎΡΡΠ΅Π±Π½ΠΎ Π·Π° Π΄Π° ΡΠ΅ Π½Π°ΠΌΠ°Π»Π°Ρ Π²ΡΠ΅Π΄Π½ΠΎΡΡΠΈΡΠ΅ Π½Π° ΠΏΠΈΠΊΡΠ΅Π»ΠΈΡΠ΅ ΠΎΠ΄ ΠΈΠ½ΡΠ΅ΡΠ²Π°Π»ΠΎΡ [0, 1] Π΄ΠΎ ΠΈΠ½ΡΠ΅ΡΠ²Π°Π»ΠΎΡ [-1, 1], ΡΡΠΎ ΡΠ΅ ΠΊΠΎΡΠΈΡΡΠ΅ΡΠ΅ ΠΏΡΠΈ ΠΎΠ±ΡΠΊΠ° Π½Π° ΠΈΡΠΏΠΎΡΠ°ΡΠ°Π½ΠΈΡΠ΅ ΠΊΠ΅ΡΠ°Ρ ΠΌΠΎΠ΄Π΅Π»ΠΈ.
ΠΠ°Π΄Π²ΠΎΡΠ΅ΡΠ½Π°ΡΠ° ΡΡΠ½ΠΊΡΠΈΡΠ° ΡΠΎΠ΄ΡΠΆΠΈ ΠΏΡΠΎΠ²Π΅ΡΠΊΠ° Π½Π° ΡΠΈΠΏΠΎΡ Π½Π° Π°ΡΠ³ΡΠΌΠ΅Π½ΡΠΈ, ΡΠ°Π±Π΅Π»Π° data.table
ΡΠΎ ΡΠ»ΡΡΠ°ΡΠ½ΠΎ ΠΈΠ·ΠΌΠ΅ΡΠ°Π½ΠΈ Π»ΠΈΠ½ΠΈΠΈ ΠΎΠ΄ samples_index
ΠΈ Π±ΡΠΎΠ΅Π²ΠΈ Π½Π° ΡΠ΅ΡΠΈΠΈ, Π±ΡΠΎΡΠ°Ρ ΠΈ ΠΌΠ°ΠΊΡΠΈΠΌΠ°Π»Π΅Π½ Π±ΡΠΎΡ Π½Π° ΡΠ΅ΡΠΈΠΈ, ΠΊΠ°ΠΊΠΎ ΠΈ SQL ΠΈΠ·ΡΠ°Π· Π·Π° ΠΈΡΡΠΎΠ²Π°Ρ Π½Π° ΠΏΠΎΠ΄Π°ΡΠΎΡΠΈ ΠΎΠ΄ Π±Π°Π·Π°ΡΠ° Π½Π° ΠΏΠΎΠ΄Π°ΡΠΎΡΠΈ. ΠΠΎΠΏΠΎΠ»Π½ΠΈΡΠ΅Π»Π½ΠΎ, Π΄Π΅ΡΠΈΠ½ΠΈΡΠ°Π²ΠΌΠ΅ Π±ΡΠ· Π°Π½Π°Π»ΠΎΠ³ Π½Π° ΡΡΠ½ΠΊΡΠΈΡΠ°ΡΠ° Π²Π½Π°ΡΡΠ΅ keras::to_categorical()
. ΠΠΈ ΠΈΡΠΊΠΎΡΠΈΡΡΠΈΠ²ΠΌΠ΅ ΡΠΊΠΎΡΠΎ ΡΠΈΡΠ΅ ΠΏΠΎΠ΄Π°ΡΠΎΡΠΈ Π·Π° ΠΎΠ±ΡΠΊΠ°, ΠΎΡΡΠ°Π²Π°ΡΡΠΈ ΠΏΠΎΠ»ΠΎΠ²ΠΈΠ½Π° ΠΏΡΠΎΡΠ΅Π½Ρ Π·Π° Π²Π°Π»ΠΈΠ΄Π°ΡΠΈΡΠ°, ΡΠ°ΠΊΠ° ΡΡΠΎ Π³ΠΎΠ»Π΅ΠΌΠΈΠ½Π°ΡΠ° Π½Π° Π΅ΠΏΠΎΡ
Π°ΡΠ° Π±Π΅ΡΠ΅ ΠΎΠ³ΡΠ°Π½ΠΈΡΠ΅Π½Π° ΡΠΎ ΠΏΠ°ΡΠ°ΠΌΠ΅ΡΠ°ΡΠΎΡ steps_per_epoch
ΠΊΠΎΠ³Π° ΡΠ΅ ΡΠ΅ ΠΏΠΎΠ²ΠΈΠΊΠ°Π°Ρ keras::fit_generator()
, ΠΈ ΡΠΎΡΡΠΎΡΠ±Π°ΡΠ° if (i > max_i)
ΡΠ°Π±ΠΎΡΠ΅ΡΠ΅ ΡΠ°ΠΌΠΎ Π·Π° ΠΈΡΠ΅ΡΠ°ΡΠΎΡ Π·Π° Π²Π°Π»ΠΈΠ΄Π°ΡΠΈΡΠ°.
ΠΠΎ Π²Π½Π°ΡΡΠ΅ΡΠ½Π°ΡΠ° ΡΡΠ½ΠΊΡΠΈΡΠ°, ΠΈΠ½Π΄Π΅ΠΊΡΠΈΡΠ΅ Π½Π° ΡΠ΅Π΄ΠΎΠ²ΠΈ ΡΠ΅ ΠΏΡΠ΅Π·Π΅ΠΌΠ°Π°Ρ Π·Π° ΡΠ»Π΅Π΄Π½Π°ΡΠ° ΡΠ΅ΡΠΈΡΠ°, Π·Π°ΠΏΠΈΡΠΈΡΠ΅ ΡΠ΅ ΠΈΡΡΠΎΠ²Π°ΡΡΠ²Π°Π°Ρ ΠΎΠ΄ Π±Π°Π·Π°ΡΠ° Π½Π° ΠΏΠΎΠ΄Π°ΡΠΎΡΠΈ ΡΠΎ Π·Π³ΠΎΠ»Π΅ΠΌΡΠ²Π°ΡΠ΅ Π½Π° Π±ΡΠΎΡΠ°ΡΠΎΡ Π½Π° ΡΠ΅ΡΠΈΡΠ°, ΠΏΠ°ΡΡΠΈΡΠ°ΡΠ΅ JSON (ΡΡΠ½ΠΊΡΠΈΡΠ° cpp_process_json_vector()
, Π½Π°ΠΏΠΈΡΠ°Π½ΠΎ Π²ΠΎ C++) ΠΈ ΡΠΎΠ·Π΄Π°Π²Π°ΡΠ΅ Π½ΠΈΠ·ΠΈ ΡΡΠΎ ΠΎΠ΄Π³ΠΎΠ²Π°ΡΠ°Π°Ρ Π½Π° ΡΠ»ΠΈΠΊΠΈ. ΠΠΎΡΠΎΠ° ΡΠ΅ ΡΠΎΠ·Π΄Π°Π²Π°Π°Ρ Π΅Π΄Π½ΠΎ-ΠΆΠ΅ΡΠΊΠΈ Π²Π΅ΠΊΡΠΎΡΠΈ ΡΠΎ ΠΎΠ·Π½Π°ΠΊΠΈ Π·Π° ΠΊΠ»Π°ΡΠΈ, Π½ΠΈΠ·ΠΈ ΡΠΎ Π²ΡΠ΅Π΄Π½ΠΎΡΡΠΈ Π½Π° ΠΏΠΈΠΊΡΠ΅Π»ΠΈ ΠΈ Π΅ΡΠΈΠΊΠ΅ΡΠΈ ΡΠ΅ ΠΊΠΎΠΌΠ±ΠΈΠ½ΠΈΡΠ°Π°Ρ Π²ΠΎ Π»ΠΈΡΡΠ°, ΡΡΠΎ Π΅ ΠΏΠΎΠ²ΡΠ°ΡΠ½Π°ΡΠ° Π²ΡΠ΅Π΄Π½ΠΎΡΡ. ΠΠ° Π΄Π° ΡΠ° Π·Π°Π±ΡΠ·Π°ΠΌΠ΅ ΡΠ°Π±ΠΎΡΠ°ΡΠ°, ΠΊΠΎΡΠΈΡΡΠ΅Π²ΠΌΠ΅ ΡΠΎΠ·Π΄Π°Π²Π°ΡΠ΅ Π½Π° ΠΈΠ½Π΄Π΅ΠΊΡΠΈ Π²ΠΎ ΡΠ°Π±Π΅Π»ΠΈ data.table
ΠΈ ΠΌΠΎΠ΄ΠΈΡΠΈΠΊΠ°ΡΠΈΡΠ° ΠΏΡΠ΅ΠΊΡ Π²ΡΡΠΊΠ°ΡΠ° - Π±Π΅Π· ΠΎΠ²ΠΈΠ΅ ΠΏΠ°ΠΊΠ΅ΡΠΈ βΡΠΈΠΏΠΎΠ²ΠΈβ ΠΏΠΎΠ΄Π°ΡΠΎΡΠΈ. ΡΠ°Π±Π΅Π»Π° ΠΡΠΈΠ»ΠΈΡΠ½ΠΎ Π΅ ΡΠ΅ΡΠΊΠΎ Π΄Π° ΡΠ΅ Π·Π°ΠΌΠΈΡΠ»ΠΈ Π΄Π° ΡΠ΅ ΡΠ°Π±ΠΎΡΠΈ Π΅ΡΠ΅ΠΊΡΠΈΠ²Π½ΠΎ ΡΠΎ ΠΊΠΎΡΠ° Π±ΠΈΠ»ΠΎ Π·Π½Π°ΡΠΈΡΠ΅Π»Π½Π° ΠΊΠΎΠ»ΠΈΡΠΈΠ½Π° Π½Π° ΠΏΠΎΠ΄Π°ΡΠΎΡΠΈ Π²ΠΎ Π .
Π Π΅Π·ΡΠ»ΡΠ°ΡΠΈΡΠ΅ ΠΎΠ΄ ΠΌΠ΅ΡΠ΅ΡΠ΅ΡΠΎ Π½Π° Π±ΡΠ·ΠΈΠ½Π°ΡΠ° Π½Π° Π»Π°ΠΏΡΠΎΠΏΠΎΡ Core i5 ΡΠ΅ ΠΊΠ°ΠΊΠΎ ΡΡΠΎ ΡΠ»Π΅Π΄ΡΠ²Π°:
ΠΡΠ΅ΡΠ°ΡΠΎΡ ΡΠ΅ΠΏΠ΅Ρ
library(Rcpp)
library(keras)
library(ggplot2)
source("utils/rcpp.R")
source("utils/keras_iterator.R")
con <- DBI::dbConnect(drv = MonetDBLite::MonetDBLite(), Sys.getenv("DBDIR"))
ind <- seq_len(DBI::dbGetQuery(con, "SELECT count(*) FROM doodles")[[1L]])
num_classes <- DBI::dbGetQuery(con, "SELECT max(label_int) + 1 FROM doodles")[[1L]]
# ΠΠ½Π΄Π΅ΠΊΡΡ Π΄Π»Ρ ΠΎΠ±ΡΡΠ°ΡΡΠ΅ΠΉ Π²ΡΠ±ΠΎΡΠΊΠΈ
train_ind <- sample(ind, floor(length(ind) * 0.995))
# ΠΠ½Π΄Π΅ΠΊΡΡ Π΄Π»Ρ ΠΏΡΠΎΠ²Π΅ΡΠΎΡΠ½ΠΎΠΉ Π²ΡΠ±ΠΎΡΠΊΠΈ
val_ind <- ind[-train_ind]
rm(ind)
# ΠΠΎΡΡΡΠΈΡΠΈΠ΅Π½Ρ ΠΌΠ°ΡΡΡΠ°Π±Π°
scale <- 0.5
# ΠΡΠΎΠ²Π΅Π΄Π΅Π½ΠΈΠ΅ Π·Π°ΠΌΠ΅ΡΠ°
res_bench <- bench::press(
batch_size = 2^(4:10),
{
it1 <- train_generator(
db_connection = con,
samples_index = train_ind,
num_classes = num_classes,
batch_size = batch_size,
scale = scale
)
bench::mark(
it1(),
min_iterations = 50L
)
}
)
# ΠΠ°ΡΠ°ΠΌΠ΅ΡΡΡ Π±Π΅Π½ΡΠΌΠ°ΡΠΊΠ°
cols <- c("batch_size", "min", "median", "max", "itr/sec", "total_time", "n_itr")
res_bench[, cols]
# batch_size min median max `itr/sec` total_time n_itr
# <dbl> <bch:tm> <bch:tm> <bch:tm> <dbl> <bch:tm> <int>
# 1 16 25ms 64.36ms 92.2ms 15.9 3.09s 49
# 2 32 48.4ms 118.13ms 197.24ms 8.17 5.88s 48
# 3 64 69.3ms 117.93ms 181.14ms 8.57 5.83s 50
# 4 128 157.2ms 240.74ms 503.87ms 3.85 12.71s 49
# 5 256 359.3ms 613.52ms 988.73ms 1.54 30.5s 47
# 6 512 884.7ms 1.53s 2.07s 0.674 1.11m 45
# 7 1024 2.7s 3.83s 5.47s 0.261 2.81m 44
ggplot(res_bench, aes(x = factor(batch_size), y = median, group = 1)) +
geom_point() +
geom_line() +
ylab("median time, s") +
theme_minimal()
DBI::dbDisconnect(con, shutdown = TRUE)
ΠΠΊΠΎ ΠΈΠΌΠ°ΡΠ΅ Π΄ΠΎΠ²ΠΎΠ»Π½ΠΎ ΠΊΠΎΠ»ΠΈΡΠ΅ΡΡΠ²ΠΎ RAM ΠΌΠ΅ΠΌΠΎΡΠΈΡΠ°, ΠΌΠΎΠΆΠ΅ΡΠ΅ ΡΠ΅ΡΠΈΠΎΠ·Π½ΠΎ Π΄Π° ΡΠ° Π·Π°Π±ΡΠ·Π°ΡΠ΅ ΡΠ°Π±ΠΎΡΠ°ΡΠ° Π½Π° Π±Π°Π·Π°ΡΠ° ΡΠΎ ΠΏΡΠ΅ΡΡΠ»Π°ΡΠ΅ Π½Π° ΠΈΡΡΠ°ΡΠ° RAM ΠΌΠ΅ΠΌΠΎΡΠΈΡΠ° (32 GB ΡΠ΅ Π΄ΠΎΠ²ΠΎΠ»Π½ΠΈ Π·Π° Π½Π°ΡΠ°ΡΠ° Π·Π°Π΄Π°ΡΠ°). ΠΠΎ Linux, ΠΏΠ°ΡΡΠΈΡΠΈΡΠ°ΡΠ° Π΅ ΡΡΠ°Π½Π΄Π°ΡΠ΄Π½ΠΎ ΠΌΠΎΠ½ΡΠΈΡΠ°Π½Π° /dev/shm
, Π·Π°ΡΠ°ΡΠ°ΡΡΠΈ Π΄ΠΎ ΠΏΠΎΠ»ΠΎΠ²ΠΈΠ½Π° ΠΎΠ΄ ΠΊΠ°ΠΏΠ°ΡΠΈΡΠ΅ΡΠΎΡ Π½Π° RAM ΠΌΠ΅ΠΌΠΎΡΠΈΡΠ°ΡΠ°. ΠΠΎΠΆΠ΅ΡΠ΅ Π΄Π° ΠΈΡΡΠ°ΠΊΠ½Π΅ΡΠ΅ ΠΏΠΎΠ²Π΅ΡΠ΅ ΡΠΎ ΡΡΠ΅Π΄ΡΠ²Π°ΡΠ΅ /etc/fstab
Π΄Π° ΡΠ΅ Π΄ΠΎΠ±ΠΈΠ΅ ΡΠ΅ΠΊΠΎΡΠ΄ ΠΊΠ°ΠΊΠΎ tmpfs /dev/shm tmpfs defaults,size=25g 0 0
. ΠΠΈΠ΄Π΅ΡΠ΅ ΡΠΈΠ³ΡΡΠ½ΠΈ Π΄Π° ΡΠ΅ ΡΠ΅ΡΡΠ°ΡΡΠΈΡΠ°ΡΠ΅ ΠΈ ΠΏΡΠΎΠ²Π΅ΡΠ΅ΡΠ΅ Π³ΠΎ ΡΠ΅Π·ΡΠ»ΡΠ°ΡΠΎΡ ΡΠΎ ΠΈΠ·Π²ΡΡΡΠ²Π°ΡΠ΅ Π½Π° ΠΊΠΎΠΌΠ°Π½Π΄Π°ΡΠ° df -h
.
ΠΡΠ΅ΡΠ°ΡΠΎΡΠΎΡ Π·Π° ΡΠ΅ΡΡ-ΠΏΠΎΠ΄Π°ΡΠΎΡΠΈ ΠΈΠ·Π³Π»Π΅Π΄Π° ΠΌΠ½ΠΎΠ³Ρ ΠΏΠΎΠ΅Π΄Π½ΠΎΡΡΠ°Π²Π΅Π½, Π±ΠΈΠ΄Π΅ΡΡΠΈ ΡΠ΅ΡΠΎΡ Π·Π° ΡΠ΅ΡΡΠΈΡΠ°ΡΠ΅ ΡΠ΅Π»ΠΎΡΠ½ΠΎ ΡΠ΅ Π²ΠΊΠ»ΠΎΠΏΡΠ²Π° Π²ΠΎ RAM-ΠΎΡ:
ΠΡΠ΅ΡΠ°ΡΠΎΡ Π·Π° ΡΠ΅ΡΡ ΠΏΠΎΠ΄Π°ΡΠΎΡΠΈ
test_generator <- function(dt,
batch_size = 32,
scale = 1,
color = FALSE,
imagenet_preproc = FALSE) {
# ΠΡΠΎΠ²Π΅ΡΠΊΠ° Π°ΡΠ³ΡΠΌΠ΅Π½ΡΠΎΠ²
checkmate::assert_data_table(dt)
checkmate::assert_count(batch_size)
checkmate::assert_number(scale, lower = 0.001, upper = 5)
checkmate::assert_flag(color)
checkmate::assert_flag(imagenet_preproc)
# ΠΡΠΎΡΡΠ°Π²Π»ΡΠ΅ΠΌ Π½ΠΎΠΌΠ΅ΡΠ° Π±Π°ΡΡΠ΅ΠΉ
dt[, batch := (.I - 1L) %/% batch_size + 1L]
data.table::setkey(dt, batch)
i <- 1
max_i <- dt[, max(batch)]
# ΠΠ°ΠΌΡΠΊΠ°Π½ΠΈΠ΅
function() {
batch_x <- cpp_process_json_vector(dt[batch == i, drawing],
scale = scale, color = color)
if (imagenet_preproc) {
# Π¨ΠΊΠ°Π»ΠΈΡΠΎΠ²Π°Π½ΠΈΠ΅ c ΠΈΠ½ΡΠ΅ΡΠ²Π°Π»Π° [0, 1] Π½Π° ΠΈΠ½ΡΠ΅ΡΠ²Π°Π» [-1, 1]
batch_x <- (batch_x - 0.5) * 2
}
result <- list(batch_x)
i <<- i + 1
return(result)
}
}
4. ΠΠ·Π±ΠΎΡ Π½Π° ΠΌΠΎΠ΄Π΅Π» Π°ΡΡ ΠΈΡΠ΅ΠΊΡΡΡΠ°
ΠΡΠ²Π°ΡΠ° ΠΊΠΎΡΠΈΡΡΠ΅Π½Π° Π°ΡΡ
ΠΈΡΠ΅ΠΊΡΡΡΠ° Π±ΠΈΠ»Π° (batch, height, width, 3)
, ΠΎΠ΄Π½ΠΎΡΠ½ΠΎ Π±ΡΠΎΡΠΎΡ Π½Π° ΠΊΠ°Π½Π°Π»ΠΈ Π½Π΅ ΠΌΠΎΠΆΠ΅ Π΄Π° ΡΠ΅ ΠΏΡΠΎΠΌΠ΅Π½ΠΈ. ΠΠ΅ΠΌΠ° ΡΠ°ΠΊΠ²ΠΎ ΠΎΠ³ΡΠ°Π½ΠΈΡΡΠ²Π°ΡΠ΅ Π²ΠΎ Python, ΠΏΠ° Π·Π°ΡΠΎΠ° ΠΏΠΎΠ±ΡΠ·Π°Π²ΠΌΠ΅ ΠΈ Π½Π°ΠΏΠΈΡΠ°Π²ΠΌΠ΅ ΡΠΎΠΏΡΡΠ²Π΅Π½Π° ΠΈΠΌΠΏΠ»Π΅ΠΌΠ΅Π½ΡΠ°ΡΠΈΡΠ° Π½Π° ΠΎΠ²Π°Π° Π°ΡΡ
ΠΈΡΠ΅ΠΊΡΡΡΠ°, ΡΠ»Π΅Π΄Π΅ΡΡΠΈ ΡΠ° ΠΎΡΠΈΠ³ΠΈΠ½Π°Π»Π½Π°ΡΠ° ΡΡΠ°ΡΠΈΡΠ° (Π±Π΅Π· ΠΎΡΠΏΠΈΡΡΠ²Π°ΡΠ΅ΡΠΎ ΡΡΠΎ Π΅ Π²ΠΎ Π²Π΅ΡΠ·ΠΈΡΠ°ΡΠ° keras):
ΠΡΡ ΠΈΡΠ΅ΠΊΡΡΡΠ° Π½Π° Mobilenet v1
library(keras)
top_3_categorical_accuracy <- custom_metric(
name = "top_3_categorical_accuracy",
metric_fn = function(y_true, y_pred) {
metric_top_k_categorical_accuracy(y_true, y_pred, k = 3)
}
)
layer_sep_conv_bn <- function(object,
filters,
alpha = 1,
depth_multiplier = 1,
strides = c(2, 2)) {
# NB! depth_multiplier != resolution multiplier
# https://github.com/keras-team/keras/issues/10349
layer_depthwise_conv_2d(
object = object,
kernel_size = c(3, 3),
strides = strides,
padding = "same",
depth_multiplier = depth_multiplier
) %>%
layer_batch_normalization() %>%
layer_activation_relu() %>%
layer_conv_2d(
filters = filters * alpha,
kernel_size = c(1, 1),
strides = c(1, 1)
) %>%
layer_batch_normalization() %>%
layer_activation_relu()
}
get_mobilenet_v1 <- function(input_shape = c(224, 224, 1),
num_classes = 340,
alpha = 1,
depth_multiplier = 1,
optimizer = optimizer_adam(lr = 0.002),
loss = "categorical_crossentropy",
metrics = c("categorical_crossentropy",
top_3_categorical_accuracy)) {
inputs <- layer_input(shape = input_shape)
outputs <- inputs %>%
layer_conv_2d(filters = 32, kernel_size = c(3, 3), strides = c(2, 2), padding = "same") %>%
layer_batch_normalization() %>%
layer_activation_relu() %>%
layer_sep_conv_bn(filters = 64, strides = c(1, 1)) %>%
layer_sep_conv_bn(filters = 128, strides = c(2, 2)) %>%
layer_sep_conv_bn(filters = 128, strides = c(1, 1)) %>%
layer_sep_conv_bn(filters = 256, strides = c(2, 2)) %>%
layer_sep_conv_bn(filters = 256, strides = c(1, 1)) %>%
layer_sep_conv_bn(filters = 512, strides = c(2, 2)) %>%
layer_sep_conv_bn(filters = 512, strides = c(1, 1)) %>%
layer_sep_conv_bn(filters = 512, strides = c(1, 1)) %>%
layer_sep_conv_bn(filters = 512, strides = c(1, 1)) %>%
layer_sep_conv_bn(filters = 512, strides = c(1, 1)) %>%
layer_sep_conv_bn(filters = 512, strides = c(1, 1)) %>%
layer_sep_conv_bn(filters = 1024, strides = c(2, 2)) %>%
layer_sep_conv_bn(filters = 1024, strides = c(1, 1)) %>%
layer_global_average_pooling_2d() %>%
layer_dense(units = num_classes) %>%
layer_activation_softmax()
model <- keras_model(
inputs = inputs,
outputs = outputs
)
model %>% compile(
optimizer = optimizer,
loss = loss,
metrics = metrics
)
return(model)
}
ΠΠ΅Π΄ΠΎΡΡΠ°ΡΠΎΡΠΈΡΠ΅ Π½Π° ΠΎΠ²ΠΎΡ ΠΏΡΠΈΡΡΠ°ΠΏ ΡΠ΅ ΠΎΡΠΈΠ³Π»Π΅Π΄Π½ΠΈ. Π‘Π°ΠΊΠ°ΠΌ Π΄Π° ΡΠ΅ΡΡΠΈΡΠ°ΠΌ ΠΌΠ½ΠΎΠ³Ρ ΠΌΠΎΠ΄Π΅Π»ΠΈ, Π½ΠΎ Π½Π°ΠΏΡΠΎΡΠΈΠ², Π½Π΅ ΡΠ°ΠΊΠ°ΠΌ Π΄Π° ΡΠ° ΠΏΡΠ΅ΠΏΠΈΡΡΠ²Π°ΠΌ ΡΠ΅ΠΊΠΎΡΠ° Π°ΡΡ
ΠΈΡΠ΅ΠΊΡΡΡΠ° ΡΠ°ΡΠ½ΠΎ. ΠΠ΅Π²ΠΌΠ΅ Π»ΠΈΡΠ΅Π½ΠΈ ΠΎΠ΄ ΠΌΠΎΠΆΠ½ΠΎΡΡΠ° Π΄Π° Π³ΠΈ ΠΊΠΎΡΠΈΡΡΠΈΠΌΠ΅ ΡΠ΅ΠΆΠΈΠ½ΠΈΡΠ΅ Π½Π° ΠΌΠΎΠ΄Π΅Π»ΠΈΡΠ΅ ΠΏΡΠ΅ΡΡ
ΠΎΠ΄Π½ΠΎ ΠΎΠ±ΡΡΠ΅Π½ΠΈ Π½Π° imagenet. ΠΠ°ΠΊΠΎ ΠΈ ΠΎΠ±ΠΈΡΠ½ΠΎ, ΠΏΡΠΎΡΡΡΠ²Π°ΡΠ΅ΡΠΎ Π½Π° Π΄ΠΎΠΊΡΠΌΠ΅Π½ΡΠ°ΡΠΈΡΠ°ΡΠ° ΠΏΠΎΠΌΠΎΠ³Π½Π°. Π€ΡΠ½ΠΊΡΠΈΡΠ° get_config()
Π²ΠΈ ΠΎΠ²ΠΎΠ·ΠΌΠΎΠΆΡΠ²Π° Π΄Π° Π΄ΠΎΠ±ΠΈΠ΅ΡΠ΅ ΠΎΠΏΠΈΡ Π½Π° ΠΌΠΎΠ΄Π΅Π»ΠΎΡ Π²ΠΎ ΡΠΎΡΠΌΠ° ΠΏΠΎΠ³ΠΎΠ΄Π½Π° Π·Π° ΡΡΠ΅Π΄ΡΠ²Π°ΡΠ΅ (base_model_conf$layers
- ΡΠ΅Π΄ΠΎΠ²Π½Π° Π»ΠΈΡΡΠ° R), ΠΈ ΡΡΠ½ΠΊΡΠΈΡΠ°ΡΠ° from_config()
Π²ΡΡΠΈ ΠΎΠ±ΡΠ°ΡΠ½Π° ΠΊΠΎΠ½Π²Π΅ΡΠ·ΠΈΡΠ° Π²ΠΎ ΠΌΠΎΠ΄Π΅Π» Π½Π° ΠΎΠ±ΡΠ΅ΠΊΡ:
base_model_conf <- get_config(base_model)
base_model_conf$layers[[1]]$config$batch_input_shape[[4]] <- 1L
base_model <- from_config(base_model_conf)
Π‘Π΅Π³Π° Π½Π΅ Π΅ ΡΠ΅ΡΠΊΠΎ Π΄Π° ΡΠ΅ Π½Π°ΠΏΠΈΡΠ΅ ΡΠ½ΠΈΠ²Π΅ΡΠ·Π°Π»Π½Π° ΡΡΠ½ΠΊΡΠΈΡΠ° Π·Π° Π΄Π° ΡΠ΅ Π΄ΠΎΠ±ΠΈΠ΅ Π½Π΅ΠΊΠΎΡΠ° ΠΎΠ΄ ΠΈΡΠΏΠΎΡΠ°ΡΠ°Π½ΠΈΡΠ΅ ΠΊΠ΅ΡΠ°Ρ ΠΌΠΎΠ΄Π΅Π»ΠΈ ΡΠΎ ΠΈΠ»ΠΈ Π±Π΅Π· ΡΠ΅Π³ΠΎΠ²ΠΈ ΠΎΠ±ΡΡΠ΅Π½ΠΈ Π½Π° imagenet:
Π€ΡΠ½ΠΊΡΠΈΡΠ° Π·Π° Π²ΡΠΈΡΡΠ²Π°ΡΠ΅ Π½Π° Π³ΠΎΡΠΎΠ²ΠΈ Π°ΡΡ ΠΈΡΠ΅ΠΊΡΡΡΠΈ
get_model <- function(name = "mobilenet_v2",
input_shape = NULL,
weights = "imagenet",
pooling = "avg",
num_classes = NULL,
optimizer = keras::optimizer_adam(lr = 0.002),
loss = "categorical_crossentropy",
metrics = NULL,
color = TRUE,
compile = FALSE) {
# ΠΡΠΎΠ²Π΅ΡΠΊΠ° Π°ΡΠ³ΡΠΌΠ΅Π½ΡΠΎΠ²
checkmate::assert_string(name)
checkmate::assert_integerish(input_shape, lower = 1, upper = 256, len = 3)
checkmate::assert_count(num_classes)
checkmate::assert_flag(color)
checkmate::assert_flag(compile)
# ΠΠΎΠ»ΡΡΠ°Π΅ΠΌ ΠΎΠ±ΡΠ΅ΠΊΡ ΠΈΠ· ΠΏΠ°ΠΊΠ΅ΡΠ° keras
model_fun <- get0(paste0("application_", name), envir = asNamespace("keras"))
# ΠΡΠΎΠ²Π΅ΡΠΊΠ° Π½Π°Π»ΠΈΡΠΈΡ ΠΎΠ±ΡΠ΅ΠΊΡΠ° Π² ΠΏΠ°ΠΊΠ΅ΡΠ΅
if (is.null(model_fun)) {
stop("Model ", shQuote(name), " not found.", call. = FALSE)
}
base_model <- model_fun(
input_shape = input_shape,
include_top = FALSE,
weights = weights,
pooling = pooling
)
# ΠΡΠ»ΠΈ ΠΈΠ·ΠΎΠ±ΡΠ°ΠΆΠ΅Π½ΠΈΠ΅ Π½Π΅ ΡΠ²Π΅ΡΠ½ΠΎΠ΅, ΠΌΠ΅Π½ΡΠ΅ΠΌ ΡΠ°Π·ΠΌΠ΅ΡΠ½ΠΎΡΡΡ Π²Ρ
ΠΎΠ΄Π°
if (!color) {
base_model_conf <- keras::get_config(base_model)
base_model_conf$layers[[1]]$config$batch_input_shape[[4]] <- 1L
base_model <- keras::from_config(base_model_conf)
}
predictions <- keras::get_layer(base_model, "global_average_pooling2d_1")$output
predictions <- keras::layer_dense(predictions, units = num_classes, activation = "softmax")
model <- keras::keras_model(
inputs = base_model$input,
outputs = predictions
)
if (compile) {
keras::compile(
object = model,
optimizer = optimizer,
loss = loss,
metrics = metrics
)
}
return(model)
}
ΠΠΎΠ³Π° ΠΊΠΎΡΠΈΡΡΠΈΡΠ΅ Π΅Π΄Π½ΠΎΠΊΠ°Π½Π°Π»Π½ΠΈ ΡΠ»ΠΈΠΊΠΈ, Π½Π΅ ΡΠ΅ ΠΊΠΎΡΠΈΡΡΠ°Ρ ΠΏΡΠ΅ΡΡ
ΠΎΠ΄Π½ΠΎ ΠΎΠ±ΡΡΠ΅Π½ΠΈ ΡΠ΅ΠΆΠΈΠ½ΠΈ. ΠΠ²Π° ΠΌΠΎΠΆΠ΅ Π΄Π° ΡΠ΅ ΠΏΠΎΠΏΡΠ°Π²ΠΈ: ΠΊΠΎΡΠΈΡΡΠ΅ΡΡΠΈ ΡΠ° ΡΡΠ½ΠΊΡΠΈΡΠ°ΡΠ° get_weights()
Π·Π΅ΠΌΠ΅ΡΠ΅ Π³ΠΈ ΡΠ΅ΠΆΠΈΠ½ΠΈΡΠ΅ Π½Π° ΠΌΠΎΠ΄Π΅Π»ΠΎΡ Π²ΠΎ ΡΠΎΡΠΌΠ° Π½Π° Π»ΠΈΡΡΠ° Π½Π° R Π½ΠΈΠ·ΠΈ, ΠΏΡΠΎΠΌΠ΅Π½Π΅ΡΠ΅ ΡΠ° Π΄ΠΈΠΌΠ΅Π½Π·ΠΈΡΠ°ΡΠ° Π½Π° ΠΏΡΠ²ΠΈΠΎΡ Π΅Π»Π΅ΠΌΠ΅Π½Ρ ΠΎΠ΄ ΠΎΠ²Π°Π° Π»ΠΈΡΡΠ° (ΡΠΎ ΠΏΡΠ΅Π·Π΅ΠΌΠ°ΡΠ΅ Π½Π° Π΅Π΄Π΅Π½ ΠΊΠ°Π½Π°Π» Π²ΠΎ Π±ΠΎΡΠ° ΠΈΠ»ΠΈ ΠΏΡΠΎΡΠ΅ΠΊ Π½Π° ΡΠΈΡΠ΅ ΡΡΠΈ), Π° ΠΏΠΎΡΠΎΠ° Π²ΡΠΈΡΠ°ΡΡΠ΅ Π³ΠΈ ΡΠ΅ΠΆΠΈΠ½ΠΈΡΠ΅ Π½Π°Π·Π°Π΄ Π²ΠΎ ΠΌΠΎΠ΄Π΅Π»ΠΎΡ ΡΠΎ ΡΡΠ½ΠΊΡΠΈΡΠ°ΡΠ° set_weights()
. ΠΠΈΠΊΠΎΠ³Π°Ρ Π½Π΅ ΡΠ° Π΄ΠΎΠ΄Π°Π΄ΠΎΠ²ΠΌΠ΅ ΠΎΠ²Π°Π° ΡΡΠ½ΠΊΡΠΈΠΎΠ½Π°Π»Π½ΠΎΡΡ, Π±ΠΈΠ΄Π΅ΡΡΠΈ Π²ΠΎ ΠΎΠ²Π°Π° ΡΠ°Π·Π° Π²Π΅ΡΠ΅ Π±Π΅ΡΠ΅ ΡΠ°ΡΠ½ΠΎ Π΄Π΅ΠΊΠ° Π΅ ΠΏΠΎΠΏΡΠΎΠ΄ΡΠΊΡΠΈΠ²Π½ΠΎ Π΄Π° ΡΠ΅ ΡΠ°Π±ΠΎΡΠΈ ΡΠΎ ΡΠ»ΠΈΠΊΠΈ Π²ΠΎ Π±ΠΎΡΠ°.
ΠΠΈΠ΅ Π³ΠΈ ΡΠΏΡΠΎΠ²Π΅Π΄ΠΎΠ²ΠΌΠ΅ ΠΏΠΎΠ²Π΅ΡΠ΅ΡΠΎ Π΅ΠΊΡΠΏΠ΅ΡΠΈΠΌΠ΅Π½ΡΠΈ ΠΊΠΎΡΠΈΡΡΠ΅ΡΡΠΈ Π³ΠΈ ΠΌΠΎΠ±ΠΈΠ»Π½ΠΈΡΠ΅ Π²Π΅ΡΠ·ΠΈΠΈ 1 ΠΈ 2, ΠΊΠ°ΠΊΠΎ ΠΈ resnet34. ΠΠΎΠΌΠΎΠ΄Π΅ΡΠ½ΠΈΡΠ΅ Π°ΡΡ ΠΈΡΠ΅ΠΊΡΡΡΠΈ ΠΊΠ°ΠΊΠΎ SE-ResNeXt ΡΠ΅ ΠΏΡΠ΅ΡΡΡΠ°Π²ΠΈΡΠ° Π΄ΠΎΠ±ΡΠΎ Π½Π° ΠΎΠ²ΠΎΡ Π½Π°ΡΠΏΡΠ΅Π²Π°Ρ. ΠΠ° ΠΆΠ°Π», Π½Π΅ΠΌΠ°Π²ΠΌΠ΅ Π³ΠΎΡΠΎΠ²ΠΈ ΠΈΠΌΠΏΠ»Π΅ΠΌΠ΅Π½ΡΠ°ΡΠΈΠΈ Π½Π° ΡΠ°ΡΠΏΠΎΠ»Π°Π³Π°ΡΠ΅, Π° Π½Π΅ Π½Π°ΠΏΠΈΡΠ°Π²ΠΌΠ΅ Π½Π°ΡΠΈ (Π½ΠΎ Π΄Π΅ΡΠΈΠ½ΠΈΡΠΈΠ²Π½ΠΎ ΡΠ΅ ΠΏΠΈΡΡΠ²Π°ΠΌΠ΅).
5. ΠΠ°ΡΠ°ΠΌΠ΅ΡΠ°ΡΠΈΠ·Π°ΡΠΈΡΠ° Π½Π° ΡΠΊΡΠΈΠΏΡΠΈ
ΠΠ° ΠΏΠΎΠ³ΠΎΠ΄Π½ΠΎΡΡ, ΡΠ΅Π»ΠΈΠΎΡ ΠΊΠΎΠ΄ Π·Π° Π·Π°ΠΏΠΎΡΠ½ΡΠ²Π°ΡΠ΅ Π½Π° ΠΎΠ±ΡΠΊΠ°ΡΠ° Π±Π΅ΡΠ΅ Π΄ΠΈΠ·Π°ΡΠ½ΠΈΡΠ°Π½ ΠΊΠ°ΠΊΠΎ Π΅Π΄Π½Π° ΡΠΊΡΠΈΠΏΡΠ°, ΠΏΠ°ΡΠ°ΠΌΠ΅ΡΡΠΈΠΈΠ·ΠΈΡΠ°Π½Π° ΡΠΎ ΠΊΠΎΡΠΈΡΡΠ΅ΡΠ΅
doc <- '
Usage:
train_nn.R --help
train_nn.R --list-models
train_nn.R [options]
Options:
-h --help Show this message.
-l --list-models List available models.
-m --model=<model> Neural network model name [default: mobilenet_v2].
-b --batch-size=<size> Batch size [default: 32].
-s --scale-factor=<ratio> Scale factor [default: 0.5].
-c --color Use color lines [default: FALSE].
-d --db-dir=<path> Path to database directory [default: Sys.getenv("db_dir")].
-r --validate-ratio=<ratio> Validate sample ratio [default: 0.995].
-n --n-gpu=<number> Number of GPUs [default: 1].
'
args <- docopt::docopt(doc)
ΠΠ°ΠΊΠ΅Ρ Π΄ΠΎΠΊΠΎΠΏΡ ΠΏΡΠ΅ΡΡΡΠ°Π²ΡΠ²Π° ΠΈΠΌΠΏΠ»Π΅ΠΌΠ΅Π½ΡΠ°ΡΠΈΡΠ° 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
ΠΎΠ΄ ΡΠ΅ΠΊΠΎΠ²Π½Π°ΡΠ° Π²Π΅ΡΠ·ΠΈΡΠ° ΠΊΠ΅ΡΠ°Ρ Π²ΠΎ Π ΡΠΏΠΎΡΡΠ΅Π±Π°
ΠΠ²ΠΎΡ ΠΏΡΠΈΡΡΠ°ΠΏ ΠΎΠ²ΠΎΠ·ΠΌΠΎΠΆΠΈ Π·Π½Π°ΡΠΈΡΠ΅Π»Π½ΠΎ Π΄Π° ΡΠ΅ Π·Π°Π±ΡΠ·Π°Π°Ρ Π΅ΠΊΡΠΏΠ΅ΡΠΈΠΌΠ΅Π½ΡΠΈΡΠ΅ ΡΠΎ ΡΠ°Π·Π»ΠΈΡΠ½ΠΈ ΠΌΠΎΠ΄Π΅Π»ΠΈ Π²ΠΎ ΡΠΏΠΎΡΠ΅Π΄Π±Π° ΡΠΎ ΠΏΠΎΡΡΠ°Π΄ΠΈΡΠΈΠΎΠ½Π°Π»Π½ΠΎΡΠΎ Π»Π°Π½ΡΠΈΡΠ°ΡΠ΅ Π½Π° ΡΠΊΡΠΈΠΏΡΠΈ Π²ΠΎ RStudio (Π³ΠΎ Π·Π°Π±Π΅Π»Π΅ΠΆΡΠ²Π°ΠΌΠ΅ ΠΏΠ°ΠΊΠ΅ΡΠΎΡ ΠΊΠ°ΠΊΠΎ ΠΌΠΎΠΆΠ½Π° Π°Π»ΡΠ΅ΡΠ½Π°ΡΠΈΠ²Π°
6. ΠΠΎΠΊΠ΅ΡΠΈΠ·Π°ΡΠΈΡΠ° Π½Π° ΡΠΊΡΠΈΠΏΡΠΈ
ΠΠΎ ΠΊΠΎΡΠΈΡΡΠ΅Π²ΠΌΠ΅ Docker Π·Π° Π΄Π° ΠΎΠ±Π΅Π·Π±Π΅Π΄ΠΈΠΌΠ΅ ΠΏΡΠ΅Π½ΠΎΡΠ»ΠΈΠ²ΠΎΡΡ Π½Π° ΠΎΠΊΠΎΠ»ΠΈΠ½Π°ΡΠ° Π·Π° ΠΌΠΎΠ΄Π΅Π»ΠΈ Π·Π° ΠΎΠ±ΡΠΊΠ° ΠΏΠΎΠΌΠ΅ΡΡ ΡΠ»Π΅Π½ΠΎΠ²ΠΈΡΠ΅ Π½Π° ΡΠΈΠΌΠΎΡ ΠΈ Π·Π° Π±ΡΠ·ΠΎ ΡΠ°ΡΠΏΠΎΡΠ΅Π΄ΡΠ²Π°ΡΠ΅ Π²ΠΎ ΠΎΠ±Π»Π°ΠΊΠΎΡ. ΠΠΎΠΆΠ΅ΡΠ΅ Π΄Π° ΠΏΠΎΡΠ½Π΅ΡΠ΅ Π΄Π° ΡΠ΅ Π·Π°ΠΏΠΎΠ·Π½Π°Π²Π°ΡΠ΅ ΡΠΎ ΠΎΠ²Π°Π° Π°Π»Π°ΡΠΊΠ°, ΠΊΠΎΡΠ° Π΅ ΡΠ΅Π»Π°ΡΠΈΠ²Π½ΠΎ Π½Π΅Π²ΠΎΠΎΠ±ΠΈΡΠ°Π΅Π½Π° Π·Π° R ΠΏΡΠΎΠ³ΡΠ°ΠΌΠ΅Ρ, ΡΠΎ
Docker Π²ΠΈ ΠΎΠ²ΠΎΠ·ΠΌΠΎΠΆΡΠ²Π° Π΄Π° ΠΊΡΠ΅ΠΈΡΠ°ΡΠ΅ ΡΠ²ΠΎΠΈ ΡΠ»ΠΈΠΊΠΈ ΠΎΠ΄ Π½ΡΠ»Π° ΠΈ Π΄Π° ΠΊΠΎΡΠΈΡΡΠΈΡΠ΅ Π΄ΡΡΠ³ΠΈ ΡΠ»ΠΈΠΊΠΈ ΠΊΠ°ΠΊΠΎ ΠΎΡΠ½ΠΎΠ²Π° Π·Π° ΡΠΎΠ·Π΄Π°Π²Π°ΡΠ΅ Π½Π° ΡΠ²ΠΎΠΈ. ΠΠΎΠ³Π° Π³ΠΈ Π°Π½Π°Π»ΠΈΠ·ΠΈΡΠ°Π²ΠΌΠ΅ Π΄ΠΎΡΡΠ°ΠΏΠ½ΠΈΡΠ΅ ΠΎΠΏΡΠΈΠΈ, Π΄ΠΎΡΠ΄ΠΎΠ²ΠΌΠ΅ Π΄ΠΎ Π·Π°ΠΊΠ»ΡΡΠΎΠΊ Π΄Π΅ΠΊΠ° ΠΈΠ½ΡΡΠ°Π»ΠΈΡΠ°ΡΠ΅ΡΠΎ Π½Π° NVIDIA, CUDA+cuDNN Π΄ΡΠ°ΡΠ²Π΅ΡΠΈΡΠ΅ ΠΈ Π±ΠΈΠ±Π»ΠΈΠΎΡΠ΅ΠΊΠΈΡΠ΅ Π½Π° Python Π΅ ΠΏΡΠΈΠ»ΠΈΡΠ½ΠΎ ΠΎΠ±Π΅ΠΌΠ΅Π½ Π΄Π΅Π» ΠΎΠ΄ ΡΠ»ΠΈΠΊΠ°ΡΠ° ΠΈ ΡΠ΅ΡΠΈΠ²ΠΌΠ΅ Π΄Π° ΡΠ° Π·Π΅ΠΌΠ΅ΠΌΠ΅ ΠΎΡΠΈΡΠΈΡΠ°Π»Π½Π°ΡΠ° ΡΠ»ΠΈΠΊΠ° ΠΊΠ°ΠΊΠΎ ΠΎΡΠ½ΠΎΠ²Π° tensorflow/tensorflow:1.12.0-gpu
, Π΄ΠΎΠ΄Π°Π²Π°ΡΡΠΈ Π³ΠΈ ΠΏΠΎΡΡΠ΅Π±Π½ΠΈΡΠ΅ R ΠΏΠ°ΠΊΠ΅ΡΠΈ ΡΠ°ΠΌΡ.
ΠΠΎΠ½Π΅ΡΠ½Π°ΡΠ° Π΄ΠΎΠΊΠ΅Ρ-Π΄Π°ΡΠΎΡΠ΅ΠΊΠ° ΠΈΠ·Π³Π»Π΅Π΄Π°ΡΠ΅ Π²Π°ΠΊΠ°:
dockerfile
FROM tensorflow/tensorflow:1.12.0-gpu
MAINTAINER Artem Klevtsov <[email protected]>
SHELL ["/bin/bash", "-c"]
ARG LOCALE="en_US.UTF-8"
ARG APT_PKG="libopencv-dev r-base r-base-dev littler"
ARG R_BIN_PKG="futile.logger checkmate data.table rcpp rapidjsonr dbi keras jsonlite curl digest remotes"
ARG R_SRC_PKG="xtensor RcppThread docopt MonetDBLite"
ARG PY_PIP_PKG="keras"
ARG DIRS="/db /app /app/data /app/models /app/logs"
RUN source /etc/os-release &&
echo "deb https://cloud.r-project.org/bin/linux/ubuntu ${UBUNTU_CODENAME}-cran35/" > /etc/apt/sources.list.d/cran35.list &&
apt-key adv --keyserver keyserver.ubuntu.com --recv-keys E084DAB9 &&
add-apt-repository -y ppa:marutter/c2d4u3.5 &&
add-apt-repository -y ppa:timsc/opencv-3.4 &&
apt-get update &&
apt-get install -y locales &&
locale-gen ${LOCALE} &&
apt-get install -y --no-install-recommends ${APT_PKG} &&
ln -s /usr/lib/R/site-library/littler/examples/install.r /usr/local/bin/install.r &&
ln -s /usr/lib/R/site-library/littler/examples/install2.r /usr/local/bin/install2.r &&
ln -s /usr/lib/R/site-library/littler/examples/installGithub.r /usr/local/bin/installGithub.r &&
echo 'options(Ncpus = parallel::detectCores())' >> /etc/R/Rprofile.site &&
echo 'options(repos = c(CRAN = "https://cloud.r-project.org"))' >> /etc/R/Rprofile.site &&
apt-get install -y $(printf "r-cran-%s " ${R_BIN_PKG}) &&
install.r ${R_SRC_PKG} &&
pip install ${PY_PIP_PKG} &&
mkdir -p ${DIRS} &&
chmod 777 ${DIRS} &&
rm -rf /tmp/downloaded_packages/ /tmp/*.rds &&
rm -rf /var/lib/apt/lists/*
COPY utils /app/utils
COPY src /app/src
COPY tests /app/tests
COPY bin/*.R /app/
ENV DBDIR="/db"
ENV CUDA_HOME="/usr/local/cuda"
ENV PATH="/app:${PATH}"
WORKDIR /app
VOLUME /db
VOLUME /app
CMD bash
ΠΠ° ΠΏΠΎΠ³ΠΎΠ΄Π½ΠΎΡΡ, ΠΊΠΎΡΠΈΡΡΠ΅Π½ΠΈΡΠ΅ ΠΏΠ°ΠΊΠ΅ΡΠΈ Π±Π΅Π° ΡΡΠ°Π²Π΅Π½ΠΈ Π²ΠΎ ΠΏΡΠΎΠΌΠ΅Π½Π»ΠΈΠ²ΠΈ; Π½Π°ΡΠ³ΠΎΠ»Π΅ΠΌΠΈΠΎΡ Π΄Π΅Π» ΠΎΠ΄ Π½Π°ΠΏΠΈΡΠ°Π½ΠΈΡΠ΅ ΡΠΊΡΠΈΠΏΡΠΈ ΡΠ΅ ΠΊΠΎΠΏΠΈΡΠ°Π°Ρ Π²ΠΎ ΠΊΠΎΠ½ΡΠ΅ΡΠ½Π΅ΡΠΈΡΠ΅ Π·Π° Π²ΡΠ΅ΠΌΠ΅ Π½Π° ΡΠΊΠ»ΠΎΠΏΡΠ²Π°ΡΠ΅ΡΠΎ. ΠΠ° ΡΠΌΠ΅Π½ΠΈΠ²ΠΌΠ΅ ΠΈ ΠΊΠΎΠΌΠ°Π½Π΄Π½Π°ΡΠ° ΡΠΊΠΎΠ»ΠΊΠ° Π²ΠΎ /bin/bash
Π·Π° Π»Π΅ΡΠ½ΠΎ ΠΊΠΎΡΠΈΡΡΠ΅ΡΠ΅ Π½Π° ΡΠΎΠ΄ΡΠΆΠΈΠ½Π°ΡΠ° /etc/os-release
. ΠΠ²Π° ΡΠ° ΠΈΠ·Π±Π΅Π³Π½Π° ΠΏΠΎΡΡΠ΅Π±Π°ΡΠ° Π΄Π° ΡΠ΅ Π½Π°Π²Π΅Π΄Π΅ Π²Π΅ΡΠ·ΠΈΡΠ°ΡΠ° Π½Π° ΠΠ‘ Π²ΠΎ ΠΊΠΎΠ΄ΠΎΡ.
ΠΠΎΠΏΠΎΠ»Π½ΠΈΡΠ΅Π»Π½ΠΎ, Π½Π°ΠΏΠΈΡΠ°Π½Π° Π΅ ΠΌΠ°Π»Π° Π±Π°Ρ ΡΠΊΡΠΈΠΏΡΠ° ΠΊΠΎΡΠ° Π²ΠΈ ΠΎΠ²ΠΎΠ·ΠΌΠΎΠΆΡΠ²Π° Π΄Π° ΡΡΠ°ΡΡΡΠ²Π°ΡΠ΅ ΠΊΠΎΠ½ΡΠ΅ΡΠ½Π΅Ρ ΡΠΎ ΡΠ°Π·Π»ΠΈΡΠ½ΠΈ ΠΊΠΎΠΌΠ°Π½Π΄ΠΈ. ΠΠ° ΠΏΡΠΈΠΌΠ΅Ρ, ΠΎΠ²Π° ΠΌΠΎΠΆΠ΅ Π΄Π° Π±ΠΈΠ΄Π°Ρ ΡΠΊΡΠΈΠΏΡΠΈ Π·Π° ΠΎΠ±ΡΠΊΠ° Π½Π° Π½Π΅Π²ΡΠΎΠ½ΡΠΊΠΈ ΠΌΡΠ΅ΠΆΠΈ ΠΊΠΎΠΈ ΠΏΡΠ΅ΡΡ ΠΎΠ΄Π½ΠΎ Π±ΠΈΠ»Π΅ ΠΏΠΎΡΡΠ°Π²Π΅Π½ΠΈ Π²ΠΎ ΠΊΠΎΠ½ΡΠ΅ΡΠ½Π΅ΡΠΎΡ ΠΈΠ»ΠΈ ΠΊΠΎΠΌΠ°Π½Π΄Π½Π° ΠΎΠ±Π²ΠΈΠ²ΠΊΠ° Π·Π° Π΄Π΅Π±Π°Π³ΠΈΡΠ°ΡΠ΅ ΠΈ ΡΠ»Π΅Π΄Π΅ΡΠ΅ Π½Π° ΡΠ°Π±ΠΎΡΠ°ΡΠ° Π½Π° ΠΊΠΎΠ½ΡΠ΅ΡΠ½Π΅ΡΠΎΡ:
Π‘ΠΊΡΠΈΠΏΡΠ° Π·Π° ΡΡΠ°ΡΡΡΠ²Π°ΡΠ΅ Π½Π° ΠΊΠΎΠ½ΡΠ΅ΡΠ½Π΅ΡΠΎΡ
#!/bin/sh
DBDIR=${PWD}/db
LOGSDIR=${PWD}/logs
MODELDIR=${PWD}/models
DATADIR=${PWD}/data
ARGS="--runtime=nvidia --rm -v ${DBDIR}:/db -v ${LOGSDIR}:/app/logs -v ${MODELDIR}:/app/models -v ${DATADIR}:/app/data"
if [ -z "$1" ]; then
CMD="Rscript /app/train_nn.R"
elif [ "$1" = "bash" ]; then
ARGS="${ARGS} -ti"
else
CMD="Rscript /app/train_nn.R $@"
fi
docker run ${ARGS} doodles-tf ${CMD}
ΠΠΊΠΎ ΠΎΠ²Π°Π° Π±Π°Ρ ΡΠΊΡΠΈΠΏΡΠ° ΡΠ΅ ΠΈΠ·Π²ΡΡΡΠ²Π° Π±Π΅Π· ΠΏΠ°ΡΠ°ΠΌΠ΅ΡΡΠΈ, ΡΠΊΡΠΈΠΏΡΠ°ΡΠ° ΡΠ΅ ΡΠ΅ ΠΏΠΎΠ²ΠΈΠΊΠ° Π²Π½Π°ΡΡΠ΅ Π²ΠΎ ΠΊΠΎΠ½ΡΠ΅ΡΠ½Π΅ΡΠΎΡ train_nn.R
ΡΠΎ ΡΡΠ°Π½Π΄Π°ΡΠ΄Π½ΠΈ Π²ΡΠ΅Π΄Π½ΠΎΡΡΠΈ; Π°ΠΊΠΎ ΠΏΡΠ²ΠΈΠΎΡ ΠΏΠΎΠ·ΠΈΡΠΈΠΎΠ½Π΅Π½ Π°ΡΠ³ΡΠΌΠ΅Π½Ρ Π΅ βbashβ, ΡΠΎΠ³Π°Ρ ΠΊΠΎΠ½ΡΠ΅ΡΠ½Π΅ΡΠΎΡ ΡΠ΅ Π·Π°ΠΏΠΎΡΠ½Π΅ ΠΈΠ½ΡΠ΅ΡΠ°ΠΊΡΠΈΠ²Π½ΠΎ ΡΠΎ ΠΊΠΎΠΌΠ°Π½Π΄Π½Π° ΡΠΊΠΎΠ»ΠΊΠ°. ΠΠΎ ΡΠΈΡΠ΅ Π΄ΡΡΠ³ΠΈ ΡΠ»ΡΡΠ°ΠΈ, Π²ΡΠ΅Π΄Π½ΠΎΡΡΠΈΡΠ΅ Π½Π° ΠΏΠΎΠ·ΠΈΡΠΈΡΠΊΠΈΡΠ΅ Π°ΡΠ³ΡΠΌΠ΅Π½ΡΠΈ ΡΠ΅ Π·Π°ΠΌΠ΅Π½ΡΠ²Π°Π°Ρ: CMD="Rscript /app/train_nn.R $@"
.
ΠΡΠ΅Π΄ΠΈ Π΄Π° ΡΠ΅ Π½Π°ΠΏΠΎΠΌΠ΅Π½Π΅ Π΄Π΅ΠΊΠ° Π΄ΠΈΡΠ΅ΠΊΡΠΎΡΠΈΡΠΌΠΈΡΠ΅ ΡΠΎ ΠΈΠ·Π²ΠΎΡΠ½ΠΈ ΠΏΠΎΠ΄Π°ΡΠΎΡΠΈ ΠΈ Π±Π°Π·Π° Π½Π° ΠΏΠΎΠ΄Π°ΡΠΎΡΠΈ, ΠΊΠ°ΠΊΠΎ ΠΈ Π΄ΠΈΡΠ΅ΠΊΡΠΎΡΠΈΡΠΌΠΎΡ Π·Π° Π·Π°ΡΡΠ²ΡΠ²Π°ΡΠ΅ ΠΎΠ±ΡΡΠ΅Π½ΠΈ ΠΌΠΎΠ΄Π΅Π»ΠΈ, ΡΠ΅ ΠΌΠΎΠ½ΡΠΈΡΠ°Π½ΠΈ Π²ΠΎ ΠΊΠΎΠ½ΡΠ΅ΡΠ½Π΅ΡΠΎΡ ΠΎΠ΄ ΡΠΈΡΡΠ΅ΠΌΠΎΡ Π½Π° Π΄ΠΎΠΌΠ°ΡΠΈΠ½ΠΎΡ, ΡΡΠΎ Π²ΠΈ ΠΎΠ²ΠΎΠ·ΠΌΠΎΠΆΡΠ²Π° Π΄Π° ΠΏΡΠΈΡΡΠ°ΠΏΠΈΡΠ΅ Π΄ΠΎ ΡΠ΅Π·ΡΠ»ΡΠ°ΡΠΈΡΠ΅ ΠΎΠ΄ ΡΠΊΡΠΈΠΏΡΠΈΡΠ΅ Π±Π΅Π· Π½Π΅ΠΏΠΎΡΡΠ΅Π±Π½ΠΈ ΠΌΠ°Π½ΠΈΠΏΡΠ»Π°ΡΠΈΠΈ.
7. ΠΠΎΡΠΈΡΡΠ΅ΡΠ΅ Π½Π° ΠΏΠΎΠ²Π΅ΡΠ΅ Π³ΡΠ°ΡΠΈΡΠΊΠΈ ΠΏΡΠΎΡΠ΅ΡΠΎΡΠΈ Π½Π° Google Cloud
ΠΠ΄Π½Π° ΠΎΠ΄ ΠΊΠ°ΡΠ°ΠΊΡΠ΅ΡΠΈΡΡΠΈΠΊΠΈΡΠ΅ Π½Π° Π½Π°ΡΠΏΡΠ΅Π²Π°ΡΠΎΡ Π±Π΅Π° ΠΌΠ½ΠΎΠ³Ρ Π±ΡΡΠ½ΠΈΡΠ΅ ΠΏΠΎΠ΄Π°ΡΠΎΡΠΈ (Π²ΠΈΠ΄Π΅ΡΠ΅ ΡΠ° Π½Π°ΡΠ»ΠΎΠ²Π½Π°ΡΠ° ΡΠ»ΠΈΠΊΠ°, ΠΏΠΎΠ·Π°ΡΠΌΠ΅Π½Π° ΠΎΠ΄ @Leigh.plt ΠΎΠ΄ ODS slack). ΠΠΎΠ»Π΅ΠΌΠΈΡΠ΅ ΡΠ΅ΡΠΈΠΈ ΠΏΠΎΠΌΠ°Π³Π°Π°Ρ Π²ΠΎ Π±ΠΎΡΠ±Π°ΡΠ° ΠΏΡΠΎΡΠΈΠ² ΠΎΠ²Π°, ΠΈ ΠΏΠΎ Π΅ΠΊΡΠΏΠ΅ΡΠΈΠΌΠ΅Π½ΡΠΈΡΠ΅ Π½Π° ΠΊΠΎΠΌΠΏΡΡΡΠ΅Ρ ΡΠΎ 1 Π³ΡΠ°ΡΠΈΡΠΊΠΈ ΠΏΡΠΎΡΠ΅ΡΠΎΡ, ΡΠ΅ΡΠΈΠ²ΠΌΠ΅ Π΄Π° Π³ΠΈ ΡΠΎΠ²Π»Π°Π΄Π°ΠΌΠ΅ ΠΌΠΎΠ΄Π΅Π»ΠΈΡΠ΅ Π·Π° ΠΎΠ±ΡΠΊΠ° Π½Π° Π½Π΅ΠΊΠΎΠ»ΠΊΡ Π³ΡΠ°ΡΠΈΡΠΊΠΈ ΠΏΡΠΎΡΠ΅ΡΠΎΡΠΈ Π²ΠΎ ΠΎΠ±Π»Π°ΠΊΠΎΡ. ΠΠΎΡΠΈΡΡΠ΅Π² GoogleCloud (dev/shm
.
ΠΠ΄ Π½Π°ΡΠ³ΠΎΠ»Π΅ΠΌ ΠΈΠ½ΡΠ΅ΡΠ΅Ρ Π΅ ΡΡΠ°Π³ΠΌΠ΅Π½ΡΠΎΡ Π½Π° ΠΊΠΎΠ΄ΠΎΡ ΠΎΠ΄Π³ΠΎΠ²ΠΎΡΠ΅Π½ Π·Π° ΠΊΠΎΡΠΈΡΡΠ΅ΡΠ΅ Π½Π° ΠΏΠΎΠ²Π΅ΡΠ΅ Π³ΡΠ°ΡΠΈΡΠΊΠΈ ΠΏΡΠΎΡΠ΅ΡΠΎΡΠΈ. ΠΡΠ²ΠΎ, ΠΌΠΎΠ΄Π΅Π»ΠΎΡ ΡΠ΅ ΠΊΡΠ΅ΠΈΡΠ° Π½Π° ΠΏΡΠΎΡΠ΅ΡΠΎΡΠΎΡ ΡΠΎ ΠΏΠΎΠΌΠΎΡ Π½Π° ΠΊΠΎΠ½ΡΠ΅ΠΊΡΡΡΠ°Π»Π΅Π½ ΠΌΠ΅Π½Π°ΡΠ΅Ρ, ΠΈΡΡΠΎ ΠΊΠ°ΠΊΠΎ Π²ΠΎ Python:
with(tensorflow::tf$device("/cpu:0"), {
model_cpu <- get_model(
name = model_name,
input_shape = input_shape,
weights = weights,
metrics =(top_3_categorical_accuracy,
compile = FALSE
)
})
ΠΠΎΡΠΎΠ° Π½Π΅ΠΊΠΎΠΌΠΏΠ°ΡΠ»ΠΈΡΠ°Π½ΠΈΠΎΡ (ΠΎΠ²Π° Π΅ Π²Π°ΠΆΠ½ΠΎ) ΠΌΠΎΠ΄Π΅Π» ΡΠ΅ ΠΊΠΎΠΏΠΈΡΠ° Π½Π° Π΄Π°Π΄Π΅Π½ Π±ΡΠΎΡ Π΄ΠΎΡΡΠ°ΠΏΠ½ΠΈ Π³ΡΠ°ΡΠΈΡΠΊΠΈ ΠΏΡΠΎΡΠ΅ΡΠΎΡΠΈ ΠΈ ΡΠ°ΠΌΠΎ ΠΏΠΎΡΠ»Π΅ ΡΠΎΠ° ΡΠ΅ ΠΊΠΎΠΌΠΏΠ°ΡΠ»ΠΈΡΠ°:
model <- keras::multi_gpu_model(model_cpu, gpus = n_gpu)
keras::compile(
object = model,
optimizer = keras::optimizer_adam(lr = 0.0004),
loss = "categorical_crossentropy",
metrics = c(top_3_categorical_accuracy)
)
ΠΠ»Π°ΡΠΈΡΠ½Π°ΡΠ° ΡΠ΅Ρ Π½ΠΈΠΊΠ° Π½Π° Π·Π°ΠΌΡΠ·Π½ΡΠ²Π°ΡΠ΅ Π½Π° ΡΠΈΡΠ΅ ΡΠ»ΠΎΠ΅Π²ΠΈ ΠΎΡΠ²Π΅Π½ ΠΏΠΎΡΠ»Π΅Π΄Π½ΠΈΠΎΡ, ΠΎΠ±ΡΠΊΠ° Π½Π° ΠΏΠΎΡΠ»Π΅Π΄Π½ΠΈΠΎΡ ΡΠ»ΠΎΡ, ΠΎΠ΄ΠΌΡΠ·Π½ΡΠ²Π°ΡΠ΅ ΠΈ ΠΏΡΠ΅ΠΊΠ²Π°Π»ΠΈΡΠΈΠΊΠ°ΡΠΈΡΠ° Π½Π° ΡΠ΅Π»ΠΈΠΎΡ ΠΌΠΎΠ΄Π΅Π» Π·Π° Π½Π΅ΠΊΠΎΠ»ΠΊΡ Π³ΡΠ°ΡΠΈΡΠΊΠΈ ΠΏΡΠΎΡΠ΅ΡΠΎΡΠΈ Π½Π΅ ΠΌΠΎΠΆΠ΅ΡΠ΅ Π΄Π° ΡΠ΅ ΠΈΠΌΠΏΠ»Π΅ΠΌΠ΅Π½ΡΠΈΡΠ°.
ΠΠ±ΡΠΊΠ°ΡΠ° Π±Π΅ΡΠ΅ ΡΠ»Π΅Π΄Π΅Π½Π° Π±Π΅Π· ΡΠΏΠΎΡΡΠ΅Π±Π°. ΡΠ΅Π½Π·ΠΎΡΠ±ΠΎΡΠ΄, ΠΎΠ³ΡΠ°Π½ΠΈΡΡΠ²Π°ΡΡΠΈ ΡΠ΅ Π½Π° ΡΠ½ΠΈΠΌΠ°ΡΠ΅ Π»ΠΎΠ³ΠΎΠ²ΠΈ ΠΈ Π·Π°ΡΡΠ²ΡΠ²Π°ΡΠ΅ ΠΌΠΎΠ΄Π΅Π»ΠΈ ΡΠΎ ΠΈΠ½ΡΠΎΡΠΌΠ°ΡΠΈΠ²Π½ΠΈ ΠΈΠΌΠΈΡΠ° ΠΏΠΎ ΡΠ΅ΠΊΠΎΡΠ° Π΅ΠΏΠΎΡ Π°:
ΠΠΎΠ²ΡΠ°ΡΠ½ΠΈ ΠΏΠΎΠ²ΠΈΡΠΈ
# Π¨Π°Π±Π»ΠΎΠ½ ΠΈΠΌΠ΅Π½ΠΈ ΡΠ°ΠΉΠ»Π° Π»ΠΎΠ³Π°
log_file_tmpl <- file.path("logs", sprintf(
"%s_%d_%dch_%s.csv",
model_name,
dim_size,
channels,
format(Sys.time(), "%Y%m%d%H%M%OS")
))
# Π¨Π°Π±Π»ΠΎΠ½ ΠΈΠΌΠ΅Π½ΠΈ ΡΠ°ΠΉΠ»Π° ΠΌΠΎΠ΄Π΅Π»ΠΈ
model_file_tmpl <- file.path("models", sprintf(
"%s_%d_%dch_{epoch:02d}_{val_loss:.2f}.h5",
model_name,
dim_size,
channels
))
callbacks_list <- list(
keras::callback_csv_logger(
filename = log_file_tmpl
),
keras::callback_early_stopping(
monitor = "val_loss",
min_delta = 1e-4,
patience = 8,
verbose = 1,
mode = "min"
),
keras::callback_reduce_lr_on_plateau(
monitor = "val_loss",
factor = 0.5, # ΡΠΌΠ΅Π½ΡΡΠ°Π΅ΠΌ lr Π² 2 ΡΠ°Π·Π°
patience = 4,
verbose = 1,
min_delta = 1e-4,
mode = "min"
),
keras::callback_model_checkpoint(
filepath = model_file_tmpl,
monitor = "val_loss",
save_best_only = FALSE,
save_weights_only = FALSE,
mode = "min"
)
)
8. ΠΠ°ΠΌΠ΅ΡΡΠΎ Π·Π°ΠΊΠ»ΡΡΠΎΠΊ
ΠΠΎΠ»Π΅ΠΌ Π±ΡΠΎΡ ΠΏΡΠΎΠ±Π»Π΅ΠΌΠΈ ΡΠΎ ΠΊΠΎΠΈ ΡΠ΅ ΡΠΎΠΎΡΠΈΠ²ΠΌΠ΅ ΡΓ¨ ΡΡΡΠ΅ Π½Π΅ ΡΠ΅ Π½Π°Π΄ΠΌΠΈΠ½Π°ΡΠΈ:
- Π² ΠΊΠ΅ΡΠ°Ρ Π½Π΅ΠΌΠ° Π³ΠΎΡΠΎΠ²Π° ΡΡΠ½ΠΊΡΠΈΡΠ° Π·Π° Π°Π²ΡΠΎΠΌΠ°ΡΡΠΊΠΎ ΠΏΡΠ΅Π±Π°ΡΡΠ²Π°ΡΠ΅ Π½Π° ΠΎΠΏΡΠΈΠΌΠ°Π»Π½Π° ΡΡΠ°ΠΏΠΊΠ° Π½Π° ΡΡΠ΅ΡΠ΅ (Π°Π½Π°Π»ΠΎΠ³Π½Π°
lr_finder
Π²ΠΎ Π±ΠΈΠ±Π»ΠΈΠΎΡΠ΅ΠΊΠ°ΡΠ° Π±ΡΠ·ΠΎ.ai); Π‘ΠΎ ΠΎΠ΄ΡΠ΅Π΄Π΅Π½ Π½Π°ΠΏΠΎΡ, ΠΌΠΎΠΆΠ½ΠΎ Π΅ Π΄Π° ΡΠ΅ ΠΏΡΠ΅ΡΡΠ»Π°Ρ ΠΈΠΌΠΏΠ»Π΅ΠΌΠ΅Π½ΡΠ°ΡΠΈΠΈ ΠΎΠ΄ ΡΡΠ΅ΡΠΈ ΡΡΡΠ°Π½ΠΈ Π½Π° R, Π½Π° ΠΏΡΠΈΠΌΠ΅Ρ,ΠΎΠ²Π° ; - ΠΊΠ°ΠΊΠΎ ΠΏΠΎΡΠ»Π΅Π΄ΠΈΡΠ° Π½Π° ΠΏΡΠ΅ΡΡ ΠΎΠ΄Π½Π°ΡΠ° ΡΠΎΡΠΊΠ°, Π½Π΅ Π±Π΅ΡΠ΅ ΠΌΠΎΠΆΠ½ΠΎ Π΄Π° ΡΠ΅ ΠΈΠ·Π±Π΅ΡΠ΅ ΡΠΎΡΠ½Π°ΡΠ° Π±ΡΠ·ΠΈΠ½Π° Π½Π° ΠΎΠ±ΡΠΊΠ° ΠΏΡΠΈ ΠΊΠΎΡΠΈΡΡΠ΅ΡΠ΅ Π½Π° Π½Π΅ΠΊΠΎΠ»ΠΊΡ Π³ΡΠ°ΡΠΈΡΠΊΠΈ ΠΏΡΠΎΡΠ΅ΡΠΎΡΠΈ;
- Π½Π΅Π΄ΠΎΡΡΠΈΠ³Π°Π°Ρ ΠΌΠΎΠ΄Π΅ΡΠ½ΠΈ Π°ΡΡ ΠΈΡΠ΅ΠΊΡΡΡΠΈ Π½Π° Π½Π΅Π²ΡΠΎΠ½ΡΠΊΠΈ ΠΌΡΠ΅ΠΆΠΈ, ΠΎΡΠΎΠ±Π΅Π½ΠΎ ΠΎΠ½ΠΈΠ΅ ΠΊΠΎΠΈ ΡΠ΅ ΠΏΡΠ΅ΡΡ ΠΎΠ΄Π½ΠΎ ΠΎΠ±ΡΡΠ΅Π½ΠΈ Π½Π° ΠΈΠΌΠΈΡΠ½Π΅Ρ;
- ΠΠΈΠΊΠΎΡ ΡΠΈΠΊΠ»ΡΡ ΠΏΠΎΠ»ΠΈΡΠΈΠΊΠ° ΠΈ Π΄ΠΈΡΠΊΡΠΈΠΌΠΈΠ½Π°ΡΠΈΠ²Π½ΠΈ ΡΡΠ°ΠΏΠΊΠΈ Π½Π° ΡΡΠ΅ΡΠ΅ (ΠΊΠΎΡΠΈΠ½ΡΡΠ½Π°ΡΠ° ΠΆΠ°ΡΠ΅ΡΠ΅ Π±Π΅ΡΠ΅ Π½Π° Π½Π°ΡΠ΅ Π±Π°ΡΠ°ΡΠ΅
ΠΈΠΌΠΏΠ»Π΅ΠΌΠ΅Π½ΡΠΈΡΠ°Π½ΠΈ , ΠΠΈ Π±Π»Π°Π³ΠΎΠ΄Π°ΡΠ°ΠΌΡΠΊΠ΅ΡΠ΄Π°Π½ ).
ΠΠΎΠΈ ΠΊΠΎΡΠΈΡΠ½ΠΈ ΡΠ°Π±ΠΎΡΠΈ ΡΠ΅ Π½Π°ΡΡΠΈΡΠ° ΠΎΠ΄ ΠΎΠ²ΠΎΡ Π½Π°ΡΠΏΡΠ΅Π²Π°Ρ:
- ΠΠ° Ρ Π°ΡΠ΄Π²Π΅Ρ ΡΠΎ ΡΠ΅Π»Π°ΡΠΈΠ²Π½ΠΎ ΠΌΠ°Π»Π° ΠΌΠΎΡΠ½ΠΎΡΡ, ΠΌΠΎΠΆΠ΅ΡΠ΅ Π΄Π° ΡΠ°Π±ΠΎΡΠΈΡΠ΅ ΡΠΎ ΠΏΡΠΈΡΡΠΎΡΠ½ΠΈ (ΠΌΠ½ΠΎΠ³Ρ ΠΏΠ°ΡΠΈ ΠΏΠΎΠ³ΠΎΠ»Π΅ΠΌΠΈ ΠΎΠ΄ RAM ΠΌΠ΅ΠΌΠΎΡΠΈΡΠ°ΡΠ°) Π²ΠΎΠ»ΡΠΌΠ΅Π½ΠΈ Π½Π° ΠΏΠΎΠ΄Π°ΡΠΎΡΠΈ Π±Π΅Π· Π±ΠΎΠ»ΠΊΠ°. ΠΠ»Π°ΡΡΠΈΡΠ½Π° ΠΊΠ΅ΡΠ° ΠΏΠΎΠ΄Π°ΡΠΎΡΠΈ. ΡΠ°Π±Π΅Π»Π° Π·Π°ΡΡΠ΅Π΄ΡΠ²Π° ΠΌΠ΅ΠΌΠΎΡΠΈΡΠ° ΠΏΠΎΡΠ°Π΄ΠΈ Π½Π°ΠΌΠ΅ΡΡΠ΅Π½Π°ΡΠ° ΠΌΠΎΠ΄ΠΈΡΠΈΠΊΠ°ΡΠΈΡΠ° Π½Π° ΡΠ°Π±Π΅Π»ΠΈΡΠ΅, ΡΠΎ ΡΡΠΎ ΡΠ΅ ΠΈΠ·Π±Π΅Π³Π½ΡΠ²Π° Π½ΠΈΠ²Π½ΠΎ ΠΊΠΎΠΏΠΈΡΠ°ΡΠ΅, Π° ΠΊΠΎΠ³Π° ΡΠ΅ ΠΊΠΎΡΠΈΡΡΠΈ ΠΏΡΠ°Π²ΠΈΠ»Π½ΠΎ, Π½Π΅Π³ΠΎΠ²ΠΈΡΠ΅ ΡΠΏΠΎΡΠΎΠ±Π½ΠΎΡΡΠΈ ΡΠ΅ΡΠΈΡΠΈ ΡΠ΅ΠΊΠΎΠ³Π°Ρ ΠΏΠΎΠΊΠ°ΠΆΡΠ²Π°Π°Ρ Π½Π°ΡΠ³ΠΎΠ»Π΅ΠΌΠ° Π±ΡΠ·ΠΈΠ½Π° ΠΌΠ΅ΡΡ ΡΠΈΡΠ΅ Π°Π»Π°ΡΠΊΠΈ ΠΊΠΎΠΈ Π½ΠΈ ΡΠ΅ ΠΏΠΎΠ·Π½Π°ΡΠΈ Π·Π° ΡΠ°Π·ΠΈΡΠΈΡΠ΅ Π·Π° ΡΠΊΡΠΈΠΏΡΠΈΡΠ°ΡΠ΅. ΠΠ°ΡΡΠ²ΡΠ²Π°ΡΠ΅ΡΠΎ Π½Π° ΠΏΠΎΠ΄Π°ΡΠΎΡΠΈΡΠ΅ Π²ΠΎ Π±Π°Π·Π°ΡΠ° Π½Π° ΠΏΠΎΠ΄Π°ΡΠΎΡΠΈ Π²ΠΈ ΠΎΠ²ΠΎΠ·ΠΌΠΎΠΆΡΠ²Π°, Π²ΠΎ ΠΌΠ½ΠΎΠ³Ρ ΡΠ»ΡΡΠ°ΠΈ, Π²ΠΎΠΎΠΏΡΡΠΎ Π΄Π° Π½Π΅ ΡΠ°Π·ΠΌΠΈΡΠ»ΡΠ²Π°ΡΠ΅ Π·Π° ΠΏΠΎΡΡΠ΅Π±Π°ΡΠ° Π΄Π° ΡΠ΅ ΠΏΡΠΈΡΠΈΡΠ½Π΅ ΡΠ΅Π»Π°ΡΠ° Π±Π°Π·Π° Π½Π° ΠΏΠΎΠ΄Π°ΡΠΎΡΠΈ Π²ΠΎ RAM ΠΌΠ΅ΠΌΠΎΡΠΈΡΠ°ΡΠ°.
- ΠΠ°Π²Π½ΠΈΡΠ΅ ΡΡΠ½ΠΊΡΠΈΠΈ Π²ΠΎ R ΠΌΠΎΠΆΠ΅ Π΄Π° ΡΠ΅ Π·Π°ΠΌΠ΅Π½Π°Ρ ΡΠΎ Π±ΡΠ·ΠΈ Π²ΠΎ C++ ΠΊΠΎΡΠΈΡΡΠ΅ΡΡΠΈ Π³ΠΎ ΠΏΠ°ΠΊΠ΅ΡΠΎΡ Rcpp. ΠΠΎΠΊΠΎΠ»ΠΊΡ ΠΏΠΎΠΊΡΠ°Ρ ΡΠΏΠΎΡΡΠ΅Π±Π°ΡΠ° RcppThread ΠΈΠ»ΠΈ RcppΠΠ°ΡΠ°Π»Π΅Π»Π½ΠΎ, Π΄ΠΎΠ±ΠΈΠ²Π°ΠΌΠ΅ ΠΈΠΌΠΏΠ»Π΅ΠΌΠ΅Π½ΡΠ°ΡΠΈΠΈ ΡΠΎ ΠΏΠΎΠ²Π΅ΡΠ΅ Π½ΠΈΡΠΊΠΈ ΠΌΠ΅ΡΡ ΠΏΠ»Π°ΡΡΠΎΡΠΌΠΈ, ΡΠ°ΠΊΠ° ΡΡΠΎ Π½Π΅ΠΌΠ° ΠΏΠΎΡΡΠ΅Π±Π° Π΄Π° ΡΠ΅ ΠΏΠ°ΡΠ°Π»Π΅Π»ΠΈΠ·ΠΈΡΠ° ΠΊΠΎΠ΄ΠΎΡ Π½Π° Π½ΠΈΠ²ΠΎ R.
- ΠΠ°ΠΊΠ΅Ρ Rcpp ΠΌΠΎΠΆΠ΅ Π΄Π° ΡΠ΅ ΠΊΠΎΡΠΈΡΡΠΈ Π±Π΅Π· ΡΠ΅ΡΠΈΠΎΠ·Π½ΠΎ ΠΏΠΎΠ·Π½Π°Π²Π°ΡΠ΅ Π½Π° C++, Π½Π°Π²Π΅Π΄Π΅Π½ Π΅ ΠΏΠΎΡΡΠ΅Π±Π½ΠΈΠΎΡ ΠΌΠΈΠ½ΠΈΠΌΡΠΌ
ΡΡΠΊΠ° . ΠΠ°Π³Π»Π°Π²ΠΈΠ΅ Π΄Π°ΡΠΎΡΠ΅ΠΊΠΈ Π·Π° Π³ΠΎΠ»Π΅ΠΌ Π±ΡΠΎΡ Π½Π° ΠΊΡΠ» C-Π±ΠΈΠ±Π»ΠΈΠΎΡΠ΅ΠΊΠΈ ΠΊΠ°ΠΊΠΎ xtensor Π΄ΠΎΡΡΠ°ΠΏΠ΅Π½ Π½Π° CRAN, ΠΎΠ΄Π½ΠΎΡΠ½ΠΎ ΡΠ΅ ΡΠΎΡΠΌΠΈΡΠ° ΠΈΠ½ΡΡΠ°ΡΡΡΡΠΊΡΡΡΠ° Π·Π° ΠΈΠΌΠΏΠ»Π΅ΠΌΠ΅Π½ΡΠ°ΡΠΈΡΠ° Π½Π° ΠΏΡΠΎΠ΅ΠΊΡΠΈ ΠΊΠΎΠΈ ΠΈΠ½ΡΠ΅Π³ΡΠΈΡΠ°Π°Ρ Π³ΠΎΡΠΎΠ² C++ ΠΊΠΎΠ΄ ΡΠΎ Π²ΠΈΡΠΎΠΊΠΈ ΠΏΠ΅ΡΡΠΎΡΠΌΠ°Π½ΡΠΈ Π²ΠΎ Π . ΠΠΎΠΏΠΎΠ»Π½ΠΈΡΠ΅Π»Π½Π° ΠΏΠΎΠ³ΠΎΠ΄Π½ΠΎΡΡ Π΅ ΠΈΡΡΠ°ΠΊΠ½ΡΠ²Π°ΡΠ΅ΡΠΎ Π½Π° ΡΠΈΠ½ΡΠ°ΠΊΡΠ°ΡΠ° ΠΈ ΡΡΠ°ΡΠΈΡΠ½ΠΈΠΎΡ C++ Π°Π½Π°Π»ΠΈΠ·Π°ΡΠΎΡ Π½Π° ΠΊΠΎΠ΄ΠΎΠ²ΠΈ Π²ΠΎ RStudio. - Π΄ΠΎΠΊΠΎΠΏΡ Π²ΠΈ ΠΎΠ²ΠΎΠ·ΠΌΠΎΠΆΡΠ²Π° Π΄Π° ΠΈΠ·Π²ΡΡΡΠ²Π°ΡΠ΅ ΡΠ°ΠΌΠΎΡΡΠΎΡΠ½ΠΈ ΡΠΊΡΠΈΠΏΡΠΈ ΡΠΎ ΠΏΠ°ΡΠ°ΠΌΠ΅ΡΡΠΈ. ΠΠ²Π° Π΅ ΠΏΠΎΠ³ΠΎΠ΄Π½ΠΎ Π·Π° ΡΠΏΠΎΡΡΠ΅Π±Π° Π½Π° ΠΎΠ΄Π΄Π°Π»Π΅ΡΠ΅Π½ ΡΠ΅ΡΠ²Π΅Ρ, Π²ΠΊΠ». ΠΏΠΎΠ΄ Π΄ΠΎΠΊΠ΅Ρ. ΠΠΎ RStudio, Π½Π΅Π·Π³ΠΎΠ΄Π½ΠΎ Π΅ Π΄Π° ΡΠ΅ ΡΠΏΡΠΎΠ²Π΅Π΄ΡΠ²Π°Π°Ρ ΠΌΠ½ΠΎΠ³Ρ ΡΠ°ΡΠΎΠ²ΠΈ Π΅ΠΊΡΠΏΠ΅ΡΠΈΠΌΠ΅Π½ΡΠΈ ΡΠΎ ΠΎΠ±ΡΠΊΠ° Π½Π° Π½Π΅Π²ΡΠΎΠ½ΡΠΊΠΈ ΠΌΡΠ΅ΠΆΠΈ, Π° ΠΈΠ½ΡΡΠ°Π»ΠΈΡΠ°ΡΠ΅ΡΠΎ Π½Π° IDE Π½Π° ΡΠ°ΠΌΠΈΠΎΡ ΡΠ΅ΡΠ²Π΅Ρ Π½Π΅ Π΅ ΡΠ΅ΠΊΠΎΠ³Π°Ρ ΠΎΠΏΡΠ°Π²Π΄Π°Π½ΠΎ.
- Docker ΠΎΠ±Π΅Π·Π±Π΅Π΄ΡΠ²Π° ΠΏΡΠ΅Π½ΠΎΡΠ»ΠΈΠ²ΠΎΡΡ Π½Π° ΠΊΠΎΠ΄ΠΎΡ ΠΈ ΡΠ΅ΠΏΡΠΎΠ΄ΡΠΊΡΠΈΠ²Π½ΠΎΡΡ Π½Π° ΡΠ΅Π·ΡΠ»ΡΠ°ΡΠΈΡΠ΅ ΠΏΠΎΠΌΠ΅ΡΡ ΠΏΡΠΎΠ³ΡΠ°ΠΌΠ΅ΡΠΈΡΠ΅ ΡΠΎ ΡΠ°Π·Π»ΠΈΡΠ½ΠΈ Π²Π΅ΡΠ·ΠΈΠΈ Π½Π° ΠΠ‘ ΠΈ Π±ΠΈΠ±Π»ΠΈΠΎΡΠ΅ΠΊΠΈ, ΠΊΠ°ΠΊΠΎ ΠΈ Π»Π΅ΡΠ½ΠΎΡΠΈΡΠ° Π½Π° ΠΈΠ·Π²ΡΡΡΠ²Π°ΡΠ΅ Π½Π° ΡΠ΅ΡΠ²Π΅ΡΠΈΡΠ΅. ΠΠΎΠΆΠ΅ΡΠ΅ Π΄Π° Π³ΠΎ ΡΡΠ°ΡΡΡΠ²Π°ΡΠ΅ ΡΠ΅Π»ΠΈΠΎΡ ΡΠ΅Π²ΠΊΠΎΠ²ΠΎΠ΄ Π·Π° ΠΎΠ±ΡΠΊΠ° ΡΠΎ ΡΠ°ΠΌΠΎ Π΅Π΄Π½Π° ΠΊΠΎΠΌΠ°Π½Π΄Π°.
- Google Cloud Π΅ Π±ΡΡΠ΅ΡΡΠΊΠΈ Π½Π°ΡΠΈΠ½ Π·Π° Π΅ΠΊΡΠΏΠ΅ΡΠΈΠΌΠ΅Π½ΡΠΈΡΠ°ΡΠ΅ Π½Π° ΡΠΊΠ°ΠΏ Ρ Π°ΡΠ΄Π²Π΅Ρ, Π½ΠΎ ΡΡΠ΅Π±Π° Π²Π½ΠΈΠΌΠ°ΡΠ΅Π»Π½ΠΎ Π΄Π° Π³ΠΈ ΠΈΠ·Π±ΠΈΡΠ°ΡΠ΅ ΠΊΠΎΠ½ΡΠΈΠ³ΡΡΠ°ΡΠΈΠΈΡΠ΅.
- ΠΠ΅ΡΠ΅ΡΠ΅ΡΠΎ Π½Π° Π±ΡΠ·ΠΈΠ½Π°ΡΠ° Π½Π° ΠΏΠΎΠ΅Π΄ΠΈΠ½Π΅ΡΠ½ΠΈΡΠ΅ ΡΡΠ°Π³ΠΌΠ΅Π½ΡΠΈ ΠΎΠ΄ ΠΊΠΎΠ΄ΠΎΡ Π΅ ΠΌΠ½ΠΎΠ³Ρ ΠΊΠΎΡΠΈΡΠ½ΠΎ, ΠΎΡΠΎΠ±Π΅Π½ΠΎ ΠΊΠΎΠ³Π° ΡΠ΅ ΠΊΠΎΠΌΠ±ΠΈΠ½ΠΈΡΠ°Π°Ρ R ΠΈ C++ ΠΈ ΡΠΎ ΠΏΠ°ΠΊΠ΅ΡΠΎΡ ΠΊΠ»ΡΠΏΠ°ΡΠ° - ΠΈΡΡΠΎ ΡΠ°ΠΊΠ° ΠΌΠ½ΠΎΠ³Ρ Π»Π΅ΡΠ½ΠΎ.
ΠΠ΅Π½Π΅ΡΠ°Π»Π½ΠΎ, ΠΎΠ²Π° ΠΈΡΠΊΡΡΡΠ²ΠΎ Π±Π΅ΡΠ΅ ΠΌΠ½ΠΎΠ³Ρ Π½Π°Π³ΡΠ°Π΄ΡΠ²Π°ΡΠΊΠΎ ΠΈ Π½ΠΈΠ΅ ΠΏΡΠΎΠ΄ΠΎΠ»ΠΆΡΠ²Π°ΠΌΠ΅ Π΄Π° ΡΠ°Π±ΠΎΡΠΈΠΌΠ΅ Π½Π° ΡΠ΅ΡΠ°Π²Π°ΡΠ΅ Π½Π° Π½Π΅ΠΊΠΎΠΈ ΠΎΠ΄ ΠΏΠΎΠΊΡΠ΅Π½Π°ΡΠΈΡΠ΅ ΠΏΡΠ°ΡΠ°ΡΠ°.
ΠΠ·Π²ΠΎΡ: www.habr.com