áá ááĽá!
áŁááá áá¸áᣠáŤáá á áĽá
á¨á°áłá ááľáá˝á ááŁá áľáá áąáľá ááááŤá áááá°áĽ ááľáľá á ááá
áˇáᣠá áá
ááľáĽáŁ á¨ááá˝ ááŤá¨á á¨á á áłááá˛áľáśá˝ áĄáľá á¨á°áłá°áá áľáĄ-
á áá
áá á ááłá፠áĽááť áá á áá°áŤá, ááá áá áĽá á áá á°áááŽáá˝ á°ááá°áá, áľááá
á áŤáá áĽá á áááľ á°áááľ áľáŤ ááľáĽ áľá áĽá á áľá°áłá˝ áĽá á áá áááŽá˝ áá
áĽá¨á°á°áĄ áááá áĽááááá. á¨á°ááŤáŠáľ ááá° ááłáŽá˝ ááŤá¨á: áŤá á áľá¸á᪠ááááľ OpenCVJSON áá°áá°á (áĽááá
ááłááá˝ á¨C++ áŽáľá áá° áľááŞááśá˝ ááá áĽá
áá˝ R á áá áá áááááá ááá¨ááŤá á áá˛á.á), á¨áľááŞááśá˝á áááá áĽá á¨áá¨á¨áťáá áááľá áśáá¨á ááľá¨á. áá áááá á°áľáá á áá ááአá¨áááááą á¨á°áá ááá áŽáľ á ááľáĽ ááááá˘
áááśá˝
áááĽá á¨CSV áá° MonetDB á áĽááľ ááŤá áľáĽáľáŚá˝á á áááááľ áá á¨áá¨á ááą ááľáĽ áľáĽáľáŚá˝á áááŤáá á°á°ááááá˝ á¨áá´á á ááá´áá¸á ááá¨áĽ á¨áľááŞááľ áááŞáŤ á¨áľááŞááśá˝á áśáá¨á ááľá¨á á Google á°áá áá á ááŤáł áááŠáá˝á áá áá á¨áá ááá á ááľ áá°áá°ááŤ
1. áááĽá á¨CSV áá° MonetDB á¨ááἠááł á áĽááľ ááŤá
á áá ááľáľá ááľáĽ áŤáá áá¨á á¨áááá á á á°ááá ááľáá˝ áłááá á 340 CSV áááá˝ (ááĽáŤááłááą ááá á ááľ ááá) JSONs á ááĽáĽ ááá ááŤáá˝ á áŤá ááá ááᢠáĽááá á ááĽáŚá˝ á ááľááŽá˝ á áááááľ 256x256 ááá°áá˝ á¨áááŤáá á¨áá¨á¨áť ááľá áĽáááááᢠáĽáá˛áá ááĽáŤááłááą áááἠáľáá áá¨áá á áá°á á°áĽá áľ áá áĽá á áá á áááá ááá˛áá¨á ᣠá¨áľáá ááá á¨áááŞáŤ ááá áŁá áááľ áá°á áŽáľ ᣠáአáá፠ᣠá¨áá áá á°á á¨ááŤááááľ áá፠á á ᢠáĽá á¨ááá áľá áá á¨ááááľ á¨ááá áľá. ááá áŤá á¨ááá áá¨á áľáŞáľ á áá á°áŠ ááľáĽ 7.4 áᢠááááá áĽá á¨á°ááł á áá áá° 20 áᢠáŤá á ááááá ᣠá¨á°ááł á áá áŤáá áá áá¨á 240 áᢠáááľáłáᢠá ááááš áááąá áľáŞáśá˝ á°ááłáłá áľááá˝á ááľááá¸áá á á¨ááá ááᣠáá á áááľ ááá áĽáľá áĽá áá á¨ááááá áá áᢠá ááááá áááł 50 áááŽá ááľáá˝á á ááŤáá áááá˝ ááá á áľááľá ááá áá¨áá¸áľ áá˛áŤáá áľááá áĽááłááá á°ááĽáŽ áááá á¨á˛á¤áľáŞ áááá˝ á¨áá á°áŠ ááľáĽ áááááľ ááľááá áŁáĄá_ááá.áá ááĽáŤááłááą áŁá˝ "á á á¨áŤ áá" á¨ááááá áá á áŤáá¸áá ááľáá˝ á ááŁá áľáááľ áá° áłáłá¤á áŤáľááĄá˘
á á°áἠá¨á°á¨ááá áľáááľ áĽáá° á˛á˘á¤áá¤áľ á°ááá§á áááľ á˛.á˘., áááľá á R áĽáá° áĽá
á á á°ááŁá á
con <- DBI::dbConnect(drv = MonetDBLite::MonetDBLite(), Sys.getenv("DBDIR"))
áááľ á°áá á¨áŚá˝á ááá á á ááĽá-á áá°áá áááá ááἠᣠáááá áľá á¨áá¨áą áááá˝ á¨á áááááľ áá¨á (á ááľ ááá á¨á°áłáłá° áĽá áĽá áááá˝á áŤáá¨áą á áá áá°áą ááá á á áá áľ)
á á¨á´ááá˝á ááá á
if (!DBI::dbExistsTable(con, "doodles")) {
DBI::dbCreateTable(
con = con,
name = "doodles",
fields = c(
"countrycode" = "char(2)",
"drawing" = "text",
"key_id" = "bigint",
"recognized" = "bool",
"timestamp" = "timestamp",
"word" = "text"
)
)
}
if (!DBI::dbExistsTable(con, "upload_log")) {
DBI::dbCreateTable(
con = con,
name = "upload_log",
fields = c(
"id" = "serial",
"file_name" = "text UNIQUE",
"uploaded" = "bool DEFAULT false"
)
)
}
áá¨áá áá° áłáłá¤á áááŤá ááŁá áááᾠᨠCSV áááá˝á SQL - áľáááá á áá áá áá
áłáľ ááᢠCOPY OFFSET 2 INTO tablename FROM path USING DELIMITERS ',','n','"' NULL AS '' BEST EFFORT
á¨áľ tablename
- á¨á á¨á´á áľá áĽá path
- áá° ááá á¨áááľá°á ááááľ. á¨áá
á°áŠ áá á áĽáŽ á ááľáŤáľ áá áĽáŤá á áĽáŽ á¨á°á°áŤá áľáá ፠á°áááˇá unzip
in 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
áĽáá° á°á ááá áľáŤáá á¨ááĽááľ áŁá áŞáá˝ áá á áááľá¨áľ á¨ááἠá¨ááŤá áá áááŤá áá˝ááᢠá áĽá áááł á á ááľ á¤áľá¤áľá˛ ááľáĽ ááá á¨ááá˝ á ááá (ááá ááá) áá° á¤áľá¤áľá˛ (á˛á˘) ááá ἠáĽá ááťá á¨10 á°áá áŤáá° áá áááľáłáá˘
á¨á˘áá˛áá ááá áá፠áĽá á¨áá¨á á áá á ááľ áŤáá á ááľ áááá á áĽááľ á°á¨á᪠á°á¨ááśá˝ áááľáłá (ORDERED INDEX
) áľáĽáľáŚá˝á á áááĽáŠá áľ áá ááá¨áłáá˝ á¨ááááĄáŁá¸á á¨ááľáá ááĽáŽá˝áĄ-
á°á¨á᪠á ááśá˝ áĽá áá፠ááá á
message("Generate lables")
invisible(DBI::dbExecute(con, "ALTER TABLE doodles ADD label_int int"))
invisible(DBI::dbExecute(con, "UPDATE doodles SET label_int = dense_rank() OVER (ORDER BY word) - 1"))
message("Generate row numbers")
invisible(DBI::dbExecute(con, "ALTER TABLE doodles ADD id serial"))
invisible(DBI::dbExecute(con, "CREATE ORDERED INDEX doodles_id_ord_idx ON doodles(id)"))
á á á¨áŤ áá áŁá˝ á¨ááá á á˝ááá ááááłáľ á¨áááá° á¨áľáá˝á á¨á á¨á´áá áá á¨áááŁáľ á¨áá°ááá ááĽááľ ááááľ á ááĽáᢠdoodles
. ááá
á 3 áá´áá˝á á°á ááá. á¨ááááŞáŤá á¨áááá¨áť ááłáááŤáá á¨ááŤá¨áá˝á áľá ááááľ áá á ááááľ áá áᢠá ááááŞáŤá á¨ááἠáľáĽáľáĽ ááľáĽ ááłáááŤáá ááá¨áá¸áľ á¨ááŤáľáááá á áááľ áá bigint
ááá áá á¨ááá¨áłáá˝ áĽááľ áááŤá¸áá á¨áá°á áá ááĽá áá áĽáŠá á¨á áááą áá áááľáááľ áŤáľá˝ááᢠint
. á áá
ááłá áá áááá á áŁá ááŁá áá. ááá°áá áá´ áá áá áá á ORDERED INDEX
- áá°áá
ááłá á¨á°á¨áľáá áááá ááá á ááá á á°á¨áŁá ááᢠPREPARE
á°ááłáłá á áááľ áĽá áá ááá˝á á áááĽáŠá áľ áá á á°ááá á áááá˝ á áá áá ᣠáá á áĽáááą á¨ááá áá á˛ááłá°á áĽá
á á á ᢠSELECT
á áľáłá˛áľá˛ááľ áľá
á°áľ ááá ááľáĽ áá á°áááˇáá˘
áá¨áá á¨ááŤá áá°áľ ᨠ450 áᣠáŤá á áá ááĽá. áŤá áááľáŁ á¨á°áááá á ááŤá¨áĽ á á áľá áááŁááľ á¨áááá á¨ááἠáľáĽáľáŚá˝á á ááááá á¨á ááľ áááľáá áá áĽáá˛áŤáááłá áą ááá áľáááłáᣠá ááłááľ áá á-áŚááľ ááłáŞáŤáá˝á á¨áᎠᣠáááá˘
á¨áá¨á áá á¨(áááá°) áááĽá á¨áááŁáľ ááĽááľá áááŤáľ áĽá á¨á°ááŤá¨ áá á áŤáá¸áá ááááá˝ á˛ááľáą ááŹáąá ááááá áĽáť ááá˘
á¨ááἠááł áááŞáŤ
library(ggplot2)
set.seed(0)
# ĐОдкНŃŃонио Đş йаСо даннŃŃ
con <- DBI::dbConnect(MonetDBLite::MonetDBLite(), Sys.getenv("DBDIR"))
# ФŃнкŃĐ¸Ń Đ´ĐťŃ ĐżĐžĐ´ĐłĐžŃОвки СапŃĐžŃĐ° на ŃŃĐžŃОно ŃĐľŃвоŃĐ°
prep_sql <- function(batch_size) {
sql <- sprintf("PREPARE SELECT id FROM doodles WHERE id IN (%s)",
paste(rep("?", batch_size), collapse = ","))
res <- DBI::dbSendQuery(con, sql)
return(res)
}
# ФŃнкŃĐ¸Ń Đ´ĐťŃ Đ¸ĐˇĐ˛ĐťĐľŃĐľĐ˝Đ¸Ń Đ´Đ°Đ˝Đ˝ŃŃ
fetch_data <- function(rs, batch_size) {
ids <- sample(seq_len(n), batch_size)
res <- DBI::dbFetch(DBI::dbBind(rs, as.list(ids)))
return(res)
}
# ĐŃОводонио СаПоŃĐ°
res_bench <- bench::press(
batch_size = 2^(4:10),
{
rs <- prep_sql(batch_size)
bench::mark(
fetch_data(rs, batch_size),
min_iterations = 50L
)
}
)
# ĐĐ°ŃаПоŃŃŃ ĐąĐľĐ˝ŃПаŃка
cols <- c("batch_size", "min", "median", "max", "itr/sec", "total_time", "n_itr")
res_bench[, cols]
# batch_size min median max `itr/sec` total_time n_itr
# <dbl> <bch:tm> <bch:tm> <bch:tm> <dbl> <bch:tm> <int>
# 1 16 23.6ms 54.02ms 93.43ms 18.8 2.6s 49
# 2 32 38ms 84.83ms 151.55ms 11.4 4.29s 49
# 3 64 63.3ms 175.54ms 248.94ms 5.85 8.54s 50
# 4 128 83.2ms 341.52ms 496.24ms 3.00 16.69s 50
# 5 256 232.8ms 653.21ms 847.44ms 1.58 31.66s 50
# 6 512 784.6ms 1.41s 1.98s 0.740 1.1m 49
# 7 1024 681.7ms 2.72s 4.06s 0.377 2.16m 49
ggplot(res_bench, aes(x = factor(batch_size), y = median, group = 1)) +
geom_point() +
geom_line() +
ylab("median time, s") +
theme_minimal()
DBI::dbDisconnect(con, shutdown = TRUE)
2. áľáĽáľáŚá˝á áááááľ
á á ááá á¨áľáá ááá áľ áá°áľ á¨áá¨á°ááľá á°á¨ááá˝ áŤáŤáľáłá:
- á¨ááĽá¨ááááá˝ áŹáá°áŽá˝á á¨ááĽáĽ ááá ááŤáá˝ áá á¨áŤá á ááŤáł JSONáá˝á áá°áá°áá˘
- á ááááá áá á (áááłá 256Ă256 ááá 128Ă128) ááľá áá á ááĽáŚá˝ ááá ááŤáá˝ áá á áááľá¨áľ áŁáááá ááľááŽá˝á ááłáá˘
- á¨á°áááľá ááľáá˝ áá° á´ááśá ááááĽ.
á áááá áŽáááá˝ ááŤá¨á áĽáá° ááľáľá á áŤáᣠá˝áአá áááááľ á¨á°ááłá á áá áá ááᢠOpenCV. á R ááľáĽ á áŁá ááá áĽá á áŁá ááá á¨áááľ á áááá˝ á ááą áá áá áááľááá˘
á¨JSON áá° Tensor ááá¨áá á á á
r_process_json_str <- function(json, line.width = 3,
color = TRUE, scale = 1) {
# ĐĐ°ŃŃинг JSON
coords <- jsonlite::fromJSON(json, simplifyMatrix = FALSE)
tmp <- tempfile()
# ĐŁĐ´Đ°ĐťŃоП вŃоПоннŃĐš ŃаКН пО СавоŃŃĐľĐ˝Đ¸Ń ŃŃнкŃии
on.exit(unlink(tmp))
png(filename = tmp, width = 256 * scale, height = 256 * scale, pointsize = 1)
# ĐŃŃŃОК ĐłŃĐ°Ńик
plot.new()
# Đ Đ°ĐˇĐźĐľŃ ĐžĐşĐ˝Đ° ĐłŃĐ°Ńика
plot.window(xlim = c(256 * scale, 0), ylim = c(256 * scale, 0))
# ЌвоŃĐ° НиниК
cols <- if (color) rainbow(length(coords)) else "#000000"
for (i in seq_along(coords)) {
lines(x = coords[[i]][[1]] * scale, y = coords[[i]][[2]] * scale,
col = cols[i], lwd = line.width)
}
dev.off()
# ĐŃоОйŃаСОванио иСОйŃĐ°ĐśĐľĐ˝Đ¸Ń Đ˛ 3-Ń
ПоŃĐ˝ŃĐš ПаŃŃив
res <- png::readPNG(tmp)
return(res)
}
r_process_json_vector <- function(x, ...) {
res <- lapply(x, r_process_json_str, ...)
# ĐĐąŃодинонио 3-Ń
ПоŃĐ˝ŃŃ
ПаŃŃивОв каŃŃинОк в 4-Ń
ПоŃĐ˝ŃĐš в ŃонСОŃ
res <- do.call(abind::abind, c(res, along = 0))
return(res)
}
áľáá áá°á á R ááłáŞáŤáá˝á á áá áá áá¨áááá áĽá á RAM ááľáĽ áá°á°á¨áḠáááŤá PNG ááááŁá (á ááááľ áá ᣠáááŤá R áááŤáá˝ á áááŤá ááľáĽ áááá) /tmp
, á RAM ááľáĽ á°ááá). áá
ááá á¨0 áĽáľá¨ 1 á¨áá°ááą ááĽáŽá˝ áŤááľ áŁá áśáľáľ á á
áŁáŤá áľááľá ááá áŁáᢠáá
á áŁá á áľááá áá ááááŤáąá á¨á áá á¨á°ááá° BMP á áááľ ááá áŽáľ áá° áĽáŹ áľááľá áľáááá áĽá˘
áá¤áąá áĽáááľá˝áĄ-
zip_file <- file.path("data", "train_simplified.zip")
csv_file <- "cat.csv"
unzip(zip_file, files = csv_file, exdir = tempdir(),
junkpaths = TRUE, unzip = getOption("unzip"))
tmp_data <- data.table::fread(file.path(tempdir(), csv_file), sep = ",",
select = "drawing", nrows = 10000)
arr <- r_process_json_str(tmp_data[4, drawing])
dim(arr)
# [1] 256 256 3
plot(magick::image_read(arr))
áĄáľá áŤáą áĽáá°áá¨á°áá ááá°á¨áłá-
res <- r_process_json_vector(tmp_data[1:4, drawing], scale = 0.5)
str(res)
# num [1:4, 1:128, 1:128, 1:3] 1 1 1 1 1 1 1 1 1 1 ...
# - attr(*, "dimnames")=List of 4
# ..$ : NULL
# ..$ : NULL
# ..$ : NULL
# ..$ : NULL
áľááá áĄáľáá˝ ááá á á ááŁáĽ áŁááá ááááľ á¨á á áá áľááááľáľ áá áľáá ፠á áŁá áĽáŠ ááľá ááłá áá ááŁáĽáá áááá á¤á°ááá ááľ á áá áá á¨áŁáá°á¨áŚáťá˝áá áááľ ááá áá áá°ááᢠOpenCV. á ááŤá áá á R á¨á°ááá ááŹá á ááá á¨á (á áá á¨áá) áľááá á¨ááááá á°ááŁá á ááľá°á á á°ááŁá á á C ++ ááľáĽ á°á˝áá áá° R áŽáľ á áá áá á áá˛á.á.
á˝ááŠá ááááłáľ á¨áá¨á°ááľ ááŹáá˝ áĽá á¤á° ááťáááľ áĽá á áá áááááĄ
-
OpenCV ááľáá˝á áĽá á¨áľáá ááľááŽá˝á áááľáŤáľ. áŤáááá ááľá á¨á°áŤá á¨áľáááľ á¤á°-ááááá˝ áĽá áŤáľá áááá˝áŁ áĽáá˛áá á°áááá áááááľá˘
-
xtensor á¨áĽá ááŹáľ áľááľáŽá˝ áĽá á´áá°áŽá˝ áá áááľáŤáľá˘ á á°ááłáłá áľá á R áĽá á ááľáĽ á¨á°áŤá°áąáľá á¨áŤáľá áááá˝á á°á áááᢠá¤á° ááá ááą á¨áĽá ááŹáľ áľááľáŽá˝ áá áĽáá˛á°áŠ ááá áľáááłáᣠá á¨áľá áá áĽá á á ááľ áá á á°á á°á¨á°áá˘
-
ndjson JSON á ááá°áá°áᢠáá á¤á°-áá˝áááľ á ááľáĽ áĽá á áá áááá xtensor á ááŽáááą ááľáĽ áŤá á áŤáľ-á°á.
-
RcppThread á¨JSON á¨áŹáá°á áŁááĽá-áá áá°áľá ááá°áŤááľ. á áá áĽá á á¨áá¨áĄáľá á¨áŤáľá áááá˝ á°á á áááᢠá¨á°á¨á᪠áłáá RcppParallel áĽá á á¨ááá˝ áááŽá˝ á á°á¨á᪠á áĽáŽ á¨á°á°áŤ á¨áá ááá¨áĽ áá´ á ááá˘
áá á áἠááŁá á¨áááŁá xtensor á ááááľ áá á°ááᥠá°á á°ááŁá áĽá á¨áá°á á áááá áŤáá áĽáááł á á°á¨á᪠ááá˘ááš á áŁá ááá˝ á°á ááá ááĽáŤááá˝ á ááĽááľ áĽá á áááá áááąá˘ á áĽááą áĽááłáł ᨠOpenCV ááľáŞááľ áááŚá˝á áá° xtensor tensor, áĽáá˛áá áŁá 3-ááŹáľ á¨ááľá ááłáŤáá˝á áá° áŁá 4-ááŹáľ á´áá°á áľáááááá áááŞáŤ (áŁá˝ áĽáŤáą) á¨ááŁáá ááááľá á°ááŁáŤá ááľá¨á á°á˝áá.
Rcppᣠxtensor áĽá RcppThread áááá ááśá˝
á¨áľáááľ áááá˝á áĽá á áľáááą áá á¨á°áŤá á¤á°-ááťáááľ áá á°áááá áááááśá˝á á¨áá áá áááá˝á ááá°áŁá°áĽ á áĽá á ááľáĽ á¨á°á°áá á¨áá á°á°áŞ áá´ á°á á áá áá áᢠá áá˛á.á. áąáŤáá˝á áĽá áŁáá˛áŤáá˝á á áŤáľ á°á áááááľáŁ áłáá á¨ááááľ á áááááľá á°á áááᢠpkg-áá á.
á¨OpenCV á¤á°-áá˝áááľá ááá áá á¨Rcpp á°á°áŞá áá°áá á
Rcpp::registerPlugin("opencv", function() {
# ĐОСПОМнŃĐľ Đ˝Đ°ĐˇĐ˛Đ°Đ˝Đ¸Ń ĐżĐ°ĐşĐľŃĐ°
pkg_config_name <- c("opencv", "opencv4")
# ĐинаŃĐ˝ŃĐš ŃаКН ŃŃиНиŃŃ pkg-config
pkg_config_bin <- Sys.which("pkg-config")
# ĐŃОвŃока наНиŃĐ¸Ń ŃŃиНиŃŃ Đ˛ ŃиŃŃоПо
checkmate::assert_file_exists(pkg_config_bin, access = "x")
# ĐŃОвоŃка наНиŃĐ¸Ń ŃаКНа наŃŃŃОок OpenCV Đ´ĐťŃ pkg-config
check <- sapply(pkg_config_name,
function(pkg) system(paste(pkg_config_bin, pkg)))
if (all(check != 0)) {
stop("OpenCV config for the pkg-config not found", call. = FALSE)
}
pkg_config_name <- pkg_config_name[check == 0]
list(env = list(
PKG_CXXFLAGS = system(paste(pkg_config_bin, "--cflags", pkg_config_name),
intern = TRUE),
PKG_LIBS = system(paste(pkg_config_bin, "--libs", pkg_config_name),
intern = TRUE)
))
})
á á°á°áŞá á á áŤá ááááŤáľ á¨áá¨á°ááľ áĽá´áśá˝ á áá ááá áá°áľ ááľáĽ áá°áŤááĄ
Rcpp:::.plugins$opencv()$env
# $PKG_CXXFLAGS
# [1] "-I/usr/include/opencv"
#
# $PKG_LIBS
# [1] "-lopencv_shape -lopencv_stitching -lopencv_superres -lopencv_videostab -lopencv_aruco -lopencv_bgsegm -lopencv_bioinspired -lopencv_ccalib -lopencv_datasets -lopencv_dpm -lopencv_face -lopencv_freetype -lopencv_fuzzy -lopencv_hdf -lopencv_line_descriptor -lopencv_optflow -lopencv_video -lopencv_plot -lopencv_reg -lopencv_saliency -lopencv_stereo -lopencv_structured_light -lopencv_phase_unwrapping -lopencv_rgbd -lopencv_viz -lopencv_surface_matching -lopencv_text -lopencv_ximgproc -lopencv_calib3d -lopencv_features2d -lopencv_flann -lopencv_xobjdetect -lopencv_objdetect -lopencv_ml -lopencv_xphoto -lopencv_highgui -lopencv_videoio -lopencv_imgcodecs -lopencv_photo -lopencv_imgproc -lopencv_core"
JSON á ááá°áá°á áĽá áá° á ááłáŤá áááľá°ááá áľáá á¨áááá¨áľ á¨áľáá ፠áŽáľ á á áĽáá áľá á°á°áĽáˇáᢠá ááááŞáŤáŁ á¨áŤáľá áááá˝á ááááá á¨á áŤáŁá˘ á¨ááŽáááľ áá፠áŤáá (á ndjson áŤáľáááá)
Sys.setenv("PKG_CXXFLAGS" = paste0("-I", normalizePath(file.path("src"))))
á C++ ááľáĽ á¨JSON áá° tensor ááᣠáá°áá á
// [[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
) áá° tensorxt::xtensor
; -
parse_json
- á°ááŁáŠ ᨠJSON ááĽá¨áááá áá°ááľáá ᣠá¨ááĽáŚá˝á ááá ááŤáá˝ áŤááŁá ᣠáá° áŹáá°á á áá¸á ᣠ-
ocv_draw_lines
- á¨á°áá á¨á á¨áŹáá°á ááĽáŚá˝, áŁááĽá ááá ááľááŽá˝á ááľáá; -
process
- á¨áá áŤááľá á°ááŁáŤáľ áŤáŁááŤá áĽáá˛áá á¨á°áááá ááľá á¨áá á á˝ááłá áá¨ááŤá; -
cpp_process_json_str
- á á°ááŁáŠ áá áá á ááŤprocess
áá¤áąá áá° R-object (multidimensional array) áá° áá á¨ááá; -
cpp_process_json_vector
- á á°ááŁáŠ áá áá á ááŤcpp_process_json_str
, áá á áŁááĽá-áá áááł ááľáĽ 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. á¨áá¨á ááą ááľáĽ áľáĽáľáŚá˝á áááŤáá á°á°ááááá˝
R ᨠRAM áá á¨ááľáá áá¨áá á áááááľ á¨ááľ áĽáŠ áľá áŤáá á˛áá áááá á áá áἠá¨ááłááá á á°á°ááá áá¨áá á áááááľ á˛áá áá á á¨áá á᪠á¨áá áľááśá˝á (ááŤá áá á°á¨ áľááľáłá á áá áá áľááśá˝á) á ááá áĽá á á°ááĽáŽ á°ááŁáŤá áááľá¨á áŤáľá˝ááᢠá¨á°ááá¸á á˝áá á ááá ááĽá á¨ááłááá áĽá á áá ááłá á áĽáááľ áá¨áľ áá´ á¨á°áá á áĽáá ááá ááľáááŽá˝ á áĽáŤááłááą á°á¨á áá áŤááá á¨ááŤá˛á¨ááľ áá áááľ á áľáá˝ ááá¨áłáá˝ ááá áá áŁá˝ á áá áá ááá˘
á Python ááľáĽ á¨á°áá áĽáá á¨áááŞáŤ ááááá˝ á áá¨á áá á°ááľáá°á á°á°ááááá˝á á¨áá°ááĽáŠ áአáááá˝ á áá¸á: á°áá á¨áŚá˝, á á áááá˝ ááľáĽ áŤá áľááá˝, áááľáŽá˝ á áááśá˝, ááá°. ááá á¨áá á ááŤáŽá˝á áá áá ááá áá°áá°á áľáŤáá˝ á¨áŤáľáá ááťá áá˝áá. á R ááľáĽ áááá ᨠPython á¤á°-áá˝áááľ áŁá áŞáŤáľ áá áá áĽáá˝ááá keras á¨á°ááŤáŠ áááŁáá˝ áá á°ááłáłá áľá áŤáá áĽá á á áá áá, áĽáąá á á°áŤá á áĽá á áá áá áŤá áĽáá°áá á ááŁá áĽ. á¨áááá á¨á°áᨠá¨á á á˝áá áááŁáá; ᨠPython áŽáľá ᨠR áĽáá˛áŤááą áĽáť áłááá áááŽá˝á á R áĽá Python ááá áááá˝ ááŤá¨á áĽáá˛áŤáľá°ááá ááá áľáááłá ᣠáá á áááá á áľááá áááŚá˝á á áŤáľ-á°á áŤá¨ááááá˘
MonetDLite á á áá áá áááá áá¨ááá˝ á RAM ááľáĽ á¨áá¨áá¸áľ á áľáááááľá á áľááá°áá ᣠááá âá¨ááá á ááłá¨ áá¨áĽâ áĽáŤ á¨áá¨áááá á Python ááľáĽ áŁáá áŚáŞá áá áŽáľ áá ᣠááá ááá á¨áá ááá áľááá á áá¨áá áá á°á°ááá ááá á ááĽáᢠá R ááá Python ááľáĽ áĽáá°áá ááá áááł. ááĽáą á áá á¨áą áááľ ááľáááśá˝ áĽáť á á-áĄáľáášá ááá፠á ááá áá°áľ ááááľ áĽá á áľáááá˝ ááŤá¨á áŤááá áááł ááá ἠá áá áľ (á R ááľáĽ áŤáá á¨áááá ááááŤáá˝á á áá áá á ááá ááááľ áá°áá áŤá)ᢠá¨áá áá°á ᨠR áľááľáá á áľááá ááľáĽ áá° ááĽá áľááľá ááá¨á áá á á áĽááᣠááá áá á¨á áá á¨áĽá á áľáŞáľá˘ keras áĽáŤáˇ áłá°áááá˝á˘
á¨áĽáá á áĽá á¨áá¨áá፠áá¨áá á°á°áááá á¨áá¨á°áá áá á°áááˇáá˘
á¨áĽáá á áĽá á¨áá¨áá፠ááἠá°ááá
train_generator <- function(db_connection = con,
samples_index,
num_classes = 340,
batch_size = 32,
scale = 1,
color = FALSE,
imagenet_preproc = FALSE) {
# ĐŃОвоŃка Đ°ŃĐłŃПонŃОв
checkmate::assert_class(con, "DBIConnection")
checkmate::assert_integerish(samples_index)
checkmate::assert_count(num_classes)
checkmate::assert_count(batch_size)
checkmate::assert_number(scale, lower = 0.001, upper = 5)
checkmate::assert_flag(color)
checkmate::assert_flag(imagenet_preproc)
# ĐĐľŃоПоŃиваоП, ŃŃĐžĐąŃ ĐąŃĐ°ŃŃ Đ¸ ŃĐ´Đ°ĐťŃŃŃ Đ¸ŃпОНŃСОваннŃĐľ индокŃŃ ĐąĐ°ŃŃоК пО пОŃŃĐ´ĐşŃ
dt <- data.table::data.table(id = sample(samples_index))
# ĐŃĐžŃŃавНŃоП нОПоŃĐ° йаŃŃоК
dt[, batch := (.I - 1L) %/% batch_size + 1L]
# ĐŃŃавНŃоП ŃОНŃкО пОНнŃĐľ йаŃŃи и индокŃиŃŃоП
dt <- dt[, if (.N == batch_size) .SD, keyby = batch]
# ĐŁŃŃанавНиваоП ŃŃŃŃŃик
i <- 1
# ĐОНиŃĐľŃŃвО йаŃŃоК
max_i <- dt[, max(batch)]
# ĐОдгОŃОвка вŃŃĐ°ĐśĐľĐ˝Đ¸Ń Đ´ĐťŃ Đ˛ŃĐłŃŃСки
sql <- sprintf(
"PREPARE SELECT drawing, label_int FROM doodles WHERE id IN (%s)",
paste(rep("?", batch_size), collapse = ",")
)
res <- DBI::dbSendQuery(con, sql)
# ĐнаНОг keras::to_categorical
to_categorical <- function(x, num) {
n <- length(x)
m <- numeric(n * num)
m[x * n + seq_len(n)] <- 1
dim(m) <- c(n, num)
return(m)
}
# ĐĐ°ĐźŃканио
function() {
# ĐĐ°ŃинаоП нОвŃŃ ŃпОŃ
Ń
if (i > max_i) {
dt[, id := sample(id)]
data.table::setkey(dt, batch)
# ĐĄĐąŃĐ°ŃŃваоП ŃŃŃŃŃик
i <<- 1
max_i <<- dt[, max(batch)]
}
# ID Đ´ĐťŃ Đ˛ŃĐłŃŃСки даннŃŃ
batch_ind <- dt[batch == i, id]
# ĐŃĐłŃŃСка даннŃŃ
batch <- DBI::dbFetch(DBI::dbBind(res, as.list(batch_ind)), n = -1)
# УвоНиŃиваоП ŃŃŃŃŃик
i <<- i + 1
# ĐĐ°ŃŃинг JSON и пОдгОŃОвка ПаŃŃива
batch_x <- cpp_process_json_vector(batch$drawing, scale = scale, color = color)
if (imagenet_preproc) {
# ШкаНиŃОванио c инŃĐľŃваНа [0, 1] на инŃĐľŃваН [-1, 1]
batch_x <- (batch_x - 0.5) * 2
}
batch_y <- to_categorical(batch$label_int, num_classes)
result <- list(batch_x, batch_y)
return(result)
}
}
á°ááŁáŠ á¨áá¨á ááą áá áŤáá ááááᾠᣠáĽá
á áá á¨áá á¨ááľááŽá˝ áĽáᾠᣠá¨áááá˝ áĽáᾠᣠá¨áľáĽáľáĽ áá á ᣠááá áŤáá á°áááá áĽáá° ááĽááľ áááľáłáá˘scale = 1
ᨠ256x256 ááá°áá˝ ááľáá˝á á¨ááľá áľ áá ááááłá ᣠscale = 0.5
- 128x128 ááá°áá˝) ᣠá¨ááá á áááŤá˝ (color = FALSE
áĽá
á áá á áááá áľ áá á ááŤáŤ áá á ááľá áľá ááááťá color = TRUE
áĽáŤááłááą áľáľáŽá á á á˛áľ ááá ááłáá) áĽá á ááľáááľ áá á áľááľá á¨á°áá á á ááłá¨ áá¨áŚá˝ á
áľá-áá°áľ á áááŤá˝á˘ á¨ááá°á áĽá´áśá˝á á¨ááŤá¨á [0, 1] áá° ááá°áľ [-1, 1] ááááŤáľ á¨áááá áŤáľáááá, áá
á á¨áá¨á áá á áá°áá á áá áĽá
á áá áááá. keras áá´áá˝á˘
ááŤáá á°ááŁá á¨áááá á áááľ ááá°á˝áŁ á áá á¨áĽ ááá data.table
á áááá° á¨á°á°áŁáá ááľáá ááĽáŽá˝ ᨠsamples_index
áĽá áŁá˝ ááĽáŽá˝áŁ ááŁáŞ áĽá á¨áá°áá á¨áŁá˝á˝ áĽááľáŁ áĽáá˛áá á¨ááἠááł ááἠáááŤáá ᨠSQL á áááá˝á˘ á á°á¨ááŞáᣠá ááľáĄ áŤááá á°ááŁá ááŁá á ááá ááá˝áᢠkeras::to_categorical()
. áááá áá¨ááá˝ ááľáá á á°á áááá áľáŁ ááášá á ááśáá ááá¨áá፠áľá°ááᣠáľááá
á¨ááá áá á á áááŞáŤ á¨á°áá°á áá áᢠsteps_per_epoch
á˛á ፠keras::fit_generator()
, áĽá áááłá if (i > max_i)
ááá¨áá፠áľáá áĽáť á°ááˇáá˘
á ááľáŁáá á°ááŁá ááľáĽ á¨á¨áľá á˘áá´ááśá˝ áááŁáŠ áŁá˝ á°á°ááľá¨ááᣠááááŚá˝ á¨áá¨á ááą ááááłá á¨áŁá˝ ááŁáŞá áĽá¨á¨áá¨áŁ JSON áá°áá°á (á°ááŁá) cpp_process_json_vector()
ᣠá C ++ á¨á°áá) áĽá á¨áľááá˝ áá á¨ááááą áľááľáŽá˝á ááá áᢠá¨á፠á ááľ-áľáŠáľ áŹáá°áŽá˝ á¨ááá áááŤáá˝ áá ááá áŤá ᣠá¨ááá°á áĽá´áśá˝ áĽá áááŤáá˝ áá° áááá ááŁááŤá ᣠáá
á á¨ááááť áá ááᢠáĽáŤá áááá á á á á¨á´ááá˝ ááľáĽ á˘áá´ááśá˝á ááá áá áĽáá áááá data.table
áĽá á á ááá á áŠá ááťáťáŤ - áŤá áĽááá
áĽá
á âáşááľâ áłáł á á á ááľáĽ á¨ááááá ááá
á¨áá á¨ááἠáá á áá áá¤áłá á áá ááááľ áááľáŤáľ áá°áĽ á áŁá á¨áŁáľ ááá˘
á Core i5 áááśá áá á¨ááĽááľ áááŞáŤáá˝ áá¤áśá˝ áĽáá°áá¨á°áá áá¸áá˘
á˘á°áá°á á¤áá˝ááá
library(Rcpp)
library(keras)
library(ggplot2)
source("utils/rcpp.R")
source("utils/keras_iterator.R")
con <- DBI::dbConnect(drv = MonetDBLite::MonetDBLite(), Sys.getenv("DBDIR"))
ind <- seq_len(DBI::dbGetQuery(con, "SELECT count(*) FROM doodles")[[1L]])
num_classes <- DBI::dbGetQuery(con, "SELECT max(label_int) + 1 FROM doodles")[[1L]]
# ĐндокŃŃ Đ´ĐťŃ ĐžĐąŃŃĐ°ŃŃоК вŃйОŃки
train_ind <- sample(ind, floor(length(ind) * 0.995))
# ĐндокŃŃ Đ´ĐťŃ ĐżŃОвоŃĐžŃнОК вŃйОŃки
val_ind <- ind[-train_ind]
rm(ind)
# ĐĐžŃŃŃиŃĐ¸ĐľĐ˝Ń ĐźĐ°ŃŃŃайа
scale <- 0.5
# ĐŃОводонио СаПоŃĐ°
res_bench <- bench::press(
batch_size = 2^(4:10),
{
it1 <- train_generator(
db_connection = con,
samples_index = train_ind,
num_classes = num_classes,
batch_size = batch_size,
scale = scale
)
bench::mark(
it1(),
min_iterations = 50L
)
}
)
# ĐĐ°ŃаПоŃŃŃ ĐąĐľĐ˝ŃПаŃка
cols <- c("batch_size", "min", "median", "max", "itr/sec", "total_time", "n_itr")
res_bench[, cols]
# batch_size min median max `itr/sec` total_time n_itr
# <dbl> <bch:tm> <bch:tm> <bch:tm> <dbl> <bch:tm> <int>
# 1 16 25ms 64.36ms 92.2ms 15.9 3.09s 49
# 2 32 48.4ms 118.13ms 197.24ms 8.17 5.88s 48
# 3 64 69.3ms 117.93ms 181.14ms 8.57 5.83s 50
# 4 128 157.2ms 240.74ms 503.87ms 3.85 12.71s 49
# 5 256 359.3ms 613.52ms 988.73ms 1.54 30.5s 47
# 6 512 884.7ms 1.53s 2.07s 0.674 1.11m 45
# 7 1024 2.7s 3.83s 5.47s 0.261 2.81m 44
ggplot(res_bench, aes(x = factor(batch_size), y = median, group = 1)) +
geom_point() +
geom_line() +
ylab("median time, s") +
theme_minimal()
DBI::dbDisconnect(con, shutdown = TRUE)
á á áá á áŤáá áŤá áŤáááľ á¨ááἠááłáá áá°áá
á°ááłáłá áŤá á áááá áľáŤáá á áá ááá ááá á áá˝áá (32 áᢠáá°ááŁáŤá˝á á á áá)ᢠá ááááľ ááľáĽ ááአá ááŁáŞááľ á°ááá /dev/shm
, áĽáľá¨ ááá˝ RAM á á
á á¨ááá. á áááľá á¨á áá ááľáá
áá˝ááᢠ/etc/fstab
áĽáá° áŞá¨ááľ áááááľ tmpfs /dev/shm tmpfs defaults,size=25g 0 0
. áľáááá á áááľ áĽáá°áá ááľááá áĽá áá¤áąá áá¨áááĽáá áŤá¨ááᥠdf -h
.
á¨áá¨áŤ ááἠáľáĽáľáĽ áá á áá ᨠRAM áá áľáááŁáŁá ááá¨áŤ ááἠá°á°áááá á áŁá ááá áááľááá˘
ááá¨áŤ ááἠá°ááá
test_generator <- function(dt,
batch_size = 32,
scale = 1,
color = FALSE,
imagenet_preproc = FALSE) {
# ĐŃОвоŃка Đ°ŃĐłŃПонŃОв
checkmate::assert_data_table(dt)
checkmate::assert_count(batch_size)
checkmate::assert_number(scale, lower = 0.001, upper = 5)
checkmate::assert_flag(color)
checkmate::assert_flag(imagenet_preproc)
# ĐŃĐžŃŃавНŃоП нОПоŃĐ° йаŃŃоК
dt[, batch := (.I - 1L) %/% batch_size + 1L]
data.table::setkey(dt, batch)
i <- 1
max_i <- dt[, max(batch)]
# ĐĐ°ĐźŃканио
function() {
batch_x <- cpp_process_json_vector(dt[batch == i, drawing],
scale = scale, color = color)
if (imagenet_preproc) {
# ШкаНиŃОванио c инŃĐľŃваНа [0, 1] на инŃĐľŃваН [-1, 1]
batch_x <- (batch_x - 0.5) * 2
}
result <- list(batch_x)
i <<- i + 1
return(result)
}
}
4. á¨áá´á á ááá´áá¸á áááŤ
áĽá
á áá á¨ááá á¨ááááŞáŤá á ááá´áá¸á áá á (batch, height, width, 3)
ᣠáááľá ᣠá¨á°ááŚá˝ áĽááľ ááá¨á á áá˝ááᢠá áááá ááľáĽ áĽáá°áá
áŤá áá°áĽ á¨ááᣠáľááá
ááĽáá á¨áá
á á ááá´áá¸á á á°ááŁá á á¨áŤáłá˝áá á
áááᣠáááá ááŁáĽá á°á¨áľáá (á 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)
}
á¨áá
á á°áŤá ááłáśá˝ ááá˝ áá¸á. áĽá áá´áá˝á ááá¨á áĽááááá, áá á á°ááŤáá, áĽáŤááłááąá á ááá´áá¸á áĽáá°áá ááťá á ááááá. áĽáá˛áá á ááľáááľ áá ááľáá á¨á°áá á áá´áá˝á ááĽá°áľ ááá áá áĽáľáá á°áááá áá áᢠáĽáá°á°ááá°á, á°ááśášá ááĽááľ á¨áľáˇá. á°ááŁá 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 á ááľáááľ áá á¨á°áá á ááĽá°áľ áŤáá¸á ááá á¨ááá¸á áá´áá˝áĄ-
ááá á¨áá á ááá´ááśá˝á áááŤá á°ááŁá
get_model <- function(name = "mobilenet_v2",
input_shape = NULL,
weights = "imagenet",
pooling = "avg",
num_classes = NULL,
optimizer = keras::optimizer_adam(lr = 0.002),
loss = "categorical_crossentropy",
metrics = NULL,
color = TRUE,
compile = FALSE) {
# ĐŃОвоŃка Đ°ŃĐłŃПонŃОв
checkmate::assert_string(name)
checkmate::assert_integerish(input_shape, lower = 1, upper = 256, len = 3)
checkmate::assert_count(num_classes)
checkmate::assert_flag(color)
checkmate::assert_flag(compile)
# ĐОНŃŃаоП ОйŃĐľĐşŃ Đ¸Đˇ пакоŃĐ° keras
model_fun <- get0(paste0("application_", name), envir = asNamespace("keras"))
# ĐŃОвоŃка наНиŃĐ¸Ń ĐžĐąŃокŃĐ° в пакоŃĐľ
if (is.null(model_fun)) {
stop("Model ", shQuote(name), " not found.", call. = FALSE)
}
base_model <- model_fun(
input_shape = input_shape,
include_top = FALSE,
weights = weights,
pooling = pooling
)
# ĐŃНи иСОйŃаМонио но ŃвоŃнОо, ПонŃоП ŃаСПоŃнОŃŃŃ Đ˛Ń
Ода
if (!color) {
base_model_conf <- keras::get_config(base_model)
base_model_conf$layers[[1]]$config$batch_input_shape[[4]] <- 1L
base_model <- keras::from_config(base_model_conf)
}
predictions <- keras::get_layer(base_model, "global_average_pooling2d_1")$output
predictions <- keras::layer_dense(predictions, units = num_classes, activation = "softmax")
model <- keras::keras_model(
inputs = base_model$input,
outputs = predictions
)
if (compile) {
keras::compile(
object = model,
optimizer = optimizer,
loss = loss,
metrics = metrics
)
}
return(model)
}
áá á-á°áἠááľáá˝á á áá ááá áľ áá, ááá ááááľ ááľá á¨á°áá á ááĽá°áśá˝ áĽá
á áá á áááá. áá
ááľá°áŤá¨á áá˝áá: á°ááŁáŠá á áá áá get_weights()
á¨áá´áá ááĽá°áśá˝ á R áľááľáŽá˝ áááá ááľáĽ áŤáá ᣠá¨áá
á áááá á¨ááááŞáŤ á áŤá ááŹáľ áááᥠ(á ááľ áŁá ááá á°áἠááá á ááŤá áŚáľáąá) áááᥠáĽá á¨á፠á á°ááŁáŠ áá° áá´á ááá°á ááŤáᢠset_weights()
. áá
áá á°ááŁá á ááŤá˝ á áá¨áá¨áá, ááááŤáąá á áá
á°á¨á áá á¨ááá áľááá˝ áá ááľáŤáľ á¨á áá áá¤áłá áĽáá°áá ááľááá ááá˝ áá á.
á áĽáááášá áá¨áŤáá˝ á¨á°áŤáá á¨ááŁáá ááľ áľáŞáľ 1 áĽá 2 áĽáá˛áá resnet34á á áá áá ááᢠáĽáá° SE-ResNeXt áŤá á°á¨á᪠áááá á ááá´áá¸á á áá ááľáľá áĽáŠ á ááťá¸á á áłáá°ááᢠáĽáá° á áááłá°á áá áĽá á áĽáá˝á ááá á¨áá á á°ááŁá á á ááá á¨áá áĽá á¨áŤáłá˝áá á ááťááá (áá á áĽááá áááľ áĽáá˝ááá)á˘
5. á¨áľááŞááśá˝ áááŞáŤ
ááážáľ á˛áŁá ááá á¨áĽáá á áŽáśá˝ áĽáá° áá á áľááŞááľ á°ááá
á°á á°ááá
á°á á°ááá
á°ááá˘
doc <- '
Usage:
train_nn.R --help
train_nn.R --list-models
train_nn.R [options]
Options:
-h --help Show this message.
-l --list-models List available models.
-m --model=<model> Neural network model name [default: mobilenet_v2].
-b --batch-size=<size> Batch size [default: 32].
-s --scale-factor=<ratio> Scale factor [default: 0.5].
-c --color Use color lines [default: FALSE].
-d --db-dir=<path> Path to database directory [default: Sys.getenv("db_dir")].
-r --validate-ratio=<ratio> Validate sample ratio [default: 0.995].
-n --n-gpu=<number> Number of GPUs [default: 1].
'
args <- docopt::docopt(doc)
áĽá
á áśáŽááľ á á°ááŁá áŠá ááááá Rscript bin/train_nn.R -m resnet50 -c -d /home/andrey/doodle_db
ááá ./bin/train_nn.R -m resnet50 -c -d /home/andrey/doodle_db
, ááá á¨áá train_nn.R
á°ááťá áá (áá
áľááá áá´áá áá°áá á ááááŤá resnet50
128x128 ááá°áá˝ á ááአáŁá áśáľáľ ááá ááľáá˝ áá á¨ááἠááłá á á ááá ááľáĽ áááἠá áá áľ /home/andrey/doodle_db
). á áááአááľáĽ á¨ááá ááĽááľáŁ á ááťá˝ á áááľ áĽá ááá˝ áá á á¨áá˝á áááŞáŤáá˝á áá¨á áá˝ááᢠá
áľááąá á áááááľ áá°áľ ááľáĽ, áľá-á
ááá á°áááˇá mobilenet_v2
á¨á áá áľáŞáľ keras á R á á ááá
áá
á áŤááľ á RStudio ááľáĽ áŤááľ á¨áľááŞááľ á
áá áá á˛áááá á á°ááŤáŠ áá´áá˝ áá¨áŤáá˝á á á¨áá°á áááł áááá á á áľá˝ááłá (áĽá
áá áĽáá° á ááŤá á ááŤá áĽááľá°áááá)
6. á¨áľááŞááśá˝á áśáá¨á ááľá¨á
á áĄáľá á áŁááľ ááŤá¨á ááľáá á áá´áá˝ áĽá á á°áá ááľáĽ á ááĽááľ ááá°ááŤáľ á¨á áŤáŁá˘á á°áááłáá˝ááľ ááá¨ááἠDockerá á°á áááᢠá R ááŽááŤáá á á áááŤáááľ áŤáá°ááá°á á¨áá
ááłáŞáŤ áá áá°ááá
áľá˝ááá˝á
Docker áááąáá á¨áĽáŤáľáá ááľáá˝ á¨áŁáś áĽáá˛ááĽáŠ áĽá á¨áŤáľáá áááá á ááá˝ ááľáá˝á áĽáá˛á áá ááá
áľáááłáᢠáŤááľá á ááŤáŽá˝ áľááá¨áá á¨NVDIAᣠCUDA+cuDNN ážááŽá˝ áĽá Python á¤á°ááá
ááľá ááŤá á¨ááľá áľáá
ááá áá áá°áá áá°áá°á፠áá á°áá°ááᣠáĽá ááááá ááľá áĽáá° áá°á¨áľ áááá°áľ ááľáááᢠtensorflow/tensorflow:1.12.0-gpu
, áĽá፠á áľááááášá ᨠR ááŹáá˝á áá¨áá.
á¨áá¨á¨áťá áśá¨á ááá áá á áááľááá˘
Dockerfile
FROM tensorflow/tensorflow:1.12.0-gpu
MAINTAINER Artem Klevtsov <[email protected]>
SHELL ["/bin/bash", "-c"]
ARG LOCALE="en_US.UTF-8"
ARG APT_PKG="libopencv-dev r-base r-base-dev littler"
ARG R_BIN_PKG="futile.logger checkmate data.table rcpp rapidjsonr dbi keras jsonlite curl digest remotes"
ARG R_SRC_PKG="xtensor RcppThread docopt MonetDBLite"
ARG PY_PIP_PKG="keras"
ARG DIRS="/db /app /app/data /app/models /app/logs"
RUN source /etc/os-release &&
echo "deb https://cloud.r-project.org/bin/linux/ubuntu ${UBUNTU_CODENAME}-cran35/" > /etc/apt/sources.list.d/cran35.list &&
apt-key adv --keyserver keyserver.ubuntu.com --recv-keys E084DAB9 &&
add-apt-repository -y ppa:marutter/c2d4u3.5 &&
add-apt-repository -y ppa:timsc/opencv-3.4 &&
apt-get update &&
apt-get install -y locales &&
locale-gen ${LOCALE} &&
apt-get install -y --no-install-recommends ${APT_PKG} &&
ln -s /usr/lib/R/site-library/littler/examples/install.r /usr/local/bin/install.r &&
ln -s /usr/lib/R/site-library/littler/examples/install2.r /usr/local/bin/install2.r &&
ln -s /usr/lib/R/site-library/littler/examples/installGithub.r /usr/local/bin/installGithub.r &&
echo 'options(Ncpus = parallel::detectCores())' >> /etc/R/Rprofile.site &&
echo 'options(repos = c(CRAN = "https://cloud.r-project.org"))' >> /etc/R/Rprofile.site &&
apt-get install -y $(printf "r-cran-%s " ${R_BIN_PKG}) &&
install.r ${R_SRC_PKG} &&
pip install ${PY_PIP_PKG} &&
mkdir -p ${DIRS} &&
chmod 777 ${DIRS} &&
rm -rf /tmp/downloaded_packages/ /tmp/*.rds &&
rm -rf /var/lib/apt/lists/*
COPY utils /app/utils
COPY src /app/src
COPY tests /app/tests
COPY bin/*.R /app/
ENV DBDIR="/db"
ENV CUDA_HOME="/usr/local/cuda"
ENV PATH="/app:${PATH}"
WORKDIR /app
VOLUME /db
VOLUME /app
CMD bash
ááááťá¸áľ, áĽá
á áá á¨áá áĽá
áá˝ áá° á°ááááŽá˝ á°ááá áá; á áĽááááš á¨á°áá áľááŞááśá˝ á áŽáá´áááŽá˝ ááľáĽ á áá°á á°áĄá áľ áá áááá áŁá. á¨áľáĽáá ááááá áá° ááá¨ááá /bin/bash
ááááľ á á ááá áááááľ /etc/os-release
. áá
á áŽáą ááľáĽ á¨áľááá° ááááá áľáŞáľ á¨áááá˝ á áľáááááľá á áľáááˇá.
á á°á¨ááŞáᣠá¨á°ááŤáŠ áľáááá˝á á¨áŤá ááŤáŁ áááľááá á¨ááŤáľá˝á áľáá˝ á¨áŁá˝ áľááŞááľ á°á˝á áá áᢠáááłáᣠáĽááá áá°á á˛á á ááŤáŁá ááľáĽ á¨á°ááᥠá¨ááá ááľáááŽá˝á ááá°áá á áľááŞááśá˝áŁ ááá á¨áĽááá áá°áľ ááá¨á áĽá ááá¨áłá°á á¨áľáĽáá áźá ááá áá˝ááá˘
ááŤáŁáá áááľááá áľááŞááľ
#!/bin/sh
DBDIR=${PWD}/db
LOGSDIR=${PWD}/logs
MODELDIR=${PWD}/models
DATADIR=${PWD}/data
ARGS="--runtime=nvidia --rm -v ${DBDIR}:/db -v ${LOGSDIR}:/app/logs -v ${MODELDIR}:/app/models -v ${DATADIR}:/app/data"
if [ -z "$1" ]; then
CMD="Rscript /app/train_nn.R"
elif [ "$1" = "bash" ]; then
ARGS="${ARGS} -ti"
else
CMD="Rscript /app/train_nn.R $@"
fi
docker run ${ARGS} doodles-tf ${CMD}
áá
á¨áŁá˝ áľááŞááľ áŤá áááááá˝ á¨áá°áŤ á¨áá áľááŞááą á ááŤáŁá ááľáĽ áá áŤá train_nn.R
á¨ááŁáŞ áĽá´áśá˝ áá; á¨ááááŞáŤá á¨á áááἠáááá "bash" á¨áá, ááŤáŁá á¨áľááá áźá áá á ááá°ááá ááááŤá. á ááá˝ á ááá áááłáὠᣠá¨á áááἠáá᪠áĽá´áśá˝ áĽá´áśá˝ á°á°áá°áá- CMD="Rscript /app/train_nn.R $@"
.
á¨ááá ááἠáĽá á¨ááἠááł áŤáá¸á áááŤáá˝ áĽáá˛áá á¨á°áá á áá´áá˝á áááłá áááŤá á¨á áľá°ááá áľáááľ ááľáĽ á ááŤáŁá ááľáĽ á°áááá ᣠáá á á¨áľááŞááľ áá¤áśá˝á áŤá á ááľááá ááá áá áŽá˝ áĽáá˛áŤáá á¨ááŤáľá˝áá ááá áἠááŁá áááŁá á˘
7. á ááá ááááľ áá á ááŤáł áááŠáá˝á áá áá
á¨ááľáľáŠ á ááą áŁá
᪠á áŁá áŤáŤáł áŤáá áá¨á áá á (á¨áááľ áľááá áááá¨áąáŁ á¨@Leigh.plt ᨠODS slack á¨á°áá°áą)ᢠáľááá
áľáĽáľáŚá˝ áá
áá áááááľ áá¨áłá, áĽá á áᲠáá ᨠ1 ááአáá á¨á°á°á¨á áá¨áŤáá˝ á áá, á á°áá ááľáĽ á á ááŤáł áááŠáá˝ áá á¨áľáá á áá´áá˝á ááááŁá á áá°áá. áŤáááá GoogleCloud (dev/shm
.
á áŁá á¨ááľá á áĽá áááŠáá˝á á¨áá áá áááááľ áŤáá á¨áŽáľ áááĽáŤá ááᢠá ááááŞáŤáŁ áá´á á á˛áአáá á¨á°áá ᨠá ááľ á áľá°áłáłáŞá á áá áá ááᣠáá á áááá ááľáĽáĄ-
with(tensorflow::tf$device("/cpu:0"), {
model_cpu <- get_model(
name = model_name,
input_shape = input_shape,
weights = weights,
metrics =(top_3_categorical_accuracy,
compile = FALSE
)
})
á¨á፠áŤáá°á ááᨠ(áá á áľááá áá) áá´á áá°áá°ááľ áááŠáá˝ áááá áŁá áĽá á¨á፠á áá áĽáť ááááááĄ
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)
)
á¨áá¨á¨áťá á áľá°áá áááá ááĽááĽáŽá˝ á¨áááááᣠá¨áá¨á¨áťáá ááĽááĽá á¨áá°áá áᣠáááá áá´á ááĽá áááŠáá˝ á¨áááŁáľ áĽá á¨áá°áá á ááá˛á á´ááá áá°áá á á ááťááá˘
áľáá á áłáá ááá áľ ááľáľá á°á°áááᢠ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
á á¤á° ááťáááľ ááľáĽ ááŁá.á á); á á°áá°á áĽá¨áľ á¨áśáľá°á ááá á á°ááŁá áá áá° á á ááá ááťáá áááłááĄ-áá ; - á áá°áá ááĽáĽ ááááŤáľ áĽá áááŠáá˝á á˛á áá áľáááááá á¨áĽáá á ááĽááľ ááá¨áĽ á áá°áťááá˘
- á á°ááá á ááľáááľ áá ááľá á¨á°áá á áááá á¨ááá á ááłá¨áá¨áĽ á ááá´áá¸á áĽáĽá¨áľ á á á˘
- ááá á¨áá°áľ ááᲠáĽá ááľáá á á¨áááŞáŤ á°ááá˝ (á¨áŽáłáá áá°ááᣠá áĽá áĽáŤá áá áá˘
á°á°ááĽáŻá , á áá°ááááskydan ).
á¨áá ááľáľá áá á áá áááŽá˝ á°áá¨áááĄ-
- á á áááŤáááľ áá á°á ááá áŁáá áááľáá áá áŤá á áá áĽáŠ (áĽá áá ᨠRAM áá á) áá á áŁáá á¨ááἠáá á ááľáŤáľ áá˝ááᢠáááľá˛á á¨á¨á˘áľ áłáł á á°áá á¨áŚá˝ ááľáĽ áŁá ááľá°áŤá¨áŤáá˝ ááááŤáľ áá á°á¨ áľááľáłá áááĽáŁá ᣠáá á áĽááąá áá áłáľ áŤáľáááłá ᣠáĽá á áľááá áĽá á áá á˛áá ᣠá á á áá áá áááľ ááťáá ááááá˝á áááá á¨ááłáááľ ááá ááłáŞáŤáá˝ ááŤá¨á á¨áá°ááá ááĽááľ áŤáłáŤáᢠá áá¨á ááľ ááľáĽ áááĽá ááá ἠáŁá áĽá áááłáὠᣠáááá á¨ááἠáľáĽáľáĽ áá° RAM á¨áááá á áľáááááľ á ááŤá˝ áĽááłáłáľáĄ áŤáľá˝áááłáá˘
- á R ááľáĽ áŤá áááá á°ááŁáŤáľ áĽá áá á áá áá á C ++ ááľáĽ á ááĽááľ áá°áŤáľ áá˝ááᢠá áá˛á.á. á¨á á ááá á á°á¨á᪠RcppThread ááá RcppParallel, á°áťá᪠áŁááĽá-áá á á°ááŁá áá áĽááááá, áľááá á R á°á¨á áá áŤááá áŽáľ áľáአááľá¨á á áŤáľáááá.
- áĽá
á á áá˛á.á áľá C ++ á¨áá°á áĽáááľ áłááá áĽá
á áá ááá áá˝áá, á¨ááááá áá
á°áá á°ááááŻá
áĽáá . áĽáá° á áŞá C-áááĽá¨áŞáá˝ áĽááľ á¨áŤáľá áááá˝ xtensor á CRAN áá ááááᣠáááľáᣠááá á¨áá á¨áá°á á ááťá¸á C++ áŽáľá áá° R á¨ááŤáá áą ááŽáááśá˝á áááľáá¸á áá á¨á° áááľ áĽá¨á°ááᨠááᢠá°á¨á᪠áážáľ á¨á ááŁáĽ ááľáá áĽá á RStudio ááľáĽ á¨áááááłááľ C++ áŽáľ á°ááłá ááᢠ- áśáŽááľ á¨áá¤áśá˝ áá á¨áŤáľ-á¨áŤá áľááŞááśá˝á áĽáá˛áŤááą ááá áľáááłá. áá á áŠá á áááá áá ááá áá ááš áá, á¨ááŽ. á áśáá°á áľá. á RStudio ááľáĽ á¨ááá á ááłá¨ áá¨áŚá˝á á áá°áá á ááĽá á°ááłáľ áá¨áŤáá˝á ááŤááľ á¨áááá˝ áá ᣠáĽá IDE á á áááአáá ááŤá áá áá áľááá á áá°ááá˘
- áśá¨á á¨á°ááŤáŠ á¨áľááá° ááá áĽá á¨á¤á°-ááťá ááľ áľáŞáśá˝ áŁáá¸á ááá˘áá˝ ááŤá¨á á¨áŽáľ á°áááłáá˝ááľ áĽá á¨áá¤áśá˝á ááŁááľ áĽáá˛áá á á ááááŽá˝ áá á¨á áááá áááááľá áŤá¨áááŁáᢠá á ááľ áľááá áĽáť áááá á¨áľáá á á§á᧠ááľááá áá˝áá.
- ááá ááááľ ááľ áááľááá áááá¨á á¨á ááľ á°áľáá ááááľ áááŁááá áá áá áŽá˝á á áĽááá ááá¨áĽ á ááŚáľá˘
- á¨áá á áŽáľ áááĽáŤáŽá˝á ááĽááľ áááŤáľ á áŁá á áá áááŁá á°áá R áĽá C++ á˛áŁáአáĽá á¨áĽá á ááᢠááá፠- áĽáá˛áá á áŁá ááá.
á á á ááá áá á°ááᎠá áŁá á¨áááľ áá á áĽáá á¨á°ááąáľá á ááłááľ ááłáŽá˝ ááááłáľ ááľáŤáłá˝áá ááĽáááá˘
ááá: hab.com