Skip to content

Commit 61b56d7

Browse files
author
cheng wen
committed
add sum and globalavgpool op
1 parent 7ac03ca commit 61b56d7

File tree

9 files changed

+425
-10
lines changed

9 files changed

+425
-10
lines changed

include/tvm/relax/attrs/nn.h

Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -371,6 +371,28 @@ struct Pool3DAttrs : public tvm::AttrsNode<Pool3DAttrs> {
371371
}
372372
}; // struct Pool3dAttrs
373373

374+
/*! \brief Attributes for 1d adaptive pool operator */
375+
struct AdaptivePool1DAttrs : public tvm::AttrsNode<AdaptivePool1DAttrs> {
376+
Optional<Array<IntImm>> output_size;
377+
String layout;
378+
String out_layout;
379+
380+
TVM_DECLARE_ATTRS(AdaptivePool1DAttrs, "relax.attrs.AdaptivePool1DAttrs") {
381+
TVM_ATTR_FIELD(output_size).describe("Output width.");
382+
TVM_ATTR_FIELD(layout).describe(
383+
"Dimension ordering of input data. Can be 'NCW', 'NWC', etc."
384+
"'N', 'C', 'W' stands for batch, channel and width"
385+
"dimensions respectively. Pooling is applied on the"
386+
"'W' dimensions.");
387+
TVM_ATTR_FIELD(out_layout)
388+
.describe(
389+
"Dimension ordering of output data. Can be 'NCW', 'NWC', etc."
390+
"'N', 'C', 'W' stands for batch, channel and width"
391+
"dimensions respectively. Pooling is applied on the"
392+
"'W' dimensions.");
393+
}
394+
}; // struct AdaptivePool1DAttrs
395+
374396
/*! \brief Attributes for 2d adaptive pool operator */
375397
struct AdaptivePool2DAttrs : public tvm::AttrsNode<AdaptivePool2DAttrs> {
376398
Optional<Array<IntImm>> output_size;
@@ -393,6 +415,28 @@ struct AdaptivePool2DAttrs : public tvm::AttrsNode<AdaptivePool2DAttrs> {
393415
}
394416
}; // struct AdaptivePool2DAttrs
395417

418+
/*! \brief Attributes for 3d adaptive pool operator */
419+
struct AdaptivePool3DAttrs : public tvm::AttrsNode<AdaptivePool3DAttrs> {
420+
Optional<Array<IntImm>> output_size;
421+
String layout;
422+
String out_layout;
423+
424+
TVM_DECLARE_ATTRS(AdaptivePool3DAttrs, "relax.attrs.AdaptivePool3DAttrs") {
425+
TVM_ATTR_FIELD(output_size).describe("Output depth, height and width.");
426+
TVM_ATTR_FIELD(layout).describe(
427+
"Dimension ordering of input data. Can be 'NCDHW', 'NDHWC', etc."
428+
"'N', 'C', 'D', 'H', 'W' stands for batch, channel, depth, height, and width"
429+
"dimensions respectively. Pooling is applied on 'D', 'H' and"
430+
"'W' dimensions.");
431+
TVM_ATTR_FIELD(out_layout)
432+
.describe(
433+
"Dimension ordering of output data. Can be 'NCDHW', 'NDHWC', etc."
434+
"'N', 'C', 'D', 'H', 'W' stands for batch, channel, depth, height, and width"
435+
"dimensions respectively. Pooling is applied on 'D', 'H' and"
436+
"'W' dimensions.");
437+
}
438+
}; // struct AdaptivePool3DAttrs
439+
396440
/*! \brief Attributes used in softmax operators */
397441
struct SoftmaxAttrs : public tvm::AttrsNode<SoftmaxAttrs> {
398442
int axis;

python/tvm/relax/frontend/onnx/onnx_frontend.py

Lines changed: 23 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -399,6 +399,17 @@ def _impl_v13(cls, bb, inputs, attr, params):
399399
return relax.op.add(inputs[0], inputs[1])
400400

401401

402+
class Sum(OnnxOpConverter):
403+
"""Convert an onnx Sum node into an equivalent Relax expression."""
404+
405+
@classmethod
406+
def _impl_v1(cls, bb, inputs, attr, params):
407+
for in_index in range(len(inputs) - 1):
408+
inputs[in_index + 1] = relax.op.add(inputs[in_index], inputs[in_index + 1])
409+
410+
return inputs[len(inputs) - 1]
411+
412+
402413
class Mul(OnnxOpConverter):
403414
"""Convert an onnx Mul node into an equivalent Relax expression."""
404415

@@ -1538,7 +1549,17 @@ class GlobalAveragePool(OnnxOpConverter):
15381549

15391550
@classmethod
15401551
def _impl_v1(cls, bb, inputs, attr, params):
1541-
return relax.op.nn.adaptive_avg_pool2d(inputs[0], 1)
1552+
rank = len(inputs[0].struct_info.shape)
1553+
if rank == 3:
1554+
return relax.op.nn.adaptive_avg_pool1d(inputs[0], 1)
1555+
elif rank == 4:
1556+
return relax.op.nn.adaptive_avg_pool2d(inputs[0], 1)
1557+
elif rank == 5:
1558+
return relax.op.nn.adaptive_avg_pool3d(inputs[0], 1)
1559+
raise NotImplementedError(
1560+
"Global average pooling is only implemented for 1D, 2D, and 3D kernels, got %dD."
1561+
% (rank - 2)
1562+
)
15421563

15431564

15441565
class Flatten(OnnxOpConverter):
@@ -1899,6 +1920,7 @@ def _get_convert_map():
18991920
"Add": Add,
19001921
"Mul": Mul,
19011922
"Cast": Cast,
1923+
"Sum": Sum,
19021924
"Gather": Gather,
19031925
"Gemm": Gemm,
19041926
"Reshape": Reshape,

python/tvm/relax/op/nn/__init__.py

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,9 @@
1616
# under the License.
1717
"""Neural network related operators."""
1818
from .nn import (
19+
adaptive_avg_pool1d,
1920
adaptive_avg_pool2d,
21+
adaptive_avg_pool3d,
2022
attention,
2123
attention_var_len,
2224
avg_pool1d,

python/tvm/relax/op/nn/nn.py

Lines changed: 109 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1043,6 +1043,59 @@ def avg_pool3d(
10431043
)
10441044

10451045

1046+
def adaptive_avg_pool1d(
1047+
data: Expr,
1048+
output_size: Optional[Union[int, Tuple[int]]] = None,
1049+
layout: str = "NCW",
1050+
out_layout: Optional[str] = None,
1051+
) -> Expr:
1052+
r"""1D adaptive average pooling operator. This operator is experimental.
1053+
1054+
This operator takes data as input and does 1D average value calculation
1055+
across each window represented by W.
1056+
1057+
1058+
In the default case, where the data_layout is `NCW`
1059+
a data Tensor with shape `(batch_size, in_channels, width)`,
1060+
to produce an output Tensor with shape
1061+
(batch_size, in_channels, output_width).
1062+
1063+
The pooling kernel and stride sizes are automatically chosen for
1064+
desired output sizes.
1065+
1066+
For output_size:
1067+
If this argument is not provided, input height and width will be used
1068+
as output width.
1069+
1070+
If a single integer is provided for output_size, the output size is
1071+
(N x C x output_size) for any input (NCW).
1072+
1073+
Parameters
1074+
----------
1075+
data : relax.Expr
1076+
The input data to the operator.
1077+
1078+
output_size : Optional[Union[int, Tuple[int, int]]]
1079+
Output height and width.
1080+
If not specified, it will be the same as the input height and width.
1081+
If specified, it is required to have length either 1 or 2.
1082+
1083+
layout : str
1084+
Layout of the input.
1085+
1086+
out_layout : Optional[str]
1087+
Layout of the output. If not specified, it is the same as data_layout
1088+
1089+
Returns
1090+
-------
1091+
result : relax.Expr
1092+
The computed result.
1093+
"""
1094+
if isinstance(output_size, int):
1095+
output_size = (output_size,)
1096+
return _ffi_api.adaptive_avg_pool1d(data, output_size, layout, out_layout) # type: ignore
1097+
1098+
10461099
def adaptive_avg_pool2d(
10471100
data: Expr,
10481101
output_size: Optional[Union[int, Tuple[int, int]]] = None,
@@ -1099,6 +1152,62 @@ def adaptive_avg_pool2d(
10991152
return _ffi_api.adaptive_avg_pool2d(data, output_size, layout, out_layout) # type: ignore
11001153

11011154

1155+
def adaptive_avg_pool3d(
1156+
data: Expr,
1157+
output_size: Optional[Union[int, Tuple[int, int]]] = None,
1158+
layout: str = "NCDHW",
1159+
out_layout: Optional[str] = None,
1160+
) -> Expr:
1161+
r"""3D adaptive average pooling operator. This operator is experimental.
1162+
1163+
This operator takes data as input and does 3D average value calculation
1164+
across each window represented by WxH.
1165+
1166+
1167+
In the default case, where the data_layout is `NCDHW`
1168+
a data Tensor with shape `(batch_size, in_channels, depth, height, width)`,
1169+
to produce an output Tensor with shape
1170+
(batch_size, in_channels, output_depth, output_height, output_width).
1171+
1172+
The pooling kernel and stride sizes are automatically chosen for
1173+
desired output sizes.
1174+
1175+
For output_size:
1176+
If this argument is not provided, input depth, height and width will be used
1177+
as output depth, height and width.
1178+
1179+
If a single integer is provided for output_size, the output size is
1180+
(N x C x output_size x output_size x output_size) for any input (NCDHW).
1181+
1182+
If a tuple of integers (depth, height, width) are provided for output_size,
1183+
the output size is (N x C x depth x height x width) for any input (NCDHW).
1184+
1185+
Parameters
1186+
----------
1187+
data : relax.Expr
1188+
The input data to the operator.
1189+
1190+
output_size : Optional[Union[int, Tuple[int, int]]]
1191+
Output height and width.
1192+
If not specified, it will be the same as the input height and width.
1193+
If specified, it is required to have length either 1 or 3.
1194+
1195+
layout : str
1196+
Layout of the input.
1197+
1198+
out_layout : Optional[str]
1199+
Layout of the output. If not specified, it is the same as data_layout
1200+
1201+
Returns
1202+
-------
1203+
result : relax.Expr
1204+
The computed result.
1205+
"""
1206+
if isinstance(output_size, int):
1207+
output_size = (output_size, output_size, output_size)
1208+
return _ffi_api.adaptive_avg_pool3d(data, output_size, layout, out_layout) # type: ignore
1209+
1210+
11021211
def relu(data: Expr) -> Expr:
11031212
r"""Rectified linear unit.
11041213

python/tvm/relax/transform/legalize_ops/nn.py

Lines changed: 56 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -382,6 +382,33 @@ def _nn_avg_pool3d(bb: BlockBuilder, call: Call) -> Expr:
382382
)
383383

384384

385+
@register_legalize("relax.nn.adaptive_avg_pool1d")
386+
def _nn_adaptive_avg_pool1d(bb: BlockBuilder, call: Call) -> Expr:
387+
if call.attrs.out_layout != call.attrs.layout:
388+
logging.info(
389+
"TOPI adaptive_avg_pool1d does not support different input-output "
390+
"layouts, and thus cannot be legalized by TOPI"
391+
)
392+
return call
393+
394+
def te_adaptive_avg_pool1d(data, output_size, layout_str):
395+
if output_size is None:
396+
layout = tir.layout(layout_str)
397+
idx_W = layout.index_of("W")
398+
assert idx_W != -1
399+
output_size = data.shape[idx_W]
400+
401+
return topi.nn.adaptive_pool1d(data, output_size, "avg", layout_str)
402+
403+
return bb.call_te(
404+
te_adaptive_avg_pool1d,
405+
call.args[0],
406+
call.attrs.output_size,
407+
call.attrs.layout,
408+
primfunc_name_hint="adaptive_avg_pool1d",
409+
)
410+
411+
385412
@register_legalize("relax.nn.adaptive_avg_pool2d")
386413
def _nn_adaptive_avg_pool2d(bb: BlockBuilder, call: Call) -> Expr:
387414
if call.attrs.out_layout != call.attrs.layout:
@@ -410,6 +437,35 @@ def te_adaptive_avg_pool2d(data, output_size, layout_str):
410437
)
411438

412439

440+
@register_legalize("relax.nn.adaptive_avg_pool3d")
441+
def _nn_adaptive_avg_pool3d(bb: BlockBuilder, call: Call) -> Expr:
442+
if call.attrs.out_layout != call.attrs.layout:
443+
logging.info(
444+
"TOPI adaptive_avg_pool3d does not support different input-output "
445+
"layouts, and thus cannot be legalized by TOPI"
446+
)
447+
return call
448+
449+
def te_adaptive_avg_pool3d(data, output_size, layout_str):
450+
if output_size is None:
451+
layout = tir.layout(layout_str)
452+
idx_D = layout.index_of("D")
453+
idx_H = layout.index_of("H")
454+
idx_W = layout.index_of("W")
455+
assert idx_D != -1 and idx_H != -1 and idx_W != -1
456+
output_size = (data.shape[idx_D], data.shape[idx_H], data.shape[idx_W])
457+
458+
return topi.nn.adaptive_pool3d(data, output_size, "avg", layout_str)
459+
460+
return bb.call_te(
461+
te_adaptive_avg_pool3d,
462+
call.args[0],
463+
call.attrs.output_size,
464+
call.attrs.layout,
465+
primfunc_name_hint="adaptive_avg_pool3d",
466+
)
467+
468+
413469
register_legalize("relax.nn.relu", _call_topi_without_attr(topi.nn.relu))
414470

415471

python/tvm/topi/nn/pooling.py

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -169,6 +169,13 @@ def adaptive_pool(data, output_size, pool_type, layout="NCHW"):
169169
return cpp.nn.adaptive_pool(data, output_size, POOL_TYPE_CODE[pool_type], layout)
170170

171171

172+
def adaptive_pool1d(data, output_size, pool_type, layout="NCW"):
173+
"""Perform pooling on three dimensional data.
174+
See the two dimensional version above for details.
175+
"""
176+
return cpp.nn.adaptive_pool1d(data, output_size, POOL_TYPE_CODE[pool_type], layout)
177+
178+
172179
def adaptive_pool3d(data, output_size, pool_type, layout="NCDHW"):
173180
"""Perform pooling on three dimensional data.
174181
See the two dimensional version above for details.

0 commit comments

Comments
 (0)