Add local_bound attribute support to conv ops
This includes both respecting the local_bound attribute in the reference
model and generating tests with local_bound=True and local_bound=False
for floating point types. For non-floating point types, we always set it
to False.
Signed-off-by: IanTayler <ian.taylerlessa@arm.com>
Change-Id: Ifa47b6df31b9142835f48da00b595b89c7082734
diff --git a/reference_model/src/ops/tensor_ops.cc b/reference_model/src/ops/tensor_ops.cc
index f38f486..28d54fd 100644
--- a/reference_model/src/ops/tensor_ops.cc
+++ b/reference_model/src/ops/tensor_ops.cc
@@ -744,18 +744,24 @@
weight_val = weight_val - (WeightEigenType)attribute->weight_zp();
}
- ETensor4<InEigenType> input_padded = input_val.pad(pad);
-
TBias bias_val = this->bias->getTensor();
if (g_func_config.abs_mode)
{
// in abs_mode: take abs values of conv operands
- input_padded = input_padded.abs();
- weight_val = weight_val.abs();
- bias_val = bias_val.abs();
+ input_val = input_val.abs();
+ weight_val = weight_val.abs();
+ bias_val = bias_val.abs();
+
+ if (!this->attribute->local_bound())
+ {
+ Eigen::Tensor<InEigenType, 0> input_abs_max = input_val.maximum();
+ input_val.setConstant(input_abs_max(0));
+ }
}
+ ETensor4<InEigenType> input_padded = input_val.pad(pad);
+
// extract_image_patches() output [N, KH, KW, H * W, C]
// need to transpose to [N, H * W, KH, KW, C]
ETensor5<InEigenType> input_extract_patches =
@@ -938,18 +944,24 @@
weight_val = weight_val - (WeightEigenType)attribute->weight_zp();
}
- ETensor5<InEigenType> input_padded = input_val.pad(pad);
-
TBias bias_val = this->bias->getTensor();
if (g_func_config.abs_mode)
{
// in abs_mode: take abs values of conv operands
- input_padded = input_padded.abs();
- weight_val = weight_val.abs();
- bias_val = bias_val.abs();
+ input_val = input_val.abs();
+ weight_val = weight_val.abs();
+ bias_val = bias_val.abs();
+
+ if (!this->attribute->local_bound())
+ {
+ Eigen::Tensor<InEigenType, 0> input_abs_max = input_val.maximum();
+ input_val.setConstant(input_abs_max(0));
+ }
}
+ ETensor5<InEigenType> input_padded = input_val.pad(pad);
+
// 1. initialize with bias
Eigen::array<Eigen::Index, 5> reshape_dim;
reshape_dim.fill(1);
@@ -1140,18 +1152,24 @@
weight_val = weight_val - (WeightEigenType)attribute->weight_zp();
}
- ETensor4<InEigenType> input_padded = input_val.pad(pad);
-
TBias bias_val = this->bias->getTensor();
if (g_func_config.abs_mode)
{
// in abs_mode: take abs values of conv operands
- input_padded = input_padded.abs();
- weight_val = weight_val.abs();
- bias_val = bias_val.abs();
+ input_val = input_val.abs();
+ weight_val = weight_val.abs();
+ bias_val = bias_val.abs();
+
+ if (!this->attribute->local_bound())
+ {
+ Eigen::Tensor<InEigenType, 0> input_abs_max = input_val.maximum();
+ input_val.setConstant(input_abs_max(0));
+ }
}
+ ETensor4<InEigenType> input_padded = input_val.pad(pad);
+
// GEMM doesn't fit well with DepthwiseConv2d
// 1. use extract_image_patches() to handle stride/dilation/pad
// 2. perform direct convolution
@@ -2078,6 +2096,12 @@
input_val = input_val.abs();
weight_val = weight_val.abs();
bias_val = bias_val.abs();
+
+ if (!this->attribute->local_bound())
+ {
+ Eigen::Tensor<InEigenType, 0> input_abs_max = input_val.maximum();
+ input_val.setConstant(input_abs_max(0));
+ }
}
Eigen::array<Eigen::Index, 4> reshape_dim;
diff --git a/verif/conformance/test_select.py b/verif/conformance/test_select.py
index e3f1738..76f0160 100644
--- a/verif/conformance/test_select.py
+++ b/verif/conformance/test_select.py
@@ -555,21 +555,48 @@
"""Test selector for the CONV2D operator."""
name = "conv2d"
- param_names = ["kernel", "shape", "type", "accum_type", "stride", "pad", "dilation"]
+ param_names = [
+ "kernel",
+ "shape",
+ "type",
+ "accum_type",
+ "stride",
+ "pad",
+ "dilation",
+ "local_bound",
+ ]
class Conv3dOperator(Operator):
"""Test selector for the CONV3D operator."""
name = "conv3d"
- param_names = ["kernel", "shape", "type", "accum_type", "stride", "pad", "dilation"]
+ param_names = [
+ "kernel",
+ "shape",
+ "type",
+ "accum_type",
+ "stride",
+ "pad",
+ "dilation",
+ "local_bound",
+ ]
class DepthwiseConv2dOperator(Operator):
"""Test selector for the DEPTHWISE_CONV2D operator."""
name = "depthwise_conv2d"
- param_names = ["kernel", "shape", "type", "accum_type", "stride", "pad", "dilation"]
+ param_names = [
+ "kernel",
+ "shape",
+ "type",
+ "accum_type",
+ "stride",
+ "pad",
+ "dilation",
+ "local_bound",
+ ]
class DimOeprator(Operator):
@@ -953,6 +980,7 @@
"stride",
"pad",
"out_shape",
+ "local_bound",
]
def path_params(self, path):
diff --git a/verif/generator/tosa_arg_gen.py b/verif/generator/tosa_arg_gen.py
index 6f130a8..c2407ab 100644
--- a/verif/generator/tosa_arg_gen.py
+++ b/verif/generator/tosa_arg_gen.py
@@ -2364,6 +2364,10 @@
dots = gtu.product(
(ifm_shape[0], *outputs, filter_shape[0])
)
+ if gtu.dtypeIsFloat(dtypes[0]):
+ local_bound = rng.choice((False, True))
+ else:
+ local_bound = False
args_dict = {
"acc_type": a,
"stride": s,
@@ -2373,17 +2377,19 @@
"ks": k_size,
"dot_products": dots,
"shape": ifm_shape,
+ "local_bound": local_bound,
}
# Support for larger values than 9 needs different delimiter
delim = "" if max(s + p + d) <= 9 else "x"
arg_list.append(
(
- "acc{}_st{}_pad{}_dilat{}".format(
+ "acc{}_st{}_pad{}_dilat{}_lclbnd{}".format(
testGen.typeStr(a),
delim.join([str(x) for x in s]),
delim.join([str(x) for x in p]),
delim.join([str(x) for x in d]),
+ "1" if local_bound else "0",
),
args_dict,
)
@@ -2620,6 +2626,11 @@
ow = (ifm_shape[2] - 1) * s[1] + p[2] + p[3] + k_shape[1]
os = [ifm_shape[0], oh, ow, filter_shape[0]]
+ if gtu.dtypeIsFloat(dtypes[0]):
+ local_bound = rng.choice((False, True))
+ else:
+ local_bound = False
+
# N*OH*OW*OC
dots = gtu.product((ifm_shape[0], oh, ow, filter_shape[0]))
args_dict = {
@@ -2631,17 +2642,19 @@
"dot_products": dots,
"shape": ifm_shape,
"out_shape": os,
+ "local_bound": local_bound,
}
# Support for larger values than 9 needs different delimiter
delim = "" if max(s + p) <= 9 else "x"
arg_list.append(
(
- "acc{}_st{}_pad{}_os{}".format(
+ "acc{}_st{}_pad{}_os{}_lclbnd{}".format(
testGen.typeStr(a),
delim.join([str(x) for x in s]),
delim.join([str(x) for x in p]),
"x".join([str(x) for x in os]),
+ "1" if local_bound else "0",
),
args_dict,
)
diff --git a/verif/generator/tosa_test_gen.py b/verif/generator/tosa_test_gen.py
index 2db094a..482e8f8 100644
--- a/verif/generator/tosa_test_gen.py
+++ b/verif/generator/tosa_test_gen.py
@@ -860,6 +860,7 @@
strides = args_dict["stride"]
padding = args_dict["pad"]
dilations = args_dict["dilation"]
+ local_bound = args_dict["local_bound"]
assert len(padding) == 4
result_tensor = OutputShaper.conv2dOp(
@@ -916,9 +917,6 @@
):
return None
- # TODO - Test local_bound, for now set local bound attribute to False
- local_bound = False
-
attr = ts.TosaSerializerAttribute()
attr.ConvAttribute(
padding, strides, dilations, qinfo[0], qinfo[1], local_bound, accum_dtype
@@ -948,6 +946,7 @@
strides = args_dict["stride"]
padding = args_dict["pad"]
dilations = args_dict["dilation"]
+ local_bound = args_dict["local_bound"]
assert len(padding) == 6
result_tensor = OutputShaper.conv3dOp(
@@ -1004,9 +1003,6 @@
):
return None
- # TODO - Test local_bound, for now set local bound attribute to False
- local_bound = False
-
attr = ts.TosaSerializerAttribute()
attr.ConvAttribute(
padding, strides, dilations, qinfo[0], qinfo[1], local_bound, accum_dtype
@@ -1035,6 +1031,7 @@
accum_dtype = args_dict["acc_type"]
strides = args_dict["stride"]
out_pad = args_dict["pad"]
+ local_bound = args_dict["local_bound"]
assert len(out_pad) == 4
result_tensor = OutputShaper.transposeConv2DOp(
@@ -1082,9 +1079,6 @@
):
return None
- # TODO - Test local_bound, for now set local bound attribute to False
- local_bound = False
-
attr = ts.TosaSerializerAttribute()
attr.TransposeConvAttribute(
out_pad, strides, qinfo[0], qinfo[1], local_bound, accum_dtype
@@ -1114,6 +1108,7 @@
strides = args_dict["stride"]
padding = args_dict["pad"]
dilations = args_dict["dilation"]
+ local_bound = args_dict["local_bound"]
result_tensor = OutputShaper.depthwiseConv2dOp(
self.ser,
@@ -1169,9 +1164,6 @@
):
return None
- # TODO - Test local_bound, for now set local bound attribute to False
- local_bound = False
-
attr = ts.TosaSerializerAttribute()
attr.ConvAttribute(
padding, strides, dilations, qinfo[0], qinfo[1], local_bound, accum_dtype