Public
Edited
Dec 29, 2022
Paused
2 forks
2 stars
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
// Generate a Linear Reality
reality = make_linear(a, b)
Insert cell
// Initialize Generator of Linear Realities
Insert cell
function make_linear(slope, intercept) {
return function(position) {
return linear(slope, intercept, position);
}
}
Insert cell
function linear(...params) {
// normalize parameters to tensors
let anyTensors = params.filter(isTensor).length > 0
params = params.map(toTensor)
let [slope, intercept, position] = params

// Calculate y = f(position) = slope*position + intercept
let y = position.mul(slope).add(intercept)

// return y with same type as original params
return anyTensors ? y : y.arraySync()
}
Insert cell
Insert cell
Insert cell
Insert cell
// A rainbow colored, string universe
{
let rainbow_universe = make_linear(a, b)
return Plot.plot({
grid: true,
x: {label: "position in string universe →", domain: [_.min(sampled_positions), _.max(sampled_positions)]},
y: {label: "↑ color in rainbow universe", domain: [-2, 2]},
marks: [
Plot.ruleY([0]),
Plot.ruleX([0]),
Plot.dot(
_.range(_.min(sampled_positions), _.max(sampled_positions), 0.01),
{
x: point_on_string => point_on_string,
y: point_on_string => rainbow_universe(point_on_string),
fill: point_on_string => rainbow_universe(point_on_string)
})
]
})
}
Insert cell
Insert cell
// Perform Scientific Experiments to Sample Data from Reality
Insert cell
sampled_positions = _.range(-2, 2, 0.1)
Insert cell
sampled_reality = sampled_positions.map(position => reality(position))
Insert cell
Insert cell
noisy_sampled_reality = add_noise(sampled_reality, noise);
Insert cell
// Visualize data samples of reality collected from our experiment
// It gives us a glimpse into the true nature of reality
Plot.plot({
grid: true,
x: {label: "position in string universe →", domain: [_.min(sampled_positions), _.max(sampled_positions)]},
y: {label: "↑ color in rainbow universe", domain: [-2, 2]},
marks: [
Plot.ruleY([0]),
Plot.ruleX([0]),
Plot.dot(
sampled_positions,
{
x: sampled_positions,
y: noisy_sampled_reality,
fill: sampled_positions,
})
]
})
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
belief_updates = {
// Setup Iteration Parameters
const learning_rate = 0.01
const steps = 10;
const theoretical_scientist = make_theoretical_scientist(sampled_positions);
const actual = reality(sampled_positions)
// Our first (random) theory to explain reality
var theory_parameters = [2, 2];
var belief_updates = [];
var latest_predictions;
// The Scientific Method
for (let step = 0; step < steps; step++) {
// Predictions by the latest theory
var latest_predictions = theoretical_scientist(...theory_parameters);
// How close are the predictions to reality?
var latest_loss = get_loss(actual, latest_predictions).arraySync()
// Collate results
sampled_positions.map((p, id) => {
belief_updates.push({
"predictions": latest_predictions[id],
"loss": `i=${step}, error=${latest_loss.toFixed(2)}`,
"sampled_positions": p,
"iteration": step
})
});
// Update theory to make predictions that better match our experimental data of reality
theory_parameters = update(theory_parameters, sampled_positions, learning_rate);
}
return belief_updates
}
Insert cell
Plot.plot({
grid: true,
x: {label: "position →", domain: [_.min(sampled_positions), _.max(sampled_positions)]},
y: {label: "↑ value", domain: [-10, 10]},
marks: [
Plot.ruleX([0]),
Plot.ruleY([0]),
// Visualize the true nature of our reality
Plot.line(sampled_positions.map(position => [position, reality(position)])),
// Visualize data samples of reality collected from our experiment
Plot.dot(sampled_positions,
{x: sampled_positions, y: noisy_sampled_reality, fill: "red"}),
// Visualize our (hopefully) improving theories with each iteration of the scientific process
// Color of each newer theory is darker
Plot.line(belief_updates,
{x: "sampled_positions", y: "predictions", z: "iteration", stroke: "iteration"}),
// Label loss/error, step of each belief update
Plot.text(belief_updates,
Plot.selectLast({x: "sampled_positions", y: "predictions", z: "iteration", text: "loss", textAnchor: "start", dx: -80})),
]
})
Insert cell
Insert cell
Insert cell
tf = require('@tensorflow/tfjs@3.0')
Insert cell
function make_noise(x, scale) {
return tf.randomNormal([x.length], 0, scale).arraySync();
}
Insert cell
function add_noise(points, scale) {
const noise_in_sample = make_noise(points, scale)
return points.map((point, id) => point + noise_in_sample[id])
}
Insert cell
function mean_absolute_error(prediction, actual) {
return tf.sub(prediction, actual).abs().mean()
}
Insert cell
function get_loss(predictions, actual) {
return mean_absolute_error(predictions, actual);
}
Insert cell
function make_loss(theory, experiment) {
return (sample) => get_loss(theory(sample), experiment);
}
Insert cell
function make_theoretical_scientist(experimental_data) {
return (a, b) => linear(a, b, experimental_data);
}
Insert cell
function isTensor(item) {
return tf.tensor_util.getTensorsInContainer(item).length > 0
}
Insert cell
function toTensor(item) {
return isTensor(item) ? item : tf.tensor(item)
}
Insert cell
function update(theory_params, sample_points, learning_rate) {
// Setup
// Initialize, normalize variables
sample_points = toTensor(sample_points)
learning_rate = tf.scalar(learning_rate)
const theoretical_scientist = make_theoretical_scientist(sample_points)
const gradient_generators = tf.grads(theoretical_scientist);

// Calculate loss
// How off were the theoretical scientists beliefs from reality?
let predictions = theoretical_scientist(...theory_params)
let actual = reality(sample_points)
let loss = get_loss(predictions, actual)

// Calculate gradients
// Find the direction, magnitude of updates to the theories required
let gradients = gradient_generators(theory_params)
gradients = tf.tensor(gradients.map(g => g.arraySync()))

// Update theory paramaters
// Move the theoretical scientists beliefs closer to reality
theory_params = tf.tensor(theory_params)
.sub(gradients
.mul(learning_rate)
.mul(loss))
.arraySync()
return theory_params
}
Insert cell
slider = (min, max, step, value, labelText="") => {
const form = html`
<form>
${labelText}
<input type=range name=iters step=${step} min=${min} max=${max} value=${value}> <i><span class="value">${value}</span></i>
</form>`;
const label = form.querySelector('span.value');
form.value = form.iters.valueAsNumber;
form.iters.oninput = () => {
form.value = form.iters.valueAsNumber;
label.innerHTML = form.iters.valueAsNumber;
};
return form;
}
Insert cell
import {toc} from "@nebrius/indented-toc"
Insert cell
import {show} from "@zaidalyafeai/show-tensor"
Insert cell

Purpose-built for displays of data

Observable is your go-to platform for exploring data and creating expressive data visualizations. Use reactive JavaScript notebooks for prototyping and a collaborative canvas for visual data exploration and dashboard creation.
Learn more