Skip to content

Commit 21e9918

Browse files
More typos
1 parent 3fd9fb9 commit 21e9918

File tree

2 files changed

+173
-172
lines changed

2 files changed

+173
-172
lines changed

README.md

Lines changed: 172 additions & 171 deletions
Original file line numberDiff line numberDiff line change
@@ -133,189 +133,190 @@ width=2,height=2,depth=3 width=4,height=4,depth=2
133133
```
134134

135135
## What does this log mean?
136-
If you prefer code to learn take a look at the [included example](example.js)
136+
If you prefer to learn by code rather than have step by step instructions take a look at (or run) the [included example](example.js)
137+
* NOTE: the [included example](example.js) correlates to the following step by step instructions.
137138
1. Suppose we had a (contrived) block of CPU code we'd like to run on the GPU:
138-
```js
139-
const filters = [
140-
[0,0],
141-
[0,0]
142-
];
143-
144-
const weights = [
145-
[1,2,3,4],
146-
[5,6,7,8],
147-
[9,10,11,12],
148-
[13,14,15,16]
149-
];
150-
151-
for (let y = 0; y < 4; y++) {
152-
let filterY = y < 2 ? 0 : 1;
153-
for (let x = 0; x < 4; x++) {
154-
let filterX = x < filter.length ? 0 : 1;
155-
filters[filterY][filterX] += weights[y][x];
156-
}
157-
}
158-
159-
console.log(filters); // -> [ [ 14, 22 ], [ 46, 54 ] ]
160-
```
161-
162-
This code doesn't directly work on the GPU, because we can only _either_ read or write to arrays there. Currently `filters` violates this. However, we could use MatrixLog to _help us_ (note, there is a little thinking that needs to take place) solve this issue by finding the algorithm that `filters` needs.
139+
```js
140+
const filters = [
141+
[0,0],
142+
[0,0]
143+
];
144+
145+
const weights = [
146+
[1,2,3,4],
147+
[5,6,7,8],
148+
[9,10,11,12],
149+
[13,14,15,16]
150+
];
151+
152+
for (let y = 0; y < 4; y++) {
153+
let filterY = y < 2 ? 0 : 1;
154+
for (let x = 0; x < 4; x++) {
155+
let filterX = x < filter.length ? 0 : 1;
156+
filters[filterY][filterX] += weights[y][x];
157+
}
158+
}
159+
160+
console.log(filters); // -> [ [ 14, 22 ], [ 46, 54 ] ]
161+
```
162+
163+
This code doesn't directly work on the GPU, because we can only _either_ read or write to arrays there. Currently `filters` violates this. However, we could use MatrixLog to _help us_ (note, there is a little thinking that needs to take place) solve this issue by finding the algorithm that `filters` needs.
163164
164165
2. Convert the code as follows and see the output below:
165-
```js
166-
const MatrixLog = require('./index');
167-
168-
const filters = [
169-
[0,0],
170-
[0,0]
171-
];
172-
const weights = [
173-
[1,2,3,4],
174-
[5,6,7,8],
175-
[9,10,11,12],
176-
[13,14,15,16]
177-
];
178-
179-
const matrixLog = new MatrixLog('filters', 2, 2);
180-
for (let y = 0; y < 4; y++) {
181-
let filterY = y < 2 ? 0 : 1;
182-
for (let x = 0; x < 4; x++) {
183-
let filterX = x < filter.length ? 0 : 1;
184-
filters[filterY][filterX] += weights[y][x];
185-
matrixLog
186-
.at({ x, y })
187-
.add({
188-
name: 'weights',
189-
x: filterX,
190-
y: filterY,
191-
width: weights[0].length,
192-
height: weights.length
193-
});
194-
}
195-
}
196-
197-
console.log(matrixLog.toString('weights'));
198-
```
199-
200-
Gives us the output:
201-
```
202-
filters x=0,y=0 weights
203-
width=2,height=2 width=4,height=4
204-
[*][ ] [*][*][ ][ ]
205-
[ ][ ] [*][*][ ][ ]
206-
[ ][ ][ ][ ]
207-
[ ][ ][ ][ ]
208-
209-
filters x=1,y=0 weights
210-
width=2,height=2 width=4,height=4
211-
[ ][*] [ ][ ][*][*]
212-
[ ][ ] [ ][ ][*][*]
213-
[ ][ ][ ][ ]
214-
[ ][ ][ ][ ]
215-
216-
filters x=0,y=1 weights
217-
width=2,height=2 width=4,height=4
218-
[ ][ ] [ ][ ][ ][ ]
219-
[*][ ] [ ][ ][ ][ ]
220-
[*][*][ ][ ]
221-
[*][*][ ][ ]
222-
223-
filters x=1,y=1 weights
224-
width=2,height=2 width=4,height=4
225-
[ ][ ] [ ][ ][ ][ ]
226-
[ ][*] [ ][ ][ ][ ]
227-
[ ][ ][*][*]
228-
[ ][ ][*][*]
229-
```
166+
```js
167+
const MatrixLog = require('./index');
168+
169+
const filters = [
170+
[0,0],
171+
[0,0]
172+
];
173+
const weights = [
174+
[1,2,3,4],
175+
[5,6,7,8],
176+
[9,10,11,12],
177+
[13,14,15,16]
178+
];
179+
180+
const matrixLog = new MatrixLog('filters', 2, 2);
181+
for (let y = 0; y < 4; y++) {
182+
let filterY = y < 2 ? 0 : 1;
183+
for (let x = 0; x < 4; x++) {
184+
let filterX = x < filter.length ? 0 : 1;
185+
filters[filterY][filterX] += weights[y][x];
186+
matrixLog
187+
.at({ x, y })
188+
.add({
189+
name: 'weights',
190+
x: filterX,
191+
y: filterY,
192+
width: weights[0].length,
193+
height: weights.length
194+
});
195+
}
196+
}
197+
198+
console.log(matrixLog.toString('weights'));
199+
```
200+
201+
Gives us the output:
202+
```
203+
filters x=0,y=0 weights
204+
width=2,height=2 width=4,height=4
205+
[*][ ] [*][*][ ][ ]
206+
[ ][ ] [*][*][ ][ ]
207+
[ ][ ][ ][ ]
208+
[ ][ ][ ][ ]
209+
210+
filters x=1,y=0 weights
211+
width=2,height=2 width=4,height=4
212+
[ ][*] [ ][ ][*][*]
213+
[ ][ ] [ ][ ][*][*]
214+
[ ][ ][ ][ ]
215+
[ ][ ][ ][ ]
216+
217+
filters x=0,y=1 weights
218+
width=2,height=2 width=4,height=4
219+
[ ][ ] [ ][ ][ ][ ]
220+
[*][ ] [ ][ ][ ][ ]
221+
[*][*][ ][ ]
222+
[*][*][ ][ ]
223+
224+
filters x=1,y=1 weights
225+
width=2,height=2 width=4,height=4
226+
[ ][ ] [ ][ ][ ][ ]
227+
[ ][*] [ ][ ][ ][ ]
228+
[ ][ ][*][*]
229+
[ ][ ][*][*]
230+
```
230231
231232
3. Now we have enough logic to visibly see how to build out our algorythm that will work on the GPU.
232-
For `filters`@`x=0,y=0` we can see we need the values from `weights`@`x=0,y=0`,`x=1,y=0`,`x=0,y=1`, and `x=1,y=1`.
233-
Then to get `filters`@`x=1,y=0`, we seem to increment by two on `weights`.
234-
If we were to write a loop that emulates this behaviour, it'd look something like this:
235-
236-
```js
237-
const filterHeight = 2;
238-
const filterWidth = 2;
239-
240-
for (let filterY = 0; filterY < filterHeight; filterY++) {
241-
for (let filterX = 0; filterX < filterWidth; filterX++) {
242-
// NOTE: += filters!
243-
let sum = filters[filterY][filterX];
244-
245-
const yMin = filterHeight * filterY;
246-
const yMax = yMin + filterHeight;
247-
const xMin = filterWidth * filterX;
248-
const xMax = xMin + filterWidth;
249-
250-
for (let y = yMin; y < yMax; y++) {
251-
for (let x = xMin; x < xMax; x++) {
252-
sum += weights[y][x];
233+
For `filters`@`x=0,y=0` we can see we need the values from `weights`@`x=0,y=0`,`x=1,y=0`,`x=0,y=1`, and `x=1,y=1`.
234+
Then to get `filters`@`x=1,y=0`, we seem to increment by two on `weights`.
235+
If we were to write a loop that emulates this behaviour, it'd look something like this:
236+
237+
```js
238+
const filterHeight = 2;
239+
const filterWidth = 2;
240+
241+
for (let filterY = 0; filterY < filterHeight; filterY++) {
242+
for (let filterX = 0; filterX < filterWidth; filterX++) {
243+
// NOTE: += filters!
244+
let sum = filters[filterY][filterX];
245+
246+
const yMin = filterHeight * filterY;
247+
const yMax = yMin + filterHeight;
248+
const xMin = filterWidth * filterX;
249+
const xMax = xMin + filterWidth;
250+
251+
for (let y = yMin; y < yMax; y++) {
252+
for (let x = xMin; x < xMax; x++) {
253+
sum += weights[y][x];
254+
}
255+
}
256+
257+
// single assignment
258+
filters[filterY][filterX] = sum;
253259
}
254260
}
255-
256-
// single assignment
257-
filters[filterY][filterX] = sum;
258-
}
259-
}
260-
261-
console.log(filters); // -> [ [ 14, 22 ], [ 46, 54 ] ]
262-
```
261+
262+
console.log(filters); // -> [ [ 14, 22 ], [ 46, 54 ] ]
263+
```
263264

264265
4. On the GPU we are writing from a kernel, which acts like the `filters` loop already, so we can omit that and pretend that the function will run in its own "fragment" (like iteration of the inner most loops for building the value).
265-
If that function was just simple Javascript that we imagined might work on a GPU kernel, it'd looks something like this:
266-
267-
```js
268-
function filterKernel(filters, filterX, filterY, filterWidth, filterHeight, weights) {
269-
// NOTE: += filters!
270-
let sum = filters[filterY][filterX];
271-
272-
const yMin = filterHeight * filterY;
273-
const yMax = yMin + filterHeight;
274-
const xMin = filterWidth * filterX;
275-
const xMax = xMin + filterWidth;
276-
277-
for (let y = yMin; y < yMax; y++) {
278-
for (let x = xMin; x < xMax; x++) {
279-
sum += weights[y][x];
266+
If that function was just simple Javascript that we imagined might work on a GPU kernel, it'd looks something like this:
267+
268+
```js
269+
function filterKernel(filters, filterX, filterY, filterWidth, filterHeight, weights) {
270+
// NOTE: += filters!
271+
let sum = filters[filterY][filterX];
272+
273+
const yMin = filterHeight * filterY;
274+
const yMax = yMin + filterHeight;
275+
const xMin = filterWidth * filterX;
276+
const xMax = xMin + filterWidth;
277+
278+
for (let y = yMin; y < yMax; y++) {
279+
for (let x = xMin; x < xMax; x++) {
280+
sum += weights[y][x];
281+
}
282+
}
283+
284+
return sum;
280285
}
281-
}
282-
283-
return sum;
284-
}
285-
286-
console.log(filterKernel(filters, 0, 0, 2, 2, weights)); // -> 14
287-
console.log(filterKernel(filters, 1, 0, 2, 2, weights)); // -> 22
288-
console.log(filterKernel(filters, 0, 1, 2, 2, weights)); // -> 46
289-
console.log(filterKernel(filters, 1, 1, 2, 2, weights)); // -> 54
290-
```
286+
287+
console.log(filterKernel(filters, 0, 0, 2, 2, weights)); // -> 14
288+
console.log(filterKernel(filters, 1, 0, 2, 2, weights)); // -> 22
289+
console.log(filterKernel(filters, 0, 1, 2, 2, weights)); // -> 46
290+
console.log(filterKernel(filters, 1, 1, 2, 2, weights)); // -> 54
291+
```
291292

292293
5. If we use a GPU environment, such as GPU.js, we could then then convert the kernel so that our algorithm actually works for setting the value of `filters` like this:
293-
294-
```js
295-
import GPU from 'gpu.js';
296-
const gpu = new GPU();
297-
298-
const filterKernel = gpu.createKernel(function(filters, weights) {
299-
let sum = filters[this.thread.y][this.thread.x];
300-
301-
const yMin = this.output.y * this.thread.y;
302-
const yMax = yMin + this.output.y;
303-
const xMin = this.output.x * this.thread.x;
304-
const xMax = xMin + this.output.x;
305-
306-
for (let y = yMin; y < yMax; y++) {
307-
for (let x = xMin; x < xMax; x++) {
308-
sum += weights[y][x];
309-
}
310-
}
311-
return sum;
312-
}, {
313-
output: [2, 2]
314-
});
315-
316-
console.log(filterKernel(filters, weights));// -> [ [ 14, 22 ], [ 46, 54 ] ]
317-
```
294+
295+
```js
296+
import GPU from 'gpu.js';
297+
const gpu = new GPU();
298+
299+
const filterKernel = gpu.createKernel(function(filters, weights) {
300+
let sum = filters[this.thread.y][this.thread.x];
301+
302+
const yMin = this.output.y * this.thread.y;
303+
const yMax = yMin + this.output.y;
304+
const xMin = this.output.x * this.thread.x;
305+
const xMax = xMin + this.output.x;
306+
307+
for (let y = yMin; y < yMax; y++) {
308+
for (let x = xMin; x < xMax; x++) {
309+
sum += weights[y][x];
310+
}
311+
}
312+
return sum;
313+
}, {
314+
output: [2, 2]
315+
});
316+
317+
console.log(filterKernel(filters, weights));// -> [ [ 14, 22 ], [ 46, 54 ] ]
318+
```
318319

319320
## What benefits are there to using MatrixLog?
320321
1. Seeing is understanding
321-
2. Automated unit testing new GPU algorithm against already existing CPU code with an output that can be understood by humans.
322+
2. Automated unit testing new GPU algorithm against already existing CPU code with an output that can be understood by mere mortals.

package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"name": "matrix-log.js",
3-
"version": "1.2.2",
3+
"version": "1.2.3",
44
"description": "A matrix log dependency utility. Useful for converting and testing algorithm behavior of CPU code to GPU code.",
55
"main": "index.js",
66
"scripts": {

0 commit comments

Comments
 (0)