Files
wehub-resource-sync 5cbd3f29e3
Fuzz / Run fuzz harnesses (${{ github.event_name == 'schedule' && 'nightly' || 'smoke' }}) (push) Has been cancelled
Create Releases / call-mac (push) Has been cancelled
Create Releases / call-linux (push) Has been cancelled
Create Releases / call-sdist (push) Has been cancelled
Create Releases / call-win (push) Has been cancelled
Create Releases / call-pyodide (push) Has been cancelled
Windows_No_Exception_CI / build (x64, 3.10) (push) Has been cancelled
Check URLs / build (push) Has been cancelled
Create Releases / Attest CI build artifacts (push) Has been cancelled
Create Releases / Check for Publish release build to pypi (push) Has been cancelled
Create Releases / Check for Publish preview build to test.pypi-weekly (push) Has been cancelled
Create Releases / Publish preview build to test.pypi-weekly (push) Has been cancelled
Create Releases / Check for Publish release build to test.pypi (rc-candidates) (push) Has been cancelled
Create Releases / Publish release build to test.pypi (push) Has been cancelled
Create Releases / Check for Publish preview build to pypi-weekly (push) Has been cancelled
Create Releases / Publish preview build to pypi-weekly (push) Has been cancelled
Create Releases / Publish release build to pypi (push) Has been cancelled
Create Releases / test source distribution (push) Has been cancelled
clang-tidy / clang-tidy (push) Has been cancelled
Lint / Validate SBOM (push) Has been cancelled
Lint / Enforce style (push) Has been cancelled
CI / Test windows-2022, 3.14, External, debug=0, unity_build=0, onnx_ml=1, autogen=0 (push) Has been cancelled
CI / Test windows-latest, 3.10, Internal, debug=0, unity_build=0, onnx_ml=1, autogen=0 (push) Has been cancelled
CI / Test windows-latest, 3.14, Internal, debug=0, unity_build=0, onnx_ml=1, autogen=0 (push) Has been cancelled
CI / Test windows-latest, 3.14t, Internal, debug=0, unity_build=0, onnx_ml=1, autogen=0 (push) Has been cancelled
CI / Test ubuntu-24.04, 3.14, Internal, debug=1, unity_build=0, onnx_ml=1, autogen=0 (push) Has been cancelled
CI / Test ubuntu-24.04, 3.14, External, debug=0, unity_build=1, onnx_ml=1, autogen=1 (push) Has been cancelled
CI / Test ubuntu-24.04, 3.14, External, debug=0, unity_build=0, onnx_ml=0, autogen=0 (push) Has been cancelled
CI / Test macos-latest, 3.10, Internal, debug=0, unity_build=0, onnx_ml=1, autogen=0 (push) Has been cancelled
CI / Test macos-latest, 3.14, Internal, debug=0, unity_build=0, onnx_ml=1, autogen=0 (push) Has been cancelled
CI / Test macos-latest, 3.14t, Internal, debug=0, unity_build=0, onnx_ml=1, autogen=0 (push) Has been cancelled
CI / Test ubuntu-24.04, 3.14, External, debug=0, unity_build=0, onnx_ml=1, autogen=0 (push) Has been cancelled
CI / Test ubuntu-24.04, 3.10, Internal, debug=0, unity_build=0, onnx_ml=1, autogen=0 (push) Has been cancelled
CI / Test ubuntu-24.04, 3.14, Internal, debug=0, unity_build=0, onnx_ml=1, autogen=0 (push) Has been cancelled
CI / Test ubuntu-24.04, 3.14t, Internal, debug=0, unity_build=0, onnx_ml=1, autogen=0 (push) Has been cancelled
Pixi CI / Install and lint (ubuntu-24.04-arm) (push) Has been cancelled
Pixi CI / Install and lint (windows-2022) (push) Has been cancelled
Pixi CI / Xcode generator build (push) Has been cancelled
Pixi CI / Install and test (macos-latest, default) (push) Has been cancelled
Pixi CI / Install and test (ubuntu-24.04-arm, default) (push) Has been cancelled
Pixi CI / Install and test (ubuntu-latest, default) (push) Has been cancelled
Pixi CI / Install and test (windows-2022, default) (push) Has been cancelled
Pixi CI / Install and test (macos-latest, oldies) (push) Has been cancelled
Pixi CI / Install and test (ubuntu-24.04-arm, oldies) (push) Has been cancelled
Pixi CI / Install and test (ubuntu-latest, oldies) (push) Has been cancelled
Pixi CI / Install and test (windows-2022, oldies) (push) Has been cancelled
CodeQL / Analyze (actions) (push) Has been cancelled
CodeQL / Analyze (cpp) (push) Has been cancelled
CodeQL / Analyze (python) (push) Has been cancelled
Copilot Setup Steps / copilot-setup-steps (push) Has been cancelled
Generate and publish ONNX docs / build (push) Has been cancelled
Generate and publish ONNX docs / deploy (push) Has been cancelled
Scorecard supply-chain security / Scorecard analysis (push) Has been cancelled
chore: import upstream snapshot with attribution
2026-07-13 12:41:19 +08:00

182 lines
6.4 KiB
Python

# Copyright (c) ONNX Project Contributors
# SPDX-License-Identifier: Apache-2.0
from __future__ import annotations
import numpy as np
from onnx.reference.op_run import OpRun
class Scan(OpRun):
def __init__(self, onnx_node, run_params):
OpRun.__init__(self, onnx_node, run_params)
if not hasattr(self.body, "run"):
raise RuntimeError(
f"Parameter 'body' must have a method 'run', type {type(self.body)}."
)
if self.num_scan_inputs <= 0:
raise RuntimeError(
f"Scan requires num_scan_inputs > 0, got {self.num_scan_inputs}."
)
self.input_directions_ = [
(
0
if self.scan_input_directions is None
or i >= len(self.scan_input_directions)
else self.scan_input_directions[i]
)
for i in range(self.num_scan_inputs)
]
if self.input_directions_:
max_dir_in = max(self.input_directions_)
if max_dir_in != 0:
raise RuntimeError(
"Scan is not implemented for other output input_direction than 0."
)
self.input_axes_ = [
(
0
if self.scan_input_axes is None or i >= len(self.scan_input_axes)
else self.scan_input_axes[i]
)
for i in range(self.num_scan_inputs)
]
if self.input_axes_:
max_axe_in = max(self.input_axes_)
if max_axe_in != 0:
raise RuntimeError(
"Scan is not implemented for other input axes than 0."
)
self.input_names = self.body.input_names
self.output_names = self.body.output_names
def need_context(self) -> bool:
"""Scan body subgraphs may reference names from the enclosing graph
(lexical capture, per the ONNX spec). Request the outer-scope
context so those names resolve at body-evaluation time.
"""
return True
def _common_run_shape(self, *args):
num_loop_state_vars = len(args) - self.num_scan_inputs
num_scan_outputs = len(self.output_names) - num_loop_state_vars
output_directions = [
(
0
if self.scan_output_directions is None
or i >= len(self.scan_output_directions)
else self.scan_output_directions[i]
)
for i in range(num_scan_outputs)
]
max_dir_out = max(output_directions) if output_directions else 0
if max_dir_out != 0:
raise RuntimeError(
"Scan is not implemented for other output output_direction than 0."
)
output_axes = [
(
0
if self.scan_output_axes is None or i >= len(self.scan_output_axes)
else self.scan_output_axes[i]
)
for i in range(num_scan_outputs)
]
max_axe_out = max(output_axes) if output_axes else 0
if max_axe_out != 0:
raise RuntimeError("Scan is not implemented for other output axes than 0.")
state_names_in = self.input_names[:num_loop_state_vars]
state_names_out = self.output_names[: len(state_names_in)]
scan_names_in = self.input_names[num_loop_state_vars:]
scan_names_out = self.output_names[num_loop_state_vars:]
scan_values = args[num_loop_state_vars:]
states = list(args[:num_loop_state_vars])
return (
num_loop_state_vars,
num_scan_outputs,
output_directions,
max_dir_out,
output_axes,
max_axe_out,
state_names_in,
state_names_out,
scan_names_in,
scan_names_out,
scan_values,
states,
)
def _run( # type: ignore[override]
self,
*args,
context=None,
body=None, # noqa: ARG002
num_scan_inputs=None, # noqa: ARG002
scan_input_axes=None, # noqa: ARG002
scan_input_directions=None, # noqa: ARG002
scan_output_axes=None, # noqa: ARG002
scan_output_directions=None, # noqa: ARG002
attributes=None, # noqa: ARG002
):
# TODO: support overridden attributes.
(
num_loop_state_vars,
_num_scan_outputs,
_output_directions,
_max_dir_out,
_output_axes,
_max_axe_out,
state_names_in,
state_names_out,
scan_names_in,
scan_names_out,
scan_values,
states,
) = self._common_run_shape(*args)
max_iter = args[num_loop_state_vars].shape[self.input_axes_[0]]
results = [[] for _ in scan_names_out]
for it in range(max_iter):
# Seed with outer-scope values first; per-iteration state and
# scan-slice inputs (added below) shadow any same-named outer
# values, matching ONNX's lexical-capture semantics.
inputs: dict = {}
if context is not None:
inputs.update(context)
inputs.update(dict(zip(state_names_in, states, strict=False)))
inputs.update(
{
name: value[it]
for name, value in zip(scan_names_in, scan_values, strict=False)
}
)
try:
outputs_list = self._run_body(inputs)
except TypeError as e:
raise TypeError(
f"Unable to call 'run' for type '{type(self.body)}'."
) from e
outputs = dict(zip(self.output_names, outputs_list, strict=False))
states = [outputs[name] for name in state_names_out]
for i, name in enumerate(scan_names_out):
results[i].append(np.expand_dims(outputs[name], axis=0))
if max_iter == 0 and results:
# Zero-trip Scan with scan outputs is not supported: the per-iteration
# element shape/dtype cannot be reliably inferred without executing
# the body. Treat as an error rather than guessing.
raise RuntimeError(
"Scan with zero scan-input length and scan outputs is not supported."
)
for res in results:
states.append(np.concatenate(res, axis=0))
return self._check_and_fix_outputs(tuple(states))