diff --git a/TODO.md b/TODO.md index 3d97a3e1..896cbd5b 100644 --- a/TODO.md +++ b/TODO.md @@ -6,6 +6,7 @@ WebGL shader optimizations for faster load and initial detection - Implement WebGL uniforms for shaders: - Fix shader packing: +- Event emitters
diff --git a/demo/benchmark/browser.html b/demo/benchmark/browser.html new file mode 100644 index 00000000..595ec88f --- /dev/null +++ b/demo/benchmark/browser.html @@ -0,0 +1,30 @@ + + + + + Human + + + + + + + + + + + + + +
+ +
+ + diff --git a/demo/benchmark/node.js b/demo/benchmark/node.js new file mode 100644 index 00000000..1ddcf84f --- /dev/null +++ b/demo/benchmark/node.js @@ -0,0 +1,71 @@ +// eslint-disable-next-line no-unused-vars, @typescript-eslint/no-unused-vars +const tf = require('@tensorflow/tfjs-node-gpu'); +const log = require('@vladmandic/pilogger'); +const canvasJS = require('canvas'); +const Human = require('../../dist/human.node-gpu.js').default; + +const input = 'samples/groups/group1.jpg'; +const loop = 20; + +const myConfig = { + backend: 'tensorflow', + modelBasePath: 'https://vladmandic.github.io/human/models', + wasmPath: 'https://cdn.jsdelivr.net/npm/@tensorflow/tfjs-backend-wasm@3.9.0/dist/', + debug: true, + async: true, + cacheSensitivity: 0, + filter: { enabled: false }, + face: { + enabled: true, + detector: { enabled: true, rotation: false }, + mesh: { enabled: true }, + iris: { enabled: true }, + description: { enabled: true }, + emotion: { enabled: true }, + }, + hand: { + enabled: true, + }, + body: { enabled: true }, + object: { enabled: false }, +}; + +async function getImage(human) { + const img = await canvasJS.loadImage(input); + const canvas = canvasJS.createCanvas(img.width, img.height); + const ctx = canvas.getContext('2d'); + ctx.drawImage(img, 0, 0, img.width, img.height); + const imageData = ctx.getImageData(0, 0, canvas.width, canvas.height); + const res = human.tf.tidy(() => { + const tensor = human.tf.tensor(Array.from(imageData.data), [canvas.height, canvas.width, 4], 'int32'); // create rgba image tensor from flat array + const channels = human.tf.split(tensor, 4, 2); // split rgba to channels + const rgb = human.tf.stack([channels[0], channels[1], channels[2]], 2); // stack channels back to rgb + const reshape = human.tf.reshape(rgb, [1, canvas.height, canvas.width, 3]); // move extra dim from the end of tensor and use it as batch number instead + return reshape; + }); + log.info('Image:', input, res.shape); + return res; +} + +async function main() { + log.header(); + const human = new Human(myConfig); + await human.tf.ready(); + log.info('Human:', human.version); + await human.load(); + const loaded = Object.keys(human.models).filter((a) => human.models[a]); + log.info('Loaded:', loaded); + log.info('Memory state:', human.tf.engine().memory()); + const tensor = await getImage(human); + log.state('Processing:', tensor['shape']); + const t0 = performance.now(); + await human.detect(tensor, myConfig); + const t1 = performance.now(); + log.state('Backend:', human.tf.getBackend()); + log.data('Warmup:', Math.round(t1 - t0)); + for (let i = 0; i < loop; i++) await human.detect(tensor, myConfig); + const t2 = performance.now(); + log.data('Average:', Math.round((t2 - t1) / loop)); +} + +main(); diff --git a/package.json b/package.json index 4cd6a46e..5d262ad6 100644 --- a/package.json +++ b/package.json @@ -73,7 +73,7 @@ "canvas": "^2.8.0", "chokidar": "^3.5.2", "dayjs": "^1.10.6", - "esbuild": "^0.12.24", + "esbuild": "^0.12.25", "eslint": "^7.32.0", "eslint-config-airbnb-base": "^14.2.1", "eslint-plugin-import": "^2.24.2", @@ -83,7 +83,7 @@ "node-fetch": "^3.0.0", "rimraf": "^3.0.2", "seedrandom": "^3.0.5", - "simple-git": "^2.45.0", + "simple-git": "^2.45.1", "tslib": "^2.3.1", "typedoc": "0.21.9", "typescript": "4.4.2" diff --git a/src/human.ts b/src/human.ts index fee348c1..cb3212ed 100644 --- a/src/human.ts +++ b/src/human.ts @@ -62,7 +62,7 @@ export type TensorFlow = typeof tf; */ export class Human { /** Current version of Human library in *semver* format */ - static version: string; + version: string; /** Current configuration * - Details: {@link Config} */ @@ -148,7 +148,7 @@ export class Human { * @param userConfig: {@link Config} */ constructor(userConfig?: Config | Record) { - Human.version = app.version; // expose version property on instance of class + 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 || {}); @@ -270,7 +270,7 @@ export class Human { if (userConfig) this.config = mergeDeep(this.config, userConfig) as Config; if (this.#firstRun) { // print version info on first run and check for correct backend setup - if (this.config.debug) log(`version: ${Human.version}`); + 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); diff --git a/wiki b/wiki index 7f55fd1c..82ce7a69 160000 --- a/wiki +++ b/wiki @@ -1 +1 @@ -Subproject commit 7f55fd1c8aea22f33a767da840147b15aeeed034 +Subproject commit 82ce7a69656a11fa4cd5c5bea447cd1a2797b903