From 4a6fb9bdb4188b53516f7df0fbaa3695cce76319 Mon Sep 17 00:00:00 2001 From: Jeremy Johnson Date: Tue, 26 Apr 2022 15:47:21 +0100 Subject: Update tensor ops ERROR_IF criteria Update to ref model to check ERROR_IF criteria for pooling and convolution ops to match specification Update to tosa_verif_build_tests to produce valid test ranges and new ERROR_IF tests Plus update pooling ops big kernel to 9 (from 6) for better testing coverage and set dilation to 1 and add out_pad bottom & right for transpose_conv2d to match specification Signed-off-by: Jeremy Johnson Change-Id: Ic5759872d40ae8d3f3d07043d9a0f2fa0244d72e --- reference_model/src/ops/tensor_ops.cc | 145 ++++++++++++++++++++++++++++------ 1 file changed, 122 insertions(+), 23 deletions(-) (limited to 'reference_model') diff --git a/reference_model/src/ops/tensor_ops.cc b/reference_model/src/ops/tensor_ops.cc index 02fdf01..4a56093 100644 --- a/reference_model/src/ops/tensor_ops.cc +++ b/reference_model/src/ops/tensor_ops.cc @@ -92,10 +92,22 @@ int check_pool2d_attribute(tosa::TosaPoolAttribute* attribute, return 1; } - if ((OH != (IH + pad_top + pad_bottom + stride_y - kernel_y) / stride_y) || - (OW != (IW + pad_left + pad_right + stride_x - kernel_x) / stride_x)) + int32_t full_H = IH + pad_top + pad_bottom - kernel_y; + int32_t full_W = IW + pad_left + pad_right - kernel_x; + + if ((full_H % stride_y != 0) || + (full_W % stride_x != 0)) { - msg = "Mismatch between output shape provided and expected output shape"; + msg = "Parameters must yield exact integer output dimensions"; + return 1; + } + + if ((OH != (full_H / stride_y) + 1) || + (OW != (full_W / stride_x) + 1)) + { + msg = "Mismatch between output shape provided and expected output shape (" + + std::to_string((full_H / stride_y) + 1) + "," + + std::to_string((full_W / stride_x) + 1) + ")"; return 1; } @@ -107,6 +119,8 @@ int check_conv_attribute_qinfo(tosa::TosaConvAttribute* attribute, uint32_t conv_dimension, std::vector input_shape, std::vector output_shape, + std::vector weights, + uint32_t offset_kernel, DType InDtype, DType WeightDtype, std::string& msg) @@ -156,6 +170,62 @@ int check_conv_attribute_qinfo(tosa::TosaConvAttribute* attribute, } } + ASSERT_MSG(conv_dimension == 2 || conv_dimension == 3, "Unsupported convolution dimension") + + int32_t offset_d = 1 ? conv_dimension == 3 : 0; + int32_t ID = conv_dimension == 3 ? input_shape[1] : 1; + int32_t IH = input_shape[1 + offset_d]; + int32_t IW = input_shape[2 + offset_d]; + int32_t OD = conv_dimension == 3 ? output_shape[1] : 1; + int32_t OH = output_shape[1 + offset_d]; + int32_t OW = output_shape[2 + offset_d]; + + int32_t stride_d = conv_dimension == 3 ? attribute->stride()[0] : 1; + int32_t stride_y = attribute->stride()[0 + offset_d]; + int32_t stride_x = attribute->stride()[1 + offset_d]; + int32_t kernel_d = conv_dimension == 3 ? weights[offset_kernel] : 1; + int32_t kernel_h = weights[offset_kernel + offset_d]; + int32_t kernel_w = weights[offset_kernel + 1 + offset_d]; + int32_t dilation_d = conv_dimension == 3 ? attribute->dilation()[0] : 1; + int32_t dilation_y = attribute->dilation()[0 + offset_d]; + int32_t dilation_x = attribute->dilation()[1 + offset_d]; + + offset_d *= 2; + int32_t pad_d0 = conv_dimension == 3 ? attribute->padding()[0] : 0; + int32_t pad_d1 = conv_dimension == 3 ? attribute->padding()[1] : 0; + int32_t pad_top = attribute->padding()[0 + offset_d]; + int32_t pad_bottom = attribute->padding()[1 + offset_d]; + int32_t pad_left = attribute->padding()[2 + offset_d]; + int32_t pad_right = attribute->padding()[3 + offset_d]; + + int32_t full_D = ID - 1 + pad_d0 + pad_d1 - (kernel_d - 1) * dilation_d; + int32_t full_H = IH - 1 + pad_top + pad_bottom - (kernel_h - 1) * dilation_y; + int32_t full_W = IW - 1 + pad_left + pad_right - (kernel_w - 1) * dilation_x; + + if ((full_H % stride_y != 0) || + (full_W % stride_x != 0) || + (full_D % stride_d != 0)) + { + msg = "Parameters must yield exact integer output dimensions"; + return 1; + } + + if ((OH != (full_H / stride_y) + 1) || + (OW != (full_W / stride_x) + 1) || + (OD != (full_D / stride_d) + 1)) + { + std::string msg_d = ""; + if (conv_dimension == 3) + { + msg_d += std::to_string((full_D / stride_d) + 1) + ","; + } + msg = "Mismatch between output shape provided and expected output shape (" + + msg_d + + std::to_string((full_H / stride_y) + 1) + "," + + std::to_string((full_W / stride_x) + 1) + ")"; + return 1; + } + if (qinfo) { if (InDtype != DType_INT8 && qinfo->input_zp() != 0) @@ -529,7 +599,7 @@ int OpConv2d::checkTensorAttributes() std::string msg; if (check_conv_attribute_qinfo(attribute, qinfo, 2 /* conv_dimension */, input->getShape(), output->getShape(), - InDtype, WeightDtype, msg)) + weight->getShape(), 1 /* offset_kernel */, InDtype, WeightDtype, msg)) { msg = "OpConv2d: " + msg; printNodeValidationError(msg.c_str()); @@ -715,7 +785,7 @@ int OpConv3d::checkTensorAttributes() std::string msg; if (check_conv_attribute_qinfo(attribute, qinfo, 3 /* conv_dimension */, input->getShape(), output->getShape(), - InDtype, WeightDtype, msg)) + weight->getShape(), 1 /* offset_kernel */, InDtype, WeightDtype, msg)) { msg = "OpConv3d: " + msg; printNodeValidationError(msg.c_str()); @@ -904,7 +974,7 @@ int OpDepthwiseConv2d::checkTensorAttributes() std::string msg; if (check_conv_attribute_qinfo(attribute, qinfo, 2 /* conv_dimension */, input->getShape(), output->getShape(), - InDtype, WeightDtype, msg)) + weight->getShape(), 0 /* offset_kernel */, InDtype, WeightDtype, msg)) { msg = "OpDepthwiseConv2d: " + msg; printNodeValidationError(msg.c_str()); @@ -1447,7 +1517,7 @@ int OpTransposeConv2d::checkTensorAttributes() bias = dynamic_cast*>(inputs[2]); output = dynamic_cast*>(outputs[0]); - if (attribute->outpad().size() != 2) + if (attribute->outpad().size() != 4) { printNodeValidationError("OpTransposeConv2d: illegal size for attribute outpad"); return 1; @@ -1489,11 +1559,12 @@ int OpTransposeConv2d::checkTensorAttributes() } } + // TODO: Remove dilation once schema updated for (int32_t i : attribute->dilation()) { - if (i < 1) + if (i != 1) { - printNodeValidationError("OpTransposeConv2d: At least one dilation is smaller than one"); + printNodeValidationError("OpTransposeConv2d: Dilation is deprecated and must be set to one"); return 1; } } @@ -1507,6 +1578,33 @@ int OpTransposeConv2d::checkTensorAttributes() } } + int32_t IH = input->getShape()[1]; + int32_t IW = input->getShape()[2]; + int32_t OH = output->getShape()[1]; + int32_t OW = output->getShape()[2]; + + int32_t stride_y = attribute->stride()[0]; + int32_t stride_x = attribute->stride()[1]; + int32_t kernel_h = weight->getShape()[1]; + int32_t kernel_w = weight->getShape()[2]; + + int32_t outpad_top = attribute->outpad()[0]; + int32_t outpad_bottom = attribute->outpad()[1]; + int32_t outpad_left = attribute->outpad()[2]; + int32_t outpad_right = attribute->outpad()[3]; + + int32_t H = (IH - 1) * stride_y - outpad_top - outpad_bottom + kernel_h; + int32_t W = (IW - 1) * stride_x - outpad_left - outpad_right + kernel_w; + + if ((OH != H) || (OW != W)) + { + std::string msg = "OpTransposeConv2d: Mismatch between output shape provided and expected output shape (" + + std::to_string(H) + "," + + std::to_string(W) + ")"; + printNodeValidationError(msg.c_str()); + return 1; + } + if (this->qinfo) { if (InDtype != DType_INT8) @@ -1542,12 +1640,13 @@ int OpTransposeConv2d::eval() int out_width = this->output->getShape()[2]; int out_channels = this->output->getShape()[3]; - int padding_top = this->attribute->outpad()[0]; - int padding_left = this->attribute->outpad()[1]; - int stride_h = this->attribute->stride()[0]; - int stride_w = this->attribute->stride()[1]; - int dilation_h = this->attribute->dilation()[0]; - int dilation_w = this->attribute->dilation()[1]; + int outpad_top = this->attribute->outpad()[0]; + int outpad_bottom = this->attribute->outpad()[1]; + int outpad_left = this->attribute->outpad()[2]; + int outpad_right = this->attribute->outpad()[3]; + + int stride_h = this->attribute->stride()[0]; + int stride_w = this->attribute->stride()[1]; ERROR_IF(in_batch != out_batch, "OpTransposeConv2d: tensor batch mismatch %d != %d", in_batch, out_batch); ERROR_IF(f_in_channels != in_channels, "OpTransposeConv2d: tensor input channel mismatch %d != %d", f_in_channels, @@ -1559,10 +1658,10 @@ int OpTransposeConv2d::eval() DEBUG_INFO(OP, "perform OpTransposeConv2d, input.shape=[%d,%d,%d,%d], weight.shape=[%d,%d,%d,%d], " - "output.shape=[%d,%d,%d,%d], stride=[%d,%d], dilation=[%d,%d], padding=[%d,%d]", - in_batch, in_height, in_width, in_channels, f_height, f_width, f_out_channels, f_in_channels, out_batch, - out_height, out_width, out_channels, stride_h, stride_w, dilation_h, dilation_w, padding_top, - padding_left); + "output.shape=[%d,%d,%d,%d], stride=[%d,%d], outpad=[%d,%d,%d,%d]", + in_batch, in_height, in_width, in_channels, f_height, f_width, f_out_channels, f_in_channels, + out_batch, out_height, out_width, out_channels, stride_h, stride_w, outpad_top, + outpad_bottom, outpad_left, outpad_right); TIn input_val = this->input->getTensor(); TWeight weight_val = this->weight->getTensor(); @@ -1595,16 +1694,16 @@ int OpTransposeConv2d::eval() { for (int iw = 0; iw < in_width; iw++) { - out_x_origin = iw * stride_w - padding_left; - out_y_origin = ih * stride_h - padding_top; + out_x_origin = iw * stride_w - outpad_left; + out_y_origin = ih * stride_h - outpad_top; for (int ic = 0; ic < in_channels; ic++) { for (int fh = 0; fh < f_height; fh++) { for (int fw = 0; fw < f_width; fw++) { - out_x = out_x_origin + fw * dilation_w; - out_y = out_y_origin + fh * dilation_h; + out_x = out_x_origin + fw; + out_y = out_y_origin + fh; for (int oc = 0; oc < out_channels; oc++) { if ((out_x >= 0 && out_x < out_width) && (out_y >= 0 && out_y < out_height)) -- cgit v1.2.1