TensorFlow.js: Kendi "Öğrenebilir Makinenizi" yapın TensorFlow.js ile aktarım öğrenimi kullanma

1. Başlamadan önce

TensorFlow.js model kullanımı son birkaç yılda katlanarak artmıştır ve birçok JavaScript geliştiricisi şu anda mevcut son teknoloji modelleri alıp kendi sektörlerine özgü özel verilerle çalışmak üzere bu modelleri yeniden eğitmek istemektedir. Mevcut bir modeli alıp (genellikle temel model olarak adlandırılır) ve bu modeli benzer ancak farklı bir alanda kullanma eylemine aktarım öğrenimi denir.

Aktarım öğrenimi, tamamen boş bir modelle çalışmaya kıyasla birçok avantaj sunar. Önceden eğitilmiş bir modelden edindiğiniz bilgileri tekrar kullanabilirsiniz ve sınıflandırmak istediğiniz yeni öğe için daha az örnek gerekir. Ayrıca, ağın tamamı yerine model mimarisinin yalnızca son birkaç katmanını yeniden eğitmek zorunda kalacağından eğitim genellikle önemli ölçüde daha hızlıdır. Bu nedenle, aktarımla öğrenme, kaynakların çalıştırılan cihaza göre değişebildiği ancak kolay veri edinme için sensörlere doğrudan erişimi olduğu web tarayıcısı ortamı için çok uygundur.

Bu codelab'de, Google'ın popüler " Öğrenebilir Makine" web sitesi. Web sitesi, kullanıcıların web kamerasından alınan birkaç örnek resimle özel nesneleri tanımak için kullanabileceği işlevsel bir web uygulaması oluşturmanıza olanak tanır. Web sitesi, bu codelab'in makine öğrenimi özelliklerine odaklanabilmeniz için özellikle minimum düzeyde tutulmuştur. Bununla birlikte, orijinal Öğrenebilir Makine web sitesinde olduğu gibi, kullanıcı deneyimini iyileştirmek için mevcut web geliştiricisi deneyiminizden yararlanabileceğiniz pek çok seçenek vardır.

Ön koşullar

Bu codelab, TensorFlow.js önceden hazırlanmış modelleri ve temel API kullanımı hakkında biraz bilgi sahibi olan ve TensorFlow.js'de aktarım öğrenimine başlamak isteyen web geliştiricileri için yazılmıştır.

  • Bu laboratuvarda TensorFlow.js, HTML5, CSS ve JavaScript ile ilgili temel düzeyde bilgi sahibi olduğunuz varsayılır.

Tensorflow.js'yi kullanmaya yeni başladıysanız önce bu ücretsiz sıfır odaklı kursu alabilirsiniz. Bu ücretsiz kurs, makine öğrenimi veya TensorFlow.js ile ilgili bilgi sahibi olmadığını varsaymakta ve bilmeniz gereken her şeyi küçük adımlarla size öğretmektedir.

Neler öğreneceksiniz?

  • TensorFlow.js'nin ne olduğu ve bir sonraki web uygulamanızda neden kullanmanız gerektiği.
  • Öğrenebilir Makine kullanıcı deneyimini taklit eden basitleştirilmiş bir HTML/CSS /JS web sayfası oluşturma.
  • Aktarım öğreniminde kullanılabilecek görüntü özellikleri oluşturmak için önceden eğitilmiş bir temel modeli, özellikle de MobileNet'i yüklemek amacıyla TensorFlow.js'yi kullanma.
  • Tanımak istediğiniz birden çok veri sınıfı için kullanıcının web kamerasından veri toplama.
  • Görüntü özelliklerini alan ve bunları kullanarak yeni nesneleri sınıflandırmayı öğrenen çok katmanlı bir algılayıcı oluşturma ve tanımlama.

Haydi bilgisayar korsanlığı yapalım...

Gerekenler

  • Bu sürecin takibi için bir Glitch.com hesabı tercih edilir veya kendiniz düzenleme ve çalıştırma konusunda rahat olduğunuz bir web sunma ortamı kullanabilirsiniz.

2. TensorFlow.js nedir?

54e81d02971f53e8.png

TensorFlow.js, JavaScript'in mümkün olduğu her yerde çalıştırabilen açık kaynak bir makine öğrenimi kitaplığıdır. Python'da yazılmış orijinal TensorFlow kitaplığına dayanan bu geliştirici deneyimini ve JavaScript ekosistemi için API setini yeniden oluşturmayı amaçlar.

Nerede kullanılabilir?

JavaScript'in taşınabilirliği sayesinde artık 1 dilde yazabilir ve aşağıdaki platformların tümünde kolayca makine öğrenimi gerçekleştirebilirsiniz:

  • Normal JavaScript kullanan web tarayıcısında istemci tarafı
  • Node.js kullanan sunucu tarafı ve hatta Raspberry Pi gibi IoT cihazları
  • Electron kullanan masaüstü uygulamaları
  • React Native kullanan yerel mobil uygulamalar

TensorFlow.js bu ortamların her birinde de birden çok arka ucu destekler (örneğin, CPU veya WebGL gibi çalıştırabildiği donanım tabanlı gerçek ortamlar). Bir "arka uç" (bu bağlamda sunucu tarafı ortamı anlamına gelmez. Yürütme için arka ucu, örneğin WebGL'de istemci tarafı olabilir) uyumluluğu sağlamak ve aynı zamanda çalışmaya hızlı devam etmesini sağlamak için de kullanılmalıdır. TensorFlow.js şu anda aşağıdakileri desteklemektedir:

  • Cihazın grafik kartında WebGL'nin çalıştırılması (GPU): Bu, GPU hızlandırmalı olarak daha büyük modelleri (3 MB'ın üzerinde) yürütmenin en hızlı yoludur.
  • CPU'da Web Derlemesi (WASM) yürütme: Örneğin, eski nesil cep telefonları da dahil olmak üzere tüm cihazlarda CPU performansını iyileştirir. Bu, bir grafik işlemciye içerik yüklemenin ek yükü nedeniyle WASM ile CPU'da WebGL'ye göre daha hızlı çalışabilen daha küçük (boyutu 3 MB'tan küçük) daha küçük modeller için daha uygundur.
  • CPU yürütme: Yedek, diğer ortamların hiçbirinin mevcut olmamasıdır. Bu üçünden en yavaş olanıdır ama her zaman yanınızdadır.

Not: Hangi cihazda çalışacağınızı biliyorsanız bu arka uçlardan birini zorunlu kılmayı seçebilir veya bunu belirtmezseniz TensorFlow.js'nin sizin yerinize karar vermesine izin verebilirsiniz.

İstemci tarafının süper güçleri

İstemci makinedeki web tarayıcısında TensorFlow.js çalıştırmak, dikkate değer birçok avantaj sağlayabilir.

Gizlilik

3. taraf web sunucusuna hiç veri göndermeden istemci makinesinde verileri hem eğitebilir hem de sınıflandırabilirsiniz. Bunun, örneğin GDPR gibi yerel yasalara uymanın gerekli olduğu veya kullanıcının makinesinde tutmak isteyebileceği ve üçüncü bir tarafa göndermeyeceği herhangi bir veriyi işlerken zorunlu olabileceği zamanlar olabilir.

Hız

Uzak sunucuya veri göndermek zorunda olmadığınızdan çıkarım (verileri sınıflandırma işlemi) daha hızlı olabilir. Daha da iyisi, kullanıcı erişim izni verirse kamera, mikrofon, GPS, ivme ölçer ve benzeri cihaz sensörlerine doğrudan erişebilirsiniz.

Erişim ve ölçeklendirme

Dünyadaki herkes tek bir tıklamayla kendisine gönderdiğiniz bir bağlantıyı tıklayabilir, web sayfasını tarayıcılarında açabilir ve yaptıklarınızdan yararlanabilir. CUDA sürücüleri ile karmaşık bir sunucu tarafı Linux kurulumu ve makine öğrenimi sistemini kullanmak için çok daha fazlası gerekmez.

Maliyet

Sunucu olmadığında tek yapmanız gereken HTML, CSS, JS ve model dosyalarınızı barındıracak bir CDN'dir. CDN'nin maliyeti, bir sunucuyu (potansiyel olarak bir grafik kartı takılı) 7/24 çalışan tutmaktan çok daha düşüktür.

Sunucu tarafı özellikler

TensorFlow.js'nin Node.js uygulamasından yararlanmak aşağıdaki özellikleri sağlar.

Tam CUDA desteği

Sunucu tarafında, grafik kartı hızlandırması için TensorFlow'un grafik kartıyla çalışmasını sağlamak amacıyla NVIDIA CUDA sürücülerini yüklemeniz gerekir (WebGL kullanan tarayıcının aksine, yükleme gerekmez). Ancak tam CUDA desteğiyle grafik kartının alt seviye yeteneklerinden 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ığından, performans, Python TensorFlow uygulamasıyla eşittir.

Model Boyutu

Araştırmalardan elde edilen son teknoloji modeller için, belki gigabaytlarca büyüklüğünde çok büyük modellerle çalışıyor olabilirsiniz. Bu modeller, tarayıcı sekmesi başına bellek kullanımı sınırlamaları nedeniyle şu anda web tarayıcısında çalıştırılamaz. Daha büyük olan bu modelleri çalıştırmak için Node.js'yi kendi sunucunuzda, böyle bir modeli verimli bir şekilde çalıştırmak için ihtiyacınız olan donanım özellikleriyle birlikte kullanabilirsiniz.

IOT

Node.js, Raspberry Pi gibi popüler tek kartlı bilgisayarlarda desteklenir. Böylece TensorFlow.js modellerini bu tür cihazlarda da yürütebilirsiniz.

Hız

Node.js, JavaScript'te yazıldığından tam zamanında derleme özelliğinden yararlanır. Bu nedenle, Node.js kullandığınızda, özellikle de yaptığınız ön işlemeler için çalışma zamanında optimize edileceğinden, bu dosyayı kullanırken sıklıkla performans artışları görebilirsiniz. Bunun mükemmel bir örneğini bu başarılı örnekte Hugging Face'in, doğal dil işleme modelinde 2 kat performans artışı elde etmek için Node.js'yi nasıl kullandığını görebilirsiniz.

Artık TensorFlow.js ile ilgili temel bilgileri, nerede çalışabileceğini ve bazı avantajlarını biliyorsunuz. Şimdi de TensorFlow'la faydalı şeyler yapmaya başlayalım.

3. Öğrenmeyi aktar

Aktarımla öğrenme tam olarak nedir?

Aktarımla öğrenme, farklı ama benzer bir şeyi öğrenmek için daha önce öğrenilmiş bilgileri almayı içerir.

İnsanlar da bunu sürekli yaparız. Beyninizde yaşayan, daha önce hiç görmediğiniz yeni şeyleri tanımak için kullanabileceğiniz deneyimler vardır. Örneğin şu söğüt ağacını ele alalım:

e28070392cd4afb9.png

Dünyanın neresinde olduğunuza bağlı olarak, bu ağaç türünü daha önce görmemiş olabilirsiniz.

Yine de aşağıdaki yeni resimde söğüt ağaçları olup olmadığını söylersem, farklı açıda ve size gösterdiğim söğüt ağacından biraz farklı olsalar bile bunları çok hızlı bir şekilde fark edebilirsiniz.

d9073a0d5df27222.png

Beyninizde zaten ağaç benzeri nesneleri tanımlamayı bilen çok sayıda nöron ve uzun, düz çizgileri bulmada başarılı olan diğer nöronlar var. Edindiğiniz bilgileri kullanarak söğüt ağacını hızlı bir şekilde sınıflandırabilirsiniz. Söğüt ağacı, çok sayıda uzun ve düz dikey dallara sahip ağaca benzeyen bir nesnedir.

Benzer şekilde, resimleri tanıma gibi bir alanda zaten eğitilmiş bir makine öğrenimi modeliniz varsa farklı ancak alakalı bir görev gerçekleştirmek için bu modeli yeniden kullanabilirsiniz.

Aynısını, 1000 farklı nesne türünde görüntü tanıma yapabilen çok popüler bir araştırma modeli olan MobileNet gibi gelişmiş bir modelle de yapabilirsiniz. Proje, köpeklerden arabalara kadar milyonlarca etiketli görüntü içeren ImageNet adlı devasa bir veri kümesi kullanılarak eğitildi.

Bu animasyonda, bu MobileNet V1 modelinde sahip olduğu çok sayıda katman görebilirsiniz:

7d4e1e35c1a89715.gif

Bu model, eğitimi sırasında bu 1.000 nesnenin tümü için önemli olan ortak özellikleri nasıl çıkaracağını öğrendi. Bu tür nesneleri tanımlamak için kullandığı alt seviye özelliklerin birçoğu, daha önce hiç görmediği yeni nesnelerin tespit edilmesinde yararlı olabilir. Sonuçta her şey çizgilerin, dokuların ve şekillerin birleşiminden ibarettir.

Şimdi, geleneksel bir Evrimsel Sinir Ağı (CNN) mimarisine (MobileNet'e benzer) bir göz atalım ve aktarımla öğrenmenin yeni bir şey öğrenmek için bu eğitilen ağdan nasıl yararlanabileceğini görelim. Aşağıdaki resimde, elle yazılmış 0 ile 9 arasındaki rakamları tanımak üzere eğitilmiş bir CNN'nin tipik model mimarisi gösterilmektedir:

baf4e3d434576106.png

Eğitilmiş mevcut bir modelin önceden eğitilmiş alt seviye katmanlarını solda gösterilen modelin sonlarına yakın sınıflandırma katmanlarından (bazen modelin sınıflandırma başı olarak da adlandırılır) ayırabilseydiniz, bu katmanları kullanarak herhangi bir görüntü için, eğitimin yapıldığı orijinal verilere göre çıkış özellikleri oluşturabilirsiniz. Aynı ağı, sınıflandırma başlığı kaldırılmış olarak burada görebilirsiniz:

369a8a9041c6917d.png

Tanımaya çalıştığınız yeni şeyin, önceki modelin öğrendiği bu tür çıkış özelliklerinden de yararlanabileceğini varsayarsak bunların yeni bir amaçla yeniden kullanılma olasılıkları yüksektir.

Yukarıdaki şemada, bu varsayımsal model rakamlarla eğitilmiştir. Dolayısıyla, belki rakamlarla ilgili öğrenilenler a, b ve c gibi harflere de uygulanabilir.

Dolayısıyla şimdi gösterildiği gibi bunun yerine a, b veya c'yi tahmin etmeye çalışan yeni bir sınıflandırma başlığı ekleyebilirsiniz:

db97e5e60ae73bbd.png

Burada alt seviye katmanlar donmuş ve eğitilmemiştir. Yalnızca yeni sınıflandırma kafası, soldaki önceden eğitilmiş doğranmış modelin sağladığı özellikleri öğrenmek için kendisini günceller.

Bu eylem, öğrenime aktarma olarak bilinir ve perde arkasında Öğrenebilir Makine'nin yaptığı işlemlerdir.

Ayrıca, çok katmanlı algılayıcıyı yalnızca ağın en ucunda eğitmeniz halinde, tüm ağı sıfırdan eğitmek zorunda kalacağınız duruma göre çok daha hızlı eğitildiğini görebilirsiniz.

Peki, bir modelin alt bölümlerini nasıl kullanabilirsiniz? Öğrenmek için bir sonraki bölüme geçin.

4. TensorFlow Hub - temel modeller

Kullanılacak uygun bir temel model bulun

MobileNet gibi daha gelişmiş ve popüler araştırma modelleri için TensorFlow hub'ına gidebilir, ardından burada gösterilenlere benzer sonuçlar bulmak için MobileNet v3 mimarisini kullanan TensorFlow.js'ye uygun modelleri filtreleyebilirsiniz:

c5dc1420c6238c14.png

Bu sonuçlardan bazılarının "resim sınıflandırması" türünde olduğunu unutmayın (her model kartı sonucunun sol üst tarafında ayrıntılı olarak açıklanmıştır) ve diğerleri "görsel özellik vektörü" türündedir.

Bu Resim Özelliği Vektörü sonuçları, temelde MobileNet'in önceden kesilmiş sürümleridir. Bu sürümleri, nihai sınıflandırma yerine görüntü özelliği vektörlerini almak için kullanabilirsiniz.

Bunun gibi modeller genellikle "temel modeller" Daha sonra, önceki bölümde gösterildiği gibi yeni bir sınıflandırma başlığı ekleyip kendi verilerinizle eğiterek aktarım öğrenmesini gerçekleştirmek için kullanabilirsiniz.

Bir sonraki adım, belirli bir temel model için modelin yayınlandığı TensorFlow.js biçiminin kullanıldığıdır. Bu özellik vektörü MobileNet v3 modellerinden birinin sayfasını açarsanız JS dokümanlarından, bunun tf.loadGraphModel() kullanan dokümanlardaki örnek kod snippet'ine dayalı bir grafik modeli biçiminde olduğunu görebilirsiniz.

f97d903d2e46924b.png

Ayrıca, grafik biçimi yerine katman biçiminde bir model bulursanız eğitim için hangi katmanların dondurulacağını, hangilerinin çözüleceğini seçebileceğinizi de unutmayın. Genellikle "aktarım modeli" olarak adlandırılan yeni bir görev için bir model oluştururken bu çok güçlü olabilir. Ancak şimdilik bu eğitimde çoğu TF Hub modelinin dağıtıldığı varsayılan grafik modeli türünü kullanacaksınız. Katman modelleriyle çalışma hakkında daha fazla bilgi edinmek için sıfırdan hero TensorFlow.js kursuna göz atın.

Öğrenim aktarımının avantajları

Tüm model mimarisini sıfırdan eğitmek yerine aktarımla öğrenmeyi kullanmanın avantajları nelerdir?

Öncelikle eğitim süresi, öğrenmeyi aktarma yaklaşımını kullanmanın en önemli avantajlarından biridir. Bunun nedeni, üzerine inşa edeceğiniz eğitilmiş bir temel modeliniz olması.

İkinci olarak, sınıflandırmaya çalıştığınız yeni ürün için zaten alınmış eğitim yüzünden çok daha az örnek gösterebilirsiniz.

Sınıflandırmak istediğiniz şeye ilişkin örnek verileri toplamak için sınırlı zamanınız ve kaynağınız varsa ve daha sağlam hale getirmek üzere daha fazla eğitim verisi toplamadan önce hızlıca bir prototip oluşturmanız gerekiyorsa bu gerçekten harika bir yöntemdir.

Daha az veri ihtiyacı ve daha küçük bir ağı eğitme hızı göz önünde bulundurulduğunda, aktarım öğrenimi daha az kaynak kullanır. Bu da modern bir makinede tam model eğitiminin saatler, günler veya haftalar yerine sadece onlarca saniyesini aldığından tarayıcı ortamı için son derece uygun olmasını sağlar.

Tamam. Artık Öğrenme Aktarımı'nın ne olduğunu öğrendiniz. Öğrenebilir Makinenizin kendi sürümünüzü oluşturma zamanı geldi. Haydi, başlayalım.

5. Kodlamaya hazırlanın

Gerekenler

Kodlamaya başlayalım

Glitch.com veya Codepen.io için başlangıç olarak kullanılacak ortak şablon şablonları oluşturulmuştur. Bu kod laboratuvarı için iki şablondan birini temel durumunuz olarak tek tıklamayla klonlayabilirsiniz.

Glitch'te, çatallamak ve düzenleyebileceğiniz yeni bir dosya grubu oluşturmak için "remiks yap" düğmesini tıklayın.

Alternatif olarak, Codepen'de " fork" (fork) düğmesini tıklayın.

Bu çok basit iskelet size aşağıdaki dosyaları sağlar:

  • HTML sayfası (index.html)
  • Stil sayfası (style.css)
  • JavaScript kodumuzun (script.js) yazılacağı dosya

Size kolaylık sağlamak amacıyla, TensorFlow.js kitaplığı için HTML dosyasında ek bir içe aktarma işlemi bulunmaktadır. Şö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üzenleyicisini kullanın veya yerel olarak çalışın

Kodu indirip yerel olarak veya farklı bir online düzenleyicide çalışmak istiyorsanız, yukarıda adı geçen 3 dosyayı aynı dizinde oluşturun ve Glitch ortak metnimizdeki kodu kopyalayıp bu dosyaların her birine yapıştırın.

6. Uygulama HTML ortak metni

Nereden başlamalıyım?

Tüm prototipler, bulgularınızı oluşturabileceğiniz bazı temel HTML iskeleleri gerektirir. Şimdi ayarlayın. Şunları ekleyeceksiniz:

  • Sayfa için bir başlık.
  • Açıklayıcı metinler.
  • 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 birkaç düğme.
  • Daha sonra kodlayacağınız TensorFlow.js ve JS dosyaları için içe aktarma işlemleri.

index.html uygulamasını açın ve yukarıdaki özellikleri ayarlamak için aşağıdaki kodu içeren mevcut kodu 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 &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>

Ayrıntılı bilgi edinin

Eklediğiniz bazı önemli öğeleri vurgulamak için yukarıdaki HTML kodunun bazılarını daha ayrıntılı bir şekilde inceleyelim.

  • Sayfa başlığı için bir <h1> etiketi ile birlikte "durum" kimliğine sahip bir <p> etiketi eklediniz. Bu, çıktıları görüntülemek için sistemin farklı bölümlerini kullandığınızda bilgileri yazdıracağınız yerdir.
  • Kimliği "web kamerası" olan bir <video> öğesi eklediniz: Bunlara giderek daha sonra web kamerası akışınızı oluşturabilirsiniz.
  • 5 <button> öğesi eklediniz. İlki, 'enableCam' kimliğine sahip, kamerayı etkinleştirir. Sonraki iki düğmenin sınıfı "dataCollector"dır. Bu, tanımak istediğiniz nesneler için örnek görüntüler toplamanızı sağlar. Daha sonra yazdığınız kod, bu düğmeleri istediğiniz kadar ekleyebilmeniz için tasarlanmıştır ve bu düğmeler otomatik olarak amaçlanan şekilde çalışır.

Bu düğmelerin, birinci sınıf için 0'dan başlayan bir tam sayı değerine sahip, data-1hot adı verilen özel bir kullanıcı tanımlı özelliğe de sahip olduğuna dikkat edin. Belirli bir sınıfın verilerini temsil etmek için kullanacağınız sayısal dizindir. ML modelleri yalnızca sayılarla çalışabildiğinden, çıkış sınıflarını dize yerine sayısal bir gösterimle doğru şekilde kodlamak için dizin kullanılır.

Ayrıca, bu sınıf için kullanmak istediğiniz okunabilir adı içeren bir data-name özelliği vardır. Bu özellik, 1 etkin kodlamadaki sayısal dizin değeri yerine kullanıcıya daha anlamlı bir ad sağlamanıza olanak tanır.

Son olarak, veriler toplandıktan sonra eğitim sürecini başlatmak veya uygulamayı sırasıyla sıfırlamak için bir eğit ve sıfırlama düğmesi bulunur.

  • Ayrıca 2 <script> içe aktarma işlemi eklediniz. Biri TensorFlow.js için, diğeri de kısa süre içinde tanımlayacağınız script.js içindir.

7. Stil ekle

Öğe varsayılanları

Doğru şekilde oluşturulduklarından emin olmak için az önce eklediğiniz HTML öğelerine stil ekleyin. Konum ve boyut öğelerine doğru şekilde eklenen bazı stilleri burada görebilirsiniz. Çok özel bir şey yok. Öğrenilebilir makine videosunda gördüğünüz gibi daha sonra bunu daha iyi bir kullanıcı deneyimi oluşturmak için elbette ekleyebilirsiniz.

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%;
}

Çok güzel! Hepsi bu kadar. Çıkışı şu anda önizlerseniz aşağıdaki gibi görünecektir:

81909685d7566dcb.png

8. JavaScript: Anahtar sabit değerleri ve işleyiciler

Anahtar sabit değerlerini tanımlama

Öncelikle, uygulama genelinde kullanacağınız bazı temel sabit değerleri ekleyin. script.js içeriğini şu sabit değerlerle 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 = [];

Bunların ne işe yaradığını adım adım inceleyelim:

  • STATUS yalnızca durum güncellemelerini yazacağınız paragraf etiketine bir referans içerir.
  • VIDEO, web kamerası feed'ini oluşturacak HTML video öğesine bir referans içerir.
  • ENABLE_CAM_BUTTON, RESET_BUTTON ve TRAIN_BUTTON, HTML sayfasındaki tüm tuş düğmelerine ilişkin DOM referanslarını alır.
  • MOBILE_NET_INPUT_WIDTH ve MOBILE_NET_INPUT_HEIGHT, sırasıyla MobileNet modelinin beklenen giriş genişliğini ve yüksekliğini tanımlar. Bunu dosyanın üst kısmına yakın bir yerde sabit bir konumda depolayarak, daha sonra farklı bir sürüm kullanmaya karar verirseniz, değerleri birçok farklı yerde değiştirmek yerine bir kez güncellemek daha kolay olur.
  • STOP_DATA_GATHER - 1 olarak ayarlandı. Kullanıcının web kamerası feed'inden veri toplamak için bir düğmeyi tıklamayı ne zaman bıraktığını bilebilmeniz için bir durum değeri depolanır. Bu numaraya daha anlamlı bir ad verilmesi, kodu daha sonra daha okunabilir hale getirir.
  • CLASS_NAMES, arama işlevi görür ve olası sınıf tahminleri için kullanıcılar tarafından okunabilen adları tutar. Bu dizi daha sonra doldurulacak.

Temel öğelere referanslarınız olduğuna göre şimdi bazı etkinlik işleyicileri bunlarla ilişkilendirmenin zamanı geldi.

Önemli etkinlik işleyiciler ekleme

Aşağıdaki gibi tuş düğmelerine tıklama etkinlik 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 enabledCam işlevini çağırır.

TRAIN_BUTTON - tıklandığında TrainAndEstimate'i çağırır.

RESET_BUTTON - Tıklandığında aramalar sıfırlanır.

Son olarak bu bölümde, "dataCollector" sınıfına sahip tüm düğmeleri document.querySelectorAll() kullanılıyor. Bu komut, dokümanda bulunan ve aşağıdakilerle eşleşen bir öğe 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ı:

Daha sonra bulunan düğmeleri tekrarlıyor ve her biriyle 2 etkinlik işleyici ilişkilendiriyorsunuz. Biri "mousedown", diğeri de "mouseup" içindir. Bu sayede, düğmeye basıldığı sürece örnekleri kaydetmeye devam edebilirsiniz. Bu da veri toplama açısından kullanışlıdır.

Her iki etkinlik de daha sonra tanımlayacağınız bir gatherDataForClass işlevini çağırır.

Bu noktada, HTML düğmesi özelliğindeki data-name özelliğinde bulunan insan tarafından okunabilen sınıf adlarını da CLASS_NAMES dizisine aktarabilirsiniz.

Ardından, daha sonra kullanılacak temel öğeleri 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;

Bunları tek tek ele alalım.

İlk olarak, yüklenen mobil ağ modelini depolamak için bir mobilenet değişkeniniz vardır. Başlangıçta bunu tanımsız olarak ayarlayın.

Şimdi gatherDataState adlı bir değişkeniniz var. "DataCollector" düğmesine basıldığında, bu düğme, HTML'de tanımlandığı gibi ilgili düğmenin 1 etkin 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ılmadan veri toplamaz.

videoPlaying, web kamerası akışının başarıyla yüklenip oynatılmadığını ve kullanılabilir olup olmadığını takip eder. Siz ENABLE_CAM_BUTTON. düğmesine basana kadar web kamerası açık olmadığından başlangıçta bu ayar false değerine ayarlanır

Ardından 2 dizi (trainingDataInputs ve trainingDataOutputs) tanımlayın. Bu öğeler, "dataCollector" öğesini tıkladığınızda toplanan eğitim verisi değerlerini depolar sırasıyla MobileNet temel modeli tarafından oluşturulan giriş özellikleri ve örneklenen çıkış sınıfı için düğmeler.

Ardından son bir dizi olan examplesCount,, sınıfları eklemeye başladığınızda her bir sınıf için kaç örnek bulunduğunu izlemek amacıyla tanımlanır.

Son olarak, tahmin döngünüzü kontrol eden predict adlı bir değişkene sahipsiniz. Bu, başlangıçta false olarak ayarlanır. Bu ayar daha sonra true olarak ayarlanana kadar tahmin gerçekleştirilemez.

Tüm anahtar değişkenler tanımlandığına göre şimdi sınıflandırma yerine görüntü özelliği vektörleri sağlayan önceden kesilmiş 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, eş zamansız bir işlev 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, yüklenecek modelin TFHub dokümanlarında bulunduğu URL öğesini tanımlarsınız.

Daha sonra, bu Google web sitesinden bir model yüklerken fromTFHub özel özelliğini true olarak ayarlamayı hatırlayarak await tf.loadGraphModel() yöntemini kullanarak modeli yükleyebilirsiniz. Bu, yalnızca bu ek özelliğin ayarlanması gereken TF Hub'da barındırılan modellerin kullanımına yönelik özel bir durumdur.

Yükleme tamamlandıktan sonra, STATUS öğesinin innerText değerini bir mesajla ayarlayabilirsiniz. Böylece, doğru şekilde yüklendiğini ve veri toplamaya hazır olduğunuzu görsel olarak görebilirsiniz.

Şu anda yapmanız gereken tek şey modeli ısıtmak. Bunun gibi daha büyük modellerle, modeli ilk kez kullandığınızda her şeyin ayarlanması biraz zaman alabilir. Bu nedenle, zamanlamanın daha kritik olabileceği gelecekte bekleme durumlarını önlemek için modelde sıfırların iletilmesine yardımcı olur.

Tensörlerin doğru şekilde atılmasını sağlamak için tf.tidy() içine sarmalanmış tf.zeros() kullanabilirsiniz. Grup boyutu 1 olmalıdır ve başlangıçta sabit değerlerinizde tanımladığınız doğru yükseklik ve genişliğe sahip olmalıdır. Son olarak, renk kanallarını da belirtirsiniz. Bu durumda, model RGB resimleri beklediği için bu sayı 3'tür.

Daha sonra, 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 elde edilen şeklini günlüğe kaydedin.

Bu işlevi tanımladıktan sonra, sayfa yüklenirken model indirme işlemini başlatmak için işlevi hemen çağırabilirsiniz.

Canlı önizlemenizi şu anda görüntülüyorsanız, birkaç dakika sonra durum metninin "TF.js yüklemesi bekleniyor" durumundan değiştiğini görürsünüz "MobileNet v3 başarıyla yüklendi!" aşağıda gösterildiği gibidir. Devam etmeden önce bunun çalıştığından emin olun.

a28b734e190afff.png

Bu modelin ürettiği çıkış özelliklerinin yazdırılan boyutunu görmek için konsol çıkışını da kontrol edebilirsiniz. MobileNet modelinde sıfırlar çalıştırdıktan sonra [1, 1024] biçiminde bir şekil görürsünüz. İlk öğe sadece 1'lik grup boyutudur ve gerçekte daha sonra yeni nesneleri sınıflandırmanıza yardımcı olmak için kullanılabilecek 1024 özellikleri döndürdüğünü görebilirsiniz.

10. Yeni model başlığını tanımlayın

Şimdi, temel olarak çok katmanlı çok katmanlı bir algılayıcı olan modelinizin başını tanımlama zamanı geldi.

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']  
});

Şimdi bu kodu inceleyelim. Model katmanları ekleyeceğiniz bir tf.sıralı model tanımlayarak başlarsınız.

Daha sonra, bu modele giriş katmanı olarak yoğun bir katman ekleyin. MobileNet v3 özelliklerinden gelen çıkışlar bu boyutta olduğundan 1024 biçiminde bir giriş şekline sahiptir. Bunu, önceki adımda modelden geçirdikten sonra keşfettiniz. Bu katmanda ReLU aktivasyon işlevini kullanan 128 nöron vardır.

Etkinleştirme işlevleri ve model katmanları konusunda yeniyseniz bu özelliklerin perde arkasında neler yaptığını öğrenmek için bu atölyenin başında ayrıntılı olarak verilen 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, kaç sınıfı sınıflandırmayı planladığınızı bulmak üzere CLASS_NAMES.length kullanabilirsiniz. Bu, 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 problemlerini çözmek için model oluşturmaya çalışırken kullanılması gereken softmax etkinleştirmesini bu çıkış katmanında kullanırsınız.

Şimdi, yeni tanımlanan modelin genel bakışını konsola yazdırmak için bir model.summary() yazdırın.

Son olarak, modeli eğitilmeye hazır olacak şekilde derleyin. Burada, optimize edici adam olarak ayarlanmıştır. CLASS_NAMES.length, 2 değerine eşitse kayıp binaryCrossentropy, sınıflandırılacak 3 veya daha fazla sınıf varsa categoricalCrossentropy değerini kullanır. Hata ayıklama amacıyla daha sonra günlüklerde izlenebilmesi için doğruluk metrikleri de istenir.

Konsolda şuna benzer bir şey görürsünüz:

22eaf32286fea4bb.png

Bunun 130 binden fazla eğitilebilir parametreye sahip olduğunu unutmayın. Ama bu, normal nöronlardan oluşan basit, yoğun bir katman olduğu için oldukça hızlı eğitilecek.

Proje tamamlandığında yapılacak bir etkinlik olarak, yine iyi performans elde ederken ilk katmandaki nöron sayısını değiştirmeyi deneyerek bunu ne kadar düşük yapabileceğinizi görebilirsiniz. Makine öğreniminde, kaynak kullanımı ile hız arasında en iyi dengeyi sağlamak amacıyla optimum parametre değerlerini bulmak için belirli bir düzeyde deneme yanılma yöntemi gerekir.

11. Web kamerasını etkinleştirme

Şimdi, daha önce tanımladığınız enableCam() işlevini geliştirme zamanı. Aşağıda gösterildiği gibi hasGetUserMedia() adlı yeni bir işlev ekleyin ve daha sonra, önceden tanımlanan 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'si özelliklerinin olup olmadığını kontrol ederek tarayıcının getUserMedia() öğesini 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. Değilse konsola bir uyarı yazdırın.

Destekleniyorsa getUserMedia() çağrınız için bazı kısıtlamalar tanımlayın (örneğin, yalnızca video akışını istediğiniz gibi) ve videonun width öğesinin 640 piksel boyutunda, height öğesinin ise 480 piksel olmasını tercih edin. Neden? Aslında bir videoyu bundan daha büyük hale getirmenin pek bir anlamı yoktur. MobileNet modeline aktarılması için 224 x 224 piksel olarak yeniden boyutlandırılması gerekir. Daha düşük bir çözünürlük isteyerek de bazı bilgi işlem kaynaklarından tasarruf edebilirsiniz. Çoğu kamera bu boyuttaki çözünürlüğü destekler.

Ardından, yukarıda ayrıntıları verilen constraints ile navigator.mediaDevices.getUserMedia() numaralı telefonu arayın ve stream ürününün döndürülmesini bekleyin. stream döndürüldükten sonra, VIDEO öğenizi srcObject değeri olarak ayarlayarak stream öğesini oynatmasını sağlayabilirsiniz.

stream öğesinin ne zaman yüklendiğini ve başarıyla oynatıldığını öğrenmek için VIDEO öğesine bir eventListener eklemeniz gerekir.

Akış yüklendikten sonra videoPlaying öğesini true olarak ayarlayabilir ve tekrar tıklanmasını önlemek için sınıfını "removed" olarak ayarlayarak ENABLE_CAM_BUTTON öğesini kaldırabilirsiniz.

Şimdi kodunuzu çalıştırın, kamerayı etkinleştir düğmesini tıklayın ve web kamerasına erişim izni verin. Bunu ilk kez yapıyorsanız sayfadaki video öğesinde kendinizi aşağıdaki gibi görürsünüz:

b378eb1affa9b883.png

Pekala, şimdi dataCollector düğme tıklamaları ile ilgilenmek için bir işlev ekleme zamanı.

12. Veri toplama düğmesi etkinlik işleyicisi

Şimdi sıra, şu anda boş olan gatherDataForClass(). işlevinizi doldurmaya geldi. Bu, codelab'in başında dataCollector düğmeleri için etkinlik işleyici işleviniz olarak atadığınız işlevdir.

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, özelliğin adı ile this.getAttribute() (bu örnekte parametre olarak data-1hot) çağrısı yaparak o anda tıklanan düğmedeki data-1hot özelliğini kontrol edin. Bu bir dize olduğundan, parseInt() kullanarak onu bir tam sayıya dönüştürebilir ve bu sonucu classNumber. adlı bir değişkene atayabilirsiniz

Sonra, gatherDataState değişkenini uygun şekilde ayarlayın. Geçerli gatherDataState, STOP_DATA_GATHER değerine eşitse (-1 olarak ayarladığınız) bu, şu anda hiç veri toplamdığınız ve tetiklenen bir mousedown etkinliği olduğu anlamına gelir. gatherDataState öğesini az önce bulduğunuz classNumber olarak ayarlayın.

Aksi takdirde, şu anda veri toplamakta olduğunuz, tetiklenen etkinliğin bir mouseup etkinliği olduğu ve 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 bunu tekrar STOP_DATA_GATHER durumuna ayarlamanız yeterlidir.

Son olarak, sınıf verilerini kaydeden dataGatherLoop(), aramasını başlatın.

13. Veri toplama

Şimdi, dataGatherLoop() işlevini tanımlayın. Bu işlev, web kamerası videosundan görüntü örneklemekten, bunları MobileNet modelinden geçirmekten ve bu modelin çıktılarını (1024 özellik vektörleri) yakalamaktan sorumludur.

Daha sonra, bu verilerin hangi sınıfı temsil ettiğini bilmeniz için bunları şu anda basılan düğmenin gatherDataState kimliğiyle birlikte depolar.

Bu konuyu 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 true ise, yani web kamerası etkin olduğunda ve gatherDataState, STOP_DATA_GATHER değerine eşit değilse ve sınıf verilerini toplamak için bir düğmeye basılıyorsa devam edeceksiniz.

Ardından, oluşturulan tensörleri aşağıdaki kodda atmak için kodunuzu tf.tidy() içine yerleştirin. Bu tf.tidy() kod yürütme işleminin sonucu imageFeatures adlı bir değişkende depolanır.

Artık tf.browser.fromPixels() kullanarak VIDEO web kamerasının bir karesini alabilirsiniz. Resim verilerini içeren elde edilen tensör, videoFrameAsTensor adlı bir değişkende depolanır.

Ardından, videoFrameAsTensor değişkenini MobileNet modelinin girişi için doğru şekilde olacak şekilde yeniden boyutlandırın. İlk parametre olarak yeniden şekillendirmek istediğiniz tensörü ve ardından daha önce oluşturduğunuz sabitlerle tanımlanan yeni yüksekliği ve genişliği tanımlayan bir şekli içeren bir tf.image.resizeBilinear() çağrısı kullanın. Son olarak, yeniden boyutlandırma sırasında hizalama sorunlarını önlemek için üçüncü parametreyi ileterek köşeleri doğru değerine ayarlayın. Bu yeniden boyutlandırmanın sonucu resizedTensorFrame adlı bir değişkende depolanır.

Web kamerası resminizin boyutu 640 x 480 piksel olduğundan ve modelin 224 x 224 piksel boyutunda kare bir resme ihtiyacı olduğundan, bu temel yeniden boyutlandırmanın görüntüyü uzattığını unutmayın.

Bu demonun amacına uygun şekilde çalışması gerekir. Ancak bu codelab'i tamamladıktan sonra, daha sonra oluşturabileceğiniz üretim sistemlerinde daha da iyi sonuçlar elde etmek için resimdeki bir kareyi kırpmayı deneyebilirsiniz.

Daha sonra, resim verilerini normalleştirin. tf.browser.frompixels() kullanılırken resim verileri her zaman 0-255 aralığında olur. Böylece, tüm değerlerin 0 ile 1 arasında olmasını sağlamak için yeniden boyutlandırılanTensorFrame'i 255'e bölebilirsiniz. MobileNet modelinin giriş olarak beklediği değer budur.

Son olarak, kodun tf.tidy() bölümünde, mobilenet.predict() öğesini çağırarak bu normalleştirilmiş tensörü yüklenen modele aktarın. Daha sonra, expandDims() kullanarak normalizedTensorFrame öğesinin genişletilmiş sürümünü iletirsiniz ve model, işleme için toplu giriş yapılmasını beklediğinden, bu tensor 1'den oluşur.

Sonuç geri geldiğinde, döndürülen bu sonuçta hemen squeeze() öğesini çağırarak sonucu 1D tensöre indirgeyebilirsiniz. Daha sonra, döndürüp tf.tidy() öğesinden sonucu yakalayan imageFeatures değişkenine atayabilirsiniz.

Artık MobileNet modelinden imageFeatures aldınız. Bunları önceden tanımladığınız trainingDataInputs dizisine aktararak kaydedebilirsiniz.

Ayrıca, geçerli gatherDataState değerini trainingDataOutputs dizisine aktararak bu girişin temsil ettiği şeyi kaydedebilirsiniz.

gatherDataState değişkeninin, önceden tanımlanan gatherDataForClass() işlevinde düğme tıklandığında veri kaydettiğiniz geçerli sınıfın sayısal kimliğine ayarlanmış olacağını unutmayın.

Bu noktada, belirli bir sınıf için sahip olduğunuz örnek sayısını da artırabilirsiniz. Bunu yapmak için önce examplesCount dizisindeki dizinin 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 STATUS öğesinin web sayfasındaki metnini güncelleyerek her sınıfın mevcut sayılarını yakalandıklarında gösterin. Bunu yapmak için CLASS_NAMES dizisinde döngü yapın ve okunabilir adı, examplesCount dizinindeki veri sayısıyla birlikte yazdırın.

Son olarak, bu işlevi yinelenen şekilde tekrar çağırmak için parametre olarak dataGatherLoop iletilmiş window.requestAnimationFrame() öğesini çağırın. Bu işlem, düğmenin mouseup değeri algılanana kadar videodan kare örneklemeye devam eder. gatherDataState ise STOP_DATA_GATHER, değerine ayarlandığında veri toplama döngüsü sona erer.

Kodunuzu şimdi çalıştırırsanız kamerayı etkinleştir düğmesini tıklayabilir, web kamerasının yüklenmesini bekleyebilir ve her bir veri sınıfına ilişkin örnekler toplamak için 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.

541051644a45131f.gif

Yukarıdaki ekran görüntüsünde gösterildiği gibi, tüm tensörler bellekte depolandığından durum metninin güncellendiğini görürsünüz.

14. Eğit ve tahmin et

Sonraki adım, şu anda boş olan trainAndPredict() fonksiyonunuz için kodu uygulamaktır. Bu işlev, aktarım öğrenmenin gerçekleştiği yerdir. 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);
}

Öncelikle, predict öğesini false olarak ayarlayarak mevcut tahminlerin gerçekleşmesini durdurduğunuzdan emin olun.

Ardından, sıralamanın eğitimde sorunlara neden olmaması için tf.util.shuffleCombo() kullanarak giriş ve çıkış dizilerinizi karıştırın.

trainingDataOutputs, çıkış dizinizi, int32 türünde bir tensor1d olacak şekilde değiştirerek tek çalışan kodlamada kullanılmaya hazır olmasını sağlayın. Bu değer, outputsAsTensor adlı bir değişkende depolanır.

tf.oneHot() işlevini, kodlanacak maksimum sınıf sayısı (yalnızca CLASS_NAMES.length) ile birlikte bu outputsAsTensor değişkeniyle birlikte kullanın. Çalışır durumda kodlanmış bir çıktınız artık oneHotOutputs adlı yeni bir tensörde depolanır.

Şu anda trainingDataInputs değerinin, kayıtlı bir tensör dizisi olduğunu unutmayın. Bunları eğitimde kullanmak için, tensör dizisini normal bir 2D tensör olacak şekilde dönüştürmeniz gerekir.

Bunu yapmak için TensorFlow.js kitaplığında tf.stack() adlı harika bir işlev vardır,

Bu yöntem, bir tensör dizisi alır ve bunları bir araya getirerek çıktı olarak daha yüksek boyutlu bir tensör üretir. Bu durumda bir tensör 2D döndürülür. Bu, her biri 1024 uzunluğunda olan ve kaydedilen özellikleri içeren ve eğitim için ihtiyacınız olan 1 boyutsal girdiden oluşan bir gruptur.

Ardından, özel model başlığını eğitmek için await model.fit(). Burada, sırasıyla örnek girişler ve hedef çıkışlar gibi kullanılacak eğitim verilerini temsil etmek için inputsAsTensor değişkeninizi oneHotOutputs ile birlikte iletirsiniz. 3. parametrenin yapılandırma nesnesinde shuffle öğesini true olarak ayarlayın, epochs değeri 10 olacak şekilde batchSize öğesini kullanın ve ardından kısa süre içinde tanımlayacağınız logProgress işlevine onEpochEnd için bir callback değeri belirtin.5

Son olarak, model eğitilirken oluşturulan tensörleri kaldırabilirsiniz. Ardından, tahminlerin tekrar gerçekleşebilmesi için predict değerini yeniden true değerine ayarlayabilir ve canlı web kamerası görüntülerini tahmin etmeye başlamak için predictLoop() işlevini çağırabilirsiniz.

Yukarıdaki model.fit() öğesinde kullanılan ve her eğitim turundan sonra sonuçları konsola yazdıran eğitim durumunu kaydetmek için logProcess() işlevini de tanımlayabilirsiniz.

Doğru cevaba yaklaştınız. Tahminde bulunmak için predictLoop() işlevini eklemeniz gerekir.

Temel tahmin döngüsü

Burada, bir web kamerasından kareleri örnekleyen ve tarayıcıdaki gerçek zamanlı sonuçlarla her karede neler olduğunu 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);
  }
}

Öncelikle, tahminlerin yalnızca model eğitildikten ve kullanılabilir hale geldikten sonra yapılması için predict değerinin doğru olduğundan emin olun.

Daha sonra, dataGatherLoop() işlevinde yaptığınız gibi geçerli görsel için resim özelliklerini kullanabilirsiniz. Esasen, tf.browser.from pixels() kullanarak web kamerasından bir kare alır, bu kareyi normalleştirir, 224 x 224 piksel boyutunda olacak şekilde yeniden boyutlandırır ve ardından, elde edilen görüntü özelliklerini elde etmek için bu verileri MobileNet modeli üzerinden aktarırsınız.

Şimdi ise yeni eğitilen model başlığını kullanarak, eğitilen modelin predict()işlevinden az önce bulunan imageFeatures değerini ileterek bir tahmin gerçekleştirebilirsiniz. Daha sonra, elde edilen tensörü sıkarak tekrar 1 boyutlu hale getirebilir ve prediction adlı bir değişkene atayabilirsiniz.

Bu prediction ile, argMax() kullanarak en yüksek değere sahip dizini bulabilir ve ardından en yüksek değere sahip öğenin konumunu öğrenmek için temel verileri almak amacıyla arraySync() kullanarak bu sonuç tensörü bir diziye dönüştürebilirsiniz. Bu değer, highestIndex adlı değişkende depolanır.

Ayrıca, doğrudan prediction tensöründe arraySync() öğesini çağırarak gerçek tahmin güven puanlarını aynı şekilde alabilirsiniz.

Artık STATUS metnini prediction verileriyle güncellemek için ihtiyacınız olan her şeye sahipsiniz. Sınıf için okunabilir dizeyi elde etmek üzere CLASS_NAMES dizisinde highestIndex öğesini arayabilir ve ardından predictionArray öğesinden güven değerini alabilirsiniz. Yüzde olarak daha okunabilir hale getirmek için 100 ile çarpıp sonucu math.floor() ile çarpmanız yeterlidir.

Son olarak, video akışınızdaki gerçek zamanlı sınıflandırmaları almak üzere hazır olduğunda predictionLoop() işlemini baştan yapmak için window.requestAnimationFrame() öğesini kullanabilirsiniz. Yeni verilerle yeni bir model eğitmeyi seçerseniz bu durum predict, false olarak ayarlanana kadar devam eder.

Bu da sizi yapbozun son parçasına getiriyor. Sıfırlama düğmesini uygulama.

15. Sıfırla düğmesini uygulama

Neredeyse tamamlandı. Yapbozun son parçası, baştan başlamak için bir sıfırlama düğmesi uygulamaktır. Şu anda boş olan reset() işlevinizin kodu aşağıdadır. Aşağıdaki gibi 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);
}

Öncelikle, predict öğesini false olarak ayarlayarak çalışan tüm tahmin döngülerini durdurun. Daha sonra, uzunluğunu 0 değerine ayarlayarak examplesCount dizisindeki tüm içerikleri silin. Bu işlem, bir dizideki tüm içerikleri temizlemek için kullanışlı bir yöntemdir.

Şimdi kayıtlı tüm trainingDataInputs öğelerini gözden geçirin ve Tensor'lar JavaScript çöp toplayıcı tarafından temizlenmeyeceğinden, bellekte tekrar yer açmak için tensörde bulunan her tensörden dispose() emin olun.

Bu işlem tamamlandıktan sonra artık dizi uzunluğunu hem trainingDataInputs hem de trainingDataOutputs dizilerinde 0 değerine ayarlayarak bunları da temizleyebilirsiniz.

Son olarak STATUS metnini mantıklı bir yere ayarlayın ve doğruluk kontrolü için bellekte kalan tensörleri yazdırın.

Hem MobileNet modeli hem de çok katmanlı algılayıcı atılmadığı için hâlâ bellekte birkaç yüz tensör bulunacağını unutmayın. Bu sıfırlama işleminden sonra tekrar eğitime karar verirseniz yeni eğitim verileriyle bunları yeniden kullanmanız gerekir.

16. Haydi deneyelim

Öğrenebilir Makine'nin kendi sürümünüzü test etmenin zamanı geldi.

Canlı önizlemeye gidin, web kamerasını etkinleştirin, odanızdaki bir nesne için 1. sınıf için en az 30 örnek toplayın, ardından aynı işlemi 2. sınıf için başka bir nesne için yapın, eğit'i tıklayın ve ilerleme durumunu görmek için konsol günlüğünü kontrol edin. Oldukça hızlı eğitilmesi gerekir:

bf1ac3cc5b15740.gif

Eğitildikten sonra, web sayfasının üst kısmına yakın durum metni alanına yazdırılacak canlı tahminleri almak için nesneleri kameraya gösterin. Sorun yaşıyorsanız, kopyalamayı gözden kaçırıp atlamadığınızı görmek için tamamlanan çalışma kodumu kontrol edin.

17. Tebrikler

Tebrikler! Tarayıcıda TensorFlow.js canlı yayını kullanarak ilk aktarım öğrenme örneğinizi tamamladınız.

Deneyin ve çeşitli nesneler üzerinde test edin. Özellikle başka bir şeye benziyorlarsa, bazı şeyleri tanımanın diğerlerinden daha zor olduğunu fark edebilirsiniz. Bunları birbirinden ayırt edebilmek için daha fazla sınıf veya eğitim verisi eklemeniz gerekebilir.

Özet

Bu codelab'de şunları öğrendiniz:

  1. Aktarım öğreniminin ne olduğu ve tam modelin eğitilmesine kıyasla avantajları.
  2. Yeniden kullanılacak modelleri TensorFlow Hub'dan alma.
  3. Aktarımla öğrenmeye uygun bir web uygulaması oluşturma.
  4. Görsel özellikleri oluşturmak için temel model yükleme ve kullanma
  5. Web kamerası görüntülerinden özel nesneleri tanıyabilen yeni bir tahmin kafası nasıl eğitilir?
  6. Elde edilen modelleri kullanarak verileri gerçek zamanlı olarak sınıflandırma.

Sırada ne var?

Artık başlangıç yapacağınız bir çalışma tabanınız olduğuna göre, üzerinde çalışıyor olabileceğiniz gerçek bir kullanım alanına yönelik bu makine öğrenimi modelinin ortak çalışmasını geliştirmek için hangi yaratıcı fikirleri düşünebilirsiniz? Belki şu anda çalıştığınız sektörde devrim yaratarak şirketinizdeki insanların günlük işlerinde önemli olan şeyleri sınıflandırmaları için modeller eğitmesine yardımcı olabilirsiniz. Seçeneklerin sonu gelmez.

Şu anda bu codelab'de sahip olduğunuz 2 modeli verimlilik için tek bir modelde nasıl birleştireceğinizi gösteren bu kursun tamamına ücretsiz olarak katılabilirsiniz.

Ayrıca, öğretilebilir orijinal makine uygulamasının arkasındaki teori hakkında daha fazla bilgi edinmek isterseniz bu eğitime göz atın.

Yaptıklarınızı bizimle paylaşın

Bugün öğrendiklerinizi diğer yaratıcı kullanım alanlarına da kolayca genişletebilirsiniz. Ayrıca, kalıpların dışına çıkarak fikir edinmenizi ve saldırıya devam etmenizi öneririz.

Projenizin TensorFlow blogumuzda ve hatta gelecekteki etkinliklerde öne çıkarılması için #MadeWithTFJS hashtag'ini kullanarak bizi sosyal medyada etiketlemeyi unutmayın. Neler ürettiğinizi görmekten memnuniyet duyarız.

Göz atılabilecek web siteleri