CalSync — Automate Outlook Calendar Colors

Auto-color-code events for your team using rules. Faster visibility, less admin. 10-user minimum · 12-month term.

CalSync Colors is a service by CPI Consulting

In this blog post Practical ways to run PyTorch in .NET with TorchSharp and more we will walk through reliable ways to use PyTorch from .NET, when to choose each approach, and how the pieces work under the hood.

At a high level, you have three good options: write and run models directly in .NET with TorchSharp; train in Python and deploy in .NET via ONNX Runtime; or keep Python for inference behind a service boundary and call it from .NET. Each route can be production-grade with the right packaging and testing.

What’s happening under the hood

PyTorch is a tensor library and autograd system with a rich operator set, a module system (torch.nn), and multiple backends (CPU, CUDA). The C++ core of PyTorch is called LibTorch and exposes high-performance kernels and the JIT runtime.

TorchSharp is a .NET binding over LibTorch. It provides C# and F# APIs for tensors, autograd, and nn modules, and calls into the same native kernels that Python PyTorch uses. That means it’s fast, supports CPU or GPU, and is deployable as a pure .NET application with native dependencies.

ONNX is an open model format. You can export many PyTorch models to ONNX in Python, then load and run them in .NET with Microsoft’s ONNX Runtime. This is excellent for inference, especially when you want a minimal runtime without shipping the whole PyTorch stack.

Finally, a service boundary (REST/gRPC) lets you keep Python in production for inference while .NET owns the app and business logic. This is often the quickest bridge when you have existing Python models or teams.

Three production patterns to choose from

1) TorchSharp for end-to-end .NET

  • Pros: Single tech stack, full control, no Python in prod, great performance.
  • Cons: API surface isn’t identical to Python; you’ll port training code to C#.
  • Best for: Teams committed to .NET who want training and inference in one runtime.

2) PyTorch to ONNX to .NET

  • Pros: Keep training in Python; lightweight, fast inference with ONNX Runtime.
  • Cons: Some models/operators don’t export cleanly; no training, inference only.
  • Best for: Inference at scale, simpler deployment, minimal native dependencies.

3) Python service with a .NET client

  • Pros: Reuse existing Python code/libs as-is; easy iteration.
  • Cons: Two runtimes to operate; network hop; latency considerations.
  • Best for: Fast time-to-value when models frequently change or are Python-heavy.

Getting started with TorchSharp in .NET

Install packages

Add the TorchSharp NuGet package to your .NET project. For GPU acceleration, add the matching CUDA-enabled native runtime for your OS/CUDA version as documented by TorchSharp. For CPU-only scenarios, use the CPU runtime (often brought in by default).

Note: TorchSharp ships native LibTorch binaries per OS/arch. Align your package choice with your deployment target, and prefer 64-bit builds.

A minimal TorchSharp example

The sample below trains a tiny binary classifier in C#. It shows device selection (CPU/GPU), model definition, a training loop, and inference.

What to notice:

  • Same concepts as Python PyTorch: tensors, modules, optimizers, autograd.
  • Device placement mirrors PyTorch. If CUDA is available, GPU is used.
  • Dispose intermediate tensors in tight loops to keep memory steady.

Train in Python, run in .NET with ONNX Runtime

Export to ONNX in Python

Run the ONNX model in .NET

Tip: For GPU inference with ONNX Runtime, use the appropriate GPU-enabled package and ensure CUDA/cuDNN drivers are present on the host image.

Keep Python, call it from .NET

When you already have stable Python inference code, wrap it behind a small HTTP or gRPC service. FastAPI makes this easy.

Minimal FastAPI wrapper (Python)

.NET client call

Keep requests small, batch where possible, and consider gRPC for low-latency, high-throughput scenarios.

How to choose

  • If you want a single runtime and full control, pick TorchSharp.
  • If you want Python for training and a slim, fast inference in .NET, use ONNX Runtime.
  • If you want to move fast with existing Python code, expose a service.

Performance and deployment tips

TorchSharp

  • Package native LibTorch with your app. Choose the CPU or CUDA runtime matching your OS/arch.
  • For containers, start from an image that includes the right CUDA drivers if using GPU.
  • Use batches and disable grads for inference (no_grad()). Warm up the model before first request.
  • Dispose temporary tensors in loops to avoid memory growth.
  • Align TorchSharp version with its documented LibTorch version to avoid ABI mismatches.

ONNX Runtime

  • Validate the ONNX export as part of CI. Mismatched opsets cause runtime errors.
  • Use dynamic axes in export if your batch sizes vary.
  • Normalize inputs in .NET the same way as in Python. Shape and layout (NCHW vs NHWC) must match.
  • Consider the Execution Providers you need (CPU vs CUDA vs DirectML) based on your hardware.

Python service

  • Set concurrency with uvicorn/gunicorn workers tuned to your hardware.
  • Batch requests server-side to maximize GPU utilization.
  • Version your model artifact and expose a health/metadata endpoint.
  • Secure the service (auth, TLS) and rate-limit externally.

Common pitfalls to avoid

  • Data type mismatches: INT64 vs INT32 indices, float32 vs float64 tensors.
  • Silent shape errors: log and assert shapes at boundaries; add unit tests.
  • Export gaps: some custom ops or control flow don’t export well to ONNX. Use TorchScript or service boundary if needed.
  • Driver/ABI mismatches: keep CUDA and LibTorch versions aligned across build and deploy.

Wrapping up

You have solid, well-supported paths to run PyTorch with .NET. TorchSharp gives you native training and inference in a single stack. ONNX Runtime delivers lightweight, fast inference for many exported models. A Python service is a pragmatic bridge when you need full PyTorch flexibility right now.

Pick the pattern that fits your team and deployment constraints, automate validation in CI, and standardize packaging for your target environments. With that foundation, bringing ML to your .NET applications becomes straightforward and maintainable.


Discover more from CPI Consulting

Subscribe to get the latest posts sent to your email.