1. Başlamadan önce
TensorFlow.js model kullanımı son birkaç yılda katlanarak arttı ve birçok JavaScript geliştiricisi artık mevcut son teknoloji modelleri alıp kendi sektörlerine özgü özel verilerle çalışacak şekilde yeniden eğitmek istiyor. Mevcut bir modeli (genellikle temel model olarak adlandırılır) alıp benzer ancak farklı bir alanda kullanma işlemine transfer öğrenimi denir.
Transfer öğrenimi, tamamen boş bir modelle başlamaya kıyasla birçok avantaj sunar. Daha önce eğitilmiş bir modelden öğrenilen bilgileri yeniden kullanabilir ve sınıflandırmak istediğiniz yeni öğeyle ilgili daha az örnek gerekir. Ayrıca, yalnızca model mimarisinin son birkaç katmanının yeniden eğitilmesi gerektiğinden eğitim genellikle tüm ağın yeniden eğitilmesine kıyasla önemli ölçüde daha hızlıdır. Bu nedenle, kaynakların yürütme cihazına göre değişebileceği ancak kolay veri edinimi için sensörlere doğrudan erişimin de olduğu web tarayıcısı ortamı için transfer öğrenimi çok uygundur.
Bu codelab'de, Google'ın popüler "Öğrenebilir Makine" web sitesini yeniden oluşturarak boş bir tuvalden web uygulaması oluşturma işlemi gösterilmektedir. Bu web sitesi, herhangi bir kullanıcının web kamerasından alınan birkaç örnek resimle özel bir nesneyi tanımasına olanak tanıyan işlevsel bir web uygulaması oluşturmanıza imkan tanır. Bu codelab'in makine öğrenimi yönlerine odaklanabilmeniz için web sitesi kasıtlı olarak en basit şekilde tasarlanmıştır. Ancak orijinal Teachable Machine web sitesinde olduğu gibi, kullanıcı deneyimini iyileştirmek için mevcut web geliştirici deneyiminizi uygulayabileceğiniz birçok alan vardır.
Ön koşullar
Bu codelab, TensorFlow.js'nin hazır modelleri ve temel API kullanımı hakkında biraz bilgi sahibi olan ve TensorFlow.js'de transfer öğrenimine başlamak isteyen web geliştiriciler için hazırlanmıştır.
- Bu laboratuvarda TensorFlow.js, HTML5, CSS ve JavaScript hakkında temel düzeyde bilgi sahibi olduğunuz varsayılır.
Tensorflow.js'ye yeni başladıysanız öncelikle bu ücretsiz kursu tamamlamanızı öneririz. Bu kursta makine öğrenimi veya TensorFlow.js hakkında herhangi bir bilgiye sahip olmadığınız varsayılır ve bilmeniz gereken her şey daha küçük adımlarla öğretilir.
Neler öğreneceksiniz?
- TensorFlow.js'nin ne olduğu ve bir sonraki web uygulamanızda neden kullanmanız gerektiği.
- Öğrenebilir Makine kullanıcı deneyimini kopyalayan basitleştirilmiş bir HTML/CSS /JS web sayfası oluşturma
- Önceden eğitilmiş bir temel modeli (özellikle MobileNet) yüklemek için TensorFlow.js'yi kullanarak aktarım öğreniminde kullanılabilecek görüntü özellikleri oluşturma
- Tanımak istediğiniz birden fazla veri sınıfı için kullanıcının web kamerasından nasıl veri toplayacağınızı öğrenin.
- Görüntü özelliklerini alan ve bunları kullanarak yeni nesneleri sınıflandırmayı öğrenen çok katmanlı bir algılayıcıyı nasıl oluşturup tanımlayacağınızı öğrenin.
Haydi, hacklemeye başlayalım...
Gerekenler
- Takip etmek için Glitch.com hesabınızın olması tercih edilir. Dilerseniz kendiniz düzenleyip çalıştırabileceğiniz bir web sunma ortamı da kullanabilirsiniz.
2. TensorFlow.js nedir?

TensorFlow.js, JavaScript'in çalıştırılabildiği her yerde çalışabilen bir açık kaynaklı makine öğrenimi kitaplığıdır. Python'da yazılmış orijinal TensorFlow kitaplığına dayanan bu kitaplık, JavaScript ekosisteminde bu geliştirici deneyimini ve API'lerini yeniden oluşturmayı amaçlar.
Nerede kullanılabilir?
JavaScript'in taşınabilirliği sayesinde artık tek bir dilde yazabilir ve aşağıdaki platformların tümünde kolayca makine öğrenimi gerçekleştirebilirsiniz:
- Düz JavaScript kullanılarak web tarayıcısında istemci tarafında
- Node.js kullanan sunucu tarafı ve Raspberry Pi gibi IoT cihazları
- Electron'u kullanan masaüstü uygulamaları
- React Native kullanan yerel mobil uygulamalar
TensorFlow.js, bu ortamların her birinde birden fazla arka ucu da destekler (örneğin, CPU veya WebGL gibi, içinde yürütülebileceği gerçek donanım tabanlı ortamlar). Bu bağlamda "arka uç", sunucu tarafı bir ortam anlamına gelmez. Örneğin, yürütme için arka uç WebGL'de istemci tarafı olabilir. Bu, uyumluluğu sağlamak ve her şeyin hızlı çalışmasını sağlamak içindir. TensorFlow.js şu anda şunları desteklemektedir:
- Cihazın grafik kartında (GPU) WebGL yürütme: Bu, GPU hızlandırmasıyla daha büyük modelleri (boyutu 3 MB'tan fazla) yürütmenin en hızlı yoludur.
- Örneğin, eski nesil cep telefonları da dahil olmak üzere cihazlarda CPU performansını artırmak için CPU'da Web Assembly (WASM) yürütme. Bu, içeriklerin grafik işlemciye yüklenmesiyle ilgili ek yük nedeniyle WASM ile CPU'da WebGL'ye kıyasla daha hızlı çalışabilen daha küçük modeller (boyutu 3 MB'tan az) için daha uygundur.
- CPU yürütme: Diğer ortamların hiçbiri kullanılamıyorsa yedek olarak bu ortam kullanılmalıdır. Bu yöntem üçü arasında en yavaş olanıdır ancak her zaman kullanılabilir.
Not: Hangi cihazda çalıştıracağınızı biliyorsanız bu arka uçlardan birini zorunlu kılmayı seçebilirsiniz. Bunu belirtmezseniz TensorFlow.js'in sizin için karar vermesine izin verebilirsiniz.
İstemci tarafı süper güçleri
TensorFlow.js'yi istemci makinesindeki web tarayıcısında çalıştırmak, dikkate alınması gereken çeşitli avantajlar sağlayabilir.
Gizlilik
Verileri hiçbir zaman üçüncü taraf web sunucusuna göndermeden istemci makinesinde hem eğitebilir hem de sınıflandırabilirsiniz. Bu, yerel yasalara (ör. GDPR) uymak veya kullanıcının makinesinde tutmak isteyebileceği ve üçüncü tarafa gönderilmeyen verileri işlemek için gerekli olabilir.
Hız
Verileri uzak bir sunucuya göndermeniz gerekmediğinden çıkarım (verileri sınıflandırma işlemi) daha hızlı olabilir. Daha da iyisi, kullanıcı size erişim izni verirse kamera, mikrofon, GPS, ivmeölçer gibi cihaz sensörlerine doğrudan erişebilirsiniz.
Erişim ve ölçeklendirme
Dünyanın herhangi bir yerindeki kullanıcılar, tek bir tıklamayla kendilerine gönderdiğiniz bağlantıyı tıklayabilir, web sayfasını tarayıcılarında açabilir ve oluşturduğunuz içeriği kullanabilir. Makine öğrenimi sistemini kullanmak için CUDA sürücüleri ve çok daha fazlasıyla karmaşık bir sunucu tarafı Linux kurulumuna gerek yoktur.
Maliyet
Sunucu olmadığı için HTML, CSS, JS ve model dosyalarınızı barındırmak üzere yalnızca bir CDN için ödeme yapmanız gerekir. CDN'nin maliyeti, 7/24 çalışan bir sunucu (muhtemelen bağlı bir grafik kartıyla) bulundurmaktan çok daha düşüktür.
Sunucu tarafı özellikleri
TensorFlow.js'in Node.js uygulamasından yararlanarak aşağıdaki özellikler etkinleştirilir.
Tam CUDA desteği
Sunucu tarafında, grafik kartı hızlandırması için TensorFlow'un grafik kartıyla çalışmasını sağlamak üzere NVIDIA CUDA sürücülerini yüklemeniz gerekir (WebGL'nin kullanıldığı tarayıcıda yükleme gerekmez). Ancak tam CUDA desteğiyle grafik kartının daha düşük seviyeli özelliklerinden tam olarak yararlanabilir, böylece daha hızlı eğitim ve çıkarım süreleri elde edebilirsiniz. Her ikisi de aynı C++ arka ucunu paylaştığı için performans, Python TensorFlow uygulamasıyla aynı düzeydedir.
Model Boyutu
Araştırmalardaki en yeni modellerle çalışırken çok büyük modellerle (ör. gigabaytlarca) çalışabilirsiniz. Bu modeller, tarayıcı sekmesi başına bellek kullanımıyla ilgili sınırlamalar nedeniyle şu anda web tarayıcısında çalıştırılamaz. Bu büyük modelleri çalıştırmak için kendi sunucunuzda Node.js'yi kullanabilirsiniz. Sunucunuz, bu tür bir modeli verimli bir şekilde çalıştırmak için gereken donanım özelliklerine sahip olmalıdır.
IOT
Node.js, Raspberry Pi gibi popüler tek kartlı bilgisayarlarda desteklenir. Bu da TensorFlow.js modellerini bu tür cihazlarda da çalıştırabileceğiniz anlamına gelir.
Hız
Node.js, JavaScript ile yazıldığından tam zamanında derlemeden yararlanır. Bu nedenle, Node.js'yi kullandığınızda genellikle performans artışı görebilirsiniz. Çünkü Node.js, özellikle yaptığınız tüm ön işleme için çalışma zamanında optimize edilir. Bununla ilgili harika bir örneği bu örnek olayda görebilirsiniz. Bu örnek olayda, Hugging Face'in doğal dil işleme modelinde 2 kat performans artışı elde etmek için Node.js'yi nasıl kullandığı gösterilmektedir.
TensorFlow.js'in temellerini, nerede çalışabileceğini ve bazı avantajlarını öğrendiğinize göre artık TensorFlow.js ile faydalı şeyler yapmaya başlayabiliriz.
3. Transfer öğrenimi
Transfer öğrenimi tam olarak nedir?
Öğrenim aktarma, farklı ancak benzer bir şeyi öğrenmeye yardımcı olmak için önceden öğrenilmiş bilgileri kullanmayı içerir.
İnsanlar olarak bunu sürekli yaparız. Beyninizde, daha önce hiç görmediğiniz yeni şeyleri tanımanıza yardımcı olabilecek bir ömürlük deneyim vardır. Örneğin, bu söğüt ağacını ele alalım:

Dünyanın neresinde olduğunuza bağlı olarak bu tür bir ağacı daha önce görmemiş olabilirsiniz.
Ancak aşağıdaki yeni resimde söğüt ağacı olup olmadığını söylemenizi istersem farklı bir açıda ve size gösterdiğim orijinal resimden biraz farklı olsalar da muhtemelen onları oldukça hızlı bir şekilde fark edebilirsiniz.

Beyninizde ağaç benzeri nesneleri tanımlamayı bilen bir grup nöron ve uzun düz çizgileri bulmakta iyi olan başka nöronlar vardır. Bu bilgiyi, çok sayıda uzun ve düz dikey dalı olan ağaç benzeri bir nesne olan söğüt ağacını hızlıca sınıflandırmak için yeniden kullanabilirsiniz.
Benzer şekilde, bir alanda (ör. görüntü tanıma) önceden eğitilmiş bir makine öğrenimi modeliniz varsa bunu farklı ancak ilişkili bir görevi gerçekleştirmek için yeniden kullanabilirsiniz.
Aynı işlemi, 1.000 farklı nesne türünde görüntü tanıma gerçekleştirebilen çok popüler bir araştırma modeli olan MobileNet gibi gelişmiş bir modelle de yapabilirsiniz. Köpeklerden arabalara kadar milyonlarca etiketli resmin bulunduğu ImageNet adlı büyük bir veri kümesiyle eğitildi.
Bu animasyonda, MobileNet V1 modelinde bulunan çok sayıda katmanı görebilirsiniz:

Bu model, eğitimi sırasında bu 1.000 nesne için önemli olan ortak özellikleri nasıl çıkaracağını öğrendi. Bu tür nesneleri tanımlamak için kullandığı alt düzey özelliklerin çoğu, daha önce hiç görmediği yeni nesneleri algılamak için de kullanılabilir. Sonuçta her şey çizgilerin, dokuların ve şekillerin bir kombinasyonundan ibarettir.
Geleneksel bir evrişimli nöral ağ (CNN) mimarisine (MobileNet'e benzer) göz atalım ve aktarımlı öğrenmenin, bu eğitilmiş ağdan yararlanarak nasıl yeni şeyler öğrenebileceğini görelim. Aşağıdaki resimde, bu örnekte 0-9 arasındaki el yazısı rakamları tanımak için eğitilmiş bir CNN'nin tipik model mimarisi gösterilmektedir:

Solda gösterildiği gibi, mevcut eğitilmiş bir modelin önceden eğitilmiş alt düzey katmanlarını sağda gösterilen modelin sonuna yakın sınıflandırma katmanlarından (bazen modelin sınıflandırma başlığı olarak da adlandırılır) ayırabilirseniz alt düzey katmanları, eğitildiği orijinal verilere dayalı olarak herhangi bir görüntü için çıkış özellikleri üretmek üzere kullanabilirsiniz. Aynı ağın sınıflandırma başlığı kaldırılmış hali:

Tanımaya çalıştığınız yeni şeyin, önceki modelin öğrendiği bu tür çıkış özelliklerinden de yararlanabileceğini varsayarsak bu özelliklerin yeni bir amaç için yeniden kullanılma ihtimali yüksektir.
Yukarıdaki şemada, bu varsayımsal model rakamlar üzerinde eğitilmiştir. Bu nedenle, rakamlar hakkında öğrenilenler a, b ve c gibi harflere de uygulanabilir.
Bu nedenle, artık gösterildiği gibi a, b veya c'yi tahmin etmeye çalışan yeni bir sınıflandırma başlığı ekleyebilirsiniz:

Burada alt düzey katmanlar dondurulur ve eğitilmez. Yalnızca yeni sınıflandırma başlığı, soldaki önceden eğitilmiş ve parçalanmış modelden sağlanan özelliklerden öğrenmek için kendini günceller.
Bu işlem, transfer öğrenimi olarak bilinir ve Teachable Machine'in arka planda yaptığı işlemdir.
Ayrıca, çok katmanlı algılayıcıyı yalnızca ağın en sonunda eğitmeniz gerektiğinden, tüm ağı sıfırdan eğitmeniz gerekseydi eğitimin çok daha hızlı olacağını da görebilirsiniz.
Peki bir modelin alt bölümlerini nasıl kullanabilirsiniz? Öğrenmek için sonraki bölüme geçin.
4. TensorFlow Hub - temel modeller
Kullanılacak uygun bir temel model bulma
MobileNet gibi daha gelişmiş ve popüler araştırma modelleri için TensorFlow Hub'a gidip MobileNet v3 mimarisini kullanan ve TensorFlow.js için uygun olan modelleri filtreleyerek burada gösterilenlere benzer sonuçlar bulabilirsiniz:

Bu sonuçlardan bazılarının "resim sınıflandırma" türünde (her model kartı sonucunun sol üst kısmında ayrıntılı olarak açıklanmıştır), bazılarının ise "resim özellik vektörü" türünde olduğunu unutmayın.
Bu resim özelliği vektörü sonuçları, esasen son sınıflandırma yerine resim özelliği vektörlerini elde etmek için kullanabileceğiniz MobileNet'in önceden parçalanmış sürümleridir.
Bu tür modeller genellikle "temel modeller" olarak adlandırılır. Bu modelleri, yeni bir sınıflandırma başlığı ekleyip kendi verilerinizle eğiterek önceki bölümde gösterildiği gibi aktarımlı öğrenme gerçekleştirmek için kullanabilirsiniz.
Kontrol etmeniz gereken bir sonraki şey, ilgilendiğiniz belirli bir temel modelin hangi TensorFlow.js biçiminde yayınlandığıdır. Bu özellik vektörü MobileNet v3 modellerinden birinin sayfasını açarsanız dokümantasyondaki örnek kod snippet'ine dayalı bir grafik modeli biçiminde olduğunu JS dokümanlarından görebilirsiniz. Bu modelde tf.loadGraphModel() kullanılır.

Grafik biçimi yerine katman biçiminde bir model bulursanız eğitim için hangi katmanların dondurulacağını ve hangilerinin çözüleceğini seçebileceğinizi de unutmayın. Bu, yeni bir görev için model oluştururken çok etkili olabilir. Bu işleme genellikle "transfer modeli" adı verilir. Ancak şimdilik bu eğitimde, çoğu TF Hub modelinin dağıtıldığı varsayılan grafik modeli türünü kullanacaksınız. Katmanlar modelleriyle çalışma hakkında daha fazla bilgi edinmek için zero to hero TensorFlow.js kursuna göz atın.
Transfer öğrenmenin avantajları
Model mimarisinin tamamını sıfırdan eğitmek yerine aktarımlı öğrenmeyi kullanmanın avantajları nelerdir?
İlk olarak, aktarımlı öğrenme yaklaşımı kullanmanın temel avantajlarından biri eğitim süresidir. Çünkü bu yaklaşımda, üzerine inşa edebileceğiniz eğitilmiş bir temel modeliniz vardır.
İkincisi, önceden yapılmış eğitim sayesinde sınıflandırmaya çalıştığınız yeni şeyin çok daha az örneğini gösterebilirsiniz.
Sınıflandırmak istediğiniz öğenin örnek verilerini toplamak için sınırlı zamanınız ve kaynağınız varsa ve daha fazla eğitim verisi toplayarak daha sağlam hale getirmeden önce hızlı bir şekilde prototip oluşturmanız gerekiyorsa bu özellik çok işinize yarar.
Daha az veriye ihtiyaç duyulması ve daha küçük bir ağın eğitilme hızı göz önüne alındığında, transfer öğrenimi daha az kaynak yoğun bir yöntemdir. Bu nedenle, tarayıcı ortamı için çok uygundur. Tam model eğitimi saatler, günler veya haftalar yerine modern bir makinede yalnızca onlarca saniye sürer.
Tamam. Aktarım Öğreniminin ne olduğunu öğrendiğinize göre artık Öğrenebilir Makine'nin kendi sürümünüzü oluşturabilirsiniz. Haydi, başlayalım.
5. Kod yazmaya hazırlanma
Gerekenler
- Modern bir web tarayıcısı.
- HTML, CSS, JavaScript ve Chrome Geliştirici Araçları (konsol çıkışını görüntüleme) hakkında temel bilgi sahibi olmanız gerekir.
Kodlamaya başlayalım
Başlangıç için ortak metin şablonları Glitch.com veya Codepen.io için oluşturulmuştur. Bu kod laboratuvarı için temel durum olarak şablonlardan birini tek bir tıklamayla klonlayabilirsiniz.
Glitch'te, projeyi çatallayıp düzenleyebileceğiniz yeni bir dosya grubu oluşturmak için "remix this" (Bunu remiksle) düğmesini tıklayın.
Alternatif olarak, CodePen'de ekranın sağ alt kısmındaki "fork" (çatal) seçeneğini tıklayın.
Bu çok basit iskelet, aşağıdaki dosyaları sağlar:
- HTML sayfası (index.html)
- Stil sayfası (style.css)
- JavaScript kodumuzu yazacağımız dosya (script.js)
Kolaylık sağlamak için HTML dosyasına TensorFlow.js kitaplığı için bir içe aktarma işlemi eklenmiştir. Şöyle görünür:
index.html
<!-- Import TensorFlow.js library -->
<script src="https://cdn.jsdelivr.net/npm/@tensorflow/tfjs/dist/tf.min.js" type="text/javascript"></script>
Alternatif: Tercih ettiğiniz web düzenleyiciyi kullanın veya yerel olarak çalışın
Kodu indirip yerel olarak veya farklı bir online düzenleyicide çalışmak istiyorsanız yukarıda belirtilen 3 dosyayı aynı dizinde oluşturmanız ve Glitch boilerplate'imizdeki kodu kopyalayıp her birine yapıştırmanız yeterlidir.
6. Uygulama HTML'si ortak metni
Nereden başlamalıyım?
Tüm prototipler, bulgularınızı oluşturabileceğiniz bazı temel HTML iskeletleri gerektirir. Şimdi ayarlayın. Ekleyecekleriniz:
- Sayfanın başlığı.
- Açıklayıcı bir metin.
- Durum paragrafı.
- Hazır olduğunda web kamerası feed'ini tutacak bir video.
- Kamerayı başlatmak, veri toplamak veya deneyimi sıfırlamak için çeşitli düğmeler.
- TensorFlow.js ve daha sonra kodlayacağınız JS dosyaları için içe aktarmalar.
index.html bağlantısını açın ve yukarıdaki özellikleri ayarlamak için mevcut kodun üzerine aşağıdakileri yapıştırın:
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>
Açıkla
Eklediğiniz bazı önemli noktaları vurgulamak için yukarıdaki HTML kodunun bir kısmını inceleyelim.
- Sayfa başlığı için bir
<h1>etiketi ve sistemin farklı bölümlerini kullanarak çıktıları görüntülediğinizde bilgileri yazdıracağınız yer olan "durum" kimliğine sahip bir<p>etiketi eklediniz. - "webcam" kimliğine sahip bir
<video>öğesi eklediniz. Web kamerası akışınızı daha sonra bu öğede oluşturacaksınız. - 5
<button>öğesi eklediniz. "enableCam" kimliğine sahip olan ilk işlev, kamerayı etkinleştirir. Sonraki iki düğme, "dataCollector" sınıfına sahiptir. Bu sınıf, tanımak istediğiniz nesneler için örnek resimler toplamanıza olanak tanır. Daha sonra yazacağınız kod, bu düğmelerden istediğiniz kadar ekleyebileceğiniz ve bunların otomatik olarak beklendiği gibi çalışacağı şekilde tasarlanır.
Bu düğmelerde, ilk sınıf için 0'dan başlayan bir tam sayı değeriyle özel bir kullanıcı tanımlı özellik olan data-1hot da bulunur. Bu, belirli bir sınıfın verilerini temsil etmek için kullanacağınız sayısal indekstir. Makine öğrenimi modelleri yalnızca sayılarla çalışabildiğinden, dizeler yerine sayısal gösterimle çıkış sınıflarını doğru şekilde kodlamak için dizin kullanılır.
Bu sınıf için kullanmak istediğiniz, kullanıcı tarafından okunabilir adı içeren bir data-name özelliği de vardır. Bu özellik, kullanıcılara 1 sıcak kodlamadan gelen sayısal bir dizin değeri yerine daha anlamlı bir ad sağlamanıza olanak tanır.
Son olarak, veri toplandıktan sonra eğitim sürecini başlatmak veya uygulamayı sıfırlamak için bir eğitim ve sıfırlama düğmesi bulunur.
- Ayrıca 2
<script>içe aktarma işlemi de eklediniz. Biri TensorFlow.js, diğeri de kısa süre içinde tanımlayacağınız script.js için.
7. Stil ekle
Öğe varsayılanları
Doğru şekilde oluşturulmalarını sağlamak için yeni eklediğiniz HTML öğelerine stil ekleyin. Öğeleri doğru şekilde konumlandırmak ve boyutlandırmak için eklenen bazı stiller aşağıda verilmiştir. Çok özel bir şey yok. Öğretilebilir makine videosunda gördüğünüz gibi, daha iyi bir kullanıcı deneyimi sunmak için bu listeye daha sonra eklemeler yapabilirsiniz.
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%;
}
Mükemmel! İhtiyacınız olan tek şey bu. Çıkışı şu anda önizlerseniz aşağıdaki gibi görünür:

8. JavaScript: Anahtar sabitleri ve dinleyiciler
Temel sabitleri tanımlama
Öncelikle uygulama genelinde kullanacağınız bazı temel sabitleri ekleyin. script.js içeriğini bu sabitlerle değiştirerek başlayın:
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 = [];
Bu özelliklerin ne için kullanıldığını inceleyelim:
STATUS, durum güncellemelerini yazacağınız paragraf etiketine yalnızca bir referans tutar.VIDEO, web kamerası feed'ini oluşturacak HTML video öğesine bir referans içerir.ENABLE_CAM_BUTTON,RESET_BUTTONveTRAIN_BUTTON, HTML sayfasındaki tüm önemli düğmelerin DOM referanslarını alır.MOBILE_NET_INPUT_WIDTHveMOBILE_NET_INPUT_HEIGHT, MobileNet modelinin beklenen giriş genişliğini ve yüksekliğini tanımlar. Bu değeri dosyanın üst kısmına yakın bir yerde sabit olarak sakladığınızda, daha sonra farklı bir sürüm kullanmaya karar verirseniz değeri birçok farklı yerde değiştirmeniz gerekmez. Değeri yalnızca bir kez güncellemeniz yeterli olur.STOP_DATA_GATHERdeğeri -1 olarak ayarlanır. Bu, bir durum değerini depolar. Böylece, kullanıcının web kamerası feed'inden veri toplamak için bir düğmeyi tıklamayı ne zaman bıraktığını bilirsiniz. Bu sayıya daha anlamlı bir ad vererek kodun daha sonra okunmasını kolaylaştırır.CLASS_NAMES, arama işlevi görür ve olası sınıf tahminlerinin kullanıcılar tarafından okunabilir adlarını içerir. Bu dizi daha sonra doldurulacaktır.
Tamam, artık temel öğelere referanslarınız olduğuna göre bunlarla bazı etkinlik dinleyicilerini ilişkilendirme zamanı.
Önemli etkinlik işleyicileri ekleme
Önemli düğmelere tıklama etkinliği işleyicileri ekleyerek başlayın.
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: Tıklandığında enableCam işlevini çağırır.
TRAIN_BUTTON - Tıklandığında trainAndPredict'i çağırır.
RESET_BUTTON: Tıklandığında sıfırlanır.
Son olarak bu bölümde, document.querySelectorAll() kullanılarak "dataCollector" sınıfına sahip tüm düğmeleri bulabilirsiniz. Bu işlev, dokümanda bulunan ve aşağıdaki ölçütlere uyan öğelerin dizisini döndürür:
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!
}
Kod açıklaması:
Ardından, bulunan düğmeler arasında yineleme yapıp her birine 2 etkinlik işleyici ilişkilendirirsiniz. Biri "mousedown", diğeri "mouseup" için. Bu sayede, düğmeye basılı tuttuğunuz sürece kayıt örnekleri almaya devam edebilirsiniz. Bu özellik, veri toplama için kullanışlıdır.
Her iki etkinlik de daha sonra tanımlayacağınız bir gatherDataForClass işlevini çağırır.
Bu noktada, bulunan okunabilir sınıf adlarını HTML düğmesi özelliğindeki data-name'den CLASS_NAMES dizisine de aktarabilirsiniz.
Ardından, daha sonra kullanılacak önemli şeyleri depolamak için bazı değişkenler ekleyin.
script.js
let mobilenet = undefined;
let gatherDataState = STOP_DATA_GATHER;
let videoPlaying = false;
let trainingDataInputs = [];
let trainingDataOutputs = [];
let examplesCount = [];
let predict = false;
Bu adımları birlikte inceleyelim.
İlk olarak, yüklenen MobileNet modelini depolamak için mobilenet değişkeniniz var. Başlangıçta bunu tanımlanmamış olarak ayarlayın.
Ardından, gatherDataState adlı bir değişkeniniz var. Bir "dataCollector" düğmesine basılırsa bu, HTML'de tanımlandığı şekilde düğmenin 1 sıcak kimliği olarak değişir. Böylece o anda hangi veri sınıfını topladığınızı bilirsiniz. Başlangıçta bu değer STOP_DATA_GATHER olarak ayarlanır. Böylece, daha sonra yazacağınız veri toplama döngüsü, hiçbir düğmeye basılmadığında veri toplamaz.
videoPlaying, web kamerası akışının başarıyla yüklenip oynatıldığını ve kullanıma hazır olup olmadığını takip eder. Başlangıçta, ENABLE_CAM_BUTTON. düğmesine basana kadar web kamerası açık olmadığından bu ayar false olarak belirlenir.
Ardından, trainingDataInputs ve trainingDataOutputs olmak üzere 2 dizi tanımlayın. Bunlar, MobileNet temel modeli tarafından oluşturulan giriş özellikleri ve sırasıyla örneklenen çıkış sınıfı için "dataCollector" düğmelerini tıkladığınızda toplanan eğitim verisi değerlerini depolar.
Ardından, örnekleri eklemeye başladığınızda her sınıfta kaç örnek olduğunu takip etmek için son bir dizi olan examplesCount, tanımlanır.
Son olarak, tahmin döngünüzü kontrol eden predict adlı bir değişkeniniz var. Bu, başlangıçta false olarak ayarlanır. Bu ayar true daha sonra olarak değiştirilene kadar tahmin yapılamaz.
Tüm temel değişkenler tanımlandığına göre, sınıflandırmalar yerine görüntü özelliği vektörleri sağlayan önceden parçalanmış MobileNet v3 temel modelini yükleyelim.
9. MobileNet temel modelini yükleme
Öncelikle, aşağıda gösterildiği gibi loadMobileNetFeatureModel adlı yeni bir işlev tanımlayın. Model yükleme işlemi eşzamansız olduğundan bu işlev eşzamansız olmalıdır:
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();
Bu kodda, TFHub belgelerinden yüklenecek modelin bulunduğu URL tanımlanır.
Ardından, bu Google web sitesinden bir model yüklediğiniz için özel mülk fromTFHub değerini true olarak ayarlamayı unutmadan await tf.loadGraphModel() kullanarak modeli yükleyebilirsiniz. Bu, yalnızca TF Hub'da barındırılan modellerin kullanıldığı özel bir durumdur ve bu ek özelliğin ayarlanması gerekir.
Yükleme tamamlandıktan sonra STATUS öğesinin innerText özelliğini bir mesajla ayarlayabilirsiniz. Böylece, öğenin doğru şekilde yüklendiğini görsel olarak görebilir ve veri toplamaya başlayabilirsiniz.
Şimdi yapmanız gereken tek şey modeli ısıtmak. Bunun gibi daha büyük modelleri ilk kez kullandığınızda her şeyi ayarlamak biraz zaman alabilir. Bu nedenle, gelecekte zamanlamanın daha kritik olabileceği durumlarda bekleme süresini önlemek için modele sıfır geçirmek faydalı olur.
Tensorların doğru şekilde, 1 grup boyutuyla ve başlangıçta sabitlerinizde tanımladığınız doğru yükseklik ve genişlikle atıldığından emin olmak için tf.zeros() işlevini tf.tidy() içinde kullanabilirsiniz. Son olarak, renk kanallarını da belirtirsiniz. Bu örnekte model, RGB resimler beklediği için renk kanalı sayısı 3'tür.
Ardından, bu modelin ürettiği görüntü özelliklerinin boyutunu anlamanıza yardımcı olması için answer.shape() kullanarak döndürülen tensörün ortaya çıkan şeklini kaydedin.
Bu işlevi tanımladıktan sonra, sayfa yüklenirken model indirme işlemini başlatmak için hemen çağırabilirsiniz.
Canlı önizlemenizi şu anda görüntülerseniz birkaç dakika sonra durum metninin "TF.js yükleniyor"dan "MobileNet v3 başarıyla yüklendi!" olarak değiştiğini görürsünüz (aşağıda gösterildiği gibi). Devam etmeden önce bu işlemin çalıştığından emin olun.

Bu modelin ürettiği çıktı özelliklerinin yazdırılan boyutunu görmek için konsol çıktısını da kontrol edebilirsiniz. MobileNet modelinde sıfırları çalıştırdıktan sonra [1, 1024] şeklinin yazdırıldığını görürsünüz. İlk öğe yalnızca 1'lik bir grup boyutudur ve yeni nesneleri sınıflandırmanıza yardımcı olmak için kullanılabilecek 1.024 özellik döndürdüğünü görebilirsiniz.
10. Yeni model başlığını tanımlayın
Şimdi de modelinizin başını tanımlama zamanı. Bu, aslında çok minimal bir çok katmanlı algılayıcıdır.
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']
});
Bu kodu inceleyelim. Öncelikle, model katmanları ekleyeceğiniz bir tf.sequential modeli tanımlayarak başlarsınız.
Ardından, bu modele giriş katmanı olarak yoğun bir katman ekleyin. MobileNet v3 özelliklerinden elde edilen çıkışlar bu boyutta olduğundan giriş şekli 1024'dir. Bu durumu, önceki adımda modelden geçirdikten sonra keşfettiniz. Bu katmanda, ReLU etkinleştirme işlevini kullanan 128 nöron bulunur.
Etkinleştirme işlevleri ve model katmanları konusunda yeniyseniz bu özelliklerin arka planda ne yaptığını anlamak için bu atölyenin başında ayrıntılı olarak açıklanan kursa katılabilirsiniz.
Eklenecek bir sonraki katman, çıkış katmanıdır. Nöron sayısı, tahmin etmeye çalıştığınız sınıf sayısına eşit olmalıdır. Bunu yapmak için CLASS_NAMES.length simgesini kullanarak kaç sınıflandırma yapmayı planladığınızı öğrenebilirsiniz. Bu sayı, kullanıcı arayüzünde bulunan veri toplama düğmelerinin sayısına eşittir. Bu bir sınıflandırma sorunu olduğundan, regresyon yerine sınıflandırma sorunlarını çözmek için model oluşturmaya çalışırken kullanılması gereken bu çıkış katmanında softmax etkinleştirmesini kullanırsınız.
Şimdi, yeni tanımlanan modelin genel görünümünü konsola yazdırmak için model.summary() yazdırın.
Son olarak, modeli eğitilmeye hazır hale getirmek için derleyin. Burada optimize edici adam olarak ayarlanmıştır ve CLASS_NAMES.length, 2 değerine eşitse kayıp binaryCrossentropy olur. Sınıflandırılacak 3 veya daha fazla sınıf varsa categoricalCrossentropy kullanılır. Hata ayıklama amacıyla daha sonra günlüklerde izlenebilmesi için doğruluk metrikleri de istenir.
Konsolda aşağıdakine benzer bir şey görmelisiniz:

Bu modelin 130 binden fazla eğitilebilir parametresi olduğunu unutmayın. Ancak bu, normal nöronlardan oluşan basit bir yoğun katman olduğundan oldukça hızlı bir şekilde eğitilir.
Proje tamamlandıktan sonra yapılacak bir etkinlik olarak, ilk katmandaki nöron sayısını değiştirerek iyi bir performans elde etmeye devam ederken bu sayıyı ne kadar düşürebileceğinizi deneyebilirsiniz. Genellikle makine öğreniminde, kaynak kullanımı ve hız arasında en iyi dengeyi sağlayacak optimum parametre değerlerini bulmak için bir miktar deneme yanılma gerekir.
11. Web kamerasını etkinleştirme
Şimdi de daha önce tanımladığınız enableCam() işlevini ayrıntılandırma zamanı. Aşağıda gösterildiği gibi hasGetUserMedia() adlı yeni bir işlev ekleyin ve daha önce tanımlanmış enableCam() işlevinin içeriğini aşağıdaki ilgili kodla değiştirin.
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');
}
}
Öncelikle, temel tarayıcı API'leri özelliklerinin varlığını kontrol ederek tarayıcının getUserMedia() özelliğini destekleyip desteklemediğini kontrol etmek için hasGetUserMedia() adlı bir işlev oluşturun.
enableCam() işlevinde, desteklenip desteklenmediğini kontrol etmek için yukarıda tanımladığınız hasGetUserMedia() işlevini kullanın. Aksi takdirde konsola bir uyarı yazdırın.
Destekliyorsa getUserMedia() çağrınız için bazı kısıtlamalar tanımlayın. Örneğin, yalnızca video akışı istediğinizi, videonun width değerinin 640 piksel, height değerinin ise 480 piksel olmasını tercih ettiğinizi belirtin. Neden? MobileNet modeline aktarılabilmesi için 224 x 224 piksel boyutuna getirilmesi gerekeceğinden bu boyuttan daha büyük bir video elde etmenin pek bir anlamı yoktur. Daha düşük bir çözünürlük isteyerek bazı bilgi işlem kaynaklarından da tasarruf edebilirsiniz. Çoğu kamera bu boyutta çözünürlüğü destekler.
Ardından, yukarıda ayrıntılı olarak açıklanan constraints ile navigator.mediaDevices.getUserMedia() numaralı telefonu arayın ve stream'nin iade edilmesini bekleyin. stream döndürüldüğünde, VIDEO öğenizi srcObject değerini ayarlayarak stream oynatabilirsiniz.
Ayrıca, stream öğesinin ne zaman yüklendiğini ve başarıyla oynatıldığını öğrenmek için VIDEO öğesine bir eventListener da eklemeniz gerekir.
Akış yüklendikten sonra videoPlaying değerini true olarak ayarlayabilir ve ENABLE_CAM_BUTTON değerini kaldırarak sınıfını "removed" olarak ayarlayarak tekrar tıklanmasını önleyebilirsiniz.
Şimdi kodunuzu çalıştırın, kamerayı etkinleştir düğmesini tıklayın ve web kamerasına erişime izin verin. Bu işlemi ilk kez yapıyorsanız sayfadaki video öğesinde aşağıdaki gibi oluşturulmuş bir şekilde görünürsünüz:

Şimdi dataCollector düğmesi tıklamalarıyla ilgilenecek bir işlev ekleme zamanı.
12. Veri toplama düğmesi etkinlik işleyicisi
Şimdi sıra, şu anda boş olan gatherDataForClass(). işlevini doldurmaya geldi. Bu işlevi, codelab'in başında dataCollector düğmeleri için etkinlik işleyici işlevi olarak atamıştınız.
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();
}
Öncelikle, data-1hot işlevini parametre olarak özellik adıyla (bu örnekte data-1hot) çağırarak şu anda tıklanan düğmedeki data-1hot özelliğini kontrol edin.this.getAttribute() Bu bir dize olduğundan, parseInt() işlevini kullanarak bunu tam sayıya dönüştürebilir ve bu sonucu classNumber. adlı bir değişkene atayabilirsiniz.
Ardından, gatherDataState değişkenini uygun şekilde ayarlayın. Mevcut gatherDataState değeri STOP_DATA_GATHER değerine (bunu -1 olarak ayarladınız) eşitse şu anda herhangi bir veri toplamıyorsunuz demektir ve tetiklenen etkinlik bir mousedown etkinliğidir. gatherDataState değerini, az önce bulduğunuz classNumber olarak ayarlayın.
Aksi takdirde, şu anda veri topladığınız ve tetiklenen etkinliğin bir mouseup etkinliği olduğu, artık bu sınıf için veri toplamayı durdurmak istediğiniz anlamına gelir. Kısa süre içinde tanımlayacağınız veri toplama döngüsünü sonlandırmak için durumu STOP_DATA_GATHER olarak ayarlamanız yeterlidir.
Son olarak, sınıf verilerinin kaydını gerçekleştiren dataGatherLoop(), işlevini çağırın.
13. Veri toplama
Şimdi dataGatherLoop() işlevini tanımlayın. Bu işlev, web kamerası videosundan görüntü örnekleme, bu görüntüleri MobileNet modelinden geçirme ve modelin çıkışlarını (1024 özellik vektörü) yakalama işlemlerinden sorumludur.
Ardından, bu verileri hangi sınıfı temsil ettiğini bilmeniz için şu anda basılan düğmenin gatherDataState kimliğiyle birlikte depolar.
Şimdi bu süreci adım adım inceleyelim:
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);
}
}
Bu işlevin yürütülmesine yalnızca videoPlaying doğruysa (yani web kamerası etkinse) ve gatherDataState, STOP_DATA_GATHER'ye eşit değilse ve şu anda sınıf verisi toplama düğmesine basılıyorsa devam edeceksiniz.
Ardından, sonraki kodda oluşturulan tüm tensörleri silmek için kodunuzu tf.tidy() içine alın. Bu tf.tidy() kod yürütme işleminin sonucu imageFeatures adlı bir değişkende saklanır.
Artık tf.browser.fromPixels() kullanarak web kamerasının VIDEO bir karesini alabilirsiniz. Resim verilerini içeren sonuç tensörü videoFrameAsTensor adlı bir değişkende depolanır.
Ardından, videoFrameAsTensor değişkenini MobileNet modelinin girişi için doğru şekle getirin. Yeniden şekillendirmek istediğiniz tensörle birlikte tf.image.resizeBilinear() çağrısını ilk parametre olarak, ardından da daha önce oluşturduğunuz sabitler tarafından tanımlanan yeni yüksekliği ve genişliği tanımlayan bir şekli kullanın. Son olarak, yeniden boyutlandırma sırasında hizalama sorunlarını önlemek için üçüncü parametreyi ileterek köşeleri hizalama ayarını doğru olarak belirleyin. Bu yeniden boyutlandırmanın sonucu resizedTensorFrame adlı bir değişkende saklanır.
Bu basit yeniden boyutlandırma işleminin, web kameranızın görüntüsü 640 x 480 piksel boyutunda olduğundan ve modelin 224 x 224 piksel boyutunda kare bir görüntüye ihtiyacı olduğundan görüntüyü uzattığını unutmayın.
Bu demo için bu yöntem yeterlidir. Ancak bu codelab'i tamamladıktan sonra, daha sonra oluşturabileceğiniz tüm üretim sistemlerinde daha iyi sonuçlar elde etmek için bu resimden kare kırpmayı deneyebilirsiniz.
Ardından, görüntü verilerini normalleştirin. tf.browser.frompixels() kullanılırken görüntü verileri her zaman 0 ile 255 arasında olduğundan, tüm değerlerin 0 ile 1 arasında olmasını sağlamak için yeniden boyutlandırılmışTensorFrame'i 255'e bölmeniz yeterlidir. MobileNet modeli, giriş olarak bu değerleri bekler.
Son olarak, kodun tf.tidy() bölümünde, mobilenet.predict() işlevini çağırarak bu normalleştirilmiş tensörü yüklenen modelden geçirin. Bu işlev, normalizedTensorFrame tensörünün genişletilmiş sürümünü expandDims() kullanarak alır. Böylece, modelin işleme için bir giriş grubu beklediği gibi, 1 öğeli bir grup oluşturulur.
Sonuç döndüğünde, squeeze() işlevini hemen bu döndürülen sonuçta çağırarak sonucu tekrar 1 boyutlu tensöre dönüştürebilirsiniz. Ardından, tf.tidy() işlevinden gelen sonucu yakalayan imageFeatures değişkenine döndürüp atayabilirsiniz.
MobileNet modelinden imageFeatures elde ettiğinize göre, bunları daha önce tanımladığınız trainingDataInputs dizisine aktararak kaydedebilirsiniz.
Ayrıca, geçerli gatherDataState değerini trainingDataOutputs dizisine de göndererek bu girişin neyi temsil ettiğini kaydedebilirsiniz.
gatherDataState değişkeninin, daha önce tanımlanan gatherDataForClass() işlevinde düğme tıklandığında verilerini kaydettiğiniz mevcut sınıfın sayısal kimliğine ayarlanacağını unutmayın.
Bu noktada, belirli bir sınıf için sahip olduğunuz örneklerin sayısını da artırabilirsiniz. Bunu yapmak için öncelikle examplesCount dizinindeki dizinin daha önce başlatılıp başlatılmadığını kontrol edin. Tanımlanmamışsa belirli bir sınıfın sayısal kimliği için sayacı başlatmak üzere 0 olarak ayarlayın. Ardından, geçerli gatherDataState için examplesCount değerini artırabilirsiniz.
Şimdi web sayfasındaki STATUS öğesinin metnini, her sınıf için yakalandıkça geçerli sayıları gösterecek şekilde güncelleyin. Bunu yapmak için CLASS_NAMES dizisinde döngü oluşturun ve examplesCount dizisindeki aynı dizinde bulunan veri sayısı ile birlikte okunabilir adı yazdırın.
Son olarak, bu işlevi tekrar yinelemeli olarak çağırmak için parametre olarak dataGatherLoop ile window.requestAnimationFrame() işlevini çağırın. Bu işlem, düğmenin mouseup değeri algılanana ve gatherDataState değeri STOP_DATA_GATHER, olarak ayarlanana kadar videodan kare örneklemeye devam eder. Bu noktada veri toplama döngüsü sona erer.
Kodunuzu şimdi çalıştırırsanız kamera etkinleştirme düğmesini tıklayabilir, web kamerasının yüklenmesini bekleyebilir ve ardından her bir veri sınıfı için örnek toplamak üzere veri toplama düğmelerinin her birini tıklayıp basılı tutabilirsiniz. Burada, sırasıyla cep telefonum ve elim için veri topladığımı görüyorsunuz.

Yukarıdaki ekran görüntüsünde gösterildiği gibi, tüm tensörler bellekte depolanırken durum metninin güncellendiğini görmelisiniz.
14. Eğit ve tahmin et
Sonraki adım, şu anda boş olan trainAndPredict() işleviniz için kodu uygulamaktır. Transfer öğrenimi burada gerçekleşir. Koda göz atalım:
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);
}
İlk olarak, predict ayarını false olarak belirleyerek mevcut tahminlerin yapılmasını durdurduğunuzdan emin olun.
Ardından, sıranın eğitimde sorunlara neden olmaması için giriş ve çıkış dizilerinizi tf.util.shuffleCombo() kullanarak karıştırın.
Çıkış dizinizi, trainingDataOutputs,, tek sıcaklık kodlamasında kullanılmaya hazır olacak şekilde int32 türünde bir tensor1d'ye dönüştürün. Bu, outputsAsTensor adlı bir değişkende saklanır.
Bu outputsAsTensor değişkeniyle birlikte tf.oneHot() işlevini, kodlanacak maksimum sınıf sayısıyla (yalnızca CLASS_NAMES.length) kullanın. Tek sıcak kodlanmış çıkışlarınız artık oneHotOutputs adlı yeni bir tensörde saklanıyor.
Şu anda trainingDataInputs'nın kaydedilmiş tensör dizisi olduğunu unutmayın. Bunları eğitim için kullanmak üzere tensör dizisini normal bir 2 boyutlu tensöre dönüştürmeniz gerekir.
Bunu yapmak için TensorFlow.js kitaplığında tf.stack() adlı harika bir işlev bulunur.
Bu işlem, bir tensör dizisi alır ve bunları birlikte yığıp çıktı olarak daha yüksek boyutlu bir tensör üretir. Bu durumda, kaydedilen özellikleri içeren ve her biri 1024 uzunluğunda olan 1 boyutlu girişlerden oluşan bir grup olan 2 boyutlu bir tensör döndürülür. Bu, eğitim için ihtiyacınız olan şeydir.
Ardından, özel model başlığını eğitmek için await model.fit() simgesini tıklayın. Burada, eğitim verilerini sırasıyla örnek girişler ve hedef çıkışlar olarak temsil etmek için inputsAsTensor değişkeninizi oneHotOutputs ile birlikte iletiyorsunuz. 3. parametrenin yapılandırma nesnesinde shuffle değerini true olarak ayarlayın, batchSize değerini 5 olarak kullanın, epochs değerini 10 olarak ayarlayın ve ardından kısa süre içinde tanımlayacağınız logProgress işlevi için onEpochEnd değerine callback değerini belirtin.
Son olarak, model eğitildiği için oluşturulan tensörleri atabilirsiniz. Ardından, tahminlerin tekrar yapılabilmesi için predict değerini true olarak ayarlayabilir ve canlı web kamerası görüntülerini tahmin etmeye başlamak için predictLoop() işlevini çağırabilirsiniz.
Ayrıca, yukarıdaki model.fit() içinde kullanılan ve her eğitim turundan sonra sonuçları konsola yazdıran logProcess() işlevini, eğitimin durumunu kaydetmek için tanımlayabilirsiniz.
Doğru cevaba yaklaştınız. Tahmin yapmak için predictLoop() işlevini ekleme zamanı.
Temel tahmin döngüsü
Burada, bir web kamerasından kareler örnekleyen ve her karede ne olduğunu tarayıcıda gerçek zamanlı sonuçlarla sürekli olarak tahmin eden ana tahmin döngüsünü uygularsınız.
Kodu kontrol edelim:
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);
}
}
Tahminlerin yalnızca bir model eğitildikten ve kullanılabilir hale geldikten sonra yapılabilmesi için öncelikle predict değerinin doğru olduğunu kontrol edin.
Ardından, dataGatherLoop() işlevinde yaptığınız gibi mevcut resmin resim özelliklerini alabilirsiniz. Temel olarak, tf.browser.from pixels() kullanarak web kamerasından bir kare alıp normalleştirir, 224 x 224 piksel boyutunda olacak şekilde yeniden boyutlandırır ve ardından sonuçtaki görüntü özelliklerini elde etmek için bu verileri MobileNet modelinden geçirirsiniz.
Ancak artık, yeni eğitilmiş modelinizin başını kullanarak, az önce bulunan imageFeatures sonucunu eğitilmiş modelin predict() işlevinden geçirerek tahmin gerçekleştirebilirsiniz. Ardından, ortaya çıkan tensörü sıkıştırarak tekrar 1 boyutlu hale getirebilir ve prediction adlı bir değişkene atayabilirsiniz.
Bu prediction ile argMax() kullanarak en yüksek değere sahip indeksi bulabilir, ardından en yüksek değere sahip öğenin konumunu keşfetmek için JavaScript'teki temel verilere erişmek üzere arraySync() kullanarak ortaya çıkan tensörü bir diziye dönüştürebilirsiniz. Bu değer, highestIndex adlı değişkende saklanır.
Aynı şekilde, arraySync() tensörünü doğrudan çağırarak gerçek tahmin güven puanlarını da alabilirsiniz.prediction
Artık STATUS metnini prediction verileriyle güncellemek için gereken her şeye sahipsiniz. Sınıfın kullanıcılar tarafından okunabilir dizesini almak için CLASS_NAMES dizisindeki highestIndex değerini arayabilir ve ardından predictionArray değerinden güven değerini alabilirsiniz. Yüzde olarak daha okunabilir hale getirmek için 100 ile çarpıp sonucu math.floor() yapmanız yeterlidir.
Son olarak, hazır olduğunuzda window.requestAnimationFrame() simgesini kullanarak predictionLoop()'ı tekrar arayabilir ve video akışınızda gerçek zamanlı sınıflandırma yapabilirsiniz. Yeni verilerle yeni bir model eğitmek isterseniz bu işlem, predict değeri false olarak ayarlanana kadar devam eder.
Bu da sizi yapbozun son parçasına götürür. Sıfırlama düğmesini uygulama
15. Sıfırlama düğmesini uygulama
Neredeyse tamamlandı. Bulmacanın son parçası, baştan başlamak için sıfırlama düğmesini uygulamaktır. Şu anda boş olan reset() işlevinizin kodu aşağıda verilmiştir. Şu şekilde güncelleyin:
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);
}
İlk olarak, predict değerini false olarak ayarlayarak çalışan tüm tahmin döngülerini durdurun. Ardından, uzunluğunu 0 olarak ayarlayarak examplesCount dizisindeki tüm içerikleri silin. Bu, bir dizideki tüm içerikleri temizlemenin pratik bir yoludur.
Şimdi mevcut tüm kaydedilmiş trainingDataInputs öğelerini inceleyin ve JavaScript çöp toplayıcısı tarafından temizlenmediği için belleği tekrar boşaltmak üzere içindeki her tensörün dispose() olduğundan emin olun.
Bu işlem tamamlandıktan sonra, trainingDataInputs ve trainingDataOutputs dizilerinde dizi uzunluğunu 0 olarak ayarlayarak bunları da temizleyebilirsiniz.
Son olarak, STATUS metnini mantıklı bir değere ayarlayın ve bellekten kalan tensörleri doğruluk kontrolü olarak yazdırın.
Hem MobileNet modeli hem de tanımladığınız çok katmanlı algılayıcı bertaraf edilmediğinden bellekte birkaç yüz tensör kalacağını unutmayın. Bu sıfırlamadan sonra tekrar eğitim yapmaya karar verirseniz bunları yeni eğitim verileriyle yeniden kullanmanız gerekir.
16. Birlikte deneyelim
Öğrenebilir Makine'nin kendi sürümünüzü test etme zamanı geldi!
Canlı önizlemeye gidin, web kamerasını etkinleştirin, odanızdaki bir nesne için 1. sınıf adına en az 30 örnek toplayın, ardından farklı bir nesne için 2. sınıf adına aynı işlemi yapın, eğit'i tıklayın ve ilerlemeyi görmek için konsol günlüğünü kontrol edin. Oldukça hızlı bir şekilde eğitilmesi gerekir:

Eğitim tamamlandıktan sonra, nesneleri kameraya göstererek web sayfasının üst kısmına yakın durum metni alanına yazdırılacak canlı tahminler alın. Sorun yaşıyorsanız tamamlanmış çalışan kodumu kontrol ederek herhangi bir şeyi kopyalamayı unutup unutmadığınızı görün.
17. Tebrikler
Tebrikler! TensorFlow.js'yi tarayıcıda canlı olarak kullanarak ilk transfer öğrenimi örneğinizi tamamladınız.
Bu özelliği deneyin ve çeşitli nesneler üzerinde test edin. Bazı şeylerin, özellikle başka bir şeye benziyorlarsa diğerlerinden daha zor tanındığını fark edebilirsiniz. Bu iki türü ayırt edebilmek için daha fazla sınıf veya eğitim verisi eklemeniz gerekebilir.
Özet
Bu codelab'de şunları öğrendiniz:
- Transfer öğrenimi nedir ve tam bir modeli eğitmenin avantajları nelerdir?
- TensorFlow Hub'dan yeniden kullanıma uygun modelleri nasıl edineceğinizi öğrenin.
- Transfer öğrenmeye uygun bir web uygulaması oluşturma
- Görüntü özellikleri oluşturmak için temel modeli yükleme ve kullanma
- Web kamerası görüntülerindeki özel nesneleri tanıyabilen yeni bir tahmin başlığı nasıl eğitilir?
- Elde edilen modelleri, verileri anlık olarak sınıflandırmak için kullanma
Yapabilecekleriniz
Artık çalışmaya başlayabileceğiniz bir temeliniz olduğuna göre, üzerinde çalıştığınız gerçek hayattaki bir kullanım alanı için bu makine öğrenimi modeli şablonunu genişletmek üzere hangi yaratıcı fikirleri üretebilirsiniz? Belki de şu anda çalıştığınız sektörde devrim yaparak şirketinizdeki kişilerin günlük işlerinde önemli olan şeyleri sınıflandırmak için modeller eğitmesine yardımcı olabilirsiniz. Seçeneklerin sonu gelmez.
Daha fazla bilgi edinmek için bu kursun tamamını ücretsiz olarak inceleyebilirsiniz. Bu kursta, bu codelab'de kullandığınız 2 modeli verimlilik için tek bir modelde nasıl birleştireceğiniz gösterilmektedir.
Ayrıca, orijinal Teachable Machine uygulamasının arkasındaki teori hakkında daha fazla bilgi edinmek isterseniz bu eğitime göz atın.
Ürettiklerinizi bizimle paylaşma
Bugün oluşturduğunuz içerikleri diğer yaratıcı kullanım alanlarında da kolayca kullanabilirsiniz. Yaratıcılığınızı konuşturmaya ve denemeye devam etmenizi öneririz.
Projenizin TensorFlow blogumuzda veya gelecekteki etkinliklerde yer alma şansı için sosyal medyada #MadeWithTFJS hashtag'ini kullanarak bizi etiketlemeyi unutmayın. Ürettiklerinizi görmeyi çok isteriz.
Göz atabileceğiniz web siteleri
- TensorFlow.js resmi web sitesi
- TensorFlow.js hazır modelleri
- TensorFlow.js API'si
- TensorFlow.js Show & Tell: İlham alın ve diğer kullanıcıların neler yaptığını görün.