Published
Edited
Aug 7, 2020
Importers
11 stars
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
f = x => (x - 40)**2 + x
Insert cell
fp = x => 2 * x - 79
Insert cell
fpp = x => 2
Insert cell
Insert cell
Insert cell
Insert cell
class Func {
constructor() {
// Some generic constructor
}
calc(x) {
// Return the value of this function at x
}
df() {
// Return the differential of this function
}
toString() {
return `?`
}
clean() {
return "?"; // Returns a cleaned function.
}
}
Insert cell
Insert cell
class Add extends Func {
constructor(left, right) {
super();
this.left = left;
this.right = right;
}
calc(x) {
return this.left.calc(x) + this.right.calc(x);
}
df() {
return new Add(this.left.df(), this.right.df())
}
toString() {
return `(${this.left.toString()} + ${this.right.toString()})`
}
}
Insert cell
Insert cell
class Mult extends Func {
constructor(left, right) {
super();
this.left = left;
this.right = right;
}
calc(x) {
return this.left.calc(x) * this.right.calc(x);
}
df() {
return new Add(
new Mult(this.left, this.right.df()),
new Mult(this.right, this.left.df())
)
}
toString() {
return `(${this.left.toString()} * ${this.right.toString()})`
}
}
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
F = new Add(new Pow(new Add(new X(), new Constant(-40)), 2), new X())
Insert cell
Insert cell
F.df()
Insert cell
Insert cell
Insert cell
tex `f'(x)=${F.df().toString()}`
Insert cell
tex `f''(x)=${F.df().df().toString()}`
Insert cell
Insert cell
md `We should get that ${tex `${F.df().df().clean().toString()}`} = 2.`
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
x = new Value(35);
Insert cell
y = new Value(-40);
Insert cell
z = add(pow(add(x, y), 2), x);
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
class Value {
constructor(data, _deps=[], _op='') {
this.data = data;
this.grad = 0;
this._dependencies = _deps
this._op = _op;
this._order = [];
}
_backward() {
// Reimplemented by the operators.
}
zeroGrad() {
this.grad = 0;
}
backward(focus) {
// Find the topological ordering of the values
// For each value, visit it's dependencies first and add them to the ordering
let order = [];
let visited = [];

function get_deps(focus) {
if (!visited.includes(focus)) {
visited.push(focus);
focus._dependencies.forEach(
(dep) => get_deps(dep)
)

order.push(focus)
}
}

get_deps(this);

// Initialize the gradient of the whole function to 1
// and calculate the gradient for each value.
this.grad = 1;

for (let i = 1; i <= order.length; i++) {
let focus = order[order.length - i]
focus._backward()
}
this._order = order;
}

}
Insert cell
function neg(val) {
return mul(val, new Value(-1))
}
Insert cell
function sub(left, right) {
return add(left, neg(right))
}
Insert cell
function sum(items) {
return items.reduce((acc, current) => add(acc, current), new Value(0))
}
Insert cell
function add(left, right) {
let val = new Value(left.data+right.data, [left, right], '+');
val._backward = function() {
left.grad += val.grad;
right.grad += val.grad;
}
return val;
}
Insert cell
function div(left, right) {
return mul(left, pow(right, -1))
}
Insert cell
function mul(left, right) {
let val = new Value(left.data*right.data, [left, right], '*');
val._backward = function() {
left.grad += val.grad * right.data;
right.grad += val.grad * left.data;
}
return val;
}
Insert cell
function pow(base, power) {
let val = new Value(base.data ** power, [base] , `^${power}`);
val._backward = function() {
base.grad += power * (base.data ** (power -1)) * val.grad;
}
return val;
}
Insert cell
function relu(input) {
let val = new Value(Math.max(0, input.data),[input], 'relu');
val._backward = function() {
input.grad += val.data > 0 ? val.grad : 0;
}
return val;
}
Insert cell
Math.min
Insert cell
Insert cell
function graph(root) {
let nodes = [];
let edges = [];
for(let i=0; i<root._order.length;i++) {
let node = root._order[i];
let index = root._order.indexOf(node);
nodes.push(`n${index} [shape=record label="val ${node.data} | grad ${node.grad}"]`);
if(node._op !== "") {
nodes.push(`n${index}op [label="${node._op}"]`);
edges.push(`n${index}op -> n${index}`);
node._dependencies.forEach(d => {
edges.push(`n${root._order.indexOf(d)} -> n${index}op`);
})
}
}
return edges.join(";\n") + ";\n" + nodes.join(";\n")
}
Insert cell
Insert cell
Insert cell
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