1. Sebelum memulai
Penggunaan model TensorFlow.js telah tumbuh 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 untuk industri mereka. Tindakan mengambil model yang sudah ada (sering disebut sebagai model dasar), dan menggunakannya di domain serupa tetapi berbeda dikenal sebagai pembelajaran transfer.
Pemelajaran transfer memiliki banyak keuntungan dibandingkan dengan 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 terakhir arsitektur model, bukan keseluruhan jaringan. Karena alasan ini, pemelajaran transfer sangat cocok untuk lingkungan browser web yang memerlukan resource yang bervariasi berdasarkan perangkat eksekusi, tetapi juga memiliki akses langsung ke sensor untuk akuisisi data yang mudah.
Codelab ini menunjukkan cara membuat aplikasi web dari kanvas kosong, membuat ulang situs "Teachable Machine" populer Google. Situs ini memungkinkan Anda membuat aplikasi web fungsional yang dapat digunakan pengguna untuk mengenali objek kustom hanya dengan beberapa contoh gambar dari webcam mereka. Situs ini sengaja dijaga minimal agar Anda dapat berfokus pada aspek Machine Learning codelab ini. Namun, seperti situs Teachable Machine asli, ada banyak cakupan untuk menerapkan pengalaman developer web yang sudah ada untuk meningkatkan UX.
Prasyarat
Codelab ini ditulis untuk developer web yang terbiasa dengan model siap pakai TensorFlow.js dan penggunaan API dasar, serta yang ingin memulai pembelajaran transfer di TensorFlow.js.
- Pemahaman dasar tentang TensorFlow.js, HTML5, CSS, dan JavaScript diasumsikan untuk lab ini.
Jika Anda baru mengenal Tensorflow.js, pertimbangkan untuk mengikuti kursus nol gratis ini, yang mengasumsikan tidak ada 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 mengapa Anda harus menggunakannya di aplikasi web berikutnya.
- Cara membuat halaman web HTML/CSS /JS yang disederhanakan untuk meniru 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 class data yang ingin Anda kenali.
- Cara membuat dan menentukan persepsi multi-lapisan yang mengambil fitur gambar serta belajar untuk mengklasifikasikan objek baru yang menggunakannya.
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.
2. Apa itu TensorFlow.js?
TensorFlow.js adalah library machine learning open source yang dapat berjalan di mana pun JavaScript dapat dijalankan. Ini didasarkan pada library TensorFlow asli yang ditulis dengan Python dan bertujuan untuk membuat ulang pengalaman developer ini dan sekumpulan API untuk ekosistem JavaScript.
Di mana dapat digunakan?
Mengingat portabilitas JavaScript, Anda sekarang bisa 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 menggunakan Node.js
- Aplikasi desktop menggunakan Electron
- Aplikasi seluler native menggunakan React Native
TensorFlow.js juga mendukung beberapa backend dalam masing-masing lingkungan ini (lingkungan berbasis hardware sebenarnya yang dapat dieksekusi di dalamnya seperti CPU atau WebGL misalnya. "backend" dalam konteks ini tidak berarti lingkungan sisi server - backend untuk eksekusi bisa menjadi sisi klien di WebGL misalnya) untuk memastikan kompatibilitas dan juga menjaga semuanya tetap berjalan cepat. Saat ini, TensorFlow.js mendukung:
- Eksekusi WebGL di kartu grafis perangkat (GPU) - ini adalah cara tercepat untuk menjalankan model yang lebih besar (ukuran lebih dari 3 MB) dengan akselerasi GPU.
- Eksekusi Web Assembly (WASM) pada CPU - untuk meningkatkan performa CPU di seluruh perangkat, termasuk ponsel generasi lama, misalnya. Ini lebih cocok dengan model yang lebih kecil (ukurannya kurang dari 3 MB) yang dapat dieksekusi lebih cepat di CPU dengan WASM dibandingkan dengan WebGL karena overhead mengupload konten ke prosesor grafis.
- Eksekusi CPU - penggantian seharusnya tidak tersedia di lingkungan lain. Ini adalah yang paling lambat di antara ketiganya tetapi selalu ada untuk Anda.
Catatan: Anda dapat memilih untuk memaksa salah satu backend ini jika mengetahui perangkat apa yang akan Anda gunakan, atau membiarkan TensorFlow.js memutuskan untuk Anda jika Anda melakukannya tidak menentukannya.
Super kecanggihan sisi klien
Menjalankan TensorFlow.js di browser web di komputer klien dapat menghasilkan beberapa manfaat yang layak dipertimbangkan.
Privasi
Anda dapat melatih dan mengklasifikasikan data di komputer klien tanpa pernah mengirim data ke server web pihak ketiga. Kadang-kadang persyaratan ini mungkin diperlukan untuk mematuhi hukum setempat, seperti GDPR, atau saat memproses data apa pun yang mungkin ingin disimpan oleh pengguna di komputer mereka dan tidak dikirim ke pihak ketiga.
Kecepatan
Karena Anda tidak harus mengirim data ke server jarak jauh, inferensi (tindakan mengklasifikasi data) dapat lebih cepat. Yang lebih menarik, 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 saja di dunia dapat mengklik link yang Anda kirim, membuka halaman web di browser mereka, dan memanfaatkan apa yang telah Anda buat. Tidak perlu penyiapan Linux pada sisi server yang kompleks dengan driver CUDA dan banyak lagi, hanya dengan menggunakan sistem machine learning.
Biaya
Tanpa 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 menjaga server (berpotensi dengan memasang kartu grafis) 24/7.
Fitur sisi server
Memanfaatkan implementasi Node.js dari 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 dapat berfungsi dengan kartu grafis (tidak seperti di browser yang menggunakan WebGL - tidak diperlukan penginstalan). Namun, dengan dukungan CUDA penuh, Anda dapat sepenuhnya memanfaatkan kemampuan level kartu grafis yang lebih rendah, sehingga menghasilkan pelatihan dan waktu 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 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 papan tunggal yang populer seperti Raspberry Pi, yang berarti Anda juga dapat menjalankan model TensorFlow.js di perangkat tersebut.
Kecepatan
Node.js ditulis dalam JavaScript yang berarti dapat memanfaatkan hanya dari kompilasi 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 bagusnya dapat dilihat dalam studi kasus ini yang menunjukkan cara Hugging Face menggunakan Node.js untuk mendapatkan peningkatan performa 2x bagi model pemrosesan natural language-nya.
Kini Anda memahami dasar-dasar TensorFlow.js, tempatnya dapat berjalan, dan beberapa manfaatnya, mari kita mulai melakukan hal yang berguna dengan TensorFlow.
3 Transfer pembelajaran
Apa sebenarnya yang dimaksud dengan pemelajaran transfer?
Pemelajaran transfer melibatkan pengetahuan yang telah dipelajari untuk membantu mempelajari hal yang berbeda namun serupa.
Kita manusia melakukan hal ini sepanjang waktu. Anda memiliki pengalaman seumur hidup yang terkandung di dalam 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, ada kemungkinan Anda belum pernah melihat jenis pohon ini sebelumnya.
Namun, jika saya meminta Anda untuk memberi tahu jika ada pohon dedalu pada gambar baru di bawah, Anda mungkin dapat melihatnya dengan cukup cepat, meskipun pohon itu berada pada sudut yang berbeda, dan sedikit berbeda dengan yang asli yang saya tunjukkan.
Anda sudah memiliki banyak neuron di otak yang tahu cara mengidentifikasi objek mirip pohon, dan neuron lain yang ahli dalam menemukan garis lurus panjang. Anda dapat menggunakan kembali pengetahuan tersebut untuk mengklasifikasikan pohon willow dengan cepat, yang merupakan objek mirip pohon yang memiliki banyak cabang vertikal lurus panjang.
Demikian pula, jika Anda memiliki model machine learning yang sudah dilatih di domain, seperti mengenali gambar, Anda dapat menggunakannya kembali untuk melakukan tugas lain yang terkait.
Anda dapat melakukan hal yang sama dengan model lanjutan, seperti MobileNet, yang merupakan model riset sangat populer yang dapat melakukan pengenalan gambar di 1.000 jenis objek berbeda. Dari anjing hingga mobil, alat tersebut dilatih pada set data besar yang dikenal sebagai ImageNet yang memiliki jutaan gambar berlabel.
Dalam animasi ini, Anda dapat melihat sejumlah besar lapisan yang dimilikinya dalam 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 lebih rendah yang digunakannya untuk mengidentifikasi objek tersebut dapat berguna untuk mendeteksi objek baru yang belum pernah dilihat sebelumnya. Lagi pula, semuanya hanya merupakan kombinasi garis, tekstur, dan bentuk.
Mari kita lihat arsitektur Convolutional Neural Network (CNN) tradisional (mirip dengan MobileNet) dan lihat bagaimana pemelajaran transfer dapat memanfaatkan jaringan terlatih ini untuk mempelajari sesuatu yang baru. Gambar di bawah menampilkan arsitektur model standar CNN yang dalam kasus ini dilatih untuk mengenali angka dari tulisan tangan dari 0 hingga 9:
Jika Anda dapat memisahkan lapisan tingkat bawah yang telah dilatih dari model terlatih yang ada seperti ini yang ditampilkan 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 yang lebih rendah untuk menghasilkan fitur output untuk setiap gambar tertentu berdasarkan data asli tempat pelatihan tersebut dijalankan. Berikut adalah jaringan yang sama dengan penghapusan header klasifikasi:
Dengan asumsi bahwa hal baru yang ingin Anda kenali juga dapat memanfaatkan fitur output tersebut yang telah dipelajari oleh model sebelumnya, dan kemungkinan besar fitur tersebut dapat digunakan kembali untuk tujuan baru.
Pada diagram di atas, model hipotesis ini dilatih pada digit, jadi mungkin apa yang dipelajari tentang digit 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 yang lebih rendah dibekukan dan tidak dilatih, hanya kepala klasifikasi baru yang akan diperbarui sendiri untuk belajar dari fitur yang disediakan dari model terlatih yang dipotong di sebelah kiri.
Tindakan ini dikenal sebagai transfer learning dan merupakan fungsi Teachable Machine di balik layar.
Anda juga dapat melihat bahwa dengan hanya perlu melatih perseptron berlapis di bagian akhir jaringan, cara ini akan berlatih jauh lebih cepat dibandingkan jika Anda harus melatih seluruh jaringan dari awal.
Namun, bagaimana cara mendapatkan sub-bagian dari suatu model? Buka bagian berikutnya untuk mencari tahu.
4. TensorFlow Hub - model dasar
Menemukan model dasar yang cocok untuk digunakan
Untuk model riset yang lebih canggih dan populer seperti MobileNet, Anda dapat membuka TensorFlow hub, lalu memfilter model yang cocok untuk TensorFlow.js yang menggunakan arsitektur MobileNet v3 untuk menemukan hasil seperti yang ditampilkan di sini:
Perhatikan bahwa sebagian dari hasil ini berjenis "klasifikasi gambar" (dijelaskan 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 transfer learning dengan cara yang sama seperti yang ditampilkan di bagian sebelumnya dengan menambahkan head klasifikasi baru dan melatihnya dengan data Anda sendiri.
Hal berikutnya yang perlu diperiksa adalah untuk model minat tertentu berdasarkan format TensorFlow.js yang dirilis sebagai modelnya. Jika Anda membuka halaman untuk salah satu model vektor MobileNet v3 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 diingat juga bahwa jika Anda menemukan model dalam format lapisan, bukan format grafik, Anda dapat memilih lapisan mana yang akan dibekukan dan mana yang akan dicairkan untuk pelatihan. Fungsi ini bisa 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 menjadi tempat sebagian besar model TF Hub di-deploy. Untuk mempelajari lebih lanjut cara bekerja dengan model Lapisan, lihat kursus zero to hero TensorFlow.js.
Keuntungan transfer learning
Apa keuntungan menggunakan transfer learning daripada melatih seluruh arsitektur model dari awal?
Pertama, waktu pelatihan adalah keuntungan utama menggunakan pendekatan pemelajaran transfer karena Anda sudah memiliki model dasar yang terlatih untuk dikembangkan.
Kedua, Anda dapat menampilkan lebih sedikit contoh hal baru yang coba Anda klasifikasikan karena pelatihan yang sudah berlangsung.
Ini sangat bagus jika Anda memiliki waktu dan sumber daya terbatas untuk mengumpulkan data contoh hal yang ingin diklasifikasikan, dan perlu membuat prototipe dengan cepat sebelum mengumpulkan lebih banyak data pelatihan agar lebih kuat.
Karena kebutuhan untuk data yang lebih sedikit dan kecepatan pelatihan jaringan yang lebih kecil, pembelajaran transfer kurang intensif resource. Itu sangat cocok untuk lingkungan browser, yang hanya membutuhkan puluhan detik di mesin modern, bukan jam, hari, atau minggu untuk pelatihan model penuh.
Oke! Sekarang Anda tahu esensi dari apa itu Transfer Learning, sekarang 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 yang dimulai dari awal telah dibuat untuk Glitch.com atau Codepen.io. Anda dapat meng-clone salah satu template sebagai status dasar untuk codelab ini, hanya dengan sekali klik.
Di Glitch, klik tombol "remix this" untuk menyalinnya dan membuat kumpulan file baru yang dapat Anda edit.
Atau, di Codepen, klik"garpu" di kanan bawah layar.
Kerangka yang sangat sederhana ini menyediakan file-file berikut:
- Halaman HTML (index.html)
- Stylesheet (style.css)
- File untuk menulis kode JavaScript (script.js)
Demi kenyamanan 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: Menggunakan editor web pilihan Anda atau bekerja secara lokal
Jika Anda ingin mendownload kode dan bekerja secara lokal, atau pada editor online lain, cukup buat 3 file yang disebutkan di atas di direktori yang sama, lalu salin dan tempel kode dari boilerplate Glitch ke masing-masing file.
6. boilerplate HTML aplikasi
Dari mana saya harus memulai?
Semua prototipe memerlukan beberapa scaffolding HTML dasar tempat Anda dapat merender temuan Anda. Siapkan sekarang. Anda akan menambahkan:
- Judul halaman.
- Beberapa teks deskriptif.
- Paragraf status.
- Video untuk menyimpan feed webcam setelah siap.
- Beberapa tombol untuk memulai kamera, mengumpulkan data, atau mereset pengalaman.
- Impor untuk file TensorFlow.js dan JS yang akan Anda kode nanti.
Buka index.html
dan tempelkan kode yang sudah ada dengan yang berikut ini 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>
Kelompokkan
Mari kita uraikan beberapa kode HTML di atas untuk menyoroti beberapa hal penting yang Anda tambahkan.
- Anda telah menambahkan tag
<h1>
untuk judul halaman beserta tag<p>
dengan ID 'status', tempat Anda akan mencetak informasi, saat Anda menggunakan bagian sistem yang berbeda untuk melihat output. - Anda menambahkan elemen
<video>
dengan ID 'webcam', yang akan digunakan untuk merender streaming webcam Anda nanti. - Anda telah menambahkan 5 elemen
<button>
. Parameter pertama, dengan ID 'enableCam,' mengaktifkan kamera. Dua tombol berikutnya memiliki class 'dataCollector', yang memungkinkan Anda mengumpulkan gambar contoh untuk objek yang ingin dikenali. Kode yang Anda tulis nantinya akan dirancang agar Anda dapat menambahkan sejumlah tombol ini dan tombol tersebut akan berfungsi sebagaimana mestinya secara otomatis.
Perlu diketahui bahwa tombol ini juga memiliki atribut khusus buatan pengguna yang disebut data-1hot, dengan nilai bilangan bulat yang dimulai dari 0 untuk class pertama. Ini adalah indeks numerik yang akan Anda gunakan untuk mewakili data kelas 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 kepada pengguna, bukan nilai indeks numerik dari 1 hot encoding.
Terakhir, Anda memiliki tombol pelatihan 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 segera Anda tentukan.
7. Tambah gaya
Default elemen
Tambahkan gaya untuk elemen HTML yang baru saja Anda tambahkan untuk memastikan elemen dirender dengan benar. Berikut adalah beberapa gaya yang ditambahkan ke elemen posisi dan ukuran dengan benar. Tidak ada yang terlalu spesial. Tentu saja Anda dapat menambahkan atribut ini nanti untuk membuat UX yang lebih baik, seperti yang Anda lihat di video pelajaran 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 sudah melihat pratinjau outputnya sekarang, output-nya akan terlihat seperti ini:
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 hal ini:
STATUS
hanya menyimpan referensi ke tag paragraf yang akan menjadi tujuan penulisan status.VIDEO
memiliki referensi ke elemen video HTML yang akan merender feed webcam.ENABLE_CAM_BUTTON
,RESET_BUTTON
, danTRAIN_BUTTON
mengambil referensi DOM ke semua tombol utama dari halaman HTML.MOBILE_NET_INPUT_WIDTH
danMOBILE_NET_INPUT_HEIGHT
masing-masing menentukan lebar dan tinggi input yang diharapkan dari model MobileNet. Dengan menyimpannya secara konstan di dekat bagian atas file seperti ini, jika Anda memutuskan untuk menggunakan versi yang berbeda di lain waktu, akan memudahkan pembaruan nilai satu kali daripada harus menggantinya di banyak tempat yang berbeda.STOP_DATA_GATHER
disetel ke - 1. Tindakan ini akan menyimpan nilai status sehingga Anda tahu kapan pengguna berhenti mengklik tombol untuk mengumpulkan data dari feed webcam. Dengan memberi nomor ini nama yang lebih bermakna, kode akan dibuat lebih mudah dibaca di lain waktu.CLASS_NAMES
bertindak sebagai pencarian dan menyimpan nama yang dapat dibaca manusia untuk kemungkinan prediksi class. Array ini akan diisi nanti.
Oke, karena Anda sekarang memiliki referensi ke elemen utama, sekarang saatnya mengaitkan beberapa pemroses peristiwa ke elemen tersebut.
Menambahkan pemroses peristiwa utama
Mulai dengan menambahkan pengendali peristiwa klik ke tombol kunci 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
- panggilan telepon 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 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 mendorong nama class yang dapat dibaca manusia yang ditemukan dari nama data atribut tombol HTML ke array CLASS_NAMES
.
Selanjutnya, tambahkan beberapa variabel untuk menyimpan hal-hal utama 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 setel ini ke belum ditentukan.
Selanjutnya, Anda memiliki variabel yang disebut gatherDataState
. Jika tombol 'dataCollector' ditekan, tombol ini akan berubah menjadi 1 ID panas dari tombol tersebut, seperti yang ditentukan dalam HTML, sehingga Anda mengetahui class data yang Anda kumpulkan pada saat itu. Awalnya, ini ditetapkan 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
memantau apakah streaming webcam berhasil dimuat dan diputar serta tersedia untuk digunakan. Awalnya, setelan ini disetel ke false
karena webcam tidak aktif hingga Anda menekan ENABLE_CAM_BUTTON.
Selanjutnya, tentukan 2 array, trainingDataInputs
dan trainingDataOutputs
. Ini akan menyimpan nilai data pelatihan yang dikumpulkan, saat Anda mengklik tombol 'dataCollector' untuk fitur input yang dihasilkan oleh model dasar MobileNet, dan class output dengan sampel masing-masing.
Satu array terakhir, examplesCount,
, kemudian ditentukan untuk melacak jumlah contoh yang ada di setiap class setelah Anda mulai menambahkannya.
Terakhir, Anda memiliki variabel bernama predict
yang mengontrol loop prediksi. Ini awalnya disetel ke false
. Prediksi tidak dapat dilakukan hingga opsi ini disetel ke true
nanti.
Setelah semua variabel utama ditentukan, mari kita muat model dasar MobileNet v3 yang telah dipotong sebelumnya, yang menyediakan vektor fitur gambar, bukan klasifikasi.
9. Memuat model dasar MobileNet
Pertama, tentukan fungsi baru yang disebut 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.
Selanjutnya, Anda dapat memuat model menggunakan await tf.loadGraphModel()
, jangan lupa menyetel 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 tempat properti tambahan ini harus ditetapkan.
Setelah pemuatan selesai, Anda dapat menyetel innerText
elemen STATUS
dengan pesan sehingga Anda dapat melihat secara visual bahwa elemen telah dimuat dengan benar dan Anda siap untuk mulai mengumpulkan data.
Satu-satunya hal yang harus dilakukan sekarang adalah menyiapkan modelnya. Dengan model yang lebih besar seperti ini, saat pertama kali Anda menggunakan model, diperlukan waktu beberapa saat untuk menyiapkan semuanya. Oleh karena itu, akan sangat membantu jika meneruskan nol melalui model untuk menghindari waktu tunggu di masa mendatang yang mungkin akan menjadi waktu yang sangat penting.
Anda dapat menggunakan tf.zeros()
yang digabungkan dalam tf.tidy()
untuk memastikan tensor dibuang dengan benar, dengan ukuran batch 1, serta tinggi dan lebar yang benar yang Anda tentukan di konstanta Anda di awal. Terakhir, Anda juga menentukan saluran warna, yang dalam hal ini adalah 3 karena model mengharapkan gambar RGB.
Selanjutnya, buat log bentuk tensor yang dihasilkan menggunakan answer.shape()
untuk membantu Anda memahami ukuran fitur gambar yang dihasilkan oleh model ini.
Setelah menentukan fungsi ini, Anda dapat segera memanggilnya untuk memulai download model saat pemuatan halaman.
Jika Anda melihat pratinjau langsung sekarang, setelah beberapa saat Anda akan melihat teks status berubah dari "Menunggu pemuatan TF.js" menjadi "MobileNet v3 yang berhasil dimuat!" seperti yang ditunjukkan di bawah ini. Pastikan hal 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 sebenarnya menampilkan 1024 fitur yang kemudian dapat digunakan untuk membantu Anda mengklasifikasikan objek baru.
10. Menentukan head model baru
Sekarang saatnya menentukan model kepala, 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. Mulai dengan menentukan model tf.urutan tempat lapisan model akan ditambahkan.
Selanjutnya, tambahkan lapisan padat sebagai lapisan input ke model ini. Ini memiliki bentuk input 1024
karena output dari fitur MobileNet v3 berukuran sama. Anda menemukan ini di langkah sebelumnya setelah meneruskannya 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 apa yang dilakukan properti ini di balik layar.
Lapisan berikutnya yang akan ditambahkan adalah lapisan output. Jumlah neuron harus sama dengan jumlah class yang ingin Anda prediksi. Untuk melakukannya, Anda dapat menggunakan CLASS_NAMES.length
untuk menemukan berapa banyak class yang ingin Anda klasifikasikan, 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 memecahkan 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 ditetapkan ke adam
, dan kerugiannya adalah binaryCrossentropy
jika CLASS_NAMES.length
sama dengan 2
, atau akan menggunakan categoricalCrossentropy
jika ada 3 class atau lebih untuk mengklasifikasikan. Metrik akurasi juga diminta agar dapat dipantau dalam log nanti untuk tujuan proses debug.
Di konsol, Anda akan melihat yang seperti ini:
Perhatikan bahwa ini memiliki lebih dari 130 ribu parameter yang dapat dilatih. Karena ini adalah lapisan neuron padat sederhana yang akan dilatih cukup cepat.
Sebagai aktivitas yang harus dilakukan setelah project selesai, Anda dapat mencoba mengubah jumlah neuron di lapisan pertama untuk melihat seberapa rendah Anda dapat membuatnya sambil tetap mendapatkan performa yang layak. Sering kali dengan machine learning, ada beberapa tingkat uji coba untuk menemukan nilai parameter optimal untuk memberi Anda keseimbangan terbaik antara penggunaan resource dan kecepatan.
11. Aktifkan webcam
Sekarang saatnya menyempurnakan 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 ditetapkan 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 ingin streaming video, dan Anda lebih suka width
video berukuran 640
piksel, dan height
menjadi 480
piksel. Mengapa? Tidak ada gunanya mendapatkan video dengan ukuran lebih besar dari yang seharusnya karena ukuran harus diubah menjadi 224 x 224 piksel untuk dimasukkan ke model MobileNet. Anda juga dapat menghemat beberapa resource komputasi dengan meminta resolusi yang lebih kecil. Sebagian besar kamera mendukung resolusi sebesar 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 menetapkannya sebagai nilai srcObject
.
Anda juga harus menambahkan eventListener pada elemen VIDEO
untuk mengetahui kapan stream
dimuat dan berhasil diputar.
Setelah thread dimuat, Anda dapat menyetel videoPlaying
ke benar (true) dan menghapus ENABLE_CAM_BUTTON
agar tidak 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 berikut:
Oke, kini saatnya menambahkan fungsi untuk menangani klik tombol dataCollector
.
12. Pengendali peristiwa tombol pengumpulan data
Sekarang saatnya mengisi fungsi yang saat ini kosong yang disebut gatherDataForClass().
. Inilah fungsi yang ditetapkan 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 dapat menggunakan parseInt()
untuk mentransmisikannya ke bilangan bulat dan menetapkan hasil ini ke variabel bernama classNumber.
Selanjutnya, tetapkan variabel gatherDataState
yang sesuai. Jika gatherDataState
saat ini sama dengan STOP_DATA_GATHER
(yang Anda tetapkan ke -1), artinya Anda saat ini tidak mengumpulkan data apa pun dan itu adalah peristiwa mousedown
yang diaktifkan. Tetapkan gatherDataState
menjadi classNumber
yang baru Anda temukan.
Jika tidak, artinya saat ini Anda mengumpulkan data dan peristiwa yang diaktifkan adalah peristiwa mouseup
, dan sekarang Anda 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 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 mengambil output model tersebut (vektor fitur 1024).
Kemudian, class ini disimpan bersama dengan ID gatherDataState
dari tombol yang saat ini 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 bahwa webcam aktif, dan gatherDataState
tidak sama dengan STOP_DATA_GATHER
, dan tombol untuk pengumpulan data class saat ini ditekan.
Selanjutnya, gabungkan kode Anda dalam tf.tidy()
untuk membuang setiap tensor yang dibuat dalam kode berikutnya. Hasil eksekusi kode tf.tidy()
ini disimpan dalam variabel yang disebut 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 dibentuk ulang sebagai parameter pertama, lalu bentuk yang menetapkan tinggi dan lebar baru seperti yang didefinisikan oleh konstanta yang sudah Anda buat sebelumnya. Terakhir, tetapkan sudut rata 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 meregangkan gambar, karena gambar webcam Anda berukuran 640 x 480 piksel, dan model ini memerlukan gambar persegi 224 x 224 piksel.
Untuk keperluan demo ini, ini akan berfungsi dengan baik. Namun, setelah Anda menyelesaikan codelab ini, sebaiknya coba potong persegi dari gambar ini untuk memperoleh hasil yang lebih baik lagi bagi sistem produksi mana pun yang mungkin Anda buat nanti.
Selanjutnya, normalkan data gambar. Data gambar selalu berada dalam rentang 0 hingga 255 ketika menggunakan tf.browser.frompixels()
, sehingga Anda cukup membagi ukuran tensorTensor dengan 255 untuk memastikan semua nilai antara 0 dan 1, yang diinginkan oleh model MobileNet sebagai input.
Terakhir, di bagian tf.tidy()
kode, dorong tensor yang dinormalkan ini melalui model yang dimuat dengan memanggil mobilenet.predict()
, tempat Anda meneruskan versi normalizedTensorFrame
yang diluaskan menggunakan expandDims()
sehingga batch 1, karena model mengharapkan batch input untuk diproses.
Setelah hasilnya muncul kembali, Anda dapat segera memanggilsqueeze()
pada hasil yang dikembalikan untuk menekannya kembali ke tensor 1D, yang kemudian Anda kembalikan dan tetapkan keimageFeatures
variabel yang menangkap hasil daritf.tidy()
data.
Setelah memiliki imageFeatures
dari model MobileNet, Anda dapat merekamnya dengan mendorongnya ke array trainingDataInputs
yang telah ditentukan sebelumnya.
Anda juga dapat merekam apa yang direpresentasikan oleh input ini dengan mendorong 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 di fungsi gatherDataForClass()
yang ditentukan sebelumnya.
Pada tahap ini, Anda juga dapat menambah jumlah contoh yang dimiliki untuk class tertentu. Untuk melakukannya, periksa terlebih dahulu apakah indeks dalam array examplesCount
telah diinisialisasi sebelumnya atau tidak. 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 untuk menampilkan jumlah saat ini untuk setiap class saat dicatat. Untuk melakukannya, lakukan loop pada array CLASS_NAMES
, dan cetak nama yang dapat dibaca manusia 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 berulang. Ini akan terus mengambil sampel frame dari video sampai mouseup
tombol terdeteksi, dan gatherDataState
ditetapkan ke STOP_DATA_GATHER,
pada saat loop pengumpulan data akan berakhir.
Jika Anda menjalankan kode sekarang, Anda akan dapat mengklik tombol aktifkan kamera, menunggu webcam untuk memuat, lalu mengklik dan menahan setiap tombol kumpulkan data untuk mengumpulkan contoh untuk setiap class data. Di sini Anda melihat data saya dikumpulkan melalui ponsel dan tangan saya.
Anda akan melihat teks status diperbarui karena menyimpan semua tensor di memori seperti yang ditampilkan di screenshot di atas.
14. Latih dan prediksi
Langkah berikutnya adalah mengimplementasikan kode untuk fungsi trainAndPredict()
yang saat ini kosong, tempat proses transfer berlangsung. Mari kita lihat tata 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 tidak melanjutkan prediksi yang ada dengan menetapkan predict
ke false
.
Selanjutnya, acak array input dan output menggunakan tf.util.shuffleCombo()
untuk memastikan urutannya tidak menyebabkan masalah dalam pelatihan.
Konversikan array output Anda, trainingDataOutputs,
menjadi tensor1d dari jenis int32 sehingga siap digunakan dalam satu encoding panas. Ini disimpan dalam variabel bernama outputsAsTensor
.
Gunakan fungsi tf.oneHot()
dengan variabel outputsAsTensor
ini bersama jumlah maksimum class untuk dienkode, yang merupakan CLASS_NAMES.length
. Satu output berenkode panas sekarang disimpan di tensor baru bernama oneHotOutputs
.
Perhatikan bahwa saat ini trainingDataInputs
adalah array tensor yang direkam. Untuk menggunakannya sebagai pelatihan, Anda perlu mengonversi array tensor untuk menjadi tensor 2D biasa.
Untuk melakukannya, ada fungsi hebat dalam library TensorFlow.js yang disebut tf.stack()
,
yang mengambil array tensor dan menumpuknya bersama untuk menghasilkan tensor dimensi yang lebih tinggi sebagai output. Dalam hal ini tensor 2D ditampilkan, yaitu batch input 1 dimensi yang masing-masing 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
beserta oneHotOutputs
untuk merepresentasikan data pelatihan yang akan digunakan untuk masing-masing contoh input dan target output. Dalam objek konfigurasi untuk parameter ke-3, tetapkanshuffle
hinggatrue
, gunakanbatchSize
dari5
, denganepochs
atur ke10
, lalu tentukancallback
untukonEpochEnd
ke halamanlogProgress
yang akan segera Anda tentukan.
Terakhir, Anda dapat membuang tensor yang dibuat karena model tersebut sekarang dilatih. Anda kemudian dapat menetapkan predict
kembali ke true
agar prediksi dapat terjadi lagi, lalu memanggil fungsi predictLoop()
untuk mulai memprediksi gambar webcam live.
Anda juga dapat menentukan fungsi logProcess()
untuk mencatat status pelatihan, yang digunakan dalam model.fit()
di atas dan yang mencetak hasil ke konsol setelah setiap putaran pelatihan.
Anda hampir selesai! Saatnya menambahkan fungsi predictLoop()
untuk membuat prediksi.
Loop prediksi inti
Di sini Anda menerapkan 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-tama, 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 dilakukan di 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 saja dilatih untuk benar-benar menjalankan prediksi dengan meneruskan imageFeatures
yang dihasilkan yang baru saja ditemukan melalui fungsi predict()
model yang dilatih. Selanjutnya, Anda dapat menekan 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 yang mendasari pada JavaScript untuk menemukan posisi elemen bernilai tertinggi. Nilai ini disimpan dalam variabel yang disebut highestIndex
.
Anda juga bisa mendapatkan skor keyakinan prediksi yang sebenarnya dengan cara yang sama dengan memanggil arraySync()
di 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 class, Anda cukup mencari highestIndex
di array CLASS_NAMES
, lalu mengambil nilai keyakinan dari predictionArray
. Untuk membuatnya lebih mudah dibaca sebagai persentase, cukup kalikan 100 dan math.floor()
hasilnya.
Terakhir, Anda dapat menggunakan window.requestAnimationFrame()
untuk memanggil predictionLoop()
lagi setelah siap, guna mendapatkan klasifikasi real-time di streaming video Anda. Ini berlanjut sampai predict
ditetapkan ke false
jika Anda memilih untuk melatih model baru dengan data baru.
Yang membawa Anda ke bagian terakhir teka-teki. Menerapkan tombol reset.
15. Mengimplementasikan tombol reset
Hampir selesai. Bagian terakhir pelajaran ini adalah mengimplementasikan tombol reset untuk memulai dari awal. Kode untuk fungsi reset()
Anda yang saat ini kosong ada di bawah. Lanjutkan dan update 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 menetapkan panjangnya ke 0, yang merupakan cara praktis untuk menghapus semua konten dari array.
Sekarang lihat semua trainingDataInputs
yang saat ini direkam dan pastikan Anda dispose()
dari setiap tensor yang ada di dalamnya untuk mengosongkan memori kembali, karena Tensor tidak dibersihkan oleh pembersih sampah JavaScript.
Setelah selesai, Anda kini dapat menetapkan panjang array secara aman ke 0 pada array trainingDataInputs
dan trainingDataOutputs
untuk menghapusnya.
Terakhir, tetapkan teks STATUS
ke sesuatu yang masuk akal, dan cetak tensor yang tersisa di memori sebagai pemeriksaan stabilitas.
Perlu diperhatikan bahwa akan ada beberapa ratus tensor yang masih tersimpan dalam memori karena model MobileNet dan perceptron multi-lapisan yang Anda tetapkan tidak akan dibuang. Anda harus menggunakannya kembali dengan data pelatihan baru jika Anda memutuskan untuk berlatih lagi setelah reset ini.
16. Mari kita coba
Saatnya untuk menguji versi Teachable Machine 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 latih, dan periksa log konsol untuk melihat kemajuan. Konten akan dilatih cukup cepat:
Setelah dilatih, tampilkan 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 mengetahui apakah Anda tidak menyalinnya.
17. Selamat
Selamat! Anda baru saja menyelesaikan contoh pembelajaran transfer pertama Anda menggunakan TensorFlow.js secara langsung di browser.
Cobalah, uji di berbagai objek, Anda mungkin melihat beberapa hal lebih sulit dikenali daripada yang lain, terutama jika mereka mirip dengan yang lain. Anda mungkin perlu menambahkan kelas atau data pelatihan lainnya agar dapat membedakannya.
Rangkuman
Dalam codelab ini, Anda mempelajari:
- Pengertian pembelajaran transfer, dan keuntungannya dibandingkan melatih model lengkap.
- Cara mendapatkan model untuk digunakan kembali dari TensorFlow Hub.
- Cara menyiapkan aplikasi web yang cocok untuk pembelajaran transfer.
- Cara memuat dan menggunakan model dasar untuk membuat fitur gambar.
- Cara melatih head prediksi baru yang dapat mengenali objek kustom dari citra 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 di dunia nyata yang mungkin sedang Anda kerjakan? Apakah Anda dapat merevolusi industri yang saat ini Anda kerjakan untuk membantu rakyat di perusahaan Anda melatih model agar mengklasifikasikan hal-hal yang penting dalam pekerjaan mereka sehari-hari? Kemungkinannya tak terbatas.
Untuk melangkah lebih lanjut, pertimbangkan untuk mengikuti kursus lengkap ini secara gratis, yang menunjukkan cara menggabungkan 2 model yang saat ini Anda miliki di codelab ini menjadi 1 model tunggal untuk efisiensi.
Selain itu, jika Anda ingin tahu lebih lanjut tentang teori di balik aplikasi asli yang dapat diajarkan, lihat tutorial ini.
Bagikan hal yang Anda buat dengan kami
Anda juga dapat dengan mudah memperluas hasil yang Anda buat hari ini untuk kasus penggunaan materi iklan lainnya, dan sebaiknya Anda berpikir secara kreatif dan tetap meretas.
Jangan lupa untuk memberi tag di media sosial menggunakan hashtag #MadeWithTFJS agar project Anda mendapat peluang untuk ditampilkan di blog TensorFlow atau bahkan acara mendatang. Kami ingin sekali melihat hasil kreasi Anda.
Beberapa situs untuk dipelajari
- Situs resmi TensorFlow.js
- Model siap pakai TensorFlow.js
- API TensorFlow.js
- Show & Tell TensorFlow.js — dapatkan inspirasi dan lihat apa yang telah dibuat orang lain.