Quick Draw Doodle RecognitionαŸ– αžšαž”αŸ€αž”αž”αž„αŸ’αž€αžΎαžαž˜αž·αžαŸ’αžαž‡αžΆαž˜αž½αž™ R, C++ αž“αž·αž„αž”αžŽαŸ’αžαžΆαž‰αžŸαžšαžŸαŸƒαž”αŸ’αžšαžŸαžΆαž‘

Quick Draw Doodle RecognitionαŸ– αžšαž”αŸ€αž”αž”αž„αŸ’αž€αžΎαžαž˜αž·αžαŸ’αžαž‡αžΆαž˜αž½αž™ R, C++ αž“αž·αž„αž”αžŽαŸ’αžαžΆαž‰αžŸαžšαžŸαŸƒαž”αŸ’αžšαžŸαžΆαž‘

ហេហេ!

αž€αžΆαž›αž–αžΈαžšαžŠαžΌαžœαžŸαŸ’αž›αžΉαž€αžˆαžΎαž‡αŸ’αžšαž»αŸ‡αž€αž“αŸ’αž›αž„αž‘αŸ… Kaggle αž”αžΆαž“αžšαŸ€αž”αž…αŸ†αž€αžΆαžšαž”αŸ’αžšαž€αž½αžαž”αŸ’αžšαž‡αŸ‚αž„αž˜αž½αž™αžŠαžΎαž˜αŸ’αž”αžΈαž…αžΆαžαŸ‹αžαŸ’αž“αžΆαž€αŸ‹αžšαžΌαž”αž—αžΆαž–αžŠαŸ‚αž›αž‚αžΌαžšαžŠαŸ„αž™αžŠαŸƒ Quick Draw Doodle Recognition αžŠαŸ‚αž›αž€αŸ’αž“αž»αž„αž“αŸ„αŸ‡αž€αŸ’αžšαž»αž˜αž’αŸ’αž“αž€αžœαž·αž‘αŸ’αž™αžΆαžŸαžΆαžŸαŸ’αžαŸ’αžš R αž˜αž½αž™αž€αŸ’αžšαž»αž˜αž”αžΆαž“αž…αžΌαž›αžšαž½αž˜αŸ– Artem Klevtsova, αž’αŸ’αž“αž€αž‚αŸ’αžšαž”αŸ‹αž‚αŸ’αžšαž„ Philippa ΠΈ Andrey Ogurtsov. αž™αžΎαž„β€‹αž“αžΉαž„β€‹αž˜αž·αž“β€‹αžšαŸ€αž”αžšαžΆαž”αŸ‹β€‹αž›αž˜αŸ’αž’αž·αžβ€‹αž’αŸ†αž–αžΈβ€‹αž€αžΆαžšβ€‹αž”αŸ’αžšαž€αž½αžβ€‹αž”αŸ’αžšαž‡αŸ‚αž„β€‹αž“αŸ„αŸ‡β€‹αž‘αŸ αžŠαŸ‚αž›β€‹αžαŸ’αžšαžΌαžœβ€‹αž”αžΆαž“β€‹αž’αŸ’αžœαžΎβ€‹αžšαž½αž…β€‹αž αžΎαž™β€‹αž“αŸ…β€‹αž€αŸ’αž“αž»αž„ αž€αžΆαžšαž”αŸ„αŸ‡αž–αž»αž˜αŸ’αž–αž•αŸ’αžŸαžΆαž™αžαŸ’αž˜αžΈαŸ—.

αž›αžΎαž€αž“αŸαŸ‡αžœαžΆαž˜αž·αž“αžŠαŸ†αžŽαžΎαžšαž€αžΆαžšαž‡αžΆαž˜αž½αž™αž“αžΉαž„αž€αžΆαžšαž’αŸ’αžœαžΎαž€αžŸαž·αž€αž˜αŸ’αž˜αž˜αŸαžŠαžΆαž™αž‘αŸ αž”αŸ‰αž»αž“αŸ’αžαŸ‚αž”αž‘αž–αž·αžŸαŸ„αž’αž“αŸαžŠαŸαž˜αžΆαž“αžαž˜αŸ’αž›αŸƒαž‡αžΆαž…αŸ’αžšαžΎαž“αžαŸ’αžšαžΌαžœαž”αžΆαž“αž‘αž‘αž½αž› αžŠαžΌαž…αŸ’αž“αŸαŸ‡αžαŸ’αž‰αž»αŸ†αž…αž„αŸ‹αž”αŸ’αžšαžΆαž”αŸ‹αžŸαž αž‚αž˜αž“αŸαž’αŸ†αž–αžΈαž’αŸ’αžœαžΈαžŠαŸ‚αž›αž‚αž½αžšαž±αŸ’αž™αž…αžΆαž”αŸ‹αž’αžΆαžšαž˜αŸ’αž˜αžŽαŸ αž“αž·αž„αž˜αžΆαž“αž”αŸ’αžšαž™αŸ„αž‡αž“αŸαž”αŸ†αž•αž»αžαž˜αž½αž™αž…αŸ†αž“αž½αž“αž“αŸ…αž›αžΎ Kagle αž“αž·αž„αž€αŸ’αž“αž»αž„αž€αžΆαžšαž„αžΆαžšαž”αŸ’αžšαž…αžΆαŸ†αžαŸ’αž„αŸƒαŸ” αž€αŸ’αž“αž»αž„αž…αŸ†αžŽαŸ„αž˜αž”αŸ’αžšαž’αžΆαž“αž”αž‘αžŠαŸ‚αž›αž”αžΆαž“αž–αž·αž—αžΆαž€αŸ’αžŸαžΆαŸ– αž‡αžΈαžœαž·αžαž›αŸ†αž”αžΆαž€αžŠαŸ„αž™αž‚αŸ’αž˜αžΆαž“ αž’αžΌαžŸαŸŠαžΈαžŸαŸŠαžΈαžŸαŸŠαžΈαŸ”αž€αžΆαžšαž‰αŸ‚αž€ JSON (αž§αž‘αžΆαž αžšαžŽαŸαž‘αžΆαŸ†αž„αž“αŸαŸ‡αž–αž·αž“αž·αžαŸ’αž™αž˜αžΎαž›αž€αžΆαžšαžšαž½αž˜αž”αž‰αŸ’αž…αžΌαž›αž€αžΌαžŠ C++ αž‘αŸ…αž€αŸ’αž“αž»αž„αžŸαŸ’αž‚αŸ’αžšαžΈαž” αž¬αž€αž‰αŸ’αž…αž”αŸ‹αž€αŸ’αž“αž»αž„ R αžŠαŸ„αž™αž”αŸ’αžšαžΎ Rcpp), αž€αžΆαžšαž€αŸ†αžŽαžαŸ‹αž”αŸ‰αžΆαžšαŸ‰αžΆαž˜αŸ‰αŸ‚αžαŸ’αžšαž“αŸƒαžŸαŸ’αž‚αŸ’αžšαžΈαž” αž“αž·αž„ dockerization αž“αŸƒαžŠαŸ†αžŽαŸ„αŸ‡αžŸαŸ’αžšαžΆαž™αž…αž»αž„αž€αŸ’αžšαŸ„αž™αŸ” αž€αžΌαžŠαž‘αžΆαŸ†αž„αž’αžŸαŸ‹αž–αžΈαžŸαžΆαžšαž€αŸ’αž“αž»αž„αž‘αž˜αŸ’αžšαž„αŸ‹αžŸαž˜αžšαž˜αŸ’αž™αžŸαž˜αŸ’αžšαžΆαž”αŸ‹αž€αžΆαžšαž”αŸ’αžšαžαž·αž”αžαŸ’αžαž·αž‚αžΊαž’αžΆαž…αžšαž€αž”αžΆαž“αž“αŸ…αž€αŸ’αž“αž»αž„ αžƒαŸ’αž›αžΆαŸ†αž„.

αž˜αžΆαžαž·αž€αžΆ:

  1. αž•αŸ’αž‘αž»αž€αž‘αž·αž“αŸ’αž“αž“αŸαž™αž–αžΈ CSV αž‘αŸ…αž€αŸ’αž“αž»αž„ MonetDB αž”αŸ’αžšαž€αž”αžŠαŸ„αž™αž”αŸ’αžšαžŸαž·αž‘αŸ’αž’αž—αžΆαž–
  2. αž€αŸ†αž–αž»αž„αžšαŸ€αž”αž…αŸ†αž”αžΆαž…αŸ‹
  3. Iterators αžŸαž˜αŸ’αžšαžΆαž”αŸ‹ unloading batches αž–αžΈ database
  4. αž€αžΆαžšαž‡αŸ’αžšαžΎαžŸαžšαžΎαžŸαžŸαŸ’αžαžΆαž”αžαŸ’αž™αž€αž˜αŸ’αž˜αž‚αŸ†αžšαžΌ
  5. αž€αžΆαžšαž€αŸ†αžŽαžαŸ‹αžŸαŸ’αž‚αŸ’αžšαžΈαž”
  6. Dockerization αž“αŸƒαžŸαŸ’αž‚αŸ’αžšαžΈαž”
  7. αž€αžΆαžšαž”αŸ’αžšαžΎαž”αŸ’αžšαžΆαžŸαŸ‹ GPU αž‡αžΆαž…αŸ’αžšαžΎαž“αž“αŸ…αž›αžΎ Google Cloud
  8. αž‡αŸ†αž“αž½αžŸαž±αŸ’αž™αž€αžΆαžšαžŸαž“αŸ’αž“αž·αžŠαŸ’αž‹αžΆαž“αž˜αž½αž™

1. αž•αŸ’αž‘αž»αž€αž‘αž·αž“αŸ’αž“αž“αŸαž™αž–αžΈ CSV αž™αŸ‰αžΆαž„αž˜αžΆαž“αž”αŸ’αžšαžŸαž·αž‘αŸ’αž’αž—αžΆαž–αž‘αŸ…αž€αŸ’αž“αž»αž„αž˜αžΌαž›αžŠαŸ’αž‹αžΆαž“αž‘αž·αž“αŸ’αž“αž“αŸαž™ MonetDB

αž‘αž·αž“αŸ’αž“αž“αŸαž™αž“αŸ…αž€αŸ’αž“αž»αž„αž€αžΆαžšαž”αŸ’αžšαž€αž½αžαž”αŸ’αžšαž‡αŸ‚αž„αž“αŸαŸ‡αžαŸ’αžšαžΌαžœαž”αžΆαž“αž•αŸ’αžαž›αŸ‹αž‡αžΌαž“αž˜αž·αž“αž˜αŸ‚αž“αž€αŸ’αž“αž»αž„αž‘αž˜αŸ’αžšαž„αŸ‹αž‡αžΆαžšαžΌαž”αž—αžΆαž–αžŠαŸ‚αž›αžαŸ’αžšαŸ€αž˜αžšαž½αž…αž‡αžΆαžŸαŸ’αžšαŸαž…αž“αŸ„αŸ‡αž‘αŸ αž”αŸ‰αž»αž“αŸ’αžαŸ‚αž‡αžΆαž‘αž˜αŸ’αžšαž„αŸ‹αž―αž€αžŸαžΆαžš CSV αž…αŸ†αž“αž½αž“ 340 (αž―αž€αžŸαžΆαžšαž˜αž½αž™αžŸαž˜αŸ’αžšαžΆαž”αŸ‹αžαŸ’αž“αžΆαž€αŸ‹αž“αžΈαž˜αž½αž™αŸ—) αžŠαŸ‚αž›αž˜αžΆαž“ JSONs αž‡αžΆαž˜αž½αž™αž…αŸ†αžŽαž»αž…αž€αžΌαž’αžšαžŠαŸ„αžŽαŸαŸ” αžŠαŸ„αž™αž—αŸ’αž‡αžΆαž”αŸ‹αž…αŸ†αžŽαž»αž…αž‘αžΆαŸ†αž„αž“αŸαŸ‡αž‡αžΆαž˜αž½αž™αž”αž“αŸ’αž‘αžΆαžαŸ‹ αž™αžΎαž„αž‘αž‘αž½αž›αž”αžΆαž“αžšαžΌαž”αž—αžΆαž–αž…αž»αž„αž€αŸ’αžšαŸ„αž™αžŠαŸ‚αž›αžœαžΆαžŸαŸ‹ 256x256 αž—αžΈαž€αžŸαŸ‚αž›αŸ” αž•αž„αžŠαŸ‚αžšαžŸαž˜αŸ’αžšαžΆαž”αŸ‹αž€αŸ†αžŽαžαŸ‹αžαŸ’αžšαžΆαž“αžΈαž˜αž½αž™αŸ—αž˜αžΆαž“αžŸαŸ’αž›αžΆαž€αž˜αž½αž™αžŠαŸ‚αž›αž”αž„αŸ’αž αžΆαž‰αžαžΆαžšαžΌαž”αž—αžΆαž–αžαŸ’αžšαžΌαžœαž”αžΆαž“αž‘αž‘αž½αž›αžŸαŸ’αž‚αžΆαž›αŸ‹αžαŸ’αžšαžΉαž˜αžαŸ’αžšαžΌαžœαžŠαŸ„αž™αž’αŸ’αž“αž€αž…αžΆαžαŸ‹αžαŸ’αž“αžΆαž€αŸ‹αžŠαŸ‚αž›αž”αžΆαž“αž”αŸ’αžšαžΎαž“αŸ…αž–αŸαž›αžŸαŸ†αžŽαž»αŸ†αž‘αž·αž“αŸ’αž“αž“αŸαž™αžαŸ’αžšαžΌαžœαž”αžΆαž“αž”αŸ’αžšαž˜αžΌαž› αž›αŸαžαž€αžΌαžŠαž–αžΈαžšαž’αž€αŸ’αžŸαžšαž“αŸƒαž”αŸ’αžšαž‘αŸαžŸαžŠαŸ‚αž›αžšαžŸαŸ‹αž“αŸ…αžšαž”αžŸαŸ‹αž’αŸ’αž“αž€αž“αž·αž–αž“αŸ’αž’αžšαžΌαž”αž—αžΆαž– αž’αžαŸ’αžαžŸαž‰αŸ’αž‰αžΆαžŽαžαŸ‚αž˜αž½αž™αž‚αžαŸ‹ αžαŸ’αžšαžΆαž–αŸαž›αžœαŸαž›αžΆαŸ” αž“αž·αž„αžˆαŸ’αž˜αŸ„αŸ‡αžαŸ’αž“αžΆαž€αŸ‹αžŠαŸ‚αž›αžαŸ’αžšαžΌαžœαž“αžΉαž„αžˆαŸ’αž˜αŸ„αŸ‡αž―αž€αžŸαžΆαžšαŸ” αž€αŸ†αžŽαŸ‚αžŸαžΆαž˜αž‰αŸ’αž‰αž“αŸƒαž‘αž·αž“αŸ’αž“αž“αŸαž™αžŠαžΎαž˜αž˜αžΆαž“αž‘αž˜αŸ’αž„αž“αŸ‹ 7.4 GB αž“αŸ…αž€αŸ’αž“αž»αž„αž”αžŽαŸ’αžŽαžŸαžΆαžš αž αžΎαž™αž”αŸ’αžšαž αŸ‚αž› 20 GB αž”αž“αŸ’αž‘αžΆαž”αŸ‹αž–αžΈαž–αž“αŸ’αž›αžΆ αž‘αž·αž“αŸ’αž“αž“αŸαž™αž–αŸαž‰αž›αŸαž‰αž”αž“αŸ’αž‘αžΆαž”αŸ‹αž–αžΈαž€αžΆαžšαž–αž“αŸ’αž›αžΆαž™αž€ 240 GB αŸ” αž’αŸ’αž“αž€αžšαŸ€αž”αž…αŸ†αž”αžΆαž“αž’αžΆαž“αžΆαžαžΆ αž€αŸ†αžŽαŸ‚αž‘αžΆαŸ†αž„αž–αžΈαžšαž“αŸαŸ‡αž•αž›αž·αžαž‘αžΎαž„αžœαž·αž‰αž“αžΌαžœαž‚αŸ†αž“αžΌαžšαžŠαžΌαž…αž‚αŸ’αž“αžΆ αžŠαŸ‚αž›αž˜αžΆαž“αž“αŸαž™αžαžΆαž€αŸ†αžŽαŸ‚αž–αŸαž‰αž›αŸαž‰αž‚αžΊαž›αŸ‚αž„αžαŸ’αžšαžΌαžœαž€αžΆαžšαžαž‘αŸ…αž‘αŸ€αžαŸ” αž€αŸ’αž“αž»αž„αž€αžšαžŽαžΈαžŽαžΆαž€αŸαžŠαŸ„αž™ αž€αžΆαžšαžšαž€αŸ’αžŸαžΆαž‘αž»αž€αžšαžΌαž”αž—αžΆαž–αž…αŸ†αž“αž½αž“ 50 αž›αžΆαž“αž“αŸ…αž€αŸ’αž“αž»αž„αž―αž€αžŸαžΆαžšαž€αŸ’αžšαžΆαž αŸ’αžœαž·αž€ αž¬αž€αŸ’αž“αž»αž„αž‘αž˜αŸ’αžšαž„αŸ‹αž‡αžΆαž’αžΆαžšαŸαž—αŸ’αž›αžΆαž˜αŸ—αžαŸ’αžšαžΌαžœαž”αžΆαž“αž…αžΆαžαŸ‹αž‘αž»αž€αžαžΆαž˜αž·αž“αž˜αžΆαž“αž•αž›αž…αŸ†αžŽαŸαž‰ αž αžΎαž™αž™αžΎαž„αž”αžΆαž“αžŸαž˜αŸ’αžšαŸαž…αž…αž·αžαŸ’αžαž”αž‰αŸ’αž…αžΌαž›αž―αž€αžŸαžΆαžš CSV αž‘αžΆαŸ†αž„αž’αžŸαŸ‹αž–αžΈαž”αžŽαŸ’αžŽαžŸαžΆαžš train_simplified.zip αž‘αŸ…αž€αŸ’αž“αž»αž„αž˜αžΌαž›αžŠαŸ’αž‹αžΆαž“αž‘αž·αž“αŸ’αž“αž“αŸαž™αž‡αžΆαž˜αž½αž™αž“αžΉαž„αžšαžΌαž”αž—αžΆαž–αž‡αŸ†αž“αžΆαž“αŸ‹αž”αž“αŸ’αž‘αžΆαž”αŸ‹αž“αŸƒαž‘αŸ†αž αŸ†αžŠαŸ‚αž›αžαŸ’αžšαžΌαžœαž€αžΆαžš "αž“αŸ…αž›αžΎαž€αžΆαžšαž αŸ„αŸ‡αž αžΎαžš" αžŸαž˜αŸ’αžšαžΆαž”αŸ‹αž”αžΆαž…αŸ‹αž“αžΈαž˜αž½αž™αŸ—αŸ”

αž”αŸ’αžšαž–αŸαž“αŸ’αž’αžŠαŸ‚αž›αž”αžΆαž“αž”αž‰αŸ’αž‡αžΆαž€αŸ‹αž™αŸ‰αžΆαž„αž…αŸ’αž”αžΆαžŸαŸ‹αžαŸ’αžšαžΌαžœαž”αžΆαž“αž‡αŸ’αžšαžΎαžŸαžšαžΎαžŸαž‡αžΆ DBMS MonetDBαž–αŸ„αž›αž‚αžΊαž€αžΆαžšαž’αž“αž»αžœαžαŸ’αžαžŸαž˜αŸ’αžšαžΆαž”αŸ‹ R αž‡αžΆαž€αž‰αŸ’αž…αž”αŸ‹αž˜αž½αž™αŸ” MonetDBLite. αž€αž‰αŸ’αž…αž”αŸ‹αžšαž½αž˜αž”αž‰αŸ’αž…αžΌαž›αž€αŸ†αžŽαŸ‚αžŠαŸ‚αž›αž”αžΆαž“αž”αž„αŸ’αž€αž”αŸ‹αž“αŸƒαž˜αŸ‰αžΆαžŸαŸŠαžΈαž“αž˜αŸαž˜αžΌαž›αžŠαŸ’αž‹αžΆαž“αž‘αž·αž“αŸ’αž“αž“αŸαž™ αž“αž·αž„αž’αž“αž»αž‰αŸ’αž‰αžΆαžαž±αŸ’αž™αž’αŸ’αž“αž€αž™αž€αž˜αŸ‰αžΆαžŸαŸŠαžΈαž“αž˜αŸαžŠαŸ„αž™αž•αŸ’αž‘αžΆαž›αŸ‹αž–αžΈαžŸαž˜αŸαž™ R αž αžΎαž™αž’αŸ’αžœαžΎαž€αžΆαžšαž‡αžΆαž˜αž½αž™αžœαžΆαž“αŸ…αž‘αžΈαž“αŸ„αŸ‡αŸ” αž€αžΆαžšαž”αž„αŸ’αž€αžΎαžαž˜αžΌαž›αžŠαŸ’αž‹αžΆαž“αž‘αž·αž“αŸ’αž“αž“αŸαž™ αž“αž·αž„αž€αžΆαžšαž—αŸ’αž‡αžΆαž”αŸ‹αž‘αŸ…αžœαžΆαžαŸ’αžšαžΌαžœαž”αžΆαž“αž’αž“αž»αžœαžαŸ’αžαžŠαŸ„αž™αž”αŸ’αžšαžΎαž–αžΆαž€αŸ’αž™αž”αž‰αŸ’αž‡αžΆαž˜αž½αž™αŸ–

con <- DBI::dbConnect(drv = MonetDBLite::MonetDBLite(), Sys.getenv("DBDIR"))

αž™αžΎαž„αž“αžΉαž„αžαŸ’αžšαžΌαžœαž€αžΆαžšαž”αž„αŸ’αž€αžΎαžαžαžΆαžšαžΆαž„αž–αžΈαžšαŸ– αž˜αž½αž™αžŸαž˜αŸ’αžšαžΆαž”αŸ‹αž‘αž·αž“αŸ’αž“αž“αŸαž™αž‘αžΆαŸ†αž„αž’αžŸαŸ‹ αž˜αž½αž™αž‘αŸ€αžαžŸαž˜αŸ’αžšαžΆαž”αŸ‹αž–αŸαžαŸŒαž˜αžΆαž“αžŸαŸαžœαžΆαž€αž˜αŸ’αž˜αž’αŸ†αž–αžΈαž―αž€αžŸαžΆαžšαžŠαŸ‚αž›αž”αžΆαž“αž‘αžΆαž‰αž™αž€ (αž˜αžΆαž“αž”αŸ’αžšαž™αŸ„αž‡αž“αŸαž”αŸ’αžšαžŸαž·αž“αž”αžΎαž˜αžΆαž“αž’αŸ’αžœαžΈαžαž»αžŸ αž αžΎαž™αžŠαŸ†αžŽαžΎαžšαž€αžΆαžšαžαŸ’αžšαžΌαžœαžαŸ‚αž”αž“αŸ’αžαž”αž“αŸ’αž‘αžΆαž”αŸ‹αž–αžΈαž‘αžΆαž‰αž™αž€αž―αž€αžŸαžΆαžšαž‡αžΆαž…αŸ’αžšαžΎαž“)αŸ–

αž€αžΆαžšαž”αž„αŸ’αž€αžΎαžαžαžΆαžšαžΆαž„

if (!DBI::dbExistsTable(con, "doodles")) {
  DBI::dbCreateTable(
    con = con,
    name = "doodles",
    fields = c(
      "countrycode" = "char(2)",
      "drawing" = "text",
      "key_id" = "bigint",
      "recognized" = "bool",
      "timestamp" = "timestamp",
      "word" = "text"
    )
  )
}

if (!DBI::dbExistsTable(con, "upload_log")) {
  DBI::dbCreateTable(
    con = con,
    name = "upload_log",
    fields = c(
      "id" = "serial",
      "file_name" = "text UNIQUE",
      "uploaded" = "bool DEFAULT false"
    )
  )
}

αž˜αž’αŸ’αž™αŸ„αž”αžΆαž™αž›αžΏαž“αž”αŸ†αž•αž»αžαž€αŸ’αž“αž»αž„αž€αžΆαžšαž•αŸ’αž‘αž»αž€αž‘αž·αž“αŸ’αž“αž“αŸαž™αž‘αŸ…αž€αŸ’αž“αž»αž„αž˜αžΌαž›αžŠαŸ’αž‹αžΆαž“αž‘αž·αž“αŸ’αž“αž“αŸαž™αž‚αžΊαž…αž˜αŸ’αž›αž„αž―αž€αžŸαžΆαžš CSV αžŠαŸ„αž™αž•αŸ’αž‘αžΆαž›αŸ‹αžŠαŸ„αž™αž”αŸ’αžšαžΎαž–αžΆαž€αŸ’αž™αž”αž‰αŸ’αž‡αžΆ SQL COPY OFFSET 2 INTO tablename FROM path USING DELIMITERS ',','n','"' NULL AS '' BEST EFFORTαžŠαŸ‚αž›αž‡αžΆαž€αž“αŸ’αž›αŸ‚αž„ tablename - αžˆαŸ’αž˜αŸ„αŸ‡αžαžΆαžšαžΆαž„αž“αž·αž„ path - αž•αŸ’αž›αžΌαžœαž‘αŸ…αž€αžΆαž“αŸ‹αž―αž€αžŸαžΆαžšαŸ” αžαžŽαŸˆαž–αŸαž›αž€αŸ†αž–αž»αž„αž’αŸ’αžœαžΎαž€αžΆαžšαž‡αžΆαž˜αž½αž™αž”αžŽαŸ’αžŽαžŸαžΆαžš αžœαžΆαžαŸ’αžšαžΌαžœαž”αžΆαž“αž‚αŸαžšαž€αžƒαžΎαž‰αžαžΆαž€αžΆαžšαž’αž“αž»αžœαžαŸ’αžαž“αŸαžŠαŸ‚αž›αž”αžΆαž“αž—αŸ’αž‡αžΆαž”αŸ‹αž˜αž€αž‡αžΆαž˜αž½αž™ unzip αž“αŸ…αž€αŸ’αž“αž»αž„ R αž˜αž·αž“αžŠαŸ†αžŽαžΎαžšαž€αžΆαžšαžαŸ’αžšαžΉαž˜αžαŸ’αžšαžΌαžœαž‡αžΆαž˜αž½αž™αž―αž€αžŸαžΆαžšαž˜αž½αž™αž…αŸ†αž“αž½αž“αž–αžΈαž”αžŽαŸ’αžŽαžŸαžΆαžš αžŠαžΌαž…αŸ’αž“αŸαŸ‡αž™αžΎαž„αž”αžΆαž“αž”αŸ’αžšαžΎαž”αŸ’αžšαž–αŸαž“αŸ’αž’ unzip (αžŠαŸ„αž™αž”αŸ’αžšαžΎαž”αŸ‰αžΆαžšαŸ‰αžΆαž˜αŸ‰αŸ‚αžαŸ’αžš getOption("unzip")).

αž˜αž»αžαž„αžΆαžšαžŸαž˜αŸ’αžšαžΆαž”αŸ‹αžŸαžšαžŸαŸαžšαž‘αŸ…αž˜αžΌαž›αžŠαŸ’αž‹αžΆαž“αž‘αž·αž“αŸ’αž“αž“αŸαž™

#' @title Π˜Π·Π²Π»Π΅Ρ‡Π΅Π½ΠΈΠ΅ ΠΈ Π·Π°Π³Ρ€ΡƒΠ·ΠΊΠ° Ρ„Π°ΠΉΠ»ΠΎΠ²
#'
#' @description
#' Π˜Π·Π²Π»Π΅Ρ‡Π΅Π½ΠΈΠ΅ CSV-Ρ„Π°ΠΉΠ»ΠΎΠ² ΠΈΠ· ZIP-Π°Ρ€Ρ…ΠΈΠ²Π° ΠΈ Π·Π°Π³Ρ€ΡƒΠ·ΠΊΠ° ΠΈΡ… Π² Π±Π°Π·Ρƒ Π΄Π°Π½Π½Ρ‹Ρ…
#'
#' @param con ΠžΠ±ΡŠΠ΅ΠΊΡ‚ ΠΏΠΎΠ΄ΠΊΠ»ΡŽΡ‡Π΅Π½ΠΈΡ ΠΊ Π±Π°Π·Π΅ Π΄Π°Π½Π½Ρ‹Ρ… (класс `MonetDBEmbeddedConnection`).
#' @param tablename НазваниС Ρ‚Π°Π±Π»ΠΈΡ†Ρ‹ Π² Π±Π°Π·Π΅ Π΄Π°Π½Π½Ρ‹Ρ….
#' @oaram zipfile ΠŸΡƒΡ‚ΡŒ ΠΊ ZIP-Π°Ρ€Ρ…ΠΈΠ²Ρƒ.
#' @oaram filename Имя Ρ„Π°ΠΉΠ»Π° Π²Π½ΡƒΡ€ΠΈ ZIP-Π°Ρ€Ρ…ΠΈΠ²Π°.
#' @param preprocess Ѐункция ΠΏΡ€Π΅Π΄ΠΎΠ±Ρ€Π°Π±ΠΎΡ‚ΠΊΠΈ, которая Π±ΡƒΠ΄Π΅Ρ‚ ΠΏΡ€ΠΈΠΌΠ΅Π½Π΅Π½Π° ΠΈΠ·Π²Π»Π΅Ρ‡Ρ‘Π½Π½ΠΎΠΌΡƒ Ρ„Π°ΠΉΠ»Ρƒ.
#'   Π”ΠΎΠ»ΠΆΠ½Π° ΠΏΡ€ΠΈΠ½ΠΈΠΌΠ°Ρ‚ΡŒ ΠΎΠ΄ΠΈΠ½ Π°Ρ€Π³ΡƒΠΌΠ΅Π½Ρ‚ `data` (ΠΎΠ±ΡŠΠ΅ΠΊΡ‚ `data.table`).
#'
#' @return `TRUE`.
#'
upload_file <- function(con, tablename, zipfile, filename, preprocess = NULL) {
  # ΠŸΡ€ΠΎΠ²Π΅Ρ€ΠΊΠ° Π°Ρ€Π³ΡƒΠΌΠ΅Π½Ρ‚ΠΎΠ²
  checkmate::assert_class(con, "MonetDBEmbeddedConnection")
  checkmate::assert_string(tablename)
  checkmate::assert_string(filename)
  checkmate::assert_true(DBI::dbExistsTable(con, tablename))
  checkmate::assert_file_exists(zipfile, access = "r", extension = "zip")
  checkmate::assert_function(preprocess, args = c("data"), null.ok = TRUE)

  # Π˜Π·Π²Π»Π΅Ρ‡Π΅Π½ΠΈΠ΅ Ρ„Π°ΠΉΠ»Π°
  path <- file.path(tempdir(), filename)
  unzip(zipfile, files = filename, exdir = tempdir(), 
        junkpaths = TRUE, unzip = getOption("unzip"))
  on.exit(unlink(file.path(path)))

  # ΠŸΡ€ΠΈΠΌΠ΅Π½ΡΠ΅ΠΌ функция ΠΏΡ€Π΅Π΄ΠΎΠ±Ρ€Π°Π±ΠΎΡ‚ΠΊΠΈ
  if (!is.null(preprocess)) {
    .data <- data.table::fread(file = path)
    .data <- preprocess(data = .data)
    data.table::fwrite(x = .data, file = path, append = FALSE)
    rm(.data)
  }

  # Запрос ΠΊ Π‘Π” Π½Π° ΠΈΠΌΠΏΠΎΡ€Ρ‚ CSV
  sql <- sprintf(
    "COPY OFFSET 2 INTO %s FROM '%s' USING DELIMITERS ',','n','"' NULL AS '' BEST EFFORT",
    tablename, path
  )
  # Π’Ρ‹ΠΏΠΎΠ»Π½Π΅Π½ΠΈΠ΅ запроса ΠΊ Π‘Π”
  DBI::dbExecute(con, sql)

  # Π”ΠΎΠ±Π°Π²Π»Π΅Π½ΠΈΠ΅ записи ΠΎΠ± ΡƒΡΠΏΠ΅ΡˆΠ½ΠΎΠΉ Π·Π°Π³Ρ€ΡƒΠ·ΠΊΠ΅ Π² ΡΠ»ΡƒΠΆΠ΅Π±Π½ΡƒΡŽ Ρ‚Π°Π±Π»ΠΈΡ†Ρƒ
  DBI::dbExecute(con, sprintf("INSERT INTO upload_log(file_name, uploaded) VALUES('%s', true)",
                              filename))

  return(invisible(TRUE))
}

αž”αŸ’αžšαžŸαž·αž“αž”αžΎαž’αŸ’αž“αž€αžαŸ’αžšαžΌαžœαž€αžΆαžšαž”αŸ†αž”αŸ’αž›αŸ‚αž„αžαžΆαžšαžΆαž„αž˜αž»αž“αž“αžΉαž„αžŸαžšαžŸαŸαžšαžœαžΆαž‘αŸ…αž˜αžΌαž›αžŠαŸ’αž‹αžΆαž“αž‘αž·αž“αŸ’αž“αž“αŸαž™ αžœαžΆαž‚αŸ’αžšαž”αŸ‹αž‚αŸ’αžšαžΆαž“αŸ‹αž€αŸ’αž“αž»αž„αž€αžΆαžšαž†αŸ’αž›αž„αž€αžΆαžαŸ‹αž€αŸ’αž“αž»αž„αž’αžΆαž‚αž»αž™αž˜αŸ‰αž„αŸ‹ preprocess αž˜αž»αžαž„αžΆαžšαžŠαŸ‚αž›αž“αžΉαž„αž”αŸ†αž”αŸ’αž›αŸ‚αž„αž‘αž·αž“αŸ’αž“αž“αŸαž™αŸ”

αž€αžΌαžŠαžŸαž˜αŸ’αžšαžΆαž”αŸ‹αž•αŸ’αž‘αž»αž€αž‘αž·αž“αŸ’αž“αž“αŸαž™αž‡αžΆαž”αž“αŸ’αžαž”αž“αŸ’αž‘αžΆαž”αŸ‹αž‘αŸ…αž€αŸ’αž“αž»αž„αž˜αžΌαž›αžŠαŸ’αž‹αžΆαž“αž‘αž·αž“αŸ’αž“αž“αŸαž™αŸ–

αž€αžΆαžšαžŸαžšαžŸαŸαžšαž‘αž·αž“αŸ’αž“αž“αŸαž™αž‘αŸ…αž˜αžΌαž›αžŠαŸ’αž‹αžΆαž“αž‘αž·αž“αŸ’αž“αž“αŸαž™

# Бписок Ρ„Π°ΠΉΠ»ΠΎΠ² для записи
files <- unzip(zipfile, list = TRUE)$Name

# Бписок ΠΈΡΠΊΠ»ΡŽΡ‡Π΅Π½ΠΈΠΉ, Ссли Ρ‡Π°ΡΡ‚ΡŒ Ρ„Π°ΠΉΠ»ΠΎΠ² ΡƒΠΆΠ΅ Π±Ρ‹Π»Π° Π·Π°Π³Ρ€ΡƒΠΆΠ΅Π½Π°
to_skip <- DBI::dbGetQuery(con, "SELECT file_name FROM upload_log")[[1L]]
files <- setdiff(files, to_skip)

if (length(files) > 0L) {
  # ЗапускаСм Ρ‚Π°ΠΉΠΌΠ΅Ρ€
  tictoc::tic()
  # ΠŸΡ€ΠΎΠ³Ρ€Π΅ΡΡ Π±Π°Ρ€
  pb <- txtProgressBar(min = 0L, max = length(files), style = 3)
  for (i in seq_along(files)) {
    upload_file(con = con, tablename = "doodles", 
                zipfile = zipfile, filename = files[i])
    setTxtProgressBar(pb, i)
  }
  close(pb)
  # ΠžΡΡ‚Π°Π½Π°Π²Π»ΠΈΠ²Π°Π΅ΠΌ Ρ‚Π°ΠΉΠΌΠ΅Ρ€
  tictoc::toc()
}

# 526.141 sec elapsed - ΠΊΠΎΠΏΠΈΡ€ΠΎΠ²Π°Π½ΠΈΠ΅ SSD->SSD
# 558.879 sec elapsed - ΠΊΠΎΠΏΠΈΡ€ΠΎΠ²Π°Π½ΠΈΠ΅ USB->SSD

αž–αŸαž›αžœαŸαž›αžΆαž•αŸ’αž‘αž»αž€αž‘αž·αž“αŸ’αž“αž“αŸαž™αž’αžΆαž…αž”αŸ’αžšαŸ‚αž”αŸ’αžšαž½αž›αž’αžΆαžŸαŸ’αžšαŸαž™αž›αžΎαž›αž€αŸ’αžαžŽαŸˆαž›αŸ’αž”αžΏαž“αž“αŸƒαžŠαŸ’αžšαžΆαž™αžŠαŸ‚αž›αž”αžΆαž“αž”αŸ’αžšαžΎαŸ” αž€αŸ’αž“αž»αž„αž€αžšαžŽαžΈαžšαž”αžŸαŸ‹αž™αžΎαž„ αž€αžΆαžšαž’αžΆαž“ αž“αž·αž„αžŸαžšαžŸαŸαžšαž€αŸ’αž“αž»αž„ SSD αž˜αž½αž™ αž¬αž–αžΈ 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. αžŸαž˜αŸ’αžšαžΆαž”αŸ‹αžšαžΏαž„αž“αŸαŸ‡αž™αžΎαž„αž”αžΆαž“αž”αŸ’αžšαžΎαž›αŸ’αž”αž·αž… 3 αŸ” αž‘αžΈαž˜αž½αž™αž‚αžΊαž€αžΆαžαŸ‹αž”αž“αŸ’αžαž™αžœαž·αž˜αžΆαžαŸ’αžšαž“αŸƒαž”αŸ’αžšαž—αŸαž‘αžŠαŸ‚αž›αžšαž€αŸ’αžŸαžΆαž‘αž»αž€αž›αŸαžαžŸαž˜αŸ’αž‚αžΆαž›αŸ‹αžŸαž„αŸ’αž€αŸαžαŸ” αž“αŸ…αž€αŸ’αž“αž»αž„αžŸαŸ†αžŽαž»αŸ†αž‘αž·αž“αŸ’αž“αž“αŸαž™αžŠαžΎαž˜ αž”αŸ’αžšαž—αŸαž‘αžŠαŸ‚αž›αžαŸ’αžšαžΌαžœαž€αžΆαžšαžŠαžΎαž˜αŸ’αž”αžΈαžšαž€αŸ’αžŸαžΆαž‘αž»αž€αž›αŸαžαžŸαž˜αŸ’αž‚αžΆαž›αŸ‹αž‚αžΊ bigintαž”αŸ‰αž»αž“αŸ’αžαŸ‚αž…αŸ†αž“αž½αž“αž“αŸƒαž€αžΆαžšαžŸαž„αŸ’αž€αŸαžαž’αŸ’αžœαžΎαž±αŸ’αž™αžœαžΆαž’αžΆαž…αž’αŸ’αžœαžΎαž‘αŸ…αž”αžΆαž“αžŠαžΎαž˜αŸ’αž”αžΈαž±αŸ’αž™αžŸαž˜αž“αžΉαž„αž€αžΆαžšαž€αŸ†αžŽαžαŸ‹αž’αžαŸ’αžαžŸαž‰αŸ’αž‰αžΆαžŽαžšαž”αžŸαŸ‹αž–αž½αž€αž‚αŸ αžŸαŸ’αž˜αžΎαž“αžΉαž„αž…αŸ†αž“αž½αž“αž’αž˜αŸ’αž˜αžαžΆαž‘αŸ…αž€αŸ’αž“αž»αž„αž”αŸ’αžšαž—αŸαž‘ int. αž€αžΆαžšαžŸαŸ’αžœαŸ‚αž„αžšαž€αž‚αžΊαž›αžΏαž“αž‡αžΆαž„αž€αŸ’αž“αž»αž„αž€αžšαžŽαžΈαž“αŸαŸ‡αŸ” αž›αŸ’αž”αž·αž…αž‘αžΈαž–αžΈαžšαž‚αžΊαžαŸ’αžšαžΌαžœαž”αŸ’αžšαžΎ ORDERED INDEX - αž™αžΎαž„αž”αžΆαž“αžˆαžΆαž“αž‘αŸ…αžŠαž›αŸ‹αž€αžΆαžšαžŸαž˜αŸ’αžšαŸαž…αž…αž·αžαŸ’αžαž“αŸαŸ‡αž‡αžΆαž€αŸ‹αžŸαŸ’αžαŸ‚αž„ αžŠαŸ„αž™αž”αžΆαž“αž†αŸ’αž›αž„αž€αžΆαžαŸ‹αž‚αŸ’αžšαž”αŸ‹αž˜αž’αŸ’αž™αŸ„αž”αžΆαž™αž‘αžΆαŸ†αž„αž’αžŸαŸ‹αŸ” αž‡αž˜αŸ’αžšαžΎαžŸ. αž‘αžΈαž”αžΈαž‚αžΊαžαŸ’αžšαžΌαžœαž”αŸ’αžšαžΎαžŸαŸ†αžŽαž½αžšαžŠαŸ‚αž›αž˜αžΆαž“αž”αŸ‰αžΆαžšαŸ‰αžΆαž˜αŸ‰αŸ‚αžαŸ’αžšαŸ” αžαŸ’αž›αžΉαž˜αžŸαžΆαžšαž“αŸƒαžœαž·αž’αžΈαžŸαžΆαžŸαŸ’αžαŸ’αžšαž‚αžΊ αž”αŸ’αžšαžαž·αž”αžαŸ’αžαž·αž–αžΆαž€αŸ’αž™αž”αž‰αŸ’αž‡αžΆαž˜αŸ’αžαž„ PREPARE αž‡αžΆαž˜αž½αž™αž“αžΉαž„αž€αžΆαžšαž”αŸ’αžšαžΎαž”αŸ’αžšαžΆαžŸαŸ‹αž‡αžΆαž”αž“αŸ’αžαž”αž“αŸ’αž‘αžΆαž”αŸ‹αž“αŸƒαž€αž“αŸ’αžŸαŸ„αž˜αžŠαŸ‚αž›αž”αžΆαž“αžšαŸ€αž”αž…αŸ†αž“αŸ…αž–αŸαž›αž”αž„αŸ’αž€αžΎαžαž”αžŽαŸ’αžαž»αŸ†αž“αŸƒαžŸαŸ†αžŽαž½αžšαž“αŸƒαž”αŸ’αžšαž—αŸαž‘αžŠαžΌαž…αž‚αŸ’αž“αžΆ αž”αŸ‰αž»αž“αŸ’αžαŸ‚αžαžΆαž˜αž–αž·αžαžœαžΆαž˜αžΆαž“αž’αžαŸ’αžαž”αŸ’αžšαž™αŸ„αž‡αž“αŸαž˜αž½αž™αž€αŸ’αž“αž»αž„αž€αžΆαžšαž”αŸ’αžšαŸ€αž”αž’αŸ€αž”αž‡αžΆαž˜αž½αž™αžŸαžΆαž˜αž‰αŸ’αž‰αž˜αž½αž™αŸ” 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)

Quick Draw Doodle RecognitionαŸ– αžšαž”αŸ€αž”αž”αž„αŸ’αž€αžΎαžαž˜αž·αžαŸ’αžαž‡αžΆαž˜αž½αž™ R, C++ αž“αž·αž„αž”αžŽαŸ’αžαžΆαž‰αžŸαžšαžŸαŸƒαž”αŸ’αžšαžŸαžΆαž‘

2. αž€αžΆαžšαžšαŸ€αž”αž…αŸ†αž”αžΆαž…αŸ‹

αžŠαŸ†αžŽαžΎαžšαž€αžΆαžšαžšαŸ€αž”αž…αŸ†αž”αžŽαŸ’αžαž»αŸ†αž‘αžΆαŸ†αž„αž˜αžΌαž›αž˜αžΆαž“αž‡αŸ†αž αžΆαž“αžŠαžΌαž…αžαžΆαž„αž€αŸ’αžšαŸ„αž˜αŸˆ

  1. αž€αžΆαžšαž‰αŸ‚αž€ JSON αž‡αžΆαž…αŸ’αžšαžΎαž“αžŠαŸ‚αž›αž˜αžΆαž“αžœαŸ‰αž·αž…αž‘αŸαžšαž“αŸƒαžαŸ’αžŸαŸ‚αž’αž€αŸ’αžŸαžšαž‡αžΆαž˜αž½αž™αž“αžΉαž„αž€αžΌαž’αžšαžŠαŸ„αž“αŸαž“αŸƒαž…αŸ†αžŽαž»αž…αŸ”
  2. αž‚αžΌαžšαž”αž“αŸ’αž‘αžΆαžαŸ‹αž–αžŽαŸŒαžŠαŸ„αž™αž•αŸ’αž’αŸ‚αž€αž›αžΎαž€αžΌαž’αžšαžŠαŸ„αžŽαŸαž“αŸƒαž…αŸ†αžŽαž»αž…αž“αŸ…αž›αžΎαžšαžΌαž”αž—αžΆαž–αž“αŸƒαž‘αŸ†αž αŸ†αžŠαŸ‚αž›αžαŸ’αžšαžΌαžœαž€αžΆαžš (αž§αž‘αžΆαž αžšαžŽαŸ 256 Γ— 256 ឬ 128 Γ— 128) αŸ”
  3. αž€αžΆαžšαž”αŸ†αž”αŸ’αž›αŸ‚αž„αžšαžΌαž”αž—αžΆαž–αž›αž‘αŸ’αž’αž•αž›αž‘αŸ…αž‡αžΆ tensor αŸ”

αž‡αžΆαž•αŸ’αž“αŸ‚αž€αž˜αž½αž™αž“αŸƒαž€αžΆαžšαž”αŸ’αžšαž€αž½αžαž”αŸ’αžšαž‡αŸ‚αž„αž€αŸ’αž“αž»αž„αž…αŸ†αžŽαŸ„αž˜αžαžΊαžŽαŸ‚αž› Python αž”αž‰αŸ’αž αžΆαžαŸ’αžšαžΌαžœαž”αžΆαž“αžŠαŸ„αŸ‡αžŸαŸ’αžšαžΆαž™αž‡αžΆαž…αž˜αŸ’αž”αž„αžŠαŸ„αž™αž”αŸ’αžšαžΎ αž’αžΌαžŸαŸŠαžΈαžŸαŸŠαžΈαžŸαŸŠαžΈαŸ”. αž˜αž½αž™αž“αŸƒ analogues αžŸαžΆαž˜αž‰αŸ’αž‰αž”αŸ†αž•αž»αžαž“αž·αž„αž‡αžΆαž€αŸ‹αžŸαŸ’αžαŸ‚αž„αž”αŸ†αž•αž»αžαž“αŸ…αž€αŸ’αž“αž»αž„ R αž“αžΉαž„αž˜αžΎαž›αž‘αŸ…αžŠαžΌαž…αž“αŸαŸ‡:

αž€αžΆαžšαž’αž“αž»αžœαžαŸ’αž JSON αž‘αŸ…αž‡αžΆαž€αžΆαžšαž”αŸ†αž”αŸ’αž›αŸ‚αž„ Tensor αž€αŸ’αž“αž»αž„ R

r_process_json_str <- function(json, line.width = 3, 
                               color = TRUE, scale = 1) {
  # ΠŸΠ°Ρ€ΡΠΈΠ½Π³ JSON
  coords <- jsonlite::fromJSON(json, simplifyMatrix = FALSE)
  tmp <- tempfile()
  # УдаляСм Π²Ρ€Π΅ΠΌΠ΅Π½Π½Ρ‹ΠΉ Ρ„Π°ΠΉΠ» ΠΏΠΎ Π·Π°Π²Π΅Ρ€ΡˆΠ΅Π½ΠΈΡŽ Ρ„ΡƒΠ½ΠΊΡ†ΠΈΠΈ
  on.exit(unlink(tmp))
  png(filename = tmp, width = 256 * scale, height = 256 * scale, pointsize = 1)
  # ΠŸΡƒΡΡ‚ΠΎΠΉ Π³Ρ€Π°Ρ„ΠΈΠΊ
  plot.new()
  # Π Π°Π·ΠΌΠ΅Ρ€ ΠΎΠΊΠ½Π° Π³Ρ€Π°Ρ„ΠΈΠΊΠ°
  plot.window(xlim = c(256 * scale, 0), ylim = c(256 * scale, 0))
  # Π¦Π²Π΅Ρ‚Π° Π»ΠΈΠ½ΠΈΠΉ
  cols <- if (color) rainbow(length(coords)) else "#000000"
  for (i in seq_along(coords)) {
    lines(x = coords[[i]][[1]] * scale, y = coords[[i]][[2]] * scale, 
          col = cols[i], lwd = line.width)
  }
  dev.off()
  # ΠŸΡ€Π΅ΠΎΠ±Ρ€Π°Π·ΠΎΠ²Π°Π½ΠΈΠ΅ изобраТСния Π² 3-Ρ… ΠΌΠ΅Ρ€Π½Ρ‹ΠΉ массив
  res <- png::readPNG(tmp)
  return(res)
}

r_process_json_vector <- function(x, ...) {
  res <- lapply(x, r_process_json_str, ...)
  # ОбъСдинСниС 3-Ρ… ΠΌΠ΅Ρ€Π½Ρ‹Ρ… массивов ΠΊΠ°Ρ€Ρ‚ΠΈΠ½ΠΎΠΊ Π² 4-Ρ… ΠΌΠ΅Ρ€Π½Ρ‹ΠΉ Π² Ρ‚Π΅Π½Π·ΠΎΡ€
  res <- do.call(abind::abind, c(res, along = 0))
  return(res)
}

αž€αžΆαžšαž‚αžΌαžšαžαŸ’αžšαžΌαžœαž”αžΆαž“αž’αž“αž»αžœαžαŸ’αžαžŠαŸ„αž™αž”αŸ’αžšαžΎαž§αž”αž€αžšαžŽαŸ R αžŸαŸ’αžαž„αŸ‹αžŠαžΆαžš αž αžΎαž™αžšαž€αŸ’αžŸαžΆαž‘αž»αž€αž€αŸ’αž“αž»αž„ PNG αž”αžŽαŸ’αžαŸ„αŸ‡αž’αžΆαžŸαž“αŸ’αž“αžŠαŸ‚αž›αžšαž€αŸ’αžŸαžΆαž‘αž»αž€αž€αŸ’αž“αž»αž„ RAM (αž“αŸ…αž›αžΎ Linux ថត R αž”αžŽαŸ’αžαŸ„αŸ‡αž’αžΆαžŸαž“αŸ’αž“αž˜αžΆαž“αž‘αžΈαžαžΆαŸ†αž„αž“αŸ…αž€αŸ’αž“αž»αž„αžαž /tmpαžŠαŸ†αž‘αžΎαž„αž€αŸ’αž“αž»αž„ RAM) αŸ” αž”αž“αŸ’αž‘αžΆαž”αŸ‹αž˜αž€αž―αž€αžŸαžΆαžšαž“αŸαŸ‡αžαŸ’αžšαžΌαžœαž”αžΆαž“αž’αžΆαž“αž‡αžΆαž’αžΆαžšαŸαž”αžΈαžœαž·αž˜αžΆαžαŸ’αžšαžŠαŸ‚αž›αž˜αžΆαž“αž›αŸαžαž…αžΆαž”αŸ‹αž–αžΈ 0 αžŠαž›αŸ‹ 1αŸ” αž“αŸαŸ‡αž‚αžΊαžŸαŸ†αžαžΆαž“αŸ‹αž–αŸ’αžšαŸ„αŸ‡ BMP αžŸαžΆαž˜αž‰αŸ’αž‰αž‡αžΆαž„αž“αžΉαž„αžαŸ’αžšαžΌαžœαž”αžΆαž“αž’αžΆαž“αž‘αŸ…αž€αŸ’αž“αž»αž„αž’αžΆαžšαŸαž†αŸ…αžŠαŸ‚αž›αž˜αžΆαž“αž›αŸαžαž€αžΌαžŠαž–αžŽαŸŒαž‚αŸ„αž›αžŠαž”αŸ‹αž”αŸ’αžšαžΆαŸ†αž˜αž½αž™αŸ”

αžαŸ„αŸ‡αžŸαžΆαž€αž›αŸ’αž”αž„αž›αž‘αŸ’αž’αž•αž›αŸ–

zip_file <- file.path("data", "train_simplified.zip")
csv_file <- "cat.csv"
unzip(zip_file, files = csv_file, exdir = tempdir(), 
      junkpaths = TRUE, unzip = getOption("unzip"))
tmp_data <- data.table::fread(file.path(tempdir(), csv_file), sep = ",", 
                              select = "drawing", nrows = 10000)
arr <- r_process_json_str(tmp_data[4, drawing])
dim(arr)
# [1] 256 256   3
plot(magick::image_read(arr))

Quick Draw Doodle RecognitionαŸ– αžšαž”αŸ€αž”αž”αž„αŸ’αž€αžΎαžαž˜αž·αžαŸ’αžαž‡αžΆαž˜αž½αž™ R, C++ αž“αž·αž„αž”αžŽαŸ’αžαžΆαž‰αžŸαžšαžŸαŸƒαž”αŸ’αžšαžŸαžΆαž‘

αž”αžŽαŸ’αžαž»αŸ†αžαŸ’αž›αž½αž“αžœαžΆαž“αžΉαž„αžαŸ’αžšαžΌαžœαž”αžΆαž“αž”αž„αŸ’αž€αžΎαžαž‘αžΎαž„αžŠαžΌαž…αžαžΆαž„αž€αŸ’αžšαŸ„αž˜αŸ–

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

αž€αžΆαžšαž’αž“αž»αžœαžαŸ’αžαž“αŸαŸ‡αž αžΆαž€αŸ‹αžŠαžΌαž…αž‡αžΆαžŸαž˜αžŸαŸ’αžšαž”αž”αŸ†αž•αž»αžαžŸαž˜αŸ’αžšαžΆαž”αŸ‹αž™αžΎαž„ αžŠαŸ„αž™αžŸαžΆαžšαž€αžΆαžšαž”αž„αŸ’αž€αžΎαžαž”αžŽαŸ’αžαž»αŸ†αž’αŸ†αŸ—αž…αŸ†αžŽαžΆαž™αž–αŸαž›αž™αžΌαžšαž˜αž·αž“αžŸαž˜αžšαž˜αŸ’αž™ αž αžΎαž™αž™αžΎαž„αž”αžΆαž“αžŸαž˜αŸ’αžšαŸαž…αž…αž·αžαŸ’αžαž‘αžΆαž‰αž™αž€αž’αžαŸ’αžαž”αŸ’αžšαž™αŸ„αž‡αž“αŸαž–αžΈαž”αž‘αž–αž·αžŸαŸ„αž’αž“αŸαžšαž”αžŸαŸ‹αžŸαž αž€αžΆαžšαžΈαžšαž”αžŸαŸ‹αž™αžΎαž„αžŠαŸ„αž™αž”αŸ’αžšαžΎαž”αžŽαŸ’αžŽαžΆαž›αŸαž™αžŠαŸαž˜αžΆαž“αž₯αž‘αŸ’αž’αž·αž–αž›αŸ” αž’αžΌαžŸαŸŠαžΈαžŸαŸŠαžΈαžŸαŸŠαžΈαŸ”. αž“αŸ…αž–αŸαž›αž“αŸ„αŸ‡αž˜αž·αž“αž˜αžΆαž“αž€αž‰αŸ’αž…αž”αŸ‹αžŠαŸ‚αž›αžαŸ’αžšαŸ€αž˜αžšαž½αž…αž‡αžΆαžŸαŸ’αžšαŸαž…αžŸαž˜αŸ’αžšαžΆαž”αŸ‹ R (αž˜αž·αž“αž˜αžΆαž“αž₯αž‘αžΌαžœαž“αŸαŸ‡αž‘αŸ) αžŠαžΌαž…αŸ’αž“αŸαŸ‡αž€αžΆαžšαž’αž“αž»αžœαžαŸ’αžαžαž·αž…αžαž½αž…αž“αŸƒαž˜αž»αžαž„αžΆαžšαžŠαŸ‚αž›αžαŸ’αžšαžΌαžœαž€αžΆαžšαžαŸ’αžšαžΌαžœαž”αžΆαž“αžŸαžšαžŸαŸαžšαž“αŸ…αž€αŸ’αž“αž»αž„ C ++ αž‡αžΆαž˜αž½αž™αž“αžΉαž„αž€αžΆαžšαž”αž‰αŸ’αž…αžΌαž›αž‘αŸ…αž€αŸ’αž“αž»αž„αž€αžΌαžŠ R αžŠαŸ„αž™αž”αŸ’αžšαžΎ Rcpp.

αžŠαžΎαž˜αŸ’αž”αžΈαžŠαŸ„αŸ‡αžŸαŸ’αžšαžΆαž™αž”αž‰αŸ’αž αžΆ αž€αž‰αŸ’αž…αž”αŸ‹ αž“αž·αž„αž”αžŽαŸ’αžŽαžΆαž›αŸαž™αžαžΆαž„αž€αŸ’αžšαŸ„αž˜αžαŸ’αžšαžΌαžœαž”αžΆαž“αž”αŸ’αžšαžΎαž”αŸ’αžšαžΆαžŸαŸ‹αŸ–

  1. αž’αžΌαžŸαŸŠαžΈαžŸαŸŠαžΈαžŸαŸŠαžΈαŸ” αžŸαž˜αŸ’αžšαžΆαž”αŸ‹αž’αŸ’αžœαžΎαž€αžΆαžšαž‡αžΆαž˜αž½αž™αžšαžΌαž”αž—αžΆαž– αž“αž·αž„αž‚αžΌαžšαž”αž“αŸ’αž‘αžΆαžαŸ‹αŸ” αž”αžΆαž“αž”αŸ’αžšαžΎαž”αžŽαŸ’αžŽαžΆαž›αŸαž™αž”αŸ’αžšαž–αŸαž“αŸ’αž’αžŠαŸ‚αž›αž”αžΆαž“αžŠαŸ†αž‘αžΎαž„αž‡αžΆαž˜αž»αž“ αž“αž·αž„αž―αž€αžŸαžΆαžšαž”αž‹αž˜αž€αžαžΆ αž€αŸαžŠαžΌαž…αž‡αžΆαž€αžΆαžšαž—αŸ’αž‡αžΆαž”αŸ‹αžαžΆαž˜αžœαž“αŸ’αžαŸ”

  2. xtensor αžŸαž˜αŸ’αžšαžΆαž”αŸ‹αž’αŸ’αžœαžΎαž€αžΆαžšαž‡αžΆαž˜αž½αž™αž’αžΆαžšαŸαž–αž αž»αžœαž·αž˜αžΆαžαŸ’αžš αž“αž·αž„αžαž„αŸ‹αžŸαŸŠαžΈαžαŸαŸ” αž™αžΎαž„αž”αžΆαž“αž”αŸ’αžšαžΎαž―αž€αžŸαžΆαžšαž”αž‹αž˜αž€αžαžΆαžŠαŸ‚αž›αžšαž½αž˜αž”αž‰αŸ’αž…αžΌαž›αž€αŸ’αž“αž»αž„αž€αž‰αŸ’αž…αž”αŸ‹ R αž“αŸƒαžˆαŸ’αž˜αŸ„αŸ‡αžŠαžΌαž…αž‚αŸ’αž“αžΆαŸ” αž”αžŽαŸ’αžŽαžΆαž›αŸαž™αž’αž“αž»αž‰αŸ’αž‰αžΆαžαž±αŸ’αž™αž’αŸ’αž“αž€αž’αŸ’αžœαžΎαž€αžΆαžšαž‡αžΆαž˜αž½αž™αž’αžΆαžšαŸαž–αž αž»αžœαž·αž˜αžΆαžαŸ’αžš αž‘αžΆαŸ†αž„αž“αŸ…αž€αŸ’αž“αž»αž„αž›αŸ†αžŠαžΆαž”αŸ‹αž‡αž½αžšαž’αŸ† αž“αž·αž„αž‡αž½αžšαž’αŸ†αŸ”

  3. ndjson αžŸαž˜αŸ’αžšαžΆαž”αŸ‹αž‰αŸ‚αž€ JSON αŸ” αž”αžŽαŸ’αžŽαžΆαž›αŸαž™αž“αŸαŸ‡αžαŸ’αžšαžΌαžœαž”αžΆαž“αž”αŸ’αžšαžΎαž“αŸ…αž€αŸ’αž“αž»αž„ xtensor αžŠαŸ„αž™αžŸαŸ’αžœαŸαž™αž”αŸ’αžšαžœαžαŸ’αžαž·αž”αŸ’αžšαžŸαž·αž“αž”αžΎαžœαžΆαž˜αžΆαž“αžœαžαŸ’αžαž˜αžΆαž“αž“αŸ…αž€αŸ’αž“αž»αž„αž‚αž˜αŸ’αžšαŸ„αž„αŸ”

  4. RcppThread αžŸαž˜αŸ’αžšαžΆαž”αŸ‹αž€αžΆαžšαžšαŸ€αž”αž…αŸ†αžŠαŸ†αžŽαžΎαžšαž€αžΆαžšαž–αž αž»αžαŸ’αžŸαŸ‚αž“αŸƒαžœαŸ‰αž·αž…αž‘αŸαžšαž–αžΈ JSON αŸ” αž”αžΆαž“αž”αŸ’αžšαžΎαž―αž€αžŸαžΆαžšαž”αž‹αž˜αž€αžαžΆαžŠαŸ‚αž›αž•αŸ’αžαž›αŸ‹αžŠαŸ„αž™αž€αž‰αŸ’αž…αž”αŸ‹αž“αŸαŸ‡αŸ” αž–αžΈβ€‹αž€αžΆαžšβ€‹αž–αŸαž‰β€‹αž“αž·αž™αž˜β€‹αž€αžΆαž“αŸ‹β€‹αžαŸ‚β€‹αž…αŸ’αžšαžΎαž“β€‹ RcppParallel αž€αž‰αŸ’αž…αž”αŸ‹αž€αŸ’αž“αž»αž„αž…αŸ†αžŽαŸ„αž˜αžšαž”αžŸαŸ‹αž•αŸ’αžŸαŸαž„αž‘αŸ€αžαž˜αžΆαž“αž™αž“αŸ’αžαž€αžΆαžšαžšαŸ†αžαžΆαž“αžšαž„αŸ’αžœαž·αž›αž‡αž»αŸ†αžŠαŸ‚αž›αž—αŸ’αž‡αžΆαž”αŸ‹αž˜αž€αž‡αžΆαž˜αž½αž™αŸ”

αžœαžΆαž‚αž½αžšαž±αŸ’αž™αž€αžαŸ‹αžŸαž˜αŸ’αž‚αžΆαž›αŸ‹αžαžΆ xtensor αž”αŸ’αžšαŸ‚αž€αŸ’αž›αžΆαž™αžαžΆαž‡αžΆ godsendαŸ– αž”αž“αŸ’αžαŸ‚αž˜αž–αžΈαž›αžΎαž€αžΆαžšαž–αž·αžαžŠαŸ‚αž›αžαžΆαžœαžΆαž˜αžΆαž“αž˜αž»αžαž„αžΆαžšαž‘αžΌαž›αŸ†αž‘αžΌαž›αžΆαž™ αž“αž·αž„αžŠαŸ†αžŽαžΎαžšαž€αžΆαžšαžαŸ’αž–αžŸαŸ‹ αž’αŸ’αž“αž€αž’αž—αž·αžœαžŒαŸ’αžαž“αŸαžšαž”αžŸαŸ‹αžœαžΆαž”αžΆαž“αž†αŸ’αž›αžΎαž™αžαž”αž™αŸ‰αžΆαž„αžαŸ’αžšαžΉαž˜αžαŸ’αžšαžΌαžœ αž“αž·αž„αž†αŸ’αž›αžΎαž™αžŸαŸ†αžŽαž½αžšαž—αŸ’αž›αžΆαž˜αŸ— αž“αž·αž„αž›αž˜αŸ’αž’αž·αžαŸ” αžŠαŸ„αž™αž˜αžΆαž“αž‡αŸ†αž“αž½αž™αžšαž”αžŸαŸ‹αž–αž½αž€αž‚αŸ αžœαžΆαž’αžΆαž…αž’αž“αž»αžœαžαŸ’αžαž€αžΆαžšαž”αŸ†αž”αŸ’αž›αŸ‚αž„αž˜αŸ‰αžΆαž‘αŸ’αžšαžΈαžŸ OpenCV αž‘αŸ…αž‡αžΆ xtensor tensors αž€αŸαžŠαžΌαž…αž‡αžΆαžœαž·αž’αžΈαž˜αž½αž™αžŠαžΎαž˜αŸ’αž”αžΈαž”αž‰αŸ’αž…αžΌαž›αž‚αŸ’αž“αžΆαž“αžΌαžœαžšαžΌαž”αž—αžΆαž– 3-dimensional tensor αž‘αŸ…αž‡αžΆ tensor 4-dimensional αž“αŸƒαžœαž·αž˜αžΆαžαŸ’αžšαžαŸ’αžšαžΉαž˜αžαŸ’αžšαžΌαžœ (αž”αžΆαž…αŸ‹αžαŸ’αž›αž½αž“αžœαžΆαž•αŸ’αž‘αžΆαž›αŸ‹)αŸ”

αžŸαž˜αŸ’αž—αžΆαžšαŸˆαžŸαž˜αŸ’αžšαžΆαž”αŸ‹αžšαŸ€αž“ Rcpp, xtensor αž“αž·αž„ RcppThread

https://thecoatlessprofessor.com/programming/unofficial-rcpp-api-documentation

https://docs.opencv.org/4.0.1/d7/dbd/group__imgproc.html

https://xtensor.readthedocs.io/en/latest/

https://xtensor.readthedocs.io/en/latest/file_loading.html#loading-json-data-into-xtensor

https://cran.r-project.org/web/packages/RcppThread/vignettes/RcppThread-vignette.pdf

αžŠαžΎαž˜αŸ’αž”αžΈαž…αž„αž€αŸ’αžšαž„αž―αž€αžŸαžΆαžšαžŠαŸ‚αž›αž”αŸ’αžšαžΎαž―αž€αžŸαžΆαžšαž”αŸ’αžšαž–αŸαž“αŸ’αž’ αž“αž·αž„αž€αžΆαžšαž—αŸ’αž‡αžΆαž”αŸ‹αžαžΆαž˜αžœαž“αŸ’αžαž‡αžΆαž˜αž½αž™αž”αžŽαŸ’αžŽαžΆαž›αŸαž™αžŠαŸ‚αž›αž”αžΆαž“αžŠαŸ†αž‘αžΎαž„αž“αŸ…αž›αžΎαž”αŸ’αžšαž–αŸαž“αŸ’αž’ αž™αžΎαž„αž”αžΆαž“αž”αŸ’αžšαžΎαž™αž“αŸ’αžαž€αžΆαžšαž€αž˜αŸ’αž˜αžœαž·αž’αžΈαž‡αŸ†αž“αž½αž™αžŠαŸ‚αž›αž”αžΆαž“αž’αž“αž»αžœαžαŸ’αžαž“αŸ…αž€αŸ’αž“αž»αž„αž€αž‰αŸ’αž…αž”αŸ‹ Rcpp. αžŠαžΎαž˜αŸ’αž”αžΈαžŸαŸ’αžœαŸ‚αž„αžšαž€αž•αŸ’αž›αžΌαžœ αž“αž·αž„αž‘αž„αŸ‹αžŠαŸ„αž™αžŸαŸ’αžœαŸαž™αž”αŸ’αžšαžœαžαŸ’αžαž· αž™αžΎαž„αž”αžΆαž“αž”αŸ’αžšαžΎαž§αž”αž€αžšαžŽαŸαž”αŸ’αžšαžΎαž”αŸ’αžšαžΆαžŸαŸ‹αž›αžΈαž“αž»αž…αžŠαŸαž–αŸαž‰αž“αž·αž™αž˜ pkg- αž€αŸ†αžŽαžαŸ‹αžšαž…αž“αžΆαžŸαž˜αŸ’αž–αŸαž“αŸ’αž’.

αž€αžΆαžšαž’αž“αž»αžœαžαŸ’αžαž€αž˜αŸ’αž˜αžœαž·αž’αžΈαž‡αŸ†αž“αž½αž™ Rcpp αžŸαž˜αŸ’αžšαžΆαž”αŸ‹αž€αžΆαžšαž”αŸ’αžšαžΎαž”αŸ’αžšαžΆαžŸαŸ‹αž”αžŽαŸ’αžŽαžΆαž›αŸαž™ OpenCV

Rcpp::registerPlugin("opencv", function() {
  # Π’ΠΎΠ·ΠΌΠΎΠΆΠ½Ρ‹Π΅ названия ΠΏΠ°ΠΊΠ΅Ρ‚Π°
  pkg_config_name <- c("opencv", "opencv4")
  # Π‘ΠΈΠ½Π°Ρ€Π½Ρ‹ΠΉ Ρ„Π°ΠΉΠ» ΡƒΡ‚ΠΈΠ»ΠΈΡ‚Ρ‹ pkg-config
  pkg_config_bin <- Sys.which("pkg-config")
  # ΠŸΡ€ΠΎΠ²Ρ€Π΅ΠΊΠ° наличия ΡƒΡ‚ΠΈΠ»ΠΈΡ‚Ρ‹ Π² систСмС
  checkmate::assert_file_exists(pkg_config_bin, access = "x")
  # ΠŸΡ€ΠΎΠ²Π΅Ρ€ΠΊΠ° наличия Ρ„Π°ΠΉΠ»Π° настроСк OpenCV для pkg-config
  check <- sapply(pkg_config_name, 
                  function(pkg) system(paste(pkg_config_bin, pkg)))
  if (all(check != 0)) {
    stop("OpenCV config for the pkg-config not found", call. = FALSE)
  }

  pkg_config_name <- pkg_config_name[check == 0]
  list(env = list(
    PKG_CXXFLAGS = system(paste(pkg_config_bin, "--cflags", pkg_config_name), 
                          intern = TRUE),
    PKG_LIBS = system(paste(pkg_config_bin, "--libs", pkg_config_name), 
                      intern = TRUE)
  ))
})

αž‡αžΆαž›αž‘αŸ’αž’αž•αž›αž“αŸƒαž”αŸ’αžšαžαž·αž”αžαŸ’αžαž·αž€αžΆαžšαžšαž”αžŸαŸ‹αž€αž˜αŸ’αž˜αžœαž·αž’αžΈαž‡αŸ†αž“αž½αž™ αžαž˜αŸ’αž›αŸƒαžαžΆαž„αž€αŸ’αžšαŸ„αž˜αž“αžΉαž„αžαŸ’αžšαžΌαžœαž”αžΆαž“αž‡αŸ†αž“αž½αžŸαž€αŸ’αž“αž»αž„αž’αŸ†αž‘αž»αž„αž–αŸαž›αžŠαŸ†αžŽαžΎαžšαž€αžΆαžšαž…αž„αž€αŸ’αžšαž„αŸ–

Rcpp:::.plugins$opencv()$env

# $PKG_CXXFLAGS
# [1] "-I/usr/include/opencv"
#
# $PKG_LIBS
# [1] "-lopencv_shape -lopencv_stitching -lopencv_superres -lopencv_videostab -lopencv_aruco -lopencv_bgsegm -lopencv_bioinspired -lopencv_ccalib -lopencv_datasets -lopencv_dpm -lopencv_face -lopencv_freetype -lopencv_fuzzy -lopencv_hdf -lopencv_line_descriptor -lopencv_optflow -lopencv_video -lopencv_plot -lopencv_reg -lopencv_saliency -lopencv_stereo -lopencv_structured_light -lopencv_phase_unwrapping -lopencv_rgbd -lopencv_viz -lopencv_surface_matching -lopencv_text -lopencv_ximgproc -lopencv_calib3d -lopencv_features2d -lopencv_flann -lopencv_xobjdetect -lopencv_objdetect -lopencv_ml -lopencv_xphoto -lopencv_highgui -lopencv_videoio -lopencv_imgcodecs -lopencv_photo -lopencv_imgproc -lopencv_core"

αž›αŸαžαž€αžΌαžŠαž’αž“αž»αžœαžαŸ’αžαžŸαž˜αŸ’αžšαžΆαž”αŸ‹αž€αžΆαžšαž‰αŸ‚αž€ JSON αž“αž·αž„αž”αž„αŸ’αž€αžΎαžαž”αžŽαŸ’αžαž»αŸ†αžŸαž˜αŸ’αžšαžΆαž”αŸ‹αž€αžΆαžšαž”αž‰αŸ’αž‡αžΌαž“αž‘αŸ…αž€αžΆαž“αŸ‹αž˜αŸ‰αžΌαžŠαŸ‚αž›αžαŸ’αžšαžΌαžœαž”αžΆαž“αž•αŸ’αžαž›αŸ‹αž±αŸ’αž™αž“αŸ…αž€αŸ’αžšαŸ„αž˜ spoiler αŸ” αž‡αžΆαžŠαŸ†αž”αžΌαž„ αž”αž“αŸ’αžαŸ‚αž˜αžαžαž‚αž˜αŸ’αžšαŸ„αž„αž€αŸ’αž“αž»αž„αžαŸ†αž”αž“αŸ‹ αžŠαžΎαž˜αŸ’αž”αžΈαžŸαŸ’αžœαŸ‚αž„αžšαž€αž―αž€αžŸαžΆαžšαž”αž‹αž˜αž€αžαžΆ (αžαŸ’αžšαžΌαžœαž€αžΆαžšαžŸαž˜αŸ’αžšαžΆαž”αŸ‹ ndjson)αŸ–

Sys.setenv("PKG_CXXFLAGS" = paste0("-I", normalizePath(file.path("src"))))

αž€αžΆαžšαž’αž“αž»αžœαžαŸ’αž JSON αž‘αŸ…αž‡αžΆαž€αžΆαžšαž”αž˜αŸ’αž›αŸ‚αž„ tensor αž“αŸ…αž€αŸ’αž“αž»αž„ C++

// [[Rcpp::plugins(cpp14)]]
// [[Rcpp::plugins(opencv)]]
// [[Rcpp::depends(xtensor)]]
// [[Rcpp::depends(RcppThread)]]

#include <xtensor/xjson.hpp>
#include <xtensor/xadapt.hpp>
#include <xtensor/xview.hpp>
#include <xtensor-r/rtensor.hpp>
#include <opencv2/core/core.hpp>
#include <opencv2/highgui/highgui.hpp>
#include <opencv2/imgproc/imgproc.hpp>
#include <Rcpp.h>
#include <RcppThread.h>

// Π‘ΠΈΠ½ΠΎΠ½ΠΈΠΌΡ‹ для Ρ‚ΠΈΠΏΠΎΠ²
using RcppThread::parallelFor;
using json = nlohmann::json;
using points = xt::xtensor<double,2>;     // Π˜Π·Π²Π»Π΅Ρ‡Ρ‘Π½Π½Ρ‹Π΅ ΠΈΠ· JSON ΠΊΠΎΠΎΡ€Π΄ΠΈΠ½Π°Ρ‚Ρ‹ Ρ‚ΠΎΡ‡Π΅ΠΊ
using strokes = std::vector<points>;      // Π˜Π·Π²Π»Π΅Ρ‡Ρ‘Π½Π½Ρ‹Π΅ ΠΈΠ· JSON ΠΊΠΎΠΎΡ€Π΄ΠΈΠ½Π°Ρ‚Ρ‹ Ρ‚ΠΎΡ‡Π΅ΠΊ
using xtensor3d = xt::xtensor<double, 3>; // Π’Π΅Π½Π·ΠΎΡ€ для хранСния ΠΌΠ°Ρ‚Ρ€ΠΈΡ†Ρ‹ изообраТСния
using xtensor4d = xt::xtensor<double, 4>; // Π’Π΅Π½Π·ΠΎΡ€ для хранСния мноТСства ΠΈΠ·ΠΎΠ±Ρ€Π°ΠΆΠ΅Π½ΠΈΠΉ
using rtensor3d = xt::rtensor<double, 3>; // ΠžΠ±Ρ‘Ρ€Ρ‚ΠΊΠ° для экспорта Π² R
using rtensor4d = xt::rtensor<double, 4>; // ΠžΠ±Ρ‘Ρ€Ρ‚ΠΊΠ° для экспорта Π² R

// БтатичСскиС константы
// Π Π°Π·ΠΌΠ΅Ρ€ изобраТСния Π² пиксСлях
const static int SIZE = 256;
// Π’ΠΈΠΏ Π»ΠΈΠ½ΠΈΠΈ
// Π‘ΠΌ. https://en.wikipedia.org/wiki/Pixel_connectivity#2-dimensional
const static int LINE_TYPE = cv::LINE_4;
// Π’ΠΎΠ»Ρ‰ΠΈΠ½Π° Π»ΠΈΠ½ΠΈΠΈ Π² пиксСлях
const static int LINE_WIDTH = 3;
// Алгоритм рСсайза
// https://docs.opencv.org/3.1.0/da/d54/group__imgproc__transform.html#ga5bb5a1fea74ea38e1a5445ca803ff121
const static int RESIZE_TYPE = cv::INTER_LINEAR;

// Π¨Π°Π±Π»ΠΎΠ½ для конвСртирования OpenCV-ΠΌΠ°Ρ‚Ρ€ΠΈΡ†Ρ‹ Π² Ρ‚Π΅Π½Π·ΠΎΡ€
template <typename T, int NCH, typename XT=xt::xtensor<T,3,xt::layout_type::column_major>>
XT to_xt(const cv::Mat_<cv::Vec<T, NCH>>& src) {
  // Π Π°Π·ΠΌΠ΅Ρ€Π½ΠΎΡΡ‚ΡŒ Ρ†Π΅Π»Π΅Π²ΠΎΠ³ΠΎ Ρ‚Π΅Π½Π·ΠΎΡ€Π°
  std::vector<int> shape = {src.rows, src.cols, NCH};
  // ΠžΠ±Ρ‰Π΅Π΅ количСство элСмСнтов Π² массивС
  size_t size = src.total() * NCH;
  // ΠŸΡ€Π΅ΠΎΠ±Ρ€Π°Π·ΠΎΠ²Π°Π½ΠΈΠ΅ cv::Mat Π² xt::xtensor
  XT res = xt::adapt((T*) src.data, size, xt::no_ownership(), shape);
  return res;
}

// ΠŸΡ€Π΅ΠΎΠ±Ρ€Π°Π·ΠΎΠ²Π°Π½ΠΈΠ΅ JSON Π² список ΠΊΠΎΠΎΡ€Π΄ΠΈΠ½Π°Ρ‚ Ρ‚ΠΎΡ‡Π΅ΠΊ
strokes parse_json(const std::string& x) {
  auto j = json::parse(x);
  // Π Π΅Π·ΡƒΠ»ΡŒΡ‚Π°Ρ‚ парсинга Π΄ΠΎΠ»ΠΆΠ΅Π½ Π±Ρ‹Ρ‚ΡŒ массивом
  if (!j.is_array()) {
    throw std::runtime_error("'x' must be JSON array.");
  }
  strokes res;
  res.reserve(j.size());
  for (const auto& a: j) {
    // ΠšΠ°ΠΆΠ΄Ρ‹ΠΉ элСмСнт массива Π΄ΠΎΠ»ΠΆΠ΅Π½ Π±Ρ‹Ρ‚ΡŒ 2-ΠΌΠ΅Ρ€Π½Ρ‹ΠΌ массивом
    if (!a.is_array() || a.size() != 2) {
      throw std::runtime_error("'x' must include only 2d arrays.");
    }
    // Π˜Π·Π²Π»Π΅Ρ‡Π΅Π½ΠΈΠ΅ Π²Π΅ΠΊΡ‚ΠΎΡ€Π° Ρ‚ΠΎΡ‡Π΅ΠΊ
    auto p = a.get<points>();
    res.push_back(p);
  }
  return res;
}

// ΠžΡ‚Ρ€ΠΈΡΠΎΠ²ΠΊΠ° Π»ΠΈΠ½ΠΈΠΉ
// Π¦Π²Π΅Ρ‚Π° HSV
cv::Mat ocv_draw_lines(const strokes& x, bool color = true) {
  // Π˜ΡΡ…ΠΎΠ΄Π½Ρ‹ΠΉ Ρ‚ΠΈΠΏ ΠΌΠ°Ρ‚Ρ€ΠΈΡ†Ρ‹
  auto stype = color ? CV_8UC3 : CV_8UC1;
  // Π˜Ρ‚ΠΎΠ³ΠΎΠ²Ρ‹ΠΉ Ρ‚ΠΈΠΏ ΠΌΠ°Ρ‚Ρ€ΠΈΡ†Ρ‹
  auto dtype = color ? CV_32FC3 : CV_32FC1;
  auto bg = color ? cv::Scalar(0, 0, 255) : cv::Scalar(255);
  auto col = color ? cv::Scalar(0, 255, 220) : cv::Scalar(0);
  cv::Mat img = cv::Mat(SIZE, SIZE, stype, bg);
  // ΠšΠΎΠ»ΠΈΡ‡Π΅ΡΡ‚Π²ΠΎ Π»ΠΈΠ½ΠΈΠΉ
  size_t n = x.size();
  for (const auto& s: x) {
    // ΠšΠΎΠ»ΠΈΡ‡Π΅ΡΡ‚Π²ΠΎ Ρ‚ΠΎΡ‡Π΅ΠΊ Π² Π»ΠΈΠ½ΠΈΠΈ
    size_t n_points = s.shape()[1];
    for (size_t i = 0; i < n_points - 1; ++i) {
      // Π’ΠΎΡ‡ΠΊΠ° Π½Π°Ρ‡Π°Π»Π° ΡˆΡ‚Ρ€ΠΈΡ…Π°
      cv::Point from(s(0, i), s(1, i));
      // Π’ΠΎΡ‡ΠΊΠ° окончания ΡˆΡ‚Ρ€ΠΈΡ…Π°
      cv::Point to(s(0, i + 1), s(1, i + 1));
      // ΠžΡ‚Ρ€ΠΈΡΠΎΠ²ΠΊΠ° Π»ΠΈΠ½ΠΈΠΈ
      cv::line(img, from, to, col, LINE_WIDTH, LINE_TYPE);
    }
    if (color) {
      // МСняСм Ρ†Π²Π΅Ρ‚ Π»ΠΈΠ½ΠΈΠΈ
      col[0] += 180 / n;
    }
  }
  if (color) {
    // МСняСм Ρ†Π²Π΅Ρ‚ΠΎΠ²ΠΎΠ΅ прСдставлСниС Π½Π° RGB
    cv::cvtColor(img, img, cv::COLOR_HSV2RGB);
  }
  // МСняСм Ρ„ΠΎΡ€ΠΌΠ°Ρ‚ прСдставлСния Π½Π° float32 с Π΄ΠΈΠ°ΠΏΠ°Π·ΠΎΠ½ΠΎΠΌ [0, 1]
  img.convertTo(img, dtype, 1 / 255.0);
  return img;
}

// ΠžΠ±Ρ€Π°Π±ΠΎΡ‚ΠΊΠ° JSON ΠΈ ΠΏΠΎΠ»ΡƒΡ‡Π΅Π½ΠΈΠ΅ Ρ‚Π΅Π½Π·ΠΎΡ€Π° с Π΄Π°Π½Π½Ρ‹ΠΌΠΈ изобраТСния
xtensor3d process(const std::string& x, double scale = 1.0, bool color = true) {
  auto p = parse_json(x);
  auto img = ocv_draw_lines(p, color);
  if (scale != 1) {
    cv::Mat out;
    cv::resize(img, out, cv::Size(), scale, scale, RESIZE_TYPE);
    cv::swap(img, out);
    out.release();
  }
  xtensor3d arr = color ? to_xt<double,3>(img) : to_xt<double,1>(img);
  return arr;
}

// [[Rcpp::export]]
rtensor3d cpp_process_json_str(const std::string& x, 
                               double scale = 1.0, 
                               bool color = true) {
  xtensor3d res = process(x, scale, color);
  return res;
}

// [[Rcpp::export]]
rtensor4d cpp_process_json_vector(const std::vector<std::string>& x, 
                                  double scale = 1.0, 
                                  bool color = false) {
  size_t n = x.size();
  size_t dim = floor(SIZE * scale);
  size_t channels = color ? 3 : 1;
  xtensor4d res({n, dim, dim, channels});
  parallelFor(0, n, [&x, &res, scale, color](int i) {
    xtensor3d tmp = process(x[i], scale, color);
    auto view = xt::view(res, i, xt::all(), xt::all(), xt::all());
    view = tmp;
  });
  return res;
}

αž›αŸαžαž€αžΌαžŠαž“αŸαŸ‡αž‚αž½αžšαžαŸ‚αžαŸ’αžšαžΌαžœαž”αžΆαž“αžŠαžΆαž€αŸ‹αž€αŸ’αž“αž»αž„αž―αž€αžŸαžΆαžš src/cv_xt.cpp αž αžΎαž™αž…αž„αž€αŸ’αžšαž„αž‡αžΆαž˜αž½αž™αž–αžΆαž€αŸ’αž™αž”αž‰αŸ’αž‡αžΆ Rcpp::sourceCpp(file = "src/cv_xt.cpp", env = .GlobalEnv); αž‘αžΆαž˜αž‘αžΆαžšαžŸαž˜αŸ’αžšαžΆαž”αŸ‹αž€αžΆαžšαž„αžΆαžšαž•αž„αžŠαŸ‚αžšαŸ” nlohmann/json.hpp αž–αžΈ αžƒαŸ’αž›αžΆαŸ†αž„. αž€αžΌαžŠαžαŸ’αžšαžΌαžœαž”αžΆαž“αž”αŸ‚αž„αž…αŸ‚αž€αž‡αžΆαž˜αž»αžαž„αžΆαžšαž‡αžΆαž…αŸ’αžšαžΎαž“αŸ–

  • to_xt - αž˜αž»αžαž„αžΆαžšαž‚αŸ†αžšαžΌαžŸαž˜αŸ’αžšαžΆαž”αŸ‹αž”αŸ†αž”αŸ’αž›αŸ‚αž„αž˜αŸ‰αžΆαž‘αŸ’αžšαžΈαžŸαžšαžΌαž”αž—αžΆαž– (cv::Mat) αž‘αŸ… tensor αž˜αž½αž™αŸ” xt::xtensor;

  • parse_json - αž˜αž»αžαž„αžΆαžšαž‰αŸ‚αž€αžαŸ’αžŸαŸ‚αž’αž€αŸ’αžŸαžš JSON αžŸαŸ’αžšαž„αŸ‹αž€αžΌαž’αžšαžŠαŸ„αžŽαŸαž“αŸƒαž…αŸ†αž“αž»αž… αžŠαŸ„αž™αžαŸ’αž…αž”αŸ‹αžœαžΆαž‘αŸ…αž‡αžΆαžœαŸ‰αž·αž…αž‘αŸαžšαŸ”

  • ocv_draw_lines - αž–αžΈαžœαŸ‰αž·αž…αž‘αŸαžšαž›αž‘αŸ’αž’αž•αž›αž“αŸƒαž…αŸ†αžŽαž»αž… αž‚αžΌαžšαž”αž“αŸ’αž‘αžΆαžαŸ‹αž–αž αž»αž–αžŽαŸŒ;

  • process - αžšαž½αž˜αž”αž‰αŸ’αž…αžΌαž›αž‚αŸ’αž“αžΆαž“αžΌαžœαž˜αž»αžαž„αžΆαžšαžαžΆαž„αž›αžΎ αž αžΎαž™αžαŸ‚αž˜αž‘αžΆαŸ†αž„αž”αž“αŸ’αžαŸ‚αž˜αžŸαž˜αžαŸ’αžαž—αžΆαž–αž€αŸ’αž“αž»αž„αž€αžΆαžšαž’αŸ’αžœαžΎαž˜αžΆαžαŸ’αžšαžŠαŸ’αž‹αžΆαž“αžšαžΌαž”αž—αžΆαž–αž›αž‘αŸ’αž’αž•αž›αŸ”

  • cpp_process_json_str - αžšαž»αŸ†αž›αžΎαž˜αž»αžαž„αžΆαžš processαžŠαŸ‚αž›αž“αžΆαŸ†αž…αŸαž‰αž›αž‘αŸ’αž’αž•αž›αž‘αŸ…αž‡αžΆαžœαžαŸ’αžαž» R (αž’αžΆαžšαŸαž–αž αž»αžœαž·αž˜αžΆαžαŸ’αžš);

  • cpp_process_json_vector - αžšαž»αŸ†αž›αžΎαž˜αž»αžαž„αžΆαžš cpp_process_json_strαžŠαŸ‚αž›αž’αž“αž»αž‰αŸ’αž‰αžΆαžαž±αŸ’αž™αž’αŸ’αž“αž€αžŠαŸ†αžŽαžΎαžšαž€αžΆαžšαžœαŸ‰αž·αž…αž‘αŸαžšαžαŸ’αžŸαŸ‚αž’αž€αŸ’αžŸαžšαž€αŸ’αž“αž»αž„αžšαž”αŸ€αž”αž–αž αž»αžαŸ’αžŸαŸ‚αŸ”

αžŠαžΎαž˜αŸ’αž”αžΈαž‚αžΌαžšαž”αž“αŸ’αž‘αžΆαžαŸ‹αž–αž αž»αž–αžŽαŸŒ αž‚αŸ†αžšαžΌαž–αžŽαŸŒ HSV αžαŸ’αžšαžΌαžœαž”αžΆαž“αž”αŸ’αžšαžΎ αž”αž“αŸ’αž‘αžΆαž”αŸ‹αž˜αž€αžŠαŸ„αž™αž€αžΆαžšαž”αŸ†αž”αŸ’αž›αŸ‚αž„αž‘αŸ…αž‡αžΆ RGB αŸ” αžαŸ„αŸ‡αžŸαžΆαž€αž›αŸ’αž”αž„αž›αž‘αŸ’αž’αž•αž›αŸ–

arr <- cpp_process_json_str(tmp_data[4, drawing])
dim(arr)
# [1] 256 256   3
plot(magick::image_read(arr))

Quick Draw Doodle RecognitionαŸ– αžšαž”αŸ€αž”αž”αž„αŸ’αž€αžΎαžαž˜αž·αžαŸ’αžαž‡αžΆαž˜αž½αž™ R, C++ αž“αž·αž„αž”αžŽαŸ’αžαžΆαž‰αžŸαžšαžŸαŸƒαž”αŸ’αžšαžŸαžΆαž‘
αž€αžΆαžšαž”αŸ’αžšαŸ€αž”αž’αŸ€αž”αž›αŸ’αž”αžΏαž“αž“αŸƒαž€αžΆαžšαž’αž“αž»αžœαžαŸ’αžαž“αŸ…αž€αŸ’αž“αž»αž„ 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") 

Quick Draw Doodle RecognitionαŸ– αžšαž”αŸ€αž”αž”αž„αŸ’αž€αžΎαžαž˜αž·αžαŸ’αžαž‡αžΆαž˜αž½αž™ R, C++ αž“αž·αž„αž”αžŽαŸ’αžαžΆαž‰αžŸαžšαžŸαŸƒαž”αŸ’αžšαžŸαžΆαž‘

αžŠαžΌαž…αžŠαŸ‚αž›αž’αŸ’αž“αž€αž’αžΆαž…αžƒαžΎαž‰αž€αžΆαžšαž”αž„αŸ’αž€αžΎαž“αž›αŸ’αž”αžΏαž“αž”αžΆαž“αž”αŸ’αžšαŸ‚αž‘αŸ…αž‡αžΆαž˜αžΆαž“αžŸαžΆαžšαŸˆαžŸαŸ†αžαžΆαž“αŸ‹αžαŸ’αž›αžΆαŸ†αž„αžŽαžΆαžŸαŸ‹αž αžΎαž™αžœαžΆαž˜αž·αž“αž’αžΆαž…αž‘αŸ…αžšαž½αž…αž‘αŸαž€αŸ’αž“αž»αž„αž€αžΆαžšαž…αžΆαž”αŸ‹αž›αŸαžαž€αžΌαžŠ C ++ αžŠαŸ„αž™αž€αžΆαžšαž”αŸ’αžšαŸ€αž”αž’αŸ€αž”αž›αŸαžαž€αžΌαžŠ R αŸ”

3. Iterators αžŸαž˜αŸ’αžšαžΆαž”αŸ‹ unloading batches αž–αžΈ database

R αž˜αžΆαž“αž€αŸαžšαŸ’αžαž·αŸαžˆαŸ’αž˜αŸ„αŸ‡αž‚αž½αžšαžŸαž˜αžŸαž˜αŸ’αžšαžΆαž”αŸ‹αžŠαŸ†αžŽαžΎαžšαž€αžΆαžšαž‘αž·αž“αŸ’αž“αž“αŸαž™αžŠαŸ‚αž›αžŸαž˜αž“αžΉαž„ RAM αžαžŽαŸˆαž–αŸαž›αžŠαŸ‚αž› Python αžαŸ’αžšαžΌαžœαž”αžΆαž“αž€αŸ†αžŽαžαŸ‹αž›αž€αŸ’αžαžŽαŸˆαžŠαŸ„αž™αžŠαŸ†αžŽαžΎαžšαž€αžΆαžšαž‘αž·αž“αŸ’αž“αž“αŸαž™αžŠαžŠαŸ‚αž›αŸ— αžŠαŸ‚αž›αž’αž“αž»αž‰αŸ’αž‰αžΆαžαž±αŸ’αž™αž’αŸ’αž“αž€αž’αž“αž»αžœαžαŸ’αžαž€αžΆαžšαž‚αžŽαž“αžΆαž€αŸ’αžšαŸ…αžŸαŸ’αž“αžΌαž›αž”αžΆαž“αž™αŸ‰αžΆαž„αž„αžΆαž™αžŸαŸ’αžšαž½αž› αž“αž·αž„αžŠαŸ„αž™αž’αž˜αŸ’αž˜αž‡αžΆαžαž· (αž€αžΆαžšαž‚αžŽαž“αžΆαžŠαŸ„αž™αž”αŸ’αžšαžΎαž’αž„αŸ’αž‚αž…αž„αž…αžΆαŸ†αžαžΆαž„αž€αŸ’αžšαŸ…) αŸ” αž‚αŸ†αžšαžΌαž”αž»αžšαžΆαžŽ αž“αž·αž„αž–αžΆαž€αŸ‹αž–αŸαž“αŸ’αž’αžŸαž˜αŸ’αžšαžΆαž”αŸ‹αž™αžΎαž„αž“αŸ…αž€αŸ’αž“αž»αž„αž”αžšαž·αž”αž‘αž“αŸƒαž”αž‰αŸ’αž αžΆαžŠαŸ‚αž›αž”αžΆαž“αž–αž·αž–αžŽαŸŒαž“αžΆαž‚αžΊαž”αžŽαŸ’αžαžΆαž‰αžŸαžšαžŸαŸƒαž”αŸ’αžšαžŸαžΆαž‘αž‡αŸ’αžšαŸ…αžŠαŸ‚αž›αžαŸ’αžšαžΌαžœαž”αžΆαž“αž”αžŽαŸ’αžαž»αŸ‡αž”αžŽαŸ’αžαžΆαž›αžŠαŸ„αž™αžœαž·αž’αžΈαžŸαžΆαžŸαŸ’αžαŸ’αžšαž…αž»αŸ‡αž‡αž˜αŸ’αžšαžΆαž›αž‡αžΆαž˜αž½αž™αž“αžΉαž„αž€αžΆαžšαž”αŸ‰αžΆαž“αŸ‹αž”αŸ’αžšαž˜αžΆαžŽαž“αŸƒαž‡αž˜αŸ’αžšαžΆαž›αž“αŸ…αž‡αŸ†αž αžΆαž“αž“αžΈαž˜αž½αž™αŸ—αžŠαŸ„αž™αž”αŸ’αžšαžΎαž•αŸ’αž“αŸ‚αž€αžαžΌαž…αž˜αž½αž™αž“αŸƒαž€αžΆαžšαžŸαž„αŸ’αž€αŸαž αž¬αž”αžŽαŸ’αžαž»αŸ†αžαŸ’αž“αžΆαžαžαžΌαž…αŸ”

αž€αŸ’αžšαž”αžαžŽαŸ’αžŒαžŸαž·αž€αŸ’αžŸαžΆαž‡αŸ’αžšαŸ…αžŠαŸ‚αž›αžŸαžšαžŸαŸαžšαž€αŸ’αž“αž»αž„ Python αž˜αžΆαž“αžαŸ’αž“αžΆαž€αŸ‹αž–αž·αžŸαŸαžŸαžŠαŸ‚αž›αž’αž“αž»αžœαžαŸ’αž iterators αžŠαŸ„αž™αž•αŸ’αž’αŸ‚αž€αž›αžΎαž‘αž·αž“αŸ’αž“αž“αŸαž™αŸ– αžαžΆαžšαžΆαž„ αžšαžΌαž”αž—αžΆαž–αž€αŸ’αž“αž»αž„αžαžαž―αž€αžŸαžΆαžš αž‘αž˜αŸ’αžšαž„αŸ‹αž‚αŸ„αž›αž–αžΈαžšαŸ”αž›αŸ” αž’αŸ’αž“αž€αž’αžΆαž…αž”αŸ’αžšαžΎαž‡αž˜αŸ’αžšαžΎαžŸαžŠαŸ‚αž›αžαŸ’αžšαŸ€αž˜αžšαž½αž…αž‡αžΆαžŸαŸ’αžšαŸαž… αž¬αžŸαžšαžŸαŸαžšαžŠαŸ„αž™αžαŸ’αž›αž½αž“αž―αž„αžŸαž˜αŸ’αžšαžΆαž”αŸ‹αž€αž·αž…αŸ’αž…αž€αžΆαžšαž‡αžΆαž€αŸ‹αž›αžΆαž€αŸ‹αŸ” αž“αŸ…αž€αŸ’αž“αž»αž„ R αž™αžΎαž„αž’αžΆαž…αž‘αžΆαž‰αž™αž€αž’αžαŸ’αžαž”αŸ’αžšαž™αŸ„αž‡αž“αŸαž–αžΈαž›αž€αŸ’αžαžŽαŸˆαž–αž·αžŸαŸαžŸαž‘αžΆαŸ†αž„αž’αžŸαŸ‹αž“αŸƒαž”αžŽαŸ’αžŽαžΆαž›αŸαž™ Python keras αž‡αžΆαž˜αž½αž™αž“αžΉαž„αž•αŸ’αž“αŸ‚αž€αžαžΆαž„αž€αŸ’αžšαŸ„αž™αž•αŸ’αžŸαŸαž„αŸ—αžšαž”αžŸαŸ‹αžœαžΆ αžŠαŸ„αž™αž”αŸ’αžšαžΎαž€αž‰αŸ’αž…αž”αŸ‹αž“αŸƒαžˆαŸ’αž˜αŸ„αŸ‡αžŠαžΌαž…αž‚αŸ’αž“αžΆ αžŠαŸ‚αž›αžœαžΆαžŠαŸ†αžŽαžΎαžšαž€αžΆαžšαž“αŸ…αž›αžΎαž€αŸ†αž–αžΌαž›αž“αŸƒαž€αž‰αŸ’αž…αž”αŸ‹ αž’αŸ’αžœαžΎαž‘αžΎαž„αžœαž·αž‰. αž€αŸ’αžšαŸ„αž™αž˜αž€αž‘αŸ€αžαžŸαž˜αž“αžΉαž„αž‘αž‘αž½αž›αž”αžΆαž“αž’αžαŸ’αžαž”αž‘αžœαŸ‚αž„αžŠαžΆαž…αŸ‹αžŠαŸ„αž™αž‘αŸ‚αž€αž˜αž½αž™; αžœαžΆαž˜αž·αž“αžαŸ’αžšαžΉαž˜αžαŸ‚αž’αž“αž»αž‰αŸ’αž‰αžΆαžαž±αŸ’αž™αž’αŸ’αž“αž€αžŠαŸ†αžŽαžΎαžšαž€αžΆαžšαž€αžΌαžŠ Python αž–αžΈ R αž”αŸ‰αž»αžŽαŸ’αžŽαŸ„αŸ‡αž‘αŸαž”αŸ‰αž»αž“αŸ’αžαŸ‚αžαŸ‚αž˜αž‘αžΆαŸ†αž„αž’αž“αž»αž‰αŸ’αž‰αžΆαžαž±αŸ’αž™αž’αŸ’αž“αž€αž•αŸ’αž‘αŸαžšαžœαžαŸ’αžαž»αžšαžœαžΆαž„ R αž“αž·αž„ Python sessions αžŠαŸ„αž™αžŠαŸ†αžŽαžΎαžšαž€αžΆαžšαžŠαŸ„αž™αžŸαŸ’αžœαŸαž™αž”αŸ’αžšαžœαžαŸ’αžαž·αž“αžΌαžœαž€αžΆαžšαž”αŸ†αž›αŸ‚αž„αž”αŸ’αžšαž—αŸαž‘αž…αžΆαŸ†αž”αžΆαž…αŸ‹αž‘αžΆαŸ†αž„αž’αžŸαŸ‹αŸ”

αž™αžΎαž„αž”αžΆαž“αž€αž˜αŸ’αž…αžΆαžαŸ‹αžαž˜αŸ’αžšαžΌαžœαž€αžΆαžšαž€αŸ’αž“αž»αž„αž€αžΆαžšαžšαž€αŸ’αžŸαžΆαž‘αž»αž€αž‘αž·αž“αŸ’αž“αž“αŸαž™αž‘αžΆαŸ†αž„αž’αžŸαŸ‹αž“αŸ…αž€αŸ’αž“αž»αž„ RAM αžŠαŸ„αž™αž”αŸ’αžšαžΎ MonetDBLite αž€αžΆαžšαž„αžΆαžš "αž”αžŽαŸ’αžαžΆαž‰αžŸαžšαžŸαŸƒαž”αŸ’αžšαžŸαžΆαž‘" αž‘αžΆαŸ†αž„αž’αžŸαŸ‹αž“αžΉαž„αžαŸ’αžšαžΌαžœαž”αžΆαž“αž’αž“αž»αžœαžαŸ’αžαžŠαŸ„αž™αž€αžΌαžŠαžŠαžΎαž˜αž“αŸ…αž€αŸ’αž“αž»αž„ Python αž™αžΎαž„αž‚αŸ’αžšαžΆαž“αŸ‹αžαŸ‚αžαŸ’αžšαžΌαžœαžŸαžšαžŸαŸαžš iterator αž›αžΎαž‘αž·αž“αŸ’αž“αž“αŸαž™ αž–αŸ’αžšαŸ„αŸ‡αž˜αž·αž“αž˜αžΆαž“αž’αŸ’αžœαžΈαžšαž½αž…αžšαžΆαž›αŸ‹αŸ” αžŸαž˜αŸ’αžšαžΆαž”αŸ‹αžŸαŸ’αžαžΆαž“αž—αžΆαž–αž”αŸ‚αž”αž“αŸαŸ‡αž“αŸ…αž€αŸ’αž“αž»αž„ R ឬ Python αŸ” αžœαžΆαž˜αžΆαž“αžαž˜αŸ’αžšαžΌαžœαž€αžΆαžšαž–αžΈαžšαž™αŸ‰αžΆαž„αžŸαŸ†αžαžΆαž“αŸ‹αžŸαž˜αŸ’αžšαžΆαž”αŸ‹αžœαžΆαŸ– αžœαžΆαžαŸ’αžšαžΌαžœαžαŸ‚αžαŸ’αžšαž‘αž”αŸ‹αž‡αžΆαž”αžΆαž…αŸ‹αž“αŸ…αž€αŸ’αž“αž»αž„αžšαž„αŸ’αžœαž·αž›αž‡αž»αŸ†αž‚αŸ’αž˜αžΆαž“αž‘αžΈαž”αž‰αŸ’αž…αž”αŸ‹ αž αžΎαž™αžšαž€αŸ’αžŸαžΆαž‘αž»αž€αžŸαŸ’αžαžΆαž“αž—αžΆαž–αžšαž”αžŸαŸ‹αžœαžΆαžšαžœαžΆαž„αž€αžΆαžšαž’αŸ’αžœαžΎαž˜αŸ’αžαž„αž‘αŸ€αž (αž€αŸ’αžšαŸ„αž™αž˜αž€αž‘αŸ€αžαž“αŸ…αž€αŸ’αž“αž»αž„ R αžαŸ’αžšαžΌαžœαž”αžΆαž“αž’αž“αž»αžœαžαŸ’αžαžαžΆαž˜αžœαž·αž’αžΈαžŸαžΆαž˜αž‰αŸ’αž‰αž”αŸ†αž•αž»αžαžŠαŸ„αž™αž”αŸ’αžšαžΎαž€αžΆαžšαž”αž·αž‘)αŸ” αž–αžΈαž˜αž»αž“ αžœαžΆαžαŸ’αžšαžΌαžœαž”αžΆαž“αžαž˜αŸ’αžšαžΌαžœαž±αŸ’αž™αž”αŸ†αž”αŸ’αž›αŸ‚αž„αž’αžΆαžšαŸ R αž™αŸ‰αžΆαž„αž…αŸ’αž”αžΆαžŸαŸ‹αž‘αŸ…αž‡αžΆαž’αžΆαžšαŸ numpy αž“αŸ…αžαžΆαž„αž€αŸ’αž“αž»αž„ iterator αž”αŸ‰αž»αž“αŸ’αžαŸ‚αž€αŸ†αžŽαŸ‚αž”αž…αŸ’αž…αž»αž”αŸ’αž”αž“αŸ’αž“αž“αŸƒαž€αž‰αŸ’αž…αž”αŸ‹ keras αž’αŸ’αžœαžΎαžœαžΆαžŠαŸ„αž™αžαŸ’αž›αž½αž“αž―αž„αŸ”

αž’αŸ’αž“αž€αžαŸ’αžšαž½αžŸαžαŸ’αžšαžΆαž™αž•αŸ’αž›αžΌαžœαžŸαž˜αŸ’αžšαžΆαž”αŸ‹αž€αžΆαžšαž”αžŽαŸ’αžαž»αŸ‡αž”αžŽαŸ’αžαžΆαž› αž“αž·αž„αž‘αž·αž“αŸ’αž“αž“αŸαž™αžŸαž»αž–αž›αž—αžΆαž–αž”αžΆαž“αž”αŸ’αžšαŸ‚αž€αŸ’αž›αžΆαž™αžŠαžΌαž…αžαžΆαž„αž€αŸ’αžšαŸ„αž˜αŸ–

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 αž—αžΈαž€αžŸαŸ‚αž›β€‹, scale = 0.5 - 128x128 αž—αžΈαž€αžŸαŸ‚αž›) αžŸαžΌαž…αž“αžΆαž€αžšαž–αžŽαŸŒ (color = FALSE αž”αž‰αŸ’αž‡αžΆαž€αŸ‹αž€αžΆαžšαž”αž„αŸ’αž αžΆαž‰αž‡αžΆαž˜αžΆαžαŸ’αžšαžŠαŸ’αž‹αžΆαž“αž”αŸ’αžšαž•αŸαŸ‡αž“αŸ…αž–αŸαž›αž”αŸ’αžšαžΎ color = TRUE αž€αžΆαžšαžŠαžΆαž…αŸ‹αžŸαžšαžŸαŸƒαžˆαžΆαž˜αžαž½αžšαž€αŸ’αž”αžΆαž›αž“αžΈαž˜αž½αž™αŸ—αžαŸ’αžšαžΌαžœαž”αžΆαž“αž‚αžΌαžšαž‡αžΆαž–αžŽαŸŒαžαŸ’αž˜αžΈ) αž“αž·αž„αžŸαžΌαž…αž“αžΆαž€αžšαžŠαŸ†αžŽαžΎαžšαž€αžΆαžšαž˜αž»αž“αžŸαž˜αŸ’αžšαžΆαž”αŸ‹αž”αžŽαŸ’αžαžΆαž‰αžŠαŸ‚αž›αžαŸ’αžšαžΌαžœαž”αžΆαž“αž”αžŽαŸ’αžαž»αŸ‡αž”αžŽαŸ’αžαžΆαž›αž‡αžΆαž˜αž»αž“αž“αŸ…αž›αžΎ imagenet αŸ” αž€αŸ’αžšαŸ„αž™αž˜αž€αž‘αŸ€αžαž‚αžΊαžαŸ’αžšαžΌαžœαž€αžΆαžšαž‡αžΆαž…αžΆαŸ†αž”αžΆαž…αŸ‹αžŠαžΎαž˜αŸ’αž”αžΈαž’αŸ’αžœαžΎαž˜αžΆαžαŸ’αžšαžŠαŸ’αž‹αžΆαž“αžαž˜αŸ’αž›αŸƒαž—αžΈαž€αžŸαŸ‚αž›αž–αžΈαž…αž“αŸ’αž›αŸ„αŸ‡ [0, 1] αž‘αŸ…αž…αž“αŸ’αž›αŸ„αŸ‡ [-1, 1] αžŠαŸ‚αž›αžαŸ’αžšαžΌαžœαž”αžΆαž“αž”αŸ’αžšαžΎαž“αŸ…αž–αŸαž›αž”αžŽαŸ’αžαž»αŸ‡αž”αžŽαŸ’αžαžΆαž›αž§αž”αž€αžšαžŽαŸαžŠαŸ‚αž›αž”αžΆαž“αž•αŸ’αž‚αžαŸ‹αž•αŸ’αž‚αž„αŸ‹αŸ” keras αž˜αŸ‰αžΌαžŠαŸ‚αž›

αž˜αž»αžαž„αžΆαžšαžαžΆαž„αž€αŸ’αžšαŸ…αž˜αžΆαž“αž€αžΆαžšαžαŸ’αžšαž½αžαž–αž·αž“αž·αžαŸ’αž™αž”αŸ’αžšαž—αŸαž‘αž’αžΆαž‚αž»αž™αž˜αŸ‰αž„αŸ‹ αžαžΆαžšαžΆαž„αž˜αž½αž™αŸ” data.table αž‡αžΆαž˜αž½αž™β€‹αž“αžΉαž„β€‹αž›αŸαžβ€‹αž”αž“αŸ’αž‘αžΆαžαŸ‹β€‹αž…αž˜αŸ’αžšαž»αŸ‡β€‹αžŠαŸ„αž™β€‹αž…αŸƒαžŠαž“αŸ’αž™β€‹αž–αžΈ samples_index αž“αž·αž„αž›αŸαžαž”αžΆαž…αŸ‹ αžšαžΆαž”αŸ‹ αž“αž·αž„αž…αŸ†αž“αž½αž“αž’αžαž·αž”αžšαž˜αžΆαž“αŸƒαž”αžΆαž…αŸ‹ αž€αŸαžŠαžΌαž…αž‡αžΆαž€αž“αŸ’αžŸαŸ„αž˜ SQL αžŸαž˜αŸ’αžšαžΆαž”αŸ‹αž•αŸ’αž‘αž»αž€αž‘αž·αž“αŸ’αž“αž“αŸαž™αž…αŸαž‰αž–αžΈαž˜αžΌαž›αžŠαŸ’αž‹αžΆαž“αž‘αž·αž“αŸ’αž“αž“αŸαž™αŸ” αž›αžΎαžŸαž–αžΈαž“αŸαŸ‡αž‘αŸ€αžαž™αžΎαž„αž”αžΆαž“αž€αŸ†αžŽαžαŸ‹ analogue αž›αžΏαž“αž“αŸƒαž˜αž»αžαž„αžΆαžšαž“αŸ…αžαžΆαž„αž€αŸ’αž“αž»αž„ keras::to_categorical(). αž™αžΎαž„αž”αžΆαž“αž”αŸ’αžšαžΎαž”αŸ’αžšαžΆαžŸαŸ‹αž‘αž·αž“αŸ’αž“αž“αŸαž™αžŸαŸ’αž‘αžΎαžšαžαŸ‚αž‘αžΆαŸ†αž„αž’αžŸαŸ‹αžŸαž˜αŸ’αžšαžΆαž”αŸ‹αž€αžΆαžšαž”αžŽαŸ’αžαž»αŸ‡αž”αžŽαŸ’αžαžΆαž› αžŠαŸ„αž™αž”αž“αŸ’αžŸαž›αŸ‹αž‘αž»αž€αž–αžΆαž€αŸ‹αž€αžŽαŸ’αžαžΆαž›αž—αžΆαž‚αžšαž™αžŸαž˜αŸ’αžšαžΆαž”αŸ‹αžŸαž»αž–αž›αž—αžΆαž– αžŠαžΌαž…αŸ’αž“αŸαŸ‡αž‘αŸ†αž αŸ†αžŸαž˜αŸαž™αžαŸ’αžšαžΌαžœαž”αžΆαž“αž€αŸ†αžŽαžαŸ‹αžŠαŸ„αž™αž”αŸ‰αžΆαžšαŸ‰αžΆαž˜αŸ‰αŸ‚αžαŸ’αžš steps_per_epoch αž“αŸ…αž–αŸαž›αž αŸ… keras::fit_generator()αž“αž·αž„αž›αž€αŸ’αžαžαžŽαŸ’αžŒ if (i > max_i) αž’αŸ’αžœαžΎαž€αžΆαžšαžŸαž˜αŸ’αžšαžΆαž”αŸ‹αžαŸ‚αž€αž˜αŸ’αž˜αžœαž·αž’αžΈαž”αž‰αŸ’αž‡αžΆαž€αŸ‹αžŸαž»αž–αž›αž—αžΆαž–αž”αŸ‰αž»αžŽαŸ’αžŽαŸ„αŸ‡αŸ”

αž“αŸ…αž€αŸ’αž“αž»αž„αž˜αž»αžαž„αžΆαžšαžαžΆαž„αž€αŸ’αž“αž»αž„ αž›αž·αž”αž·αž€αŸ’αžšαž˜αž‡αž½αžšαžαŸ’αžšαžΌαžœαž”αžΆαž“αž‘αžΆαž‰αž™αž€αž˜αž€αžœαž·αž‰αžŸαž˜αŸ’αžšαžΆαž”αŸ‹αž”αžΆαž…αŸ‹αž”αž“αŸ’αž‘αžΆαž”αŸ‹ αž€αŸ†αžŽαžαŸ‹αžαŸ’αžšαžΆαžαŸ’αžšαžΌαžœαž”αžΆαž“αžŠαž€αž…αŸαž‰αž–αžΈαž˜αžΌαž›αžŠαŸ’αž‹αžΆαž“αž‘αž·αž“αŸ’αž“αž“αŸαž™ αž‡αžΆαž˜αž½αž™αž“αžΉαž„αž€αžΆαžšαžšαžΆαž”αŸ‹αž”αžΆαž…αŸ‹αž€αžΎαž“αž‘αžΎαž„ αž€αžΆαžšαž‰αŸ‚αž€ JSON (αž˜αž»αžαž„αžΆαžš cpp_process_json_vector()αžŸαžšαžŸαŸαžšαž€αŸ’αž“αž»αž„ C++) αž“αž·αž„αž”αž„αŸ’αž€αžΎαžαž’αžΆαžšαŸαžŠαŸ‚αž›αžαŸ’αžšαžΌαžœαž‚αŸ’αž“αžΆαž“αžΉαž„αžšαžΌαž”αž—αžΆαž–αŸ” αž”αž“αŸ’αž‘αžΆαž”αŸ‹αž˜αž€ αžœαŸ‰αž·αž…αž‘αŸαžšαž€αŸ’αžαŸ…αž˜αž½αž™αž‡αžΆαž˜αž½αž™αžŸαŸ’αž›αžΆαž€αžαŸ’αž“αžΆαž€αŸ‹αžαŸ’αžšαžΌαžœαž”αžΆαž“αž”αž„αŸ’αž€αžΎαž αž’αžΆαžšαŸαžŠαŸ‚αž›αž˜αžΆαž“αžαž˜αŸ’αž›αŸƒαž—αžΈαž€αžŸαŸ‚αž› αž“αž·αž„αžŸαŸ’αž›αžΆαž€αžαŸ’αžšαžΌαžœαž”αžΆαž“αž”αž‰αŸ’αž…αžΌαž›αž‚αŸ’αž“αžΆαž‘αŸ…αž€αŸ’αž“αž»αž„αž”αž‰αŸ’αž‡αžΈ αžŠαŸ‚αž›αž‡αžΆαžαž˜αŸ’αž›αŸƒαžαŸ’αžšαž‘αž”αŸ‹αŸ” αžŠαžΎαž˜αŸ’αž”αžΈαž”αž„αŸ’αž€αžΎαž“αž›αŸ’αž”αžΏαž“αž€αžΆαžšαž„αžΆαžš αž™αžΎαž„αž”αžΆαž“αž”αŸ’αžšαžΎαž€αžΆαžšαž”αž„αŸ’αž€αžΎαžαž›αž·αž”αž·αž€αŸ’αžšαž˜αž€αŸ’αž“αž»αž„αžαžΆαžšαžΆαž„ data.table αž“αž·αž„αž€αžΆαžšαž€αŸ‚αž”αŸ’αžšαŸ‚αžαžΆαž˜αžšαž™αŸˆαžαŸ†αžŽ - αžŠαŸ„αž™αž‚αŸ’αž˜αžΆαž“αž€αž‰αŸ’αž…αž”αŸ‹ "αž”αž“αŸ’αž‘αŸ‡αžŸαŸ€αž‚αŸ’αžœαžΈ" αž‘αžΆαŸ†αž„αž“αŸαŸ‡ αžαžΆαžšαžΆαž„αž‘αž·αž“αŸ’αž“αž“αŸαž™ αžœαžΆαž–αž·αž”αžΆαž€αžŽαžΆαžŸαŸ‹αž€αŸ’αž“αž»αž„αž€αžΆαžšαžŸαŸ’αžšαž˜αŸƒαžαžΆαž’αŸ’αžœαžΎαž€αžΆαžšαž”αŸ’αžšαž€αž”αžŠαŸ„αž™αž”αŸ’αžšαžŸαž·αž‘αŸ’αž’αž—αžΆαž–αž‡αžΆαž˜αž½αž™αž“αžΉαž„αž…αŸ†αž“αž½αž“αž‘αž·αž“αŸ’αž“αž“αŸαž™αžŸαŸ†αžαžΆαž“αŸ‹αŸ—αžŽαžΆαž˜αž½αž™αž“αŸ…αž€αŸ’αž“αž»αž„ 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)

Quick Draw Doodle RecognitionαŸ– αžšαž”αŸ€αž”αž”αž„αŸ’αž€αžΎαžαž˜αž·αžαŸ’αžαž‡αžΆαž˜αž½αž™ R, C++ αž“αž·αž„αž”αžŽαŸ’αžαžΆαž‰αžŸαžšαžŸαŸƒαž”αŸ’αžšαžŸαžΆαž‘

αž”αŸ’αžšαžŸαž·αž“αž”αžΎαž’αŸ’αž“αž€αž˜αžΆαž“ RAM αž‚αŸ’αžšαž”αŸ‹αž‚αŸ’αžšαžΆαž“αŸ‹ αž’αŸ’αž“αž€αž’αžΆαž…αž”αž„αŸ’αž€αžΎαž“αž›αŸ’αž”αžΏαž“αž”αŸ’αžšαžαž·αž”αžαŸ’αžαž·αž€αžΆαžšαžšαž”αžŸαŸ‹αž˜αžΌαž›αžŠαŸ’αž‹αžΆαž“αž‘αž·αž“αŸ’αž“αž“αŸαž™αžŠαŸ„αž™αž•αŸ’αž‘αŸαžšαžœαžΆαž‘αŸ… RAM αžŠαžΌαž…αž‚αŸ’αž“αžΆαž“αŸαŸ‡ (32 GB αž‚αžΊαž‚αŸ’αžšαž”αŸ‹αž‚αŸ’αžšαžΆαž“αŸ‹αžŸαž˜αŸ’αžšαžΆαž”αŸ‹αž€αž·αž…αŸ’αž…αž€αžΆαžšαžšαž”αžŸαŸ‹αž™αžΎαž„)αŸ” αž“αŸ…αž€αŸ’αž“αž»αž„αž›αžΈαž“αž»αž… αž—αžΆαž‚αžαžΆαžŸαžαŸ’αžšαžΌαžœαž”αžΆαž“αž˜αŸ‰αŸ„αž“αžαžΆαž˜αž›αŸ†αž“αžΆαŸ†αžŠαžΎαž˜ /dev/shmαž€αžΆαž“αŸ‹αž€αžΆαž”αŸ‹αžšαž αžΌαžαžŠαž›αŸ‹αž–αžΆαž€αŸ‹αž€αžŽαŸ’αžαžΆαž›αž“αŸƒαžŸαž˜αžαŸ’αžαž—αžΆαž– RAM αŸ” αž’αŸ’αž“αž€αž’αžΆαž…αž”αž“αŸ’αž›αž·αž…αž”αž“αŸ’αžαŸ‚αž˜αž‘αŸ€αžαžŠαŸ„αž™αž€αžΆαžšαž€αŸ‚αžŸαž˜αŸ’αžšαž½αž› /etc/fstabαžŠαžΎαž˜αŸ’αž”αžΈαž‘αž‘αž½αž›αž”αžΆαž“αž€αŸ†αžŽαžαŸ‹αžαŸ’αžšαžΆαžŠαžΌαž… tmpfs /dev/shm tmpfs defaults,size=25g 0 0. αžαŸ’αžšαžΌαžœαž”αŸ’αžšαžΆαž€αžŠαžαžΆαž…αžΆαž”αŸ‹αž•αŸ’αžαžΎαž˜αž‘αžΎαž„αžœαž·αž‰αž αžΎαž™αž–αž·αž“αž·αžαŸ’αž™αž˜αžΎαž›αž›αž‘αŸ’αž’αž•αž›αžŠαŸ„αž™αžŠαŸ†αžŽαžΎαžšαž€αžΆαžšαž–αžΆαž€αŸ’αž™αž”αž‰αŸ’αž‡αžΆ 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. αž€αžΆαžšαž‡αŸ’αžšαžΎαžŸαžšαžΎαžŸαžŸαŸ’αžαžΆαž”αžαŸ’αž™αž€αž˜αŸ’αž˜αž‚αŸ†αžšαžΌ

αžŸαŸ’αžαžΆαž”αžαŸ’αž™αž€αž˜αŸ’αž˜αžŠαŸ†αž”αžΌαž„αžŠαŸ‚αž›αž”αŸ’αžšαžΎαž‚αžΊ mobilenet v1, αž›αž€αŸ’αžαžŽαŸˆαž–αž·αžŸαŸαžŸαžŠαŸ‚αž›αžαŸ’αžšαžΌαžœαž”αžΆαž“αž–αž·αž—αžΆαž€αŸ’αžŸαžΆαž“αŸ…αž€αŸ’αž“αž»αž„ αž“αŸαŸ‡ αžŸαžΆαžšαŸ” αžœαžΆαžαŸ’αžšαžΌαžœαž”αžΆαž“αžšαž½αž˜αž”αž‰αŸ’αž…αžΌαž›αž‡αžΆαžŸαŸ’αžαž„αŸ‹αžŠαžΆαžš keras αž αžΎαž™αžαžΆαž˜αž“αŸ„αŸ‡ αž˜αžΆαž“αž“αŸ…αž€αŸ’αž“αž»αž„αž€αž‰αŸ’αž…αž”αŸ‹αž“αŸƒαžˆαŸ’αž˜αŸ„αŸ‡αžŠαžΌαž…αž‚αŸ’αž“αžΆαžŸαž˜αŸ’αžšαžΆαž”αŸ‹ R. αž”αŸ‰αž»αž“αŸ’αžαŸ‚αž“αŸ…αž–αŸαž›αž–αŸ’αž™αžΆαž™αžΆαž˜αž”αŸ’αžšαžΎαžœαžΆαž‡αžΆαž˜αž½αž™αžšαžΌαž”αž—αžΆαž–αž†αžΆαž“αŸ‚αž›αžαŸ‚αž˜αž½αž™ αžšαžΏαž„αž…αž˜αŸ’αž›αŸ‚αž€αž˜αž½αž™αž”αžΆαž“αž”αŸ’αžšαŸ‚αž€αŸ’αž›αžΆαž™αŸ– αžαž„αŸ‹αžŸαŸŠαžΈαžαŸαž”αž‰αŸ’αž…αžΌαž›αžαŸ’αžšαžΌαžœαžαŸ‚αž˜αžΆαž“αžœαž·αž˜αžΆαžαŸ’αžšαž‡αžΆαž“αž·αž…αŸ’αž…αŸ” (batch, height, width, 3)αž“αŸ„αŸ‡αž‚αžΊαž…αŸ†αž“αž½αž“αž”αŸ‰αž»αžŸαŸ’αžαž·αŸαž˜αž·αž“αž’αžΆαž…αž•αŸ’αž›αžΆαžŸαŸ‹αž”αŸ’αžαžΌαžšαž”αžΆαž“αž‘αŸαŸ” αž˜αž·αž“αž˜αžΆαž“αž€αžΆαžšαž€αŸ†αžŽαžαŸ‹αž”αŸ‚αž”αž“αŸαŸ‡αž“αŸ…αž€αŸ’αž“αž»αž„ Python αž‘αŸ αžŠαžΌαž…αŸ’αž“αŸαŸ‡αž αžΎαž™αž™αžΎαž„αž”αžΆαž“αž”αŸ’αžšαž‰αžΆαž”αŸ‹αž”αŸ’αžšαž‰αžΆαž›αŸ‹ αž“αž·αž„αžŸαžšαžŸαŸαžšαž€αžΆαžšαž’αž“αž»αžœαžαŸ’αžαž•αŸ’αž‘αžΆαž›αŸ‹αžαŸ’αž›αž½αž“αžšαž”αžŸαŸ‹αž™αžΎαž„αž“αŸƒαžŸαŸ’αžαžΆαž”αžαŸ’αž™αž€αž˜αŸ’αž˜αž“αŸαŸ‡ αžŠαŸ„αž™αž’αŸ’αžœαžΎαžαžΆαž˜αž’αžαŸ’αžαž”αž‘αžŠαžΎαž˜ (αžŠαŸ„αž™αž‚αŸ’αž˜αžΆαž“αž€αžΆαžšαž”αŸ„αŸ‡αž”αž„αŸ‹αž…αŸ„αž›αžŠαŸ‚αž›αž˜αžΆαž“αž“αŸ…αž€αŸ’αž“αž»αž„αž€αŸ†αžŽαŸ‚ keras):

αžŸαŸ’αžαžΆαž”αžαŸ’αž™αž€αž˜αŸ’αž˜ Mobilenet v1

library(keras)

top_3_categorical_accuracy <- custom_metric(
    name = "top_3_categorical_accuracy",
    metric_fn = function(y_true, y_pred) {
         metric_top_k_categorical_accuracy(y_true, y_pred, k = 3)
    }
)

layer_sep_conv_bn <- function(object, 
                              filters,
                              alpha = 1,
                              depth_multiplier = 1,
                              strides = c(2, 2)) {

  # NB! depth_multiplier !=  resolution multiplier
  # https://github.com/keras-team/keras/issues/10349

  layer_depthwise_conv_2d(
    object = object,
    kernel_size = c(3, 3), 
    strides = strides,
    padding = "same",
    depth_multiplier = depth_multiplier
  ) %>%
  layer_batch_normalization() %>% 
  layer_activation_relu() %>%
  layer_conv_2d(
    filters = filters * alpha,
    kernel_size = c(1, 1), 
    strides = c(1, 1)
  ) %>%
  layer_batch_normalization() %>% 
  layer_activation_relu() 
}

get_mobilenet_v1 <- function(input_shape = c(224, 224, 1),
                             num_classes = 340,
                             alpha = 1,
                             depth_multiplier = 1,
                             optimizer = optimizer_adam(lr = 0.002),
                             loss = "categorical_crossentropy",
                             metrics = c("categorical_crossentropy",
                                         top_3_categorical_accuracy)) {

  inputs <- layer_input(shape = input_shape)

  outputs <- inputs %>%
    layer_conv_2d(filters = 32, kernel_size = c(3, 3), strides = c(2, 2), padding = "same") %>%
    layer_batch_normalization() %>% 
    layer_activation_relu() %>%
    layer_sep_conv_bn(filters = 64, strides = c(1, 1)) %>%
    layer_sep_conv_bn(filters = 128, strides = c(2, 2)) %>%
    layer_sep_conv_bn(filters = 128, strides = c(1, 1)) %>%
    layer_sep_conv_bn(filters = 256, strides = c(2, 2)) %>%
    layer_sep_conv_bn(filters = 256, strides = c(1, 1)) %>%
    layer_sep_conv_bn(filters = 512, strides = c(2, 2)) %>%
    layer_sep_conv_bn(filters = 512, strides = c(1, 1)) %>%
    layer_sep_conv_bn(filters = 512, strides = c(1, 1)) %>%
    layer_sep_conv_bn(filters = 512, strides = c(1, 1)) %>%
    layer_sep_conv_bn(filters = 512, strides = c(1, 1)) %>%
    layer_sep_conv_bn(filters = 512, strides = c(1, 1)) %>%
    layer_sep_conv_bn(filters = 1024, strides = c(2, 2)) %>%
    layer_sep_conv_bn(filters = 1024, strides = c(1, 1)) %>%
    layer_global_average_pooling_2d() %>%
    layer_dense(units = num_classes) %>%
    layer_activation_softmax()

    model <- keras_model(
      inputs = inputs,
      outputs = outputs
    )

    model %>% compile(
      optimizer = optimizer,
      loss = loss,
      metrics = metrics
    )

    return(model)
}

αž‚αž»αžŽαžœαž·αž”αžαŸ’αžαž·αž“αŸƒαžœαž·αž’αžΈαžŸαžΆαžŸαŸ’αžšαŸ’αžαž“αŸαŸ‡αž‚αžΊαž‡αžΆαž€αŸ‹αžŸαŸ’αžαŸ‚αž„αŸ” αžαŸ’αž‰αž»αŸ†αž…αž„αŸ‹αžŸαžΆαž€αž›αŸ’αž”αž„αž˜αŸ‰αžΌαžŠαŸ‚αž›αž‡αžΆαž…αŸ’αžšαžΎαž“ αž”αŸ‰αž»αž“αŸ’αžαŸ‚αž•αŸ’αž‘αž»αž™αž‘αŸ…αžœαž·αž‰ αžαŸ’αž‰αž»αŸ†αž˜αž·αž“αž…αž„αŸ‹αžŸαžšαžŸαŸαžšαž‘αžΎαž„αžœαž·αž‰αž“αžΌαžœαžŸαŸ’αžαžΆαž”αžαŸ’αž™αž€αž˜αŸ’αž˜αž“αžΈαž˜αž½αž™αŸ—αžŠαŸ„αž™αžŠαŸƒαž‘αŸαŸ” αž™αžΎαž„β€‹αž€αŸβ€‹αžαŸ’αžšαžΌαžœβ€‹αž”αžΆαž“β€‹αž‚αŸβ€‹αžŠαž€β€‹αž αžΌαžβ€‹αž±αž€αžΆαžŸβ€‹αž€αŸ’αž“αž»αž„β€‹αž€αžΆαžšβ€‹αž”αŸ’αžšαžΎβ€‹αž‘αž˜αŸ’αž„αž“αŸ‹β€‹αž“αŸƒβ€‹αž˜αŸ‰αžΌαžŠαŸ‚αž›β€‹αžŠαŸ‚αž›β€‹αž”αžΆαž“β€‹αž αŸ’αžœαžΉαž€αž αžΆαžαŸ‹β€‹αž˜αž»αž“β€‹αž“αŸ…β€‹αž›αžΎ imagenetαŸ” αžŠαžΌαž…αž’αž˜αŸ’αž˜αžαžΆ αž€αžΆαžšαžŸαž·αž€αŸ’αžŸαžΆαž―αž€αžŸαžΆαžšαž”αžΆαž“αž‡αž½αž™αŸ” αž˜αž»αžαž„αžΆαžš get_config() αž’αž“αž»αž‰αŸ’αž‰αžΆαžβ€‹αž±αŸ’αž™β€‹αž’αŸ’αž“αž€β€‹αž‘αž‘αž½αž›β€‹αž”αžΆαž“β€‹αž€αžΆαžšβ€‹αž–αž·αž–αžŽαŸŒαž“αžΆβ€‹αž’αŸ†αž–αžΈβ€‹αž‚αŸ†αžšαžΌβ€‹αž€αŸ’αž“αž»αž„β€‹αž‘αž˜αŸ’αžšαž„αŸ‹β€‹αžŠαŸ‚αž›β€‹αžŸαž˜αžšαž˜αŸ’αž™β€‹αžŸαž˜αŸ’αžšαžΆαž”αŸ‹β€‹αž€αžΆαžšβ€‹αž€αŸ‚αžŸαž˜αŸ’αžšαž½αž› (base_model_conf$layers - αž”αž‰αŸ’αž‡αžΈ R αž’αž˜αŸ’αž˜αžαžΆ) αž“αž·αž„αž˜αž»αžαž„αžΆαžš from_config() αž’αž“αž»αžœαžαŸ’αžαž€αžΆαžšαž”αž˜αŸ’αž›αŸ‚αž„αž”αž‰αŸ’αž…αŸ’αžšαžΆαžŸαž‘αŸ…αž‡αžΆαžœαžαŸ’αžαž»αž‚αŸ†αžšαžΌαŸ–

base_model_conf <- get_config(base_model)
base_model_conf$layers[[1]]$config$batch_input_shape[[4]] <- 1L
base_model <- from_config(base_model_conf)

αž₯αž‘αžΌαžœαž“αŸαŸ‡αžœαžΆαž˜αž·αž“αž–αž·αž”αžΆαž€αž‘αŸαž€αŸ’αž“αž»αž„αž€αžΆαžšαžŸαžšαžŸαŸαžšαž˜αž»αžαž„αžΆαžšαž‡αžΆαžŸαž€αž›αžŠαžΎαž˜αŸ’αž”αžΈαž‘αž‘αž½αž›αž”αžΆαž“αžŽαžΆαž˜αž½αž™αžŠαŸ‚αž›αž”αžΆαž“αž•αŸ’αž‚αžαŸ‹αž•αŸ’αž‚αž„αŸ‹ keras αž˜αŸ‰αžΌαžŠαŸ‚αž›αžŠαŸ‚αž›αž˜αžΆαž“αž¬αž‚αŸ’αž˜αžΆαž“αž‘αž˜αŸ’αž„αž“αŸ‹αžŠαŸ‚αž›αž”αžΆαž“αž”αžŽαŸ’αžαž»αŸ‡αž”αžŽαŸ’αžαžΆαž›αž“αŸ…αž›αžΎ imagenetαŸ–

αž˜αž»αžαž„αžΆαžšαžŸαž˜αŸ’αžšαžΆαž”αŸ‹αž•αŸ’αž‘αž»αž€αžŸαŸ’αžαžΆαž”αžαŸ’αž™αž€αž˜αŸ’αž˜αžŠαŸ‚αž›αžαŸ’αžšαŸ€αž˜αžšαž½αž…αž‡αžΆαžŸαŸ’αžšαŸαž…

get_model <- function(name = "mobilenet_v2",
                      input_shape = NULL,
                      weights = "imagenet",
                      pooling = "avg",
                      num_classes = NULL,
                      optimizer = keras::optimizer_adam(lr = 0.002),
                      loss = "categorical_crossentropy",
                      metrics = NULL,
                      color = TRUE,
                      compile = FALSE) {
  # ΠŸΡ€ΠΎΠ²Π΅Ρ€ΠΊΠ° Π°Ρ€Π³ΡƒΠΌΠ΅Π½Ρ‚ΠΎΠ²
  checkmate::assert_string(name)
  checkmate::assert_integerish(input_shape, lower = 1, upper = 256, len = 3)
  checkmate::assert_count(num_classes)
  checkmate::assert_flag(color)
  checkmate::assert_flag(compile)

  # ΠŸΠΎΠ»ΡƒΡ‡Π°Π΅ΠΌ ΠΎΠ±ΡŠΠ΅ΠΊΡ‚ ΠΈΠ· ΠΏΠ°ΠΊΠ΅Ρ‚Π° keras
  model_fun <- get0(paste0("application_", name), envir = asNamespace("keras"))
  # ΠŸΡ€ΠΎΠ²Π΅Ρ€ΠΊΠ° наличия ΠΎΠ±ΡŠΠ΅ΠΊΡ‚Π° Π² ΠΏΠ°ΠΊΠ΅Ρ‚Π΅
  if (is.null(model_fun)) {
    stop("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. αž”αŸ‰αžΆαžšαŸ‰αžΆαž˜αŸ‰αŸ‚αžαŸ’αžšαž“αŸƒαžŸαŸ’αž‚αŸ’αžšαžΈαž”

αžŠαžΎαž˜αŸ’αž”αžΈαž—αžΆαž–αž„αžΆαž™αžŸαŸ’αžšαž½αž› αž€αžΌαžŠαž‘αžΆαŸ†αž„αž’αžŸαŸ‹αžŸαž˜αŸ’αžšαžΆαž”αŸ‹αž€αžΆαžšαž…αžΆαž”αŸ‹αž•αŸ’αžαžΎαž˜αž€αžΆαžšαž”αžŽαŸ’αžαž»αŸ‡αž”αžŽαŸ’αžαžΆαž›αžαŸ’αžšαžΌαžœαž”αžΆαž“αžšαž…αž“αžΆαž‘αžΎαž„αž‡αžΆαžŸαŸ’αž‚αŸ’αžšαžΈαž”αžαŸ‚αž˜αž½αž™ αž€αŸ†αžŽαžαŸ‹αžŠαŸ„αž™αž€αžΆαžšαž”αŸ’αžšαžΎαž”αŸ’αžšαžΆαžŸαŸ‹ αž―αž€αžŸαžΆαžš αžŠαžΌαž…αžαž„αŸαŸ’αžšαž€αž˜:

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)

αž€αž‰αŸ’αž…αž”αŸ‹ αž―αž€αžŸαžΆαžš αžαŸ†αžŽαžΆαž„αž±αŸ’αž™αž€αžΆαžšαž’αž“αž»αžœαžαŸ’αž http://docopt.org/ αžŸαž˜αŸ’αžšαžΆαž”αŸ‹ R. αžŠαŸ„αž™αž˜αžΆαž“αž‡αŸ†αž“αž½αž™αžšαž”αžŸαŸ‹αžœαžΆ αžŸαŸ’αž‚αŸ’αžšαžΈαž”αžαŸ’αžšαžΌαžœαž”αžΆαž“αž…αžΆαž”αŸ‹αž•αŸ’αžαžΎαž˜αž‡αžΆαž˜αž½αž™αž“αžΉαž„αž–αžΆαž€αŸ’αž™αž”αž‰αŸ’αž‡αžΆαžŸαžΆαž˜αž‰αŸ’αž‰αžŠαžΌαž…αž‡αžΆ Rscript bin/train_nn.R -m resnet50 -c -d /home/andrey/doodle_db ឬ ./bin/train_nn.R -m resnet50 -c -d /home/andrey/doodle_dbαž”αŸ’αžšαžŸαž·αž“αž”αžΎαž―αž€αžŸαžΆαžš train_nn.R αž’αžΆαž…αž”αŸ’αžšαžαž·αž”αžαŸ’αžαž·αž”αžΆαž“ (αž–αžΆαž€αŸ’αž™αž”αž‰αŸ’αž‡αžΆαž“αŸαŸ‡αž“αžΉαž„αž…αžΆαž”αŸ‹αž•αŸ’αžαžΎαž˜αž”αžŽαŸ’αžαž»αŸ‡αž”αžŽαŸ’αžαžΆαž›αž‚αŸ†αžšαžΌ resnet50 αž“αŸ…αž›αžΎαžšαžΌαž”αž—αžΆαž–αž”αžΈαž–αžŽαŸŒαžŠαŸ‚αž›αž˜αžΆαž“αž‘αŸ†αž αŸ† 128x128 αž—αžΈαž€αžŸαŸ‚αž› αž˜αžΌαž›αžŠαŸ’αž‹αžΆαž“αž‘αž·αž“αŸ’αž“αž“αŸαž™αžαŸ’αžšαžΌαžœαžαŸ‚αž˜αžΆαž“αž‘αžΈαžαžΆαŸ†αž„αž“αŸ…αž€αŸ’αž“αž»αž„αžαžαž―αž€αžŸαžΆαžš /home/andrey/doodle_db) αž’αŸ’αž“αž€αž’αžΆαž…αž”αž“αŸ’αžαŸ‚αž˜αž›αŸ’αž”αžΏαž“αžŸαž·αž€αŸ’αžŸαžΆ αž”αŸ’αžšαž—αŸαž‘αž€αž˜αŸ’αž˜αžœαž·αž’αžΈαž”αž„αŸ’αž€αžΎαž“αž”αŸ’αžšαžŸαž·αž‘αŸ’αž’αž—αžΆαž– αž“αž·αž„αž”αŸ‰αžΆαžšαŸ‰αžΆαž˜αŸ‰αŸ‚αžαŸ’αžšαžŠαŸ‚αž›αž’αžΆαž…αž”αŸ’αžŠαžΌαžšαžαžΆαž˜αž”αŸ†αžŽαž„αž•αŸ’αžŸαŸαž„αž‘αŸ€αžαž‘αŸ…αž€αŸ’αž“αž»αž„αž”αž‰αŸ’αž‡αžΈαŸ” αž“αŸ…αž€αŸ’αž“αž»αž„αžŠαŸ†αžŽαžΎαžšαž€αžΆαžšαž“αŸƒαž€αžΆαžšαžšαŸ€αž”αž…αŸ†αž€αžΆαžšαž”αŸ„αŸ‡αž–αž»αž˜αŸ’αž–αžœαžΆαž”αžΆαž“αž”αŸ’αžšαŸ‚αž€αŸ’αž›αžΆαž™αžαžΆαžŸαŸ’αžαžΆαž”αžαŸ’αž™αž€αž˜αŸ’αž˜ mobilenet_v2 αž–αžΈαž€αŸ†αžŽαŸ‚αž”αž…αŸ’αž…αž»αž”αŸ’αž”αž“αŸ’αž“ keras αž€αŸ’αž“αž»αž„αž€αžΆαžšαž”αŸ’αžšαžΎαž”αŸ’αžšαžΆαžŸαŸ‹ R αž˜αž·αž“αž’αžΆαž… αžŠαŸ„αž™αžŸαžΆαžšαžαŸ‚αž€αžΆαžšαž•αŸ’αž›αžΆαžŸαŸ‹αž”αŸ’αžαžΌαžšαž˜αž·αž“αžαŸ’αžšαžΌαžœαž”αžΆαž“αž‚αž·αžαž“αŸ…αž€αŸ’αž“αž»αž„αž€αž‰αŸ’αž…αž”αŸ‹ R αž™αžΎαž„αž€αŸ†αž–αž»αž„αžšαž„αŸ‹αž…αžΆαŸ†αž–αž½αž€αž‚αŸαžŠαžΎαž˜αŸ’αž”αžΈαž‡αž½αžŸαž‡αž»αž›αžœαžΆαŸ”

αžœαž·αž’αžΈαžŸαžΆαžŸαŸ’αžšαŸ’αžαž“αŸαŸ‡αž”αžΆαž“αž’αŸ’αžœαžΎαž±αŸ’αž™αžœαžΆαž’αžΆαž…αž’αŸ’αžœαžΎαž‘αŸ…αž”αžΆαž“αžŠαžΎαž˜αŸ’αž”αžΈαž”αž„αŸ’αž€αžΎαž“αž›αŸ’αž”αžΏαž“αž€αžΆαžšαž–αž·αžŸαŸ„αž’αž“αŸαž‡αžΆαž˜αž½αž™αž“αžΉαž„αž˜αŸ‰αžΌαžŠαŸ‚αž›αž•αŸ’αžŸαŸαž„αŸ—αž‚αŸ’αž“αžΆαž”αžΎαž”αŸ’αžšαŸ€αž”αž’αŸ€αž”αž‘αŸ…αž“αžΉαž„αž€αžΆαžšαž”αžΎαž€αžŠαŸ†αžŽαžΎαžšαž€αžΆαžšαžŸαŸ’αž‚αŸ’αžšαžΈαž”αž”αŸ‚αž”αž”αŸ’αžšαž–αŸƒαžŽαžΈαž“αŸ…αž€αŸ’αž“αž»αž„ RStudio (αž™αžΎαž„αž€αžαŸ‹αžŸαŸ†αž‚αžΆαž›αŸ‹αž€αž‰αŸ’αž…αž”αŸ‹αž‡αžΆαž‡αž˜αŸ’αžšαžΎαžŸαžŠαŸ‚αž›αž’αžΆαž…αž’αŸ’αžœαžΎαž‘αŸ…αž”αžΆαž“ tfruns) αž”αŸ‰αž»αž“αŸ’αžαŸ‚αž’αžαŸ’αžαž”αŸ’αžšαž™αŸ„αž‡αž“αŸαž…αž˜αŸ’αž”αž„αž‚αžΊαžŸαž˜αžαŸ’αžαž—αžΆαž–αž€αŸ’αž“αž»αž„αž€αžΆαžšαž‚αŸ’αžšαž”αŸ‹αž‚αŸ’αžšαž„αž€αžΆαžšαž”αžΎαž€αžŠαŸ†αžŽαžΎαžšαž€αžΆαžšαžŸαŸ’αž‚αŸ’αžšαžΈαž”αž€αŸ’αž“αž»αž„ Docker αž¬αžŸαžΆαž˜αž‰αŸ’αž‰αž“αŸ…αž›αžΎαž˜αŸ‰αžΆαžŸαŸŠαžΈαž“αž˜αŸ αžŠαŸ„αž™αž˜αž·αž“αž…αžΆαŸ†αž”αžΆαž…αŸ‹αžŠαŸ†αž‘αžΎαž„ RStudio αžŸαž˜αŸ’αžšαžΆαž”αŸ‹αžšαžΏαž„αž“αŸαŸ‡αŸ”

6. Dockerization αž“αŸƒ scripts

αž™αžΎαž„αž”αžΆαž“αž”αŸ’αžšαžΎ 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

αžŠαžΎαž˜αŸ’αž”αžΈαž—αžΆαž–αž„αžΆαž™αžŸαŸ’αžšαž½αž› αž€αž‰αŸ’αž…αž”αŸ‹αžŠαŸ‚αž›αž”αžΆαž“αž”αŸ’αžšαžΎαžαŸ’αžšαžΌαžœαž”αžΆαž“αžŠαžΆαž€αŸ‹αž…αžΌαž›αž‘αŸ…αž€αŸ’αž“αž»αž„αž’αžαŸαžšαŸ” αž—αžΆαž‚αž…αŸ’αžšαžΎαž“αž“αŸƒαžŸαŸ’αž‚αŸ’αžšαžΈαž”αžŠαŸ‚αž›αž”αžΆαž“αžŸαžšαžŸαŸαžšαžαŸ’αžšαžΌαžœαž”αžΆαž“αž…αž˜αŸ’αž›αž„αž“αŸ…αžαžΆαž„αž€αŸ’αž“αž»αž„αž’αž»αž„αž€αŸ†αž‘αž»αž„αž–αŸαž›αžŠαŸ†αž‘αžΎαž„αŸ” αž™αžΎαž„αž€αŸαž”αžΆαž“αž•αŸ’αž›αžΆαžŸαŸ‹αž”αŸ’αžαžΌαžš command shell αž‘αŸ… /bin/bash αžŸαž˜αŸ’αžšαžΆαž”αŸ‹αž—αžΆαž–αž„αžΆαž™αžŸαŸ’αžšαž½αž›αž“αŸƒαž€αžΆαžšαž”αŸ’αžšαžΎαž”αŸ’αžšαžΆαžŸαŸ‹αž˜αžΆαžαž·αž€αžΆ /etc/os-release. αž“αŸαŸ‡αž‡αŸ€αžŸαžœαžΆαž„αžαž˜αŸ’αžšαžΌαžœαž€αžΆαžšαž€αŸ’αž“αž»αž„αž€αžΆαžšαž”αž‰αŸ’αž‡αžΆαž€αŸ‹αž€αŸ†αžŽαŸ‚ OS αž“αŸ…αž€αŸ’αž“αž»αž„αž€αžΌαžŠαŸ”

αž›αžΎαžŸαž–αžΈαž“αŸαŸ‡αž‘αŸ€αž αžŸαŸ’αž‚αŸ’αžšαžΈαž” bash αžαžΌαž…αž˜αž½αž™αžαŸ’αžšαžΌαžœαž”αžΆαž“αžŸαžšαžŸαŸαžšαžŠαŸ‚αž›αž’αž“αž»αž‰αŸ’αž‰αžΆαžαž±αŸ’αž™αž’αŸ’αž“αž€αž”αžΎαž€αž€αž»αž„αžαžΊαž“αŸαžšαž‡αžΆαž˜αž½αž™αž“αžΉαž„αž–αžΆαž€αŸ’αž™αž”αž‰αŸ’αž‡αžΆαž•αŸ’αžŸαŸαž„αŸ—αŸ” αž§αž‘αžΆαž αžšαžŽαŸ αž‘αžΆαŸ†αž„αž“αŸαŸ‡αž’αžΆαž…αž‡αžΆαžŸαŸ’αž‚αŸ’αžšαžΈαž”αžŸαž˜αŸ’αžšαžΆαž”αŸ‹αž”αžŽαŸ’αžŠαž»αŸ‡αž”αžŽαŸ’αžŠαžΆαž›αž”αžŽαŸ’αžαžΆαž‰αžŸαžšαžŸαŸƒαž”αŸ’αžšαžŸαžΆαž‘αžŠαŸ‚αž›αž–αžΈαž˜αž»αž“αžαŸ’αžšαžΌαžœαž”αžΆαž“αžŠαžΆαž€αŸ‹αž“αŸ…αžαžΆαž„αž€αŸ’αž“αž»αž„αž€αž»αž„αžαžΊαž“αŸαžš αž¬αžŸαŸ‚αž›αž–αžΆαž€αŸ’αž™αž”αž‰αŸ’αž‡αžΆαžŸαž˜αŸ’αžšαžΆαž”αŸ‹αž”αŸ†αž”αžΆαžαŸ‹αž€αŸ†αž αž»αžŸ αž“αž·αž„αžαŸ’αžšαž½αžαž–αž·αž“αž·αžαŸ’αž™αž”αŸ’αžšαžαž·αž”αžαŸ’αžαž·αž€αžΆαžšαžšαž”αžŸαŸ‹αž€αž»αž„αžαžΊαž“αŸαžšαŸ–

αžŸαŸ’αž‚αŸ’αžšαžΈαž”αžŠαžΎαž˜αŸ’αž”αžΈαž”αžΎαž€αžŠαŸ†αžŽαžΎαžšαž€αžΆαžšαž€αž»αž„αžαžΊαž“αŸαžš

#!/bin/sh

DBDIR=${PWD}/db
LOGSDIR=${PWD}/logs
MODELDIR=${PWD}/models
DATADIR=${PWD}/data
ARGS="--runtime=nvidia --rm -v ${DBDIR}:/db -v ${LOGSDIR}:/app/logs -v ${MODELDIR}:/app/models -v ${DATADIR}:/app/data"

if [ -z "$1" ]; then
    CMD="Rscript /app/train_nn.R"
elif [ "$1" = "bash" ]; then
    ARGS="${ARGS} -ti"
else
    CMD="Rscript /app/train_nn.R $@"
fi

docker run ${ARGS} doodles-tf ${CMD}

αž”αŸ’αžšαžŸαž·αž“αž”αžΎαžŸαŸ’αž‚αŸ’αžšαžΈαž” bash αž“αŸαŸ‡αžŠαŸ†αžŽαžΎαžšαž€αžΆαžšαžŠαŸ„αž™αž‚αŸ’αž˜αžΆαž“αž”αŸ‰αžΆαžšαŸ‰αžΆαž˜αŸ‰αŸ‚αžαŸ’αžš αžŸαŸ’αž‚αŸ’αžšαžΈαž”αž“αžΉαž„αžαŸ’αžšαžΌαžœαž”αžΆαž“αž αŸ…αž“αŸ…αžαžΆαž„αž€αŸ’αž“αž»αž„αž’αž»αž„ train_nn.R αž‡αžΆαž˜αž½αž™αž“αžΉαž„αžαž˜αŸ’αž›αŸƒαž›αŸ†αž“αžΆαŸ†αžŠαžΎαž˜; αž”αŸ’αžšαžŸαž·αž“αž”αžΎαž’αžΆαž‚αž»αž™αž˜αŸ‰αž„αŸ‹αž‘αžΈαžαžΆαŸ†αž„αžŠαŸ†αž”αžΌαž„αž‚αžΊ "bash" αž“αŸ„αŸ‡αž€αž»αž„αžαžΊαž“αŸαžšαž“αžΉαž„αž…αžΆαž”αŸ‹αž•αŸ’αžαžΎαž˜αž’αž“αŸ’αžαžšαž€αž˜αŸ’αž˜αž‡αžΆαž˜αž½αž™αžŸαŸ‚αž›αž–αžΆαž€αŸ’αž™αž”αž‰αŸ’αž‡αžΆαŸ” αž“αŸ…αž€αŸ’αž“αž»αž„αž€αžšαžŽαžΈαž•αŸ’αžŸαŸαž„αž‘αŸ€αžαž‘αžΆαŸ†αž„αž’αžŸαŸ‹ αžαž˜αŸ’αž›αŸƒαž“αŸƒαž’αžΆαž‚αž»αž™αž˜αŸ‰αž„αŸ‹αž‘αžΈαžαžΆαŸ†αž„αžαŸ’αžšαžΌαžœαž”αžΆαž“αž‡αŸ†αž“αž½αžŸαŸ– CMD="Rscript /app/train_nn.R $@".

αž‚αž½αžšαž€αžαŸ‹αžŸαŸ†αž‚αžΆαž›αŸ‹αžαžΆ αžαžαžŠαŸ‚αž›αž˜αžΆαž“αž‘αž·αž“αŸ’αž“αž“αŸαž™αž”αŸ’αžšαž—αž– αž“αž·αž„αž˜αžΌαž›αžŠαŸ’αž‹αžΆαž“αž‘αž·αž“αŸ’αž“αž“αŸαž™ αž€αŸαžŠαžΌαž…αž‡αžΆαžαžαžŸαž˜αŸ’αžšαžΆαž”αŸ‹αžšαž€αŸ’αžŸαžΆαž‘αž»αž€αž‚αŸ†αžšαžΌαžŠαŸ‚αž›αž”αžΆαž“αž”αžŽαŸ’αžαž»αŸ‡αž”αžŽαŸ’αžαžΆαž›αžαŸ’αžšαžΌαžœαž”αžΆαž“αž˜αŸ‰αŸ„αž“αž“αŸ…αžαžΆαž„αž€αŸ’αž“αž»αž„αž€αž»αž„αžαžΊαž“αŸαžšαž–αžΈαž”αŸ’αžšαž–αŸαž“αŸ’αž’αž˜αŸ‰αžΆαžŸαŸŠαžΈαž“ αžŠαŸ‚αž›αž’αž“αž»αž‰αŸ’αž‰αžΆαžαž±αŸ’αž™αž’αŸ’αž“αž€αž…αžΌαž›αž”αŸ’αžšαžΎαž›αž‘αŸ’αž’αž•αž›αž“αŸƒαžŸαŸ’αž‚αŸ’αžšαžΈαž”αžŠαŸ„αž™αž˜αž·αž“αž…αžΆαŸ†αž”αžΆαž…αŸ‹αžšαŸ€αž”αž…αŸ†αŸ”

7. αž€αžΆαžšαž”αŸ’αžšαžΎαž”αŸ’αžšαžΆαžŸαŸ‹ GPU αž…αŸ’αžšαžΎαž“αž“αŸ…αž›αžΎ Google Cloud

αž›αž€αŸ’αžαžŽαŸˆαž–αž·αžŸαŸαžŸαž˜αž½αž™αž“αŸƒαž€αžΆαžšαž”αŸ’αžšαž€αž½αžαž”αŸ’αžšαž‡αŸ‚αž„αž‚αžΊαž‘αž·αž“αŸ’αž“αž“αŸαž™αžŠαŸ‚αž›αžšαŸ†αžαžΆαž“αžαŸ’αž›αžΆαŸ†αž„ (αžŸαžΌαž˜αž˜αžΎαž›αžšαžΌαž”αž—αžΆαž–αž…αŸ†αžŽαž„αž‡αžΎαž„ αžαŸ’αž…αžΈαž–αžΈ @Leigh.plt αž–αžΈ ODS slack) αŸ” αž”αžŽαŸ’αžαž»αŸ†αž’αŸ†αž‡αž½αž™αž”αŸ’αžšαž™αž»αž‘αŸ’αž’αž”αŸ’αžšαž†αžΆαŸ†αž„αž“αžΉαž„αž”αž‰αŸ’αž αžΆαž“αŸαŸ‡ αž αžΎαž™αž”αž“αŸ’αž‘αžΆαž”αŸ‹αž–αžΈαž€αžΆαžšαž–αž·αžŸαŸ„αž’αž“αŸαž›αžΎαž€αž»αŸ†αž–αŸ’αž™αžΌαž‘αŸαžšαžŠαŸ‚αž›αž˜αžΆαž“ 1 GPU αž™αžΎαž„αž”αžΆαž“αžŸαž˜αŸ’αžšαŸαž…αž…αž·αžαŸ’αžαž’αŸ’αžœαžΎαž‡αžΆαž˜αŸ’αž…αžΆαžŸαŸ‹αž“αŸƒαž‚αŸ†αžšαžΌαž”αžŽαŸ’αžαž»αŸ‡αž”αžŽαŸ’αžαžΆαž›αž“αŸ…αž›αžΎ GPUs αž‡αžΆαž…αŸ’αžšαžΎαž“αž“αŸ…αž€αŸ’αž“αž»αž„αž–αž–αž€αŸ” αž”αžΆαž“αž”αŸ’αžšαžΎ GoogleCloud (αž€αžΆαžšαžŽαŸ‚αž“αžΆαŸ†αžŠαŸαž›αŸ’αž’αž…αŸ†αž–αŸ„αŸ‡αž˜αžΌαž›αžŠαŸ’αž‹αžΆαž“) αžŠαŸ„αž™αžŸαžΆαžšαžαŸ‚αž‡αž˜αŸ’αžšαžΎαžŸαžŠαŸαž’αŸ†αž“αŸƒαž€αžΆαžšαž€αŸ†αžŽαžαŸ‹αžŠαŸ‚αž›αž˜αžΆαž“ αžαž˜αŸ’αž›αŸƒαžŸαž˜αžšαž˜αŸ’αž™ αž“αž·αž„αž”αŸ’αžšαžΆαž€αŸ‹αžšαž„αŸ’αžœαžΆαž“αŸ‹ 300 αžŠαž»αž›αŸ’αž›αžΆαžšαŸ” αžŠαŸ„αž™αž€αžΆαžšαž›αŸ„αž—αž›αž“αŸ‹ αžαŸ’αž‰αž»αŸ†αž”αžΆαž“αž”αž‰αŸ’αž‡αžΆαž‘αž·αž‰αž§αž‘αžΆαž αžšαžŽαŸ 4xV100 αž‡αžΆαž˜αž½αž™αž“αžΉαž„ SSD αž“αž·αž„ RAM αž˜αž½αž™αžαŸ„αž“ αž αžΎαž™αž“αŸ„αŸ‡αž‡αžΆαž€αŸ†αž αž»αžŸαžŠαŸαž’αŸ†αž˜αž½αž™αŸ” αž˜αŸ‰αžΆαžŸαŸŠαžΈαž“αž”αŸ‚αž”αž“αŸαŸ‡αžŸαŸŠαžΈαž›αž»αž™αž™αŸ‰αžΆαž„αž›αžΏαž“ αž’αŸ’αž“αž€αž’αžΆαž…αžŸαžΆαž€αž›αŸ’αž”αž„αžŠαŸ„αž™αž˜αž·αž“αž…αžΆαŸ†αž”αžΆαž…αŸ‹αž˜αžΆαž“αž”αŸ†αž–αž„αŸ‹αž”αž„αŸ’αž αžΌαžšαŸ” αžŸαž˜αŸ’αžšαžΆαž”αŸ‹αž‚αŸ„αž›αž”αŸ†αžŽαž„αž’αž”αŸ‹αžšαŸ† αžœαžΆαž‡αžΆαž€αžΆαžšαž”αŸ’αžšαžŸαžΎαžšαž€αŸ’αž“αž»αž„αž€αžΆαžšαž™αž€ K80 αŸ” αž”αŸ‰αž»αž“αŸ’αžαŸ‚αž…αŸ†αž“αž½αž“ RAM αžŠαŸαž…αŸ’αžšαžΎαž“αž”αžΆαž“αž˜αž€αž„αžΆαž™αžŸαŸ’αžšαž½αž› - SSD αž–αž–αž€αž˜αž·αž“αž…αžΆαž”αŸ‹αž’αžΆαžšαž˜αŸ’αž˜αžŽαŸαž“αžΉαž„αžŠαŸ†αžŽαžΎαžšαž€αžΆαžšαžšαž”αžŸαŸ‹αžœαžΆαž‘αŸ αžŠαžΌαž…αŸ’αž“αŸαŸ‡αž˜αžΌαž›αžŠαŸ’αž‹αžΆαž“αž‘αž·αž“αŸ’αž“αž“αŸαž™αžαŸ’αžšαžΌαžœαž”αžΆαž“αž•αŸ’αž‘αŸαžšαž‘αŸ… dev/shm.

αž€αžΆαžšαž…αžΆαž”αŸ‹αž’αžΆαžšαž˜αŸ’αž˜αžŽαŸαžαŸ’αž›αžΆαŸ†αž„αž”αŸ†αž•αž»αžαž‚αžΊαž”αŸ†αžŽαŸ‚αž€αž€αžΌαžŠαžŠαŸ‚αž›αž‘αž‘αž½αž›αžαž»αžŸαžαŸ’αžšαžΌαžœαž€αŸ’αž“αž»αž„αž€αžΆαžšαž”αŸ’αžšαžΎαž”αŸ’αžšαžΆαžŸαŸ‹ GPUs αž…αŸ’αžšαžΎαž“αŸ” αžŠαŸ†αž”αžΌαž„ αž‚αŸ†αžšαžΌαžαŸ’αžšαžΌαžœαž”αžΆαž“αž”αž„αŸ’αž€αžΎαžαž“αŸ…αž›αžΎ CPU αžŠαŸ„αž™αž”αŸ’αžšαžΎαž€αž˜αŸ’αž˜αžœαž·αž’αžΈαž‚αŸ’αžšαž”αŸ‹αž‚αŸ’αžšαž„αž”αžšαž·αž”αž‘ αžŠαžΌαž…αž“αŸ…αž€αŸ’αž“αž»αž„ PythonαŸ–

with(tensorflow::tf$device("/cpu:0"), {
  model_cpu <- get_model(
    name = model_name,
    input_shape = input_shape,
    weights = weights,
    metrics =(top_3_categorical_accuracy,
    compile = FALSE
  )
})

αž”αž“αŸ’αž‘αžΆαž”αŸ‹αž˜αž€αž‚αŸ†αžšαžΌαžŠαŸ‚αž›αž˜αž·αž“αž”αžΆαž“αž…αž„αž€αŸ’αžšαž„ (αž“αŸαŸ‡αžŸαŸ†αžαžΆαž“αŸ‹) αžαŸ’αžšαžΌαžœαž”αžΆαž“αž…αž˜αŸ’αž›αž„αž‘αŸ…αž…αŸ†αž“αž½αž“ GPUs αžŠαŸ‚αž›αž˜αžΆαž“αžŸαŸ’αžšαžΆαž”αŸ‹ αž αžΎαž™αž˜αžΆαž“αžαŸ‚αž”αž“αŸ’αž‘αžΆαž”αŸ‹αž–αžΈαž“αŸ„αŸ‡αžœαžΆαžαŸ’αžšαžΌαžœαž”αžΆαž“αž…αž„αž€αŸ’αžšαž„αŸ–

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)
)

αž”αž…αŸ’αž…αŸαž€αž‘αŸαžŸαž”αž»αžšαžΆαžŽαž“αŸƒαž€αžΆαžšαž”αž„αŸ’αž€αž€αžŸαŸ’αžšαž‘αžΆαž”αŸ‹αž‘αžΆαŸ†αž„αž’αžŸαŸ‹ αž›αžΎαž€αž›αŸ‚αž„αžαŸ‚αžŸαŸ’αžšαž‘αžΆαž”αŸ‹αž…αž»αž„αž€αŸ’αžšαŸ„αž™ αž€αžΆαžšαž”αžŽαŸ’αžαž»αŸ‡αž”αžŽαŸ’αžαžΆαž›αžŸαŸ’αžšαž‘αžΆαž”αŸ‹αž…αž»αž„αž€αŸ’αžšαŸ„αž™ αž€αžΆαžšαž˜αž·αž“αž”αž„αŸ’αž€αž€ αž“αž·αž„αž€αžΆαžšαž αŸ’αžœαžΉαž€αž αžΆαžαŸ‹αž‘αžΎαž„αžœαž·αž‰αž“αžΌαžœαž‚αŸ†αžšαžΌαž‘αžΆαŸ†αž„αž˜αžΌαž›αžŸαž˜αŸ’αžšαžΆαž”αŸ‹ GPUs αž‡αžΆαž…αŸ’αžšαžΎαž“αž˜αž·αž“αž’αžΆαž…αžαŸ’αžšαžΌαžœαž”αžΆαž“αž’αž“αž»αžœαžαŸ’αžαž”αžΆαž“αž‘αŸαŸ”

αž€αžΆαžšαž”αžŽαŸ’αžαž»αŸ‡αž”αžŽαŸ’αžαžΆαž›αžαŸ’αžšαžΌαžœαž”αžΆαž“αžαŸ’αžšαž½αžαž–αž·αž“αž·αžαŸ’αž™αžŠαŸ„αž™αž‚αŸ’αž˜αžΆαž“αž€αžΆαžšαž”αŸ’αžšαžΎαž”αŸ’αžšαžΆαžŸαŸ‹αŸ” 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 αž˜αž·αž“αž˜αžΆαž“αž˜αž»αžαž„αžΆαžšαžŠαŸ‚αž›αžαŸ’αžšαŸ€αž˜αžšαž½αž…αž‡αžΆαžŸαŸ’αžšαŸαž…αžŸαž˜αŸ’αžšαžΆαž”αŸ‹αž€αžΆαžšαžŸαŸ’αžœαŸ‚αž„αžšαž€αžŠαŸ„αž™αžŸαŸ’αžœαŸαž™αž”αŸ’αžšαžœαžαŸ’αžαž·αžŸαž˜αŸ’αžšαžΆαž”αŸ‹αž’αžαŸ’αžšαžΆαžŸαž·αž€αŸ’αžŸαžΆαžŠαŸαž›αŸ’αž’αž”αŸ’αžšαžŸαžΎαžš (analogue lr_finder αž“αŸ…αž€αŸ’αž“αž»αž„αž”αžŽαŸ’αžŽαžΆαž›αŸαž™ fast.ai); αž‡αžΆαž˜αž½αž™αž“αžΉαž„αž€αžΆαžšαžαž·αžαžαŸ†αž”αŸ’αžšαžΉαž„αž”αŸ’αžšαŸ‚αž„αž˜αž½αž™αž…αŸ†αž“αž½αž“ αžœαžΆαž’αžΆαž…αž”αž‰αŸ’αž‡αžΌαž“αž€αžΆαžšαž’αž“αž»αžœαžαŸ’αžαž—αžΆαž‚αžΈαž‘αžΈαž”αžΈαž‘αŸ… R αž§αž‘αžΆαž αžšαžŽαŸαŸ” αž“αŸαŸ‡;
  • αž‡αžΆαž›αž‘αŸ’αž’αž•αž›αž“αŸƒαž…αŸ†αžŽαž»αž…αž˜αž»αž“ αžœαžΆαž˜αž·αž“αž’αžΆαž…αž‘αŸ…αžšαž½αž…αž‘αŸαž€αŸ’αž“αž»αž„αž€αžΆαžšαž‡αŸ’αžšαžΎαžŸαžšαžΎαžŸαž›αŸ’αž”αžΏαž“αž αŸ’αžœαžΉαž€αž αžΆαžαŸ‹αžαŸ’αžšαžΉαž˜αžαŸ’αžšαžΌαžœαž“αŸ…αž–αŸαž›αž”αŸ’αžšαžΎ GPUs αž‡αžΆαž…αŸ’αžšαžΎαž“αŸ”
  • αž˜αžΆαž“αž€αžΆαžšαžαŸ’αžœαŸ‡αžαžΆαžαž“αŸƒαžŸαŸ’αžαžΆαž”αžαŸ’αž™αž€αž˜αŸ’αž˜αž”αžŽαŸ’αžαžΆαž‰αžŸαžšαžŸαŸƒαž”αŸ’αžšαžŸαžΆαž‘αž‘αŸ†αž“αžΎαž” αž‡αžΆαž–αž·αžŸαŸαžŸαž’αŸ’αž“αž€αžŠαŸ‚αž›αž”αžΆαž“αž‘αž‘αž½αž›αž€αžΆαžšαž”αžŽαŸ’αžαž»αŸ‡αž”αžŽαŸ’αžαžΆαž›αž‡αžΆαž˜αž»αž“αž“αŸ…αž›αžΎαž”αžŽαŸ’αžαžΆαž‰αžšαžΌαž”αž—αžΆαž–αŸ”
  • αž‚αŸ’αž˜αžΆαž“αž‚αŸ„αž›αž€αžΆαžšαžŽαŸαžœαžŠαŸ’αžαž˜αž½αž™ αž“αž·αž„αž’αžαŸ’αžšαžΆαž€αžΆαžšαžšαŸ€αž“αžŸαžΌαžαŸ’αžšαžŠαŸ‚αž›αžšαžΎαžŸαž’αžΎαž„αž‘αŸ (αž€αžΆαžšαž›αž»αž”αž”αŸ†αž”αžΆαžαŸ‹αž€αžΌαžŸαŸŠαžΈαž“αž»αžŸαž‚αžΊαžαžΆαž˜αžŸαŸ†αžŽαžΎαžšαž”αžŸαŸ‹αž™αžΎαž„αŸ” αž”αžΆαž“αž’αž“αž»αžœαžαŸ’αž, αžŸαžΌαž˜αž’αžšαž‚αž»αžŽ αžŸαŸ’αž‚αžΈαžŠαžΆαž“).

αž’αŸ’αžœαžΈαžŠαŸ‚αž›αž˜αžΆαž“αž”αŸ’αžšαž™αŸ„αž‡αž“αŸαžαŸ’αžšαžΌαžœαž”αžΆαž“αžšαŸ€αž“αž–αžΈαž€αžΆαžšαž”αŸ’αžšαž€αž½αžαž“αŸαŸ‡αŸ–

  • αž“αŸ…αž›αžΎαž•αŸ’αž“αŸ‚αž€αžšαžΉαž„αžŠαŸ‚αž›αž˜αžΆαž“αžαžΆαž˜αž–αž›αž‘αžΆαž” αž’αŸ’αž“αž€αž’αžΆαž…αž’αŸ’αžœαžΎαž€αžΆαžšαž‡αžΆαž˜αž½αž™αž”αžšαž·αž˜αžΆαžŽαž‘αž·αž“αŸ’αž“αž“αŸαž™αžŸαž˜αžšαž˜αŸ’αž™ (αž…αŸ’αžšαžΎαž“αžŠαž„αž“αŸƒαž‘αŸ†αž αŸ† RAM) αžŠαŸ„αž™αž‚αŸ’αž˜αžΆαž“αž€αžΆαžšαžˆαžΊαž…αžΆαž”αŸ‹αŸ” αžαž„αŸ‹αž•αŸ’αž›αžΆαžŸαŸ’αž‘αž·αž… αžαžΆαžšαžΆαž„αž‘αž·αž“αŸ’αž“αž“αŸαž™ αžšαž€αŸ’αžŸαžΆαž‘αž»αž€αž’αž„αŸ’αž‚αž…αž„αž…αžΆαŸ†αžŠαŸ„αž™αžŸαžΆαžšαžαŸ‚αž€αžΆαžšαž€αŸ‚αž”αŸ’αžšαŸ‚αžαžΆαžšαžΆαž„αž“αŸ…αž“αžΉαž„αž€αž“αŸ’αž›αŸ‚αž„ αžŠαŸ‚αž›αž‡αŸ€αžŸαžœαžΆαž„αž€αžΆαžšαž…αž˜αŸ’αž›αž„αž–αž½αž€αžœαžΆ αž αžΎαž™αž“αŸ…αž–αŸαž›αž”αŸ’αžšαžΎαž”αžΆαž“αžαŸ’αžšαžΉαž˜αžαŸ’αžšαžΌαžœ αžŸαž˜αžαŸ’αžαž—αžΆαž–αžšαž”αžŸαŸ‹αžœαžΆαžŸαŸ’αž‘αžΎαžšαžαŸ‚αžαŸ‚αž„αžαŸ‚αž”αž„αŸ’αž αžΆαž‰αž–αžΈαž›αŸ’αž”αžΏαž“αžαŸ’αž–αžŸαŸ‹αž”αŸ†αž•αž»αžαž€αŸ’αž“αž»αž„αž…αŸ†αžŽαŸ„αž˜αž§αž”αž€αžšαžŽαŸαž‘αžΆαŸ†αž„αž’αžŸαŸ‹αžŠαŸ‚αž›αžŸαŸ’αž‚αžΆαž›αŸ‹αž™αžΎαž„αžŸαž˜αŸ’αžšαžΆαž”αŸ‹αž—αžΆαžŸαžΆαžŸαŸ’αž‚αŸ’αžšαžΈαž”αŸ” αž€αžΆαžšαžšαž€αŸ’αžŸαžΆαž‘αž»αž€αž‘αž·αž“αŸ’αž“αž“αŸαž™αž“αŸ…αž€αŸ’αž“αž»αž„αž˜αžΌαž›αžŠαŸ’αž‹αžΆαž“αž‘αž·αž“αŸ’αž“αž“αŸαž™αž’αž“αž»αž‰αŸ’αž‰αžΆαžαž±αŸ’αž™αž’αŸ’αž“αž€αž€αŸ’αž“αž»αž„αž€αžšαžŽαžΈαž‡αžΆαž…αŸ’αžšαžΎαž“αžŠαŸ„αž™αž˜αž·αž“αž‚αž·αžαž–αžΈαžαž˜αŸ’αžšαžΌαžœαž€αžΆαžšαž€αŸ’αž“αž»αž„αž€αžΆαžšαž…αŸ’αžšαž”αžΆαž…αŸ‹αžŸαŸ†αžŽαž»αŸ†αž‘αž·αž“αŸ’αž“αž“αŸαž™αž‘αžΆαŸ†αž„αž˜αžΌαž›αž‘αŸ…αž€αŸ’αž“αž»αž„ RAM αŸ”
  • αž˜αž»αžαž„αžΆαžšαž™αžΊαžαž€αŸ’αž“αž»αž„ R αž’αžΆαž…αžαŸ’αžšαžΌαžœαž”αžΆαž“αž‡αŸ†αž“αž½αžŸαžŠαŸ„αž™αž˜αž»αžαž„αžΆαžšαž›αžΏαž“αž€αŸ’αž“αž»αž„ C++ αžŠαŸ„αž™αž”αŸ’αžšαžΎαž€αž‰αŸ’αž…αž”αŸ‹ Rcpp. αž”αŸ’αžšαžŸαž·αž“αž”αžΎαž”αž“αŸ’αžαŸ‚αž˜αž›αžΎαž€αžΆαžšαž”αŸ’αžšαžΎαž”αŸ’αžšαžΆαžŸαŸ‹ RcppThread ឬ RcppParallelαž™αžΎαž„αž‘αž‘αž½αž›αž”αžΆαž“αž€αžΆαžšαž’αž“αž»αžœαžαŸ’αžαž–αž αž»αžαŸ’αžŸαŸ‚αž†αŸ’αž›αž„αžœαŸαž‘αž·αž€αžΆ αžŠαžΌαž…αŸ’αž“αŸαŸ‡αž˜αž·αž“αž…αžΆαŸ†αž”αžΆαž…αŸ‹αž’αŸ’αžœαžΎαžŸαŸ’αžšαž”αž‚αŸ’αž“αžΆαž‡αžΆαž˜αž½αž™αž€αžΌαžŠαž“αŸ…αž€αž˜αŸ’αžšαž·αž R αž‘αŸαŸ”
  • αž€αž‰αŸ’αž…αž”αŸ‹ Rcpp αž’αžΆαž…αžαŸ’αžšαžΌαžœαž”αžΆαž“αž”αŸ’αžšαžΎαžŠαŸ„αž™αž‚αŸ’αž˜αžΆαž“αž…αŸ†αžŽαŸαŸ‡αžŠαžΉαž„αž’αŸ’αž„αž“αŸ‹αž’αŸ’αž„αžšαž“αŸƒ C ++ αž’αž”αŸ’αž”αž”αžšαž˜αžΆαžŠαŸ‚αž›αžαŸ’αžšαžΌαžœαž€αžΆαžšαžαŸ’αžšαžΌαžœαž”αžΆαž“αž‚αžΌαžŸαž”αž‰αŸ’αž‡αžΆαž€αŸ‹ αž“αŸ…αž‘αžΈαž“αŸαŸ‡. αž―αž€αžŸαžΆαžšαž”αž‹αž˜αž€αžαžΆαžŸαž˜αŸ’αžšαžΆαž”αŸ‹αž”αžŽαŸ’αžŽαžΆαž›αŸαž™ C αžαŸ’αžšαž‡αžΆαž€αŸ‹αž˜αž½αž™αž…αŸ†αž“αž½αž“αžŠαžΌαž…αž‡αžΆ xtensor αž˜αžΆαž“αž“αŸ…αž›αžΎ CRAN αž–αŸ„αž›αž‚αžΊαž αŸαžŠαŸ’αž‹αžΆαžšαž…αž“αžΆαžŸαž˜αŸ’αž–αŸαž“αŸ’αž’αž˜αž½αž™αž€αŸ†αž–αž»αž„αžαŸ’αžšαžΌαžœαž”αžΆαž“αž”αž„αŸ’αž€αžΎαžαž‘αžΎαž„αžŸαž˜αŸ’αžšαžΆαž”αŸ‹αž€αžΆαžšαž’αž“αž»αžœαžαŸ’αžαž‚αž˜αŸ’αžšαŸ„αž„αžŠαŸ‚αž›αžšαž½αž˜αž”αž‰αŸ’αž…αžΌαž›αž€αžΌαžŠ C++ αžŠαŸ‚αž›αž˜αžΆαž“αž”αŸ’αžšαžŸαž·αž‘αŸ’αž’αž—αžΆαž–αžαŸ’αž–αžŸαŸ‹αžŠαŸ‚αž›αžαŸ’αžšαŸ€αž˜αžšαž½αž…αž‡αžΆαžŸαŸ’αžšαŸαž…αž‘αŸ…αž€αŸ’αž“αž»αž„ R αŸ” αž—αžΆαž–αž„αžΆαž™αžŸαŸ’αžšαž½αž›αž”αž“αŸ’αžαŸ‚αž˜αž‚αžΊαž€αžΆαžšαž”αž“αŸ’αž›αž·αž…αžœαžΆαž€αŸ’αž™αžŸαž˜αŸ’αž–αŸαž“αŸ’αž’ αž“αž·αž„αž§αž”αž€αžšαžŽαŸαžœαž·αž—αžΆαž‚αž€αžΌαžŠ C++ αž‹αž·αžαž·αžœαž“αŸ’αžαž“αŸ…αž€αŸ’αž“αž»αž„ RStudio αŸ”
  • αž―αž€αžŸαžΆαžš αž’αž“αž»αž‰αŸ’αž‰αžΆαžαž±αŸ’αž™αž’αŸ’αž“αž€αžŠαŸ†αžŽαžΎαžšαž€αžΆαžšαžŸαŸ’αž‚αŸ’αžšαžΈαž”αžŠαŸ„αž™αžαŸ’αž›αž½αž“αž―αž„αž‡αžΆαž˜αž½αž™αž“αžΉαž„αž”αŸ‰αžΆαžšαŸ‰αžΆαž˜αŸ‰αŸ‚αžαŸ’αžšαŸ” αžœαžΆαž„αžΆαž™αžŸαŸ’αžšαž½αž›αž”αŸ’αžšαžΎαž“αŸ…αž›αžΎαž˜αŸ‰αžΆαžŸαŸŠαžΈαž“αž˜αŸαž–αžΈαž…αž˜αŸ’αž„αžΆαž™ αžšαž½αž˜αž‘αžΆαŸ†αž„αŸ” αž“αŸ…αž€αŸ’αžšαŸ„αž˜ docker αŸ” αž“αŸ…αž€αŸ’αž“αž»αž„ RStudio αžœαžΆαž˜αžΆαž“αž€αžΆαžšαžšαž’αžΆαž€αŸ‹αžšαž’αž½αž›αž€αŸ’αž“αž»αž„αž€αžΆαžšαž’αŸ’αžœαžΎαž€αžΆαžšαž–αž·αžŸαŸ„αž’αž“αŸαž‡αžΆαž…αŸ’αžšαžΎαž“αž˜αŸ‰αŸ„αž„αž‡αžΆαž˜αž½αž™αž“αžΉαž„αž€αžΆαžšαž”αžŽαŸ’αžαž»αŸ‡αž”αžŽαŸ’αžαžΆαž›αž”αžŽαŸ’αžαžΆαž‰αžŸαžšαžŸαŸƒαž”αŸ’αžšαžŸαžΆαž‘ αž αžΎαž™αž€αžΆαžšαžŠαŸ†αž‘αžΎαž„ IDE αž“αŸ…αž›αžΎ server αžαŸ’αž›αž½αž“αžœαžΆαž˜αž·αž“αžαŸ‚αž„αžαŸ‚αžαŸ’αžšαžΉαž˜αžαŸ’αžšαžΌαžœαž“αŸ„αŸ‡αž‘αŸαŸ”
  • Docker αž’αžΆαž“αžΆαž“αžΌαžœαž—αžΆαž–αž„αžΆαž™αžŸαŸ’αžšαž½αž›αž“αŸƒαž€αžΌαžŠ αž“αž·αž„αž€αžΆαžšαž•αž›αž·αžαž‘αžΎαž„αžœαž·αž‰αž“αŸƒαž›αž‘αŸ’αž’αž•αž›αžšαžœαžΆαž„αž’αŸ’αž“αž€αž’αž—αž·αžœαžŒαŸ’αžαž“αŸαžŠαŸ‚αž›αž˜αžΆαž“αž€αŸ†αžŽαŸ‚αž•αŸ’αžŸαŸαž„αž‚αŸ’αž“αžΆαž“αŸƒ OS αž“αž·αž„αž”αžŽαŸ’αžŽαžΆαž›αŸαž™ αž€αŸαžŠαžΌαž…αž‡αžΆαž—αžΆαž–αž„αžΆαž™αžŸαŸ’αžšαž½αž›αž“αŸƒαž€αžΆαžšαž”αŸ’αžšαžαž·αž”αžαŸ’αžαž·αž“αŸ…αž›αžΎαž˜αŸ‰αžΆαžŸαŸŠαžΈαž“αž˜αŸαŸ” αž’αŸ’αž“αž€αž’αžΆαž…αž”αžΎαž€αžŠαŸ†αžŽαžΎαžšαž€αžΆαžšαž”αŸ†αž–αž„αŸ‹αž”αžŽαŸ’αžαž»αŸ‡αž”αžŽαŸ’αžαžΆαž›αž‘αžΆαŸ†αž„αž˜αžΌαž›αžŠαŸ„αž™αž‚αŸ’αžšαžΆαž“αŸ‹αžαŸ‚αž–αžΆαž€αŸ’αž™αž”αž‰αŸ’αž‡αžΆαž˜αž½αž™αŸ”
  • Google Cloud αž‚αžΊαž‡αžΆαžœαž·αž’αžΈαžŠαŸ‚αž›αžŸαŸαž€αŸ’αžαž·αžŸαž˜αž“αžΉαž„αžαžœαž·αž€αžΆαž€αŸ’αž“αž»αž„αž€αžΆαžšαž–αž·αžŸαŸ„αž’αž“αŸαž›αžΎ Hardware αžŠαŸ‚αž›αž˜αžΆαž“αžαž˜αŸ’αž›αŸƒαžαŸ’αž›αŸƒ αž”αŸ‰αž»αž“αŸ’αžαŸ‚αž’αŸ’αž“αž€αžαŸ’αžšαžΌαžœαž‡αŸ’αžšαžΎαžŸαžšαžΎαžŸαž€αžΆαžšαž€αŸ†αžŽαžαŸ‹αžšαž…αž“αžΆαžŸαž˜αŸ’αž–αŸαž“αŸ’αž’αžŠαŸ„αž™αž”αŸ’αžšαž»αž„αž”αŸ’αžšαž™αŸαžαŸ’αž“αŸ”
  • αž€αžΆαžšαžœαžΆαžŸαŸ‹αž›αŸ’αž”αžΏαž“αž“αŸƒαž”αŸ†αžŽαŸ‚αž€αž€αžΌαžŠαž“αžΈαž˜αž½αž™αŸ—αž‚αžΊαž˜αžΆαž“αž”αŸ’αžšαž™αŸ„αž‡αž“αŸαžαŸ’αž›αžΆαŸ†αž„αžŽαžΆαžŸαŸ‹ αž‡αžΆαž–αž·αžŸαŸαžŸαž“αŸ…αž–αŸαž›αžšαž½αž˜αž”αž‰αŸ’αž…αžΌαž› R αž“αž·αž„ C++ αž“αž·αž„αž‡αžΆαž˜αž½αž™αž€αž‰αŸ’αž…αž”αŸ‹ αž›αŸαž„αž‡αžΆαž€αžΈαž‘αžΆαž€αžšαž”αž˜αŸ’αžšαž»αž„ - αž€αŸαž„αžΆαž™αžŸαŸ’αžšαž½αž›αž•αž„αžŠαŸ‚αžšαŸ”

αžŸαžšαž»αž”αž˜αž€ αž”αž‘αž–αž·αžŸαŸ„αž’αž“αŸαž“αŸαŸ‡αž–αž·αžαž‡αžΆαž˜αžΆαž“αž”αŸ’αžšαž™αŸ„αž‡αž“αŸαžαŸ’αž›αžΆαŸ†αž„αžŽαžΆαžŸαŸ‹ αž αžΎαž™αž™αžΎαž„αž”αž“αŸ’αžαž’αŸ’αžœαžΎαž€αžΆαžšαžŠαžΎαž˜αŸ’αž”αžΈαžŠαŸ„αŸ‡αžŸαŸ’αžšαžΆαž™αž”αž‰αŸ’αž αžΆαž˜αž½αž™αž…αŸ†αž“αž½αž“αžŠαŸ‚αž›αž”αžΆαž“αž›αžΎαž€αž‘αžΎαž„αŸ”

αž”αŸ’αžšαž—αž–: www.habr.com

αž”αž“αŸ’αžαŸ‚αž˜αž˜αžαž·αž™αŸ„αž”αž›αŸ‹