UNPKG

@tensorflow/tfjs-core

Version:

Hardware-accelerated JavaScript library for machine intelligence

1,139 lines (1,138 loc) 158 kB
"use strict"; /** * @license * Copyright 2017 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 seedrandom = require("seedrandom"); var engine_1 = require("../../engine"); var environment_1 = require("../../environment"); var log_1 = require("../../log"); var array_ops_util = require("../../ops/array_ops_util"); var axis_util = require("../../ops/axis_util"); var broadcast_util = require("../../ops/broadcast_util"); var complex_ops_1 = require("../../ops/complex_ops"); var concat_util = require("../../ops/concat_util"); var erf_util = require("../../ops/erf_util"); var gather_nd_util = require("../../ops/gather_nd_util"); var ops = require("../../ops/ops"); var ops_1 = require("../../ops/ops"); var scatter_nd_util = require("../../ops/scatter_nd_util"); var selu_util = require("../../ops/selu_util"); var slice_util_1 = require("../../ops/slice_util"); var tensor_1 = require("../../tensor"); var types_1 = require("../../types"); var util = require("../../util"); var util_1 = require("../../util"); var backend_1 = require("../backend"); var backend_util = require("../backend_util"); var complex_util = require("../complex_util"); var non_max_suppression_impl_1 = require("../non_max_suppression_impl"); var split_shared_1 = require("../split_shared"); var tile_impl_1 = require("../tile_impl"); var topk_impl_1 = require("../topk_impl"); var where_impl_1 = require("../where_impl"); var cpu_util_1 = require("./cpu_util"); function mapActivation(backend, x, activation, preluActivationWeights) { if (activation === 'linear') { return backend.linear(x); } else if (activation === 'relu') { return backend.relu(x); } else if (activation === 'elu') { return backend.elu(x); } else if (activation === 'relu6') { return backend.relu6(x); } else if (activation === 'prelu') { return backend.prelu(x, preluActivationWeights); } throw new Error("Activation " + activation + " has not been implemented for the CPU backend."); } var MathBackendCPU = /** @class */ (function (_super) { __extends(MathBackendCPU, _super); function MathBackendCPU() { var _this = _super.call(this) || this; _this.blockSize = 48; _this.firstUse = true; _this.data = new backend_1.DataStorage(_this, engine_1.ENGINE); return _this; } MathBackendCPU.prototype.write = function (values, shape, dtype) { if (this.firstUse) { this.firstUse = false; if (environment_1.env().get('IS_NODE')) { log_1.warn('\n============================\n' + 'Hi there 👋. Looks like you are running TensorFlow.js in ' + 'Node.js. To speed things up dramatically, install our node ' + 'backend, which binds to TensorFlow C++, by running ' + 'npm i @tensorflow/tfjs-node, ' + 'or npm i @tensorflow/tfjs-node-gpu if you have CUDA. ' + 'Then call require(\'@tensorflow/tfjs-node\'); (-gpu ' + 'suffix for CUDA) at the start of your program. ' + 'Visit https://github.com/tensorflow/tfjs-node for more details.' + '\n============================'); } } var dataId = {}; this.data.set(dataId, { values: values, dtype: dtype }); return dataId; }; MathBackendCPU.prototype.move = function (dataId, values, shape, dtype) { this.data.set(dataId, { values: values, dtype: dtype }); }; MathBackendCPU.prototype.numDataIds = function () { return this.data.numDataIds(); }; MathBackendCPU.prototype.read = function (dataId) { return __awaiter(this, void 0, void 0, function () { return __generator(this, function (_a) { return [2 /*return*/, this.readSync(dataId)]; }); }); }; MathBackendCPU.prototype.readSync = function (dataId) { var _a = this.data.get(dataId), dtype = _a.dtype, complexTensors = _a.complexTensors; if (dtype === 'complex64') { var realValues = this.readSync(complexTensors.real.dataId); var imagValues = this.readSync(complexTensors.imag.dataId); return complex_util.mergeRealAndImagArrays(realValues, imagValues); } return this.data.get(dataId).values; }; MathBackendCPU.prototype.bufferSync = function (t) { var data = this.readSync(t.dataId); var decodedData = data; if (t.dtype === 'string') { try { // Decode the bytes into string. decodedData = data.map(function (d) { return util.decodeString(d); }); } catch (_a) { throw new Error('Failed to decode encoded string bytes into utf-8'); } } return ops_1.buffer(t.shape, t.dtype, decodedData); }; MathBackendCPU.prototype.makeOutput = function (values, shape, dtype) { var dataId = this.write(values, shape, dtype); return engine_1.ENGINE.makeTensorFromDataId(dataId, shape, dtype, this); }; MathBackendCPU.prototype.disposeData = function (dataId) { if (this.data.has(dataId)) { var complexTensors = this.data.get(dataId).complexTensors; if (complexTensors != null) { complexTensors.real.dispose(); complexTensors.imag.dispose(); } this.data.delete(dataId); } }; MathBackendCPU.prototype.time = function (f) { return __awaiter(this, void 0, void 0, function () { var start, kernelMs; return __generator(this, function (_a) { start = util_1.now(); f(); kernelMs = util_1.now() - start; return [2 /*return*/, { kernelMs: kernelMs }]; }); }); }; MathBackendCPU.prototype.memory = function () { return { // Unreliable due to automatic gc. The numbers above are cumulative. unreliable: true, reasons: ['The reported memory is an upper bound. Due to automatic garbage ' + 'collection, the true allocated memory may be less.'] }; }; MathBackendCPU.prototype.complex = function (real, imag) { var result = this.makeOutput(null, real.shape, 'complex64'); var resultData = this.data.get(result.dataId); // The backend owns the reference to the underlying real and imaginary // clones. These will explicitly get disposed when the complex tensor is // disposed. resultData.complexTensors = { real: engine_1.ENGINE.keep(real.clone()), imag: engine_1.ENGINE.keep(imag.clone()) }; return result; }; MathBackendCPU.prototype.real = function (input) { var resultData = this.data.get(input.dataId); return resultData.complexTensors.real.clone(); }; MathBackendCPU.prototype.imag = function (input) { var resultData = this.data.get(input.dataId); return resultData.complexTensors.imag.clone(); }; MathBackendCPU.prototype.slice = function (x, begin, size) { cpu_util_1.assertNotComplex(x, 'slice'); var isContinous = slice_util_1.isSliceContinous(x.shape, begin, size); if (isContinous) { var flatOffset = slice_util_1.computeFlatOffset(begin, x.strides); var length_1 = util.sizeFromShape(size); var vals = this.readSync(x.dataId); return ops_1.tensor(vals.subarray(flatOffset, flatOffset + length_1), size, x.dtype); } var buffer = ops.buffer(size, x.dtype); var xBuf = this.bufferSync(x); for (var i = 0; i < buffer.size; ++i) { var loc = buffer.indexToLoc(i); var xLoc = loc.map(function (idx, j) { return idx + begin[j]; }); buffer.values[i] = xBuf.get.apply(xBuf, xLoc); } return buffer.toTensor(); }; MathBackendCPU.prototype.stridedSlice = function (x, begin, end, strides) { cpu_util_1.assertNotComplex(x, 'stridedSlice'); var outShape = slice_util_1.computeOutShape(begin, end, strides); if (outShape.some(function (axis) { return axis === 0; })) { return ops.tensor([], outShape); } var buffer = ops.buffer(outShape, x.dtype); var xBuf = this.bufferSync(x); for (var i = 0; i < buffer.size; i++) { var loc = buffer.indexToLoc(i); var newLoc = new Array(loc.length); for (var j = 0; j < newLoc.length; j++) { newLoc[j] = loc[j] * strides[j] + begin[j]; } buffer.set.apply(buffer, [xBuf.get.apply(xBuf, newLoc)].concat(loc)); } return buffer.toTensor(); }; MathBackendCPU.prototype.diag = function (x) { var xVals = this.readSync(x.dataId); var buffer = ops.buffer([x.size, x.size], x.dtype); var vals = buffer.values; for (var i = 0; i < xVals.length; i++) { vals[i * x.size + i] = xVals[i]; } return buffer.toTensor(); }; MathBackendCPU.prototype.unstack = function (x, axis) { var num = x.shape[axis]; var outShape = new Array(x.rank - 1); var outIndex = 0; for (var i = 0; i < x.rank; i++) { if (i !== axis) { outShape[outIndex++] = x.shape[i]; } } var begin = new Array(x.rank).fill(0); var size = x.shape.slice(); size[axis] = 1; var res = new Array(num); for (var i = 0; i < res.length; i++) { begin[axis] = i; res[i] = this.slice(x, begin, size).reshape(outShape); } return res; }; MathBackendCPU.prototype.reverse = function (x, axis) { cpu_util_1.assertNotComplex(x, 'reverse'); var buffer = ops.buffer(x.shape, x.dtype); var xBuf = this.bufferSync(x); var _loop_1 = function (i) { var outLoc = buffer.indexToLoc(i); var inLoc = outLoc.slice(); axis.forEach(function (ax) { return inLoc[ax] = x.shape[ax] - 1 - inLoc[ax]; }); buffer.set.apply(buffer, [xBuf.get.apply(xBuf, inLoc)].concat(outLoc)); }; for (var i = 0; i < buffer.size; i++) { _loop_1(i); } return buffer.toTensor(); }; MathBackendCPU.prototype.concat = function (tensors, axis) { var _this = this; if (tensors[0].dtype === 'complex64') { var reals = tensors.map(function (t) { return complex_ops_1.real(t); }); var imags = tensors.map(function (t) { return complex_ops_1.imag(t); }); return complex_ops_1.complex(this.concat(reals, axis), this.concat(imags, axis)); } var tensors2D = tensors.map(function (t) { var innerSize = util.sizeFromShape(t.shape.slice(axis)); return t.as2D(-1, innerSize); }); var outShape = concat_util.computeOutShape(tensors2D.map(function (t) { return t.shape; }), 1 /* axis */); var values = ops.buffer(outShape, tensors[0].dtype) .values; if (tensors2D[0].shape[0] === 1) { // Use built-in TypedArray.set() method for speed. var offset_1 = 0; tensors2D.forEach(function (t) { values.set(_this.readSync(t.dataId), offset_1); offset_1 += t.size; }); } else { var colOffset_1 = 0; tensors2D.forEach(function (t) { var tVals = _this.readSync(t.dataId); var tIdx = 0; for (var row = 0; row < t.shape[0]; ++row) { var resIdx = row * outShape[1] + colOffset_1; for (var col = 0; col < t.shape[1]; ++col) { values[resIdx + col] = tVals[tIdx++]; } } colOffset_1 += t.shape[1]; }); } var finalOutShape = concat_util.computeOutShape(tensors.map(function (t) { return t.shape; }), axis); return ops_1.tensor(values, finalOutShape, tensors[0].dtype); }; MathBackendCPU.prototype.neg = function (x) { cpu_util_1.assertNotComplex(x, 'neg'); return this.multiply(ops.scalar(-1), x); }; MathBackendCPU.prototype.add = function (a, b) { if (a.dtype === 'complex64' || b.dtype === 'complex64') { return this.broadcastedBinaryComplexOp(a.cast('complex64'), b.cast('complex64'), function (aReal, aImag, bReal, bImag) { return { real: aReal + bReal, imag: aImag + bImag }; }); } return this.broadcastedBinaryOp(a, b, types_1.upcastType(a.dtype, b.dtype), function (aValue, bValue) { return aValue + bValue; }); }; MathBackendCPU.prototype.addN = function (tensors) { var _this = this; cpu_util_1.assertNotComplex(tensors, 'addN'); var vals = tensors.map(function (t) { return _this.readSync(t.dataId); }); var result = ops.buffer(tensors[0].shape, tensors[0].dtype); var resultVals = result.values; for (var i = 0; i < tensors.length; i++) { var currVals = vals[i]; for (var j = 0; j < resultVals.length; j++) { resultVals[j] += currVals[j]; } } return result.toTensor(); }; MathBackendCPU.prototype.subtract = function (a, b) { if (a.dtype === 'complex64' || b.dtype === 'complex64') { return this.broadcastedBinaryComplexOp(a.cast('complex64'), b.cast('complex64'), function (aReal, aImag, bReal, bImag) { return { real: aReal - bReal, imag: aImag - bImag }; }); } return this.broadcastedBinaryOp(a, b, types_1.upcastType(a.dtype, b.dtype), function (aValue, bValue) { return aValue - bValue; }); }; MathBackendCPU.prototype.pow = function (a, b) { cpu_util_1.assertNotComplex([a, b], 'pow'); return this.broadcastedBinaryOp(a, b, a.dtype, function (aValue, bValue) { return Math.pow(aValue, bValue); }); }; MathBackendCPU.prototype.batchMatMul = function (a, b, transposeA, transposeB) { cpu_util_1.assertNotComplex([a, b], 'matMul'); var sharedDim = transposeA ? a.shape[1] : a.shape[2]; var leftDim = transposeA ? a.shape[2] : a.shape[1]; var rightDim = transposeB ? b.shape[1] : b.shape[2]; var batchDim = a.shape[0]; var aValues = this.readSync(a.dataId); var bValues = this.readSync(b.dataId); var _a = transposeA ? [a.strides[0], 1, a.strides[1]] : [a.strides[0], a.strides[1], 1], aBatch = _a[0], aOuterStep = _a[1], aInnerStep = _a[2]; var _b = transposeB ? [1, b.strides[1], b.strides[0]] : [b.strides[1], 1, b.strides[0]], bInnerStep = _b[0], bOuterStep = _b[1], bBatch = _b[2]; var size = leftDim * rightDim; var result = ops_1.buffer([batchDim, leftDim, rightDim], a.dtype); var resVals = result.values; var blockSize = this.blockSize; for (var b_1 = 0; b_1 < batchDim; b_1++) { for (var i0 = 0; i0 < leftDim; i0 += blockSize) { for (var j0 = 0; j0 < rightDim; j0 += blockSize) { for (var k0 = 0; k0 < sharedDim; k0 += blockSize) { // for when blockSize doesn't evenly divide the input var iBlock = Math.min(i0 + blockSize, leftDim); var jBlock = Math.min(j0 + blockSize, rightDim); var kBlock = Math.min(k0 + blockSize, sharedDim); for (var i = i0; i < iBlock; i++) { for (var j = j0; j < jBlock; j++) { var sum = 0.0; for (var k = k0; k < kBlock; k++) { sum += aValues[b_1 * aBatch + i * aOuterStep + k * aInnerStep] * bValues[k * bInnerStep + j * bOuterStep + b_1 * bBatch]; } resVals[b_1 * size + (i * rightDim + j)] += sum; } } } } } } return result.toTensor(); }; MathBackendCPU.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; var result = this.batchMatMul(a, b, transposeA, transposeB); if (bias) { result = this.add(result, bias); } if (activation) { result = mapActivation(this, result, activation, preluActivationWeights); } return result; }; MathBackendCPU.prototype.multiply = function (a, b) { if (a.dtype === 'complex64' || b.dtype === 'complex64') { return this.broadcastedBinaryComplexOp(a.cast('complex64'), b.cast('complex64'), function (aReal, aImag, bReal, bImag) { return { real: aReal * bReal - aImag * bImag, imag: aReal * bImag + aImag * bReal }; }); } return this.broadcastedBinaryOp(a, b, types_1.upcastType(a.dtype, b.dtype), function (aValue, bValue) { return aValue * bValue; }); }; MathBackendCPU.prototype.realDivide = function (a, b) { cpu_util_1.assertNotComplex([a, b], 'realDivide'); var op = function (a, b) { return a / b; }; var outputDtype = 'float32'; return this.broadcastedBinaryOp(a, b, outputDtype, op); }; MathBackendCPU.prototype.floorDiv = function (a, b) { cpu_util_1.assertNotComplex([a, b], 'floorDiv'); var op = function (a, b) { return Math.floor(a / b); }; var outputDtype = 'int32'; return this.broadcastedBinaryOp(a, b, outputDtype, op); }; MathBackendCPU.prototype.sum = function (x, axes) { cpu_util_1.assertNotComplex(x, 'sum'); axis_util.assertAxesAreInnerMostDims('sum', axes, x.rank); var _a = axis_util.computeOutAndReduceShapes(x.shape, axes), outShape = _a[0], reduceShape = _a[1]; var resultDtype = types_1.upcastType(x.dtype, 'int32'); var result = ops.zeros(outShape, resultDtype); var reduceSize = util.sizeFromShape(reduceShape); var vals = this.readSync(result.dataId); var aVals = this.readSync(x.dataId); for (var i = 0; i < vals.length; ++i) { var offset = i * reduceSize; var sum = 0; for (var j = 0; j < reduceSize; ++j) { sum += aVals[offset + j]; } vals[i] = sum; } return result; }; MathBackendCPU.prototype.prod = function (x, axes) { cpu_util_1.assertNotComplex(x, 'sum'); var _a = axis_util.computeOutAndReduceShapes(x.shape, axes), outShape = _a[0], reduceShape = _a[1]; var resultDtype = types_1.upcastType(x.dtype, 'int32'); var result = ops.zeros(outShape, resultDtype); var reduceSize = util.sizeFromShape(reduceShape); var vals = this.readSync(result.dataId); var aVals = this.readSync(x.dataId); for (var i = 0; i < vals.length; ++i) { var offset = i * reduceSize; var prod = 1; for (var j = 0; j < reduceSize; ++j) { prod *= aVals[offset + j]; } vals[i] = prod; } return result; }; MathBackendCPU.prototype.unsortedSegmentSum = function (x, segmentIds, numSegments) { cpu_util_1.assertNotComplex(x, 'unsortedSegmentSum'); var res = []; // Reshape the segment id's so that they can be broadcast with // x. The new shape should be [segmentIds.shape, 1, ..., 1] var numIters = x.rank - segmentIds.rank; for (var i = 0; i < numIters; ++i) { segmentIds = segmentIds.expandDims(i + 1); } for (var i = 0; i < numSegments; ++i) { var segmentId = ops.scalar(i, 'int32'); var mask = ops.equal(segmentId, segmentIds).asType('float32'); var sum = mask.mul(x).sum(0); res.push(sum); } return ops.stack(res); }; MathBackendCPU.prototype.argMin = function (x, axis) { cpu_util_1.assertNotComplex(x, 'argMin'); var axes = [axis]; axis_util.assertAxesAreInnerMostDims('argMin', axes, x.rank); var _a = axis_util.computeOutAndReduceShapes(x.shape, axes), outShape = _a[0], reduceShape = _a[1]; var result = ops.zeros(outShape, 'int32'); var reduceSize = util.sizeFromShape(reduceShape); var vals = this.readSync(result.dataId); var aVals = this.readSync(x.dataId); for (var i = 0; i < vals.length; ++i) { var offset = i * reduceSize; var min = aVals[offset]; var minIndex = 0; for (var j = 0; j < reduceSize; ++j) { var value = aVals[offset + j]; if (value < min) { min = value; minIndex = j; } } vals[i] = minIndex; } return result; }; MathBackendCPU.prototype.argMax = function (x, axis) { cpu_util_1.assertNotComplex(x, 'argMax'); var axes = [axis]; axis_util.assertAxesAreInnerMostDims('argMax', axes, x.rank); var _a = axis_util.computeOutAndReduceShapes(x.shape, axes), outShape = _a[0], reduceShape = _a[1]; var result = ops.zeros(outShape, 'int32'); var reduceSize = util.sizeFromShape(reduceShape); var vals = this.readSync(result.dataId); var aVals = this.readSync(x.dataId); for (var i = 0; i < vals.length; ++i) { var offset = i * reduceSize; var max = aVals[offset]; var maxIndex = 0; for (var j = 0; j < reduceSize; ++j) { var value = aVals[offset + j]; if (value > max) { max = value; maxIndex = j; } } vals[i] = maxIndex; } return result; }; MathBackendCPU.prototype.cumsum = function (x, axis, exclusive, reverse) { cpu_util_1.assertNotComplex(x, 'cumsum'); if (axis !== x.rank - 1) { throw new Error("backend.cumsum in CPU expects an inner-most axis=" + (x.rank - 1) + " " + ("but got axis=" + axis)); } var resultDtype = types_1.upcastType(x.dtype, 'int32'); var result = ops.zeros(x.shape, resultDtype); var vals = this.readSync(result.dataId); var aVals = this.readSync(x.dataId); var finalDim = x.shape[x.rank - 1]; var indexAdjuster = reverse ? function (i, j) { return i + finalDim - j - 1; } : function (i, j) { return i + j; }; for (var i = 0; i < aVals.length; i += finalDim) { for (var j = 0; j < finalDim; j++) { var idx = indexAdjuster(i, j); if (j === 0) { vals[idx] = exclusive ? 0 : aVals[idx]; } else { var prevIdx = indexAdjuster(i, j - 1); vals[idx] = exclusive ? aVals[prevIdx] + vals[prevIdx] : aVals[idx] + vals[prevIdx]; } } } return result; }; MathBackendCPU.prototype.equal = function (a, b) { cpu_util_1.assertNotComplex([a, b], 'equal'); return this.broadcastedBinaryOp(a, b, 'bool', function (aVal, bVal) { return (aVal === bVal) ? 1 : 0; }); }; MathBackendCPU.prototype.notEqual = function (a, b) { cpu_util_1.assertNotComplex([a, b], 'notEqual'); return this.broadcastedBinaryOp(a, b, 'bool', function (aVal, bVal) { return (aVal !== bVal) ? 1 : 0; }); }; MathBackendCPU.prototype.less = function (a, b) { cpu_util_1.assertNotComplex([a, b], 'less'); return this.broadcastedBinaryOp(a, b, 'bool', function (aVal, bVal) { return (aVal < bVal) ? 1 : 0; }); }; MathBackendCPU.prototype.lessEqual = function (a, b) { cpu_util_1.assertNotComplex([a, b], 'lessEqual'); return this.broadcastedBinaryOp(a, b, 'bool', function (aVal, bVal) { return (aVal <= bVal) ? 1 : 0; }); }; MathBackendCPU.prototype.greater = function (a, b) { cpu_util_1.assertNotComplex([a, b], 'greater'); return this.broadcastedBinaryOp(a, b, 'bool', function (aVal, bVal) { return (aVal > bVal) ? 1 : 0; }); }; MathBackendCPU.prototype.greaterEqual = function (a, b) { cpu_util_1.assertNotComplex([a, b], 'greaterEqual'); return this.broadcastedBinaryOp(a, b, 'bool', function (aVal, bVal) { return (aVal >= bVal) ? 1 : 0; }); }; MathBackendCPU.prototype.logicalNot = function (x) { cpu_util_1.assertNotComplex(x, 'logicalNot'); var values = this.readSync(x.dataId); var newValues = new Uint8Array(values.length); for (var i = 0; i < values.length; ++i) { newValues[i] = values[i] ? 0 : 1; } return this.makeOutput(newValues, x.shape, 'bool'); }; MathBackendCPU.prototype.logicalAnd = function (a, b) { cpu_util_1.assertNotComplex([a, b], 'logicalAnd'); return this.broadcastedBinaryOp(a, b, 'bool', function (aVal, bVal) { return aVal && bVal; }); }; MathBackendCPU.prototype.logicalOr = function (a, b) { cpu_util_1.assertNotComplex([a, b], 'logicalOr'); return this.broadcastedBinaryOp(a, b, 'bool', function (aVal, bVal) { return aVal || bVal; }); }; MathBackendCPU.prototype.select = function (condition, a, b) { cpu_util_1.assertNotComplex([condition, a, b], 'select'); var values = this.readSync(condition.dataId); var aValues = this.readSync(a.dataId); var bValues = this.readSync(b.dataId); var result = ops.zeros(a.shape, types_1.upcastType(a.dtype, b.dtype)); var newValues = this.readSync(result.dataId); var index = 0; var offset = condition.rank === 0 || condition.rank > 1 || a.rank === 1 ? 1 : util.sizeFromShape(a.shape.slice(1)); for (var i = 0; i < values.length; i++) { for (var j = 0; j < offset; j++) { if (values[i] === 1) { newValues[index++] = aValues[i]; } else { newValues[index++] = bValues[i]; } } } return result; }; MathBackendCPU.prototype.where = function (condition) { cpu_util_1.assertNotComplex([condition], 'where'); var condVals = this.readSync(condition.dataId); return where_impl_1.whereImpl(condition.shape, condVals); }; MathBackendCPU.prototype.topk = function (x, k, sorted) { cpu_util_1.assertNotComplex(x, 'topk'); var xVals = this.readSync(x.dataId); return topk_impl_1.topkImpl(xVals, x.shape, x.dtype, k, sorted); }; MathBackendCPU.prototype.min = function (x, axes) { cpu_util_1.assertNotComplex(x, 'min'); axis_util.assertAxesAreInnerMostDims('min', axes, x.rank); var _a = axis_util.computeOutAndReduceShapes(x.shape, axes), outShape = _a[0], reduceShape = _a[1]; var result = ops.zeros(outShape, x.dtype); var reduceSize = util.sizeFromShape(reduceShape); var vals = this.readSync(result.dataId); var aVals = this.readSync(x.dataId); for (var i = 0; i < vals.length; ++i) { var offset = i * reduceSize; var min = aVals[offset]; for (var j = 0; j < reduceSize; ++j) { var value = aVals[offset + j]; if (value < min) { min = value; } } vals[i] = min; } return result; }; MathBackendCPU.prototype.minimum = function (a, b) { cpu_util_1.assertNotComplex([a, b], 'minimum'); return this.broadcastedBinaryOp(a, b, a.dtype, function (aVal, bVal) { return Math.min(aVal, bVal); }); }; MathBackendCPU.prototype.mod = function (a, b) { cpu_util_1.assertNotComplex([a, b], 'mod'); return this.broadcastedBinaryOp(a, b, a.dtype, function (aVal, bVal) { var rem = aVal % bVal; if ((aVal < 0 && bVal < 0) || (aVal >= 0 && bVal >= 0)) { return rem; } else { return (rem + bVal) % bVal; } }); }; MathBackendCPU.prototype.max = function (x, axes) { cpu_util_1.assertNotComplex(x, 'max'); axis_util.assertAxesAreInnerMostDims('max', axes, x.rank); var _a = axis_util.computeOutAndReduceShapes(x.shape, axes), outShape = _a[0], reduceShape = _a[1]; var result = ops.zeros(outShape, x.dtype); var reduceSize = util.sizeFromShape(reduceShape); var vals = this.readSync(result.dataId); var aVals = this.readSync(x.dataId); for (var i = 0; i < vals.length; ++i) { var offset = i * reduceSize; var max = aVals[offset]; for (var j = 0; j < reduceSize; ++j) { var value = aVals[offset + j]; if (value > max) { max = value; } } vals[i] = max; } return result; }; MathBackendCPU.prototype.maximum = function (a, b) { cpu_util_1.assertNotComplex([a, b], 'maximum'); return this.broadcastedBinaryOp(a, b, a.dtype, function (aVal, bVal) { return Math.max(aVal, bVal); }); }; MathBackendCPU.prototype.all = function (x, axes) { cpu_util_1.assertNotComplex(x, 'all'); axis_util.assertAxesAreInnerMostDims('all', axes, x.rank); var _a = axis_util.computeOutAndReduceShapes(x.shape, axes), outShape = _a[0], reduceShape = _a[1]; var result = ops.zeros(outShape, x.dtype); var reduceSize = util.sizeFromShape(reduceShape); var vals = this.readSync(result.dataId); var aVals = this.readSync(x.dataId); for (var i = 0; i < vals.length; ++i) { var offset = i * reduceSize; var all = aVals[offset]; for (var j = 0; j < reduceSize; ++j) { var value = aVals[offset + j]; all = all && value; } vals[i] = all; } return result; }; MathBackendCPU.prototype.any = function (x, axes) { cpu_util_1.assertNotComplex(x, 'any'); axis_util.assertAxesAreInnerMostDims('any', axes, x.rank); var _a = axis_util.computeOutAndReduceShapes(x.shape, axes), outShape = _a[0], reduceShape = _a[1]; var result = ops.zeros(outShape, x.dtype); var reduceSize = util.sizeFromShape(reduceShape); var vals = this.readSync(result.dataId); var aVals = this.readSync(x.dataId); for (var i = 0; i < vals.length; ++i) { var offset = i * reduceSize; var anyVal = aVals[offset]; for (var j = 0; j < reduceSize; ++j) { var value = aVals[offset + j]; anyVal = anyVal || value; } vals[i] = anyVal; } return result; }; MathBackendCPU.prototype.squaredDifference = function (a, b) { cpu_util_1.assertNotComplex([a, b], 'squaredDifference'); return this.broadcastedBinaryOp(a, b, a.dtype, function (aVal, bVal) { var diff = aVal - bVal; return diff * diff; }); }; MathBackendCPU.prototype.ceil = function (x) { cpu_util_1.assertNotComplex(x, 'ceil'); var values = this.readSync(x.dataId); var newValues = new Float32Array(values.length); for (var i = 0; i < values.length; ++i) { newValues[i] = Math.ceil(values[i]); } return this.makeOutput(newValues, x.shape, 'float32'); }; MathBackendCPU.prototype.floor = function (x) { cpu_util_1.assertNotComplex(x, 'floor'); var values = this.readSync(x.dataId); var newValues = new Float32Array(values.length); for (var i = 0; i < values.length; ++i) { newValues[i] = Math.floor(values[i]); } return this.makeOutput(newValues, x.shape, 'float32'); }; MathBackendCPU.prototype.sign = function (x) { cpu_util_1.assertNotComplex(x, 'x'); var values = this.readSync(x.dataId); var newValues = new Float32Array(values.length); for (var i = 0; i < values.length; ++i) { if (values[i] < 0) { newValues[i] = -1; } else if (values[i] > 0) { newValues[i] = 1; } else { newValues[i] = 0; } } return this.makeOutput(newValues, x.shape, 'float32'); }; MathBackendCPU.prototype.isNaN = function (x) { cpu_util_1.assertNotComplex(x, 'x'); var values = this.readSync(x.dataId); var newValues = new Uint8Array(values.length); for (var i = 0; i < values.length; ++i) { if (Number.isNaN(values[i])) { newValues[i] = 1; } } return this.makeOutput(newValues, x.shape, 'bool'); }; MathBackendCPU.prototype.isInf = function (x) { cpu_util_1.assertNotComplex(x, 'x'); var values = this.readSync(x.dataId); var newValues = new Uint8Array(values.length); for (var i = 0; i < values.length; ++i) { if (Math.abs(values[i]) === Infinity) { newValues[i] = 1; } } return this.makeOutput(newValues, x.shape, 'bool'); }; MathBackendCPU.prototype.isFinite = function (x) { cpu_util_1.assertNotComplex(x, 'x'); var values = this.readSync(x.dataId); var newValues = new Uint8Array(values.length); for (var i = 0; i < values.length; ++i) { if (Number.isFinite(values[i])) { newValues[i] = 1; } } return this.makeOutput(newValues, x.shape, 'bool'); }; MathBackendCPU.prototype.round = function (x) { cpu_util_1.assertNotComplex(x, 'round'); var values = this.readSync(x.dataId); var newValues = new Float32Array(values.length); for (var i = 0; i < values.length; ++i) { // The algorithm is based on banker's rounding. var base = Math.floor(values[i]); if (values[i] - base < 0.5) { newValues[i] = Math.floor(values[i]); } else if (values[i] - base > 0.5) { newValues[i] = Math.ceil(values[i]); } else { if (base % 2.0 === 0.0) { newValues[i] = base; } else { newValues[i] = base + 1.0; } } } return this.makeOutput(newValues, x.shape, 'float32'); }; MathBackendCPU.prototype.exp = function (x) { cpu_util_1.assertNotComplex(x, 'exp'); var values = this.readSync(x.dataId); var newValues = new Float32Array(values.length); for (var i = 0; i < values.length; ++i) { newValues[i] = Math.exp(values[i]); } return this.makeOutput(newValues, x.shape, 'float32'); }; MathBackendCPU.prototype.expm1 = function (x) { cpu_util_1.assertNotComplex(x, 'expm1'); var values = this.readSync(x.dataId); var newValues = new Float32Array(values.length); for (var i = 0; i < values.length; ++i) { newValues[i] = Math.expm1(values[i]); } return this.makeOutput(newValues, x.shape, 'float32'); }; MathBackendCPU.prototype.log = function (x) { cpu_util_1.assertNotComplex(x, 'log'); var values = this.readSync(x.dataId); var newValues = new Float32Array(values.length); for (var i = 0; i < values.length; ++i) { var value = values[i]; newValues[i] = Math.log(value); } return this.makeOutput(newValues, x.shape, 'float32'); }; MathBackendCPU.prototype.log1p = function (x) { cpu_util_1.assertNotComplex(x, 'log1p'); var values = this.readSync(x.dataId); var newValues = new Float32Array(values.length); for (var i = 0; i < values.length; ++i) { var value = values[i]; newValues[i] = Math.log1p(value); } return this.makeOutput(newValues, x.shape, 'float32'); }; MathBackendCPU.prototype.sqrt = function (x) { cpu_util_1.assertNotComplex(x, 'sqrt'); var values = this.readSync(x.dataId); var newValues = new Float32Array(values.length); for (var i = 0; i < values.length; ++i) { var value = values[i]; newValues[i] = Math.sqrt(value); } return this.makeOutput(newValues, x.shape, 'float32'); }; MathBackendCPU.prototype.rsqrt = function (x) { cpu_util_1.assertNotComplex(x, 'rsqrt'); var values = this.readSync(x.dataId); var newValues = new Float32Array(values.length); for (var i = 0; i < values.length; ++i) { var value = values[i]; newValues[i] = 1 / Math.sqrt(value); } return this.makeOutput(newValues, x.shape, 'float32'); }; MathBackendCPU.prototype.reciprocal = function (x) { cpu_util_1.assertNotComplex(x, 'reciprocal'); var values = this.readSync(x.dataId); var newValues = new Float32Array(values.length); for (var i = 0; i < values.length; ++i) { newValues[i] = 1 / values[i]; } return this.makeOutput(newValues, x.shape, 'float32'); }; MathBackendCPU.prototype.linear = function (x) { return x; }; MathBackendCPU.prototype.relu = function (x) { cpu_util_1.assertNotComplex(x, 'relu'); var res = ops.zeros(x.shape, x.dtype); var resVals = this.readSync(res.dataId); var inVals = this.readSync(x.dataId); for (var i = 0; i < inVals.length; ++i) { resVals[i] = Math.max(0, inVals[i]); } return res; }; MathBackendCPU.prototype.relu6 = function (x) { cpu_util_1.assertNotComplex(x, 'relu'); var res = ops.zeros(x.shape, x.dtype); var resVals = this.readSync(res.dataId); var inVals = this.readSync(x.dataId); for (var i = 0; i < inVals.length; ++i) { resVals[i] = Math.min(Math.max(0, inVals[i]), 6); } return res; }; MathBackendCPU.prototype.prelu = function (x, a) { cpu_util_1.assertNotComplex([x, a], 'prelu'); return this.broadcastedBinaryOp(x, a, x.dtype, function (xValue, aValue) { return xValue < 0 ? aValue * xValue : xValue; }); }; MathBackendCPU.prototype.elu = function (x) { cpu_util_1.assertNotComplex(x, 'elu'); var resultValues = new Float32Array(x.size); var values = this.readSync(x.dataId); for (var i = 0; i < values.length; ++i) { var v = values[i]; if (v >= 0) { resultValues[i] = v; } else { resultValues[i] = (Math.exp(v) - 1); } } return this.makeOutput(resultValues, x.shape, 'float32'); }; MathBackendCPU.prototype.eluDer = function (dy, y) { cpu_util_1.assertNotComplex([dy, y], 'eluDer'); var resultValues = new Float32Array(y.size); var values = this.readSync(y.dataId); var dyValues = this.readSync(dy.dataId); for (var i = 0; i < values.length; ++i) { var v = values[i]; if (v >= 1) { resultValues[i] = dyValues[i]; } else { resultValues[i] = dyValues[i] * (v + 1); } } return this.makeOutput(resultValues, y.shape, 'float32'); }; MathBackendCPU.prototype.selu = function (x) { cpu_util_1.assertNotComplex(x, 'selu'); // Stable and Attracting Fixed Point (0, 1) for Normalized Weights. // see: https://arxiv.org/abs/1706.02515 var scaleAlpha = selu_util.SELU_SCALEALPHA; var scale = selu_util.SELU_SCALE; var resultValues = new Float32Array(x.size); var values = this.readSync(x.dataId); for (var i = 0; i < values.length; ++i) { var v = values[i]; if (v >= 0) { resultValues[i] = scale * v; } else { resultValues[i] = scaleAlpha * (Math.exp(v) - 1); } } return this.makeOutput(resultValues, x.shape, 'float32'); }; MathBackendCPU.prototype.clip = function (x, min, max) { cpu_util_1.assertNotComplex(x, 'clip'); var resultValues = new Float32Array(x.size); var values = this.readSync(x.dataId); for (var i = 0; i < values.length; ++i) { var v = values[i]; resultValues[i] = v > max ? max : (v < min ? min : v); } return this.makeOutput(resultValues, x.shape, 'float32'); }; MathBackendCPU.prototype.abs = function (x) { var resultValues = new Float32Array(x.size); var values = this.readSync(x.dataId); for (var i = 0; i < values.length; ++i) { resultValues[i] = Math.abs(values[i]); } return this.makeOutput(resultValues, x.shape, 'float32'); }; MathBackendCPU.prototype.complexAbs = function (x) { var resultValues = new Float32Array(x.size); var values = this.readSync(x.dataId); for (var i = 0; i < x.size; ++i) { var real_1 = values[i * 2]; var imag_1 = values[i * 2 + 1]; resultValues[i] = Math.hypot(real_1, imag_1); } return this.makeOutput(resultValues, x.shape, 'float32'); }; MathBackendCPU.prototype.int = function (x) { cpu_util_1.assertNotComplex(x, 'int'); var resultValues = new Int32Array(x.size); var values = this.readSync(x.dataId); for (var i = 0; i < values.length; ++i) { resultValues[i] = values[i]; } return this.makeOutput(resultValues, x.shape, 'int32'); }; MathBackendCPU.prototype.sigmoid = function (x) { cpu_util_1.assertNotComplex(x, 'sigmoid'); var resultValues = new Float32Array(x.size); var values = this.readSync(x.dataId); for (var i = 0; i < values.length; ++i) { resultValues[i] = 1 / (1 + Math.exp(-values[i])); } return this.makeOutput(resultValues, x.shape, 'float32'); }; MathBackendCPU.prototype.softplus = function (x) { cpu_util_1.assertNotComplex(x, 'softplus'); // mirrors the implementation of tf.nn.softplus: https://goo.gl/vkcvwX // epsilon is the difference between 1.0 and the next representable float. // For a single precision 32 bit float this should be 2^-23, see: // https://math.byu.edu/~schow/work/IEEEFloatingPoint.htm var epsilon = 1.1920928955078125e-7; var threshold = Math.log(epsilon) + 2.0; var resultValues = new Float32Array(x.size); var values = this.readSync(x.dataId); for (var i = 0; i < values.length; ++i) { // Value above which exp(x) may overflow, but softplus(x) == x // is within machine epsilon. var tooLarge = values[i] > -threshold; // Value below which exp(x) may underflow, but softplus(x) == exp(x) // is within machine epsilon. var tooSmall = values[i] < threshold; var expX = Math.exp(values[i]); var result = void 0; if (tooSmall) { result = expX; } else if (tooLarge) { result = values[i]; } else { result = Math.log(1.0 + expX); } resultValues[i] = result; } return this.makeOutput(resultValues, x.shape, 'float32'); }; MathBackendCPU.prototype.sin = function (x) { cpu_util_1.assertNotComplex(x, 'sin'); var resultValues = new Float32Array(x.size); var values = this.readSync(x.dataId); for (var i = 0; i < values.length; ++i) { resultValues[i] = Math.sin(values[i]); } return this.makeOutput(resultValues, x.shape, 'float32'); }; MathBackendCPU.prototype.cos = function (x) { cpu_util_1.assertNotComplex(x, 'cos'); var resultValues = new Float32Array(x.size); var values = this.readSync(x.dataId); for (var i = 0; i < values.length; ++i) { resultValues[i] = Math.cos(values[i]); } return this.makeOutput(resultValues, x.shape, 'float32'); }; MathBackendCPU.prototype.tan = function (x) { cpu_util_1.assertNotComplex(x, 'tan'); var resultValues = new Float32Array(x.size); var values = this.readSync(x.dataId); for (var i = 0; i < values.length; ++i) { resultValues[i] = Math.tan(values[i]); } return this.makeOutput(resultValues, x.shape, 'float32'); }; MathBackendCPU.prototype.asin = function (x) { cpu_util_1.assertNotComplex(x, 'asin'); var resultValues = new Float32Array(x.size); var values = this.readSync(x.dataId); for (var i = 0; i < values.length; ++i) {