mirror of https://github.com/vladmandic/human
fix wasm detection
parent
554ed81f49
commit
6fc26e793c
|
@ -11,9 +11,8 @@
|
||||||
|
|
||||||
### **HEAD -> main** 2022/08/12 mandic00@live.com
|
### **HEAD -> main** 2022/08/12 mandic00@live.com
|
||||||
|
|
||||||
|
- enumerate additional models
|
||||||
### **origin/main** 2022/08/10 mandic00@live.com
|
- release refresh
|
||||||
|
|
||||||
|
|
||||||
### **2.9.3** 2022/08/10 mandic00@live.com
|
### **2.9.3** 2022/08/10 mandic00@live.com
|
||||||
|
|
||||||
|
|
11
TODO.md
11
TODO.md
|
@ -57,6 +57,8 @@ Model is supported using `WebGL` backend in browser
|
||||||
Models can be downloaded from <https://github.com/vladmandic/insightface>
|
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
|
- Add `human.check()` which validates all kernel ops for currently loaded models with currently selected backend
|
||||||
Example: `console.error(human.check());`
|
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>
|
- Host models in <human-models>
|
||||||
Models can be directly used without downloading to local storage
|
Models can be directly used without downloading to local storage
|
||||||
Example: `modelPath: 'https://vladmandic.github.io/human-models/models/facemesh.json'`
|
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 **NanoDet** module as alternative object detection
|
||||||
- Fix `demo/multithread/node-multiprocess.js` demo
|
- Fix `demo/multithread/node-multiprocess.js` demo
|
||||||
- Fix `human.match` when using mixed descriptor lengths
|
- Fix `human.match` when using mixed descriptor lengths
|
||||||
- Increased test coverage
|
- Fix WASM feature detection issue in TFJS with Edge/Chromium
|
||||||
Run using `npm run test`
|
- Increased test coverage
|
||||||
|
**NodeJS**: Run using `npm run test`
|
||||||
|
**Browser**: Run using `demo/browser.html`
|
||||||
- Increase availability of alternative models
|
- Increase availability of alternative models
|
||||||
See `models/model.json` for full list
|
See `models/model.json` for full list
|
||||||
- Update **NMS** methods resulting in some performance improvements
|
|
||||||
- Update profiling methods in `human.profile()`
|
- Update profiling methods in `human.profile()`
|
||||||
- Update project dependencies
|
- Update project dependencies
|
||||||
|
|
|
@ -79,7 +79,7 @@
|
||||||
"@tensorflow/tfjs-node": "^3.19.0",
|
"@tensorflow/tfjs-node": "^3.19.0",
|
||||||
"@tensorflow/tfjs-node-gpu": "^3.19.0",
|
"@tensorflow/tfjs-node-gpu": "^3.19.0",
|
||||||
"@tensorflow/tfjs-tflite": "0.0.1-alpha.8",
|
"@tensorflow/tfjs-tflite": "0.0.1-alpha.8",
|
||||||
"@types/node": "^18.7.2",
|
"@types/node": "^18.7.4",
|
||||||
"@types/offscreencanvas": "^2019.7.0",
|
"@types/offscreencanvas": "^2019.7.0",
|
||||||
"@typescript-eslint/eslint-plugin": "^5.33.0",
|
"@typescript-eslint/eslint-plugin": "^5.33.0",
|
||||||
"@typescript-eslint/parser": "^5.33.0",
|
"@typescript-eslint/parser": "^5.33.0",
|
||||||
|
@ -87,8 +87,8 @@
|
||||||
"@vladmandic/pilogger": "^0.4.6",
|
"@vladmandic/pilogger": "^0.4.6",
|
||||||
"@vladmandic/tfjs": "github:vladmandic/tfjs",
|
"@vladmandic/tfjs": "github:vladmandic/tfjs",
|
||||||
"@webgpu/types": "^0.1.21",
|
"@webgpu/types": "^0.1.21",
|
||||||
"esbuild": "^0.15.1",
|
"esbuild": "^0.15.3",
|
||||||
"eslint": "8.21.0",
|
"eslint": "8.22.0",
|
||||||
"eslint-config-airbnb-base": "^15.0.0",
|
"eslint-config-airbnb-base": "^15.0.0",
|
||||||
"eslint-plugin-html": "^7.1.0",
|
"eslint-plugin-html": "^7.1.0",
|
||||||
"eslint-plugin-import": "^2.26.0",
|
"eslint-plugin-import": "^2.26.0",
|
||||||
|
|
|
@ -71,7 +71,7 @@ export async function decode(boxesTensor: Tensor, logitsTensor: Tensor, config:
|
||||||
detected.push({ box, boxRaw, score: scores[i] });
|
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 boxes = t.boxes.arraySync();
|
||||||
const scores = t.scores.dataSync();
|
const scores = t.scores.dataSync();
|
||||||
const nms = t.nms.dataSync();
|
const nms = t.nms.dataSync();
|
||||||
|
|
|
@ -75,7 +75,7 @@ export async function getBoxes(inputImage: Tensor, config: Config) {
|
||||||
t.logits = tf.slice(t.batch, [0, 0], [-1, 1]);
|
t.logits = tf.slice(t.batch, [0, 0], [-1, 1]);
|
||||||
t.sigmoid = tf.sigmoid(t.logits);
|
t.sigmoid = tf.sigmoid(t.logits);
|
||||||
t.scores = tf.squeeze(t.sigmoid);
|
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 nms = await t.nms.array() as number[];
|
||||||
const boxes: Array<DetectBox> = [];
|
const boxes: Array<DetectBox> = [];
|
||||||
const scores = await t.scores.data();
|
const scores = await t.scores.data();
|
||||||
|
|
|
@ -67,7 +67,7 @@ export class HandDetector {
|
||||||
t.boxes = tf.slice(t.predictions, [0, 1], [-1, 4]);
|
t.boxes = tf.slice(t.predictions, [0, 1], [-1, 4]);
|
||||||
t.norm = this.normalizeBoxes(t.boxes);
|
t.norm = this.normalizeBoxes(t.boxes);
|
||||||
// box detection is flaky so we look for 3x boxes than we need results
|
// 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 nms = await t.nms.array() as Array<number>;
|
||||||
const hands: Array<{ startPoint: Point; endPoint: Point; palmLandmarks: Point[]; confidence: number }> = [];
|
const hands: Array<{ startPoint: Point; endPoint: Point; palmLandmarks: Point[]; confidence: number }> = [];
|
||||||
for (const index of nms) {
|
for (const index of nms) {
|
||||||
|
|
|
@ -121,7 +121,7 @@ async function detectHands(input: Tensor, config: Config): Promise<HandDetectRes
|
||||||
t.max = tf.max(t.filtered, 1); // max overall score
|
t.max = tf.max(t.filtered, 1); // max overall score
|
||||||
t.argmax = tf.argMax(t.filtered, 1); // class index of max overall score
|
t.argmax = tf.argMax(t.filtered, 1); // class index of max overall score
|
||||||
let id = 0;
|
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 nms = await t.nms.data();
|
||||||
const scores = await t.max.data();
|
const scores = await t.max.data();
|
||||||
const classNum = await t.argmax.data();
|
const classNum = await t.argmax.data();
|
||||||
|
|
|
@ -42,7 +42,7 @@ async function process(res: Tensor | null, outputShape: [number, number], config
|
||||||
t.scores = tf.squeeze(arr[4]);
|
t.scores = tf.squeeze(arr[4]);
|
||||||
t.classes = tf.squeeze(arr[5]);
|
t.classes = tf.squeeze(arr[5]);
|
||||||
tf.dispose([res, ...arr]);
|
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();
|
const nms = await t.nms.data();
|
||||||
let i = 0;
|
let i = 0;
|
||||||
for (const id of Array.from(nms)) {
|
for (const id of Array.from(nms)) {
|
||||||
|
|
|
@ -91,7 +91,7 @@ async function process(res: Tensor[], outputShape: [number, number], config: Con
|
||||||
const nmsScores = results.map((a) => a.score);
|
const nmsScores = results.map((a) => a.score);
|
||||||
let nmsIdx: Array<number> = [];
|
let nmsIdx: Array<number> = [];
|
||||||
if (nmsBoxes && nmsBoxes.length > 0) {
|
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();
|
nmsIdx = await nms.data();
|
||||||
tf.dispose(nms);
|
tf.dispose(nms);
|
||||||
}
|
}
|
||||||
|
|
|
@ -90,10 +90,16 @@ export async function check(instance: Human, force = false) {
|
||||||
if (instance.config.debug) log('wasm path:', instance.config.wasmPath);
|
if (instance.config.debug) log('wasm path:', instance.config.wasmPath);
|
||||||
if (typeof tf?.setWasmPaths !== 'undefined') await tf.setWasmPaths(instance.config.wasmPath, instance.config.wasmPlatformFetch);
|
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');
|
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');
|
let mt = false;
|
||||||
const mt = await tf.env().getAsync('WASM_HAS_MULTITHREAD_SUPPORT');
|
let simd = false;
|
||||||
if (instance.config.debug) log(`wasm execution: ${simd ? 'SIMD' : 'no SIMD'} ${mt ? 'multithreaded' : 'singlethreaded'}`);
|
try {
|
||||||
if (instance.config.debug && !simd) log('warning: wasm simd support is not enabled');
|
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 {
|
try {
|
||||||
|
|
|
@ -27,6 +27,10 @@ export class Env {
|
||||||
offscreen: undefined | boolean;
|
offscreen: undefined | boolean;
|
||||||
/** Are performance counter instant values or additive */
|
/** Are performance counter instant values or additive */
|
||||||
perfadd: boolean = false;
|
perfadd: boolean = false;
|
||||||
|
/** If using tfjs-node get version of underlying tensorflow shared library */
|
||||||
|
tensorflow: {
|
||||||
|
version: undefined | string,
|
||||||
|
} = { version: undefined };
|
||||||
/** WASM detected capabilities */
|
/** WASM detected capabilities */
|
||||||
wasm: {
|
wasm: {
|
||||||
supported: undefined | boolean,
|
supported: undefined | boolean,
|
||||||
|
@ -84,6 +88,7 @@ export class Env {
|
||||||
this.tfjs = { version: tf.version['tfjs-core'] };
|
this.tfjs = { version: tf.version['tfjs-core'] };
|
||||||
this.offscreen = typeof OffscreenCanvas !== 'undefined';
|
this.offscreen = typeof OffscreenCanvas !== 'undefined';
|
||||||
this.initial = true;
|
this.initial = true;
|
||||||
|
|
||||||
// @ts-ignore WorkerGlobalScope evaluated in browser only
|
// @ts-ignore WorkerGlobalScope evaluated in browser only
|
||||||
this.worker = this.browser && this.offscreen ? (typeof WorkerGlobalScope !== 'undefined') : undefined;
|
this.worker = this.browser && this.offscreen ? (typeof WorkerGlobalScope !== 'undefined') : undefined;
|
||||||
if (typeof navigator !== 'undefined') {
|
if (typeof navigator !== 'undefined') {
|
||||||
|
@ -114,6 +119,7 @@ export class Env {
|
||||||
async updateBackend() {
|
async updateBackend() {
|
||||||
// analyze backends
|
// analyze backends
|
||||||
this.backends = Object.keys(tf.engine().registryFactory);
|
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.supported = typeof WebAssembly !== 'undefined';
|
||||||
this.wasm.backend = this.backends.includes('wasm');
|
this.wasm.backend = this.backends.includes('wasm');
|
||||||
if (this.wasm.supported && this.wasm.backend && tf.getBackend() === 'wasm') {
|
if (this.wasm.supported && this.wasm.backend && tf.getBackend() === 'wasm') {
|
||||||
|
|
|
@ -13,9 +13,9 @@
|
||||||
<style>
|
<style>
|
||||||
@font-face { font-family: 'Lato'; font-display: swap; font-style: normal; font-weight: 100; src: local('Lato'), url('../../assets/lato-light.woff2') }
|
@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; }
|
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; }
|
.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; }
|
.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; }
|
.state { position: absolute; top: 60px; right: 10px; width: 12rem; height: 1.25rem; background-color: grey; padding: 8px; z-index: 99; }
|
||||||
</style>
|
</style>
|
||||||
|
@ -36,16 +36,16 @@
|
||||||
object: { enabled: true },
|
object: { enabled: true },
|
||||||
};
|
};
|
||||||
|
|
||||||
const backends = ['wasm', 'webgl', 'humangl', 'webgpu'];
|
const backends = ['wasm', 'humangl', 'webgl', 'webgpu'];
|
||||||
|
|
||||||
const start = performance.now();
|
const start = performance.now();
|
||||||
|
|
||||||
function str(...msg) {
|
function str(long, ...msg) {
|
||||||
if (!Array.isArray(msg)) return msg;
|
if (!Array.isArray(msg)) return msg;
|
||||||
let line = '';
|
let line = '';
|
||||||
for (const entry of msg) {
|
for (const entry of msg) {
|
||||||
if (typeof entry === 'object') line += JSON.stringify(entry).replace(/"/g, '').replace(/,/g, ', ').replace(/:/g, ': ');
|
if (typeof entry === 'object') line += ' ' + JSON.stringify(entry, null, long ? 2 : 0).replace(/"/g, '').replace(/,/g, ', ').replace(/:/g, ': ');
|
||||||
else line += entry;
|
else line += ' ' + entry;
|
||||||
}
|
}
|
||||||
return line + '\n';
|
return line + '\n';
|
||||||
}
|
}
|
||||||
|
@ -55,9 +55,19 @@
|
||||||
const dt = new Date();
|
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 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');
|
const elap = (dt - last).toString().padStart(5, '0');
|
||||||
document.getElementById('log').innerHTML += ts + ' +' + elap + 'ms  ' + str(...msgs);
|
document.getElementById('log').innerHTML += ts + ' +' + elap + 'ms  ' + str(false, ...msgs);
|
||||||
// eslint-disable-next-line no-console
|
document.documentElement.scrollTop = document.documentElement.scrollHeight
|
||||||
console.log(ts, elap, ...msgs);
|
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  ' + str(true, ...msgs);
|
||||||
|
document.documentElement.scrollTop = document.documentElement.scrollHeight
|
||||||
|
console.log(ts, elap, ...msgs); // eslint-disable-line no-console
|
||||||
last = dt;
|
last = dt;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -95,37 +105,44 @@
|
||||||
human.events.addEventListener('image', () => events('image'));
|
human.events.addEventListener('image', () => events('image'));
|
||||||
human.events.addEventListener('detect', () => events('detect'));
|
human.events.addEventListener('detect', () => events('detect'));
|
||||||
const timer = setInterval(() => { document.getElementById('state').innerText = `State: ${human.state}`; }, 10);
|
const timer = setInterval(() => { document.getElementById('state').innerText = `State: ${human.state}`; }, 10);
|
||||||
log({ version: human.version });
|
log('version', human.version);
|
||||||
log({ tfjs: human.tf.version.tfjs });
|
log('tfjs', human.tf.version.tfjs);
|
||||||
log({ environment: human.env });
|
|
||||||
log({ config: human.config });
|
const env = JSON.parse(JSON.stringify(human.env));
|
||||||
|
env.kernels = human.env.kernels.length;
|
||||||
|
detailed('environment', env);
|
||||||
|
|
||||||
|
detailed('config', human.config);
|
||||||
await human.load();
|
await human.load();
|
||||||
const models = Object.keys(human.models).map((model) => ({ name: model, loaded: (human.models[model] !== null) }));
|
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) {
|
for (const backend of backends) {
|
||||||
log();
|
log();
|
||||||
log('test start:', backend);
|
log('test start:', backend);
|
||||||
human.config.backend = backend;
|
human.config.backend = backend;
|
||||||
await human.init();
|
await human.init();
|
||||||
log({ initialized: human.tf.getBackend() });
|
log('desired', backend, 'detected', human.tf.getBackend());
|
||||||
log({ memory: human.tf.memory() });
|
if (human.tf.getBackend() !== backend) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
log('memory', human.tf.memory());
|
||||||
res = await human.validate();
|
res = await human.validate();
|
||||||
log({ validate: res });
|
log('validate', res);
|
||||||
res = await human.warmup({ warmup: 'face' });
|
res = await human.warmup({ warmup: 'face' });
|
||||||
draw(res.canvas);
|
draw(res.canvas);
|
||||||
log({ warmup: 'face' });
|
log('warmup', 'face');
|
||||||
let img = await image('../../samples/in/ai-body.jpg');
|
let img = await image('../../samples/in/ai-body.jpg');
|
||||||
const input = await human.image(img);
|
const input = await human.image(img);
|
||||||
log({ input: input.tensor.shape });
|
log('input', input.tensor.shape);
|
||||||
draw(res.canvas);
|
draw(res.canvas);
|
||||||
res = await human.detect(input.tensor);
|
res = await human.detect(input.tensor);
|
||||||
log({ detect: true });
|
log('detect');
|
||||||
human.next();
|
human.next();
|
||||||
log({ interpolated: true });
|
log('interpolate');
|
||||||
const persons = res.persons;
|
const persons = res.persons;
|
||||||
log({ persons: true });
|
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('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('performance', human.performance);
|
||||||
human.tf.dispose(input.tensor);
|
human.tf.dispose(input.tensor);
|
||||||
draw();
|
draw();
|
||||||
|
|
||||||
|
@ -138,12 +155,12 @@
|
||||||
draw(res.canvas);
|
draw(res.canvas);
|
||||||
}
|
}
|
||||||
const t1 = performance.now();
|
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);
|
await wait(10);
|
||||||
}
|
}
|
||||||
draw();
|
draw();
|
||||||
|
|
||||||
log({ memory: human.tf.memory() });
|
log('memory', human.tf.memory());
|
||||||
}
|
}
|
||||||
clearInterval(timer);
|
clearInterval(timer);
|
||||||
log();
|
log();
|
||||||
|
|
|
@ -1,39 +1,39 @@
|
||||||
2022-08-12 09:50:24 [32mDATA: [39m Build {"name":"@vladmandic/human","version":"2.9.3"}
|
2022-08-15 11:28:08 [32mDATA: [39m Build {"name":"@vladmandic/human","version":"2.9.3"}
|
||||||
2022-08-12 09:50:24 [36mINFO: [39m Application: {"name":"@vladmandic/human","version":"2.9.3"}
|
2022-08-15 11:28:08 [36mINFO: [39m Application: {"name":"@vladmandic/human","version":"2.9.3"}
|
||||||
2022-08-12 09:50:24 [36mINFO: [39m Environment: {"profile":"production","config":".build.json","package":"package.json","tsconfig":true,"eslintrc":true,"git":true}
|
2022-08-15 11:28:08 [36mINFO: [39m Environment: {"profile":"production","config":".build.json","package":"package.json","tsconfig":true,"eslintrc":true,"git":true}
|
||||||
2022-08-12 09:50:24 [36mINFO: [39m Toolchain: {"build":"0.7.9","esbuild":"0.15.1","typescript":"4.7.4","typedoc":"0.23.10","eslint":"8.21.0"}
|
2022-08-15 11:28:08 [36mINFO: [39m Toolchain: {"build":"0.7.9","esbuild":"0.15.3","typescript":"4.7.4","typedoc":"0.23.10","eslint":"8.22.0"}
|
||||||
2022-08-12 09:50:24 [36mINFO: [39m Build: {"profile":"production","steps":["clean","compile","typings","typedoc","lint","changelog"]}
|
2022-08-15 11:28:08 [36mINFO: [39m Build: {"profile":"production","steps":["clean","compile","typings","typedoc","lint","changelog"]}
|
||||||
2022-08-12 09:50:24 [35mSTATE:[39m Clean: {"locations":["dist/*","types/lib/*","typedoc/*"]}
|
2022-08-15 11:28:08 [35mSTATE:[39m Clean: {"locations":["dist/*","types/lib/*","typedoc/*"]}
|
||||||
2022-08-12 09:50:24 [35mSTATE:[39m 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 [35mSTATE:[39m 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 [35mSTATE:[39m 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-15 11:28:08 [35mSTATE:[39m 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-12 09:50:24 [35mSTATE:[39m 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 [35mSTATE:[39m 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 [35mSTATE:[39m 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-15 11:28:08 [35mSTATE:[39m 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-12 09:50:24 [35mSTATE:[39m 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 [35mSTATE:[39m 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 [35mSTATE:[39m 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-15 11:28:08 [35mSTATE:[39m 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-12 09:50:24 [35mSTATE:[39m 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 [35mSTATE:[39m 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 [35mSTATE:[39m 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 [35mSTATE:[39m 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 [35mSTATE:[39m 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-15 11:28:08 [35mSTATE:[39m 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-12 09:50:24 [35mSTATE:[39m 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 [35mSTATE:[39m 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 [35mSTATE:[39m 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-15 11:28:09 [35mSTATE:[39m 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-12 09:50:24 [35mSTATE:[39m 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-15 11:28:09 [35mSTATE:[39m 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-12 09:50:31 [35mSTATE:[39m Typings: {"input":"src/human.ts","output":"types/lib","files":30}
|
2022-08-15 11:28:14 [35mSTATE:[39m Typings: {"input":"src/human.ts","output":"types/lib","files":30}
|
||||||
2022-08-12 09:50:33 [35mSTATE:[39m TypeDoc: {"input":"src/human.ts","output":"typedoc","objects":77,"generated":true}
|
2022-08-15 11:28:15 [35mSTATE:[39m TypeDoc: {"input":"src/human.ts","output":"typedoc","objects":77,"generated":true}
|
||||||
2022-08-12 09:50:33 [35mSTATE:[39m 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 [35mSTATE:[39m 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 [35mSTATE:[39m 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:15 [35mSTATE:[39m 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 [35mSTATE:[39m Lint: {"locations":["*.json","src/**/*.ts","test/**/*.js","demo/**/*.js"],"files":109,"errors":0,"warnings":0}
|
2022-08-15 11:28:24 [35mSTATE:[39m Lint: {"locations":["*.json","src/**/*.ts","test/**/*.js","demo/**/*.js"],"files":109,"errors":0,"warnings":0}
|
||||||
2022-08-12 09:50:42 [35mSTATE:[39m ChangeLog: {"repository":"https://github.com/vladmandic/human","branch":"main","output":"CHANGELOG.md"}
|
2022-08-15 11:28:24 [35mSTATE:[39m ChangeLog: {"repository":"https://github.com/vladmandic/human","branch":"main","output":"CHANGELOG.md"}
|
||||||
2022-08-12 09:50:42 [35mSTATE:[39m Copy: {"input":"tfjs/tfjs.esm.d.ts"}
|
2022-08-15 11:28:24 [35mSTATE:[39m Copy: {"input":"tfjs/tfjs.esm.d.ts"}
|
||||||
2022-08-12 09:50:42 [36mINFO: [39m Done...
|
2022-08-15 11:28:24 [36mINFO: [39m Done...
|
||||||
2022-08-12 09:50:42 [35mSTATE:[39m API-Extractor: {"succeeeded":true,"errors":0,"warnings":198}
|
2022-08-15 11:28:24 [35mSTATE:[39m API-Extractor: {"succeeeded":true,"errors":0,"warnings":198}
|
||||||
2022-08-12 09:50:42 [35mSTATE:[39m Copy: {"input":"types/human.d.ts"}
|
2022-08-15 11:28:24 [35mSTATE:[39m Copy: {"input":"types/human.d.ts"}
|
||||||
2022-08-12 09:50:42 [36mINFO: [39m Analyze models: {"folders":8,"result":"models/models.json"}
|
2022-08-15 11:28:24 [36mINFO: [39m Analyze models: {"folders":8,"result":"models/models.json"}
|
||||||
2022-08-12 09:50:42 [35mSTATE:[39m Models {"folder":"./models","models":13}
|
2022-08-15 11:28:24 [35mSTATE:[39m Models {"folder":"./models","models":13}
|
||||||
2022-08-12 09:50:42 [35mSTATE:[39m Models {"folder":"../human-models/models","models":42}
|
2022-08-15 11:28:24 [35mSTATE:[39m Models {"folder":"../human-models/models","models":42}
|
||||||
2022-08-12 09:50:42 [35mSTATE:[39m Models {"folder":"../blazepose/model/","models":4}
|
2022-08-15 11:28:24 [35mSTATE:[39m Models {"folder":"../blazepose/model/","models":4}
|
||||||
2022-08-12 09:50:42 [35mSTATE:[39m Models {"folder":"../anti-spoofing/model","models":1}
|
2022-08-15 11:28:24 [35mSTATE:[39m Models {"folder":"../anti-spoofing/model","models":1}
|
||||||
2022-08-12 09:50:42 [35mSTATE:[39m Models {"folder":"../efficientpose/models","models":3}
|
2022-08-15 11:28:24 [35mSTATE:[39m Models {"folder":"../efficientpose/models","models":3}
|
||||||
2022-08-12 09:50:42 [35mSTATE:[39m Models {"folder":"../insightface/models","models":5}
|
2022-08-15 11:28:24 [35mSTATE:[39m Models {"folder":"../insightface/models","models":5}
|
||||||
2022-08-12 09:50:42 [35mSTATE:[39m Models {"folder":"../movenet/models","models":3}
|
2022-08-15 11:28:24 [35mSTATE:[39m Models {"folder":"../movenet/models","models":3}
|
||||||
2022-08-12 09:50:42 [35mSTATE:[39m Models {"folder":"../nanodet/models","models":4}
|
2022-08-15 11:28:24 [35mSTATE:[39m Models {"folder":"../nanodet/models","models":4}
|
||||||
2022-08-12 09:50:43 [35mSTATE:[39m Models: {"count":57,"totalSize":383017442}
|
2022-08-15 11:28:25 [35mSTATE:[39m Models: {"count":57,"totalSize":383017442}
|
||||||
2022-08-12 09:50:43 [36mINFO: [39m Human Build complete... {"logFile":"test/build.log"}
|
2022-08-15 11:28:25 [36mINFO: [39m Human Build complete... {"logFile":"test/build.log"}
|
||||||
|
|
|
@ -5,7 +5,7 @@ const { fork } = require('child_process');
|
||||||
const log = require('@vladmandic/pilogger');
|
const log = require('@vladmandic/pilogger');
|
||||||
|
|
||||||
let logFile = 'test.log';
|
let logFile = 'test.log';
|
||||||
log.configure({ inspect: { breakLength: 500 } });
|
log.configure({ inspect: { breakLength: 350 } });
|
||||||
|
|
||||||
const tests = [
|
const tests = [
|
||||||
'test-node.js',
|
'test-node.js',
|
||||||
|
|
|
@ -12,7 +12,8 @@ const log = (status, ...data) => {
|
||||||
};
|
};
|
||||||
|
|
||||||
process.on('uncaughtException', (err) => {
|
process.on('uncaughtException', (err) => {
|
||||||
log('error', 'uncaughtException', lastOp, err);
|
log('error', 'uncaughtException', lastOp, err); // abort immediately
|
||||||
|
process.exit(1);
|
||||||
});
|
});
|
||||||
|
|
||||||
async function testHTTP() {
|
async function testHTTP() {
|
||||||
|
@ -74,12 +75,17 @@ async function testInstance(human) {
|
||||||
log('info', 'human version:', human.version);
|
log('info', 'human version:', human.version);
|
||||||
log('info', 'platform:', human.env.platform, 'agent:', human.env.agent);
|
log('info', 'platform:', human.env.platform, 'agent:', human.env.agent);
|
||||||
log('info', 'tfjs version:', human.tf.version.tfjs);
|
log('info', 'tfjs version:', human.tf.version.tfjs);
|
||||||
const bindingVer = human.tf.backend()['binding'] ? human.tf.backend()['binding']['TF_Version'] : null;
|
const env = JSON.parse(JSON.stringify(human.env));
|
||||||
if (bindingVer) log('info', 'tensorflow binding version:', bindingVer);
|
env.kernels = human.env.kernels.length;
|
||||||
|
log('info', 'env:', env);
|
||||||
|
|
||||||
await human.load();
|
await human.load();
|
||||||
if (config.backend === human.tf.getBackend()) log('state', 'passed: set backend:', config.backend);
|
if (config.backend === human.tf.getBackend()) {
|
||||||
else log('error', 'failed: set backend:', config.backend);
|
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);
|
log('state', 'tensors', human.tf.memory().numTensors);
|
||||||
|
|
||||||
if (human.models) {
|
if (human.models) {
|
||||||
|
@ -296,7 +302,11 @@ async function test(Human, inputConfig) {
|
||||||
|
|
||||||
// test warmup sequences
|
// test warmup sequences
|
||||||
log('info', 'test: warmup');
|
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.cacheSensitivity = 0;
|
||||||
config.warmup = 'none';
|
config.warmup = 'none';
|
||||||
res = await testWarmup(human, 'default');
|
res = await testWarmup(human, 'default');
|
||||||
|
@ -475,7 +485,7 @@ async function test(Human, inputConfig) {
|
||||||
// test face attention
|
// test face attention
|
||||||
log('info', 'test face attention');
|
log('info', 'test face attention');
|
||||||
human.models.facemesh = null;
|
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');
|
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 });
|
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');
|
else log('state', 'passed: face attention');
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
process.env.TF_CPP_MIN_LOG_LEVEL = '2';
|
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 test = require('./test-main.js').test;
|
||||||
|
|
||||||
const config = {
|
const config = {
|
||||||
|
@ -25,4 +25,8 @@ const config = {
|
||||||
filter: { enabled: false },
|
filter: { enabled: false },
|
||||||
};
|
};
|
||||||
|
|
||||||
test(Human, config);
|
async function main() {
|
||||||
|
test(H.Human, config);
|
||||||
|
}
|
||||||
|
|
||||||
|
main();
|
||||||
|
|
|
@ -1,20 +1,21 @@
|
||||||
|
const log = require('@vladmandic/pilogger');
|
||||||
const tf = require('@tensorflow/tfjs'); // wasm backend requires tfjs to be loaded first
|
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 wasm = require('@tensorflow/tfjs-backend-wasm'); // wasm backend does not get auto-loaded in nodejs
|
||||||
const { Canvas, Image } = require('canvas');
|
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;
|
const test = require('./test-main.js').test;
|
||||||
|
|
||||||
// @ts-ignore
|
// @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
|
// @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 = {
|
const config = {
|
||||||
cacheSensitivity: 0,
|
cacheSensitivity: 0,
|
||||||
modelBasePath: 'https://vladmandic.github.io/human/models/',
|
modelBasePath: 'https://vladmandic.github.io/human/models/',
|
||||||
backend: 'wasm',
|
backend: 'wasm',
|
||||||
wasmPath: 'node_modules/@tensorflow/tfjs-backend-wasm/dist/',
|
// wasmPath: 'node_modules/@tensorflow/tfjs-backend-wasm/dist/',
|
||||||
// wasmPath: `cdn.jsdelivr.net/npm/@tensorflow/tfjs-backend-wasm@${tf.version_core}/dist/`,
|
wasmPath: `https://cdn.jsdelivr.net/npm/@tensorflow/tfjs-backend-wasm@${tf.version_core}/dist/`,
|
||||||
debug: false,
|
debug: false,
|
||||||
async: false,
|
async: false,
|
||||||
face: {
|
face: {
|
||||||
|
@ -38,7 +39,9 @@ async function main() {
|
||||||
wasm.setWasmPaths(config.wasmPath);
|
wasm.setWasmPaths(config.wasmPath);
|
||||||
await tf.setBackend('wasm');
|
await tf.setBackend('wasm');
|
||||||
await tf.ready();
|
await tf.ready();
|
||||||
test(Human.Human, config);
|
H.env.updateBackend();
|
||||||
|
log.info(H.env.wasm);
|
||||||
|
test(H.Human, config);
|
||||||
}
|
}
|
||||||
|
|
||||||
main();
|
main();
|
||||||
|
|
|
@ -1,5 +1,6 @@
|
||||||
process.env.TF_CPP_MIN_LOG_LEVEL = '2';
|
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 test = require('./test-main.js').test;
|
||||||
|
|
||||||
const config = {
|
const config = {
|
||||||
|
@ -25,4 +26,8 @@ const config = {
|
||||||
filter: { enabled: false },
|
filter: { enabled: false },
|
||||||
};
|
};
|
||||||
|
|
||||||
test(Human, config);
|
async function main() {
|
||||||
|
test(H.Human, config);
|
||||||
|
}
|
||||||
|
|
||||||
|
main();
|
||||||
|
|
1752
test/test.log
1752
test/test.log
File diff suppressed because it is too large
Load Diff
Loading…
Reference in New Issue