// // This confidential and proprietary software may be used only as // authorised by a licensing agreement from ARM Limited // (C) COPYRIGHT 2020-2021 ARM Limited // ALL RIGHTS RESERVED // The entire notice above must be reproduced on all authorised // copies and copies may only be made to the extent permitted // by a licensing agreement from ARM Limited. === Image Operators ==== RESIZE Resizes a tensor. Resize is only allowed in the H and W dimensions. 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 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 stride_y = ( (IH-1) * (1<= 16384); 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) { 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)) { iy = (int32_t)apply_floor(y); dy = y - (resize_t)iy; ix = (int32_t)apply_floor(x); dx = x - (resize_t)ix; } else { iy = y >> shift; dy = y - (iy<> shift; dx = x - (ix<(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) { 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); } } ---- *Supported Data Types:* |=== |Profile|Mode|resize_t|in_t|out_t |Any|signed 8, bilinear|int16_t|int8_t|int32_t |Any|signed 8, nearest |int16_t|int8_t|int8_t |Any|signed 16, bilinear|int16_t|int16_t|int48_t |Any|signed 16, nearest |int16_t|int16_t|int16_t |MI,MT|fp16|fp32_t|fp16_t|fp16_t |MI,MT|bf16|fp32_t|bf16_t|bf16_t |MI,MT|fp32|fp32_t|fp32_t|fp32_t |=== *Resize Modes:* |=== |Mode|Description |NEAREST|Nearest Neighbor |BILINEAR|Bilinear interpoloation |===