added multi backend support

pull/50/head
Vladimir Mandic 2020-10-15 08:16:34 -04:00
parent 9ae61216fb
commit b4cccc3c76
17 changed files with 86701 additions and 28 deletions

View File

@ -1,8 +1,10 @@
# Human: 3D Face Detection, Body Pose, Hand & Finger Tracking, Iris Tracking, Age & Gender Prediction & Emotion Prediction
# Human Library
## 3D Face Detection, Body Pose, Hand & Finger Tracking, Iris Tracking, Age & Gender Prediction & Emotion Prediction
- [**Documentation**](https://github.com/vladmandic/human#readme)
- [**Code Repository**](https://github.com/vladmandic/human)
- [**Package**](https://www.npmjs.com/package/@vladmandic/human)
- [**NPM Package**](https://www.npmjs.com/package/@vladmandic/human)
- [**Issues Tracker**](https://github.com/vladmandic/human/issues)
- [**Live Demo**](https://vladmandic.github.io/human/demo/demo-esm.html)
@ -30,6 +32,25 @@ Compatible with Browser, WebWorker and NodeJS execution!
There are multiple ways to use `Human` library, pick one that suits you:
### Included
- `dist/human.js`: IIFE format minified bundle with TFJS for Browsers
- `dist/human.esm.js`: ESM format minified bundle with TFJS for Browsers
- `dist/human.esm-nobundle.js`: ESM format non-minified bundle without TFJS for Browsers
- `dist/human.cjs`: CommonJS format minified bundle with TFJS for NodeJS
- `dist/human-nobundle.cjs`: CommonJS format non-minified bundle without TFJS for NodeJS
All versions include `sourcemap`
Defaults:
```json
{
"main": "dist/human.cjs",
"module": "dist/human.esm.js",
"browser": "dist/human.esm.js",
}
```
### 1. [IIFE](https://developer.mozilla.org/en-US/docs/Glossary/IIFE) script
*Simplest way for usage within Browser*
@ -43,8 +64,6 @@ Simply download `dist/human.js`, include it in your `HTML` file & it's ready to
IIFE script auto-registers global namespace `human` within global `Window` object
This way you can also use `Human` library within embbedded `<script>` tag within your `html` page for all-in-one approach
IIFE script is distributed in minified form with attached sourcemap
### 2. [ESM](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/import) module
*Recommended for usage within `Browser`*
@ -53,18 +72,25 @@ IIFE script is distributed in minified form with attached sourcemap
If you're using bundler *(such as rollup, webpack, esbuild)* to package your client application, you can import ESM version of `Human` library which supports full tree shaking
Install with:
```shell
npm install @vladmandic/human
```
```js
import human from '@vladmandic/human'; // points to @vladmandic/human/dist/human.esm.js
```
Or if you prefer to package your version of `tfjs`, you can use `nobundle` version
Install with:
```shell
npm install @vladmandic/human @tensorflow/tfjs-node
```
```js
import tf from '@tensorflow/tfjs'
import human from '@vladmandic/human/dist/human.nobundle.js'; // same functionality as default import, but without tfjs bundled
import human from '@vladmandic/human/dist/human.esm-nobundle.js'; // same functionality as default import, but without tfjs bundled
```
#### 2.2 Using Script Module
You could use same syntax within your main `JS` file if it's imported with `<script type="module">`
@ -74,11 +100,10 @@ You could use same syntax within your main `JS` file if it's imported with `<scr
and then in your `index.js`
```js
import human from 'dist/human.esm.js';
import * as tf from `https://cdnjs.cloudflare.com/ajax/libs/tensorflow/2.6.0/tf.es2017.min.js`; // load tfjs directly from CDN link
import human from 'dist/human.esm.js'; // for direct import must use path to module, not package name
```
ESM script is distributed in minified form with attached sourcemap
### 3. [NPM](https://www.npmjs.com/) module
*Recommended for `NodeJS` projects that will execute in the backend*
@ -88,13 +113,22 @@ You also need to install and include `tfjs-node` or `tfjs-node-gpu` in your proj
Install with:
```shell
npm install @tensorflow/tfjs-node @vladmandic/human
npm install @vladmandic/human
```
And then use with:
```js
const tf = require('@tensorflow/tfjs-node');
const human = require('@vladmandic/human'); // points to @vladmandic/human/dist/human.node.js
const human = require('@vladmandic/human'); // points to @vladmandic/human/dist/human.cjs
```
or
```shell
npm install @vladmandic/human @tensorflow/tfjs-node
```
And then use with:
```js
const tf = require('@tensorflow/tfjs-node'); // can also use '@tensorflow/tfjs-node-gpu' if you have environment with CUDA extensions
const human = require('@vladmandic/human/dist/human-nobundle.cjs');
```
Since NodeJS projects load `weights` from local filesystem instead of using `http` calls, you must modify default configuration to include correct paths with `file://` prefix
For example:

1
assets/quicksettings.js Normal file

File diff suppressed because one or more lines are too long

18
assets/tf-backend-wasm.min.js vendored Normal file

File diff suppressed because one or more lines are too long

82571
assets/tf.esnext.js Normal file

File diff suppressed because it is too large Load Diff

18
assets/tf.min.js vendored Normal file

File diff suppressed because one or more lines are too long

Binary file not shown.

Binary file not shown.

Binary file not shown.

View File

@ -1,5 +1,7 @@
<head>
<script src="https://cdn.jsdelivr.net/npm/quicksettings"></script>
<script src="../assets/quicksettings.js"></script>
<script src="../assets/tf.min.js"></script>
<script src="../assets/tf-backend-wasm.min.js"></script>
<script src="./demo-esm.js" type="module"></script>
</head>
<body style="margin: 0; background: black; color: white; font-family: 'Segoe UI'; font-variant: small-caps">

View File

@ -1,8 +1,9 @@
/* global QuickSettings */
/* global tf, QuickSettings */
import human from '../dist/human.esm.js';
const ui = {
backend: 'wasm',
baseColor: 'rgba(255, 200, 255, 0.3)',
baseLabel: 'rgba(255, 200, 255, 0.8)',
baseFont: 'small-caps 1.2rem "Segoe UI"',
@ -34,6 +35,15 @@ function str(...msg) {
return line;
}
async function setupTF() {
if (ui.backend === 'wasm') {
tf.env().set('WASM_HAS_SIMD_SUPPORT', false);
tf.env().set('WASM_HAS_MULTITHREAD_SUPPORT', true);
}
await human.tf.setBackend(ui.backend);
await human.tf.ready();
}
async function drawFace(result, canvas) {
const ctx = canvas.getContext('2d');
ctx.strokeStyle = ui.baseColor;
@ -217,9 +227,10 @@ async function runHumanDetect(input, canvas) {
drawHand(result.hand, canvas);
// update log
const engine = await human.tf.engine();
const memory = `Memory: ${engine.state.numBytes.toLocaleString()} bytes ${engine.state.numDataBuffers.toLocaleString()} buffers ${engine.state.numTensors.toLocaleString()} tensors`;
const memory = `${engine.state.numBytes.toLocaleString()} bytes ${engine.state.numDataBuffers.toLocaleString()} buffers ${engine.state.numTensors.toLocaleString()} tensors`;
const gpu = engine.backendInstance.numBytesInGPU ? `GPU: ${engine.backendInstance.numBytesInGPU.toLocaleString()} bytes` : '';
log.innerText = `
TFJS Version: ${human.tf.version_core} | ${memory} | GPU: ${engine.backendInstance.numBytesInGPU.toLocaleString()} bytes
TFJS Version: ${human.tf.version_core} | Backend: ${human.tf.getBackend()} | Memory: ${memory} ${gpu}
Performance: ${str(result.performance)} | Object size: ${(str(result)).length.toLocaleString()} bytes
`;
// rinse & repeate
@ -255,6 +266,11 @@ function setupGUI() {
}
runHumanDetect(video, canvas);
});
settings.addDropDown('Backend', ['webgl', 'wasm', 'cpu'], (val) => {
ui.backend = val.value;
setupTF();
});
settings.addHTML('title', 'Enabled Models'); settings.hideTitle('title');
settings.addBoolean('Face Detect', config.face.enabled, (val) => config.face.enabled = val);
settings.addBoolean('Face Mesh', config.face.mesh.enabled, (val) => config.face.mesh.enabled = val);
settings.addBoolean('Face Iris', config.face.iris.enabled, (val) => config.face.iris.enabled = val);
@ -263,7 +279,7 @@ function setupGUI() {
settings.addBoolean('Face Emotion', config.face.emotion.enabled, (val) => config.face.emotion.enabled = val);
settings.addBoolean('Body Pose', config.body.enabled, (val) => config.body.enabled = val);
settings.addBoolean('Hand Pose', config.hand.enabled, (val) => config.hand.enabled = val);
settings.addHTML('line3', '<hr>'); settings.hideTitle('line3');
settings.addHTML('title', 'Model Parameters'); settings.hideTitle('title');
settings.addRange('Max Objects', 1, 20, 5, 1, (val) => {
config.face.detector.maxFaces = parseInt(val);
config.body.maxDetections = parseInt(val);
@ -288,7 +304,7 @@ function setupGUI() {
config.face.detector.iouThreshold = parseFloat(val);
config.hand.iouThreshold = parseFloat(val);
});
settings.addHTML('line1', '<hr>'); settings.hideTitle('line1');
settings.addHTML('title', 'UI Options'); settings.hideTitle('title');
settings.addBoolean('Draw Boxes', true);
settings.addBoolean('Draw Points', true);
settings.addBoolean('Draw Polygons', true);
@ -342,8 +358,7 @@ async function setupImage() {
async function main() {
// initialize tensorflow
await human.tf.setBackend('webgl');
await human.tf.ready();
await setupTF();
// setup ui control panel
await setupGUI();
// setup webcam

View File

@ -5236,4 +5236,4 @@ exports.ssrnet = ssrnet;
exports.posenet = posenet;
exports.handpose = handpose;
exports.tf = tf;
//# sourceMappingURL=human.node.js.map
//# sourceMappingURL=human-nobundle.cjs.map

4006
dist/human.cjs vendored Normal file

File diff suppressed because one or more lines are too long

7
dist/human.cjs.map vendored Normal file

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View File

@ -3,9 +3,9 @@
"version": "0.3.1",
"description": "human: 3D Face Detection, Iris Tracking and Age & Gender Prediction",
"sideEffects": false,
"main": "dist/human.node.js",
"main": "dist/human.cjs",
"module": "dist/human.esm.js",
"browser": "dist/human.esmjs",
"browser": "dist/human.esm.js",
"author": "Vladimir Mandic <mandic00@live.com>",
"bugs": {
"url": "https://github.com/vladmandic/human/issues"
@ -36,11 +36,12 @@
"scripts": {
"start": "node --trace-warnings --trace-uncaught --no-deprecation demo/demo-node.js",
"lint": "eslint src/*.js demo/*.js",
"build": "rimraf dist/ && npm run build-iife && npm run build-esm && npm run build-nobundle && npm run build-node && ls -l dist/",
"build-iife": "esbuild --bundle --platform=browser --sourcemap --target=esnext --format=iife --minify --external:fs --global-name=human --outfile=dist/human.js src/index.js",
"build-esm": "esbuild --bundle --platform=browser --sourcemap --target=esnext --format=esm --external:fs --outfile=dist/human.esm.js src/index.js",
"build-nobundle": "esbuild --bundle --platform=browser --sourcemap --target=esnext --format=esm --minify --external:@tensorflow --external:fs --outfile=dist/human.nobundle.js src/index.js",
"build-node": "esbuild --bundle --platform=node --sourcemap --target=esnext --format=cjs --external:@tensorflow --outfile=dist/human.node.js src/index.js",
"build-esm-bundle": "esbuild --bundle --platform=browser --sourcemap --target=esnext --format=esm --external:fs --outfile=dist/human.esm.js src/index.js",
"build-esm-nobundle": "esbuild --bundle --platform=browser --sourcemap --target=esnext --format=esm --minify --external:@tensorflow --external:fs --outfile=dist/human.esm-nobundle.js src/index.js",
"build-node-bundle": "esbuild --bundle --platform=node --sourcemap --target=esnext --format=cjs --minify --outfile=dist/human.cjs src/index.js",
"build-node-nobundle": "esbuild --bundle --platform=node --sourcemap --target=esnext --format=cjs --external:@tensorflow --outfile=dist/human-nobundle.cjs src/index.js",
"build": "rimraf dist/* && npm run build-iife && npm run build-esm-bundle && npm run build-esm-nobundle && npm run build-node-bundle && npm run build-node-nobundle && ls -l dist/",
"update": "npm update --depth 20 && npm dedupe && npm prune && npm audit"
},
"keywords": [