Обновление директив OpenACC

Когда у меня есть ядро ​​в верхнем цикле, почему я не могу использовать эти 2 директивы:

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

Мне нужно обновить эти переменные hbias, vbias, W в приведенном ниже коде, но он не будет работать:

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;
}

2

Решение

Директивы «Update» могут использоваться только в коде хоста, поскольку перемещение данных должно начинаться с хоста. Вы не можете иметь их в вычислительной области.

Есть много проблем с этим кодом. Во-первых, вероятно, плохая практика использовать ту же самую индексную переменную, в данном случае «i», для вложенных циклов. Хотя правила области видимости позволяют это сделать, трудно сказать, какое «i» предполагается использовать в коде.

Внешний цикл «i», вероятно, не безопасен для распараллеливания, поэтому не следует помещать директиву «kernels» вне этого цикла. Возможно, если вы приватизировали массив «input», а затем использовали атомики при обновлении массивов vbias, hbias, W, это может сработать, но ваша производительность будет низкой. (вам также необходимо определить, нужно ли приватизировать другие массивы или они являются глобальными, поэтому нужны атомарные операции).

Я хотел бы начать с размещения «#pragma acc параллельный цикл» вокруг внутренних циклов, по одному за раз. Убедитесь, что каждый работает, прежде чем перейти к следующему. Кроме того, я очень сомневаюсь, что «пошаговый» цикл распараллеливается, поэтому вам, скорее всего, нужно будет распараллелить циклы внутри подпрограммы «gibbs_hvh».

Поскольку вы используете унифицированную память CUDA (-ta = tesla: managed), добавление областей данных, вероятно, не требуется. Однако, если вы планируете не использовать управляемую память в будущем, следующим шагом будет добавление директив данных вокруг внешнего цикла «i» (или в более высокой точке программы, а затем использование директивы update для синхронизации данных после внешней ». я «петля).

2

Другие решения

Других решений пока нет …

По вопросам рекламы ammmcru@yandex.ru
Adblock
detector