A lightweight deep learning framework in JavaScript. Designed to feel like PyTorch. Uses reverse-mode automatic differentiation and wraps around numjs for base matrix operations.
See Examples/ to see what onegrad can do.
There's also a web demo demonstrating entirely in the browser machine learning with Onegrad.
var onegrad = require("./../onegrad/tensor.js")
var x = new onegrad.eye(3);
var y = new onegrad.tensor([[2, 0, -2]]);
var z = y.dot(x).sum();
z.backward();
console.log("x: ", x.grad.tolist()); // dz/dx
console.log("y: ", y.grad.tolist()); // dz/dyOnegrad has many helper functions for creating tensors. All helper functions have the optional argument requiresGrad for specifying if the tensors gradient should be saved after a backwards pass (set to true by default)
> onegrad.tensor([1, 2, 3]);
tensor([1, 2, 3])
> onegrad.ones([2, 2]);
tensor([[1, 1],
[1, 1]])
> onegrad.zeros([2, 2]);
tensor([[0, 0],
[0, 0]])
> onegrad.randn([2]);
tensor([0.5607564512157093, 0.9575847907431982])
> onegrad.arange([5]);
tensor([0, 1, 2, 3, 4])
> onegrad.arange([5, 10]);
tensor([5, 6, 7, 8, 9])
> onegrad.eye(3);
tensor([[ 1, 0, 0 ],
[ 0, 1, 0 ],
[ 0, 0, 1 ]])Onegrad tensors have multiple properties that can be accessed by the user:
.shapedimenstions of the tensor.selectionNumjs array contained in the tensor.gradgradient of the tensor.opoperation used to create the tensor (set to none when made with the above helper functions).parentsparent tensors used for the tensors creation (empty array for tensors made with the above helpers)requiresGradwhether the tensor will save its gradient value after each backwards pass
Additionaly .tolist() is used to convert the tensor into a js array.
> var a = onegrad.tensor([1, 2, 3]);
> a
tensor([1, 2, 3])
> a.tolist();
[1, 2, 3]
> a.shape
[3]
> a.selection
array([1, 2, 3])
> a.requiresGrad
trueCalling .backward() on a tensor performs a backwards pass on its DAG.
> var a = onegrad.tensor([1, 2, 3]);
> var b = onegrad.tensor([2, 2, 2]);
> var c = a.sub(b);
> c
tensor([-1, 0, 1])
> c.parents
[tensor([1, 2, 3]), tensor([2, 2, 2])
> c.op
Sub
> c.backward();
> a.grad
tensor([1, 1, 1])
> b.grad
tensor([-1, -1, -1])Onegrad supports most tensor operations required for deep learning
> var a = onegrad.tensor([1, 2]);
> a.max()
tensor([2])
> a.min()
tensor([1])
> a.sum()
tensor([3])
> a.exp()
tensor([2.718281828459045, 7.38905609893065])
> a.negative()
tensor([-1, -2])
> a.log()
tensor([0, 0.300975762292638])> var a = onegrad.tensor([1, 2]);
> var b = onegrad.tensor([3, 4]);
> var c = onegrad.tensor([2]);
> a.dot(b)
tensor([11])
> a.add(b)
tensor([4, 6])
> a.sub(b)
tensor([-2, -2])
> a.pow(b)
tensor([1, 4])Onegrad supports the transpose and reshape operations for manipulating tensors.
Note: reshape reshapes the tensor in-place
> var a = onegrad.tensor([[1, 2, 3, 4]]);
> a.shape
[1, 4]
> a.transpose()
tensor([[1], [2], [3], [4]])
> a.transpose().shape
[4, 1]
> a.reshape([2, 2])
> a
tensor([[1, 2],
[3, 4]])
> a.shape
[2, 2]Onegrad supports most of the common activations functions
> var a = onegrad.tensor([-2.5673934, 4]);
> onegrad.sigmoid(a)
tensor([0.07126663626540311, 0.9820137900379085])
> onegrad.tanh(a)
tensor([-0.9882923248658222, 0.999329299739067])
> onegrad.relu(a)
tensor([0, 4])
> onegrad.relu6(a)
tensor([0, 4])
> onegrad.leakyRelu(a)
tensor([-0.025673934, 4])
> onegrad.selu(a)
tensor([-1.5448988171423363, 4])
> var b = onegrad.tensor([[1.3, 5.1, 2.2, 0.7, 1.1]]);
> onegrad.softmax(b)
tensor([
0.02019046473258069,
0.9025376890165726,
0.04966052987196014,
0.011080761983386348,
0.016530554395500222
])Onegrad supports some layer abstractions to help make building networks easier. All layers have 3 parameters:
inDimnumber of input nodesoutDimnumber of output nodesuseBiasbias toggle (true by default)
Note: recurrent layers requires a call to .resetPrev() to reset the previous hidden output.
> var x = onegrad.randn([1, 10]);
> var denselayer = new nn.Linear(10, 1, false);
> denseLayer.forward(x)
tensor([0.4736675307891193])
> var rnnLayer = new nn.RNN(10, 1, false);
> rnnLayer.forward(x)
tensor([0.06440360973284968])
// reset previous hidden output after each complete forward pass on a sequence
> rnnLayer.resetPrev()The parameters of each layer can be accessed using the .parameters() function.
> var rnnLayer = new nn.RNN(10, 1, true);
> rnnLayer.parameters()
list([tensor([...]), tensor([...]), tensor([...])])Modules can be used to define entire models inside a class by extending from nn.Modules.
Defined models requires constructor() for defining the model layers and forward(x) for specifying how the layers interact.
Model layers need to be placed in an array called layers (required for the framework to extract model parameters)
> class Model extends nn.Module {
constructor(inDim, outDim) {
super()
this.layers = [
new nn.Linear(inDim, 100),
new nn.Linear(100, outDim)
]
}
forward(x) {
x = onegrad.sigmoid(this.layers[0].forward(x))
x = onegrad.sigmoid(this.layers[1].forward(x))
return x
}
}
> var model = new Model(10, 1);
> var x = onegrad.randn([1, 10]);
> model.forward(x)
tensor([0.7826402419856238])Models can be saved and loaded from a .json file. requires the model filepath to be specified.
> model.save('model.json');
> model.load('model.json');Onegrad supports a few of the basic loss functions.
To compute the loss call .compute(output, target) on the loss function.
> var x = onegrad.randn([1, 10]);
> var tar = onegrad.randn([1, 10]);
> var lossfn = new nn.MSE();
> lossfn.compute(x, tar)
tensor([0.0270..., 0.2257..., 0.0173..., 0.4238..., 0.2901...])
> var lossfn = new nn.MAE();
> lossfn.compute(x, tar)
tensor([0.1082..., 0.0471..., 0.4704..., 0.4681..., 0.0965...])Onegrad currently supports the SGD and Adam optimisers.
Parameters of SGD
paramsparameters to updatelrlearning rate (default 0.01)bsbatch size (default 1)
Parameters of Adam
paramsparameters to updatelrlearning rate (default 0.001)bsbatch sizeb1beta 1 (default 0.9)b2beta 2 (default 0.999)epsepsilon (default 1e-8)
> var opt = new optim.SGD(model.parameters(), lr=0.01);
// update model weights
> opt.step()
// reset parameter gradients
> opt.zeroGrad()Onegrad supports a basic learning rate scheduler which decays the learning rate every n steps.
Parameters
optimoptimiser to schedulestepSizehow many steps to decay on (default 30)gammahow much to decay the gradient (default 0.1)lastEpochthe index of last epoch (default -1)
> var opt = new optim.SGD(model.parameters(), lr=0.01);
> var scheduler = new optim.StepLR(opt);
// step scheduler every iteration
scheduler.step()Onegrad supports the ability to visualise the computational graph of a model. Each node in the graph corresponds to a tensor which contains information about its creation, shape, etc.
To visualise the model first construct the graph by calling .constructDAG on the last tensor, then pass the DAG to vis.visualise(DAG). The graph of the model will then be visable at localhost:5000.
Note: A forward pass is required to compute the computational graph which is to be displayed.
// Compute forward pass through model
> var out = model.forward(x);
> var loss = lossfn.forward(out);
// Create computational graph and visualise
> var dag = loss.constructDAG();
> vis.visualise(dag)
'View graph at http://localhost:5000'By default tensors are given generic names, however individual tensors can be labelled which will be displayed on the graph instead, this often makes for easier interpretation and is recommended.
Note: layers created with nn abstractions will be labelled by default to indicate the tensors purpose and which layer it belongs to.
// Add label on tensor creation
> var a = onegrad.tensor([1, 2, 3], {label:"input"});
// Add label after tensor creation
> var b = onegrad.tensor([4, 5, 6]);
> b.label = "second input";The following is an example visualisation on a 2 layer feed forward network, the code to generate this graph can be found at tests/visualise.js.
- add ability to convert trained pytorch models to onegrad
implement backprop for all operationsadd more optimiser functionsadd module class for defining modelsadd more activation functions (LeakyReLU, ReLU6, SELU)add ability to save and load model weightsadd visualisations for the DAGadd more loss functions (CategoricalCrossEntropy, NLLLoss)- add more nn abstractions (LSTM,
GRU, Conv2d) - add more examples
bundle source code for in browser support

