使用 TensorFlow.js 进行人脸检测
本指南介绍了如何将TensorFlow.js与Docker无缝集成以进行人脸检测。在本指南中,您将探索如何:
- 使用Docker运行一个容器化的TensorFlow.js应用程序。
- 在Web应用程序中使用TensorFlow.js实现人脸检测。
- 为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 专业知识的 Web 开发人员也能进行复杂的 ML 任务。
为什么要一起使用 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。
应用程序运行后,打开网页浏览器并访问应用程序 在 http://localhost:80。您可能需要授予应用程序访问您的网络摄像头的权限。
在网页应用程序中,您可以更改后端以使用以下之一:
- WASM
- WebGL
- CPU
要停止应用程序,请在终端中按下ctrl+c。
关于应用程序
示例应用程序使用MediaPipe进行实时人脸检测,这是一个用于构建多模态机器学习管道的综合框架。它特别使用了BlazeFace模型,这是一个用于检测图像中人脸的轻量级模型。
在TensorFlow.js或类似的基于Web的机器学习框架的背景下,WASM、WebGL和CPU后端可用于执行操作。这些后端各自利用现代浏览器中可用的不同资源和技术,并有其优势和局限性。以下部分是对不同后端的简要分析。
WASM
WebAssembly (WASM) 是一种低级的、类似汇编的语言,具有紧凑的二进制格式,可以在网络浏览器中以接近本机的速度运行。它允许将用 C/C++ 等语言编写的代码编译成可以在浏览器中执行的二进制文件。
当需要高性能时,这是一个很好的选择,特别是在WebGL后端不受支持或者您希望在所有设备上保持一致性能而不依赖GPU的情况下。
WebGL
WebGL 是一种浏览器 API,允许在网页画布中使用 GPU 加速的物理和图像处理及效果。
WebGL非常适合那些可以并行化并且能够显著受益于GPU加速的操作,例如在深度学习模型中常见的矩阵乘法和卷积。
CPU
CPU 后端使用纯 JavaScript 执行,利用设备的中央处理器(CPU)。此后端具有最广泛的兼容性,并在 WebGL 或 WASM 后端不可用或不适用时作为备用方案。
探索应用程序的代码
在以下部分中探索每个文件的用途及其内容。
index.html 文件
index.html 文件作为使用 TensorFlow.js 从网络摄像头视频流进行实时面部检测的 Web 应用程序的前端。它结合了多种技术和库,以便直接在浏览器中进行机器学习。它使用了多个 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 文件负责执行面部检测逻辑。它展示了在网页开发和机器学习集成中的几个高级概念。以下是其一些关键组件和功能的分解:
- Stats.js: 脚本首先创建一个 Stats 实例,用于实时监控和显示应用程序的帧率(FPS)。这对于性能分析非常有帮助,尤其是在测试不同 TensorFlow.js 后端对应用程序速度的影响时。
- TensorFlow.js: 该应用程序允许用户通过dat.GUI提供的图形界面在TensorFlow.js的不同计算后端(wasm、webgl和cpu)之间切换。更改后端可能会影响性能和兼容性,具体取决于设备和浏览器。addFlagLabels函数动态检查并显示是否支持SIMD(单指令多数据)和多线程,这些对于wasm后端的性能优化至关重要。
- setupCamera 函数:使用 MediaDevices Web API 初始化用户的网络摄像头。它配置视频流以不包括音频并使用前置摄像头(facingMode: 'user')。一旦视频元数据加载完成,它会解析一个带有视频元素的 promise,然后用于面部检测。
- 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 库
的一部分。它是一个用于 WebAssembly 后端的 WASM 二进制文件,特别优化以利用 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
应用程序运行后,打开网页浏览器并访问应用程序 在 http://localhost: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。
- Go to Docker Hub.
- Select Repositories.
- View the Last pushed time for your repository.
其他用户现在可以使用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镜像,以便为其他人简化部署流程,从而扩大应用程序在开发者社区中的影响力。
相关信息: