Install micrograd via pip
masterInstall the micrograd library using pip to get access to the autograd engine and neural network library.
pip install microgradrepository·master·Indexed 12 days ago
https://github.com/karpathy/microgradA tiny Autograd engine that implements reverse-mode autodiff over a dynamically built DAG of scalar values. Designed for educational purposes, it includes a small neural networks library with a PyTorch-like API, featuring the Value class for autograd operations and an MLP class for building multi-layer perceptrons.
Install the micrograd library using pip to get access to the autograd engine and neural network library.
pip install microgradTo visualize the computational graph in micrograd, you must install the graphviz system library and the Python wrapper.
On macOS using Homebrew:
brew install graphvizUsing pip:
pip install graphvizbrew install graphviz
pip install graphvizYou can visualize the flow of gradients and data through your Value objects using a draw_dot function. This function traces the graph from a root Value node and renders it using Graphviz.
Parameters:
root: The Value object representing the end of your computation.format: The output format (e.g., 'svg', 'png'). Defaults to 'svg'.rankdir: The direction of the graph. 'LR' (Left to Right) or 'TB' (Top to Bottom). Defaults to 'LR'.Usage:
Value objects..backward() on the output node to populate gradients.draw_dot(node)..render('filename') on the returned object to save the graph to a file.from micrograd.engine import Value
# 1. Define computation
x = Value(1.0)
y = (x * 2 + 1).relu()
# 2. Compute gradients
y.backward()
# 3. Visualize
dot = draw_dot(y)
# 4. Save to file
dot.render('graph_output')When defining a custom loss function, you can incorporate regularization and specific loss types using Value operations:
(1 + -yi * scorei).relu() for each sample.alpha * sum((p*p for p in model.parameters())).# svm "max-margin" loss
losses = [(1 + -yi*scorei).relu() for yi, scorei in zip(yb, scores)]
data_loss = sum(losses) * (1.0 / len(losses))
# L2 regularization
alpha = 1e-4
reg_loss = alpha * sum((p*p for p in model.parameters()))
total_loss = data_loss + reg_lossTo train a model in MicroGrad, follow the standard optimization loop:
total_loss (which must be a Value object).model.zero_grad() to clear previous gradients.total_loss.backward() to compute gradients via autograd.model.parameters() and manually update the .data attribute using the calculated .grad and a learning rate.Note: MicroGrad does not provide a built-in optimizer like Adam; you implement the update step manually.
for k in range(100):
# 1. Forward
total_loss, acc = loss()
# 2. Backward
model.zero_grad()
total_loss.backward()
# 3. Update (Stochastic Gradient Descent)
learning_rate = 0.01
for p in model.parameters():
p.data -= learning_rate * p.gradYou can visualize the internal structure of a micrograd.nn.Neuron by passing its output through draw_dot after calling .backward().
import random
from micrograd import nn
from micrograd.engine import Value
random.seed(1337)
n = nn.Neuron(2)
x = [Value(1.0), Value(-2.0)]
y = n(x)
y.backward()
dot = draw_dot(y)
dot.render('neuron_graph')The core of micrograd is the Value class from micrograd.engine. It implements reverse-mode autodiff over scalar values. You can perform standard arithmetic operations and activation functions (like .relu()) on Value objects. After a forward pass, calling .backward() on the output node computes the gradients for all nodes in the computational graph, which can be accessed via the .grad attribute.
from micrograd.engine import Value
a = Value(-4.0)
b = Value(2.0)
c = a + b
d = a * b + b**3
c += c + 1
c += 1 + c + (-a)
d += d * 2 + (b + a).relu()
d += 3 * d + (b - a).relu()
e = c - d
f = e**2
g = f / 2.0
g += 10.0 / f
print(f'{g.data:.4f}') # prints the outcome of the forward pass
g.backward()
print(f'{a.grad:.4f}') # prints the numerical value of dg/da
print(f'{b.grad:.4f}') # prints the numerical value of dg/dbTo verify the correctness of the calculated gradients, you can run the unit tests. Note that you must have PyTorch installed, as the tests use it as a reference implementation for verification.
python -m pytestMicroGrad operates on Value objects. When passing data through a model, you must convert your raw numerical inputs (e.g., from a NumPy array) into a list of Value objects.
Because MLP is a container of layers, you can iterate over your inputs and call the model instance directly on each input list to get the corresponding Value scores.
from micrograd.engine import Value
# Assuming Xb is a batch of numpy arrays
inputs = [list(map(Value, xrow)) for xrow in Xb]
# Forward pass to get scores
scores = list(map(model, inputs))You can create a neural network using the MLP class from micrograd.nn. The constructor takes the input dimension as the first argument, followed by a list representing the number of neurons in each hidden layer and the output layer.
To inspect the model or count the total number of trainable parameters, use the print() function on the model instance and call the .parameters() method.
from micrograd.nn import MLP
# Create a 2-layer neural network with 2 inputs, two hidden layers of 16 neurons, and 1 output
model = MLP(2, [16, 16, 1])
print(model)
print("number of parameters", len(model.parameters()))