@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/).
1,023 lines (1,022 loc) • 81.7 kB
JavaScript
"use strict";
/**
* @license
* Copyright 2018 Google Inc. 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 __extends = (this && this.__extends) || (function () {
var extendStatics = function (d, b) {
extendStatics = Object.setPrototypeOf ||
({ __proto__: [] } instanceof Array && function (d, b) { d.__proto__ = b; }) ||
function (d, b) { for (var p in b) if (b.hasOwnProperty(p)) d[p] = b[p]; };
return extendStatics(d, b);
};
return function (d, b) {
extendStatics(d, b);
function __() { this.constructor = d; }
d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __());
};
})();
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
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) : new P(function (resolve) { resolve(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 (_) 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 tfc = require("@tensorflow/tfjs-core");
var tfjs_core_1 = require("@tensorflow/tfjs-core");
// tslint:disable-next-line: no-imports-from-dist
var backend_1 = require("@tensorflow/tfjs-core/dist/backends/backend");
var util_1 = require("util");
var int64_tensors_1 = require("./int64_tensors");
var NodeJSKernelBackend = /** @class */ (function (_super) {
__extends(NodeJSKernelBackend, _super);
function NodeJSKernelBackend(binding, packageName) {
var _this = _super.call(this) || this;
_this.binding = binding;
_this.isGPUPackage = packageName === '@tensorflow/tfjs-node-gpu';
_this.isUsingGpuDevice = _this.binding.isUsingGpuDevice();
_this.tensorMap = new tfc.DataStorage(_this, tfc.engine());
return _this;
}
NodeJSKernelBackend.prototype.getDTypeInteger = function (dtype) {
switch (dtype) {
case 'float32':
return this.binding.TF_FLOAT;
case 'int32':
return this.binding.TF_INT32;
case 'bool':
return this.binding.TF_BOOL;
case 'complex64':
return this.binding.TF_COMPLEX64;
case 'string':
return this.binding.TF_STRING;
default:
throw new Error("Unsupported DType: " + dtype);
}
};
NodeJSKernelBackend.prototype.typeAttributeFromTensor = function (value) {
return this.getDTypeInteger(value.dtype);
};
// Creates a new Tensor and maps the dataId to the passed in ID.
NodeJSKernelBackend.prototype.createOutputTensor = function (metadata) {
var newId = {};
this.tensorMap.set(newId, {
shape: metadata.shape,
dtype: metadata.dtype,
id: metadata.id,
values: null
});
var dtype;
switch (metadata.dtype) {
case this.binding.TF_FLOAT:
dtype = 'float32';
break;
case this.binding.TF_INT32:
dtype = 'int32';
break;
case this.binding.TF_BOOL:
dtype = 'bool';
break;
case this.binding.TF_COMPLEX64:
dtype = 'complex64';
break;
case this.binding.TF_STRING:
dtype = 'string';
break;
case this.binding.TF_RESOURCE:
// NOTE(cais): We currently represent resource-type Tensors
// as string of ubytes.
dtype = 'string';
break;
case this.binding.TF_UINT8:
// TensorFlow uses UINT8 as dtype for image tensor. UINT8 is not
// supported in TFJS yet, cast it to int32.
dtype = 'int32';
break;
default:
throw new Error("Unknown dtype enum " + metadata.dtype);
}
return tfc.engine().makeTensorFromDataId(newId, metadata.shape, dtype);
};
// Prepares Tensor instances for Op execution.
NodeJSKernelBackend.prototype.getInputTensorIds = function (tensors) {
var ids = [];
for (var i = 0; i < tensors.length; i++) {
if (tensors[i] instanceof int64_tensors_1.Int64Scalar) {
// Then `tensors[i]` is a Int64Scalar, which we currently represent
// using an `Int32Array`.
var value = tensors[i].valueArray;
var id = this.binding.createTensor([], this.binding.TF_INT64, value);
ids.push(id);
}
else {
var info = this.tensorMap.get(tensors[i].dataId);
// TODO - what about ID in this case? Handle in write()??
if (info.values != null) {
// Values were delayed to write into the TensorHandle. Do that before
// Op execution and clear stored values.
info.id =
this.binding.createTensor(info.shape, info.dtype, info.values);
info.values = null;
}
ids.push(info.id);
}
}
return ids;
};
NodeJSKernelBackend.prototype.createReductionOpAttrs = function (tensor) {
return [
{ name: 'keep_dims', type: this.binding.TF_ATTR_BOOL, value: false },
createTypeOpAttr('T', tensor.dtype), createTypeOpAttr('Tidx', 'int32')
];
};
NodeJSKernelBackend.prototype.executeSingleInput = function (name, input) {
var opAttrs = [createTypeOpAttr('T', input.dtype)];
return this.executeSingleOutput(name, opAttrs, [input]);
};
NodeJSKernelBackend.prototype.floatPrecision = function () {
return 32;
};
NodeJSKernelBackend.prototype.epsilon = function () {
return backend_1.EPSILON_FLOAT32;
};
/**
* Executes a TensorFlow Eager Op that provides one output Tensor.
* @param name The name of the Op to execute.
* @param opAttrs The list of Op attributes required to execute.
* @param inputs The list of input Tensors for the Op.
* @return A resulting Tensor from Op execution.
*/
NodeJSKernelBackend.prototype.executeSingleOutput = function (name, opAttrs, inputs) {
var outputMetadata = this.binding.executeOp(name, opAttrs, this.getInputTensorIds(inputs), 1);
return this.createOutputTensor(outputMetadata[0]);
};
/**
* Executes a TensorFlow Eager Op that provides multiple output Tensors.
* @param name The name of the Op to execute.
* @param opAttrs The list of Op attributes required to execute.
* @param inputs The list of input Tensors for the Op.
* @param numOutputs The number of output Tensors for Op execution.
* @return A resulting Tensor array from Op execution.
*/
NodeJSKernelBackend.prototype.executeMultipleOutputs = function (name, opAttrs, inputs, numOutputs) {
var _this = this;
var outputMetadata = this.binding.executeOp(name, opAttrs, this.getInputTensorIds(inputs), numOutputs);
return outputMetadata.map(function (m) { return _this.createOutputTensor(m); });
};
NodeJSKernelBackend.prototype.numDataIds = function () {
return this.tensorMap.numDataIds();
};
NodeJSKernelBackend.prototype.dispose = function () { };
NodeJSKernelBackend.prototype.read = function (dataId) {
return __awaiter(this, void 0, void 0, function () {
return __generator(this, function (_a) {
return [2 /*return*/, this.readSync(dataId)];
});
});
};
NodeJSKernelBackend.prototype.readSync = function (dataId) {
if (!this.tensorMap.has(dataId)) {
throw new Error("Tensor " + dataId + " was not registered!");
}
var info = this.tensorMap.get(dataId);
if (info.values != null) {
return info.values;
}
else {
return this.binding.tensorDataSync(info.id);
}
};
NodeJSKernelBackend.prototype.disposeData = function (dataId) {
// No-op if already disposed.
if (!this.tensorMap.has(dataId)) {
return;
}
var id = this.tensorMap.get(dataId).id;
if (id != null && id >= 0) {
this.binding.deleteTensor(id);
}
this.tensorMap.delete(dataId);
};
NodeJSKernelBackend.prototype.move = function (dataId, values, shape, dtype) {
this.tensorMap.set(dataId, { shape: shape, dtype: getTFDType(dtype), values: values, id: -1 });
};
NodeJSKernelBackend.prototype.write = function (values, shape, dtype) {
var dataId = {};
this.move(dataId, values, shape, dtype);
return dataId;
};
NodeJSKernelBackend.prototype.fill = function (shape, value, dtype) {
// TODO(cais, nkreeger): Investigate whether this can be made into
// a dtype helper method. The underlying op kernel doesn't accept undefined
// or null dtype.
if (dtype == null) {
if (typeof value === 'number') {
dtype = 'float32';
}
else {
dtype = 'string';
}
}
var shapeTensor = tfjs_core_1.tensor1d(shape, 'int32');
var valueTensor = tfjs_core_1.scalar(value, dtype);
var opAttrs = [
{
name: 'T',
type: this.binding.TF_ATTR_TYPE,
value: this.getDTypeInteger(dtype)
},
{
name: 'index_type',
type: this.binding.TF_ATTR_TYPE,
value: this.binding.TF_INT32
}
];
return this.executeSingleOutput('Fill', opAttrs, [shapeTensor, valueTensor]);
};
NodeJSKernelBackend.prototype.onesLike = function (x) {
var opAttrs = [{
name: 'T',
type: this.binding.TF_ATTR_TYPE,
value: this.getDTypeInteger(x.dtype)
}];
return this.executeSingleOutput('OnesLike', opAttrs, [x]);
};
NodeJSKernelBackend.prototype.zerosLike = function (x) {
var opAttrs = [{
name: 'T',
type: this.binding.TF_ATTR_TYPE,
value: this.getDTypeInteger(x.dtype)
}];
return this.executeSingleOutput('ZerosLike', opAttrs, [x]);
};
NodeJSKernelBackend.prototype.stridedSlice = function (x, begin, end, strides) {
var beginTensor = tfjs_core_1.tensor1d(begin, 'int32');
for (var axis = 0; axis < end.length; axis++) {
// Unlike Numpy, when the strides are negative, TF C uses -n-1 instead of
// -1 as the "end" in order to include the first element.
if (strides[axis] < 0 && end[axis] === -1) {
end[axis] -= x.shape[axis];
}
}
var endTensor = tfjs_core_1.tensor1d(end, 'int32');
var stridesTensor = tfjs_core_1.tensor1d(strides, 'int32');
// All of the masks have already been accounted for in the high level op,
// so the backend does NOT need to deal with masks.
var opAttrs = [
createTypeOpAttr('T', x.dtype), createTypeOpAttr('Index', 'int32'),
{ name: 'begin_mask', type: this.binding.TF_ATTR_INT, value: 0 },
{ name: 'end_mask', type: this.binding.TF_ATTR_INT, value: 0 },
{ name: 'ellipsis_mask', type: this.binding.TF_ATTR_INT, value: 0 },
{ name: 'new_axis_mask', type: this.binding.TF_ATTR_INT, value: 0 },
{ name: 'shrink_axis_mask', type: this.binding.TF_ATTR_INT, value: 0 }
];
return this.executeSingleOutput('StridedSlice', opAttrs, [x, beginTensor, endTensor, stridesTensor]);
};
NodeJSKernelBackend.prototype.unstack = function (x, axis) {
if (axis >= x.shape.length) {
throw new Error("Invalid axis supplied: " + axis + " shape length: " + x.shape.length);
}
var num = x.shape[axis];
var opAttrs = [
{ name: 'num', type: this.binding.TF_ATTR_INT, value: num },
createTypeOpAttr('T', x.dtype),
{ name: 'axis', type: this.binding.TF_ATTR_INT, value: axis }
];
return this.executeMultipleOutputs('Unpack', opAttrs, [x], num);
};
NodeJSKernelBackend.prototype.batchMatMul = function (a, b, transposeA, transposeB) {
var opAttrs = [
createTypeOpAttr('T', a.dtype),
{ name: 'adj_x', type: this.binding.TF_ATTR_BOOL, value: transposeA },
{ name: 'adj_y', type: this.binding.TF_ATTR_BOOL, value: transposeB }
];
return this.executeSingleOutput('BatchMatMul', opAttrs, [a, b]);
};
NodeJSKernelBackend.prototype.applyActivation = function (input, activation, preluActivationWeights) {
var result = input;
if (activation != null) {
if (activation === 'linear') {
// No-op
}
else if (activation === 'relu') {
result = this.relu(result);
}
else if (activation === 'prelu') {
result = this.prelu(result, preluActivationWeights);
}
else if (activation === 'elu') {
result = this.elu(result);
}
else if (activation === 'relu6') {
result = this.relu6(result);
}
else {
throw new Error("Activation: " + activation + " has not been implemented for the Node.js backend");
}
}
return result;
};
NodeJSKernelBackend.prototype.fusedConv2d = function (_a) {
var input = _a.input, filter = _a.filter, convInfo = _a.convInfo, bias = _a.bias, activation = _a.activation, preluActivationWeights = _a.preluActivationWeights;
var result = this.conv2d(input, filter, convInfo);
if (bias != null) {
result = this.add(result, bias);
}
result = this.applyActivation(result, activation, preluActivationWeights);
return result;
};
NodeJSKernelBackend.prototype.fusedBatchMatMul = function (_a) {
var a = _a.a, b = _a.b, transposeA = _a.transposeA, transposeB = _a.transposeB, bias = _a.bias, activation = _a.activation, preluActivationWeights = _a.preluActivationWeights;
// Core TensorFlow does not have a fused BatchMatMul op. Combine calls to
// achieve the same results:
var result = this.batchMatMul(a, b, transposeA, transposeB);
if (bias != null) {
result = this.add(result, bias);
}
result = this.applyActivation(result, activation, preluActivationWeights);
return result;
};
NodeJSKernelBackend.prototype.slice = function (x, begin, size) {
var opAttrs = [createTypeOpAttr('T', x.dtype), createTypeOpAttr('Index', 'int32')];
// Bind tensor values
var beginTensor = tfjs_core_1.tensor1d(begin, 'int32');
var sizeTensor = tfjs_core_1.tensor1d(size, 'int32');
return this.executeSingleOutput('Slice', opAttrs, [x, beginTensor, sizeTensor]);
};
NodeJSKernelBackend.prototype.reverse = function (a, axis) {
var opAttrs = [createTypeOpAttr('Tidx', 'int32'), createTypeOpAttr('T', a.dtype)];
var axisTensor = tfjs_core_1.tensor1d(axis, 'int32');
return this.executeSingleOutput('ReverseV2', opAttrs, [a, axisTensor]);
};
NodeJSKernelBackend.prototype.concat = function (tensors, axis) {
var opAttrs = [
{ name: 'N', type: this.binding.TF_ATTR_INT, value: tensors.length }, {
name: 'Tidx',
type: this.binding.TF_ATTR_TYPE,
value: this.binding.TF_INT32
},
createTensorsTypeOpAttr('T', tensors)
];
var inputs = Array.from(tensors);
inputs.push(tfjs_core_1.scalar(axis, 'int32'));
return this.executeSingleOutput('ConcatV2', opAttrs, inputs);
};
NodeJSKernelBackend.prototype.neg = function (a) {
return this.executeSingleInput('Neg', a);
};
NodeJSKernelBackend.prototype.diag = function (x) {
return this.executeSingleInput('Diag', x);
};
NodeJSKernelBackend.prototype.add = function (a, b) {
var opAttrs = [createTypeOpAttr('T', tfjs_core_1.backend_util.upcastType(a.dtype, b.dtype))];
return this.executeSingleOutput('Add', opAttrs, [a, b]);
};
NodeJSKernelBackend.prototype.select = function (condition, a, b) {
var opAttrs = [createTypeOpAttr('T', tfjs_core_1.backend_util.upcastType(a.dtype, b.dtype))];
return this.executeSingleOutput('Select', opAttrs, [condition, a, b]);
};
NodeJSKernelBackend.prototype.addN = function (tensors) {
var opAttrs = [
createTypeOpAttr('T', tensors[0].dtype),
{ name: 'N', type: this.binding.TF_ATTR_INT, value: tensors.length }
];
return this.executeSingleOutput('AddN', opAttrs, tensors);
};
NodeJSKernelBackend.prototype.subtract = function (a, b) {
var opAttrs = [createTypeOpAttr('T', tfjs_core_1.backend_util.upcastType(a.dtype, b.dtype))];
return this.executeSingleOutput('Sub', opAttrs, [a, b]);
};
NodeJSKernelBackend.prototype.multiply = function (a, b) {
var opAttrs = [createTypeOpAttr('T', tfjs_core_1.backend_util.upcastType(a.dtype, b.dtype))];
return this.executeSingleOutput('Mul', opAttrs, [a, b]);
};
NodeJSKernelBackend.prototype.realDivide = function (a, b) {
var opAttrs = [createTypeOpAttr('T', tfjs_core_1.backend_util.upcastType(a.dtype, b.dtype))];
return this.executeSingleOutput('RealDiv', opAttrs, [a, b]);
};
NodeJSKernelBackend.prototype.floorDiv = function (a, b) {
var opAttrs = [createTypeOpAttr('T', tfjs_core_1.backend_util.upcastType(a.dtype, b.dtype))];
return this.executeSingleOutput('FloorDiv', opAttrs, [a, b]);
};
NodeJSKernelBackend.prototype.divide = function (a, b) {
var opAttrs = [createTypeOpAttr('T', tfjs_core_1.backend_util.upcastType(a.dtype, b.dtype))];
return this.executeSingleOutput('Div', opAttrs, [a, b]);
};
NodeJSKernelBackend.prototype.divNoNan = function (a, b) {
var opAttrs = [createTypeOpAttr('T', tfjs_core_1.backend_util.upcastType(a.dtype, b.dtype))];
return this.executeSingleOutput('DivNoNan', opAttrs, [a, b]);
};
NodeJSKernelBackend.prototype.unsortedSegmentSum = function (x, segmentIds, numSegments) {
var opAttrs = [
createTypeOpAttr('T', x.dtype), createTypeOpAttr('Tindices', 'int32'),
createTypeOpAttr('Tnumsegments', 'int32')
];
return this.executeSingleOutput('UnsortedSegmentSum', opAttrs, [x, segmentIds, tfjs_core_1.scalar(numSegments, 'int32')]);
};
NodeJSKernelBackend.prototype.sum = function (x, axes) {
var axisTensor = tfjs_core_1.tensor1d(axes, 'int32');
return this.executeSingleOutput('Sum', this.createReductionOpAttrs(x), [x, axisTensor]);
};
NodeJSKernelBackend.prototype.prod = function (x, axes) {
var axesTensor = tfjs_core_1.tensor1d(axes, 'int32');
var opAttrs = [
{ name: 'keep_dims', type: this.binding.TF_ATTR_BOOL, value: false },
createTypeOpAttr('T', x.dtype), createTypeOpAttr('Tidx', 'int32')
];
return this.executeSingleOutput('Prod', opAttrs, [x, axesTensor]);
};
NodeJSKernelBackend.prototype.argMin = function (x, axis) {
var xInput = x.dtype === 'bool' ? x.toInt() : x;
var axisScalar = tfjs_core_1.scalar(axis, 'int32');
var opAttrs = [
createTypeOpAttr('T', xInput.dtype), createTypeOpAttr('Tidx', 'int32'),
createTypeOpAttr('output_type', 'int32')
];
return this.executeSingleOutput('ArgMin', opAttrs, [xInput, axisScalar]);
};
NodeJSKernelBackend.prototype.argMax = function (x, axis) {
var xInput = x.dtype === 'bool' ? x.toInt() : x;
var axisScalar = tfjs_core_1.scalar(axis, 'int32');
var opAttrs = [
createTypeOpAttr('T', xInput.dtype), createTypeOpAttr('Tidx', 'int32'),
createTypeOpAttr('output_type', 'int32')
];
return this.executeSingleOutput('ArgMax', opAttrs, [xInput, axisScalar]);
};
NodeJSKernelBackend.prototype.equal = function (a, b) {
var opAttrs = [createTypeOpAttr('T', tfjs_core_1.backend_util.upcastType(a.dtype, b.dtype))];
return this.executeSingleOutput('Equal', opAttrs, [a, b]);
};
NodeJSKernelBackend.prototype.notEqual = function (a, b) {
var opAttrs = [createTypeOpAttr('T', tfjs_core_1.backend_util.upcastType(a.dtype, b.dtype))];
return this.executeSingleOutput('NotEqual', opAttrs, [a, b]);
};
NodeJSKernelBackend.prototype.less = function (a, b) {
var opAttrs = [createTypeOpAttr('T', tfjs_core_1.backend_util.upcastType(a.dtype, b.dtype))];
return this.executeSingleOutput('Less', opAttrs, [a, b]);
};
NodeJSKernelBackend.prototype.lessEqual = function (a, b) {
var opAttrs = [createTypeOpAttr('T', tfjs_core_1.backend_util.upcastType(a.dtype, b.dtype))];
return this.executeSingleOutput('LessEqual', opAttrs, [a, b]);
};
NodeJSKernelBackend.prototype.greater = function (a, b) {
var opAttrs = [createTypeOpAttr('T', tfjs_core_1.backend_util.upcastType(a.dtype, b.dtype))];
return this.executeSingleOutput('Greater', opAttrs, [a, b]);
};
NodeJSKernelBackend.prototype.greaterEqual = function (a, b) {
var opAttrs = [createTypeOpAttr('T', tfjs_core_1.backend_util.upcastType(a.dtype, b.dtype))];
return this.executeSingleOutput('GreaterEqual', opAttrs, [a, b]);
};
NodeJSKernelBackend.prototype.logicalNot = function (a) {
return this.executeSingleOutput('LogicalNot', [], [a]);
};
NodeJSKernelBackend.prototype.logicalAnd = function (a, b) {
return this.executeSingleOutput('LogicalAnd', [], [a, b]);
};
NodeJSKernelBackend.prototype.logicalOr = function (a, b) {
return this.executeSingleOutput('LogicalOr', [], [a, b]);
};
NodeJSKernelBackend.prototype.where = function (condition) {
return this.executeSingleOutput('Where', [], [condition]);
};
NodeJSKernelBackend.prototype.topKValues = function (x, k) {
throw new Error('Method not implemented.');
};
NodeJSKernelBackend.prototype.topKIndices = function (x, k) {
throw new Error('Method not implemented.');
};
NodeJSKernelBackend.prototype.topk = function (x, k, sorted) {
var kCount = util_1.isNullOrUndefined(k) ? 1 : k;
var isSorted = util_1.isNullOrUndefined(sorted) ? true : sorted;
var opAttrs = [
{ name: 'sorted', type: this.binding.TF_ATTR_BOOL, value: isSorted },
createTypeOpAttr('T', x.dtype),
];
var kTensor = tfjs_core_1.scalar(kCount, 'int32');
// 'TopKV2' has two-hard coded output attributes:
return this.executeMultipleOutputs('TopKV2', opAttrs, [x, kTensor], 2);
};
NodeJSKernelBackend.prototype.min = function (x, axes) {
var axesTensor = tfjs_core_1.tensor1d(axes, 'int32');
return this.executeSingleOutput('Min', this.createReductionOpAttrs(x), [x, axesTensor]);
};
NodeJSKernelBackend.prototype.minimum = function (a, b) {
var opAttrs = [createTypeOpAttr('T', tfjs_core_1.backend_util.upcastType(a.dtype, b.dtype))];
return this.executeSingleOutput('Minimum', opAttrs, [a, b]);
};
NodeJSKernelBackend.prototype.max = function (x, axes) {
var axesTensor = tfjs_core_1.tensor1d(axes, 'int32');
return this.executeSingleOutput('Max', this.createReductionOpAttrs(x), [x, axesTensor]);
};
NodeJSKernelBackend.prototype.maximum = function (a, b) {
var opAttrs = [createTypeOpAttr('T', tfjs_core_1.backend_util.upcastType(a.dtype, b.dtype))];
return this.executeSingleOutput('Maximum', opAttrs, [a, b]);
};
NodeJSKernelBackend.prototype.all = function (x, axes) {
var opAttrs = [
{ name: 'keep_dims', type: this.binding.TF_ATTR_BOOL, value: false },
createTypeOpAttr('Tidx', 'int32')
];
var axesTensor = tfjs_core_1.tensor1d(axes, 'int32');
return this.executeSingleOutput('All', opAttrs, [x, axesTensor]);
};
NodeJSKernelBackend.prototype.any = function (x, axes) {
var opAttrs = [
{ name: 'keep_dims', type: this.binding.TF_ATTR_BOOL, value: false },
createTypeOpAttr('Tidx', 'int32')
];
var axesTensor = tfjs_core_1.tensor1d(axes, 'int32');
return this.executeSingleOutput('Any', opAttrs, [x, axesTensor]);
};
NodeJSKernelBackend.prototype.ceil = function (x) {
return this.executeSingleInput('Ceil', x);
};
NodeJSKernelBackend.prototype.floor = function (x) {
return this.executeSingleInput('Floor', x);
};
NodeJSKernelBackend.prototype.pow = function (a, b) {
var dtype = tfjs_core_1.backend_util.upcastType(a.dtype, b.dtype);
var opAttrs = [createTypeOpAttr('T', dtype)];
return this.executeSingleOutput('Pow', opAttrs, [a.cast(dtype), b.cast(dtype)]);
};
NodeJSKernelBackend.prototype.exp = function (x) {
var xTensor = x.dtype === 'int32' ? x.toFloat() : x;
return this.executeSingleInput('Exp', xTensor);
};
NodeJSKernelBackend.prototype.log = function (x) {
return this.executeSingleInput('Log', x);
};
NodeJSKernelBackend.prototype.log1p = function (x) {
return this.executeSingleInput('Log1p', x);
};
NodeJSKernelBackend.prototype.sqrt = function (x) {
return this.executeSingleInput('Sqrt', x);
};
NodeJSKernelBackend.prototype.square = function (x) {
return this.executeSingleInput('Square', x);
};
NodeJSKernelBackend.prototype.relu = function (x) {
return this.executeSingleInput('Relu', x);
};
NodeJSKernelBackend.prototype.relu6 = function (x) {
return this.executeSingleInput('Relu6', x);
};
NodeJSKernelBackend.prototype.prelu = function (x, a) {
var pos = this.relu(x);
var neg = a.mul(x.sub(this.abs(x))).mul(0.5);
return pos.add(neg);
};
NodeJSKernelBackend.prototype.elu = function (x) {
return this.executeSingleInput('Elu', x);
};
NodeJSKernelBackend.prototype.eluDer = function (dy, y) {
var opAttrs = [createTypeOpAttr('T', y.dtype)];
return this.executeSingleOutput('EluGrad', opAttrs, [dy, y]);
};
NodeJSKernelBackend.prototype.selu = function (x) {
return this.executeSingleInput('Selu', x);
};
NodeJSKernelBackend.prototype.int = function (x) {
throw new Error('Method not implemented.');
};
NodeJSKernelBackend.prototype.clip = function (x, min, max) {
var xMin = this.minimum(x, tfjs_core_1.scalar(max));
return this.maximum(xMin, tfjs_core_1.scalar(min));
};
NodeJSKernelBackend.prototype.abs = function (x) {
return this.executeSingleInput('Abs', x);
};
NodeJSKernelBackend.prototype.complexAbs = function (x) {
var opAttrs = [createTypeOpAttr('T', x.dtype), createTypeOpAttr('Tout', 'float32')];
return this.executeSingleOutput('ComplexAbs', opAttrs, [x]);
};
NodeJSKernelBackend.prototype.sigmoid = function (x) {
return this.executeSingleInput('Sigmoid', x);
};
NodeJSKernelBackend.prototype.sin = function (x) {
return this.executeSingleInput('Sin', x);
};
NodeJSKernelBackend.prototype.cos = function (x) {
return this.executeSingleInput('Cos', x);
};
NodeJSKernelBackend.prototype.tan = function (x) {
return this.executeSingleInput('Tan', x);
};
NodeJSKernelBackend.prototype.asin = function (x) {
return this.executeSingleInput('Asin', x);
};
NodeJSKernelBackend.prototype.acos = function (x) {
return this.executeSingleInput('Acos', x);
};
NodeJSKernelBackend.prototype.atan = function (x) {
return this.executeSingleInput('Atan', x);
};
NodeJSKernelBackend.prototype.sinh = function (x) {
return this.executeSingleInput('Sinh', x);
};
NodeJSKernelBackend.prototype.cosh = function (x) {
return this.executeSingleInput('Cosh', x);
};
NodeJSKernelBackend.prototype.tanh = function (x) {
return this.executeSingleInput('Tanh', x);
};
NodeJSKernelBackend.prototype.mod = function (a, b) {
var opAttrs = [createTypeOpAttr('T', a.dtype)];
return this.executeSingleOutput('FloorMod', opAttrs, [a, b]);
};
NodeJSKernelBackend.prototype.round = function (x) {
return this.executeSingleInput('Round', x);
};
NodeJSKernelBackend.prototype.sign = function (x) {
return this.executeSingleInput('Sign', x);
};
NodeJSKernelBackend.prototype.isNaN = function (x) {
return this.executeSingleInput('IsNan', x);
};
NodeJSKernelBackend.prototype.isInf = function (x) {
return this.executeSingleInput('IsInf', x);
};
NodeJSKernelBackend.prototype.isFinite = function (x) {
return this.executeSingleInput('IsFinite', x);
};
NodeJSKernelBackend.prototype.rsqrt = function (x) {
return this.executeSingleInput('Rsqrt', x);
};
NodeJSKernelBackend.prototype.reciprocal = function (x) {
return this.executeSingleInput('Reciprocal', x);
};
NodeJSKernelBackend.prototype.asinh = function (x) {
return this.executeSingleInput('Asinh', x);
};
NodeJSKernelBackend.prototype.acosh = function (x) {
return this.executeSingleInput('Acosh', x);
};
NodeJSKernelBackend.prototype.atanh = function (x) {
return this.executeSingleInput('Atanh', x);
};
NodeJSKernelBackend.prototype.erf = function (x) {
return this.executeSingleInput('Erf', x);
};
NodeJSKernelBackend.prototype.squaredDifference = function (a, b) {
var opAttrs = [createTypeOpAttr('T', a.dtype)];
return this.executeSingleOutput('SquaredDifference', opAttrs, [a, b]);
};
NodeJSKernelBackend.prototype.expm1 = function (x) {
return this.executeSingleInput('Expm1', x);
};
NodeJSKernelBackend.prototype.softplus = function (x) {
return this.executeSingleInput('Softplus', x);
};
NodeJSKernelBackend.prototype.atan2 = function (a, b) {
var opAttrs = [createTypeOpAttr('T', a.dtype)];
return this.executeSingleOutput('Atan2', opAttrs, [a, b]);
};
NodeJSKernelBackend.prototype.step = function (x, alpha) {
var dtype = x.dtype;
var nans = this.isNaN(x);
var stepNoNans = this.select(this.greater(x, tfjs_core_1.scalar(0, dtype)), tfjs_core_1.ones(x.shape), tfjs_core_1.fill(x.shape, alpha, dtype));
return this.select(nans, x, stepNoNans);
};
NodeJSKernelBackend.prototype.conv2d = function (x, filter, convInfo) {
if (convInfo.padInfo.type !== 'VALID' && convInfo.padInfo.type !== 'SAME') {
throw new Error("TF Backend supports only 'valid' and 'same' padding " +
("while padding was " + convInfo.padInfo.type));
}
var strides = [1, convInfo.strideHeight, convInfo.strideWidth, 1];
var padding = convInfo.padInfo.type;
var dataFormat = convInfo.dataFormat === 'channelsLast' ? 'NHWC' : 'NCHW';
var dilations = [1, convInfo.dilationHeight, convInfo.dilationWidth, 1];
var opAttrs = [
createTypeOpAttr('T', x.dtype),
{ name: 'strides', type: this.binding.TF_ATTR_INT, value: strides },
{ name: 'padding', type: this.binding.TF_ATTR_STRING, value: padding },
{
name: 'data_format',
type: this.binding.TF_ATTR_STRING,
value: dataFormat
},
{ name: 'use_cudnn_on_gpu', type: this.binding.TF_ATTR_BOOL, value: true },
{ name: 'dilations', type: this.binding.TF_ATTR_INT, value: dilations },
];
return this.executeSingleOutput('Conv2D', opAttrs, [x, filter]);
};
NodeJSKernelBackend.prototype.conv2dDerInput = function (dy, filter, convInfo) {
if (convInfo.padInfo.type !== 'VALID' && convInfo.padInfo.type !== 'SAME') {
throw new Error("TF Backend supports only 'valid' and 'same' padding " +
("while padding was " + convInfo.padInfo.type));
}
var strides = [1, convInfo.strideHeight, convInfo.strideWidth, 1];
var padding = convInfo.padInfo.type;
var dataFormat = convInfo.dataFormat === 'channelsLast' ? 'NHWC' : 'NCHW';
var dilations = [1, convInfo.dilationHeight, convInfo.dilationWidth, 1];
var opAttrs = [
createTypeOpAttr('T', 'float32'),
{ name: 'strides', type: this.binding.TF_ATTR_INT, value: strides },
{ name: 'padding', type: this.binding.TF_ATTR_STRING, value: padding }, {
name: 'data_format',
type: this.binding.TF_ATTR_STRING,
value: dataFormat
},
{ name: 'use_cudnn_on_gpu', type: this.binding.TF_ATTR_BOOL, value: true },
{ name: 'dilations', type: this.binding.TF_ATTR_INT, value: dilations }
];
var inputSizes = tfjs_core_1.tensor1d(convInfo.inShape, 'int32');
return this.executeSingleOutput('Conv2DBackpropInput', opAttrs, [inputSizes, filter, dy]);
};
NodeJSKernelBackend.prototype.conv2dDerFilter = function (x, dy, convInfo) {
if (convInfo.padInfo.type !== 'VALID' && convInfo.padInfo.type !== 'SAME') {
throw new Error("TF Backend supports only 'valid' and 'same' padding " +
("while padding was " + convInfo.padInfo.type));
}
var strides = [1, convInfo.strideHeight, convInfo.strideWidth, 1];
var padding = convInfo.padInfo.type;
var dataFormat = convInfo.dataFormat === 'channelsLast' ? 'NHWC' : 'NCHW';
var dilations = [1, convInfo.dilationHeight, convInfo.dilationWidth, 1];
var opAttrs = [
createTypeOpAttr('T', 'float32'),
{ name: 'strides', type: this.binding.TF_ATTR_INT, value: strides },
{ name: 'padding', type: this.binding.TF_ATTR_STRING, value: padding }, {
name: 'data_format',
type: this.binding.TF_ATTR_STRING,
value: dataFormat
},
{ name: 'use_cudnn_on_gpu', type: this.binding.TF_ATTR_BOOL, value: true },
{ name: 'dilations', type: this.binding.TF_ATTR_INT, value: dilations }
];
var filterSizes = tfjs_core_1.tensor1d(convInfo.filterShape, 'int32');
return this.executeSingleOutput('Conv2DBackpropFilter', opAttrs, [x, filterSizes, dy]);
};
NodeJSKernelBackend.prototype.depthwiseConv2DDerInput = function (dy, filter, convInfo) {
var strides = [1, convInfo.strideHeight, convInfo.strideWidth, 1];
var padding = convInfo.padInfo.type;
var dataFormat = convInfo.dataFormat === 'channelsLast' ? 'NHWC' : 'NCHW';
var dilations = [1, convInfo.dilationHeight, convInfo.dilationWidth, 1];
var opAttrs = [
createTypeOpAttr('T', 'float32'),
{ name: 'strides', type: this.binding.TF_ATTR_INT, value: strides },
{ name: 'padding', type: this.binding.TF_ATTR_STRING, value: padding }, {
name: 'data_format',
type: this.binding.TF_ATTR_STRING,
value: dataFormat
},
{ name: 'dilations', type: this.binding.TF_ATTR_INT, value: dilations }
];
var inputSizes = tfjs_core_1.tensor1d(convInfo.inShape, 'int32');
return this.executeSingleOutput('DepthwiseConv2dNativeBackpropInput', opAttrs, [inputSizes, filter, dy]);
};
NodeJSKernelBackend.prototype.depthwiseConv2DDerFilter = function (x, dY, convInfo) {
var strides = [1, convInfo.strideHeight, convInfo.strideWidth, 1];
var padding = convInfo.padInfo.type;
var dataFormat = convInfo.dataFormat === 'channelsLast' ? 'NHWC' : 'NCHW';
var dilations = [1, convInfo.dilationHeight, convInfo.dilationWidth, 1];
var opAttrs = [
createTypeOpAttr('T', 'float32'),
{ name: 'strides', type: this.binding.TF_ATTR_INT, value: strides },
{ name: 'padding', type: this.binding.TF_ATTR_STRING, value: padding }, {
name: 'data_format',
type: this.binding.TF_ATTR_STRING,
value: dataFormat
},
{ name: 'dilations', type: this.binding.TF_ATTR_INT, value: dilations }
];
var filterSizes = tfjs_core_1.tensor1d(convInfo.filterShape, 'int32');
return this.executeSingleOutput('DepthwiseConv2dNativeBackpropFilter', opAttrs, [x, filterSizes, dY]);
};
NodeJSKernelBackend.prototype.fusedDepthwiseConv2D = function (_a) {
var input = _a.input, filter = _a.filter, convInfo = _a.convInfo, bias = _a.bias, activation = _a.activation, preluActivationWeights = _a.preluActivationWeights;
var result = this.depthwiseConv2D(input, filter, convInfo);
if (bias != null) {
result = this.add(result, bias);
}
result = this.applyActivation(result, activation, preluActivationWeights);
return result;
};
NodeJSKernelBackend.prototype.depthwiseConv2D = function (input, filter, convInfo) {
if (convInfo.padInfo.type !== 'VALID' && convInfo.padInfo.type !== 'SAME') {
throw new Error("TF Backend supports only 'valid' and 'same' padding " +
("while padding was " + convInfo.padInfo.type));
}
var strides = [1, convInfo.strideHeight, convInfo.strideWidth, 1];
var padding = convInfo.padInfo.type;
var dataFormat = convInfo.dataFormat === 'channelsLast' ? 'NHWC' : 'NCHW';
var dilations = [1, convInfo.dilationHeight, convInfo.dilationWidth, 1];
var opAttrs = [
createTypeOpAttr('T', input.dtype),
{ name: 'strides', type: this.binding.TF_ATTR_INT, value: strides },
{ name: 'padding', type: this.binding.TF_ATTR_STRING, value: padding }, {
name: 'data_format',
type: this.binding.TF_ATTR_STRING,
value: dataFormat
},
{ name: 'dilations', type: this.binding.TF_ATTR_INT, value: dilations }
];
return this.executeSingleOutput('DepthwiseConv2dNative', opAttrs, [input, filter]);
};
NodeJSKernelBackend.prototype.conv3d = function (x, filter, convInfo) {
var strides = [
1, convInfo.strideDepth, convInfo.strideHeight, convInfo.strideWidth, 1
];
var padding = convInfo.padInfo.type;
var dataFormat = convInfo.dataFormat === 'channelsLast' ? 'NDHWC' : 'NCDHW';
if (!this.isGPUPackage && convInfo.dilationDepth > 1) {
throw new Error('CPU Dilation depth must be 1');
}
var dilations = [
1, convInfo.dilationDepth, convInfo.dilationHeight,
convInfo.dilationWidth, 1
];
var opAttrs = [
createTypeOpAttr('T', x.dtype),
{ name: 'strides', type: this.binding.TF_ATTR_INT, value: strides },
{ name: 'padding', type: this.binding.TF_ATTR_STRING, value: padding }, {
name: 'data_format',
type: this.binding.TF_ATTR_STRING,
value: dataFormat
},
{ name: 'dilations', type: this.binding.TF_ATTR_INT, value: dilations }
];
return this.executeSingleOutput('Conv3D', opAttrs, [x, filter]);
};
NodeJSKernelBackend.prototype.conv3dDerInput = function (dy, filter, convInfo) {
var strides = [
1, convInfo.strideDepth, convInfo.strideHeight, convInfo.strideWidth, 1
];
var padding = convInfo.padInfo.type;
var dataFormat = convInfo.dataFormat === 'channelsLast' ? 'NDHWC' : 'NCDHW';
if (!this.isGPUPackage && convInfo.dilationDepth > 1) {
throw new Error('CPU Dilation depth must be 1');
}
var dilations = [
1, convInfo.dilationDepth, convInfo.dilationHeight,
convInfo.dilationWidth, 1
];
var opAttrs = [
createTypeOpAttr('T', dy.dtype),
{ name: 'strides', type: this.binding.TF_ATTR_INT, value: strides },
{ name: 'padding', type: this.binding.TF_ATTR_STRING, value: padding }, {
name: 'data_format',
type: this.binding.TF_ATTR_STRING,
value: dataFormat
},
{ name: 'dilations', type: this.binding.TF_ATTR_INT, value: dilations },
createTypeOpAttr('Tshape', 'int32')
];
var inputSizes = tfjs_core_1.tensor1d(convInfo.inShape, 'int32');
return this.executeSingleOutput('Conv3DBackpropInputV2', opAttrs, [inputSizes, filter, dy]);
};
NodeJSKernelBackend.prototype.conv3dDerFilter = function (x, dY, convInfo) {
var strides = [
1, convInfo.strideDepth, convInfo.strideHeight, convInfo.strideWidth, 1
];
var padding = convInfo.padInfo.type;
var dataFormat = convInfo.dataFormat === 'channelsLast' ? 'NDHWC' : 'NCDHW';
if (!this.isGPUPackage && convInfo.dilationDepth > 1) {
throw new Error('CPU Dilation depth must be 1');
}
var dilations = [
1, convInfo.dilationDepth, convInfo.dilationHeight,
convInfo.dilationWidth, 1
];
var opAttrs = [
createTypeOpAttr('T', x.dtype),
{ name: 'strides', type: this.binding.TF_ATTR_INT, value: strides },
{ name: 'padding', type: this.binding.TF_ATTR_STRING, value: padding }, {
name: 'data_format',
type: this.binding.TF_ATTR_STRING,
value: dataFormat
},
{ name: 'dilations', type: this.binding.TF_ATTR_INT, value: dilations }
];
var filterSizes = tfjs_core_1.tensor1d(convInfo.filterShape, 'int32');
return this.executeSingleOutput('Conv3DBackpropFilterV2', opAttrs, [x, filterSizes, dY]);
};
NodeJSKernelBackend.prototype.maxPool = function (x, convInfo) {
if (convInfo.padInfo.type !== 'VALID' && convInfo.padInfo.type !== 'SAME') {
throw new Error("TF Backend supports only 'valid' and 'same' padding " +
("while padding was " + convInfo.padInfo.type));
}
var ksize = [1, convInfo.filterHeight, convInfo.filterWidth, 1];
var strides = [1, convInfo.strideHeight, convInfo.strideWidth, 1];
var padding = convInfo.padInfo.type;
var dataFormat = convInfo.dataFormat === 'channelsLast' ? 'NHWC' : 'NCHW';
var opAttrs = [
createTypeOpAttr('T', x.dtype),
{ name: 'ksize', type: this.binding.TF_ATTR_INT, value: ksize },
{ name: 'strides', type: this.binding.TF_ATTR_INT, value: strides },
{ name: 'padding', type: this.binding.TF_ATTR_STRING, value: padding }, {
name: 'data_format',
type: this.binding.TF_ATTR_STRING,
value: dataFormat
}
];
return this.executeSingleOutput('MaxPool', opAttrs, [x]);
};
NodeJSKernelBackend.prototype.maxPoolBackprop = function (dy, x, y, convInfo) {
if (convInfo.padInfo.type !== 'VALID' && convInfo.padInfo.type !== 'SAME') {
throw new Error("TF Backend supports only 'valid' and 'same' padding " +
("while padding type was " + convInfo.padInfo.type));
}
var ksize = [1, convInfo.filterHeight, convInfo.filterWidth, 1];
var strides = [1, convInfo.strideHeight, convInfo.strideWidth, 1];
var padding = convInfo.padInfo.type;
var dataFormat = convInfo.dataFormat === 'channelsLast' ? 'NHWC' : 'NCHW';
var opAttrs = [
createTypeOpAttr('T', x.dtype),
{ name: 'ksize', type: this.binding.TF_ATTR_INT, value: ksize },
{ name: 'strides', type: this.binding.TF_ATTR_INT, value: strides },
{ name: 'padding', type: this.binding.TF_ATTR_STRING, value: padding },
{
name: 'data_format',
type: this.binding.TF_ATTR_STRING,
value: dataFormat
},
];
return this.executeSingleOutput('MaxPoolGrad', opAttrs, [x, y, dy]);
};
NodeJSKernelBackend.prototype.avgPool = function (x, convInfo) {
if (convInfo.padInfo.type !== 'VALID' && convInfo.padInfo.type !== 'SAME') {
throw new Error("TF Backend supports only 'valid' and 'same' padding " +
("while padding was " + convInfo.padInfo.type));
}
var ksize = [1, convInfo.filterHeight, convInfo.filterWidth, 1];
var strides = [1, convInfo.strideHeight, convInfo.strideWidth, 1];
var padding = convInfo.padInfo.type;
var dataFormat = convInfo.dataFormat === 'channelsLast' ? 'NHWC' : 'NCHW';
var opAttrs = [
createTypeOpAttr('T', x.dtype),
{ name: 'ksize', type: this.binding.TF_ATTR_INT, value: ksize },
{ name: 'strides', type: this.binding.TF_ATTR_INT, value: strides },
{ name: 'padding', type: this.binding.TF_ATTR_STRING, value: padding },
{
name: 'data_format',
type: this.binding.TF_ATTR_STRING,
value: dataFormat
},
];
return this.executeSingleOutput('AvgPool', opAttrs, [x]);
};
NodeJSKernelBackend.prototype.avgPoolBackprop = function (dy, x, convInfo) {
if (convInfo.padInfo.type !== 'VALID' && convInfo.padInfo.type !== 'SAME') {
throw new Error("TF Backend supports only 'valid' and 'same' padding " +
("while padding type was " + convInfo.padInfo.type));
}
var ksize = [1, convInfo.filterHeight, convInfo.filterWidth, 1];
var strides = [1, convInfo.strideHeight, convInfo.strideWidth, 1];
var padding = convInfo.padInfo.type;
var dataFormat = convInfo.dataFormat === 'channelsLast' ? 'NHWC' : 'NCHW';
var opAttrs = [
createTypeOpAttr('T', x.dtype),
{ name: 'ksize', type: this.binding.TF_ATTR_INT, value: ksize },
{ name: 'strides', type: this.binding.TF_ATTR_INT, value: strides },
{ name: 'padding', type: this.binding.TF_ATTR_STRING, value: padding },
{
name: 'data_format',
type: this.binding.TF_ATTR_STRING,
value: dataFormat
},
];
var origInputShape = tfjs_core_1.tensor1d(x.shape, 'int32');
return this.executeSingleOutput('AvgPoolGrad', opAttrs, [origInputShape, dy]);