// // 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 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). 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); 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); 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; } else { dy = y - iy * scale_y_n; dx = y - ix * scale_x_n; } // Note that -1 <= iy < IH and -1 <= ix < IW int16_t iy0 = apply_max(iy, 0); int16_t iy1 = apply_min(iy+1, IH-1); int16_t ix0 = apply_max(ix, 0); int16_t ix1 = apply_min(ix+1, IW-1); if (mode==BILINEAR) { in_t v00 = tensor_read(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; 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]); 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 |===