TensorFlow.js是一個(gè)基于deeplearn.js構(gòu)建的強(qiáng)大而靈活的Javascript機(jī)器學(xué)習(xí)庫(kù),它可直接在瀏覽器上創(chuàng)建深度學(xué)習(xí)模塊。使用它可以在瀏覽器上創(chuàng)建CNN(卷積神經(jīng)網(wǎng)絡(luò))、RNN(循環(huán)神經(jīng)網(wǎng)絡(luò))等等,且可以使用終端的GPU處理能力訓(xùn)練這些模型。接下來(lái)我們將學(xué)習(xí)如何建立一個(gè)簡(jiǎn)單的“可學(xué)習(xí)機(jī)器”——基于 TensorFlow.js 的遷移學(xué)習(xí)圖像分類器。 加載 TensorFlow.js 和MobileNet 模型 在編輯器中創(chuàng)建一個(gè)HTML文件,命名為index.html,添加以下內(nèi)容。 <!DOCTYPE html> <html> <head> <meta charset="utf-8" /> <title></title> <!--加載最新版本的TensorFlow.js --> <script src="https:///@tensorflow/tfjs"></script> <script src="https:///@tensorflow-models/mobilenet"></script> </head> <body> <div id="console></div> <!--添加一個(gè)用于測(cè)試的圖像--> <img id="img" crossOrigin src="https://i./JlUvsxa.jpg" width=227 height=227/> <!-- 加載 index.js 在內(nèi)容頁(yè)之后--> <script src="js/index.js"></script> </body> </html> |
注意:在img里請(qǐng)使用有用的圖片地址 在瀏覽器中設(shè)置 MobileNet 用于預(yù)測(cè) 在代碼編輯器中打開/創(chuàng)建index.js 文件,添加以下代碼: let net; async function app(){ console.log('Loading mobilenet..'); // 加載模型 net = await mobilenet.load(); console.log('Sucessfully loaded model'); // 通過模型預(yù)測(cè)圖像 const imgEl = document.getElementById('img'); const result = await net.classify(imgEl); console.log(result); } app(); |
在瀏覽器中測(cè)試 MobileNet 的預(yù)測(cè) 運(yùn)行index.html文件,調(diào)出JavaScript控制臺(tái),你將看見一張狗的照片,而這就是MobileNet 的預(yù)測(cè)結(jié)果。 通過網(wǎng)絡(luò)攝像頭圖像在瀏覽器中執(zhí)行 MobileNet 預(yù)測(cè) 接下來(lái),我們來(lái)設(shè)置網(wǎng)絡(luò)攝像頭來(lái)預(yù)測(cè)由網(wǎng)絡(luò)攝像頭傳輸?shù)膱D像。 現(xiàn)在,讓我們讓它更具交互性和實(shí)時(shí)性。讓我們?cè)O(shè)置網(wǎng)絡(luò)攝像頭來(lái)預(yù)測(cè)由網(wǎng)絡(luò)攝像頭傳輸?shù)膱D像。 首先要設(shè)置網(wǎng)絡(luò)攝像頭的視頻元素。打開 index.html 文件,在 <body> 部分中添加如下行,并刪除我們用于加載狗圖像的<img> 標(biāo)簽。 <video autoplay playsinline muted id="webcam" width="224" height="224"></video> |
打開 index.js 文件并將webcamElement 添加到文件的最頂部。 const webcamElement = document.getElementById('webcam'); |
在同一個(gè) index.js 文件中,在調(diào)用 “app()” 函數(shù)之前添加網(wǎng)絡(luò)攝像頭的設(shè)置函數(shù): async function setupWebcam() { return new Promise((resolve, reject) => { const navigatorAny = navigator; navigator.getUserMedia = navigator.getUserMedia || navigatorAny.webkitGetUserMedia || navigatorAny.mozGetUserMedia || navigatorAny.msGetUserMedia; if (navigator.getUserMedia) { navigator.getUserMedia({video: true}, stream=> { webcamElement.srcObject = stream; webcamElement.addEventListener('loadeddata', () => resolve(), false); }, error=> reject()); }else{ reject(); } }); } |
在之前添加的 app() 函數(shù)中,你可以刪除通過圖像預(yù)測(cè)的部分,用一個(gè)無(wú)限循環(huán),通過網(wǎng)絡(luò)攝像頭預(yù)測(cè)代替。 async function app(){ console.log('Loading mobilenet..'); // 加載模型 net = await mobilenet.load(); console.log('Sucessfully loaded model'); await setupWebcam(); while(true){ const result = await net.classify(webcamElement); document.getElementById('console').innerText =` prediction: ${result[0].className}\n probability: ${result[0].probability} `; // 給自己一些喘息的空間 // 等待下一個(gè)動(dòng)畫幀開始 await tf.nextFrame(); } } |
如果你在網(wǎng)頁(yè)中打開控制臺(tái),現(xiàn)在你應(yīng)該會(huì)看到 MobileNet 的預(yù)測(cè)和網(wǎng)絡(luò)攝像頭收集到的每一幀圖像。 在 MobileNet 預(yù)測(cè)的基礎(chǔ)上添加一個(gè)自定義的分類器 現(xiàn)在,讓我們把它變得更加實(shí)用。我們使用網(wǎng)絡(luò)攝像頭動(dòng)態(tài)創(chuàng)建一個(gè)自定義的 3 對(duì)象的分類器。我們將通過 MobileNet 進(jìn)行分類,但這次我們將使用特定網(wǎng)絡(luò)攝像頭圖像在模型的內(nèi)部表示(激活值)來(lái)進(jìn)行分類。 我們將使用一個(gè)叫做 "K-Nearest NeighborsClassifier" 的模塊,他將有效的讓我們把攝像頭采集的圖像(實(shí)際上是 MobileNet 中的激活值)分成不同的類別,當(dāng)用戶要求做出預(yù)測(cè)時(shí),我們只需選擇擁有與待預(yù)測(cè)圖像最相似的激活值的類即可。 在 index.html 的<head> 標(biāo)簽的末尾添加 KNN 分類器的導(dǎo)入(你仍然需要 MobileNet,所以不要?jiǎng)h除它的導(dǎo)入): <script src="https:///@tensorflow-models/knn-classifier"></script> |
在 index.html 視頻部分下面添加三個(gè)按鈕。這些按鈕將用于向模型添加訓(xùn)練圖像。 <button id="class-a">add a</button> <button id="class-b">add a</button> <button id="class-c">add a</button> |
在 index.js 的頂部,創(chuàng)建一個(gè)分類器 const classifier = knnClassifier.create(); |
更新 app 函數(shù); async function app(){ console.log('Loading mobilenet..'); //losd the model net = await mobilenet.load(); console.log('Sucessfully loaded model'); await setupWebcam(); //從網(wǎng)絡(luò)攝像頭中讀取圖像并將其與特定類關(guān)聯(lián) const addExample classId=>{ // 獲取 MobileNet 中間的 'conv_preds' 的激活值 // 并將其傳遞給 KNN 分類器 const activation = net.infer(webcamElement, 'conv_preds'); // 將中間激活值傳遞給分類器 classifier.addExample(activation, classId); }; // 單擊該按鈕是,為該類添加一個(gè)實(shí)例 document.getElementById("class-a").addEventListener('click',()=>addExample(0)); document.getElementById("class-b").addEventListener('click',()=>addExample(1)); document.getElementById("class-c").addEventListener('click',()=>addExample(2)); while(true){ if(classifier.getNumClasses() > 0) { // 獲取 MobileNet 在網(wǎng)絡(luò)攝像頭中圖像上的激活值 const activation = net.infer(webcamElement, 'conv_preds'); // 從分類器模塊上獲取最可能的類 const result = await classifier.predictClass(activation); const classes = ['A', 'B', 'C']; document.getElementById('console').innerText = ` prediction: ${classes[result.classIndex]}\n probability: ${result.confidences[result.classIndex]} `; } await tf.nextFrame(); } } |
當(dāng)你加載 index.html 頁(yè)面時(shí),你可以使用常用對(duì)象或面部表情/手勢(shì)為這三個(gè)類中的每一個(gè)類捕獲圖像。每次單擊其中一個(gè) "Add" 按鈕,就會(huì)向該類添加一個(gè)圖像作為訓(xùn)練實(shí)例。當(dāng)你這樣做的時(shí)候,模型會(huì)繼續(xù)預(yù)測(cè)網(wǎng)絡(luò)攝像頭的圖像,并實(shí)時(shí)顯示結(jié)果。 注意:在這里可能會(huì)報(bào)錯(cuò),出現(xiàn):Uncaught (in promise)TypeError: Failed to fetch。 這個(gè)錯(cuò)誤提示是網(wǎng)絡(luò)連接超時(shí)的意思,解決辦法如下:
|