Skip to main content

Polygrad Python

The Python API for Polygrad, a tensor library and JIT compiler built around a C11 port of tinygrad. It provides automatic differentiation, neural-network layers, optimizers and NumPy data exchange. Models saved in Python can load in JavaScript without their original Python classes.

Project overview and shared C/runtime reference | JavaScript guide

Contents

Install

pip install polygrad

Requirements:

  • Linux
  • Python 3.9 or newer (installed wheels tested on CPython 3.9-3.13)
  • NumPy
  • A C compiler on PATH for CPU execution: clang recommended, GCC fallback; generated float16 kernels require clang's __fp16 support

CPython 3.9-3.13 on x86_64 Linux with glibc 2.27+ can install a prebuilt wheel. Other Linux configurations build from source and require a C compiler and Python development headers. Wheels do not remove the CPU backend's runtime compiler requirement; use DEV=X86 (x86_64) or DEV=INTERP to run without one.

Optional dependency for downloading Hugging Face checkpoints (loading local config and weight files does not need it):

pip install huggingface_hub

For a source checkout, see building from source.

Quickstart: Tensors

from polygrad import Tensor

a = Tensor.rand(3, 4)
b = Tensor.rand(4, 5)
c = (a @ b).softmax(-1)

print(c.numpy())

Autograd:

from polygrad import Tensor

x = Tensor([1.0, 2.0, 3.0])

loss = (x * x).sum()
loss.backward()

print(x.grad.numpy())  # [2. 4. 6.]

Quickstart: Models

Fit y = 3x + 2 in Python, save its graph and weights, then load it in JavaScript without redefining the model.

from polygrad import Model, Tensor

class Linear:
    def __init__(self):
        self.a = Tensor([0.0])
        self.b = Tensor([0.0])
    def __call__(self, x):
        return {"prediction": self.a * x + self.b}

model = Model(
    Linear(), inputs={"x": Tensor.empty(5)}, targets={"y": Tensor.empty(5)},
    loss=lambda outputs, y: (outputs["prediction"] - y).square().mean(),
)
try:
    model.fit({"x": [-2, -1, 0, 1, 2], "y": [-4, -1, 2, 5, 8]},
              epochs=100, optimizer="sgd", lr=0.1)
    model.save("linear.pgb", include_optimizer=False)
finally:
    model.dispose()

In Node, using a matching Polygrad package:

const { Model } = require('polygrad')
const model = Model.load('linear.pgb')
try {
  const { prediction } = model.forward({x: new Float32Array([3, 4, 5, 6, 7])})
  console.log(Array.from(prediction)) // approximately [11, 14, 17, 20, 23]
} finally {
  model.dispose()
}

See Models for capture, input shapes, minibatches and export options.

Working With Tensors

Creation

from polygrad import Tensor

x = Tensor([1, 2, 3])
a = Tensor.zeros(2, 3)
b = Tensor.ones(2, 3)
c = Tensor.randn(2, 3)
d = Tensor.arange(0, 6).reshape(2, 3)

Math And Indexing

from polygrad import Tensor

x = Tensor.arange(0, 12).reshape(3, 4)
y = x.permute(1, 0).reshape(2, 6)
z = y.relu().sum(axis=1)
picked = x.gather(1, Tensor([[0, 2], [1, 3], [0, 1]], dtype="int32"))

NumPy And Data Updates

import numpy as np
from polygrad import Tensor

arr = np.array([1, 2, 3, 4], dtype=np.float32)
x = Tensor(arr).reshape(2, 2)
print((x * 2 + 1).numpy())

Polygrad tensors are lazy. Use realize() to execute and numpy() when host readback is needed.

import numpy as np
from polygrad import Tensor

x = Tensor.empty((4,), dtype="float32")
x.copy_from(np.array([1, 2, 3, 4], dtype=np.float32))

y = (x * 3 - 1).realize()
print(y.numpy())

x.update_from(np.array([5, 6, 7, 8], dtype=np.float32))
print((x + 1).realize().numpy())

Use copy_from or update_from for repeated loops that should preserve input buffer identity for compiled replay.

Linear Algebra

from polygrad import Tensor

A = Tensor([[4.0, 2.0], [2.0, 5.0]])
b = Tensor([1.0, 3.0])
x = A.solve(b)

print(x.numpy())

Structured linalg methods are portable tensor-composed fallbacks tested against NumPy and Torch. They do not add LAPACK or runtime library dependencies. Current lstsq is solution-only for full-rank tall or square systems.

Training

Use Tensor autograd when you want to control the training loop:

from polygrad import Context, Tensor
from polygrad.nn import Linear, get_parameters
from polygrad.nn.optim import SGD

Tensor.manual_seed(42)
model = Linear(2, 1)
opt = SGD(get_parameters(model), lr=0.01)

with Context(TRAINING=1):
    for _ in range(100):
        opt.zero_grad()
        x = Tensor([[1.0, 2.0], [3.0, 4.0]])
        y = Tensor([[5.0], [11.0]])
        loss = (model(x) - y).square().mean()
        loss.backward()
        opt.step()

print(loss.item())

Layers And Optimizers

from polygrad.nn import Linear, LayerNorm, RMSNorm, Embedding
from polygrad.nn import get_parameters
from polygrad.nn.optim import SGD, Adam, AdamW

Layers include Linear, LayerNorm, LayerNorm2d, RMSNorm, Embedding, Dropout, GroupNorm, Conv1d, Conv2d, ConvTranspose1d, ConvTranspose2d, InstanceNorm, LSTMCell, and BatchNorm. Optimizers include SGD, Adam, and AdamW; each provides step() and zero_grad().

Models

Start with Quickstart: Models for capture, fitting and export. More runnable scripts are in Python examples.

For stateful loops, model.call('step', {}, controls={'iteration': i}, readback=False) executes without collecting outputs and returns {}. Read a named state/output with model.read_buffer(name) when needed. The shared models.Graph description supports fixed-shape state and explicit entrypoint writes; see the Graph schema.

Capture and input rules

  • controls declares named integer Variables. Pass values through model.call(..., controls={...}). An entrypoint's controls mapping overrides shared declarations; {} declares none. Controls must occur in that entrypoint's graph. They are currently inference-only; combining them with a loss is rejected during construction. Pass training data through Tensor inputs instead.
  • params defaults to named Tensor attributes of the supplied object; functions require explicit closure state. model.summary() inspects metadata without executing or reading weights.
  • With loss, construction captures evaluation and training forwards against the same state. The callable runs twice during construction, never during execution. Without a loss, capture uses the current TRAINING value; changing it later does not recapture the graph.
  • Set the seed before construction. BatchNorm/RNG updates affect Model-owned state. Authoring Tensor roots and training mode are restored even on failure; arbitrary Python side effects are not. Capture rejects parameter/input assignments and effectful reads.
  • Variable-size calls support bounded dimensions, including [N, N] and independent [N, M] axes. State shapes remain fixed. Save/load preserves the signature; storage currently reserves maximum capacity. Tensor results retain their invocation's values and shape across later calls and Model disposal, but require a live runtime.
  • Flat arrays can infer one variable axis; multiple variable axes require a shaped array. Multidimensional NumPy arrays must match the declared shape, not merely its element count. The equivalent JS binding is {data: typedArray, shape: [rows, columns]}.

model.place('CPU:1') and set_device_map(...) accept the same exact native CPU identities. Unsupported accelerator ordinals reject without changing the Model.

Minibatches

  • Use model.fit(data, epochs=2, batch_size=32) when every input/target's leading-axis bounds admit 32. Epochs visit samples in input order and return one loss per step. Omit batch_size to repeat one full batch.
  • An incomplete final batch rejects before training unless remainder='drop' discards it or remainder='keep' processes the smaller extent permitted by every input's bounds. No padding or shuffling is implicit.
  • Tensor datasets are sliced on-device without frontend host readback and may mix with host inputs.

Saving And Loading

model.save() returns bundle bytes; model.save(path) also writes a file. Model.load(bytes_or_path) uses the default runtime, or pass runtime=rt. Each load owns independent state, while tied weights within a Model stay tied. Disposing a Model does not dispose its runtime. Newer releases load older portable models; files saved by a newer release may require that release or later. Check the changelog when exchanging models.

Bundles preserve auxiliary/RNG and optional optimizer state. include_optimizer=False omits optimizer state, not training entrypoints. To resume training, reapply the optimizer configuration after loading. See export products for graph, program and weight exports and version compatibility.

ONNX Import

Model.from_onnx(path_or_bytes, dimensions={'batch': 2}) imports a supported ONNX graph as an ordinary inference Model. Omit dimensions for fixed shapes. Use model.call('forward', inputs) with the graph's input names; outputs retain their ONNX names. The imported Model supports placement and bundle save/load.

For external weights, pass external_data={'weights.bin': weight_bytes}; locations are exact keys, not files fetched by the loader. Initializers are copied into frozen state; this import does not create a training objective or Transformer generation methods. Unsupported operators and shapes raise an import error; see ONNX import.

Pretrained models

from polygrad.hf import download_hf, load_hf, generate
import numpy as np

model_path = download_hf("hf-internal-testing/tiny-random-gpt2")
model = load_hf(model_path, max_batch=1, max_seq_len=16)
try:
    tokens = np.array([[1, 2, 3, 4]], dtype=np.int32)
    result = generate(model, tokens, max_new_tokens=2, temperature=1.0, top_k=10)
    print(result)
finally:
    model.dispose()

load_hf uses the same checkpoint importer as Model.from_hf, including the vision and embedding models below, with F32/F16/BF16 safetensors. The generate helper above expects GPT-2 input/output names; it is not a Llama generation API. Qwen loading uses the shared C/GGUF path.

models.GPT2(config) and models.Llama(config) build topology without pretrained weights. They reject execution and saving until every required parameter has been written; use a checkpoint loader for a ready-to-run model. Explicit zero weights are valid. Wrong input dtypes are rejected, not silently narrowed.

models.list() (also rt.models.list()) reports construction and checkpoint capabilities; see supported models. Calling models.Qwen3(...) reports that it is import-only and points to Model.from_gguf(...); it does not construct an uninitialized model.

For cached Qwen3 generation, use models.Transformer.from_gguf(data, cache_capacity=4096, prefill_chunk_size=64), or the runtime-bound rt.models.Transformer.from_gguf(...). The loader validates the generation contract; Model.from_gguf accepts the same cache options but stays generic.

Qwen3 GGUF imports accept only int32 token input x and return output: model.forward(x=token_ids)['output']. Rotary tables are Model-owned state, included in saved bundles. Older bundles retain their original signatures; use model.entrypoints() to inspect them.

Llama supports dense Llama 2/base 3 and text-only 3.x llama3 RoPE scaling. Set cache_capacity and prefill_chunk_size in its configuration to enable batch-one FP32 cached decoding and return a models.Transformer subclass. After loading weights, model.append_tokens(ids) accepts int32 [N] or [1,N] tokens and returns last-token logits [1,vocab]. C handles variable-width chunks up to prefill_chunk_size and checks capacity before writing the cache. model.decode_position reports the committed count. reset() starts a new conversation without changing weights or rewinding the sampling RNG. Saved bundles preserve RNG state but load with empty KV caches. Use models.Transformer.load(bundle) to restore generation methods; Model.load(bundle) stays generic. model.generate(ids, temperature=0, max_tokens=32) yields token IDs sampled in C. prefill_tokens(ids) reuses a matching prompt prefix; rewind(position) discards a suffix without clearing cache storage. Load or adopt only trusted Transformer bundles: bounds checks do not verify the causal, append-only cache semantics required by prefix reuse and rewind. polygrad.llm.model.Transformer aliases models.Transformer; it does not provide Tinygrad constructor or method compatibility.

After a failed append, cache-writing direct call, weight write or placement during a conversation, reset before appending again. Read-only calls and rejected inputs preserve the conversation. Borrowed C storage pointers must not mutate an active decoder. Uncached forward(tokens=...) remains available. MoE, arbitrary RoPE schemes, tokenizers and chat templates are not supplied by this loader.

The C Model GGUF loader converts F32/F16/BF16, I8/I16/I32 and complete Q4_0/Q4_1/Q8_0/Q6_K blocks. Q4_K/Q5_K metadata is readable but weight conversion is unsupported. This is narrower than Python's Tensor-level GGUF decoder; decoding a file does not imply support for its model architecture.

Vision models

models.CLIP, models.ViT, models.DINOv2 and models.DINOv3 use shared C components. Construct from a configuration, write all required weights, or load a Hugging Face directory with Model.from_hf(path). Unloaded models reject execution and saving. Their bundles load in JavaScript with pg.Model.load(bytes).

Model Inputs Forward outputs
CLIP pixel_values, input_ids image_embeds, text_embeds, logits_per_image, logits_per_text
ViT pixel_values last_hidden_state, pooler_output (tanh pooler)
DINOv2 / DINOv3 pixel_values last_hidden_state, pooler_output (CLS token)

Inputs are already normalized float32 images in [batch, channels, height, width] layout. Use the checkpoint's image processor; the Model does not decode, resize or normalize images. CLIP additionally takes int32, right-padded token IDs with an EOS token. Its encode_image and encode_text entrypoints accept one modality and return normalized embeddings. Both modalities use the configured batch size. Normalization clamps the L2 norm to at least 1e-12; zero projections return zero embeddings rather than NaNs.

This implementation is fixed-square-resolution, unmasked inference. It supports HF CLIPModel, ViTModel, Dinov2Model and DINOv3ViTModel weights, not classification heads, DINOv2-with-registers, DINOv3 ConvNeXt, training augmentations or dynamic input resolutions. DINOv2's optional input_image_size config selects a fixed input resolution and bicubically interpolates the original checkpoint's positions; image_size must retain the checkpoint resolution. DINOv3 includes register tokens and patch-only 2D RoPE; last_hidden_state retains those prefix tokens. DINOv2 SwiGLU and DINOv3 gated MLP configurations are supported. JSON type tags are clip, vit, dinov2 and dinov3_vit.

For C-built model types and JSON-based models.Sequential / models.Graph, see shared JSON reference. These return the same Model type and use the same training and export APIs. Sequential/Graph configurations support typed inputs, one bounded leading batch dimension, and shared embedding, normalization, RoPE and attention components. For example, {"dtype":"int32","shape":[{"name":"batch","min":1,"max":32},16]} declares token batches of 1 to 32 rows without rebuilding the model.

EmbeddingGemma 2

models.EmbeddingGemma2Text constructs the text backbone from a resolved HF text config. For a full embedding_gemma2 checkpoint, set "modalities": ["text"] in its parsed configuration for text-only inference; there is no need to remove the image/audio configuration. Pass the serialized config and a list of safetensors file contents together as Model.from_hf(config_json=config_text, weight_bytes_list=weight_files). These are bytes/text, not filenames; use Model.from_hf(directory) when the checkpoint config needs no changes. Omitting modalities includes every configured tower. Computation and imported parameters use float32.

Pass fixed-shape int32 input_ids and int32 attention_mask (1 for tokens, 0 for padding) to forward. Outputs are projected last_hidden_state and normalized sentence_embedding. Both left and right padding are supported; masked tokens are excluded from pooling. Tokenization and task prompts use the official HF tokenizer outside Polygrad. Shortening an embedding requires L2 normalization after slicing.

For image inference, select "modalities": ["text", "image"]. Set image_num_patches to the HF processor's patch capacity, then pass its float32 pixel_values [batch, patches, 3*patch_size*patch_size] and int32 image_position_ids [batch, patches, 2] alongside tokens and mask. Use one nonempty image per batch item and processor-generated matching image token slots; mismatches are rejected before inference, including after Model save/load. Token IDs and patch positions must be host arrays, not Tensors. These are flattened, unnormalized patches with (x,y) positions, not the normalized NCHW images used by the vision models above. Padding positions are (-1,-1). Outputs also include padded image_hidden_states and their boolean image_attention_mask.

For audio, select "modalities": ["text", "audio"], set audio_seq_len to the processor's feature frame count, and pass float32 input_features [batch, frames, features] plus an int32 0/1 input_features_mask [batch, frames]. Supply matching audio-token slots in input_ids; mismatches are rejected before inference. Token IDs and feature masks must be host arrays, not Tensors. Outputs include padded audio_hidden_states and audio_attention_mask. Video and clipped vision projections are not implemented. Tokenization and preprocessing remain external; no Hugging Face packages are required by Polygrad itself. This is an embedding model, not a text generator. Set output_hidden_states to true in the config to expose per-layer text/image/audio hidden states.

Devices And Runtimes

Choose a device explicitly or through the environment:

from polygrad import Device, Tensor

device = "cuda" if Device.cuda_available() else "cpu"
x = Tensor.rand(4, device=device)
y = x * 2

print(y.numpy())

Environment variables:

DEV=CPU python app.py
POLY_DUMP_KERNELS=1 python app.py
BEAM=4 python app.py

Device selection uses an explicit device=, then POLY_DEV, then DEV. Names are case-insensitive; available native backends include CPU, CUDA, X86 and INTERP. Unsupported device ordinals and multi-device targets are rejected.

Explicit runtimes are optional. Tinygrad-style programs use from polygrad import Tensor, nn and from polygrad.nn.optim import Adam without create() or a Model wrapper. The Python package uses a module-level default C context. Caller-created tensors share that context, so package functions should accept and return Tensor objects rather than copying through NumPy unless readback is required.

For explicit context/device ownership, create a runtime:

import polygrad

rt = polygrad.create(device="cpu")
try:
    layer = rt.nn.Linear(2, 1)
    x = rt.Tensor([[1.0, 2.0]])
    print(layer(x).numpy())
finally:
    rt.dispose()

Use explicit runtimes for isolation, device-specific package wiring, or tests that need independent compiler caches.

Use rt.nn for layers, optimizers and state loaders, rt.models for C-backed model types, and rt.Model for capture/import on that runtime. For example, rt.Model.load("model.pgb") is equivalent to polygrad.Model.load("model.pgb", runtime=rt). Create tensors and layers on the same runtime: mixing owners is rejected even when their devices match; package-level constructors use the default runtime.

Threads

Never use one runtime concurrently from multiple Python threads: native calls release the GIL, and overlapping context mutations can crash the process. The default runtime is process-global. For parallel work, create one runtime per thread, construct through rt.Tensor and rt.Model, and keep its objects in that thread, including cleanup. Separate-runtime CPU, INTERP and X86 execution is tested; concurrent GPU initialization is not validated. Alternatively, serialize all use and cleanup of a shared runtime yourself. Global configuration changes still need coordination. Call collect() and dispose() only when no other thread is using the runtime.

Runtime Inspection

import polygrad

print(polygrad.stats())
print(polygrad.can_run("add", shape=[1024]))

can_run(...) is conservative. For some compound op/shape queries it raises when support cannot be proven statically.

JIT And Compile

@jit follows tinygrad's raw Tensor JIT behavior. The first call runs normally, the second call captures realized schedules, and later calls replay those schedules with current input buffers.

from polygrad import Tensor, jit

@jit
def step(x):
    return (x + 1).realize()

print(step(Tensor([1, 2, 3])).numpy())  # normal run
print(step(Tensor([4, 5, 6])).numpy())  # capture
print(step(Tensor([7, 8, 9])).numpy())  # replay

For embedding loops, compile(...) performs the same warmup and capture up front and exposes an explicit callable:

from polygrad import Tensor, compile

def step(x):
    return (x + 1).realize()

compiled = compile(step, [Tensor([1, 2, 3]).realize()])
out = compiled.run([Tensor([7, 8, 9]).realize()])

print(out.numpy())
print(compiled.stats())
compiled.dispose()

polygrad.stats() exposes shared C runtime counters. The tinygrad-compatible top-level GlobalCounters provides global_ops, global_mem, time_sum_s, kernel_count, mem_used, mem_used_per_device, and reset(); reset keeps live allocation bytes. Jit.stats() and CompiledCallable.stats() expose wrapper-level capture and replay counters.

polygrad.can_run(op, dtype="float32", shape=..., shapes=..., device="auto") is an advisory backend capability probe.

Capture requires at least one Tensor argument. Host reads must stay outside the captured function; otherwise their values would be fixed during capture. Compiler settings such as BEAM and NOOPT are documented in the shared runtime reference.

Reusing Input Buffers

import numpy as np
from polygrad import Tensor, compile

x = Tensor(np.array([1, 2, 3], dtype=np.float32)).realize()
f = compile(lambda x: x.square().sum().realize(), [x])

print(f.run([x]).item())
x.copy_from(np.array([4, 5, 6], dtype=np.float32))
print(f.run([x]).item())
f.dispose()

Custom Kernels

Tensor.custom_kernel(...) mirrors tinygrad's alpha custom-kernel shape. The kernel function receives placeholder UOps and returns a SINK body. Polygrad wraps the body in CALL, returns AFTER(...) tensors, and keeps execution in the normal schedule and runtime caches.

from polygrad import Tensor
from polygrad.uop.ops import KernelInfo, UOp

def add_kernel(out, a, b):
    out, a, b = out.flatten(), a.flatten(), b.flatten()
    i = UOp.range(out.ctx, out.numel(), 0)
    return out[i].store(a[i] + b[i]).end(i).sink(
        arg=KernelInfo(name="custom_add_4")
    )

out = Tensor.empty((4,), dtype="float32")
y = out.custom_kernel(
    Tensor([1.0, 2.0, 3.0, 4.0]),
    Tensor([10.0, 20.0, 30.0, 40.0]),
    fxn=add_kernel,
)[0]
print(y.numpy())  # [11. 22. 33. 44.]

KernelInfo is required to mark the executable kernel boundary. Without it, the body can leave the output unchanged, as in pinned tinygrad. Match each stored value's dtype to its destination, using an explicit UOp cast when needed. Current C and Wasm renderers reject mismatched vector stores with vector STORE dtype mismatch; cast the value to the destination dtype. Scalar C stores can convert numerically, but that is not a portable kernel contract. INTERP follows Tinygrad's Python memoryview conversion rules. Cast explicitly on every backend.

Package Integration

Python packages should accept caller-created Polygrad tensors and return Polygrad tensors:

from polygrad import Tensor

def normalize(x: Tensor) -> Tensor:
    mean = x.mean(axis=-1, keepdim=True)
    scale = (x - mean).square().mean(axis=-1, keepdim=True).sqrt()
    return (x - mean) / scale.maximum(1e-6)

This keeps execution in the caller's Polygrad context and avoids unnecessary NumPy readback. The denominator guard returns zeros for constant inputs.

C-authored graphs

rt.load_extension(path) attaches a separately built C author to this runtime's existing core. The author calls existing poly_tensor_* functions; it does not link another Polygrad implementation. Build its adapter with scripts/extension_bindings.py --source author.c --entry build_graph --inputs 1 --outputs 1 --output build/author from a matching Polygrad checkout. Clang reads the public declarations; unknown pointer signatures reject rather than being forwarded incorrectly.

For a runnable example from the checkout root, first run make build/extension/author.so. The supplied test/extension_fixture.c constructs a Gaussian log density and its gradient (mode 0):

import polygrad

with polygrad.create(device='CPU', logical='always') as rt:
    x = rt.Tensor([1., 2., 3.])
    author = rt.load_extension('./build/extension/author.so')
    try:
        logp, gradient = author.build([x, x, x], [0])
        author.dispose()  # Returned Tensors remain valid.
        try:
            assert logp.item() == -7.0
            assert gradient.numpy().tolist() == [-1., -2., -3.]
        finally:
            logp.dispose()
            gradient.dispose()
    finally:
        author.dispose()
        x.dispose()

The C entry returns int and takes PolyCtx*, a borrowed PolyTensor** input array, optional int/double values, and an owned PolyTensor** output array. It builds graphs only: no execution, retained host callbacks or private struct access. It must release intermediate references and unwind captures on failure. Seal results with rt.Model.from_tensors when persistence is needed. ABI mismatches and inputs from another context reject. This loads trusted native code, not sandboxed plugins. Linux is tested; other native platforms are untested.

API Overview

Tokenizer.from_gguf(bytes) and Tokenizer.from_json(bytes_or_text) use the shared C tokenizer. Instances expose encode(text), decode(ids), vocab_size, bos_id, eos_id, and free(), and support with for cleanup. They own their vocabulary independently of Tensor runtimes; runtime.Tokenizer is the same class. JSON accepts the supported byte-level BPE pipeline. Unsupported pipelines raise ValueError; strict=False permits skipping NFC only, with UserWarning. Use Hugging Face tokenizers for other pipelines. No Unicode dependency is added.

create(device='cpu', kernels=True) accepts the same kernel option as Runtime.

Area Main APIs
Runtime polygrad.create, polygrad.stats, polygrad.can_run, Device
Models Model, from_callable, from_tensors, fit, forward, save, load, summary, dispose; polygrad.models factories
Tensor creation Tensor(data), zeros, ones, full, rand, randn, randint, arange, linspace, eye, empty
Tensor math +, -, *, /, **, exp, log, sqrt, abs, sin, cos, tanh, sigmoid, relu, gelu, silu, softmax
Reductions sum, mean, max, min, argmax, sort, argsort, topk, var, std
Movement/indexing reshape, view, permute, transpose, expand, squeeze, unsqueeze, flatten, shrink, pad, flip, repeat, gather, take_along_axis, cat, stack, split, chunk
Linalg matmul, dot, linear, qr, triangular_solve, solve_triangular, cholesky, cholesky_solve, solve, lstsq
Data/readback realize, numpy, item, tolist, copy_from, update_from, to, cpu, cuda, detach, clone
Compilation function, jit, compile, Tensor.custom_kernel
Tokenization Tokenizer.from_json, Tokenizer.from_gguf, encode, decode
Neural nets polygrad.nn layers, SGD, Adam, AdamW, get_parameters, get_state_dict

Troubleshooting

  • unknown type name '__fp16': float16 CPU kernels require Clang. Install it and select CC=clang; check that CC is not forcing GCC.
  • args mismatch in jit: the call must match the traced input shapes, dtypes and devices. An int32 input cannot replace a float32 sample.
  • Model format mismatch: upgrade the reader to the version that saved the model or a newer release. See bundle compatibility; do not edit artifact version fields to bypass validation.
  • CPU compilation cannot find a compiler: install clang (recommended) or GCC, or try DEV=X86 on a supported x86 machine or DEV=INTERP for interpreted execution.
  • "TRAINING must be enabled": wrap optimizer steps in with Context(TRAINING=1):, as in Training.
  • Operands belong to different runtimes: create layers and Tensors through the same runtime (rt.nn, rt.Tensor), or use the default API consistently.
  • Memory grows across many different graphs: at an idle boundary, use rt.clear_schedule_cache() and rt.collect(). Live owners still retain their resources; later execution rebuilds cleared schedules. This is a memory-pressure tool, not a per-step requirement.

For contributor checks, see tests.

License

MIT

Metadata

Release files for polygrad 0.7.1

For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.

Source distribution (sdist)

Source distribution for polygrad 0.7.1
File Size Uploaded Provenance Actions
polygrad-0.7.1.tar.gz 1.2 MB Without provenance Details for polygrad-0.7.1.tar.gz

Built distributions (wheels)

Table of built distributions (wheels) for polygrad 0.7.1
File Actions
polygrad-0.7.1-cp313-cp313-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl CPython 3.13 CPython 3.13 Linux glibc 2.28+ x86-64, Linux glibc 2.27+ x86-64 Details for polygrad-0.7.1-cp313-cp313-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl
polygrad-0.7.1-cp312-cp312-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl CPython 3.12 CPython 3.12 Linux glibc 2.28+ x86-64, Linux glibc 2.27+ x86-64 Details for polygrad-0.7.1-cp312-cp312-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl
polygrad-0.7.1-cp311-cp311-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl CPython 3.11 CPython 3.11 Linux glibc 2.28+ x86-64, Linux glibc 2.27+ x86-64 Details for polygrad-0.7.1-cp311-cp311-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl
polygrad-0.7.1-cp310-cp310-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl CPython 3.10 CPython 3.10 Linux glibc 2.27+ x86-64, Linux glibc 2.28+ x86-64 Details for polygrad-0.7.1-cp310-cp310-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl
polygrad-0.7.1-cp39-cp39-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl CPython 3.9 CPython 3.9 Linux glibc 2.28+ x86-64, Linux glibc 2.27+ x86-64 Details for polygrad-0.7.1-cp39-cp39-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl

Total release size: 21.9 MB

Release files / polygrad-0.7.1.tar.gz

Download URL polygrad-0.7.1.tar.gz
Size 1.2 MB
Tags Source
SHA-256 checksum
How to use checksums
aa67dec9b9faebe7383c9768392319c2c88920083347865b4c1dceb5b6fb63a8
BLAKE2b-256 checksum
How to use checksums
0ff9be991697037e0b8cfa3eaa26563574a4fe3b9651dc97e4c3c88adb86cd6f
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via twine/7.0.0 CPython/3.11.12

Release files / polygrad-0.7.1-cp313-cp313-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl

Download URL polygrad-0.7.1-cp313-cp313-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl
Size 4.1 MB
Tags CPython 3.13 Linux glibc 2.27+ x86-64 Linux glibc 2.28+ x86-64
SHA-256 checksum
How to use checksums
2645d43996db77aa236e07ede8d651eac628ffe0e133c628262200fd265734df
BLAKE2b-256 checksum
How to use checksums
5a097522ead0a3760954fa25c84e554d3da5f039908f1dde00f47f91cf1b558b
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via twine/7.0.0 CPython/3.11.12

Release files / polygrad-0.7.1-cp312-cp312-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl

Download URL polygrad-0.7.1-cp312-cp312-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl
Size 4.1 MB
Tags CPython 3.12 Linux glibc 2.27+ x86-64 Linux glibc 2.28+ x86-64
SHA-256 checksum
How to use checksums
4633f09f05706c5175822142346752bf0bf13c8dc41fb5dc93f6257d47dda94f
BLAKE2b-256 checksum
How to use checksums
c3ad8e37402ff073378bc33ec8ef73d39b18c7fd1d909598d84d4dcfaf9e7e8e
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via twine/7.0.0 CPython/3.11.12

Release files / polygrad-0.7.1-cp311-cp311-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl

Download URL polygrad-0.7.1-cp311-cp311-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl
Size 4.1 MB
Tags CPython 3.11 Linux glibc 2.27+ x86-64 Linux glibc 2.28+ x86-64
SHA-256 checksum
How to use checksums
b85fcf87e8b57bf987d248396e1d0d2821abb5ea324046d7dc1d80399e8dcf79
BLAKE2b-256 checksum
How to use checksums
0c5e5aae1fd2e1c3a51cc38255ed4f7fa894621316bf28402452ea83cc5f6380
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via twine/7.0.0 CPython/3.11.12

Release files / polygrad-0.7.1-cp310-cp310-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl

Download URL polygrad-0.7.1-cp310-cp310-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl
Size 4.1 MB
Tags CPython 3.10 Linux glibc 2.27+ x86-64 Linux glibc 2.28+ x86-64
SHA-256 checksum
How to use checksums
cd48ce49a06a404de87ecc6dab34e02a2305285ad6a2da16191b5d660a7d0dc2
BLAKE2b-256 checksum
How to use checksums
7335885b420b6ed92bdd860eb29dc9b9a4a091d1b9cb237e70ef1db6a63b0014
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via twine/7.0.0 CPython/3.11.12

Release files / polygrad-0.7.1-cp39-cp39-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl

Download URL polygrad-0.7.1-cp39-cp39-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl
Size 4.1 MB
Tags CPython 3.9 Linux glibc 2.27+ x86-64 Linux glibc 2.28+ x86-64
SHA-256 checksum
How to use checksums
d52ffc866c35dfda4f350d40c0c3d3928ba6a12e3a137f32442312ed4ba3f3c0
BLAKE2b-256 checksum
How to use checksums
23cb08292b3844472fd935407bb96c8dd73e373cd550a55381f07d6d1bba1c95
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via twine/7.0.0 CPython/3.11.12

Security for polygrad 0.7.1

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

No provenance found

None of the files in this release were uploaded with provenance metadata.

A note on package security

PyPI is a repository for distributing packages, not a service for auditing them. While third-party security researchers and our staff do their best to detect and remove malicious packages, PyPI cannot guarantee the quality, security or suitability of any given package.

To learn more about protecting yourself from malicious actors, visit our package security documentation.

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page