TensorPlay

Latest development documentation · Updated 2026-09-08. A documentation snapshot for package 1.0.0.dev20260909 is not available.

On this page

tensorplay.library

tensorplay.library is a collection of APIs for extending TensorPlay’s core library of operators. It contains utilities for testing custom operators, creating new custom operators, and extending operators defined with TensorPlay’s C++ operator registration APIs (e.g. built-in operators). For a detailed guide on effectively using these APIs, please see TensorPlay Custom Operators Landing Page for more details on how to effectively use these APIs.

Testing custom ops

Use tensorplay.library.opcheck() to test custom ops for incorrect usage of the Python tensorplay.library and/or C++ TORCH_LIBRARY APIs. Also, if your operator supports training, use tensorplay.autograd.gradcheck() to test that the gradients are mathematically correct.

tensorplay.library.opcheck

Runs each selected check and reports failures keyed by test name:

Creating new custom ops in Python

Use tensorplay.library.custom_op() to create new custom ops.

Choosing the kind of custom op

When defining a custom op, first decide what aliasing and mutation behavior the operator has. This choice determines the mutates_args, tags, return schema, and fake-kernel behavior.

Does the operator mutate any Tensor input?
  |
  +-- no --> Functional operator
  |         Use mutates_args=().
  |         Return new Tensor objects that do not alias inputs or each other.
  |
  +-- yes --> Does it mutate the first positional Tensor argument and return it?
        |
        +-- yes --> In-place operator
        |          Use tags=tensorplay.Tag.inplace.
        |          Use mutates_args with exactly the first argument name.
        |          Return that same first argument.
        |
        +-- no --> Does it mutate keyword-only Tensor out= arguments and return them?
              |
              +-- yes --> out= operator
              |          Use tags=tensorplay.Tag.out.
              |          Do not read from the out= tensors.
              |          Put mutable output tensors after * as keyword-only args.
              |          Return all out= tensors in declaration order.
              |
              +-- no --> Mutable operator
                         Use mutates_args for the mutated arguments.
                         Do not return mutated inputs or aliases of inputs.

Functional operators are the simplest and should be preferred when possible. They should not mutate inputs, and their outputs should be fresh values that do not alias any input or other output. Use tags=tensorplay.Tag.inplace only for the conventional in-place shape: the first positional argument is a Tensor, it is the only mutated argument, and the operator returns that same Tensor. For example, an inferred in-place custom op has a schema shaped like:

(Tensor(a!) x, ...) -> Tensor(a!)

Use tags=tensorplay.Tag.out only for conventional out= variants: all mutable output tensors are keyword-only arguments, and the operator returns those outputs in declaration order. The implementation must write to out= tensors, but must not read from them. For example:

(Tensor x, *, Tensor(a!) out) -> Tensor(a!)
(Tensor x, *, Tensor(a!) out0, Tensor(b!) out1) -> (Tensor(a!), Tensor(b!))

In-place and out= custom ops get an autogenerated fake kernel from their tag and schema. Registering a fake kernel for these ops is usually unnecessary, though it is still allowed if you need to override the autogenerated behavior. out= custom ops follow the same autograd rule as built-in out= operators: they do not support automatic differentiation when any argument requires grad. Arbitrary aliasing, such as returning an alias of an input that is not one of the in-place or out= patterns above, is not supported by custom_op. TensorPlay compiler transforms such as functionalization need to reason precisely about mutations and aliases, so custom op aliasing is intentionally limited to the conventional forms described here. If your operator mutates inputs but is not an in-place or out= operator, model it as a mutable operator and return no aliases of inputs. The same operation can have different contracts depending on how it handles its outputs:

from tensorplay import Tensor


@tensorplay.library.custom_op(
    "mylib::add_inplace",
    mutates_args={"x"},
    tags=tensorplay.Tag.inplace,
)
def add_inplace(x: Tensor, y: Tensor) -> Tensor:
    x.add_(y)
    return x


@tensorplay.library.custom_op(
    "mylib::add_out",
    mutates_args={"out"},
    tags=tensorplay.Tag.out,
)
def add_out(x: Tensor, y: Tensor, *, out: Tensor) -> Tensor:
    out.copy_(x + y)
    return out


@tensorplay.library.custom_op("mylib::add_mutate", mutates_args={"x"})
def add_mutate(x: Tensor, y: Tensor) -> None:
    x.add_(y)

Note

More details on mutation, aliasing, and transforms custom_op asks for a precise mutation and aliasing contract because TensorPlay uses that contract in FakeTensor, autograd, functionalization, and tensorplay.compile.

For a functional custom op, TensorPlay assumes the operator does not mutate any input and that returned tensors are fresh values. This is the easiest kind of op for TensorPlay transforms to reason about.

For an in-place custom op, tensorplay.Tag.inplace gives TensorPlay a stronger and more specific contract: the first Tensor argument is mutated and the returned Tensor is the same object. This lets TensorPlay derive the fake behavior from the schema instead of requiring a separate fake kernel.

For an out= custom op, tensorplay.Tag.out gives TensorPlay the corresponding out=-variant contract: keyword-only output tensors are mutated and returned in schema order. The out= tensors are output buffers only: the implementation must not use their current values as inputs. Like built-in out= operators, these custom ops do not support automatic differentiation when any argument requires grad.

For other mutable custom ops, use mutates_args to name the mutated arguments, but do not return mutated inputs or aliases of inputs. Arbitrary aliasing is hard for transforms because functionalization rewrites mutating programs into functional programs and must know exactly which returned tensors share storage with which inputs. custom_op therefore supports the conventional in-place and out= aliasing patterns directly, but does not model arbitrary view or alias relationships.

tensorplay.library.custom_op

Example.

tensorplay.library.triton_op

The registered kernel(s) must launch their Triton kernels through wrap_triton() and only mutate arguments listed in mutates_args.

tensorplay.library.wrap_triton

Mark a Triton kernel as launchable from within a triton_op.

Extending custom ops (created from Python or C++)

Use the register.* methods, such as tensorplay.library.register_kernel() and tensorplay.library.register_fake(), to add implementations for any operators (they may have been created using tensorplay.library.custom_op() or via TensorPlay’s C++ operator registration APIs).

tensorplay.library.register_kernel

Accepts a CustomOpDef or a qualified operator name.

tensorplay.library.register_autocast

tensorplay.library.register_autograd

tensorplay.library.register_fake

tensorplay.library.register_vmap

tensorplay.library.impl_abstract

tensorplay.library.infer_schema

Produces "ns::op(Tensor self, SymInt n, Tensor(a!) out) -> Tensor" alias-annotation (<type>(<letter>!)) marker.

tensorplay.library.get_kernel

dispatch_key accepts "cpu"/"cuda"/"default" and the composite spellings.

Low-level APIs

The following APIs are direct bindings to TensorPlay’s C++ low-level operator registration APIs.

Warning

The low-level operator registration APIs and the TensorPlay Dispatcher are a complicated TensorPlay concept. We recommend you use the higher level APIs above (that do not require a tensorplay.library.Library object) when possible. This blog post is a good starting point to learn about the TensorPlay Dispatcher.

A tutorial that walks you through some examples on how to use this API is available on Google Colab.

tensorplay.library.Library

one DEF library per process/namespace), "IMPL" adds kernels, and "FRAGMENT" extends an existing namespace from multiple locations.

tensorplay.library.define

Creates the CustomOpDef if absent (kernels are then attached with impl() or Library("ns", "IMPL").impl).

tensorplay.library.impl

types accepts concrete devices ("CPU"/"CUDA") or composite spellings (CompositeExplicitAutograd → the device-agnostic slot).

Search documentation

Search all 1,743 documentation pages.

Keyboard shortcuts

Global

  • /Focus search
  • ?This dialog
  • ,Open settings
  • jAI assistant

Search

  • Navigate results
  • Open result
  • escClose

Package

  • mMain information
  • dDocs
  • .Code
  • -Changelog
  • tTimeline
  • sStats
  • vVersions