Deyrtii hore, Kaggle waxa ay martigelisay tartan lagu kala saarayo sawirada gacanta lagu sawiray, Aqoonsiga Draw Degdega ah ee Doodle, kaas oo ay ka mid yihiin, koox saynisyahano R ah ayaa ka qayb qaatay: Artem Klevtsova, Maareeyaha Philippa ΠΈ Andrey Ogurtsov. Si faahfaahsan kuma sifayn doonno tartanka; taas oo hore loo qabtay daabacaad dhawaan.
Markan kuma aysan shaqeynin bilad-falashada, laakiin khibrado badan oo qiimo leh ayaa la helay, sidaa darteed waxaan jeclaan lahaa inaan bulshada u sheego waxyaabo badan oo xiiso leh oo faa'iido leh oo ku saabsan Kagle iyo shaqada maalinlaha ah. Mawduucyada laga wada hadlay waxaa ka mid ah: nolol adag la'aanteed OpenCV, JSON parsing (tusaalooyinkani waxay eegayaan is dhexgalka koodka C++ ee qoraallada ama baakadaha R iyadoo la isticmaalayo Rcpp), cabbirida qoraallada iyo dockerization ee xalka ugu dambeeya. Dhammaan koodka fariinta ee foomka ku habboon fulinta waa la helayaa kayd.
1. Si hufan uga soo rar xogta CSV galka xogta MonetDB
Xogta ku jirta tartankan looma bixin qaab muuqaalo diyaar ah, laakiin qaab 340 CSV ah oo fayl ah (hal fayl fasal kasta) oo ka kooban JSONs leh dhibco isku-duwayaal ah. Marka lagu xidho dhibcahan xariiqyada, waxaan helnaa sawirka kama dambaysta ah ee cabbiraya 256x256 pixels. Sidoo kale diiwaan kasta waxaa ku qoran calaamad muujinaysa in sawirka si sax ah loo aqoonsaday kala saarta la isticmaalay wakhtiga xogta la ururinayey, laba xaraf ka kooban oo code dalka uu degan yahay qoraaga sawirka, aqoonsi gaar ah, waqti-stambabada iyo magac fasal oo u dhigma magaca faylka. Nooca la fududeeyay ee xogta asalka ah ayaa miisaankeedu yahay 7.4 GB ee kaydka iyo ku dhawaad ββ20 GB ka dib marka la furo, xogta buuxda ka dib marka la furayo waxay qaadataa 240 GB. Qabanqaabiyayaashu waxay hubiyeen in labada noocba ay soo saareen sawiro isku mid ah, taasoo la micno ah in nuqulka buuxa uu ahaa mid aan loo baahnayn. Si kastaba ha ahaatee, kaydinta 50 milyan oo sawir faylal garaaf ah ama qaab qaabaysan ayaa isla markiiba loo arkaa mid aan faa'iido lahayn, waxaanan go'aansanay inaan ku dhex darno dhammaan faylasha CSV ee kaydka tareenka_fududeeyey.zip geli kaydka xogta jiilka xiga ee sawirada cabbirka loo baahan yahay "duuqsi" dufcad kasta.
Nidaam si wanaagsan loo xaqiijiyay ayaa loo doortay DBMS MonetDB, oo ah hirgelinta R sida xirmo ahaan MonetDLite. Xirmada waxaa ku jira nooc ku lifaaqan kaydka xogta waxayna kuu oggolaaneysaa inaad si toos ah uga soo qaadato server-ka fadhiga R oo aad halkaas kula shaqeyso. Abuuritaanka xog-ururin iyo ku xidhiddeeda waxa lagu sameeyaa hal amar:
con <- DBI::dbConnect(drv = MonetDBLite::MonetDBLite(), Sys.getenv("DBDIR"))
Waxaan u baahan doonaa inaan abuurno laba shax: mid xogta oo dhan ah, kan kalena macluumaadka adeegga ee ku saabsan faylalka la soo dejiyey (waxtar leh haddii ay wax qaldamaan oo geeddi-socodku waa in dib loo bilaabo ka dib markii la soo dejiyo dhowr fayl):
Sida ugu dhaqsaha badan ee xogta loogu shubi karo kaydka xogta waxay ahayd in si toos ah loo koobiyeeyo faylasha CSV iyadoo la isticmaalayo SQL - Command COPY OFFSET 2 INTO tablename FROM path USING DELIMITERS ',','n','"' NULL AS '' BEST EFFORThalkaas oo tablename - magaca miiska iyo path - jidka loo maro faylka. Iyadoo la shaqeyneysa kaydka, waxaa la ogaaday in hirgelinta la dhisay unzip in R si sax ah uma shaqeeyo tiro ka mid ah faylalka kaydka, sidaas darteed waxaan isticmaalnay nidaamka unzip (adoo isticmaalaya parameterka getOption("unzip")).
Haddii aad u baahan tahay inaad beddesho miiska ka hor intaadan u qorin kaydka xogta, waa ku filan inaad u gudubto doodda preprocess function bedeli doona xogta.
Wakhtiga rarida xogta way kala duwanaan kartaa iyadoo ku xidhan sifooyinka xawaaraha wadista la isticmaalo. Xaaladeena, akhrinta iyo qorista hal SSD gudaheed ama flash drive (faylka isha) ilaa SSD (DB) waxay qaadataa wax ka yar 10 daqiiqo.
Waxay qaadanaysaa dhowr ilbiriqsi oo dheeraad ah si loo abuuro tiir leh sumadda fasalka shaandheynta iyo tiirka tusaha (ORDERED INDEX) oo leh nambaro xariiq ah oo indha-indheynta lagu soo qaadan doono marka la samaynayo dufcooyin:
Abuuritaanka Tiirar Dheeraad ah iyo Tusmo
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)"))
Si loo xalliyo dhibaatada abuurista dufcaddii duulista, waxaan u baahnnahay inaan gaarno xawaaraha ugu badan ee safafka aan tooska ahayn ee miiska laga soo saaro. doodles. Tan waxaan u isticmaalnay 3 farsamo. Midda kowaad waxay ahayd in la dhimo cabbirka nooca kaydiya aqoonsiga indha-indheynta. Qaybta xogta asalka ah, nooca loo baahan yahay si loo kaydiyo aqoonsiga waa bigint, laakiin tirada indha-indhayntu waxay suurtogal ka dhigaysaa in lagu dhejiyo tilmaameyaashooda, oo la mid ah lambarka caadiga ah, nooca int. Baadhitaanku aad buu u dheereeyaa kiiskan. Habka labaad waa in la isticmaalo ORDERED INDEX - Waxaan u nimid go'aankan si macquul ah, anagoo soo marnay wax walba oo la heli karo doorashooyinka. Midda saddexaad waxay ahayd in la isticmaalo weydiimo la xaddiday. Nuxurka habka waa in la fuliyo amarka hal mar PREPARE iyada oo la adeegsanayo odhaah la diyaariyay marka la abuurayo tiro su'aalo ah oo isku mid ah, laakiin dhab ahaantii waxaa jira faa'iido marka la barbardhigo mid fudud. SELECT Waxay u soo baxday inay ku dhex jirto inta u dhaxaysa khaladaadka tirakoobka.
Habka raritaanka xogta ma cunayso wax ka badan 450 MB ee RAM. Taasi waa, habka lagu sharraxay wuxuu kuu ogolaanayaa inaad dhaqaajiso xog-ururin miisaankeedu yahay tobanaan gigabytes ku dhawaad ββqalab kasta oo miisaaniyadeed, oo ay ku jiraan qaar ka mid ah qalabka hal-board-ka ah, taas oo aad u fiican.
Waxa hadhay oo dhan waa in la cabbiro xawaaraha soo celinta xogta ( random) iyo in la qiimeeyo cabbirka marka la samaynayo qaybo cabbirro kala duwan ah:
Sawirida khadadka midabka leh ee ku salaysan isu-duwayaasha dhibcaha sawirka cabbirka loo baahan yahay (tusaale, 256Γ256 ama 128Γ128).
U beddelashada sawirada ka soo baxday tensor.
Iyada oo qayb ka ah tartanka u dhexeeya kernels Python, dhibaatada waxaa la xalliyey ugu horreyn iyadoo la adeegsanayo OpenCV. Mid ka mid ah analoogyada ugu fudud uguna cad ee R ayaa u ekaan doona sidan:
Sawirka waxaa lagu sameeyaa iyadoo la adeegsanayo qalabka caadiga ah ee R waxaana lagu keydiyaa PNG ku meel gaar ah oo lagu kaydiyay RAM (Linux, hagayaasha R ku meel gaarka ah waxay ku yaalliin hagaha /tmp, ku rakiban RAM). Faylkan waxaa markaa loo akhriyaa qaab saddex-cabbir ah oo leh tirooyinka u dhexeeya 0 ilaa 1. Tani waa muhiim sababtoo ah BMP-ga caadiga ah ayaa loo akhriyi doonaa qaab cayriin ah oo leh codes midab leh.
Hirgelintani waxay nooga muuqatay mid aan fiicneyn, maadaama samaynta dufcadaha waaweyni ay qaadanayso waqti dheer oo aan munaasib ahayn, waxaana go'aansanay inaan ka faa'iidaysanno khibradda asxaabta annaga oo adeegsanayna maktabad awood leh. OpenCV. Waqtigaas ma jirin xirmo diyaarsan oo loogu talagalay R (midna hadda ma jiro), markaa hirgelinta ugu yar ee shaqeynta loo baahan yahay ayaa lagu qoray C ++ oo leh isdhexgalka R code iyadoo la adeegsanayo Rcpp.
Si loo xalliyo dhibaatada, xirmooyinka soo socda iyo maktabadaha ayaa la isticmaalay:
OpenCV si loogu shaqeeyo sawirada iyo khadadka sawirida. La isticmaalay maktabadaha nidaamka horay loo rakibay iyo faylalka madaxa, iyo sidoo kale isku xidhka firfircoon.
xtensor si aad ula shaqeyso arrays iyo tenorsooyin badan. Waxaan isticmaalnay faylalka madaxa ee ku jira xirmada R ee isku magaca ah. Maktabadu waxay kuu ogolaanaysaa inaad la shaqeyso qalabyo kala duwan, labadaba safka waaweyn iyo siday u kala horreeyaan.
ndjson si loo qiimeeyo JSON. Maktabaddan waxaa lagu isticmaalaa gudaha xtensor si toos ah haddii ay ku jirto mashruuca.
RcppThread si loo abaabulo habaynta silsilado badan oo vector ah oo ka socda JSON. Isticmaalay faylalka madaxa ee xirmadan ay bixisay. Ka caan ah RcppParallel Xirmada, iyo waxyaabo kale, waxay leedahay hab-dhex-dhexaad ah oo dhex-dhexaad ah.
Waa muhiim in la ogaado taas xtensor Waxay isu rogtay ilaahnimo: marka lagu daro xaqiiqda ah in ay leedahay hawlkarnimo balaadhan iyo wax qabad sare, horumariyayaasheeda waxa ay noqdeen kuwo si fiican uga jawaaba su'aalaha isla markiiba oo faahfaahsan. Caawinaadkooda, waxaa suurtagal ah in la hirgeliyo isbeddelada matrices OpenCV ee xtensor tenors, iyo sidoo kale habka la isugu daro sawir-qaadayaasha 3-cabbirka ah ee 4-cabbir ah ee cabbirka saxda ah (qaybta lafteeda).
Si loo ururiyo faylalka adeegsada faylalka nidaamka iyo isku xidhka firfircoon ee maktabadaha lagu rakibay nidaamka, waxaanu isticmaalnay habka plugin ee lagu hirgeliyay xirmada Rcpp. Si aad si toos ah u hesho waddooyinka iyo calanka, waxaan isticmaalnay utility Linux ah oo caan ah pkg-isku xidhka.
Hirgelinta plugin Rcpp ee isticmaalka maktabadda OpenCV
Xeerka dhaqangelinta ee kala-soocidda JSON iyo soo saarista dufcaddii gudbinta moodeelka waxa lagu bixiyaa qaswade hoosteeda. Marka hore, ku dar hagaha mashruuca deegaanka si aad u raadiso faylalka madaxa (loo baahan yahay ndjson):
// [[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;
}
Koodhkan waa in lagu dhejiyaa faylka src/cv_xt.cpp oo la soo ururiyo amarka Rcpp::sourceCpp(file = "src/cv_xt.cpp", env = .GlobalEnv); sidoo kale looga baahan yahay shaqada nlohmann/json.hpp ka kayd. Xeerku waxa uu u qaybsan yahay dhawr hawlood:
Sida aad arki karto, kororka xawaaraha wuxuu noqday mid aad u muhiim ah, mana dhici karto in la qabsado koodhka C++ iyadoo la barbardhigayo R code.
3. Iterators ee soo dejinta dufcadaha kaydka xogta
R waxay sumcad u qalantaa habaynta xogta ku habboon RAM-ka, halka Python ay aad ugu astaysan tahay habaynta xogta, taasoo kuu oggolaanaysa inaad si fudud oo dabiici ah u hirgeliso xisaabaadka ka baxsan ( xisaabinta iyadoo la adeegsanayo xusuusta dibadda). Tusaalaha caadiga ah ee khuseeya annaga marka la eego macnaha guud ee dhibaatada la tilmaamay waa shabakadaha neerfaha qoto dheer ee lagu tababaray habka farcanka jilbaha leh ee qiyaasida jaangooyooyinka tallaabo kasta iyadoo la adeegsanayo qayb yar oo indho-indhayn ah, ama dufcad-yar.
Qaab dhismeedka waxbarashada qoto dheer ee ku qoran Python waxay leeyihiin fasalo gaar ah oo hirgeliya dib-u-eegis ku salaysan xogta: miisaska, sawirada faylalka, qaababka binary, iwm. Waxaad isticmaali kartaa doorashooyin diyaarsan ama waxaad qori kartaa naftaada hawlo gaar ah. Gudaha R waxaan uga faa'iidaysan karnaa dhammaan sifooyinka maktabadda Python keras oo leh dhabarka dambe ee kala duwan iyadoo la adeegsanayo xirmada magaca isku midka ah, taas oo iyaduna ka shaqeysa korka xirmada dib u dhigid. Midda dambe waxay mudan tahay maqaal dheer oo gooni ah; kaliya kuma ogola inaad ku socodsiiso code Python ka R, laakiin sidoo kale waxay kuu ogolaaneysaa inaad ku wareejiso walxaha u dhexeeya fadhiyada R iyo Python, si toos ah u fulinaya dhammaan beddelka nooca lagama maarmaanka ah.
Waxaan ka takhalusnay baahida loo qabo in lagu keydiyo dhammaan xogta RAM iyadoo la adeegsanayo MonetDLite, dhammaan shaqada "shabakadda neerfaha" waxaa lagu fulin doonaa code asalka ah ee Python, kaliya waa inaan ku qornaa xogta xogta, maadaama aysan jirin wax diyaar ah. xaaladdan oo kale ee R ama Python midkood. Asal ahaan waxa jira laba shuruudood oo keliya: waa inay ku soo celisaa dufcad aan dhammaad lahayn oo ay beddesho xaaladdeeda inta u dhaxaysa ku celcelinta (kan dambe ee R waxa loo fuliyaa habka ugu fudud iyadoo la isticmaalayo xidhidhyo). Markii hore, waxa loo baahnaa in si toos ah loogu beddelo arrays R oo loo beddelo habab tiro badan oo ku dhex jira terator, laakiin nooca hadda ee xidhmada keras lafteedu way samaysaa.
Shaqadu waxay u qaadanaysaa doorsoome ahaan xidhiidh la leh kaydka xogta, tirooyinka laynka la isticmaalay, tirada fasalada, cabbirka dufcada, miisaanka (scale = 1 waxay u dhigantaa samaynta sawirada 256x256 pixels, scale = 0.5 - 128x128 pixels), tilmaame midab (color = FALSE qeexaa ku-bandhigidda cabbirka cawl marka la isticmaalo color = TRUE istaroog kasta waxaa lagu sawiraa midab cusub) iyo tilmaame horudhac u ah shabakadaha horay loogu tababaray imagenet. Midda dambe ayaa loo baahan yahay si loo cabbiro qiyamka pixel laga bilaabo muddada u dhaxaysa [0, 1] ilaa inta u dhaxaysa [-1, 1], kaas oo la isticmaalay markii la tababbaray waxa la keenay keras moodooyinka.
Shaqada dibadda waxay ka kooban tahay dooda nooca hubinta, miis data.table oo leh lambarro khad isku qasan oo aan kala sooc lahayn samples_index iyo tirada dufcadaha, miiska iyo tirada ugu badan ee dufcadaha, iyo sidoo kale tibaaxaha SQL ee soo dejinta xogta kaydka. Intaa waxaa dheer, waxaan qeexnay analoogga degdega ah ee shaqada gudaha keras::to_categorical(). Waxaan u isticmaalnay ku dhawaad ββdhammaan xogta tababarka, anagoo ka tagnay boqolkiiba nus si loo ansixiyo, markaa cabbirka waagii wuxuu ku xaddidnaa cabbirka steps_per_epoch marka loo yeero keras::fit_generator(), iyo shuruudda if (i > max_i) kaliya u shaqeeyay ku celcelinta ansaxinta.
Shaqada gudaha, tusmooyinka safafka ayaa loo soo saaray dufcada soo socota, diiwaanada waxaa laga soo dajiyay xogta iyada oo miiska dufcada uu kordho, JSON parsing (shaqo cpp_process_json_vector(), ku qoran C++) oo abuuraya habab u dhiganta sawirro. Kadibna hal-kulul oo leh calaamado fasalka ayaa la abuuray, qalabyo leh qiyamka pixels iyo calaamadaha ayaa lagu daraa liis, taas oo ah qiimaha soo noqoshada. Si loo dardargeliyo shaqada, waxaan isticmaalnay abuurista tusmooyinka miisaska data.table iyo wax ka beddelka iyada oo la marayo isku xirka - iyada oo aan la helin xirmadan "chips" miiska Aad bay u adagtahay in la qiyaaso in si wax ku ool ah loogu shaqeeyo iyada oo la adeegsanayo xog kasta oo muhiim ah oo ku jirta R.
Natiijooyinka cabbiraadda xawaaraha ee laptop-ka Core i5 waa sida soo socota:
Nashqadii ugu horeysay ee la isticmaalo waxay ahayd mobilenet v1, kuwaas oo sifooyinkooda lagu falanqeeyay tan fariinta. Waxaa lagu daraa sida caadiga ah keras iyo, si waafaqsan, waxaa laga heli karaa xirmada magaca isku midka ah ee R. Laakiin marka la isku dayayo in lagu isticmaalo sawirada hal kanaalka ah, wax la yaab leh ayaa soo baxay: Tensor-ku-gelinta waa in uu had iyo jeer lahaadaa cabbirka (batch, height, width, 3), taas oo ah, tirada kanaalada lama beddeli karo. Ma jiro xaddidaad noocaas ah Python, markaa waanu ku degdegnay oo qornay hirgelinta noo gaar ah ee qaab dhismeedkan, annagoo raacayna maqaalkii asalka ahaa (iyada oo aan laga tegin nooca keras):
Hadda ma adka in la qoro hawl caalami ah si loo helo mid ka mid ah kuwa la keenay keras moodooyinka leh ama aan lahayn miisaan lagu tababaray imagenet:
Markaad isticmaalayso sawirro hal kanaal ah, miisaan hore loo tababaray lama isticmaalo. Tan waxaa lagu hagaajin karaa: iyadoo la isticmaalayo shaqada get_weights() hel miisaanka moodeelka qaab liis ah R arrays, beddel cabbirka qaybta ugu horreysa ee liiskan (adiga oo qaadanaya hal kanaal midab ama celcelis ahaan saddexda), ka dibna miisaannada dib ugu celi moodeelka shaqada set_weights(). Marna kuma darin shaqeyntan, sababtoo ah marxaladan waxay horeyba u caddaatay in ay waxtar badan tahay in lagu shaqeeyo sawirada midabka.
Waxaan samaynay inta badan tijaabooyinka anagoo adeegsanayna nooca mobilnetka 1 iyo 2, iyo sidoo kale resnet34. Nashqado casri ah oo badan sida SE-ResNeXt ayaa si fiican u soo bandhigay tartankan. Nasiib darro, ma aanan haysanin wax-qabadyo diyaarsan oo annagu gacanta ku hayno, mana aanaan qorin anaga (laakin hubaal waan qori doonnaa).
5. Barbaarinta qoraallada
Si loo fududeeyo, dhammaan koodka bilowga tababarka waxaa loo qaabeeyey sidii hal qoraal, oo la cabbiray iyadoo la isticmaalayo docopt sida soo socota:
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)
Xirmo docopt waxay ka dhigan tahay fulinta http://docopt.org/ loogu talagalay R. Iyadoo la kaashanayo, qoraallada waxaa la bilaabay amarro fudud sida Rscript bin/train_nn.R -m resnet50 -c -d /home/andrey/doodle_db ama ./bin/train_nn.R -m resnet50 -c -d /home/andrey/doodle_db, haddii faylka train_nn.R waa la fulin karaa (amarkani wuxuu bilaabi doonaa tababarka moodeelka resnet50 Sawirada saddexda midab leh ee cabbiraya 128x128 pixels, xog-ururinta waa in ay ku jirtaa galka /home/andrey/doodle_db). Waxaad ku dari kartaa xawaaraha waxbarashada, nooca wax hagaajiya, iyo wax kasta oo kale oo la beddeli karo liiska. Habka diyaarinta daabacaadda, waxaa soo baxday in naqshadeynta mobilenet_v2 laga bilaabo nooca hadda jira keras in R la isticmaalo ma awoodo sababtoo ah isbeddelada aan lagu xisaabtamin xirmada R, waxaan sugeynaa inay hagaajiyaan.
Habkani wuxuu suurtogal ka dhigay in si weyn loo dedejiyo tijaabooyinka moodooyinka kala duwan marka la barbar dhigo soo saarista dhaqameed ee qoraallada ee RStudio (waxaan u aragnaa xirmada sida beddelka suurtagalka ah). tfruns). Laakiin faa'iidada ugu weyn waa awoodda si fudud loo maareeyo bilaabista qoraallada Docker ama si fudud server-ka, iyada oo aan lagu rakibin RStudio tan.
6. Dockerization of scripts
Waxaan u isticmaalnay Docker si aan u hubinno qaadista deegaanka ee moodooyinka tababarka ee u dhexeeya xubnaha kooxda iyo si degdeg ah loo geeyo daruuraha. Waxaad bilaabi kartaa inaad barato qalabkan, kaas oo aan caadi u ahayn barnaamijka R, oo leh tan daabacaado taxane ah ama koorsada video.
Docker wuxuu kuu ogolaanayaa inaad labadiinaba ka abuurtaan sawiradaada xoqan oo aad isticmaasho sawirro kale oo saldhig u ah abuuristaada. Markii aan falanqeynay xulashooyinka jira, waxaan gaadhnay in rakibidda NVIDIA, CUDA+cuDNN darawallada iyo maktabadaha Python ay tahay qayb si caddaalad ah qayb uga ah sawirka, waxaanan go'aansannay inaan sawirka rasmiga ah u qaadanno saldhig ahaan. tensorflow/tensorflow:1.12.0-gpu, ku darida xirmooyinka R ee lagama maarmaanka ah halkaas.
Si ay ugu habboonaato, baakadaha la isticmaalay waxaa lagu riday doorsoomayaal; Inta badan qoraallada qoran waxaa lagu koobiyeeyaa gudaha weelasha inta lagu jiro kulanka. Waxaan sidoo kale u bedelnay qolofka taliska /bin/bash si ay u fududaato isticmaalka nuxurka /etc/os-release. Tani waxay ka fogaatay baahida loo qabo in lagu qeexo nooca OS ee koodka.
Intaa waxaa dheer, qoraal yar oo bash ah ayaa la qoray kaas oo kuu ogolaanaya inaad bilowdo weel leh amarro kala duwan. Tusaale ahaan, kuwani waxay noqon karaan qoraallo loogu talagalay tababbarka shabakadaha neerfaha ee hore loogu dhejiyay gudaha weelka, ama qolofka taliska ee ciladaha iyo la socodka shaqada weelka:
Qoraal si aad u furto weelka
#!/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}
Haddii qoraalka bashku uu socdo iyada oo aan la xaddidin, qoraalka waxaa loogu yeeri doonaa gudaha weelka train_nn.R oo leh qiyamka caadiga ah; haddii dooda ugu horeysa ee mawqifku tahay "bash", markaa weelku wuxuu ku bilaabi doonaa si dhexgal ah qolof amar ah. Dhammaan kiisaska kale, qiyamka doodaha booska ayaa la beddelay: CMD="Rscript /app/train_nn.R $@".
Waxaa xusid mudan in tusaha leh xogta ilaha iyo xogta, iyo sidoo kale tusaha badbaadinta moodooyinka tababaran, lagu rakibay gudaha weelka laga soo bilaabo nidaamka martida loo yahay, kaas oo kuu ogolaanaya inaad hesho natiijooyinka qoraallada iyada oo aan loo baahnayn khalkhalgelinta.
7. Isticmaalka GPU-yo badan oo Google Cloud ah
Mid ka mid ah sifooyinka tartanka ayaa ahaa xogta buuqa badan (fiiri sawirka cinwaanka, oo laga soo amaahday @Leigh.plt oo ka yimid ODS slack). Dufcooyin waaweyn ayaa ka caawiya la dagaalanka tan, ka dib tijaabooyin lagu sameeyay kombuyuutar leh 1 GPU, waxaan go'aansanay in aan xirfad u samayno moodooyinka tababarka ee GPU-yada daruuraha ah. GoogleCloud la isticmaalay (hagaha wanaagsan ee aasaasiga ah) iyadoo ay ugu wacan tahay xulashada badan ee habaynta la heli karo, qiimo macquul ah iyo $300 oo gunno ah. Hungurinimo awgeed, waxaan dalbaday tusaale 4xV100 ah oo wata SSD iyo tan RAM ah, taasina waxay ahayd qalad weyn. Mashiinka noocan oo kale ah si dhakhso ah ayuu u cunaa lacagta; waxaad tagi kartaa tijaabada jaban iyada oo aan la helin dhuumo la xaqiijiyay. Ujeeddooyin waxbarasho, waxa fiican inaad qaadato K80. Laakiin qadarka badan ee RAM ayaa ku anfacay - Cloud SSD ma cajabin waxqabadkeeda, sidaas darteed kaydinta xogta ayaa loo wareejiyay dev/shm.
Xiisaha ugu weyni waa jajabka koodka ee mas'uul ka ah isticmaalka GPU-yo badan. Marka hore, qaabka waxaa lagu abuuray CPU iyadoo la adeegsanayo maamulaha macnaha guud, sida Python:
Farsamada caadiga ah ee qaboojinta dhammaan lakabyada marka laga reebo kan u dambeeya, tababbarka lakabka u dambeeya, barafaynta iyo dib-u-tabaridda dhammaan moodeelka dhowr GPUs lama hirgelin.
Tababarka ayaa lala socday iyadoo aan la isticmaalin. tensorboard, annaga oo ku xaddidnayna duubista diiwaannada iyo kaydinta moodooyinka leh magacyo wargelin ah xilli kasta:
Dhibaatooyin dhowr ah oo aan la kulannay ayaa weli aan laga gudbi karin:
Π² keras ma jirto hawl diyaarsan oo si toos ah loogu raadinayo heerka waxbarashada ugu wanaagsan (analogue lr_finder maktabadda soomi.ai; Dedaal xoogaa ah, waxaa suurtagal ah in la geeyo fulinta dhinac saddexaad R, tusaale ahaan, tan;
Natiijo ahaan qodobkii hore, ma suurtagal ahayn in la doorto xawaaraha saxda ah ee tababarka marka la isticmaalayo dhowr GPUs;
waxaa jira la'aanta naqshadaha shabakadaha neerfaha ee casriga ah, gaar ahaan kuwa horay loogu tababaray imagenet;
qofna ma wareego siyaasadda iyo heerarka waxbarashada takoorid (cosine annealing waxay ahayd codsigeena la fuliyay, Mahadsanid skydan).
Maxaa faa'iido leh oo laga bartay tartankan:
Qalab awood yar leh, waxaad ku shaqayn kartaa mugga xogta saxda ah (mar badan cabbirka RAM) xanuun la'aan. Bac caag ah miiska kaydiya xusuusta sababtoo ah wax ka beddelka goobta ee miisaska, taas oo ka fogaanaysa in la koobiyeeyo, iyo marka si sax ah loo isticmaalo, awoodeeda had iyo jeer waxay muujisaa xawaaraha ugu sarreeya ee dhammaan qalabka naloo yaqaanno qorista luqadaha. Ku kaydinta xogta database-ku waxay kuu ogolaanaysaa, marar badan, inaadan ka fikirin dhammaan baahida loo qabo in la tuujiyo dhammaan xogta kaydinta RAM.
Hawlaha qunyar socodka ah ee R waxaa lagu bedeli karaa kuwa degdega ah ee C++ iyadoo la isticmaalayo xirmada Rcpp. Haddii lagu daro isticmaalka RcppThread ama RcppParallel, Waxaan helnaa hirgelinta iskudubarid badan oo isku dhafan, markaa looma baahna in la barbar dhigo koodhka heerka R.
Xidhmada Rcpp waxaa loo isticmaali karaa iyada oo aan aqoon dhab ah loo lahayn C++, ugu yaraan loo baahan yahay ayaa la qeexay halkan. Faylasha madaxa ee tiro ka mid ah maktabadaha C-ga fiican sida xtensor laga heli karo CRAN, taas oo ah, kaabayaal ayaa loo sameeyay hirgelinta mashaariicda isku-dhafka C++ ee waxqabadka sare ee diyaarsan ee R. Ku habboonaanta dheeriga ah waa muujinta syntax iyo falanqaynta koodhka C++ ee RStudio.
docopt wuxuu kuu ogolaanayaa inaad ku socodsiiso qoraallada is-ku jira oo leh cabbirro. Tani waxay ku habboon tahay isticmaalka server-ka fog, oo ay ku jiraan. docker hoostiisa. Gudaha RStudio, way dhib badan tahay in la sameeyo saacado badan oo tijaabo ah oo lagu sameeyo shabakadaha neerfaha, iyo ku rakibida IDE ee server-ka laftiisa mar walba ma aha mid xaq ah.
Docker wuxuu xaqiijiyaa qaadista koodhka iyo dib u soo saarista natiijooyinka u dhexeeya horumariyayaal leh noocyo kala duwan oo OS ah iyo maktabadaha, iyo sidoo kale fududaynta fulinta ee adeegayaasha. Waxaad bilaabi kartaa dhammaan dhuumaha tababarka hal amar oo keliya.
Google Cloud waa hab ku habboon miisaaniyada oo lagu tijaabiyo qalab qaali ah, laakiin waxaad u baahan tahay inaad si taxadar leh u doorato qaabaynta.
Cabbiraadda xawaaraha jajabyada koodhka shakhsi ahaaneed aad bay faa'iido u leedahay, gaar ahaan marka la isku daro R iyo C++, iyo xirmada kursiga keydka - sidoo kale aad u fudud.
Guud ahaan, waayo-aragnimadani waxay ahayd mid aad u faa'iido badan waxaanan sii wadeynaa inaan ka shaqeyno xallinta qaar ka mid ah arrimaha la soo qaaday.