
ΠΠ΄ΡΠ°Π²Π΅ΠΉ, Π₯Π°Π±Ρ!
ΠΡΠ΅Π· Π΅ΡΠ΅Π½ΡΠ° Π½Π° ΠΌΠΈΠ½Π°Π»Π°ΡΠ° Π³ΠΎΠ΄ΠΈΠ½Π° ΡΠ΅ ΠΏΡΠΎΠ²Π΅Π΄Π΅ ΠΊΠΎΠ½ΠΊΡΡΡ Π½Π° Kaggle Π·Π° ΠΊΠ»Π°ΡΠΈΡΠΈΡΠΈΡΠ°Π½Π΅ Π½Π° ΡΡΡΠ½ΠΎ Π½Π°ΡΠΈΡΡΠ²Π°Π½ΠΈ ΠΈΠ·ΠΎΠ±ΡΠ°ΠΆΠ΅Π½ΠΈΡ Quick Draw Doodle Recognition, Π² ΠΊΠΎΠΉΡΠΎ ΡΡΠ΅Π΄ Π΄ΡΡΠ³ΠΈΡΠ΅ ΡΡΠ°ΡΡΠ²Π° Π΅ΠΊΠΈΠΏ ΠΎΡ R-ΠΏΡΠΎΠ³ΡΠ°ΠΌΠΈΡΡΠΈ, ΡΡΡΡΠ°Π²Π΅Π½ ΠΎΡ , ΠΈ . ΠΡΠΌΠ° Π΄Π° ΠΎΠΏΠΈΡΠ²Π°ΠΌΠ΅ ΠΏΠΎΠ΄ΡΠΎΠ±Π½ΠΎ ΡΡΡΡΠ΅Π·Π°Π½ΠΈΠ΅ΡΠΎ, ΡΠΎΠ²Π° Π²Π΅ΡΠ΅ Π΅ Π½Π°ΠΏΡΠ°Π²Π΅Π½ΠΎ Π² .
Π’ΠΎΠ·ΠΈ ΠΏΡΡ Π½Π΅ ΡΡΠΏΡΡ ΠΌΠ΅ Π΄Π° ΡΠΏΠ΅ΡΠ΅Π»ΠΈΠΌ ΠΌΠ΅Π΄Π°Π»ΠΈ, Π½ΠΎ ΠΏΠΎΠ»ΡΡΠΈΡ ΠΌΠ΅ ΠΌΠ½ΠΎΠ³ΠΎ ΡΠ΅Π½Π½ΠΎ ΠΎΠΏΠΈΡ, Π·Π°ΡΠΎΠ²Π° ΠΈΡΠΊΠ°Ρ ΠΌΠ΅ Π΄Π° ΡΠΏΠΎΠ΄Π΅Π»ΠΈΠΌ Ρ ΠΎΠ±ΡΠ½ΠΎΡΡΡΠ° Π·Π° ΡΠ΅Π΄ΠΈΡΠ° Π½Π°ΠΉ-ΠΈΠ½ΡΠ΅ΡΠ΅ΡΠ½ΠΈ ΠΈ ΠΏΠΎΠ»Π΅Π·Π½ΠΈ Π½Π΅ΡΠ° ΠΎΡ Kaggle ΠΈ Π² Π΅ΠΆΠ΅Π΄Π½Π΅Π²Π½Π°ΡΠ° ΡΠ°Π±ΠΎΡΠ°. Π‘ΡΠ΅Π΄ ΡΠ°Π·Π³Π»Π΅Π΄Π°Π½ΠΈΡΠ΅ ΡΠ΅ΠΌΠΈ: ΡΡΡΠ΄Π½ΠΈΡΡ ΠΆΠΈΠ²ΠΎΡ Π±Π΅Π· OpenCV, ΠΏΠ°ΡΡΠΈΡΠ°Π½Π΅ Π½Π° JSON (Π² ΡΠ΅Π·ΠΈ ΠΏΡΠΈΠΌΠ΅ΡΠΈ ΡΠ΅ ΡΠ°Π·Π³Π»Π΅ΠΆΠ΄Π° ΠΈΠ½ΡΠ΅Π³ΡΠ°ΡΠΈΡ Π½Π° C++ ΠΊΠΎΠ΄ Π² ΡΠΊΡΠΈΠΏΡΠΎΠ²Π΅ ΠΈΠ»ΠΈ ΠΏΠ°ΠΊΠ΅ΡΠΈ Π½Π° R ΡΡΠ΅Π· Rcpp), ΠΏΠ°ΡΠ°ΠΌΠ΅ΡΡΠΈΠ·Π°ΡΠΈΡ Π½Π° ΡΠΊΡΠΈΠΏΡΠΎΠ²Π΅ ΠΈ Π΄ΠΎΠΊΠ΅ΡΠΈΠ·Π°ΡΠΈΡ Π½Π° ΠΊΡΠ°ΠΉΠ½ΠΎΡΠΎ ΡΠ΅ΡΠ΅Π½ΠΈΠ΅. Π¦Π΅Π»ΠΈΡΡ ΠΊΠΎΠ΄ ΠΎΡ ΡΡΠΎΠ±ΡΠ΅Π½ΠΈΠ΅ΡΠΎ Π΅ Π½Π°Π»ΠΈΡΠ΅Π½ Π² ΠΈΠ·ΠΏΠΎΠ»Π·Π²Π°Π΅ΠΌ ΡΠΎΡΠΌΠ°Ρ Π² .
Π‘ΡΠ΄ΡΡΠΆΠ°Π½ΠΈΠ΅:
1. ΠΡΠ΅ΠΊΡΠΈΠ²Π½ΠΎ Π·Π°ΡΠ΅ΠΆΠ΄Π°Π½Π΅ Π½Π° Π΄Π°Π½Π½ΠΈ ΠΎΡ CSV Π² Π±Π°Π·Π° MonetDB
ΠΠ°Π½Π½ΠΈΡΠ΅ Π² ΡΠΎΠ²Π° ΡΡΡΡΠ΅Π·Π°Π½ΠΈΠ΅ Π½Π΅ ΡΠ° ΠΏΡΠ΅Π΄ΠΎΡΡΠ°Π²Π΅Π½ΠΈ ΠΏΠΎΠ΄ ΡΠΎΡΠΌΠ°ΡΠ° Π½Π° Π³ΠΎΡΠΎΠ²ΠΈ ΠΈΠ·ΠΎΠ±ΡΠ°ΠΆΠ΅Π½ΠΈΡ, Π° Π² 340 CSV ΡΠ°ΠΉΠ»Π° (ΠΏΠΎ Π΅Π΄ΠΈΠ½ ΡΠ°ΠΉΠ» Π·Π° Π²ΡΠ΅ΠΊΠΈ ΠΊΠ»Π°Ρ), ΡΡΠ΄ΡΡΠΆΠ°ΡΠΈ JSON Ρ ΠΊΠΎΠΎΡΠ΄ΠΈΠ½Π°ΡΠΈΡΠ΅ Π½Π° ΡΠΎΡΠΊΠΈΡΠ΅. Π‘Π²ΡΡΠ·Π²Π°ΠΉΠΊΠΈ ΡΠ΅Π·ΠΈ ΡΠΎΡΠΊΠΈ Ρ Π»ΠΈΠ½ΠΈΠΈ, ΠΏΠΎΠ»ΡΡΠ°Π²Π°ΠΌΠ΅ ΠΊΡΠ°ΠΉΠ½ΠΎΡΠΎ ΠΈΠ·ΠΎΠ±ΡΠ°ΠΆΠ΅Π½ΠΈΠ΅ Ρ ΡΠ°Π·ΠΌΠ΅Ρ 256x256 ΠΏΠΈΠΊΡΠ΅Π»Π°. Π‘ΡΡΠΎ ΡΠ°ΠΊΠ° Π·Π° Π²ΡΠ΅ΠΊΠΈ Π·Π°ΠΏΠΈΡ ΡΠ΅ ΠΏΡΠ΅Π΄ΠΎΡΡΠ°Π²Ρ Π΅ΡΠΈΠΊΠ΅Ρ, Π΄Π°Π»ΠΈ ΠΈΠ·ΠΎΠ±ΡΠ°ΠΆΠ΅Π½ΠΈΠ΅ΡΠΎ Π΅ Π±ΠΈΠ»ΠΎ ΠΊΠΎΡΠ΅ΠΊΡΠ½ΠΎ ΡΠ°Π·ΠΏΠΎΠ·Π½Π°ΡΠΎ ΠΎΡ ΠΊΠ»Π°ΡΠΈΡΠΈΠΊΠ°ΡΠΎΡΠ°, ΠΈΠ·ΠΏΠΎΠ»Π·Π²Π°Π½ ΠΏΠΎ Π²ΡΠ΅ΠΌΠ΅ Π½Π° ΡΡΠ±ΠΈΡΠ°Π½Π΅ Π½Π° Π΄Π°ΡΠ°ΡΠ΅ΡΠ°; Π΄Π²ΡΠ±ΡΠΊΠ²Π΅Π½ ΠΊΠΎΠ΄ Π½Π° ΡΡΡΠ°Π½Π°ΡΠ° Π½Π° ΠΏΡΠ΅Π±ΠΈΠ²Π°Π²Π°Π½Π΅ Π½Π° Π°Π²ΡΠΎΡΠ° Π½Π° ΡΠΈΡΡΠ½ΠΊΠ°ΡΠ°; ΡΠ½ΠΈΠΊΠ°Π»Π΅Π½ ΠΈΠ΄Π΅Π½ΡΠΈΡΠΈΠΊΠ°ΡΠΎΡ; Π²ΡΠ΅ΠΌΠ΅Π²ΠΈ Π΅ΡΠΈΠΊΠ΅Ρ ΠΈ ΠΈΠΌΠ΅ Π½Π° ΠΊΠ»Π°ΡΠ°, ΡΡΠ²ΠΏΠ°Π΄Π°ΡΠΎ Ρ ΠΈΠΌΠ΅ΡΠΎ Π½Π° ΡΠ°ΠΉΠ»Π°. ΠΠΏΡΠΈΠΌΠΈΠ·ΠΈΡΠ°Π½Π°ΡΠ° Π²Π΅ΡΡΠΈΡ Π½Π° ΠΈΠ·Ρ ΠΎΠ΄Π½ΠΈΡΠ΅ Π΄Π°Π½Π½ΠΈ ΡΠ΅ΠΆΠΈ 7.4 ΠΠ± Π² Π°ΡΡ ΠΈΠ² ΠΈ ΠΎΠΊΠΎΠ»ΠΎ 20 ΠΠ± ΡΠ»Π΅Π΄ ΡΠ°Π·Π°ΡΡ ΠΈΠ²ΠΈΡΠ°Π½Π΅, Π° ΠΏΡΠ»Π½ΠΈΡΠ΅ Π΄Π°Π½Π½ΠΈ ΡΠ»Π΅Π΄ ΡΠ°Π·Π°ΡΡ ΠΈΠ²ΠΈΡΠ°Π½Π΅ Π·Π°Π΅ΠΌΠ°Ρ 240 ΠΠ±. ΠΡΠ³Π°Π½ΠΈΠ·Π°ΡΠΎΡΠΈΡΠ΅ Π³Π°ΡΠ°Π½ΡΠΈΡΠ°Ρ Π°, ΡΠ΅ ΠΈ Π΄Π²Π΅ΡΠ΅ Π²Π΅ΡΡΠΈΠΈ Π²ΡΠ·ΠΏΡΠΎΠΈΠ·Π²Π΅ΠΆΠ΄Π°Ρ Π΅Π΄Π½ΠΈ ΠΈ ΡΡΡΠΈ ΡΠΈΡΡΠ½ΠΊΠΈ, Ρ.Π΅. ΠΏΡΠ»Π½Π°ΡΠ° Π²Π΅ΡΡΠΈΡ Π΅ ΠΈΠ·Π»ΠΈΡΠ½Π°. ΠΡΠ² Π²ΡΠ΅ΠΊΠΈ ΡΠ»ΡΡΠ°ΠΉ, ΡΡΡ ΡΠ°Π½ΡΠ²Π°Π½Π΅ΡΠΎ Π½Π° 50 ΠΌΠ»Π½. ΠΈΠ·ΠΎΠ±ΡΠ°ΠΆΠ΅Π½ΠΈΡ Π² Π³ΡΠ°ΡΠΈΡΠ½ΠΈ ΡΠ°ΠΉΠ»ΠΎΠ²Π΅ ΠΈΠ»ΠΈ ΠΏΠΎΠ΄ ΡΠΎΡΠΌΠ°ΡΠ° Π½Π° ΠΌΠ°ΡΠΈΠ²ΠΈ Π½Π΅Π·Π°Π±Π°Π²Π½ΠΎ Π±Π΅ΡΠ΅ ΠΏΡΠΈΠ·Π½Π°ΡΠΎ Π·Π° Π½Π΅ΡΠ΅Π½ΡΠ°Π±ΠΈΠ»Π½ΠΎ ΠΈ ΡΠ΅ΡΠΈΡ ΠΌΠ΅ Π΄Π° ΡΠ»Π΅Π΅ΠΌ Π²ΡΠΈΡΠΊΠΈ CSV ΡΠ°ΠΉΠ»ΠΎΠ²Π΅ ΠΎΡ Π°ΡΡ ΠΈΠ²Π° train_simplified.zip Π² Π±Π°Π·Π° Π΄Π°Π½Π½ΠΈ Ρ ΠΏΠΎΡΠ»Π΅Π΄Π²Π°ΡΠ° Π³Π΅Π½Π΅ΡΠ°ΡΠΈΡ Π½Π° ΠΈΠ·ΠΎΠ±ΡΠ°ΠΆΠ΅Π½ΠΈΡ Ρ Π½Π΅ΠΎΠ±Ρ ΠΎΠ΄ΠΈΠΌΠΈΡ ΡΠ°Π·ΠΌΠ΅Ρ "Π½Π° Π»Π΅ΡΠΎ" Π·Π° Π²ΡΡΠΊΠ° ΠΏΠ°ΡΡΠΈΠ΄Π°.
ΠΠ° Π‘Π£ΠΠ Π±Π΅ΡΠ΅ ΠΈΠ·Π±ΡΠ°Π½Π° Π΄ΠΎΠ±ΡΠ΅ Π·Π°ΡΠ΅ΠΊΠΎΠΌΠ΅Π½Π΄Π°Π»Π° ΡΠ΅ ΠΎΠΏΡΠΈΡ MonetDB, Π° ΠΈΠΌΠ΅Π½Π½ΠΎ ΡΠ΅Π°Π»ΠΈΠ·ΠΈΡΠΈΡΡΠ° Π·Π° R ΠΏΠΎΠ΄ ΡΠΎΡΠΌΠ°ΡΠ° Π½Π° ΠΏΠ°ΠΊΠ΅Ρ . ΠΠ°ΠΊΠ΅ΡΡΡ Π²ΠΊΠ»ΡΡΠ²Π° Π² ΡΠ΅Π±Π΅ ΡΠΈ Π²Π³ΡΠ°Π΄Π΅Π½Π° Π²Π΅ΡΡΠΈΡ Π½Π° ΡΡΡΠ²ΡΡΠ° Π½Π° Π±Π°Π·Π°ΡΠ° Π΄Π°Π½Π½ΠΈ ΠΈ ΠΏΠΎΠ·Π²ΠΎΠ»ΡΠ²Π° Π΄Π° ΡΡΠ°ΡΡΠΈΡΠ°ΡΠ΅ ΡΡΡΠ²ΡΡΠ° Π΄ΠΈΡΠ΅ΠΊΡΠ½ΠΎ ΠΎΡ ΡΠ΅ΡΠΈΡΡΠ° Π½Π° 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 β ΠΈΠΌΠ΅ΡΠΎ Π½Π° ΡΠ°Π±Π»ΠΈΡΠ°ΡΠ° ΠΈ ΠΏΡΡ β ΠΏΡΡΡΡ ΠΊΡΠΌ ΡΠ°ΠΉΠ»Π°. ΠΡΠΈ ΡΠ°Π±ΠΎΡΠ° Ρ Π°ΡΡ
ΠΈΠ²Π° ΠΎΡΠΊΡΠΈΡ
ΠΌΠ΅, ΡΠ΅ Π²Π³ΡΠ°Π΄Π΅Π½Π°ΡΠ° ΡΠ΅Π°Π»ΠΈΠ·Π°ΡΠΈΡ 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 (ΠΠ) ΠΎΡΠ½Π΅ΠΌΠ° ΠΏΠΎ-ΠΌΠ°Π»ΠΊΠΎ ΠΎΡ 10 ΠΌΠΈΠ½ΡΡΠΈ.
ΠΡΠ΅ Π½ΡΠΊΠΎΠ»ΠΊΠΎ ΡΠ΅ΠΊΡΠ½Π΄ΠΈ ΡΠ° Π½Π΅ΠΎΠ±Ρ
ΠΎΠ΄ΠΈΠΌΠΈ Π·Π° ΡΡΠ·Π΄Π°Π²Π°Π½Π΅ΡΠΎ Π½Π° ΡΡΡΠ»Π± Ρ ΡΠ΅Π»ΠΎΡΠΈΡΠ»Π΅Π½Π° Π΅ΡΠΈΠΊΠ΅ΡΠ½Π° ΠΊΠ»Π°Ρ ΠΈ ΡΡΡΠ»Π± ΠΈΠ½Π΄Π΅ΠΊΡ (ORDERED INDEX) Ρ Π½ΠΎΠΌΠ΅ΡΠ° Π½Π° ΡΠ΅Π΄ΠΎΠ²Π΅ΡΠ΅, ΠΏΠΎ ΠΊΠΎΠΉΡΠΎ ΡΠ΅ ΡΠ΅ ΠΈΠ·Π²ΡΡΡΠ²Π° ΠΈΠ·Π±ΠΎΡΡΡ Π½Π° Π½Π°Π±Π»ΡΠ΄Π΅Π½ΠΈΡ ΠΏΡΠΈ ΡΡΠ·Π΄Π°Π²Π°Π½Π΅ΡΠΎ Π½Π° ΠΏΠ°ΡΡΠΈΠ΄ΠΈ:
Π‘ΡΠ·Π΄Π°Π²Π°Π½Π΅ Π½Π° Π΄ΠΎΠΏΡΠ»Π½ΠΈΡΠ΅Π»Π½ΠΈ ΡΡΡΠ»Π±ΠΎΠ²Π΅ ΠΈ ΠΈΠ½Π΄Π΅ΠΊΡ
message("ΠΠ΅Π½Π΅ΡΠΈΡΠ°Π½Π΅ Π½Π° Π΅ΡΠΈΠΊΠ΅ΡΠΈ")
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("ΠΠ΅Π½Π΅ΡΠΈΡΠ°Π½Π΅ Π½Π° Π½ΠΎΠΌΠ΅ΡΠ° Π½Π° ΡΠ΅Π΄ΠΎΠ²Π΅")
invisible(DBI::dbExecute(con, "ALTER TABLE doodles ADD id serial"))
invisible(DBI::dbExecute(con, "CREATE ORDERED INDEX doodles_id_ord_idx ON doodles(id)"))ΠΠ° Π΄Π° ΡΠ΅ΡΠΈΠΌ Π·Π°Π΄Π°ΡΠ°ΡΠ° Π·Π° Π³Π΅Π½Π΅ΡΠΈΡΠ°Π½Π΅ Π½Π° ΠΏΠ°ΡΡΠΈΠ΄Π° Β«Π½Π° Π»Π΅ΡΠΎΒ», ΡΡΡΠ±Π²Π°ΡΠ΅ Π΄Π° ΠΏΠΎΡΡΠΈΠ³Π½Π΅ΠΌ ΠΌΠ°ΠΊΡΠΈΠΌΠ°Π»Π½Π° ΡΠΊΠΎΡΠΎΡΡ Π½Π° ΠΈΠ·Π²Π»ΠΈΡΠ°Π½Π΅ Π½Π° ΡΠ»ΡΡΠ°ΠΉΠ½ΠΈ ΡΠ΅Π΄ΠΎΠ²Π΅ ΠΎΡ ΡΠ°Π±Π»ΠΈΡΠ°ΡΠ° Π΄ΡΠ΄Π»ΠΈ. ΠΠ° ΡΠΎΠ²Π° ΠΈΠ·ΠΏΠΎΠ»Π·Π²Π°Ρ
ΠΌΠ΅ 3 ΡΡΠΈΠΊΠ°. ΠΡΡΠ²ΠΈΡΡ ΡΠ΅ ΡΡΡΡΠΎΠ΅ΡΠ΅ Π² Π½Π°ΠΌΠ°Π»ΡΠ²Π°Π½Π΅ Π½Π° ΡΠ°Π·ΠΌΠ΅ΡΠ½ΠΎΡΡΡΠ° Π½Π° ΡΠΈΠΏΠ°, Π² ΠΊΠΎΠΉΡΠΎ ΡΠ΅ ΡΡΡ
ΡΠ°Π½ΡΠ²Π° ID Π½Π° Π½Π°Π±Π»ΡΠ΄Π΅Π½ΠΈΠ΅ΡΠΎ. Π ΠΈΠ·Ρ
ΠΎΠ΄Π½ΠΈΡ Π½Π°Π±ΠΎΡ ΠΎΡ Π΄Π°Π½Π½ΠΈ Π·Π° ΡΡΡ
ΡΠ°Π½Π΅Π½ΠΈΠ΅ Π½Π° ID Π΅ Π½Π΅ΠΎΠ±Ρ
ΠΎΠ΄ΠΈΠΌ ΡΠΈΠΏ bigint, Π½ΠΎ Π±ΡΠΎΡΡ Π½Π° Π½Π°Π±Π»ΡΠ΄Π΅Π½ΠΈΡΡΠ° ΠΏΠΎΠ·Π²ΠΎΠ»ΡΠ²Π° Π΄Π° ΡΠ΅ Π²ΠΌΠ΅ΡΡΡΡ ΠΈΠ΄Π΅Π½ΡΠΈΡΠΈΠΊΠ°ΡΠΎΡΠΈΡΠ΅, ΡΠ°Π²Π½ΠΈ Π½Π° ΠΏΠΎΡΡΠ΄ΠΊΠΎΠ²ΠΈΡ Π½ΠΎΠΌΠ΅Ρ, Π² ΡΠΈΠΏ int. Π’ΡΡΡΠ΅Π½Π΅ΡΠΎ ΠΏΡΠΈ ΡΠΎΠ²Π° ΡΡΠ°Π²Π° Π·Π½Π°ΡΠΈΡΠ΅Π»Π½ΠΎ ΠΏΠΎ-Π±ΡΡΠ·ΠΎ. ΠΡΠΎΡΠΈΡΡ ΡΡΠΈΠΊ Π±Π΅ΡΠ΅ ΠΈΠ·ΠΏΠΎΠ»Π·Π²Π°Π½Π΅ΡΠΎ Π½Π° ORDERED INDEX β Π΄ΠΎ ΡΠΎΠ²Π° ΡΠ΅ΡΠ΅Π½ΠΈΠ΅ Π΄ΠΎΡΡΠΈΠ³Π½Π°Ρ
ΠΌΠ΅ Π΅ΠΌΠΏΠΈΡΠΈΡΠ΅ΡΠΊΠΈ, ΠΏΡΠΎΠ²Π΅ΡΡΠ²Π°ΠΉΠΊΠΈ Π²ΡΠΈΡΠΊΠΈ Π½Π°Π»ΠΈΡΠ½ΠΈ . Π’ΡΠ΅ΡΠΈΡΡ ΡΠ΅ ΡΡΡΡΠΎΠ΅ΡΠ΅ Π² ΠΈΠ·ΠΏΠΎΠ»Π·Π²Π°Π½Π΅ΡΠΎ Π½Π° ΠΏΠ°ΡΠ°ΠΌΠ΅ΡΡΠΈΠ·ΠΈΡΠ°Π½ΠΈ Π·Π°ΡΠ²ΠΊΠΈ. Π‘ΡΡΠ½ΠΎΡΡΡΠ° Π½Π° ΠΌΠ΅ΡΠΎΠ΄Π° ΡΠ΅ ΡΡΡΡΠΎΠΈ Π² Π΅Π΄Π½ΠΎΠΊΡΠ°ΡΠ½ΠΎΡΠΎ ΠΈΠ·ΠΏΡΠ»Π½Π΅Π½ΠΈΠ΅ Π½Π° ΠΊΠΎΠΌΠ°Π½Π΄Π°ΡΠ° PREPARE Ρ ΠΏΠΎΡΠ»Π΅Π΄Π²Π°ΡΠ° ΡΠΏΠΎΡΡΠ΅Π±Π° Π½Π° ΠΏΠΎΠ΄Π³ΠΎΡΠ²Π΅Π½ΠΎΡΠΎ ΠΈΠ·ΡΠ°Π·ΡΠ²Π°Π½Π΅ ΠΏΡΠΈ ΡΡΠ·Π΄Π°Π²Π°Π½Π΅ΡΠΎ Π½Π° ΠΊΡΠΏ ΠΎΡ Π΅Π΄Π½ΠΎΡΠΈΠΏΠ½ΠΈ Π·Π°ΡΠ²ΠΊΠΈ, Π½ΠΎ Π½Π° ΠΏΡΠ°ΠΊΡΠΈΠΊΠ° ΠΏΠ΅ΡΠ°Π»Π±Π°ΡΠ° Π² ΡΡΠ°Π²Π½Π΅Π½ΠΈΠ΅ Ρ ΠΏΡΠΎΡΡΠΈΡ SELECT ΡΠ΅ ΠΎΠΊΠ°Π·Π° ΠΎΠΊΠΎΠ»ΠΎ ΡΡΠ°ΡΠΈΡΡΠΈΡΠ΅ΡΠΊΠ°ΡΠ° Π³ΡΠ΅ΡΠΊΠ°.
ΠΡΠΎΡΠ΅ΡΡΡ Π½Π° Π·Π°ΡΠ΅ΠΆΠ΄Π°Π½Π΅ Π½Π° Π΄Π°Π½Π½ΠΈ Π½Π΅ ΠΈΠ·ΡΠ°Π·Ρ ΠΎΠ΄Π²Π° ΠΏΠΎΠ²Π΅ΡΠ΅ ΠΎΡ 450 ΠΠ± 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
#
# 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("ΠΌΠ΅Π΄ΠΈΠΉΠ½ΠΎ Π²ΡΠ΅ΠΌΠ΅, Ρ") +
theme_minimal()
DBI::dbDisconnect(con, shutdown = TRUE) 
2. ΠΠΎΠ΄Π³ΠΎΡΠΎΠ²ΠΊΠ° Π½Π° ΠΏΠ°ΡΡΠΈΠ΄ΠΈ
Π¦Π΅Π»ΠΈΡΡ ΠΏΡΠΎΡΠ΅Ρ Π½Π° ΠΏΠΎΠ΄Π³ΠΎΡΠΎΠ²ΠΊΠ° Π½Π° ΠΏΠ°ΡΡΠΈΠ΄ΠΈ ΡΠ΅ ΡΡΡΡΠΎΠΈ ΠΎΡ ΡΠ»Π΅Π΄Π½ΠΈΡΠ΅ Π΅ΡΠ°ΠΏΠΈ:
- ΠΠ°ΡΡΠΈΠ½Π³ Π½Π° Π½ΡΠΊΠΎΠ»ΠΊΠΎ JSON-Π°, ΡΡΠ΄ΡΡΠΆΠ°ΡΠΈ Π²Π΅ΠΊΡΠΎΡΠΈ ΠΎΡ Π½ΠΈΠ·ΠΎΠ²Π΅ Ρ ΠΊΠΎΠΎΡΠ΄ΠΈΠ½Π°ΡΠΈΡΠ΅ Π½Π° ΡΠΎΡΠΊΠΈΡΠ΅.
- ΠΠ°Π½Π°ΡΡΠ½Π΅ Π½Π° ΡΠ²Π΅ΡΠ½ΠΈ Π»ΠΈΠ½ΠΈΠΈ ΠΏΠΎ ΠΊΠΎΠΎΡΠ΄ΠΈΠ½Π°ΡΠΈΡΠ΅ Π½Π° ΡΠΎΡΠΊΠΈΡΠ΅ Π² ΠΈΠ·ΠΎΠ±ΡΠ°ΠΆΠ΅Π½ΠΈΠ΅ Ρ Π½Π΅ΠΎΠ±Ρ ΠΎΠ΄ΠΈΠΌΠΈΡ ΡΠ°Π·ΠΌΠ΅Ρ (Π½Π°ΠΏΡΠΈΠΌΠ΅Ρ 256Γ256 ΠΈΠ»ΠΈ 128Γ128).
- ΠΡΠ΅ΠΎΠ±ΡΠ°Π·ΡΠ²Π°Π½Π΅ Π½Π° ΠΏΠΎΠ»ΡΡΠ΅Π½ΠΈΡΠ΅ ΠΈΠ·ΠΎΠ±ΡΠ°ΠΆΠ΅Π½ΠΈΡ Π² ΡΠ΅Π½Π·ΠΎΡ.
Π ΠΊΠΎΠ½ΡΠ΅ΠΊΡΡΠ° Π½Π° ΡΡΡΡΠ΅Π·Π°Π½ΠΈΠ΅ ΠΌΠ΅ΠΆΠ΄Ρ kernel-ΠΈ Π½Π° Python, Π·Π°Π΄Π°ΡΠ°ΡΠ° Π±Π΅ΡΠ΅ ΡΠ΅ΡΠ΅Π½Π° ΠΏΡΠ΅Π΄ΠΈΠΌΠ½ΠΎ Ρ ΠΏΠΎΠΌΠΎΡΡΠ° Π½Π° OpenCV. ΠΠ΄ΠΈΠ½ ΠΎΡ Π½Π°ΠΉ-ΠΏΡΠΎΡΡΠΈΡΠ΅ ΠΈ ΠΎΡΠ΅Π²ΠΈΠ΄Π½ΠΈ Π°Π½Π°Π»ΠΎΠ·ΠΈ Π½Π° R ΡΠ΅ ΠΈΠ·Π³Π»Π΅ΠΆΠ΄Π° ΠΏΠΎ ΡΠ»Π΅Π΄Π½ΠΈΡ Π½Π°ΡΠΈΠ½:
Π Π΅Π°Π»ΠΈΠ·Π°ΡΠΈΡ Π½Π° ΠΏΡΠ΅ΠΎΠ±ΡΠ°Π·ΡΠ²Π°Π½Π΅ΡΠΎ Π½Π° JSON Π² ΡΠ΅Π½Π·ΠΎΡ Π½Π° R
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()
# ΠΡΠ΅ΠΎΠ±ΡΠ°Π·ΡΠ²Π°Π½Π΅ Π½Π° ΠΈΠ·ΠΎΠ±ΡΠ°ΠΆΠ΅Π½ΠΈΠ΅ΡΠΎ Π² 3D ΠΌΠ°ΡΠΈΠ²
res <- png::readPNG(tmp)
return(res)
}
r_process_json_vector <- function(x, ...) {
res <- lapply(x, r_process_json_str, ...)
# ΠΠ±Π΅Π΄ΠΈΠ½Π΅Π½ΠΈΠ΅ Π½Π° 3D ΠΌΠ°ΡΠΈΠ²ΠΈ Π² 4D ΡΠ΅Π½Π·ΠΎΡ
res <- do.call(abind::abind, c(res, along = 0))
return(res)
}Π ΠΈΡΡΠ²Π°Π½Π΅ΡΠΎ ΡΠ΅ ΠΈΠ·Π²ΡΡΡΠ²Π° ΡΡΡ ΡΡΠ°Π½Π΄Π°ΡΡΠ½ΠΈ ΡΡΠ΅Π΄ΡΡΠ²Π° Π½Π° R, ΠΊΠ°ΡΠΎ ΡΠ΅ ΡΡΡ
ΡΠ°Π½ΡΠ²Π° Π² Π²ΡΠ΅ΠΌΠ΅Π½Π½ΠΎ PNG, ΠΊΠΎΠ΅ΡΠΎ ΡΠ΅ ΡΡΡ
ΡΠ°Π½ΡΠ²Π° Π² RAM (Π² Linux Π²ΡΠ΅ΠΌΠ΅Π½Π½ΠΎΡΠΎ Π΄ΠΈΡΠ΅ΠΊΡΠΎΡΠΈΠΈ Π½Π° R ΡΠ° Π² ΠΏΠ°ΠΏΠΊΠ° /tmp, ΠΌΠΎΠ½ΡΠΈΡΠ°Π½Π° Π² RAM). Π‘Π»Π΅Π΄ ΡΠΎΠ²Π° ΡΠΎΠ·ΠΈ ΡΠ°ΠΉΠ» ΡΠ΅ ΠΏΡΠΎΡΠΈΡΠ° ΠΊΠ°ΡΠΎ ΡΡΠΈΠΌΠ΅ΡΠ΅Π½ ΠΌΠ°ΡΠΈΠ² Ρ ΡΠΈΡΠ»Π° Π² Π΄ΠΈΠ°ΠΏΠ°Π·ΠΎΠ½Π° ΠΎΡ 0 Π΄ΠΎ 1. Π’ΠΎΠ²Π° Π΅ Π²Π°ΠΆΠ½ΠΎ, ΡΡΠΉ ΠΊΠ°ΡΠΎ ΠΏΠΎ-ΡΠ°Π·ΠΏΡΠΎΡΡΡΠ°Π½Π΅Π½ΠΈΡΡ BMP Π±ΠΈ Π±ΠΈΠ» ΠΏΡΠΎΡΠ΅ΡΠ΅Π½ ΠΊΠ°ΡΠΎ raw-ΠΌΠ°ΡΠΈΠ² Ρ hex-ΠΊΠΎΠ΄ΠΎΠ²Π΅ Π½Π° ΡΠ²Π΅ΡΠΎΠ²Π΅.
ΠΠ΅ΠΊΠ° ΡΠ΅ΡΡΠ²Π°ΠΌΠ΅ ΡΠ΅Π·ΡΠ»ΡΠ°ΡΠ°:
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Π’Π°Π·ΠΈ ΡΠ΅Π°Π»ΠΈΠ·Π°ΡΠΈΡ Π½ΠΈ ΡΠ΅ ΡΡΠΎΡΠΈ Π½Π΅ΠΎΠΏΡΠΈΠΌΠ°Π»Π½Π°, ΡΡΠΉ ΠΊΠ°ΡΠΎ ΠΎΠ±ΡΠ°Π·ΡΠ²Π°Π½Π΅ΡΠΎ Π½Π° Π³ΠΎΠ»Π΅ΠΌΠΈ Π±Π°ΡΡΠΎΠ²Π΅ ΠΎΡΠ½Π΅ΠΌΠ° Π½Π΅ΠΏΠΎΠ΄Ρ ΠΎΠ΄ΡΡΠΎ ΠΌΠ½ΠΎΠ³ΠΎ Π²ΡΠ΅ΠΌΠ΅, ΠΈ ΡΠ΅ΡΠΈΡ ΠΌΠ΅ Π΄Π° ΡΠ΅ Π²ΡΠ·ΠΏΠΎΠ»Π·Π²Π°ΠΌΠ΅ ΠΎΡ ΠΎΠΏΠΈΡa Π½Π° ΠΊΠΎΠ»Π΅Π³ΠΈΡΠ΅, ΠΊΠ°ΡΠΎ Π²ΠΊΠ»ΡΡΠΈΠΌ ΠΌΠΎΡΠ½Π° Π±ΠΈΠ±Π»ΠΈΠΎΡΠ΅ΠΊΠ° OpenCV. Π ΡΠΎΠ·ΠΈ ΠΌΠΎΠΌΠ΅Π½Ρ Π½ΡΠΌΠ°ΡΠ΅ Π³ΠΎΡΠΎΠ² ΠΏΠ°ΠΊΠ΅Ρ Π·Π° R (ΠΈ Π²ΡΠ΅ ΠΎΡΠ΅ Π½ΡΠΌΠ°), Π·Π°ΡΠΎΠ²Π° Π±Π΅ΡΠ΅ Π½Π°ΠΏΠΈΡΠ°Π½Π° ΠΌΠΈΠ½ΠΈΠΌΠ°Π»Π½Π° ΡΠ΅Π°Π»ΠΈΠ·Π°ΡΠΈΡ Π½Π° Π½Π΅ΠΎΠ±Ρ ΠΎΠ΄ΠΈΠΌΠ°ΡΠ° ΡΡΠ½ΠΊΡΠΈΠΎΠ½Π°Π»Π½ΠΎΡΡ Π½Π° C++ Ρ ΠΈΠ½ΡΠ΅Π³ΡΠ°ΡΠΈΡ Π² ΠΊΠΎΠ΄Π° Π½Π° R Ρ ΠΏΠΎΠΌΠΎΡΡΠ° Π½Π° Rcpp.
ΠΠ° ΡΠ΅ΡΠ°Π²Π°Π½Π΅ΡΠΎ Π½Π° Π·Π°Π΄Π°ΡΠ°ΡΠ° ΡΠ΅ ΠΈΠ·ΠΏΠΎΠ»Π·Π²Π°Ρ Π° ΡΠ»Π΅Π΄Π½ΠΈΡΠ΅ ΠΏΠ°ΠΊΠ΅ΡΠΈ ΠΈ Π±ΠΈΠ±Π»ΠΈΠΎΡΠ΅ΠΊΠΈ:
OpenCV Π·Π° ΡΠ°Π±ΠΎΡΠ° Ρ ΠΈΠ·ΠΎΠ±ΡΠ°ΠΆΠ΅Π½ΠΈΡ ΠΈ ΡΠΈΡΡΠ²Π°Π½Π΅ Π½Π° Π»ΠΈΠ½ΠΈΠΈ. ΠΠ·ΠΏΠΎΠ»Π·Π²Π°Π½ΠΈ ΠΏΡΠ΅Π΄Π²Π°ΡΠΈΡΠ΅Π»Π½ΠΎ ΠΈΠ½ΡΡΠ°Π»ΠΈΡΠ°Π½ΠΈ ΡΠΈΡΡΠ΅ΠΌΠ½ΠΈ Π±ΠΈΠ±Π»ΠΈΠΎΡΠ΅ΠΊΠΈ ΠΈ Π·Π°Π³Π»Π°Π²Π½ΠΈ ΡΠ°ΠΉΠ»ΠΎΠ²Π΅, Π° ΡΡΡΠΎ ΠΈ Π΄ΠΈΠ½Π°ΠΌΠΈΡΠ½ΠΎ ΡΠ²ΡΡΠ·Π²Π°Π½Π΅.
xtensor Π·Π° ΡΠ°Π±ΠΎΡΠ° Ρ ΠΌΠ½ΠΎΠ³ΠΎΠΌΠ΅ΡΠ½ΠΈ ΠΌΠ°ΡΠΈΠ²ΠΈ ΠΈ ΡΠ΅Π½Π·ΠΎΡΠΈ. ΠΠ·ΠΏΠΎΠ»Π·Π²Π°Ρ ΠΌΠ΅ Π·Π°Π³Π»Π°Π²Π½ΠΈ ΡΠ°ΠΉΠ»ΠΎΠ²Π΅, Π²ΠΊΠ»ΡΡΠ΅Π½ΠΈ Π² Π΅Π΄Π½ΠΎΠΈΠΌΠ΅Π½Π½ΠΈΡ R-ΠΏΠ°ΠΊΠ΅Ρ. ΠΠΈΠ±Π»ΠΈΠΎΡΠ΅ΠΊΠ°ΡΠ° ΠΏΠΎΠ·Π²ΠΎΠ»ΡΠ²Π° ΡΠ°Π±ΠΎΡΠ° Ρ ΠΌΠ½ΠΎΠ³ΠΎΠΌΠ΅ΡΠ½ΠΈ ΠΌΠ°ΡΠΈΠ²ΠΈ, ΠΊΠ°ΠΊΡΠΎ Π² ΡΠ΅Π΄ΠΎΠ²ΠΎ, ΡΠ°ΠΊΠ° ΠΈ Π² ΠΊΠΎΠ»ΠΎΠ½ΠΎΠ²ΠΎ ΠΏΠΎΠ΄ΡΠ΅ΠΆΠ΄Π°Π½Π΅.
ndjson Π·Π° ΠΏΠ°ΡΡΠΈΡΠ°Π½Π΅ Π½Π° JSON. Π’Π°Π·ΠΈ Π±ΠΈΠ±Π»ΠΈΠΎΡΠ΅ΠΊΠ° ΡΠ΅ ΠΈΠ·ΠΏΠΎΠ»Π·Π²Π° Π² xtensor Π°Π²ΡΠΎΠΌΠ°ΡΠΈΡΠ½ΠΎ ΠΏΡΠΈ Π½Π΅ΠΉΠ½ΠΎΡΠΎ Π½Π°Π»ΠΈΡΠΈΠ΅ Π² ΠΏΡΠΎΠ΅ΠΊΡΠ°.
RcppThread Π·Π° ΠΎΡΠ³Π°Π½ΠΈΠ·ΠΈΡΠ°Π½Π΅ Π½Π° ΠΌΠ½ΠΎΠ³ΠΎΠΏΠΎΡΠΎΡΠ½Π° ΠΎΠ±ΡΠ°Π±ΠΎΡΠΊΠ° Π½Π° Π²Π΅ΠΊΡΠΎΡ ΠΎΡ JSON-ΠΎΠ²Π΅. ΠΠ·ΠΏΠΎΠ»Π·Π²Π°Ρ ΠΌΠ΅ Π·Π°Π³Π»Π°Π²Π½ΠΈ ΡΠ°ΠΉΠ»ΠΎΠ²Π΅, ΠΏΡΠ΅Π΄ΠΎΡΡΠ°Π²Π΅Π½ΠΈ ΠΎΡ ΡΠΎΠ·ΠΈ ΠΏΠ°ΠΊΠ΅Ρ. ΠΡΠΏΡΠ΅ΠΊΠΈ ΡΠ΅ Π΅ ΠΏΠΎ-ΠΌΠ°Π»ΠΊΠΎ ΠΏΠΎΠΏΡΠ»ΡΡΠ΅Π½ ΠΎΡ RcppParallel ΠΏΠ°ΠΊΠ΅ΡΡΡ Π½Π°ΡΠ΅Π΄ Ρ Π΄ΡΡΠ³ΠΎΡΠΎ ΡΠ΅ ΠΎΡΠ»ΠΈΡΠ°Π²Π° Ρ Π²Π³ΡΠ°Π΄Π΅Π½ ΠΌΠ΅Ρ Π°Π½ΠΈΠ·ΡΠΌ Π·Π° ΠΏΡΠ΅ΠΊΡΡΠ²Π°Π½Π΅ Π½Π° ΡΠΈΠΊΡΠ»Π° (interrupt).
Π‘ΡΡΡΠ²Π° ΡΠΈ Π΄Π° ΡΠ΅ ΠΎΡΠ±Π΅Π»Π΅ΠΆΠΈ, ΡΠ΅ xtensor ΡΠ΅ ΠΎΠΊΠ°Π·Π° ΠΈΡΡΠΈΠ½ΡΠΊΠΎ ΠΎΡΠΊΡΠΈΡΠΈΠ΅: ΠΎΡΠ²Π΅Π½ ΡΠ΅ ΡΠ°Π·ΠΏΠΎΠ»Π°Π³Π° Ρ ΠΎΠ±ΡΠΈΡΠ΅Π½ ΡΡΠ½ΠΊΡΠΈΠΎΠ½Π°Π» ΠΈ Π²ΠΈΡΠΎΠΊΠ° ΠΏΡΠΎΠΈΠ·Π²ΠΎΠ΄ΠΈΡΠ΅Π»Π½ΠΎΡΡ, ΡΠ°Π·ΡΠ°Π±ΠΎΡΡΠΈΡΠΈΡΠ΅ ΠΌΡ Π±ΡΡ Π° Π΄ΠΎΡΡΠ° ΠΎΡΠ·ΠΈΠ²ΡΠΈΠ²ΠΈ ΠΈ Π±ΡΡΠ·ΠΎ ΠΈ ΠΏΠΎΠ΄ΡΠΎΠ±Π½ΠΎ ΠΎΡΠ³ΠΎΠ²Π°ΡΡΡ Π° Π½Π° Π²ΡΠ·Π½ΠΈΠΊΠ½Π°Π»ΠΈ Π²ΡΠΏΡΠΎΡΠΈ. Π‘ ΡΡΡ Π½Π° ΠΏΠΎΠΌΠΎΡ ΡΡΠΏΡΡ ΠΌΠ΅ Π΄Π° ΡΠ΅Π°Π»ΠΈΠ·ΠΈΡΠ°ΠΌΠ΅ ΠΏΡΠ΅ΠΎΠ±ΡΠ°Π·ΡΠ²Π°Π½ΠΈΡ Π½Π° ΠΌΠ°ΡΡΠΈΡΠΈ OpenCV Π² ΡΠ΅Π½Π·ΠΎΡΠΈ xtensor, Π° ΡΡΡΠΎ ΠΈ ΠΌΠ΅ΡΠΎΠ΄ Π·Π° ΠΊΠΎΠΌΠ±ΠΈΠ½ΠΈΡΠ°Π½Π΅ Π½Π° 3-ΠΌΠ΅ΡΠ½ΠΈ ΡΠ΅Π½Π·ΠΎΡΠΈ Π½Π° ΠΈΠ·ΠΎΠ±ΡΠ°ΠΆΠ΅Π½ΠΈΡ Π² 4-ΠΌΠ΅ΡΠ΅Π½ ΡΠ΅Π½Π·ΠΎΡ Ρ ΠΏΡΠ°Π²ΠΈΠ»Π½ΠΈ ΡΠ°Π·ΠΌΠ΅ΡΠ½ΠΎΡΡΠΈ (ΡΠΎΠ±ΡΡΠ²Π΅Π½ΠΈΡΡ Π±Π°ΡΡ).
ΠΠ°ΡΠ΅ΡΠΈΠ°Π»ΠΈ Π·Π° ΠΈΠ·ΡΡΠ°Π²Π°Π½Π΅ Π½Π° Rcpp, xtensor ΠΈ RcppThread
ΠΠ° ΠΊΠΎΠΌΠΏΠΈΠ»Π°ΡΠΈΡ Π½Π° ΡΠ°ΠΉΠ»ΠΎΠ²Π΅, ΠΈΠ·ΠΏΠΎΠ»Π·Π²Π°ΡΠΈ ΡΠΈΡΡΠ΅ΠΌΠ½ΠΈ ΡΠ°ΠΉΠ»ΠΎΠ²Π΅ ΠΈ Π΄ΠΈΠ½Π°ΠΌΠΈΡΠ½ΠΎ ΡΠ²ΡΡΠ·Π²Π°Π½Π΅ Ρ ΠΈΠ½ΡΡΠ°Π»ΠΈΡΠ°Π½ΠΈΡΠ΅ Π² ΡΠΈΡΡΠ΅ΠΌΠ°ΡΠ° Π±ΠΈΠ±Π»ΠΈΠΎΡΠ΅ΠΊΠΈ, Π½ΠΈΠ΅ ΠΈΠ·ΠΏΠΎΠ»Π·Π²Π°Ρ ΠΌΠ΅ ΠΌΠ΅Ρ Π°Π½ΠΈΠ·ΠΌΠ° Π·Π° ΠΏΠ»ΡΠ³ΠΈΠ½ΠΈ, ΡΠ΅Π°Π»ΠΈΠ·ΠΈΡΠ°Π½ Π² ΠΏΠ°ΠΊΠ΅ΡΠ° Rcpp. ΠΠ° Π°Π²ΡΠΎΠΌΠ°ΡΠΈΡΠ½ΠΎ Π½Π°ΠΌΠΈΡΠ°Π½Π΅ Π½Π° ΠΏΡΡΠΈΡΠ° ΠΈ ΡΠ»Π°Π³ΠΎΠ²Π΅ ΠΈΠ·ΠΏΠΎΠ»Π·Π²Π°Ρ ΠΌΠ΅ ΠΏΠΎΠΏΡΠ»ΡΡΠ½Π°ΡΠ° linux-ΡΡΠΈΠ»ΠΈΡΠ° pkg-config.
Π Π΅Π°Π»ΠΈΠ·Π°ΡΠΈΡ Π½Π° 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 ΠΊΠΎΠ½ΡΠΈΠ³ΡΡΠ°ΡΠΈΡ Π·Π° pkg-config Π½Π΅ Π΅ Π½Π°ΠΌΠ΅ΡΠ΅Π½Π°", 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/ ΡΠ΅ΠΊ", "total_time", "n_itr")
res_bench[, cols]
# expression min median max `itr/ ΡΠ΅ΠΊ` total_time n_itr
#
# 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/ ΡΠ΅ΠΊ` total_time n_itr
# <bch:tm> <bch:tm> <bch:tm> <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("ΠΌΠ΅Π΄ΠΈΠΉΠ½ΠΎ Π²ΡΠ΅ΠΌΠ΅, Ρ") +
theme_minimal() +
scale_color_discrete(name = "", labels = c("cpp", "r")) +
theme(legend.position = "bottom") 
ΠΠ°ΠΊΡΠΎ Π²ΠΈΠΆΠ΄Π°ΠΌΠ΅, ΡΠ²Π΅Π»ΠΈΡΠ΅Π½ΠΈΠ΅ΡΠΎ Π½Π° ΡΠΊΠΎΡΠΎΡΡΡΠ° Π΅ ΠΌΠ½ΠΎΠ³ΠΎ Π·Π½Π°ΡΠΈΡΠ΅Π»Π½ΠΎ ΠΈ Π½Π΅ Π΅ Π²ΡΠ·ΠΌΠΎΠΆΠ½ΠΎ Π΄Π° ΡΠ΅ Π΄ΠΎΡΡΠΈΠ³Π½Π΅ ΠΊΠΎΠ΄ΡΡ Π½Π° C++ ΡΡΠ΅Π· ΠΏΠ°ΡΠ°Π»Π΅Π»ΠΈΠ·Π°ΡΠΈΡ Π½Π° ΠΊΠΎΠ΄Π° Π½Π° R.
3. ΠΡΠ΅ΡΠ°ΡΠΎΡΠΈ Π·Π° ΠΈΠ·Π²Π»ΠΈΡΠ°Π½Π΅ Π½Π° Π±Π°ΡΡΠΎΠ²Π΅ ΠΎΡ ΠΠ
R ΠΈΠΌΠ° Π·Π°ΡΠ»ΡΠΆΠ΅Π½Π° ΡΠ΅ΠΏΡΡΠ°ΡΠΈΡ Π½Π° Π΅Π·ΠΈΠΊ Π·Π° ΠΎΠ±ΡΠ°Π±ΠΎΡΠΊΠ° Π½Π° Π΄Π°Π½Π½ΠΈ, ΠΊΠΎΠΈΡΠΎ ΡΠ΅ ΠΏΠΎΠ±ΠΈΡΠ°Ρ Π² RAM, Π΄ΠΎΠΊΠ°ΡΠΎ Python Π΅ ΠΏΠΎ-Ρ Π°ΡΠ°ΠΊΡΠ΅ΡΠ΅Π½ Ρ ΠΈΡΠ΅ΡΠ°ΡΠΈΠ²Π½Π°ΡΠ° ΠΎΠ±ΡΠ°Π±ΠΎΡΠΊΠ° Π½Π° Π΄Π°Π½Π½ΠΈ, ΠΊΠΎΠ΅ΡΠΎ ΠΏΠΎΠ·Π²ΠΎΠ»ΡΠ²Π° Π»Π΅ΡΠ½ΠΎ ΠΈ Π½Π΅ΡΡΠ΅ΡΠ½ΠΎ ΡΠ΅Π°Π»ΠΈΠ·ΠΈΡΠ°Π½Π΅ Π½Π° out-of-core ΠΈΠ·ΡΠΈΡΠ»Π΅Π½ΠΈΡ (ΠΈΠ·ΡΠΈΡΠ»Π΅Π½ΠΈΡ Ρ ΠΈΠ·ΠΏΠΎΠ»Π·Π²Π°Π½Π΅ Π½Π° Π²ΡΠ½ΡΠ½Π° ΠΏΠ°ΠΌΠ΅Ρ). ΠΠ»Π°ΡΠΈΡΠ΅ΡΠΊΠΈ ΠΈ Π°ΠΊΡΡΠ°Π»Π΅Π½ Π·Π° Π½Π°Ρ ΠΏΡΠΈΠΌΠ΅Ρ Π·Π° ΡΠ°ΠΊΠΈΠ²Π° ΠΈΠ·ΡΠΈΡΠ»Π΅Π½ΠΈΡ Π² ΠΊΠΎΠ½ΡΠ΅ΠΊΡΡΠ° Π½Π° ΠΎΠ±ΡΡΠΆΠ΄Π°Π½Π°ΡΠ° Π·Π°Π΄Π°ΡΠ° ΡΠ° Π΄ΡΠ»Π±ΠΎΠΊΠΈΡΠ΅ Π½Π΅Π²ΡΠΎΠ½Π½ΠΈ ΠΌΡΠ΅ΠΆΠΈ, ΠΎΠ±ΡΡΠ°Π²Π°ΡΠΈ ΡΠ΅ ΡΡΠ΅Π· ΠΌΠ΅ΡΠΎΠ΄Π° Π½Π° Π³ΡΠ°Π΄ΠΈΠ΅Π½ΡΠ½ΠΈΡ ΡΠΏΡΡΠΊ Ρ Π°ΠΏΠΏΡΠΎΠΊΡΠΈΠΌΠ°ΡΠΈΡ Π½Π° Π³ΡΠ°Π΄ΠΈΠ΅Π½ΡΠ° Π½Π° Π²ΡΡΠΊΠ° ΡΡΡΠΏΠΊΠ° ΠΏΠΎ ΠΌΠ°Π»ΠΊΠ° ΠΏΠΎΡΡΠΈΡ Π½Π°Π±Π»ΡΠ΄Π΅Π½ΠΈΡ ΠΈΠ»ΠΈ ΠΌΠΈΠ½ΠΈ-Π±Π°ΡΡ.
Π€ΡΠ΅ΠΉΠΌΠ²ΠΎΡΡΠΈΡΠ΅ Π·Π° Π΄ΡΠ»Π±ΠΎΠΊΠΎ ΠΎΠ±ΡΡΠ΅Π½ΠΈΠ΅, Π½Π°ΠΏΠΈΡΠ°Π½ΠΈ Π½Π° Python, ΡΠ°Π·ΠΏΠΎΠ»Π°Π³Π°Ρ ΡΡΡ ΡΠΏΠ΅ΡΠΈΠ°Π»Π½ΠΈ ΠΊΠ»Π°ΡΠΎΠ²Π΅, ΡΠ΅Π°Π»ΠΈΠ·ΠΈΡΠ°ΡΠΈ ΠΈΡΠ΅ΡΠ°ΡΠΎΡΠΈ Π·Π° Π΄Π°Π½Π½ΠΈ: ΡΠ°Π±Π»ΠΈΡΠΈ, ΠΈΠ·ΠΎΠ±ΡΠ°ΠΆΠ΅Π½ΠΈΡ Π² ΠΏΠ°ΠΏΠΊΠΈ, Π±ΠΈΠ½Π°ΡΠ½ΠΈ ΡΠΎΡΠΌΠ°ΡΠΈ ΠΈ Π΄Ρ. ΠΠΎΠΆΠ΅ Π΄Π° ΡΠ΅ ΠΈΠ·ΠΏΠΎΠ»Π·Π²Π°Ρ Π³ΠΎΡΠΎΠ²ΠΈ Π²Π°ΡΠΈΠ°Π½ΡΠΈ ΠΈΠ»ΠΈ Π΄Π° ΡΠ΅ ΠΏΠΈΡΠ°Ρ ΡΠΎΠ±ΡΡΠ²Π΅Π½ΠΈ Π·Π° ΡΠΏΠ΅ΡΠΈΡΠΈΡΠ½ΠΈ Π·Π°Π΄Π°ΡΠΈ. Π R ΠΌΠΎΠΆΠ΅ΠΌ Π΄Π° ΡΠ΅ Π²ΡΠ·ΠΏΠΎΠ»Π·Π²Π°ΠΌΠ΅ ΠΎΡ Π²ΡΠΈΡΠΊΠΈ ΡΡΠ½ΠΊΡΠΈΠΈ Π½Π° Π±ΠΈΠ±Π»ΠΈΠΎΡΠ΅ΠΊΠ°ΡΠ° Π½Π° Python keras Ρ Π½Π΅Π³ΠΎΠ²ΠΈΡΠ΅ ΡΠ°Π·Π»ΠΈΡΠ½ΠΈ Π±Π΅ΠΊΠ΅Π½Π΄ΠΈ ΡΡΠ΅Π· Π΅Π΄Π½ΠΎΠΈΠΌΠ΅Π½Π½ΠΈΡ ΠΏΠ°ΠΊΠ΅Ρ, ΠΊΠΎΠΉΡΠΎ ΠΎΡ ΡΠ²ΠΎΡ ΡΡΡΠ°Π½Π° ΡΠ°Π±ΠΎΡΠΈ Π²ΡΡΡ Ρ ΠΏΠ°ΠΊΠ΅ΡΠ° reticulate. ΠΠΎΡΠ»Π΅Π΄Π½ΠΈΡΡ Π·Π°ΡΠ»ΡΠΆΠ°Π²Π° ΠΎΡΠ΄Π΅Π»Π½Π° Π³ΠΎΠ»ΡΠΌΠ° ΡΡΠ°ΡΠΈΡ; ΡΠΎΠΉ Π½Π΅ ΡΠ°ΠΌΠΎ ΠΏΠΎΠ·Π²ΠΎΠ»ΡΠ²Π° ΠΈΠ·ΠΏΡΠ»Π½Π΅Π½ΠΈΠ΅ Π½Π° ΠΊΠΎΠ΄ Π½Π° Python ΠΎΡ R, Π½ΠΎ ΠΈ ΠΎΡΠΈΠ³ΡΡΡΠ²Π° ΠΏΡΠ΅Π΄Π°Π²Π°Π½Π΅ Π½Π° ΠΎΠ±Π΅ΠΊΡΠΈ ΠΌΠ΅ΠΆΠ΄Ρ R ΠΈ Python ΡΠ΅ΡΠΈΠΈ, Π°Π²ΡΠΎΠΌΠ°ΡΠΈΡΠ½ΠΎ ΠΈΠ·Π²ΡΡΡΠ²Π°ΠΉΠΊΠΈ Π²ΡΠΈΡΠΊΠΈ Π½Π΅ΠΎΠ±Ρ ΠΎΠ΄ΠΈΠΌΠΈ ΠΏΡΠ΅ΠΎΠ±ΡΠ°Π·ΡΠ²Π°Π½ΠΈΡ Π½Π° ΡΠΈΠΏΠΎΠ²Π΅.
ΠΡΠ²ΠΎΠ±ΠΎΠ΄ΠΈΡ ΠΌΠ΅ ΡΠ΅ ΠΎΡ Π½Π΅ΠΎΠ±Ρ ΠΎΠ΄ΠΈΠΌΠΎΡΡΡΠ° Π΄Π° ΡΡΡ ΡΠ°Π½ΡΠ²Π°ΠΌΠ΅ Π²ΡΠΈΡΠΊΠΈ Π΄Π°Π½Π½ΠΈ Π² RAM Ρ ΠΏΠΎΠΌΠΎΡΡΠ° Π½Π° MonetDBLite, ΡΡΠ»Π°ΡΠ° "Π½Π΅Π²ΡΠΎΠ½Π½Π°" ΡΠ°Π±ΠΎΡΠ° ΡΠ΅ ΡΠ΅ ΠΈΠ·Π²ΡΡΡΠ²Π° ΠΎΡ ΠΎΡΠΈΠ³ΠΈΠ½Π°Π»Π½ΠΈΡ ΠΊΠΎΠ΄ Π½Π° Python, Π° Π½ΠΈΠ΅ ΡΡΡΠ±Π²Π° ΡΠ°ΠΌΠΎ Π΄Π° Π½Π°ΠΏΠΈΡΠ΅ΠΌ ΠΈΡΠ΅ΡΠ°ΡΠΎΡ Π·Π° Π΄Π°Π½Π½ΠΈ, ΡΡΠΉ ΠΊΠ°ΡΠΎ Π½ΡΠΌΠ° Π³ΠΎΡΠΎΠ² ΡΠ°ΠΊΡΠ² Π½ΠΈΡΠΎ Π·Π° R, Π½ΠΈΡΠΎ Π·Π° Python. ΠΠ·ΠΈΡΠΊΠ²Π°Π½ΠΈΡΡΠ° ΠΊΡΠΌ Π½Π΅Π³ΠΎ ΡΠ° ΠΎΡΠ½ΠΎΠ²Π½ΠΎ Π΄Π²Π΅: ΡΠΎΠΉ ΡΡΡΠ±Π²Π° Π΄Π° Π²ΡΡΡΠ° Π±Π°ΡΡΠΎΠ²Π΅ΡΠ΅ Π² Π±Π΅Π·ΠΊΡΠ°Π΅Π½ ΡΠΈΠΊΡΠ» ΠΈ Π΄Π° Π·Π°ΠΏΠ°Π·Π²Π° ΡΡΡΡΠΎΡΠ½ΠΈΠ΅ΡΠΎ ΡΠΈ ΠΌΠ΅ΠΆΠ΄Ρ ΠΈΡΠ΅ΡΠ°ΡΠΈΠΈΡΠ΅ (ΠΏΠΎΡΠ»Π΅Π΄Π½ΠΎΡΠΎ Π² R ΡΠ΅ ΡΠ΅Π°Π»ΠΈΠ·ΠΈΡΠ° ΠΏΠΎ Π½Π°ΠΉ-ΠΏΡΠΎΡΡΠΈΡ Π½Π°ΡΠΈΠ½ Ρ ΠΏΠΎΠΌΠΎΡΡΠ° Π½Π° Π·Π°ΠΌΠΈΠΊΠ°Π½ΠΈΡ). ΠΠΎ-ΡΠ°Π½ΠΎ Π±Π΅ΡΠ΅ Π½Π΅ΠΎΠ±Ρ ΠΎΠ΄ΠΈΠΌΠΎ Π²ΡΡΡΠ΅ Π² ΠΈΡΠ΅ΡΠ°ΡΠΎΡΠ° ΡΠ²Π½ΠΎ Π΄Π° ΠΏΡΠ΅ΠΎΠ±ΡΠ°Π·ΡΠ²Π°ΠΌΠ΅ ΠΌΠ°ΡΠΈΠ²ΠΈΡΠ΅ Π½Π° R Π² numpy ΠΌΠ°ΡΠΈΠ²ΠΈ, Π½ΠΎ Π°ΠΊΡΡΠ°Π»Π½Π°ΡΠ° Π²Π΅ΡΡΠΈΡ Π½Π° ΠΏΠ°ΠΊΠ΅ΡΠ° 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 Π²ΡΠΈΡΠΊΠΈ ΡΡΠΈΡ
ΠΈ ΡΠ΅ ΡΠΈΡΡΠ²Π°Ρ Ρ Π½ΠΎΠ² ΡΠ²ΡΡ) ΠΈ ΠΈΠ½Π΄ΠΈΠΊΠ°ΡΠΎΡ Π·Π° ΠΏΡΠ΅ΠΏΡΠΎΡΠ΅ΡΠΈΡΠ°Π½Π΅ Π·Π° ΠΌΡΠ΅ΠΆΠΈ, ΠΏΡΠ΅Π΄ΠΎΠ±ΡΡΠ΅Π½ΠΈ Π½Π° imagenet. ΠΠΎΡΠ»Π΅Π΄Π½ΠΈΡΡ Π΅ Π½Π΅ΠΎΠ±Ρ
ΠΎΠ΄ΠΈΠΌ, Π·Π° Π΄Π° ΡΠ΅ ΡΠΊΠ°Π»ΠΈΡΠ°Ρ ΡΡΠΎΠΉΠ½ΠΎΡΡΠΈΡΠ΅ Π½Π° ΠΏΠΈΠΊΡΠ΅Π»ΠΈΡΠ΅ ΠΎΡ ΠΈΠ½ΡΠ΅ΡΠ²Π°Π»Π° [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++) ΠΈ ΡΡΠ·Π΄Π°Π²Π°Π½Π΅ Π½Π° ΠΌΠ°ΡΠΈΠ²ΠΈ, ΠΎΡΠ³ΠΎΠ²Π°ΡΡΡΠΈ Π½Π° ΠΈΠ·ΠΎΠ±ΡΠ°ΠΆΠ΅Π½ΠΈΡΡΠ°. Π‘Π»Π΅Π΄ ΡΠΎΠ²Π° ΡΠ΅ ΡΡΠ·Π΄Π°Π²Π°Ρ one-hot Π²Π΅ΠΊΡΠΎΡΠΈ Ρ Π΅ΡΠΈΠΊΠ΅ΡΠΈ Π½Π° ΠΊΠ»Π°ΡΠΎΠ²Π΅ΡΠ΅, ΠΌΠ°ΡΠΈΠ²ΠΈΡΠ΅ ΡΡΡ ΡΡΠΎΠΉΠ½ΠΎΡΡΠΈ Π½Π° ΠΏΠΈΠΊΡΠ΅Π»ΠΈΡΠ΅ ΠΈ Ρ Π΅ΡΠΈΠΊΠ΅ΡΠΈΡΠ΅ ΡΠ΅ ΠΎΠ±Π΅Π΄ΠΈΠ½ΡΠ²Π°Ρ Π² ΡΠΏΠΈΡΡΠΊ, ΠΊΠΎΠΉΡΠΎ Π΅ Π²ΡΡΠ½Π°ΡΠ°ΡΠ° ΡΡΠΎΠΉΠ½ΠΎΡΡ. ΠΠ° ΡΡΠΊΠΎΡΠ΅Π½ΠΈΠ΅ Π½Π° ΡΠ°Π±ΠΎΡΠ°ΡΠ° Π±Π΅ΡΠ΅ ΠΈΠ·ΠΏΠΎΠ»Π·Π²Π°Π½ΠΎ ΡΡΠ·Π΄Π°Π²Π°Π½Π΅ΡΠΎ Π½Π° ΠΈΠ½Π΄Π΅ΠΊΡΠΈ Π² ΡΠ°Π±Π»ΠΈΡΠΈΡΠ΅ data.table ΠΈ ΠΌΠΎΠ΄ΠΈΡΠΈΠΊΠ°ΡΠΈΡΡΠ° ΠΏΠΎ ΡΠ΅ΡΠ΅ΡΠ΅Π½ΡΠΈΡ β Π±Π΅Π· ΡΠ΅Π·ΠΈ Β«ΡΡΠΈΠΊΠΎΠ²Π΅Β» Π½Π° ΠΏΠ°ΠΊΠ΅ΡΠ° data.table ΠΌΠ½ΠΎΠ³ΠΎ ΡΡΡΠ΄Π½ΠΎ ΡΠ΅ ΠΏΡΠ΅Π΄ΡΡΠ°Π²Ρ Π΅ΡΠ΅ΠΊΡΠΈΠ²Π½Π° ΡΠ°Π±ΠΎΡΠ° Ρ ΠΊΠ°ΠΊΠ²ΠΈΡΠΎ ΠΈ Π΄Π° Π΅ Π·Π½Π°ΡΠΈΡΠ΅Π»Π½ΠΈ ΠΎΠ±Π΅ΠΌΠΈ Π΄Π°Π½Π½ΠΈ Π² R.
Π Π΅Π·ΡΠ»ΡΠ°ΡΠΈΡΠ΅ ΠΎΡ ΠΈΠ·ΠΌΠ΅ΡΠ²Π°Π½ΠΈΡΡΠ° Π½Π° ΡΠΊΠΎΡΠΎΡΡΡΠ° Π½Π° ΡΠ°Π±ΠΎΡΠ° Π½Π° Π»Π°ΠΏΡΠΎΠΏΠ° Ρ 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
#
# 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. ΠΠ·Π±ΠΎΡ Π½Π° Π°ΡΡ ΠΈΡΠ΅ΠΊΡΡΡΠ° Π½Π° ΠΌΠΎΠ΄Π΅Π»Π°
ΠΡΡΠ²Π°ΡΠ° ΠΎΡ ΠΈΠ·ΠΏΠΎΠ»Π·Π²Π°Π½ΠΈΡΠ΅ Π°ΡΡ
ΠΈΡΠ΅ΠΊΡΡΡΠΈ Π±Π΅ΡΠ΅ , ΠΎΡΠΎΠ±Π΅Π½ΠΎΡΡΠΈΡΠ΅ Π½Π° ΠΊΠΎΡΡΠΎ ΡΠ° ΡΠ°Π·Π³Π»Π΅Π΄Π°Π½ΠΈ Π² ΡΡΠΎΠ±ΡΠ΅Π½ΠΈΠ΅ΡΠΎ. Π’Ρ ΠΏΡΠΈΡΡΡΡΠ²Π° Π² ΡΡΠ°Π½Π΄Π°ΡΡΠ½Π°ΡΠ° Π΄ΠΎΡΡΠ°Π²ΠΊΠ° keras ΠΈ ΡΡΠΎΡΠ²Π΅ΡΠ½ΠΎ Π΅ Π½Π°Π»ΠΈΡΠ½Π° Π² ΠΈΠ΄Π΅Π½ΡΠΈΡΠ½ΠΎΡΠΎ ΠΈΠΌΠ΅ ΠΏΠ°ΠΊΠ΅Ρ Π·Π° R. ΠΠΎ ΠΏΡΠΈ ΠΎΠΏΠΈΡ Π΄Π° Ρ ΠΈΠ·ΠΏΠΎΠ»Π·Π²Π°ΡΠ΅ Ρ Π΅Π΄Π½ΠΎΠΊΠ°Π½Π°Π»Π½ΠΈ ΠΈΠ·ΠΎΠ±ΡΠ°ΠΆΠ΅Π½ΠΈΡ, ΡΡΠ°Π½Π° ΡΡΡΠ°Π½Π½ΠΎ: Π²Ρ
ΠΎΠ΄Π½ΠΈΡΡ ΡΠ΅Π½Π·ΠΎΡ Π²ΠΈΠ½Π°Π³ΠΈ ΡΡΡΠ±Π²Π° Π΄Π° ΠΈΠΌΠ° ΡΠ°Π·ΠΌΠ΅Ρ (batch, height, width, 3), Ρ.Π΅. Π±ΡΠΎΠΉΡΠ΅ Π½Π° ΠΊΠ°Π½Π°Π»ΠΈΡΠ΅ Π½Π΅ ΠΌΠΎΠΆΠ΅ Π΄Π° ΡΠ΅ ΠΏΡΠΎΠΌΠ΅Π½Ρ. Π Python ΡΠ°ΠΊΠΎΠ²Π° ΠΎΠ³ΡΠ°Π½ΠΈΡΠ΅Π½ΠΈΠ΅ Π½ΡΠΌΠ°, Π·Π°ΡΠΎΠ²Π° ΠΏΠΎΠ±ΡΡΠ·Π°Ρ
ΠΌΠ΅ ΠΈ Π½Π°ΠΏΠΈΡΠ°Ρ
ΠΌΠ΅ ΡΠΎΠ±ΡΡΠ²Π΅Π½Π° ΡΠ΅Π°Π»ΠΈΠ·Π°ΡΠΈΡ Π½Π° Π°ΡΡ
ΠΈΡΠ΅ΠΊΡΡΡΠ°ΡΠ°, ΡΠ»Π΅Π΄Π²Π°ΠΉΠΊΠΈ ΠΎΡΠΈΠ³ΠΈΠ½Π°Π»Π½Π°ΡΠ° ΡΡΠ°ΡΠΈΡ (Π±Π΅Π· Π΄ΡΠΎΠΏΠ°ΡΡΠ°, ΠΊΠΎΠΉΡΠΎ ΡΡΡΠ΅ΡΡΠ²ΡΠ²Π° Π² Π²Π΅ΡΡΠΈΡΡΠ° Π½Π° keras):
ΠΡΡ ΠΈΡΠ΅ΠΊΡΡΡΠ° mobilenet v1
library(keras)
top_3_categorical_accuracy <- custom_metric(
name = "top_3_categorical_accuracy",
metric_fn = function(y_true, y_pred) {
metric_top_k_categorical_accuracy(y_true, y_pred, k = 3)
}
)
layer_sep_conv_bn %
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 %
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 % 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)Π‘Π΅Π³Π° Π½Π΅ Π΅ ΡΡΡΠ΄Π½ΠΎ Π΄Π° ΡΠ΅ Π½Π°ΠΏΠΈΡΠ΅ ΡΠ½ΠΈΠ²Π΅ΡΡΠ°Π»Π½Π° ΡΡΠ½ΠΊΡΠΈΡ Π·Π° ΠΏΠΎΠ»ΡΡΠ°Π²Π°Π½Π΅ Π½Π° Π²ΡΡΠΊΠ° ΠΎΡ Π΄ΠΎΡΡΠ°Π²Π΅Π½ΠΈΡΠ΅ Π² ΠΊΠΎΠΌΠΏΠ»Π΅ΠΊΡΠ° keras ΠΌΠΎΠ΄Π΅Π»ΠΈ Ρ ΠΎΠ±ΡΡΠ΅Π½ΠΈ Π½Π° 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("ΠΠΎΠ΄Π΅Π» ", shQuote(name), " Π½Π΅ Π΅ Π½Π°ΠΌΠ΅ΡΠ΅Π½.", 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(). ΠΠΈΠ΅ Π½Π΅ Π΄ΠΎΠ±Π°Π²ΠΈΡ
ΠΌΠ΅ ΡΠ°Π·ΠΈ ΡΡΠ½ΠΊΡΠΈΠΎΠ½Π°Π»Π½ΠΎΡΡ, ΡΡΠΉ ΠΊΠ°ΡΠΎ Π½Π° ΡΠΎΠ·ΠΈ Π΅ΡΠ°ΠΏ Π²Π΅ΡΠ΅ ΡΡΠ°Π½Π° ΡΡΠ½ΠΎ, ΡΠ΅ Π΅ ΠΏΠΎ-ΠΏΡΠΎΠ΄ΡΠΊΡΠΈΠ²Π½ΠΎ Π΄Π° ΡΠ°Π±ΠΎΡΠΈΠΌ Ρ ΡΠ²Π΅ΡΠ½ΠΈ ΠΈΠ·ΠΎΠ±ΡΠ°ΠΆΠ΅Π½ΠΈΡ.
ΠΡΠ½ΠΎΠ²Π½Π°ΡΠ° ΡΠ°ΡΡ ΠΎΡ Π΅ΠΊΡΠΏΠ΅ΡΠΈΠΌΠ΅Π½ΡΠΈΡΠ΅ ΠΏΡΠΎΠ²Π΅Π΄ΠΎΡ ΠΌΠ΅ Ρ mobilenet Π²Π΅ΡΡΠΈΡ 1 ΠΈ 2, ΠΊΠ°ΠΊΡΠΎ ΠΈ Ρ resnet34. Π ΡΠΎΠ²Π° ΡΡΡΡΠ΅Π·Π°Π½ΠΈΠ΅ Π΄ΠΎΠ±ΡΠ΅ ΡΠ΅ ΠΏΡΠ΅Π΄ΡΡΠ°Π²ΠΈΡ Π° ΠΏΠΎ-ΡΡΠ²ΡΠ΅ΠΌΠ΅Π½Π½ΠΈ Π°ΡΡ ΠΈΡΠ΅ΠΊΡΡΡΠΈ, ΠΊΠ°ΡΠΎ SE-ResNeXt. ΠΠ° ΡΡΠΆΠ°Π»Π΅Π½ΠΈΠ΅, Π½ΡΠΌΠ°Ρ ΠΌΠ΅ Π³ΠΎΡΠΎΠ²ΠΈ ΡΠ΅Π°Π»ΠΈΠ·Π°ΡΠΈΠΈ Π½Π° ΡΠ°Π·ΠΏΠΎΠ»ΠΎΠΆΠ΅Π½ΠΈΠ΅, Π° ΡΠΎΠ±ΡΡΠ²Π΅Π½ΠΈ Π½Π΅ Π½Π°ΠΏΠΈΡΠ°Ρ ΠΌΠ΅ (Π½ΠΎ ΠΎΠΏΡΠ΅Π΄Π΅Π»Π΅Π½ΠΎ ΡΠ΅ Π½Π°ΠΏΠΈΡΠ΅ΠΌ).
5. ΠΠ°ΡΠ°ΠΌΠ΅ΡΡΠΈΠ·ΠΈΡΠ°Π½Π΅ Π½Π° ΡΠΊΡΠΈΠΏΡΠΎΠ²Π΅
ΠΠ° ΡΠ΄ΠΎΠ±ΡΡΠ²ΠΎ ΡΠ΅Π»ΠΈΡΡ ΠΊΠΎΠ΄ Π·Π° ΡΡΠ°ΡΡΠΈΡΠ°Π½Π΅ Π½Π° ΠΎΠ±ΡΡΠ΅Π½ΠΈΠ΅ΡΠΎ Π΅ ΠΎΡΠΎΡΠΌΠ΅Π½ Π² Π΅Π΄ΠΈΠ½Π΅Π½ ΡΠΊΡΠΈΠΏΡ, ΠΏΠ°ΡΠ°ΠΌΠ΅ΡΡΠΈΠ·ΠΈΡΠ°Π½ Ρ ΠΏΠΎ ΡΠ»Π΅Π΄Π½ΠΈΡ Π½Π°ΡΠΈΠ½:
doc <- '
ΠΠ·ΠΏΠΎΠ»Π·Π²Π°Π½Π΅:
train_nn.R --help
train_nn.R --list-models
train_nn.R [options]
ΠΠΏΡΠΈΠΈ:
-h --help ΠΠΎΠΊΠ°ΠΆΠΈ ΡΠΎΠ²Π° ΡΡΠΎΠ±ΡΠ΅Π½ΠΈΠ΅.
-l --list-models ΠΠ·Π±ΡΠΎΠΈ Π½Π°Π»ΠΈΡΠ½ΠΈΡΠ΅ ΠΌΠΎΠ΄Π΅Π»ΠΈ.
-m --model= ΠΠΌΠ΅ Π½Π° ΠΌΠΎΠ΄Π΅Π»Π° Π½Π° Π½Π΅Π²ΡΠΎΠ½Π½Π° ΠΌΡΠ΅ΠΆΠ° [ΠΏΠΎ ΠΏΠΎΠ΄ΡΠ°Π·Π±ΠΈΡΠ°Π½Π΅: mobilenet_v2].
-b --batch-size= Π Π°Π·ΠΌΠ΅Ρ Π½Π° ΠΏΠ°ΡΡΠΈΠ΄Π°ΡΠ° [ΠΏΠΎ ΠΏΠΎΠ΄ΡΠ°Π·Π±ΠΈΡΠ°Π½Π΅: 32].
-s --scale-factor= Π€Π°ΠΊΡΠΎΡ Π½Π° ΠΌΠ°ΡΠ°Π±ΠΈΡΠ°Π½Π΅ [ΠΏΠΎ ΠΏΠΎΠ΄ΡΠ°Π·Π±ΠΈΡΠ°Π½Π΅: 0.5].
-c --color ΠΠ·ΠΏΠΎΠ»Π·Π²Π°ΠΉ ΡΠ²Π΅ΡΠ½ΠΈ Π»ΠΈΠ½ΠΈΠΈ [ΠΏΠΎ ΠΏΠΎΠ΄ΡΠ°Π·Π±ΠΈΡΠ°Π½Π΅: FALSE].
-d --db-dir= ΠΡΡ Π΄ΠΎ Π΄ΠΈΡΠ΅ΠΊΡΠΎΡΠΈΡΡΠ° Π½Π° Π±Π°Π·Π°ΡΠ° Π΄Π°Π½Π½ΠΈ [ΠΏΠΎ ΠΏΠΎΠ΄ΡΠ°Π·Π±ΠΈΡΠ°Π½Π΅: Sys.getenv("db_dir")].
-r --validate-ratio= Π‘ΡΠΎΡΠ½ΠΎΡΠ΅Π½ΠΈΠ΅ Π·Π° Π²Π°Π»ΠΈΠ΄ΠΈΡΠ°Π½Π΅ Π½Π° ΠΏΡΠΎΠ±Π°ΡΠ° [ΠΏΠΎ ΠΏΠΎΠ΄ΡΠ°Π·Π±ΠΈΡΠ°Π½Π΅: 0.995].
-n --n-gpu= ΠΡΠΎΠΉ GPU [ΠΏΠΎ ΠΏΠΎΠ΄ΡΠ°Π·Π±ΠΈΡΠ°Π½Π΅: 1].
'
args <- docopt::docopt(doc)ΠΠ°ΠΊΠ΅Ρ docopt ΠΏΡΠ΅Π΄ΡΡΠ°Π²Π»ΡΠ²Π° ΡΠ΅Π°Π»ΠΈΠ·Π°ΡΠΈΡ Π·Π° R. Π‘ Π½Π΅Π³ΠΎ ΡΠΊΡΠΈΠΏΡΠΎΠ²Π΅ΡΠ΅ ΡΠ΅ ΡΡΠ°ΡΡΠΈΡΠ°Ρ Ρ ΠΏΡΠΎΡΡΠΈ ΠΊΠΎΠΌΠ°Π½Π΄ΠΈ ΠΎΡ Π²ΠΈΠ΄Π° Rscript bin/train_nn.R -m resnet50 -c -d /home/andrey/doodle_db ΠΈΠ»ΠΈ ./bin/train_nn.R -m resnet50 -c -d /home/andrey/doodle_db, Π°ΠΊΠΎ ΡΠ°ΠΉΠ»ΡΡ train_nn.R Π΅ ΠΈΠ·ΠΏΡΠ»Π½ΡΠ΅ΠΌ (ΡΠ°Π·ΠΈ ΠΊΠΎΠΌΠ°Π½Π΄Π° ΡΠ΅ ΡΡΠ°ΡΡΠΈΡΠ° ΠΎΠ±ΡΡΠ΅Π½ΠΈΠ΅ΡΠΎ Π½Π° ΠΌΠΎΠ΄Π΅Π»Π° resnet50 Π½Π° ΡΠ²Π΅ΡΠ½ΠΈ ΠΈΠ·ΠΎΠ±ΡΠ°ΠΆΠ΅Π½ΠΈΡ Ρ ΡΠ°Π·ΠΌΠ΅ΡΠΈ 128Ρ
128 ΠΏΠΈΠΊΡΠ΅Π»Π°, Π±Π°Π·Π°ΡΠ° Π΄Π°Π½Π½ΠΈ ΡΡΡΠ±Π²Π° Π΄Π° ΡΠ΅ Π½Π°ΠΌΠΈΡΠ° Π² ΠΏΠ°ΠΏΠΊΠ° /home/andrey/doodle_db). Π ΡΠΏΠΈΡΡΠΊΠ° ΠΌΠΎΠ³Π°Ρ Π΄Π° ΡΠ΅ Π΄ΠΎΠ±Π°Π²ΡΡ ΡΠΊΠΎΡΠΎΡΡ Π½Π° ΠΎΠ±ΡΡΠ΅Π½ΠΈΠ΅, Π²ΠΈΠ΄ ΠΎΠΏΡΠΈΠΌΠΈΠ·Π°ΡΠΎΡ ΠΈ Π²ΡΡΠΊΠ°ΠΊΠ²ΠΈ Π΄ΡΡΠ³ΠΈ ΠΏΠ°ΡΠ°ΠΌΠ΅ΡΡΠΈ Π·Π° Π½Π°ΡΡΡΠΎΠΉΠΊΠ°. Π ΠΏΡΠΎΡΠ΅ΡΠ° Π½Π° ΠΏΠΎΠ΄Π³ΠΎΡΠΎΠ²ΠΊΠ° Π½Π° ΠΏΡΠ±Π»ΠΈΠΊΠ°ΡΠΈΡΡΠ° ΡΡΠ°Π½Π° ΡΡΠ½ΠΎ, ΡΠ΅ Π°ΡΡ
ΠΈΡΠ΅ΠΊΡΡΡΠ°ΡΠ° mobilenet_v2 ΠΎΡ Π°ΠΊΡΡΠ°Π»Π½Π°ΡΠ° Π²Π΅ΡΡΠΈΡ keras Π² R ΡΠ΅ ΠΈΠ·ΠΏΠΎΠ»Π·Π²Π° Π·Π°ΡΠ°Π΄ΠΈ Π½Π΅ΠΎΡΡΠ΅ΡΠ΅Π½ΠΈ ΠΏΡΠΎΠΌΠ΅Π½ΠΈ Π² R-ΠΏΠ°ΠΊΠ΅ΡΠ° β ΡΠ°ΠΊΠ°ΠΌΠ΅, Π΄ΠΎΠΊΠ°ΡΠΎ Π³ΠΎ ΠΏΠΎΠΏΡΠ°Π²ΡΡ.
Π’ΠΎΠ·ΠΈ ΠΏΠΎΠ΄Ρ ΠΎΠ΄ ΠΏΠΎΠ·Π²ΠΎΠ»ΠΈ Π·Π½Π°ΡΠΈΡΠ΅Π»Π½ΠΎ ΡΡΠΊΠΎΡΡΠ²Π°Π½Π΅ Π½Π° Π΅ΠΊΡΠΏΠ΅ΡΠΈΠΌΠ΅Π½ΡΠΈΡΠ΅ Ρ ΡΠ°Π·Π»ΠΈΡΠ½ΠΈ ΠΌΠΎΠ΄Π΅Π»ΠΈ Π² ΡΡΠ°Π²Π½Π΅Π½ΠΈΠ΅ Ρ ΠΏΠΎ-ΡΡΠ°Π΄ΠΈΡΠΈΠΎΠ½Π½ΠΎΡΠΎ ΡΡΠ°ΡΡΠΈΡΠ°Π½Π΅ Π½Π° ΡΠΊΡΠΈΠΏΡΠΎΠ²Π΅ Π² RStudio (ΠΊΠ°ΡΠΎ Π°Π»ΡΠ΅ΡΠ½Π°ΡΠΈΠ²Π° ΠΌΠΎΠΆΠ΅ΠΌ Π΄Π° ΠΎΡΠ±Π΅Π»Π΅ΠΆΠΈΠΌ ΠΏΠ°ΠΊΠ΅ΡΠ° ). ΠΠΎ ΠΎΡΠ½ΠΎΠ²Π½ΠΎΡΠΎ ΠΏΡΠ΅Π΄ΠΈΠΌΡΡΠ²ΠΎ Π΅ Π²ΡΠ·ΠΌΠΎΠΆΠ½ΠΎΡΡΡΠ° Π»Π΅ΡΠ½ΠΎ Π΄Π° ΡΠΏΡΠ°Π²Π»ΡΠ²Π°ΡΠ΅ ΡΡΠ°ΡΡΠΈΡΠ°Π½Π΅ΡΠΎ Π½Π° ΡΠΊΡΠΈΠΏΡΠΎΠ²Π΅ Π² Docker ΠΈΠ»ΠΈ ΠΏΡΠΎΡΡΠΎ Π½Π° ΡΡΡΠ²ΡΡ, Π±Π΅Π· Π΄Π° ΠΈΠ½ΡΡΠ°Π»ΠΈΡΠ°ΡΠ΅ RStudio Π·Π° ΡΠΎΠ²Π°.
6. ΠΠΎΠΊΠ΅ΡΠΈΠ·Π°ΡΠΈΡ Π½Π° ΡΠΊΡΠΈΠΏΡΠΎΠ²Π΅
ΠΠ·ΠΏΠΎΠ»Π·Π²Π°Ρ ΠΌΠ΅ Docker Ρ ΡΠ΅Π» Π΄Π° ΠΎΡΠΈΠ³ΡΡΠΈΠΌ ΠΏΡΠ΅Π½ΠΎΡΠΈΠΌΠΎΡΡ Π½Π° ΡΡΠ΅Π΄Π°ΡΠ° Π·Π° ΠΎΠ±ΡΡΠ΅Π½ΠΈΠ΅ Π½Π° ΠΌΠΎΠ΄Π΅Π»ΠΈΡΠ΅ ΠΌΠ΅ΠΆΠ΄Ρ ΡΠ»Π΅Π½ΠΎΠ²Π΅ΡΠ΅ Π½Π° Π΅ΠΊΠΈΠΏΠ° ΠΈ Π·Π° Π±ΡΡΠ·ΠΎ ΡΠ°Π·Π³ΡΠ²Π°Π½Π΅ Π² ΠΎΠ±Π»Π°ΠΊΠ°. ΠΠΎΠΆΠ΅ΡΠ΅ Π΄Π° Π·Π°ΠΏΠΎΡΠ½Π΅ΡΠ΅ ΡΠ²ΠΎΡΡΠ° ΠΏΠΎΠ΄Π³ΠΎΡΠΎΠ²ΠΊΠ° Ρ ΡΠ°Π·ΠΈ ΠΎΡΠ½ΠΎΡΠΈΡΠ΅Π»Π½ΠΎ Π½Π΅ΠΎΠ±ΠΈΡΠ°ΠΉΠ½Π° Π·Π° R-ΠΏΡΠΎΠ³ΡΠ°ΠΌΠΈΡΡ ΠΈΠ½ΡΡΡΡΠΌΠ΅Π½Ρ ΠΎΡ ΡΠ΅ΡΠΈΡ ΠΏΡΠ±Π»ΠΈΠΊΠ°ΡΠΈΠΈ ΠΈΠ»ΠΈ ΠΎΡ .
Docker ΠΏΠΎΠ·Π²ΠΎΠ»ΡΠ²Π° ΠΊΠ°ΠΊΡΠΎ Π΄Π° ΡΡΠ·Π΄Π°Π²Π°ΡΠ΅ ΡΠΎΠ±ΡΡΠ²Π΅Π½ΠΈ ΠΎΠ±ΡΠ°Π·ΠΈ "ΠΎΡ Π½ΡΠ»Π°ΡΠ°", ΡΠ°ΠΊΠ° ΠΈ Π΄Π° ΠΈΠ·ΠΏΠΎΠ»Π·Π²Π°ΡΠ΅ Π΄ΡΡΠ³ΠΈ ΠΎΠ±ΡΠ°Π·ΠΈ ΠΊΠ°ΡΠΎ ΠΎΡΠ½ΠΎΠ²Π° Π·Π° ΡΡΠ·Π΄Π°Π²Π°Π½Π΅ Π½Π° ΡΠΎΠ±ΡΡΠ²Π΅Π½ΠΈ. ΠΡΠΈ Π°Π½Π°Π»ΠΈΠ·Π° Π½Π° Π½Π°Π»ΠΈΡΠ½ΠΈΡΠ΅ Π²Π°ΡΠΈΠ°Π½ΡΠΈ ΡΡΠΈΠ³Π½Π°Ρ
ΠΌΠ΅ Π΄ΠΎ ΠΈΠ·Π²ΠΎΠ΄Π°, ΡΠ΅ ΠΈΠ½ΡΡΠ°Π»ΠΈΡΠ°Π½Π΅ΡΠΎ Π½Π° Π΄ΡΠ°ΠΉΠ²Π΅ΡΠΈ NVIDIA, CUDA+cuDNN ΠΈ Python Π±ΠΈΠ±Π»ΠΈΠΎΡΠ΅ΠΊΠΈ Π΅ Π΄ΠΎΡΡΠ° ΠΎΠ±Π΅ΠΌΠ½Π° ΡΠ°ΡΡ ΠΎΡ ΠΎΠ±ΡΠ°Π·Π° ΠΈ ΡΠ΅ΡΠΈΡ
ΠΌΠ΅ Π΄Π° Π²Π·Π΅ΠΌΠ΅ΠΌ Π·Π° ΠΎΡΠ½ΠΎΠ²Π° ΠΎΡΠΈΡΠΈΠ°Π»Π½ΠΈΡ ΠΎΠ±ΡΠ°Π·. tensorflow/tensorflow:1.12.0-gpu, Π΄ΠΎΠ±Π°Π²ΡΠΉΠΊΠΈ Π½Π΅ΠΎΠ±Ρ
ΠΎΠ΄ΠΈΠΌΠΈΡΠ΅ R ΠΏΠ°ΠΊΠ΅ΡΠΈ.
ΠΡΠ°ΠΉΠ½ΠΈΡΡ Docker ΡΠ°ΠΉΠ» ΠΈΠ·Π³Π»Π΅ΠΆΠ΄Π° ΡΠ°ΠΊΠ°:
Dockerfile
FROM tensorflow/tensorflow:1.12.0-gpu
MAINTAINER Artem Klevtsov
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. Π’ΠΎΠ²Π° ΠΏΠΎΠ·Π²ΠΎΠ»ΠΈ Π΄Π° ΡΠ΅ ΠΈΠ·Π±Π΅Π³Π½Π΅ Π½Π΅ΠΎΠ±Ρ
ΠΎΠ΄ΠΈΠΌΠΎΡΡΡΠ° ΠΎΡ ΡΠΊΠ°Π·Π²Π°Π½Π΅ Π½Π° Π²Π΅ΡΡΠΈΡ Π½Π° ΠΠ‘ Π² ΠΊΠΎΠ΄Π°.
ΠΠΎΠΏΡΠ»Π½ΠΈΡΠ΅Π»Π½ΠΎ Π±Π΅ΡΠ΅ Π½Π°ΠΏΠΈΡΠ°Π½ ΠΌΠ°Π»ΡΠΊ bash ΡΠΊΡΠΈΠΏΡ, ΠΊΠΎΠΉΡΠΎ ΠΏΠΎΠ·Π²ΠΎΠ»ΡΠ²Π° ΡΡΠ°ΡΡΠΈΡΠ°Π½Π΅ Π½Π° ΠΊΠΎΠ½ΡΠ΅ΠΉΠ½Π΅ΡΠ° Ρ ΡΠ°Π·Π»ΠΈΡΠ½ΠΈ ΠΊΠΎΠΌΠ°Π½Π΄ΠΈ. ΠΠ°ΠΏΡΠΈΠΌΠ΅Ρ, ΡΠΎΠ²Π° ΠΌΠΎΠ³Π°Ρ Π΄Π° Π±ΡΠ΄Π°Ρ ΡΠΊΡΠΈΠΏΡΠΎΠ²Π΅ Π·Π° ΠΎΠ±ΡΡΠ΅Π½ΠΈΠ΅ Π½Π° Π½Π΅Π²ΡΠΎΠ½Π½ΠΈ ΠΌΡΠ΅ΠΆΠΈ, ΠΊΠΎΠΈΡΠΎ ΡΠ° Π±ΠΈΠ»ΠΈ ΠΏΡΠ΅Π΄Π²Π°ΡΠΈΡΠ΅Π»Π½ΠΎ ΠΏΠΎΡΡΠ°Π²Π΅Π½ΠΈ Π² ΠΊΠΎΠ½ΡΠ΅ΠΉΠ½Π΅ΡΠ°, ΠΈΠ»ΠΈ ΠΊΠΎΠΌΠ°Π½Π΄Π½Π°ΡΠ° ΠΎΠ±Π²ΠΈΠ²ΠΊΠ° Π·Π° ΠΎΡΡΡΡΠ°Π½ΡΠ²Π°Π½Π΅ Π½Π° Π³ΡΠ΅ΡΠΊΠΈ ΠΈ ΠΌΠΎΠ½ΠΈΡΠΎΡΠΈΠ½Π³ Π½Π° ΡΠ°Π±ΠΎΡΠ°ΡΠ° Π½Π° ΠΊΠΎΠ½ΡΠ΅ΠΉΠ½Π΅ΡΠ°:
Π‘ΠΊΡΠΈΠΏΡ Π·Π° ΡΡΠ°ΡΡΠΈΡΠ°Π½Π΅ Π½Π° ΠΊΠΎΠ½ΡΠ΅ΠΉΠ½Π΅ΡΠ°
#!/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}ΠΠΊΠΎ ΡΠΎΠ·ΠΈ bash ΡΠΊΡΠΈΠΏΡ Π±ΡΠ΄Π΅ ΡΡΠ°ΡΡΠΈΡΠ°Π½ Π±Π΅Π· ΠΏΠ°ΡΠ°ΠΌΠ΅ΡΡΠΈ, Π² ΠΊΠΎΠ½ΡΠ΅ΠΉΠ½Π΅ΡΠ° ΡΠ΅ ΡΠ΅ ΠΈΠ·Π²ΠΈΠΊΠ° ΡΠΊΡΠΈΠΏΡ train_nn.R Ρ ΠΏΠΎΠ΄ΡΠ°Π·Π±ΠΈΡΠ°ΡΠΈ ΡΠ΅ ΡΡΠΎΠΉΠ½ΠΎΡΡΠΈ; Π°ΠΊΠΎ ΠΏΡΡΠ²ΠΈΡΡ ΠΏΠΎΠ·ΠΈΡΠΈΠΎΠ½Π΅Π½ Π°ΡΠ³ΡΠΌΠ΅Π½Ρ Π΅ "bash", ΠΊΠΎΠ½ΡΠ΅ΠΉΠ½Π΅ΡΡΡ ΡΠ΅ ΡΡΠ°ΡΡΠΈΡΠ° Π² ΠΈΠ½ΡΠ΅ΡΠ°ΠΊΡΠΈΠ²Π΅Π½ ΡΠ΅ΠΆΠΈΠΌ Ρ ΠΊΠΎΠΌΠ°Π½Π΄Π΅Π½ ΠΈΠ½ΡΠ΅ΡΠΏΡΠ΅ΡΠ°ΡΠΎΡ. ΠΡΠ² Π²ΡΠΈΡΠΊΠΈ ΠΎΡΡΠ°Π½Π°Π»ΠΈ ΡΠ»ΡΡΠ°ΠΈ ΡΠ΅ ΡΠ΅ ΠΈΠ·Π²ΡΡΡΠΈ ΠΏΠΎΠ΄ΠΌΡΠ½Π° Π½Π° ΡΡΠΎΠΉΠ½ΠΎΡΡΠΈΡΠ΅ Π½Π° ΠΏΠΎΠ·ΠΈΡΠΈΠΎΠ½Π½ΠΈΡΠ΅ Π°ΡΠ³ΡΠΌΠ΅Π½ΡΠΈ: CMD="Rscript /app/train_nn.R $@".
ΠΠ°ΠΆΠ½ΠΎ Π΅ Π΄Π° ΡΠ΅ ΠΎΡΠ±Π΅Π»Π΅ΠΆΠΈ, ΡΠ΅ Π΄ΠΈΡΠ΅ΠΊΡΠΎΡΠΈΠΈΡΠ΅ Ρ Π²Ρ ΠΎΠ΄ΡΡΠΈΡΠ΅ Π΄Π°Π½Π½ΠΈ ΠΈ Π±Π°Π·Π°ΡΠ° Π΄Π°Π½Π½ΠΈ, ΠΊΠ°ΠΊΡΠΎ ΠΈ Π΄ΠΈΡΠ΅ΠΊΡΠΎΡΠΈΡΡΠ° Π·Π° Π·Π°ΠΏΠ°Π·Π²Π°Π½Π΅ Π½Π° ΠΎΠ±ΡΡΠ΅Π½ΠΈΡΠ΅ ΠΌΠΎΠ΄Π΅Π»ΠΈ, ΡΠ΅ ΠΌΠΎΠ½ΡΠΈΡΠ°Ρ Π²ΡΡΡΠ΅ Π² ΠΊΠΎΠ½ΡΠ΅ΠΉΠ½Π΅ΡΠ° ΠΎΡ Ρ ΠΎΡΡ ΡΠΈΡΡΠ΅ΠΌΠ°ΡΠ°, ΠΊΠΎΠ΅ΡΠΎ ΠΏΠΎΠ·Π²ΠΎΠ»ΡΠ²Π° Π΄ΠΎΡΡΡΠΏ Π΄ΠΎ ΡΠ΅Π·ΡΠ»ΡΠ°ΡΠΈΡΠ΅ ΠΎΡ ΡΠ°Π±ΠΎΡΠ°ΡΠ° Π½Π° ΡΠΊΡΠΈΠΏΡΠΎΠ²Π΅ΡΠ΅ Π±Π΅Π· ΠΈΠ·Π»ΠΈΡΠ½ΠΈ ΠΌΠ°Π½ΠΈΠΏΡΠ»Π°ΡΠΈΠΈ.
7. ΠΠ·ΠΏΠΎΠ»Π·Π²Π°Π½Π΅ Π½Π° Π½ΡΠΊΠΎΠ»ΠΊΠΎ GPU Π² Google Cloud
ΠΠ΄Π½Π° ΠΎΡ Ρ
Π°ΡΠ°ΠΊΡΠ΅ΡΠ½ΠΈΡΠ΅ ΡΠ΅ΡΡΠΈ Π½Π° ΡΡΡΡΠ΅Π·Π°Π½ΠΈΠ΅ΡΠΎ Π±ΡΡ
Π° ΠΌΠ½ΠΎΠ³ΠΎ ΡΡΠΌΠ½ΠΈ Π΄Π°Π½Π½ΠΈ (Π²ΠΆ. Π·Π°Π³Π»Π°Π²Π½Π°ΡΠ° ΠΊΠ°ΡΡΠΈΠ½ΠΊΠ°, ΠΏΡΠ΅Π΄ΠΎΡΡΠ°Π²Π΅Π½Π° ΠΎΡ @Leigh.plt ΠΎΡ ODS Slack). ΠΠ° ΡΠΏΡΠ°Π²ΡΠ½Π΅ Ρ ΡΠΎΠ²Π°, Π³ΠΎΠ»ΡΠΌΠΈΡΠ΅ ΠΏΠ°ΡΡΠΈΠ΄ΠΈ ΠΏΠΎΠΌΠ°Π³Π°Ρ, ΠΈ ΡΠ»Π΅Π΄ Π΅ΠΊΡΠΏΠ΅ΡΠΈΠΌΠ΅Π½ΡΠΈ Π½Π° ΠΊΠΎΠΌΠΏΡΡΡΡ Ρ 1 GPU ΡΠ΅ΡΠΈΡ
ΠΌΠ΅ Π΄Π° ΠΎΡΠ²ΠΎΠΈΠΌ ΠΎΠ±ΡΡΠ΅Π½ΠΈΠ΅ΡΠΎ Π½Π° ΠΌΠΎΠ΄Π΅Π»ΠΈ Π½Π° Π½ΡΠΊΠΎΠ»ΠΊΠΎ GPU Π² ΠΎΠ±Π»Π°ΠΊΠ°. ΠΠ·ΠΏΠΎΠ»Π·Π²Π°Ρ
ΠΌΠ΅ Google Cloud () Π·Π°ΡΠ°Π΄ΠΈ Π³ΠΎΠ»ΡΠΌΠΎΡΠΎ ΡΠ°Π·Π½ΠΎΠΎΠ±ΡΠ°Π·ΠΈΠ΅ ΠΎΡ Π΄ΠΎΡΡΡΠΏΠ½ΠΈ ΠΊΠΎΠ½ΡΠΈΠ³ΡΡΠ°ΡΠΈΠΈ, ΠΏΡΠΈΠ΅ΠΌΠ»ΠΈΠ²ΠΈ ΡΠ΅Π½ΠΈ ΠΈ Π±ΠΎΠ½ΡΡ ΠΎΡ $300. ΠΡ Π½Π΅Π½Π°ΡΠΈΡΠ½ΠΎΡΡ ΠΏΠΎΡΡΡΠ°Ρ
ΠΌΠ΅ ΠΈΠ½ΡΡΠ°Π½ΡΠΈΡ Ρ 4xV100 Ρ SSD ΠΈ ΠΌΠ½ΠΎΠ³ΠΎ RAM, ΠΈ ΡΠΎΠ²Π° ΡΠ΅ ΠΎΠΊΠ°Π·Π° Π³ΠΎΠ»ΡΠΌΠ° Π³ΡΠ΅ΡΠΊΠ°. ΠΠ°ΡΠΈ ΡΠ°ΠΊΠ°Π²Π° ΠΌΠ°ΡΠΈΠ½Π° ΡΠ΄Π΅ Π±ΡΡΠ·ΠΎ, ΠΏΡΠΈ Π΅ΠΊΡΠΏΠ΅ΡΠΈΠΌΠ΅Π½ΡΠΈ Π±Π΅Π· ΡΡΡΠ°Π½ΠΎΠ²Π΅Π½ ΠΏΠΎΡΠΎΠΊ ΡΠ΅ ΠΌΠΎΠΆΠ΅ Π΄Π° ΡΠ΅ ΡΠ°Π·ΠΎΡΠΈΡΠ΅. ΠΠ° ΡΡΠ΅Π±Π½ΠΈ ΡΠ΅Π»ΠΈ Π΅ ΠΏΠΎ-Π΄ΠΎΠ±ΡΠ΅ Π΄Π° Π²Π·Π΅ΠΌΠ΅ΡΠ΅ K80. ΠΠΎ Π³ΠΎΠ»ΡΠΌΠΎΡΠΎ ΠΊΠΎΠ»ΠΈΡΠ΅ΡΡΠ²ΠΎ RAM Π±Π΅ΡΠ΅ ΠΏΠΎΠ»Π΅Π·Π½ΠΎ - ΠΎΠ±Π»Π°ΡΠ½ΠΈΡΡ SSD Π½Π΅ Π²ΠΏΠ΅ΡΠ°ΡΠ»ΠΈ Ρ Π±ΡΡΠ·ΠΎΠ΄Π΅ΠΉΡΡΠ²ΠΈΠ΅ΡΠΎ ΡΠΈ, Π·Π°ΡΠΎΠ²Π° Π±Π°Π·Π°ΡΠ° Π΄Π°Π½Π½ΠΈ ΠΏΡΠΈ Π²ΡΡΠΊΠΎ ΡΡΠ°ΡΡΠΈΡΠ°Π½Π΅ Π½Π° ΠΈΠ½ΡΡΠ°Π½ΡΠΈΡΡΠ° ΡΠ΅ ΠΏΡΠ΅Π½ΠΎΡΠ΅ΡΠ΅ Π½Π° dev/shm.
ΠΠ°ΠΉ-ΠΈΠ½ΡΠ΅ΡΠ΅ΡΠ΅Π½ Π΅ ΡΡΠ°Π³ΠΌΠ΅Π½ΡΡΡ ΠΎΡ ΠΊΠΎΠ΄Π°, ΠΎΡΠ³ΠΎΠ²ΠΎΡΠ΅Π½ Π·Π° ΠΈΠ·ΠΏΠΎΠ»Π·Π²Π°Π½Π΅ΡΠΎ Π½Π° Π½ΡΠΊΠΎΠ»ΠΊΠΎ GPU. ΠΡΡΠ²ΠΎ ΠΌΠΎΠ΄Π΅Π»ΡΡ ΡΠ΅ ΡΡΠ·Π΄Π°Π²Π° Π½Π° CPU Ρ ΠΏΠΎΠΌΠΎΡΡΠ° Π½Π° ΠΌΠ΅Π½ΠΈΠ΄ΠΆΡΡ Π½Π° ΠΊΠΎΠ½ΡΠ΅ΠΊΡΡΠ°, ΡΠΎΡΠ½ΠΎ ΠΊΠ°ΠΊΡΠΎ Π½Π° 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
)
})Π‘Π»Π΅Π΄ ΡΠΎΠ²Π° Π½Π΅ΡΡΠ±ΡΠ°Π½ (ΡΠΎΠ²Π° Π΅ Π²Π°ΠΆΠ½ΠΎ) ΠΌΠΎΠ΄Π΅Π»ΡΡ ΡΠ΅ ΠΊΠΎΠΏΠΈΡΠ° Π½Π° Π·Π°Π΄Π°Π΄Π΅Π½ΠΎΡΠΎ ΠΊΠΎΠ»ΠΈΡΠ΅ΡΡΠ²ΠΎ Π½Π°Π»ΠΈΡΠ½ΠΈ 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)
)ΠΠ»Π°ΡΠΈΡΠ΅ΡΠΊΠ°ΡΠ° ΠΏΡΠ°ΠΊΡΠΈΠΊΠ° Ρ Π·Π°ΠΌΡΠ°Π·ΡΠ²Π°Π½Π΅ Π½Π° Π²ΡΠΈΡΠΊΠΈ ΡΠ»ΠΎΠ΅Π²Π΅, ΠΎΡΠ²Π΅Π½ ΠΏΠΎΡΠ»Π΅Π΄Π½ΠΈΡ, ΠΎΠ±ΡΡΠ°Π²Π°Π½Π΅ Π½Π° ΠΏΠΎΡΠ»Π΅Π΄Π½ΠΈΡ ΡΠ»ΠΎΠΉ, ΡΠ°Π·ΠΌΡΠ°Π·ΡΠ²Π°Π½Π΅ ΠΈ Π΄ΠΎΠΎΠ±ΡΡΠ°Π²Π°Π½Π΅ Π½Π° ΠΌΠΎΠ΄Π΅Π»Π° ΠΈΠ·ΡΡΠ»ΠΎ Π·Π° Π½ΡΠΊΠΎΠ»ΠΊΠΎ GPU Π½Π΅ ΡΡΠΏΡ Π΄Π° ΡΠ΅Π°Π»ΠΈΠ·ΠΈΡΠ°.
Π‘Π»Π΅Π΄Π΅Π½Π΅ΡΠΎ Π½Π° ΠΎΠ±ΡΡΠ΅Π½ΠΈΠ΅ΡΠΎ ΡΠ΅ ΠΈΠ·Π²ΡΡΡΠ²Π°ΡΠ΅ Π±Π΅Π· ΠΈΠ·ΠΏΠΎΠ»Π·Π²Π°Π½Π΅ΡΠΎ Π½Π° tensorboard, ΠΎΠ³ΡΠ°Π½ΠΈΡΠ°Π²Π°ΠΉΠΊΠΈ ΡΠ΅ Π΄ΠΎ Π·Π°ΠΏΠΈΡ Π½Π° Π»ΠΎΠ³ΠΎΠ²Π΅ ΠΈ Π·Π°ΠΏΠ°Π·Π²Π°Π½Π΅ Π½Π° ΠΌΠΎΠ΄Π΅Π»ΠΈ Ρ ΠΈΠ½ΡΠΎΡΠΌΠ°ΡΠΈΠ²Π½ΠΈ ΠΈΠΌΠ΅Π½Π° ΡΠ»Π΅Π΄ Π²ΡΡΠΊΠ° Π΅ΠΏΠΎΡ Π°:
ΠΠΎΠ»Π±Π΅ΠΊΠΈ
# Π¨Π°Π±Π»ΠΎΠ½ ΠΈΠΌΠ΅Π½ΠΈ ΡΠ°ΠΉΠ»Π° Π»ΠΎΠ³Π°
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Π² Π±ΠΈΠ±Π»ΠΈΠΎΡΠ΅ΠΊΠ΅ fast.ai); ΠΏΡΠΈΠ»ΠΎΠΆΠΈΡ ΠΌΠ΅ ΡΡΠΈΠ»ΠΈΡ, Π·Π° Π΄Π° ΠΏΡΠ΅Π½ΠΎΡΠΈΠΌ Π½Π° R Π²ΡΠ½ΡΠ½ΠΈ ΡΠ΅Π°Π»ΠΈΠ·Π°ΡΠΈΠΈ, Π½Π°ΠΏΡΠΈΠΌΠ΅Ρ, ; - ΠΊΠ°ΡΠΎ ΡΠ»Π΅Π΄ΡΡΠ²ΠΈΠ΅ ΠΎΡ ΠΏΡΠ΅Π΄Ρ ΠΎΠ΄Π½Π°ΡΠ° ΡΠΎΡΠΊΠ°, Π½Π΅ ΡΡΠΏΡΡ ΠΌΠ΅ Π΄Π° ΠΏΠΎΠ΄Π±Π΅ΡΠ΅ΠΌ ΠΏΡΠ°Π²ΠΈΠ»Π½Π°ΡΠ° ΡΠΊΠΎΡΠΎΡΡ Π½Π° ΠΎΠ±ΡΡΠ΅Π½ΠΈΠ΅ ΠΏΡΠΈ ΠΈΠ·ΠΏΠΎΠ»Π·Π²Π°Π½Π΅ Π½Π° Π½ΡΠΊΠΎΠ»ΠΊΠΎ GPU;
- Π»ΠΈΠΏΡΠ²Π°Ρ ΡΡΠ²ΡΠ΅ΠΌΠ΅Π½Π½ΠΈ Π°ΡΡ ΠΈΡΠ΅ΠΊΡΡΡΠΈ Π½Π° Π½Π΅Π²ΡΠΎΠ½Π½ΠΈΡΠ΅ ΠΌΡΠ΅ΠΆΠΈ, ΠΎΡΠΎΠ±Π΅Π½ΠΎ ΠΏΡΠ΅Π΄Π²Π°ΡΠΈΡΠ΅Π»Π½ΠΎ ΠΎΠ±ΡΡΠ΅Π½ΠΈ Π½Π° imagenet;
- Π½ΡΠΌΠ° one cycle policy ΠΈ Π΄ΠΈΡΠΊΡΠ΅ΡΠ½ΠΈ ΡΠΊΠΎΡΠΎΡΡΠΈ Π½Π° ΠΎΠ±ΡΡΠ΅Π½ΠΈΠ΅ (cosine annealing ΠΏΠΎ Π½Π°ΡΠ°ΡΠ° ΠΌΠΎΠ»Π±Π° Π±Π΅ΡΠ΅ , Π±Π»Π°Π³ΠΎΠ΄Π°ΡΡ ).
ΠΠ°ΠΊΠ²ΠΎ ΠΏΠΎΠ»Π΅Π·Π½ΠΎ ΡΡΠΏΡΡ ΠΌΠ΅ Π΄Π° ΠΈΠ·Π²Π»Π΅ΡΠ΅ΠΌ ΠΎΡ ΡΠΎΠ²Π° ΡΡΡΡΠ΅Π·Π°Π½ΠΈΠ΅:
- ΠΠ° ΡΡΠ°Π²Π½ΠΈΡΠ΅Π»Π½ΠΎ ΡΠ»Π°Π± Ρ Π°ΡΠ΄ΡΠ΅Ρ ΠΌΠΎΠΆΠ΅ Π±Π΅Π· ΡΡΡΠ΄Π½ΠΎΡΡΠΈ Π΄Π° ΡΠ΅ ΡΠ°Π±ΠΎΡΠΈ Ρ ΠΏΡΠΈΠ»ΠΈΡΠ½ΠΈ (ΠΌΠ½ΠΎΠ³ΠΎΠΊΡΠ°ΡΠ½ΠΎ ΠΏΡΠ΅Π²ΠΈΡΠ°Π²Π°ΡΠΈ ΡΠ°Π·ΠΌΠ΅ΡΠ° Π½Π° RAM) ΠΎΠ±Π΅ΠΌΠΈ Π΄Π°Π½Π½ΠΈ. ΠΠ°ΠΊΠ΅ΡΡΡ data.table Π΅ΠΊΠΎΠ½ΠΎΠΌΠΈΡΠ²Π° ΠΏΠ°ΠΌΠ΅Ρ ΡΡΠ΅Π· in-place ΠΌΠΎΠ΄ΠΈΡΠΈΠΊΠ°ΡΠΈΡ Π½Π° ΡΠ°Π±Π»ΠΈΡΠΈΡΠ΅, ΠΊΠΎΠ΅ΡΠΎ ΠΏΠΎΠ·Π²ΠΎΠ»ΡΠ²Π° Π΄Π° ΡΠ΅ ΠΈΠ·Π±Π΅Π³Π½Π΅ ΠΊΠΎΠΏΠΈΡΠ°Π½Π΅ΡΠΎ ΠΈΠΌ, ΠΈ ΠΏΡΠΈ ΠΏΡΠ°Π²ΠΈΠ»Π½ΠΎ ΠΈΠ·ΠΏΠΎΠ»Π·Π²Π°Π½Π΅ Π½Π° Π½Π΅Π³ΠΎΠ²ΠΈΡΠ΅ Π²ΡΠ·ΠΌΠΎΠΆΠ½ΠΎΡΡΠΈ ΠΏΠΎΡΡΠΈ Π²ΠΈΠ½Π°Π³ΠΈ Π΄Π΅ΠΌΠΎΠ½ΡΡΡΠΈΡΠ° Π½Π°ΠΉ-Π²ΠΈΡΠΎΠΊΠ° ΡΠΊΠΎΡΠΎΡΡ ΡΡΠ΅Π΄ Π²ΡΠΈΡΠΊΠΈ ΠΈΠ·Π²Π΅ΡΡΠ½ΠΈ Π½Π° Π½Π°Ρ ΠΈΠ½ΡΡΡΡΠΌΠ΅Π½ΡΠΈ Π·Π° ΡΠΊΡΠΈΠΏΡΠΎΠ²ΠΈ Π΅Π·ΠΈΡΠΈ. ΠΠ°ΠΏΠ°Π·Π²Π°Π½Π΅ΡΠΎ Π½Π° Π΄Π°Π½Π½ΠΈ Π² ΠΠ ΠΏΠΎΠ·Π²ΠΎΠ»ΡΠ²Π° Π² ΠΌΠ½ΠΎΠ³ΠΎ ΡΠ»ΡΡΠ°ΠΈ ΠΈΠ·ΠΎΠ±ΡΠΎ Π΄Π° Π½Π΅ ΡΠ΅ ΠΌΠΈΡΠ»ΠΈ Π·Π° Π½Π΅ΠΎΠ±Ρ ΠΎΠ΄ΠΈΠΌΠΎΡΡΡΠ° Π΄Π° ΡΠ΅ Π²ΠΌΠ΅ΡΡΠ²Π° ΡΠ΅Π»ΠΈΡ dataset Π² RAM.
- ΠΠ°Π²Π½ΠΈ ΡΡΠ½ΠΊΡΠΈΠΈ Π½Π° R ΠΌΠΎΠ³Π°Ρ Π΄Π° Π±ΡΠ΄Π°Ρ Π·Π°ΠΌΠ΅Π½Π΅Π½ΠΈ Ρ Π±ΡΡΠ·ΠΈ Π½Π° C++ Ρ ΠΏΠΎΠΌΠΎΡΡΠ° Π½Π° ΠΏΠ°ΠΊΠ΅ΡΠ° Rcpp. ΠΠΊΠΎ Π΄ΠΎΠΏΡΠ»Π½ΠΈΡΠ΅Π»Π½ΠΎ ΠΈΠ·ΠΏΠΎΠ»Π·Π²Π°ΠΌΠ΅ RcppThread ΠΈΠ»ΠΈ RcppParallel, ΠΏΠΎΠ»ΡΡΠ°Π²Π°ΠΌΠ΅ ΠΊΡΠΎΡΠΏΠ»Π°ΡΡΠΎΡΠΌΠ΅Π½ΠΈ ΠΌΠ½ΠΎΠ³ΠΎΠΏΠΎΡΠΎΡΠ½ΠΈ ΡΠ΅Π°Π»ΠΈΠ·Π°ΡΠΈΠΈ, ΡΠ°ΠΊΠ° ΡΠ΅ ΠΊΠΎΠ΄ΡΡ Π½Π° Π½ΠΈΠ²ΠΎ R Π½Π΅ ΡΠ΅ Π½Π°Π»Π°Π³Π° Π΄Π° ΡΠ΅ ΠΏΠ°ΡΠ°Π»Π΅Π»ΠΈΠ·ΠΈΡΠ°.
- Π‘ ΠΏΠ°ΠΊΠ΅ΡΠ° Rcpp ΠΌΠΎΠΆΠ΅ Π΄Π° ΡΠ΅ ΡΠ°Π±ΠΎΡΠΈ Π±Π΅Π· ΡΠ΅ΡΠΈΠΎΠ·Π½ΠΈ ΠΏΠΎΠ·Π½Π°Π½ΠΈΡ ΠΏΠΎ C++, Π½Π΅ΠΎΠ±Ρ ΠΎΠ΄ΠΈΠΌΠΈΡΡ ΠΌΠΈΠ½ΠΈΠΌΡΠΌ Π΅ ΠΈΠ·Π»ΠΎΠΆΠ΅Π½ . ΠΠ°Π³Π»Π°Π²Π½ΠΈΡΠ΅ ΡΠ°ΠΉΠ»ΠΎΠ²Π΅ Π·Π° ΡΠ΅Π΄ΠΈΡΠ° ΡΡΡΠ°Ρ ΠΎΡΠ½ΠΈ C-Π±ΠΈΠ±Π»ΠΈΠΎΡΠ΅ΠΊΠΈ ΠΊΠ°ΡΠΎ xtensor ΡΠ° Π½Π°Π»ΠΈΡΠ½ΠΈ Π½Π° CRAN, Ρ.Π΅. ΡΠ΅ ΡΠΎΡΠΌΠΈΡΠ° ΠΈΠ½ΡΡΠ°ΡΡΡΡΠΊΡΡΡΠ° Π·Π° ΡΠ΅Π°Π»ΠΈΠ·ΠΈΡΠ°Π½Π΅ Π½Π° ΠΏΡΠΎΠ΅ΠΊΡΠΈ, ΠΈΠ½ΡΠ΅Π³ΡΠΈΡΠ°ΡΠΈ Π² R Π³ΠΎΡΠΎΠ² Π²ΠΈΡΠΎΠΊΠΎΠΏΡΠΎΠΈΠ·Π²ΠΎΠ΄ΠΈΡΠ΅Π»Π΅Π½ ΠΊΠΎΠ΄ Π½Π° C++. ΠΠΎΠΏΡΠ»Π½ΠΈΡΠ΅Π»Π½ΠΎ ΡΠ΄ΠΎΠ±ΡΡΠ²ΠΎ β ΠΏΠΎΠ΄ΡΠ²Π΅ΡΠΊΠ°ΡΠ° Π½Π° ΡΠΈΠ½ΡΠ°ΠΊΡΠΈΡΠ° ΠΈ ΡΡΠ°ΡΠΈΡΠ½ΠΈΡΡ Π°Π½Π°Π»ΠΈΠ·Π°ΡΠΎΡ Π½Π° ΠΊΠΎΠ΄ Π½Π° C++ Π² RStudio.
- docopt ΠΏΠΎΠ·Π²ΠΎΠ»ΡΠ²Π° Π΄Π° ΡΡΠ°ΡΡΠΈΡΠ°ΡΠ΅ ΡΠ°ΠΌΠΎΡΡΠΎΡΡΠ΅Π»Π½ΠΈ ΡΠΊΡΠΈΠΏΡΠΎΠ²Π΅ Ρ ΠΏΠ°ΡΠ°ΠΌΠ΅ΡΡΠΈ. Π’ΠΎΠ²Π° Π΅ ΡΠ΄ΠΎΠ±Π½ΠΎ Π·Π° ΠΈΠ·ΠΏΠΎΠ»Π·Π²Π°Π½Π΅ Π½Π° ΠΎΡΠ΄Π°Π»Π΅ΡΠ΅Π½ ΡΡΡΠ²ΡΡ, Π²ΠΊΠ»ΡΡΠΈΡΠ΅Π»Π½ΠΎ ΠΏΠΎΠ΄ docker. Π RStudio ΠΏΡΠΎΠ²Π΅ΠΆΠ΄Π°Π½Π΅ΡΠΎ Π½Π° ΠΌΠ½ΠΎΠ³ΠΎΠΊΡΠ°ΡΠ½ΠΈ Π΅ΠΊΡΠΏΠ΅ΡΠΈΠΌΠ΅Π½ΡΠΈ Ρ ΠΎΠ±ΡΡΠ΅Π½ΠΈΠ΅ Π½Π° Π½Π΅Π²ΡΠΎΠ½Π½ΠΈ ΠΌΡΠ΅ΠΆΠΈ Π΅ Π½Π΅ΡΠ΄ΠΎΠ±Π½ΠΎ, Π° ΠΈ ΡΠ°ΠΌΠ°ΡΠ° ΠΈΠ½ΡΡΠ°Π»Π°ΡΠΈΡ Π½Π° IDE Π½Π° ΡΡΡΠ²Π΅ΡΠ° Π½Π΅ Π²ΠΈΠ½Π°Π³ΠΈ Π΅ ΠΎΠΏΡΠ°Π²Π΄Π°Π½Π°.
- Docker ΠΎΡΠΈΠ³ΡΡΡΠ²Π° ΠΏΡΠ΅Π½ΠΎΡΠΈΠΌΠΎΡΡ Π½Π° ΠΊΠΎΠ΄Π° ΠΈ Π²ΡΠ·ΠΏΡΠΎΠΈΠ·Π²ΠΎΠ΄ΠΈΠΌΠΎΡΡ Π½Π° ΡΠ΅Π·ΡΠ»ΡΠ°ΡΠΈΡΠ΅ ΠΌΠ΅ΠΆΠ΄Ρ ΡΠ°Π·ΡΠ°Π±ΠΎΡΡΠΈΡΠΈ Ρ ΡΠ°Π·Π»ΠΈΡΠ½ΠΈ Π²Π΅ΡΡΠΈΠΈ Π½Π° ΠΠ‘ ΠΈ Π±ΠΈΠ±Π»ΠΈΠΎΡΠ΅ΠΊΠΈ, ΠΊΠ°ΠΊΡΠΎ ΠΈ Π»Π΅ΡΠ½ΠΎ ΡΡΠ°ΡΡΠΈΡΠ°Π½Π΅ Π½Π° ΡΡΡΠ²ΡΡΠΈ. Π¦Π΅Π»ΠΈΡΡ pipeline Π·Π° ΠΎΠ±ΡΡΠ΅Π½ΠΈΠ΅ ΠΌΠΎΠΆΠ΅ Π΄Π° ΡΠ΅ ΡΡΠ°ΡΡΠΈΡΠ° Ρ Π΅Π΄Π½ΠΎ Π΅Π΄ΠΈΠ½ΡΡΠ²Π΅Π½ΠΎ ΠΊΠΎΠΌΠ°Π½Π΄Π½ΠΎ ΠΈΠ·ΡΠ΅ΡΠ΅Π½ΠΈΠ΅.
- Google Cloud Π΅ ΠΈΠΊΠΎΠ½ΠΎΠΌΠΈΡΠ΅Π½ Π½Π°ΡΠΈΠ½ Π΄Π° Π΅ΠΊΡΠΏΠ΅ΡΠΈΠΌΠ΅Π½ΡΠΈΡΠ°ΡΠ΅ Ρ ΠΏΡΠ΅Π½ΠΎΡΠΈΠΌΠΎ ΠΎΠ±ΠΎΡΡΠ΄Π²Π°Π½Π΅, Π½ΠΎ Π΅ Π½Π΅ΠΎΠ±Ρ ΠΎΠ΄ΠΈΠΌΠΎ Π²Π½ΠΈΠΌΠ°ΡΠ΅Π»Π½ΠΎ Π΄Π° ΠΈΠ·Π±ΠΈΡΠ°ΡΠ΅ ΠΊΠΎΠ½ΡΠΈΠ³ΡΡΠ°ΡΠΈΠΈΡΠ΅.
- ΠΠ·ΠΌΠ΅ΡΠ²Π°Π½Π΅ΡΠΎ Π½Π° ΠΏΡΠΎΠΈΠ·Π²ΠΎΠ΄ΠΈΡΠ΅Π»Π½ΠΎΡΡΡΠ° Π½Π° ΠΎΡΠ΄Π΅Π»Π½ΠΈ ΡΡΠ°Π³ΠΌΠ΅Π½ΡΠΈ ΠΎΡ ΠΊΠΎΠ΄Π° Π΅ ΠΌΠ½ΠΎΠ³ΠΎ ΠΏΠΎΠ»Π΅Π·Π½ΠΎ, ΠΎΡΠΎΠ±Π΅Π½ΠΎ Π² ΠΊΠΎΠΌΠ±ΠΈΠ½Π°ΡΠΈΡ Ρ R ΠΈ C++, Π° Ρ ΠΏΠ°ΠΊΠ΅ΡΠ° bench β Π΅ ΠΎΡΠ΅ ΠΏΠΎ-Π»Π΅ΡΠ½ΠΎ.
ΠΠ°ΡΠΎ ΡΡΠ»ΠΎ ΡΠΎΠ·ΠΈ ΠΎΠΏΠΈΡ Π±Π΅ΡΠ΅ ΠΌΠ½ΠΎΠ³ΠΎ ΠΏΠΎΠ»Π΅Π·Π΅Π½ ΠΈ ΠΏΡΠΎΠ΄ΡΠ»ΠΆΠ°Π²Π°ΠΌΠ΅ Π΄Π° ΡΠ°Π±ΠΎΡΠΈΠΌ ΠΏΠΎ ΡΠ΅ΡΠ°Π²Π°Π½Π΅ΡΠΎ Π½Π° Π½ΡΠΊΠΎΠΈ ΠΎΡ ΠΏΠΎΡΠΎΡΠ΅Π½ΠΈΡΠ΅ ΠΏΡΠΎΠ±Π»Π΅ΠΌΠΈ.
ΠΠ·ΡΠΎΡΠ½ΠΈΠΊ: habr.com
