MindSpore实现Grid_Sample方法

举报
江桃人 发表于 2022/11/30 19:23:23 2022/11/30
【摘要】 原理 一. 背景​ Grid_Sample方法由两个单词Grid(网格)和Sample(采样),顾名思义,此方法要做的工作就是根据给定的网格对原始数据进行采样。既然是根据网格采样,自然地,就需要给定:原始数据(被采样的数据),称其为input给定的归一化的网格(需要采样的点的坐标),称其为grid,点的取值为[-1, 1]采样所用的方法,称其为mode,包括但不限于:nearest(最近邻...

原理

一. 背景

​ Grid_Sample方法由两个单词Grid(网格)和Sample(采样),顾名思义,此方法要做的工作就是根据给定的网格对原始数据进行采样。既然是根据网格采样,自然地,就需要给定:

  1. 原始数据(被采样的数据),称其为input
  2. 给定的归一化的网格(需要采样的点的坐标),称其为grid,点的取值为[-1, 1]
  3. 采样所用的方法,称其为mode,包括但不限于:nearest(最近邻)、bilinear(双线性插值)等

​ 除以上三个参数外,也需要给定:

  1. 原始数据点的指定方式,即原始数据四角上的的点是否位于归一化网格的四个角上(比较绕,下面有图),称该参数为:align_corners
  2. 外部网格的填充方式,即当采样点位于原始数据外侧时(align_corners=False时可能出现),怎么给定边缘的点的值,该参数为:padding_mode

二. 计算过程

​ Grid_Sample采样大的分为网格化原始数据和采样两个部分,更详细的采样过程见附录:

  1. 网格化input,这里分align_corners为真和假两种情况。不失一般性,并为了描述清楚概念,假设这里input的大小为 h i n × w i n h_{in} \times w_{in} ,考虑高度为 h i n h_{in}^{'} ,宽度为 w i n w_{in}^{'} p i n p_{in} 的坐标,同时为了写代码方便,这里的高度 h i n h_{in}^{'} 定义为距离最上方的距离,宽度 w i n w_{in}^{'} 定义为距离最左边的距离 h i n ( 0 , 2 , . . . , h i n 1 ) h_{in}^{'} \in (0, 2, ..., h_{in}-1) w i n ( 0 , 2 , . . . , w i n 1 ) w_{in}^{'} \in (0, 2, ..., w_{in}-1)

grid_sample1.png

A. *align_corners=True*, 左上角点的坐标为(-1, -1),右下角的点的坐标为(1, 1),点$p_{in}$的坐标为$(\frac{2 \times w_{in}^{'}}{w_{in}-1}-1, \frac{2 \times h_{in}^{'}}{h_{in}-1}-1)$

B. *align_corners=False*,左上角点坐标为($\frac{1}{w_{in}}-1$, $\frac{1}{h_{in}}-1$),右下角的坐标为($1- \frac{1}{w_{in}}$, $1-\frac{1}{h_{in}}$),点$p_{in}$的坐标为$(\frac{2 \times w_{in}^{'}+1}{w_{in}}-1, \frac{2 \times h_{in}^{'}+1}{h_{in}}-1)$
  1. 寻找input中与grid采样点最近邻点的坐标,这里也要分align_corners为真和假两种情况。不失一般性,并为了描述清楚概念,这里仅考虑一个点且插值方法为双线性插值的情况,假设该采样点 p g p_{g} 的坐标为 ( x g , y g ) (x_{g}, y_{g})

    A. align_corners=True, 原始图像中,每相邻两个点之间的横坐标间隔 d x d_x 2 w i n 1 \frac{2}{w_{in}-1} ,纵坐标的间隔 d y d_y 2 h i n 1 \frac{2}{h_{in}-1}

    ​ a. 距离最左边的绝对距离 d l = x g + 1 d_{l}=x_{g}+1 ,距离最上面的绝对距离 d t = y g + 1 d_{t}=y_{g}+1

    ​ b. 距离最左边的间隔数 d δ l = d l d x d_{\delta_l}=\frac{d_l}{d_x} ,距离最上面的间隔数 d δ t = d t d y d_{\delta_t}=\frac{d_t}{d_y}

    ​ c. 易推得点 p g p_{g} 最近邻的左上方点 p t l p_{tl} 的坐标为 ( x t l , y t l ) = ( 2 × d δ l w i n 1 1 , 2 × d δ t h i n 1 1 ) (x_{tl}, y_{tl}) = (\frac{2 \times \lfloor d_{\delta_l} \rfloor} {w_{in} - 1} - 1, \frac{2 \times \lfloor d_{\delta_t} \rfloor} {h_{in} - 1} - 1) ,最近邻的左下方点 p b l p_{bl} 的坐标为 ( x b l , y b l ) = ( 2 × d δ l w i n 1 1 , 2 × d δ t h i n 1 1 ) (x_{bl}, y_{bl}) = (\frac{2 \times \lfloor d_{\delta_l} \rfloor} {w_{in} - 1} - 1, \frac{2 \times \lceil d_{\delta_t} \rceil} {h_{in} - 1} - 1) ,最近邻的右上方点 p t r p_{tr} 的坐标为 ( x t r , y t r ) = ( 2 × d δ l w i n 1 1 , 2 × d δ t h i n 1 1 ) (x_{tr}, y_{tr}) = (\frac{2 \times \lceil d_{\delta_l} \rceil} {w_{in} - 1} - 1, \frac{2 \times \lfloor d_{\delta_t} \rfloor} {h_{in} - 1} - 1) ,最近邻的右下方点 p b r p_{br} 的坐标为 ( x b r , y b r ) = ( 2 × d δ l w i n 1 1 , 2 × d δ t h i n 1 1 ) (x_{br}, y_{br}) = (\frac{2 \times \lceil d_{\delta_l} \rceil} {w_{in} - 1} - 1, \frac{2 \times \lceil d_{\delta_t} \rceil} {h_{in} - 1} - 1) ,在具体实现中求得点的坐标索引值即可,即 d δ l d_{\delta_l} d δ t d_{\delta_t} 的向上向下取整即可。

grid_sample2.png

二维情况下的python实现,(注:代码中以h向下为x,w向右为y,与上面描述略有差异)

```python
# 参照pytorch,grid->[w, h]
x_index, y_index = 1, 0
h_in, w_in = input.shape
d_x, d_y = 2 / (h_in - 1), 2 / (w_in -1)
# the given horizontal and vertical coordinates
x_g = grid[..., x_index]
y_g = grid[..., y_index]
# distance from the top/left
d_t, d_l = x_g + 1, y_g + 1
# how many pixels away from the top/left
d_delta_t, d_delta_l = d_t / d_x, d_l / d_y
x_t, y_l = np.floor(d_delta_t).astype(np.int), np.floor(d_delta_l).astype(np.int)
x_b, y_r = x_t + 1, y_l + 1
# obtain the nearest point
p_tl, p_tr, p_bl, p_br = input[x_t, y_l], input[x_t, y_r], input[x_b, y_l], input[x_b, y_r]
# weights are inversely proportional to distance
w_l, w_r, w_t, w_b = y_r - d_delta_l, d_delta_l - y_l, x_b - d_delta_t, d_delta_t - x_t
if mode == 'nearest':
    max_lr = np.concatenate((np.expand_dims(w_l, -1), np.expand_dims(w_r, -1)), -1).max(-1)
    max_tb = np.concatenate((np.expand_dims(w_t, -1), np.expand_dims(w_b, -1)), -1).max(-1)
    w_l, w_r = (max_lr - (w_l, w_r)) < 1e-8
    w_t, w_b = (max_tb - (w_t, w_b)) < 1e-8
w_tl, w_tr, w_bl, w_br = w_t * w_l, w_t * w_r, w_b * w_l, w_b * w_r
sample = p_tl * w_tl + p_tr * w_tr + p_bl * w_bl + p_br * w_br
```

考虑到越界(grid中坐标范围超过[-1, 1])的二维情况下的python实现,pad分不同情况:

```python
trans_pix = 0
if padding_mode == 'zeros':
    input = np.pad(input, ((1, 1), (1, 1)))
    trans_pix = 1
elif padding_mode == 'border':
    input = np.pad(input, ((1, 1), (1, 1)), 'edge')
    trans_pix = 1

h_in, w_in = input.shape
h_in, w_in = h_in - 2 * trans_pix, w_in - 2 * trans_pix
d_x, d_y = 2 / (h_in - 1), 2 / (w_in - 1)
# the given horizontal and vertical coordinates
x_g = grid[..., x_index]
y_g = grid[..., y_index]
# distance from the top/left
d_t, d_l = x_g + 1, y_g + 1
# how many pixels away from the far top/left
d_delta_t, d_delta_l = d_t / d_x, d_l / d_y
x_t, y_l = np.floor(d_delta_t).astype(np.int) + trans_pix, np.floor(d_delta_l).astype(np.int) + trans_pix
x_b, y_r = np.ceil(d_delta_t).astype(np.int) + trans_pix, np.ceil(d_delta_l).astype(np.int) + trans_pix
if padding_mode == 'zeros' or padding_mode == 'border':
    min_coordinate = np.zeros_like(x_t)
    x_t = np.concatenate((np.expand_dims(x_t, -1), np.expand_dims(min_coordinate, -1)), -1).max(-1)
    y_l = np.concatenate((np.expand_dims(y_l, -1), np.expand_dims(min_coordinate, -1)), -1).max(-1)
    x_b = np.concatenate((np.expand_dims(x_b, -1), np.expand_dims(min_coordinate, -1)), -1).max(-1)
    y_r = np.concatenate((np.expand_dims(y_r, -1), np.expand_dims(min_coordinate, -1)), -1).max(-1)
    max_coordinate_x = np.ones_like(x_t) * (h_in + trans_pix)
    x_t = np.concatenate((np.expand_dims(x_t, -1), np.expand_dims(max_coordinate_x, -1)), -1).min(-1)
    x_b = np.concatenate((np.expand_dims(x_b, -1), np.expand_dims(max_coordinate_x, -1)), -1).min(-1)
    max_coordinate_y = np.ones_like(x_t) * (w_in + trans_pix)
    y_l = np.concatenate((np.expand_dims(y_l, -1), np.expand_dims(max_coordinate_y, -1)), -1).min(-1)
    y_r = np.concatenate((np.expand_dims(y_r, -1), np.expand_dims(max_coordinate_y, -1)), -1).min(-1)
else:
    x_t, x_b, y_l, y_r = np.abs(x_t), np.abs(x_b), np.abs(y_l), np.abs(y_r)
    x_t, x_b = x_t % (2 *(h_in - 1)), x_b % (2 *(h_in - 1))
    y_l, y_r = y_l % (2 *(w_in - 1)), y_r % (2 * (w_in - 1))
    x_t_ref, x_b_ref = 2 * (h_in - 1) - x_t, 2 * (h_in - 1) - x_b
    y_l_ref, y_r_ref = 2 * (w_in - 1) - y_l, 2 * (w_in - 1) - y_r
    x_t = np.concatenate((np.expand_dims(x_t, -1), np.expand_dims(x_t_ref, -1)), -1).min(-1)
    x_b = np.concatenate((np.expand_dims(x_b, -1), np.expand_dims(x_b_ref, -1)), -1).min(-1)
    y_l = np.concatenate((np.expand_dims(y_l, -1), np.expand_dims(y_l_ref, -1)), -1).min(-1)
    y_r = np.concatenate((np.expand_dims(y_r, -1), np.expand_dims(y_r_ref, -1)), -1).min(-1)
# obtain the nearest point
p_tl, p_tr, p_bl, p_br = input[x_t, y_l], input[x_t, y_r], input[x_b, y_l], input[x_b, y_r]
# weights are inversely proportional to distance
w_l, w_r, w_t, w_b = np.abs(1.0 - d_delta_l % 1), np.abs(d_delta_l % 1), np.abs(1.0 - d_delta_t % 1), np.abs(d_delta_t % 1)
# w_l, w_r, w_t, w_b = y_r - d_delta_l, d_delta_l - y_l, x_b - d_delta_t, d_delta_t - x_t
if mode == 'nearest':
    max_lr = np.concatenate((np.expand_dims(w_l, -1), np.expand_dims(w_r, -1)), -1).max(-1)
    max_tb = np.concatenate((np.expand_dims(w_t, -1), np.expand_dims(w_b, -1)), -1).max(-1)
    w_l, w_r = (max_lr - (w_l, w_r)) < 1e-8
    w_t, w_b = (max_tb - (w_t, w_b)) < 1e-8
w_tl, w_tr, w_bl, w_br = w_t * w_l, w_t * w_r, w_b * w_l, w_b * w_r
sample = p_tl * w_tl + p_tr * w_tr + p_bl * w_bl + p_br * w_br
```



B. *align_corners=False*,原始图像中,每相邻两个点之间的横坐标间隔$d_x$为$\frac{2}{w_{in}}$,纵坐标的间隔$d_y$为$\frac{2}{h_{in}}$,相对于True的情况坐标轴整体向右下平移半个单位距离即可。

```python
def grid_sample_numpy(input, grid, mode=None, padding_mode=None, align_corners=None, grid_format='wh'):
    if mode is None:
        mode = 'bilinear'
    if align_corners is None:
        align_corners = True
    if padding_mode is None:
        padding_mode = 'zeros'
    dims_input = len(input.shape)

    assert mode in ['nearest', 'bilinear']
    assert padding_mode in ['zeros', 'border', 'reflection']
    assert dims_input in [2, 3, 4, 5]

    sample = None

    if grid_format == 'wh':
        x_index, y_index = 1, 0
    elif grid_format == 'hw':
        x_index, y_index = 0, 1

    trans_pix = 0
    if padding_mode == 'zeros':
        input = np.pad(input, ((1, 1), (1, 1)))
        trans_pix = 1
    elif padding_mode == 'border':
        input = np.pad(input, ((1, 1), (1, 1)), 'edge')
        trans_pix = 1

    # 2-D input
    if dims_input == 2:
        # origin input: 0->h->x, 1->w->y
        h_in, w_in = input.shape
        h_in, w_in = h_in - 2 * trans_pix, w_in - 2 * trans_pix
        if align_corners is True:
            d_x, d_y = 2 / (h_in - 1), 2 / (w_in - 1)
            x_0, y_0 = - 1, - 1
        else:
            d_x, d_y = 2 / h_in, 2 / w_in
            x_0, y_0 = d_x / 2 - 1, d_y / 2 - 1
        # the given horizontal and vertical coordinates
        x_g = grid[..., x_index]
        y_g = grid[..., y_index]
        # distance from the top/left
        d_t, d_l = x_g - x_0, y_g - y_0
        # how many pixels away from the far top/left
        d_delta_t, d_delta_l = d_t / d_x, d_l / d_y
        x_t, y_l = np.floor(d_delta_t).astype(np.int) + trans_pix, np.floor(d_delta_l).astype(np.int) + trans_pix
        x_b, y_r = np.ceil(d_delta_t).astype(np.int) + trans_pix, np.ceil(d_delta_l).astype(np.int) + trans_pix
        # Handle out-of-bounds grids
        if padding_mode == 'zeros' or padding_mode == 'border':
            min_coordinate = np.zeros_like(x_t)
            x_t = np.concatenate((np.expand_dims(x_t, -1), np.expand_dims(min_coordinate, -1)), -1).max(-1)
            y_l = np.concatenate((np.expand_dims(y_l, -1), np.expand_dims(min_coordinate, -1)), -1).max(-1)
            x_b = np.concatenate((np.expand_dims(x_b, -1), np.expand_dims(min_coordinate, -1)), -1).max(-1)
            y_r = np.concatenate((np.expand_dims(y_r, -1), np.expand_dims(min_coordinate, -1)), -1).max(-1)
            max_coordinate_x = np.ones_like(x_t) * (h_in + trans_pix)
            x_t = np.concatenate((np.expand_dims(x_t, -1), np.expand_dims(max_coordinate_x, -1)), -1).min(-1)
            x_b = np.concatenate((np.expand_dims(x_b, -1), np.expand_dims(max_coordinate_x, -1)), -1).min(-1)
            max_coordinate_y = np.ones_like(x_t) * (w_in + trans_pix)
            y_l = np.concatenate((np.expand_dims(y_l, -1), np.expand_dims(max_coordinate_y, -1)), -1).min(-1)
            y_r = np.concatenate((np.expand_dims(y_r, -1), np.expand_dims(max_coordinate_y, -1)), -1).min(-1)
        else:
            x_t, x_b, y_l, y_r = np.abs(x_t), np.abs(x_b), np.abs(y_l), np.abs(y_r)
            x_t, x_b = x_t % (2 * (h_in - 1)), x_b % (2 * (h_in - 1))
            y_l, y_r = y_l % (2 * (w_in - 1)), y_r % (2 * (w_in - 1))
            x_t_ref, x_b_ref = 2 * (h_in - 1) - x_t, 2 * (h_in - 1) - x_b
            y_l_ref, y_r_ref = 2 * (w_in - 1) - y_l, 2 * (w_in - 1) - y_r
            x_t = np.concatenate((np.expand_dims(x_t, -1), np.expand_dims(x_t_ref, -1)), -1).min(-1)
            x_b = np.concatenate((np.expand_dims(x_b, -1), np.expand_dims(x_b_ref, -1)), -1).min(-1)
            y_l = np.concatenate((np.expand_dims(y_l, -1), np.expand_dims(y_l_ref, -1)), -1).min(-1)
            y_r = np.concatenate((np.expand_dims(y_r, -1), np.expand_dims(y_r_ref, -1)), -1).min(-1)
        # obtain the nearest point
        p_tl, p_tr, p_bl, p_br = input[x_t, y_l], input[x_t, y_r], input[x_b, y_l], input[x_b, y_r]
        # weights are inversely proportional to distance
        w_l, w_r, w_t, w_b = 1.0 - np.abs(d_delta_l % 1), np.abs(d_delta_l % 1), 1.0 - np.abs(
            d_delta_t % 1), np.abs(d_delta_t % 1)
        # interpolation method
        if mode == 'nearest':
            max_lr = np.concatenate((np.expand_dims(w_l, -1), np.expand_dims(w_r, -1)), -1).max(-1)
            max_tb = np.concatenate((np.expand_dims(w_t, -1), np.expand_dims(w_b, -1)), -1).max(-1)
            w_l, w_t = (max_lr - w_l) < 1e-8, (max_tb - w_t) < 1e-8
            w_r, w_b = 1 - w_l, 1 - w_t
        w_tl, w_tr, w_bl, w_br = w_t * w_l, w_t * w_r, w_b * w_l, w_b * w_r
        sample = p_tl * w_tl + p_tr * w_tr + p_bl * w_bl + p_br * w_br
    return sample
```
  1. 采样。二维情况下,双线性插值采样,假设距离左右上下整数像素点的距离依次为 d l d_l d r d_r d t d_t d b d_b ,则左右上下依次在最后采样中所占的权重与他们的距离成反比,依次为 w l w_l , w r w_r , w t w_t , w b w_b ,四个像素所占的权重依次为 w t l , w t r , w b l , w b r = w t w l , w t w r , w b w l , w b w r w_{tl}, w_{tr}, w_{bl}, w_{br} = w_t * w_l, w_t * w_r, w_b * w_l, w_b * w_r ,采样值为 s a m p l e = p t l w t l + p t r w t r + p b l w b l + p b r w b r sample = p_{tl} * w_{tl} + p_{tr} * w_{tr} + p_{bl} * w_{bl} + p_{br} * w_{br}

附完整代码:
`import copy
import numpy as np
import mindspore.numpy as mnp
import mindspore
from mindspore import context, ops, nn
from mindspore import Tensor as M_Tensor
import torch
context.set_context(mode=context.PYNATIVE_MODE, device_target=‘GPU’, device_id=0)

class Grid_Sample(nn.Cell):
pass

def grid_sample_numpy(input, grid, mode=None, padding_mode=None, align_corners=None, grid_format=‘wh’):
if mode is None:
mode = ‘bilinear’
if align_corners is None:
align_corners = True
if padding_mode is None:
padding_mode = ‘zeros’
dims_input = len(input.shape)

assert mode in ['nearest', 'bilinear']
assert padding_mode in ['zeros', 'border', 'reflection']
assert dims_input in [2, 3, 4, 5]

sample = None

if grid_format == 'wh':
    x_index, y_index = 1, 0
elif grid_format == 'hw':
    x_index, y_index = 0, 1

# 2-D input
if dims_input == 2 or dims_input == 3:
    trans_pix = 0
    if padding_mode == 'zeros':
        if dims_input == 2:
            input = np.pad(input, ((1, 1), (1, 1)))
        elif dims_input == 3:
            input = np.pad(input, ((0, 0), (1, 1), (1, 1)))
        trans_pix = 1
    elif padding_mode == 'border':
        if dims_input == 2:
            input = np.pad(input, ((1, 1), (1, 1)), 'edge')
        elif dims_input == 3:
            input = np.pad(input, ((0, 0), (1, 1), (1, 1)), 'edge')
        trans_pix = 1
    # origin input: 0->h->x, 1->w->y
    if dims_input == 2:
        h_in, w_in = input.shape
    elif dims_input == 3:
        c_in, h_in, w_in = input.shape
    h_in, w_in = h_in - 2 * trans_pix, w_in - 2 * trans_pix
    if align_corners is True:
        d_x, d_y = 2 / (h_in - 1), 2 / (w_in - 1)
        x_0, y_0 = - 1, - 1
    else:
        d_x, d_y = 2 / h_in, 2 / w_in
        x_0, y_0 = d_x / 2 - 1, d_y / 2 - 1
    # the given horizontal and vertical coordinates
    x_g = grid[..., x_index]
    y_g = grid[..., y_index]
    # distance from the top/left
    d_t, d_l = x_g - x_0, y_g - y_0
    # how many pixels away from the far top/left
    d_delta_t, d_delta_l = d_t / d_x, d_l / d_y
    x_t, y_l = np.floor(d_delta_t).astype(np.int) + trans_pix, np.floor(d_delta_l).astype(np.int) + trans_pix
    x_b, y_r = np.ceil(d_delta_t).astype(np.int) + trans_pix, np.ceil(d_delta_l).astype(np.int) + trans_pix
    # Handle out-of-bounds grids
    if padding_mode == 'zeros' or padding_mode == 'border':
        min_coordinate = np.zeros_like(x_t)
        x_t = np.concatenate((np.expand_dims(x_t, -1), np.expand_dims(min_coordinate, -1)), -1).max(-1)
        y_l = np.concatenate((np.expand_dims(y_l, -1), np.expand_dims(min_coordinate, -1)), -1).max(-1)
        x_b = np.concatenate((np.expand_dims(x_b, -1), np.expand_dims(min_coordinate, -1)), -1).max(-1)
        y_r = np.concatenate((np.expand_dims(y_r, -1), np.expand_dims(min_coordinate, -1)), -1).max(-1)
        max_coordinate_x = np.ones_like(x_t) * (h_in + trans_pix)
        x_t = np.concatenate((np.expand_dims(x_t, -1), np.expand_dims(max_coordinate_x, -1)), -1).min(-1)
        x_b = np.concatenate((np.expand_dims(x_b, -1), np.expand_dims(max_coordinate_x, -1)), -1).min(-1)
        max_coordinate_y = np.ones_like(x_t) * (w_in + trans_pix)
        y_l = np.concatenate((np.expand_dims(y_l, -1), np.expand_dims(max_coordinate_y, -1)), -1).min(-1)
        y_r = np.concatenate((np.expand_dims(y_r, -1), np.expand_dims(max_coordinate_y, -1)), -1).min(-1)
    else:
        x_t, x_b, y_l, y_r = np.abs(x_t), np.abs(x_b), np.abs(y_l), np.abs(y_r)
        x_t, x_b = x_t % (2 * (h_in - 1)), x_b % (2 * (h_in - 1))
        y_l, y_r = y_l % (2 * (w_in - 1)), y_r % (2 * (w_in - 1))
        x_t_ref, x_b_ref = 2 * (h_in - 1) - x_t, 2 * (h_in - 1) - x_b
        y_l_ref, y_r_ref = 2 * (w_in - 1) - y_l, 2 * (w_in - 1) - y_r
        x_t = np.concatenate((np.expand_dims(x_t, -1), np.expand_dims(x_t_ref, -1)), -1).min(-1)
        x_b = np.concatenate((np.expand_dims(x_b, -1), np.expand_dims(x_b_ref, -1)), -1).min(-1)
        y_l = np.concatenate((np.expand_dims(y_l, -1), np.expand_dims(y_l_ref, -1)), -1).min(-1)
        y_r = np.concatenate((np.expand_dims(y_r, -1), np.expand_dims(y_r_ref, -1)), -1).min(-1)
    # obtain the nearest point
    p_tl, p_tr, p_bl, p_br = input[..., x_t, y_l], input[..., x_t, y_r], input[..., x_b, y_l], input[..., x_b, y_r]
    # weights are inversely proportional to distance
    w_l, w_r, w_t, w_b = 1.0 - np.abs(d_delta_l % 1), np.abs(d_delta_l % 1), 1.0 - np.abs(
        d_delta_t % 1), np.abs(d_delta_t % 1)
    # interpolation method
    if mode == 'nearest':
        max_lr = np.concatenate((np.expand_dims(w_l, -1), np.expand_dims(w_r, -1)), -1).max(-1)
        max_tb = np.concatenate((np.expand_dims(w_t, -1), np.expand_dims(w_b, -1)), -1).max(-1)
        w_l, w_t = (max_lr - w_l) < 1e-8, (max_tb - w_t) < 1e-8
        w_r, w_b = 1 - w_l, 1 - w_t
    w_tl, w_tr, w_bl, w_br = w_t * w_l, w_t * w_r, w_b * w_l, w_b * w_r
    sample = p_tl * w_tl + p_tr * w_tr + p_bl * w_bl + p_br * w_br
return sample

def cal_np(input, grid, mode, padding_mode, align_corners):
return grid_sample_numpy(input, grid, mode, padding_mode, align_corners)

def cal_torch(input, grid, mode, padding_mode, align_corners):
input = torch.from_numpy(input)
grid = torch.from_numpy(grid)
dims_input = len(input.shape)
if dims_input == 2:
h_in, w_in = input.shape
h_out, w_out, _ = grid.shape
input = input.reshape(1, 1, h_in, w_in)
grid = grid.reshape(1, h_out, w_out, 2)
out = torch.nn.functional.grid_sample(input, grid, mode, padding_mode, align_corners)
out = out.reshape(h_out, w_out)
elif dims_input == 3:
c_in, h_in, w_in = input.shape
h_out, w_out, _ = grid.shape
input = input.reshape(1, c_in, h_in, w_in)
grid = grid.reshape(1, h_out, w_out, 2)
out = torch.nn.functional.grid_sample(input, grid, mode, padding_mode, align_corners)
out = out.reshape(c_in, h_out, w_out)
out = out.numpy()
return out

def normalize_grid(grid, range=(-1, 1)):
max = grid.max()
min = grid.min()
grid = (range[1] - range[0]) * (grid - min) / (max - min) + range[0]
return grid

def generate_data(dims):
if dims == 2:
a, b, c, d, e, f, g, h, i, j = 1, 2, 3, 4, 5, 6, 7, 8, 9, 10
k, l, m, n, o, p, q, s, t, u = 11, 12, 13, 14, 15, 16, 17, 18, 19, 20
input = [[a, b, c, d, e], [f, g, h, i, j], [k, l, m, n, o], [p, q, s, t, u]]
input = np.array(input).astype(np.float32)
grid = np.random.random((1, 1, 2)).astype(np.float32)
grid = normalize_grid(grid)
# 0:w, 1:h
index_w, index_h = 0, 1
# d_w, d_h = 2 / 5, 2 / 4
# w_0, h_0 = d_w - 1, d_h - 1
grid[0][0][index_w] = 1
grid[0][0][index_h] = -1
if dims == 3:
c_in, h_in, w_in = 3, 20, 30
input = np.random.random((c_in, h_in, w_in)).astype(np.float32)
grid = np.random.random((2, 1, 2)).astype(np.float32)
grid = normalize_grid(grid)
return input, grid

def tst_grid_sample(input, grid, mode, padding_mode, align_corners):
print(’================================’)
print(mode, align_corners, padding_mode)
torch_grid_sample = cal_torch(input, grid, mode, padding_mode, align_corners)
np_grid_sample = cal_np(input, grid, mode, padding_mode, align_corners)

difference = np.abs(torch_grid_sample - np_grid_sample) > 1e-5
if np.max(difference) == True:
    print('failure, for more details as followings:')
    print('torch', torch_grid_sample[difference])
    print('numpy', np_grid_sample[difference])
    # print('grid', grid[difference])
else:
    print('success')

if name == ‘main’:
dims_lst = [2, 3]
mode_lst = [‘nearest’, ‘bilinear’]
align_corners_lst = [True, False]
# ‘border’ ‘border’, ‘zeros’
padding_mode_lst = [‘border’, ‘zeros’, ‘reflection’]

for dims in dims_lst:
    input, grid = generate_data(dims=dims)
    for mode in mode_lst:
        for align_corners in align_corners_lst:
            for padding_mode in padding_mode_lst:
                tst_grid_sample(input, grid, mode, padding_mode, align_corners)

`

【版权声明】本文为华为云社区用户原创内容,转载时必须标注文章的来源(华为云社区)、文章链接、文章作者等基本信息, 否则作者和本社区有权追究责任。如果您发现本社区中有涉嫌抄袭的内容,欢迎发送邮件进行举报,并提供相关证据,一经查实,本社区将立刻删除涉嫌侵权内容,举报邮箱: cloudbbs@huaweicloud.com
  • 点赞
  • 收藏
  • 关注作者

评论(0

0/1000
抱歉,系统识别当前为高风险访问,暂不支持该操作

全部回复

上滑加载中

设置昵称

在此一键设置昵称,即可参与社区互动!

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。