@tensorflow/tfjs-core
Version:
Hardware-accelerated JavaScript library for machine intelligence
319 lines • 16.2 kB
JavaScript
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
var test_util_1 = require("../../test_util");
var jasmine_util_1 = require("../../jasmine_util");
var gpgpu_context_1 = require("./gpgpu_context");
var mulmat_packed_gpu = require("./mulmat_packed_gpu");
var mulmat_packed_gpu_1 = require("./mulmat_packed_gpu");
jasmine_util_1.describeWithFlags('mulmat_packed_gpu (1x1 * 1x1)', test_util_1.WEBGL_ENVS, function () {
it('returns a 1x1 matrix', function () {
var a = new Float32Array([0]);
var b = new Float32Array([0]);
var result = mulmat_packed_gpu.uploadMultiplyMatrixPackedDownload(a, [1, 1], b, [1, 1]);
expect(result.length).toEqual(1);
});
it('returns [0] when multiplying [0] by [0]', function () {
var a = new Float32Array([0]);
var b = new Float32Array([0]);
var result = mulmat_packed_gpu.uploadMultiplyMatrixPackedDownload(a, [1, 1], b, [1, 1]);
expect(result[0]).toEqual(0);
});
it('returns [1] when multiplying [1] by [1]', function () {
var a = new Float32Array([1]);
var b = new Float32Array([1]);
var result = mulmat_packed_gpu.uploadMultiplyMatrixPackedDownload(a, [1, 1], b, [1, 1]);
expect(result[0]).toEqual(1);
});
it('returns [-1] when multiplying [1] by [-1]', function () {
var a = new Float32Array([1]);
var b = new Float32Array([-1]);
var result = mulmat_packed_gpu.uploadMultiplyMatrixPackedDownload(a, [1, 1], b, [1, 1]);
expect(result[0]).toEqual(-1);
});
it('returns [4.08] when multiplying [1.2] by [3.4]', function () {
var a = new Float32Array([1.2]);
var b = new Float32Array([3.4]);
var result = mulmat_packed_gpu.uploadMultiplyMatrixPackedDownload(a, [1, 1], b, [1, 1]);
test_util_1.expectNumbersClose(result[0], 4.08);
});
it('returns [356000] when multiplying [356] by [1000]', function () {
var a = new Float32Array([356]);
var b = new Float32Array([1000]);
var result = mulmat_packed_gpu.uploadMultiplyMatrixPackedDownload(a, [1, 1], b, [1, 1]);
expect(result[0]).toEqual(356000);
});
it('returns [-31415926] when multiplying [-3.1415926] by [10000000]', function () {
var a = new Float32Array([-3.1415926]);
var b = new Float32Array([10000000]);
var result = mulmat_packed_gpu.uploadMultiplyMatrixPackedDownload(a, [1, 1], b, [1, 1]);
expect(result[0]).toEqual(-31415926);
});
});
jasmine_util_1.describeWithFlags('mulmat_packed_gpu (dot product)', test_util_1.WEBGL_ENVS, function () {
it('returns a 1x1 matrix', function () {
var a = new Float32Array(5);
var b = new Float32Array(5);
var result = mulmat_packed_gpu.uploadMultiplyMatrixPackedDownload(a, [1, a.length], b, [b.length, 1]);
expect(result.length).toEqual(1);
});
it('returns zero when one vector is all zeroes', function () {
var a = new Float32Array(5);
var b = new Float32Array([1, 2, 3, 4, 5]);
var result = mulmat_packed_gpu.uploadMultiplyMatrixPackedDownload(a, [1, a.length], b, [b.length, 1]);
expect(result[0]).toEqual(0);
});
it('returns the sum of b when a is all ones', function () {
var a = new Float32Array([1, 1, 1, 1, 1]);
var b = new Float32Array([0, 1, 2, 3, 100]);
var result = mulmat_packed_gpu.uploadMultiplyMatrixPackedDownload(a, [1, a.length], b, [b.length, 1]);
expect(result[0]).toEqual(106);
});
it('computes the dot product of a and b', function () {
var a = new Float32Array([10, 20, 30, 40, 50]);
var b = new Float32Array([0.5, 1.1, 12.4, 32.5, -123.98]);
var result = mulmat_packed_gpu.uploadMultiplyMatrixPackedDownload(a, [1, a.length], b, [b.length, 1]);
var expected = cpuDotProduct(a, b);
test_util_1.expectNumbersClose(result[0], expected);
});
it('computes a dot product on very large vectors', function () {
var a = randomArrayInRange(2048, -1, 1);
var b = randomArrayInRange(2048, -1, 1);
var result = mulmat_packed_gpu.uploadMultiplyMatrixPackedDownload(a, [1, a.length], b, [b.length, 1]);
var expected = cpuDotProduct(a, b);
test_util_1.expectNumbersClose(result[0], expected);
});
});
function cpuMul2x2(a, b) {
if (a.length !== 4 || b.length !== 4) {
throw new Error('a and b must have 4 elements.');
}
var result = new Float32Array(4);
result[0] = (a[0] * b[0]) + (a[1] * b[2]);
result[1] = (a[0] * b[1]) + (a[1] * b[3]);
result[2] = (a[2] * b[0]) + (a[3] * b[2]);
result[3] = (a[2] * b[1]) + (a[3] * b[3]);
return result;
}
jasmine_util_1.describeWithFlags('mulmat_packed_gpu (2x2 * 2x2)', test_util_1.WEBGL_ENVS, function () {
it('returns a 2x2 matrix', function () {
var a = new Float32Array([0, 0, 0, 0]);
var b = new Float32Array([0, 0, 0, 0]);
var result = mulmat_packed_gpu.uploadMultiplyMatrixPackedDownload(a, [2, 2], b, [2, 2]);
expect(result.length).toEqual(4);
});
it('returns the identity when multiplying two identity matrices', function () {
var a = makeIdentity(2);
var b = makeIdentity(2);
var result = mulmat_packed_gpu.uploadMultiplyMatrixPackedDownload(a, [2, 2], b, [2, 2]);
expect(result).toEqual(cpuMul2x2(a, b));
});
it('returns [0] when A is [0]', function () {
var a = new Float32Array([0, 0, 0, 0]);
var b = new Float32Array([1, 2, 3, 4]);
var result = mulmat_packed_gpu.uploadMultiplyMatrixPackedDownload(a, [2, 2], b, [2, 2]);
expect(result).toEqual(a);
});
it('returns [0] when B is [0]', function () {
var a = new Float32Array([1, 2, 3, 4]);
var b = new Float32Array(4);
var result = mulmat_packed_gpu.uploadMultiplyMatrixPackedDownload(a, [2, 2], b, [2, 2]);
expect(result).toEqual(b);
});
it('returns B when A is identity', function () {
var a = makeIdentity(2);
var b = new Float32Array([11, -22, 33.333, -44.44444]);
var result = mulmat_packed_gpu.uploadMultiplyMatrixPackedDownload(a, [2, 2], b, [2, 2]);
expect(result).toEqual(b);
});
it('returns A when B is identity', function () {
var a = new Float32Array([11, -22, 33.333, -44.44444]);
var b = makeIdentity(2);
var result = mulmat_packed_gpu.uploadMultiplyMatrixPackedDownload(a, [2, 2], b, [2, 2]);
expect(result).toEqual(a);
});
it('returns the product of A and B when non-identity', function () {
var a = new Float32Array([10000.02, -1.2, 3.14159, -2345.1234]);
var b = new Float32Array([-23.45, 0.01234, 100, 2.5]);
var result = mulmat_packed_gpu.uploadMultiplyMatrixPackedDownload(a, [2, 2], b, [2, 2]);
expect(result).toEqual(cpuMul2x2(a, b));
});
});
jasmine_util_1.describeWithFlags('mulmat_packed_gpu (different shapes)', test_util_1.WEBGL_ENVS, function () {
it('returns a 4x1 when multiplying a 4x4 with a 4x1', function () {
var a = new Float32Array(16);
var b = new Float32Array(4);
var result = mulmat_packed_gpu.uploadMultiplyMatrixPackedDownload(a, [4, 4], b, [4, 1]);
expect(result.length).toEqual(4);
});
it('returns B (4x1) when A (4x4) is I', function () {
var a = makeIdentity(4);
var b = new Float32Array([1, 2, 3, 4]);
var result = mulmat_packed_gpu.uploadMultiplyMatrixPackedDownload(a, [4, 4], b, [4, 1]);
expect(result).toEqual(b);
});
it('4x2 * 2x2', function () {
var a = new Float32Array([1, 2, 3, 4, 5, 6, 7, 8]);
var b = new Float32Array([9, 10, 11, 12]);
var result = mulmat_packed_gpu.uploadMultiplyMatrixPackedDownload(a, [4, 2], b, [2, 2]);
var expected = cpuMultiplyMatrix(a, 4, 2, b, 2, 2);
test_util_1.expectArraysClose(result, expected);
});
it('multiplies a 4x1 by a non-identity 4x4', function () {
var a = new Float32Array([1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16]);
var b = new Float32Array([1, 2, 3, 4]);
var result = mulmat_packed_gpu.uploadMultiplyMatrixPackedDownload(a, [4, 4], b, [4, 1]);
expect(result).toEqual(cpuMultiplyMatrix(a, 4, 4, b, 4, 1));
});
it('returns a 2x3 when multiplying a 2x4 by a 4x3', function () {
var a = new Float32Array(8);
var b = new Float32Array(12);
var result = mulmat_packed_gpu.uploadMultiplyMatrixPackedDownload(a, [2, 4], b, [4, 3]);
expect(result.length).toEqual(6);
});
it('multiplies A (2x4) by B(4x3)', function () {
var a = new Float32Array([0.1, 3.2, -4.5, 11.78, -0.234, -2.999, 7, 9]);
var b = new Float32Array([1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12]);
var result = mulmat_packed_gpu.uploadMultiplyMatrixPackedDownload(a, [2, 4], b, [4, 3]);
var expected = cpuMultiplyMatrix(a, 2, 4, b, 4, 3);
test_util_1.expectArraysClose(result, expected);
});
});
jasmine_util_1.describeWithFlags('mulmat_packed_gpu (large matrices)', test_util_1.WEBGL_ENVS, function () {
it('returns 128x128 when multiplying 2 128x128s', function () {
var a = new Float32Array(128 * 128);
var b = new Float32Array(128 * 128);
var result = mulmat_packed_gpu.uploadMultiplyMatrixPackedDownload(a, [128, 128], b, [128, 128]);
expect(result.length).toEqual(128 * 128);
});
it('multiplies 2 128x128s', function () {
var a = randomArrayInRange(128 * 128, -1, 1);
var b = randomArrayInRange(128 * 128, -1, 1);
var result = mulmat_packed_gpu.uploadMultiplyMatrixPackedDownload(a, [128, 128], b, [128, 128]);
var expected = cpuMultiplyMatrix(a, 128, 128, b, 128, 128);
test_util_1.expectArraysClose(result, expected);
});
});
jasmine_util_1.describeWithFlags('mulmat_packed_gpu (multiple matrices)', test_util_1.WEBGL_ENVS, function () {
it('4x2 * 2x12 * 12x1 === 4x1', function () {
var aData = new Float32Array([0.1, 0.2, 0.3, 0.4, 0.5, 0.6, 0.7, 0.8]);
var bData = new Float32Array([
1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12,
13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24
]);
var cData = new Float32Array([
-0.1, -0.2, -0.3, -0.4, -0.5, -0.6, -0.7, -0.8, -0.9, -1.0, -1.1, -1.2
]);
var gpgpu = new gpgpu_context_1.GPGPUContext();
var axbProgram = gpgpu.createProgram(mulmat_packed_gpu.getFragmentShaderSource(2, mulmat_packed_gpu_1.MatrixOrientation.REGULAR, mulmat_packed_gpu_1.MatrixOrientation.REGULAR));
var abxcProgram = gpgpu.createProgram(mulmat_packed_gpu.getFragmentShaderSource(12, mulmat_packed_gpu_1.MatrixOrientation.REGULAR, mulmat_packed_gpu_1.MatrixOrientation.REGULAR));
var a = gpgpu.createPackedMatrixTexture(4, 2);
var b = gpgpu.createPackedMatrixTexture(2, 12);
var ab = gpgpu.createPackedMatrixTexture(4, 12);
var c = gpgpu.createPackedMatrixTexture(12, 1);
var r = gpgpu.createPackedMatrixTexture(4, 1);
gpgpu.uploadMatrixToPackedTexture(a, 4, 2, aData);
gpgpu.uploadMatrixToPackedTexture(b, 2, 12, bData);
gpgpu.uploadMatrixToPackedTexture(c, 12, 1, cData);
mulmat_packed_gpu.multiplyMatrixPacked(gpgpu, axbProgram, a, b, ab, [4, 12]);
mulmat_packed_gpu.multiplyMatrixPacked(gpgpu, abxcProgram, ab, c, r, [4, 1]);
var result = gpgpu.downloadMatrixFromPackedTexture(r, 4, 1);
var expected = cpuMultiplyMatrix(cpuMultiplyMatrix(aData, 4, 2, bData, 2, 12), 4, 12, cData, 12, 1);
test_util_1.expectArraysClose(result, expected);
gpgpu.deleteMatrixTexture(a);
gpgpu.deleteMatrixTexture(b);
gpgpu.deleteMatrixTexture(ab);
gpgpu.deleteMatrixTexture(c);
gpgpu.deleteMatrixTexture(r);
gpgpu.deleteProgram(axbProgram);
gpgpu.deleteProgram(abxcProgram);
gpgpu.dispose();
});
});
jasmine_util_1.describeWithFlags('mulmat_packed_gpu A * B^t', test_util_1.WEBGL_ENVS, function () {
it('1x1 * 1x1', function () {
var a = new Float32Array([2]);
var b = new Float32Array([3]);
var result = mulmat_packed_gpu.uploadMultiplyMatrixPackedDownload(a, [1, 1], b, [1, 1], mulmat_packed_gpu_1.MatrixOrientation.REGULAR, mulmat_packed_gpu_1.MatrixOrientation.TRANSPOSED);
expect(result[0]).toEqual(6);
});
it('2x2 * 2x2', function () {
var a = new Float32Array([1, 2, 3, 4]);
var b = new Float32Array([5, 6, 7, 8]);
var result = mulmat_packed_gpu.uploadMultiplyMatrixPackedDownload(a, [2, 2], b, [2, 2], mulmat_packed_gpu_1.MatrixOrientation.REGULAR, mulmat_packed_gpu_1.MatrixOrientation.TRANSPOSED);
var bt = new Float32Array([b[0], b[2], b[1], b[3]]);
var expected = cpuMultiplyMatrix(a, 2, 2, bt, 2, 2);
test_util_1.expectArraysClose(result, expected);
});
it('2x4 * 4x2', function () {
var a = new Float32Array([1, 2, 3, 4, 5, 6, 7, 8]);
var b = new Float32Array([9, 10, 11, 12, 13, 14, 15, 16]);
var result = mulmat_packed_gpu.uploadMultiplyMatrixPackedDownload(a, [2, 4], b, [2, 4], mulmat_packed_gpu_1.MatrixOrientation.REGULAR, mulmat_packed_gpu_1.MatrixOrientation.TRANSPOSED);
var bt = new Float32Array([b[0], b[4], b[1], b[5], b[2], b[6], b[3], b[7]]);
var expected = cpuMultiplyMatrix(a, 2, 4, bt, 4, 2);
test_util_1.expectArraysClose(result, expected);
});
});
jasmine_util_1.describeWithFlags('mulmat_packed_gpu (transposed versions)', test_util_1.WEBGL_ENVS, function () {
it('A * B^t', function () {
var a = new Float32Array([1, 2, 3, 4, 5, 6]);
var b = new Float32Array([1, 0, 2, 4, 3, 0]);
var c = mulmat_packed_gpu.uploadMultiplyMatrixPackedDownload(a, [2, 3], b, [2, 3], mulmat_packed_gpu_1.MatrixOrientation.REGULAR, mulmat_packed_gpu_1.MatrixOrientation.TRANSPOSED);
var expected = new Float32Array([7, 10, 16, 31]);
expect(c).toEqual(expected);
});
it('A^t * B', function () {
var a = new Float32Array([1, 2, 3, 4, 5, 6]);
var b = new Float32Array([1, 0, 2, 4, 3, 0]);
var c = mulmat_packed_gpu.uploadMultiplyMatrixPackedDownload(a, [2, 3], b, [2, 3], mulmat_packed_gpu_1.MatrixOrientation.TRANSPOSED, mulmat_packed_gpu_1.MatrixOrientation.REGULAR);
var expected = new Float32Array([17, 12, 2, 22, 15, 4, 27, 18, 6]);
expect(c).toEqual(expected);
});
it('A^t * B^t', function () {
var a = new Float32Array([1, 2, 3, 4, 5, 6]);
var b = new Float32Array([1, 0, 2, 4, 3, 0]);
var c = mulmat_packed_gpu.uploadMultiplyMatrixPackedDownload(a, [3, 2], b, [2, 3], mulmat_packed_gpu_1.MatrixOrientation.TRANSPOSED, mulmat_packed_gpu_1.MatrixOrientation.TRANSPOSED);
var expected = new Float32Array([11, 13, 14, 20]);
expect(c).toEqual(expected);
});
});
function randomArrayInRange(n, minValue, maxValue) {
var v = new Float32Array(n);
var range = maxValue - minValue;
for (var i = 0; i < n; ++i) {
v[i] = (Math.random() * range) + minValue;
}
return v;
}
function makeIdentity(n) {
var i = new Float32Array(n * n);
for (var j = 0; j < n; ++j) {
i[(j * n) + j] = 1;
}
return i;
}
function cpuMultiplyMatrix(a, aRow, aCol, b, bRow, bCol) {
var result = new Float32Array(aRow * bCol);
for (var r = 0; r < aRow; ++r) {
var aOffset = (r * aCol);
var cOffset = (r * bCol);
for (var c = 0; c < bCol; ++c) {
var d = 0;
for (var k = 0; k < aCol; ++k) {
d += a[aOffset + k] * b[(k * bCol) + c];
}
result[cOffset + c] = d;
}
}
return result;
}
function cpuDotProduct(a, b) {
if (a.length !== b.length) {
throw new Error('cpuDotProduct: incompatible vectors.');
}
var d = 0;
for (var i = 0; i < a.length; ++i) {
d += a[i] * b[i];
}
return d;
}
//# sourceMappingURL=mulmat_packed_gpu_test.js.map