tripy-new-operation

bởi nvidia

Thêm một operation mới vào nvtripy. Sử dụng khi: triển khai một op mới, thêm một frontend op, tạo một trace op, đăng ký một op trong API. Bao gồm toàn bộ…

npx skills add https://github.com/nvidia/tensorrt-incubator --skill tripy-new-operation

Adding a New Operation to nvtripy

When to Use

  • Adding a new mathematical, tensor, or neural network operation
  • Creating a new frontend function that maps to TensorRT/MLIR ops
  • Extending the op registry with unary, binary, or custom operations

Architecture Overview

Operations in nvtripy follow a Frontend → Trace → MLIR pipeline:

  1. Trace Op (nvtripy/trace/ops/): Defines the computational graph node — rank inference, dtype inference, and MLIR code generation.
  2. Frontend Op (nvtripy/frontend/ops/): The public API function — exports, constraints, docstring, and bridges to the trace op via create_op().
  3. Registration: Both __init__.py files must be updated so the op is discoverable.

Procedure

Step 1: Create the Trace Operation

Create a file in nvtripy/trace/ops/<op_name>.py:

from dataclasses import dataclass

import nvtripy.trace.ops.utils as op_utils
from mlir_tensorrt.compiler.dialects import tensorrt
from nvtripy.trace.ops.base import TraceOp


@dataclass(repr=False)
class MyOp(TraceOp):
    # Add any op-specific parameters as dataclass fields:
    dim: int

    # Choose a rank inference policy:
    infer_rank = op_utils.InferRankPolicies.same_as_input()

    def to_mlir(self, inputs, outputs):
        # Generate MLIR using the tensorrt dialect:
        return [tensorrt.some_op(inputs[0], self.dim)]

Key base class requirements (from TraceOp):

  • infer_rank (required): Set output rank. Use policies from InferRankPolicies:
    • same_as_input(idx=0) — output rank matches input[idx]
    • same_shape_as_input(idx=0) — output has same shape (not just rank)
    • same_as_shape_of_shape_input(idx=0) — rank from a shape tensor
    • max_of_inputs() — rank is max across all inputs
    • Or define a custom function
  • to_mlir(self, inputs, outputs) (required): Return list of MLIR operations
  • infer_dtypes() (optional): Default propagates from inputs[0]. Override for multi-dtype ops.
  • infer_devices() (optional): Default sets all outputs to GPU.
  • get_num_outputs() (optional): Default is 1. Override for multi-output ops.
  • str_skip_fields() (optional): Fields to omit from string representation.

Factory pattern for families of similar ops (see trace/ops/unary.py):

def make_unary_op(name, attr_name):
    @dataclass(repr=False)
    class UnaryOp(TraceOp):
        infer_rank = op_utils.InferRankPolicies.same_as_input()

        def to_mlir(self, inputs, outputs):
            return [tensorrt.unary(inputs[0], tensorrt.UnaryOperationAttr.get(attr_name))]

    UnaryOp.__name__ = name
    return UnaryOp

Exp = make_unary_op("Exp", "kEXP")

Step 2: Create the Frontend Operation

Create a file in nvtripy/frontend/ops/<op_name>.py:

from typing import Optional

from nvtripy import export
from nvtripy.common import datatype as dt
from nvtripy.frontend import wrappers
from nvtripy.frontend.constraints import GetInput, GetReturn, OneOf
from nvtripy.frontend.ops import utils as op_utils
from nvtripy.trace.ops.my_op import MyOp


@export.public_api(document_under="operations/functions")
@wrappers.interface(
    input_requirements=OneOf(GetInput("input").dtype, [dt.float32, dt.float16, dt.bfloat16]),
    output_guarantees=GetReturn(0).dtype == GetInput("input").dtype,
)
def my_op(input: "nvtripy.Tensor", dim: Optional[int] = None) -> "nvtripy.Tensor":
    r"""
    Brief description of what the op does.

    Args:
        input: The input tensor.
        dim: The dimension to operate on.

    Returns:
        A tensor of the same shape as the input.

    .. code-block:: python
        :linenos:

        input = tp.iota([2, 3], dtype=tp.float32)
        output = tp.my_op(input, dim=0)

        assert tp.allclose(output, expected_tensor)
    """
    dim = op_utils.process_dim(dim, input.rank)
    return op_utils.create_op(MyOp, [input], dim=dim)

Key decorator details:

  • @export.public_api(document_under="..."): Registers in public API and docs hierarchy. Common paths:
    • "operations/functions" — general tensor ops
    • "operations/initializers" — tensor creation ops (ones, zeros, full)
    • "operations/modules" — nn module classes
  • @wrappers.interface(...): Defines input constraints and output guarantees (see constraint skill)
  • Bridge to trace via op_utils.create_op(TraceOpClass, [inputs], **kwargs)

Step 3: Register in __init__.py Files

nvtripy/frontend/ops/__init__.py: Add import so auto-discovery finds the module.

nvtripy/trace/ops/__init__.py: Usually empty — trace ops are imported directly by frontend ops.

Step 4: Add as Tensor Method (Optional)

If the op should be callable as tensor.my_op(), register it in the TENSOR_METHOD_REGISTRY via the frontend tensor metaclass system. Check nvtripy/frontend/tensor.py for the pattern.

Complete Example: Softmax

Trace op (nvtripy/trace/ops/softmax.py):

@dataclass(repr=False)
class Softmax(TraceOp):
    dim: int
    infer_rank = op_utils.InferRankPolicies.same_as_input()

    def to_mlir(self, inputs, outputs):
        return [tensorrt.softmax(inputs[0], self.dim)]

Frontend op (nvtripy/frontend/ops/softmax.py):

@export.public_api(document_under="operations/functions")
@wrappers.interface(
    input_requirements=OneOf(GetInput("input").dtype, [dt.float32, dt.float16, dt.bfloat16]),
    output_guarantees=GetReturn(0).dtype == GetInput("input").dtype,
)
def softmax(input: "nvtripy.Tensor", dim: Optional[int] = None) -> "nvtripy.Tensor":
    # Handle None dim by flattening
    # Handle rank < 2 by unsqueezing (TensorRT requirement)
    dim = op_utils.process_dim(dim, input.rank)
    return op_utils.create_op(Softmax, [input], dim=dim)

Checklist

  • Trace op created in nvtripy/trace/ops/ with infer_rank and to_mlir
  • Frontend op created in nvtripy/frontend/ops/ with @export.public_api and @wrappers.interface
  • Constraints defined for valid dtypes and output guarantees
  • Docstring includes Args, Returns, and a working .. code-block:: python example
  • __init__.py updated if needed for auto-discovery
  • Tests added in tests/frontend/ops/ and tests/trace/ops/ (see testing skill)

Thêm skills từ nvidia

compileiq-debug
nvidia
Sử dụng khi có điều gì đó không ổn: Search() bị treo, tất cả các đánh giá đều trả về INVALID_SCORE, điểm số không cải thiện, mọi cấu hình đều trả về cùng một số, lỗi ptxas…
create-github-pr
nvidia
Tạo pull request GitHub bằng cách sử dụng gh CLI. Sử dụng khi người dùng muốn tạo PR mới, gửi mã để xem xét, hoặc mở pull request. Từ khóa kích hoạt -…
nemoclaw-maintainer-cross-issue-sweep
nvidia
Quét các vấn đề đang mở khác để tìm những vấn đề mà một PR nhất định có thể sửa hoặc vô tình làm hỏng. Đưa ra các cơ hội sửa lỗi liền kề và rủi ro mâu thuẫn với file:dòng…
fhir-basics
nvidia
Dạy các tác nhân cách hoạt động của API FHIR R4, những tài nguyên có sẵn, cách truy vấn chúng với tham số tìm kiếm, và cách phân tích chính xác tất cả các định dạng phản hồi…
compileiq-validate-result
nvidia
Sử dụng SAU KHI tìm kiếm hoàn tất và TRƯỚC KHI yêu cầu tăng tốc hoặc gửi ACF. Tải tệp CSV dump_results, trích xuất các ứng viên top-K (đơn mục tiêu)…
changelog-audit
nvidia
Kiểm tra Warp CHANGELOG.md trước khi phát hành: khôi phục các mục bị mất, sắp xếp theo tác động người dùng, tinh chỉnh ngôn ngữ mục, xuống dòng và (chế độ nhánh phát hành) so sánh bump…
maintain-dynamic-plugins
nvidia
Duy trì các bộ nạp plugin động NeMo Relay, tệp kê khai, SDK gốc Rust, giao thức worker gRPC, SDK worker Python, tài liệu, kiểm thử và phạm vi quy trình phát hành
dgx-diagnose
nvidia
Chẩn đoán các sự cố thường gặp của DGX Station GB300 — lỗi CUDA, nhắm sai GPU, lỗi container vLLM/SGLang, vấn đề trạng thái MIG, lỗi NVLink/Fabric Manager,…