@tensorflow/tfjs-core
Version:
Hardware-accelerated JavaScript library for machine intelligence
913 lines • 45 kB
JavaScript
"use strict";
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 = y[op[0] & 2 ? "return" : op[0] ? "throw" : "next"]) && !(t = t.call(y, op[1])).done) return t;
if (y = 0, t) op = [0, 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 environment_1 = require("../environment");
var axis_util = require("../ops/axis_util");
var ops = require("../ops/ops");
var reduce_util = require("../ops/reduce_util");
var slice_util_1 = require("../ops/slice_util");
var tensor_1 = require("../tensor");
var types = require("../types");
var util = require("../util");
var backend_util = require("./backend_util");
var argminmax_gpu_1 = require("./webgl/argminmax_gpu");
var avg_pool_backprop_gpu_1 = require("./webgl/avg_pool_backprop_gpu");
var batchnorm_gpu_1 = require("./webgl/batchnorm_gpu");
var binaryop_gpu = require("./webgl/binaryop_gpu");
var binaryop_gpu_1 = require("./webgl/binaryop_gpu");
var clip_gpu_1 = require("./webgl/clip_gpu");
var concat_gpu_1 = require("./webgl/concat_gpu");
var conv_backprop_gpu_1 = require("./webgl/conv_backprop_gpu");
var conv_gpu_1 = require("./webgl/conv_gpu");
var conv_gpu_depthwise_1 = require("./webgl/conv_gpu_depthwise");
var cumsum_gpu_1 = require("./webgl/cumsum_gpu");
var from_pixels_gpu_1 = require("./webgl/from_pixels_gpu");
var gather_gpu_1 = require("./webgl/gather_gpu");
var gpgpu_context_1 = require("./webgl/gpgpu_context");
var gpgpu_math = require("./webgl/gpgpu_math");
var gpgpu_util = require("./webgl/gpgpu_util");
var logical_gpu_1 = require("./webgl/logical_gpu");
var lrn_gpu_1 = require("./webgl/lrn_gpu");
var max_pool_backprop_gpu_1 = require("./webgl/max_pool_backprop_gpu");
var mulmat_gpu_1 = require("./webgl/mulmat_gpu");
var multinomial_gpu_1 = require("./webgl/multinomial_gpu");
var onehot_gpu_1 = require("./webgl/onehot_gpu");
var pad_gpu_1 = require("./webgl/pad_gpu");
var pool_gpu_1 = require("./webgl/pool_gpu");
var reduce_gpu_1 = require("./webgl/reduce_gpu");
var resize_bilinear_backprop_gpu_1 = require("./webgl/resize_bilinear_backprop_gpu");
var resize_bilinear_gpu_1 = require("./webgl/resize_bilinear_gpu");
var resize_nearest_neighbor_gpu_1 = require("./webgl/resize_nearest_neighbor_gpu");
var reverse_gpu_1 = require("./webgl/reverse_gpu");
var slice_gpu_1 = require("./webgl/slice_gpu");
var strided_slice_gpu_1 = require("./webgl/strided_slice_gpu");
var tex_util_1 = require("./webgl/tex_util");
var texture_manager_1 = require("./webgl/texture_manager");
var tile_gpu_1 = require("./webgl/tile_gpu");
var transpose_gpu_1 = require("./webgl/transpose_gpu");
var unary_op = require("./webgl/unaryop_gpu");
var unaryop_gpu_1 = require("./webgl/unaryop_gpu");
var webgl_util = require("./webgl/webgl_util");
var MathBackendWebGL = (function () {
function MathBackendWebGL(gpgpu, delayedStorage) {
if (delayedStorage === void 0) { delayedStorage = true; }
this.gpgpu = gpgpu;
this.delayedStorage = delayedStorage;
this.texData = new WeakMap();
this.uploadWaitMs = 0;
this.downloadWaitMs = 0;
this.binaryCache = {};
this.disposed = false;
if (environment_1.ENV.get('WEBGL_VERSION') < 1) {
throw new Error('WebGL is not supported on this device');
}
if (typeof document !== 'undefined') {
this.canvas = document.createElement('canvas');
}
if (gpgpu == null) {
this.gpgpu = new gpgpu_context_1.GPGPUContext(gpgpu_util.createWebGLContext(this.canvas));
this.gpgpuCreatedLocally = true;
}
else {
this.gpgpuCreatedLocally = false;
}
this.textureManager = new texture_manager_1.TextureManager(this.gpgpu);
}
MathBackendWebGL.prototype.register = function (dataId, shape, dtype) {
if (this.texData.has(dataId)) {
throw new Error('Data buffer is already registered');
}
this.texData.set(dataId, {
shape: shape,
dtype: dtype,
values: null,
texture: null,
texShape: null,
texType: tex_util_1.TextureType.FLOAT
});
};
MathBackendWebGL.prototype.fromPixels = function (pixels, numChannels) {
if (pixels == null) {
throw new Error('MathBackendWebGL.writePixels(): pixels can not be null');
}
var texShape = [pixels.height, pixels.width];
var outShape = [pixels.height, pixels.width, numChannels];
if (pixels instanceof HTMLVideoElement) {
if (this.fromPixelsCanvas == null) {
if (typeof document === 'undefined') {
throw new Error('Can\'t read pixels from HTMLImageElement outside the browser.');
}
if (document.readyState !== 'complete') {
throw new Error('The DOM is not ready yet. Please call tf.fromPixels() ' +
'once the DOM is ready. One way to do that is to add an event ' +
'listener for `DOMContentLoaded` on the document object');
}
this.fromPixelsCanvas = document.createElement('canvas');
}
this.fromPixelsCanvas.width = pixels.width;
this.fromPixelsCanvas.height = pixels.height;
this.fromPixelsCanvas.getContext('2d').drawImage(pixels, 0, 0, pixels.width, pixels.height);
pixels = this.fromPixelsCanvas;
}
var tempPixelArray = tensor_1.Tensor.make(texShape, {}, 'int32');
this.texData.get(tempPixelArray.dataId).texType = tex_util_1.TextureType.UNSIGNED_BYTE;
this.gpgpu.uploadPixelDataToTexture(this.getTexture(tempPixelArray.dataId), pixels);
var program = new from_pixels_gpu_1.FromPixelsProgram(outShape);
var res = this.compileAndRun(program, [tempPixelArray]);
tempPixelArray.dispose();
return res;
};
MathBackendWebGL.prototype.write = function (dataId, values) {
if (values == null) {
throw new Error('MathBackendWebGL.write(): values can not be null');
}
this.throwIfNoData(dataId);
var texData = this.texData.get(dataId);
var texture = texData.texture, texShape = texData.texShape, texType = texData.texType;
if (texture != null) {
this.textureManager.releaseTexture(texture, texShape, texType);
texData.texture = null;
texData.texShape = null;
}
texData.values = values;
if (!this.delayedStorage) {
this.uploadToGPU(dataId);
}
};
MathBackendWebGL.prototype.readSync = function (dataId) {
this.throwIfNoData(dataId);
var texData = this.texData.get(dataId);
var texture = texData.texture, values = texData.values, texShape = texData.texShape;
if (values != null) {
this.cacheOnCPU(dataId);
return values;
}
var shouldTimeProgram = this.activeTimers != null;
var start;
if (shouldTimeProgram) {
start = performance.now();
}
var float32Values = this.gpgpu.downloadMatrixFromTexture(texture, texShape[0], texShape[1]);
if (shouldTimeProgram) {
this.downloadWaitMs += performance.now() - start;
}
this.cacheOnCPU(dataId, float32Values);
return texData.values;
};
MathBackendWebGL.prototype.read = function (dataId) {
return __awaiter(this, void 0, void 0, function () {
var texData, texture, values, texShape, float32Values;
return __generator(this, function (_a) {
switch (_a.label) {
case 0:
this.throwIfNoData(dataId);
texData = this.texData.get(dataId);
texture = texData.texture, values = texData.values, texShape = texData.texShape;
if (values != null) {
this.cacheOnCPU(dataId);
return [2, values];
}
if (!environment_1.ENV.get('WEBGL_GET_BUFFER_SUB_DATA_ASYNC_EXTENSION_ENABLED')) return [3, 2];
return [4, this.gpgpu.downloadMatrixFromTextureAsync(texture, texShape[0], texShape[1])];
case 1:
float32Values = _a.sent();
this.cacheOnCPU(dataId, float32Values);
return [2, texData.values];
case 2:
if (environment_1.ENV.get('WEBGL_DISJOINT_QUERY_TIMER_EXTENSION_VERSION') === 0) {
return [2, this.readSync(dataId)];
}
return [4, this.gpgpu.runQuery(function () { })];
case 3:
_a.sent();
return [2, this.readSync(dataId)];
}
});
});
};
MathBackendWebGL.prototype.time = function (f) {
return __awaiter(this, void 0, void 0, function () {
var oldActiveTimers, newActiveTimers, outerMostTime, flattenedActiveTimers, kernelMs, res;
return __generator(this, function (_a) {
switch (_a.label) {
case 0:
oldActiveTimers = this.activeTimers;
newActiveTimers = [];
outerMostTime = false;
if (this.programTimersStack == null) {
this.programTimersStack = newActiveTimers;
outerMostTime = true;
}
else {
this.activeTimers.push(newActiveTimers);
}
this.activeTimers = newActiveTimers;
f();
flattenedActiveTimers = util.flatten(this.activeTimers);
this.activeTimers = oldActiveTimers;
if (outerMostTime) {
this.programTimersStack = null;
}
return [4, Promise.all(flattenedActiveTimers).then(function (results) {
var sum = 0;
results.forEach(function (result) { return sum += result; });
return sum;
})];
case 1:
kernelMs = _a.sent();
res = {
uploadWaitMs: this.uploadWaitMs,
downloadWaitMs: this.downloadWaitMs,
kernelMs: kernelMs,
wallMs: null
};
this.uploadWaitMs = 0;
this.downloadWaitMs = 0;
return [2, res];
}
});
});
};
MathBackendWebGL.prototype.memory = function () {
return { unreliable: false };
};
MathBackendWebGL.prototype.startTimer = function () {
if (environment_1.ENV.get('WEBGL_DISJOINT_QUERY_TIMER_EXTENSION_VERSION') > 0) {
return this.gpgpu.beginQuery();
}
return { startMs: performance.now(), endMs: null };
};
MathBackendWebGL.prototype.endTimer = function (query) {
if (environment_1.ENV.get('WEBGL_DISJOINT_QUERY_TIMER_EXTENSION_VERSION') > 0) {
this.gpgpu.endQuery();
return query;
}
query.endMs = performance.now();
return query;
};
MathBackendWebGL.prototype.getQueryTime = function (query) {
return __awaiter(this, void 0, void 0, function () {
var timerQuery;
return __generator(this, function (_a) {
if (environment_1.ENV.get('WEBGL_DISJOINT_QUERY_TIMER_EXTENSION_VERSION') > 0) {
return [2, this.gpgpu.pollQueryTime(query)];
}
timerQuery = query;
return [2, timerQuery.endMs - timerQuery.startMs];
});
});
};
MathBackendWebGL.prototype.disposeData = function (dataId) {
if (this.texData.has(dataId)) {
var _a = this.texData.get(dataId), texture = _a.texture, texShape = _a.texShape, texType = _a.texType;
if (texture != null) {
this.textureManager.releaseTexture(texture, texShape, texType);
}
this.texData.delete(dataId);
}
};
MathBackendWebGL.prototype.getTexture = function (dataId) {
this.uploadToGPU(dataId);
return this.texData.get(dataId).texture;
};
MathBackendWebGL.prototype.getTextureData = function (dataId) {
this.uploadToGPU(dataId);
return this.texData.get(dataId);
};
MathBackendWebGL.prototype.getGPGPUContext = function () {
return this.gpgpu;
};
MathBackendWebGL.prototype.getCanvas = function () {
return this.canvas;
};
MathBackendWebGL.prototype.slice = function (x, begin, size) {
var program = new slice_gpu_1.SliceProgram(size);
var customSetup = program.getCustomSetupFunc(begin);
return this.compileAndRun(program, [x], null, customSetup);
};
MathBackendWebGL.prototype.stridedSlice = function (x, begin, end, strides, beginMask, endMask) {
var _a = slice_util_1.getStridedSlicedInfo(x.shape, begin, end, strides, beginMask, endMask), beginIndex = _a[0], size = _a[1];
if (size.some(function (axis) { return axis === 0; })) {
return ops.tensor([], size);
}
var program = new strided_slice_gpu_1.StridedSliceProgram(beginIndex, strides, size);
return this.compileAndRun(program, [x]);
};
MathBackendWebGL.prototype.reverse = function (x, axis) {
var program = new reverse_gpu_1.ReverseProgram(x.shape, axis);
return this.compileAndRun(program, [x]);
};
MathBackendWebGL.prototype.concat = function (a, b) {
var program = new concat_gpu_1.ConcatProgram(a.shape, b.shape);
return this.compileAndRun(program, [a, b]);
};
MathBackendWebGL.prototype.neg = function (x) {
var program = new unaryop_gpu_1.UnaryOpProgram(x.shape, unary_op.NEG);
return this.compileAndRun(program, [x]);
};
MathBackendWebGL.prototype.matMul = function (a, b, transposeA, transposeB) {
var program = new mulmat_gpu_1.MatMulProgram(a.shape, b.shape, transposeA, transposeB);
return this.compileAndRun(program, [a, b]);
};
MathBackendWebGL.prototype.multiply = function (a, b) {
var program = new binaryop_gpu_1.BinaryOpProgram(binaryop_gpu.MUL, a.shape, b.shape);
var output = this.makeOutputArray(program.outputShape, types.upcastType(a.dtype, b.dtype));
return this.compileAndRun(program, [a, b], output);
};
MathBackendWebGL.prototype.batchNormalization = function (x, mean, variance, varianceEpsilon, scale, offset) {
var inputs = [x, mean, variance];
var offsetShape = null;
if (offset != null) {
offsetShape = offset.shape;
inputs.push(offset);
}
var scaleShape = null;
if (scale != null) {
scaleShape = scale.shape;
inputs.push(scale);
}
var program = new batchnorm_gpu_1.BatchNormProgram(x.shape, mean.shape, variance.shape, offsetShape, scaleShape, varianceEpsilon);
return this.compileAndRun(program, inputs);
};
MathBackendWebGL.prototype.localResponseNormalization4D = function (x, radius, bias, alpha, beta) {
var program = new lrn_gpu_1.LRNProgram(x.shape, radius, bias, alpha, beta);
return this.compileAndRun(program, [x]);
};
MathBackendWebGL.prototype.tile = function (x, reps) {
var program = new tile_gpu_1.TileProgram(x.shape, reps);
return this.compileAndRun(program, [x]);
};
MathBackendWebGL.prototype.pad = function (x, paddings, constantValue) {
var program = new pad_gpu_1.PadProgram(x.shape, paddings, constantValue);
return this.compileAndRun(program, [x]);
};
MathBackendWebGL.prototype.transpose = function (x, perm) {
var program = new transpose_gpu_1.TransposeProgram(x.shape, perm);
return this.compileAndRun(program, [x]);
};
MathBackendWebGL.prototype.gather = function (x, indices, axis) {
var program = new gather_gpu_1.GatherProgram(x.shape, indices.size, axis);
return this.compileAndRun(program, [x, indices]);
};
MathBackendWebGL.prototype.reduce = function (x, reduceType, dtype) {
var batchSize = x.shape[0];
var inSize = x.shape[1];
var windowSize = reduce_util.computeOptimalWindowSize(inSize);
var reduceInfo = { windowSize: windowSize, inSize: inSize, batchSize: batchSize };
var program = new reduce_gpu_1.ReduceProgram(reduceInfo, reduceType);
var _a = program.outputShape, rows = _a[0], cols = _a[1];
var output = this.makeOutputArray([rows, cols], dtype);
this.compileAndRun(program, [x], output);
if (output.shape[1] === 1) {
return output;
}
return this.reduce(output, reduceType, dtype);
};
MathBackendWebGL.prototype.argReduce = function (x, reduceType, bestIndicesA) {
if (bestIndicesA === void 0) { bestIndicesA = null; }
var batchSize = x.shape[0];
var inSize = x.shape[1];
if (bestIndicesA != null) {
batchSize = bestIndicesA.shape[0];
inSize = bestIndicesA.shape[1];
}
var windowSize = reduce_util.computeOptimalWindowSize(inSize);
var reduceInfo = { windowSize: windowSize, inSize: inSize, batchSize: batchSize };
var program = new argminmax_gpu_1.ArgMinMaxProgram(reduceInfo, reduceType, bestIndicesA == null);
var _a = program.outputShape, rows = _a[0], cols = _a[1];
var output = this.makeOutputArray([rows, cols], 'int32');
var inputs = [x];
if (bestIndicesA != null) {
inputs.push(bestIndicesA);
}
this.compileAndRun(program, inputs, output);
if (output.shape[1] === 1) {
return output;
}
return this.argReduce(x, reduceType, output);
};
MathBackendWebGL.prototype.sum = function (x, axes) {
axis_util.assertAxesAreInnerMostDims('sum', axes, x.rank);
var _a = axis_util.computeOutAndReduceShapes(x.shape, axes), outShape = _a[0], reduceShape = _a[1];
var inSize = util.sizeFromShape(reduceShape);
var a2D = x.as2D(-1, inSize);
var outputDType = types.sumOutType(x.dtype);
return this.reduce(a2D, 'sum', outputDType).reshape(outShape);
};
MathBackendWebGL.prototype.argMin = function (x, axis) {
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 inSize = util.sizeFromShape(reduceShape);
var a2D = x.as2D(-1, inSize);
return this.argReduce(a2D, 'min').reshape(outShape);
};
MathBackendWebGL.prototype.argMax = function (x, axis) {
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 inSize = util.sizeFromShape(reduceShape);
var a2D = x.as2D(-1, inSize);
return this.argReduce(a2D, 'max').reshape(outShape);
};
MathBackendWebGL.prototype.cumsum = function (x, axis, exclusive, reverse) {
if (axis !== x.rank - 1) {
throw new Error("WebGL cumsum shader expects an inner-most axis=" + (x.rank - 1) + " " +
("but got axis=" + axis));
}
var program = new cumsum_gpu_1.CumSumProgram(x.shape, exclusive, reverse);
return this.compileAndRun(program, [x]);
};
MathBackendWebGL.prototype.equal = function (a, b) {
var program = new binaryop_gpu_1.BinaryOpProgram(binaryop_gpu.EQUAL, a.shape, b.shape);
var output = this.makeOutputArray(program.outputShape, 'bool');
return this.compileAndRun(program, [a, b], output);
};
MathBackendWebGL.prototype.notEqual = function (a, b) {
var program = new binaryop_gpu_1.BinaryOpProgram(binaryop_gpu.NOT_EQUAL, a.shape, b.shape);
var output = this.makeOutputArray(program.outputShape, 'bool');
return this.compileAndRun(program, [a, b], output);
};
MathBackendWebGL.prototype.less = function (a, b) {
var program = new binaryop_gpu_1.BinaryOpProgram(binaryop_gpu.LESS, a.shape, b.shape);
var output = this.makeOutputArray(program.outputShape, 'bool');
return this.compileAndRun(program, [a, b], output);
};
MathBackendWebGL.prototype.lessEqual = function (a, b) {
var program = new binaryop_gpu_1.BinaryOpProgram(binaryop_gpu.LESS_EQUAL, a.shape, b.shape);
var output = this.makeOutputArray(program.outputShape, 'bool');
return this.compileAndRun(program, [a, b], output);
};
MathBackendWebGL.prototype.greater = function (a, b) {
var program = new binaryop_gpu_1.BinaryOpProgram(binaryop_gpu.GREATER, a.shape, b.shape);
var output = this.makeOutputArray(program.outputShape, 'bool');
return this.compileAndRun(program, [a, b], output);
};
MathBackendWebGL.prototype.greaterEqual = function (a, b) {
var program = new binaryop_gpu_1.BinaryOpProgram(binaryop_gpu.GREATER_EQUAL, a.shape, b.shape);
var output = this.makeOutputArray(program.outputShape, 'bool');
return this.compileAndRun(program, [a, b], output);
};
MathBackendWebGL.prototype.logicalNot = function (x) {
var program = new unaryop_gpu_1.UnaryOpProgram(x.shape, unary_op.LOGICAL_NOT);
return this.compileAndRun(program, [x]);
};
MathBackendWebGL.prototype.logicalAnd = function (a, b) {
var program = new binaryop_gpu_1.BinaryOpProgram(binaryop_gpu.LOGICAL_AND, a.shape, b.shape);
var output = this.makeOutputArray(program.outputShape, 'bool');
return this.compileAndRun(program, [a, b], output);
};
MathBackendWebGL.prototype.logicalOr = function (a, b) {
var program = new binaryop_gpu_1.BinaryOpProgram(binaryop_gpu.LOGICAL_OR, a.shape, b.shape);
var output = this.makeOutputArray(program.outputShape, 'bool');
return this.compileAndRun(program, [a, b], output);
};
MathBackendWebGL.prototype.where = function (condition, a, b, dtype) {
var program = new logical_gpu_1.WhereProgram(condition.rank, a.shape, a.rank);
var output = this.makeOutputArray(program.outputShape, dtype);
return this.compileAndRun(program, [condition, a, b], output);
};
MathBackendWebGL.prototype.topKValues = function (x, k) {
throw new Error('topKValues GPU not yet implemented!');
};
MathBackendWebGL.prototype.topKIndices = function (x, k) {
throw new Error('topKIndices GPU not yet implemented!');
};
MathBackendWebGL.prototype.min = function (x, axes) {
axis_util.assertAxesAreInnerMostDims('min', axes, x.rank);
var _a = axis_util.computeOutAndReduceShapes(x.shape, axes), outShape = _a[0], reduceShape = _a[1];
var inSize = util.sizeFromShape(reduceShape);
var a2D = x.as2D(-1, inSize);
return this.reduce(a2D, 'min', a2D.dtype).reshape(outShape);
};
MathBackendWebGL.prototype.minimum = function (a, b) {
var program = new binaryop_gpu_1.BinaryOpProgram(binaryop_gpu.MIN, a.shape, b.shape);
return this.compileAndRun(program, [a, b]);
};
MathBackendWebGL.prototype.mod = function (a, b) {
var program = new binaryop_gpu_1.BinaryOpProgram(binaryop_gpu.MOD, a.shape, b.shape);
return this.compileAndRun(program, [a, b]);
};
MathBackendWebGL.prototype.max = function (x, axes) {
axis_util.assertAxesAreInnerMostDims('max', axes, x.rank);
var _a = axis_util.computeOutAndReduceShapes(x.shape, axes), outShape = _a[0], reduceShape = _a[1];
var inSize = util.sizeFromShape(reduceShape);
var a2D = x.as2D(-1, inSize);
return this.reduce(a2D, 'max', a2D.dtype).reshape(outShape);
};
MathBackendWebGL.prototype.maximum = function (a, b) {
var program = new binaryop_gpu_1.BinaryOpProgram(binaryop_gpu.MAX, a.shape, b.shape);
return this.compileAndRun(program, [a, b]);
};
MathBackendWebGL.prototype.squaredDifference = function (a, b) {
var program = new binaryop_gpu_1.BinaryOpProgram(binaryop_gpu.SQUARED_DIFFERENCE, a.shape, b.shape);
return this.compileAndRun(program, [a, b]);
};
MathBackendWebGL.prototype.divide = function (a, b) {
var op;
var outputDtype;
if (a.dtype === 'int32' && b.dtype === 'int32') {
op = binaryop_gpu.INT_DIV;
outputDtype = 'int32';
}
else {
op = binaryop_gpu.DIV;
outputDtype = 'float32';
}
var program = new binaryop_gpu_1.BinaryOpProgram(op, a.shape, b.shape);
var output = this.makeOutputArray(program.outputShape, outputDtype);
return this.compileAndRun(program, [a, b], output);
};
MathBackendWebGL.prototype.add = function (a, b) {
var program = new binaryop_gpu_1.BinaryOpProgram(binaryop_gpu.ADD, a.shape, b.shape);
var output = this.makeOutputArray(program.outputShape, types.upcastType(a.dtype, b.dtype));
return this.compileAndRun(program, [a, b], output);
};
MathBackendWebGL.prototype.subtract = function (a, b) {
var program = new binaryop_gpu_1.BinaryOpProgram(binaryop_gpu.SUB, a.shape, b.shape);
var output = this.makeOutputArray(program.outputShape, types.upcastType(a.dtype, b.dtype));
return this.compileAndRun(program, [a, b], output);
};
MathBackendWebGL.prototype.pow = function (a, b) {
var program = new binaryop_gpu_1.BinaryOpProgram(binaryop_gpu.POW, a.shape, b.shape);
var output = this.makeOutputArray(program.outputShape, types.upcastType(a.dtype, b.dtype));
return this.compileAndRun(program, [a, b], output);
};
MathBackendWebGL.prototype.ceil = function (x) {
var program = new unaryop_gpu_1.UnaryOpProgram(x.shape, unary_op.CEIL);
return this.compileAndRun(program, [x]);
};
MathBackendWebGL.prototype.floor = function (x) {
var program = new unaryop_gpu_1.UnaryOpProgram(x.shape, unary_op.FLOOR);
return this.compileAndRun(program, [x]);
};
MathBackendWebGL.prototype.sign = function (x) {
var program = new unaryop_gpu_1.UnaryOpProgram(x.shape, unary_op.SIGN);
return this.compileAndRun(program, [x]);
};
MathBackendWebGL.prototype.round = function (x) {
var program = new unaryop_gpu_1.UnaryOpProgram(x.shape, unary_op.ROUND);
return this.compileAndRun(program, [x]);
};
MathBackendWebGL.prototype.exp = function (x) {
var program = new unaryop_gpu_1.UnaryOpProgram(x.shape, unary_op.EXP);
return this.compileAndRun(program, [x]);
};
MathBackendWebGL.prototype.expm1 = function (x) {
var program = new unaryop_gpu_1.UnaryOpProgram(x.shape, unary_op.EXPM1);
return this.compileAndRun(program, [x]);
};
MathBackendWebGL.prototype.log = function (x) {
var program = new unaryop_gpu_1.UnaryOpProgram(x.shape, unary_op.LOG);
return this.compileAndRun(program, [x]);
};
MathBackendWebGL.prototype.log1p = function (x) {
var program = new unaryop_gpu_1.UnaryOpProgram(x.shape, unary_op.LOG1P);
return this.compileAndRun(program, [x]);
};
MathBackendWebGL.prototype.sqrt = function (x) {
var program = new unaryop_gpu_1.UnaryOpProgram(x.shape, unary_op.SQRT);
return this.compileAndRun(program, [x]);
};
MathBackendWebGL.prototype.rsqrt = function (x) {
var program = new unaryop_gpu_1.UnaryOpProgram(x.shape, unary_op.RSQRT);
return this.compileAndRun(program, [x]);
};
MathBackendWebGL.prototype.square = function (x) {
var program = new unaryop_gpu_1.UnaryOpProgram(x.shape, unary_op.SQUARE);
return this.compileAndRun(program, [x]);
};
MathBackendWebGL.prototype.reciprocal = function (x) {
var program = new unaryop_gpu_1.UnaryOpProgram(x.shape, unary_op.RECIPROCAL);
return this.compileAndRun(program, [x]);
};
MathBackendWebGL.prototype.relu = function (x) {
var program = new unaryop_gpu_1.UnaryOpProgram(x.shape, unary_op.RELU);
return this.compileAndRun(program, [x]);
};
MathBackendWebGL.prototype.elu = function (x) {
var program = new unaryop_gpu_1.UnaryOpProgram(x.shape, unary_op.ELU);
return this.compileAndRun(program, [x]);
};
MathBackendWebGL.prototype.eluDer = function (dy, y) {
var program = new binaryop_gpu_1.BinaryOpProgram(binaryop_gpu.ELU_DER, dy.shape, y.shape);
return this.compileAndRun(program, [dy, y]);
};
MathBackendWebGL.prototype.selu = function (x) {
var program = new unaryop_gpu_1.UnaryOpProgram(x.shape, unary_op.SELU);
return this.compileAndRun(program, [x]);
};
MathBackendWebGL.prototype.int = function (x) {
var program = new unaryop_gpu_1.UnaryOpProgram(x.shape, unary_op.TO_INT);
var output = this.makeOutputArray(program.outputShape, 'int32');
return this.compileAndRun(program, [x], output);
};
MathBackendWebGL.prototype.clip = function (x, min, max) {
var program = new clip_gpu_1.ClipProgram(x.shape, min, max);
return this.compileAndRun(program, [x]);
};
MathBackendWebGL.prototype.abs = function (x) {
var program = new unaryop_gpu_1.UnaryOpProgram(x.shape, unary_op.ABS);
return this.compileAndRun(program, [x]);
};
MathBackendWebGL.prototype.sigmoid = function (x) {
var program = new unaryop_gpu_1.UnaryOpProgram(x.shape, unary_op.SIGMOID);
return this.compileAndRun(program, [x]);
};
MathBackendWebGL.prototype.softplus = function (x) {
var program = new unaryop_gpu_1.UnaryOpProgram(x.shape, unary_op.SOFTPLUS);
return this.compileAndRun(program, [x]);
};
MathBackendWebGL.prototype.sin = function (x) {
var program = new unaryop_gpu_1.UnaryOpProgram(x.shape, unary_op.SIN);
return this.compileAndRun(program, [x]);
};
MathBackendWebGL.prototype.cos = function (x) {
var program = new unaryop_gpu_1.UnaryOpProgram(x.shape, unary_op.COS);
return this.compileAndRun(program, [x]);
};
MathBackendWebGL.prototype.tan = function (x) {
var program = new unaryop_gpu_1.UnaryOpProgram(x.shape, unary_op.TAN);
return this.compileAndRun(program, [x]);
};
MathBackendWebGL.prototype.asin = function (x) {
var program = new unaryop_gpu_1.UnaryOpProgram(x.shape, unary_op.ASIN);
return this.compileAndRun(program, [x]);
};
MathBackendWebGL.prototype.acos = function (x) {
var program = new unaryop_gpu_1.UnaryOpProgram(x.shape, unary_op.ACOS);
return this.compileAndRun(program, [x]);
};
MathBackendWebGL.prototype.atan = function (x) {
var program = new unaryop_gpu_1.UnaryOpProgram(x.shape, unary_op.ATAN);
return this.compileAndRun(program, [x]);
};
MathBackendWebGL.prototype.atan2 = function (a, b) {
var program = new binaryop_gpu_1.BinaryOpProgram(binaryop_gpu.ATAN2, a.shape, b.shape);
return this.compileAndRun(program, [a, b]);
};
MathBackendWebGL.prototype.sinh = function (x) {
var program = new unaryop_gpu_1.UnaryOpProgram(x.shape, unary_op.SINH);
return this.compileAndRun(program, [x]);
};
MathBackendWebGL.prototype.cosh = function (x) {
var program = new unaryop_gpu_1.UnaryOpProgram(x.shape, unary_op.COSH);
return this.compileAndRun(program, [x]);
};
MathBackendWebGL.prototype.tanh = function (x) {
var program = new unaryop_gpu_1.UnaryOpProgram(x.shape, unary_op.TANH);
return this.compileAndRun(program, [x]);
};
MathBackendWebGL.prototype.asinh = function (x) {
var program = new unaryop_gpu_1.UnaryOpProgram(x.shape, unary_op.ASINH);
return this.compileAndRun(program, [x]);
};
MathBackendWebGL.prototype.acosh = function (x) {
var program = new unaryop_gpu_1.UnaryOpProgram(x.shape, unary_op.ACOSH);
return this.compileAndRun(program, [x]);
};
MathBackendWebGL.prototype.atanh = function (x) {
var program = new unaryop_gpu_1.UnaryOpProgram(x.shape, unary_op.ATANH);
return this.compileAndRun(program, [x]);
};
MathBackendWebGL.prototype.erf = function (x) {
var program = new unaryop_gpu_1.UnaryOpProgram(x.shape, unary_op.ERF);
return this.compileAndRun(program, [x]);
};
MathBackendWebGL.prototype.step = function (x, alpha) {
var program = new unaryop_gpu_1.UnaryOpProgram(x.shape, unary_op.STEP(alpha));
return this.compileAndRun(program, [x]);
};
MathBackendWebGL.prototype.conv2d = function (x, filter, convInfo) {
var program = new conv_gpu_1.Conv2DProgram(convInfo);
return this.compileAndRun(program, [x, filter]);
};
MathBackendWebGL.prototype.conv2dDerInput = function (dy, filter, convInfo) {
var program = new conv_backprop_gpu_1.Conv2DDerInputProgram(convInfo);
return this.compileAndRun(program, [dy, filter]);
};
MathBackendWebGL.prototype.conv2dDerFilter = function (x, dy, convInfo) {
var program = new conv_backprop_gpu_1.Conv2DDerFilterProgram(convInfo);
return this.compileAndRun(program, [x, dy]);
};
MathBackendWebGL.prototype.depthwiseConv2D = function (x, filter, convInfo) {
var program = new conv_gpu_depthwise_1.DepthwiseConv2DProgram(convInfo);
return this.compileAndRun(program, [x, filter]);
};
MathBackendWebGL.prototype.maxPool = function (x, convInfo) {
var program = new pool_gpu_1.Pool2DProgram(convInfo, 'max', false);
var output = this.makeOutputArray(program.outputShape, x.dtype);
return this.compileAndRun(program, [x], output);
};
MathBackendWebGL.prototype.avgPool = function (x, convInfo) {
var program = new pool_gpu_1.Pool2DProgram(convInfo, 'avg', false);
var output = this.makeOutputArray(program.outputShape, 'float32');
return this.compileAndRun(program, [x], output);
};
MathBackendWebGL.prototype.maxPoolBackprop = function (dy, x, y, convInfo) {
var getPositions = true;
var maxPoolPositionsProgram = new pool_gpu_1.Pool2DProgram(convInfo, 'max', getPositions);
var maxPoolPositions = this.compileAndRun(maxPoolPositionsProgram, [x]);
var maxPoolBackPropProgram = new max_pool_backprop_gpu_1.MaxPool2DBackpropProgram(convInfo);
var output = this.makeOutputArray(maxPoolBackPropProgram.outputShape, x.dtype);
var result = this.compileAndRun(maxPoolBackPropProgram, [dy, maxPoolPositions], output);
maxPoolPositions.dispose();
return result;
};
MathBackendWebGL.prototype.avgPoolBackprop = function (dy, x, convInfo) {
var avgPoolBackpropProgram = new avg_pool_backprop_gpu_1.AvgPool2DBackpropProgram(convInfo);
var output = this.makeOutputArray(avgPoolBackpropProgram.outputShape, x.dtype);
return this.compileAndRun(avgPoolBackpropProgram, [dy], output);
};
MathBackendWebGL.prototype.cast = function (x, dtype) {
return backend_util.castTensor(x, dtype, this);
};
MathBackendWebGL.prototype.reshape = function (x, shape) {
return backend_util.reshapeTensor(x, shape);
};
MathBackendWebGL.prototype.resizeBilinear = function (x, newHeight, newWidth, alignCorners) {
var program = new resize_bilinear_gpu_1.ResizeBilinearProgram(x.shape, newHeight, newWidth, alignCorners);
return this.compileAndRun(program, [x]);
};
MathBackendWebGL.prototype.resizeBilinearBackprop = function (dy, x, alignCorners) {
var program = new resize_bilinear_backprop_gpu_1.ResizeBilinearBackpropProgram(dy, x, alignCorners);
return this.compileAndRun(program, [dy]);
};
MathBackendWebGL.prototype.resizeNearestNeighbor = function (x, newHeight, newWidth, alignCorners) {
var program = new resize_nearest_neighbor_gpu_1.ResizeNearestNeighborProgram(x.shape, newHeight, newWidth, alignCorners);
return this.compileAndRun(program, [x]);
};
MathBackendWebGL.prototype.multinomial = function (logits, normalized, numSamples, seed) {
var probs = normalized ? logits : ops.softmax(logits);
var batchSize = probs.shape[0];
var numOutcomes = probs.shape[1];
var program = new multinomial_gpu_1.MultinomialProgram(batchSize, numOutcomes, numSamples);
var output = this.makeOutputArray(program.outputShape, 'int32');
var customSetup = program.getCustomSetupFunc(seed);
return this.compileAndRun(program, [probs], output, customSetup);
};
MathBackendWebGL.prototype.oneHot = function (indices, depth, onValue, offValue) {
var program = new onehot_gpu_1.OneHotProgram(indices.size, depth, onValue, offValue);
return this.compileAndRun(program, [indices]);
};
MathBackendWebGL.prototype.makeOutputArray = function (shape, dtype) {
return tensor_1.Tensor.make(shape, {}, dtype);
};
MathBackendWebGL.prototype.compileAndRun = function (program, inputs, output, customSetup) {
var _this = this;
if (output == null) {
output = this.makeOutputArray(program.outputShape, inputs[0].dtype);
}
var inputsData = inputs.map(function (input) {
_this.uploadToGPU(input.dataId);
return { tensor: input, texData: _this.texData.get(input.dataId) };
});
this.uploadToGPU(output.dataId);
var outputData = {
tensor: output,
texData: this.texData.get(output.dataId)
};
var key = gpgpu_math.makeShaderKey(program, inputsData, outputData);
var binary = this.getAndSaveBinary(key, function () {
return gpgpu_math.compileProgram(_this.gpgpu, program, inputsData, outputData);
});
var shouldTimeProgram = this.activeTimers != null;
var query;
if (shouldTimeProgram) {
query = this.startTimer();
}
gpgpu_math.runProgram(binary, inputsData, outputData, customSetup);
if (shouldTimeProgram) {
query = this.endTimer(query);
this.activeTimers.push(this.getQueryTime(query));
}
return output;
};
MathBackendWebGL.prototype.getAndSaveBinary = function (key, getBinary) {
if (!(key in this.binaryCache)) {
this.binaryCache[key] = getBinary();
}
return this.binaryCache[key];
};
MathBackendWebGL.prototype.getTextureManager = function () {
return this.textureManager;
};
MathBackendWebGL.prototype.dispose = function () {
if (this.disposed) {
return;
}
for (var key in this.binaryCache) {
this.gpgpu.deleteProgram(this.binaryCache[key].webGLProgram);
}
this.textureManager.dispose();
this.canvas.remove();
if (this.fromPixelsCanvas != null) {
this.fromPixelsCanvas.remove();
}
if (this.gpgpuCreatedLocally) {
this.gpgpu.dispose();
}
this.disposed = true;
};
MathBackendWebGL.prototype.throwIfNoData = function (dataId) {
if (!this.texData.has(dataId)) {
throw new Error("WebGL backend: No data found for this tensor. " +
"Did you change your backend in the middle of the program? " +
"New backends can't use Tensors created with previous backends");
}
};
MathBackendWebGL.prototype.uploadToGPU = function (dataId) {
this.throwIfNoData(dataId);
var texData = this.texData.get(dataId);
var shape = texData.shape, values = texData.values, texture = texData.texture, dtype = texData.dtype, texType = texData.texType;
if (texture != null) {
return;
}
var shouldTimeProgram = this.activeTimers != null;
var start;
if (shouldTimeProgram) {
start = performance.now();
}
var texShape = webgl_util.getTextureShapeFromLogicalShape(this.gpgpu.gl, shape);
texData.texShape = texShape;
var newTexture = this.textureManager.acquireTexture(texShape, texType);
texData.texture = newTexture;
if (values != null) {
this.gpgpu.uploadMatrixToTexture(newTexture, texShape[0], texShape[1], typedArrayToFloat32(values, dtype));
texData.values = null;
if (shouldTimeProgram) {
this.uploadWaitMs += performance.now() - start;
}
}
};
MathBackendWebGL.prototype.cacheOnCPU = function (dataId, float32Values) {
var dontKeepCopyOnGPU = this.delayedStorage;
var texData = this.texData.get(dataId);
var texture = texData.texture, texShape = texData.texShape, dtype = texData.dtype, texType = texData.texType;
if (dontKeepCopyOnGPU && texture != null) {
this.textureManager.releaseTexture(texture, texShape, texType);
texData.texture = null;
texData.texShape = null;
}
if (float32Values != null) {
texData.values = float32ToTypedArray(float32Values, dtype);
}
};
return MathBackendWebGL;
}());
exports.MathBackendWebGL = MathBackendWebGL;
environment_1.ENV.registerBackend('webgl', function () { return new MathBackendWebGL(); }, 2);
function float32ToTypedArray(a, dtype) {
if (dtype === 'float32') {
return a;
}
else if (dtype === 'int32' || dtype === 'bool') {
var result = (dtype === 'int32') ? new Int32Array(a.length) :
new Uint8Array(a.length);
for (var i = 0; i < result.length; ++i) {
result[i] = Math.round(a[i]);
}
return result;
}
else {
throw new Error("Unknown dtype " + dtype);
}
}
function typedArrayToFloat32(a, dtype) {
return (a instanceof Float32Array) ? a : new Float32Array(a);
}
//# sourceMappingURL=backend_webgl.js.map