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
414 lines
14 KiB
Python
414 lines
14 KiB
Python
# Copyright (c) ONNX Project Contributors
|
|
|
|
# SPDX-License-Identifier: Apache-2.0
|
|
from __future__ import annotations
|
|
|
|
import numpy as np
|
|
|
|
from onnx.reference.ops._op_common_pool import CommonPool
|
|
|
|
|
|
class MaxPool(CommonPool):
|
|
def _run(
|
|
self,
|
|
x,
|
|
auto_pad=None,
|
|
ceil_mode=None,
|
|
dilations=None,
|
|
kernel_shape=None,
|
|
pads=None,
|
|
storage_order=None,
|
|
strides=None,
|
|
):
|
|
if (
|
|
dilations is not None
|
|
and (min(dilations) != max(dilations) or min(dilations) != 1)
|
|
) or (
|
|
strides is not None and (min(strides) != max(strides) or min(strides) != 1)
|
|
):
|
|
return self._max_pool(
|
|
x,
|
|
auto_pad=auto_pad,
|
|
ceil_mode=ceil_mode,
|
|
dilations=dilations,
|
|
kernel_shape=kernel_shape,
|
|
pads=pads,
|
|
storage_order=storage_order,
|
|
strides=strides,
|
|
)
|
|
|
|
return CommonPool._run(
|
|
self,
|
|
"MAX",
|
|
0,
|
|
x,
|
|
auto_pad=auto_pad,
|
|
ceil_mode=ceil_mode,
|
|
dilations=dilations,
|
|
kernel_shape=kernel_shape,
|
|
pads=pads,
|
|
storage_order=storage_order,
|
|
strides=strides,
|
|
)
|
|
|
|
def _max_pool(
|
|
self,
|
|
x,
|
|
auto_pad,
|
|
ceil_mode,
|
|
dilations,
|
|
kernel_shape,
|
|
pads,
|
|
storage_order,
|
|
strides,
|
|
):
|
|
if pads is None:
|
|
pads = [0 for i in range(len(kernel_shape) * 2)]
|
|
if strides is None:
|
|
strides = [1 for i in range(len(kernel_shape))]
|
|
if dilations is None:
|
|
dilations = [1 for i in range(len(kernel_shape))]
|
|
|
|
n_dims = len(kernel_shape)
|
|
new_pads = np.array([(pads[i], pads[i + n_dims]) for i in range(n_dims)])
|
|
|
|
input_spatial_shape = x.shape[2:]
|
|
output_spatial_shape = [0 for s in input_spatial_shape]
|
|
if ceil_mode:
|
|
for i in range(len(input_spatial_shape)):
|
|
output_spatial_shape[i] = int(
|
|
np.ceil(
|
|
(
|
|
input_spatial_shape[i]
|
|
+ new_pads[i].sum()
|
|
- ((kernel_shape[i] - 1) * dilations[i] + 1)
|
|
)
|
|
/ strides[i]
|
|
+ 1
|
|
)
|
|
)
|
|
need_to_reduce_out_size_in_ceil_mode = (
|
|
output_spatial_shape[i] - 1
|
|
) * strides[i] >= input_spatial_shape[i] + new_pads[i][0]
|
|
if need_to_reduce_out_size_in_ceil_mode:
|
|
output_spatial_shape[i] -= 1
|
|
else:
|
|
for i in range(len(input_spatial_shape)):
|
|
output_spatial_shape[i] = int(
|
|
np.floor(
|
|
(
|
|
input_spatial_shape[i]
|
|
+ new_pads[i].sum()
|
|
- ((kernel_shape[i] - 1) * dilations[i] + 1)
|
|
)
|
|
/ strides[i]
|
|
+ 1
|
|
)
|
|
)
|
|
|
|
if auto_pad and auto_pad != "NOTSET":
|
|
# Deprecated attribute
|
|
if auto_pad in ("SAME_UPPER", "SAME_LOWER"):
|
|
for i in range(len(input_spatial_shape)):
|
|
if auto_pad == "SAME_UPPER":
|
|
output_spatial_shape[i] = int(
|
|
np.ceil(input_spatial_shape[i] / strides[i])
|
|
)
|
|
else:
|
|
output_spatial_shape[i] = int(
|
|
np.floor(input_spatial_shape[i] / strides[i])
|
|
)
|
|
pad_i = (
|
|
(output_spatial_shape[i] - 1) * strides[i]
|
|
+ ((kernel_shape[i] - 1) * dilations[i] + 1)
|
|
- input_spatial_shape[i]
|
|
)
|
|
new_pads[i, 0] = pad_i // 2
|
|
new_pads[i, 1] = pad_i - new_pads[i, 0]
|
|
else:
|
|
for i in range(len(input_spatial_shape)):
|
|
output_spatial_shape[i] = int(
|
|
np.ceil(
|
|
(
|
|
input_spatial_shape[i]
|
|
- ((kernel_shape[i] - 1) * dilations[i] + 1)
|
|
+ 1
|
|
)
|
|
/ strides[i]
|
|
)
|
|
)
|
|
|
|
if len(input_spatial_shape) == 1:
|
|
return self._max_pool_1d(
|
|
x,
|
|
auto_pad,
|
|
ceil_mode,
|
|
dilations,
|
|
kernel_shape,
|
|
new_pads,
|
|
storage_order,
|
|
strides,
|
|
output_spatial_shape,
|
|
)
|
|
|
|
if len(input_spatial_shape) == 2:
|
|
return self._max_pool_2d(
|
|
x,
|
|
auto_pad,
|
|
ceil_mode,
|
|
dilations,
|
|
kernel_shape,
|
|
new_pads,
|
|
storage_order,
|
|
strides,
|
|
output_spatial_shape,
|
|
)
|
|
|
|
if len(input_spatial_shape) == 3:
|
|
return self._max_pool_3d(
|
|
x,
|
|
auto_pad,
|
|
ceil_mode,
|
|
dilations,
|
|
kernel_shape,
|
|
new_pads,
|
|
storage_order,
|
|
strides,
|
|
output_spatial_shape,
|
|
)
|
|
|
|
raise RuntimeError(f"Not implemented yet for shape {x.shape}.")
|
|
|
|
def _max_pool_1d(
|
|
self,
|
|
x,
|
|
auto_pad, # noqa: ARG002
|
|
ceil_mode, # noqa: ARG002
|
|
dilations,
|
|
kernel_shape,
|
|
new_pads,
|
|
storage_order, # noqa: ARG002
|
|
strides,
|
|
output_spatial_shape,
|
|
):
|
|
global_pooling = False
|
|
y_dims = x.shape[:2] + tuple(output_spatial_shape)
|
|
y = np.zeros(y_dims, dtype=x.dtype)
|
|
indices = np.full(y_dims, dtype=np.int64, fill_value=-1)
|
|
x_dims = x.shape
|
|
channels = x_dims[1]
|
|
height = x_dims[2]
|
|
pooled_height = y_dims[2]
|
|
total_channels = x_dims[0] * channels
|
|
stride_h = 1 if global_pooling else strides[0]
|
|
|
|
x_step = height
|
|
y_step = pooled_height
|
|
dilation_h = dilations[0]
|
|
|
|
X_data = x.ravel()
|
|
Y_data = y.ravel()
|
|
I_data = indices.ravel()
|
|
|
|
def iteration(c):
|
|
x_d = c * x_step
|
|
y_d = c * y_step
|
|
i_d = c * y_step
|
|
for ph in range(pooled_height):
|
|
hstart = ph * stride_h - new_pads[0, 0]
|
|
hend = hstart + kernel_shape[0] * dilation_h
|
|
Yh = None
|
|
h_index = -1
|
|
for h in range(hstart, hend, dilation_h):
|
|
if h < 0 or h >= height:
|
|
continue
|
|
if Yh is None or X_data[x_d + h] > Yh:
|
|
Yh = X_data[x_d + h]
|
|
h_index = h
|
|
Y_data[y_d + ph] = Yh
|
|
I_data[i_d + ph] = c * x_step + h_index
|
|
|
|
for c in range(total_channels):
|
|
iteration(c)
|
|
|
|
if len(self.output) == 1:
|
|
return (Y_data.reshape(y_dims),)
|
|
return (Y_data.reshape(y_dims), I_data.reshape(y_dims))
|
|
|
|
def _max_pool_2d(
|
|
self,
|
|
x,
|
|
auto_pad, # noqa: ARG002
|
|
ceil_mode, # noqa: ARG002
|
|
dilations,
|
|
kernel_shape,
|
|
new_pads,
|
|
storage_order,
|
|
strides,
|
|
output_spatial_shape,
|
|
):
|
|
global_pooling = False
|
|
y_dims = x.shape[:2] + tuple(output_spatial_shape)
|
|
y = np.zeros(y_dims, dtype=x.dtype)
|
|
indices = np.full(y_dims, dtype=np.int64, fill_value=-1)
|
|
x_dims = x.shape
|
|
channels = x_dims[1]
|
|
height = x_dims[2]
|
|
width = x_dims[3] if len(kernel_shape) > 1 else 1
|
|
pooled_height = y_dims[2]
|
|
pooled_width = y_dims[3] if len(kernel_shape) > 1 else 1
|
|
total_channels = x_dims[0] * channels
|
|
stride_h = 1 if global_pooling else strides[0]
|
|
stride_w = 1 if global_pooling else strides[1]
|
|
|
|
x_step = height * width
|
|
y_step = pooled_height * pooled_width
|
|
dilation_h = dilations[0]
|
|
dilation_w = dilations[1]
|
|
|
|
X_data = x.ravel()
|
|
Y_data = y.ravel()
|
|
I_data = indices.ravel()
|
|
|
|
def iteration(c):
|
|
x_d = c * x_step # X_data
|
|
y_d = c * y_step # Y_data
|
|
for ph in range(pooled_height):
|
|
hstart = ph * stride_h - new_pads[0, 0]
|
|
hend = hstart + kernel_shape[0] * dilation_h
|
|
for pw in range(pooled_width):
|
|
wstart = pw * stride_w - new_pads[1, 0]
|
|
wend = wstart + kernel_shape[1] * dilation_w
|
|
pool_index = ph * pooled_width + pw
|
|
Yh = None
|
|
h_index = -1
|
|
w_index = -1
|
|
for h in range(hstart, hend, dilation_h):
|
|
if h < 0 or h >= height:
|
|
continue
|
|
for w in range(wstart, wend, dilation_w):
|
|
if w < 0 or w >= width:
|
|
continue
|
|
input_index = h * width + w
|
|
if input_index < 0 or input_index > X_data.shape[0]:
|
|
continue
|
|
if Yh is None or X_data[x_d + input_index] > Yh:
|
|
Yh = X_data[x_d + input_index]
|
|
h_index = h
|
|
w_index = w
|
|
if Yh is None:
|
|
continue
|
|
Y_data[y_d + pool_index] = Yh
|
|
I_data[y_d + pool_index] = (
|
|
c * x_step + h_index * width + w_index
|
|
if storage_order == 0
|
|
else c * x_step + h_index + w_index * height
|
|
)
|
|
|
|
for c in range(total_channels):
|
|
iteration(c)
|
|
|
|
if len(self.output) == 1:
|
|
return (Y_data.reshape(y_dims),)
|
|
return (Y_data.reshape(y_dims), I_data.reshape(y_dims))
|
|
|
|
def _max_pool_3d(
|
|
self,
|
|
x,
|
|
auto_pad, # noqa: ARG002
|
|
ceil_mode, # noqa: ARG002
|
|
dilations,
|
|
kernel_shape,
|
|
new_pads,
|
|
storage_order,
|
|
strides,
|
|
output_spatial_shape,
|
|
):
|
|
global_pooling = False
|
|
y_dims = x.shape[:2] + tuple(output_spatial_shape)
|
|
y = np.zeros(y_dims, dtype=x.dtype)
|
|
indices = np.full(y_dims, dtype=np.int64, fill_value=-1)
|
|
x_dims = x.shape
|
|
channels = x_dims[1]
|
|
height = x_dims[2]
|
|
width = x_dims[3] if len(kernel_shape) > 1 else 1
|
|
depth = x_dims[4] if len(kernel_shape) > 2 else 1
|
|
pooled_height = y_dims[2]
|
|
pooled_width = y_dims[3] if len(kernel_shape) > 1 else 1
|
|
pooled_depth = y_dims[4] if len(kernel_shape) > 2 else 1
|
|
total_channels = x_dims[0] * channels
|
|
stride_h = 1 if global_pooling else strides[0]
|
|
stride_w = 1 if global_pooling else strides[1]
|
|
stride_d = 1 if global_pooling else strides[2]
|
|
|
|
x_step = height * width * depth
|
|
y_step = pooled_height * pooled_width * pooled_depth
|
|
dilation_h = dilations[0]
|
|
dilation_w = dilations[1]
|
|
dilation_d = dilations[2]
|
|
|
|
X_data = x.ravel()
|
|
Y_data = y.ravel()
|
|
I_data = indices.ravel()
|
|
|
|
def iteration(c):
|
|
x_d = c * x_step
|
|
y_d = c * y_step
|
|
i_d = c * y_step
|
|
|
|
for ph in range(pooled_height):
|
|
hstart = ph * stride_h - new_pads[0, 0]
|
|
hend = hstart + kernel_shape[0] * dilation_h
|
|
for pw in range(pooled_width):
|
|
wstart = pw * stride_w - new_pads[1, 0]
|
|
wend = wstart + kernel_shape[1] * dilation_w
|
|
for pd in range(pooled_depth):
|
|
dstart = pd * stride_d - new_pads[2, 0]
|
|
dend = dstart + kernel_shape[2] * dilation_d
|
|
pool_index = (
|
|
ph * pooled_width * pooled_depth + pw * pooled_depth + pd
|
|
)
|
|
Yh = None
|
|
h_index = -1
|
|
w_index = -1
|
|
d_index = -1
|
|
for h in range(hstart, hend, dilation_h):
|
|
if h < 0 or h >= height:
|
|
continue
|
|
for w in range(wstart, wend, dilation_w):
|
|
if w < 0 or w >= width:
|
|
continue
|
|
for d in range(dstart, dend, dilation_d):
|
|
if d < 0 or d >= depth:
|
|
continue
|
|
input_index = h * width * depth + w * depth + d
|
|
if Yh is None or X_data[x_d + input_index] > Yh:
|
|
Yh = X_data[x_d + input_index]
|
|
h_index = h
|
|
w_index = w
|
|
d_index = d
|
|
|
|
Y_data[y_d + pool_index] = Yh
|
|
I_data[i_d + pool_index] = (
|
|
(
|
|
c * x_step
|
|
+ h_index * width * depth
|
|
+ w_index * depth
|
|
+ d_index
|
|
)
|
|
if storage_order == 0
|
|
else (
|
|
c * x_step
|
|
+ h_index
|
|
+ w_index * height
|
|
+ d_index * height * width
|
|
)
|
|
)
|
|
|
|
for c in range(total_channels):
|
|
iteration(c)
|
|
|
|
if len(self.output) == 1:
|
|
return (Y_data.reshape(y_dims),)
|
|
return (Y_data.reshape(y_dims), I_data.reshape(y_dims))
|