-
Notifications
You must be signed in to change notification settings - Fork 1
/
Copy pathexample.js
160 lines (138 loc) · 3.95 KB
/
example.js
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
const assert = require('assert');
const MatrixLog = require('./index');
const weights = [
[1,2,3,4],
[5,6,7,8],
[9,10,11,12],
[13,14,15,16]
];
const targetValue = step1CPU();
assert.deepStrictEqual(step2CPUWithMatrixLog(), targetValue);
assert.deepStrictEqual(step3GPUStyleLoops(), targetValue);
assert.deepStrictEqual(step4GPUStyleKernel(), targetValue);
assert.deepStrictEqual(step5GPUKernel(), targetValue);
function step1CPU() {
const filters = [
[0,0],
[0,0]
];
for (let y = 0; y < 4; y++) {
let filterY = y < 2 ? 0 : 1;
for (let x = 0; x < 4; x++) {
let filterX = x < 2 ? 0 : 1;
filters[filterY][filterX] += weights[y][x];
}
}
return filters;
}
function step2CPUWithMatrixLog() {
const filters = [
[0,0],
[0,0]
];
const matrixLog = new MatrixLog('filters', 2, 2);
for (let y = 0; y < 4; y++) {
let filterY = y < 2 ? 0 : 1;
for (let x = 0; x < 4; x++) {
let filterX = x < 2 ? 0 : 1;
// IMPORTANT: GPU violation, we are reading (+) and writing (=) multiple times to a point in the filter matrix, CPU works fine, GPU explodes
// Don't understand?
// * Watch this video: https://www.youtube.com/watch?v=-P28LKWTzrI and think of the
// * Think of the Leonardo 2's cannons talking with each other
filters[filterY][filterX] += weights[y][x];
// IMPORTANT: We added the following code to show us the shape of the algorithm
matrixLog
.at({
x: filterX,
y: filterY
})
.add({
name: 'weights',
x,
y,
width: weights[0].length,
height: weights.length
});
}
}
console.log(filters);
console.log(matrixLog.toString('weights'));
return filters;
}
function step3GPUStyleLoops() {
const filters = [
[0,0],
[0,0]
];
const filterHeight = 2;
const filterWidth = 2;
for (let filterY = 0; filterY < filterHeight; filterY++) {
for (let filterX = 0; filterX < filterWidth; filterX++) {
// NOTE: += filters!
let sum = filters[filterY][filterX];
const yMin = filterHeight * filterY;
const yMax = yMin + filterHeight;
const xMin = filterWidth * filterX;
const xMax = xMin + filterWidth;
for (let y = yMin; y < yMax; y++) {
for (let x = xMin; x < xMax; x++) {
sum += weights[y][x];
}
}
// IMPORTANT: single assignment
filters[filterY][filterX] = sum;
}
}
return filters;
}
function step4GPUStyleKernel() {
const filters = [
[0,0],
[0,0]
];
filters[0][0] = filterKernel(filters, 0, 0, 2, 2, weights);
filters[0][1] = filterKernel(filters, 1, 0, 2, 2, weights);
filters[1][0] = filterKernel(filters, 0, 1, 2, 2, weights);
filters[1][1] = filterKernel(filters, 1, 1, 2, 2, weights);
function filterKernel(filters, filterX, filterY, filterWidth, filterHeight, weights) {
// NOTE: += filters!
let sum = filters[filterY][filterX];
const yMin = filterHeight * filterY;
const yMax = yMin + filterHeight;
const xMin = filterWidth * filterX;
const xMax = xMin + filterWidth;
for (let y = yMin; y < yMax; y++) {
for (let x = xMin; x < xMax; x++) {
sum += weights[y][x];
}
}
// IMPORTANT: single assignment
return sum;
}
return filters;
}
function step5GPUKernel() {
const filters = [
[0,0],
[0,0]
];
const GPU = require('gpu.js');
const gpu = new GPU();
const filterKernel = gpu.createKernel(function (filters, weights) {
let sum = filters[this.thread.y][this.thread.x];
const yMin = this.output.y * this.thread.y;
const yMax = yMin + this.output.y;
const xMin = this.output.x * this.thread.x;
const xMax = xMin + this.output.x;
for (let y = yMin; y < yMax; y++) {
for (let x = xMin; x < xMax; x++) {
sum += weights[y][x];
}
}
// IMPORTANT: single assignment
return sum;
}, {
output: [2, 2]
});
return filterKernel(filters, weights);
}