def forward(self, inputs):
    xp = cuda.get_array_module(*inputs)
    (gy,) = inputs
    (B, C, H, W, D) = self.input_shape
    u_1d = xp.linspace(0, (W - 1), num=self.out_W)
    v_1d = xp.linspace(0, (H - 1), num=self.out_H)
    t_1d = xp.linspace(0, (D - 1), num=self.out_D)
    grid = xp.meshgrid(u_1d, v_1d, t_1d)
    u = grid[0].ravel()
    v = grid[1].ravel()
    t = grid[2].ravel()
    u0 = xp.floor(u).astype(numpy.int32)
    u0 = u0.clip(0, (W - 2))
    u1 = (u0 + 1)
    v0 = xp.floor(v).astype(numpy.int32)
    v0 = v0.clip(0, (H - 2))
    v1 = (v0 + 1)
    t0 = xp.floor(t).astype(numpy.int32)
    t0 = t0.clip(0, (D - 2))
    t1 = (t0 + 1)
    wu0 = (u - u0)
    wu1 = (u1 - u)
    wv0 = (v - v0)
    wv1 = (v1 - v)
    wt0 = (t - t0)
    wt1 = (t1 - t)
    wu0 = wu0.astype(gy.dtype)
    wu1 = wu1.astype(gy.dtype)
    wv0 = wv0.astype(gy.dtype)
    wv1 = wv1.astype(gy.dtype)
    wt0 = wt0.astype(gy.dtype)
    wt1 = wt1.astype(gy.dtype)
    if (xp is numpy):
        scatter_add = numpy.add.at
    else:
        scatter_add = cuda.cupyx.scatter_add
    gx = xp.zeros(self.input_shape, dtype=gy.dtype)
    gy = gy.reshape(B, C, (- 1))
    scatter_add(gx, (slice(None), slice(None), v0, u0, t0), (((gy * wu1) * wv1) * wt1))
    scatter_add(gx, (slice(None), slice(None), v0, u1, t0), (((gy * wu0) * wv1) * wt1))
    scatter_add(gx, (slice(None), slice(None), v1, u0, t0), (((gy * wu1) * wv0) * wt1))
    scatter_add(gx, (slice(None), slice(None), v1, u1, t0), (((gy * wu0) * wv0) * wt1))
    scatter_add(gx, (slice(None), slice(None), v0, u0, t1), (((gy * wu1) * wv1) * wt0))
    scatter_add(gx, (slice(None), slice(None), v0, u1, t1), (((gy * wu0) * wv1) * wt0))
    scatter_add(gx, (slice(None), slice(None), v1, u0, t1), (((gy * wu1) * wv0) * wt0))
    scatter_add(gx, (slice(None), slice(None), v1, u1, t1), (((gy * wu0) * wv0) * wt0))
    return (gx,)
def forward(self, inputs):
    xp = cuda.get_array_module(*inputs)
    (gy,) = inputs
    (B, C, H, W, D) = self.input_shape
    u_1d = xp.linspace(0, (W - 1), num=self.out_W)
    v_1d = xp.linspace(0, (H - 1), num=self.out_H)
    t_1d = xp.linspace(0, (D - 1), num=self.out_D)
    grid = xp.meshgrid(u_1d, v_1d, t_1d)
    u = grid[0].ravel()
    v = grid[1].ravel()
    t = grid[2].ravel()
    u0 = xp.floor(u).astype(numpy.int32)
    u0 = u0.clip(0, (W - 2))
    u1 = (u0 + 1)
    v0 = xp.floor(v).astype(numpy.int32)
    v0 = v0.clip(0, (H - 2))
    v1 = (v0 + 1)
    t0 = xp.floor(t).astype(numpy.int32)
    t0 = t0.clip(0, (D - 2))
    t1 = (t0 + 1)
    wu0 = (u - u0)
    wu1 = (u1 - u)
    wv0 = (v - v0)
    wv1 = (v1 - v)
    wt0 = (t - t0)
    wt1 = (t1 - t)
    wu0 = wu0.astype(gy.dtype)
    wu1 = wu1.astype(gy.dtype)
    wv0 = wv0.astype(gy.dtype)
    wv1 = wv1.astype(gy.dtype)
    wt0 = wt0.astype(gy.dtype)
    wt1 = wt1.astype(gy.dtype)
    if (xp is numpy):
        scatter_add = numpy.add.at
    else:
        scatter_add = cuda.cupyx.scatter_add
    gx = xp.zeros(self.input_shape, dtype=gy.dtype)
    gy = gy.reshape(B, C, (- 1))
    scatter_add(gx, (slice(None), slice(None), v0, u0, t0), (((gy * wu1) * wv1) * wt1))
    scatter_add(gx, (slice(None), slice(None), v0, u1, t0), (((gy * wu0) * wv1) * wt1))
    scatter_add(gx, (slice(None), slice(None), v1, u0, t0), (((gy * wu1) * wv0) * wt1))
    scatter_add(gx, (slice(None), slice(None), v1, u1, t0), (((gy * wu0) * wv0) * wt1))
    scatter_add(gx, (slice(None), slice(None), v0, u0, t1), (((gy * wu1) * wv1) * wt0))
    scatter_add(gx, (slice(None), slice(None), v0, u1, t1), (((gy * wu0) * wv1) * wt0))
    scatter_add(gx, (slice(None), slice(None), v1, u0, t1), (((gy * wu1) * wv0) * wt0))
    scatter_add(gx, (slice(None), slice(None), v1, u1, t1), (((gy * wu0) * wv0) * wt0))
    return (gx,)