#c #compilation #tensorflow
#c #Сборник #tensorflow
Вопрос:
Я новичок в c , но мне удалось разработать оригинальную новую операцию процессора для tensorflow. Теперь я хотел бы разработать операцию для графического процессора. У меня есть небольшой опыт работы с open-cl. Я следую приведенному здесь руководству:
https://www.tensorflow.org/versions/r0.11/how_tos/adding_an_op/index.html#gpu-support
ниже приведен мой код на c , за которым следует файл cuda. Я ничего не делаю с этим кодом. Он компилируется правильно, но каждый раз, когда я пытаюсь его запустить, я получаю дамп ядра. В целях отладки я удалил все содержимое моего класса, чтобы я мог сосредоточиться на проблеме. Это также говорит по существу об этом:
*** Error in `/usr/bin/python': free(): invalid next size (fast): 0x00007fef04033ba0 ***
вот d_grid_gpu.cc файл:
#include "tensorflow/core/framework/op.h"
#include "tensorflow/core/framework/op_kernel.h"
REGISTER_OP("DGridGpu")
.Input("grid: int32")
.Attr("start_x: int = 0")
.Attr("start_y: int = 0")
.Attr("stop_x: int = 28")
.Attr("stop_y: int = 28")
.Attr("size_x: int = 28")
.Attr("size_y: int = 28")
.Attr("wall_height: float = 2.5")
.Output("prev: int32");
using namespace tensorflow;
void run();
class DGridGpuOp : public OpKernel {
public:
explicit DGridGpuOp(OpKernelConstruction* context) : OpKernel(context) {
}
void Compute(OpKernelContext* context) override {
run();
}
};
REGISTER_KERNEL_BUILDER(Name("DGridGpu").Device(DEVICE_GPU), DGridGpuOp);
вот d_grid_gpu.cu.cc файл:
#if GOOGLE_CUDA
#define EIGEN_USE_GPU
#include "third_party/eigen3/unsupported/Eigen/CXX11/Tensor"
// content here
#include <stdio.h>
#define SIZE 1024
__global__ void VectorAdd(int *a, int *b, int *c, int n)
{
int i = threadIdx.x;
if (i < n)
c[i] = a[i] b[i];
}
void run() {
int *a, *b, *c;
int *d_a, *d_b, *d_c;
a = (int *)malloc(SIZE*sizeof(int));
b = (int *)malloc(SIZE*sizeof(int));
c = (int *)malloc(SIZE*sizeof(int));
cudaMalloc( amp;d_a, SIZE*sizeof(int));
cudaMalloc( amp;d_b, SIZE*sizeof(int));
cudaMalloc( amp;d_c, SIZE*sizeof(int));
for( int i = 0; i < SIZE; i )
{
a[i] = i;
b[i] = i;
c[i] = 0;
}
cudaMemcpy( d_a, a, SIZE*sizeof(int), cudaMemcpyHostToDevice );
cudaMemcpy( d_b, b, SIZE*sizeof(int), cudaMemcpyHostToDevice );
cudaMemcpy( d_c, c, SIZE*sizeof(int), cudaMemcpyHostToDevice );
// blocks, threads
VectorAdd<<< 1, SIZE >>>(d_a, d_b, d_c, SIZE);
cudaMemcpy( c, d_c, SIZE*sizeof(int), cudaMemcpyDeviceToHost );
for( int i = 0; i < 10; i)
printf("output : c[%d] = %dn", i, c[i]);
free(a);
free(b);
free(c);
cudaFree(d_a);
cudaFree(d_b);
cudaFree(d_c);
}
#endif
вот код, который я использую для сборки операционной системы:
TF_INC=$(python -c 'import tensorflow as tf; print(tf.sysconfig.get_include())')
nvcc -std=c 11 -c -o d_grid_gpu.cu.o d_grid_gpu.cu.cc
-I $TF_INC -D GOOGLE_CUDA=1 -x cu -Xcompiler -fPIC --expt-relaxed-constexpr
g -std=c 11 -shared -o d_grid_gpu.so d_grid_gpu.cc
d_grid_gpu.cu.o -I $TF_INC -fPIC -lcudart -D_GLIBCXX_USE_CXX11_ABI=0 -L /usr/lib/x86_64-linux-gnu/
that’s all I have. as I say, the cuda code does nothing, but the whole op compiles. I have python code that calls this library which I have not included. I do believe my cuda is working. I am using ubuntu 16.10 and cuda 8
edit — some of the error before the dump:
*** Error in `/usr/bin/python': free(): invalid next size (fast): 0x00007f34f4033ba0 ***
======= Backtrace: =========
/lib/x86_64-linux-gnu/libc.so.6( 0x790cb)[0x7f35664f20cb]
/lib/x86_64-linux-gnu/libc.so.6( 0x8275a)[0x7f35664fb75a]
/lib/x86_64-linux-gnu/libc.so.6(cfree 0x4c)[0x7f35664ff18c]
/usr/local/lib/python2.7/dist-packages/tensorflow/python/_pywrap_tensorflow.so( 0x22223a1)[0x7f354d7953a1]
/usr/local/lib/python2.7/dist-packages/tensorflow/python/_pywrap_tensorflow.so( 0x222b6a2)[0x7f354d79e6a2]
/usr/local/lib/python2.7/dist-packages/tensorflow/python/_pywrap_tensorflow.so( 0x221fd90)[0x7f354d792d90]
/usr/local/lib/python2.7/dist-packages/tensorflow/python/_pywrap_tensorflow.so(_ZN5Eigen26NonBlockingThreadPoolTemplIN10tensorflow6thread16EigenEnvironmentEE10WorkerLoopEi 0x3c8)[0x7f354d9f4ce8]
/usr/local/lib/python2.7/dist-packages/tensorflow/python/_pywrap_tensorflow.so(_ZNSt17_Function_handlerIFvvEZN10tensorflow6thread16EigenEnvironment12CreateThreadESt8functionIS0_EEUlvE_E9_M_invokeERKSt9_Any_data 0x22)[0x7f354d9f44b2]
/usr/lib/x86_64-linux-gnu/libstdc .so.6( 0xbb8f0)[0x7f354b0408f0]
/lib/x86_64-linux-gnu/libpthread.so.0( 0x770a)[0x7f356684770a]
/lib/x86_64-linux-gnu/libc.so.6(clone 0x5f)[0x7f35665810af]
======= Memory map: ========
200000000-200100000 rw-s 3cf997000 00:06 570 /dev/nvidiactl
... more memory map here...
Я надеюсь, что это полезно. Я попробовал это, и на мгновение мне показалось, что это работает, но я не могу воспроизвести результаты.
редактировать: я немного изменил свой код, но все равно получаю дамп памяти.
d_grid_gpu.cc
#include "tensorflow/core/framework/op.h"
#include "tensorflow/core/framework/op_kernel.h"
REGISTER_OP("DGridGpu")
.Input("grid: int32")
.Output("prev: int32");
using namespace tensorflow;
void run(const int * in, int * out);
class DGridGpuOp : public OpKernel {
public:
explicit DGridGpuOp(OpKernelConstruction* context) : OpKernel(context) {
}
void Compute(OpKernelContext* context) override {
Tensor* prev_h = NULL;
const Tensoramp; grid_h = context->input(0);
auto grid = grid_h.flat<int32>();
OP_REQUIRES_OK(context, context->allocate_output(
0,
TensorShape({64}), amp;prev_h));
auto prev = prev_h->flat<int32>();
run(grid.data(), prev.data()); // do something to grid_host and move it to prev_host
//exit
}
};
REGISTER_KERNEL_BUILDER(Name("DGridGpu").Device(DEVICE_GPU), DGridGpuOp);
//REGISTER_KERNEL_BUILDER(Name("DGridGpu").Device(DEVICE_CPU), DGridGpuOp);
d_grid_gpu.cu.cc
#if GOOGLE_CUDA
#define EIGEN_USE_GPU
#include "third_party/eigen3/unsupported/Eigen/CXX11/Tensor"
#include <stdio.h>
#define SIZE 20
__global__ void VectorAdd( const int *in, int *out, int n)
{
int i = threadIdx.x;
if (i < n)
out[i] = in[i] out[i];
}
void run(const int * in, int * out) {
VectorAdd<<< 1, SIZE >>>( in, out, SIZE);
}
#endif
Комментарии:
1. можете ли вы указать полную трассировку ошибок? также у вас не определен какой-либо код gpu.
2. Я немного изменил вопрос.
Ответ №1:
Вкратце, более серьезная проблема заключается в том, что вы пытаетесь управлять памятью самостоятельно, но Tensorflow уже знает, как это сделать за вас. Вы должны использовать Tensorflow механизмы управления памятью; вам не нужен какой-либо из malloc
, free
, cudaMalloc
, cudaFree
, cudaMemcpy
код.
Я бы начал с модификации ядра GPU из руководства:
https://github.com/tensorflow/tensorflow/blob/r0.11/tensorflow/g3doc/how_tos/adding_an_op/cuda_op_kernel.cc
https://github.com/tensorflow/tensorflow/blob/r0.11/tensorflow/g3doc/how_tos/adding_an_op/cuda_op_kernel.cu.cc
Ядро получает в качестве входных данных буферы, которые уже выделены в памяти GPU. Вам просто нужно передать их адреса в ядро GPU.
Чтобы выделить буфер для вашего вывода, вы должны использовать OpKernelContext::allocate_output()
для выделения тензора и передачи его адреса в ядро вашего графического процессора. Также есть allocate_temp()
для выделения временных буферов. Приведенный выше пример распределяет свои выходные данные таким образом. По умолчанию на GPU при этом выделяется буфер в памяти GPU. Таким образом, нет необходимости самостоятельно выделять память или копировать данные с устройства на хост.
В данный момент вы заполняете буфер, загружаемый в качестве входных данных в ваше ядро на хосте, а затем копируете его на графический процессор вручную. Возможно, проще всего либо заполнить этот буфер с помощью графического процессора, либо использовать отдельный оператор Tensorflow CPU для создания входных данных; Tensorflow при необходимости выполняет копирование на хост -> устройство.
Я надеюсь, что это поможет!
Комментарии:
1. Я полагаю, что вы правы, но я не могу заставить это работать сам. Я немного изменил свой вопрос. Не могли бы вы взглянуть на новый код?
Ответ №2:
Если я изменю d_grid_gpu.cc следующим образом я могу заставить метод ‘run ()’ работать без дампа памяти. Наиболее важным является изменение в строке ‘REGISTER_KERNEL_BUILDER’. Теперь он содержит спецификацию ‘DEVICE_CPU’ вместо ‘DEVICE_GPU’. Хотя я почему-то чувствую, что разработчики tensorflow сделали бы это не так.
#include "tensorflow/core/framework/op.h"
#include "tensorflow/core/framework/op_kernel.h"
REGISTER_OP("DGridGpu")
.Input("grid: int32")
.Attr("start_x: int = 0")
.Attr("start_y: int = 0")
.Attr("stop_x: int = 28")
.Attr("stop_y: int = 28")
.Attr("size_x: int = 28")
.Attr("size_y: int = 28")
.Attr("wall_height: float = 2.5")
.Output("prev: int32");
using namespace tensorflow;
void run();
class DGridGpuOp : public OpKernel {
public:
explicit DGridGpuOp(OpKernelConstruction* context) : OpKernel(context) {
}
void Compute(OpKernelContext* context) override {
Tensor grid;
Tensor * prev;
grid = context->input(0);
auto grid_host = grid.template flat<int32>();
OP_REQUIRES_OK(context, context->allocate_output(
0,
TensorShape({64}), amp;prev));
auto prev_host = prev->flat<int32>();
run(); // do something to grid_host and move it to grid_prev
//exit
}
};
REGISTER_KERNEL_BUILDER(Name("DGridGpu").Device(DEVICE_CPU), DGridGpuOp);