áá±áž áá¬á!
ááŒá®ážáá²á·ááá·áºáá±á¬ááºážáŠážáá¬áá®ááœáẠKaggle ááẠáááºááœá²áá¯ááºáá¯á¶áá»á¬ážá Quick Draw Doodle Recognition ááᯠá¡áá»áá¯ážá¡á
á¬ážááœá²ááẠááŒáá¯ááºááœá²áá
áºáá¯áá»ááºážááá²á·ááŒá®áž áááºážááœáẠR-áááá¹áá¶ááá¬ááŸááºá¡ááœá²á·áá
áºááœá²á· áá«áááºáá²á·áááºá
áá®áá
áºáá«áá±á¬á· áá¯áá¶ááááºá
áá¯ááºáá»áá¯ážááŒááºážáá²á· á¡áááºáááŒá±áá±ááá·áº áááºááá¯ážááŒá®ážáá²á· á¡ááœá±á·á¡ááŒá¯á¶ááœá± á¡áá»á¬ážááŒá®ážááá²á·áá«áááºá áá«ááŒá±á¬áá·áº Kagle áá²á· áá±á·á
ááºáá¯ááºáááºážááœááºááœá±ááŸá¬ á
áááºáááºá
á¬ážá
áá¬á¡áá±á¬ááºážáá¯á¶ážáá²á· á¡áá¯á¶ážáááºáá¯á¶ážá¡áá¬áá»á¬ážá
áœá¬á¡ááŒá±á¬ááºážááᯠá¡ááá¯ááºážá¡ááá¯ááºážááᯠááŒá±á¬ááŒáá»ááºáá«áááºá ááœá±ážááœá±ážáá²á·ááá·áº áá±á«ááºážá
ááºáá»á¬ážáá²ááœáẠáá²áááºážáá±á¬áá OpenCVá JSON ááœá²ááŒááºážá
áááºááŒá¬ááŒááºáž (á€á¥ááá¬áá»á¬ážááẠR ááœáẠC++ áá¯ááºááᯠscripts ááá¯á·ááá¯áẠpackages áá»á¬ážá¡ááœááºážááá¯á· áá±á«ááºážá
ááºážááŒááºážá¡á¬áž á
á
áºáá±ážááẠRcpp), scripts áá»á¬ážá parameterization ááŸáá·áº dockerization ááá±á¬ááºáá¯á¶ážááŒá±ááŸááºážáá»ááºá áá¯ááºáá±á¬ááºáááºá¡ááœáẠááá·áºáá»á±á¬áºáá±á¬áá¯á¶á
á¶ááŸá áááºáá±á·áá»áºá០áá¯ááºá¡á¬ážáá¯á¶ážááᯠáááŸáááá¯ááºáá«áááºá
áá¬áááá¬:
CSV á០áá±áá¬ááᯠMonetDB ááá¯á· áááá±á¬ááºá áœá¬ áááºáá«á á¡ááœá²áá»á¬ážááŒááºáááºááŒááºážá áá±áá¬áá±á·á áºá០á¡ááœá²áá»á¬ážááᯠááœáŸáá·áºáááºáááºá¡ááœáẠIterators áá±á¬áºáááºáááá¯áá¬ááá¯ááœá±ážáá»ááºááŒááºážá áá¬ááºááœáŸááºážáá±á¬ááºáááºááŸááºááŒááºáž Script áá»á¬ážááᯠDockerization ááŒá¯áá¯ááºááŒááºážá Google Cloud ááœáẠGPU áá»á¬ážá áœá¬ááᯠá¡áá¯á¶ážááŒá¯ááŒááºážá á¡á²áá®á¡á á¬ážáá áºá¥á®ážáááá¯á¶ážááá¯ááºážá
1. CSV ááŸáá±áá¬áá»á¬ážááᯠMonetDB áá±áá¬áá±á·á áºááá¯á· áááá±á¬ááºá áœá¬áááºáá«á
á€ááŒáá¯ááºááœá²ááŸááá±áá¬ááᯠá¡áááºááá·áºáá¯ááºáá¬ážáá±á¬áá¯á¶áá»á¬ážááá¯ááºáá² 340 CSV ááá¯ááºáá»á¬áž (á¡áááºážáá áºáá¯á á®á¡ááœáẠááá¯ááºáá áºááá¯ááº) ááŒáá·áº JSON áá»á¬ážáá«ááŸááá±á¬ point coordinates áá»á¬ážáá«ááŸááááºá á€á¡áá»ááºáá»á¬ážááᯠáá»ááºážááŒá±á¬ááºážáá»á¬ážááŒáá·áº áá»áááºáááºááŒááºážááŒáá·áºá áá»áœááºá¯ááºááá¯á·ááẠ256x256 pixels ááá¯ááºážáá¬ááá·áº áá±á¬ááºáá¯á¶ážáá¯á¶ááááºááᯠáááŸááááºááŒá áºáááºá ááá¯á·á¡ááŒáẠááŸááºáááºážáá áºáá¯á á®ááœáẠáá±áá¬á¡ááœá²ááᯠá á¯áá±á¬ááºážáá»áááºááœáẠá¡áá¯á¶ážááŒá¯ááá·áº á¡áá»áá¯ážá¡á á¬ážááœá²ááŒá¬ážáá°á áá¯á¶á¡á¬áž ááŸááºáááºá áœá¬ á¡ááá¡ááŸááºááŒá¯ááŒááºáž ááŸáá áááŸáá áá¯á¶áá±ážáá¬ážáá°á áá±ááá¯ááºáá¬ááá¯ááºáá¶á á¡áá¹ááá¬ááŸá áºáá¯á¶ážáá« áá¯ááºáá áºáá¯á áá°ážááŒá¬ážáá±á¬ ááœá²ááŒá¬ážáááºááŸááºááŸá¯á á¡áá»áááºáá¶ááááºáá áºáá¯á ááá¯ááºá¡áááºááŸáá·áº ááá¯ááºáá®áá±á¬ á¡áááºážá¡áááºá áá°áááºážáá±áá¬á ááá¯ážááŸááºážáá±á¬áá¬ážááŸááºážááẠááá¯ááŸá±á¬ááºááŸá¯ááœáẠ7.4 GB á¡áá±ážáá»áááºááŸáááŒá®áž áá¯ááºááá¯ážááŒá®ážáá±á¬áẠááá·áºááŸááºážááŒá± 20 GB ááŸáááŒá®ážá áá¯ááºááá¯ážááŒá®ážáá±á¬áẠáá±áá¬á¡ááŒáá·áºá¡á á¯á¶ááẠ240 GB á¡áá ááŸááááºá áá¬ážááŸááºážááŸá áºáá»áá¯ážá áá¯á¶ážááẠáá°áá®áá±á¬áá¯á¶áá»á¬ážááᯠááŒááºáá¯ááºáá±ážááŒá±á¬ááºáž á á®á ááºáá°áá»á¬ážá á¡á¬ááá¶áá¬ážáá±á¬ááŒá±á¬áá·áº áá¬ážááŸááºážá¡ááŒáá·áºá¡á á¯á¶ááŸá¬ áááá¯á¡ááºáá±á¬á·áá«á áááºááá¯á·áááºááá¯á á±áá¬áá° ááááºáá áºááá¯ááºáá»á¬áž ááá¯á·ááá¯áẠá¡áááºážá¡áá»ááºážáá¯á¶á á¶ááŒáá·áº áá¯á¶áááºáž 50 ááᯠááááºážáááºážááŒááºážááẠá¡áá»áá¯ážáááŸááᯠáá»ááºáá»ááºážáá°ááᬠááŸááºáááºážáá±á¬ááºážá០CSV ááá¯ááºá¡á¬ážáá¯á¶ážááᯠáá±á«ááºážá ááºážááẠáá¯á¶ážááŒááºááá¯ááºáá«áááºá train_simplified.zip á¡áá¯ááºáá áºáá¯á á®á¡ááœáẠááá¯á¡ááºáá±á¬ á¡ááœááºá¡á á¬áž "on the fly" á áá±á¬ááºáááºááœá²áá¯á¶ááááºáá»á¬ážááŸáá·áºá¡áá° áá±áá¬áá±á·á áºáá²ááá¯á·á
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"
)
)
}
áá±áá¬áá±á·á
áºáá²ááá¯á· áá±áá¬áááºááẠá¡ááŒááºáá¯á¶ážáááºážáááºážááŸá¬ SQL - command ááᯠá¡áá¯á¶ážááŒá¯á CSV ááá¯ááºáá»á¬ážááᯠááá¯ááºááá¯ááºáá°ážáá°ááŒááºážááŒá
áºáááºá COPY OFFSET 2 INTO tablename FROM path USING DELIMITERS ',','n','"' NULL AS '' BEST EFFORT
áááºááŸá¬ tablename
- ááá¬ážá¡áááºááŸáá·áº path
- ááá¯ááºááá¯á·áááºážááŒá±á¬ááºážá archive ááŸáá·áºá¡áá¯ááºáá¯ááºáá±á
ááºááœáẠbuilt-in á¡áá±á¬ááºá¡áááºáá±á¬áºááŸá¯ááá¯ááœá±á·ááŸááá²á·áááºá unzip
R ááẠááŸááºáááºážáá±á¬ááºážá០ááá¯ááºáá»á¬ážá
áœá¬ááŒáá·áº ááŸááºáááºá
áœá¬ á¡áá¯ááºááá¯ááºáá±á¬ááŒá±á¬áá·áº áá»áœááºá¯ááºááá¯á·ááẠá
áá
áºá¡á¬áž á¡áá¯á¶ážááŒá¯áá²á·áááºá unzip
( parameter ááᯠá¡áá¯á¶ážááŒá¯ 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
áá±áá¬ááᯠááŒá±á¬ááºážáá²áá±ážááá·áº áá¯ááºáá±á¬ááºáá»ááºá
áá±áá¬áá±á·á áºáá²ááá¯á· áá±áá¬áá»á¬ážááᯠáááºááá¯ááºáááºááŒááºážá¡ááœáẠáá¯ááºá
Database ááœáẠdata áá±ážááŒááºážá
# СпОÑПк ÑайлПв ÐŽÐ»Ñ Ð·Ð°Ð¿ÐžÑО
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
á¡áá¯á¶ážááŒá¯áá¬ážáá±á¬ drive á á¡ááŒááºááŸá¯ááºáž ááá¹ááá¬áá»á¬ážáá±á«áºáá°áááºá áá±áá¬ááœáá·áºáá»ááẠááœá²ááŒá¬ážááá¯ááºáááºá áá»áœááºá¯ááºááá¯á·áá¡ááŒá±á¡áá±ááœááºá SSD áá áºáá¯á¡ááœááºáž ááá¯á·ááá¯áẠflash drive (á¡áááºážá¡ááŒá áºááá¯ááº) á០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
. á€á¡ááœáẠáá»áœááºá¯ááºááá¯á·ááẠááŸáá·áºááœáẠá áá¯ááᯠá¡áá¯á¶ážááŒá¯áá²á·áááºá áááá¡áá»ááºááŸá¬ á
á±á¬áá·áºááŒáá·áºáá±áž ID ááᯠááááºážáááºážááá·áº á¡áá»áá¯ážá¡á
á¬ážá á¡ááá¯ááºážá¡áá¬ááᯠáá»áŸá±á¬á·áá»áááºááŒá
áºáááºá áá°áááºážáá±áá¬á¡ááœá²ááœáẠID ááááºážáááºážááẠááá¯á¡ááºáá±á¬á¡áá»áá¯ážá¡á
á¬ážááŸá¬ bigint
áá«áá±ááá·áº áá±á·áá¬ááœá±á·ááŸááá»ááºá¡áá±á¡ááœááºá á¡áá»áá¯ážá¡á
á¬ážá¡ááá¯áẠáá¯á¶ááŸááºáá¶áá«ááºáá²á· áá®áá²á· áá°ááá¯á·áá²á· identifiers ááœá±ááᯠá¡á¶ááá¯ááºááŒá
áºááá¯ááºá
á±áááºá int
. á€ááá
á¹á
ááœááºááŸá¬ááœá±ááŸá¯áááºá¡ááœááºááŒááºáááºá áá¯ááá ááŸáá·áºááœááºááá±á¬á· áá¯á¶ážááá¯á·áá«áá²á ORDERED INDEX
â áááá¯ááºááá»áŸá¡á¬ážáá¯á¶ážááᯠáá»á±á¬áºááŒááºááŒá®ážá០á€áá¯á¶ážááŒááºáá»ááºááᯠáá»ááºááŒááºááá¯ááºááœá±á· áá±á¬ááºááŸááá¬áá«áááºá PREPARE
á¡áá»áá¯ážá¡á
á¬ážáá° queries á¡á
á¯á¡áá±ážááᯠáááºáá®ážáá±á¬á¡áá«ááœáẠááŒááºáááºáá¬ážáá±á¬ expression ááá¯á¡áá¯á¶ážááŒá¯ááŒááºážááŒáá·áºá ááá¯á·áá±á¬áº ááááºáá±á¬á· ááá¯ážááá¯ážááŸááºážááŸááºážáá
áºáá¯ááŸáá·áº ááŸáá¯ááºážááŸááºáá»áŸáẠá¡á¬ážáá¬áá»ááºáá
áºáá¯ááŸááá«áááºá SELECT
ááááºážááááºážá¡ááŸá¬ážá¡ááœááºážáá¡ááœá¬á¡áá±ážá¡ááœááºážááœááºááŸááá²á·áááºá
áá±áá¬áááºááŒááºážáá¯ááºáááºážá ááºááẠRAM 450 MB áááºáááá¯áá«á ááá¯ááá¯áááºááŸá¬á áá±á¬áºááŒáá¬ážáá±á¬ áá»ááºážáááºááŸá¯ááẠááá·áºá¡á¬áž áááºááááºážááŸááá±á¬ áá áºáá«ááá¯ááºá¡áá±ážáá»áááºááŸááá±á¬ áá±áá¬á¡ááœá²áá»á¬ážááᯠáá¯ááºá¡ááœá²á·áá áºáá¯áááºáž á ááºáá á¹á ááºážá¡áá»áá¯á·á¡áá«á¡ááẠáááºáá»áẠáá¬á·ááºáá²ááá¯ááºážáá®ážáá«ážááœáẠááœáŸá±á·ááá¯ááºá á±áááºá á¡ááœááºááá¯ááºáááºá
áá»ááºááŸááá±áá±ážáááºááŸá¬ á¡ááœááºá¡á á¬ážá¡áá»áá¯ážáá»áá¯ážááŸá ááá°áá¬á¡ááœá²áá»á¬ážááᯠááá°áá¬áá°ááá·áºá¡áá« (áá»áááºáž) áá±áá¬ááá°ááŒááºážá á¡ááŒááºááŸá¯ááºážááᯠááá¯ááºážáá¬áááºááŒá áºáááº
áá±áá¬áá±á·á áºá á¶ááŸá¯ááºáž
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)á
- ááá¬áá²á·áá¯á¶ááœá±ááᯠtensor á¡ááŒá áºááŒá±á¬ááºážááŒááºážá
Python kernels áá»á¬ážááŒá¬ážááœáẠááŸááºááŒáá¯ááºááŸá¯á áá áºá áááºáá áºááá¯ááºážá¡áá±ááŒáá·áº ááŒá¿áá¬ááᯠá¡áááá¡á¬ážááŒáá·áº ááŒá±ááŸááºážáá²á·áááºá OpenCV. R ááœáẠá¡ááá¯ážááŸááºážáá¯á¶ážááŸáá·áº á¡áááºááŸá¬ážáá¯á¶áž analogues áá»á¬ážáá²á០áá áºáá¯ááẠá€áá²á·ááá¯á· ááŒá áºáááº-
R ááœáẠTensor ááŒá±á¬ááºážááŒááºážááá¯á· 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 áááááá¬áá»á¬ážááᯠá¡áá¯á¶ážááŒá¯á RAM ááœáẠááááºážáááºážáá¬ážáá±á¬ áá¬áá® PNG ááœáẠááááºážáááºážáá¬ážáá«ááẠ(Linux ááœáẠáá¬áá® R áááºážááœáŸááºáá»á¬ážááẠáááºážááœáŸááºáá²ááœáẠáááºááŸáááẠ/tmp
RAM ááœááºáááºáááºáá¬ážáááºá) ááá¯á·áá±á¬áẠá€ááá¯ááºááᯠ0 á០1 á¡áá áá¶áá«ááºáá»á¬ážáá«ááŸááá±á¬ áá¯á¶ážáááºááŒáẠáááºážáá»ááºážáá
áºáá¯á¡ááŒá
Ạáááºáááºá ááá¯ááá¬ážááá¯ážáá» BMP ááᯠââ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
á¡á á®á¡á á¥áºááŒá®ážáá»á¬ážááœá²á·á ááºážááŒááºážááẠááá±á¬áºááá±á¬áºá¡áá»áááºááŒá¬ááŒáá·áºááá·áºá¡ááœááºááŒá±á¬áá·áº á€á¡áá±á¬ááºá¡áááºáá±á¬áºááŸá¯ááẠáá»áœááºá¯ááºááá¯á·á¡ááœáẠá¡ááá·áºáá±á¬áºáá¯á¶ážáá¯áááºáááŒá®áž á¡á áœááºážáááºáá±á¬á á¬ááŒáá·áºááá¯ááºááá¯á¡áá¯á¶ážááŒá¯ááŒááºážááŒáá·áº áá»áœááºá¯ááºááá¯á·ááá¯ááºáá±á¬áºááá¯ááºáááºáá»á¬ážáá¡ááœá±á·á¡ááŒá¯á¶ááᯠá¡ááœáá·áºáá±á¬ááºážáá°ááẠáá¯á¶ážááŒááºáá²á·áááºá OpenCV. ááá¯á¡áá»áááºááœáẠR á¡ááœáẠá¡áááºááá·áºáá¯ááºáá¬ážáá±á¬ áááºáá±á·áá»áºáááŸááá« (ááá¯áááŸááá«) ááá¯á·ááŒá±á¬áá·áº ááá¯á¡ááºáá±á¬ áá¯ááºáá±á¬ááºááá¯ááºá áœááºážááᯠC++ ááŒáá·áº R áá¯ááºááá¯á· áá±á«ááºážá ááºážááŒááºážááŒáá·áº á¡áááºážáááºáá»áŸáᬠá¡áá±á¬ááºáááºáá±á¬áºáá²á·áá«áááºá Rcpp.
ááŒá¿áá¬ááá¯ááŒá±ááŸááºážáááºá á¡á±á¬ááºáá« áááºáá±á·áá»áºáá»á¬ážááŸáá·áº á á¬ááŒáá·áºááá¯ááºáá»á¬ážááᯠá¡áá¯á¶ážááŒá¯áá²á·áááº-
-
OpenCV áá¯á¶áá»á¬ážááŸáá·áº áá»ááºážááŒá±á¬ááºážáá»á¬ážááŒáá·áº á¡áá¯ááºáá¯ááºáááºá ááŒáá¯áááºááá·áºááœááºážáá¬ážááá·áº á áá áºáá áºáá»á áºááá¯ááºáá»á¬ážááŸáá·áº áá±á«ááºážá á®ážááá¯ááºáá»á¬ážá¡ááŒáẠááœá±á·áá»á¬ážáá»áááºáááºááŒááºážááᯠá¡áá¯á¶ážááŒá¯áá¬ážáááºá
-
xtensor multidimensional arrays ááŸáá·áº tensors áá»á¬ážááŸáá·áºá¡áá¯ááºáá¯ááºáááºá¡ááœááºá áá»áœááºá¯ááºááá¯á·ááẠáá¬áááºáá° R áááºáá±á·ááºá»ááœáẠáá«áááºáá±á¬ áá±á«ááºážá á®ážááá¯ááºáá»á¬ážááᯠá¡áá¯á¶ážááŒá¯áá²á·áááºá á á¬ááŒáá·áºááá¯ááºááẠááá·áºá¡á¬áž á¡áááºážá¡áááááŸáá·áº áá±á¬áºáá¶á¡ááŒá®ážá á¬ážá¡á á®á¡á á¥áºá¡á áááºá á¯á¶á¡áááºážá¡áá»ááºážáá»á¬ážááŒáá·áº áá¯ááºáá±á¬ááºááá¯ááºá á±áá«áááºá
-
ndjson JSON ááá¯ááºážááŒá¬ážáááºá á€á á¬ááŒáá·áºááá¯ááºááᯠá¡áá¯á¶ážááŒá¯áááºá xtensor ááá±á¬áá»ááºááœáẠááŸááá±áá»áŸáẠá¡ááá¯á¡áá»á±á¬ááºá
-
RcppThread JSON á០vector áá áºáá¯á multi-threaded processing ááᯠá á®á ááºáááºá á€áááºáá±á·áá»áºá០áá¶á·ááá¯ážáá±ážáá±á¬ áá±á«ááºážá á®ážááá¯ááºáá»á¬ážááᯠá¡áá¯á¶ážááŒá¯áá²á·áááºá ááá¯áá¬áááºááŒá®ážáá¬áᬠRcppParallel áááºáá±á·áá»áºááœáẠá¡ááŒá¬ážá¡áá¬áá»á¬ážááŒá¬ážááœáẠáááºáááºáá¬ážáá±á¬ á ááºááá¯ááºážááŒá¬ážááŒááºá áá áºáá«ááŸááááºá
ááá¯ááá¯á·áááááŒá¯ááá»áá¯ážáááºááẠxtensor áááºáá¯áá¬ážáá»á¬ážááŒá áºáá¬áááº- áááºážááœáẠáá»ááºááŒáá·áºáá±á¬áá¯ááºáá±á¬ááºááá¯ááºá áœááºážááŸáá·áº á áœááºážáá±á¬ááºáááºááŒáá·áºáá¬ážááá·áºá¡áá»ááºá¡ááŒááºá áááºážááá±á¬á·ááºáá²á¡ááºáá»ááºáá®áá¬áá»á¬ážááẠá¡áá±á¬áºáá±ážáá¯á¶á·ááŒááºááŸá¯ááŸáá·áº áá±ážááœááºážáá»á¬ážááᯠáá»ááºááŒááºážá¡áá±ážá áááºááŒá±ááŒá¬ážáá±ážáá²á·ááŒáááºá áááºážááá¯á·áá¡áá°á¡áá®ááŒáá·áºá OpenCV matrices á xtensor tensors áá»á¬ážá¡ááŒá Ạá¡ááœááºááŒá±á¬ááºážááŒááºážá¡ááŒáẠ3-áááºááŒááºáá¯ááºáá¯á¶áááºážáá¬áá»á¬ážááᯠááŸááºáááºáá±á¬á¡ááá¯ááºážá¡áá¬á 4-dimensional tensor á¡ááŒá Ạ(á¡áá¯ááºááá¯ááºááá¯ááº) áá±á«ááºážá ááºááẠáááºážáááºážáá áºáá¯áááºáž ááŒá áºááá¯ááºáááºá
Rcppá xtensor ááŸáá·áº RcppThread áááºáá°áááºá¡ááœáẠáá á¹á ááºážáá»á¬áž
á áá áºááá¯ááºáá»á¬ážááŸáá·áº á áá áºááœááºááá·áºááœááºážáá¬ážááá·áº áá áºáá»á áºáááºáá»á¬ážááŸáá·áº ááœá±á·áá»á¬ážáá»áááºáááºááŒááºážááá¯á·ááᯠá¡áá¯á¶ážááŒá¯ááá·áº ááá¯ááºáá»á¬ážááᯠá á¯á ááºážáááºá áááºáá±á·áá»áºááœáẠá¡áá±á¬ááºá¡áááºáá±á¬áºáá¬ážááá·áº ááááºá¡ááºááá¹ááá¬ážááᯠáá»áœááºá¯ááºááá¯á· á¡áá¯á¶ážááŒá¯áá²á·áááºá Rcpp. áááºážááŒá±á¬ááºážáá»á¬ážááŸáá·áº á¡áá¶áá»á¬ážááᯠá¡ááá¯á¡áá»á±á¬ááºááŸá¬ááœá±áááºá áá»áœááºá¯ááºááá¯á·ááẠáá°ááŒáá¯ááºáá»á¬ážáá±á¬ Linux utility ááᯠá¡áá¯á¶ážááŒá¯áá²á·áááºá pkg-config ááá¯.
OpenCV á á¬ááŒáá·áºááá¯ááºááᯠá¡áá¯á¶ážááŒá¯áááºá¡ááœáẠRcpp plugin ááᯠá¡áá±á¬ááºá¡áááºáá±á¬áºááŒááºážá
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 ááᯠááœá²ááŒááºážá áááºááŒá¬ááŒá®áž áá±á¬áºáááºááá¯á· áá¯ááºááœáŸáá·áºááŒááºážá¡ááœáẠá¡áá¯ááºáá áºáᯠáááºáá®ážááŒááºážá¡ááœáẠá¡áá±á¬ááºá¡áááºáá±á¬áºááŸá¯áá¯ááºááᯠspoiler á¡á±á¬ááºááœáẠáá±ážáá¬ážáááºá ááááŠážá áœá¬á áá±á«ááºážá á®ážááá¯ááºáá»á¬ážááá¯ááŸá¬ááœá±ááẠ(ndjson á¡ááœááºááá¯á¡ááºáááº) ááá¯ááŸá¬ááœá±ááẠáá±ááá¶ááá±á¬áá»ááºáááºážááœáŸááºáá áºáá¯ááᯠááá·áºáá«á
Sys.setenv("PKG_CXXFLAGS" = paste0("-I", normalizePath(file.path("src"))))
C++ ááœáẠtensor ááŒá±á¬ááºážáá²ááŒááºážááá¯á· JSON ááᯠá¡áá±á¬ááºá¡áááºáá±á¬áºááŒááºážá
// [[Rcpp::plugins(cpp14)]]
// [[Rcpp::plugins(opencv)]]
// [[Rcpp::depends(xtensor)]]
// [[Rcpp::depends(RcppThread)]]
#include <xtensor/xjson.hpp>
#include <xtensor/xadapt.hpp>
#include <xtensor/xview.hpp>
#include <xtensor-r/rtensor.hpp>
#include <opencv2/core/core.hpp>
#include <opencv2/highgui/highgui.hpp>
#include <opencv2/imgproc/imgproc.hpp>
#include <Rcpp.h>
#include <RcppThread.h>
// Ð¡ÐžÐœÐŸÐœÐžÐŒÑ ÐŽÐ»Ñ ÑОпПв
using RcppThread::parallelFor;
using json = nlohmann::json;
using points = xt::xtensor<double,2>; // ÐзвлеÑÑММÑе Оз JSON кППÑЎОМаÑÑ ÑПÑек
using strokes = std::vector<points>; // ÐзвлеÑÑММÑе Оз JSON кППÑЎОМаÑÑ ÑПÑек
using xtensor3d = xt::xtensor<double, 3>; // Ð¢ÐµÐœÐ·ÐŸÑ ÐŽÐ»Ñ Ñ
ÑÐ°ÐœÐµÐœÐžÑ ÐŒÐ°ÑÑОÑÑ ÐžÐ·ÐŸÐŸÐ±ÑажеМОÑ
using xtensor4d = xt::xtensor<double, 4>; // Ð¢ÐµÐœÐ·ÐŸÑ ÐŽÐ»Ñ Ñ
ÑÐ°ÐœÐµÐœÐžÑ ÐŒÐœÐŸÐ¶ÐµÑÑва ОзПбÑажеМОй
using rtensor3d = xt::rtensor<double, 3>; // ÐбÑÑÑка ÐŽÐ»Ñ ÑкÑпПÑÑа в R
using rtensor4d = xt::rtensor<double, 4>; // ÐбÑÑÑка ÐŽÐ»Ñ ÑкÑпПÑÑа в R
// СÑаÑОÑеÑкОе кПМÑÑаМÑÑ
// Ð Ð°Ð·ÐŒÐµÑ ÐžÐ·ÐŸÐ±ÑÐ°Ð¶ÐµÐœÐžÑ Ð² пОкÑелÑÑ
const static int SIZE = 256;
// ТОп лОМОО
// СЌ. https://en.wikipedia.org/wiki/Pixel_connectivity#2-dimensional
const static int LINE_TYPE = cv::LINE_4;
// ТПлÑОМа лОМОО в пОкÑелÑÑ
const static int LINE_WIDTH = 3;
// ÐлгПÑОÑÐŒ ÑеÑайза
// https://docs.opencv.org/3.1.0/da/d54/group__imgproc__transform.html#ga5bb5a1fea74ea38e1a5445ca803ff121
const static int RESIZE_TYPE = cv::INTER_LINEAR;
// КаблПМ ÐŽÐ»Ñ ÐºÐŸÐœÐ²ÐµÑÑОÑÐŸÐ²Ð°ÐœÐžÑ OpenCV-ЌаÑÑОÑÑ Ð² ÑеМзПÑ
template <typename T, int NCH, typename XT=xt::xtensor<T,3,xt::layout_type::column_major>>
XT to_xt(const cv::Mat_<cv::Vec<T, NCH>>& src) {
// РазЌеÑМПÑÑÑ ÑелевПгП ÑеМзПÑа
std::vector<int> shape = {src.rows, src.cols, NCH};
// ÐбÑее кПлОÑеÑÑвП ÑлеЌеМÑПв в ЌаÑÑОве
size_t size = src.total() * NCH;
// ÐÑеПбÑазПваМОе cv::Mat в xt::xtensor
XT res = xt::adapt((T*) src.data, size, xt::no_ownership(), shape);
return res;
}
// ÐÑеПбÑазПваМОе JSON в ÑпОÑПк кППÑÐŽÐžÐœÐ°Ñ ÑПÑек
strokes parse_json(const std::string& x) {
auto j = json::parse(x);
// РезÑлÑÑÐ°Ñ Ð¿Ð°ÑÑОМга ЎПлжеМ бÑÑÑ ÐŒÐ°ÑÑОвПЌ
if (!j.is_array()) {
throw std::runtime_error("'x' must be JSON array.");
}
strokes res;
res.reserve(j.size());
for (const auto& a: j) {
// ÐажЎÑй ÑÐ»ÐµÐŒÐµÐœÑ ÐŒÐ°ÑÑОва ЎПлжеМ бÑÑÑ 2-ЌеÑÐœÑÐŒ ЌаÑÑОвПЌ
if (!a.is_array() || a.size() != 2) {
throw std::runtime_error("'x' must include only 2d arrays.");
}
// ÐзвлеÑеМОе векÑПÑа ÑПÑек
auto p = a.get<points>();
res.push_back(p);
}
return res;
}
// ÐÑÑОÑПвка лОМОй
// ЊвеÑа HSV
cv::Mat ocv_draw_lines(const strokes& x, bool color = true) {
// ÐÑÑ
ПЎМÑй ÑОп ЌаÑÑОÑÑ
auto stype = color ? CV_8UC3 : CV_8UC1;
// ÐÑПгПвÑй ÑОп ЌаÑÑОÑÑ
auto dtype = color ? CV_32FC3 : CV_32FC1;
auto bg = color ? cv::Scalar(0, 0, 255) : cv::Scalar(255);
auto col = color ? cv::Scalar(0, 255, 220) : cv::Scalar(0);
cv::Mat img = cv::Mat(SIZE, SIZE, stype, bg);
// ÐПлОÑеÑÑвП лОМОй
size_t n = x.size();
for (const auto& s: x) {
// ÐПлОÑеÑÑвП ÑПÑек в лОМОО
size_t n_points = s.shape()[1];
for (size_t i = 0; i < n_points - 1; ++i) {
// ТПÑка МаÑала ÑÑÑОÑ
а
cv::Point from(s(0, i), s(1, i));
// ТПÑка ПкПМÑÐ°ÐœÐžÑ ÑÑÑОÑ
а
cv::Point to(s(0, i + 1), s(1, i + 1));
// ÐÑÑОÑПвка лОМОО
cv::line(img, from, to, col, LINE_WIDTH, LINE_TYPE);
}
if (color) {
// ÐеМÑеЌ ÑÐ²ÐµÑ Ð»ÐžÐœÐžÐž
col[0] += 180 / n;
}
}
if (color) {
// ÐеМÑеЌ ÑвеÑПвПе пÑеЎÑÑавлеМОе Ма RGB
cv::cvtColor(img, img, cv::COLOR_HSV2RGB);
}
// ÐеМÑеЌ ÑПÑÐŒÐ°Ñ Ð¿ÑеЎÑÑÐ°Ð²Ð»ÐµÐœÐžÑ ÐœÐ° float32 Ñ ÐŽÐžÐ°Ð¿Ð°Ð·ÐŸÐœÐŸÐŒ [0, 1]
img.convertTo(img, dtype, 1 / 255.0);
return img;
}
// ÐбÑабПÑка JSON О пПлÑÑеМОе ÑеМзПÑа Ñ ÐŽÐ°ÐœÐœÑЌО ОзПбÑажеМОÑ
xtensor3d process(const std::string& x, double scale = 1.0, bool color = true) {
auto p = parse_json(x);
auto img = ocv_draw_lines(p, color);
if (scale != 1) {
cv::Mat out;
cv::resize(img, out, cv::Size(), scale, scale, RESIZE_TYPE);
cv::swap(img, out);
out.release();
}
xtensor3d arr = color ? to_xt<double,3>(img) : to_xt<double,1>(img);
return arr;
}
// [[Rcpp::export]]
rtensor3d cpp_process_json_str(const std::string& x,
double scale = 1.0,
bool color = true) {
xtensor3d res = process(x, scale, color);
return res;
}
// [[Rcpp::export]]
rtensor4d cpp_process_json_vector(const std::vector<std::string>& x,
double scale = 1.0,
bool color = false) {
size_t n = x.size();
size_t dim = floor(SIZE * scale);
size_t channels = color ? 3 : 1;
xtensor4d res({n, dim, dim, channels});
parallelFor(0, n, [&x, &res, scale, color](int i) {
xtensor3d tmp = process(x[i], scale, color);
auto view = xt::view(res, i, xt::all(), xt::all(), xt::all());
view = tmp;
});
return res;
}
áá®áá¯ááºááᯠááá¯ááºáá²ááŸá¬ ááá·áºáá¬ážááá·áºáá«áááºá src/cv_xt.cpp
command ááŒáá·áº compile áá¯ááºáá«á Rcpp::sourceCpp(file = "src/cv_xt.cpp", env = .GlobalEnv)
; á¡áá¯ááºá¡ááœááºáááºáž ááá¯á¡ááºáááºá nlohmann/json.hpp
ááŸ
-
to_xt
â image matrix áá áºáá¯á¡ááœááºááŒá±á¬ááºážáááºá¡ááœáẠááá°áá¬áá¯á¶á á¶áá¯ááºáá±á¬ááºáá»ááºáá áºáᯠ(cv::Mat
) tensor áá áºáá¯ááá¯á·xt::xtensor
; -
parse_json
â áá¯ááºáá±á¬ááºáá»ááºááẠJSON á á¬ááŒá±á¬ááºážáá áºáá¯ááᯠááœá²ááŒááºážá áááºááŒá¬ááŒá®áž á¡ááŸááºáá»á¬ážá ááŒáá®ááááºáá»á¬ážááᯠáá¯ááºáá°áᬠvector áá áºáá¯á¡ááŒá Ạáá¯ááºááá¯ážáááºá -
ocv_draw_lines
- á¡ááŸááºáá»á¬ážááááẠvector á០áá±á¬ááºá á¯á¶áá»ááºážááŒá±á¬ááºážáá»á¬ážááœá²áá«á -
process
â á¡áááºáá±á¬áºááŒáá« áá¯ááºáá±á¬ááºáá»ááºáá»á¬ážááᯠáá±á«ááºážá ááºááŒá®áž ááœááºáá±á«áºáá¬áá±á¬ áá¯ááºáá¯á¶á¡á¬áž á¡ááá¯ááºážá¡áá¬ááᯠáá»á²á·ááœááºááá¯ááºá áœááºážááá¯áááºáž áá±á«ááºážááá·áºáááºá -
cpp_process_json_str
- function ááá¯áá»á±á¬áºáá¯ááºááá¯ážprocess
ááááºááᯠR-object ( multidimensional array ) ááá¯á· áááºááá¯á·áááºá -
cpp_process_json_vector
- function ááá¯áá»á±á¬áºáá¯ááºááá¯ážcpp_process_json_str
Multi-threaded áá¯ááºááœáẠstring vector áá áºáá¯ááᯠáá¯ááºáá±á¬ááºááẠááœáá·áºááŒá¯áááºá
áá±á¬ááºá á¯á¶ááá¯ááºážáá»á¬ážááœá²ááẠ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")
áááºááœá±á·ááŒááºáááá·áºá¡ááá¯ááºáž ááŒááºááŸá¯ááºážááá¯ážááŸá¯ááẠá¡ááœááºáááá¬áááºááŸá¬ážáá¬ááŒá®áž R áá¯ááºááᯠá¡ááŒáá¯ááºááŒá¯áá¯ááºááŒááºážááŒáá·áº C++ áá¯ááºááᯠá¡áá®ááá¯ááºááẠáááŒá áºááá¯ááºáá«á
3. áá±áá¬áá±á·á áºá០á¡ááœá²áá»á¬ážááᯠááœáŸáá·áºáááºáááºá¡ááœáẠIterators
R ááẠRAM ááœáẠá¡á¶áááºááœááºáá»ááŸááá±á¬ áá±áá¬ááᯠá á®áá¶áá±á¬ááºááœááºáá±ážááŒááºážá¡ááœáẠááá¯ááºáááºáá±á¬ áá¯ááºááááºážáá áºáᯠááŸáááŒá®áž Python ááẠááá·áºá¡á¬áž ááŒááºáááŸááºáá¬ááºááᯠá¡áá¯á¶ážááŒá¯á ááœááºáá»ááºááŸá¯áá»á¬áž (ááŒááºáááŸááºáá¬ááºááᯠá¡áá¯á¶ážááŒá¯á ááœááºáá»ááºááŸá¯áá»á¬áž) ááᯠááœááºáá°ááŒá®áž ááá¬ááá»áá» áá¯ááºáá±á¬ááºááá¯ááºá á±ááá·áº áááºááá²áá² áá±áá¬áá¯ááºáá±á¬ááºááŒááºážááŒáá·áº ááá¯ááá¯ááœááºááŒááºááá¹ááá¬ááŸááááºá áá±á¬áºááŒáá¬ážáá±á¬ááŒá¿áá¬áá¡ááŒá±á¡áá±ááœáẠáá»áœááºá¯ááºááá¯á·á¡ááœáẠááá¹ááááºááŸáá·áºáááºááá¯ááºáá±á¬ á¥ááá¬áá áºáá¯ááẠáá±ážáááºáá±á¬á¡á áááºá¡ááá¯ááºáž ááá¯á·ááá¯áẠá¡áá±ážá á¬ážá¡áá¯ááºááᯠá¡áá¯á¶ážááŒá¯á á¡ááá·áºáá áºááá·áºáá»ááºážá á®ááŸá gradient áá¡áá®ážá ááºáá¯á¶ážáááºážáááºážááŒáá·áº áá±á·áá»áá·áºáá¬ážáá±á¬ áááºáá²áá±á¬á¡á¬áá¯á¶ááŒá±á¬ááœááºáááºáá»á¬ážááŒá áºáááºá
Python ááœááºáá±ážáá¬ážáá±á¬ áááºááŸáá¯ááºážáá±á¬áááºáá°ááŸá¯áá±á¬ááºáá»á¬ážááœáẠáá±áá¬á¡áá±á«áºá¡ááŒá±áá¶á iterators áá»á¬ážááá¯á¡áá±á¬ááºá¡áááºáá±á¬áºááá·áº á¡áá°ážá¡áááºážáá»á¬ážááŸááááº- ááá¬ážáá»á¬ážá ááá¯ááºááœá²áá»á¬ážááŸááá¯á¶áá»á¬ážá binary áá±á¬áºáááºáá»á¬ážá áááºááŒáá·áº á¡áááºááá·áºáá¯ááºáá¬ážáá±á¬ááœá±ážáá»ááºá áá¬áá»á¬ážááá¯áá¯á¶ážááá¯ááºááẠááá¯á·ááá¯áẠáá®ážááŒá¬ážáá¯ááºáá±á¬ááºá áá¬áá»á¬ážá¡ááœáẠááá·áºááá¯ááºááá¯ááºáá±ážáá¬ážááá¯ááºáááºá R ááœáẠáá»áœááºá¯ááºááá¯á·ááẠPython á á¬ááŒáá·áºááá¯ááºá á¡ááºá¹áá«áááºá¡á¬ážáá¯á¶ážááᯠá¡áá¯á¶ážáá»ááá¯ááºáááºá ááá¬áž á¡áá¯ááºáááááºááœááºá¡áá¯ááºáá¯ááºáá±á¬á¡áááºáá°á¡áá¯ááºááá¯á¡áá¯á¶ážááŒá¯ááŒá®ážáááºážáá¡áá»áá¯ážáá»áá¯ážáá±á¬ backend áá»á¬ážááŸáá·áºá¡áá° ááá°ážáá±á¬ááºááŒáá¯á·. áá±á¬ááºáá¯á¶ážááœáẠáá®ážááŒá¬ážááŸááºáá»á¬ážáá±á¬ áá±á¬ááºážáá«ážáá áºáá¯ááºááᯠááá¯ááºáááºáá«áááºá áááºážááẠááá·áºá¡á¬áž R á០Python áá¯ááºááᯠrun ááá¯ááºáá¯á¶áá¬áá R ááŸáá·áº Python sessions áá»á¬ážááŒá¬ážááœáẠá¡áá¬ááá¹áá¯áá»á¬ážááᯠááœáŸá²ááŒá±á¬ááºážáá±ážáᬠááá¯á¡ááºáá±á¬á¡áá»áá¯ážá¡á á¬ážáá°ážááŒá±á¬ááºážááŸá¯áá»á¬ážááᯠá¡ááá¯á¡áá»á±á¬ááºáá¯ááºáá±á¬ááºááá¯ááºá á±áááºááŒá áºáááºá
MonetDBLite ááᯠá¡áá¯á¶ážááŒá¯á RAM ááœáẠáá±áá¬á¡á¬ážáá¯á¶ážááᯠááááºážáááºážáá¬ážááẠááá¯á¡ááºááŸá¯ááᯠáááºááŸá¬ážááá¯ááºááŒá®ážá "Neural Network" á¡á¬ážáá¯á¶ážááᯠPython ááœáẠáá°áááºážáá¯ááºááŒáá·áº áá¯ááºáá±á¬ááºááœá¬ážáááºááŒá áºááŒá®ážá áá»áœááºá¯ááºááá¯á·ááẠáá±áá¬áá±á«áºááœáẠáááºáá±á¬ááºážáá±ážáá¬ážááẠááá¯á¡ááºáá±á¬ááŒá±á¬áá·áºá R ááá¯á·ááá¯áẠPython ááœááºááá¯áá²á·ááá¯á·áá±á¬á¡ááŒá±á¡áá±á¡ááœááºá áááºážá¡ááœáẠá¡ááŒá±áá¶á¡á¬ážááŒáá·áº ááá¯á¡ááºáá»áẠááŸá áºáá¯áᬠááŸááááº- áááºážááẠá¡áá¯á¶ážáááŸááá±á¬ ááœááºáááºáá áºáá¯ááœáẠá¡á á¯ááá¯ááºá¡á ááºážáá»á¬ážááᯠááŒááºá áááºáá«áááºáá« áá¯ááºáá±á¬ááºááŸá¯áá»á¬ážááŒá¬ážááœáẠáááºážáá¡ááŒá±á¡áá±ááᯠááááºážáááºážáááẠ(áá±á¬ááºááá¯ááºážááœáẠR ááẠá¡ááá¯ážááŸááºážáá¯á¶ážáááºážáááºážááŒáá·áº á¡áá±á¬ááºá¡áááºáá±á¬áºáááº)á ááááºáá R array áá»á¬ážááᯠiterator á¡ááœááºážááŸá numpy array áá»á¬ážá¡ááŒá áºááá¯á· ááŒááºáá¬ážá áœá¬ááŒá±á¬ááºážáá²ááẠááá¯á¡ááºáá±á¬áºáááºážá package á áááºááŸááá¬ážááŸááºáž ááá¬áž áá°ááá¯ááºááá¯ááºáá¯ááºáááºá
áá±á·áá»áá·áºáá±áž ááŸáá·áº ááŸááºáááºááŒá±á¬ááºáž á¡áá»ááºá¡áááºáá»á¬ážá¡ááœáẠáááºáá±á¬ááºážááŸáá·áºáá±ážáá°ááŸá¬ á¡á±á¬ááºáá«á¡ááá¯ááºážááŒá áºááẠá
áá±á·áá»áá·áºáá±ážááŸáá·áº á¡áááºááŒá¯áá»ááºáá±áá¬á¡ááœáẠIterator
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 pixels á rendering áá¯á¶áá»á¬ážááŸáá·áº ááá¯ááºáá®áááºá scale = 0.5
â 128x128 pixels)á á¡áá±á¬ááºá¡ááœáŸááºáž (color = FALSE
á¡áá¯á¶ážááŒá¯ááá·áºá¡áá« áá®ážááá¯ážáá±á¬ááºá
áá±ážááŒáá·áº rendering ááᯠáááºááŸááºáááºá color = TRUE
áá±ááŒááºááŒááºážáá
áºáá¯á
á®ááᯠá¡áá±á¬ááºá¡áá
áºááŒáá·áº áá±ážááœá²áá¬ážáááº) ááŸáá·áº imagenet ááœáẠááŒáá¯áááºáá±á·áá»áá·áºáá¬ážáá±á¬ ááœááºáááºáá»á¬ážá¡ááœáẠááŒáá¯áááºáá¯ááºáá±á¬ááºááŒááºáž á¡ááœáŸááºážáá
áºáá¯á ááŒá¬ážáá¬á [0á 1] á០ááŒá¬ážáá¬á [-1á 1] á¡áá pixel áááºááá¯ážáá»á¬ážááᯠááá¯ááºážáá¬áááºá¡ááœáẠáá±á¬ááºááá¯ááºážááœáẠááá¯á¡ááºáááºá ááá¬áž áá±á¬áºáááºáá»á¬ážá
ááŒááºááá¯ááºáá±á¬ááºáá»ááºááœáẠá¡ááŒááºážá¡áá¯á¶á¡áá»áá¯ážá¡á
á¬ážá
á
áºáá±ážááŒááºážá ááá¬ážáá
áºáá¯áá«ááŸááááºá data.table
áá»áááºáž áá»ááºážááŒá±á¬ááºážáá¶áá«ááºáá»á¬áž áá±á¬á
ááºáá¬ážááẠsamples_index
ááŸáá·áº á¡áá¯ááºáá¶áá«ááºáá»á¬ážá áááºááŒáẠááŸáá·áº á¡áá»á¬ážáá¯á¶áž á¡á
á¯á¡áá±áž á¡áá±á¡ááœáẠááŸáá·áº áá±áá¬áá±á·á
áºá០áá±áá¬ááᯠááœáŸáá·áºáááºáááºá¡ááœáẠSQL á
áá¬ážáááºá ááá¯á·á¡ááŒááºá áá»áœááºá¯ááºááá¯á·ááẠá¡ááœááºážá áá¯ááºáá±á¬ááºááŸá¯á ááŒááºáááºáá±á¬ analogue áá
áºáá¯ááᯠáááºááŸááºáá²á·áááºá keras::to_categorical()
. áá»áœááºá¯ááºááá¯á·ááẠáá±á·áá»áá·áºáá±ážá¡ááœáẠáá±áá¬á¡á¬ážáá¯á¶ážáá®ážáá«ážááᯠá¡áá¯á¶ážááŒá¯ááŒá®áž á¡áááºááŒá¯ááẠáá¬ááá¯ááºááŸá¯ááºážáá
áºáááºááᯠáá»ááºáá¬ážáá±á¬ááŒá±á¬áá·áº á¡ááá¯ááºážá¡ááœááºá¡á
á¬ážááᯠááá·áºáááºáá»ááºááŒáá·áº ááá·áºáááºáá¬ážáááºá steps_per_epoch
áá±á«áºáá±á¬á¡áá« keras::fit_generator()
, ááŸáá·áºá¡ááŒá±á¡áá± if (i > max_i)
validation iterator á¡ááœááºáá¬á¡áá¯ááºáá¯ááºáá²á·áááºá
á¡ááœááºážáá¯ááºáá±á¬ááºáá»ááºááœááºá áá±á¬ááºá¡áá¯ááºá¡ááœáẠá¡áááºážá¡ááœáŸááºážáá»á¬ážááᯠááŒááºáááºááá°áááºá á¡áá¯ááºáá±á¬ááºáá¬ááá¯ážáá¬ááŒááºážááŒáá·áº áá±áá¬áá±á·á
áºá០ááŸááºáááºážáá»á¬ážááᯠááŒá¯ááºáá°áááºá JSON ááœá²ááŒááºážá
áááºááŒá¬ááŒááºáž (áá¯ááºáá±á¬ááºáá»áẠcpp_process_json_vector()
C++ ááŒáá·áº áá±ážáá¬ážáá¬ážáá±á¬) ááŸáá·áº áá¯á¶áá»á¬ážááŸáá·áº áááºááá¯ááºáá±á¬ array áá»á¬ážááᯠáááºáá®ážááŒááºážá ááá¯á·áá±á¬áẠá¡áááºážá¡ááœáŸááºážáá»á¬ážáá«ááá·áº hot vector áá»á¬ážááᯠáááºáá®ážááŒá®áž pixel áááºááá¯ážáá»á¬ážááŸáá·áº á¡ááœáŸááºážáá»á¬ážáá«ááá·áº array áá»á¬ážááᯠreturn valueááŒá
áºááá·áº á
á¬áááºážáá
áºáá¯á¡ááŒá
Ạáá±á«ááºážá
ááºáá¬ážáááºá á¡áá¯ááºááᯠá¡ááŸáááºááŒáŸáá·áºáááºá ááá¬ážáá»á¬ážááœáẠá¡ááœáŸááºážáá»á¬ážáááºáá®ážááŒááºážááᯠá¡áá¯á¶ážááŒá¯áá²á·áááºá data.table
ááá·áºááºááŸáá
áºááá·áº ááŒá¯ááŒááºááœááºážáá¶ááŒááºáž - á€áááºáá±á·áá»áº "chips" ááá«áá² áá±áᬠR ááœáẠáááá¬áááºááŸá¬ážáá±á¬ áá±áá¬ááá¬ááá
áºáá¯ááŸáá·áº áááááá±á¬ááºáá±á¬áẠáá¯ááºáá±á¬ááºááẠá
áááºáá°ážáááºááŸá¬ á¡ááœááºáááºáá²áááºá
Core i5 áááºááºáá±á¬á·áá áºáá¯á¶ážááŸá á¡ááŒááºááŸá¯ááºážááá¯ááºážáá¬ááŸá¯ááááºáá»á¬ážááŸá¬ á¡á±á¬ááºáá«á¡ááá¯ááºážááŒá áºáááºá
Iterator á á¶ááŸá¯ááºáž
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
. command ááᯠrun ááŒááºážááŒáá·áº reboot áá¯ááºááŒá®ážááááºááá¯á
á
áºáá±ážáá«á df -h
.
á ááºážáááºáá±áá¬á¡ááœáẠiterator ááẠRAM ááŸáá·áº áá¯á¶ážáá¯á¶ážáá»á¬ážáá»á¬ážááá¯ááºáá®áá±á¬ááŒá±á¬áá·áº á ááºážáááºáá±áá¬ááẠááá¯ááá¯ááá¯ážááŸááºážáá«áááºá
á ááºážáááºáá±áá¬á¡ááœáẠIterator
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 á
á¬áááºáž) ááŸáá·áº function ááᯠ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)
ááᯠáá¶á·ááá¯ážáá±ážáá¬ážááá·áº áááºááá·áºá¡áá¬ááá¯áááᯠááá°ááẠuniversal function áá áºáá¯áá±ážááẠááááºáá²áá«á ááá¬áž 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()
. áá»áœááºá¯ááºááá¯á·ááẠá€áá¯ááºáá±á¬ááºáá»ááºááᯠáááºáá±á¬á¡áá«á០áááá·áºáá²á·áá«á á¡ááŒá±á¬ááºážááŸá¬ á€á¡ááá·áºááœáẠá¡áá±á¬ááºá¡ááœá±ážáá¯á¶áá»á¬ážááŸáá·áº á¡áá¯ááºáá¯ááºáá¬ááœáẠááá¯ááá¯á¡áá»áá¯ážááŒá
áºááœááºážááŒá±á¬ááºáž ááŸááºážáááºážáá±ááŒá®ááŒá
áºáá±á¬ááŒá±á¬áá·áºááŒá
áºáááºá
áá»áœááºá¯ááºááá¯á·ááẠmobilenet áá¬ážááŸááºáž 1 ááŸáá·áº 2 á¡ááŒáẠresnet34 ááᯠá¡áá¯á¶ážááŒá¯á á ááºážáááºááŸá¯á¡áá»á¬ážá á¯ááᯠáá¯ááºáá±á¬ááºáá²á·áááºá SE-ResNeXt áá²á·ááá¯á·áá±á¬ áá±ááºáá®áááá¯áá¬áááºáá¬áá»á¬ážááẠá€ááŒáá¯ááºááœá²ááœáẠáá±á¬ááºážááœááºá áœá¬ á áœááºážáá±á¬ááºááá¯ááºáá²á·áááºá áá¶ááá±á¬ááºážá áœá¬ááŒáá·áºá áá»áœááºá¯ááºááá¯á·ááœáẠá¡áááºááá·áºáá¯ááºáá¬ážáá±á¬ á¡áá±á¬ááºá¡áááºáá±á¬áºááŸá¯áá»á¬áž áááŸááá«á áá»áœááºá¯ááºááá¯á·ááá¯ááºááá¯áẠááá±ážáá« (ááá¯á·áá±á¬áº áá»áááºážáá± áá±ážáá«áááº)á
5. Script áá»á¬ážá ááá·áºáááºáá»ááºáá»á¬áž
á¡áááºááŒá±á
á±áááºá áá±á·áá»áá·áºááŸá¯á
áááºááŒááºážá¡ááœáẠáá¯ááºá¡á¬ážáá¯á¶ážááᯠáá¬ááºááœáŸááºážáá
áºáá¯áááºážá¡ááŒá
Ạááá·áºáááºáááºááŸááºáá¬ážááŒá®áž á¡áá¯á¶ážááŒá¯áá¬ážáááºá
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)
á¡áá¯áẠdocopt á¡áá±á¬ááºá¡áááºáá±á¬áºááŸá¯ááᯠááá¯ááºá
á¬ážááŒá¯áááºá 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
á¡áá±á¬ááºá¡áááºáá±á¬áºááá¯ááºááẠ(ဠcommand ááẠmodel ááá¯á
áááºáá±á·áá»áá·áºáá±ážáááá·áºáááºá resnet50
128x128 pixels ááá¯ááºážáá¬ááá·áº áá¯á¶ážáá±á¬ááºá
á¯á¶áá¯á¶áá»á¬ážááœááºá áá±áá¬áá±á·á
áºááᯠááá¯áá«ááœáẠáá¬ážááŸáááááºá /home/andrey/doodle_db
) áááºáá°ááŸá¯á¡ááŒááºááŸá¯ááºážá ááá¯ááá¯áá±á¬ááºážááœááºá¡á±á¬ááºáá¯ááºáá±á¬ááºááá¯ááºáá±á¬ á¡áá»áá¯ážá¡á
á¬ážááŸáá·áº á¡ááŒá¬ážá
áááºááŒáá¯ááºááŒááºáááºááá¯ááºáá±á¬ áá±á¬ááºáá»á¬ážááᯠá
á¬áááºážáá²ááá¯á· áááºááá·áºááá¯ááºáááºá áá¯ááºáá±ááŸá¯ááŒááºáááºááŒááºážáá¯ááºáááºážá
ááºááœááº, ááááá¯áá¬ááá¯ááœááºááŸáá·áº mobilenet_v2
áááºááŸááá¬ážááŸááºážá០ááá¬áž R ááá¯á¡áá¯á¶ážááŒá¯áááºá
á€áá»ááºážáááºááŸá¯ááẠRStudio ááœáẠscripts áá»á¬ážááᯠáá¬ááá¯á¶ážáá±á·ááŸááááºááŸáá·áº ááŸáá¯ááºážááŸááºáá«á ááá°áá®áá±á¬ áá±á¬áºáááºáá»á¬ážááŸáá·áº á
ááºážáááºááŸá¯áá»á¬ážááᯠáááááá¬áᬠá¡ááŸáááºááŒáŸáá·áºááá¯ááºá
á±ááẠ(áááºáá±á·áá»áºááᯠááŒá
áºááá¯ááºááŒá±ááŸááá±á¬ á¡ááŒá¬ážááœá±ážáá»ááºá
áá¬á¡ááŒá
Ạáá»áœááºá¯ááºááá¯á· ááŸááºáá°áá«áááºá
6. Script áá»á¬ážááᯠDockerization ááŒá¯áá¯ááºááŒááºážá
á¡ááœá²á·áááºáá»á¬ážááŒá¬áž áá±á·áá»áá·áºáá±ážáá¯á¶á
á¶áá»á¬ážááŸáá·áº cloud ááœáẠáá»ááºááŒááºá
áœá¬ ááŒáá·áºáá»ááºááŒááºážá¡ááœáẠáááºáááºážáá»ááºá áááºáá±á¬ááºáááœááºáá°á
á±áááºá¡ááœáẠ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 <[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
á¡áááºááŒá±á
á±áááºá¡ááœááºá á¡áá¯á¶ážááŒá¯áá¬ážáá±á¬ áááºáá±á·áá»áºáá»á¬ážááᯠááŒá±á¬ááºážáá²ááá¯ááºáá±á¬ áá¯á¶á
á¶áá»á¬ážááŒáá·áº ááá·áºááœááºážáá¬ážáá«áááºá ááœááºááááºáá¬á¡ááœááºážááœáẠáá±ážáá¬ážáá¬ážáá±á¬ Script á¡áá»á¬ážá
á¯ááᯠááœááºááááºáá¬á¡ááœááºáž áá°ážáá°áá«áááºá áá»áœááºá¯ááºááá¯á·áááºáááºáž command shell ááá¯ááŒá±á¬ááºážáá¬ážáááºá /bin/bash
á¡ááŒá±á¬ááºážá¡áá¬á¡áá¯á¶ážááŒá¯áááœááºáá°á
á±ááẠ/etc/os-release
. áááºážááẠáá¯ááºááœáẠOS áá¬ážááŸááºážááᯠáááºááŸááºááẠááá¯á¡ááºááŸá¯ááᯠááŸá±á¬ááºááŸá¬ážáá²á·áááºá
ááá¯á·á¡ááŒááºá áá±ážáááºáá±á¬ bash script ááá¯áááºááẠcommand á¡áá»áá¯ážáá»áá¯ážááŒáá·áº container áá áºáá¯ááá¯á áááºáááºááœáá·áºááŒá¯áááºá á¥ááá¬á¡á¬ážááŒáá·áºá áááºážááá¯á·ááẠááœááºááááºáá¬á¡ááœááºáž ááááºá áá¬ážááŸááá²á·áá±á¬ á¡á¬áá¯á¶ááŒá±á¬ááœááºáááºáá»á¬ážááᯠáá±á·áá»áá·áºáááºá¡ááœáẠscript áá»á¬áž ááá¯á·ááá¯áẠááœááºááááºáá¬á áá¯ááºáá±á¬ááºáá»ááºááᯠá¡ááŸá¬ážááŸá¬ááŒááºááŒááºážááŸáá·áº á á±á¬áá·áºááŒáá·áºááŒááºážá¡ááœáẠá¡áááá·áºáá±ážááœá¶áá»á¬áž ááŒá áºááá¯ááºáááº-
ááœááºááááºáá¬ááá¯ááœáá·áºááẠScript
#!/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 script ááᯠááá·áºáááºáá»ááºáá»á¬ážááá«áá² áá¯ááºáá±á¬ááºáá«áá script ááᯠcontainer á¡ááœááºážááœáẠáá±á«áºáá«áááºá train_nn.R
áá°áááºážáááºááá¯ážáá»á¬ážááŸáá·áºá¡áá°; á¡áááºá ááá positional argument ááẠ"bash" ááŒá
áºáá«á container ááẠcommand shell ááŒáá·áº á¡ááŒááºá¡ááŸááºá¡áá»áá¯ážáááºáá±á¬ááºá
áœá¬ á
áááºáááºááŒá
áºáá«áááºá á¡ááŒá¬ážááá
á¹á
áá»á¬ážááœááºá positional arguments áá»á¬ážááááºááá¯ážáá»á¬ážááᯠá¡á
á¬ážááá¯ážáááº- CMD="Rscript /app/train_nn.R $@"
.
á¡áááºážá¡ááŒá áºáá±áá¬ááŸáá·áº áá±áá¬áá±á·á áºáá»á¬ážáá«ááá·áº áááºážááœáŸááºáá»á¬ážá¡ááŒáẠáá±á·áá»áá·áºáááºááŒá¬ážáá¬ážáá±á¬ áá±á¬áºáááºáá»á¬ážááᯠááááºážáááºážáááºá¡ááœáẠáááºážááœáŸááºáá»á¬ážááᯠáááºáá¶áá±á¬ááºááœááºáá±ážááá·áºá áá áºá០ááœááºááááºáá¬á¡ááœááºážááœáẠáááºáááºáá¬ážáá±á¬ááŒá±á¬áá·áº áááá¯á¡ááºáá² áá¬ááºááœáŸááºážáá»á¬ážá ááááºáá»á¬ážááᯠáááºáá±á¬ááºááŒáá·áºááŸá¯ááá¯ááºá á±ááŒá±á¬ááºáž áááááŒá¯ááá·áºáááºá
7. Google Cloud ááœáẠGPU áá»á¬ážá áœá¬ááᯠá¡áá¯á¶ážááŒá¯ááŒááºážá
ááŒáá¯ááºááá¯ááºááŸá¯áá¡ááºá¹áá«áááºáá»á¬ážáá²ááŸáá
áºáá¯ááŸá¬ á¡ááœááºáá°áá¶áá±á¬áá±áá¬ááŒá
áºááẠ(áá±á«ááºážá
ááºáá¯á¶ááá¯ááŒáá·áºáá«á ODS slack á០@Leigh.plt ááŸáá»á±ážáá°áá¬ážáááº)á ááŒá®ážáá¬ážáá±á¬á¡áá¯ááºáá»á¬ážááẠáááºážááá¯ááá¯ááºáá»ááºááẠáá°áá®áá±ážááŒá®áž GPU 1 áá¯áá«ááá·áº PC ááœáẠá
ááºážáááºááŸá¯áá»á¬ážááŒá®ážáá±á¬ááºá cloud ááŸá GPU áá»á¬ážá
áœá¬ááœáẠáá±á·áá»áá·áºáá±ážáá±á¬áºáááºáá»á¬ážááᯠáá»áœááºážáá»ááºááẠáá¯á¶ážááŒááºáá²á·áááºá áá¯á¶ážáá¬ážáá±á¬ GoogleCloud (dev/shm
.
á áááºáááºá á¬ážá áᬠá¡áá±á¬ááºážáá¯á¶ážááŸá¬ GPU á¡áá»á¬ážá¡ááŒá¬ážááᯠá¡áá¯á¶ážááŒá¯ááẠáá¬áááºááŸááá±á¬ áá¯ááºá¡ááá¯ááºážá¡á ááŒá áºáááºá ááááŠážá áœá¬á áá±á¬áºáááºááᯠPython ááœááºáá²á·ááá¯á· context manager ááá¯á¡áá¯á¶ážááŒá¯á CPU áá±á«áºááœááºáááºáá®ážáááº-
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 áá»á¬ážá áœá¬á¡ááœáẠáá±á¬áºáááºáá áºáá¯áá¯á¶ážááᯠá¡á±ážáá²á á±ááŒááºážááŸáá·áº ááŒááºáááºáá±á·áá»áá·áºááŒááºážááá¯á·ááᯠá¡áá±á¬ááºá¡áááºááá±á¬áºááá¯ááºáá«á
áá±á·áá»áá·áºááŸá¯ááᯠá¡áá¯á¶ážáááŒá¯áá² á á±á¬áá·áºááŒáá·áºáá²á·áááºá áááŸááºáááºážáá»á¬ážááᯠááŸááºáááºážáááºááŒááºážááŸáá·áº áá±ááºáá áºáá¯á á®ááŒá®ážáá±á¬áẠááááºážá¡áá»ááºá¡áááºáá±ážááá·áºá¡áááºáá»á¬ážááŒáá·áº áá±á¬áºáááºáá»á¬ážááᯠááááºážáááºážááŒááºážááœáẠáá»áœááºá¯ááºááá¯á·á¡á¬áž ááá·áºáááºááŒááºáž-
ááŒááºáááºáá±á«áºááá¯ááŸá¯áá»á¬áž
# КаблПМ ОЌеМО Ñайла лПга
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. áá±á¬ááºáá»ááºáá»áá¬áá
áá»áœááºá¯ááºááá¯á· ááŒá¯á¶ááœá±á·áá±ááá±á¬ ááŒá¿áá¬áá»á¬ážá áœá¬ááᯠááá»á±á¬áºááœáŸá¬ážááá¯ááºáá±ážáá«á
- в ááá¬áž á¡áá±á¬ááºážáá¯á¶ážáááºáá°ááŸá¯ááŸá¯ááºážááᯠá¡ááá¯á¡áá»á±á¬ááºááŸá¬ááœá±áááºá¡ááœáẠá¡áááºááá·áºáá¯ááºáá¬ážáá±á¬ áá¯ááºáá±á¬ááºáá»ááºáááŸááá«á (analogue
lr_finder
á á¬ááŒáá·áºááá¯ááºáá²ááŸá¬ fast.ai); á¡á¬ážá áá¯ááºáá¯ááºááŸá¯á¡áá»áá¯á·ááŒáá·áºá á¥ááá¬á¡á¬ážááŒáá·áºá ááŒááºáá¡ááœá²á·á¡á ááºážáá¡áá±á¬ááºá¡áááºáá±á¬áºááŸá¯áá»á¬ážááᯠR ááá¯á· áá±ážááá¯á·ááá¯ááºáááºáဠ; - ááááºá¡áá»ááºáá¡áá»áá¯ážáááºá¡áá±ááŒáá·áº GPU áá»á¬ážá áœá¬ááá¯á¡áá¯á¶ážááŒá¯ááá·áºá¡áá« ááŸááºáááºáá±á¬áá±á·áá»áá·áºáá±ážá¡ááŒááºááŸá¯ááºážááᯠááœá±ážáá»ááºááẠáááŒá áºááá¯ááºáá«á
- á¡áá°ážáááŒáá·áº imagenet ááœáẠááŒáá¯áááºáá±á·áá»áá·áºáá¬ážáá±á¬ áá±ááºáá®á¡á¬áá¯á¶ááŒá±á¬ááœááºáááºáááá¯áá¬áááºáá¬áá»á¬áž áááºážáá«ážáá±áá«áááºá
- áá°áá«áááŸáá·áº ááœá²ááŒá¬ážáááºáá¶ááŸá¯ááá¯ááºáᬠáááºáá°ááŸá¯ááŸá¯ááºážáá»á¬ážááᯠáá¶ááá¬áááºááŒááºážáááŸááá« (cosine annealing ááẠáá»áœááºá¯ááºááá¯á·ááá±á¬ááºážááá¯áá»ááºá¡áááŒá
áºáááºá
á¡áá±á¬ááºá¡áááºáá±á¬áºáá²á·áááºá , áá»á±ážáá°ážáááºáá«áááºá áá®ážááẠ).
áá®ááŒáá¯ááºááœá²ááá± áááºááᯠá¡áá¯á¶ážáááºáá²á·á¡áá¬ááœá±ááᯠáááºáá°áá²á·ááá²á
- áá«áá«áááºážáá«ážáá±á¬ áá¬á·ááºáá²ááœááºá áááºááẠáá¬áá»ááºááŸá¯áááŸááá² ááá·áºáá»á±á¬áºáá±á¬ (RAM á á¡ááœááºá¡á á¬áž á¡ááá»á¬ážá áœá¬) áá±áá¬ááá¬ááá»á¬ážááŒáá·áº áá¯ááºáá±á¬ááºááá¯ááºáááºá ááááºá áá áºá¡ááẠáá±áᬠáááºážááá¯á·ááᯠáá°ážáá°ááŒááºážá០ááŸá±á¬ááºááŒááºááŒá®áž ááŸááºáááºá áœá¬ á¡áá¯á¶ážááŒá¯áá±á¬á¡áá«ááœááºá áááºážá á áœááºážáá±á¬ááºáááºáá»á¬ážááẠáá»áœááºá¯ááºááá¯á·áᶠáá¬ááºááœáŸááºážáá±ážáá¬ážááá·áº áá¬áá¬á áá¬ážáá»á¬ážá¡ááœáẠááááŒááá·áº áááááá¬á¡á¬ážáá¯á¶ážááŒá¬ážááœáẠá¡ááŒáá·áºáá¯á¶ážááŒááºááŸá¯ááºážááᯠá¡ááŒá²áááºážáá®ážáá«áž ááŒááá±áá±á¬ááŒá±á¬áá·áº ááŸááºáá¬ááºááᯠááááºážáááºážáá±ážáá«áááºá áá±áá¬áá±á·á áºáá áºáá¯ááœáẠáá±áá¬ááááºážáááºážááŒááºážááẠáá»á¬ážá áœá¬áá±á¬ááá á¹á áá»á¬ážááœáẠáá±áá¬á¡ááœá²áá áºáá¯áá¯á¶ážááᯠRAM á¡ááœááºážááá¯á· ááŸá áºáá¯ááºááẠáááá¯á¡ááºááŒá±á¬ááºáž áá¯á¶ážááááœá±ážáá² áá¬ážááá¯ááºá á±áá«áááºá
- áááºáá±á·áá»áºááᯠá¡áá¯á¶ážááŒá¯á R ááœáẠááŸá±ážááœá±ážáá±á¬ áá¯ááºáá±á¬ááºáá»ááºáá»á¬ážááᯠC++ ááœáẠááŒááºáááºáá±á¬ á¡áá¬áá»á¬ážááŒáá·áº á¡á á¬ážááá¯ážááá¯ááºáááºá Rcpp. á¡ááŒááºááá¯áá¯á¶ážááẠRcppThread ááá¯á·ááá¯áẠRcppParalleláá»áœááºá¯ááºááá¯á·ááẠcross-platform multi-threaded á¡áá±á¬ááºá¡áááºáá±á¬áºááŸá¯áá»á¬ážááᯠáááŸááááºá ááá¯á·ááŒá±á¬áá·áº R á¡ááá·áºááœáẠáá¯ááºááᯠá¡ááŒáá¯ááºááœá²ááẠáááá¯á¡ááºáá«á
- á¡áá¯áẠRcpp C++ ááᯠáá±ážáááºá
áœá¬ ááááá² á¡áá¯á¶ážááŒá¯ááá¯ááºáááºá ááá¯á¡ááºáá±á¬ á¡áááá·áºáá¯á¶ážááᯠáá±á¬áºááŒáá¬ážáá«áááºá
áá®ááŸá¬ . á¡ááá¯ááºá á¬áž C-libraries á¡áá»á¬ážá¡ááŒá¬ážá¡ááœáẠáá±á«ááºážá á®ážááá¯ááºáá»á¬áž xtensor CRAN ááœáẠáááŸáááá¯ááºáááºá ááá¯ááá¯áááºááŸá¬á á¡áááºááá·áºáá¯ááºáá¬ážáá±á¬ á áœááºážáá±á¬ááºáááºááŒáá·áº C++ áá¯ááºááᯠR ááá¯á· áá±á«ááºážá ááºáá¬ážááá·áº ááá±á¬áá»ááºáá»á¬ážááᯠá¡áá±á¬ááºá¡áááºáá±á¬áºáááºá¡ááœáẠá¡ááŒá±áá¶á¡áá±á¬ááºá¡áŠáá áºáá¯ááᯠááœá²á·á ááºážáá¬ážáá«áááºá áááºáá±á¬ááºážá¡áááºááŒá±ááŸá¯ááŸá¬ RStudio ááŸá static C++ áá¯ááºááœá²ááŒááºážá áááºááŒá¬ááŸá¯áá áºáá¯ááŒá áºáááºá - docopt parameters áá»á¬ážááŒáá·áº ááá¯ááºááá¯ááºáá«ááŸááá±á¬ script áá»á¬ážááᯠrun ááá¯ááºá á±áá«áááºá áááºážááẠá¡áá±ážááááºážáá¬áá¬ááœáẠá¡áá¯á¶ážááŒá¯ááẠá¡áááºááŒá±áááºá docker á¡á±á¬ááºááœááºá RStudio ááœááºá áá±á·áá»áá·áºáá±ážá¡á¬áá¯á¶ááŒá±á¬ááœááºáááºáá»á¬ážááŸáá·áºá¡áá° áá¬áá®áá±á«ááºážáá»á¬ážá áœá¬ á ááºážáááºááŸá¯áá»á¬ážááŒá¯áá¯ááºááẠá¡áááºáááŒá±ááŒá áºááŒá®áž áá¬áá¬áá±á«áºááœáẠIDE ááᯠááá·áºááœááºážááŒááºážááẠá¡ááŒá²áááºáž ááá¬ážáá»áŸáááŸá¯áááŸááá«á
- Docker ááẠOS ááŸáá·áº libraries á¡áá»áá¯ážáá»áá¯ážááŸá developer áá»á¬ážááŒá¬ážááœáẠááááºáá»á¬ážááᯠáááºáá±á¬ááºáááœááºáá°ááŒá®áž ááŒááºáá¯ááºáá±ážááá¯ááºááŸá¯ááᯠáá±áá»á¬á á±ááá·áºá¡ááŒáẠáá¬áá¬áá»á¬ážááœáẠáá¯ááºáá±á¬ááºáááœááºáá°á á±áááºá á¡áááá·áºáá áºáá¯áááºážááŒáá·áº áá±á·áá»áá·áºáá±ážááá¯ááºááá¯ááºážáá áºáá¯áá¯á¶ážááᯠáááºá áááºááá¯ááºáááºá
- Google Cloud ááẠá á»á±ážááŒá®ážáá±á¬ áá¬á·ááºáá²ááᯠá ááºážáááºááẠáááºáá»ááºááŸáá·áº á¡áááºááŒá±áá±á¬ áááºážáááºážááŒá áºáááºá ááá¯á·áá±á¬áº áááºááá¯áá áá¯áẠááœá²á·á ááºážááŸá¯áá¯á¶á á¶áá»á¬ážááᯠááœá±ážáá»ááºááẠááá¯á¡ááºáá«áááºá
- áá¯ááºá¡ááá¯ááºážá¡á áá áºáá¯áá»ááºážá á®á á¡ááŒááºááŸá¯ááºážááᯠááá¯ááºážáá¬ááŒááºážááẠá¡áá°ážáááŒáá·áº R ááŸáá·áº C++ ááᯠáá±á«ááºážá ááºááá¯ááºáá±á¬á¡áá«ááœááºá package ááŸáá·áº á¡ááœááºá¡áá¯á¶ážáááºáá«áááºá áá¯á¶ááŸáẠ- á¡áááºážááœááºáá«áááºá
áá±áá¯áá»á¡á¬ážááŒáá·áº á€á¡ááœá±á·á¡ááŒá¯á¶ááẠá¡ááœááºá¡áá»áá¯ážááŸáááŒá®áž áá±á«áºáá±á«ááºáá¬áá±á¬ ááŒá¿áá¬á¡áá»áá¯á·ááᯠááŒá±ááŸááºážááẠáá»áœááºá¯ááºááá¯á· áááºáááºáá¯ááºáá±á¬ááºáá«áááºá
source: www.habr.com