Skip to content
This repository was archived by the owner on Aug 15, 2019. It is now read-only.

Commit 86c6188

Browse files
authored
Migrate conv2D and related ops to logical sampling (#52)
* migrate addScaledMat and conv2d to logical sampling and improve shader compiler * fix conv2d zero paddig and make the project build * migrate rest of conv shaders to logical * replace zero pad with if * migrate pool ops * address review comments
1 parent 4f0de84 commit 86c6188

39 files changed

+947
-2151
lines changed

.vscode/settings.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@
99
},
1010
"tslint.enable": true,
1111
"tslint.run": "onType",
12+
"tslint.configFile": "tslint.json",
1213
"editor.tabSize": 2,
1314
"editor.insertSpaces": true,
1415
"files.insertFinalNewline": true,

demos/benchmarks/conv_gpu_benchmark.ts

Lines changed: 31 additions & 54 deletions
Original file line numberDiff line numberDiff line change
@@ -14,76 +14,53 @@ limitations under the License.
1414
==============================================================================*/
1515

1616
import * as conv_util from '../../src/math/conv_util';
17-
import * as conv_gpu from '../../src/math/webgl/conv_gpu';
17+
import {Array1D, Array3D, Array4D, initializeGPU} from '../../src/math/ndarray';
18+
import {Conv2DProgram} from '../../src/math/webgl/conv_gpu';
1819
import {GPGPUContext} from '../../src/math/webgl/gpgpu_context';
19-
import * as test_util from '../../src/test_util';
20+
import * as gpgpu_math from '../../src/math/webgl/gpgpu_math';
21+
import {TextureManager} from '../../src/math/webgl/texture_manager';
2022

2123
import {BenchmarkTest} from './benchmark';
2224

2325
const OP_RUNS = 40;
2426

2527
export const BENCHMARK_TEST: BenchmarkTest = (size: number) => {
26-
const inputShapeRCD: [number, number, number] = [size, size, 1];
28+
const gpgpu = new GPGPUContext();
29+
const texManager = new TextureManager(gpgpu);
30+
initializeGPU(gpgpu, texManager);
31+
32+
const inputDepth = 1;
33+
const inputShape: [number, number, number] = [size, size, inputDepth];
2734
const outputDepth = 1;
2835
const fieldSize = 11;
2936
const stride = 1;
30-
const zeroPad = conv_util.computeDefaultPad(inputShapeRCD, fieldSize, stride);
31-
const outputShapeRCD: [number, number, number] =
32-
conv_util.computeOutputShape3D(
33-
inputShapeRCD, fieldSize, outputDepth, stride, zeroPad);
34-
35-
const inputTexShapeRC = conv_util.computeTexShapeFrom3D(inputShapeRCD);
36-
const outputTexShapeRC = conv_util.computeTexShapeFrom3D(outputShapeRCD);
37-
const weightsTexShapeRC = conv_util.computeWeightsTexShape(
38-
inputShapeRCD[2], outputDepth, fieldSize);
39-
const biasesTexShapeRC = conv_util.computeBiasesTexShape(outputDepth);
37+
const zeroPad = conv_util.computeDefaultPad(inputShape, fieldSize, stride);
4038

4139
const hasBias = true;
42-
const gpgpu = new GPGPUContext();
43-
const program = gpgpu.createProgram(conv_gpu.getFragmentShaderSource(
44-
inputShapeRCD, outputDepth, fieldSize, stride, zeroPad, hasBias));
45-
46-
const inputTexture =
47-
gpgpu.createMatrixTexture(inputTexShapeRC[0], inputTexShapeRC[1]);
48-
const weightsTexture =
49-
gpgpu.createMatrixTexture(weightsTexShapeRC[0], weightsTexShapeRC[1]);
50-
const biasesTexture =
51-
gpgpu.createMatrixTexture(biasesTexShapeRC[0], biasesTexShapeRC[1]);
52-
const outputTexture =
53-
gpgpu.createMatrixTexture(outputTexShapeRC[0], outputTexShapeRC[1]);
54-
55-
const inputData = test_util.randomArrayInRange(
56-
inputTexShapeRC[0] * inputTexShapeRC[1], -1, 1);
57-
const weightsData = test_util.randomArrayInRange(
58-
weightsTexShapeRC[0] * weightsTexShapeRC[1], -1, 1);
59-
const biasesData = test_util.randomArrayInRange(
60-
biasesTexShapeRC[0] * biasesTexShapeRC[1], -1, 1);
61-
62-
gpgpu.uploadMatrixToTexture(
63-
inputTexture, inputTexShapeRC[0], inputTexShapeRC[1], inputData);
64-
gpgpu.uploadMatrixToTexture(
65-
weightsTexture, weightsTexShapeRC[0], weightsTexShapeRC[1], weightsData);
66-
gpgpu.uploadMatrixToTexture(
67-
biasesTexture, biasesTexShapeRC[0], biasesTexShapeRC[1], biasesData);
40+
const program = new Conv2DProgram(
41+
inputShape, fieldSize, outputDepth, stride, zeroPad, hasBias);
42+
const outputShape = program.outputShape as [number, number, number];
43+
const out = Array3D.zeros(outputShape);
44+
const x = Array3D.randUniform(inputShape, -1, 1);
45+
const wShape = conv_util.computeWeightsShape4D(1, outputDepth, fieldSize);
46+
const W = Array4D.randUniform(wShape, -1, 1);
47+
const b = Array1D.randUniform([outputDepth], -1, 1);
48+
const inputs = [x, W, b];
49+
const binary = gpgpu_math.compileProgram(gpgpu, program, inputs, out);
6850

6951
const start = performance.now();
7052
for (let i = 0; i < OP_RUNS; i++) {
71-
conv_gpu.convolve(
72-
gpgpu, program, inputTexture, weightsTexture, biasesTexture,
73-
outputTexture, outputTexShapeRC);
53+
gpgpu_math.runProgram(binary, inputs, out);
7454
}
75-
76-
gpgpu.downloadMatrixFromTexture(
77-
outputTexture, outputTexShapeRC[0], outputTexShapeRC[1]);
78-
const end = performance.now();
79-
80-
const avgTime = (end - start) / OP_RUNS;
81-
82-
gpgpu.deleteMatrixTexture(inputTexture);
83-
gpgpu.deleteMatrixTexture(weightsTexture);
84-
gpgpu.deleteMatrixTexture(biasesTexture);
85-
gpgpu.deleteMatrixTexture(outputTexture);
86-
gpgpu.deleteProgram(program);
55+
out.getValues();
56+
const avgTime = (performance.now() - start) / OP_RUNS;
57+
58+
x.dispose();
59+
W.dispose();
60+
b.dispose();
61+
out.dispose();
62+
texManager.dispose();
63+
gpgpu.deleteProgram(binary.webGLProgram);
8764
gpgpu.dispose();
8865

8966
return avgTime;

demos/benchmarks/conv_transpose_gpu_benchmark.ts

Lines changed: 24 additions & 47 deletions
Original file line numberDiff line numberDiff line change
@@ -14,71 +14,48 @@ limitations under the License.
1414
==============================================================================*/
1515

1616
import * as conv_util from '../../src/math/conv_util';
17-
import * as conv_backprop_gpu from '../../src/math/webgl/conv_backprop_gpu';
17+
import {Array3D, Array4D, initializeGPU} from '../../src/math/ndarray';
18+
import {Conv2DTransposeProgram} from '../../src/math/webgl/conv_backprop_gpu';
1819
import {GPGPUContext} from '../../src/math/webgl/gpgpu_context';
19-
import * as test_util from '../../src/test_util';
20-
20+
import * as gpgpu_math from '../../src/math/webgl/gpgpu_math';
21+
import {TextureManager} from '../../src/math/webgl/texture_manager';
2122
import {BenchmarkTest} from './benchmark';
2223

23-
const OP_RUNS = 100;
24+
const OP_RUNS = 40;
2425

2526
export const BENCHMARK_TEST: BenchmarkTest = (size: number) => {
26-
const xShapeRCD: [number, number, number] = [size, size, 1];
27+
const origInputDepth = 1;
2728
const origOutputDepth = 2;
29+
const xShape: [number, number, number] = [size, size, 1];
2830
const fieldSize = 11;
2931
const origStride = 1;
3032
const origPad = 1;
3133

3234
const gpgpu = new GPGPUContext();
35+
const texManager = new TextureManager(gpgpu);
36+
initializeGPU(gpgpu, texManager);
3337
gpgpu.enableAutomaticDebugValidation(true);
34-
const origInputDepth = xShapeRCD[2];
35-
const src = conv_backprop_gpu.getFragmentShaderConvTransposeSource(
36-
xShapeRCD, fieldSize, origInputDepth, origStride, origPad, false);
37-
const program = gpgpu.createProgram(src);
38-
39-
// Upload x.
40-
const xTexShapeRC = conv_util.computeTexShapeFrom3D(xShapeRCD);
41-
const xTex = gpgpu.createMatrixTexture(xTexShapeRC[0], xTexShapeRC[1]);
42-
const xData =
43-
test_util.randomArrayInRange(xTexShapeRC[0] * xTexShapeRC[1], -1, 1);
44-
gpgpu.uploadMatrixToTexture(xTex, xTexShapeRC[0], xTexShapeRC[1], xData);
4538

46-
// Upload weights.
47-
const wTexShapeRC = conv_util.computeWeightsTexShape(
39+
const hasBias = false;
40+
const program = new Conv2DTransposeProgram(
41+
xShape, fieldSize, origInputDepth, origStride, origPad, hasBias);
42+
const outputShape = program.outputShape as [number, number, number];
43+
const out = Array3D.zeros(outputShape);
44+
const x = Array3D.randUniform(xShape, -1, 1);
45+
const wShape = conv_util.computeWeightsShape4D(
4846
origInputDepth, origOutputDepth, fieldSize);
49-
const wData =
50-
test_util.randomArrayInRange(wTexShapeRC[0] * wTexShapeRC[1], -1, 1);
51-
const wTex = gpgpu.createMatrixTexture(wTexShapeRC[0], wTexShapeRC[1]);
52-
gpgpu.uploadMatrixToTexture(wTex, wTexShapeRC[0], wTexShapeRC[1], wData);
53-
54-
// Figure out the output shape by dilating the input.
55-
const dilatedRC =
56-
conv_util.computeDilatedRC([xShapeRCD[0], xShapeRCD[1]], origStride);
57-
const pad = fieldSize - 1 - origPad;
58-
const resultShapeRCD = conv_util.computeOutputShape3D(
59-
[dilatedRC[0], dilatedRC[1], origOutputDepth], fieldSize, origInputDepth,
60-
1, pad);
61-
62-
const resultTexRC = conv_util.computeTexShapeFrom3D(resultShapeRCD);
63-
const resultTex = gpgpu.createMatrixTexture(resultTexRC[0], resultTexRC[1]);
64-
47+
const W = Array4D.randUniform(wShape, -1, 1);
48+
const inputs = [x, W];
49+
const binary = gpgpu_math.compileProgram(gpgpu, program, inputs, out);
6550
const start = performance.now();
6651
for (let i = 0; i < OP_RUNS; i++) {
67-
conv_backprop_gpu.convTranspose(
68-
gpgpu, program, xTex, wTex, null, resultTex, resultTexRC);
52+
gpgpu_math.runProgram(binary, inputs, out);
6953
}
54+
out.getValues();
55+
const avgTime = (performance.now() - start) / OP_RUNS;
7056

71-
gpgpu.downloadMatrixFromTexture(resultTex, resultTexRC[0], resultTexRC[1]);
72-
73-
const end = performance.now();
74-
75-
const avgTime = (end - start) / OP_RUNS;
76-
77-
gpgpu.deleteMatrixTexture(resultTex);
78-
gpgpu.deleteMatrixTexture(xTex);
79-
gpgpu.deleteMatrixTexture(wTex);
80-
gpgpu.deleteProgram(program);
57+
texManager.dispose();
58+
gpgpu.deleteProgram(binary.webGLProgram);
8159
gpgpu.dispose();
82-
8360
return avgTime;
8461
};

demos/benchmarks/logsumexp_gpu_benchmark.ts

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -13,14 +13,15 @@ See the License for the specific language governing permissions and
1313
limitations under the License.
1414
==============================================================================*/
1515

16+
import {Array2D, initializeGPU, Scalar} from '../../src/math/ndarray';
1617
import {GPGPUContext} from '../../src/math/webgl/gpgpu_context';
17-
import {LogSumExpProgram} from '../../src/math/webgl/logsumexp_gpu';
1818
import * as gpgpu_math from '../../src/math/webgl/gpgpu_math';
19-
import {Scalar, Array2D, initializeGPU} from '../../src/math/ndarray';
19+
import {LogSumExpProgram} from '../../src/math/webgl/logsumexp_gpu';
2020
import {TextureManager} from '../../src/math/webgl/texture_manager';
21+
2122
import {BenchmarkTest} from './benchmark';
2223

23-
const OP_RUNS = 100;
24+
const OP_RUNS = 2;
2425

2526
export const BENCHMARK_TEST: BenchmarkTest = (size: number) => {
2627
const gpgpu = new GPGPUContext();
@@ -35,7 +36,7 @@ export const BENCHMARK_TEST: BenchmarkTest = (size: number) => {
3536
for (let i = 0; i < OP_RUNS; i++) {
3637
gpgpu_math.runProgram(binary, [a], out);
3738
}
38-
39+
out.getValues();
3940
const avgTime = (performance.now() - start) / OP_RUNS;
4041
a.dispose();
4142
out.dispose();

demos/benchmarks/max_pool_backprop_gpu_benchmark.ts

Lines changed: 30 additions & 50 deletions
Original file line numberDiff line numberDiff line change
@@ -14,69 +14,49 @@ limitations under the License.
1414
==============================================================================*/
1515

1616
import * as conv_util from '../../src/math/conv_util';
17+
import {Array3D, initializeGPU, NDArray} from '../../src/math/ndarray';
1718
import {GPGPUContext} from '../../src/math/webgl/gpgpu_context';
19+
import * as gpgpu_math from '../../src/math/webgl/gpgpu_math';
1820
// tslint:disable-next-line:max-line-length
19-
import * as max_pool_backprop_gpu from '../../src/math/webgl/max_pool_backprop_gpu';
20-
import * as test_util from '../../src/test_util';
21-
import * as util from '../../src/util';
22-
21+
import {MaxPool2DBackpropProgram} from '../../src/math/webgl/max_pool_backprop_gpu';
22+
import {TextureManager} from '../../src/math/webgl/texture_manager';
2323
import {BenchmarkTest} from './benchmark';
2424

25-
const OP_RUNS = 100;
25+
const OP_RUNS = 40;
2626

2727
export const BENCHMARK_TEST: BenchmarkTest = (size: number) => {
28-
const dyShapeRCD: [number, number, number] = [size, size, 1];
29-
const outputDepth = 1;
30-
const fieldSize = 11;
31-
const stride = 1;
32-
const zeroPad = conv_util.computeDefaultPad(dyShapeRCD, fieldSize, stride);
33-
const outputShapeRCD: [number, number, number] =
34-
conv_util.computeOutputShape3D(
35-
dyShapeRCD, fieldSize, outputDepth, stride, zeroPad);
36-
37-
const dyTexShapeRC = conv_util.computeTexShapeFrom3D(dyShapeRCD);
38-
const outputTexShapeRC = conv_util.computeTexShapeFrom3D(outputShapeRCD);
39-
4028
const gpgpu = new GPGPUContext();
41-
const program = gpgpu.createProgram(
42-
max_pool_backprop_gpu.getFragmentShaderMaxPoolBackprop(
43-
dyShapeRCD, fieldSize, stride, zeroPad));
44-
45-
const dyTexture = gpgpu.createMatrixTexture(dyTexShapeRC[0], dyTexShapeRC[1]);
46-
const maxPositionsTexture =
47-
gpgpu.createMatrixTexture(dyTexShapeRC[0], dyTexShapeRC[1]);
48-
const outputTexture =
49-
gpgpu.createMatrixTexture(outputTexShapeRC[0], outputTexShapeRC[1]);
29+
const texManager = new TextureManager(gpgpu);
30+
initializeGPU(gpgpu, texManager);
5031

51-
const dyData =
52-
test_util.randomArrayInRange(dyTexShapeRC[0] * dyTexShapeRC[1], -1, 1);
53-
const maxPositionsData = new Float32Array(util.sizeFromShape(dyShapeRCD));
54-
for (let i = 0; i < maxPositionsData.length; i++) {
55-
maxPositionsData[i] = Math.floor(Math.random() * fieldSize * fieldSize);
32+
const outputDepth = 1;
33+
const dyShape: [number, number, number] = [size, size, outputDepth];
34+
const fSize = 11;
35+
const stride = 1;
36+
const zeroPad = conv_util.computeDefaultPad(dyShape, fSize, stride);
37+
const program = new MaxPool2DBackpropProgram(dyShape, fSize, stride, zeroPad);
38+
const res = NDArray.zeros(program.outputShape);
39+
const dy = Array3D.randUniform(dyShape, -1, 1);
40+
const positionsData = new Float32Array(dy.size);
41+
for (let i = 0; i < positionsData.length; i++) {
42+
positionsData[i] = Math.floor(Math.random() * fSize * fSize);
5643
}
57-
58-
gpgpu.uploadMatrixToTexture(
59-
dyTexture, dyTexShapeRC[0], dyTexShapeRC[1], dyData);
60-
gpgpu.uploadMatrixToTexture(
61-
maxPositionsTexture, dyTexShapeRC[0], dyTexShapeRC[1], maxPositionsData);
44+
const positions = Array3D.new(dyShape, positionsData);
45+
const binary =
46+
gpgpu_math.compileProgram(gpgpu, program, [dy, positions], res);
6247

6348
const start = performance.now();
6449
for (let i = 0; i < OP_RUNS; i++) {
65-
max_pool_backprop_gpu.maxPoolBackprop(
66-
gpgpu, program, dyTexture, maxPositionsTexture, outputTexture,
67-
outputTexShapeRC);
50+
gpgpu_math.runProgram(binary, [dy, positions], res);
6851
}
69-
70-
gpgpu.downloadMatrixFromTexture(
71-
outputTexture, outputTexShapeRC[0], outputTexShapeRC[1]);
72-
const end = performance.now();
73-
74-
const avgTime = (end - start) / OP_RUNS;
75-
76-
gpgpu.deleteMatrixTexture(dyTexture);
77-
gpgpu.deleteMatrixTexture(maxPositionsTexture);
78-
gpgpu.deleteMatrixTexture(outputTexture);
79-
gpgpu.deleteProgram(program);
52+
res.getValues();
53+
const avgTime = (performance.now() - start) / OP_RUNS;
54+
55+
dy.dispose();
56+
positions.dispose();
57+
res.dispose();
58+
texManager.dispose();
59+
gpgpu.deleteProgram(binary.webGLProgram);
8060
gpgpu.dispose();
8161

8262
return avgTime;

0 commit comments

Comments
 (0)