Skip to content

Commit 66dc36b

Browse files
authored
upgrade bodypix to 3.0 api (#565)
* upgrade to 3.0 api ; * fix lint
1 parent b0ffa58 commit 66dc36b

17 files changed

+1713
-587
lines changed

body-pix/demos/index.js

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@
1414
* limitations under the License.
1515
* =============================================================================
1616
*/
17+
import '@tensorflow/tfjs-backend-webgl';
1718
import * as bodyPix from '@tensorflow-models/body-pix';
1819
import dat from 'dat.gui';
1920
import Stats from 'stats.js';

body-pix/demos/package.json

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -9,10 +9,11 @@
99
"node": ">=8.9.0"
1010
},
1111
"dependencies": {
12-
"@tensorflow-models/body-pix": "2.0.2",
12+
"@tensorflow-models/body-pix": "file:../dist",
1313
"@tensorflow-models/posenet": "^2.1.3",
14-
"@tensorflow/tfjs-converter": "~1.2.1",
15-
"@tensorflow/tfjs-core": "~1.2.1",
14+
"@tensorflow/tfjs-backend-webgl": "~3.0.0-rc.1",
15+
"@tensorflow/tfjs-converter": "~3.0.0-rc.1",
16+
"@tensorflow/tfjs-core": "~3.0.0-rc.1",
1617
"stats.js": "0.17.0"
1718
},
1819
"scripts": {
@@ -54,4 +55,4 @@
5455
"eslintIgnore": [
5556
"dist/"
5657
]
57-
}
58+
}

body-pix/demos/yarn.lock

Lines changed: 39 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -742,31 +742,48 @@
742742
"@parcel/utils" "^1.11.0"
743743
physical-cpu-count "^2.0.0"
744744

745-
"@tensorflow-models/[email protected]":
746-
version "2.0.2"
747-
resolved "https://registry.yarnpkg.com/@tensorflow-models/body-pix/-/body-pix-2.0.2.tgz#3c2c787a9621bbc40d4e20e23aad8b7e69f8c9c5"
748-
integrity sha512-2fgwuco2smxkTqPOGq6Jc/4K9lOrTIvqfMF5UjIqQGhVGwRas8DQJfOiq7pPCzRZEc1diuhCjMTx4PK4aSKFyQ==
745+
"@tensorflow-models/body-pix@file:../dist":
746+
version "0.0.0"
749747

750748
"@tensorflow-models/posenet@^2.1.3":
751749
version "2.1.3"
752750
resolved "https://registry.yarnpkg.com/@tensorflow-models/posenet/-/posenet-2.1.3.tgz#09633e6e6e41d6c00d2ee7633632fb9322651463"
753751
integrity sha512-Z6HvkJhLWtXt5BD+1c9iaUGlHjohiPkeRJQpr1hu57opvTmwswwmwwRAKsmM07AVjuUT0D49QordE6zkjIJ3mg==
754752

755-
"@tensorflow/tfjs-converter@~1.2.1":
756-
version "1.2.7"
757-
resolved "https://registry.yarnpkg.com/@tensorflow/tfjs-converter/-/tfjs-converter-1.2.7.tgz#3a1cf6d636667586010c4df79e861293ce10c4c8"
758-
integrity sha512-7MRH21zNgOOYGuztcrZwx6eXhg8gn/QvIZWljsmTJ33fnIyWLSAIHXsp5WgWalfAsj40yU92TnxaIyRuPeD/mw==
753+
"@tensorflow/[email protected]":
754+
version "3.0.0-rc.1"
755+
resolved "https://registry.yarnpkg.com/@tensorflow/tfjs-backend-cpu/-/tfjs-backend-cpu-3.0.0-rc.1.tgz#b02e05706b2d91ab601e7eb397b6ea60ac0a9e2e"
756+
integrity sha512-9+13fs3vVpfOpDY+Aa/JXdda2SuBN/clxxoNYIX3pMY0GAGwpUaAkSECLuOOhnngHcl9pxuaJtgqrCcrq+A3/A==
757+
dependencies:
758+
"@types/seedrandom" "2.4.27"
759+
seedrandom "2.4.3"
759760

760-
"@tensorflow/tfjs-core@~1.2.1":
761-
version "1.2.8"
762-
resolved "https://registry.yarnpkg.com/@tensorflow/tfjs-core/-/tfjs-core-1.2.8.tgz#d6873b88522f8cf25d34c10afd095866578d7d92"
763-
integrity sha512-lWV4vAnXAAmahXpCWBwdGGW9HO6iNw9pUeVYih7pDXeJahMk3OJs6SgjRNhwn+ldsGwRoorR0/RHg0yNLmqWxQ==
761+
"@tensorflow/tfjs-backend-webgl@~3.0.0-rc.1":
762+
version "3.0.0-rc.1"
763+
resolved "https://registry.yarnpkg.com/@tensorflow/tfjs-backend-webgl/-/tfjs-backend-webgl-3.0.0-rc.1.tgz#21aacedcef687d2bb075c7951ac9e4f57faa79e6"
764+
integrity sha512-qEjtL/71HflBHJgWXhtj+8BVYB9Q+NHw282QGWi9QLA9SlWe3BRJhbGCaD28/Ddl+mSzBWFQnK+sKdZ04LL1Sg==
765+
dependencies:
766+
"@tensorflow/tfjs-backend-cpu" "3.0.0-rc.1"
767+
"@types/offscreencanvas" "~2019.3.0"
768+
"@types/seedrandom" "2.4.27"
769+
"@types/webgl-ext" "0.0.30"
770+
"@types/webgl2" "0.0.5"
771+
seedrandom "2.4.3"
772+
773+
"@tensorflow/tfjs-converter@~3.0.0-rc.1":
774+
version "3.0.0-rc.1"
775+
resolved "https://registry.yarnpkg.com/@tensorflow/tfjs-converter/-/tfjs-converter-3.0.0-rc.1.tgz#a15eb72ade80f7ae0e6403020763be0c5af6f2f7"
776+
integrity sha512-vVezwsDtrqM9CGDU+9c1WvPbLB5Odi9uiyEUHZEXMgNnPZ9Ix8a7RFOL7Y+8uBsI3B5wmLrWJuUNeyxUjA7yiA==
777+
778+
"@tensorflow/tfjs-core@~3.0.0-rc.1":
779+
version "3.0.0-rc.1"
780+
resolved "https://registry.yarnpkg.com/@tensorflow/tfjs-core/-/tfjs-core-3.0.0-rc.1.tgz#0b5316871eef2a4c8aa149d154e6ea6bbc7b631e"
781+
integrity sha512-h9a0TyWNJFqgmyfSklwI2q0SC93WFr8FBHwHorvsfm2mDK0ZrSs6bhWqa44tWRJjCrJNRq9J4GoTZQM292RTwg==
764782
dependencies:
765783
"@types/offscreencanvas" "~2019.3.0"
766784
"@types/seedrandom" "2.4.27"
767785
"@types/webgl-ext" "0.0.30"
768-
"@types/webgl2" "0.0.4"
769-
node-fetch "~2.1.2"
786+
node-fetch "~2.6.1"
770787
seedrandom "2.4.3"
771788

772789
"@types/offscreencanvas@~2019.3.0":
@@ -789,10 +806,10 @@
789806
resolved "https://registry.yarnpkg.com/@types/webgl-ext/-/webgl-ext-0.0.30.tgz#0ce498c16a41a23d15289e0b844d945b25f0fb9d"
790807
integrity sha512-LKVgNmBxN0BbljJrVUwkxwRYqzsAEPcZOe6S2T6ZaBDIrFp0qu4FNlpc5sM1tGbXUYFgdVQIoeLk1Y1UoblyEg==
791808

792-
"@types/[email protected].4":
793-
version "0.0.4"
794-
resolved "https://registry.yarnpkg.com/@types/webgl2/-/webgl2-0.0.4.tgz#c3b0f9d6b465c66138e84e64cb3bdf8373c2c279"
795-
integrity sha512-PACt1xdErJbMUOUweSrbVM7gSIYm1vTncW2hF6Os/EeWi6TXYAYMPp+8v6rzHmypE5gHrxaxZNXgMkJVIdZpHw==
809+
"@types/[email protected].5":
810+
version "0.0.5"
811+
resolved "https://registry.yarnpkg.com/@types/webgl2/-/webgl2-0.0.5.tgz#dd925e20ab8ace80eb4b1e46fda5b109c508fb0d"
812+
integrity sha512-oGaKsBbxQOY5+aJFV3KECDhGaXt+yZJt2y/OZsnQGLRkH6Fvr7rv4pCt3SRH1somIHfej/c4u7NSpCyd9x+1Ow==
796813

797814
abab@^2.0.0:
798815
version "2.0.2"
@@ -4227,10 +4244,10 @@ node-addon-api@^1.6.0:
42274244
resolved "https://registry.yarnpkg.com/node-addon-api/-/node-addon-api-1.7.1.tgz#cf813cd69bb8d9100f6bdca6755fc268f54ac492"
42284245
integrity sha512-2+DuKodWvwRTrCfKOeR24KIc5unKjOh8mz17NCzVnHWfjAdDqbfbjqh7gUT+BkXBRQM52+xCHciKWonJ3CbJMQ==
42294246

4230-
node-fetch@~2.1.2:
4231-
version "2.1.2"
4232-
resolved "https://registry.yarnpkg.com/node-fetch/-/node-fetch-2.1.2.tgz#ab884e8e7e57e38a944753cec706f788d1768bb5"
4233-
integrity sha1-q4hOjn5X44qUR1POxwb3iNF2i7U=
4247+
node-fetch@~2.6.1:
4248+
version "2.6.1"
4249+
resolved "https://registry.yarnpkg.com/node-fetch/-/node-fetch-2.6.1.tgz#045bd323631f76ed2e2b55573394416b639a0052"
4250+
integrity sha512-V4aYg89jEoVRxRb2fJdAg8FHvI7cEyYdVAh94HH0UIK8oJxUfkjlDQN9RbMx+bEjP7+ggMiFRprSti032Oipxw==
42344251

42354252
node-forge@^0.7.1:
42364253
version "0.7.6"

body-pix/karma.conf.js

Lines changed: 22 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -15,18 +15,38 @@
1515
* =============================================================================
1616
*/
1717

18+
const karmaTypescriptConfig = {
19+
tsconfig: 'tsconfig.test.json',
20+
// Disable coverage reports and instrumentation by default for tests
21+
coverageOptions: {instrumentation: false},
22+
reports: {},
23+
bundlerOptions: {
24+
sourceMap: true, // Process any non es5 code through
25+
// karma-typescript-es6-transform (babel)
26+
acornOptions: {ecmaVersion: 8},
27+
transforms: [
28+
require('karma-typescript-es6-transform')({
29+
presets: [
30+
// ensure we get es5 by adding IE 11 as a target
31+
['@babel/env', {'targets': {'ie': '11'}, 'loose': true}]
32+
]
33+
}),
34+
]
35+
}
36+
};
37+
1838
module.exports = function(config) {
1939
config.set({
2040
frameworks: ['jasmine', 'karma-typescript'],
2141
files: [
42+
{pattern: './node_modules/@babel/polyfill/dist/polyfill.js'},
2243
'src/setup_test.ts', // Setup the environment for the tests.
2344
{pattern: 'src/**/*.ts'}
2445
],
2546
preprocessors: {
2647
'**/*.ts': ['karma-typescript'],
2748
},
28-
karmaTypescriptConfig:
29-
{tsconfig: 'tsconfig.test.json', compilerOptions: {module: 'commonjs'}},
49+
karmaTypescriptConfig,
3050
reporters: ['progress', 'karma-typescript'],
3151
browsers: ['Chrome'],
3252
browserStack: {

body-pix/package.json

Lines changed: 9 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -13,12 +13,15 @@
1313
"url": "https://github.com/tensorflow/tfjs-models.git"
1414
},
1515
"peerDependencies": {
16-
"@tensorflow/tfjs-converter": "^1.3.1",
17-
"@tensorflow/tfjs-core": "^1.3.1"
16+
"@tensorflow/tfjs-backend-webgl": "^3.0.0-rc.1",
17+
"@tensorflow/tfjs-converter": "^3.0.0-rc.1",
18+
"@tensorflow/tfjs-core": "^3.0.0-rc.1"
1819
},
1920
"devDependencies": {
20-
"@tensorflow/tfjs-converter": "^1.3.1",
21-
"@tensorflow/tfjs-core": "^1.3.1",
21+
"@babel/polyfill": "^7.8.7",
22+
"@tensorflow/tfjs-backend-webgl": "^3.0.0-rc.1",
23+
"@tensorflow/tfjs-converter": "^3.0.0-rc.1",
24+
"@tensorflow/tfjs-core": "^3.0.0-rc.1",
2225
"@types/jasmine": "~2.5.53",
2326
"jasmine": "~3.2.0",
2427
"jasmine-core": "~3.1.0",
@@ -27,7 +30,8 @@
2730
"karma-chrome-launcher": "~2.2.0",
2831
"karma-firefox-launcher": "~1.1.0",
2932
"karma-jasmine": "~1.1.1",
30-
"karma-typescript": "~4.0.0",
33+
"karma-typescript": "~5.2.0",
34+
"karma-typescript-es6-transform": "^5.0.2",
3135
"rimraf": "~2.6.2",
3236
"rollup": "~0.58.2",
3337
"rollup-plugin-node-resolve": "~3.3.0",

body-pix/src/base_model.ts

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -72,14 +72,14 @@ export abstract class BaseModel {
7272
partOffsets: tf.Tensor3D
7373
} {
7474
return tf.tidy(() => {
75-
const asFloat = this.preprocessInput(input.toFloat());
76-
const asBatch = asFloat.expandDims(0);
75+
const asFloat = this.preprocessInput(tf.cast(input, 'float32'));
76+
const asBatch = tf.expandDims(asFloat, 0);
7777
const results = this.model.predict(asBatch) as tf.Tensor4D[];
78-
const results3d: tf.Tensor3D[] = results.map(y => y.squeeze([0]));
78+
const results3d: tf.Tensor3D[] = results.map(y => tf.squeeze(y, [0]));
7979
const namedResults = this.nameOutputResults(results3d);
8080

8181
return {
82-
heatmapScores: namedResults.heatmap.sigmoid(),
82+
heatmapScores: tf.sigmoid(namedResults.heatmap),
8383
offsets: namedResults.offsets,
8484
displacementFwd: namedResults.displacementFwd,
8585
displacementBwd: namedResults.displacementBwd,

body-pix/src/body_pix_model.ts

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -479,8 +479,8 @@ export class BodyPix {
479479
APPLY_SIGMOID_ACTIVATION);
480480

481481
return {
482-
segmentation:
483-
toMaskTensor(scaledSegmentScores.squeeze(), segmentationThreshold),
482+
segmentation: toMaskTensor(
483+
tf.squeeze(scaledSegmentScores), segmentationThreshold),
484484
heatmapScores,
485485
offsets,
486486
displacementFwd,
@@ -640,7 +640,7 @@ export class BodyPix {
640640
}
641641

642642
const segmentation = toMaskTensor(
643-
scaledSegmentScores.squeeze(), config.segmentationThreshold);
643+
tf.squeeze(scaledSegmentScores), config.segmentationThreshold);
644644

645645
return {
646646
segmentation,
@@ -766,7 +766,7 @@ export class BodyPix {
766766
[[padding.top, padding.bottom], [padding.left, padding.right]],
767767
APPLY_SIGMOID_ACTIVATION);
768768
const segmentation =
769-
toMaskTensor(scaledSegmentScores.squeeze(), segmentationThreshold);
769+
toMaskTensor(tf.squeeze(scaledSegmentScores), segmentationThreshold);
770770
return {
771771
partSegmentation:
772772
decodePartSegmentation(segmentation, scaledPartHeatmapScore),
@@ -928,7 +928,7 @@ export class BodyPix {
928928

929929
const scaledLongOffsets = longOffsets;
930930
const segmentation = toMaskTensor(
931-
scaledSegmentScores.squeeze(), config.segmentationThreshold);
931+
tf.squeeze(scaledSegmentScores), config.segmentationThreshold);
932932
const partSegmentation =
933933
decodeOnlyPartSegmentation(scaledPartSegmentationScores);
934934
return {

body-pix/src/decode_part_map.ts

Lines changed: 14 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -25,15 +25,15 @@ import * as tf from '@tensorflow/tfjs-core';
2525
*/
2626
function toFlattenedOneHotPartMap(partHeatmapScores: tf.Tensor3D): tf.Tensor2D {
2727
const numParts = partHeatmapScores.shape[2];
28-
const partMapLocations = partHeatmapScores.argMax(2);
28+
const partMapLocations = tf.argMax(partHeatmapScores, 2);
2929

30-
const partMapFlattened = partMapLocations.reshape([-1]);
30+
const partMapFlattened = tf.reshape(partMapLocations, [-1]);
3131

3232
return tf.oneHot(partMapFlattened, numParts) as tf.Tensor2D;
3333
}
3434

3535
function clipByMask2d(image: tf.Tensor2D, mask: tf.Tensor2D): tf.Tensor2D {
36-
return image.mul(mask);
36+
return tf.mul(image, mask);
3737
}
3838

3939
/**
@@ -53,7 +53,8 @@ export function toMaskTensor(
5353
segmentScores: tf.Tensor2D, threshold: number): tf.Tensor2D {
5454
return tf.tidy(
5555
() =>
56-
(segmentScores.greater(tf.scalar(threshold)).toInt() as tf.Tensor2D));
56+
(tf.cast(tf.greater(
57+
segmentScores, tf.scalar(threshold)), 'int32') as tf.Tensor2D));
5758
}
5859

5960
/**
@@ -77,18 +78,18 @@ export function decodePartSegmentation(
7778
const [partMapHeight, partMapWidth, numParts] = partHeatmapScores.shape;
7879
return tf.tidy(() => {
7980
const flattenedMap = toFlattenedOneHotPartMap(partHeatmapScores);
80-
const partNumbers = tf.range(0, numParts, 1, 'int32').expandDims(1);
81+
const partNumbers = tf.expandDims(tf.range(0, numParts, 1, 'int32'), 1);
8182

8283
const partMapFlattened =
83-
flattenedMap.matMul(partNumbers as tf.Tensor2D).toInt();
84+
tf.cast(tf.matMul(flattenedMap, partNumbers as tf.Tensor2D), 'int32');
8485

85-
const partMap = partMapFlattened.reshape([partMapHeight, partMapWidth]);
86+
const partMap = tf.reshape(partMapFlattened, [partMapHeight, partMapWidth]);
8687

87-
const partMapShiftedUpForClipping = partMap.add(tf.scalar(1, 'int32'));
88+
const partMapShiftedUpForClipping = tf.add(partMap, tf.scalar(1, 'int32'));
8889

89-
return clipByMask2d(
90+
return tf.sub(clipByMask2d(
9091
partMapShiftedUpForClipping as tf.Tensor2D, segmentationMask)
91-
.sub(tf.scalar(1, 'int32'));
92+
, tf.scalar(1, 'int32'));
9293
});
9394
}
9495

@@ -97,11 +98,11 @@ export function decodeOnlyPartSegmentation(partHeatmapScores: tf.Tensor3D):
9798
const [partMapHeight, partMapWidth, numParts] = partHeatmapScores.shape;
9899
return tf.tidy(() => {
99100
const flattenedMap = toFlattenedOneHotPartMap(partHeatmapScores);
100-
const partNumbers = tf.range(0, numParts, 1, 'int32').expandDims(1);
101+
const partNumbers = tf.expandDims(tf.range(0, numParts, 1, 'int32'), 1);
101102

102103
const partMapFlattened =
103-
flattenedMap.matMul(partNumbers as tf.Tensor2D).toInt();
104+
tf.cast(tf.matMul(flattenedMap, partNumbers as tf.Tensor2D), 'int32');
104105

105-
return partMapFlattened.reshape([partMapHeight, partMapWidth]);
106+
return tf.reshape(partMapFlattened, [partMapHeight, partMapWidth]);
106107
});
107108
}

body-pix/src/mobilenet.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,7 @@ import {BaseModel} from './base_model';
2222
export class MobileNet extends BaseModel {
2323
preprocessInput(input: tf.Tensor3D): tf.Tensor3D {
2424
// Normalize the pixels [0, 255] to be between [-1, 1].
25-
return tf.tidy(() => tf.div(input, 127.5).sub(1.0));
25+
return tf.tidy(() => tf.sub(tf.div(input, 127.5), 1.0));
2626
}
2727

2828
nameOutputResults(results: tf.Tensor3D[]) {

body-pix/src/multi_person/decode_instance_masks.ts

Lines changed: 4 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -26,16 +26,15 @@ import {decodeMultipleMasksWebGl} from './decode_multiple_masks_webgl';
2626
export function toPersonKSegmentation(
2727
segmentation: tf.Tensor2D, k: number): tf.Tensor2D {
2828
return tf.tidy(
29-
() => (segmentation.equal(tf.scalar(k)).toInt() as tf.Tensor2D));
29+
() => (tf.cast(tf.equal(
30+
segmentation, tf.scalar(k)), 'int32') as tf.Tensor2D));
3031
}
3132

3233
export function toPersonKPartSegmentation(
3334
segmentation: tf.Tensor2D, bodyParts: tf.Tensor2D, k: number): tf.Tensor2D {
3435
return tf.tidy(
35-
() => segmentation.equal(tf.scalar(k))
36-
.toInt()
37-
.mul(bodyParts.add(1))
38-
.sub(1));
36+
() => tf.sub(tf.mul(tf.cast(tf.equal(
37+
segmentation, tf.scalar(k)), 'int32'), tf.add(bodyParts, 1)), 1));
3938
}
4039

4140
function isWebGlBackend() {

body-pix/src/multi_person/decode_multiple_masks_webgl.ts

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@
1616
*/
1717

1818
import * as tf from '@tensorflow/tfjs-core';
19+
import * as tf_webgl from '@tensorflow/tfjs-backend-webgl';
1920

2021
import {NUM_KEYPOINTS} from '../keypoints';
2122
import {Padding, Pose} from '../types';
@@ -33,7 +34,7 @@ export function decodeMultipleMasksWebGl(
3334
const [outHeight, outWidth] = longOffsets.shape.slice(0, 2);
3435

3536
const shapedLongOffsets: tf.Tensor4D =
36-
longOffsets.reshape([outHeight, outWidth, 2, NUM_KEYPOINTS]);
37+
tf.reshape(longOffsets, [outHeight, outWidth, 2, NUM_KEYPOINTS]);
3738

3839
// Make pose tensor of shape [MAX_NUM_PEOPLE, NUM_KEYPOINTS, 3] where
3940
// the last 3 coordinates correspond to the score, h and w coordinate of that
@@ -58,7 +59,7 @@ export function decodeMultipleMasksWebGl(
5859

5960
const {top: padT, left: padL} = padding;
6061

61-
const program: tf.webgl.GPGPUProgram = {
62+
const program: tf_webgl.GPGPUProgram = {
6263
variableNames: ['segmentation', 'longOffsets', 'poses'],
6364
outputShape: [origHeight, origWidth],
6465
userCode: `
@@ -154,7 +155,7 @@ export function decodeMultipleMasksWebGl(
154155
}
155156
`
156157
};
157-
const webglBackend = tf.backend() as tf.webgl.MathBackendWebGL;
158+
const webglBackend = tf.backend() as tf_webgl.MathBackendWebGL;
158159
return webglBackend.compileAndRun(
159160
program, [segmentation, shapedLongOffsets, posesTensor]);
160161
}

body-pix/src/resnet.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,7 @@ const imageNetMean = [-123.15, -115.90, -103.06];
2323

2424
export class ResNet extends BaseModel {
2525
preprocessInput(input: tf.Tensor3D): tf.Tensor3D {
26-
return input.add(imageNetMean);
26+
return tf.add(input, imageNetMean);
2727
}
2828

2929
nameOutputResults(results: tf.Tensor3D[]) {

0 commit comments

Comments
 (0)