added human.env diagnostic class

pull/356/head
Vladimir Mandic 2021-09-12 12:42:17 -04:00
parent f6724de956
commit 7fa09937b4
8 changed files with 177 additions and 21 deletions

View File

@ -13,16 +13,23 @@ assignees: vladmandic
**Expected Behavior**
**Environment
**Environment**
- Module version?
- Human library version?
- Built-in demo or custom code?
- Type of module used (e.g. `js`, `esm`, `esm-nobundle`)?
- Browser or NodeJS and version (e.g. NodeJS 14.15 or Chrome 89)?
- OS and Hardware platform (e.g. Windows 10, Ubuntu Linux on x64, Android 10)?
- Packager (if any) (e.g, webpack, rollup, parcel, esbuild, etc.)?
- TensorFlow/JS version (if not using bundled module)?
- Browser or NodeJS and version (e.g. *NodeJS 14.15* or *Chrome 89*)?
- OS and Hardware platform (e.g. *Windows 10*, *Ubuntu Linux on x64*, *Android 10*)?
- Packager (if any) (e.g, *webpack*, *rollup*, *parcel*, *esbuild*, etc.)?
- Framework (if any) (e.g. *React*, *NextJS*, etc.)?
**Diagnostics**
- Check out any applicable [diagnostic steps](https://github.com/vladmandic/human/wiki/Diag)
**Additional**
- For installation or startup issues include your `package.json`
- For usage issues, it is recommended to post your code as [gist](https://gist.github.com/)
- For general questions, create a [discussion topic](https://github.com/vladmandic/human/discussions)

View File

@ -11,6 +11,8 @@
### **HEAD -> main** 2021/09/12 mandic00@live.com
- release candidate
- parametrize face config
- mark all config items as optional
- redefine config and result interfaces
- fix usge of string enums

View File

@ -72,6 +72,7 @@ Check out [**Live Demo**](https://vladmandic.github.io/human/demo/index.html) ap
- [**Performance Notes**](https://github.com/vladmandic/human/wiki/Performance)
- [**Performance Profiling**](https://github.com/vladmandic/human/wiki/Profiling)
- [**Platform Support**](https://github.com/vladmandic/human/wiki/Platforms)
- [**Diagnostic and Performance trace information**](https://github.com/vladmandic/human/wiki/Diag)
- [**List of Models & Credits**](https://github.com/vladmandic/human/wiki/Models)
- [**Security & Privacy Policy**](https://github.com/vladmandic/human/blob/main/SECURITY.md)
- [**License & Usage Restrictions**](https://github.com/vladmandic/human/blob/main/LICENSE)
@ -309,6 +310,12 @@ For more info, see [**Configuration Details**](https://github.com/vladmandic/hum
<br><hr><br>
## Diagnostics
- [How to get diagnostic information or performance trace information](https://github.com/vladmandic/human/wiki/Diag)
<br><hr><br>
`Human` library is written in `TypeScript` [4.3](https://www.typescriptlang.org/docs/handbook/intro.html)
Conforming to `JavaScript` [ECMAScript version 2020](https://www.ecma-international.org/ecma-262/11.0/index.html) standard
Build target is `JavaScript` [EMCAScript version 2018](https://262.ecma-international.org/9.0/)

View File

@ -953,8 +953,7 @@ async function main() {
// create instance of human
human = new Human(userConfig);
log('human version:', Human.version);
log('tfjs version:', human.tf.version.tfjs);
log('human version:', human.version);
userConfig = { ...human.config, ...userConfig };
if (typeof tf !== 'undefined') {
// eslint-disable-next-line no-undef
@ -962,6 +961,7 @@ async function main() {
// eslint-disable-next-line no-undef
human.tf = tf; // use externally loaded version of tfjs
}
log('tfjs version:', human.tf.version.tfjs);
// setup main menu
await setupMenu();
@ -1013,6 +1013,8 @@ async function main() {
log('overriding images list:', JSON.parse(params.get('images')));
await detectSampleImages();
}
if (human.config.debug) log('environment:', human.env);
}
window.onload = main;

View File

@ -246,9 +246,11 @@ export interface Config {
*
*/
const config: Config = {
backend: 'humangl', // select tfjs backend to use, leave empty to use default backend
backend: '', // select tfjs backend to use, leave empty to use default backend
// can be 'webgl', 'wasm', 'cpu', or 'humangl' which is a custom version of webgl
modelBasePath: '../models/', // base path for all models
// default set to `humangl` for browsers and `tensorflow` for nodejs
modelBasePath: '', // base path for all models
// default set to `../models/` for browsers and `file://models/` for nodejs
wasmPath: '', // path for wasm binaries, only used for backend: wasm
// default set to download from jsdeliv during Human class instantiation
debug: true, // print additional status messages to console

128
src/env.ts Normal file
View File

@ -0,0 +1,128 @@
import * as tf from '../dist/tfjs.esm.js';
export interface Env {
browser: undefined | boolean,
node: undefined | boolean,
worker: undefined | boolean,
platform: undefined | string,
agent: undefined | string,
backends: string[],
tfjs: {
version: undefined | string,
external: undefined | boolean,
},
wasm: {
supported: undefined | boolean,
simd: undefined | boolean,
multithread: undefined | boolean,
},
webgl: {
supported: undefined | boolean,
version: undefined | string,
renderer: undefined | string,
},
webgpu: {
supported: undefined | boolean,
adapter: undefined | string,
},
kernels: string[],
}
export const env: Env = {
browser: undefined,
node: undefined,
worker: undefined,
platform: undefined,
agent: undefined,
backends: [],
tfjs: {
version: undefined,
external: undefined,
},
wasm: {
supported: undefined,
simd: undefined,
multithread: undefined,
},
webgl: {
supported: undefined,
version: undefined,
renderer: undefined,
},
webgpu: {
supported: undefined,
adapter: undefined,
},
kernels: [],
};
export function cpuinfo() {
const cpu = { model: '', flags: [] };
if (env.node && env.platform?.startsWith('linux')) {
// eslint-disable-next-line global-require
const fs = require('fs');
try {
const data = fs.readFileSync('/proc/cpuinfo').toString();
for (const line of data.split('\n')) {
if (line.startsWith('model name')) {
cpu.model = line.match(/:(.*)/g)[0].replace(':', '').trim();
}
if (line.startsWith('flags')) {
cpu.flags = line.match(/:(.*)/g)[0].replace(':', '').trim().split(' ').sort();
}
}
} catch { /**/ }
}
if (!env['cpu']) Object.defineProperty(env, 'cpu', { value: cpu });
else env['cpu'] = cpu;
}
export async function get() {
env.browser = typeof navigator !== 'undefined';
env.node = typeof process !== 'undefined';
// @ts-ignore WorkerGlobalScope evaluated in browser only
env.worker = env.browser ? (typeof WorkerGlobalScope !== 'undefined') : undefined;
env.tfjs.version = tf.version_core;
// get platform and agent
if (typeof navigator !== 'undefined') {
const raw = navigator.userAgent.match(/\(([^()]+)\)/g);
if (raw && raw[0]) {
const platformMatch = raw[0].match(/\(([^()]+)\)/g);
env.platform = (platformMatch && platformMatch[0]) ? platformMatch[0].replace(/\(|\)/g, '') : '';
env.agent = navigator.userAgent.replace(raw[0], '');
if (env.platform[1]) env.agent = env.agent.replace(raw[1], '');
env.agent = env.agent.replace(/ /g, ' ');
}
} else if (typeof process !== 'undefined') {
env.platform = `${process.platform} ${process.arch}`;
env.agent = `NodeJS ${process.version}`;
}
// analyze backends
env.backends = Object.keys(tf.engine().registryFactory);
env.wasm.supported = env.backends.includes('wasm');
if (env.wasm.supported) {
env.wasm.simd = await tf.env().getAsync('WASM_HAS_SIMD_SUPPORT');
env.wasm.multithread = await tf.env().getAsync('WASM_HAS_MULTITHREAD_SUPPORT');
}
env.webgl.supported = typeof tf.backend().gpgpu !== 'undefined';
if (env.webgl.supported) {
// @ts-ignore getGPGPUContext only exists on WebGL backend
const gl = await tf.backend().getGPGPUContext().gl;
if (gl) {
env.webgl.version = gl.getParameter(gl.VERSION);
env.webgl.renderer = gl.getParameter(gl.RENDERER);
}
}
env.webgpu.supported = env.browser && typeof navigator['gpu'] !== 'undefined';
if (env.webgpu.supported) env.webgpu.adapter = (await navigator['gpu'].requestAdapter())?.name;
// enumerate kernels
env.kernels = tf.getKernelsForBackend(tf.getBackend()).map((kernel) => kernel.kernelName);
// get cpu info
// cpuinfo();
}

View File

@ -5,7 +5,6 @@
import { log, now, mergeDeep } from './helpers';
import { Config, defaults } from './config';
import { Result, FaceResult, HandResult, BodyResult, ObjectResult, GestureResult } from './result';
import * as sysinfo from './sysinfo';
import * as tf from '../dist/tfjs.esm.js';
import * as backend from './tfjs/backend';
import * as models from './models';
@ -26,6 +25,7 @@ import * as draw from './draw/draw';
import * as persons from './persons';
import * as interpolate from './interpolate';
import * as sample from './sample';
import * as env from './env';
import * as app from '../package.json';
import { Tensor, GraphModel } from './tfjs/types';
@ -33,6 +33,7 @@ import { Tensor, GraphModel } from './tfjs/types';
export * from './config';
export * from './result';
export type { DrawOptions } from './draw/draw';
export { env } from './env';
/** Defines all possible input types for **Human** detection
* @typedef Input Type
@ -93,6 +94,10 @@ export class Human {
* - Can be embedded or externally provided
*/
tf: TensorFlow;
/**
* Object containing environment information used for diagnostics
*/
env: env.Env;
/** Draw helper classes that can draw detected objects on canvas using specified draw
* - options: {@link DrawOptions} global settings for all draw operations, can be overriden for each draw method
* - face: draw detected faces
@ -141,8 +146,6 @@ export class Human {
faceTriangulation: typeof facemesh.triangulation;
/** Refernce UV map of 468 values, used for 3D mapping of the face mesh */
faceUVMap: typeof facemesh.uvmap;
/** Platform and agent information detected by Human */
sysinfo: { platform: string, agent: string };
/** Performance object that contains values for all recently performed operations */
performance: Record<string, number>; // perf members are dynamically defined as needed
#numTensors: number;
@ -159,9 +162,13 @@ export class Human {
* @param userConfig: {@link Config}
*/
constructor(userConfig?: Partial<Config>) {
env.get();
this.env = env.env;
defaults.wasmPath = `https://cdn.jsdelivr.net/npm/@tensorflow/tfjs-backend-wasm@${tf.version_core}/dist/`;
defaults.modelBasePath = this.env.browser ? '../models/' : 'file://models/';
defaults.backend = this.env.browser ? 'humangl' : 'tensorflow';
this.version = app.version; // expose version property on instance of class
Object.defineProperty(this, 'version', { value: app.version }); // expose version property directly on class itself
defaults.wasmPath = `https://cdn.jsdelivr.net/npm/@tensorflow/tfjs-backend-wasm@${tf.version_core}/dist/`;
this.config = mergeDeep(defaults, userConfig || {});
this.tf = tf;
this.draw = draw;
@ -199,7 +206,6 @@ export class Human {
this.faceTriangulation = facemesh.triangulation;
this.faceUVMap = facemesh.uvmap;
// include platform info
this.sysinfo = sysinfo.info();
this.#lastInputSum = 1;
this.#emit('create');
}
@ -287,10 +293,9 @@ export class Human {
if (this.#firstRun) { // print version info on first run and check for correct backend setup
if (this.config.debug) log(`version: ${this.version}`);
if (this.config.debug) log(`tfjs version: ${this.tf.version_core}`);
if (this.config.debug) log('platform:', this.sysinfo.platform);
if (this.config.debug) log('agent:', this.sysinfo.agent);
if (this.config.debug) log('environment:', env.env);
await this.#checkBackend(true);
await this.#checkBackend();
if (this.tf.ENV.flags.IS_BROWSER) {
if (this.config.debug) log('configuration:', this.config);
if (this.config.debug) log('tf flags:', this.tf.ENV.flags);
@ -316,8 +321,8 @@ export class Human {
// check if backend needs initialization if it changed
/** @hidden */
#checkBackend = async (force = false) => {
if (this.config.backend && (this.config.backend.length > 0) && force || (this.tf.getBackend() !== this.config.backend)) {
#checkBackend = async () => {
if (this.#firstRun || (this.config.backend && (this.config.backend.length > 0) || (this.tf.getBackend() !== this.config.backend))) {
const timeStamp = now();
this.state = 'backend';
/* force backend reload
@ -343,7 +348,7 @@ export class Human {
this.config.backend = 'humangl';
}
if (this.tf.ENV.flags.IS_NODE && (this.config.backend === 'webgl' || this.config.backend === 'humangl')) {
log('override: backend set to webgl while running in nodejs');
log(`override: backend set to ${this.config.backend} while running in nodejs`);
this.config.backend = 'tensorflow';
}
@ -410,6 +415,9 @@ export class Human {
this.tf.enableProdMode();
await this.tf.ready();
this.performance.backend = Math.trunc(now() - timeStamp);
env.get(); // update env on backend init
this.env = env.env;
}
}

2
wiki

@ -1 +1 @@
Subproject commit ec49beb9f19c0abde3e62b24ba2c7749ef54c9aa
Subproject commit ee12bda3113d3d893c898a9827f9c174d4058fb8