Show HN: C implementation of Karpathy's micrograd and with a Python Interface
1 day ago
4
A C implementation of automatic differentiation with a Python interface, inspired by Andrej Karpathy's micrograd.
NOTE: This project is developed for both Windows and Linux platforms. The Makefile automatically detects your operating system and uses the appropriate build commands.
Python 3.7+
C compiler
Make utility
git clone https://github.com/bthndmn12/lamba
cd lamba
# Build the C librariescd src
make all
make install
git clone https://github.com/bthndmn12/lamba
cd lamba
cd src
make all
make install
cd ..
pip install -e .
The project includes C implementations for performance-critical operations. Use the provided Makefile to build the shared libraries:
frommicrograd_cimportMLP, Engine, Adam# Create modelmodel=MLP(8, [16, 8, 1])
# Large dataset (1000 samples)large_inputs= [[float(i+j) forjinrange(8)] foriinrange(1000)]
large_targets= [float(i%2) foriinrange(1000)]
# Memory-efficient traininghistory=Engine.train(
model=model,
train_inputs=large_inputs,
train_targets=large_targets,
epochs=50,
batch_size=100, # Large batches automatically use memory-efficient modelearning_rate=0.001,
optimizer_type='adam',
memory_efficient=True, # Explicit memory-efficient modemini_batch_size=20, # Process in chunks of 20verbose=True
)
print(f"Final loss: {history['train_loss'][-1]:.6f}")
As in Karpathy's micrograd, the names, classes and methods are mostly the left the same. The Value class is a scalar value with automatic differentiation capabilities.
Value(data): Create a regular value
Value.persistent(data): Create a persistent value (for model parameters)
backward(): Compute gradients via backpropagation
backward_and_free(): Compute gradients and clean up temporary nodes
Since the memory management part has evolved into an insurmountable point for me, I have resorted to LLMs a lot at this point. I will focus on this area if I continue with the project. The library implements a memory management system using persistent flags:
Persistent values survive automatic cleanup operations, making them perfect for model parameters, while temporary values are automatically freed after gradient computation.
MLP (Multi Layer Perceptron)
The MLP class provides a complete neural network implementation.
# create an MLP with custom layer specificationsmodel=MLP(nin=3, layer_specs=[16, 8, 1])
# or with Layer objects for fine controlfrommicrograd_cimportLayerlayers= [
Layer(nin=3, nout=16, activation='relu'),
Layer(nin=16, nout=8, activation='relu'),
Layer(nin=8, nout=1, activation='linear')
]
model=MLP(nin=3, layer_specs=layers)
forward(inputs): Forward pass
parameters: Get all trainable parameters
zero_grad(): Zero all gradients
initialize_parameters(method, seed): Initialize weights and biases
parameter_count(): Get total parameter count
get_gradient_norm(): Compute gradient norm for monitoring
clip_gradients(max_norm): Gradient clipping
save_parameters(filepath) / load_parameters(filepath): Model persistence
Parameter Initialization Methods:
'xavier': Xavier/Glorot initialization
'random': Random uniform initialization [-1, 1]
'zero': Zero initialization
The Engine class provides training utilities and loss functions.
# Mean Squared Errorloss=Engine.mse_loss(predictions, targets)
# Custom loss functiondefcustom_loss(pred, target):
diff=pred[0] -target[0]
returndiff*diffloss=custom_loss(predictions, targets)