Introducing ONNX Script: Authoring ONNX with the ease of Python

An ONNX refresher 

ONNX models are flexible, standardized representations of machine learning that allow them to be executed across a gamut of hardware platforms and runtime environments from large-scale cloud-based supercomputers to resource-constrained edge devices such as your web browser and phone. 

Beyond its graph format, canonically represented usingProtobuf, ONNX consists of a standard set of primitive operators which are implemented by runtimes and hardware vendors alike. With this broad ecosystem in mind, ONNX aims to keep the number of these operators low, encouraging composability through ONNX functions. This is important to reduce the overhead of supporting ONNX. 

Typically, machine learning models are developed using higher-level frameworks such asPyTorchandTensorFlow. While these frameworks tend to be productive for iterating on the development of models, the models are not typically deployed to production in this fashion. Instead, they are exported to ONNX by facilities provided by the frameworks, and then optimized for a particular target by tools such asOlive

Want to dive right into ONNX Script? Check it out on GitHub.

Announcing ONNX Script 

ONNX Script is a new open-source library for directly authoring ONNX models in Python with a focus onclean, idiomatic Pythonsyntax and composability through ONNX-native functions. Critically, it is also the foundation upon which we are building the new PyTorch ONNX exporter to supportTorchDynamothe future of PyTorch. 

Prior to ONNX Script, authoring ONNX models required deep knowledge of the specification and serialization format itself. While eventually a more convenienthelper APIwas introduced that largely abstracted the serialization format, it still required deep familiarity with ONNX constructs. 

ONNX Script takes a new approach by integrating deeply with Python on two fronts:

  1. It provides a strongly typed API for all operators in ONNX (all 186 as of opset 19).1 This allows existing Python tooling, linters, and integrated development environments (IDEs) to provide valuable feedback and enforce correctness.
  2. ONNX Script supports idiomatic Python language constructs to make authoring ONNX more natural, including support for conditionals and loops, binary and unary operators, subscripting, slicing, and more. For example, the expressiona+bin Python would translate to the ONNX operatoras Add(a,b).

Let's look at how we might implement GELU using ONNX Script and compare it withonnx.helperAPIand to be clearthe examples below produce the same ONNX model. For reference, we'll use this definition of GELU to guide the ONNX implementations: 

GELU formula and implementation in ONNX Script and using helper API

As you can see, ONNX Script emphasizes the familiar readability and productivity of Python while expressing an ONNX model that can be statically reasoned about by existing Python and ONNX tooling. 

This also means ONNX comes alive within the context of your existing tooling and development environments, be it debugging in Visual Studio Code or demonstrating concepts in a Jupyter NotebookONNX Script integrates naturally. 

Why are we investing in ONNX Script? 

Much has changed since ONNX support for PyTorch was originally introduced over five years ago in PyTorch 0.3.0. For PyTorch 2.0, TorchDynamo represents the eventual deprecation of TorchScript, which implies a major overhaul of the ONNX exporter is necessary. We are fully embracing this as an opportunity to revisit the fundamentals upon which the exporter is built, and ONNX Script is its new foundation. We began this effort in November 2022 and have worked closely with PyTorch engineers to ensure TorchDynamo is a fully capable starting point for exporting high-fidelity ONNX for years to come. 

One of the first streams of work we started was the development of what we call Torchlib, a pure ONNX implementation of the operators in PyTorchnamelyCore ATen IR and Prims IRand of course, these operators are implemented in ONNX Script. This approach greatly simplifies the central responsibility of the exporter as it "just" needs to project FX graph nodes produced by TorchDynamo into ONNX graph nodes, without concerning itself with the implementation details of individual operators. 

We will cover the new PyTorch ONNX exporter in a separate post with more depth as PyTorch 2.1 approaches, but for now, the key takeaway is that ONNX Script is pervasive throughout our renewed approach. For those willing to try bold new things, the new exporter is available as a preview in PyTorch nightly via thetorch.onnx.dynamo_exportAPI. 

By deeply weaving ONNX Script support into the PyTorch ONNX exporter, we have also made it possible to augment PyTorch model code with specialized ONNX functions as custom operators. We introduced initial support for this in the TorchScript exporter starting withPyTorch 1.13and continue to refine this capability in the new exporter. 

An end-to-end example  

Let's look at an example slightly more complicated than GELU. In fact, the following example is adapted directly from the new PyTorch ONNX exporter, implementing support fortorch.chunk, which attempts to split a tensor into the number of specified chunks. 

The aten_chunk() function

We start by importing from onnxscript the ONNX opset we wish to use (version 18 in this case), the@scriptdecorator, and the tensor types ofFLOATandINT64. In ONNX Script, tensor shapes are denoted by subscripting the type, such as FLOAT[2, 10], symbolically such as FLOAT["M", "N"], or FLOAT[...] incase the tensor shape is unknown. Without subscripting (just FLOAT), the type is intended to indicate a scalar (a tensor of rank 0).

Next, we define theaten_chunkfunction with type annotations and implement the body of the function using both built-in Python syntax and explicit invocations of ONNX operators. The example uses various binary expressions and anifstatement, but many other idiomatic Python constructs are also supported. 

We also need to define a simple model that calls our ONNX Script function so we can export and verify an end-to-end example: 

ten_chunks_model() function, calling the ONNX Script function

This model will simply split the provided tensor into ten tensors, but it also demonstrates that ONNX functions can of course call other ONNX functions, not just built-in ONNX operators. 

We'll now export our ONNX Script model to ONNX and explore it in Netron. Functions decorated with @script allow them to be exported using the to_model_proto function.

saving the ONNX model

If we openten_chunks_model.onnxin Netron, we can observe the composability of ONNX functions and how the Python code was translated into an ONNX model. 

a netron graph of the ten_chunks_model and its connected function, aten_chunk

The graphs depict our two ONNX functions. We can observe the originalinput tensorflowing fromten_chunks_modelintoaten_chunkalong with theattribute chunks=10. Asequence of 10 tensorsis returned. As one might expect, functions in ONNX can be defined once and invoked any number of times within a model.Read more about core ONNX concepts. 

Iterating and debugging 

Finally, we should test our model. ONNX Script makes this easy since it provides a mechanism for eagerly evaluating the model through eitherONNX Runtimeor the newONNX Reference Evaluator. Of note, ONNX Script has built-in support forNumPyfor input and output values to ease the overhead of creating and filling tensors in ONNX.  

setting up testing tensors and chunked_tensors arrays
Output arrays, as expected

Because ONNX Script's eager mode evaluates the model on an op-by-op basis, it is conducive to debugging ONNX using standard Python tooling such aspdbdirectly or through richer IDE and editor integrations provided by Visual Studio and Visual Studio Code. 

A screenshot of Visual Studio Code debugging the model while stopped on a breakpoint to inspect the dim_size variable and call stack.
A screenshot of Visual Studio Code debugging the model while stopped on a breakpoint to inspect the dim_size variable and call stack.

Along with debuggability, IntelliSense support is front-and-center with ONNX Script. We rely heavily on Python type annotations to enforce the correctness of ONNX and to make ONNX more discoverable, including inline documentation on hover tooltips and code completion suggestions. A single click will take you to expanded online documentation in your browser as well. 

A screenshot of Visual Studio Code displaying a hover tooltip for the ONNX Expand operator with inline documentation linking to full online documentation.
A screenshot of Visual Studio Code displaying a hover tooltip for the ONNX Expand operator with inline documentation linking to full online documentation. 

What's next for ONNX Script? 

In summary, ONNX Script offers a new Python-first programming model for authoring ONNX models that integrates with the existing rich ecosystem of Python tooling and environments. 

Going forward, we envision ONNX Script as a means for defining and extending ONNX itself. New core operators and higher-order functions that are intended to become part of the ONNX standard could be authored in ONNX Script as well, reducing the time and effort it takes for the standard to evolve. We have proven this is a viable strategy by developing Torchlib, upon which the upcoming PyTorch Dynamo-based ONNX exporter is built. 

Over the coming months, we will also support converting ONNX into ONNX Script to enable seamless editing of existing models, which can play a key role in optimization passes, but also allow for maintaining and evolving ONNX models more naturally. We also intend to propose ONNX Script for inclusion directly within the ONNX GitHub organization soon, under the Linux Foundation umbrella. 

Check out ONNX Script today on GitHub!


Ahuge thank youto the wonderful engineering team at Microsoft that has brought us to this point so far:Bowen Bao, Aaron Bockover, Shubham Bhokare, Jacky Chen, Wei-Sheng Chin, Justin Chu, Thiago Crepaldi, Xavier Dupre, Liqun Fu, Xaiowu Hu, Ganesan Ramalingam, Ti-Tai Wang, Jay Zhang


1ONNX OperatorsONNX 1.15.0 documentation.

The post Introducing ONNX Script: Authoring ONNX with the ease of Python appeared first on Microsoft Open Source Blog.

0 Response to "Introducing ONNX Script: Authoring ONNX with the ease of Python"

Post a Comment

Article Top Ads

Central Ads Article 1

Central Ads Article 2

Article Bottom Ads