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

1. Sebelum memulai

Penggunaan model TensorFlow.js telah tumbuh secara eksponensial selama beberapa tahun terakhir dan banyak developer JavaScript 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?

54e81d02971f53e8.png

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:

e28070392cd4afb9.png

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.

d9073a0d5df27222.png

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:

7d4e1e35c1a89715.gif

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:

baf4e3d434576106.png

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:

369a8a9041c6917d.png

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:

db97e5e60ae73bbd.png

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:

c5dc1420c6238c14.png

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

f97d903d2e46924b.png

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 &amp; Predict!</button>
    <button id="reset">Reset</button>

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

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

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:

81909685d7566dcb.png

8 JavaScript: Konstanta dan pemroses kunci

Menentukan konstanta kunci

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

script.js

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

Mari kita uraikan 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, dan TRAIN_BUTTON mengambil referensi DOM ke semua tombol utama dari halaman HTML.
  • MOBILE_NET_INPUT_WIDTH dan MOBILE_NET_INPUT_HEIGHT masing-masing menentukan lebar dan tinggi input yang diharapkan dari model MobileNet. Dengan 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.

a28b734e190afff.png

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:

22eaf32286fea4bb.png

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:

b378eb1affa9b883.png

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.

541051644a45131f.gif

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:

bf1ac3cc5b15740.gif

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:

  1. Pengertian pembelajaran transfer, dan keuntungannya dibandingkan melatih model lengkap.
  2. Cara mendapatkan model untuk digunakan kembali dari TensorFlow Hub.
  3. Cara menyiapkan aplikasi web yang cocok untuk pembelajaran transfer.
  4. Cara memuat dan menggunakan model dasar untuk membuat fitur gambar.
  5. Cara melatih head prediksi baru yang dapat mengenali objek kustom dari citra webcam.
  6. 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