mirror of https://github.com/vladmandic/human
add getModelStats method
parent
772964ff49
commit
ffdd43faf9
|
@ -9,7 +9,7 @@
|
|||
|
||||
## Changelog
|
||||
|
||||
### **HEAD -> main** 2022/06/10 mandic00@live.com
|
||||
### **HEAD -> main** 2022/06/21 mandic00@live.com
|
||||
|
||||
|
||||
### **release: 2.8.1** 2022/06/08 mandic00@live.com
|
||||
|
|
File diff suppressed because one or more lines are too long
|
@ -10,7 +10,7 @@
|
|||
import { Human, Config } from '../../dist/human.esm.js'; // equivalent of @vladmandic/Human
|
||||
|
||||
const humanConfig: Partial<Config> = { // user configuration for human, used to fine-tune behavior
|
||||
// backend: 'webgpu' as const,
|
||||
// backend: 'wasm' as const,
|
||||
// wasmPath: 'https://cdn.jsdelivr.net/npm/@tensorflow/tfjs-backend-wasm@3.18.0/dist/',
|
||||
// cacheSensitivity: 0,
|
||||
async: true,
|
||||
|
|
|
@ -2,6 +2,7 @@
|
|||
|
||||
import { log } from '../util/util';
|
||||
import * as tf from '../../dist/tfjs.esm.js';
|
||||
import { loadModel } from '../tfjs/load';
|
||||
import type { GraphModel, Tensor } from '../tfjs/types';
|
||||
import type { Config } from '../config';
|
||||
|
||||
|
@ -56,7 +57,7 @@ export class FaceBoxes {
|
|||
}
|
||||
|
||||
export async function load(config) {
|
||||
const model = await tf.loadGraphModel(config.face.detector.modelPath);
|
||||
const model = await loadModel(config.face.detector?.modelPath);
|
||||
if (config.debug) log(`load model: ${config.face.detector.modelPath.match(/\/(.*)\./)[1]}`);
|
||||
const faceboxes = new FaceBoxes(model, config);
|
||||
if (config.face.mesh.enabled && config.debug) log(`load model: ${config.face.mesh.modelPath.match(/\/(.*)\./)[1]}`);
|
||||
|
|
|
@ -329,6 +329,9 @@ export class Human {
|
|||
return interpolate.calc(result, this.config) as Result;
|
||||
}
|
||||
|
||||
/** get model loading/loaded stats */
|
||||
getModelStats = () => models.getModelStats();
|
||||
|
||||
/** Warmup method pre-initializes all configured models for faster inference
|
||||
* - can take significant time on startup
|
||||
* - only used for `webgl` and `humangl` backends
|
||||
|
|
|
@ -24,6 +24,7 @@ import * as movenet from './body/movenet';
|
|||
import * as nanodet from './object/nanodet';
|
||||
import * as posenet from './body/posenet';
|
||||
import * as segmentation from './segmentation/segmentation';
|
||||
import { modelStats } from './tfjs/load';
|
||||
import type { GraphModel } from './tfjs/types';
|
||||
import type { Human } from './human';
|
||||
|
||||
|
@ -58,6 +59,16 @@ export class Models {
|
|||
antispoof: null | GraphModel | Promise<GraphModel> = null;
|
||||
}
|
||||
|
||||
export const getModelStats = () => {
|
||||
let sizeManifest = 0;
|
||||
let sizeWeights = 0;
|
||||
for (const m of Object.values(modelStats)) {
|
||||
sizeManifest += m.manifest;
|
||||
sizeWeights += m.weights;
|
||||
}
|
||||
return { sizeManifest, sizeWeights, numModels: Object.values(modelStats).length };
|
||||
};
|
||||
|
||||
export function reset(instance: Human): void {
|
||||
// if (instance.config.debug) log('resetting loaded models');
|
||||
for (const model of Object.keys(instance.models)) instance.models[model as keyof Models] = null;
|
||||
|
@ -67,8 +78,12 @@ export function reset(instance: Human): void {
|
|||
export async function load(instance: Human): Promise<void> {
|
||||
if (env.initial) reset(instance);
|
||||
if (instance.config.hand.enabled) { // handpose model is a combo that must be loaded as a whole
|
||||
if (!instance.models.handpose && instance.config.hand.detector?.modelPath?.includes('handdetect')) [instance.models.handpose, instance.models.handskeleton] = await handpose.load(instance.config);
|
||||
if (!instance.models.handskeleton && instance.config.hand.landmarks && instance.config.hand.detector?.modelPath?.includes('handdetect')) [instance.models.handpose, instance.models.handskeleton] = await handpose.load(instance.config);
|
||||
if (!instance.models.handpose && instance.config.hand.detector?.modelPath?.includes('handdetect')) {
|
||||
[instance.models.handpose, instance.models.handskeleton] = await handpose.load(instance.config);
|
||||
}
|
||||
if (!instance.models.handskeleton && instance.config.hand.landmarks && instance.config.hand.detector?.modelPath?.includes('handdetect')) {
|
||||
[instance.models.handpose, instance.models.handskeleton] = await handpose.load(instance.config);
|
||||
}
|
||||
}
|
||||
if (instance.config.body.enabled && !instance.models.blazepose && instance.config.body?.modelPath?.includes('blazepose')) instance.models.blazepose = blazepose.loadPose(instance.config);
|
||||
// @ts-ignore optional model
|
||||
|
@ -99,7 +114,9 @@ export async function load(instance: Human): Promise<void> {
|
|||
|
||||
// models are loaded in parallel asynchronously so lets wait until they are actually loaded
|
||||
for await (const model of Object.keys(instance.models)) {
|
||||
if (instance.models[model as keyof Models] && typeof instance.models[model as keyof Models] !== 'undefined') instance.models[model as keyof Models] = await instance.models[model as keyof Models];
|
||||
if (instance.models[model as keyof Models] && typeof instance.models[model as keyof Models] !== 'undefined') {
|
||||
instance.models[model as keyof Models] = await instance.models[model as keyof Models];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -10,6 +10,15 @@ const options = {
|
|||
modelBasePath: '',
|
||||
};
|
||||
|
||||
type ModelStats = {
|
||||
name: string,
|
||||
cached: boolean,
|
||||
manifest: number,
|
||||
weights: number,
|
||||
}
|
||||
|
||||
export const modelStats: Record<string, ModelStats> = {};
|
||||
|
||||
async function httpHandler(url, init?): Promise<Response | null> {
|
||||
if (options.debug) log('load model fetch:', url, init);
|
||||
return fetch(url, init);
|
||||
|
@ -25,26 +34,35 @@ export async function loadModel(modelPath: string | undefined): Promise<GraphMod
|
|||
let modelUrl = join(options.modelBasePath, modelPath || '');
|
||||
if (!modelUrl.toLowerCase().endsWith('.json')) modelUrl += '.json';
|
||||
const modelPathSegments = modelUrl.split('/');
|
||||
const cachedModelName = 'indexeddb://' + modelPathSegments[modelPathSegments.length - 1].replace('.json', ''); // generate short model name for cache
|
||||
const shortModelName = modelPathSegments[modelPathSegments.length - 1].replace('.json', '');
|
||||
const cachedModelName = 'indexeddb://' + shortModelName; // generate short model name for cache
|
||||
modelStats[shortModelName] = {
|
||||
name: shortModelName,
|
||||
manifest: 0,
|
||||
weights: 0,
|
||||
cached: false,
|
||||
};
|
||||
const cachedModels = await tf.io.listModels(); // list all models already in cache
|
||||
const modelCached = options.cacheModels && Object.keys(cachedModels).includes(cachedModelName); // is model found in cache
|
||||
modelStats[shortModelName].cached = options.cacheModels && Object.keys(cachedModels).includes(cachedModelName); // is model found in cache
|
||||
const tfLoadOptions = typeof fetch === 'undefined' ? {} : { fetchFunc: (url, init?) => httpHandler(url, init) };
|
||||
const model: GraphModel = new tf.GraphModel(modelCached ? cachedModelName : modelUrl, tfLoadOptions) as unknown as GraphModel; // create model prototype and decide if load from cache or from original modelurl
|
||||
const model: GraphModel = new tf.GraphModel(modelStats[shortModelName].cached ? cachedModelName : modelUrl, tfLoadOptions) as unknown as GraphModel; // create model prototype and decide if load from cache or from original modelurl
|
||||
let loaded = false;
|
||||
try {
|
||||
// @ts-ignore private function
|
||||
model.findIOHandler(); // decide how to actually load a model
|
||||
// @ts-ignore private property
|
||||
if (options.debug) log('model load handler:', model.handler);
|
||||
if (options.debug) log('model load handler:', model['handler']);
|
||||
// @ts-ignore private property
|
||||
const artifacts = await model.handler.load(); // load manifest
|
||||
modelStats[shortModelName].manifest = artifacts?.weightData?.byteLength || 0;
|
||||
model.loadSync(artifacts); // load weights
|
||||
if (options.verbose) log('load model:', model['modelUrl']);
|
||||
// @ts-ignore private property
|
||||
modelStats[shortModelName].weights = model?.artifacts?.weightData?.byteLength || 0;
|
||||
if (options.verbose) log('load model:', model['modelUrl'], { bytes: modelStats[shortModelName].weights });
|
||||
loaded = true;
|
||||
} catch (err) {
|
||||
log('error loading model:', modelUrl, err);
|
||||
}
|
||||
if (loaded && options.cacheModels && !modelCached) { // save model to cache
|
||||
if (loaded && options.cacheModels && !modelStats[shortModelName].cached) { // save model to cache
|
||||
try {
|
||||
const saveResult = await model.save(cachedModelName);
|
||||
log('model saved:', cachedModelName, saveResult);
|
||||
|
|
|
@ -1,24 +1,24 @@
|
|||
2022-06-21 13:20:54 [36mINFO: [39m Application: {"name":"@vladmandic/human","version":"2.8.1"}
|
||||
2022-06-21 13:20:54 [36mINFO: [39m Environment: {"profile":"production","config":".build.json","package":"package.json","tsconfig":true,"eslintrc":true,"git":true}
|
||||
2022-06-21 13:20:54 [36mINFO: [39m Toolchain: {"build":"0.7.3","esbuild":"0.14.47","typescript":"4.7.4","typedoc":"0.22.17","eslint":"8.18.0"}
|
||||
2022-06-21 13:20:54 [36mINFO: [39m Build: {"profile":"production","steps":["clean","compile","typings","typedoc","lint","changelog"]}
|
||||
2022-06-21 13:20:54 [35mSTATE:[39m Clean: {"locations":["dist/*","types/lib/*","typedoc/*"]}
|
||||
2022-06-21 13:20:54 [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-06-21 13:20:54 [35mSTATE:[39m Compile: {"name":"human/nodejs/cpu","format":"cjs","platform":"node","input":"src/human.ts","output":"dist/human.node.js","files":73,"inputBytes":642839,"outputBytes":300711}
|
||||
2022-06-21 13:20:54 [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-06-21 13:20:54 [35mSTATE:[39m Compile: {"name":"human/nodejs/gpu","format":"cjs","platform":"node","input":"src/human.ts","output":"dist/human.node-gpu.js","files":73,"inputBytes":642843,"outputBytes":300715}
|
||||
2022-06-21 13:20:54 [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-06-21 13:20:54 [35mSTATE:[39m Compile: {"name":"human/nodejs/wasm","format":"cjs","platform":"node","input":"src/human.ts","output":"dist/human.node-wasm.js","files":73,"inputBytes":642895,"outputBytes":300765}
|
||||
2022-06-21 13:20:54 [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":371}
|
||||
2022-06-21 13:20:54 [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":1045,"outputBytes":596}
|
||||
2022-06-21 13:20:54 [35mSTATE:[39m Compile: {"name":"human/browser/esm/nobundle","format":"esm","platform":"browser","input":"src/human.ts","output":"dist/human.esm-nobundle.js","files":73,"inputBytes":642827,"outputBytes":299608}
|
||||
2022-06-21 13:20:55 [35mSTATE:[39m Compile: {"name":"tfjs/browser/esm/custom","format":"esm","platform":"browser","input":"tfjs/tf-custom.ts","output":"dist/tfjs.esm.js","files":1,"inputBytes":110,"outputBytes":1353541}
|
||||
2022-06-21 13:20:55 [35mSTATE:[39m Compile: {"name":"human/browser/iife/bundle","format":"iife","platform":"browser","input":"src/human.ts","output":"dist/human.js","files":73,"inputBytes":1995772,"outputBytes":1652210}
|
||||
2022-06-21 13:20:55 [35mSTATE:[39m Compile: {"name":"human/browser/esm/bundle","format":"esm","platform":"browser","input":"src/human.ts","output":"dist/human.esm.js","files":73,"inputBytes":1995772,"outputBytes":2139073}
|
||||
2022-06-21 13:21:07 [35mSTATE:[39m Typings: {"input":"src/human.ts","output":"types/lib","files":116}
|
||||
2022-06-21 13:21:13 [35mSTATE:[39m TypeDoc: {"input":"src/human.ts","output":"typedoc","objects":73,"generated":true}
|
||||
2022-06-21 13:21:13 [35mSTATE:[39m Compile: {"name":"demo/typescript","format":"esm","platform":"browser","input":"demo/typescript/index.ts","output":"demo/typescript/index.js","files":1,"inputBytes":6326,"outputBytes":3070}
|
||||
2022-06-21 13:21:13 [35mSTATE:[39m Compile: {"name":"demo/faceid","format":"esm","platform":"browser","input":"demo/faceid/index.ts","output":"demo/faceid/index.js","files":2,"inputBytes":15174,"outputBytes":7833}
|
||||
2022-06-21 13:22:08 [35mSTATE:[39m Lint: {"locations":["*.json","src/**/*.ts","test/**/*.js","demo/**/*.js"],"files":106,"errors":0,"warnings":0}
|
||||
2022-06-21 13:22:08 [35mSTATE:[39m ChangeLog: {"repository":"https://github.com/vladmandic/human","branch":"main","output":"CHANGELOG.md"}
|
||||
2022-06-21 13:22:08 [36mINFO: [39m Done...
|
||||
2022-07-02 03:34:20 [36mINFO: [39m Application: {"name":"@vladmandic/human","version":"2.8.1"}
|
||||
2022-07-02 03:34:20 [36mINFO: [39m Environment: {"profile":"production","config":".build.json","package":"package.json","tsconfig":true,"eslintrc":true,"git":true}
|
||||
2022-07-02 03:34:20 [36mINFO: [39m Toolchain: {"build":"0.7.3","esbuild":"0.14.47","typescript":"4.7.4","typedoc":"0.22.17","eslint":"8.18.0"}
|
||||
2022-07-02 03:34:20 [36mINFO: [39m Build: {"profile":"production","steps":["clean","compile","typings","typedoc","lint","changelog"]}
|
||||
2022-07-02 03:34:20 [35mSTATE:[39m Clean: {"locations":["dist/*","types/lib/*","typedoc/*"]}
|
||||
2022-07-02 03:34:20 [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-07-02 03:34:21 [35mSTATE:[39m Compile: {"name":"human/nodejs/cpu","format":"cjs","platform":"node","input":"src/human.ts","output":"dist/human.node.js","files":73,"inputBytes":643891,"outputBytes":301229}
|
||||
2022-07-02 03:34:21 [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-07-02 03:34:21 [35mSTATE:[39m Compile: {"name":"human/nodejs/gpu","format":"cjs","platform":"node","input":"src/human.ts","output":"dist/human.node-gpu.js","files":73,"inputBytes":643895,"outputBytes":301233}
|
||||
2022-07-02 03:34:21 [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-07-02 03:34:21 [35mSTATE:[39m Compile: {"name":"human/nodejs/wasm","format":"cjs","platform":"node","input":"src/human.ts","output":"dist/human.node-wasm.js","files":73,"inputBytes":643947,"outputBytes":301283}
|
||||
2022-07-02 03:34:21 [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":371}
|
||||
2022-07-02 03:34:21 [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":1045,"outputBytes":596}
|
||||
2022-07-02 03:34:21 [35mSTATE:[39m Compile: {"name":"human/browser/esm/nobundle","format":"esm","platform":"browser","input":"src/human.ts","output":"dist/human.esm-nobundle.js","files":73,"inputBytes":643879,"outputBytes":300126}
|
||||
2022-07-02 03:34:21 [35mSTATE:[39m Compile: {"name":"tfjs/browser/esm/custom","format":"esm","platform":"browser","input":"tfjs/tf-custom.ts","output":"dist/tfjs.esm.js","files":1,"inputBytes":110,"outputBytes":1353541}
|
||||
2022-07-02 03:34:21 [35mSTATE:[39m Compile: {"name":"human/browser/iife/bundle","format":"iife","platform":"browser","input":"src/human.ts","output":"dist/human.js","files":73,"inputBytes":1996824,"outputBytes":1652733}
|
||||
2022-07-02 03:34:21 [35mSTATE:[39m Compile: {"name":"human/browser/esm/bundle","format":"esm","platform":"browser","input":"src/human.ts","output":"dist/human.esm.js","files":73,"inputBytes":1996824,"outputBytes":2140101}
|
||||
2022-07-02 03:34:36 [35mSTATE:[39m Typings: {"input":"src/human.ts","output":"types/lib","files":116}
|
||||
2022-07-02 03:34:44 [35mSTATE:[39m TypeDoc: {"input":"src/human.ts","output":"typedoc","objects":73,"generated":true}
|
||||
2022-07-02 03:34:44 [35mSTATE:[39m Compile: {"name":"demo/typescript","format":"esm","platform":"browser","input":"demo/typescript/index.ts","output":"demo/typescript/index.js","files":1,"inputBytes":6324,"outputBytes":3070}
|
||||
2022-07-02 03:34:44 [35mSTATE:[39m Compile: {"name":"demo/faceid","format":"esm","platform":"browser","input":"demo/faceid/index.ts","output":"demo/faceid/index.js","files":2,"inputBytes":15174,"outputBytes":7833}
|
||||
2022-07-02 03:35:04 [35mSTATE:[39m Lint: {"locations":["*.json","src/**/*.ts","test/**/*.js","demo/**/*.js"],"files":106,"errors":0,"warnings":0}
|
||||
2022-07-02 03:35:05 [35mSTATE:[39m ChangeLog: {"repository":"https://github.com/vladmandic/human","branch":"main","output":"CHANGELOG.md"}
|
||||
2022-07-02 03:35:05 [36mINFO: [39m Done...
|
||||
|
|
Loading…
Reference in New Issue