【问题标题】:Updating directives OpenACC更新指令 OpenACC
【发布时间】:2017-05-30 15:48:50
【问题描述】:

当我在顶部循环中有一个内核时,为什么我不能使用这两个指令:

#pragma acc update device(hbias[0:n_hidden],W[0:n_hidden][0:n_visible])   
#pragma acc update device(vbias[0:n_visible)

我需要在下面的代码中更新这些变量hbiasvbiasW,但它不起作用:

void RBM::contrastive_divergence(int train_X[6][6], double learning_rate, int k) {
    double r= rand() / (RAND_MAX + 1.0);

        int * input = new int[n_visible];
        double *ph_mean = new double[n_hidden];
        int *ph_sample = new int[n_hidden];
        double *nv_means = new double[n_visible];
        int *nv_samples = new int[n_visible];
        double *nh_means = new double[n_hidden];
        int *nh_samples = new int[n_hidden];

        #pragma acc kernels
        for (int i = 0; i<train_N; i++) {


            for (int j = 0; j< n_visible; j++){
                input[j] = train_X[i][j];
            }


            sample_h_given_v(input, ph_mean, ph_sample,r);

            for (int step = 0; step<k; step++) {
                if (step == 0) {
                    gibbs_hvh(ph_sample, nv_means, nv_samples, nh_means, nh_samples,r);
                }
                else {
                    gibbs_hvh(nh_samples, nv_means, nv_samples, nh_means, nh_samples,r);
                }
            }


            for (int i = 0; i<n_hidden; i++) {
                for (int j = 0; j<n_visible; j++) {

                 W[i][j] += learning_rate * (ph_mean[i] * input[j] - nh_means[i] * nv_samples[j]) / N;

                }
                hbias[i] += learning_rate * (ph_sample[i] - nh_means[i]) / N;

            }
    //this directive
       #pragma acc update device(hbias[0:n_hidden],W[0:n_hidden][0:n_visible])


            for (int i = 0; i<n_visible; i++) {
                vbias[i] += learning_rate * (input[i] - nv_samples[i]) / N;
            }
    //and this directive
       #pragma acc update device(vbias[0:n_visible)
     }

        delete[] input;
        delete[] ph_mean;
        delete[] ph_sample;
        delete[] nv_means;
        delete[] nv_samples;
        delete[] nh_means;
        delete[] nh_samples;
    }

但是当我在每个嵌套循环上有许多分离的内核时,我可以更新变量:

   void RBM::contrastive_divergence(int train_X[6][6], double learning_rate, int k) {
    double r= rand() / (RAND_MAX + 1.0);

        int * input = new int[n_visible];
        double *ph_mean = new double[n_hidden];
        int *ph_sample = new int[n_hidden];
        double *nv_means = new double[n_visible];
        int *nv_samples = new int[n_visible];
        double *nh_means = new double[n_hidden];
        int *nh_samples = new int[n_hidden];


    for (int i = 0; i<train_N; i++) {

            #pragma acc kernels
                for (int j = 0; j< n_visible; j++){
                    input[j] = train_X[i][j];
                }


                sample_h_given_v(input, ph_mean, ph_sample,r);
            #pragma acc kernels
                for (int step = 0; step<k; step++) {
                    if (step == 0) {
                        gibbs_hvh(ph_sample, nv_means, nv_samples, nh_means, nh_samples,r);
                    }
                    else {
                        gibbs_hvh(nh_samples, nv_means, nv_samples, nh_means, nh_samples,r);
                    }
                }

            #pragma acc kernels
            {  
                for (int i = 0; i<unhidden; i++) {
                    for (int j = 0; j<n_visible; j++) {

                        W[i][j] += learning_rate * (ph_mean[i] * input[j] - nh_means[i] * nv_samples[j]) / N;

                    }
                hbias[i] += learning_rate * (ph_sample[i] - nh_means[i]) / N;

                }
        //this directive
            #pragma acc update device(hbias[0:n_hidden],W[0:n_hidden][0:n_visible])
            }


            #pragma acc kernels
            {
                for (int i = 0; i<n_visible; i++) {
                    vbias[i] += learning_rate * (input[i] - nv_samples[i]) / N;
                }

            //and this directive
                #pragma acc update device(vbias[0:n_visible)
            }
     }

        delete[] input;
        delete[] ph_mean;
        delete[] ph_sample;
        delete[] nv_means;
        delete[] nv_samples;
        delete[] nh_means;
        delete[] nh_samples;
    }

【问题讨论】:

  • 你用的是什么编译器?如果是 PGI,您能否发布 -Minfo=accel 的输出?看起来这应该可行。如果您在内核之外立即添加一个数据区域会怎样?这应该不是必需的,但可能会有所帮助。
  • 是的,我使用 PGI 编译器。基本上,我需要对一些变量进行归约操作。但它也没有被编译器接受。我需要为每次完成的迭代同步一些变量值。否则,结果将不正确。我将尝试添加一个数据区域指令,看看我会得到什么。谢谢
  • 我使用了这个命令 $ pgc++ - fast - acc - ta = tesla:managed - Minfo = accel - o task2 。 /RBM.cpp && echo "编译成功!"在没有任何附加指令的内核上,输出如下:
  • 如果您使用 -ta=tesla:managed 则更新指令将被忽略,并且数据移动将作为来自 CUDA 驱动程序的数据迁移触发。

标签: c++ parallel-processing directive openacc pgi


【解决方案1】:

“更新”指令只能在主机代码中使用,因为数据移动必须从主机启动。您不能将它们放在计算区域内。

这段代码有很多问题。首先,对嵌套循环使用相同的索引变量(在这种情况下为“i”)可能是不好的做法。尽管范围规则允许这样做,但很难判断代码应该使用哪个“i”。

外部的“i”循环并行化可能不安全,因此您不应该将“kernels”指令放在该循环之外。也许如果您将“输入”数组私有化,然后在更新 vbias、hbias、W 数组时使用原子,它可能会起作用,但您的性能会很差。 (您还需要确定其他数组是否需要私有化或者是全局的,因此需要原子操作)。

我的建议是首先将“#pragma acc 并行循环”放在内部循环周围,一次一个。在继续下一个之前,确保每个都有效。此外,我非常怀疑“step”循环是否可并行化,因此您很可能需要并行化“gibbs_hvh”子例程中的循环。

由于您使用的是 CUDA 统一内存 (-ta=tesla:managed),因此可能不需要添加数据区域。但是,如果您计划将来不使用托管内存,下一步将是在外部“i”循环周围添加数据指令(或在程序的较高点,然后使用更新指令在外部“我”循环)。

【讨论】:

  • 请注意,Alwaleed 将他的代码离线发送给我,看看我们能做什么。并行化和卸载内部循环工作得很好,但由于工作量小(6),速度很慢。由于依赖于“W”数组,外部“train_N”循环不可并行化。它在 sample_h_given_v 例程中用于初始化 mean_ph 数组,但随后在循环主体中更新。虽然我们可以使用原子来解决更新共享“W”、“hbias”和“vbais”数组的问题,但对“W”的依赖会阻止并行化(或至少获得正确的答案)
猜你喜欢
  • 2015-11-04
  • 2022-01-20
  • 2016-05-01
  • 2014-08-23
  • 2014-05-08
  • 2013-07-05
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多