.. _l-next-steps-graph-builder-authoring: Compact GraphBuilder authoring and runtime walkthroughs ======================================================= :Date: 2026-08 **discussion** Objective +++++++++ The objective is to make small ONNX graphs concise to author, easy to inspect, and easy to execute from the regular documentation. The work has two connected parts: * add a compact Python facade over the existing ``GraphBuilder`` primitives, inspired by `yet-another-onnx-builder `_; * add non-gallery documentation that follows a model from construction or a backend-test case through compact display, optimization, and runtime execution. The existing ``make_input``, ``make_output``, ``make_initializer``, and ``make_node`` methods remain the stable low-level API. The compact facade delegates to them so opset resolution, schema validation, incremental shape inference, naming, and serialization continue to have one implementation. Compact authoring contract ++++++++++++++++++++++++++ ``GraphBuilder.op`` exposes ONNX operators by their canonical CamelCase names: .. code-block:: python x = g.inp("X", TensorProto.FLOAT, [None, 4]) bias = g.init(numpy.array([1, 2, 3, 4], dtype=numpy.float32), name="bias") added = g.op.Add(x, bias) result = g.op.Relu(added, outputs="Y") custom = g.op.CustomNormalize( result, domain="com.example", outputs="Z", epsilon=1e-5 ) g.out(custom, TensorProto.FLOAT, [None, 4]) The facade follows these rules: * ``g.op.(*inputs, **kwargs)`` forwards canonical ONNX attributes from ``kwargs`` and returns one output name or a tuple of output names; * ``outputs`` controls an explicit output name, a list of names, or an output count; ``domain`` and ``name`` remain reserved node options; * ``None`` represents an omitted optional ONNX input, variadic inputs remain positional, and NumPy arrays may be converted to named initializers; * standard-domain operators use the builder's configured opset and unknown standard operators fail explicitly; * custom operators use the same ``g.op.`` surface with an explicit non-empty ``domain``; the domain and version must already exist in the builder's opset imports and are never registered silently; * a custom operator does not require a locally registered schema. When no schema is available, attributes are preserved without schema inference and ``outputs`` must specify every output for operators that do not have exactly one output; * ``g.inp(name, elem_type, shape)`` creates and returns an input name; * ``g.out(name, elem_type=None, shape=None)`` declares a graph output and returns its name; * ``g.init(value, name=None)`` adds an initializer, generates a name when necessary, and returns the final name. Operator lookup should use one cached proxy and ``__getattr__`` rather than generating one Python method per schema. Reserved options must be separated from ONNX attributes before calling the existing node builder. Multi-output, optional-input, variadic-input, custom-domain, custom-operator, unknown-standard-operator, duplicate-name, and invalid-attribute behavior require direct tests. The compact aliases are additive. Code generated by ``onnx_light.tools.translate`` continues to use the explicit ``make_*`` API until the compact facade is stable and can reproduce every generated construct. GraphBuilder documentation ++++++++++++++++++++++++++ Add ``docs/howto/graph_builder_basics.rst`` as a regular RST page, not a Sphinx-Gallery example. It should be linked from the how-to index and from the builder design section. The page covers: 1. creating a builder and selecting opsets; 2. declaring inputs, outputs, and initializers with the compact aliases; 3. adding standard, variadic, optional-input, multi-output, and custom-domain operators, including a custom operator without a local schema; 4. exporting and checking a model; 5. running the existing ``GraphGraph`` pattern optimization; 6. inspecting the optimization report and replaying its ``LocalRewriting`` records. Every snippet must execute during documentation testing or be covered by an equivalent unit test. The page should show the compact API first and link to the explicit ``make_*`` methods as the complete low-level contract. LocalRewriting display ++++++++++++++++++++++ Improve ``LocalRewriting`` presentation without changing the data consumed by ``replay()``: * add a deterministic one-line summary containing the pattern, graph path, and matched/added node counts; * add a structured multiline representation grouping matched nodes, added nodes and positions, removed initializers, value renames, and timings; * display the root graph consistently as ```` and nested graph paths in execution order; * expose the short form through Python ``repr()`` and the detailed form through ``str()`` or an explicitly named detail method; * keep node ordering, field values, replay semantics, and serialization unchanged. Tests compare stable structural lines rather than terminal width or color. Documentation output must remain readable without ANSI styling. Runtime documentation walkthrough +++++++++++++++++++++++++++++++++ Add ``docs/howto/run_backend_test_case.rst`` outside Sphinx-Gallery. The page uses public APIs to perform one reproducible end-to-end flow: 1. retrieve an exact backend-test case with ``onnx_light.onnx.backend.get_test_case``; 2. display its model with an existing ``onnx_light.tools`` representation, including the ``onnx-compact`` style; 3. construct ``onnx_light.onnx.reference.ReferenceEvaluator``; 4. execute the supplied test inputs and compare the outputs with the expected backend-test values; 5. repeat the run with representative ``verbose``, ``events_enabled``, and ``release_intermediates`` options, explaining the effect of each option. The selected case must be small, deterministic, and identified by an exact stable name. The example must not download data or depend on optional large backend-test assets. If producing ``onnx-compact`` output currently requires a private helper, first expose or reuse one stable public function under ``onnx_light.tools`` rather than documenting internals. The runtime design index should summarize the same execution path at the architecture level: * ``ReferenceEvaluator`` as the Python entry point; * ``RuntimeSession`` preparation, kernel resolution, and repeated execution; * ``RuntimeContext`` values, allocators, events, and intermediate release; * kernel registry dispatch and the session CPU executor; * the relationship between backend tests, the runtime how-to, and lower-level C++ APIs. The design page remains conceptual and links to the runnable how-to for code. Implementation sequence +++++++++++++++++++++++ .. list-table:: :header-rows: 1 :widths: 12 31 42 15 * - PR - Scope - Merge criterion - Status * - Builder PR01 - Compact ``op``, ``inp``, ``out``, and ``init`` Python facade. - Existing ``make_*`` behavior is unchanged; compact calls cover standard, optional, variadic, multi-output, custom-operator, and invalid cases. - Planned * - Builder PR02 - Deterministic short and detailed ``LocalRewriting`` display. - Reports are readable in Python and plain documentation while replay data and behavior remain unchanged. - Planned * - Builder PR03 - Non-gallery GraphBuilder basics and optimization how-to. - The documented model builds, validates, optimizes, displays its rewrites, and round-trips in documentation tests. - Planned * - Runtime PR01 - Non-gallery backend-test runtime walkthrough and runtime design summary. - One stable case is displayed in ``onnx-compact`` form, executed, validated, and rerun with documented options; the design page explains the corresponding architecture. - Planned Acceptance criteria +++++++++++++++++++ The complete plan is accepted when: * compact authoring is additive and delegates to existing builder primitives; * generated models preserve opset imports, schema validation, names, shapes, and initializer ownership; * custom operators work through ``g.op`` with explicit domain/opset ownership, including when no local schema is registered; * ``LocalRewriting`` is readable without losing any replay information; * GraphBuilder construction and optimization have a runnable non-gallery how-to; * a backend-test model can be retrieved, rendered in compact form, executed, and validated from a second non-gallery how-to; * the runtime design section explains the architecture behind that example; * relevant Python/C++ tests, documentation builds, formatting, and linting pass.