fix wasm detection

pull/356/head
Vladimir Mandic 2022-08-15 11:29:56 -04:00
parent 554ed81f49
commit 6fc26e793c
19 changed files with 1131 additions and 880 deletions

View File

@ -11,9 +11,8 @@
### **HEAD -> main** 2022/08/12 mandic00@live.com
### **origin/main** 2022/08/10 mandic00@live.com
- enumerate additional models
- release refresh
### **2.9.3** 2022/08/10 mandic00@live.com

View File

@ -57,6 +57,8 @@ Model is supported using `WebGL` backend in browser
Models can be downloaded from <https://github.com/vladmandic/insightface>
- Add `human.check()` which validates all kernel ops for currently loaded models with currently selected backend
Example: `console.error(human.check());`
- Add underlying tensorflow library version detection to `human.env`
Example: `console.log(human.env.tensorflow)`
- Host models in <human-models>
Models can be directly used without downloading to local storage
Example: `modelPath: 'https://vladmandic.github.io/human-models/models/facemesh.json'`
@ -69,10 +71,11 @@ Model is supported using `WebGL` backend in browser
- Fix **NanoDet** module as alternative object detection
- Fix `demo/multithread/node-multiprocess.js` demo
- Fix `human.match` when using mixed descriptor lengths
- Fix WASM feature detection issue in TFJS with Edge/Chromium
- Increased test coverage
Run using `npm run test`
**NodeJS**: Run using `npm run test`
**Browser**: Run using `demo/browser.html`
- Increase availability of alternative models
See `models/model.json` for full list
- Update **NMS** methods resulting in some performance improvements
- Update profiling methods in `human.profile()`
- Update project dependencies

View File

@ -79,7 +79,7 @@
"@tensorflow/tfjs-node": "^3.19.0",
"@tensorflow/tfjs-node-gpu": "^3.19.0",
"@tensorflow/tfjs-tflite": "0.0.1-alpha.8",
"@types/node": "^18.7.2",
"@types/node": "^18.7.4",
"@types/offscreencanvas": "^2019.7.0",
"@typescript-eslint/eslint-plugin": "^5.33.0",
"@typescript-eslint/parser": "^5.33.0",
@ -87,8 +87,8 @@
"@vladmandic/pilogger": "^0.4.6",
"@vladmandic/tfjs": "github:vladmandic/tfjs",
"@webgpu/types": "^0.1.21",
"esbuild": "^0.15.1",
"eslint": "8.21.0",
"esbuild": "^0.15.3",
"eslint": "8.22.0",
"eslint-config-airbnb-base": "^15.0.0",
"eslint-plugin-html": "^7.1.0",
"eslint-plugin-import": "^2.26.0",

View File

@ -71,7 +71,7 @@ export async function decode(boxesTensor: Tensor, logitsTensor: Tensor, config:
detected.push({ box, boxRaw, score: scores[i] });
}
/*
t.nms = tf.image.nonMaxSuppression(t.boxes, t.scores, 1, config.body.detector?.minConfidence || 0.1, config.body.detector?.iouThreshold || 0.1);
t.nms = await tf.image.nonMaxSuppressionAsync(t.boxes, t.scores, 1, config.body.detector?.minConfidence || 0.1, config.body.detector?.iouThreshold || 0.1);
const boxes = t.boxes.arraySync();
const scores = t.scores.dataSync();
const nms = t.nms.dataSync();

View File

@ -75,7 +75,7 @@ export async function getBoxes(inputImage: Tensor, config: Config) {
t.logits = tf.slice(t.batch, [0, 0], [-1, 1]);
t.sigmoid = tf.sigmoid(t.logits);
t.scores = tf.squeeze(t.sigmoid);
t.nms = tf.image.nonMaxSuppression(t.boxes, t.scores, (config.face.detector?.maxDetected || 0), (config.face.detector?.iouThreshold || 0), (config.face.detector?.minConfidence || 0));
t.nms = await tf.image.nonMaxSuppressionAsync(t.boxes, t.scores, (config.face.detector?.maxDetected || 0), (config.face.detector?.iouThreshold || 0), (config.face.detector?.minConfidence || 0));
const nms = await t.nms.array() as number[];
const boxes: Array<DetectBox> = [];
const scores = await t.scores.data();

View File

@ -67,7 +67,7 @@ export class HandDetector {
t.boxes = tf.slice(t.predictions, [0, 1], [-1, 4]);
t.norm = this.normalizeBoxes(t.boxes);
// box detection is flaky so we look for 3x boxes than we need results
t.nms = tf.image.nonMaxSuppression(t.norm, t.scores, 3 * config.hand.maxDetected, config.hand.iouThreshold, config.hand.minConfidence);
t.nms = await tf.image.nonMaxSuppressionAsync(t.norm, t.scores, 3 * config.hand.maxDetected, config.hand.iouThreshold, config.hand.minConfidence);
const nms = await t.nms.array() as Array<number>;
const hands: Array<{ startPoint: Point; endPoint: Point; palmLandmarks: Point[]; confidence: number }> = [];
for (const index of nms) {

View File

@ -121,7 +121,7 @@ async function detectHands(input: Tensor, config: Config): Promise<HandDetectRes
t.max = tf.max(t.filtered, 1); // max overall score
t.argmax = tf.argMax(t.filtered, 1); // class index of max overall score
let id = 0;
t.nms = tf.image.nonMaxSuppression(t.boxes, t.max, (config.hand.maxDetected || 0) + 1, config.hand.iouThreshold || 0, config.hand.minConfidence || 1);
t.nms = await tf.image.nonMaxSuppressionAsync(t.boxes, t.max, (config.hand.maxDetected || 0) + 1, config.hand.iouThreshold || 0, config.hand.minConfidence || 1);
const nms = await t.nms.data();
const scores = await t.max.data();
const classNum = await t.argmax.data();

View File

@ -42,7 +42,7 @@ async function process(res: Tensor | null, outputShape: [number, number], config
t.scores = tf.squeeze(arr[4]);
t.classes = tf.squeeze(arr[5]);
tf.dispose([res, ...arr]);
t.nms = tf.image.nonMaxSuppression(t.boxes, t.scores, config.object.maxDetected, config.object.iouThreshold, (config.object.minConfidence || 0));
t.nms = await tf.image.nonMaxSuppressionAsync(t.boxes, t.scores, config.object.maxDetected, config.object.iouThreshold, (config.object.minConfidence || 0));
const nms = await t.nms.data();
let i = 0;
for (const id of Array.from(nms)) {

View File

@ -91,7 +91,7 @@ async function process(res: Tensor[], outputShape: [number, number], config: Con
const nmsScores = results.map((a) => a.score);
let nmsIdx: Array<number> = [];
if (nmsBoxes && nmsBoxes.length > 0) {
const nms = tf.image.nonMaxSuppression(nmsBoxes, nmsScores, config.object.maxDetected, config.object.iouThreshold, config.object.minConfidence);
const nms = await tf.image.nonMaxSuppressionAsync(nmsBoxes, nmsScores, config.object.maxDetected, config.object.iouThreshold, config.object.minConfidence);
nmsIdx = await nms.data();
tf.dispose(nms);
}

View File

@ -90,10 +90,16 @@ export async function check(instance: Human, force = false) {
if (instance.config.debug) log('wasm path:', instance.config.wasmPath);
if (typeof tf?.setWasmPaths !== 'undefined') await tf.setWasmPaths(instance.config.wasmPath, instance.config.wasmPlatformFetch);
else throw new Error('backend error: attempting to use wasm backend but wasm path is not set');
const simd = await tf.env().getAsync('WASM_HAS_SIMD_SUPPORT');
const mt = await tf.env().getAsync('WASM_HAS_MULTITHREAD_SUPPORT');
if (instance.config.debug) log(`wasm execution: ${simd ? 'SIMD' : 'no SIMD'} ${mt ? 'multithreaded' : 'singlethreaded'}`);
if (instance.config.debug && !simd) log('warning: wasm simd support is not enabled');
let mt = false;
let simd = false;
try {
mt = await tf.env().getAsync('WASM_HAS_MULTITHREAD_SUPPORT');
simd = await tf.env().getAsync('WASM_HAS_SIMD_SUPPORT');
if (instance.config.debug) log(`wasm execution: ${simd ? 'simd' : 'no simd'} ${mt ? 'multithreaded' : 'singlethreaded'}`);
if (instance.config.debug && !simd) log('warning: wasm simd support is not enabled');
} catch {
log('wasm detection failed');
}
}
try {

View File

@ -27,6 +27,10 @@ export class Env {
offscreen: undefined | boolean;
/** Are performance counter instant values or additive */
perfadd: boolean = false;
/** If using tfjs-node get version of underlying tensorflow shared library */
tensorflow: {
version: undefined | string,
} = { version: undefined };
/** WASM detected capabilities */
wasm: {
supported: undefined | boolean,
@ -84,6 +88,7 @@ export class Env {
this.tfjs = { version: tf.version['tfjs-core'] };
this.offscreen = typeof OffscreenCanvas !== 'undefined';
this.initial = true;
// @ts-ignore WorkerGlobalScope evaluated in browser only
this.worker = this.browser && this.offscreen ? (typeof WorkerGlobalScope !== 'undefined') : undefined;
if (typeof navigator !== 'undefined') {
@ -114,6 +119,7 @@ export class Env {
async updateBackend() {
// analyze backends
this.backends = Object.keys(tf.engine().registryFactory);
this.tensorflow = { version: (tf.backend()['binding'] ? tf.backend()['binding']['TF_Version'] : undefined) };
this.wasm.supported = typeof WebAssembly !== 'undefined';
this.wasm.backend = this.backends.includes('wasm');
if (this.wasm.supported && this.wasm.backend && tf.getBackend() === 'wasm') {

View File

@ -13,9 +13,9 @@
<style>
@font-face { font-family: 'Lato'; font-display: swap; font-style: normal; font-weight: 100; src: local('Lato'), url('../../assets/lato-light.woff2') }
html { font-family: 'Lato', 'Segoe UI'; font-size: 14px; font-variant: small-caps; }
body { margin: 0; background: black; color: white; }
body { margin: 0; background: black; color: white; width: 100vw; overflow-x: hidden; }
.canvas { position: absolute; bottom: 10px; right: 10px; width: 256px; height: 256px; z-index: 99; }
.pre { line-height: 150%; }
.pre { line-height: 150%; white-space: break-spaces; }
.events { position: absolute; top: 10px; right: 10px; width: 12rem; height: 1.25rem; background-color: grey; padding: 8px; z-index: 99; }
.state { position: absolute; top: 60px; right: 10px; width: 12rem; height: 1.25rem; background-color: grey; padding: 8px; z-index: 99; }
</style>
@ -36,16 +36,16 @@
object: { enabled: true },
};
const backends = ['wasm', 'webgl', 'humangl', 'webgpu'];
const backends = ['wasm', 'humangl', 'webgl', 'webgpu'];
const start = performance.now();
function str(...msg) {
function str(long, ...msg) {
if (!Array.isArray(msg)) return msg;
let line = '';
for (const entry of msg) {
if (typeof entry === 'object') line += JSON.stringify(entry).replace(/"/g, '').replace(/,/g, ', ').replace(/:/g, ': ');
else line += entry;
if (typeof entry === 'object') line += ' ' + JSON.stringify(entry, null, long ? 2 : 0).replace(/"/g, '').replace(/,/g, ', ').replace(/:/g, ': ');
else line += ' ' + entry;
}
return line + '\n';
}
@ -55,9 +55,19 @@
const dt = new Date();
const ts = `${dt.getHours().toString().padStart(2, '0')}:${dt.getMinutes().toString().padStart(2, '0')}:${dt.getSeconds().toString().padStart(2, '0')}.${dt.getMilliseconds().toString().padStart(3, '0')}`;
const elap = (dt - last).toString().padStart(5, '0');
document.getElementById('log').innerHTML += ts + ' +' + elap + 'ms &nbsp' + str(...msgs);
// eslint-disable-next-line no-console
console.log(ts, elap, ...msgs);
document.getElementById('log').innerHTML += ts + ' +' + elap + 'ms &nbsp' + str(false, ...msgs);
document.documentElement.scrollTop = document.documentElement.scrollHeight
console.log(ts, elap, ...msgs); // eslint-disable-line no-console
last = dt;
}
async function detailed(...msgs) {
const dt = new Date();
const ts = `${dt.getHours().toString().padStart(2, '0')}:${dt.getMinutes().toString().padStart(2, '0')}:${dt.getSeconds().toString().padStart(2, '0')}.${dt.getMilliseconds().toString().padStart(3, '0')}`;
const elap = (dt - last).toString().padStart(5, '0');
document.getElementById('log').innerHTML += ts + ' +' + elap + 'ms &nbsp' + str(true, ...msgs);
document.documentElement.scrollTop = document.documentElement.scrollHeight
console.log(ts, elap, ...msgs); // eslint-disable-line no-console
last = dt;
}
@ -95,37 +105,44 @@
human.events.addEventListener('image', () => events('image'));
human.events.addEventListener('detect', () => events('detect'));
const timer = setInterval(() => { document.getElementById('state').innerText = `State: ${human.state}`; }, 10);
log({ version: human.version });
log({ tfjs: human.tf.version.tfjs });
log({ environment: human.env });
log({ config: human.config });
log('version', human.version);
log('tfjs', human.tf.version.tfjs);
const env = JSON.parse(JSON.stringify(human.env));
env.kernels = human.env.kernels.length;
detailed('environment', env);
detailed('config', human.config);
await human.load();
const models = Object.keys(human.models).map((model) => ({ name: model, loaded: (human.models[model] !== null) }));
log({ models });
log('models', models);
for (const backend of backends) {
log();
log('test start:', backend);
human.config.backend = backend;
await human.init();
log({ initialized: human.tf.getBackend() });
log({ memory: human.tf.memory() });
log('desired', backend, 'detected', human.tf.getBackend());
if (human.tf.getBackend() !== backend) {
continue;
}
log('memory', human.tf.memory());
res = await human.validate();
log({ validate: res });
log('validate', res);
res = await human.warmup({ warmup: 'face' });
draw(res.canvas);
log({ warmup: 'face' });
log('warmup', 'face');
let img = await image('../../samples/in/ai-body.jpg');
const input = await human.image(img);
log({ input: input.tensor.shape });
log('input', input.tensor.shape);
draw(res.canvas);
res = await human.detect(input.tensor);
log({ detect: true });
log('detect');
human.next();
log({ interpolated: true });
log('interpolate');
const persons = res.persons;
log({ persons: true });
log({ summary: { persons: persons.length, face: res.face.length, body: res.body.length, hand: res.hand.length, object: res.object.length, gesture: res.gesture.length } });
log({ performance: human.performance });
log('persons');
log('summary', { persons: persons.length, face: res.face.length, body: res.body.length, hand: res.hand.length, object: res.object.length, gesture: res.gesture.length });
log('performance', human.performance);
human.tf.dispose(input.tensor);
draw();
@ -138,12 +155,12 @@
draw(res.canvas);
}
const t1 = performance.now();
log({ benchmark: { time: Math.round((t1 - t0) / 10), cacheSensitivity: val }, performance: human.performance });
log('benchmark', { time: Math.round((t1 - t0) / 10), cacheSensitivity: val, performance: human.performance });
await wait(10);
}
draw();
log({ memory: human.tf.memory() });
log('memory', human.tf.memory());
}
clearInterval(timer);
log();

View File

@ -1,39 +1,39 @@
2022-08-12 09:50:24 DATA:  Build {"name":"@vladmandic/human","version":"2.9.3"}
2022-08-12 09:50:24 INFO:  Application: {"name":"@vladmandic/human","version":"2.9.3"}
2022-08-12 09:50:24 INFO:  Environment: {"profile":"production","config":".build.json","package":"package.json","tsconfig":true,"eslintrc":true,"git":true}
2022-08-12 09:50:24 INFO:  Toolchain: {"build":"0.7.9","esbuild":"0.15.1","typescript":"4.7.4","typedoc":"0.23.10","eslint":"8.21.0"}
2022-08-12 09:50:24 INFO:  Build: {"profile":"production","steps":["clean","compile","typings","typedoc","lint","changelog"]}
2022-08-12 09:50:24 STATE: Clean: {"locations":["dist/*","types/lib/*","typedoc/*"]}
2022-08-12 09:50:24 STATE: Compile: {"name":"tfjs/nodejs/cpu","format":"cjs","platform":"node","input":"tfjs/tf-node.ts","output":"dist/tfjs.esm.js","files":1,"inputBytes":102,"outputBytes":608}
2022-08-12 09:50:24 STATE: Compile: {"name":"human/nodejs/cpu","format":"cjs","platform":"node","input":"src/human.ts","output":"dist/human.node.js","files":75,"inputBytes":654779,"outputBytes":307161}
2022-08-12 09:50:24 STATE: Compile: {"name":"tfjs/nodejs/gpu","format":"cjs","platform":"node","input":"tfjs/tf-node-gpu.ts","output":"dist/tfjs.esm.js","files":1,"inputBytes":110,"outputBytes":612}
2022-08-12 09:50:24 STATE: Compile: {"name":"human/nodejs/gpu","format":"cjs","platform":"node","input":"src/human.ts","output":"dist/human.node-gpu.js","files":75,"inputBytes":654783,"outputBytes":307165}
2022-08-12 09:50:24 STATE: Compile: {"name":"tfjs/nodejs/wasm","format":"cjs","platform":"node","input":"tfjs/tf-node-wasm.ts","output":"dist/tfjs.esm.js","files":1,"inputBytes":149,"outputBytes":664}
2022-08-12 09:50:24 STATE: Compile: {"name":"human/nodejs/wasm","format":"cjs","platform":"node","input":"src/human.ts","output":"dist/human.node-wasm.js","files":75,"inputBytes":654835,"outputBytes":307215}
2022-08-12 09:50:24 STATE: Compile: {"name":"tfjs/browser/version","format":"esm","platform":"browser","input":"tfjs/tf-version.ts","output":"dist/tfjs.version.js","files":1,"inputBytes":1069,"outputBytes":358}
2022-08-12 09:50:24 STATE: Compile: {"name":"tfjs/browser/esm/nobundle","format":"esm","platform":"browser","input":"tfjs/tf-browser.ts","output":"dist/tfjs.esm.js","files":2,"inputBytes":1032,"outputBytes":583}
2022-08-12 09:50:24 STATE: Compile: {"name":"human/browser/esm/nobundle","format":"esm","platform":"browser","input":"src/human.ts","output":"dist/human.esm-nobundle.js","files":75,"inputBytes":654754,"outputBytes":306014}
2022-08-12 09:50:24 STATE: Compile: {"name":"tfjs/browser/esm/custom","format":"esm","platform":"browser","input":"tfjs/tf-custom.ts","output":"dist/tfjs.esm.js","files":11,"inputBytes":1271,"outputBytes":2787569}
2022-08-12 09:50:24 STATE: Compile: {"name":"human/browser/iife/bundle","format":"iife","platform":"browser","input":"src/human.ts","output":"dist/human.js","files":75,"inputBytes":3441740,"outputBytes":1668900}
2022-08-12 09:50:24 STATE: Compile: {"name":"human/browser/esm/bundle","format":"esm","platform":"browser","input":"src/human.ts","output":"dist/human.esm.js","files":75,"inputBytes":3441740,"outputBytes":3072630}
2022-08-12 09:50:31 STATE: Typings: {"input":"src/human.ts","output":"types/lib","files":30}
2022-08-12 09:50:33 STATE: TypeDoc: {"input":"src/human.ts","output":"typedoc","objects":77,"generated":true}
2022-08-12 09:50:33 STATE: Compile: {"name":"demo/typescript","format":"esm","platform":"browser","input":"demo/typescript/index.ts","output":"demo/typescript/index.js","files":1,"inputBytes":6716,"outputBytes":3141}
2022-08-12 09:50:33 STATE: Compile: {"name":"demo/faceid","format":"esm","platform":"browser","input":"demo/faceid/index.ts","output":"demo/faceid/index.js","files":2,"inputBytes":15629,"outputBytes":7798}
2022-08-12 09:50:42 STATE: Lint: {"locations":["*.json","src/**/*.ts","test/**/*.js","demo/**/*.js"],"files":109,"errors":0,"warnings":0}
2022-08-12 09:50:42 STATE: ChangeLog: {"repository":"https://github.com/vladmandic/human","branch":"main","output":"CHANGELOG.md"}
2022-08-12 09:50:42 STATE: Copy: {"input":"tfjs/tfjs.esm.d.ts"}
2022-08-12 09:50:42 INFO:  Done...
2022-08-12 09:50:42 STATE: API-Extractor: {"succeeeded":true,"errors":0,"warnings":198}
2022-08-12 09:50:42 STATE: Copy: {"input":"types/human.d.ts"}
2022-08-12 09:50:42 INFO:  Analyze models: {"folders":8,"result":"models/models.json"}
2022-08-12 09:50:42 STATE: Models {"folder":"./models","models":13}
2022-08-12 09:50:42 STATE: Models {"folder":"../human-models/models","models":42}
2022-08-12 09:50:42 STATE: Models {"folder":"../blazepose/model/","models":4}
2022-08-12 09:50:42 STATE: Models {"folder":"../anti-spoofing/model","models":1}
2022-08-12 09:50:42 STATE: Models {"folder":"../efficientpose/models","models":3}
2022-08-12 09:50:42 STATE: Models {"folder":"../insightface/models","models":5}
2022-08-12 09:50:42 STATE: Models {"folder":"../movenet/models","models":3}
2022-08-12 09:50:42 STATE: Models {"folder":"../nanodet/models","models":4}
2022-08-12 09:50:43 STATE: Models: {"count":57,"totalSize":383017442}
2022-08-12 09:50:43 INFO:  Human Build complete... {"logFile":"test/build.log"}
2022-08-15 11:28:08 DATA:  Build {"name":"@vladmandic/human","version":"2.9.3"}
2022-08-15 11:28:08 INFO:  Application: {"name":"@vladmandic/human","version":"2.9.3"}
2022-08-15 11:28:08 INFO:  Environment: {"profile":"production","config":".build.json","package":"package.json","tsconfig":true,"eslintrc":true,"git":true}
2022-08-15 11:28:08 INFO:  Toolchain: {"build":"0.7.9","esbuild":"0.15.3","typescript":"4.7.4","typedoc":"0.23.10","eslint":"8.22.0"}
2022-08-15 11:28:08 INFO:  Build: {"profile":"production","steps":["clean","compile","typings","typedoc","lint","changelog"]}
2022-08-15 11:28:08 STATE: Clean: {"locations":["dist/*","types/lib/*","typedoc/*"]}
2022-08-15 11:28:08 STATE: Compile: {"name":"tfjs/nodejs/cpu","format":"cjs","platform":"node","input":"tfjs/tf-node.ts","output":"dist/tfjs.esm.js","files":1,"inputBytes":102,"outputBytes":608}
2022-08-15 11:28:08 STATE: Compile: {"name":"human/nodejs/cpu","format":"cjs","platform":"node","input":"src/human.ts","output":"dist/human.node.js","files":75,"inputBytes":655247,"outputBytes":307391}
2022-08-15 11:28:08 STATE: Compile: {"name":"tfjs/nodejs/gpu","format":"cjs","platform":"node","input":"tfjs/tf-node-gpu.ts","output":"dist/tfjs.esm.js","files":1,"inputBytes":110,"outputBytes":612}
2022-08-15 11:28:08 STATE: Compile: {"name":"human/nodejs/gpu","format":"cjs","platform":"node","input":"src/human.ts","output":"dist/human.node-gpu.js","files":75,"inputBytes":655251,"outputBytes":307395}
2022-08-15 11:28:08 STATE: Compile: {"name":"tfjs/nodejs/wasm","format":"cjs","platform":"node","input":"tfjs/tf-node-wasm.ts","output":"dist/tfjs.esm.js","files":1,"inputBytes":149,"outputBytes":664}
2022-08-15 11:28:08 STATE: Compile: {"name":"human/nodejs/wasm","format":"cjs","platform":"node","input":"src/human.ts","output":"dist/human.node-wasm.js","files":75,"inputBytes":655303,"outputBytes":307445}
2022-08-15 11:28:08 STATE: Compile: {"name":"tfjs/browser/version","format":"esm","platform":"browser","input":"tfjs/tf-version.ts","output":"dist/tfjs.version.js","files":1,"inputBytes":1069,"outputBytes":358}
2022-08-15 11:28:08 STATE: Compile: {"name":"tfjs/browser/esm/nobundle","format":"esm","platform":"browser","input":"tfjs/tf-browser.ts","output":"dist/tfjs.esm.js","files":2,"inputBytes":1032,"outputBytes":583}
2022-08-15 11:28:08 STATE: Compile: {"name":"human/browser/esm/nobundle","format":"esm","platform":"browser","input":"src/human.ts","output":"dist/human.esm-nobundle.js","files":75,"inputBytes":655222,"outputBytes":306242}
2022-08-15 11:28:09 STATE: Compile: {"name":"tfjs/browser/esm/custom","format":"esm","platform":"browser","input":"tfjs/tf-custom.ts","output":"dist/tfjs.esm.js","files":11,"inputBytes":1271,"outputBytes":2787569}
2022-08-15 11:28:09 STATE: Compile: {"name":"human/browser/iife/bundle","format":"iife","platform":"browser","input":"src/human.ts","output":"dist/human.js","files":75,"inputBytes":3442208,"outputBytes":1669116}
2022-08-15 11:28:09 STATE: Compile: {"name":"human/browser/esm/bundle","format":"esm","platform":"browser","input":"src/human.ts","output":"dist/human.esm.js","files":75,"inputBytes":3442208,"outputBytes":3072985}
2022-08-15 11:28:14 STATE: Typings: {"input":"src/human.ts","output":"types/lib","files":30}
2022-08-15 11:28:15 STATE: TypeDoc: {"input":"src/human.ts","output":"typedoc","objects":77,"generated":true}
2022-08-15 11:28:15 STATE: Compile: {"name":"demo/typescript","format":"esm","platform":"browser","input":"demo/typescript/index.ts","output":"demo/typescript/index.js","files":1,"inputBytes":6716,"outputBytes":3141}
2022-08-15 11:28:15 STATE: Compile: {"name":"demo/faceid","format":"esm","platform":"browser","input":"demo/faceid/index.ts","output":"demo/faceid/index.js","files":2,"inputBytes":15629,"outputBytes":7798}
2022-08-15 11:28:24 STATE: Lint: {"locations":["*.json","src/**/*.ts","test/**/*.js","demo/**/*.js"],"files":109,"errors":0,"warnings":0}
2022-08-15 11:28:24 STATE: ChangeLog: {"repository":"https://github.com/vladmandic/human","branch":"main","output":"CHANGELOG.md"}
2022-08-15 11:28:24 STATE: Copy: {"input":"tfjs/tfjs.esm.d.ts"}
2022-08-15 11:28:24 INFO:  Done...
2022-08-15 11:28:24 STATE: API-Extractor: {"succeeeded":true,"errors":0,"warnings":198}
2022-08-15 11:28:24 STATE: Copy: {"input":"types/human.d.ts"}
2022-08-15 11:28:24 INFO:  Analyze models: {"folders":8,"result":"models/models.json"}
2022-08-15 11:28:24 STATE: Models {"folder":"./models","models":13}
2022-08-15 11:28:24 STATE: Models {"folder":"../human-models/models","models":42}
2022-08-15 11:28:24 STATE: Models {"folder":"../blazepose/model/","models":4}
2022-08-15 11:28:24 STATE: Models {"folder":"../anti-spoofing/model","models":1}
2022-08-15 11:28:24 STATE: Models {"folder":"../efficientpose/models","models":3}
2022-08-15 11:28:24 STATE: Models {"folder":"../insightface/models","models":5}
2022-08-15 11:28:24 STATE: Models {"folder":"../movenet/models","models":3}
2022-08-15 11:28:24 STATE: Models {"folder":"../nanodet/models","models":4}
2022-08-15 11:28:25 STATE: Models: {"count":57,"totalSize":383017442}
2022-08-15 11:28:25 INFO:  Human Build complete... {"logFile":"test/build.log"}

View File

@ -5,7 +5,7 @@ const { fork } = require('child_process');
const log = require('@vladmandic/pilogger');
let logFile = 'test.log';
log.configure({ inspect: { breakLength: 500 } });
log.configure({ inspect: { breakLength: 350 } });
const tests = [
'test-node.js',

View File

@ -12,7 +12,8 @@ const log = (status, ...data) => {
};
process.on('uncaughtException', (err) => {
log('error', 'uncaughtException', lastOp, err);
log('error', 'uncaughtException', lastOp, err); // abort immediately
process.exit(1);
});
async function testHTTP() {
@ -74,12 +75,17 @@ async function testInstance(human) {
log('info', 'human version:', human.version);
log('info', 'platform:', human.env.platform, 'agent:', human.env.agent);
log('info', 'tfjs version:', human.tf.version.tfjs);
const bindingVer = human.tf.backend()['binding'] ? human.tf.backend()['binding']['TF_Version'] : null;
if (bindingVer) log('info', 'tensorflow binding version:', bindingVer);
const env = JSON.parse(JSON.stringify(human.env));
env.kernels = human.env.kernels.length;
log('info', 'env:', env);
await human.load();
if (config.backend === human.tf.getBackend()) log('state', 'passed: set backend:', config.backend);
else log('error', 'failed: set backend:', config.backend);
if (config.backend === human.tf.getBackend()) {
log('state', 'passed: set backend:', config.backend);
} else {
log('error', 'failed: set backend:', config.backend); // abort immediately
return false;
}
log('state', 'tensors', human.tf.memory().numTensors);
if (human.models) {
@ -296,7 +302,11 @@ async function test(Human, inputConfig) {
// test warmup sequences
log('info', 'test: warmup');
await testInstance(human);
res = await testInstance(human);
if (!res) {
log('error', 'failed: instance backend:', human.tf.getBackend());
return;
}
config.cacheSensitivity = 0;
config.warmup = 'none';
res = await testWarmup(human, 'default');
@ -475,7 +485,7 @@ async function test(Human, inputConfig) {
// test face attention
log('info', 'test face attention');
human.models.facemesh = null;
config.face.attention = { enabled: true };
config.face.attention = { enabled: true, modelPath: 'https://vladmandic.github.io/human-models/models/facemesh-attention.json' };
res = await testDetect(human, 'samples/in/ai-face.jpg', 'face attention');
if (!res || !res.face[0] || res.face[0].mesh.length !== 478 || Object.keys(res.face[0].annotations).length !== 36) log('error', 'failed: face attention', { mesh: res.face?.[0]?.mesh?.length, annotations: Object.keys(res.face?.[0]?.annotations | {}).length });
else log('state', 'passed: face attention');

View File

@ -1,5 +1,5 @@
process.env.TF_CPP_MIN_LOG_LEVEL = '2';
const Human = require('../dist/human.node-gpu.js').default;
const H = require('../dist/human.node-gpu.js');
const test = require('./test-main.js').test;
const config = {
@ -25,4 +25,8 @@ const config = {
filter: { enabled: false },
};
test(Human, config);
async function main() {
test(H.Human, config);
}
main();

View File

@ -1,20 +1,21 @@
const log = require('@vladmandic/pilogger');
const tf = require('@tensorflow/tfjs'); // wasm backend requires tfjs to be loaded first
const wasm = require('@tensorflow/tfjs-backend-wasm'); // wasm backend does not get auto-loaded in nodejs
const { Canvas, Image } = require('canvas');
const Human = require('../dist/human.node-wasm.js');
const H = require('../dist/human.node-wasm.js');
const test = require('./test-main.js').test;
// @ts-ignore
Human.env.Canvas = Canvas; // requires monkey-patch as wasm does not have tf.browser namespace
H.env.Canvas = Canvas; // requires monkey-patch as wasm does not have tf.browser namespace
// @ts-ignore
Human.env.Image = Image; // requires monkey-patch as wasm does not have tf.browser namespace
H.env.Image = Image; // requires monkey-patch as wasm does not have tf.browser namespace
const config = {
cacheSensitivity: 0,
modelBasePath: 'https://vladmandic.github.io/human/models/',
backend: 'wasm',
wasmPath: 'node_modules/@tensorflow/tfjs-backend-wasm/dist/',
// wasmPath: `cdn.jsdelivr.net/npm/@tensorflow/tfjs-backend-wasm@${tf.version_core}/dist/`,
// wasmPath: 'node_modules/@tensorflow/tfjs-backend-wasm/dist/',
wasmPath: `https://cdn.jsdelivr.net/npm/@tensorflow/tfjs-backend-wasm@${tf.version_core}/dist/`,
debug: false,
async: false,
face: {
@ -38,7 +39,9 @@ async function main() {
wasm.setWasmPaths(config.wasmPath);
await tf.setBackend('wasm');
await tf.ready();
test(Human.Human, config);
H.env.updateBackend();
log.info(H.env.wasm);
test(H.Human, config);
}
main();

View File

@ -1,5 +1,6 @@
process.env.TF_CPP_MIN_LOG_LEVEL = '2';
const Human = require('../dist/human.node.js').default;
const H = require('../dist/human.node.js');
const test = require('./test-main.js').test;
const config = {
@ -25,4 +26,8 @@ const config = {
filter: { enabled: false },
};
test(Human, config);
async function main() {
test(H.Human, config);
}
main();

File diff suppressed because it is too large Load Diff