The Problem
C‑centric machine‑learning tutorials usually rely on heavyweight libraries (PyTorch, NumPy). For teams that need a minimal, portable implementation – e.g., embedded firmware, teaching environments without Python – the lack of a pure‑C tensor abstraction forces them to either write ad‑hoc code or pull in large dependencies.
What This Does
The repository delivers a tiny tensor library written in plain C with optional CUDA acceleration. Core definitions live in tensor.h (CPU) and tensor_cu.h (GPU). Simple example programs (dev.c, dev/llama3.c) and test harnesses (test.c, test_cuda.cu) show how to allocate tensors, perform element‑wise ops, and run a forward pass. A helper script, create_mnist_csv.py, converts the MNIST dataset to CSV for use with the C examples.
Key files:
tensor.h–Tensorstruct, CPU memory management, basic ops (matmul,relu,logsoftmax).tensor_cu.h– GPU equivalents, thin wrappers around CUDA kernels.dev.c– minimal “hello‑tensor” driver that creates a tensor, runs a few ops, and prints results.dev/llama3.c– a larger example that builds a three‑layer network (the duplicated code blocks were flagged here).test.c/test_cuda.cu– unit‑style programs exercising the API on CPU and GPU respectively.
How It Is Wired
There is no central runtime; the library is header‑only. Compilation of a user program pulls in the headers, which in turn define static inline functions and, for CUDA, external kernel prototypes. Execution flow is therefore:
- Entry point – a
mainfunction in an executable source file (e.g.,dev.c). maincallstensor_create(defined intensor.h) to allocate storage.- Operations such as
tensor_matmulortensor_reluare invoked; these are either pure C loops (tensor.h) or launch CUDA kernels (tensor_cu.h). - Results are read back (GPU case uses
cudaMemcpyinside the helpers) and printed or fed to the next layer.
Only the example files drive the library; the library itself does not call external services or files. Consequently, the blast radius of a change is limited to the header files and any compiled kernels they expose. No circular imports are present, and the import graph consists of a single internal module with zero edges.
How To Use It
# Clone the repo
git clone https://github.com/moses-y/tensor.h
cd tensor.h
# Build the CPU example
gcc -Wall -O2 -o dev dev.c -I.
# Build the CUDA example (requires nvcc and a CUDA‑capable device)
nvcc -O2 -o dev_cuda dev.c -I. # same source, CUDA paths resolved by headers
# Run the MNIST conversion script (Python 3 required)
python3 create_mnist_csv.py # produces train.csv / test.csv used by examples
The repo provides no makefile, so compilation commands must be issued manually as above. No configuration files or environment variables are required.
Real‑World Use
A firmware team can embed tensor.h in a microcontroller project to run a fixed‑size inference network without pulling in a full ML stack. The workflow is:
#include "tensor.h"
int main() {
Tensor x = tensor_create(1, 784); // input vector
Tensor w1 = tensor_load("w1.bin"); // pre‑trained weights
Tensor y = tensor_matmul(x, w1);
tensor_relu_inplace(&y);
// ... continue layers, then softmax
}
Compiled with the target C compiler, the code runs entirely from static memory, providing deterministic inference.
Code Health & Issues
- High – Duplicated code blocks – 30 repeated 6‑line fragments across
dev/llama3.c,tensor.h,tensor_cu.h. Consolidating these helpers would reduce maintenance overhead. - Medium – Missing CI/CD – No
.github/,Makefile, or other automation; builds and tests must be run manually. - Medium – No LICENSE – Repository lacks a license file, leaving usage and redistribution rights undefined.
No secrets were found in the history, and the test files (test.c, test_cuda.cu) are present but not integrated into an automated test runner.
The Bottom Line
The repo supplies a functional, header‑only tensor abstraction with optional CUDA support, useful for low‑overhead learning or embedded inference. However, duplicated helper code, absent CI, and lack of a license limit its readiness for production adoption. Engineers comfortable with manual builds can extract the core API, but a refactor to eliminate duplication and the addition of basic build scripts would improve maintainability.