Tensorflow.js-da MNIST tasvir ma'lumotlari bilan qanday shug'ullanish kerak

80% ma'lumotlar ma'lumotlar tozalaydi va 20 foizi ma'lumotlarni tozalashdan shikoyat qiladilar, degan hazil bor ... ma'lumotlarni tozalash tashqi ma'lumotlarga qaraganda ma'lumotlarning ancha yuqori ulushi. Amaliy o'qitish modellari odatda mashina o'rganuvchi yoki ma'lumot olimi bajaradigan ishlarning nisbatan kam (10 foizdan kam) qismini tashkil etadi.

 - Entoni Goldbloom, Kaggle bosh direktori

Ma'lumotni manipulyatsiya qilish har qanday mashina o'rganish muammosi uchun hal qiluvchi qadamdir. Ushbu maqola Tensorflow.js (0.11.1) uchun MNIST misolini olamiz va ma'lumotlarni yuklab olish tartibini boshqaruvchi kodni ko'rib chiqamiz.

MNIST misoli

18 ta import 'tf sifatida' @ tensorflow / tfjs ';
19
20 const IMAGE_SIZE = 784;
21 const NUM_CLASSES = 10;
22-son NUM_DATASET_ELEMENTS = 65000;
23
24-qator NUM_TRAIN_ELEMENTS = 55000;
25-qator NUM_TEST_ELEMENTS = NUM_DATASET_ELEMENTS - NUM_TRAIN_ELEMENTS;
26
27-qator MNIST_IMAGES_SPRITE_PATH =
28 'https://storage.googleapis.com/learnjs-data/model-builder/mnist_images.png';
29-qator MNIST_LABELS_PATH =
30 'https: //storage.googleapis.com/learnjs-data/model-builder/mnist_labels_uint8'; '

Birinchidan, kod Tensorflow-ni import qiladi (kodingizni o'zgartirganingizga ishonch hosil qiling!) Va bir qator barqarorlikni, shu jumladan:

  • IMAGE_SIZE - rasm hajmi (kengligi va balandligi 28x28 = 784)
  • NUM_CLASSES - yorliq toifalari soni (raqam 0-9 bo'lishi mumkin, shuning uchun 10 ta sinf mavjud)
  • NUM_DATASET_ELEMENTS - rasmlarning umumiy soni (65,000)
  • NUM_TRAIN_ELEMENTS - mashg'ulot rasmlarining soni (55,000)
  • NUM_TEST_ELEMENTS - sinov rasmlarining soni (10,000, qolgan qismi)
  • MNIST_IMAGES_SPRITE_PATH & MNIST_LABELS_PATH - rasmlar va yorliqlarga yo'l.

Rasmlar bitta ulkan tasvirga birlashtirilgan, ular quyidagicha:

MNISTData

Keyingi qator, 38-qatordan boshlab, MnistData, quyidagi funktsiyalarni bajaradigan sinf:

  • yuk - rasm va yorliqli ma'lumotlarni asinxron yuklash uchun javobgardir
  • nextTrainBatch - keyingi o'quv guruhini yuklang
  • nextTestBatch - keyingi sinov to'plamini yuklang
  • nextBatch - keyingi to'plamni qaytarish uchun umumiy funksiya, u mashg'ulotlar to'plamida yoki testlar to'plamida bo'lishiga bog'liq

Ishni boshlash uchun ushbu maqola faqat yuklash funktsiyasidan o'tadi.

yuklamoq

44 asinks yuki () {
45 // MNIST sepilgan tasvirni olish uchun so'rov yuboring.
46 const img = yangi Image ();
47 const kanvas = document.createElement ('tuval');
48 const ctx = canvas.getContext ('2d');

async - bu Javascript-da nisbatan yangi til xususiyatidir, buning uchun sizga translyator kerak bo'ladi.

Image ob'ekti - bu DOM funktsiyasi bo'lib, u xotiradagi tasvirni aks ettiradi. Rasmga qo'shib qo'yilganda va uning atributlariga kirish huquqini beradigan qo'ng'iroqlarni qaytarib olishni ta'minlaydi. tuval - bu DOM elementi bo'lib, u pikselli massivlarga kirish va kontekst bo'yicha ishlov berishni ta'minlaydi.

Ularning ikkalasi ham DOM elementlari ekan, agar siz Node.js (yoki Web Worker) da ishlayotgan bo'lsangiz, siz ushbu elementlarga kira olmaysiz. Muqobil yondashuvni quyida ko'rib chiqing.

imgRequest

49 const imgRequest = yangi va'da ((hal qilish, rad qilish) => {
50 img.crossOrigin = '';
51 img.onload = () => {
52 img.width = img.naturalWidth;
53 img.height = img.naturalHeight;

Kod, rasm muvaffaqiyatli yuklanganidan keyin hal qilinadigan yangi va'da beradi. Ushbu misol xato holatini aniq ko'rib chiqmaydi.

crossOrigin - bu img atributidir, domenlar bo'ylab rasmlarni yuklashga imkon beradi va DOM bilan o'zaro aloqada CORS (manbalarni o'zaro almashish) muammolari atrofida bo'ladi. naturalWidth and naturalHeight yuklangan rasmning asl o'lchamlariga murojaat qiladi va hisob-kitoblarni amalga oshirayotganda rasmning o'lchamlari to'g'ri ekanligini ta'minlashga xizmat qiladi.

55 const databaseBytesBuffer =
56 yangi ArrayBuffer (NUM_DATASET_ELEMENTS * IMAGE_SIZE * 4);
57
58 const chunkSize = 5000;
59 tuval.width = img.width;
60 tuval.height = chunkSize;

Kod har bir rasmning har bir pikselini o'z ichiga olgan yangi tamponni ishga tushiradi. U rasmlarning umumiy sonini har bir tasvirning hajmiga kanallar soniga ko'paytiradi (4).

Ishonchim komilki, chunkSize interfeysi UI-ni bir vaqtning o'zida xotiraga juda ko'p ma'lumot yuklanishiga yo'l qo'ymaslik uchun ishlatiladi, ammo men 100% amin emasman.

62 uchun (bo'lsin i = 0; i 

Ushbu kod sprite-dagi har bir rasm bo'ylab aylanadi va iteratsiya uchun yangi TypedArrayni ishga tushiradi. Keyin, kontekstdagi rasm chizilgan rasmning katta qismini oladi. Va nihoyat, chizilgan rasm kontekstning getImageData funktsiyasidan foydalangan holda tasvir ma'lumotlariga aylantiriladi, bu esa piksel ma'lumotlarini namoyish etuvchi ob'ektni qaytaradi.

72 uchun (j = 0; j 

0 dan 1 gacha bo'lgan qiymatlarni yopish uchun biz piksellarni aylanib o'tamiz va 255 ga bo'lamiz (pikselning mumkin bo'lgan maksimal qiymati) va faqat qizil kanal kerak, chunki bu kulrang rangli rasm.

78 this.datasetImages = yangi Float32Array (ma'lumotlar bazasiBytesBuffer);
79
80 qaror ();
81};
82 img.src = MNIST_IMAGES_SPRITE_PATH;
83});

Bu chiziq buferni oladi, uni yangi TypedArray ichiga joylashtiradi, u bizning piksel ma'lumotimizni saqlaydi va keyin Va'da berishni hal qiladi. Oxirgi satr (src-ni o'rnatish) aslida funktsiyani boshlaydigan rasmni yuklashni boshlaydi.

Avvaliga meni chalkashtirgan narsa bu TypedArray-ning ma'lumot bazasidagi buferga nisbatan harakati. Siz ko'rib chiqishingiz mumkinki, DatabaseBytesView tsikl ichida o'rnatildi, lekin hech qachon qaytarilmaydi.

Kaput ostida, DatabaseBytesView buferli DatabaseBuffer-ga ishora qilmoqda (u ishga tushiriladi). Kod piksel ma'lumotlarini yangilaganda, u bilvosita buferning qiymatlarini tahrirlamoqda, bu esa o'z navbatida 78-satrda yangi Float32Array-ga kiritiladi.

DOM tashqarisidagi rasm ma'lumotlari olinmoqda

Agar siz DOMda bo'lsangiz, DOM-dan foydalanishingiz kerak. Brauzer (tuval orqali) rasmlarning formatini aniqlash va bufer ma'lumotlarini piksellarga tarjima qilish bilan shug'ullanadi. Ammo agar siz DOM-dan tashqarida ishlayotgan bo'lsangiz (aytaylik, Node.js yoki Web Worker), sizga muqobil yondashuv kerak bo'ladi.

fetch sizga faylning ostidagi buferga kirishga imkon beradigan Javob.arrayBuffer mexanizmini taqdim etadi. Biz DOMni butunlay chetlab o'tib, baytlarni qo'lda o'qish uchun foydalanishimiz mumkin. Yuqoridagi kodni yozish uchun alternativa yondoshish (ushbu kodni olish kerak, uni tugun ichida izomorf-fetch kabi narsa bilan to'ldirish mumkin):

const imgRequest = olish (MNIST_IMAGES_SPRITE_PATH) .so'ngra (resp => resp.arrayBuffer ()) .so'ngra (bufer => {
  yangi va'da bering (qaror => {
    const o'quvchi = yangi PNGReader (bufer);
    return o'quvchi.parse ((err, png) => {
      const piksel = Float32Array.from (png.piksel) .map (piksel => {
        qaytarish piksel / 255;
      });
      this.datasetImages = piksel;
      hal qilmoq ();
    });
  });
});

Bu ma'lum bir rasm uchun qator buferini qaytaradi. Buni yozayotganda, avval men kiruvchi buferni tahlil qilishga harakat qildim, lekin buni men tavsiya qilmayman. (Agar siz buni qilishni xohlasangiz, png uchun massiv buferini qanday o'qish haqida ba'zi ma'lumotlar mavjud.) Buning o'rniga men sizga png-larni tahlil qiladigan pngjs-dan foydalanishni tanladim. Boshqa rasm formatlari bilan ishlashda siz tahlil qilish funktsiyalarini o'zingiz aniqlab olishingiz kerak.

Faqat sirtni tarash

Ma'lumotlar manipulyatsiyasini tushunish JavaScript-da mashina o'rganishning muhim qismidir. Foydalanish holatlarimiz va talablarimizni tushunib, biz ma'lumotlarni o'z ehtiyojlarimiz uchun to'g'ri formatlash uchun bir nechta asosiy funktsiyalardan foydalanishimiz mumkin.

Tensorflow.js jamoasi doimiy ravishda Tensorflow.js-dagi API ma'lumotlarini o'zgartirmoqda. Bu API rivojlanishi bilan ehtiyojlarimizni ko'proq qondirishga yordam beradi. Bu, shuningdek, Tensorflow.js o'sishda va yaxshilanishda davom etayotganligi sababli, API-ning rivojlanishidan xabardor bo'lib turish kerakligini anglatadi.

Dastlab thekevinscott.com saytida nashr etilgan

Ari Zilnikga alohida rahmat.