2022年7月22日 星期五

ml5.js 訓練Model實做

 

前情提要

最近工作又做到了一個撞牆期,對於自己寫出來的程式,或是用來解決問題的思考方式覺得有點乏味,於是,就在深夜學習跟找尋新題材的過程中,發現了之前嘗試過的ml5.js,終於出現了model的save/load的功能,對於前端開法者來說,是一個很好的消息。

不知道ml5.js是什麼的人,簡單來說,它就是一個Tensorflow.js的wrapper framework,它把Tensorflow中的艱深字彙與邏輯包裝起來,引出成簡單易懂的functions,讓你可以幾乎無腦的進行基礎的machine learning實做,在ml5.js的首頁上,就直接有一個image classifier的demo function讓你上傳照片進行照片內容的判別。想要先看看ml5.js能做到什麼的人,可以先到這裡看看它的Examples範例。

另外要先提醒一下,由於ml5.js是由p5.js的組織成員所發起的專案,所以在官方的文件或是範例中,它都是基於使用p5.js的程式邏輯進行撰寫,不過不用擔心,使用ml5.js時,是完全不需使用p5.js的,在等等的實做範例中,我也只會用純Javascript進行。

為了快速讓沒用過p5.js的人,還是能夠快速理解ml5.js官方網站上的範例,我再簡短的說明一下;p5.js是一個Javascript的前端框架,整體的框架架構和風格,都是借鏡另一個Java的Processing framework。而這兩個框架的產生,都是為了降低程式語言學習的門檻,讓藝術家、設計師、教育體系的人或是任何初心者都能夠容易的上手。

p5.js雖然是以繪圖為核心價值,但你上手後,其實你也可以拿來做一般網頁的開發,因為它把許多DOM元素的操作都包成了很直觀的function name。也因為如此,它的程式邏輯與生命週期會稍微和一般傳統的前端開發不太一樣。但要看懂ml5.js上的範例,你其實只要知道兩個重點就好: setup() 和 draw() function。

有寫過Arduino程式的人一定可以馬上了解,因為它就等同於Arduino程式邏輯中的setup()和loop()。在setup() function裡面的程式碼,會在網頁loading完後,先執行過一次,然後就不再執行,接著在draw() funciton 裡面的程式碼,就會像一個大while迴圈一樣,一直不斷地被重複執行。

講了這麼多前情提要,接著就該進入這次的主題了,那就是實做出一個能夠能夠讓你今天立刻帶著走的Image Classification Model。這個Model並不是從零做起,而是借用AI領域中,巨人的肩膀,對已經存在的Model進行Transfer learning的model。

Transfer Learning 的方法就是把 Pre-trained Model 最後一層拔掉 (註:最後一層是用來分類的),加入新的一層,然後用新資料訓練新層的參數。(引用)

而這次的實做,將會使用較為輕量的MobileNet這個Model進行。

開始實做- 阿ㄆ一ㄚˇ、阿尼分類器

1. 引用v0.1.3版本以上的ml5.js

https://unpkg.com/ml5@0.1.3/dist/ml5.min.js

2. 接著先在頁面上放上必要的按鈕和選擇框

說明一下,最上面的兩個file input是要用來讓我們可以選擇特定資料夾路徑用的,方便在測試階段可以比較方便替換拿來訓練的材料,因此會需要加入 webkitdirectory, dierctory, mutiple這些屬性,讓我們可以載入多個檔案,當然你也可以不用這樣做,直接在javascript的部分指定好路徑。(只是我當初在自己動手做的時候,那個moment就是想這樣寫…..) 接著在每個項目上加上id屬性,方便接下來的javascript能夠取得這些DOM元素進行操作。

3. 開始撰寫Javascrip,先從取得DOM元素開始、開始使用ml5.js的FeatureExtractor去載入MobileNet,然後產生一個classifier實例。

ml5.featureExtracture()這個function接受兩個參數:第一個是我們要retrain的model名稱,第二個則是載入後的callback function。

如果順利,這時候應該可以在開啟網頁後經過幾秒,看見”model is ready!!”出現在console中。

這邊要注意一下,ml5.js本身是不包含model檔案的,所以每一次的載入,ml5.js都會幫我們跑去google的CND下載下來,因此才會有callback執行前那幾秒鐘的等待下載時間。至於有沒有可以離線載入model的方法? 目前我還沒去找跟嘗試,所以還不知道,如果你已經有試過的人知道方法,也歡迎在文章後面留言指導。

4.開始撰寫載入素材圖片檔案的部分,同時為檔案標上正確的分類標籤

加入要訓練的圖片,並加上對應的標籤這兩個動作,我是利用在檔案的input element上綁定change event來fire處理事件,而處理方法,就是透過去得input element上的className來做為訓練圖檔的對應標籤(也就是照片的標準答案),接著就歷遍整個file清單,並將檔案圖檔和標籤餵進classifier.addImage()這個function裡面。

在接著try之前,必須要先多做一個動作,由於我們目前所做的環境都是在瀏覽器中,因此在處理local檔案時,會出現Cross-Origin Resource Sharing的問題,chrome會基於安全性的問題不讓你輕易的存取local檔案,最簡單快速的方式就是直接把這份html丟到伺服器環境中,這邊順便推薦一下在npm上的http-server這個套件,安裝好後,你只要在command line中下http-server指令,就會立刻在你當前跟目錄下創建一個伺服器環境,這時只要在localhost的8080 port瀏覽我們在做的html檔案,便可解決cross-origin的問題了。

接著,我們就可以分別載入要拿來訓練的素材圖片了,選完後應該只會先看見input框多出了已經載入圖片的數量,如果這時候你的console裡面沒有出現任何錯誤,那我們應該就已經完成了訓練前的準備動作了。

5.將訓練model匯出model的動作分別綁上Train Button和Save Button

Model的訓練和匯出非常的容易,只需要分別使用classifier.train()和classifier.save()這兩個非常直觀的function就可以做到。而在classifier.train()中,我們可以加入一個callback function來監看當前訓練的loss狀況,這個loss值,膚淺的來講,可以把它視為ml5.js/tensorflow.js在幫你處理訓練過程中的錯誤值。在正常的狀況下,你的loss值會越跑越收斂,最後趨近於零。如果你在訓練過程中loss一值出現大幅度的跳動,無法收斂,那可以嘗試加入更多照片或是重新定義訓練的方法。以下為按下Train Button後應該要成功的結果:

另外要注意的點是,你訓練時的標籤定義項目數量必須大於等於2。

6. 匯出訓練好的model

點擊Save button之後,你就會看到瀏覽器下載了兩個檔案

一個是model.json,裡面記錄了一些model的資訊,像是用了哪些方法、權重檔案的位置、分類標籤….等,而另外一個model.weights.bin則是model訓練過程中tensorflow.js所訓練調整的那些參數值,也就是訓練後的成果。得到了這兩個檔案後,我們之後只要引用他們,就可以開始使用自己的做出來的分類器了。

7.引用訓練好的model

由於我們是使用Transfer Learning,其原理就是把Mobilenet的最後一層分類階層,抽換成我們自己訓練的標籤結果,因此,在引用我們自己的model前,還是得載入MobileNet,所以,我們載入自己model的時機點,就是在載入modelnet之後,也就是modelReady()裡面。

做到這裡就已經大致完成囉,只要重新載入頁面等個幾秒,這時候應該就會看到兩個Model 皆已經載入的訊息。

接著只要頁面上多新增一個file input標籤讓我們可以選擇要分類的照片,再綁定change事件與分類動作,就大功告成囉!

我只用了這些照片進行訓練

接著只要透過最後一個新增的file input選擇欲拿來分類的照片,就可以在console中看到我們的model判定出來的標籤結果囉!

我選用這張來當作測試照片

結果如下….

結果還算不錯!而且重點是從訓練過程,我都沒有對照片進行任何前處理,連圖片的大小我也都沒有一致化,所以能有這樣的結果已經算很不錯了,當然,這次實作我是用背景相對簡單的圖片來做訓練,如果你要用的照片顏色跟圖案是很複雜的,那訓練出來的結果應該不會這麼好了。

以上就是整個ml5.js的基本實作,希望你看完之後,也能夠立刻自己做出一個屬於你自己的分類器!

結論

大概在幾個月前看到ml5.js時其實就覺得滿新奇的了,只是試完之後才發現ml5.js在v0.1.3版本之前並沒有輸出model的功能實在可惜,沒想到過沒多久後,就終於等到了,相信之後一定會有更多相關有趣的應用出現。

不過其實目前的ml5.js還有些可惜的缺點:

  1. 只能在瀏覽器裡執行,無法轉移到node.js的server環境中執行。這部分可能目前還是得使用純Tensorflow.js來達成。
  2. 針對訓練過程中的調整,好像沒有地方可以處理。這部分若要認真做,可能也還是一樣得仰賴Tensorflow.js先進行訓練後,再餵給ml5.js做後續的前端應用。

資料來源: https://dopeorion.medium.com/%E5%85%A8%E7%AB%AF%E7%94%9F%E6%B4%BB-ml5-js-%E4%B8%8D%E5%98%B4%E7%A0%B2%E5%AF%A6%E5%81%9A-77ac79a28773

沒有留言: