Skip to main content

localcorr

GitHub CI python status GitHub CI pytorch status GitHub CI build status

PyTorch local correlation kernels for optical flow networks such as RAFT and PWC-Net.

The implementations are drop-in compatible with RAFT's alt_cuda_corr and spatial_correlation_sampler, and run on NVIDIA and Intel GPUs as well as any ONNX-supported runtime (see Components).

You can check PTLFlow to see examples of optical flow models using localcorr.

Quick start

pip install localcorr

That's enough to train and run inference eagerly on Linux — the default Triton kernels are JIT-compiled on first use with no build step required (see Installation for other platforms and optional AOT plugins).

RAFT-style correlation (feature maps + sampled coordinates):

import torch
from localcorr import get_localcorr_block

# fmap1/fmap2: [B, C, H, W], coords: [B, 2, H, W] (x, y)
corr_block = get_localcorr_block(
    fmap1, fmap2, num_levels=4, radius=4,
    corr_mode="localcorr_triton",
)
corr = corr_block(coords)  # [B, levels*(2r+1)^2, H, W]

PWCNet-style spatial correlation:

from localcorr import get_localcorr_sampler

# same result as SpatialCorrelationSampler(kernel_size=1, patch_size=9, padding=0)
sampler = get_localcorr_sampler(patch_size=9, corr_mode="localcorr_triton")
corr = sampler(input1, input2)  # [B, 9, 9, H, W]

Choosing a corr mode

Everything in localcorr is selected through a single corr_mode argument (accepted by both get_localcorr_block and get_localcorr_sampler):

corr_mode Runs on Best for
localcorr_triton Any Triton-supported GPU Default. Eager execution, no build step.
localcorr_onnx Any Triton-supported GPU Same eager behavior; exports plugin-free ONNX
localcorr_cuda NVIDIA GPU (AOT CUDA kernel) Fastest CUDA path + TensorRT engines
localcorr_sycl Intel GPU (SYCL on torch.xpu) Fastest Intel-GPU path + OpenVINO custom op
localcorr_auto NVIDIA or Intel GPU (auto) One code path across both hardware platforms

Notes:

  • Strict vs. automatic dispatch: Each specific mode (triton, cuda, sycl) uses its own eager engine and fails with a clear error if the extension is missing or tensors are on the wrong device, rather than silently falling back. localcorr_auto is the exception: it inspects the tensor device and falls back to the Triton kernel when the native AOT extension is not built.
  • Export behavior: The modes only differ in eager execution and ONNX export; see ONNX export for how each one exports.

Installation

pip install localcorr

triton (the engine behind localcorr_triton and localcorr_onnx) is installed automatically on Linux. On platforms where Triton does not provide wheels, localcorr still imports and the pure-PyTorch / ONNX-export paths work, while calling a Triton kernel raises an ImportError on first use.

TensorRT and OpenVINO are deliberately not required dependencies:

  • To build or run TensorRT engines with the cuda_pyramid plugin, install TensorRT yourself (the plugin build only needs NvInfer.h and libnvinfer discoverable).
  • Likewise, OpenVINO is only needed to build the sycl extension and run models using the custom op.

Building the native components (optional)

The AOT components (cuda_pyramid, sycl_pyramid, xpu) provide the fastest eager engines and the TensorRT/OpenVINO plugins listed above. They are optional and can be compiled on demand with a single command from any directory (both the pip wheel and sdist ship the native sources):

python -m localcorr.build_native cuda   # NVIDIA: AOT kernel + TensorRT plugin
python -m localcorr.build_native sycl   # Intel: OpenVINO custom-op extension
python -m localcorr.build_native xpu    # Intel: torch.xpu SYCL extension
python -m localcorr.build_native all

When pip-installed, you can also use the console script (localcorr-build cuda) or build programmatically (from localcorr import build_native; build_native.build("cuda")). From a repository checkout, the direct scripts (bash localcorr/<component>/build.sh) also work.

Requirements per target:

  • cuda — CUDA toolkit (nvcc), CMake >= 3.18, and TensorRT (NvInfer.h + libnvinfer). Set TRT_ROOT or TENSORRT_ROOT if TensorRT is not in a default system path. Output: localcorr/cuda_pyramid/build/liblocalcorr_cuda_pyramid_plugin.so
  • sycl — Intel oneAPI (icpx with SYCL) and the OpenVINO runtime (the pip package headers are used by default; override with OV_INSTALL_DIR). Output: localcorr/sycl_pyramid/build/liblocalcorr_sycl_pyramid.so (the SYCL kernel) and localcorr/sycl_pyramid/build/liblocalcorr_sycl_pyramid_ov.so (the OpenVINO extension, plus test_kernel for correctness verification).
  • xpu — a PyTorch XPU build (pip install torch --index-url [https://download.pytorch.org/whl/xpu](https://download.pytorch.org/whl/xpu)), oneAPI (icpx), and (for the Triton fallback only) triton-xpu plus the Level Zero headers. Output: localcorr/xpu/build/localcorr_sycl_xpu*.so

Usage

Eager execution & training

All modes support fp16 and fp32 inputs as well as PyTorch autograd for training. Across all backends, backward passes compute gradients with respect to the feature maps (fmap1/fmap2 or input1/input2), while gradients for the sampling coordinates (coords) are returned as zeros.

If you want the same model code to run unchanged across NVIDIA and Intel GPUs, use corr_mode="localcorr_auto" (which also accepts an optional xpu_backend argument in both factories):

# RAFT-style: backend resolved once from the device of fmap1/fmap2
corr_block = get_localcorr_block(
    fmap1, fmap2, num_levels=4, radius=4, corr_mode="localcorr_auto"
)
corr = corr_block(coords)  # [B, levels*(2r+1)^2, H, W]

# PWCNet-style: backend dispatched per call from the device of input1/input2
# (uses the LocalCorrCudaPyramidSampler class under the hood)
sampler = get_localcorr_sampler(patch_size=9, corr_mode="localcorr_auto")
corr = sampler(input1, input2)  # [B, 9, 9, H, W]

How localcorr_auto dispatches:

  • NVIDIA GPUs: Uses the AOT CUDA kernel (localcorr_cuda) when the extension is built, otherwise falls back to the Triton kernel.
  • Intel GPUs (torch.xpu): Uses the fused SYCL kernel when the extension is built, otherwise falls back to the Triton kernel (xpu_backend="triton" forces Triton; defaults to "sycl").
  • ONNX export: Emits a single LocalCorrCudaPyramid plugin node (which also sidesteps the fact that the fused Triton kernel cannot be traced for export), or standard ONNX ops when the "onnx" backend is active.

ONNX export

By default, ONNX export emits LocalCorrCudaPyramid custom nodes understood by the TensorRT ONNX parser (via the CUDA plugin) and OpenVINO (via the sycl_pyramid SYCL custom-op extension).

To export models for runtimes without custom-plugin support, switch to the standard-ops backend before exporting:

import localcorr

localcorr.set_onnx_backend("onnx")  # or "tensorrt" (default)
# ... then export with the legacy tracer:
# torch.onnx.export(model, args, "model.onnx", dynamo=False, opset_version=17)

Important: Always pass dynamo=False when calling torch.onnx.export. Recent PyTorch versions default to the Dynamo exporter, which silently drops the correlation and emits an all-zeros placeholder instead of the plugin node.

Key behaviors during export:

  • Environment variable: You can also select the standard-ops backend via LOCALCORR_ONNX_BACKEND=onnx. This setting only affects ONNX export; eager execution is unchanged.
  • Mode compatibility: Models configured with corr_mode="localcorr_triton" cannot be exported with the default "tensorrt" backend (the fused Triton kernel raises an error on export). Either set the backend to "onnx" or initialize the model with corr_mode="localcorr_onnx".
  • localcorr_onnx mode: Always exports using standard ONNX ops without touching global state, while running the fast fused Triton kernel in eager mode. This produces plugin-free ONNX and TensorRT engines at the cost of a slower correlation subgraph than the fused plugin.
  • Standard-ops design: Rather than calling grid_sample directly over multi-channel feature maps, the standard-ops path contracts channels via matmul and gathers displacement windows from single-channel correlation planes, which is significantly faster (see design notes in localcorr/onnx_generic.py).

TensorRT inference (NVIDIA)

Models exported with LocalCorrCudaPyramid nodes require the TensorRT runtime to load the compiled plugin library before deserializing the engine (after building the cuda target):

import ctypes
import tensorrt as trt

trt_logger = trt.Logger(trt.Logger.WARNING)
trt.init_libnvinfer_plugins(trt_logger, "")
ctypes.CDLL(
    "localcorr/cuda_pyramid/build/liblocalcorr_cuda_pyramid_plugin.so",
    mode=ctypes.RTLD_GLOBAL,
)

For command-line tools such as trtexec, you can pass the library via LD_PRELOAD or --staticPlugins / --dynamicPlugins.

OpenVINO inference (Intel)

After building the sycl extension, register the custom op that maps the custom_ops::LocalCorrCudaPyramid ONNX node to the SYCL kernel:

import localcorr.openvino_ext as lcorr_ov  # Import BEFORE openvino:
# preloads the oneAPI OpenCL runtime so the SYCL extension finds the
# OpenCL CPU platform.
import openvino as ov

core = ov.Core()
lcorr_ov.add_localcorr_extension(core)  # registers the custom op
model = core.read_model("model.onnx")    # LocalCorrCudaPyramid resolves

Notes:

  • SYCL device selection: The extension computes on the SYCL GPU device by default (auto: GPU preferred, CPU fallback when no GPU is available). Set LOCALCORR_SYCL_DEVICE=cpu|gpu|default|auto to override.
  • OpenVINO device plugins: The OpenVINO GPU and NPU plugins cannot execute the custom op directly (Reference nodes are a CPU-plugin capability), so load the OpenVINO model on CPU or AUTO (which delegates the custom op and dispatches the SYCL kernel onto the GPU). For standalone NPU deployment, export with the standard-ops backend (localcorr_onnx).
  • oneAPI CPU workaround: The OpenCL CPU runtime in oneAPI 2026.1 crashes or hangs on SYCL sub-group shuffles; the CPU execution paths avoid them (see localcorr/sycl_pyramid/localcorr_cuda_pyramid_kernel.dp.cpp).
  • Symbol visibility: The oneAPI runtime preload in localcorr.openvino_ext intentionally uses RTLD_LOCAL; loading those libraries with RTLD_GLOBAL breaks the OpenVINO GPU plugin's JIT compiler (see module docstring for details).

Components

Component Path Build Used for
localcorr_triton localcorr/triton/ none (Triton JIT) Eager forward + backward for localcorr_triton and localcorr_onnx
localcorr_cuda_pyramid (localcorr_cuda) localcorr/cuda_pyramid/ CMake + nvcc Eager CUDA forward + backward (ctypes) + TensorRT engines (fastest NVIDIA path)
localcorr_sycl_pyramid localcorr/sycl_pyramid/ build.sh + icpx OpenVINO inference on Intel (SYCL custom op)
localcorr_sycl_xpu localcorr/xpu/ build.sh + icpx Eager torch.xpu forward + backward for localcorr_sycl on Intel GPUs
onnx-generic export localcorr/onnx_generic.py none Plugin-free ONNX export using standard ops

localcorr_triton

Triton kernels, JIT-compiled at first use (pip install triton, no build step):

  • triton/pyramid_corr.py: RAFT-style multi-level local correlation around sampled coordinates (LocalCorrTriton per-level, and LocalCorrTritonFused computing all pyramid levels in one launch).
  • triton/spatial_corr.py: PWCNet-style single-level spatial correlation (TritonSpatialCorrelationSampler), equivalent to SpatialCorrelationSampler(kernel_size=1, patch_size, padding=0).

localcorr_cuda_pyramid

An AOT-compiled CUDA kernel and TensorRT IPluginV3 plugin that computes all correlation pyramid levels in one kernel launch (using templated fast paths with warp-shuffle reductions; see localcorr/cuda_pyramid/localcorr_cuda_pyramid_kernel.h). During ONNX export, each correlation call is emitted as a single LocalCorrCudaPyramid node resolved by the TensorRT ONNX parser.

The same plugin serves both correlation styles:

  • RAFT-style: levels = N (pyramid), x-major displacement order.
  • PWCNet-style: levels = 1, y-major displacement order (channel = dy_idx * patch_size + dx_idx).

In eager mode (corr_mode="localcorr_cuda"), the kernel is invoked through ctypes on PyTorch's current CUDA stream, paired with a fused backward kernel.

localcorr_sycl_xpu (PyTorch on Intel GPUs)

Exposes the fused SYCL kernel to PyTorch as a torch.xpu (SyclExtension) extension. Models running on torch.xpu devices compute the entire correlation pyramid in a single fused kernel launch on the Intel GPU, ordered on PyTorch's XPU stream for both forward and backward passes.

localcorr_sycl_pyramid (OpenVINO on Intel)

A SYCL port of the fused kernel paired with an OpenVINO custom-operation extension that maps custom_ops::LocalCorrCudaPyramid ONNX nodes to the SYCL kernel. See OpenVINO inference for usage.

Plugin interface

ONNX node specification (domain custom_ops):

LocalCorrCudaPyramid(fmap1, fmap2_packed, coords) -> corr
  attributes: radius (int), levels (int), dilation (int, default 1),
              ymajor (int, default 0)
  fmap1:        [B, H1, W1, C]                     (NHWC, fp16 or fp32)
  fmap2_packed: [B, C * sum_i h_i*w_i]             (NHWC levels packed,
                                                    h_i = H1>>i, w_i = W1>>i,
                                                    batch-major)
  coords:       [B, 2, H1, W1]                     (planar, x in channel 0,
                                                    level-0 scale)
  corr:         [B, levels, (2*radius+1)^2, H1, W1]

The displacement channel order is d = iy + rd*ix by default (RAFT) or d = ix + rd*iy when ymajor=1 (PWCNet / SpatialCorrelationSampler order). dilation controls the step between consecutive displacement positions (matching dilation_patch in spatial correlation samplers).

Tests

Unit tests run on CPU by default; tests requiring a CUDA device, an Intel GPU, or optional packages (onnx, onnxruntime, openvino) are skipped automatically when unavailable. From the repository root:

pytest tests

(Prefer pytest over python -m pytest to avoid any local directory shadowing with the triton package; from the parent directory, pytest localcorr/tests also works.)

Acknowledgments

Most of the code in this repository was written by GLM-5.3, a large language model trained by Z.ai, with human guidance, testing, and review. Honestly, I wouldn't have known how to write custom CUDA, SYCL, Triton, TensorRT, and OpenVINO C++ extensions all by myself.

The implementations are based on:

  • alt_cuda_corr from the RAFT project — the original RAFT-style local correlation kernels, reimplemented here as a single fused pyramid kernel.
  • spatial_correlation_sampler by Clément Pinard — the PWCNet-style spatial correlation package whose semantics (kernel_size=1, patch_size, padding=0) this package is compatible with.

Metadata

Release files for localcorr 0.1.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 localcorr 0.1.1
File Size Uploaded Provenance
localcorr-0.1.1.tar.gz 102.3 kB With provenance Details

Built distribution (wheel)

Table of built distributions (wheels) for localcorr 0.1.1
File Interpreter ABI Platform
localcorr-0.1.1-py3-none-any.whl Python 3 none any Details

Total release size: 188.2 kB

Release files / localcorr-0.1.1.tar.gz

Download URL localcorr-0.1.1.tar.gz
Size 102.3 kB
Tags Source
SHA-256 checksum
How to use checksums
65e4ef9bb7ec1ceeef41f2f8c0571d654edcc53f0d6afcb47f39e6f13549f628
BLAKE2b-256 checksum
How to use checksums
67e3b763d468e37af45999bc557b82f4fcf440f4d8fe0c496d3137fec3a95235
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/7.0.0 CPython/3.13.14

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.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Oct 18, 2026.

Transparency log

Release files / localcorr-0.1.1-py3-none-any.whl

Download URL localcorr-0.1.1-py3-none-any.whl
Size 85.9 kB
Tags Python 3
SHA-256 checksum
How to use checksums
a1bbff999d4265cbf23b6479eeca6cb9e284cb7b613efa403ac9513389d4cee6
BLAKE2b-256 checksum
How to use checksums
5553348277566ce7a32ab78c547495400a42e5522089483b53fe40ab53677fb6
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/7.0.0 CPython/3.13.14

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.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Oct 18, 2026.

Transparency log

Security for localcorr 0.1.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.

Full provenance

All 2 files in this release have been uploaded with provenance metadata.

Select from 2 files

Attestation for localcorr-0.1.1.tar.gz

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Oct 18, 2026.

Transparency log

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.

Release history Release notifications | RSS feed

This release

0.1.1 This release

2 release files Full provenance

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