Add more operation and some refactoring of the code to ease usage.

This commit is contained in:
Fabian Groh
2018-11-06 14:00:16 +01:00
committed by PatWie
parent 32e91a688f
commit 2cbeb7e699
27 changed files with 1264 additions and 452 deletions
+26 -14
View File
@@ -25,39 +25,51 @@ Demonstration of using FlexConvolution, FlexPooling Layer.
import numpy as np
import tensorflow as tf
from tabulate import tabulate
from layers import flex_convolution, flex_convolution_transpose, flex_pooling
from layers import (flex_convolution,
flex_convolution_transpose,
flex_pooling,
knn_bruteforce)
B, Din, Dout, Dout2, Dp, N, N2, K, K2 = 1, 2, 4, 8, 3, 10, 5, 5, 3
B, Din, Dout, Dout2, Dp, N, K = 1, 2, 4, 8, 3, 10, 5
features = np.random.randn(B, Din, N).astype(np.float32)
positions = np.random.randn(B, Dp, N).astype(np.float32)
neighbors = np.random.randint(0, N, [B, K, N]).astype(np.int32)
neighbors2 = np.random.randint(0, N, [B, K2, N2]).astype(np.int32)
features = tf.convert_to_tensor(features, name='features')
positions = tf.convert_to_tensor(positions, name='positions')
neighbors = tf.convert_to_tensor(neighbors, name='neighbors')
neighbors2 = tf.convert_to_tensor(neighbors2, name='neighbors2')
net = [features]
# use our FlexConv similar to a traditional convolution layer
net.append(flex_convolution(net[-1], positions, neighbors, Dout,
neighbors = knn_bruteforce(positions, K=5)
net.append(flex_convolution(net[-1],
positions,
neighbors,
Dout,
activation=tf.nn.relu))
# pool and sub-sampling are different operations
net.append(flex_pooling(net[-1], neighbors))
# when ordering the points beforehand sub-sampling is simply
features = net[-1][:, :, :N2]
positions = positions[:, :, :N2]
features = net[-1][:, :, :N // 2]
positions = positions[:, :, :N // 2]
net.append(features)
neighbors = knn_bruteforce(positions, K=3)
# we didn't notice any improvements using the transposed version vs. pooling
net.append(flex_convolution_transpose(net[-1], positions, neighbors2, Dout2,
net.append(flex_convolution_transpose(net[-1],
positions,
neighbors,
Dout,
activation=tf.nn.relu))
# of course any commonly used arguments work here as well
net.append(flex_convolution(net[-1], positions,
neighbors2, Dout2,
trainable=False, activation=tf.nn.relu))
net.append(flex_convolution(net[-1],
positions,
neighbors,
Dout,
activation=tf.nn.relu,
trainable=False))
gradient_wrt_feature = tf.gradients(net[-1], net[0])
+88 -12
View File
@@ -20,25 +20,86 @@
import tensorflow as tf
from user_ops import flex_convolution as _flex_convolution
from user_ops import flex_pooling as _flex_pooling
from user_ops import knn_bruteforce as _knn_bruteforce
from user_ops import flex_convolution_transpose as _flex_convolution_transpose
from tensorflow.python.keras import activations
from tensorflow.python.keras import initializers
from tensorflow.python.layers.base import Layer
from tensorflow.python.util.tf_export import tf_export
from tensorflow.python.framework import tensor_shape
from tensorflow.python.framework import ops
all = ['FlexPooling', 'FlexConvolution', 'FlexConvolutionTranspose',
'flex_pooling', 'flex_convolution', 'flex_convolution_transpose']
'flex_pooling', 'flex_convolution', 'flex_convolution_transpose',
'knn_bruteforce', 'KnnBruteforce']
def _remove_dim(x, axis=2):
return tf.squeeze(x, axis=axis)
@tf_export('keras.layers.FlexPooling')
class KnnBruteforce(Layer):
"""knn bruteforce layer.
This layer performs a nearest neighbor lookup for a batch of given positions.
Arguments:
K: size of each neighborhood
data_format: A string, one of `simple` (default) or `expanded`.
If `simple` the shapes are [B, Din, N], when `expanded` the shapes
are assumed to be [B, Din, 1, N] to match `channels_first` in trad
convolutions.
name: A string, the name of the layer.
Inputs:
positions: A `Tensor` of the format [B, Dp, (1), N].
Outputs:
neighborhoods: A `Tensor` of the format [B, K, (1), N] (tf.int32).
"""
def __init__(self,
K,
data_format='simple',
name=None):
super(KnnBruteforce, self).__init__(name=name)
assert K > 0
assert data_format in ['simple', 'expanded']
self.K = K
self.data_format = data_format
def compute_output_shape(self, input_shapes):
output_shape = input_shapes[0]
output_shape[1] = self.K
return output_shape
def call(self, inputs):
positions = ops.convert_to_tensor(inputs, dtype=self.dtype)
if self.data_format == 'expanded':
positions = _remove_dim(positions, 2)
NN, _, _ = _knn_bruteforce(positions, K=4)
NN = tf.transpose(NN, [0, 2, 1])
if self.data_format == 'expanded':
NN = tf.expand_dims(NN, axis=2)
return NN
def knn_bruteforce(positions,
K,
data_format='simple',
name=None):
layer = KnnBruteforce(K, data_format=data_format, name=name)
return layer.apply(positions)
class FlexPooling(Layer):
"""flex pooling layer.
@@ -53,8 +114,19 @@ class FlexPooling(Layer):
Arguments:
features: A `Tensor` of the format [B, Din, (1), N].
neighborhoods: A `Tensor` of the format [B, K, (1), N] (tf.int32).
data_format: A string, one of `simple` (default) or `expanded`.
If `simple` the shapes are [B, Din, N], when `expanded` the shapes
are assumed to be [B, Din, 1, N] to match `channels_first` in trad
convolutions.
name: A string, the name of the layer.
Inputs:
features: A `Tensor` of the format[B, Din, (1), N].
neighborhoods: A `Tensor` of the format [B, K, (1), N] (tf.int32).
Outputs:
features: A `Tensor` of the format[B, Din, (1), N].
"""
def __init__(self,
@@ -62,6 +134,7 @@ class FlexPooling(Layer):
name=None):
super(FlexPooling, self).__init__(name=name)
assert data_format in ['simple', 'expanded']
self.data_format = data_format
def compute_output_shape(self, input_shape):
@@ -93,11 +166,9 @@ def flex_pooling(features,
name=None):
layer = FlexPooling(data_format=data_format, name=name)
return layer.apply([features, neighborhoods])
@tf_export('keras.layers.FlexConvolution')
class FlexConvolution(Layer):
"""flex convolution layer.
@@ -126,7 +197,7 @@ class FlexConvolution(Layer):
features_bias_initializer: An initializer for the bias vector after
the convolution. If None, the default initializer will be used.
use_feature_bias: Boolean, whether the layer uses a bias.
data_format: A string, one of `simple` (default) or `expaned`.
data_format: A string, one of `simple` (default) or `expanded`.
If `simple` the shapes are [B, Din, N], when `expanded` the shapes
are assumed to be [B, Din, 1, N] to match `channels_first` in trad
convolutions.
@@ -136,9 +207,11 @@ class FlexConvolution(Layer):
Inputs:
features: A `Tensor` of the format[B, Din, (1), N].
positions: A `Tensor` of the format[B, Dp, (1), N].
neigh
borhoods: A `Tensor` of the format [B, K, (1), N] (tf.int32).
positions: A `Tensor` of the format[B, Dp, (1), N].
neighborhoods: A `Tensor` of the format [B, K, (1), N] (tf.int32).
Outputs:
features: A `Tensor` of the format[B, Dout, (1), N].
"""
@@ -155,6 +228,7 @@ borhoods: A `Tensor` of the format [B, K, (1), N] (tf.int32).
super(FlexConvolution, self).__init__(trainable=trainable,
name=name)
assert data_format in ['simple', 'expanded']
self.filters = int(filters)
self.activation = activations.get(activation)
self.use_feature_bias = use_feature_bias
@@ -226,7 +300,7 @@ borhoods: A `Tensor` of the format [B, K, (1), N] (tf.int32).
Returns:
tf.tensor: A `Tensor` of the format [B, Dout, (1), N] describing
the outgoing features.
the outgoing features.
"""
if not isinstance(inputs, list):
@@ -283,7 +357,6 @@ def flex_convolution(features,
return layer.apply([features, positions, neighborhoods])
@tf_export('keras.layers.FlexConvolutionTranspose')
class FlexConvolutionTranspose(FlexConvolution):
"""flex convolution-transpose layer.
@@ -312,7 +385,7 @@ class FlexConvolutionTranspose(FlexConvolution):
features_bias_initializer: An initializer for the bias vector after
the convolution. If None, the default initializer will be used.
use_feature_bias: Boolean, whether the layer uses a bias.
data_format: A string, one of `simple` (default) or `expaned`.
data_format: A string, one of `simple` (default) or `expanded`.
If `simple` the shapes are [B, Din, N], when `expanded` the shapes
are assumed to be [B, Din, 1, N] to match `channels_first` in trad
convolutions.
@@ -325,6 +398,9 @@ class FlexConvolutionTranspose(FlexConvolution):
positions: A `Tensor` of the format [B, Dp, (1), N].
neighborhoods: A `Tensor` of the format [B, K, (1), N] (tf.int32).
Outputs:
features: A `Tensor` of the format[B, Dout, (1), N].
"""
def internal_call(self,
+8
View File
@@ -13,7 +13,12 @@ list(APPEND CMAKE_MODULE_PATH ${PROJECT_SOURCE_DIR})
find_package(CUDA REQUIRED)
find_package(TensorFlow REQUIRED)
# include CUDA Toolkit header files
set(CUDA_SAMPLE_INC "$ENV{CUDA_INSTALL_PATH}/samples/common/inc")
message(STATUS "CUDA_INCLUDE_DIRS: ${CUDA_INCLUDE_DIRS}")
message(STATUS "CUDA_SAMPLE_INC: ${CUDA_SAMPLE_INC}")
# include CUBS
if (DEFINED ENV{CUB_INC})
message(STATUS "Use Cuda-CUB from " $ENV{CUB_INC})
set(CUB_INC $ENV{CUB_INC})
@@ -31,6 +36,8 @@ include_directories(SYSTEM "/usr/local/")
# fix cgtuebingen
include_directories(SYSTEM "/graphics/opt/opt_Ubuntu18.04/cuda/toolkit_9.2")
include_directories(SYSTEM "${CUDA_SAMPLE_INC}")
include_directories(SYSTEM "${CUDA_INCLUDE_DIRS}/../../")
include_directories(SYSTEM ${CUB_INC})
include_directories(SYSTEM ${TensorFlow_INCLUDE_DIR})
include_directories(SYSTEM kernels)
@@ -38,3 +45,4 @@ include_directories(SYSTEM kernels)
add_tensorflow_gpu_operation("flex_conv")
add_tensorflow_gpu_operation("flex_deconv")
add_tensorflow_gpu_operation("flex_pool")
add_tensorflow_gpu_operation("knn_bruteforce")
+17 -4
View File
@@ -54,6 +54,7 @@ endif(WIN32)
set(PYTHON_EXECUTABLE "python3" CACHE STRING "specify the python version TensorFlow is installed on.")
if(TensorFlow_FOUND)
# reuse cached variables
message(STATUS "Reuse cached information from TensorFlow ${TensorFlow_VERSION} ")
@@ -122,7 +123,7 @@ else()
# However, only TensorFlow versions 1.9, 1.10 support all header files
# for custom ops.
set(_TensorFlow_KNOWN_VERSIONS ${TensorFlow_ADDITIONAL_VERSIONS}
"1.9" "1.9.0" "1.10" "1.10.0", "1.11", "1.11.0")
"1.9" "1.9.0" "1.10" "1.10.0" "1.11" "1.11.0")
set(_TensorFlow_TEST_VERSIONS)
if(TF_FIND_VERSION)
@@ -166,6 +167,17 @@ else()
"We tested against ${_TensorFlow_TEST_VERSIONS}")
endif(NOT TensorFlow_FOUND)
# test 1.11 version
if("${TF_DETECTED_VERSION}" VERSION_EQUAL "1.11")
set(TF_DISABLE_ASSERTS "TRUE")
endif()
endif()
if(${TF_DISABLE_ASSERTS})
message(STATUS "[WARNING] The TensorFlow version ${TF_DETECTED_VERSION} has a bug (see \#22766). We disable asserts using -DNDEBUG=True ")
add_definitions("-DNDEBUG=True")
endif()
find_library(TensorFlow_C_LIBRARY
@@ -246,8 +258,8 @@ endmacro()
# simplify TensorFlow dependencies
add_library(TensorFlow_DEP INTERFACE)
TARGET_INCLUDE_DIRECTORIES(TensorFlow_DEP INTERFACE ${TensorFlow_SOURCE_DIR})
TARGET_INCLUDE_DIRECTORIES(TensorFlow_DEP INTERFACE ${TensorFlow_INCLUDE_DIR})
TARGET_INCLUDE_DIRECTORIES(TensorFlow_DEP SYSTEM INTERFACE ${TensorFlow_SOURCE_DIR})
TARGET_INCLUDE_DIRECTORIES(TensorFlow_DEP SYSTEM INTERFACE ${TensorFlow_INCLUDE_DIR})
TARGET_LINK_LIBRARIES(TensorFlow_DEP INTERFACE -Wl,--allow-multiple-definition -Wl,--whole-archive ${TensorFlow_C_LIBRARY} -Wl,--no-whole-archive)
TARGET_LINK_LIBRARIES(TensorFlow_DEP INTERFACE -Wl,--allow-multiple-definition -Wl,--whole-archive ${TensorFlow_LIBRARY} -Wl,--no-whole-archive)
@@ -263,7 +275,7 @@ find_package_handle_standard_args(
)
mark_as_advanced(TF_INFORMATION_STRING TF_DETECTED_VERSION TF_DETECTED_VERSION_MAJOR TF_DETECTED_VERSION_MINOR TF_DETECTED_VERSION TF_DETECTED_ABI
TF_DETECTED_INCLUDE_DIR TF_DETECTED_LIBRARY
TF_DETECTED_INCLUDE_DIR TF_DETECTED_LIBRARY TF_DISABLE_ASSERTS
TensorFlow_C_LIBRARY TensorFlow_LIBRARY TensorFlow_SOURCE_DIR TensorFlow_INCLUDE_DIR TensorFlow_ABI)
SET(TensorFlow_INCLUDE_DIR ${TensorFlow_INCLUDE_DIR} CACHE PATH "path to tensorflow header files")
@@ -271,3 +283,4 @@ SET(TensorFlow_VERSION ${TensorFlow_VERSION} CACHE INTERNAL "The Python executab
SET(TensorFlow_ABI ${TensorFlow_ABI} CACHE STRING "The Python executable Version")
SET(TensorFlow_LIBRARY ${TensorFlow_LIBRARY} CACHE PATH "The Python executable Version")
SET(TensorFlow_FOUND ${TensorFlow_FOUND} CACHE BOOL "The Python executable Version")
SET(TF_DISABLE_ASSERTS ${TF_DISABLE_ASSERTS} CACHE BOOL "Workarounds")
-130
View File
@@ -1,130 +0,0 @@
#!/usr/bin/env python
# -*- coding: utf-8 -*-
# Copyright 2017 ComputerGraphics Tuebingen. All Rights Reserved.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
# ==============================================================================
# Authors: Fabian Groh, Patrick Wieschollek, Hendrik P.A. Lensch
import numpy as np
import tensorflow as tf
np.random.seed(42)
tf.set_random_seed(42)
class FakePointCloud(object):
"""docstring for FakePointCloud"""
def __init__(self, B, N, K, Din, Dout, Dp, N2, scaling=1):
super(FakePointCloud, self).__init__()
assert K < N
self.B = B
self.N = N
self.K = K
self.Din = Din
self.Dout = Dout
self.Dp = Dp
self.N2 = N2
def expected_feature_shape(self):
return [self.B, self.Din, self.N]
def expected_output_shape(self):
return [self.B, self.Dout, self.N]
def random_values(shape, human_readable=False):
"""Return random values within range [-10, 10] and precision 2
"""
length = np.prod(shape)
return np.arange(length).astype(np.float32).reshape(shape) / float(length)
def summary(numeric_grad, graph_grad, name, eps=0.001, max_outputs=20):
a, b = numeric_grad.flatten(), graph_grad.flatten()
print("summary: %s" % name)
print("\ttheirs\t\tours\t\tabs-diff")
for i in range(np.prod(numeric_grad.shape)):
if np.abs(a[i] - b[i]) > eps and max_outputs > 0:
print('%i\t%f\t%f\t%f' % (i, a[i], b[i], np.abs(a[i] - b[i])))
max_outputs -= 1
if max_outputs == 20:
for i in range(max_outputs):
print('%i\t%f\t%f\t%f' % (i, a[i], b[i], np.abs(a[i] - b[i])))
# print( np.stack([numeric_grad, graph_grad], axis=-1)
print("%s - abs-diff (sum): " % name, np.abs(
graph_grad - numeric_grad).sum())
print("%s - abs-diff (max): " % name, np.abs(
graph_grad - numeric_grad).max())
print("%s - abs-diff (mean): " % name, np.abs(
graph_grad - numeric_grad).mean())
# TestPointCloud(B, N, K, Din, Dout, Dp, N2)
# TPC = FakePointCloud(2, 32, 16, 5, 6, 3, 16)
# TPC = FakePointCloud(2, 16, 8, 5, 6, 3, 8)
TPC = FakePointCloud(2, 32, 4, 2, 6, 3, 16)
# TPC = FakePointCloud(2, 64, 8, 1, 6, 3, 64)
class PointTestCase(tf.test.TestCase):
def __init__(self, methodName="runTest", data=None):
if data is None:
data = TPC
self.position = random_values([data.B, data.Dp, data.N])
self.features = random_values([data.B, data.Din, data.N])
# make sure, each neighbor hood has no duplicates and first entry is point n
# THIS IS IMPORTANT!!
self.neighborhood = np.zeros((data.B, data.K, data.N), dtype=np.int32)
for b in range(data.B):
for n in range(data.N):
x = np.arange(data.N)
# does not support axis, hence the loop
np.random.shuffle(x)
offset = np.argwhere(x == n)[0][0]
# roll array such that n is first entry
x = np.roll(x, -offset)
self.neighborhood[b, :, n] = x[:data.K].astype(np.int32)
self.neighborhood_ds = np.zeros((data.B, data.K, data.N2), dtype=np.int32)
for b in range(data.B):
for n in range(data.N2):
x = np.arange(data.N2)
# does not support axis, hence the loop
np.random.shuffle(x)
offset = np.argwhere(x == n)[0][0]
# roll array such that n is first entry
x = np.roll(x, -offset)
self.neighborhood[b, :, n] = x[:data.K].astype(np.int32)
self.theta = random_values([1, data.Dp, data.Din, data.Dout])
self.bias = random_values([data.Din, data.Dout])
super(PointTestCase, self).__init__(methodName)
def init_ops(self):
# needs to be called in each method, otherwise graph is empty
# probably tf.reset_graph between calls
self.features_op = tf.convert_to_tensor(self.features)
self.position_op = tf.convert_to_tensor(self.position)
self.neighborhood_op = tf.convert_to_tensor(self.neighborhood)
self.neighborhood_ds_op = tf.convert_to_tensor(self.neighborhood_ds)
self.theta_op = tf.convert_to_tensor(self.theta)
self.bias_op = tf.convert_to_tensor(self.bias)
+42 -22
View File
@@ -19,27 +19,38 @@ from __future__ import division
from __future__ import print_function
import tensorflow as tf
import os
from tensorflow.python.framework import ops
from tensorflow.contrib.util import loader
from tensorflow.python.platform import resource_loader
_flex_convolution_op_so = loader.load_op_library(
resource_loader.get_path_to_datafile("flex_conv_op.so"))
_flex_pooling_op_so = loader.load_op_library(
resource_loader.get_path_to_datafile("flex_pool_op.so"))
_flex_deconvolution_op_so = loader.load_op_library(
resource_loader.get_path_to_datafile("flex_deconv_op.so"))
__all__ = []
# undocumented version
flex_conv = _flex_convolution_op_so.flex_conv
flex_conv_grad = _flex_convolution_op_so.flex_conv_grad
flex_pool = _flex_pooling_op_so.flex_pool
flex_pool_grad = _flex_pooling_op_so.flex_pool_grad
flex_deconv = _flex_deconvolution_op_so.flex_deconv
flex_deconv_grad = _flex_deconvolution_op_so.flex_deconv_grad
def load_op(name, has_grad=False, public=False):
global __all__
path = os.path.join(os.path.dirname(__file__), '%s_op.so' % name)
if os.path.isfile(path):
_module = loader.load_op_library(path)
if has_grad:
if public:
__all__.append('%s' % name)
__all__.append('%s_grad' % name)
return getattr(_module, '%s' % name), getattr(_module, '%s_grad' % name)
else:
if public:
__all__.append('%s' % name)
return getattr(_module, '%s' % name)
else:
print('[WARNING]: %s does not exists' % name)
knn_bruteforce = load_op('knn_bruteforce', has_grad=False, public=True)
_flex_conv, _flex_conv_grad = load_op(
'flex_conv', has_grad=True, public=False)
_flex_pool, _flex_pool_grad = load_op(
'flex_pool', has_grad=True, public=False)
_flex_deconv, _flex_deconv_grad = load_op(
'flex_deconv', has_grad=True, public=False)
# pylint: disable=redefined-builtin
@@ -69,7 +80,10 @@ def flex_convolution(features,
"""
with ops.name_scope(name, "flex_convolution"):
return flex_conv(features, theta, bias, neighborhood, position)
return _flex_conv(features, theta, bias, neighborhood, position)
__all__.append('flex_convolution')
@ops.RegisterGradient("FlexConv")
@@ -81,7 +95,7 @@ def _FlexConvGrad(op, *grads): # noqa
positions = ops.convert_to_tensor(op.inputs[4])
topdiff = ops.convert_to_tensor(grads[0])
df, dt, db = flex_conv_grad(
df, dt, db = _flex_conv_grad(
features, theta, bias, neighborhood, positions, topdiff)
df = ops.convert_to_tensor(df, name='gradient_features')
@@ -112,7 +126,10 @@ def flex_pooling(features,
"""
with ops.name_scope(name, "flex_pooling"):
return flex_pool(features, neighborhood)
return _flex_pool(features, neighborhood)
__all__.append('flex_pooling')
@ops.RegisterGradient("FlexPool")
@@ -122,7 +139,7 @@ def _FlexPoolGrad(op, *grads): # noqa
argmax = ops.convert_to_tensor(op.outputs[1])
topdiff = ops.convert_to_tensor(grads[0])
df = flex_pool_grad(features, neighborhood, topdiff, argmax)
df = _flex_pool_grad(features, neighborhood, topdiff, argmax)
df = ops.convert_to_tensor(df, name='gradient_features')
return [df, None]
@@ -153,7 +170,10 @@ def flex_convolution_transpose(features,
"""
with ops.name_scope(name, "flex_convolution_transpose"):
return flex_deconv(features, theta, bias, neighborhood, position)
return _flex_deconv(features, theta, bias, neighborhood, position)
__all__.append('_flex_deconv')
@ops.RegisterGradient("FlexDeconv")
@@ -165,7 +185,7 @@ def _FlexDeconvGrad(op, *grads): # noqa
positions = ops.convert_to_tensor(op.inputs[4])
topdiff = ops.convert_to_tensor(grads[0])
df, dt, db = flex_deconv_grad(
df, dt, db = _flex_deconv_grad(
features, theta, bias, neighborhood, positions, topdiff)
df = ops.convert_to_tensor(df, name='gradient_features')
+10
View File
@@ -0,0 +1,10 @@
#ifndef LIB_CUDA_UTILS_H_
#define LIB_CUDA_UTILS_H_
template <typename T>
__device__ T* DynamicSharedMemory() {
extern __shared__ __align__(sizeof(T)) unsigned char s_shm[];
return reinterpret_cast<T*>(s_shm);
}
#endif // LIB_CUDA_UTILS_H_
+2 -1
View File
@@ -70,6 +70,7 @@ struct FlexConvFunctor<CPUDevice, Dtype> {
};
template struct FlexConvFunctor<CPUDevice, float>;
template struct FlexConvFunctor<CPUDevice, double>;
template <typename Dtype>
struct FlexConvGrad<CPUDevice, Dtype> {
@@ -167,7 +168,7 @@ struct FlexConvGrad<CPUDevice, Dtype> {
// template struct FlexConvGrad<CPUDevice, int>;
template struct FlexConvGrad<CPUDevice, float>;
// template struct FlexConvGrad<CPUDevice, double>;
template struct FlexConvGrad<CPUDevice, double>;
} // namespace functor
} // namespace tensorflow
+29 -8
View File
@@ -12,7 +12,7 @@ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
==============================================================================*/
//Authors: Fabian Groh, Patrick Wieschollek, Hendrik P.A. Lensch
// Authors: Fabian Groh, Patrick Wieschollek, Hendrik P.A. Lensch
#if GOOGLE_CUDA
@@ -20,6 +20,7 @@ limitations under the License.
#include <cub/cub.cuh>
#include "cuda_utils.h"
#include "flex_conv_op.h"
#include "tensorflow/core/util/cuda_kernel_helper.h"
@@ -57,10 +58,10 @@ struct ForwardKernel {
}
__device__ __forceinline__ void operator()() const {
extern __shared__ Dtype s_shm[];
Dtype* s_shm = DynamicSharedMemory<Dtype>();
Dtype* s_theta = (float*)&s_shm[0];
Dtype* s_bias = (float*)&s_shm[Dp * C_Din * C_Dout];
Dtype* s_theta = (Dtype*)&s_shm[0];
Dtype* s_bias = (Dtype*)&s_shm[Dp * C_Din * C_Dout];
// glob ids
int b = blockIdx.z;
@@ -281,7 +282,8 @@ struct BackwardFeatureKernel {
}
__device__ __forceinline__ void operator()() const {
extern __shared__ float s_shm[];
// extern __shared__ float s_shm[];
Dtype* s_shm = DynamicSharedMemory<Dtype>();
int i_n = threadIdx.x;
int i_din = threadIdx.y;
@@ -354,7 +356,10 @@ struct BackwardFeatureKernel {
W += s_bias[i_din * C_Dout + dout_inner];
Dtype value = W * s_topdiff[dout_inner * C_N + i_n];
atomicAdd(
// atomicAdd(
// &d_features_out[b * Din * N + din * N + s_nk[k * C_N + i_n]],
// value);
tensorflow::CudaAtomicAdd(
&d_features_out[b * Din * N + din * N + s_nk[k * C_N + i_n]],
value);
}
@@ -384,6 +389,16 @@ struct BackwardFeatureKernel {
namespace tensorflow {
namespace functor {
template <class Dtype, class NBtype>
struct ForwardKernelType {
typedef FlexConvCuda::ForwardKernel<Dtype, NBtype, 3, 128, 32, 32> type;
};
template <>
struct ForwardKernelType<float, int> {
typedef FlexConvCuda::ForwardKernel<float, int, 3, 128, 32, 64> type;
};
template <typename Dtype>
struct FlexConvFunctor<GPUDevice, Dtype> {
void operator()(::tensorflow::OpKernelContext* ctx, const Tensor& features,
@@ -399,7 +414,11 @@ struct FlexConvFunctor<GPUDevice, Dtype> {
const int Din = theta.dim_size(2);
const int Dout = theta.dim_size(3);
FlexConvCuda::ForwardKernel<Dtype, NBtype, 3, 128, 32, 64> fwk;
// printf("<f> test: %s\n", __PRETTY_FUNCTION__);
typedef typename ForwardKernelType<Dtype, NBtype>::type FKT;
FKT fwk;
fwk.N = N;
fwk.K = K;
fwk.Din = Din;
@@ -422,6 +441,7 @@ struct FlexConvFunctor<GPUDevice, Dtype> {
};
template struct FlexConvFunctor<GPUDevice, float>;
template struct FlexConvFunctor<GPUDevice, double>;
template <typename Dtype>
struct FlexConvGrad<GPUDevice, Dtype> {
@@ -459,7 +479,7 @@ struct FlexConvGrad<GPUDevice, Dtype> {
const Dtype* topdiff_ptr = reinterpret_cast<const Dtype*>(topdiff.data());
Dtype* grad_features_ptr = reinterpret_cast<float*>(grad_features.data());
Dtype* grad_features_ptr = reinterpret_cast<Dtype*>(grad_features.data());
Dtype* grad_theta_ptr = reinterpret_cast<Dtype*>(grad_theta.data());
Dtype* grad_bias_ptr = reinterpret_cast<Dtype*>(grad_bias.data());
@@ -525,6 +545,7 @@ struct FlexConvGrad<GPUDevice, Dtype> {
};
template struct FlexConvGrad<GPUDevice, float>;
template struct FlexConvGrad<GPUDevice, double>;
} // namespace functor
} // namespace tensorflow
+16 -26
View File
@@ -12,7 +12,7 @@ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
==============================================================================*/
//Authors: Fabian Groh, Patrick Wieschollek, Hendrik P.A. Lensch
// Authors: Fabian Groh, Patrick Wieschollek, Hendrik P.A. Lensch
#include "flex_conv_op.h"
@@ -91,32 +91,22 @@ class FlexConvGradOp : public OpKernel {
}
};
// Register the CPU kernels.
#define REGISTER_FLEXCONV_OP_CPU(T) \
REGISTER_KERNEL_BUILDER( \
Name("FlexConv").Device(DEVICE_CPU).TypeConstraint<T>("T"), \
FlexConvOp<CPUDevice, T>) \
REGISTER_KERNEL_BUILDER( \
Name("FlexConvGrad").Device(DEVICE_CPU).TypeConstraint<T>("T"), \
FlexConvGradOp<CPUDevice, T>)
#define REGISTER_CUSTOM_OP(NAME, DEVICE, T) \
REGISTER_KERNEL_BUILDER( \
Name(#NAME).Device(DEVICE_##DEVICE).TypeConstraint<T>("T"), \
NAME##Op<DEVICE##Device, T>)
TF_CALL_float(REGISTER_FLEXCONV_OP_CPU);
#undef REGISTER_FLEXCONV_OP_CPU
REGISTER_CUSTOM_OP(FlexConv, CPU, float);
REGISTER_CUSTOM_OP(FlexConvGrad, CPU, float);
REGISTER_CUSTOM_OP(FlexConv, CPU, double);
REGISTER_CUSTOM_OP(FlexConvGrad, CPU, double);
// Register the GPU kernels.
// #ifdef GOOGLE_CUDA
#define REGISTER_FLEXCONV_OP_GPU(T) \
REGISTER_KERNEL_BUILDER( \
Name("FlexConv").Device(DEVICE_GPU).TypeConstraint<T>("T"), \
FlexConvOp<GPUDevice, T>) \
REGISTER_KERNEL_BUILDER( \
Name("FlexConvGrad").Device(DEVICE_GPU).TypeConstraint<T>("T"), \
FlexConvGradOp<GPUDevice, T>)
TF_CALL_float(REGISTER_FLEXCONV_OP_GPU);
#undef REGISTER_FLEXCONV_OP_GPU
// #endif // GOOGLE_CUDA
#ifdef GOOGLE_CUDA
REGISTER_CUSTOM_OP(FlexConv, GPU, float);
REGISTER_CUSTOM_OP(FlexConvGrad, GPU, float);
REGISTER_CUSTOM_OP(FlexConv, GPU, double);
REGISTER_CUSTOM_OP(FlexConvGrad, GPU, double);
#endif // GOOGLE_CUDA
#undef REGISTER_CUSTOM_OP
} // namespace tensorflow
+2 -2
View File
@@ -71,6 +71,7 @@ struct FlexDeconvFunctor<CPUDevice, Dtype> {
};
template struct FlexDeconvFunctor<CPUDevice, float>;
template struct FlexDeconvFunctor<CPUDevice, double>;
template <typename Dtype>
struct FlexDeconvGrad<CPUDevice, Dtype> {
@@ -165,9 +166,8 @@ struct FlexDeconvGrad<CPUDevice, Dtype> {
}
};
// template struct FlexDeconvGrad<CPUDevice, int>;
template struct FlexDeconvGrad<CPUDevice, float>;
// template struct FlexDeconvGrad<CPUDevice, double>;
template struct FlexDeconvGrad<CPUDevice, double>;
} // namespace functor
} // namespace tensorflow
@@ -177,6 +177,7 @@ struct FlexDeconvFunctor<GPUDevice, Dtype> {
};
template struct FlexDeconvFunctor<GPUDevice, float>;
template struct FlexDeconvFunctor<GPUDevice, double>;
template <typename Dtype>
struct FlexDeconvGrad<GPUDevice, Dtype> {
@@ -220,6 +221,7 @@ struct FlexDeconvGrad<GPUDevice, Dtype> {
};
template struct FlexDeconvGrad<GPUDevice, float>;
template struct FlexDeconvGrad<GPUDevice, double>;
} // namespace functor
} // namespace tensorflow
+17 -11
View File
@@ -12,7 +12,7 @@ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
==============================================================================*/
//Authors: Fabian Groh, Patrick Wieschollek, Hendrik P.A. Lensch
// Authors: Fabian Groh, Patrick Wieschollek, Hendrik P.A. Lensch
#include "flex_deconv_op.h"
@@ -88,16 +88,22 @@ class FlexDeconvGradOp : public OpKernel {
}
};
#define OPNAME(NAME) NAME##Op
#define REGISTER(NAME, Dtype) \
REGISTER_KERNEL_BUILDER( \
Name(#NAME).Device(DEVICE_CPU).TypeConstraint<Dtype>("T"), \
OPNAME(NAME) < CPUDevice, Dtype >); \
REGISTER_KERNEL_BUILDER( \
Name(#NAME).Device(DEVICE_GPU).TypeConstraint<Dtype>("T"), \
OPNAME(NAME) < GPUDevice, Dtype >);
#define REGISTER_CUSTOM_OP(NAME, DEVICE, T) \
REGISTER_KERNEL_BUILDER( \
Name(#NAME).Device(DEVICE_##DEVICE).TypeConstraint<T>("T"), \
NAME##Op<DEVICE##Device, T>)
REGISTER(FlexDeconv, float);
REGISTER(FlexDeconvGrad, float);
REGISTER_CUSTOM_OP(FlexDeconv, CPU, float);
REGISTER_CUSTOM_OP(FlexDeconvGrad, CPU, float);
REGISTER_CUSTOM_OP(FlexDeconv, CPU, double);
REGISTER_CUSTOM_OP(FlexDeconvGrad, CPU, double);
#ifdef GOOGLE_CUDA
REGISTER_CUSTOM_OP(FlexDeconv, GPU, float);
REGISTER_CUSTOM_OP(FlexDeconvGrad, GPU, float);
REGISTER_CUSTOM_OP(FlexDeconv, GPU, double);
REGISTER_CUSTOM_OP(FlexDeconvGrad, GPU, double);
#endif // GOOGLE_CUDA
#undef REGISTER_CUSTOM_OP
} // namespace tensorflow
+3 -3
View File
@@ -12,7 +12,7 @@ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
==============================================================================*/
//Authors: Fabian Groh, Patrick Wieschollek, Hendrik P.A. Lensch
// Authors: Fabian Groh, Patrick Wieschollek, Hendrik P.A. Lensch
#include "flex_pool_op.h"
#include "tensorflow/core/framework/op.h"
@@ -59,6 +59,7 @@ struct FlexPoolFunctor<CPUDevice, Dtype> {
};
template struct FlexPoolFunctor<CPUDevice, float>;
template struct FlexPoolFunctor<CPUDevice, double>;
template <typename Dtype>
struct FlexPoolGrad<CPUDevice, Dtype> {
@@ -94,9 +95,8 @@ struct FlexPoolGrad<CPUDevice, Dtype> {
}
};
// template struct FlexPoolGrad<CPUDevice, int>;
template struct FlexPoolGrad<CPUDevice, float>;
// template struct FlexPoolGrad<CPUDevice, double>;
template struct FlexPoolGrad<CPUDevice, double>;
} // namespace functor
} // namespace tensorflow
+12 -18
View File
@@ -12,7 +12,7 @@ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
==============================================================================*/
//Authors: Fabian Groh, Patrick Wieschollek, Hendrik P.A. Lensch
// Authors: Fabian Groh, Patrick Wieschollek, Hendrik P.A. Lensch
#if GOOGLE_CUDA
@@ -30,7 +30,7 @@ inline int up2(int len, int th) { return (len - 1) / th + 1; }
template <typename Dtype>
__global__ void forward(const int B, const int N, const int K, const int D,
const Dtype* features, const int* neighborhood,
Dtype* output, int* argmax, float float_min_value) {
Dtype* output, int* argmax, Dtype float_min_value) {
// features: each feature description for each point [B, D, N].
// neighborhood: all K nearest neighbors [B, K, N].
// output: each feature description for each point [B, D, N].
@@ -41,14 +41,14 @@ __global__ void forward(const int B, const int N, const int K, const int D,
d += blockDim.y * gridDim.y) {
for (int n = blockIdx.x * blockDim.x + threadIdx.x; n < N;
n += blockDim.x * gridDim.x) {
float best_value = float_min_value;
Dtype best_value = float_min_value;
int best_id = 0;
const int current_flat = b * D * N + d * N + n;
for (int k_ = 0; k_ < K; ++k_) {
const int other_global_id = neighborhood[b * K * N + k_ * N + n];
const float v = features[b * D * N + d * N + other_global_id];
const Dtype v = features[b * D * N + d * N + other_global_id];
if (best_value < v) {
best_id = other_global_id;
@@ -113,13 +113,9 @@ struct FlexPoolFunctor<GPUDevice, Dtype> {
dim3 grid(up2(N, threads), up2(D, threads), B);
forward<Dtype><<<grid, block>>>(
B, N, K, D,
features_.flat<Dtype>().data(), neighborhood_.flat<int>().data(),
output_->flat<Dtype>().data(), argmax_->flat<int>().data(),
std::numeric_limits<Dtype>::lowest());
B, N, K, D, features_.flat<Dtype>().data(),
neighborhood_.flat<int>().data(), output_->flat<Dtype>().data(),
argmax_->flat<int>().data(), std::numeric_limits<Dtype>::lowest());
if (!ctx->eigen_gpu_device().ok()) {
ctx->SetStatus(
@@ -129,6 +125,7 @@ struct FlexPoolFunctor<GPUDevice, Dtype> {
};
template struct FlexPoolFunctor<GPUDevice, float>;
template struct FlexPoolFunctor<GPUDevice, double>;
template <typename Dtype>
struct FlexPoolGrad<GPUDevice, Dtype> {
@@ -149,13 +146,9 @@ struct FlexPoolGrad<GPUDevice, Dtype> {
grad_features_->NumElements() * sizeof(Dtype));
backward<Dtype><<<grid, block>>>(
B, N, K, D,
features_.flat<Dtype>().data(), neighborhood_.flat<int>().data(),
topdiff_.flat<Dtype>().data(), argmax_.flat<int>().data(),
grad_features_->flat<Dtype>().data());
B, N, K, D, features_.flat<Dtype>().data(),
neighborhood_.flat<int>().data(), topdiff_.flat<Dtype>().data(),
argmax_.flat<int>().data(), grad_features_->flat<Dtype>().data());
if (!ctx->eigen_gpu_device().ok()) {
ctx->SetStatus(tensorflow::errors::Internal("CUDA: FlexPoolGrad Error!"));
@@ -164,6 +157,7 @@ struct FlexPoolGrad<GPUDevice, Dtype> {
};
template struct FlexPoolGrad<GPUDevice, float>;
template struct FlexPoolGrad<GPUDevice, double>;
} // namespace functor
} // namespace tensorflow
+14 -26
View File
@@ -12,7 +12,7 @@ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
==============================================================================*/
//Authors: Fabian Groh, Patrick Wieschollek, Hendrik P.A. Lensch
// Authors: Fabian Groh, Patrick Wieschollek, Hendrik P.A. Lensch
#include "flex_pool_op.h"
@@ -33,7 +33,6 @@ class FlexPoolOp : public OpKernel {
explicit FlexPoolOp(OpKernelConstruction* ctx) : OpKernel(ctx) {}
void Compute(OpKernelContext* ctx) override {
// printf("--> Compute CPU Version <--\n");
const Tensor& features_ = ctx->input(0);
const Tensor& neighborhood_ = ctx->input(1);
@@ -65,7 +64,6 @@ class FlexPoolGradOp : public OpKernel {
explicit FlexPoolGradOp(OpKernelConstruction* ctx) : OpKernel(ctx) {}
void Compute(OpKernelContext* ctx) override {
// printf("--> Compute CPU Version <--\n");
const Tensor& features_ = ctx->input(0);
const Tensor& neighborhood_ = ctx->input(1);
const Tensor& topdiff_ = ctx->input(2);
@@ -82,32 +80,22 @@ class FlexPoolGradOp : public OpKernel {
}
};
// Register the CPU kernels.
#define REGISTER_FLEXPOOL_OP_CPU(T) \
REGISTER_KERNEL_BUILDER( \
Name("FlexPool").Device(DEVICE_CPU).TypeConstraint<T>("T"), \
FlexPoolOp<CPUDevice, T>) \
REGISTER_KERNEL_BUILDER( \
Name("FlexPoolGrad").Device(DEVICE_CPU).TypeConstraint<T>("T"), \
FlexPoolGradOp<CPUDevice, T>)
#define REGISTER_CUSTOM_OP(NAME, DEVICE, T) \
REGISTER_KERNEL_BUILDER( \
Name(#NAME).Device(DEVICE_##DEVICE).TypeConstraint<T>("T"), \
NAME##Op<DEVICE##Device, T>)
TF_CALL_float(REGISTER_FLEXPOOL_OP_CPU);
#undef REGISTER_FLEXPOOL_OP_CPU
REGISTER_CUSTOM_OP(FlexPool, CPU, float);
REGISTER_CUSTOM_OP(FlexPoolGrad, CPU, float);
REGISTER_CUSTOM_OP(FlexPool, CPU, double);
REGISTER_CUSTOM_OP(FlexPoolGrad, CPU, double);
// Register the GPU kernels.
#ifdef GOOGLE_CUDA
#define REGISTER_FLEXPOOL_OP_GPU(T) \
REGISTER_KERNEL_BUILDER( \
Name("FlexPool").Device(DEVICE_GPU).TypeConstraint<T>("T"), \
FlexPoolOp<GPUDevice, T>) \
REGISTER_KERNEL_BUILDER( \
Name("FlexPoolGrad").Device(DEVICE_GPU).TypeConstraint<T>("T"), \
FlexPoolGradOp<GPUDevice, T>)
TF_CALL_float(REGISTER_FLEXPOOL_OP_GPU);
#undef REGISTER_FLEXPOOL_OP_GPU
REGISTER_CUSTOM_OP(FlexPool, GPU, float);
REGISTER_CUSTOM_OP(FlexPoolGrad, GPU, float);
REGISTER_CUSTOM_OP(FlexPool, GPU, double);
REGISTER_CUSTOM_OP(FlexPoolGrad, GPU, double);
#endif // GOOGLE_CUDA
#undef REGISTER_CUSTOM_OP
} // namespace tensorflow
+79
View File
@@ -0,0 +1,79 @@
/* Copyright 2018 ComputerGraphics Tuebingen. All Rights Reserved.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
==============================================================================*/
// Authors: Fabian Groh, Patrick Wieschollek, Hendrik P.A. Lensch
#include "knn_bruteforce_op.h"
#include "tensorflow/core/framework/op.h"
namespace tensorflow {
namespace functor {
template <typename Dtype, typename NBtype>
struct KnnBruteforceFunctor<CPUDevice, Dtype, NBtype> {
void operator()(::tensorflow::OpKernelContext* ctx, const Tensor& positions_,
Tensor* neighborhood_out_, Tensor* distances_,
Tensor* timings) {
// positions [B, Dp, N]
// neighborhood_out_ [B, N, K]
// distances_ [B, N, K]
const auto positions = positions_.tensor<Dtype, 3>();
auto neighborhood_out = neighborhood_out_->tensor<NBtype, 3>();
auto distances_out = distances_->tensor<Dtype, 3>();
const int B = positions_.dim_size(0);
const int Dp = positions_.dim_size(1);
const int N = positions_.dim_size(2);
const int K = neighborhood_out_->dim_size(2);
for (int b = 0; b < B; ++b) {
const Dtype* pc_raw = positions_.flat<Dtype>().data() + b * Dp * N;
Eigen::Map<const Eigen::Matrix<Dtype, Eigen::Dynamic, Eigen::Dynamic,
Eigen::RowMajor>>
pc(pc_raw, Dp, N);
// pc: [Dp, N]
for (int n = 0; n < N; ++n) {
const auto query = pc.col(n);
const auto diffs =
(pc.colwise() - query).array() * (pc.colwise() - query).array();
const auto distances = (diffs.colwise().sum()).array().sqrt();
std::vector<Dtype> vec_dist;
std::vector<Dtype> vec_ids;
for (int i = 0; i < N; ++i) {
vec_dist.push_back(distances(i));
vec_ids.push_back(i);
}
std::sort(std::begin(vec_ids), std::end(vec_ids),
[&](int i1, int i2) { return vec_dist[i1] < vec_dist[i2]; });
for (int k = 0; k < K; ++k) {
neighborhood_out(b, n, k) = vec_ids[k];
distances_out(b, n, k) = vec_dist[vec_ids[k]];
}
}
}
}
};
template struct KnnBruteforceFunctor<CPUDevice, float, int>;
template struct KnnBruteforceFunctor<CPUDevice, double, int>;
} // namespace functor
} // namespace tensorflow
@@ -0,0 +1,273 @@
/* Copyright 2018 ComputerGraphics Tuebingen. All Rights Reserved.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
==============================================================================*/
// Authors: Fabian Groh, Patrick Wieschollek, Hendrik P.A. Lensch
#if GOOGLE_CUDA
#define EIGEN_USE_GPU
#include <vector>
#include "cuda_utils.h"
#include <cuda.h>
#include <helper_cuda.h>
#include <cub/cub.cuh>
#include <curand.h>
#include <curand_kernel.h>
#include <limits>
#include "knn_bruteforce_op.h"
#include "tensorflow/core/util/cuda_kernel_helper.h"
template <typename Dtype, typename NBtype, int C_THREADS = 256, int C_VPT = 2>
struct BlockBFKernel;
template <typename Dtype, typename NBtype, int C_THREADS, int C_VPT>
__global__ void runBlockBFKernel(
const BlockBFKernel<Dtype, NBtype, C_THREADS, C_VPT> kernel) {
kernel();
}
template <typename Dtype, typename NBtype, int C_THREADS, int C_VPT>
struct BlockBFKernel {
void launch(int B) {
dim3 block(C_THREADS, 1);
dim3 grid(N, 1, B);
size_t shm_size = Dp * sizeof(Dtype);
runBlockBFKernel<<<grid, block, shm_size>>>((*this));
}
__device__ __forceinline__ void operator()() const {
// extern __shared__ Dtype s_shm[];
Dtype* s_shm = DynamicSharedMemory<Dtype>();
Dtype* s_point = (Dtype*)&s_shm[0];
if (N > C_THREADS * C_VPT) {
printf(
"<BlockBFKernel> Critical problem!!!!! Not enough resources spend "
"for N points!!! %d < %d \n",
C_THREADS * C_VPT, N);
return;
}
int b = blockIdx.z;
int y = blockIdx.x;
int tid = threadIdx.x;
for (int dpi = tid; dpi < Dp; dpi += blockDim.x) {
s_point[dpi] = d_data[b * N * Dp + dpi * N + y]; // not aligned with
// data!
}
__syncthreads();
Dtype thread_dists[C_VPT]; // keys
NBtype thread_ids[C_VPT]; // values
typedef cub::BlockRadixSort<Dtype, C_THREADS, C_VPT, NBtype> BlockRadixSort;
typedef cub::BlockStore<Dtype, C_THREADS, C_VPT,
cub::BLOCK_STORE_WARP_TRANSPOSE>
BlockStoreDists;
typedef cub::BlockStore<NBtype, C_THREADS, C_VPT,
cub::BLOCK_STORE_WARP_TRANSPOSE>
BlockStoreIds;
// Allocate shared memory
__shared__ union {
typename BlockRadixSort::TempStorage sort;
typename BlockStoreDists::TempStorage store_dists;
typename BlockStoreIds::TempStorage store_ids;
} temp_storage;
for (int vpt_i = 0; vpt_i < C_VPT; ++vpt_i) {
int x = vpt_i * C_THREADS + threadIdx.x;
if (x < N) {
Dtype sum = 0.f;
for (int dpi = 0; dpi < Dp; ++dpi) {
// Dtype val = d_data[b * N * Dp + dpi * N +
//x]
//- d_data[b * N * Dp + dpi * N + y];
Dtype val = d_data[b * N * Dp + dpi * N + x] - s_point[dpi];
sum += val * val;
}
thread_dists[vpt_i] = sqrt(sum);
thread_ids[vpt_i] = x;
} else {
thread_dists[vpt_i] = std::numeric_limits<Dtype>::max();
thread_ids[vpt_i] = -1;
}
}
BlockRadixSort(temp_storage.sort).Sort(thread_dists, thread_ids);
__syncthreads();
BlockStoreIds(temp_storage.store_ids)
.Store(&d_knn_ids[b * N * K + y * K], thread_ids, K);
__syncthreads();
BlockStoreDists(temp_storage.store_dists)
.Store(&d_knn_dists[b * N * K + y * K], thread_dists, K);
}
const Dtype* d_data;
Dtype* d_knn_dists;
NBtype* d_knn_ids;
int N;
int Dp;
int K;
};
template <typename Dtype, typename NBtype>
struct BlockBFKernelAttributesSetter {
template <typename T>
void setAttributes(T& kernel) {
kernel.d_data = d_data;
kernel.d_knn_dists = d_knn_dists;
kernel.d_knn_ids = d_knn_ids;
kernel.N = N;
kernel.Dp = Dp;
kernel.K = K;
}
const Dtype* d_data;
Dtype* d_knn_dists;
NBtype* d_knn_ids;
int N;
int Dp;
int K;
};
namespace tensorflow {
namespace functor {
template <typename Dtype, typename NBtype>
struct KnnBruteforceFunctor<GPUDevice, Dtype, NBtype> {
void operator()(::tensorflow::OpKernelContext* ctx, const Tensor& positions,
Tensor* neighborhood_out, Tensor* distances,
Tensor* timings) {
// printf("GPU: KNNBF! \n");
// printf("return_timings: %d \n",return_timings);
const int B = positions.dim_size(0);
const int D = positions.dim_size(1);
const int N = positions.dim_size(2);
const int K = neighborhood_out->dim_size(2);
// printf("B: %d | N: %d | K: %d \n", B, N, K);
BlockBFKernelAttributesSetter<Dtype, NBtype> attr;
attr.d_data = positions.flat<Dtype>().data();
attr.d_knn_ids = neighborhood_out->flat<NBtype>().data();
attr.d_knn_dists = distances->flat<Dtype>().data();
attr.N = N;
attr.Dp = D;
attr.K = K;
cudaEvent_t start, stop;
if (return_timings) {
cudaEventCreate(&start);
cudaEventCreate(&stop);
cudaEventRecord(start, 0);
}
// TODO: beautify
if (N <= 32) {
BlockBFKernel<Dtype, NBtype, 32, 1> knn;
attr.setAttributes(knn);
knn.launch(B);
} else if (N <= 64) {
BlockBFKernel<Dtype, NBtype, 64, 1> knn;
attr.setAttributes(knn);
knn.launch(B);
} else if (N <= 128) {
BlockBFKernel<Dtype, NBtype, 128, 1> knn;
attr.setAttributes(knn);
knn.launch(B);
} else if (N <= 256) {
BlockBFKernel<Dtype, NBtype, 128, 2> knn;
attr.setAttributes(knn);
knn.launch(B);
} else if (N <= 512) {
BlockBFKernel<Dtype, NBtype, 128, 4> knn;
attr.setAttributes(knn);
knn.launch(B);
} else if (N <= 1024) {
BlockBFKernel<Dtype, NBtype, 256, 4> knn;
attr.setAttributes(knn);
knn.launch(B);
} else if (N <= 2048) {
BlockBFKernel<Dtype, NBtype, 256, 8> knn;
attr.setAttributes(knn);
knn.launch(B);
} else if (N <= 4096) {
BlockBFKernel<Dtype, NBtype, 512, 8> knn;
attr.setAttributes(knn);
knn.launch(B);
} else if (N <= 1024 * 8) {
BlockBFKernel<Dtype, NBtype, 1024, 8> knn;
attr.setAttributes(knn);
knn.launch(B);
} else {
printf(
"point sets greater then 8k are note yet supported!! Change to "
"knn_graph operation!! \n");
}
if (return_timings) {
float time;
cudaEventRecord(stop, 0);
cudaEventSynchronize(stop);
cudaEventElapsedTime(&time, start, stop);
// printf("complete elapsed time for KNNBf: %f ms
//\n", time);
Dtype time2 = time;
cudaMemcpy(timings->flat<Dtype>().data(), &time2, sizeof(Dtype),
cudaMemcpyHostToDevice);
cudaEventDestroy(start);
cudaEventDestroy(stop);
}
cudaDeviceSynchronize();
getLastCudaError("KNNBF execution failed");
checkCudaErrors(cudaDeviceSynchronize());
}
bool return_timings;
};
template struct KnnBruteforceFunctor<GPUDevice, float, int>;
// // too much shared memory
// template struct KnnBruteforceFunctor<GPUDevice, double, int>;
} // namespace functor
} // namespace tensorflow
#endif // GOOGLE_CUDA
+81
View File
@@ -0,0 +1,81 @@
/* Copyright 2018 ComputerGraphics Tuebingen. All Rights Reserved.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
==============================================================================*/
// Authors: Fabian Groh, Patrick Wieschollek, Hendrik P.A. Lensch
#include "knn_bruteforce_op.h"
#include <stdio.h>
#include <type_traits>
#include "tensorflow/core/framework/op.h"
#include "tensorflow/core/framework/op_kernel.h"
namespace tensorflow {
// Forward-Pass (CPU, GPU)
// --------------------------------------------------
template <typename Device, typename Dtype>
class KnnBruteforceOp : public OpKernel {
public:
explicit KnnBruteforceOp(OpKernelConstruction* ctx) : OpKernel(ctx) {
OP_REQUIRES_OK(ctx, ctx->GetAttr("K", &K));
OP_REQUIRES_OK(ctx, ctx->GetAttr("return_timings", &return_timings));
}
void Compute(OpKernelContext* ctx) override {
const Tensor& positions = ctx->input(0);
const Tensor& neighborhood_in = ctx->input(1);
const int B = positions.shape().dim_size(0);
const int N = positions.shape().dim_size(2);
Tensor* neighborhood_out = nullptr;
Tensor* distances = nullptr;
Tensor* timings = nullptr;
OP_REQUIRES_OK(ctx, ctx->allocate_output(0, TensorShape({B, N, K}),
&neighborhood_out));
OP_REQUIRES_OK(ctx,
ctx->allocate_output(1, TensorShape({B, N, K}), &distances));
OP_REQUIRES_OK(ctx, ctx->allocate_output(2, TensorShape({1}), &timings));
::tensorflow::functor::KnnBruteforceFunctor<Device, Dtype, int> knnBFF;
knnBFF.return_timings = return_timings;
knnBFF(ctx, positions, neighborhood_out, distances, timings);
}
private:
TF_DISALLOW_COPY_AND_ASSIGN(KnnBruteforceOp);
int K;
bool return_timings;
// int subBatch;
};
#define REGISTER_CUSTOM_OP(NAME, DEVICE, T) \
REGISTER_KERNEL_BUILDER( \
Name(#NAME).Device(DEVICE_##DEVICE).TypeConstraint<T>("T"), \
NAME##Op<DEVICE##Device, T>)
REGISTER_CUSTOM_OP(KnnBruteforce, CPU, float);
#ifdef GOOGLE_CUDA
REGISTER_CUSTOM_OP(KnnBruteforce, GPU, float);
#endif // GOOGLE_CUDA
#undef REGISTER_CUSTOM_OP
} // namespace tensorflow
+44
View File
@@ -0,0 +1,44 @@
/* Copyright 2018 ComputerGraphics Tuebingen. All Rights Reserved.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
==============================================================================*/
// Authors: Fabian Groh, Patrick Wieschollek, Hendrik P.A. Lensch
#ifndef LIB_KNN_BF_OP_H_
#define LIB_KNN_BF_OP_H_
#include "tensorflow/core/framework/op_kernel.h"
namespace tensorflow {
class OpKernelContext;
class Tensor;
using CPUDevice = Eigen::ThreadPoolDevice;
using GPUDevice = Eigen::GpuDevice;
} // namespace tensorflow
namespace tensorflow {
namespace functor {
template <typename Device, typename Dtype, typename NBtype>
struct KnnBruteforceFunctor {
void operator()(::tensorflow::OpKernelContext *ctx, const Tensor &positions,
Tensor *neighborhood_out, Tensor *distances, Tensor *timings);
bool return_timings;
};
} // namespace functor
} // namespace tensorflow
#endif // LIB_KNN_BF_OP_H_
+128
View File
@@ -0,0 +1,128 @@
#!/usr/bin/env python
# -*- coding: utf-8 -*-
# Copyright 2017 ComputerGraphics Tuebingen. All Rights Reserved.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
# ==============================================================================
# Authors: Fabian Groh, Patrick Wieschollek, Hendrik P.A. Lensch
import numpy as np
import tensorflow as tf
from tabulate import tabulate
from scipy.spatial.distance import pdist, squareform
np.random.seed(42)
tf.set_random_seed(42)
class FakePointCloud(object):
"""docstring for FakePointCloud"""
def __init__(self, B, N, K, Din, Dout, Dp, N2=1, scaling=1):
super(FakePointCloud, self).__init__()
assert K < N
self.B = B
self.N = N
self.K = K
self.Din = Din
self.Dout = Dout
self.Dp = Dp
self.N2 = N2
dtype = np.float64
def find_neighbors(positions, K):
# B, Dpos, N
all_neighbors = []
for batch in positions:
distances = squareform(pdist(batch.T, 'euclidean'))
all_neighbors.append(np.argsort(distances, axis=1)[:, :K])
return np.array(all_neighbors).transpose(0, 2, 1)
def random_values(shape):
# return (np.random.randn(*shape) * 100).astype(np.int32).astype(np.float32)
# return (np.random.randn(*shape) * 100).astype(np.int32).astype(np.float32)
return np.random.randn(*shape).astype(np.float32)
self.theta = random_values([1, self.Dp, self.Din, self.Dout]).astype(dtype)
self.bias = random_values([self.Din, self.Dout]).astype(dtype)
self.position = random_values([self.B, self.Dp, self.N]).astype(dtype)
self.features = random_values([self.B, self.Din, self.N]).astype(dtype)
self.neighborhood = find_neighbors(
self.position, self.K).astype(dtype=np.int32)
def init_ops(self, dtype=np.float32):
self.theta_op = tf.convert_to_tensor(self.theta.astype(dtype))
self.bias_op = tf.convert_to_tensor(self.bias.astype(dtype))
self.features_op = tf.convert_to_tensor(self.features.astype(dtype))
self.position_op = tf.convert_to_tensor(self.position.astype(dtype))
self.neighborhood_op = tf.convert_to_tensor(self.neighborhood)
def expected_feature_shape(self):
return [self.B, self.Din, self.N]
def expected_output_shape(self):
return [self.B, self.Dout, self.N]
class VerboseTestCase(tf.test.TestCase):
def assertAllClose(self, a, b, rtol=1e-6, atol=1e-6):
max_outputs = 20
def max_tol(b):
return atol + rtol * np.abs(b)
if not np.allclose(a, b, rtol=rtol, atol=atol):
cond = np.logical_or(
np.abs(a - b) > atol + rtol * np.abs(b),
np.isnan(a) != np.isnan(b))
lines = []
if a.ndim:
shape = a.shape
a = a.flatten()
b = b.flatten()
cond = np.logical_or(
np.abs(a - b) > atol + rtol * np.abs(b),
np.isnan(a) != np.isnan(b))
idxArr = np.arange(a.shape[0])[np.where(cond)]
xArr = a[np.where(cond)]
yArr = b[np.where(cond)]
for idx, x, y in zip(idxArr, xArr, yArr):
idx = np.unravel_index(idx, shape)
lines.append((idx, x, y, np.abs(x - y), max_tol(y)))
max_outputs -= 1
if max_outputs == 0:
break
print(tabulate(lines, headers=["index", "actual", "expected",
"diff", "max-tol"]))
print("diff (sum): ", np.abs(a - b).sum())
print("diff (max): ", np.abs(a - b).max())
print("diff (mean): ", np.abs(a - b).mean())
else:
# np.where is broken for scalars
x, y = a, b
lines.append((x, y, np.abs(x - y), max_tol(y)))
print(tabulate(lines, headers=["actual", "expected",
"diff", "max-tol"]))
assert np.allclose(a, b, rtol=rtol, atol=atol, equal_nan=True), "failed"
+41
View File
@@ -0,0 +1,41 @@
// ComputerGraphics Tuebingen, 2018
#include "tensorflow/core/framework/op.h"
#include "tensorflow/core/framework/shape_inference.h"
namespace tensorflow {
using ::tensorflow::shape_inference::InferenceContext;
using ::tensorflow::shape_inference::ShapeHandle;
REGISTER_OP("KnnBruteforce")
.Input("position: T") // position: each datapoint in nd space [B,Dp, N].
.Output("neighborhood_out: NBtype") // neighborhood_out: all K nearest
// neighbors [B, N, K].
.Output("distances: T") // distances: all K nearest distances
// [B, N, K].
.Output("timings: T") // timings:
// [1]
.Attr("K: int")
.Attr("return_timings: bool = false")
.Attr("T: realnumbertype")
.Attr("NBtype: {int32} = DT_INT32")
.SetShapeFn([](::tensorflow::shape_inference::InferenceContext* c) {
const auto position = c->input(0);
const auto neighborhood_out = c->input(1);
int K;
c->GetAttr("K", &K);
auto B = c->Dim(position, 0);
auto N = c->Dim(position, 2);
c->set_output(0, c->MakeShape({B, N, K}));
c->set_output(1, c->MakeShape({B, N, K}));
return Status::OK();
});
} // namespace tensorflow
// doc: K: number of neighbors.
+29
View File
@@ -0,0 +1,29 @@
#!/usr/bin/env python
# -*- coding: utf-8 -*-
# Copyright 2017 ComputerGraphics Tuebingen. All Rights Reserved.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
# ==============================================================================
# Authors: Fabian Groh, Patrick Wieschollek, Hendrik P.A. Lensch
import unittest
import glob
operations = [fn[:-3] for fn in glob.glob('test_*.py') if not '_all' in fn]
suite = unittest.TestSuite()
for op in operations:
suite.addTest(unittest.defaultTestLoader.loadTestsFromName(op))
unittest.TextTestRunner().run(suite)
+89 -61
View File
@@ -18,91 +18,119 @@
# Authors: Fabian Groh, Patrick Wieschollek, Hendrik P.A. Lensch
from PointTestCase import TPC, PointTestCase, summary
from misc import FakePointCloud, VerboseTestCase
import tensorflow as tf
import numpy as np
from __init__ import flex_convolution
case = FakePointCloud(B=2, N=32, K=4, Din=2, Dout=6, Dp=3)
class FlexConvTest(PointTestCase):
class FlexConvTest(VerboseTestCase):
def __init__(self, methodName="runTest"):
super(FlexConvTest, self).__init__(methodName)
def _forward(self, use_gpu=False, force_gpu=False):
self.init_ops()
def _forward(self, use_gpu=False, force_gpu=False, dtype=np.float32):
case.init_ops(dtype=dtype)
with self.test_session(use_gpu=use_gpu, force_gpu=use_gpu) as sess:
actual_op = flex_convolution(self.features_op,
self.position_op, self.neighborhood_op,
self.theta_op, self.bias_op)
actual_op = flex_convolution(case.features_op,
case.position_op, case.neighborhood_op,
case.theta_op, case.bias_op)
actual = sess.run(actual_op)
return actual
def test_forward(self):
def test_forward(self, dtype=np.float32):
cpu = self._forward(use_gpu=False)
gpu = self._forward(use_gpu=True)
self.assertAllClose(cpu, gpu, 1e-5, 1e-5)
self.assertAllClose(cpu, gpu, 1e-4)
def _backward_features(self, use_gpu=False):
self.init_ops()
with self.test_session(use_gpu=use_gpu, force_gpu=use_gpu):
actual_op = flex_convolution(self.features_op,
self.position_op, self.neighborhood_op,
self.theta_op, self.bias_op)
graph_features_grad, num_features_grad = tf.test.compute_gradient(
[self.features_op], [self.features.shape], actual_op,
TPC.expected_output_shape())[0]
summary(num_features_grad, graph_features_grad, 'self.features')
def test_forward_features_gpu_floats(self):
cpu32 = self._forward(use_gpu=True, dtype=np.float32)
cpu64 = self._forward(use_gpu=True, dtype=np.float64)
self.assertAllClose(cpu32, cpu64)
err = tf.test.compute_gradient_error([self.features_op],
[self.features.shape],
actual_op, TPC.expected_output_shape())
self.assertLess(err, 1e-2)
def _backward_features(self, use_gpu=False, dtype=np.float32, numdiff=True):
case.init_ops(dtype=dtype)
with self.test_session(use_gpu=use_gpu, force_gpu=use_gpu) as sess:
actual_op = flex_convolution(case.features_op,
case.position_op, case.neighborhood_op,
case.theta_op, case.bias_op)
if numdiff:
return tf.test.compute_gradient(
[case.features_op], [case.features.shape], actual_op,
case.expected_output_shape())[0]
else:
return sess.run(tf.gradients(actual_op, [case.features_op]))[0]
def _backward_bias(self, use_gpu=False):
self.init_ops()
with self.test_session(use_gpu=use_gpu, force_gpu=use_gpu):
actual_op = flex_convolution(self.features_op,
self.position_op, self.neighborhood_op,
self.theta_op, self.bias_op)
def _backward_bias(self, use_gpu=False, dtype=np.float32, numdiff=True):
case.init_ops(dtype=dtype)
with self.test_session(use_gpu=use_gpu, force_gpu=use_gpu) as sess:
actual_op = flex_convolution(case.features_op,
case.position_op, case.neighborhood_op,
case.theta_op, case.bias_op)
graph_bias_grad, num_bias_grad = tf.test.compute_gradient(
[self.bias_op], [self.bias.shape], actual_op,
TPC.expected_output_shape())[0]
summary(num_bias_grad, graph_bias_grad, 'self.bias')
if numdiff:
return tf.test.compute_gradient(
[case.bias_op], [case.bias.shape], actual_op,
case.expected_output_shape())[0]
else:
return sess.run(tf.gradients(actual_op, [case.bias_op]))[0]
err = tf.test.compute_gradient_error([self.bias_op],
[self.bias.shape], actual_op,
TPC.expected_output_shape())
self.assertLess(err, 1e-2)
def _backward_theta(self, use_gpu=False, dtype=np.float32, numdiff=True):
case.init_ops(dtype=dtype)
with self.test_session(use_gpu=use_gpu, force_gpu=use_gpu) as sess:
actual_op = flex_convolution(case.features_op,
case.position_op, case.neighborhood_op,
case.theta_op, case.bias_op)
def _backward_theta(self, use_gpu=False):
self.init_ops()
with self.test_session(use_gpu=use_gpu, force_gpu=use_gpu):
actual_op = flex_convolution(self.features_op,
self.position_op, self.neighborhood_op,
self.theta_op, self.bias_op)
if numdiff:
return tf.test.compute_gradient(
[case.theta_op], [case.theta.shape], actual_op,
case.expected_output_shape())[0]
else:
return sess.run(tf.gradients(actual_op, [case.theta_op]))[0]
graph_theta_grad, num_theta_grad = tf.test.compute_gradient(
[self.theta_op], [self.theta.shape], actual_op,
TPC.expected_output_shape())[0]
summary(num_theta_grad, graph_theta_grad, 'self.theta')
def test_backward_features_cpu_float64(self):
actual, expected = self._backward_features(use_gpu=False, dtype=np.float64)
self.assertAllClose(actual, expected)
err = tf.test.compute_gradient_error([self.theta_op],
[self.theta.shape], actual_op,
TPC.expected_output_shape())
self.assertLess(err, 1e-2)
def test_backward_bias_cpu_float64(self):
actual, expected = self._backward_bias(use_gpu=False, dtype=np.float64)
self.assertAllClose(actual, expected)
def test_backward_theta_cpu_float64(self):
actual, expected = self._backward_theta(use_gpu=False, dtype=np.float64)
self.assertAllClose(actual, expected)
def test_backward_features_gpu_float64(self):
actual, expected = self._backward_features(use_gpu=True, dtype=np.float64)
self.assertAllClose(actual, expected)
def test_backward_bias_gpu_float64(self):
actual, expected = self._backward_bias(use_gpu=True, dtype=np.float64)
self.assertAllClose(actual, expected)
def test_backward_theta_gpu_float64(self):
actual, expected = self._backward_theta(use_gpu=True, dtype=np.float64)
self.assertAllClose(actual, expected)
def test_backward_features_gpu_float32(self, dtype=np.float32):
cpu = self._backward_features(use_gpu=False, dtype=dtype, numdiff=False)
gpu = self._backward_features(use_gpu=True, dtype=dtype, numdiff=False)
self.assertAllClose(cpu, gpu)
def test_backward_bias_gpu_float32(self, dtype=np.float32):
cpu = self._backward_bias(use_gpu=False, dtype=dtype, numdiff=False)
gpu = self._backward_bias(use_gpu=True, dtype=dtype, numdiff=False)
self.assertAllClose(cpu, gpu, 1e-5)
def test_backward_theta_gpu_float32(self, dtype=np.float32):
cpu = self._backward_theta(use_gpu=False, dtype=dtype, numdiff=False)
gpu = self._backward_theta(use_gpu=True, dtype=dtype, numdiff=False)
self.assertAllClose(cpu, gpu)
def test_backward_features(self):
self._backward_features(use_gpu=False)
self._backward_features(use_gpu=True)
def test_backward_bias(self):
self._backward_bias(use_gpu=False)
self._backward_bias(use_gpu=True)
def test_backward_theta(self):
self._backward_theta(use_gpu=False)
self._backward_theta(use_gpu=True)
if __name__ == '__main__':
+84 -67
View File
@@ -18,98 +18,115 @@
# Authors: Fabian Groh, Patrick Wieschollek, Hendrik P.A. Lensch
from PointTestCase import TPC, PointTestCase, summary
from misc import FakePointCloud, VerboseTestCase
import tensorflow as tf
import numpy as np
from __init__ import flex_convolution_transpose
case = FakePointCloud(B=2, N=32, K=4, Din=2, Dout=6, Dp=3)
class FlexDeconvTest(PointTestCase):
class FlexConvTest(VerboseTestCase):
def __init__(self, methodName="runTest"):
super(FlexDeconvTest, self).__init__(methodName)
super(FlexConvTest, self).__init__(methodName)
def _forward(self, use_gpu=False, force_gpu=False):
self.init_ops()
case.init_ops()
with self.test_session(use_gpu=use_gpu, force_gpu=use_gpu) as sess:
actual = flex_convolution_transpose(self.features_op,
self.position_op, self.neighborhood_op,
self.theta_op, self.bias_op)
actual = sess.run(actual)
actual_op = flex_convolution_transpose(case.features_op,
case.position_op,
case.neighborhood_op,
case.theta_op, case.bias_op)
actual = sess.run(actual_op)
return actual
def test_forward(self):
cpu = self._forward(use_gpu=False)
gpu = self._forward(use_gpu=True)
summary(cpu, gpu, 'self.features')
self.assertAllClose(cpu, gpu, rtol=1e-05)
self.assertAllClose(cpu, gpu, 1e-4)
def _backward_features(self, use_gpu=False):
self.init_ops()
with self.test_session(use_gpu=use_gpu, force_gpu=use_gpu):
actual_op = flex_convolution_transpose(self.features_op,
self.position_op,
self.neighborhood_op,
self.theta_op, self.bias_op)
def _backward_features(self, use_gpu=False, dtype=np.float32, numdiff=True):
case.init_ops(dtype=dtype)
with self.test_session(use_gpu=use_gpu, force_gpu=use_gpu) as sess:
actual_op = flex_convolution_transpose(case.features_op,
case.position_op,
case.neighborhood_op,
case.theta_op, case.bias_op)
if numdiff:
return tf.test.compute_gradient(
[case.features_op], [case.features.shape], actual_op,
case.expected_output_shape())[0]
else:
return sess.run(tf.gradients(actual_op, [case.features_op]))[0]
graph_features_grad, num_features_grad = tf.test.compute_gradient(
[self.features_op], [self.features.shape], actual_op,
TPC.expected_output_shape())[0]
summary(num_features_grad, graph_features_grad,
'self.features', max_outputs=1200000)
def _backward_bias(self, use_gpu=False, dtype=np.float32, numdiff=True):
case.init_ops(dtype=dtype)
with self.test_session(use_gpu=use_gpu, force_gpu=use_gpu) as sess:
actual_op = flex_convolution_transpose(case.features_op,
case.position_op,
case.neighborhood_op,
case.theta_op, case.bias_op)
err = tf.test.compute_gradient_error([self.features_op],
[self.features.shape],
actual_op, TPC.expected_output_shape())
self.assertLess(err, 1e-2)
if numdiff:
return tf.test.compute_gradient(
[case.bias_op], [case.bias.shape], actual_op,
case.expected_output_shape())[0]
else:
return sess.run(tf.gradients(actual_op, [case.bias_op]))[0]
def _backward_bias(self, use_gpu=False):
self.init_ops()
with self.test_session(use_gpu=use_gpu, force_gpu=use_gpu):
actual_op = flex_convolution_transpose(self.features_op,
self.position_op,
self.neighborhood_op,
self.theta_op, self.bias_op)
def _backward_theta(self, use_gpu=False, dtype=np.float32, numdiff=True):
case.init_ops(dtype=dtype)
with self.test_session(use_gpu=use_gpu, force_gpu=use_gpu) as sess:
actual_op = flex_convolution_transpose(case.features_op,
case.position_op,
case.neighborhood_op,
case.theta_op, case.bias_op)
graph_bias_grad, num_bias_grad = tf.test.compute_gradient(
[self.bias_op], [self.bias.shape], actual_op,
TPC.expected_output_shape())[0]
summary(num_bias_grad, graph_bias_grad, 'self.bias')
if numdiff:
return tf.test.compute_gradient(
[case.theta_op], [case.theta.shape], actual_op,
case.expected_output_shape())[0]
else:
return sess.run(tf.gradients(actual_op, [case.theta_op]))[0]
err = tf.test.compute_gradient_error([self.bias_op],
[self.bias.shape], actual_op,
TPC.expected_output_shape())
self.assertLess(err, 1e-2)
def test_backward_features_cpu_float64(self):
actual, expected = self._backward_features(use_gpu=False, dtype=np.float64)
self.assertAllClose(actual, expected)
def _backward_theta(self, use_gpu=False):
self.init_ops()
with self.test_session(use_gpu=use_gpu, force_gpu=use_gpu):
actual_op = flex_convolution_transpose(self.features_op,
self.position_op,
self.neighborhood_op,
self.theta_op, self.bias_op)
def test_backward_bias_cpu_float64(self):
actual, expected = self._backward_bias(use_gpu=False, dtype=np.float64)
self.assertAllClose(actual, expected)
graph_theta_grad, num_theta_grad = tf.test.compute_gradient(
[self.theta_op], [self.theta.shape], actual_op,
TPC.expected_output_shape())[0]
summary(num_theta_grad, graph_theta_grad, 'self.theta')
def test_backward_theta_cpu_float64(self):
actual, expected = self._backward_theta(use_gpu=False, dtype=np.float64)
self.assertAllClose(actual, expected)
err = tf.test.compute_gradient_error([self.theta_op],
[self.theta.shape], actual_op,
TPC.expected_output_shape())
self.assertLess(err, 1e-2)
def test_backward_features_gpu_float64(self):
actual, expected = self._backward_features(use_gpu=True, dtype=np.float64)
self.assertAllClose(actual, expected)
def test_backward_features(self):
self._backward_features(use_gpu=False)
self._backward_features(use_gpu=True)
def test_backward_bias_gpu_float64(self):
actual, expected = self._backward_bias(use_gpu=True, dtype=np.float64)
self.assertAllClose(actual, expected)
def test_backward_bias(self):
self._backward_bias(use_gpu=False)
self._backward_bias(use_gpu=True)
def test_backward_theta_gpu_float64(self):
actual, expected = self._backward_theta(use_gpu=True, dtype=np.float64)
self.assertAllClose(actual, expected)
def test_backward_theta(self):
self._backward_theta(use_gpu=False)
self._backward_theta(use_gpu=True)
def test_backward_features_gpu_float32(self, dtype=np.float32):
cpu = self._backward_features(use_gpu=False, dtype=dtype, numdiff=False)
gpu = self._backward_features(use_gpu=True, dtype=dtype, numdiff=False)
self.assertAllClose(cpu, gpu)
def test_backward_bias_gpu_float32(self, dtype=np.float32):
cpu = self._backward_bias(use_gpu=False, dtype=dtype, numdiff=False)
gpu = self._backward_bias(use_gpu=True, dtype=dtype, numdiff=False)
self.assertAllClose(cpu, gpu, 1e-5)
def test_backward_theta_gpu_float32(self, dtype=np.float32):
cpu = self._backward_theta(use_gpu=False, dtype=dtype, numdiff=False)
gpu = self._backward_theta(use_gpu=True, dtype=dtype, numdiff=False)
self.assertAllClose(cpu, gpu)
if __name__ == '__main__':
+62 -47
View File
@@ -18,70 +18,85 @@
# Authors: Fabian Groh, Patrick Wieschollek, Hendrik P.A. Lensch
from PointTestCase import PointTestCase
from misc import FakePointCloud, VerboseTestCase
import tensorflow as tf
import numpy as np
from __init__ import flex_pooling
case = FakePointCloud(B=2, N=32, K=4, Din=2, Dout=6, Dp=3)
class FlexPoolTest(PointTestCase):
def __init__(self, methodName="runTest"):
super(FlexPoolTest, self).__init__(methodName)
def _forward(self, use_gpu=False):
self.init_ops()
with self.test_session(use_gpu=use_gpu, force_gpu=use_gpu) as sess:
actual_op, winner_op = flex_pooling(self.features_op, self.neighborhood_op)
actual = sess.run(actual_op)
return actual
class FlexPoolTest(VerboseTestCase):
def __init__(self, methodName="runTest"):
super(FlexPoolTest, self).__init__(methodName)
def test_forward(self):
cpu = self._forward(use_gpu=False)
gpu = self._forward(use_gpu=True)
self.assertAllClose(cpu, gpu)
def _forward(self, use_gpu=False, dtype=np.float32):
case.init_ops(dtype=dtype)
with self.test_session(use_gpu=use_gpu, force_gpu=use_gpu) as sess:
actual_op, winner_op = flex_pooling(
case.features_op, case.neighborhood_op)
actual = sess.run(actual_op)
return actual
def test_backward(self):
cpu, winner_cpu = self._backward(use_gpu=False)
gpu, winner_gpu = self._backward(use_gpu=True)
self.assertAllClose(cpu, gpu)
self.assertAllClose(cpu[winner_cpu == 0].sum(), 0)
self.assertAllClose(gpu[winner_gpu == 0].sum(), 0)
def test_forward_same_float32(self):
cpu = self._forward(use_gpu=False, dtype=np.float32)
gpu = self._forward(use_gpu=True, dtype=np.float32)
self.assertAllClose(cpu, gpu)
def _backward(self, use_gpu=False):
self.init_ops()
with self.test_session(use_gpu=use_gpu, force_gpu=use_gpu) as sess:
actual_op, winner_op = flex_pooling(
self.features_op,
self.neighborhood_op)
def test_forward_same_float64(self):
cpu = self._forward(use_gpu=False, dtype=np.float64)
gpu = self._forward(use_gpu=True, dtype=np.float64)
self.assertAllClose(cpu, gpu)
graph_features_grad = tf.gradients(actual_op, [self.features_op])[0]
def test_backward_same_float32(self):
cpu, winner_cpu = self._backward(use_gpu=False, dtype=np.float32)
gpu, winner_gpu = self._backward(use_gpu=True, dtype=np.float32)
self.assertAllClose(winner_cpu, winner_gpu)
self.assertAllClose(cpu, gpu)
dx, winner = sess.run([graph_features_grad, winner_op])
return dx, winner
def test_backward_same_float64(self):
cpu, winner_cpu = self._backward(use_gpu=False, dtype=np.float64)
gpu, winner_gpu = self._backward(use_gpu=True, dtype=np.float64)
self.assertAllClose(winner_cpu, winner_gpu)
self.assertAllClose(cpu, gpu)
def _simple_backward(self, use_gpu=False):
# BN
x = np.array([[[1], [2], [5], [3]]]).transpose(0, 2, 1)
n = np.array([[[0, 1, 2, 3], [1, 2, 3, 0], [2, 3, 0, 1], [3, 0, 1, 2, ]]]).transpose(0, 2, 1)
def _backward(self, use_gpu=False, dtype=np.float32):
case.init_ops(dtype=dtype)
with self.test_session(use_gpu=use_gpu, force_gpu=use_gpu) as sess:
actual_op, winner_op = flex_pooling(
case.features_op,
case.neighborhood_op)
x = tf.convert_to_tensor(x.astype(np.float32))
n = tf.convert_to_tensor(n.astype(np.int32))
graph_features_grad = tf.gradients(actual_op, [case.features_op])[0]
with self.test_session(use_gpu=use_gpu, force_gpu=use_gpu) as sess:
actual_op, winner_op = flex_pooling(x, n)
graph_features_grad = tf.gradients(actual_op, [x])[0]
return sess.run(graph_features_grad)
dx, winner = sess.run([graph_features_grad, winner_op])
return dx, winner
def test_backward_simple(self):
cpu = self._simple_backward(use_gpu=False)
cpu[0, 0, 2] -= 4
self.assertEqual(cpu.sum(), 0)
def _simple_backward(self, use_gpu=False):
# BN
x = np.array([[[1], [2], [5], [3]]]).transpose(0, 2, 1)
n = np.array([[[0, 1, 2, 3], [1, 2, 3, 0], [2, 3, 0, 1],
[3, 0, 1, 2, ]]]).transpose(0, 2, 1)
gpu = self._simple_backward(use_gpu=True)
gpu[0, 0, 2] -= 4
self.assertEqual(gpu.sum(), 0)
x = tf.convert_to_tensor(x.astype(np.float32))
n = tf.convert_to_tensor(n.astype(np.int32))
with self.test_session(use_gpu=use_gpu, force_gpu=use_gpu) as sess:
actual_op, winner_op = flex_pooling(x, n)
graph_features_grad = tf.gradients(actual_op, [x])[0]
return sess.run(graph_features_grad)
def test_backward_simple_cpu(self):
cpu = self._simple_backward(use_gpu=False)
cpu[0, 0, 2] -= 4
self.assertEqual(cpu.sum(), 0)
def test_backward_simple_gpu(self):
gpu = self._simple_backward(use_gpu=True)
gpu[0, 0, 2] -= 4
self.assertEqual(gpu.sum(), 0)
if __name__ == '__main__':
tf.test.main()
tf.test.main()
+66
View File
@@ -0,0 +1,66 @@
#!/usr/bin/env python
# -*- coding: utf-8 -*-
# Copyright 2017 ComputerGraphics Tuebingen. All Rights Reserved.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
# ==============================================================================
# Authors: Fabian Groh, Patrick Wieschollek, Hendrik P.A. Lensch
from misc import FakePointCloud, VerboseTestCase
import tensorflow as tf
import numpy as np
from scipy.spatial.distance import pdist, squareform
from __init__ import knn_bruteforce
case = FakePointCloud(B=2, N=32, K=4, Din=2, Dout=6, Dp=3)
case = FakePointCloud(B=1, N=4, K=2, Din=1, Dout=1, Dp=3)
def python_bruteforce(positions, K):
# B, Dpos, N
all_neighbors = []
all_distances = []
for batch in positions:
distances = squareform(pdist(batch.T, 'euclidean'))
all_neighbors.append(np.argsort(distances, axis=1)[:, :K])
all_distances.append(np.sort(distances, axis=1)[:, :K])
return np.array(all_neighbors), np.array(all_distances)
class KnnBruteforceTest(VerboseTestCase):
def __init__(self, methodName="runTest"):
super(KnnBruteforceTest, self).__init__(methodName)
def _forward(self, use_gpu=False):
case.init_ops()
expected_nn, expected_dist = python_bruteforce(case.position, K=4)
with self.test_session(use_gpu=use_gpu, force_gpu=use_gpu) as sess:
actual_nn, actual_dist, _ = knn_bruteforce(case.position_op, K=4)
actual_nn, actual_dist = sess.run([actual_nn, actual_dist])
self.assertAllClose(expected_dist, actual_dist)
self.assertAllClose(expected_nn, actual_nn)
def test_forward_cpu(self):
self._forward(use_gpu=False)
def test_forward_gpu(self):
self._forward(use_gpu=True)
if __name__ == '__main__':
tf.test.main()