Skip to content
Closed
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Next Next commit
Initial implementation of Deformable Convolution workload
  • Loading branch information
AlexanderKalistratov committed Jun 27, 2023
commit a595aeaa065f3106d3e743e11889cef2241b90da
1 change: 1 addition & 0 deletions dpbench/benchmarks/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ add_subdirectory(rambo)
add_subdirectory(kmeans)
add_subdirectory(knn)
add_subdirectory(gpairs)
add_subdirectory(deformable_convolution)
add_subdirectory(dbscan)

# generate dpcpp version into config
Expand Down
1 change: 1 addition & 0 deletions dpbench/benchmarks/deformable_convolution/CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
add_subdirectory(deformable_convolution_sycl_native_ext)
37 changes: 37 additions & 0 deletions dpbench/benchmarks/deformable_convolution/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
# Copyright 2022 Intel Corporation
#
# SPDX-License-Identifier: Apache 2.0

from .deformable_convolution_initialize import initialize
from .deformable_convolution_numba_npr import deformable_convolution as deformable_convolution_numba_npr
from .deformable_convolution_numpy import deformable_convolution as deformable_convolution_numpy
from .deformable_convolution_sycl_native_ext import deformable_convolution_sycl

__all__ = [
"initialize",
"deformable_convolution_numba_npr",
"deformable_convolution_numba_numpy",
"deformable_convolution_sycl",
]

"""l2-norm calculation of n vectors

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Comments need to be added for this workload


Input
---------
npoints: int
number of vectors
dims: int
dimension of single vector
seed: int
random seed to generate random number

Output
-------
d: array
l2 norm of each vector

Method
------
||Vj||2=sqrt(sum(Xj[i]*Xj[i]))
here i is 0->dims, j is 0->npoints
"""
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
# Copyright 2022 Intel Corp.
#
# SPDX-License-Identifier: Apache-2.0


def initialize(batch,
in_channels, in_height, in_width,
out_channels, out_height, out_width,
kernel_height, kernel_width,
stride_y, stride_x,
dilation_y, dilation_x,
pad_y, pad_x,
groups,
deformable_groups,
dtype,
seed):
import numpy as np
import numpy.random as default_rng
default_rng.seed(seed)

return (
default_rng.random((batch, in_channels, in_height, in_width)).astype(dtype),
# np.ones((batch, in_channels, in_height, in_width)).astype(dtype),

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please cleanup commented out code.

np.zeros((batch, out_channels, out_height, out_width)).astype(dtype),
# np.zeros((kernel_height, kernel_width, 2, out_height, out_width)).astype(dtype),
2*default_rng.random((kernel_height, kernel_width, 2, out_height, out_width)).astype(dtype) - 1,
# default_rng.random((out_channels, in_channels, kernel_height, kernel_width)).astype(dtype),
np.ones((out_channels, in_channels, kernel_height, kernel_width)).astype(dtype),
default_rng.random(out_channels).astype(dtype),
# np.ones((out_channels,)).astype(dtype),
np.zeros((in_channels, kernel_height, kernel_width, out_height, out_width)).astype(dtype)
)
Original file line number Diff line number Diff line change
@@ -0,0 +1,81 @@
# Copyright 2022 Intel Corp.
#
# SPDX-License-Identifier: Apache-2.0

import math
import numpy as np
from numba import njit, prange

@njit(parallel=True, inline='always', fastmath=True)
def bilinear(input, offset_y, offset_x):
height, width = input.shape
start_x = int(math.floor(offset_x))
start_x_weight = 1 - (offset_x - start_x)
start_y = int(math.floor(offset_y))
start_y_weight = 1 - (offset_y - start_y)

output = 0
if offset_x >= width or offset_y >= height or offset_x <= -1 or offset_y <= -1:
return output

if start_x >= 0 and start_y >= 0:
w = start_x_weight*start_y_weight
output += w*input[start_y, start_x]

if start_x + 1 < width and start_y >= 0:
w = (1 - start_x_weight)*start_y_weight
output += w*input[start_y, start_x + 1]

if start_x >=0 and start_y + 1 < height:
w = start_x_weight*(1 - start_y_weight)
output += w*input[start_y + 1, start_x]

if start_x + 1 < width and start_y + 1 < height:
w = (1 - start_x_weight)*(1 - start_y_weight)
output += w*input[start_y + 1, start_x + 1]

return output

@njit(parallel=True, fastmath=True)
def deform(input, offset, output, stride, pad, dilation, groups, deformable_groups):
k_height, k_width, _, out_height, out_width = offset.shape
channels, _, _ = input.shape

k_h_m = (k_height - 1)//2
k_w_m = (k_width - 1)//2

for ckhkw in prange(channels*k_height*k_width):
for h in prange(out_height):
for w in prange(out_width):
c = ckhkw//(k_height*k_width)
khkw = ckhkw%(k_height*k_width)
kh = khkw//k_width
kw = khkw%k_width

offset_y = offset[kh, kw, 1, h, w] + h*stride[0] + (kh - k_h_m)*dilation[0] - (pad[0] - k_h_m)
offset_x = offset[kh, kw, 0, h, w] + w*stride[1] + (kw - k_w_m)*dilation[1] - (pad[1] - k_w_m)

output[c, kh, kw, h, w] = bilinear(input[c], offset_y, offset_x)

@njit(parallel=True, fastmath=True)
def deformable_convolution_b1(input, output, offset, weights, bias, tmp, stride, pad, dilation, groups, deformable_groups):
out_channels, height, width = output.shape
_, in_channels, k_height, k_width = weights.shape

deform(input, offset, tmp, stride, pad, dilation, groups, deformable_groups)

tmp = tmp.reshape((in_channels*k_height*k_width, height*width))

_weights = weights.reshape((out_channels, in_channels*k_height*k_width))
_output = output.reshape((out_channels, height*width))
np.dot(_weights, tmp, _output)

_bias = bias.reshape((out_channels, 1))
_output[:] = _output + _bias

@njit(parallel=True)
def deformable_convolution(input, output, offset, weights, bias, tmp, stride_y, stride_x, pad_y, pad_x, dilation_y, dilation_x, groups, deformable_groups):
batch, _, _, _ = input.shape
for b in range(batch):
deformable_convolution_b1(input[b], output[b], offset, weights, bias, tmp, (stride_y, stride_x), (pad_y, pad_x), (dilation_y, dilation_x), groups, deformable_groups)

Original file line number Diff line number Diff line change
@@ -0,0 +1,81 @@
# Copyright 2022 Intel Corp.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looks like this _numpy implementation is the same as the _numba_npr version. If so, we should not be adding this.

#
# SPDX-License-Identifier: Apache-2.0

import math
import numpy as np
from numba import njit, prange

@njit(parallel=True, inline='always', fastmath=True)
def bilinear(input, offset_y, offset_x):
height, width = input.shape
start_x = int(math.floor(offset_x))
start_x_weight = 1 - (offset_x - start_x)
start_y = int(math.floor(offset_y))
start_y_weight = 1 - (offset_y - start_y)

output = 0
if start_x >= width or start_y >= height or start_x < -1 or start_y < -1:
return output

if start_x >= 0 and start_y >= 0:
w = start_x_weight*start_y_weight
output += w*input[start_y, start_x]

if start_x + 1 < width and start_y >= 0:
w = (1 - start_x_weight)*start_y_weight
output += w*input[start_y, start_x + 1]

if start_x >=0 and start_y + 1 < height:
w = start_x_weight*(1 - start_y_weight)
output += w*input[start_y + 1, start_x]

if start_x + 1 < width and start_y + 1 < height:
w = (1 - start_x_weight)*(1 - start_y_weight)
output += w*input[start_y + 1, start_x + 1]

return output

@njit(parallel=True, fastmath=True)
def deform(input, offset, output, stride, pad, dilation, groups, deformable_groups):
k_height, k_width, _, out_height, out_width = offset.shape
channels, _, _ = input.shape

k_h_m = (k_height - 1)//2
k_w_m = (k_width - 1)//2

for ckhkw in prange(channels*k_height*k_width):
for h in prange(out_height):
for w in prange(out_width):
c = ckhkw//(k_height*k_width)
khkw = ckhkw%(k_height*k_width)
kh = khkw//k_width
kw = khkw%k_width

offset_y = offset[kh, kw, 1, h, w] + h*stride[0] + (kh - k_h_m)*dilation[0] - (pad[0] - k_h_m)
offset_x = offset[kh, kw, 0, h, w] + w*stride[1] + (kw - k_w_m)*dilation[1] - (pad[1] - k_w_m)

output[c, kh, kw, h, w] = bilinear(input[c], offset_y, offset_x)

# @njit(parallel=True, fastmath=True)
def deformable_convolution_b1(input, output, offset, weights, bias, tmp, stride, pad, dilation, groups, deformable_groups):
out_channels, height, width = output.shape
_, in_channels, k_height, k_width = weights.shape

deform(input, offset, tmp, stride, pad, dilation, groups, deformable_groups)

tmp = tmp.reshape((in_channels*k_height*k_width, height*width))

_weights = weights.reshape((out_channels, in_channels*k_height*k_width))
_output = output.reshape((out_channels, height*width))
np.dot(_weights, tmp, _output)

_bias = bias.reshape((out_channels, 1))
_output[:] = _output + _bias

# @njit(parallel=True)
def deformable_convolution(input, output, offset, weights, bias, tmp, stride_y, stride_x, pad_y, pad_x, dilation_y, dilation_x, groups, deformable_groups):
batch, _, _, _ = input.shape
for b in range(batch):
deformable_convolution_b1(input[b], output[b], offset, weights, bias, tmp, (stride_y, stride_x), (pad_y, pad_x), (dilation_y, dilation_x), groups, deformable_groups)

Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
set(py_module_name _deformable_convolution_sycl)
pybind11_add_module(${py_module_name}
MODULE
deformable_convolution_sycl/impl.cpp
)
find_package(MKL CONFIG REQUIRED)

# target_include_directories(${py_module_name} PUBLIC ${Dpctl_INCLUDE_DIRS} $)

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please remove commented out lines

target_compile_options(${py_module_name} PUBLIC $<TARGET_PROPERTY:MKL::MKL,INTERFACE_COMPILE_OPTIONS>)
target_include_directories(${py_module_name} PUBLIC ${Dpctl_INCLUDE_DIRS} $<TARGET_PROPERTY:MKL::MKL,INTERFACE_INCLUDE_DIRECTORIES>)
target_link_libraries(${py_module_name} PUBLIC $<LINK_ONLY:MKL::MKL> ${MKL_SYCL})

message(STATUS "${MKL_IMPORTED_TARGETS}")
message(STATUS "${INTERFACE_COMPILE_OPTIONS}")
message(STATUS "${INTERFACE_INCLUDE_DIRECTORIES}")

file(RELATIVE_PATH py_module_dest ${CMAKE_SOURCE_DIR} ${CMAKE_CURRENT_SOURCE_DIR})
install(TARGETS ${py_module_name}
DESTINATION ${py_module_dest}/deformable_convolution_sycl
)
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
# Copyright 2022 Intel Corporation
#
# SPDX-License-Identifier: Apache 2.0

from .deformable_convolution_sycl._deformable_convolution_sycl import deformable_convolution as deformable_convolution_sycl

__all__ = ["deformable_convolution_sycl"]
Loading