From 4c6b3d8058af46b930f882686e776f9e72c3f6db Mon Sep 17 00:00:00 2001 From: Eric Kunze Date: Thu, 16 Jun 2022 12:21:31 -0700 Subject: Revert RESIZE behvior to the 0.23 version The current version does not match the reference model or serialization library. Revert to the old behavior until the model is updated and tested that it works correctly. Signed-off-by: Eric Kunze Change-Id: I237dc3e94e6c31337073524527da75084ba7b578 --- chapters/image.adoc | 134 ++++++++++++++++++++++++---------------------------- 1 file changed, 63 insertions(+), 71 deletions(-) diff --git a/chapters/image.adoc b/chapters/image.adoc index 690480c..6f1d3cc 100644 --- a/chapters/image.adoc +++ b/chapters/image.adoc @@ -13,40 +13,34 @@ Resizes a tensor. Resize is only allowed in the H and W dimensions. -The height dimension is scaled by factor (scale_y_n/scale_y_d). -The width dimension is scaled by factor (scale_x_n/scale_x_d). - The NEAREST_NEIGHBOR mode returns the value of the input tensor closest to the calculated sample position for both floating-point and integer data formats. Floating-point BILINEAR mode returns a bilinearly interpolated output value based on the four closest input sample positions. -For integer BILINEAR interpolation mode, the output value must -be scaled by 1/(scale_y_n * scale_x_n) in a following operation to -complete the interpolation (for example with a RESCALE operator). +For integer BILINEAR interpolation mode, the output value is calculated by using +the shift value along with the other parameters to create a fixed point scaling +factor for each input. These values are then summed to create the value for +output, which has 2 * shift fractional bits. To convert back to the original +integer size, the output value must be rescaled. The following examples show practical uses of the parameters: * For approximate uniform input sampling between (0, 0) and (IH-1, IW-1) set -** scale_y_n/scale_y_d = (OH-1)/(IH-1) as integer ratios -** scale_x_n/scale_x_d = (OW-1)/(IW-1) as integer ratios -** offset_x = 0, offset_y = 0, border_x = 0, border_y = 0 - -* For power of two upscale [OH-1,OW-1] = (1<= 16384); -ERROR_IF(scale_y_n <= 0 || scale_y_d <=0 || scale_x_n <=0 || scale_x_d <=0); -// if in_t=int8_t ensure that an int32_t accumulator can be used -ERROR_IF(scale_y_n > (1<<11) || scale_x_n > (1<<11)); -// set a consistent lower limit of 1/16 downscale to simplify implementations -ERROR_IF(scale_y_d >= 16 * scale_y_n || scale_x_d >= 16 * scale_x_n); -ERROR_IF(offset_y < -scale_y_n || offset_y >= 16*scale_y_n); -ERROR_IF(offset_x < -scale_x_n || offset_x >= 16*scale_x_n); -ERROR_IF(border_y < -16*scale_y_n || border_y >= scale_y_n); -ERROR_IF(border_x < -16*scale_x_n || border_x >= scale_x_n); -ERROR_IF(OH != idiv_check((IH-1)*scale_y_n - offset_y + border_y, scale_y_d) + 1); -ERROR_IF(OW != idiv_check((IW-1)*scale_x_n - offset_x + border_x, scale_x_d) + 1); +ERROR_IF(stride_x <= 0 || stride_y <= 0); +if (is_floating_point(resize_t)) { + // The shift attribute is not used for floating point + ERROR_IF(shift != 0); + ERROR_IF(stride_x > IW || stride_y > IH); +} else { + // if in_t=int8_t ensure that an int32_t accumulator can be used + ERROR_IF(shift < 1 || shift > 11); + // set a consistent lower limit of 1/16 downscale + // independent of the shift value to simplify implementations + ERROR_IF(stride_x >= (16 << shift)); + ERROR_IF(stride_y >= (16 << shift)); + // offset range is similarly limited to maximum 16 pixels irrespective + // of shift. Both stride and offset fit in int16_t when shift=11. + ERROR_IF(offset_x <= (-16 << shift) || offset_x >= (16 << shift)); + ERROR_IF(offset_y <= (-16 << shift) || offset_y >= (16 << shift)); +} for_each(0 <= n < N, 0 <= oy < OH, 0 <= ox < OW; 0 <= c < C) { - out_t acc; - resize_t dx, dy; - - int32_t y = oy * scale_y_d + offset_y; - int32_t x = ox * scale_x_d + offset_x; - int16_t iy = floor(y / scale_y_n); - int16_t ix = floor(x / scale_x_n); - + unit = (is_floating_point(resize_t)) ? 1.0 : (1 << shift); + y = oy * stride_y + offset_y; + x = ox * stride_x + offset_x; if (is_floating_point(resize_t)) { - dy = ((resize_t)y / (resize_t)scale_y_n) - iy; - dx = ((resize_t)x / (resize_t)scale_x_n) - ix; + iy = (int32_t)apply_floor(y); dy = y - (resize_t)iy; + ix = (int32_t)apply_floor(x); dx = x - (resize_t)ix; } else { - dy = y - iy * scale_y_n; - dx = y - ix * scale_x_n; + iy = y >> shift; dy = y - (iy<> shift; dx = x - (ix<(input, [N,IH,IW,C], [n,iy0,ix0,c]); - in_t v01 = tensor_read(input, [N,IH,IW,C], [n,iy0,ix1,c]); - in_t v10 = tensor_read(input, [N,IH,IW,C], [n,iy1,ix0,c]); - in_t v11 = tensor_read(input, [N,IH,IW,C], [n,iy1,ix1,c]); - acc = v00 * (scale_y_n - dy) * (scale_x_n - dx); - acc += v01 * (scale_y_n - dy) * dx; - acc += v10 * dy * (scale_x_n - dx); - acc += v11 * dy * dx; + v00 = tensor_read(input, [N,IH,IW,C], [n,iy0,ix0,c]); + v01 = tensor_read(input, [N,IH,IW,C], [n,iy0,ix1,c]); + v10 = tensor_read(input, [N,IH,IW,C], [n,iy1,ix0,c]); + v11 = tensor_read(input, [N,IH,IW,C], [n,iy1,ix1,c]); + out_t acc = v00 * (unit - dy) * (unit - dx) + v01 * (unit - dy) * dx; + acc = acc + v10 * dy * (unit-dx) + v11 * dy * dx; tensor_write(output, [N,OH,OW,C], [n,oy,ox,c], acc); } else if (mode==NEAREST) { - int32_t iy, ix; - if (is_floating_point(resize_t)) { - iy = (dy >= 0.5) ? iy1 : iy0; - ix = (dx >= 0.5) ? ix1 : ix0; - } else { - iy = (2*dy >= scale_y_n) ? iy1 : iy0; - ix = (2*dx >= scale_x_n) ? ix1 : ix0; - } - in_t v = tensor_read(input, [N,IH,IW,C], [n,iy,ix,c]); + iy = (dy >= unit/2) ? iy1 : iy0; + ix = (dx >= unit/2) ? ix1 : ix0; + v = tensor_read(input, [N,IH,IW,C], [n,iy,ix,c]); tensor_write(output, [N,OH,OW,C], [n,oy,ox,c], v); } } -- cgit v1.2.1