使用 TensorFlow.js 進行人臉檢測
本指南介紹了 TensorFlow.js 與 Docker 的無縫整合,以執行人臉檢測。在本指南中,您將探索如何
- 使用 Docker 執行容器化的 TensorFlow.js 應用程式。
- 使用 TensorFlow.js 在 Web 應用程式中實現人臉檢測。
- 為 TensorFlow.js Web 應用程式構建 Dockerfile。
- 使用 Docker Compose 進行即時應用程式開發和更新。
- 在 Docker Hub 上共享您的 Docker 映象,以促進部署並擴充套件覆蓋範圍。
致謝
Docker 感謝 Harsh Manvar 對本指南的貢獻。
先決條件
- 您已安裝最新版本的 Docker Desktop。
- 您有一個 Git 客戶端。本指南中的示例使用基於命令列的 Git 客戶端,但您可以使用任何客戶端。
什麼是 TensorFlow.js?
TensorFlow.js 是一個開源的 JavaScript 機器學習庫,使您能夠在瀏覽器或 Node.js 上訓練和部署 ML 模型。它支援從頭開始建立新模型或使用預先訓練的模型,從而在 Web 環境中直接實現各種 ML 應用程式。TensorFlow.js 提供高效的計算,使複雜的 ML 任務在沒有深入的 ML 知識的情況下對 Web 開發人員可用。
為什麼要將 TensorFlow.js 和 Docker 結合使用?
- 環境一致性和簡化部署:Docker 將 TensorFlow.js 應用程式及其依賴項打包到容器中,確保在所有環境中一致執行,並簡化部署。
- 高效開發和輕鬆擴充套件:Docker 透過熱過載等功能增強開發效率,並使用 Kubernetes 等編排工具輕鬆擴充套件 TensorFlow.js 應用程式。
- 隔離和增強安全性:Docker 在安全環境中隔離 TensorFlow.js 應用程式,最大程度地減少衝突和安全漏洞,同時以有限許可權執行應用程式。
獲取並執行示例應用程式
在終端中,使用以下命令克隆示例應用程式。
$ git clone https://github.com/harsh4870/TensorJS-Face-Detection
克隆應用程式後,您會注意到該應用程式有一個 Dockerfile
。此 Dockerfile 使您能夠使用 Docker 本地構建和執行應用程式,無需其他操作。
在將應用程式作為容器執行之前,您必須將其構建成映象。在 TensorJS-Face-Detection
目錄中執行以下命令以構建名為 face-detection-tensorjs
的映象。
$ docker build -t face-detection-tensorjs .
該命令將應用程式構建成映象。根據您的網路連線情況,第一次執行該命令可能需要幾分鐘才能下載必要的元件。
要將映象作為容器執行,請在終端中執行以下命令。
$ docker run -p 80:80 face-detection-tensorjs
該命令執行容器並將容器中的埠 80 對映到系統上的埠 80。
應用程式執行後,開啟 Web 瀏覽器並訪問 https://:80 上的應用程式。您可能需要授予應用程式訪問您網路攝像頭的許可權。
在 Web 應用程式中,您可以更改後端以使用以下任一選項
- WASM
- WebGL
- CPU
要停止應用程式,請在終端中按 ctrl
+c
。
關於應用程式
示例應用程式使用 MediaPipe 執行即時人臉檢測。它使用的是 BlazeFace 模型,這是一個用於檢測影像中人臉的輕量級模型。
在 TensorFlow.js 或類似的基於 Web 的機器學習框架的背景下,可以使用 WASM、WebGL 和 CPU 後端來執行操作。這些後端中的每一個都利用了現代瀏覽器中可用的不同資源和技術,並具有其優缺點。以下部分簡要介紹了不同的後端。
WASM
WebAssembly (WASM) 是一種低階、類似組合語言的語言,具有緊湊的二進位制格式,可在 Web 瀏覽器中以接近本機的速度執行。它允許用 C/C++ 等語言編寫的程式碼編譯成二進位制檔案,可在瀏覽器中執行。
當需要高效能時,它是一個不錯的選擇,並且 WebGL 後端不支援或您希望在所有裝置上保持一致的效能,而無需依賴 GPU。
WebGL
WebGL 是一個瀏覽器 API,允許在網頁畫布中使用 GPU 加速的物理、影像處理和效果。
WebGL 非常適合可以並行化並能夠從 GPU 加速中受益匪淺的操作,例如深度學習模型中常見的矩陣乘法和卷積。
CPU
CPU 後端使用純 JavaScript 執行,利用裝置的中央處理單元 (CPU)。此後端與所有裝置相容,並且在 WebGL 或 WASM 後端不可用或不合適時充當後備。
探索應用程式程式碼
在以下部分中探索每個檔案的用途及其內容。
index.html 檔案
index.html
檔案用作 Web 應用程式的前端,該應用程式使用 TensorFlow.js 從網路攝像頭影片流中即時檢測人臉。它結合了多種技術和庫,以實現直接在瀏覽器中進行機器學習。它使用多個 TensorFlow.js 庫,包括
- tfjs-core 和 tfjs-converter 用於核心 TensorFlow.js 功能和模型轉換。
- tfjs-backend-webgl、tfjs-backend-cpu 和 tf-backend-wasm 指令碼用於 TensorFlow.js 可以使用的不同計算後端選項以進行處理。這些後端允許應用程式透過利用使用者的硬體功能來高效地執行機器學習任務。
- BlazeFace 庫,這是一個用於人臉檢測的 TensorFlow 模型。
它還使用以下其他庫
- dat.GUI 用於建立圖形介面以即時與應用程式設定進行互動,例如在 TensorFlow.js 後端之間切換。
- Stats.min.js 用於顯示效能指標(如 FPS)以監控應用程式在執行期間的效率。
<style>
body {
margin: 25px;
}
.true {
color: green;
}
.false {
color: red;
}
#main {
position: relative;
margin: 50px 0;
}
canvas {
position: absolute;
top: 0;
left: 0;
}
#description {
margin-top: 20px;
width: 600px;
}
#description-title {
font-weight: bold;
font-size: 18px;
}
</style>
<body>
<div id="main">
<video id="video" playsinline style="
-webkit-transform: scaleX(-1);
transform: scaleX(-1);
width: auto;
height: auto;
">
</video>
<canvas id="output"></canvas>
<video id="video" playsinline style="
-webkit-transform: scaleX(-1);
transform: scaleX(-1);
visibility: hidden;
width: auto;
height: auto;
">
</video>
</div>
</body>
<script src="https://unpkg.com/@tensorflow/tfjs-core@2.1.0/dist/tf-core.js"></script>
<script src="https://unpkg.com/@tensorflow/tfjs-converter@2.1.0/dist/tf-converter.js"></script>
<script src="https://unpkg.com/@tensorflow/tfjs-backend-webgl@2.1.0/dist/tf-backend-webgl.js"></script>
<script src="https://unpkg.com/@tensorflow/tfjs-backend-cpu@2.1.0/dist/tf-backend-cpu.js"></script>
<script src="./tf-backend-wasm.js"></script>
<script src="https://unpkg.com/@tensorflow-models/blazeface@0.0.5/dist/blazeface.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/dat-gui/0.7.6/dat.gui.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/stats.js/r16/Stats.min.js"></script>
<script src="./index.js"></script>
index.js 檔案
index.js
檔案執行面部檢測邏輯。它展示了 Web 開發和機器學習整合中的幾個高階概念。以下是其一些關鍵元件和功能的細分。
- Stats.js:指令碼首先建立一個 Stats 例項,以即時監控和顯示應用程式的幀速率 (FPS)。這對於效能分析非常有用,尤其是在測試不同 TensorFlow.js 後端對應用程式速度的影響時。
- TensorFlow.js:該應用程式允許使用者透過 dat.GUI 提供的圖形介面在 TensorFlow.js 的不同計算後端 (wasm、webgl 和 cpu) 之間切換。根據裝置和瀏覽器,更改後端可能會影響效能和相容性。addFlagLabels 函式動態檢查並顯示 SIMD(單指令多資料)和多執行緒是否受支援,這些與 wasm 後端中的效能最佳化相關。
- setupCamera 函式:使用 MediaDevices Web API 初始化使用者的網路攝像頭。它將影片流配置為不包含音訊並使用前置攝像頭 (facingMode: 'user')。影片元資料載入後,它會解析一個帶有影片元素的承諾,該元素隨後用於面部檢測。
- BlazeFace:此應用程式的核心是 renderPrediction 函式,該函式使用 BlazeFace 模型(用於檢測影像中人臉的輕量級模型)執行即時人臉檢測。該函式在每個動畫幀上呼叫 model.estimateFaces 以從影片流中檢測人臉。對於每個檢測到的人臉,它在覆蓋影片的畫布上繪製一個紅色矩形圍繞人臉,以及藍色圓點表示人臉特徵點。
const stats = new Stats();
stats.showPanel(0);
document.body.prepend(stats.domElement);
let model, ctx, videoWidth, videoHeight, video, canvas;
const state = {
backend: 'wasm'
};
const gui = new dat.GUI();
gui.add(state, 'backend', ['wasm', 'webgl', 'cpu']).onChange(async backend => {
await tf.setBackend(backend);
addFlagLables();
});
async function addFlagLables() {
if(!document.querySelector("#simd_supported")) {
const simdSupportLabel = document.createElement("div");
simdSupportLabel.id = "simd_supported";
simdSupportLabel.style = "font-weight: bold";
const simdSupported = await tf.env().getAsync('WASM_HAS_SIMD_SUPPORT');
simdSupportLabel.innerHTML = `SIMD supported: <span class=${simdSupported}>${simdSupported}<span>`;
document.querySelector("#description").appendChild(simdSupportLabel);
}
if(!document.querySelector("#threads_supported")) {
const threadSupportLabel = document.createElement("div");
threadSupportLabel.id = "threads_supported";
threadSupportLabel.style = "font-weight: bold";
const threadsSupported = await tf.env().getAsync('WASM_HAS_MULTITHREAD_SUPPORT');
threadSupportLabel.innerHTML = `Threads supported: <span class=${threadsSupported}>${threadsSupported}</span>`;
document.querySelector("#description").appendChild(threadSupportLabel);
}
}
async function setupCamera() {
video = document.getElementById('video');
const stream = await navigator.mediaDevices.getUserMedia({
'audio': false,
'video': { facingMode: 'user' },
});
video.srcObject = stream;
return new Promise((resolve) => {
video.onloadedmetadata = () => {
resolve(video);
};
});
}
const renderPrediction = async () => {
stats.begin();
const returnTensors = false;
const flipHorizontal = true;
const annotateBoxes = true;
const predictions = await model.estimateFaces(
video, returnTensors, flipHorizontal, annotateBoxes);
if (predictions.length > 0) {
ctx.clearRect(0, 0, canvas.width, canvas.height);
for (let i = 0; i < predictions.length; i++) {
if (returnTensors) {
predictions[i].topLeft = predictions[i].topLeft.arraySync();
predictions[i].bottomRight = predictions[i].bottomRight.arraySync();
if (annotateBoxes) {
predictions[i].landmarks = predictions[i].landmarks.arraySync();
}
}
const start = predictions[i].topLeft;
const end = predictions[i].bottomRight;
const size = [end[0] - start[0], end[1] - start[1]];
ctx.fillStyle = "rgba(255, 0, 0, 0.5)";
ctx.fillRect(start[0], start[1], size[0], size[1]);
if (annotateBoxes) {
const landmarks = predictions[i].landmarks;
ctx.fillStyle = "blue";
for (let j = 0; j < landmarks.length; j++) {
const x = landmarks[j][0];
const y = landmarks[j][1];
ctx.fillRect(x, y, 5, 5);
}
}
}
}
stats.end();
requestAnimationFrame(renderPrediction);
};
const setupPage = async () => {
await tf.setBackend(state.backend);
addFlagLables();
await setupCamera();
video.play();
videoWidth = video.videoWidth;
videoHeight = video.videoHeight;
video.width = videoWidth;
video.height = videoHeight;
canvas = document.getElementById('output');
canvas.width = videoWidth;
canvas.height = videoHeight;
ctx = canvas.getContext('2d');
ctx.fillStyle = "rgba(255, 0, 0, 0.5)";
model = await blazeface.load();
renderPrediction();
};
setupPage();
tf-backend-wasm.js 檔案
tf-backend-wasm.js
檔案是 TensorFlow.js 庫的一部分。它包含 TensorFlow.js WASM 後端的初始化邏輯,一些用於與 WASM 二進位制檔案互動的實用程式以及用於設定 WASM 二進位制檔案的自定義路徑的函式。
tfjs-backend-wasm-simd.wasm 檔案
tfjs-backend-wasm-simd.wasm
檔案是 TensorFlow.js 庫的一部分。它是一個 WASM 二進位制檔案,用於 WebAssembly 後端,專門針對利用 SIMD(單指令多資料)指令進行了最佳化。
探索 Dockerfile
在基於 Docker 的專案中,Dockerfile 是構建應用程式環境的基礎資產。
Dockerfile 是一個文字檔案,它指示 Docker 如何建立應用程式環境的映象。映象包含執行應用程式時需要的一切,例如檔案、包和工具。
以下是此專案的 Dockerfile。
FROM nginx:stable-alpine3.17-slim
WORKDIR /usr/share/nginx/html
COPY . .
此 Dockerfile 定義了一個映象,該映象使用來自 Alpine Linux 基礎映象的 Nginx 提供靜態內容。
使用 Compose 開發
Docker Compose 是一個用於定義和執行多容器 Docker 應用程式的工具。使用 Compose,您可以使用 YAML 檔案配置應用程式的服務、網路和卷。在本例中,應用程式不是多容器應用程式,但 Docker Compose 具有其他用於開發的有用功能,例如 Compose Watch。
示例應用程式目前還沒有 Compose 檔案。要建立 Compose 檔案,請在 TensorJS-Face-Detection
目錄中建立一個名為 compose.yaml
的文字檔案,然後新增以下內容。
services:
server:
build:
context: .
ports:
- 80:80
develop:
watch:
- action: sync
path: .
target: /usr/share/nginx/html
此 Compose 檔案定義了一個服務,該服務使用同一目錄中的 Dockerfile 構建。它將主機上的埠 80 對映到容器中的埠 80。它還具有一個 develop
子部分,其中包含 watch
屬性,該屬性定義了一組規則,用於根據本地檔案更改控制自動服務更新。有關 Compose 指令的更多詳細資訊,請參閱 Compose 檔案參考。
儲存對 compose.yaml
檔案的更改,然後執行以下命令以執行應用程式。
$ docker compose watch
應用程式執行後,開啟 Web 瀏覽器並訪問 https://:80 上的應用程式。您可能需要授予應用程式訪問您網路攝像頭的許可權。
現在您可以更改原始碼,並在容器中看到更改自動反映,而無需重新構建和重新執行容器。
開啟 index.js
檔案並將第 83 行的人臉特徵點更新為綠色而不是藍色。
- ctx.fillStyle = "blue";
+ ctx.fillStyle = "green";
儲存對 index.js
檔案的更改,然後重新整理瀏覽器頁面。人臉特徵點現在應該顯示為綠色。
要停止應用程式,請在終端中按 ctrl
+c
。
共享您的映象
在 Docker Hub 上釋出您的 Docker 映象可簡化他人的部署流程,從而實現與各種專案的無縫整合。它還促進了您容器化解決方案的採用,擴充套件了其在開發者生態系統中的影響。要共享您的映象
註冊 或登入 Docker Hub。
重新構建您的映象以包含對應用程式的更改。這次,在映象名稱前新增您的 Docker ID。Docker 使用此名稱來確定要將其推送到哪個儲存庫。開啟一個終端並在
TensorJS-Face-Detection
目錄中執行以下命令。將YOUR-USER-NAME
替換為您的 Docker ID。$ docker build -t YOUR-USER-NAME/face-detection-tensorjs .
執行以下
docker push
命令將映象推送到 Docker Hub。將YOUR-USER-NAME
替換為您的 Docker ID。$ docker push YOUR-USER-NAME/face-detection-tensorjs
驗證您是否已將映象推送到 Docker Hub。
- 轉到 Docker Hub。
- 選擇 **Repositories**。
- 檢視您的儲存庫的 **Last pushed** 時間。
其他使用者現在可以使用 docker run
命令下載並執行您的映象。他們需要將 YOUR-USER-NAME
替換為您的 Docker ID。
$ docker run -p 80:80 YOUR-USER-NAME/face-detection-tensorjs
總結
本指南演示瞭如何利用 TensorFlow.js 和 Docker 在 Web 應用程式中進行人臉檢測。它強調了執行容器化 TensorFlow.js 應用程式的簡便性,以及使用 Docker Compose 進行即時程式碼更改的開發。此外,它還介紹瞭如何在 Docker Hub 上共享您的 Docker 映象,以簡化他人的部署,從而增強應用程式在開發者社群中的影響力。
相關資訊