minor bug fixes and increased test coverage

pull/356/head
Vladimir Mandic 2022-08-31 11:29:19 -04:00
parent cc71013f1d
commit 39634cb25d
13 changed files with 1160 additions and 1113 deletions

View File

@ -11,9 +11,8 @@
### **HEAD -> main** 2022/08/30 mandic00@live.com
### **origin/main** 2022/08/28 mandic00@live.com
- add model load exception handling
- add softwarekernels config option
- expand type safety
- full eslint rule rewrite

View File

@ -60,6 +60,7 @@ Enable via `about:config` -> `gfx.offscreencanvas.enabled`
Example: `console.log(human.env.tensorflow)`
- Treat models that cannot be found & loaded as non-critical error
Instead of creating runtime exception, `human` will now report that model could not be loaded
- Improve `human.reset()` method to reset all config values to defaults
- 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'`

View File

@ -68,7 +68,7 @@
"@tensorflow/tfjs-backend-cpu": "^3.20.0",
"@tensorflow/tfjs-backend-wasm": "^3.20.0",
"@tensorflow/tfjs-backend-webgl": "^3.20.0",
"@tensorflow/tfjs-backend-webgpu": "0.0.1-alpha.12",
"@tensorflow/tfjs-backend-webgpu": "0.0.1-alpha.13",
"@tensorflow/tfjs-converter": "^3.20.0",
"@tensorflow/tfjs-core": "^3.20.0",
"@tensorflow/tfjs-data": "^3.20.0",
@ -78,8 +78,8 @@
"@tensorflow/tfjs-tflite": "0.0.1-alpha.8",
"@types/node": "^18.7.14",
"@types/offscreencanvas": "^2019.7.0",
"@typescript-eslint/eslint-plugin": "^5.36.0",
"@typescript-eslint/parser": "^5.36.0",
"@typescript-eslint/eslint-plugin": "^5.36.1",
"@typescript-eslint/parser": "^5.36.1",
"@vladmandic/build": "^0.7.11",
"@vladmandic/pilogger": "^0.4.6",
"@vladmandic/tfjs": "github:vladmandic/tfjs",
@ -97,7 +97,7 @@
"rimraf": "^3.0.2",
"seedrandom": "^3.0.5",
"tslib": "^2.4.0",
"typedoc": "0.23.11",
"typedoc": "0.23.12",
"typescript": "4.8.2"
}
}

View File

@ -5,12 +5,15 @@ export async function augment(rawCoords, results: Tensor[]) {
const t: Record<string, Float32Array> = { // all attention models produce 2d results so it needs to be later augmented with correct z-coords
// mesh: results[0], // already have it in rawCoords // output_mesh_identity
// flag: results[1], // already processed in parent // conv_faceflag
lips: await results.filter((r) => r.size === 160)[0].data() as Float32Array, // 80 x 2d = 160 // output_lips
irisL: await results.filter((r) => r.size === 10)[0].data() as Float32Array, // 5 x 2d = 10 // output_right_iris
eyeL: await results.filter((r) => r.size === 142)[0].data() as Float32Array, // 71 x 2d = 142 // output_right_eye
irisR: await results.filter((r) => r.size === 10)[1].data() as Float32Array, // 5 x 2d = 10 // output_left_iris
eyeR: await results.filter((r) => r.size === 142)[1].data() as Float32Array, // 71 x 2d = 142// output_left_eye
lips: await results.filter((r) => r.size === 160)?.[0]?.data() as Float32Array, // 80 x 2d = 160 // output_lips
irisL: await results.filter((r) => r.size === 10)?.[0]?.data() as Float32Array, // 5 x 2d = 10 // output_right_iris
eyeL: await results.filter((r) => r.size === 142)?.[0]?.data() as Float32Array, // 71 x 2d = 142 // output_right_eye
irisR: await results.filter((r) => r.size === 10)?.[1]?.data() as Float32Array, // 5 x 2d = 10 // output_left_iris
eyeR: await results.filter((r) => r.size === 142)?.[1]?.data() as Float32Array, // 71 x 2d = 142// output_left_eye
};
for (const val of Object.values(t)) {
if (!val) return rawCoords; // could not find tensor
}
// augment iris: adds additional 5 keypoints per eye
const irisLDepth = constants.LANDMARKS_REFINEMENT_LEFT_EYE_CONFIG.reduce((prev, curr) => prev += rawCoords[curr][2], 0) / constants.LANDMARKS_REFINEMENT_LEFT_EYE_CONFIG.length; // get average z-coord for iris

View File

@ -90,6 +90,7 @@ export async function predict(input: Tensor, config: Config): Promise<FaceResult
if (config.debug) log('face mesh detection requested, but model is not loaded');
} else { // mesh enabled
if (config.face.attention?.enabled && !env.kernels.includes('atan2')) {
config.face.attention.enabled = false;
tf.dispose(face.tensor);
return faces;
}
@ -97,7 +98,6 @@ export async function predict(input: Tensor, config: Config): Promise<FaceResult
const confidenceT = results.find((t) => t.shape[t.shape.length - 1] === 1) as Tensor;
const faceConfidence = await confidenceT.data();
face.faceScore = Math.round(100 * faceConfidence[0]) / 100;
if (face.faceScore < (config.face.detector?.minConfidence || 1)) { // low confidence in detected mesh
box.confidence = face.faceScore; // reset confidence of cached box
if (config.face.mesh.keepInvalid) {

View File

@ -204,11 +204,15 @@ export class Human {
const currentBackend = this.config.backend; // save backend;
this.config = JSON.parse(JSON.stringify(defaults));
this.config.backend = currentBackend;
image.reset();
env.initial = true;
}
/** Validate current configuration schema */
validate(userConfig?: Partial<Config>) {
return validate(defaults, userConfig || this.config);
const msgs = validate(defaults, userConfig || this.config);
if (msgs.length === 0) this.config = mergeDeep(this.config, userConfig) as Config;
return msgs;
}
/** Check model for invalid kernel ops for current backend */
@ -280,6 +284,7 @@ export class Human {
async init(): Promise<void> {
await backend.check(this, true);
await this.tf.ready();
image.reset();
}
/** Load method preloads all configured models on-demand

View File

@ -24,6 +24,13 @@ const last: { inputSum: number, cacheDiff: number, sumMethod: number, inputTenso
inputTensor: undefined,
};
export function reset() {
last.inputSum = 0;
last.cacheDiff = 1;
last.sumMethod = 0;
last.inputTensor = undefined;
}
export function canvas(width: number, height: number): AnyCanvas {
let c: AnyCanvas;
if (env.browser) { // browser defines canvas object

View File

@ -123,7 +123,7 @@ export async function load(instance: Human): Promise<void> {
if (instance.config.face.enabled && instance.config.face.description?.enabled && !instance.models.faceres) instance.models.faceres = faceres.load(instance.config);
if (instance.config.face.enabled && instance.config.face.emotion?.enabled && !instance.models.emotion) instance.models.emotion = emotion.load(instance.config);
if (instance.config.face.enabled && instance.config.face.iris?.enabled && !instance.config.face.attention?.enabled && !instance.models.faceiris) instance.models.faceiris = iris.load(instance.config);
if (instance.config.face.enabled && instance.config.face.mesh?.enabled && !instance.models.facemesh) instance.models.facemesh = facemesh.load(instance.config);
if (instance.config.face.enabled && instance.config.face.mesh?.enabled && (!instance.models.facemesh)) instance.models.facemesh = facemesh.load(instance.config);
if (instance.config.face.enabled && instance.config.face['gear']?.enabled && !instance.models.gear) instance.models.gear = gear.load(instance.config);
if (instance.config.face.enabled && instance.config.face['ssrnet']?.enabled && !instance.models.ssrnetage) instance.models.ssrnetage = ssrnetAge.load(instance.config);
if (instance.config.face.enabled && instance.config.face['ssrnet']?.enabled && !instance.models.ssrnetgender) instance.models.ssrnetgender = ssrnetGender.load(instance.config);

View File

@ -48,6 +48,7 @@ async function process(res: Tensor | null, outputShape: [number, number], config
for (const id of Array.from(nms)) {
const score = Math.trunc(100 * detections[0][id][4]) / 100;
const classVal = detections[0][id][5];
if (Number.isNaN(classVal)) continue;
const label = labels[classVal].label as ObjectType;
const [x, y] = [
detections[0][id][0] / inputSize,

View File

@ -13,11 +13,11 @@
<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; width: 100vw; overflow-x: hidden; }
body { margin: 0; background: black; color: white; width: 100vw; }
.canvas { position: fixed; bottom: 10px; right: 10px; width: 256px; height: 256px; z-index: 99; }
.events { position: fixed; top: 10px; right: 10px; width: 12rem; height: 1.25rem; background-color: grey; padding: 8px; z-index: 99; }
.state { position: fixed; top: 60px; right: 10px; width: 12rem; height: 1.25rem; background-color: grey; padding: 8px; z-index: 99; }
.pre { line-height: 150%; white-space: break-spaces; }
.pre { line-height: 150%; }
</style>
</head>
<body>

View File

@ -1,12 +1,6 @@
import { Human } from '../dist/human.esm.js';
const config = {
async: true,
warmup: 'none',
debug: true,
cacheSensitivity: 0,
object: { enabled: true },
};
let human;
const backends = ['wasm', 'humangl', 'webgl', 'webgpu'];
@ -68,10 +62,72 @@ async function events(event) {
document.getElementById('events').innerText = `${Math.round(performance.now() - start)}ms Event: ${event}`;
}
async function testDefault(title, testConfig = {}) {
const t0 = human.now();
let res;
for (const model of Object.keys(human.models)) { // unload models
if (human.models[model]) {
// if (human.models[model].dispose) human.models[model].dispose();
human.models[model] = null;
}
}
human.reset();
res = human.validate(testConfig); // validate
if (res && res.length > 0) log(' invalid configuration', res);
log(`test ${title}/${human.tf.getBackend()}`, human.config);
await human.load();
const models = Object.keys(human.models).map((model) => ({ name: model, loaded: (human.models[model] !== null) }));
log(' models', models);
const ops = await human.check();
if (ops && ops.length > 0) log(' missing ops', ops);
const img = await image('../../samples/in/ai-body.jpg');
const input = await human.image(img); // process image
draw(input.canvas);
res = await human.warmup({ warmup: 'face' }); // warmup
draw(res.canvas);
const t1 = human.now();
res = await human.detect(input.tensor, testConfig); // run detect
const t2 = human.now();
human.next(); // run interpolation
const persons = res.persons; // run persons getter
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(' memory', human.tf.memory());
// log(' performance', human.performance);
human.tf.dispose(input.tensor);
log(` finished ${title}/${human.tf.getBackend()}`, { init: Math.round(t1 - t0), detect: Math.round(t2 - t1) });
return res;
}
async function runBenchmark() {
const img = await image('../../samples/in/ai-face.jpg');
human.reset();
const s0 = human.now();
await human.load();
await human.warmup();
const s1 = human.now();
for (const val of [0, 0.25, 0.5, 0.75, 10]) {
human.performance = {};
const t0 = performance.now();
for (let i = 0; i < 10; i++) {
const res = await human.detect(img, { cacheSensitivity: val, filter: { pixelate: 5 * i }, object: { enabled: true } }); // run detect with increased pixelization on each iteration
draw(res.canvas);
}
const t1 = performance.now();
log(' benchmark', { time: Math.round((t1 - t0) / 10), backend: human.tf.getBackend(), cacheSensitivity: val, performance: human.performance });
await wait(1);
}
const s2 = human.now();
log(' total', human.tf.getBackend(), { detect: Math.round(s2 - s1), init: Math.round(s1 - s0) });
draw();
}
async function main() {
log('human tests');
let res;
const human = new Human(config);
// create instance
human = new Human({ debug: true });
// explicit init
await human.init();
human.events.addEventListener('warmup', () => events('warmup'));
human.events.addEventListener('image', () => events('image'));
@ -83,60 +139,36 @@ async function main() {
const env = JSON.parse(JSON.stringify(human.env));
env.kernels = human.env.kernels.length;
detailed('environment', env);
// detailed('config', human.config);
detailed('config', human.config);
await human.load();
const models = Object.keys(human.models).map((model) => ({ name: model, loaded: (human.models[model] !== null) }));
log('models', models);
for (const backend of backends) {
log();
log('test start:', backend);
human.config.backend = backend;
await human.init(); // init
if (human.tf.getBackend() !== backend) {
log('desired', backend, 'detected', human.tf.getBackend());
continue; // wrong backend
}
await testDefault('default', { debug: true });
await testDefault('sync', { debug: true, async: false });
await testDefault('none', { debug: true, async: true, face: { enabled: false }, body: { enabled: false }, hand: { enabled: false }, gesture: { enabled: false }, segmentation: { enabled: false }, object: { enabled: false } });
await testDefault('object', { debug: true, async: true, face: { enabled: false }, body: { enabled: false }, hand: { enabled: false }, gesture: { enabled: false }, segmentation: { enabled: false }, object: { enabled: true } });
// TBD detectors only
// TBD segmentation
// TBD face match
// TBD non-default models
// TBD web workers
// TBD multiple instances
}
log('tests complete');
for (const backend of backends) {
log('benchmark backend:', backend);
human.config.backend = backend;
await human.init();
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);
res = await human.warmup({ warmup: 'face' });
draw(res.canvas);
log('warmup', 'face');
let img = await image('../../samples/in/ai-body.jpg');
const input = await human.image(img);
log('input', input.tensor.shape);
draw(res.canvas);
res = await human.detect(input.tensor);
log('detect');
human.next();
log('interpolate');
const persons = res.persons;
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();
img = await image('../../samples/in/ai-face.jpg');
for (const val of [0, 0.25, 0.5, 0.75, 10]) {
human.performance = {};
const t0 = performance.now();
for (let i = 0; i < 10; i++) {
res = await human.detect(img, { cacheSensitivity: val, filter: { pixelate: 5 * i }, object: { enabled: false } });
draw(res.canvas);
}
const t1 = performance.now();
log('benchmark', { time: Math.round((t1 - t0) / 10), cacheSensitivity: val, performance: human.performance });
await wait(10);
}
draw();
log('memory', human.tf.memory());
if (human.tf.getBackend() !== backend) continue; // wrong backend
await runBenchmark();
}
log('benchmarks complete');
clearInterval(timer);
log();
log('tests complete');
}
main();

View File

@ -1,39 +1,39 @@
2022-08-30 10:28:42 DATA:  Build {"name":"@vladmandic/human","version":"2.9.4"}
2022-08-30 10:28:42 INFO:  Application: {"name":"@vladmandic/human","version":"2.9.4"}
2022-08-30 10:28:42 INFO:  Environment: {"profile":"production","config":".build.json","package":"package.json","tsconfig":true,"eslintrc":true,"git":true}
2022-08-30 10:28:42 INFO:  Toolchain: {"build":"0.7.11","esbuild":"0.15.6","typescript":"4.8.2","typedoc":"0.23.11","eslint":"8.23.0"}
2022-08-30 10:28:42 INFO:  Build: {"profile":"production","steps":["clean","compile","typings","typedoc","lint","changelog"]}
2022-08-30 10:28:42 STATE: Clean: {"locations":["dist/*","types/lib/*","typedoc/*"]}
2022-08-30 10:28:42 STATE: Compile: {"name":"tfjs/nodejs/cpu","format":"cjs","platform":"node","input":"tfjs/tf-node.ts","output":"dist/tfjs.esm.js","files":1,"inputBytes":159,"outputBytes":608}
2022-08-30 10:28:42 STATE: Compile: {"name":"human/nodejs/cpu","format":"cjs","platform":"node","input":"src/human.ts","output":"dist/human.node.js","files":75,"inputBytes":655263,"outputBytes":308144}
2022-08-30 10:28:42 STATE: Compile: {"name":"tfjs/nodejs/gpu","format":"cjs","platform":"node","input":"tfjs/tf-node-gpu.ts","output":"dist/tfjs.esm.js","files":1,"inputBytes":167,"outputBytes":612}
2022-08-30 10:28:42 STATE: Compile: {"name":"human/nodejs/gpu","format":"cjs","platform":"node","input":"src/human.ts","output":"dist/human.node-gpu.js","files":75,"inputBytes":655267,"outputBytes":308148}
2022-08-30 10:28:42 STATE: Compile: {"name":"tfjs/nodejs/wasm","format":"cjs","platform":"node","input":"tfjs/tf-node-wasm.ts","output":"dist/tfjs.esm.js","files":1,"inputBytes":206,"outputBytes":664}
2022-08-30 10:28:42 STATE: Compile: {"name":"human/nodejs/wasm","format":"cjs","platform":"node","input":"src/human.ts","output":"dist/human.node-wasm.js","files":75,"inputBytes":655319,"outputBytes":308198}
2022-08-30 10:28:42 STATE: Compile: {"name":"tfjs/browser/version","format":"esm","platform":"browser","input":"tfjs/tf-version.ts","output":"dist/tfjs.version.js","files":1,"inputBytes":1125,"outputBytes":358}
2022-08-30 10:28:42 STATE: Compile: {"name":"tfjs/browser/esm/nobundle","format":"esm","platform":"browser","input":"tfjs/tf-browser.ts","output":"dist/tfjs.esm.js","files":2,"inputBytes":1088,"outputBytes":583}
2022-08-30 10:28:42 STATE: Compile: {"name":"human/browser/esm/nobundle","format":"esm","platform":"browser","input":"src/human.ts","output":"dist/human.esm-nobundle.js","files":75,"inputBytes":655238,"outputBytes":307019}
2022-08-30 10:28:42 STATE: Compile: {"name":"tfjs/browser/esm/custom","format":"esm","platform":"browser","input":"tfjs/tf-custom.ts","output":"dist/tfjs.esm.js","files":11,"inputBytes":1344,"outputBytes":2879073}
2022-08-30 10:28:42 STATE: Compile: {"name":"human/browser/iife/bundle","format":"iife","platform":"browser","input":"src/human.ts","output":"dist/human.js","files":75,"inputBytes":3533728,"outputBytes":1707671}
2022-08-30 10:28:42 STATE: Compile: {"name":"human/browser/esm/bundle","format":"esm","platform":"browser","input":"src/human.ts","output":"dist/human.esm.js","files":75,"inputBytes":3533728,"outputBytes":3156709}
2022-08-30 10:28:47 STATE: Typings: {"input":"src/human.ts","output":"types/lib","files":30}
2022-08-30 10:28:49 STATE: TypeDoc: {"input":"src/human.ts","output":"typedoc","objects":77,"generated":true}
2022-08-30 10:28:49 STATE: Compile: {"name":"demo/typescript","format":"esm","platform":"browser","input":"demo/typescript/index.ts","output":"demo/typescript/index.js","files":1,"inputBytes":6714,"outputBytes":3134}
2022-08-30 10:28:49 STATE: Compile: {"name":"demo/faceid","format":"esm","platform":"browser","input":"demo/faceid/index.ts","output":"demo/faceid/index.js","files":2,"inputBytes":15488,"outputBytes":7788}
2022-08-30 10:28:59 STATE: Lint: {"locations":["*.json","src/**/*.ts","test/**/*.js","demo/**/*.js"],"files":111,"errors":0,"warnings":0}
2022-08-30 10:28:59 STATE: ChangeLog: {"repository":"https://github.com/vladmandic/human","branch":"main","output":"CHANGELOG.md"}
2022-08-30 10:28:59 STATE: Copy: {"input":"tfjs/tfjs.esm.d.ts"}
2022-08-30 10:28:59 INFO:  Done...
2022-08-30 10:29:00 STATE: API-Extractor: {"succeeeded":true,"errors":0,"warnings":198}
2022-08-30 10:29:00 STATE: Copy: {"input":"types/human.d.ts"}
2022-08-30 10:29:00 INFO:  Analyze models: {"folders":8,"result":"models/models.json"}
2022-08-30 10:29:00 STATE: Models {"folder":"./models","models":13}
2022-08-30 10:29:00 STATE: Models {"folder":"../human-models/models","models":42}
2022-08-30 10:29:00 STATE: Models {"folder":"../blazepose/model/","models":4}
2022-08-30 10:29:00 STATE: Models {"folder":"../anti-spoofing/model","models":1}
2022-08-30 10:29:00 STATE: Models {"folder":"../efficientpose/models","models":3}
2022-08-30 10:29:00 STATE: Models {"folder":"../insightface/models","models":5}
2022-08-30 10:29:00 STATE: Models {"folder":"../movenet/models","models":3}
2022-08-30 10:29:00 STATE: Models {"folder":"../nanodet/models","models":4}
2022-08-30 10:29:01 STATE: Models: {"count":57,"totalSize":383017442}
2022-08-30 10:29:01 INFO:  Human Build complete... {"logFile":"test/build.log"}
2022-08-31 11:27:08 DATA:  Build {"name":"@vladmandic/human","version":"2.9.4"}
2022-08-31 11:27:08 INFO:  Application: {"name":"@vladmandic/human","version":"2.9.4"}
2022-08-31 11:27:08 INFO:  Environment: {"profile":"production","config":".build.json","package":"package.json","tsconfig":true,"eslintrc":true,"git":true}
2022-08-31 11:27:08 INFO:  Toolchain: {"build":"0.7.11","esbuild":"0.15.6","typescript":"4.8.2","typedoc":"0.23.12","eslint":"8.23.0"}
2022-08-31 11:27:08 INFO:  Build: {"profile":"production","steps":["clean","compile","typings","typedoc","lint","changelog"]}
2022-08-31 11:27:08 STATE: Clean: {"locations":["dist/*","types/lib/*","typedoc/*"]}
2022-08-31 11:27:08 STATE: Compile: {"name":"tfjs/nodejs/cpu","format":"cjs","platform":"node","input":"tfjs/tf-node.ts","output":"dist/tfjs.esm.js","files":1,"inputBytes":159,"outputBytes":608}
2022-08-31 11:27:08 STATE: Compile: {"name":"human/nodejs/cpu","format":"cjs","platform":"node","input":"src/human.ts","output":"dist/human.node.js","files":75,"inputBytes":655767,"outputBytes":308629}
2022-08-31 11:27: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":167,"outputBytes":612}
2022-08-31 11:27:08 STATE: Compile: {"name":"human/nodejs/gpu","format":"cjs","platform":"node","input":"src/human.ts","output":"dist/human.node-gpu.js","files":75,"inputBytes":655771,"outputBytes":308633}
2022-08-31 11:27: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":206,"outputBytes":664}
2022-08-31 11:27:08 STATE: Compile: {"name":"human/nodejs/wasm","format":"cjs","platform":"node","input":"src/human.ts","output":"dist/human.node-wasm.js","files":75,"inputBytes":655823,"outputBytes":308683}
2022-08-31 11:27:08 STATE: Compile: {"name":"tfjs/browser/version","format":"esm","platform":"browser","input":"tfjs/tf-version.ts","output":"dist/tfjs.version.js","files":1,"inputBytes":1125,"outputBytes":358}
2022-08-31 11:27: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":1088,"outputBytes":583}
2022-08-31 11:27:09 STATE: Compile: {"name":"human/browser/esm/nobundle","format":"esm","platform":"browser","input":"src/human.ts","output":"dist/human.esm-nobundle.js","files":75,"inputBytes":655742,"outputBytes":307503}
2022-08-31 11:27: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":1344,"outputBytes":2821914}
2022-08-31 11:27:09 STATE: Compile: {"name":"human/browser/iife/bundle","format":"iife","platform":"browser","input":"src/human.ts","output":"dist/human.js","files":75,"inputBytes":3477073,"outputBytes":1687675}
2022-08-31 11:27:09 STATE: Compile: {"name":"human/browser/esm/bundle","format":"esm","platform":"browser","input":"src/human.ts","output":"dist/human.esm.js","files":75,"inputBytes":3477073,"outputBytes":3108312}
2022-08-31 11:27:13 STATE: Typings: {"input":"src/human.ts","output":"types/lib","files":30}
2022-08-31 11:27:15 STATE: TypeDoc: {"input":"src/human.ts","output":"typedoc","objects":77,"generated":true}
2022-08-31 11:27:15 STATE: Compile: {"name":"demo/typescript","format":"esm","platform":"browser","input":"demo/typescript/index.ts","output":"demo/typescript/index.js","files":1,"inputBytes":6714,"outputBytes":3134}
2022-08-31 11:27:15 STATE: Compile: {"name":"demo/faceid","format":"esm","platform":"browser","input":"demo/faceid/index.ts","output":"demo/faceid/index.js","files":2,"inputBytes":15488,"outputBytes":7788}
2022-08-31 11:27:25 STATE: Lint: {"locations":["*.json","src/**/*.ts","test/**/*.js","demo/**/*.js"],"files":111,"errors":0,"warnings":0}
2022-08-31 11:27:25 STATE: ChangeLog: {"repository":"https://github.com/vladmandic/human","branch":"main","output":"CHANGELOG.md"}
2022-08-31 11:27:25 STATE: Copy: {"input":"tfjs/tfjs.esm.d.ts"}
2022-08-31 11:27:25 INFO:  Done...
2022-08-31 11:27:26 STATE: API-Extractor: {"succeeeded":true,"errors":0,"warnings":198}
2022-08-31 11:27:26 STATE: Copy: {"input":"types/human.d.ts"}
2022-08-31 11:27:26 INFO:  Analyze models: {"folders":8,"result":"models/models.json"}
2022-08-31 11:27:26 STATE: Models {"folder":"./models","models":13}
2022-08-31 11:27:26 STATE: Models {"folder":"../human-models/models","models":42}
2022-08-31 11:27:26 STATE: Models {"folder":"../blazepose/model/","models":4}
2022-08-31 11:27:26 STATE: Models {"folder":"../anti-spoofing/model","models":1}
2022-08-31 11:27:26 STATE: Models {"folder":"../efficientpose/models","models":3}
2022-08-31 11:27:26 STATE: Models {"folder":"../insightface/models","models":5}
2022-08-31 11:27:26 STATE: Models {"folder":"../movenet/models","models":3}
2022-08-31 11:27:26 STATE: Models {"folder":"../nanodet/models","models":4}
2022-08-31 11:27:27 STATE: Models: {"count":57,"totalSize":383017442}
2022-08-31 11:27:27 INFO:  Human Build complete... {"logFile":"test/build.log"}

File diff suppressed because it is too large Load Diff