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

Commit a733567

Browse files
author
Nikhil Thorat
authored
Add intro.ts demo that demos intro tutorial, fix intro to actually converge when training. (#32)
* Add intro.ts demo that demos intro tutorial, fix intro to actually converge when training. * remove code accidentally added to intro.md * Respond to comments, fix line length problems, dispose inputs * Add link to intro demo from intro md
1 parent 123a37c commit a733567

File tree

4 files changed

+207
-23
lines changed

4 files changed

+207
-23
lines changed

demos/intro/index.html

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
<!-- Copyright 2017 Google Inc. All Rights Reserved.
2+
Licensed under the Apache License, Version 2.0 (the "License");
3+
you may not use this file except in compliance with the License.
4+
You may obtain a copy of the License at
5+
http://www.apache.org/licenses/LICENSE-2.0
6+
Unless required by applicable law or agreed to in writing, software
7+
distributed under the License is distributed on an "AS IS" BASIS,
8+
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
9+
See the License for the specific language governing permissions and
10+
limitations under the License.
11+
==============================================================================-->
12+
<h1>Introduction tutorial code</h1>
13+
14+
<h3>Check the JavaScript console!</h3>
15+
16+
<script src="bundle.js"></script>

demos/intro/intro.ts

Lines changed: 139 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,139 @@
1+
/* Copyright 2017 Google Inc. All Rights Reserved.
2+
3+
Licensed under the Apache License, Version 2.0 (the "License");
4+
you may not use this file except in compliance with the License.
5+
You may obtain a copy of the License at
6+
7+
http://www.apache.org/licenses/LICENSE-2.0
8+
9+
Unless required by applicable law or agreed to in writing, software
10+
distributed under the License is distributed on an "AS IS" BASIS,
11+
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12+
See the License for the specific language governing permissions and
13+
limitations under the License.
14+
==============================================================================*/
15+
16+
import {NDArrayMathGPU, Scalar, Array1D, Array2D, Graph, Session, SGDOptimizer, InCPUMemoryShuffledInputProviderBuilder, FeedEntry, CostReduction} from '../deeplearnjs';
17+
18+
// This file parallels (some of) the code in the introduction tutorial.
19+
20+
/**
21+
* 'NDArrayMathGPU' section of tutorial
22+
*/
23+
{
24+
const math = new NDArrayMathGPU();
25+
26+
math.scope((keep, track) => {
27+
const a = track(Array2D.new([2, 2], [1.0, 2.0, 3.0, 4.0]));
28+
const b = track(Array2D.new([2, 2], [0.0, 2.0, 4.0, 6.0]));
29+
30+
// Non-blocking math calls.
31+
const diff = math.sub(a, b);
32+
const squaredDiff = math.elementWiseMul(diff, diff);
33+
const sum = math.sum(squaredDiff);
34+
const size = Scalar.new(a.size);
35+
const average = math.divide(sum, size);
36+
37+
// Blocking call to actually read the values from average. Waits until the
38+
// GPU has finished executing the operations before returning values.
39+
// average is a Scalar so we use .get()
40+
console.log('mean squared difference: ' + average.get());
41+
});
42+
}
43+
44+
{
45+
/**
46+
* 'Graphs and Tensors' section of tutorial
47+
*/
48+
49+
const g = new Graph();
50+
51+
// Placeholders are input containers. This is the container for where we will
52+
// feed an input NDArray when we execute the graph.
53+
const inputShape = [3];
54+
const inputTensor = g.placeholder('input', inputShape);
55+
56+
const labelShape = [1];
57+
const labelTensor = g.placeholder('label', labelShape);
58+
59+
// Variables are containers that hold a value that can be updated from
60+
// training.
61+
// Here we initialize the multiplier variable randomly.
62+
const multiplier = g.variable('multiplier', Array2D.randNormal([1, 3]));
63+
64+
// Top level graph methods take Tensors and return Tensors.
65+
const outputTensor = g.matmul(multiplier, inputTensor);
66+
const costTensor = g.meanSquaredCost(outputTensor, labelTensor);
67+
68+
// Tensors, like NDArrays, have a shape attribute.
69+
console.log(outputTensor.shape);
70+
71+
/**
72+
* 'Session and FeedEntry' section of the tutorial.
73+
*/
74+
75+
const learningRate = .00001;
76+
const batchSize = 3;
77+
const math = new NDArrayMathGPU();
78+
79+
const session = new Session(g, math);
80+
const optimizer = new SGDOptimizer(learningRate);
81+
82+
const inputs: Array1D[] = [
83+
Array1D.new([1.0, 2.0, 3.0]),
84+
Array1D.new([10.0, 20.0, 30.0]),
85+
Array1D.new([100.0, 200.0, 300.0])
86+
];
87+
88+
const labels: Array1D[] = [
89+
Array1D.new([4.0]),
90+
Array1D.new([40.0]),
91+
Array1D.new([400.0])
92+
];
93+
94+
// Shuffles inputs and labels and keeps them mutually in sync.
95+
const shuffledInputProviderBuilder =
96+
new InCPUMemoryShuffledInputProviderBuilder([inputs, labels]);
97+
const [inputProvider, labelProvider] =
98+
shuffledInputProviderBuilder.getInputProviders();
99+
100+
// Maps tensors to InputProviders.
101+
const feedEntries: FeedEntry[] = [
102+
{tensor: inputTensor, data: inputProvider},
103+
{tensor: labelTensor, data: labelProvider}
104+
];
105+
106+
const NUM_BATCHES = 10;
107+
for (let i = 0; i < NUM_BATCHES; i++) {
108+
// Wrap session.train in a scope so the cost gets cleaned up automatically.
109+
math.scope(() => {
110+
// Train takes a cost tensor to minimize. Trains one batch. Returns the
111+
// average cost as a Scalar.
112+
const cost = session.train(
113+
costTensor, feedEntries, batchSize, optimizer, CostReduction.MEAN);
114+
115+
console.log('last average cost (' + i + '): ' + cost.get());
116+
});
117+
}
118+
119+
// Wrap session.eval in a scope so the intermediate values get cleaned up
120+
// automatically.
121+
math.scope((keep, track) => {
122+
const testInput = track(Array1D.new([0.1, 0.2, 0.3]));
123+
124+
// session.eval can take NDArrays as input data.
125+
const testFeedEntries: FeedEntry[] = [
126+
{tensor: inputTensor, data: testInput}
127+
];
128+
129+
const testOutput = session.eval(outputTensor, testFeedEntries);
130+
131+
console.log('---inference output---');
132+
console.log('shape: ' + testOutput.shape);
133+
console.log('value: ' + testOutput.get(0));
134+
});
135+
136+
// Cleanup training data.
137+
inputs.forEach(input => input.dispose());
138+
labels.forEach(label => label.dispose());
139+
}

demos/mnist/index.html

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,14 @@
1+
<!-- Copyright 2017 Google Inc. All Rights Reserved.
2+
Licensed under the Apache License, Version 2.0 (the "License");
3+
you may not use this file except in compliance with the License.
4+
You may obtain a copy of the License at
5+
http://www.apache.org/licenses/LICENSE-2.0
6+
Unless required by applicable law or agreed to in writing, software
7+
distributed under the License is distributed on an "AS IS" BASIS,
8+
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
9+
See the License for the specific language governing permissions and
10+
limitations under the License.
11+
==============================================================================-->
112
<h1>MNIST demo</h1>
213
<div>Test accuracy: <span id="accuracy"></span></div>
314
<script src="bundle.js"></script>

docs/tutorials/intro.md

Lines changed: 41 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,16 @@ functions that can be used directly.
1414
* TOC
1515
{:toc}
1616

17+
You can find the code that supplements this tutorial
18+
[here](https://github.com/PAIR-code/deeplearnjs/tree/master/demos/intro).
19+
20+
Run it yourself with:
21+
```ts
22+
./scripts/watch-demo demos/intro/intro.ts
23+
```
24+
25+
And visit `http://localhost:8080/demos/intro/`.
26+
1727
For the purposes of the documentation, we will use TypeScript code examples.
1828
For vanilla JavaScript, you may need to remove TypeScript syntax like
1929
`const`, `let`, or other type definitions.
@@ -83,7 +93,8 @@ math.scope((keep, track) => {
8393

8494
// Blocking call to actually read the values from average. Waits until the
8595
// GPU has finished executing the operations before returning values.
86-
console.log(average.get()); // average is a Scalar so we use .get()
96+
// average is a Scalar so we use .get()
97+
console.log(average.get());
8798
});
8899
```
89100

@@ -212,7 +223,8 @@ const inputTensor = g.placeholder('input', inputShape);
212223
const labelShape = [1];
213224
const labelTensor = g.placeholder('label', labelShape);
214225

215-
// Variables are containers that hold a value that can be updated from training.
226+
// Variables are containers that hold a value that can be updated from
227+
// training.
216228
// Here we initialize the multiplier variable randomly.
217229
const multiplier = g.variable('multiplier', Array2D.randNormal([1, 3]));
218230

@@ -243,10 +255,10 @@ keeping them in sync.
243255
Training with the `Graph` object from above:
244256

245257
```js
246-
const learningRate = .001;
247-
const batchSize = 2;
248-
258+
const learningRate = .00001;
259+
const batchSize = 3;
249260
const math = new NDArrayMathGPU();
261+
250262
const session = new Session(g, math);
251263
const optimizer = new SGDOptimizer(learningRate);
252264

@@ -257,42 +269,44 @@ const inputs: Array1D[] = [
257269
];
258270

259271
const labels: Array1D[] = [
260-
Array1D.new([2.0, 6.0, 12.0]),
261-
Array1D.new([20.0, 60.0, 120.0]),
262-
Array1D.new([200.0, 600.0, 1200.0])
272+
Array1D.new([4.0]),
273+
Array1D.new([40.0]),
274+
Array1D.new([400.0])
263275
];
264276

265277
// Shuffles inputs and labels and keeps them mutually in sync.
266278
const shuffledInputProviderBuilder =
267-
new InCPUMemoryShuffledInputProviderBuilder([inputs, labels]);
279+
new InCPUMemoryShuffledInputProviderBuilder([inputs, labels]);
268280
const [inputProvider, labelProvider] =
269-
shuffledInputProviderBuilder.getInputProviders();
281+
shuffledInputProviderBuilder.getInputProviders();
270282

271283
// Maps tensors to InputProviders.
272284
const feedEntries: FeedEntry[] = [
273285
{tensor: inputTensor, data: inputProvider},
274286
{tensor: labelTensor, data: labelProvider}
275287
];
276288

277-
// Wrap session.train in a scope so the cost gets cleaned up automatically.
278-
math.scope(() => {
279-
// Train takes a cost tensor to minimize. Trains one batch. Returns the
280-
// average cost as a Scalar.
281-
const cost = session.train(
282-
costTensor, feedEntries, batchSize, optimizer, CostReduction.MEAN);
289+
const NUM_BATCHES = 10;
290+
for (let i = 0; i < NUM_BATCHES; i++) {
291+
// Wrap session.train in a scope so the cost gets cleaned up automatically.
292+
math.scope(() => {
293+
// Train takes a cost tensor to minimize. Trains one batch. Returns the
294+
// average cost as a Scalar.
295+
const cost = session.train(
296+
costTensor, feedEntries, batchSize, optimizer, CostReduction.MEAN);
283297

284-
console.log('last average cost: ' + cost.get());
285-
});
298+
console.log('last average cost (' + i + '): ' + cost.get());
299+
});
300+
}
286301
```
287302

288303
After training, we can infer through the graph:
289304

290305
```js
291-
292306
// Wrap session.eval in a scope so the intermediate values get cleaned up
293307
// automatically.
294308
math.scope((keep, track) => {
295-
const testInput = track(Array1D.new([1.0, 2.0, 3.0]));
309+
const testInput = track(Array1D.new([0.1, 0.2, 0.3]));
296310

297311
// session.eval can take NDArrays as input data.
298312
const testFeedEntries: FeedEntry[] = [
@@ -301,10 +315,14 @@ math.scope((keep, track) => {
301315

302316
const testOutput = session.eval(outputTensor, testFeedEntries);
303317

304-
console.log('inference output:');
305-
console.log(testOutput.shape);
306-
console.log(testOutput.getValues());
318+
console.log('---inference output---');
319+
console.log('shape: ' + testOutput.shape);
320+
console.log('value: ' + testOutput.get(0));
307321
});
322+
323+
// Cleanup training data.
324+
inputs.forEach(input => input.dispose());
325+
labels.forEach(label => label.dispose());
308326
```
309327

310328
Want to learn more? Read [these tutorials](index.md).

0 commit comments

Comments
 (0)