проблемы при компиляции с пользовательской операцией tensorflow gpu

#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);