在 Tensorflow 中添加 GPU Op
Adding a GPU Op in Tensorflow
我正在尝试在 this document. The difference being that I am trying to implement a GPU based op. The op I'm trying to add is the cuda op from here(cuda_op.py、cuda_op_kernel.cc、cuda_op_kernel.cu.cc)之后松散地向 TensorFlow 添加一个新操作。我正在尝试在 tensorflow 之外编译这些文件,并使用 tf.load_op_library
将它们拉入。我做了一些更改,所以这是我的文件:
cuda_op_kernel.cc
#include "tensorflow/core/framework/op.h"
#include "tensorflow/core/framework/shape_inference.h"
#include "tensorflow/core/framework/op_kernel.h"
using namespace tensorflow; // NOLINT(build/namespaces)
REGISTER_OP("AddOne")
.Input("input: int32")
.Output("output: int32")
.SetShapeFn([](::tensorflow::shape_inference::InferenceContext* c) {
c->set_output(0, c->input(0));
return Status::OK();
});
void AddOneKernelLauncher(const int* in, const int N, int* out);
class AddOneOp : public OpKernel {
public:
explicit AddOneOp(OpKernelConstruction* context) : OpKernel(context) {}
void Compute(OpKernelContext* context) override {
// Grab the input tensor
const Tensor& input_tensor = context->input(0);
auto input = input_tensor.flat<int32>();
// Create an output tensor
Tensor* output_tensor = NULL;
OP_REQUIRES_OK(context, context->allocate_output(0, input_tensor.shape(),
&output_tensor));
auto output = output_tensor->template flat<int32>();
// Set all but the first element of the output tensor to 0.
const int N = input.size();
// Call the cuda kernel launcher
AddOneKernelLauncher(input.data(), N, output.data());
}
};
REGISTER_KERNEL_BUILDER(Name("AddOne").Device(DEVICE_GPU), AddOneOp);
cuda_op_kernel.cu
#define EIGEN_USE_GPU
#include <cuda.h>
#include <stdio.h>
__global__ void AddOneKernel(const int* in, const int N, int* out) {
for (int i = blockIdx.x * blockDim.x + threadIdx.x; i < N;
i += blockDim.x * gridDim.x) {
out[i] = in[i] + 1;
}
}
void AddOneKernelLauncher(const int* in, const int N, int* out) {
AddOneKernel<<<32, 256>>>(in, N, out);
cudaError_t cudaerr = cudaDeviceSynchronize();
if (cudaerr != cudaSuccess)
printf("kernel launch failed with error \"%s\".\n", cudaGetErrorString(cudaerr));
}
CMakeLists.txt
cmake_minimum_required(VERSION 3.5)
#found from running python -c 'import tensorflow as tf; print(tf.sysconfig.get_include())'
include_directories(/usr/local/lib/python3.5/dist-packages/tensorflow/include)
find_package(CUDA)
#set flags based on tutorial
set (CMAKE_CXX_FLAGS "--std=c++11 -fPIC -O2 -D_GLIBCXX_USE_CXX11_ABI=0")
#pass flags to c++ compiler
SET(CUDA_PROPAGATE_HOST_FLAGS ON)
#create library
cuda_add_library(
cuda_op SHARED
src/cuda_op_kernel.cu
src/cuda_op_kernel.cc
OPTIONS -gencode=arch=compute_20,code=sm_20)
#copy test file to build folder
configure_file(src/test.py test.py COPYONLY)
test.py
import tensorflow as tf
mod = tf.load_op_library('./libcuda_op.so')
with tf.Session() as sess:
start = [5,4,3,2,1]
print(start)
print(mod.add_one(start).eval())
我能够编译 运行 test.py
成功,但输出总是 [0 0 0 0 0]
。如果我将 AddOneKernel<<<32, 256>>>(in, N, out);
替换为 for (int i = 0; i < N; i++) out[i] = in[i] + 1;
并将 DEVICE_GPU
替换为 DEVICE_CPU
,则 op 输出正确的值 [6 5 4 3 2]
(具有完全相同的 CMakeList.txt
)。
知道如何获得正确的返回值吗?
我不完全记得我在哪里找到了 CUDA 的 cmake 东西,但这些选项不知何故弄乱了编译。将 CMakeLists.txt
中的 cuda_add_library
替换为以下内容可解决问题。
#no options needed
cuda_add_library(
cuda_op SHARED
src/cuda_op_kernel.cu
src/cuda_op_kernel.cc)
ubuntu@cubuntu:~/Desktop/src/src/build$ cmake ..
-- 配置完成
-- 生成完成
-- 构建文件已写入:/home/ubuntu/Desktop/src/src/build
ubuntu@cubuntu:~/Desktop/src/src/build$ make
[33%] 构建 NVCC(设备)对象 CMakeFiles/cuda_op.d/cuda_op_generated_cuda_op_kernel.cu.o
nvcc 警告:'compute_20'、'sm_20' 和 'sm_21' 架构已弃用,可能会在未来的版本中删除(使用 -Wno-deprecated-gpu-targets 来抑制警告)。
nvcc 警告:'compute_20'、'sm_20' 和 'sm_21' 架构已弃用,可能会在未来的版本中删除(使用 -Wno-deprecated-gpu-targets 来抑制警告)。
正在扫描目标的依赖项cuda_op
[66%] 构建 CXX 对象 CMakeFiles/cuda_op.dir/cuda_op_kernel.cc.o
/home/ubuntu/Desktop/src/src/cuda_op_kernel.cc:1:17: 错误:“tensorflow”不是命名空间名称
使用命名空间张量流; // NOLINT(build/namespaces)
查看Tensorflow adding GPU op support
上的当前官方GPU ops构建说明
nvcc -std=c++11 -c -o cuda_op_kernel.cu.o cuda_op_kernel.cu.cc \
${TF_CFLAGS[@]} -D GOOGLE_CUDA=1 -x cu -Xcompiler -fPIC
g++ -std=c++11 -shared -o cuda_op_kernel.so cuda_op_kernel.cc \
cuda_op_kernel.cu.o ${TF_CFLAGS[@]} -fPIC -lcudart ${TF_LFLAGS[@]}
正如它所说,请注意,如果您的 CUDA 库未安装在 /usr/local/lib64
中,您需要在上面的第二个 (g++) 命令中明确指定路径。例如,如果您的 CUDA 安装在 /usr/local/cuda-8.0
.
,则添加 -L /usr/local/cuda-8.0/lib64/
此外,请注意在某些 linux 设置中,nvcc 编译步骤需要额外的选项。将 -D_MWAITXINTRIN_H_INCLUDED
添加到 nvcc 命令行以避免来自 mwaitxintrin.h
.
的错误
我正在尝试在 this document. The difference being that I am trying to implement a GPU based op. The op I'm trying to add is the cuda op from here(cuda_op.py、cuda_op_kernel.cc、cuda_op_kernel.cu.cc)之后松散地向 TensorFlow 添加一个新操作。我正在尝试在 tensorflow 之外编译这些文件,并使用 tf.load_op_library
将它们拉入。我做了一些更改,所以这是我的文件:
cuda_op_kernel.cc
#include "tensorflow/core/framework/op.h"
#include "tensorflow/core/framework/shape_inference.h"
#include "tensorflow/core/framework/op_kernel.h"
using namespace tensorflow; // NOLINT(build/namespaces)
REGISTER_OP("AddOne")
.Input("input: int32")
.Output("output: int32")
.SetShapeFn([](::tensorflow::shape_inference::InferenceContext* c) {
c->set_output(0, c->input(0));
return Status::OK();
});
void AddOneKernelLauncher(const int* in, const int N, int* out);
class AddOneOp : public OpKernel {
public:
explicit AddOneOp(OpKernelConstruction* context) : OpKernel(context) {}
void Compute(OpKernelContext* context) override {
// Grab the input tensor
const Tensor& input_tensor = context->input(0);
auto input = input_tensor.flat<int32>();
// Create an output tensor
Tensor* output_tensor = NULL;
OP_REQUIRES_OK(context, context->allocate_output(0, input_tensor.shape(),
&output_tensor));
auto output = output_tensor->template flat<int32>();
// Set all but the first element of the output tensor to 0.
const int N = input.size();
// Call the cuda kernel launcher
AddOneKernelLauncher(input.data(), N, output.data());
}
};
REGISTER_KERNEL_BUILDER(Name("AddOne").Device(DEVICE_GPU), AddOneOp);
cuda_op_kernel.cu
#define EIGEN_USE_GPU
#include <cuda.h>
#include <stdio.h>
__global__ void AddOneKernel(const int* in, const int N, int* out) {
for (int i = blockIdx.x * blockDim.x + threadIdx.x; i < N;
i += blockDim.x * gridDim.x) {
out[i] = in[i] + 1;
}
}
void AddOneKernelLauncher(const int* in, const int N, int* out) {
AddOneKernel<<<32, 256>>>(in, N, out);
cudaError_t cudaerr = cudaDeviceSynchronize();
if (cudaerr != cudaSuccess)
printf("kernel launch failed with error \"%s\".\n", cudaGetErrorString(cudaerr));
}
CMakeLists.txt
cmake_minimum_required(VERSION 3.5)
#found from running python -c 'import tensorflow as tf; print(tf.sysconfig.get_include())'
include_directories(/usr/local/lib/python3.5/dist-packages/tensorflow/include)
find_package(CUDA)
#set flags based on tutorial
set (CMAKE_CXX_FLAGS "--std=c++11 -fPIC -O2 -D_GLIBCXX_USE_CXX11_ABI=0")
#pass flags to c++ compiler
SET(CUDA_PROPAGATE_HOST_FLAGS ON)
#create library
cuda_add_library(
cuda_op SHARED
src/cuda_op_kernel.cu
src/cuda_op_kernel.cc
OPTIONS -gencode=arch=compute_20,code=sm_20)
#copy test file to build folder
configure_file(src/test.py test.py COPYONLY)
test.py
import tensorflow as tf
mod = tf.load_op_library('./libcuda_op.so')
with tf.Session() as sess:
start = [5,4,3,2,1]
print(start)
print(mod.add_one(start).eval())
我能够编译 运行 test.py
成功,但输出总是 [0 0 0 0 0]
。如果我将 AddOneKernel<<<32, 256>>>(in, N, out);
替换为 for (int i = 0; i < N; i++) out[i] = in[i] + 1;
并将 DEVICE_GPU
替换为 DEVICE_CPU
,则 op 输出正确的值 [6 5 4 3 2]
(具有完全相同的 CMakeList.txt
)。
知道如何获得正确的返回值吗?
我不完全记得我在哪里找到了 CUDA 的 cmake 东西,但这些选项不知何故弄乱了编译。将 CMakeLists.txt
中的 cuda_add_library
替换为以下内容可解决问题。
#no options needed
cuda_add_library(
cuda_op SHARED
src/cuda_op_kernel.cu
src/cuda_op_kernel.cc)
ubuntu@cubuntu:~/Desktop/src/src/build$ cmake ..
-- 配置完成
-- 生成完成
-- 构建文件已写入:/home/ubuntu/Desktop/src/src/build
ubuntu@cubuntu:~/Desktop/src/src/build$ make
[33%] 构建 NVCC(设备)对象 CMakeFiles/cuda_op.d/cuda_op_generated_cuda_op_kernel.cu.o
nvcc 警告:'compute_20'、'sm_20' 和 'sm_21' 架构已弃用,可能会在未来的版本中删除(使用 -Wno-deprecated-gpu-targets 来抑制警告)。
nvcc 警告:'compute_20'、'sm_20' 和 'sm_21' 架构已弃用,可能会在未来的版本中删除(使用 -Wno-deprecated-gpu-targets 来抑制警告)。
正在扫描目标的依赖项cuda_op
[66%] 构建 CXX 对象 CMakeFiles/cuda_op.dir/cuda_op_kernel.cc.o /home/ubuntu/Desktop/src/src/cuda_op_kernel.cc:1:17: 错误:“tensorflow”不是命名空间名称 使用命名空间张量流; // NOLINT(build/namespaces)
查看Tensorflow adding GPU op support
上的当前官方GPU ops构建说明nvcc -std=c++11 -c -o cuda_op_kernel.cu.o cuda_op_kernel.cu.cc \
${TF_CFLAGS[@]} -D GOOGLE_CUDA=1 -x cu -Xcompiler -fPIC
g++ -std=c++11 -shared -o cuda_op_kernel.so cuda_op_kernel.cc \
cuda_op_kernel.cu.o ${TF_CFLAGS[@]} -fPIC -lcudart ${TF_LFLAGS[@]}
正如它所说,请注意,如果您的 CUDA 库未安装在 /usr/local/lib64
中,您需要在上面的第二个 (g++) 命令中明确指定路径。例如,如果您的 CUDA 安装在 /usr/local/cuda-8.0
.
-L /usr/local/cuda-8.0/lib64/
此外,请注意在某些 linux 设置中,nvcc 编译步骤需要额外的选项。将 -D_MWAITXINTRIN_H_INCLUDED
添加到 nvcc 命令行以避免来自 mwaitxintrin.h
.