dart_pytorch 0.1.2 copy "dart_pytorch: ^0.1.2" to clipboard
dart_pytorch: ^0.1.2 copied to clipboard

A minimal PyTorch-style tensor library for Dart with reverse-mode autograd, hand-written CUDA kernels via dart:ffi, and an nn.Module scaffolding for Transformers, GPT, MoE, ViT, and LC0 chess-network [...]

dart_pytorch #

A minimal PyTorch-style tensor library for Dart, backed by hand-written CUDA kernels via dart:ffi.

Matmul, elementwise binary ops (+ - * /, scalar and row-broadcast), unary activations (relu, sigmoid, tanh, abs, log, pow), 2D transpose, sum/mean reductions, LayerNorm, row-wise softmax, fused crossEntropy, embedding, scaled dot-product attention, concat, and dropout all run end-to-end on either CPU or GPU. Reverse-mode autograd is wired for the whole op set (with relu/abs backward CPU-only for now). A small nn.Module scaffolding exposes Linear, LayerNorm, Embedding, Dropout, MultiHeadAttention, a pre-LN TransformerBlock, TransformerEncoder (stacked blocks with optional final LN), TransformerLM (token embed + positional encoding

  • causal encoder + linear head), GPT (weight-tied GPT-2 style causal LM with learned position embeddings, embedding dropout, an EncoderCache KV-cache path for O(N) autoregressive generate(), and greedy / temperature / top-k sampling), and both SinusoidalPositionalEncoding / LearnedPositionalEmbedding as trainable / regularization layers with train() / eval() mode toggling; SGD / Adam optimizers update parameters in place on their native device, clipGradNorm bounds the global gradient L2, and LRSchedulers (StepLR, LinearWarmupCosineDecay) mutate the optimizer's lr on a schedule. Checkpoint (in nn/serialize.dart) persists any Module's parameters to a small binary format on disk and loads them back into a same-shape model. A pure-Dart byte-level BpeTokenizer in core/data/bpe_tokenizer.dart provides train / encode / decode / saveFile / loadFile for tokenizing real text. Runnable char-level demos at bin/lm_demo.dart and bin/gpt_demo.dart overfit a short refrain end-to-end (dart run bin/gpt_demo.dart); bin/gpt_train.dart shows the full pipeline: BPE + GPT + Adam + warmup/cosine schedule + gradient accumulation + checkpoint save/load + sampling.

Layout #

lib/
  dart_pytorch.dart              # package entry point (re-exports Tensor)
  core/tensor/
    tensor.dart                  # Tensor class + factories (fromList, fill) + to()
    ops.dart                     # elementwise / activation / reduction ops, CPU + GPU (part)
    mat_mul.dart                 # matmul (CPU loop + GPU tiled kernel) (part)
    layer_norm.dart              # LayerNorm forward + backward, CPU + GPU (part)
    softmax.dart                 # softmax + fused crossEntropy, CPU + GPU (part)
    embedding.dart               # table lookup with scatter-add backward (part)
    attention.dart               # scaled dot-product attention (composition) (part)
    dropout.dart                 # inverted dropout via mask multiply (part)
    concat.dart                  # last-axis 2D concat with slice-back backward (part)
    cuda_engine.dart             # dart:ffi bindings to libmat_mul.so
  core/nn/
    module.dart                  # abstract Module base (parameters, zeroGrad, train/eval)
    linear.dart                  # trainable Linear (y = x @ W.T + b)
    layer_norm.dart              # trainable LayerNorm module wrapper
    embedding.dart               # trainable Embedding module wrapper
    dropout.dart                 # nn.Dropout wrapper with train/eval toggle
    multi_head_attention.dart    # per-head Linear + SDPA + concat + out proj
    transformer.dart             # pre-LN TransformerBlock (MHA + MLP + residuals)
    positional.dart              # sinusoidal + learned positional encodings
    masks.dart                   # causalMask(n) additive attention mask helper
    transformer_encoder.dart     # stacked TransformerBlocks + optional final LN
    transformer_lm.dart          # token embed + posEnc + causal encoder + head
    kv_cache.dart                # MHACache + EncoderCache for GPT.generate fast path
    gpt.dart                     # GPT-2 style: tied weights, learned PE, generate()
    serialize.dart               # Checkpoint.save/loadInto — DPTC binary format
  core/optim/
    optimizer.dart               # abstract Optimizer base (step, zeroGrad, mutable lr)
    sgd.dart                     # SGD with optional momentum + weight decay
    adam.dart                    # Adam with bias correction + decoupled WD
    grad_utils.dart              # clipGradNorm (global L2 clip, in place)
    lr_scheduler.dart            # StepLR + LinearWarmupCosineDecay
  core/data/
    bpe_tokenizer.dart           # byte-level BPE: train / encode / decode / save / load
  native/
    src/
      engine.cu                  # extern "C" DLLEXPORT wrappers (30 symbols)
      kernels/
        common.cuh               # CUDA includes, DLLEXPORT macro, reductions
        matmul.cuh               # tiled matmul_fwd/bwd kernels
        elementwise.cuh          # add/sub/mul/div, scalar/row-bcast, activations, abs/log/pow
        transpose.cuh            # 32x32 tile transpose
        layernorm.cuh            # layernorm_fwd/bwd (block-per-row)
        softmax.cuh              # softmax_fwd/bwd + cross_entropy_fwd/bwd (fused)
        embedding.cuh            # embedding_fwd + scatter-add embedding_bwd
    lib/                         # populated by the nvcc build (gitignored)
native/lib/libmat_mul.so         # actual load path used by cuda_engine.dart
doc/device-placement.md         # per-op CPU vs GPU decisions + implementation status
test/dart_pytorch_test.dart      # matmul + CPU-op correctness tests

Note: cuda_engine.dart loads ${cwd}/native/lib/libmat_mul.so, so the .so lives at the repo root, not under lib/native/lib/.

Requirements #

  • Dart SDK ^3.9.3
  • NVIDIA GPU + CUDA toolkit (tested with CUDA 12.0, driver 576.x)
  • Linux / WSL2

Build the native library #

nvcc --shared -Xcompiler -fPIC \
     -o native/lib/libmat_mul.so \
     lib/native/src/engine.cu

No local GPU? See doc/colab.md for a copy/paste recipe that runs on a free Google Colab, Kaggle, Paperspace, or Lightning AI GPU. scripts/setup_colab.sh handles the whole install + nvcc build in one command.

Have friends with GPUs, or want to pool donated compute? See doc/coop-training.md for three cooperative training modes (single-process replicas, HTTP coordinator + workers, peer-to-peer gossip). All three use DiLoCo-style periodic parameter averaging so one full model shipment every K local steps is enough bandwidth for training over slow / free internet links.

Run the tests #

dart pub get
dart test

Expected output: +137: All tests passed! (matmul CPU + GPU paths, mixed-device rejection, device round-trip, every CPU op, every GPU op, a CPU/GPU parity chain, 22 autograd tests, 9 LayerNorm tests, 16 softmax / cross-entropy / embedding tests, 13 optimizer tests, 9 attention / Linear tests, 14 regularization tests, 17 concat / MultiHeadAttention / TransformerBlock tests, plus 15 positional-encoding tests including PE + TransformerBlock trained end-to-end with Adam).

Usage #

import 'package:dart_pytorch/dart_pytorch.dart';

void main() {
  // Small tensors default to CPU (below Tensor.autoDeviceThreshold = 4096).
  final a = Tensor.fromList([2, 3], [1, 2, 3, 4, 5, 6]);
  final b = Tensor.fromList([3, 2], [7, 8, 9, 10, 11, 12]);
  final c = a.matmul(b);            // CPU path, shape [2, 2]
  print(c.toList());                // [58, 64, 139, 154]

  // CPU elementwise + activations.
  final x = Tensor.fromList([4], [-1.0, 0.0, 1.0, 2.0]);
  print((x + 1).toList());          // [0, 1, 2, 3]
  print(x.relu().toList());         // [0, 0, 1, 2]

  // Autograd.
  final w = Tensor.fromList([1, 2], [0.5, -0.3], requiresGrad: true);
  final xVec = Tensor.fromList([2, 1], [1.0, 2.0]);
  final loss = (w.matmul(xVec) - 4.0).pow(2).sum();
  loss.backward();
  print(w.grad!.toList()); // gradient wrt w

  // Opt in to GPU for large workloads.
  final big = Tensor.fromList([64, 64],
      List<double>.generate(4096, (i) => i.toDouble()),
      device: Device.GPU);
  final bigResult = big.matmul(big); // tiled 32x32 kernel
  big.dispose();
  bigResult.dispose();

  // Or transfer explicitly.
  final gpuVersion = a.to(Device.GPU);
  gpuVersion.dispose();
}

Currently supported #

See doc/device-placement.md for the full policy and per-op status. Short version:

Area CPU GPU Notes
Tensor.fromList / Tensor.fill yes yes Device chosen by size (threshold 4096) or explicit
to(Device), toList(), dispose() yes yes
matmul (forward) yes yes CPU naive loop; GPU tiled 32x32
matmul (backward) GPU kernels compiled, not wired to Dart
Elementwise + - * / (same shape) yes yes
Scalar broadcast (t + num or t + [1]) yes yes num on GPU uploads a 1-elem tensor + disposes
Row broadcast [1,N] into [M,N] yes (all) + only Sub/mul/div row-bcast on GPU throws — use .to(Device.CPU)
relu, sigmoid, tanh, abs, log, pow yes yes
transpose (2D) yes yes CPU strided copy; GPU 32x32 tile kernel
sum, mean yes yes GPU: atomicAdd-based reduction into [1,1]
layerNorm yes yes 2D [R,C] over C; also nn.LayerNorm(dim)
softmax yes yes Row-wise on 2D [R,C], numerically stable
crossEntropy(targets) yes yes Fused softmax + NLL; returns [R,1] per-sample
embedding(indices) yes yes [V,D] table gathered by [N]; also nn.Embedding
Autograd graph yes yes Dart-side tape; relu/abs backward CPU-only
SGD / Adam optimizers yes yes State (velocity, m/v) lives on parameter's device; Tensor.assign swaps updates in-place
scaledDotProductAttention yes yes 2D single-head SDPA; composed from matmul/transpose/softmax/matmul with optional additive mask
nn.Linear(in, out) yes yes y = x @ W.T + b, Kaiming-uniform init; bias: false supported
dropout(p) / nn.Dropout yes yes Inverted dropout via mask multiply; train()/eval() toggles it
TensorConcat.concat(list, axis=1) yes yes Last-axis 2D concat; GPU round-trips through host
nn.MultiHeadAttention(D, H) yes yes Per-head Linear + SDPA + concat + out proj; optional attn Dropout
nn.TransformerBlock(D, H, {ffnDim}) yes yes Pre-LN encoder block: MHA + residual + MLP + residual, all submodules toggled by train()/eval()
nn.SinusoidalPositionalEncoding(D) yes yes Fixed sin/cos PE, no params, recomputed per forward for the exact seqLen
nn.LearnedPositionalEmbedding(maxLen, D) yes yes Trainable position table gathered via Embedding; scatter-add backward comes free
clipGradNorm(params, maxNorm) yes yes Global L2 grad clip, in-place via Tensor.assign

Placement rule: ops respect the input tensor's device. Mixed-device inputs to a binary op raise ArgumentError — call .to(...) yourself so the copy cost stays visible.

FFI surface (C entry points) #

Defined in lib/native/src/engine.cu (30 symbols):

Category Symbols
Lifecycle create_tensor, destroy_tensor, get_tensor_data
Matmul matmul_tensors
Elementwise add_tensors, sub_tensors, mul_tensors, div_tensors
Scalar bcast add_tensor_scalar, sub_tensor_scalar, mul_tensor_scalar, div_tensor_scalar
Row bcast add_tensor_row_broadcast
Unary math abs_tensor, log_tensor, pow_tensor (float exp)
Activations relu_tensor, sigmoid_tensor, tanh_tensor
Rearrangement transpose_tensor
Reductions sum_tensor, mean_tensor (both return a [1,1] handle)
LayerNorm layernorm_forward, layernorm_backward
Softmax / CE softmax_forward, softmax_backward, cross_entropy_forward, cross_entropy_backward
Embedding embedding_forward, embedding_backward (scatter-add into gTable)

All wrappers return void* (Tensor handle) except lifecycle helpers.

Provenance #

The CUDA kernels and FFI patterns were lifted from ../dart_cuda, keeping only forward-mode wrappers: kernels/common.cuh, kernels/matmul.cuh, kernels/elementwise.cuh, kernels/transpose.cuh, and the forward-only slice of engine.cu.

0
likes
130
points
149
downloads

Documentation

API reference

Publisher

unverified uploader

Weekly Downloads

A minimal PyTorch-style tensor library for Dart with reverse-mode autograd, hand-written CUDA kernels via dart:ffi, and an nn.Module scaffolding for Transformers, GPT, MoE, ViT, and LC0 chess-network inference.

Repository (GitHub)
View/report issues

Topics

#machine-learning #deep-learning #tensor #cuda #autograd

License

MIT (license)

Dependencies

ffi, image, path

More

Packages that depend on dart_pytorch