@tensorflow/tfjs-node
Version:
This repository provides native TensorFlow execution in backend JavaScript applications under the Node.js runtime, accelerated by the TensorFlow C binary under the hood. It provides the same API as [TensorFlow.js](https://js.tensorflow.org/api/latest/).
648 lines (647 loc) • 36.3 kB
JavaScript
"use strict";
/**
* @license
* Copyright 2019 Google LLC. All Rights Reserved.
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
* =============================================================================
*/
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
return new (P || (P = Promise))(function (resolve, reject) {
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
step((generator = generator.apply(thisArg, _arguments || [])).next());
});
};
var __generator = (this && this.__generator) || function (thisArg, body) {
var _ = { label: 0, sent: function() { if (t[0] & 1) throw t[1]; return t[1]; }, trys: [], ops: [] }, f, y, t, g;
return g = { next: verb(0), "throw": verb(1), "return": verb(2) }, typeof Symbol === "function" && (g[Symbol.iterator] = function() { return this; }), g;
function verb(n) { return function (v) { return step([n, v]); }; }
function step(op) {
if (f) throw new TypeError("Generator is already executing.");
while (g && (g = 0, op[0] && (_ = 0)), _) try {
if (f = 1, y && (t = op[0] & 2 ? y["return"] : op[0] ? y["throw"] || ((t = y["return"]) && t.call(y), 0) : y.next) && !(t = t.call(y, op[1])).done) return t;
if (y = 0, t) op = [op[0] & 2, t.value];
switch (op[0]) {
case 0: case 1: t = op; break;
case 4: _.label++; return { value: op[1], done: false };
case 5: _.label++; y = op[1]; op = [0]; continue;
case 7: op = _.ops.pop(); _.trys.pop(); continue;
default:
if (!(t = _.trys, t = t.length > 0 && t[t.length - 1]) && (op[0] === 6 || op[0] === 2)) { _ = 0; continue; }
if (op[0] === 3 && (!t || (op[1] > t[0] && op[1] < t[3]))) { _.label = op[1]; break; }
if (op[0] === 6 && _.label < t[1]) { _.label = t[1]; t = op; break; }
if (t && _.label < t[2]) { _.label = t[2]; _.ops.push(op); break; }
if (t[2]) _.ops.pop();
_.trys.pop(); continue;
}
op = body.call(thisArg, _);
} catch (e) { op = [6, e]; y = 0; } finally { f = t = 0; }
if (op[0] & 5) throw op[1]; return { value: op[0] ? op[1] : void 0, done: true };
}
};
Object.defineProperty(exports, "__esModule", { value: true });
var tfjs_1 = require("@tensorflow/tfjs");
var tf = require("./index");
var nodejs_kernel_backend_1 = require("./nodejs_kernel_backend");
var saved_model_1 = require("./saved_model");
// tslint:disable-next-line:no-require-imports
var messages = require('./proto/api_pb');
describe('SavedModel', function () {
it('deserialize SavedModel pb file', function () { return __awaiter(void 0, void 0, void 0, function () {
var modelMessage, signatureDefMapMessage, inputsMapMessage, inputsMapKeys, inputsMapKey1, inputTensorMessage, outputsMapMessage, outputsMapKeys, outputsMapKey1, outputTensorMessage;
return __generator(this, function (_a) {
switch (_a.label) {
case 0: return [4 /*yield*/, (0, saved_model_1.readSavedModelProto)('./test_objects/saved_model/times_three_float')];
case 1:
modelMessage = _a.sent();
// This SavedModel has one MetaGraph with tag serve
expect(modelMessage.getMetaGraphsList().length).toBe(1);
expect(modelMessage.getMetaGraphsList()[0]
.getMetaInfoDef()
.getTagsList()
.length)
.toBe(1);
expect(modelMessage.getMetaGraphsList()[0].getMetaInfoDef().getTagsList()[0])
.toBe('serve');
signatureDefMapMessage = modelMessage.getMetaGraphsList()[0].getSignatureDefMap();
expect(signatureDefMapMessage.has('serving_default'));
inputsMapMessage = signatureDefMapMessage.get('serving_default').getInputsMap();
expect(inputsMapMessage.getLength()).toBe(1);
inputsMapKeys = inputsMapMessage.keys();
inputsMapKey1 = inputsMapKeys.next();
expect(inputsMapKey1.done).toBe(false);
expect(inputsMapKey1.value).toBe('x');
inputTensorMessage = inputsMapMessage.get(inputsMapKey1.value);
expect(inputTensorMessage.getName()).toBe('serving_default_x:0');
expect((0, saved_model_1.getEnumKeyFromValue)(messages.DataType, inputTensorMessage.getDtype()))
.toBe('DT_FLOAT');
outputsMapMessage = signatureDefMapMessage.get('serving_default').getOutputsMap();
expect(outputsMapMessage.getLength()).toBe(1);
outputsMapKeys = outputsMapMessage.keys();
outputsMapKey1 = outputsMapKeys.next();
expect(outputsMapKey1.done).toBe(false);
expect(outputsMapKey1.value).toBe('output_0');
outputTensorMessage = outputsMapMessage.get(outputsMapKey1.value);
expect(outputTensorMessage.getName()).toBe('StatefulPartitionedCall:0');
expect((0, saved_model_1.getEnumKeyFromValue)(messages.DataType, outputTensorMessage.getDtype()))
.toBe('DT_FLOAT');
return [2 /*return*/];
}
});
}); });
it('get enum key based on value', function () {
var DataType = messages.DataType;
var enumKey0 = (0, saved_model_1.getEnumKeyFromValue)(DataType, 0);
expect(enumKey0).toBe('DT_INVALID');
var enumKey1 = (0, saved_model_1.getEnumKeyFromValue)(DataType, 1);
expect(enumKey1).toBe('DT_FLOAT');
var enumKey2 = (0, saved_model_1.getEnumKeyFromValue)(DataType, 2);
expect(enumKey2).toBe('DT_DOUBLE');
});
it('read non-exist file', function () { return __awaiter(void 0, void 0, void 0, function () {
return __generator(this, function (_a) {
switch (_a.label) {
case 0: return [4 /*yield*/, expectAsync((0, saved_model_1.readSavedModelProto)('/not-exist'))
.toBeRejectedWithError("There is no saved_model.pb file in the directory: /not-exist")];
case 1:
_a.sent();
return [2 /*return*/];
}
});
}); });
it('inspect SavedModel metagraphs', function () { return __awaiter(void 0, void 0, void 0, function () {
var modelInfo;
return __generator(this, function (_a) {
switch (_a.label) {
case 0: return [4 /*yield*/, tf.node.getMetaGraphsFromSavedModel('./test_objects/saved_model/times_three_float')];
case 1:
modelInfo = _a.sent();
/**
* The inspection output should be
* [{
* 'tags': ['serve'],
* 'signatureDefs': {
* '__saved_model_init_op': {
* 'inputs': {},
* 'outputs': {
* '__saved_model_init_op': {
* 'dtype': 'DT_INVALID',
* 'name': 'NoOp',
* 'shape': []
* }
* }
* },
* 'serving_default': {
* 'inputs': {
* 'x': {
* 'dtype': 'DT_FLOAT',
* 'name': 'serving_default_x:0',
* 'shape':[]
* }
* },
* 'outputs': {
* 'output_0': {
* 'dtype': 'DT_FLOAT',
* 'name': 'StatefulPartitionedCall:0',
* 'shape': []
* }
* }
* }
* }
* }]
*/
expect(modelInfo.length).toBe(1);
expect(modelInfo[0].tags.length).toBe(1);
expect(modelInfo[0].tags[0]).toBe('serve');
expect(Object.keys(modelInfo[0].signatureDefs).length).toBe(1);
expect(Object.keys(modelInfo[0].signatureDefs)[0]).toBe('serving_default');
expect(Object.keys(modelInfo[0].signatureDefs['serving_default'].inputs)
.length)
.toBe(1);
expect(modelInfo[0].signatureDefs['serving_default'].inputs['x'].name)
.toBe('serving_default_x:0');
expect(modelInfo[0].signatureDefs['serving_default'].inputs['x'].dtype)
.toBe('float32');
expect(Object.keys(modelInfo[0].signatureDefs['serving_default'].outputs)
.length)
.toBe(1);
expect(modelInfo[0].signatureDefs['serving_default'].outputs['output_0'].name)
.toBe('StatefulPartitionedCall:0');
expect(modelInfo[0].signatureDefs['serving_default'].outputs['output_0'].dtype)
.toBe('float32');
return [2 /*return*/];
}
});
}); });
it('get input and output node names from SavedModel metagraphs', function () { return __awaiter(void 0, void 0, void 0, function () {
var modelInfo, signature;
return __generator(this, function (_a) {
switch (_a.label) {
case 0: return [4 /*yield*/, tf.node.getMetaGraphsFromSavedModel('./test_objects/saved_model/times_three_float')];
case 1:
modelInfo = _a.sent();
signature = (0, saved_model_1.getSignatureDefEntryFromMetaGraphInfo)(modelInfo, ['serve'], 'serving_default');
expect(Object.keys(signature).length).toBe(2);
expect(signature.inputs['x'].name).toBe('serving_default_x:0');
expect(signature.outputs['output_0'].name)
.toBe('StatefulPartitionedCall:0');
return [2 /*return*/];
}
});
}); });
it('load TFSavedModel', function () { return __awaiter(void 0, void 0, void 0, function () {
var loadSavedModelMetaGraphSpy, model;
return __generator(this, function (_a) {
switch (_a.label) {
case 0:
loadSavedModelMetaGraphSpy = spyOn((0, nodejs_kernel_backend_1.nodeBackend)(), 'loadSavedModelMetaGraph').and.callThrough();
expect(loadSavedModelMetaGraphSpy).toHaveBeenCalledTimes(0);
return [4 /*yield*/, tf.node.loadSavedModel('./test_objects/saved_model/times_three_float', ['serve'], 'serving_default')];
case 1:
model = _a.sent();
expect(loadSavedModelMetaGraphSpy).toHaveBeenCalledTimes(1);
model.dispose();
return [2 /*return*/];
}
});
}); });
it('load TFSavedModel with wrong tags throw exception', function () { return __awaiter(void 0, void 0, void 0, function () {
return __generator(this, function (_a) {
switch (_a.label) {
case 0: return [4 /*yield*/, expectAsync(tf.node.loadSavedModel('./test_objects/saved_model/times_three_float', ['serve', 'gpu'], 'serving_default'))
.toBeRejectedWithError('The SavedModel does not have tags: serve,gpu')];
case 1:
_a.sent();
return [2 /*return*/];
}
});
}); });
it('load TFSavedModel with wrong signature throw exception', function () { return __awaiter(void 0, void 0, void 0, function () {
return __generator(this, function (_a) {
switch (_a.label) {
case 0: return [4 /*yield*/, expectAsync(tf.node.loadSavedModel('./test_objects/saved_model/times_three_float', ['serve'], 'wrong_signature')).toBeRejectedWithError('The SavedModel does not have signature: wrong_signature')];
case 1:
_a.sent();
return [2 /*return*/];
}
});
}); });
it('load TFSavedModel and delete', function () { return __awaiter(void 0, void 0, void 0, function () {
var loadSavedModelMetaGraphSpy, deleteSavedModelSpy, model;
return __generator(this, function (_a) {
switch (_a.label) {
case 0:
expect(tf.node.getNumOfSavedModels()).toBe(0);
loadSavedModelMetaGraphSpy = spyOn((0, nodejs_kernel_backend_1.nodeBackend)(), 'loadSavedModelMetaGraph').and.callThrough();
deleteSavedModelSpy = spyOn((0, nodejs_kernel_backend_1.nodeBackend)(), 'deleteSavedModel').and.callThrough();
expect(loadSavedModelMetaGraphSpy).toHaveBeenCalledTimes(0);
expect(deleteSavedModelSpy).toHaveBeenCalledTimes(0);
return [4 /*yield*/, tf.node.loadSavedModel('./test_objects/saved_model/times_three_float', ['serve'], 'serving_default')];
case 1:
model = _a.sent();
expect(loadSavedModelMetaGraphSpy).toHaveBeenCalledTimes(1);
expect(deleteSavedModelSpy).toHaveBeenCalledTimes(0);
expect(tf.node.getNumOfSavedModels()).toBe(1);
model.dispose();
expect(loadSavedModelMetaGraphSpy).toHaveBeenCalledTimes(1);
expect(deleteSavedModelSpy).toHaveBeenCalledTimes(1);
expect(tf.node.getNumOfSavedModels()).toBe(0);
return [2 /*return*/];
}
});
}); });
it('delete TFSavedModel multiple times throw exception', function () { return __awaiter(void 0, void 0, void 0, function () {
var model;
return __generator(this, function (_a) {
switch (_a.label) {
case 0: return [4 /*yield*/, tf.node.loadSavedModel('./test_objects/saved_model/times_three_float', ['serve'], 'serving_default')];
case 1:
model = _a.sent();
model.dispose();
expect(function () { return model.dispose(); })
.toThrowError('This SavedModel has already been deleted.');
return [2 /*return*/];
}
});
}); });
it('load multiple signatures from the same metagraph only call binding once', function () { return __awaiter(void 0, void 0, void 0, function () {
var backend, loadSavedModelMetaGraphSpy, model1, model2;
return __generator(this, function (_a) {
switch (_a.label) {
case 0:
expect(tf.node.getNumOfSavedModels()).toBe(0);
backend = (0, nodejs_kernel_backend_1.nodeBackend)();
loadSavedModelMetaGraphSpy = spyOn(backend, 'loadSavedModelMetaGraph').and.callThrough();
expect(loadSavedModelMetaGraphSpy).toHaveBeenCalledTimes(0);
return [4 /*yield*/, tf.node.loadSavedModel('./test_objects/saved_model/module_with_multiple_signatures', ['serve'], 'serving_default')];
case 1:
model1 = _a.sent();
expect(loadSavedModelMetaGraphSpy).toHaveBeenCalledTimes(1);
expect(tf.node.getNumOfSavedModels()).toBe(1);
return [4 /*yield*/, tf.node.loadSavedModel('./test_objects/saved_model/module_with_multiple_signatures', ['serve'], 'timestwo')];
case 2:
model2 = _a.sent();
expect(loadSavedModelMetaGraphSpy).toHaveBeenCalledTimes(1);
expect(tf.node.getNumOfSavedModels()).toBe(1);
model1.dispose();
expect(tf.node.getNumOfSavedModels()).toBe(1);
model2.dispose();
expect(loadSavedModelMetaGraphSpy).toHaveBeenCalledTimes(1);
expect(tf.node.getNumOfSavedModels()).toBe(0);
return [2 /*return*/];
}
});
}); });
it('load signature after delete call binding', function () { return __awaiter(void 0, void 0, void 0, function () {
var backend, spyOnCallBindingLoad, spyOnNodeBackendDelete, model1, model2;
return __generator(this, function (_a) {
switch (_a.label) {
case 0:
backend = (0, nodejs_kernel_backend_1.nodeBackend)();
spyOnCallBindingLoad = spyOn(backend, 'loadSavedModelMetaGraph').and.callThrough();
spyOnNodeBackendDelete = spyOn(backend, 'deleteSavedModel').and.callThrough();
expect(spyOnCallBindingLoad).toHaveBeenCalledTimes(0);
expect(spyOnNodeBackendDelete).toHaveBeenCalledTimes(0);
return [4 /*yield*/, tf.node.loadSavedModel('./test_objects/saved_model/module_with_multiple_signatures', ['serve'], 'serving_default')];
case 1:
model1 = _a.sent();
expect(spyOnCallBindingLoad).toHaveBeenCalledTimes(1);
expect(spyOnNodeBackendDelete).toHaveBeenCalledTimes(0);
model1.dispose();
expect(spyOnNodeBackendDelete).toHaveBeenCalledTimes(1);
expect(spyOnCallBindingLoad).toHaveBeenCalledTimes(1);
return [4 /*yield*/, tf.node.loadSavedModel('./test_objects/saved_model/module_with_multiple_signatures', ['serve'], 'timestwo')];
case 2:
model2 = _a.sent();
expect(spyOnCallBindingLoad).toHaveBeenCalledTimes(2);
expect(spyOnNodeBackendDelete).toHaveBeenCalledTimes(1);
model2.dispose();
expect(spyOnCallBindingLoad).toHaveBeenCalledTimes(2);
expect(spyOnNodeBackendDelete).toHaveBeenCalledTimes(2);
return [2 /*return*/];
}
});
}); });
it('throw error when input tensors do not match input ops', function () { return __awaiter(void 0, void 0, void 0, function () {
var model, input1, input2;
return __generator(this, function (_a) {
switch (_a.label) {
case 0: return [4 /*yield*/, tf.node.loadSavedModel('./test_objects/saved_model/times_three_float', ['serve'], 'serving_default')];
case 1:
model = _a.sent();
input1 = tf.tensor1d([1.0, 2, 3]);
input2 = tf.tensor1d([1.0, 2, 3]);
expect(function () { return model.predict([input1, input2]); }).toThrowError('Length of input op names (1) does not match the ' +
'length of input tensors (2).');
model.dispose();
return [2 /*return*/];
}
});
}); });
it('execute model float times three', function () { return __awaiter(void 0, void 0, void 0, function () {
var model, input, output, _a, _b, _c;
return __generator(this, function (_d) {
switch (_d.label) {
case 0: return [4 /*yield*/, tf.node.loadSavedModel('./test_objects/saved_model/times_three_float', ['serve'], 'serving_default')];
case 1:
model = _d.sent();
input = tf.tensor1d([1.0, 2, 3]);
output = model.predict(input);
expect(output.shape).toEqual(input.shape);
expect(output.dtype).toBe(input.dtype);
expect(output.dtype).toBe('float32');
_b = (_a = tfjs_1.test_util).expectArraysClose;
return [4 /*yield*/, output.data()];
case 2:
_c = [_d.sent()];
return [4 /*yield*/, input.mul(3).data()];
case 3:
_b.apply(_a, _c.concat([_d.sent()]));
model.dispose();
return [2 /*return*/];
}
});
}); });
it('execute model with tensor array as input', function () { return __awaiter(void 0, void 0, void 0, function () {
var model, input, outputArray, output, _a, _b;
return __generator(this, function (_c) {
switch (_c.label) {
case 0: return [4 /*yield*/, tf.node.loadSavedModel('./test_objects/saved_model/times_three_float', ['serve'], 'serving_default')];
case 1:
model = _c.sent();
input = tf.tensor1d([1.0, 2, 3]);
outputArray = model.predict([input]);
expect(outputArray.length).toBe(1);
output = outputArray[0];
expect(output.shape).toEqual(input.shape);
expect(output.dtype).toBe(input.dtype);
expect(output.dtype).toBe('float32');
_b = (_a = tfjs_1.test_util).expectArraysClose;
return [4 /*yield*/, output.data()];
case 2:
_b.apply(_a, [_c.sent(), [3.0, 6.0, 9.0]]);
model.dispose();
return [2 /*return*/];
}
});
}); });
it('execute model with tensor map as input', function () { return __awaiter(void 0, void 0, void 0, function () {
var model, input, outputMap, output, _a, _b;
return __generator(this, function (_c) {
switch (_c.label) {
case 0: return [4 /*yield*/, tf.node.loadSavedModel('./test_objects/saved_model/times_three_float', ['serve'], 'serving_default')];
case 1:
model = _c.sent();
input = tf.tensor1d([1.0, 2, 3]);
outputMap = model.predict({ 'x': input });
output = outputMap['output_0'];
expect(output.shape).toEqual(input.shape);
expect(output.dtype).toBe(input.dtype);
expect(output.dtype).toBe('float32');
_b = (_a = tfjs_1.test_util).expectArraysClose;
return [4 /*yield*/, output.data()];
case 2:
_b.apply(_a, [_c.sent(), [3.0, 6.0, 9.0]]);
model.dispose();
return [2 /*return*/];
}
});
}); });
it('execute model with wrong tensor name', function () { return __awaiter(void 0, void 0, void 0, function () {
var model, input;
return __generator(this, function (_a) {
switch (_a.label) {
case 0: return [4 /*yield*/, tf.node.loadSavedModel('./test_objects/saved_model/times_three_float', ['serve'], 'serving_default')];
case 1:
model = _a.sent();
input = tf.tensor1d([1.0, 2, 3]);
expect(function () { return model.predict({ 'xyz': input }); }).toThrowError('The model signatureDef input names are x, however ' +
'the provided input names are xyz.');
model.dispose();
return [2 /*return*/];
}
});
}); });
it('execute model with uint8 input', function () { return __awaiter(void 0, void 0, void 0, function () {
var model, input, output, _a, _b;
return __generator(this, function (_c) {
switch (_c.label) {
case 0: return [4 /*yield*/, tf.node.loadSavedModel('./test_objects/saved_model/uint8_multiply', ['serve'], 'serving_default')];
case 1:
model = _c.sent();
input = tf.scalar(3, 'int32');
output = model.predict(input);
expect(output.shape).toEqual([]);
expect(output.dtype).toBe('int32');
_b = (_a = tfjs_1.test_util).expectArraysClose;
return [4 /*yield*/, output.data()];
case 2:
_b.apply(_a, [_c.sent(), [18]]);
model.dispose();
return [2 /*return*/];
}
});
}); });
it('execute model with int64 input', function () { return __awaiter(void 0, void 0, void 0, function () {
var model, input, output, data;
return __generator(this, function (_a) {
switch (_a.label) {
case 0: return [4 /*yield*/, tf.node.loadSavedModel('./test_objects/saved_model/int64_multiply', ['serve'], 'serving_default')];
case 1:
model = _a.sent();
input = tf.tensor1d([3, 4], 'int32');
output = model.predict(input);
expect(output.shape).toEqual([2]);
expect(output.dtype).toBe('int32');
return [4 /*yield*/, output.data()];
case 2:
data = _a.sent();
expect(Number(data[0])).toEqual(18);
expect(Number(data[1])).toEqual(24);
model.dispose();
return [2 /*return*/];
}
});
}); });
it('execute model int times two', function () { return __awaiter(void 0, void 0, void 0, function () {
var model, input, output, _a, _b;
return __generator(this, function (_c) {
switch (_c.label) {
case 0: return [4 /*yield*/, tf.node.loadSavedModel('./test_objects/saved_model/times_two_int', ['serve'], 'serving_default')];
case 1:
model = _c.sent();
input = tf.tensor1d([1, 2, 3], 'int32');
output = model.predict(input);
expect(output.shape).toEqual(input.shape);
expect(output.dtype).toBe(input.dtype);
_b = (_a = tfjs_1.test_util).expectArraysClose;
return [4 /*yield*/, output.data()];
case 2:
_b.apply(_a, [_c.sent(), [2, 4, 6]]);
model.dispose();
return [2 /*return*/];
}
});
}); });
it('execute multiple signatures from the same model', function () { return __awaiter(void 0, void 0, void 0, function () {
var backend, loadSavedModelMetaGraphSpy, model1, input1, output1, _a, _b, model2, input2, output2, _c, _d;
return __generator(this, function (_e) {
switch (_e.label) {
case 0:
backend = (0, nodejs_kernel_backend_1.nodeBackend)();
loadSavedModelMetaGraphSpy = spyOn(backend, 'loadSavedModelMetaGraph').and.callThrough();
expect(loadSavedModelMetaGraphSpy).toHaveBeenCalledTimes(0);
return [4 /*yield*/, tf.node.loadSavedModel('./test_objects/saved_model/module_with_multiple_signatures', ['serve'], 'serving_default')];
case 1:
model1 = _e.sent();
expect(loadSavedModelMetaGraphSpy).toHaveBeenCalledTimes(1);
input1 = tf.tensor1d([1, 2, 3]);
output1 = model1.predict(input1);
expect(output1.shape).toEqual(input1.shape);
expect(output1.dtype).toBe(input1.dtype);
_b = (_a = tfjs_1.test_util).expectArraysClose;
return [4 /*yield*/, output1.data()];
case 2:
_b.apply(_a, [_e.sent(), [3.0, 6.0, 9.0]]);
expect(loadSavedModelMetaGraphSpy).toHaveBeenCalledTimes(1);
return [4 /*yield*/, tf.node.loadSavedModel('./test_objects/saved_model/module_with_multiple_signatures', ['serve'], 'timestwo')];
case 3:
model2 = _e.sent();
expect(loadSavedModelMetaGraphSpy).toHaveBeenCalledTimes(1);
input2 = tf.tensor1d([1, 2, 3]);
output2 = model2.predict(input2);
expect(output2.shape).toEqual(input2.shape);
expect(output2.dtype).toBe(input2.dtype);
_d = (_c = tfjs_1.test_util).expectArraysClose;
return [4 /*yield*/, output2.data()];
case 4:
_d.apply(_c, [_e.sent(), [2.0, 4.0, 6.0]]);
expect(loadSavedModelMetaGraphSpy).toHaveBeenCalledTimes(1);
model1.dispose();
model2.dispose();
return [2 /*return*/];
}
});
}); });
it('execute model with single input and multiple outputs', function () { return __awaiter(void 0, void 0, void 0, function () {
var model, input, output, output1, output2, _a, _b, _c, _d;
return __generator(this, function (_e) {
switch (_e.label) {
case 0: return [4 /*yield*/, tf.node.loadSavedModel('./test_objects/saved_model/model_single_input_multi_output', ['serve'], 'serving_default')];
case 1:
model = _e.sent();
input = tf.tensor1d([1, 2, 3], 'int32');
output = model.predict(input);
output1 = output[0];
output2 = output[1];
expect(output1.shape).toEqual(input.shape);
expect(output1.dtype).toBe(input.dtype);
expect(output2.shape).toEqual(input.shape);
expect(output2.dtype).toBe(input.dtype);
_b = (_a = tfjs_1.test_util).expectArraysClose;
return [4 /*yield*/, output1.data()];
case 2:
_b.apply(_a, [_e.sent(), [2, 4, 6]]);
_d = (_c = tfjs_1.test_util).expectArraysClose;
return [4 /*yield*/, output2.data()];
case 3:
_d.apply(_c, [_e.sent(), [1, 2, 3]]);
model.dispose();
return [2 /*return*/];
}
});
}); });
it('execute model with multiple inputs and multiple outputs', function () { return __awaiter(void 0, void 0, void 0, function () {
var model, input1, input2, output, output1, output2, _a, _b, _c, _d;
return __generator(this, function (_e) {
switch (_e.label) {
case 0: return [4 /*yield*/, tf.node.loadSavedModel('./test_objects/saved_model/model_multi_output', ['serve'], 'serving_default')];
case 1:
model = _e.sent();
input1 = tf.tensor1d([1, 2, 3], 'int32');
input2 = tf.tensor1d([1, 2, 3], 'int32');
output = model.predict({ 'x': input1, 'y': input2 });
output1 = output['output_0'];
output2 = output['output_1'];
expect(output1.shape).toEqual(input1.shape);
expect(output1.dtype).toBe(input1.dtype);
expect(output2.shape).toEqual(input2.shape);
expect(output2.dtype).toBe(input2.dtype);
_b = (_a = tfjs_1.test_util).expectArraysClose;
return [4 /*yield*/, output1.data()];
case 2:
_b.apply(_a, [_e.sent(), [2, 4, 6]]);
_d = (_c = tfjs_1.test_util).expectArraysClose;
return [4 /*yield*/, output2.data()];
case 3:
_d.apply(_c, [_e.sent(), [1, 2, 3]]);
model.dispose();
return [2 /*return*/];
}
});
}); });
it('load multiple models', function () { return __awaiter(void 0, void 0, void 0, function () {
var model1, model2;
return __generator(this, function (_a) {
switch (_a.label) {
case 0:
expect(tf.node.getNumOfSavedModels()).toBe(0);
return [4 /*yield*/, tf.node.loadSavedModel('./test_objects/saved_model/module_with_multiple_signatures', ['serve'], 'serving_default')];
case 1:
model1 = _a.sent();
expect(tf.node.getNumOfSavedModels()).toBe(1);
return [4 /*yield*/, tf.node.loadSavedModel('./test_objects/saved_model/model_multi_output', ['serve'], 'serving_default')];
case 2:
model2 = _a.sent();
expect(tf.node.getNumOfSavedModels()).toBe(2);
model1.dispose();
expect(tf.node.getNumOfSavedModels()).toBe(1);
model2.dispose();
expect(tf.node.getNumOfSavedModels()).toBe(0);
return [2 /*return*/];
}
});
}); });
it('return inputs and outputs', function () { return __awaiter(void 0, void 0, void 0, function () {
var model;
return __generator(this, function (_a) {
switch (_a.label) {
case 0: return [4 /*yield*/, tf.node.loadSavedModel('./test_objects/saved_model/model_multi_output', ['serve'], 'serving_default')];
case 1:
model = _a.sent();
expect(model.inputs.length).toBe(2);
expect(model.outputs.length).toBe(2);
expect(model.inputs[0].name).toBe('serving_default_x');
expect(model.inputs[0].dtype).toBe('int32');
expect(model.inputs[0].tfDtype).toBe('DT_INT32');
expect(model.inputs[0].shape.length).toBe(0);
expect(model.inputs[1].name).toBe('serving_default_y');
expect(model.inputs[1].dtype).toBe('int32');
expect(model.inputs[1].tfDtype).toBe('DT_INT32');
expect(model.inputs[1].shape.length).toBe(0);
expect(model.outputs[0].name).toBe('StatefulPartitionedCall');
expect(model.outputs[0].dtype).toBe('int32');
expect(model.outputs[0].tfDtype).toBe('DT_INT32');
expect(model.outputs[0].shape.length).toBe(0);
expect(model.outputs[1].name).toBe('StatefulPartitionedCall:1');
expect(model.outputs[1].dtype).toBe('int32');
expect(model.outputs[1].tfDtype).toBe('DT_INT32');
expect(model.outputs[1].shape.length).toBe(0);
model.dispose();
return [2 /*return*/];
}
});
}); });
});