TensorFlow.js: Buat "Teachable Machine" Anda sendiri menggunakan pemelajaran transfer dengan TensorFlow.js

1. Sebelum memulai

Penggunaan model TensorFlow.js telah tumbuh secara eksponensial selama beberapa tahun terakhir dan banyak developer JavaScript sekarang ingin menggunakan model canggih yang sudah ada dan melatihnya kembali untuk bekerja dengan data kustom yang unik bagi industri mereka. Tindakan mengambil model yang sudah ada (sering disebut sebagai model dasar), dan menggunakannya pada domain yang serupa tetapi berbeda dikenal sebagai pemelajaran transfer.

Pemelajaran transfer memiliki banyak keuntungan dibandingkan memulai dari model yang sepenuhnya kosong. Anda dapat menggunakan kembali pengetahuan yang sudah dipelajari dari model terlatih sebelumnya, dan Anda memerlukan lebih sedikit contoh item baru yang ingin diklasifikasikan. Selain itu, pelatihan sering kali jauh lebih cepat karena hanya perlu melatih ulang beberapa lapisan akhir arsitektur model, bukan seluruh jaringan. Karena alasan ini, pemelajaran transfer sangat cocok untuk lingkungan browser web yang resource-nya dapat bervariasi berdasarkan perangkat eksekusi, tetapi juga memiliki akses langsung ke sensor untuk akuisisi data yang mudah.

Codelab ini menampilkan cara membuat aplikasi web dari kanvas kosong, yang menciptakan kembali aplikasi "populer" dari Google Teachable Machine" situs Anda. Situs web ini memungkinkan Anda membuat aplikasi web fungsional yang dapat digunakan setiap pengguna untuk mengenali objek khusus hanya dengan beberapa gambar contoh dari webcam mereka. Situs sengaja dibuat seminimal mungkin agar Anda dapat berfokus pada aspek Machine Learning di codelab ini. Namun, seperti situs Teachable Machine yang asli, ada banyak ruang lingkup untuk menerapkan pengalaman developer web Anda yang sudah ada guna meningkatkan UX.

Prasyarat

Codelab ini ditulis untuk developer web yang agak familier dengan model siap pakai TensorFlow.js dan penggunaan API dasar, serta yang ingin memulai pemelajaran transfer di TensorFlow.js.

  • Pemahaman dasar tentang TensorFlow.js, HTML5, CSS, dan JavaScript dianggap untuk lab ini.

Jika Anda baru mengenal Tensorflow.js, pertimbangkan untuk mengikuti kursus zero-to-hero gratis ini terlebih dahulu, yang tidak memiliki latar belakang dengan Machine Learning atau TensorFlow.js, dan mengajarkan semua yang perlu Anda ketahui dalam langkah-langkah yang lebih kecil.

Yang akan Anda pelajari

  • Apa itu TensorFlow.js dan alasan Anda harus menggunakannya di aplikasi web berikutnya.
  • Cara membuat halaman web HTML/CSS /JS sederhana yang mereplikasi pengalaman pengguna Teachable Machine.
  • Cara menggunakan TensorFlow.js untuk memuat model dasar terlatih, khususnya MobileNet, untuk menghasilkan fitur gambar yang dapat digunakan dalam pemelajaran transfer.
  • Cara mengumpulkan data dari webcam pengguna untuk beberapa kelas data yang ingin Anda kenali.
  • Cara membuat dan menentukan perseptron multi-lapisan yang mengambil fitur gambar dan mempelajari cara mengklasifikasikan objek baru menggunakan fitur tersebut.

Ayo meretas...

Yang Anda butuhkan

  • Akun Glitch.com lebih disukai untuk diikuti, atau Anda dapat menggunakan lingkungan penayangan web yang nyaman untuk Anda edit dan jalankan sendiri.

2. Apa yang dimaksud dengan TensorFlow.js?

54e81d02971f53e8.pngS

TensorFlow.js adalah library machine learning open source yang dapat berjalan di mana pun JavaScript dapat berjalan. Library ini didasarkan pada library TensorFlow asli yang ditulis di Python dan bertujuan untuk menciptakan kembali pengalaman developer dan kumpulan API ini untuk ekosistem JavaScript.

Di mana data tersebut dapat digunakan?

Mengingat portabilitas JavaScript, Anda kini dapat menulis dalam 1 bahasa dan melakukan machine learning di semua platform berikut dengan mudah:

  • Sisi klien di browser web menggunakan vanilla JavaScript
  • Sisi server dan bahkan perangkat IoT seperti Raspberry Pi yang menggunakan Node.js
  • Aplikasi desktop yang menggunakan Electron
  • Aplikasi seluler native yang menggunakan React Native

TensorFlow.js juga mendukung beberapa backend dalam setiap lingkungan ini (lingkungan berbasis hardware sebenarnya yang dapat dijalankan di dalamnya seperti CPU atau WebGL, misalnya. "Backend" dalam konteks ini bukan berarti lingkungan sisi server - backend untuk eksekusi dapat menjadi sisi klien di WebGL) untuk memastikan kompatibilitas dan juga menjaga semuanya berjalan cepat. Saat ini TensorFlow.js mendukung:

  • Eksekusi WebGL pada kartu grafis perangkat (GPU) - ini adalah cara tercepat untuk menjalankan model yang lebih besar (berukuran lebih dari 3 MB) dengan akselerasi GPU.
  • Eksekusi Web Assembly (WASM) pada CPU - untuk meningkatkan performa CPU di berbagai perangkat, termasuk ponsel generasi lama. Cara ini lebih cocok untuk model yang lebih kecil (berukuran kurang dari 3MB) yang sebenarnya dapat dijalankan lebih cepat pada CPU dengan WASM daripada dengan WebGL karena overhead mengupload konten ke prosesor grafis.
  • Eksekusi CPU - penggantian jika tidak ada lingkungan lain yang tersedia. Ini adalah yang paling lambat dari ketiganya, tetapi selalu ada untuk Anda.

Catatan: Anda dapat memilih untuk memaksa salah satu backend ini jika mengetahui perangkat yang akan mengeksekusi, atau membiarkan TensorFlow.js memutuskan untuk Anda jika Anda tidak menentukannya.

Kekuatan super sisi klien

Menjalankan TensorFlow.js di browser web pada komputer klien dapat memberikan beberapa manfaat yang patut dipertimbangkan.

Privasi

Anda dapat melatih dan mengklasifikasikan data di komputer klien tanpa harus mengirim data ke server web pihak ketiga. Terkadang hal ini dapat menjadi persyaratan untuk mematuhi hukum setempat, misalnya GDPR, atau saat memproses data apa pun yang mungkin ingin disimpan pengguna di komputernya dan tidak dikirim ke pihak ketiga.

Speed

Karena Anda tidak harus mengirim data ke server jarak jauh, inferensi (tindakan mengklasifikasikan data) bisa lebih cepat. Yang lebih bagus lagi, Anda memiliki akses langsung ke sensor perangkat seperti kamera, mikrofon, GPS, akselerometer, dan lainnya jika pengguna memberi Anda akses.

Jangkauan dan skala

Dengan sekali klik, siapa pun di seluruh dunia dapat mengklik link yang Anda kirimkan kepada mereka, membuka halaman web di browser mereka, dan memanfaatkan apa yang telah Anda buat. Tidak perlu penyiapan Linux sisi server yang rumit dengan driver CUDA dan masih banyak lagi, hanya untuk menggunakan sistem machine learning.

Biaya

Tidak ada server berarti satu-satunya hal yang perlu Anda bayar adalah CDN untuk menghosting file HTML, CSS, JS, dan model Anda. Biaya CDN jauh lebih murah daripada mempertahankan server (kemungkinan dengan kartu grafis terpasang) yang berjalan 24/7.

Fitur sisi server

Memanfaatkan implementasi Node.js TensorFlow.js akan mengaktifkan fitur-fitur berikut.

Dukungan penuh CUDA

Di sisi server, untuk akselerasi kartu grafis, Anda harus menginstal driver NVIDIA CUDA agar TensorFlow berfungsi dengan kartu grafis (tidak seperti browser yang menggunakan WebGL - tidak perlu penginstalan). Namun, dengan dukungan CUDA penuh, Anda dapat memanfaatkan sepenuhnya kemampuan level kartu grafis yang lebih rendah, sehingga menghasilkan waktu pelatihan dan inferensi yang lebih cepat. Performa setara dengan implementasi Python TensorFlow karena keduanya memiliki backend C++ yang sama.

Ukuran Model

Untuk model mutakhir dari penelitian, Anda mungkin bekerja dengan model yang sangat besar, mungkin berukuran gigabyte. Model-model tersebut saat ini tidak dapat dijalankan di browser web karena keterbatasan penggunaan memori per tab browser. Untuk menjalankan model yang lebih besar ini, Anda dapat menggunakan Node.js di server sendiri dengan spesifikasi hardware yang diperlukan untuk menjalankan model tersebut secara efisien.

IOT

Node.js didukung di komputer single board populer seperti Raspberry Pi, yang berarti Anda juga dapat menjalankan model TensorFlow.js di perangkat tersebut.

Speed

Node.js ditulis dalam JavaScript, yang berarti ia mendapatkan manfaat hanya dari kompilasi waktu. Ini berarti bahwa Anda mungkin akan sering melihat peningkatan performa saat menggunakan Node.js karena akan dioptimalkan pada runtime, terutama untuk pra-pemrosesan yang mungkin Anda lakukan. Contoh yang bagus dapat dilihat dalam studi kasus ini yang menunjukkan bagaimana Hugging Face menggunakan Node.js untuk mendapatkan peningkatan performa 2x lipat untuk model natural language processing mereka.

Sekarang Anda telah memahami dasar-dasar TensorFlow.js, tempat TensorFlow.js dapat dijalankan, dan beberapa manfaatnya, mari kita mulai melakukan hal-hal yang bermanfaat dengan TensorFlow.js.

3. Pemelajaran transfer

Apa sebenarnya yang dimaksud dengan pemelajaran transfer?

Pemelajaran transfer melibatkan pengambilan pengetahuan yang telah dipelajari untuk membantu mempelajari hal yang berbeda, tetapi serupa.

Kita manusia melakukan ini sepanjang waktu. Anda memiliki pengalaman seumur hidup yang terkandung di otak Anda yang dapat Anda gunakan untuk membantu mengenali hal-hal baru yang belum pernah Anda lihat sebelumnya. Ambil contoh pohon dedalu ini:

e28070392cd4afb9.png

Tergantung di mana Anda berada, mungkin Anda belum pernah melihat jenis pohon ini sebelumnya.

Namun, jika saya meminta Anda untuk memberi tahu saya apakah ada pohon dedalu pada gambar baru di bawah ini, Anda mungkin bisa melihatnya dengan cepat, meskipun dari sudut yang berbeda, dan sedikit berbeda dengan yang asli yang saya tunjukkan.

d9073a0d5df27222.png

Anda sudah memiliki banyak neuron di otak Anda yang tahu cara mengidentifikasi objek seperti pohon, dan neuron lain yang pandai menemukan garis lurus panjang. Anda dapat menggunakan kembali pengetahuan tersebut untuk mengklasifikasikan pohon dedalu dengan cepat, yaitu objek mirip pohon yang memiliki banyak cabang vertikal panjang lurus.

Demikian pula, jika Anda memiliki model machine learning yang sudah dilatih di domain, seperti mengenali gambar, Anda dapat menggunakannya kembali untuk melakukan tugas yang berbeda, tetapi saling berkaitan.

Anda dapat melakukan hal yang sama dengan model tingkat lanjut seperti MobileNet, yang merupakan model penelitian sangat populer yang dapat melakukan pengenalan citra pada 1.000 jenis objek yang berbeda. Mulai dari hingga mobil, layanan ini dilatih menggunakan set data besar bernama ImageNet yang memiliki jutaan gambar berlabel.

Dalam animasi ini, Anda dapat melihat sangat banyak lapisan yang dimilikinya dalam model MobileNet V1 ini:

7d4e1e35c1a89715.gif

Selama pelatihannya, model ini mempelajari cara mengekstrak fitur umum yang penting untuk 1.000 objek tersebut, dan banyak fitur tingkat rendah yang digunakan untuk mengidentifikasi objek tersebut dapat berguna untuk mendeteksi objek baru yang belum pernah dilihat sebelumnya. Lagi pula, semuanya pada akhirnya hanyalah kombinasi garis, tekstur, dan bentuk.

Mari kita lihat arsitektur Jaringan Saraf Konvolusional (CNN) tradisional (mirip dengan MobileNet) dan lihat bagaimana pemelajaran transfer dapat memanfaatkan jaringan terlatih ini untuk mempelajari sesuatu yang baru. Gambar di bawah ini menunjukkan arsitektur model khas CNN yang dalam kasus ini dilatih untuk mengenali digit tulisan tangan dari 0 hingga 9:

baf4e3d434576106.png

Jika Anda dapat memisahkan lapisan tingkat bawah terlatih dari model terlatih yang ada seperti yang ditunjukkan di sebelah kiri, dari lapisan klasifikasi di dekat ujung model yang ditampilkan di sebelah kanan (terkadang disebut sebagai kepala klasifikasi model), Anda dapat menggunakan lapisan tingkat bawah untuk menghasilkan fitur output bagi gambar tertentu berdasarkan data asli yang digunakan untuk melatih model tersebut. Berikut adalah jaringan yang sama dengan head klasifikasi yang dihapus:

369a8a9041c6917d.pngS

Dengan asumsi bahwa hal baru yang ingin Anda kenali juga dapat memanfaatkan fitur {i>output<i} seperti yang telah dipelajari model sebelumnya, maka ada kemungkinan besar bahwa fitur itu dapat digunakan kembali untuk tujuan baru.

Dalam diagram di atas, model hipotesis ini dilatih dengan angka, jadi mungkin apa yang dipelajari tentang angka juga dapat diterapkan pada huruf seperti a, b, dan c.

Jadi, sekarang Anda dapat menambahkan head klasifikasi baru yang mencoba memprediksi a, b, atau c, seperti yang ditunjukkan:

db97e5e60ae73bbd.png

Di sini, lapisan tingkat bawah dibekukan dan tidak dilatih, hanya kepala klasifikasi baru yang akan memperbarui dirinya sendiri untuk mempelajari fitur yang disediakan dari model cincang yang dilatih sebelumnya di sebelah kiri.

Tindakan untuk melakukan ini dikenal sebagai pemelajaran transfer dan merupakan hal yang dilakukan Teachable Machine di balik layar.

Anda juga dapat melihat bahwa hanya dengan melatih perseptron multi-lapisan di bagian paling akhir jaringan, perseptron multi-lapisan akan dilatih jauh lebih cepat daripada jika Anda harus melatih seluruh jaringan dari awal.

Namun, bagaimana Anda bisa mendapatkan sub-bagian dari suatu model? Buka bagian berikutnya untuk mencari tahu.

4. TensorFlow Hub - model dasar

Menemukan model dasar yang sesuai untuk digunakan

Untuk model riset yang lebih canggih dan populer seperti MobileNet, Anda dapat membuka TensorFlow hub, lalu memfilter model yang sesuai untuk TensorFlow.js yang menggunakan arsitektur MobileNet v3 untuk menemukan hasil seperti yang ditampilkan di sini:

c5dc1420c6238c14.png

Perhatikan bahwa beberapa hasil ini adalah jenis "klasifikasi gambar" (diperinci di kiri atas setiap hasil kartu model), dan hasil lainnya berjenis "vektor fitur gambar".

Hasil Vektor Fitur Gambar ini pada dasarnya adalah versi MobileNet yang telah dipotong sebelumnya yang dapat Anda gunakan untuk mendapatkan vektor fitur gambar, bukan klasifikasi akhir.

Model seperti ini sering disebut “model dasar”, yang kemudian dapat Anda gunakan untuk melakukan pemelajaran transfer dengan cara yang sama seperti yang ditunjukkan di bagian sebelumnya dengan menambahkan kepala klasifikasi baru dan melatihnya dengan data Anda sendiri.

Hal berikutnya yang perlu diperiksa adalah untuk model dasar minat tertentu, format TensorFlow.js yang digunakan untuk merilis model. Jika membuka halaman untuk salah satu model vektor fitur MobileNet v3, Anda dapat melihat dari dokumentasi JS bahwa halaman tersebut berbentuk model grafik berdasarkan contoh cuplikan kode dalam dokumentasi yang menggunakan tf.loadGraphModel().

f97d903d2e46924b.png

Perhatikan juga bahwa jika Anda menemukan model dalam format lapisan, dan bukan format grafik, Anda dapat memilih lapisan mana yang akan dibekukan dan yang akan dicairkan untuk pelatihan. Model ini bisa sangat berguna saat membuat model untuk tugas baru, yang sering disebut sebagai "model transfer". Namun, untuk saat ini, Anda akan menggunakan jenis model grafik default untuk tutorial ini, yang digunakan oleh sebagian besar model TF Hub. Untuk mempelajari lebih lanjut cara menggunakan model Lapisan, lihat kursus TensorFlow.js zero to hero.

Manfaat pemelajaran transfer

Apa keuntungan menggunakan pemelajaran transfer daripada melatih seluruh arsitektur model dari awal?

Pertama, waktu pelatihan adalah keuntungan utama menggunakan pendekatan pemelajaran transfer karena Anda sudah memiliki model dasar terlatih untuk digunakan.

Kedua, Anda tidak perlu lagi menunjukkan contoh yang jauh lebih sedikit mengenai hal baru yang Anda coba klasifikasikan karena pelatihan yang sudah berlangsung.

Cara ini sangat bagus jika Anda memiliki waktu dan sumber daya yang terbatas untuk mengumpulkan contoh data hal yang ingin Anda klasifikasikan, dan perlu membuat prototipe dengan cepat sebelum mengumpulkan lebih banyak data pelatihan untuk membuatnya lebih tangguh.

Mengingat kebutuhan akan lebih sedikit data dan kecepatan pelatihan jaringan yang lebih kecil, pemelajaran transfer tidak memerlukan banyak sumber daya. Hal tersebut membuatnya sangat cocok untuk lingkungan browser, yang hanya memerlukan waktu puluhan detik pada mesin modern, bukan berjam-jam, berhari-hari, atau berminggu-minggu untuk pelatihan model secara lengkap.

Oke! Setelah memahami esensi Pemelajaran Transfer, sekarang Anda dapat membuat Teachable Machine versi Anda sendiri. Mari kita mulai!

5. Melakukan persiapan untuk membuat kode

Yang Anda butuhkan

  • Browser web modern.
  • Pengetahuan dasar tentang HTML, CSS, JavaScript, dan Chrome DevTools (melihat output konsol).

Mari melakukan coding

Untuk memulai, template boilerplate telah dibuat untuk Glitch.com atau Codepen.io. Anda dapat menggandakan template mana pun sebagai status dasar untuk codelab ini, hanya dengan sekali klik.

Di Glitch, klik tombol "remix this" untuk melakukan fork dan membuat kumpulan file baru yang dapat diedit.

Atau, di Codepen, klik " fork" di kanan bawah layar.

Kerangka yang sangat sederhana ini menyediakan file berikut:

  • Halaman HTML (index.html)
  • Stylesheet (style.css)
  • File untuk menulis kode JavaScript (script.js)

Untuk memudahkan Anda, ada impor tambahan dalam file HTML untuk library TensorFlow.js. Tampilannya terlihat seperti ini:

index.html

<!-- Import TensorFlow.js library -->
<script src="https://cdn.jsdelivr.net/npm/@tensorflow/tfjs/dist/tf.min.js" type="text/javascript"></script>

Alternatif: Gunakan webeditor pilihan Anda atau gunakan secara lokal

Jika Anda ingin mendownload kode dan bekerja secara lokal, atau di editor online lain, cukup buat 3 file yang disebutkan di atas dalam direktori yang sama, lalu salin dan tempel kode dari boilerplate Glitch kami ke masing-masing file.

6. Boilerplate HTML aplikasi

Dari mana saya harus memulai?

Semua prototipe memerlukan beberapa scaffolding HTML dasar yang dapat Anda gunakan untuk merender temuan Anda. Siapkan sekarang. Anda akan menambahkan:

  • Judul untuk halaman.
  • Beberapa teks deskriptif.
  • Paragraf status.
  • Video untuk menyimpan feed webcam jika sudah siap.
  • Beberapa tombol untuk memulai kamera, mengumpulkan data, atau mereset pengalaman.
  • Impor untuk file TensorFlow.js dan JS yang akan Anda kodekan nanti.

Buka index.html dan tempelkan kode yang ada dengan kode berikut untuk menyiapkan fitur di atas:

index.html

<!DOCTYPE html>
<html lang="en">
  <head>
    <title>Transfer Learning - TensorFlow.js</title>
    <meta charset="utf-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1">
    <!-- Import the webpage's stylesheet -->
    <link rel="stylesheet" href="/style.css">
  </head>  
  <body>
    <h1>Make your own "Teachable Machine" using Transfer Learning with MobileNet v3 in TensorFlow.js using saved graph model from TFHub.</h1>
    
    <p id="status">Awaiting TF.js load</p>
    
    <video id="webcam" autoplay muted></video>
    
    <button id="enableCam">Enable Webcam</button>
    <button class="dataCollector" data-1hot="0" data-name="Class 1">Gather Class 1 Data</button>
    <button class="dataCollector" data-1hot="1" data-name="Class 2">Gather Class 2 Data</button>
    <button id="train">Train &amp; Predict!</button>
    <button id="reset">Reset</button>

    <!-- Import TensorFlow.js library -->
    <script src="https://cdn.jsdelivr.net/npm/@tensorflow/tfjs@3.11.0/dist/tf.min.js" type="text/javascript"></script>

    <!-- Import the page's JavaScript to do some stuff -->
    <script type="module" src="/script.js"></script>
  </body>
</html>

Memisahkan

Mari kita uraikan beberapa kode HTML di atas untuk menyoroti beberapa hal penting yang Anda tambahkan.

  • Anda menambahkan tag <h1> untuk judul halaman beserta tag <p> dengan ID ‘status', yang digunakan untuk mencetak informasi, saat Anda menggunakan berbagai bagian sistem untuk melihat {i>output<i}.
  • Anda menambahkan elemen <video> dengan ID ‘webcam', yang menjadi tujuan render streaming webcam Anda nanti.
  • Anda menambahkan 5 elemen <button>. Yang pertama, dengan ID 'enableCam,' mengaktifkan kamera. Dua tombol berikutnya memiliki class 'dataCollector', yang memungkinkan Anda mengumpulkan gambar contoh untuk objek yang ingin Anda kenali. Kode yang Anda tulis nanti akan didesain agar Anda dapat menambahkan sejumlah tombol ini dan tombol tersebut akan berfungsi sebagaimana mestinya secara otomatis.

Perhatikan bahwa tombol ini juga memiliki atribut khusus yang ditentukan pengguna yang disebut data-1hot, dengan nilai bilangan bulat mulai dari 0 untuk kelas pertama. Ini adalah indeks numerik yang akan Anda gunakan untuk mewakili data class tertentu. Indeks akan digunakan untuk mengenkode class output dengan benar menggunakan representasi numerik, bukan string, karena model ML hanya dapat berfungsi dengan angka.

Ada juga atribut nama data yang berisi nama yang dapat dibaca manusia yang ingin Anda gunakan untuk class ini, yang memungkinkan Anda memberikan nama yang lebih bermakna bagi pengguna, alih-alih nilai indeks numerik dari 1 encoding hot.

Terakhir, Anda memiliki tombol "train" dan "reset" untuk memulai proses pelatihan setelah data dikumpulkan, atau untuk mereset aplikasi masing-masing.

  • Anda juga menambahkan 2 impor <script>. Satu untuk TensorFlow.js, dan satu lagi untuk script.js yang akan segera Anda tentukan.

7. Tambah gaya

Default elemen

Tambahkan gaya untuk elemen HTML yang baru saja Anda tambahkan untuk memastikan elemen tersebut dirender dengan benar. Berikut adalah beberapa gaya yang ditambahkan ke elemen posisi dan ukuran dengan benar. Tidak ada yang terlalu spesial. Anda pasti dapat menambahkannya nanti untuk membuat UX yang lebih baik, seperti yang Anda lihat di video yang dapat diajarkan tentang mesin.

style.css

body {
  font-family: helvetica, arial, sans-serif;
  margin: 2em;
}

h1 {
  font-style: italic;
  color: #FF6F00;
}


video {
  clear: both;
  display: block;
  margin: 10px;
  background: #000000;
  width: 640px;
  height: 480px;
}

button {
  padding: 10px;
  float: left;
  margin: 5px 3px 5px 10px;
}

.removed {
  display: none;
}

#status {
  font-size:150%;
}

Bagus! Itu saja yang Anda perlukan. Jika Anda melihat pratinjau output sekarang, outputnya akan terlihat seperti ini:

81909685d7566dcb.png

8. JavaScript: Konstanta dan pemroses kunci

Menentukan konstanta kunci

Pertama, tambahkan beberapa konstanta kunci yang akan Anda gunakan di seluruh aplikasi. Mulai dengan mengganti konten script.js dengan konstanta ini:

script.js

const STATUS = document.getElementById('status');
const VIDEO = document.getElementById('webcam');
const ENABLE_CAM_BUTTON = document.getElementById('enableCam');
const RESET_BUTTON = document.getElementById('reset');
const TRAIN_BUTTON = document.getElementById('train');
const MOBILE_NET_INPUT_WIDTH = 224;
const MOBILE_NET_INPUT_HEIGHT = 224;
const STOP_DATA_GATHER = -1;
const CLASS_NAMES = [];

Mari kita uraikan kegunaannya:

  • STATUS hanya menyimpan referensi ke tag paragraf tempat Anda akan menulis pembaruan status.
  • VIDEO menyimpan referensi ke elemen video HTML yang akan merender feed webcam.
  • ENABLE_CAM_BUTTON, RESET_BUTTON, dan TRAIN_BUTTON mengambil referensi DOM ke semua tombol utama dari halaman HTML.
  • MOBILE_NET_INPUT_WIDTH dan MOBILE_NET_INPUT_HEIGHT masing-masing menentukan lebar dan tinggi input yang diharapkan dari model MobileNet. Dengan menyimpan ini secara konstan dekat bagian atas file seperti ini, jika Anda memutuskan untuk menggunakan versi yang berbeda nanti, akan lebih mudah untuk memperbarui nilai sekali daripada harus menggantinya di banyak tempat yang berbeda.
  • STOP_DATA_GATHER ditetapkan ke - 1. Tindakan ini menyimpan nilai status sehingga Anda mengetahui saat pengguna berhenti mengklik tombol untuk mengumpulkan data dari feed webcam. Dengan memberi angka ini nama yang lebih bermakna, kode tersebut akan lebih mudah dibaca nanti.
  • CLASS_NAMES bertindak sebagai pencarian dan menyimpan nama yang dapat dibaca manusia untuk kemungkinan prediksi class. Array ini akan diisi nanti.

Oke, sekarang Anda memiliki referensi ke elemen kunci, sekarang saatnya mengaitkan beberapa pemroses peristiwa ke elemen tersebut.

Menambahkan pemroses peristiwa utama

Mulai dengan menambahkan pengendali peristiwa klik ke tombol utama seperti yang ditunjukkan berikut ini:

script.js

ENABLE_CAM_BUTTON.addEventListener('click', enableCam);
TRAIN_BUTTON.addEventListener('click', trainAndPredict);
RESET_BUTTON.addEventListener('click', reset);


function enableCam() {
  // TODO: Fill this out later in the codelab!
}


function trainAndPredict() {
  // TODO: Fill this out later in the codelab!
}


function reset() {
  // TODO: Fill this out later in the codelab!
}

ENABLE_CAM_BUTTON - memanggil fungsi enableCam saat diklik.

TRAIN_BUTTON - memanggil trainAndPredict saat diklik.

RESET_BUTTON - panggilan direset saat diklik.

Terakhir, di bagian ini, Anda dapat menemukan semua tombol yang memiliki class 'dataCollector' menggunakan document.querySelectorAll(). Tindakan ini akan menampilkan array elemen yang ditemukan dari dokumen yang cocok:

script.js

let dataCollectorButtons = document.querySelectorAll('button.dataCollector');
for (let i = 0; i < dataCollectorButtons.length; i++) {
  dataCollectorButtons[i].addEventListener('mousedown', gatherDataForClass);
  dataCollectorButtons[i].addEventListener('mouseup', gatherDataForClass);
  // Populate the human readable names for classes.
  CLASS_NAMES.push(dataCollectorButtons[i].getAttribute('data-name'));
}


function gatherDataForClass() {
  // TODO: Fill this out later in the codelab!
}

Penjelasan kode:

Anda kemudian melakukan iterasi melalui tombol yang ditemukan dan mengaitkan 2 pemroses peristiwa ke setiap tombol. Satu untuk 'mousedown', dan satu lagi untuk 'mouseup'. Hal ini memungkinkan Anda terus merekam sampel selama tombol ditekan, yang berguna untuk pengumpulan data.

Kedua peristiwa memanggil fungsi gatherDataForClass yang akan Anda tentukan nanti.

Pada tahap ini, Anda juga dapat mengirim nama class yang ditemukan dan dapat dibaca manusia dari nama data atribut tombol HTML ke array CLASS_NAMES.

Selanjutnya, tambahkan beberapa variabel untuk menyimpan hal-hal penting yang akan digunakan nanti.

script.js

let mobilenet = undefined;
let gatherDataState = STOP_DATA_GATHER;
let videoPlaying = false;
let trainingDataInputs = [];
let trainingDataOutputs = [];
let examplesCount = [];
let predict = false;

Mari kita pelajari.

Pertama, Anda memiliki variabel mobilenet untuk menyimpan model mobilenet yang dimuat. Awalnya, tetapkan ini ke tidak ditentukan.

Selanjutnya, Anda memiliki variabel bernama gatherDataState. Jika 'dataCollector' ditekan, ini akan berubah menjadi 1 hot ID dari tombol tersebut, seperti yang didefinisikan dalam HTML, sehingga Anda tahu kelas data apa yang Anda kumpulkan pada saat itu. Awalnya, opsi ini disetel ke STOP_DATA_GATHER sehingga loop pengumpulan data yang Anda tulis nanti tidak akan mengumpulkan data apa pun saat tidak ada tombol yang ditekan.

videoPlaying melacak apakah streaming webcam berhasil dimuat dan diputar, serta tersedia untuk digunakan. Awalnya, setelan ini disetel ke false karena webcam tidak aktif sebelum Anda menekan ENABLE_CAM_BUTTON.

Selanjutnya, tentukan 2 array, trainingDataInputs dan trainingDataOutputs. Kolom ini menyimpan nilai data pelatihan yang dikumpulkan, saat Anda mengklik kolom 'dataCollector' untuk fitur input yang dihasilkan oleh model dasar MobileNet, dan class output diambil sampelnya masing-masing.

Satu array terakhir, examplesCount, kemudian ditentukan untuk melacak jumlah contoh yang terdapat untuk setiap class setelah Anda mulai menambahkannya.

Terakhir, Anda memiliki variabel bernama predict yang mengontrol loop prediksi Anda. Pada awalnya, hal ini disetel ke false. Prediksi tidak dapat dilakukan sampai hal ini ditetapkan ke true nanti.

Setelah semua variabel utama ditentukan, lanjutkan dan muat model dasar MobileNet v3 yang telah dipangkas sebelumnya, yang menyediakan vektor fitur gambar, bukan klasifikasi.

9. Memuat model dasar MobileNet

Pertama, tentukan fungsi baru bernama loadMobileNetFeatureModel seperti yang ditunjukkan di bawah ini. Kode ini harus berupa fungsi asinkron karena tindakan pemuatan model bersifat asinkron:

script.js

/**
 * Loads the MobileNet model and warms it up so ready for use.
 **/
async function loadMobileNetFeatureModel() {
  const URL = 
    'https://tfhub.dev/google/tfjs-model/imagenet/mobilenet_v3_small_100_224/feature_vector/5/default/1';
  
  mobilenet = await tf.loadGraphModel(URL, {fromTFHub: true});
  STATUS.innerText = 'MobileNet v3 loaded successfully!';
  
  // Warm up the model by passing zeros through it once.
  tf.tidy(function () {
    let answer = mobilenet.predict(tf.zeros([1, MOBILE_NET_INPUT_HEIGHT, MOBILE_NET_INPUT_WIDTH, 3]));
    console.log(answer.shape);
  });
}

// Call the function immediately to start loading.
loadMobileNetFeatureModel();

Dalam kode ini, Anda menentukan URL tempat model yang akan dimuat berada dari dokumentasi TFHub.

Anda kemudian dapat memuat model menggunakan await tf.loadGraphModel(), dan jangan lupa untuk menetapkan properti khusus fromTFHub ke true saat Anda memuat model dari situs Google ini. Ini adalah kasus khusus hanya untuk penggunaan model yang dihosting di TF Hub yang properti tambahannya harus ditetapkan.

Setelah pemuatan selesai, Anda dapat menyetel innerText elemen STATUS dengan pesan sehingga Anda dapat melihatnya secara visual telah dimuat dengan benar dan Anda siap untuk mulai mengumpulkan data.

Satu-satunya hal yang perlu dilakukan sekarang adalah melakukan pemanasan model. Dengan model yang lebih besar seperti ini, perlu waktu beberapa saat untuk menyiapkan semuanya saat pertama kali Anda menggunakan model tersebut. Oleh karena itu, ada baiknya untuk memasukkan angka nol melalui model untuk menghindari adanya waktu tunggu di masa mendatang saat penentuan waktu mungkin lebih penting.

Anda dapat menggunakan tf.zeros() yang digabungkan dalam tf.tidy() untuk memastikan tensor dibuang dengan benar, dengan ukuran tumpukan 1, serta tinggi dan lebar yang benar yang Anda tetapkan dalam konstanta di awal. Terakhir, Anda juga menentukan saluran warna, yang dalam hal ini adalah 3 karena model mengharapkan gambar RGB.

Selanjutnya, catat bentuk tensor yang dihasilkan yang ditampilkan menggunakan answer.shape() untuk membantu Anda memahami ukuran fitur gambar yang dihasilkan model ini.

Setelah menentukan fungsi ini, Anda selanjutnya dapat segera memanggilnya untuk memulai download model saat pemuatan halaman.

Jika Anda melihat pratinjau langsung sekarang, setelah beberapa saat, Anda akan melihat perubahan teks status dari "Menunggu pemuatan TF.js" menjadi "MobileNet v3 berhasil dimuat!" sebagaimana ditunjukkan di bawah ini. Pastikan tindakan ini berfungsi sebelum melanjutkan.

a28b734e190afff.png

Anda juga dapat memeriksa output konsol untuk melihat ukuran cetak fitur output yang dihasilkan model ini. Setelah menjalankan angka nol melalui model MobileNet, Anda akan melihat bentuk [1, 1024] yang dicetak. Item pertama hanya berukuran batch 1, dan Anda dapat melihat bahwa item ini benar-benar menampilkan 1.024 fitur yang kemudian dapat digunakan untuk membantu Anda mengklasifikasikan objek baru.

10. Menentukan head model baru

Sekarang saatnya untuk menentukan head model Anda, yang pada dasarnya merupakan perseptron multi-lapisan yang sangat minimal.

script.js

let model = tf.sequential();
model.add(tf.layers.dense({inputShape: [1024], units: 128, activation: 'relu'}));
model.add(tf.layers.dense({units: CLASS_NAMES.length, activation: 'softmax'}));

model.summary();

// Compile the model with the defined optimizer and specify a loss function to use.
model.compile({
  // Adam changes the learning rate over time which is useful.
  optimizer: 'adam',
  // Use the correct loss function. If 2 classes of data, must use binaryCrossentropy.
  // Else categoricalCrossentropy is used if more than 2 classes.
  loss: (CLASS_NAMES.length === 2) ? 'binaryCrossentropy': 'categoricalCrossentropy', 
  // As this is a classification problem you can record accuracy in the logs too!
  metrics: ['accuracy']  
});

Mari kita pelajari kode ini. Anda mulai dengan menentukan model tf.Sequence tempat Anda akan menambahkan lapisan model.

Selanjutnya, tambahkan lapisan padat sebagai lapisan input ke model ini. Aplikasi ini memiliki bentuk input 1024 karena output dari fitur MobileNet v3 berukuran sebesar ini. Anda menemukan ini pada langkah sebelumnya setelah meneruskan yang melalui model. Lapisan ini memiliki 128 neuron yang menggunakan fungsi aktivasi ULT.

Jika Anda baru mengenal fungsi aktivasi dan lapisan model, pertimbangkan untuk mengikuti kursus yang dijelaskan di awal workshop ini untuk memahami fungsi properti ini di balik layar.

Lapisan berikutnya yang akan ditambahkan adalah lapisan output. Jumlah neuron harus sama dengan jumlah kelas yang ingin Anda prediksi. Untuk melakukannya, Anda dapat menggunakan CLASS_NAMES.length untuk menemukan jumlah class yang ingin diklasifikasikan, yang sama dengan jumlah tombol pengumpulan data yang ditemukan di antarmuka pengguna. Karena ini adalah masalah klasifikasi, Anda menggunakan aktivasi softmax pada lapisan output ini, yang harus digunakan saat mencoba membuat model untuk menyelesaikan masalah klasifikasi, bukan regresi.

Sekarang cetak model.summary() untuk mencetak ringkasan model yang baru ditentukan ke konsol.

Terakhir, kompilasi model agar siap untuk dilatih. Di sini, pengoptimal ditetapkan ke adam, dan kerugiannya akan menjadi binaryCrossentropy jika CLASS_NAMES.length sama dengan 2, atau pengoptimal akan menggunakan categoricalCrossentropy jika ada 3 class atau lebih untuk diklasifikasikan. Metrik akurasi juga diminta agar dapat dipantau di log nanti untuk tujuan proses debug.

Di konsol, Anda akan melihat yang seperti ini:

22eaf32286fea4bb.pngS

Perhatikan bahwa parameter ini memiliki lebih dari 130 ribu parameter yang dapat dilatih. Tetapi karena ini adalah lapisan padat sederhana dari neuron reguler, ia akan berlatih dengan cukup cepat.

Sebagai aktivitas yang harus dilakukan setelah proyek selesai, Anda dapat mencoba mengubah jumlah neuron di lapisan pertama untuk melihat seberapa rendah Anda bisa membuatnya sambil tetap mendapatkan kinerja yang layak. Sering kali, dengan machine learning, ada beberapa tahap uji coba untuk menemukan parameter value yang optimal agar dapat melakukan kompromi terbaik antara penggunaan dan kecepatan resource.

11. Aktifkan webcam

Sekarang saatnya untuk menyempurnakan fungsi enableCam() yang Anda tentukan sebelumnya. Tambahkan fungsi baru bernama hasGetUserMedia() seperti yang ditunjukkan di bawah, lalu ganti konten fungsi enableCam() yang telah ditentukan sebelumnya dengan kode yang sesuai di bawah.

script.js

function hasGetUserMedia() {
  return !!(navigator.mediaDevices && navigator.mediaDevices.getUserMedia);
}

function enableCam() {
  if (hasGetUserMedia()) {
    // getUsermedia parameters.
    const constraints = {
      video: true,
      width: 640, 
      height: 480 
    };

    // Activate the webcam stream.
    navigator.mediaDevices.getUserMedia(constraints).then(function(stream) {
      VIDEO.srcObject = stream;
      VIDEO.addEventListener('loadeddata', function() {
        videoPlaying = true;
        ENABLE_CAM_BUTTON.classList.add('removed');
      });
    });
  } else {
    console.warn('getUserMedia() is not supported by your browser');
  }
}

Pertama, buat fungsi bernama hasGetUserMedia() untuk memeriksa apakah browser mendukung getUserMedia() dengan memeriksa keberadaan properti API browser utama.

Dalam fungsi enableCam(), gunakan fungsi hasGetUserMedia() yang baru saja Anda tentukan di atas untuk memeriksa apakah fungsi tersebut didukung. Jika tidak, cetak peringatan ke konsol.

Jika mendukung, tentukan beberapa batasan untuk panggilan getUserMedia(), misalnya Anda hanya ingin streaming video, dan Anda lebih memilih width video berukuran 640 piksel, dan height berukuran 480 piksel. Mengapa? Yah, tidak ada gunanya membuat video yang lebih besar dari ini karena perlu diubah ukurannya menjadi 224 x 224 piksel untuk dimasukkan ke dalam model MobileNet. Anda juga dapat menghemat beberapa resource komputasi dengan meminta resolusi yang lebih kecil. Sebagian besar kamera mendukung resolusi ukuran ini.

Selanjutnya, panggil navigator.mediaDevices.getUserMedia() dengan constraints yang dijelaskan di atas, lalu tunggu hingga stream ditampilkan. Setelah stream ditampilkan, Anda bisa mendapatkan elemen VIDEO untuk memutar stream dengan menyetelnya sebagai nilai srcObject.

Anda juga harus menambahkan eventListener pada elemen VIDEO untuk mengetahui kapan stream telah dimuat dan berhasil diputar.

Setelah proses dimuat, Anda dapat menetapkan videoPlaying ke benar (true) dan menghapus ENABLE_CAM_BUTTON agar tidak diklik lagi dengan menetapkan class-nya ke "removed".

Sekarang jalankan kode Anda, klik tombol aktifkan kamera, dan izinkan akses ke webcam. Jika ini pertama kalinya Anda melakukannya, Anda akan melihat diri Anda dirender ke elemen video di halaman seperti yang ditunjukkan:

b378eb1affa9b883.png

Oke, sekarang saatnya menambahkan fungsi untuk menangani klik tombol dataCollector.

12. Pengendali peristiwa tombol pengumpulan data

Sekarang saatnya mengisi fungsi Anda yang saat ini kosong bernama gatherDataForClass(). Inilah yang Anda tetapkan sebagai fungsi pengendali peristiwa untuk tombol dataCollector di awal codelab.

script.js

/**
 * Handle Data Gather for button mouseup/mousedown.
 **/
function gatherDataForClass() {
  let classNumber = parseInt(this.getAttribute('data-1hot'));
  gatherDataState = (gatherDataState === STOP_DATA_GATHER) ? classNumber : STOP_DATA_GATHER;
  dataGatherLoop();
}

Pertama, periksa atribut data-1hot pada tombol yang saat ini diklik dengan memanggil this.getAttribute() bersama nama atribut, dalam hal ini data-1hot sebagai parameter. Karena ini adalah string, Anda kemudian dapat menggunakan parseInt() untuk mentransmisikannya menjadi bilangan bulat dan menetapkan hasil ini ke variabel bernama classNumber.

Selanjutnya, tetapkan variabel gatherDataState sebagaimana mestinya. Jika gatherDataState saat ini sama dengan STOP_DATA_GATHER (yang Anda tetapkan menjadi -1), berarti saat ini Anda tidak mengumpulkan data apa pun dan itu adalah peristiwa mousedown yang diaktifkan. Setel gatherDataState menjadi classNumber yang baru saja Anda temukan.

Jika tidak, artinya Anda sedang mengumpulkan data dan peristiwa yang diaktifkan adalah peristiwa mouseup, dan Anda sekarang ingin berhenti mengumpulkan data untuk class tersebut. Cukup setel kembali ke status STOP_DATA_GATHER untuk mengakhiri loop pengumpulan data yang akan segera Anda tentukan.

Terakhir, mulai panggilan ke dataGatherLoop(), yang akan benar-benar melakukan perekaman data class.

13. Pengumpulan data

Sekarang, tentukan fungsi dataGatherLoop(). Fungsi ini bertanggung jawab untuk mengambil sampel gambar dari video webcam, meneruskannya melalui model MobileNet, dan menangkap output dari model tersebut (vektor fitur 1024).

Kemudian, kode tersebut menyimpannya bersama dengan ID gatherDataState tombol yang sedang ditekan sehingga Anda mengetahui class yang diwakili oleh data ini.

Mari kita pelajari:

script.js

function dataGatherLoop() {
  if (videoPlaying && gatherDataState !== STOP_DATA_GATHER) {
    let imageFeatures = tf.tidy(function() {
      let videoFrameAsTensor = tf.browser.fromPixels(VIDEO);
      let resizedTensorFrame = tf.image.resizeBilinear(videoFrameAsTensor, [MOBILE_NET_INPUT_HEIGHT, 
          MOBILE_NET_INPUT_WIDTH], true);
      let normalizedTensorFrame = resizedTensorFrame.div(255);
      return mobilenet.predict(normalizedTensorFrame.expandDims()).squeeze();
    });

    trainingDataInputs.push(imageFeatures);
    trainingDataOutputs.push(gatherDataState);
    
    // Intialize array index element if currently undefined.
    if (examplesCount[gatherDataState] === undefined) {
      examplesCount[gatherDataState] = 0;
    }
    examplesCount[gatherDataState]++;

    STATUS.innerText = '';
    for (let n = 0; n < CLASS_NAMES.length; n++) {
      STATUS.innerText += CLASS_NAMES[n] + ' data count: ' + examplesCount[n] + '. ';
    }
    window.requestAnimationFrame(dataGatherLoop);
  }
}

Anda hanya akan melanjutkan eksekusi fungsi ini jika videoPlaying bernilai benar (true), yang berarti webcam aktif, dan gatherDataState tidak sama dengan STOP_DATA_GATHER serta tombol untuk pengumpulan data class saat ini sedang ditekan.

Selanjutnya, gabungkan kode Anda dalam tf.tidy() untuk membuang tensor yang dibuat dalam kode berikutnya. Hasil eksekusi kode tf.tidy() ini disimpan dalam variabel bernama imageFeatures.

Anda kini dapat mengambil frame webcam VIDEO menggunakan tf.browser.fromPixels(). Tensor yang dihasilkan yang berisi data gambar disimpan dalam variabel bernama videoFrameAsTensor.

Selanjutnya, ubah ukuran variabel videoFrameAsTensor menjadi bentuk yang benar untuk input model MobileNet. Gunakan panggilan tf.image.resizeBilinear() dengan tensor yang ingin Anda bentuk ulang sebagai parameter pertama, lalu bentuk yang menentukan tinggi dan lebar baru seperti yang ditentukan oleh konstanta yang telah Anda buat sebelumnya. Terakhir, setel sudut sejajar ke benar (true) dengan meneruskan parameter ketiga untuk menghindari masalah perataan saat mengubah ukuran. Hasil perubahan ukuran ini disimpan dalam variabel bernama resizedTensorFrame.

Perhatikan bahwa perubahan ukuran primitif ini merentangkan gambar, karena gambar webcam Anda berukuran 640 x 480 piksel, dan model memerlukan gambar persegi 224 x 224 piksel.

Untuk tujuan demo ini, hal ini akan berfungsi dengan baik. Namun, setelah menyelesaikan codelab ini, Anda dapat mencoba dan memangkas sebuah persegi dari gambar ini guna mendapatkan hasil yang lebih baik lagi untuk sistem produksi yang mungkin Anda buat nanti.

Selanjutnya, normalkan data gambar. Data gambar selalu dalam rentang 0 hingga 255 saat menggunakan tf.browser.frompixels(), sehingga Anda dapat cukup membagi TensorFrame yang diubah ukurannya dengan 255 untuk memastikan semua nilai berada antara 0 dan 1, yang diharapkan oleh model MobileNet sebagai input.

Terakhir, di bagian tf.tidy() kode, kirim tensor yang dinormalisasi ini melalui model yang dimuat dengan memanggil mobilenet.predict(), tempat Anda meneruskan versi normalizedTensorFrame yang diperluas menggunakan expandDims() sehingga menjadi batch 1, karena model mengharapkan batch input untuk diproses.

Setelah hasilnya kembali, Anda kemudian dapat segera memanggil squeeze() pada hasil yang ditampilkan tersebut untuk memperkecil kembali ke tensor 1D, yang kemudian Anda tampilkan dan tetapkan ke variabel imageFeatures yang mengambil hasil dari tf.tidy().

Setelah memiliki imageFeatures dari model MobileNet, Anda dapat merekamnya dengan mendorongnya ke array trainingDataInputs yang telah ditentukan sebelumnya.

Anda juga dapat merekam apa yang diwakili input ini dengan mengirim gatherDataState saat ini ke array trainingDataOutputs juga.

Perhatikan bahwa variabel gatherDataState akan ditetapkan ke ID numerik class saat ini yang datanya Anda catat saat tombol diklik dalam fungsi gatherDataForClass() yang ditentukan sebelumnya.

Pada tahap ini, Anda juga dapat menambah jumlah contoh yang Anda miliki untuk class tertentu. Untuk melakukannya, periksa terlebih dahulu apakah indeks dalam array examplesCount telah diinisialisasi sebelumnya atau belum. Jika tidak ditentukan, tetapkan ke 0 untuk melakukan inisialisasi penghitung untuk ID numerik class tertentu, lalu Anda dapat menambahkan examplesCount untuk gatherDataState saat ini.

Sekarang, perbarui teks elemen STATUS di halaman web guna menampilkan jumlah saat ini untuk setiap class saat diambil. Untuk melakukannya, lakukan loop melalui array CLASS_NAMES, lalu cetak nama yang dapat dibaca manusia yang dikombinasikan dengan jumlah data pada indeks yang sama di examplesCount.

Terakhir, panggil window.requestAnimationFrame() dengan dataGatherLoop yang diteruskan sebagai parameter, untuk memanggil fungsi ini lagi secara rekursif. Tindakan ini akan terus mengambil sampel frame dari video hingga mouseup tombol terdeteksi, dan gatherDataState disetel ke STOP_DATA_GATHER, saat loop pengumpulan data akan berakhir.

Jika menjalankan kode sekarang, Anda seharusnya dapat mengklik tombol aktifkan kamera, menunggu webcam dimuat, lalu mengklik lama setiap tombol pengumpulan data guna mengumpulkan contoh untuk setiap class data. Di sini Anda melihat saya mengumpulkan data untuk ponsel dan tangan saya masing-masing.

541051644a45131f.gif

Anda akan melihat teks status diperbarui karena menyimpan semua tensor di memori seperti yang ditunjukkan pada screenshot di atas.

14. Latih dan prediksi

Langkah berikutnya adalah mengimplementasikan kode untuk fungsi trainAndPredict() Anda yang saat ini kosong, tempat pemelajaran transfer berlangsung. Mari kita lihat kodenya:

script.js

async function trainAndPredict() {
  predict = false;
  tf.util.shuffleCombo(trainingDataInputs, trainingDataOutputs);
  let outputsAsTensor = tf.tensor1d(trainingDataOutputs, 'int32');
  let oneHotOutputs = tf.oneHot(outputsAsTensor, CLASS_NAMES.length);
  let inputsAsTensor = tf.stack(trainingDataInputs);
  
  let results = await model.fit(inputsAsTensor, oneHotOutputs, {shuffle: true, batchSize: 5, epochs: 10, 
      callbacks: {onEpochEnd: logProgress} });
  
  outputsAsTensor.dispose();
  oneHotOutputs.dispose();
  inputsAsTensor.dispose();
  predict = true;
  predictLoop();
}

function logProgress(epoch, logs) {
  console.log('Data for epoch ' + epoch, logs);
}

Pertama, pastikan Anda menghentikan terjadinya prediksi saat ini dengan menetapkan predict ke false.

Selanjutnya, acak array input dan output Anda menggunakan tf.util.shuffleCombo() untuk memastikan urutan tidak menyebabkan masalah dalam pelatihan.

Konversi array output Anda, trainingDataOutputs, menjadi tensor1d jenis int32 sehingga siap digunakan dalam enkode one-hot. Data ini disimpan dalam variabel bernama outputsAsTensor.

Gunakan fungsi tf.oneHot() dengan variabel outputsAsTensor ini beserta jumlah maksimum class yang akan dienkode, yang hanyalah CLASS_NAMES.length. Satu output hot encode Anda sekarang disimpan di tensor baru yang disebut oneHotOutputs.

Perhatikan bahwa saat ini trainingDataInputs adalah array tensor yang direkam. Agar dapat menggunakannya untuk pelatihan, Anda perlu mengonversi array tensor menjadi tensor 2D biasa.

Untuk melakukannya, ada fungsi bagus dalam library TensorFlow.js yang disebut tf.stack(),

yang mengambil array tensor dan menumpuk mereka bersama-sama untuk menghasilkan tensor dimensi yang lebih tinggi sebagai output. Dalam hal ini tensor 2D yang ditampilkan, yaitu batch 1 input dimensi yang panjangnya 1024 berisi fitur yang direkam, yang Anda butuhkan untuk pelatihan.

Selanjutnya, await model.fit() untuk melatih head model kustom. Di sini, Anda meneruskan variabel inputsAsTensor bersama dengan oneHotOutputs untuk merepresentasikan data pelatihan yang akan digunakan masing-masing untuk contoh input dan output target. Di objek konfigurasi untuk parameter ke-3, setel shuffle ke true, gunakan batchSize dari 5, dengan epochs disetel ke 10, lalu tentukan callback untuk onEpochEnd ke fungsi logProgress yang akan segera Anda tentukan.

Terakhir, Anda dapat membuang tensor yang dibuat saat model dilatih. Anda kemudian dapat menyetel predict kembali ke true untuk mengizinkan prediksi terjadi lagi, lalu memanggil fungsi predictLoop() untuk mulai memprediksi gambar webcam live.

Anda juga dapat menentukan fungsi logProcess() untuk mencatat status pelatihan ke dalam log, yang digunakan dalam model.fit() di atas dan yang mencetak hasil ke konsol setelah setiap sesi pelatihan.

Sedikit lagi! Saatnya menambahkan fungsi predictLoop() untuk membuat prediksi.

Loop prediksi inti

Di sini Anda mengimplementasikan loop prediksi utama yang mengambil sampel frame dari webcam dan terus memprediksi apa yang ada di setiap frame dengan hasil real time di browser.

Mari kita periksa kodenya:

script.js

function predictLoop() {
  if (predict) {
    tf.tidy(function() {
      let videoFrameAsTensor = tf.browser.fromPixels(VIDEO).div(255);
      let resizedTensorFrame = tf.image.resizeBilinear(videoFrameAsTensor,[MOBILE_NET_INPUT_HEIGHT, 
          MOBILE_NET_INPUT_WIDTH], true);

      let imageFeatures = mobilenet.predict(resizedTensorFrame.expandDims());
      let prediction = model.predict(imageFeatures).squeeze();
      let highestIndex = prediction.argMax().arraySync();
      let predictionArray = prediction.arraySync();

      STATUS.innerText = 'Prediction: ' + CLASS_NAMES[highestIndex] + ' with ' + Math.floor(predictionArray[highestIndex] * 100) + '% confidence';
    });

    window.requestAnimationFrame(predictLoop);
  }
}

Pertama, pastikan predict benar, sehingga prediksi hanya dibuat setelah model dilatih dan tersedia untuk digunakan.

Selanjutnya, Anda bisa mendapatkan fitur gambar untuk gambar saat ini seperti yang Anda lakukan pada fungsi dataGatherLoop(). Pada dasarnya, Anda mengambil frame dari webcam menggunakan tf.browser.from pixels(), menormalkannya, mengubah ukurannya menjadi 224 x 224 piksel, lalu meneruskan data tersebut melalui model MobileNet untuk mendapatkan fitur gambar yang dihasilkan.

Namun, sekarang Anda dapat menggunakan head model yang baru dilatih untuk benar-benar melakukan prediksi dengan meneruskan imageFeatures yang dihasilkan yang baru saja ditemukan melalui fungsi predict() model yang dilatih. Kemudian, Anda dapat menyelipkan tensor yang dihasilkan untuk menjadikannya 1 dimensi lagi dan menetapkannya ke variabel yang disebut prediction.

Dengan prediction ini, Anda dapat menemukan indeks yang memiliki nilai tertinggi menggunakan argMax(), lalu mengonversi tensor yang dihasilkan ini menjadi array menggunakan arraySync() untuk mendapatkan data pokok di JavaScript guna menemukan posisi elemen bernilai tertinggi. Nilai ini disimpan dalam variabel bernama highestIndex.

Anda juga bisa mendapatkan skor keyakinan prediksi aktual dengan cara yang sama dengan memanggil arraySync() pada tensor prediction secara langsung.

Anda sekarang memiliki semua yang diperlukan untuk memperbarui teks STATUS dengan data prediction. Untuk mendapatkan string yang dapat dibaca manusia untuk class, Anda cukup mencari highestIndex dalam array CLASS_NAMES, lalu mengambil nilai keyakinan dari predictionArray. Agar lebih mudah dibaca dalam persentase, cukup kalikan dengan 100 dan hasilnya adalah math.floor().

Terakhir, Anda dapat menggunakan window.requestAnimationFrame() untuk memanggil predictionLoop() sekali lagi setelah siap, untuk mendapatkan klasifikasi secara real time di streaming video Anda. Proses ini berlanjut hingga predict ditetapkan ke false jika Anda memilih untuk melatih model baru dengan data baru.

Yang membawamu ke kepingan terakhir puzzle. Menerapkan tombol reset.

15. Mengimplementasikan tombol reset

Hampir selesai! Bagian terakhir dari teka-teki ini adalah menerapkan tombol reset untuk memulai dari awal. Kode untuk fungsi reset() Anda yang saat ini kosong ada di bawah. Lanjutkan dan perbarui seperti berikut:

script.js

/**
 * Purge data and start over. Note this does not dispose of the loaded 
 * MobileNet model and MLP head tensors as you will need to reuse 
 * them to train a new model.
 **/
function reset() {
  predict = false;
  examplesCount.length = 0;
  for (let i = 0; i < trainingDataInputs.length; i++) {
    trainingDataInputs[i].dispose();
  }
  trainingDataInputs.length = 0;
  trainingDataOutputs.length = 0;
  STATUS.innerText = 'No data collected';
  
  console.log('Tensors in memory: ' + tf.memory().numTensors);
}

Pertama, hentikan loop prediksi yang sedang berjalan dengan menetapkan predict ke false. Selanjutnya, hapus semua konten dalam array examplesCount dengan menetapkan panjangnya ke 0, yang merupakan cara praktis untuk menghapus semua konten dari array.

Sekarang periksa semua trainingDataInputs yang direkam saat ini dan pastikan Anda dispose() dari setiap tensor yang ada di dalamnya untuk mengosongkan memori lagi, karena Tensor tidak dibersihkan oleh pembersih sampah memori JavaScript.

Setelah selesai, Anda kini dapat dengan aman menetapkan panjang array ke 0 pada array trainingDataInputs dan trainingDataOutputs untuk menghapusnya juga.

Terakhir, setel teks STATUS ke nilai yang logis, dan cetak tensor yang tersisa di memori sebagai pemeriksaan kesehatan.

Perhatikan bahwa akan ada beberapa ratus tensor di memori karena model MobileNet dan perceptron multi-lapisan yang Anda tetapkan tidak dibuang. Anda harus menggunakannya kembali dengan data pelatihan baru jika Anda memutuskan untuk berlatih lagi setelah reset ini.

16. Mari kita coba

Saatnya menguji Teachable Machine versi Anda sendiri.

Buka pratinjau langsung, aktifkan webcam, kumpulkan setidaknya 30 sampel untuk kelas 1 untuk beberapa objek di ruangan Anda, lalu lakukan hal yang sama untuk kelas 2 untuk objek yang berbeda, klik melatih, dan periksa log konsol untuk melihat kemajuan. Prosesnya akan dilatih cukup cepat:

bf1ac3cc5b15740.gif

Setelah dilatih, tunjukkan objek ke kamera untuk mendapatkan prediksi langsung yang akan dicetak ke area teks status di halaman web dekat bagian atas. Jika Anda mengalami masalah, periksa kode kerja saya yang sudah selesai untuk melihat apakah Anda melewatkan penyalinan.

17. Selamat

Selamat! Anda baru saja menyelesaikan contoh pemelajaran transfer pertama Anda menggunakan TensorFlow.js secara live di browser.

Cobalah, uji pada berbagai objek, Anda mungkin melihat beberapa hal lebih sulit dikenali daripada yang lain, terutama jika mereka mirip dengan sesuatu yang lain. Anda mungkin perlu menambahkan lebih banyak kelas atau data pelatihan agar dapat membedakannya.

Rangkuman

Dalam codelab ini, Anda telah mempelajari:

  1. Pengertian pemelajaran transfer, dan keuntungannya dibandingkan melatih model lengkap.
  2. Cara mendapatkan model untuk digunakan kembali dari TensorFlow Hub.
  3. Cara menyiapkan aplikasi web yang sesuai untuk pemelajaran transfer.
  4. Cara memuat dan menggunakan model dasar untuk menghasilkan fitur gambar.
  5. Cara melatih head prediksi baru yang dapat mengenali objek kustom dari gambar webcam.
  6. Cara menggunakan model yang dihasilkan untuk mengklasifikasikan data secara real time.

Apa selanjutnya?

Setelah Anda memiliki dasar untuk memulai, ide kreatif apa yang dapat Anda pikirkan untuk mengembangkan boilerplate model machine learning ini untuk kasus penggunaan nyata yang mungkin sedang Anda kerjakan? Mungkin Anda bisa merevolusi industri tempat Anda bekerja saat ini untuk membantu orang-orang di perusahaan Anda melatih model agar dapat mengklasifikasikan hal-hal yang penting dalam pekerjaan mereka sehari-hari? Kemungkinannya tak terbatas.

Untuk lebih lanjut, pertimbangkan untuk mengikuti kursus lengkap ini secara gratis, yang menunjukkan cara menggabungkan 2 model yang saat ini Anda miliki dalam codelab ini ke dalam 1 model tunggal untuk efisiensi.

Selain itu, jika Anda ingin tahu lebih lanjut mengenai teori di balik aplikasi ajaran mesin asli, lihat tutorial ini.

Bagikan hal yang Anda buat dengan kami

Anda juga dapat dengan mudah memperluas apa yang Anda buat hari ini untuk kasus penggunaan kreatif lainnya dan kami mendorong Anda untuk berpikir kreatif dan terus meretas.

Jangan lupa untuk memberi tag pada kami di media sosial menggunakan hashtag #MadeWithTFJS agar project Anda berpeluang ditampilkan di blog TensorFlow atau bahkan acara mendatang. Kami ingin melihat apa yang Anda buat.

Situs yang bisa dilihat