1. Sebelum memulai
Penggunaan model TensorFlow.js telah meningkat secara eksponensial selama beberapa tahun terakhir dan banyak developer JavaScript kini ingin mengambil model canggih yang ada dan melatih ulang model tersebut agar berfungsi dengan data kustom yang unik untuk industri mereka. Tindakan menggunakan model yang ada (sering disebut sebagai model dasar), dan menggunakannya di domain yang serupa tetapi berbeda dikenal sebagai transfer learning.
Pemelajaran transfer memiliki banyak keunggulan dibandingkan memulai dari model yang benar-benar kosong. Anda dapat menggunakan kembali pengetahuan yang telah 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 terakhir arsitektur model, bukan seluruh jaringan. Oleh karena itu, transfer learning sangat cocok untuk lingkungan browser web yang sumber dayanya dapat bervariasi berdasarkan perangkat yang digunakan, tetapi juga memiliki akses langsung ke sensor untuk memudahkan akuisisi data.
Codelab ini menunjukkan cara membuat aplikasi web dari kanvas kosong, dengan membuat ulang situs " Teachable Machine" populer Google. Situs ini memungkinkan Anda membuat aplikasi web fungsional yang dapat digunakan pengguna mana pun untuk mengenali objek kustom hanya dengan beberapa contoh gambar dari webcam mereka. Situs sengaja dibuat minimal agar Anda dapat berfokus pada aspek Machine Learning dalam codelab ini. Namun, seperti situs Teachable Machine asli, ada banyak ruang lingkup untuk menerapkan pengalaman developer web yang sudah ada guna meningkatkan UX.
Prasyarat
Codelab ini ditulis untuk developer web yang sudah cukup memahami model siap pakai TensorFlow.js dan penggunaan API dasar, serta ingin mulai menggunakan transfer learning di TensorFlow.js.
- Pemahaman dasar tentang TensorFlow.js, HTML5, CSS, dan JavaScript diasumsikan untuk lab ini.
Jika Anda baru menggunakan TensorFlow.js, pertimbangkan untuk mengikuti kursus gratis ini dari nol hingga mahir terlebih dahulu, yang tidak mengasumsikan latar belakang Machine Learning atau TensorFlow.js, dan mengajarkan semua yang perlu Anda ketahui dalam langkah-langkah yang lebih kecil.
Yang akan Anda pelajari
- Pengertian TensorFlow.js dan alasan Anda harus menggunakannya di aplikasi web berikutnya.
- Cara membuat halaman web HTML/CSS /JS yang disederhanakan 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 multi-layer perceptron yang mengambil fitur gambar dan mempelajari cara mengklasifikasikan objek baru menggunakan fitur tersebut.
Mari kita mulai peretasan...
Yang Anda butuhkan
- Sebaiknya gunakan akun Glitch.com untuk mengikuti langkah-langkahnya, atau Anda dapat menggunakan lingkungan penayangan web yang nyaman untuk diedit dan dijalankan sendiri.
2. Apa itu TensorFlow.js?

TensorFlow.js adalah library machine learning open source yang dapat berjalan di mana pun JavaScript dapat berjalan. TensorFlow.js didasarkan pada library TensorFlow asli yang ditulis dalam Python dan bertujuan untuk menciptakan kembali pengalaman developer dan serangkaian API ini untuk ekosistem JavaScript.
Di mana visibilitas dapat digunakan?
Mengingat portabilitas JavaScript, kini Anda dapat menulis dalam 1 bahasa dan melakukan machine learning di semua platform berikut dengan mudah:
- Sisi klien di browser web menggunakan JavaScript vanilla
- Sisi server dan bahkan perangkat IoT seperti Raspberry Pi yang menggunakan Node.js
- Aplikasi desktop yang menggunakan Electron
- Aplikasi seluler native menggunakan React Native
TensorFlow.js juga mendukung beberapa backend dalam setiap lingkungan ini (lingkungan berbasis hardware aktual yang dapat dijalankannya seperti CPU atau WebGL). "Backend" dalam konteks ini tidak berarti lingkungan sisi server - backend untuk eksekusi bisa berupa sisi klien di WebGL misalnya) untuk memastikan kompatibilitas dan juga menjaga agar semuanya berjalan cepat. Saat ini, TensorFlow.js mendukung:
- Eksekusi WebGL di kartu grafis perangkat (GPU) - ini adalah cara tercepat untuk mengeksekusi model yang lebih besar (berukuran lebih dari 3 MB) dengan akselerasi GPU.
- Eksekusi Web Assembly (WASM) di CPU - untuk meningkatkan performa CPU di seluruh perangkat, termasuk ponsel generasi lama. Hal ini lebih cocok untuk model yang lebih kecil (berukuran kurang dari 3 MB) yang sebenarnya dapat dieksekusi lebih cepat di 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 tersedia untuk Anda.
Catatan: Anda dapat memilih untuk memaksa salah satu backend ini jika Anda mengetahui perangkat yang akan Anda gunakan untuk menjalankan kode, atau Anda cukup membiarkan TensorFlow.js memutuskan untuk Anda jika Anda tidak menentukannya.
Kemampuan super sisi klien
Menjalankan TensorFlow.js di browser web pada perangkat klien dapat memberikan beberapa manfaat yang patut dipertimbangkan.
Privasi
Anda dapat melatih dan mengklasifikasikan data di mesin klien tanpa pernah mengirim data ke server web pihak ketiga. Terkadang, hal ini mungkin menjadi persyaratan untuk mematuhi hukum setempat, seperti GDPR misalnya, atau saat memproses data apa pun yang mungkin ingin disimpan pengguna di perangkatnya dan tidak dikirim ke pihak ketiga.
Kecepatan
Karena Anda tidak perlu mengirim data ke server jarak jauh, inferensi (tindakan mengklasifikasikan data) dapat dilakukan lebih cepat. Lebih baik 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 dunia dapat mengklik link yang Anda kirimkan, membuka halaman web di browser mereka, dan memanfaatkan apa yang telah Anda buat. Anda tidak memerlukan penyiapan Linux sisi server yang rumit dengan driver CUDA dan banyak lagi hanya untuk menggunakan sistem machine learning.
Biaya
Tanpa server berarti satu-satunya yang perlu Anda bayar adalah CDN untuk menghosting file HTML, CSS, JS, dan model Anda. Biaya CDN jauh lebih murah daripada menjalankan server (yang berpotensi memiliki kartu grafis terpasang) 24/7.
Fitur sisi server
Memanfaatkan implementasi Node.js dari TensorFlow.js memungkinkan fitur berikut.
Dukungan CUDA penuh
Di sisi server, untuk akselerasi kartu grafis, Anda harus menginstal driver NVIDIA CUDA agar TensorFlow dapat berfungsi dengan kartu grafis (tidak seperti di browser yang menggunakan WebGL - tidak perlu penginstalan). Namun, dengan dukungan CUDA penuh, Anda dapat memanfaatkan kemampuan tingkat bawah kartu grafis sepenuhnya, sehingga menghasilkan waktu pelatihan dan inferensi yang lebih cepat. Performa setara dengan implementasi Python TensorFlow karena keduanya menggunakan backend C++ yang sama.
Ukuran Model
Untuk model canggih dari penelitian, Anda mungkin bekerja dengan model yang sangat besar, mungkin berukuran gigabyte. Model ini saat ini tidak dapat dijalankan di browser web karena batasan penggunaan memori per tab browser. Untuk menjalankan model yang lebih besar ini, Anda dapat menggunakan Node.js di server Anda sendiri dengan spesifikasi hardware yang diperlukan untuk menjalankan model tersebut secara efisien.
IOT
Node.js didukung di komputer papan tunggal populer seperti Raspberry Pi, yang berarti Anda juga dapat menjalankan model TensorFlow.js di perangkat tersebut.
Kecepatan
Node.js ditulis dalam JavaScript yang berarti Node.js diuntungkan dari kompilasi tepat waktu. Artinya, Anda mungkin sering melihat peningkatan performa saat menggunakan Node.js karena akan dioptimalkan saat runtime, terutama untuk pra-pemrosesan yang mungkin Anda lakukan. Contoh yang bagus tentang hal ini dapat dilihat dalam studi kasus ini yang menunjukkan cara Hugging Face menggunakan Node.js untuk mendapatkan peningkatan performa 2x untuk model pemrosesan bahasa alami mereka.
Sekarang Anda telah memahami dasar-dasar TensorFlow.js, tempat TensorFlow.js dapat berjalan, dan beberapa manfaatnya. Mari kita mulai melakukan hal-hal yang berguna dengannya.
3. Pemelajaran transfer
Apa sebenarnya yang dimaksud dengan transfer learning?
Transfer learning melibatkan pengambilan pengetahuan yang telah dipelajari untuk membantu mempelajari hal lain yang berbeda tetapi serupa.
Kita manusia melakukannya sepanjang waktu. Anda memiliki pengalaman seumur hidup yang tersimpan di otak yang dapat Anda gunakan untuk membantu mengenali hal-hal baru yang belum pernah Anda lihat sebelumnya. Misalnya, pohon willow ini:

Bergantung pada lokasi Anda di dunia, ada kemungkinan Anda belum pernah melihat jenis pohon ini sebelumnya.
Namun, jika saya meminta Anda untuk memberi tahu saya apakah ada pohon willow dalam gambar baru di bawah, Anda mungkin dapat melihatnya dengan cukup cepat, meskipun berada pada sudut yang berbeda, dan sedikit berbeda dengan yang asli yang saya tunjukkan kepada Anda.

Anda sudah memiliki banyak neuron di otak 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 willow dengan cepat, yang merupakan objek seperti pohon yang memiliki banyak cabang vertikal lurus panjang.
Demikian pula, jika Anda memiliki model machine learning yang sudah dilatih di suatu domain, seperti mengenali gambar, Anda dapat menggunakannya kembali untuk melakukan tugas lain yang terkait.
Anda dapat melakukan hal yang sama dengan model canggih seperti MobileNet, yang merupakan model penelitian yang sangat populer dan dapat melakukan pengenalan gambar pada 1.000 jenis objek yang berbeda. Dari hingga mobil, model ini dilatih menggunakan set data besar yang dikenal sebagai ImageNet yang memiliki jutaan gambar berlabel.
Dalam animasi ini, Anda dapat melihat banyaknya lapisan yang dimiliki model MobileNet V1 ini:

Selama pelatihannya, model ini mempelajari cara mengekstrak fitur umum yang penting untuk semua 1.000 objek tersebut, dan banyak fitur tingkat bawah yang digunakannya untuk mengidentifikasi objek tersebut juga dapat berguna untuk mendeteksi objek baru yang belum pernah dilihatnya. Bagaimanapun, pada akhirnya semuanya hanyalah kombinasi garis, tekstur, dan bentuk.
Mari kita lihat arsitektur Jaringan Neural Konvolusional (CNN) tradisional (mirip dengan MobileNet) dan lihat bagaimana transfer learning dapat memanfaatkan jaringan terlatih ini untuk mempelajari sesuatu yang baru. Gambar di bawah menunjukkan arsitektur model umum CNN yang dalam kasus ini dilatih untuk mengenali digit tulisan tangan dari 0 hingga 9:

Jika Anda dapat memisahkan lapisan tingkat bawah yang telah dilatih sebelumnya dari model terlatih yang ada seperti yang ditunjukkan di sebelah kiri, dari lapisan klasifikasi di dekat akhir model yang ditunjukkan di sebelah kanan (terkadang disebut sebagai head klasifikasi model), Anda dapat menggunakan lapisan tingkat bawah untuk menghasilkan fitur output untuk gambar tertentu berdasarkan data asli yang digunakan untuk melatihnya. Berikut jaringan yang sama dengan head klasifikasi yang dihapus:

Dengan asumsi bahwa hal baru yang Anda coba kenali juga dapat menggunakan fitur output yang telah dipelajari model sebelumnya, ada kemungkinan besar fitur tersebut dapat digunakan kembali untuk tujuan baru.
Dalam diagram di atas, model hipotetis ini dilatih dengan angka, sehingga 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:

Di sini, lapisan tingkat bawah dibekukan dan tidak dilatih, hanya head klasifikasi baru yang akan memperbarui dirinya sendiri untuk mempelajari fitur yang disediakan dari model yang telah dilatih sebelumnya di sebelah kiri.
Tindakan ini dikenal sebagai transfer learning dan merupakan hal yang dilakukan Teachable Machine di balik layar.
Anda juga dapat melihat bahwa dengan hanya melatih perceptron multi-layer di bagian paling akhir jaringan, pelatihan akan jauh lebih cepat daripada jika Anda harus melatih seluruh jaringan dari awal.
Namun, bagaimana cara mendapatkan sub-bagian model? Buka bagian berikutnya untuk mengetahuinya.
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 hub TensorFlow, lalu memfilter model yang cocok untuk TensorFlow.js yang menggunakan arsitektur MobileNet v3 untuk menemukan hasil seperti yang ditunjukkan di sini:

Perhatikan bahwa beberapa hasil ini berjenis "klasifikasi gambar" (dijelaskan di kiri atas setiap hasil kartu model), dan yang lainnya berjenis "vektor fitur gambar".
Hasil Vektor Fitur Gambar ini pada dasarnya adalah versi MobileNet yang telah dipotong-potong 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 transfer learning dengan cara yang sama seperti yang ditunjukkan di bagian sebelumnya dengan menambahkan head klasifikasi baru dan melatihnya dengan data Anda sendiri.
Hal berikutnya yang perlu diperiksa adalah format TensorFlow.js yang digunakan untuk merilis model dasar tertentu yang diminati. Jika Anda membuka halaman untuk salah satu model MobileNet v3 vektor fitur ini, Anda dapat melihat dari dokumentasi JS bahwa model tersebut berbentuk model grafik berdasarkan cuplikan kode contoh dalam dokumentasi yang menggunakan tf.loadGraphModel().

Perlu juga diperhatikan bahwa jika Anda menemukan model dalam format lapisan, bukan format grafik, Anda dapat memilih lapisan mana yang akan dibekukan dan mana yang akan diaktifkan untuk pelatihan. Hal ini dapat sangat efektif 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 sebagian besar model TF Hub di-deploy sebagai model grafik. Untuk mempelajari lebih lanjut cara menggunakan model Layers, lihat kursus zero to hero TensorFlow.js.
Keunggulan pemelajaran transfer
Apa keuntungan menggunakan transfer learning dibandingkan dengan melatih seluruh arsitektur model dari awal?
Pertama, waktu pelatihan adalah keuntungan utama menggunakan pendekatan transfer learning karena Anda sudah memiliki model dasar terlatih untuk dikembangkan.
Kedua, Anda dapat lolos dengan menampilkan lebih sedikit contoh hal baru yang ingin Anda klasifikasikan karena pelatihan yang telah dilakukan.
Cara ini sangat bagus jika Anda memiliki waktu dan sumber daya terbatas untuk mengumpulkan data contoh dari hal yang ingin Anda klasifikasikan, dan perlu membuat prototipe dengan cepat sebelum mengumpulkan lebih banyak data pelatihan untuk membuatnya lebih andal.
Mengingat kebutuhan akan lebih sedikit data dan kecepatan pelatihan jaringan yang lebih kecil, transfer learning tidak terlalu intensif dalam penggunaan resource. Hal ini menjadikannya sangat cocok untuk lingkungan browser, hanya memerlukan waktu puluhan detik di komputer modern, bukan berjam-jam, berhari-hari, atau berminggu-minggu untuk pelatihan model lengkap.
Oke! Sekarang Anda telah mengetahui esensi Pemelajaran Transfer, saatnya membuat versi Teachable Machine Anda sendiri. Mari kita mulai!
5. Menyiapkan kode
Yang Anda butuhkan
- Browser web modern.
- Pengetahuan dasar tentang HTML, CSS, JavaScript, dan Chrome DevTools (melihat output konsol).
Mari kita mulai coding
Template boilerplate untuk memulai telah dibuat untuk Glitch.com atau Codepen.io. Anda cukup meng-clone salah satu template sebagai status dasar untuk codelab ini, hanya dengan sekali klik.
Di Glitch, klik tombol "remix this" untuk membuat fork dan membuat kumpulan file baru yang dapat Anda edit.
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 di 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 editor web pilihan Anda atau kerjakan secara lokal
Jika Anda ingin mendownload kode dan mengerjakannya secara lokal, atau di editor online yang berbeda, cukup buat 3 file yang disebutkan di atas dalam direktori yang sama, lalu salin dan tempel kode dari boilerplate Glitch kami ke setiap file tersebut.
6. Boilerplate HTML aplikasi
Dari mana saya harus memulai?
Semua prototipe memerlukan beberapa struktur 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 menahan feed webcam setelah siap.
- Beberapa tombol untuk memulai kamera, mengumpulkan data, atau mereset pengalaman.
- Impor untuk file TensorFlow.js dan JS yang akan Anda tulis kodenya nanti.
Buka index.html dan ganti 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 & 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>
Uraikan
Mari kita uraikan beberapa kode HTML di atas untuk menandai beberapa hal penting yang Anda tambahkan.
- Anda menambahkan tag
<h1>untuk judul halaman bersama dengan tag<p>dengan ID 'status', yang merupakan tempat Anda akan mencetak informasi, saat Anda menggunakan berbagai bagian sistem untuk melihat output. - Anda menambahkan elemen
<video>dengan ID 'webcam', yang akan Anda gunakan untuk merender streaming webcam nanti. - Anda menambahkan 5 elemen
<button>. Yang pertama, dengan ID 'enableCam', mengaktifkan kamera. Dua tombol berikutnya memiliki class ‘dataCollector,' yang memungkinkan Anda mengumpulkan contoh gambar untuk objek yang ingin Anda kenali. Kode yang Anda tulis nanti akan dirancang sehingga Anda dapat menambahkan sejumlah tombol ini dan tombol tersebut akan berfungsi secara otomatis seperti yang diinginkan.
Perhatikan bahwa tombol ini juga memiliki atribut khusus yang ditentukan pengguna bernama data-1hot, dengan nilai bilangan bulat yang dimulai dari 0 untuk class pertama. Ini adalah indeks numerik yang akan Anda gunakan untuk merepresentasikan data kelas tertentu. Indeks akan digunakan untuk mengenkode class output dengan benar menggunakan representasi numerik, bukan string, karena model ML hanya dapat bekerja dengan angka.
Ada juga atribut data-name yang berisi nama yang mudah dibaca yang ingin Anda gunakan untuk class ini, yang memungkinkan Anda memberikan nama yang lebih bermakna kepada pengguna, bukan nilai indeks numerik dari encoding 1 hot.
Terakhir, Anda memiliki tombol latih dan reset untuk memulai proses pelatihan setelah data dikumpulkan, atau untuk mereset aplikasi.
- Anda juga menambahkan 2 impor
<script>. Satu untuk TensorFlow.js, dan satu lagi untuk script.js yang akan Anda tentukan sebentar lagi.
7. Tambah gaya
Default elemen
Tambahkan gaya untuk elemen HTML yang baru saja Anda tambahkan untuk memastikan elemen tersebut dirender dengan benar. Berikut beberapa gaya yang ditambahkan untuk memosisikan dan mengukur elemen dengan benar. Tidak ada yang terlalu istimewa. Anda tentu dapat menambahkannya nanti untuk membuat UX yang lebih baik, seperti yang Anda lihat dalam video teachable machine.
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, output tersebut akan terlihat seperti ini:

8. JavaScript: Konstanta dan pemroses tombol
Menentukan konstanta utama
Pertama, tambahkan beberapa konstanta utama yang akan Anda gunakan di seluruh aplikasi. Mulai dengan mengganti konten script.js dengan konstanta berikut:
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:
STATUShanya menyimpan referensi ke tag paragraf yang akan Anda gunakan untuk menulis info terbaru tentang status.VIDEOmenyimpan referensi ke elemen video HTML yang akan merender feed webcam.ENABLE_CAM_BUTTON,RESET_BUTTON, danTRAIN_BUTTONmengambil referensi DOM ke semua tombol utama dari halaman HTML.MOBILE_NET_INPUT_WIDTHdanMOBILE_NET_INPUT_HEIGHTmasing-masing menentukan lebar dan tinggi input yang diharapkan dari model MobileNet. Dengan menyimpannya dalam konstanta di dekat bagian atas file seperti ini, jika Anda memutuskan untuk menggunakan versi yang berbeda nanti, Anda dapat memperbarui nilai dengan lebih mudah, yaitu cukup sekali, bukan menggantinya di banyak tempat yang berbeda.STOP_DATA_GATHERdisetel ke -1. Ini menyimpan nilai status sehingga Anda tahu kapan pengguna berhenti mengklik tombol untuk mengumpulkan data dari feed webcam. Dengan memberikan nama yang lebih bermakna pada angka ini, kode akan lebih mudah dibaca di kemudian hari.CLASS_NAMESbertindak sebagai pencarian dan menyimpan nama yang dapat dibaca manusia untuk kemungkinan prediksi kelas. Array ini akan diisi nanti.
Oke, setelah Anda memiliki referensi ke elemen utama, saatnya mengaitkan beberapa pemroses peristiwa dengannya.
Menambahkan pemroses peristiwa utama
Mulai dengan menambahkan pengendali peristiwa klik ke tombol utama seperti yang ditunjukkan:
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 - memanggil reset 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:
Kemudian, Anda melakukan iterasi pada tombol yang ditemukan dan mengaitkan 2 pemroses peristiwa ke setiap tombol. Satu untuk ‘mousedown’, dan satu 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 mengirimkan nama class yang dapat dibaca manusia yang ditemukan dari atribut tombol HTML data-name 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 bahas satu per satu.
Pertama, Anda memiliki variabel mobilenet untuk menyimpan model mobilenet yang dimuat. Awalnya, tetapkan nilai ini ke undefined.
Selanjutnya, Anda memiliki variabel bernama gatherDataState. Jika tombol 'dataCollector' ditekan, tombol ini akan berubah menjadi ID hot 1 dari tombol tersebut, sebagaimana ditentukan dalam HTML, sehingga Anda mengetahui class data yang Anda kumpulkan pada saat itu. Awalnya, 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 ditetapkan ke false karena webcam tidak aktif hingga Anda menekan ENABLE_CAM_BUTTON.
Selanjutnya, tentukan 2 array, trainingDataInputs dan trainingDataOutputs. Ini menyimpan nilai data pelatihan yang dikumpulkan, saat Anda mengklik tombol 'dataCollector' untuk fitur input yang dihasilkan oleh model dasar MobileNet, dan kelas output yang diambil sampelnya masing-masing.
Array terakhir, examplesCount,, kemudian ditentukan untuk melacak jumlah contoh yang ada untuk setiap class setelah Anda mulai menambahkannya.
Terakhir, Anda memiliki variabel bernama predict yang mengontrol loop prediksi Anda. Nilai ini awalnya ditetapkan ke false. Prediksi tidak dapat dilakukan hingga setelan ini diubah menjadi true nanti.
Setelah semua variabel utama ditentukan, mari kita muat model dasar MobileNet v3 yang telah dipotong-potong yang menyediakan vektor fitur gambar, bukan klasifikasi.
9. Memuat model dasar MobileNet
Pertama, tentukan fungsi baru bernama loadMobileNetFeatureModel seperti yang ditunjukkan di bawah. Ini harus berupa fungsi asinkron karena tindakan memuat 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.
Kemudian, Anda dapat memuat model menggunakan await tf.loadGraphModel(), dengan mengingat untuk menyetel properti khusus fromTFHub ke true saat Anda memuat model dari situs Google ini. Ini adalah kasus khusus hanya untuk menggunakan model yang dihosting di TF Hub yang mengharuskan properti tambahan ini ditetapkan.
Setelah pemuatan selesai, Anda dapat menyetel innerText elemen STATUS dengan pesan sehingga Anda dapat melihat secara visual bahwa pemuatan telah dilakukan dengan benar dan Anda siap untuk mulai mengumpulkan data.
Satu-satunya hal yang perlu dilakukan sekarang adalah memanaskan model. Dengan model yang lebih besar seperti ini, saat pertama kali Anda menggunakan model, penyiapan semuanya dapat memerlukan waktu beberapa saat. Oleh karena itu, meneruskan nol melalui model akan membantu menghindari penantian di masa mendatang saat pengaturan waktu mungkin lebih penting.
Anda dapat menggunakan tf.zeros() yang di-wrap dalam tf.tidy() untuk memastikan tensor dibuang dengan benar, dengan ukuran batch 1, dan tinggi serta lebar yang benar yang Anda tentukan 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 dapat langsung memanggilnya untuk memulai download model saat halaman dimuat.
Jika Anda melihat pratinjau langsung sekarang, setelah beberapa saat Anda akan melihat teks status berubah dari "Menunggu pemuatan TF.js" menjadi "MobileNet v3 berhasil dimuat!" seperti yang ditunjukkan di bawah. Pastikan ini berfungsi sebelum melanjutkan.

Anda juga dapat memeriksa output konsol untuk melihat ukuran cetak fitur output yang dihasilkan model ini. Setelah menjalankan nol melalui model MobileNet, Anda akan melihat bentuk [1, 1024] dicetak. Item pertama hanyalah ukuran batch 1, dan Anda dapat melihat bahwa item tersebut benar-benar menampilkan 1.024 fitur yang kemudian dapat digunakan untuk membantu Anda mengklasifikasikan objek baru.
10. Menentukan head model baru
Sekarang saatnya menentukan head model, yang pada dasarnya adalah perceptron multi-layer 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 memulai dengan menentukan model tf.sequential yang akan ditambahi lapisan model.
Selanjutnya, tambahkan lapisan padat sebagai lapisan input ke model ini. Input ini memiliki bentuk 1024 karena output dari fitur MobileNet v3 berukuran ini. Anda menemukannya di langkah sebelumnya setelah meneruskan angka satu melalui model. Lapisan ini memiliki 128 neuron yang menggunakan fungsi aktivasi ReLU.
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 perlu ditambahkan adalah lapisan output. Jumlah neuron harus sama dengan jumlah kelas yang ingin Anda prediksi. Untuk melakukannya, Anda dapat menggunakan CLASS_NAMES.length untuk mengetahui jumlah kelas yang akan 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 dilatih. Di sini, pengoptimal disetel ke adam, dan kerugiannya akan menjadi binaryCrossentropy jika CLASS_NAMES.length sama dengan 2, atau akan menggunakan categoricalCrossentropy jika ada 3 kelas atau lebih yang akan diklasifikasikan. Metrik akurasi juga diminta sehingga dapat dipantau di log nanti untuk tujuan proses debug.
Di konsol, Anda akan melihat sesuatu seperti ini:

Perhatikan bahwa model ini memiliki lebih dari 130 ribu parameter yang dapat dilatih. Namun, karena ini adalah lapisan padat sederhana dari neuron reguler, pelatihan akan berjalan cukup cepat.
Sebagai aktivitas yang dapat dilakukan setelah project selesai, Anda dapat mencoba mengubah jumlah neuron di lapisan pertama untuk melihat seberapa rendah jumlahnya agar tetap mendapatkan performa yang layak. Sering kali dengan machine learning, ada beberapa tingkat uji coba untuk menemukan nilai parameter yang optimal guna memberikan kompromi terbaik antara penggunaan resource dan kecepatan.
11. Mengaktifkan webcam
Sekarang saatnya melengkapi fungsi enableCam() yang Anda tentukan sebelumnya. Tambahkan fungsi baru bernama hasGetUserMedia() seperti yang ditunjukkan di bawah, lalu ganti konten fungsi enableCam() yang 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 mendukungnya, tentukan beberapa batasan untuk panggilan getUserMedia() Anda, seperti Anda hanya menginginkan streaming video, dan Anda lebih memilih width video berukuran 640 piksel, dan height berukuran 480 piksel. Mengapa? Nah, tidak ada gunanya mendapatkan video yang lebih besar dari ini karena video tersebut harus diubah ukurannya menjadi 224 x 224 piksel agar dapat 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 dapat membuat elemen VIDEO memutar stream dengan menetapkannya sebagai nilai srcObject.
Anda juga harus menambahkan eventListener pada elemen VIDEO untuk mengetahui kapan stream telah dimuat dan diputar dengan berhasil.
Setelah uap dimuat, Anda dapat menyetel videoPlaying ke benar (true) dan menghapus ENABLE_CAM_BUTTON untuk mencegahnya diklik lagi dengan menyetel 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:

Oke, sekarang saatnya menambahkan fungsi untuk menangani klik tombol dataCollector.
12. Pengendali peristiwa tombol pengumpulan data
Sekarang saatnya mengisi fungsi 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() dengan nama atribut, dalam hal ini data-1hot sebagai parameter. Karena ini adalah string, Anda kemudian dapat menggunakan parseInt() untuk mentransmisikannya ke bilangan bulat dan menetapkan hasil ini ke variabel bernama classNumber.
Selanjutnya, tetapkan variabel gatherDataState dengan tepat. Jika gatherDataState saat ini sama dengan STOP_DATA_GATHER (yang Anda tetapkan menjadi -1), berarti Anda saat ini tidak mengumpulkan data apa pun dan peristiwa mousedown yang diaktifkan. Tetapkan gatherDataState menjadi classNumber yang baru saja Anda temukan.
Jika tidak, berarti Anda saat ini 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 Anda tentukan sebentar lagi.
Terakhir, mulai panggilan ke dataGatherLoop(), yang sebenarnya melakukan perekaman data kelas.
13. Pengumpulan data
Sekarang, tentukan fungsi dataGatherLoop(). Fungsi ini bertanggung jawab untuk mengambil sampel gambar dari video webcam, meneruskannya melalui model MobileNet, dan merekam output model tersebut (vektor fitur 1024).
Kemudian, data tersebut disimpan bersama dengan ID gatherDataState tombol yang sedang ditekan sehingga Anda mengetahui class yang diwakili 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 benar, yang berarti webcam aktif, dan gatherDataState tidak sama dengan STOP_DATA_GATHER dan tombol untuk pengumpulan data class sedang ditekan.
Selanjutnya, bungkus kode Anda dalam tf.tidy() untuk menghapus 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 agar memiliki bentuk yang benar untuk input model MobileNet. Gunakan panggilan tf.image.resizeBilinear() dengan tensor yang ingin Anda ubah bentuknya sebagai parameter pertama, lalu bentuk yang menentukan tinggi dan lebar baru seperti yang ditentukan oleh konstanta yang telah Anda buat sebelumnya. Terakhir, tetapkan selaraskan sudut ke benar dengan meneruskan parameter ketiga untuk menghindari masalah penyelarasan saat mengubah ukuran. Hasil pengubahan ukuran ini disimpan dalam variabel bernama resizedTensorFrame.
Perhatikan bahwa pengubahan ukuran primitif ini meregangkan gambar, karena gambar webcam Anda berukuran 640 x 480 piksel, dan model memerlukan gambar persegi berukuran 224 x 224 piksel.
Untuk tujuan demo ini, cara ini akan berfungsi dengan baik. Namun, setelah menyelesaikan codelab ini, Anda dapat mencoba memangkas persegi dari gambar ini untuk mendapatkan hasil yang lebih baik untuk sistem produksi yang mungkin Anda buat nanti.
Selanjutnya, normalisasi data gambar. Data gambar selalu berada dalam rentang 0 hingga 255 saat menggunakan tf.browser.frompixels(), jadi Anda cukup membagi resizedTensorFrame dengan 255 untuk memastikan semua nilai berada di antara 0 dan 1, yang merupakan input yang diharapkan oleh model MobileNet.
Terakhir, di bagian tf.tidy() kode, teruskan tensor yang dinormalisasi ini melalui model yang dimuat dengan memanggil mobilenet.predict(), yang Anda teruskan versi normalizedTensorFrame yang diperluas menggunakan expandDims() sehingga menjadi batch 1, karena model mengharapkan batch input untuk diproses.
Setelah hasilnya kembali, Anda dapat langsung memanggil squeeze() pada hasil yang ditampilkan tersebut untuk mengecilkannya kembali menjadi 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 Anda tentukan sebelumnya.
Anda juga dapat merekam apa yang diwakili oleh input ini dengan mendorong gatherDataState saat ini ke array trainingDataOutputs juga.
Perhatikan bahwa variabel gatherDataState akan ditetapkan ke ID numerik kelas saat ini yang datanya Anda rekam saat tombol diklik dalam fungsi gatherDataForClass() yang ditentukan sebelumnya.
Pada tahap ini, Anda juga dapat menambahkan jumlah contoh yang Anda miliki untuk class tertentu. Untuk melakukannya, periksa terlebih dahulu apakah indeks dalam array examplesCount telah diinisialisasi atau belum. Jika tidak ditentukan, tetapkan ke 0 untuk melakukan inisialisasi penghitung ID numerik kelas tertentu, lalu Anda dapat menaikkan examplesCount untuk gatherDataState saat ini.
Sekarang perbarui teks elemen STATUS di halaman web untuk menampilkan jumlah saat ini untuk setiap class saat diambil. Untuk melakukannya, lakukan loop pada array CLASS_NAMES, dan cetak nama yang mudah dibaca yang digabungkan 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. Hal ini akan terus mengambil sampel frame dari video hingga mouseup tombol terdeteksi, dan gatherDataState disetel ke STOP_DATA_GATHER,, yang akan mengakhiri loop pengumpulan data.
Jika menjalankan kode sekarang, Anda akan dapat mengklik tombol aktifkan kamera, menunggu webcam dimuat, lalu mengklik dan menahan setiap tombol pengumpulan data untuk mengumpulkan contoh bagi setiap class data. Di sini Anda melihat saya mengumpulkan data untuk ponsel dan tangan saya.

Anda akan melihat teks status diperbarui saat menyimpan semua tensor dalam memori seperti yang ditunjukkan pada rekaman layar di atas.
14. Latih dan prediksi
Langkah berikutnya adalah menerapkan kode untuk fungsi trainAndPredict() yang saat ini kosong, yaitu tempat transfer learning 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 prediksi saat ini dengan menyetel predict ke false.
Selanjutnya, acak array input dan output menggunakan tf.util.shuffleCombo() untuk memastikan urutannya tidak menyebabkan masalah dalam pelatihan.
Konversi array output, trainingDataOutputs,, menjadi tensor1d berjenis int32 agar siap digunakan dalam enkode one-hot. Nilai ini disimpan dalam variabel bernama outputsAsTensor.
Gunakan fungsi tf.oneHot() dengan variabel outputsAsTensor ini bersama dengan jumlah maksimum kelas yang akan dienkode, yaitu CLASS_NAMES.length. Output yang dienkode one-hot kini disimpan dalam tensor baru bernama oneHotOutputs.
Perhatikan bahwa saat ini trainingDataInputs adalah array tensor yang direkam. Untuk menggunakannya dalam pelatihan, Anda harus mengonversi array tensor menjadi tensor 2D reguler.
Untuk melakukannya, ada fungsi hebat dalam library TensorFlow.js yang disebut tf.stack(),
yang mengambil array tensor dan menumpuknya bersama-sama untuk menghasilkan tensor dimensi yang lebih tinggi sebagai output. Dalam hal ini, tensor 2D ditampilkan, yaitu batch input 1 dimensi yang masing-masing memiliki panjang 1024 yang berisi fitur yang direkam, yang Anda butuhkan untuk pelatihan.
Selanjutnya, await model.fit() untuk melatih kepala model kustom. Di sini, Anda meneruskan variabel inputsAsTensor bersama dengan oneHotOutputs untuk merepresentasikan data pelatihan yang akan digunakan untuk contoh input dan output target. Dalam objek konfigurasi untuk parameter ke-3, tetapkan shuffle ke true, gunakan batchSize dari 5, dengan epochs ditetapkan ke 10, lalu tentukan callback untuk onEpochEnd ke fungsi logProgress yang akan Anda tentukan sebentar lagi.
Terakhir, Anda dapat membuang tensor yang dibuat karena model kini telah dilatih. Kemudian, Anda dapat menyetel predict kembali ke true untuk mengizinkan prediksi dilakukan lagi, lalu memanggil fungsi predictLoop() untuk mulai memprediksi gambar webcam live.
Anda juga dapat menentukan fungsi logProcess() untuk mencatat status pelatihan, yang digunakan di model.fit() di atas dan yang mencetak hasil ke konsol setelah setiap putaran 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, periksa apakah predict benar, sehingga prediksi hanya dilakukan setelah model dilatih dan tersedia untuk digunakan.
Selanjutnya, Anda bisa mendapatkan fitur gambar untuk gambar saat ini seperti yang Anda lakukan di fungsi dataGatherLoop(). Pada dasarnya, Anda mengambil frame dari webcam menggunakan tf.browser.from pixels(), menormalisasinya, 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 kepala model yang baru dilatih untuk benar-benar melakukan prediksi dengan meneruskan imageFeatures yang dihasilkan melalui fungsi predict() model terlatih. Kemudian, Anda dapat memadatkan tensor yang dihasilkan untuk menjadikannya 1 dimensi lagi dan menetapkannya ke variabel bernama 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 sebenarnya dengan cara yang sama dengan memanggil arraySync() pada tensor prediction secara langsung.
Sekarang Anda memiliki semua yang diperlukan untuk memperbarui teks STATUS dengan data prediction. Untuk mendapatkan string yang dapat dibaca manusia untuk kelas, Anda cukup mencari highestIndex dalam array CLASS_NAMES, lalu mengambil nilai keyakinan dari predictionArray. Agar lebih mudah dibaca sebagai persentase, cukup kalikan dengan 100 dan math.floor() hasilnya.
Terakhir, Anda dapat menggunakan window.requestAnimationFrame() untuk memanggil predictionLoop() lagi setelah siap, untuk mendapatkan klasifikasi real time di streaming video Anda. Proses ini berlanjut hingga predict disetel ke false jika Anda memilih untuk melatih model baru dengan data baru.
Yang akan membawa Anda ke bagian terakhir teka-teki. Menerapkan tombol reset.
15. Menerapkan tombol reset
Hampir selesai! Kepingan 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 menyetel predict ke false. Selanjutnya, hapus semua konten dalam array examplesCount dengan menyetel 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() setiap tensor yang ada di dalamnya untuk mengosongkan memori lagi, karena Tensor tidak dibersihkan oleh pengumpul sampah JavaScript.
Setelah selesai, Anda dapat menyetel panjang array ke 0 dengan aman di array trainingDataInputs dan trainingDataOutputs untuk menghapusnya juga.
Terakhir, tetapkan teks STATUS ke sesuatu yang masuk akal, dan cetak tensor yang tersisa dalam memori sebagai pemeriksaan kewarasan.
Perhatikan bahwa akan ada beberapa ratus tensor yang masih ada dalam memori karena model MobileNet dan perceptron multi-layer yang Anda tentukan tidak dibuang. Anda harus menggunakannya kembali dengan data pelatihan baru jika Anda memutuskan untuk melatih ulang setelah reset ini.
16. Mari kita coba
Saatnya menguji versi Teachable Machine Anda sendiri.
Buka pratinjau live, aktifkan webcam, kumpulkan setidaknya 30 sampel untuk class 1 untuk beberapa objek di ruangan Anda, lalu lakukan hal yang sama untuk class 2 untuk objek yang berbeda, klik latih, dan periksa log konsol untuk melihat progres. Model akan dilatih dengan cukup cepat:

Setelah dilatih, tunjukkan objek ke kamera untuk mendapatkan prediksi langsung yang akan dicetak ke area teks status di halaman web di dekat bagian atas. Jika Anda mengalami masalah, periksa kode kerja yang telah selesai untuk melihat apakah ada yang terlewat saat menyalin.
17. Selamat
Selamat! Anda baru saja menyelesaikan contoh pemelajaran transfer pertama menggunakan TensorFlow.js secara langsung di browser.
Cobalah, uji pada berbagai objek, Anda mungkin melihat bahwa beberapa objek lebih sulit dikenali daripada yang lain, terutama jika objek tersebut mirip dengan objek lain. Anda mungkin perlu menambahkan lebih banyak kelas atau data pelatihan untuk dapat membedakannya.
Rangkuman
Dalam codelab ini, Anda telah mempelajari:
- Pengertian pemelajaran transfer, dan keunggulannya dibandingkan melatih model lengkap.
- Cara mendapatkan model untuk digunakan kembali dari TensorFlow Hub.
- Cara menyiapkan aplikasi web yang cocok untuk transfer learning.
- Cara memuat dan menggunakan model dasar untuk membuat fitur gambar.
- Cara melatih head prediksi baru yang dapat mengenali objek kustom dari gambar webcam.
- Cara menggunakan model yang dihasilkan untuk mengklasifikasikan data secara real time.
Apa selanjutnya?
Setelah Anda memiliki dasar untuk memulai, apa ide kreatif yang dapat Anda pikirkan untuk memperluas boilerplate model machine learning ini untuk kasus penggunaan dunia nyata yang mungkin sedang Anda kerjakan? Mungkin Anda dapat merevolusi industri tempat Anda bekerja saat ini untuk membantu orang-orang di perusahaan Anda melatih model guna mengklasifikasikan hal-hal yang penting dalam pekerjaan sehari-hari mereka? Kemungkinannya tak terbatas.
Untuk mempelajari lebih lanjut, pertimbangkan untuk mengikuti kursus lengkap ini secara gratis, yang menunjukkan cara menggabungkan 2 model yang saat ini Anda miliki dalam codelab ini menjadi 1 model tunggal yang efisien.
Selain itu, jika Anda ingin tahu lebih banyak tentang teori di balik aplikasi teachable machine asli, lihat tutorial ini.
Bagikan hal yang Anda buat dengan kami
Anda dapat dengan mudah memperluas kreasi Anda hari ini untuk kasus penggunaan kreatif lainnya juga dan kami mendorong Anda untuk berpikir di luar kebiasaan dan terus berkreasi.
Jangan lupa untuk men-tag kami di media sosial menggunakan hashtag #MadeWithTFJS agar project Anda berpeluang ditampilkan di blog TensorFlow atau bahkan di acara mendatang. Kami ingin sekali melihat hasil kreasi Anda.
Situs untuk dipelajari
- Situs resmi TensorFlow.js
- Model siap pakai TensorFlow.js
- TensorFlow.js API
- TensorFlow.js Show & Tell — dapatkan inspirasi dan lihat apa yang telah dibuat orang lain.