Published
Edited
5 forks
40 stars
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
{
// Construct a 2x2 matrix.
const matrix = tf.tensor2d(
[[1, 2],
[3, 4]]);
// Tensors have a 'data()' method which resolves with the underlying values.
const data = await matrix.data();
// Tensors also have a 'shape', a 'dtype', and a 'rank';
return {data, shape: matrix.shape, dtype: matrix.dtype, rank: matrix.rank};
}
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
values = {
// Create a vector (rank-1 Tensor) with 1000 equally spaced values between -2*pi and 2*pi for our x-axis.
const x = tf.linspace(-2 * Math.PI, 2 * Math.PI, 1000);

// Computes y = f(x) for each element in x. y is now a vector of the same shape as x.
const y = x.add(tf.scalar(shift)).cos().abs(); // equivalent to tf.abs(tf.cos(tf.add(tf.scalar(shift), x))

// Waits on data to be ready.
const xvals = await x.data();
const yvals = await y.data();
// Map x and y into an array of {x, y} tuples for plotting.
return Array.from(yvals).map((y, i) => { return {'x': xvals[i], 'y': y}});
}
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
outputs = tf.tidy(() => {
// Initialize a, b, c, d variables to random values. These are the values we're going to update!
const a = tf.variable(tf.randomNormal([], 0, .1));
const b = tf.variable(tf.randomNormal([], 0, .1));
const c = tf.variable(tf.randomNormal([], 0, .1));
const d = tf.variable(tf.randomNormal([], 0, .1));

// This is the object that will drive training.
const optimizer = tf.train.sgd(learningRate);
// Normalize the y values between 0 and 1.
// In general, this is super important because many of the functions / initializers
// used in neural networks make assumptions about range of values.
const ymin = inputData.ys.min();
const ymax = inputData.ys.max();
const yrange = ymax.sub(ymin);
const ynormalized = inputData.ys.sub(ymin).div(yrange);
// y = a * x^3 + b * x^2 + c * x + d

// a, b, c, and d are scalar values, but x is a vector!
// We can still perform element-wise ops between the variables and x by "broadcasting", which is built in.
const three = tf.scalar(3, 'int32');
const f = x =>
a.mul(x.pow(three))
.add(b.mul(x.square()))
.add(c.mul(x))
.add(d);
// The objective function: mean squared error between prediction and actual.
// label here is the observed data.
const loss = (preds, label) => preds.sub(label).square().mean();

// Train the model.
for (let i = 0; i < iterations; i++) {
// The function that's passed to minimize should *always* return a scalar value!
optimizer.minimize(() => loss(f(inputData.xs), ynormalized));
}

// Return the prediction after the model has been trained.
const modelOutput = f(inputData.xs);
// Since we normalized the inputs, we should "undo" the normalization.
const predictions = modelOutput.mul(yrange).add(ymin);
// Variables need to be disposed manually since we continously create and dispose models.
a.dispose();
b.dispose();
c.dispose();
d.dispose();
return {predictions};
})
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell

One platform to build and deploy the best data apps

Experiment and prototype by building visualizations in live JavaScript notebooks. Collaborate with your team and decide which concepts to build out.
Use Observable Framework to build data apps locally. Use data loaders to build in any language or library, including Python, SQL, and R.
Seamlessly deploy to Observable. Test before you ship, use automatic deploy-on-commit, and ensure your projects are always up-to-date.
Learn more