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 – Tensor struct, 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:

  1. Entry point – a main function in an executable source file (e.g., dev.c).
  2. main calls tensor_create (defined in tensor.h) to allocate storage.
  3. Operations such as tensor_matmul or tensor_relu are invoked; these are either pure C loops (tensor.h) or launch CUDA kernels (tensor_cu.h).
  4. Results are read back (GPU case uses cudaMemcpy inside 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.