0

我正在尝试在OpenMP 的帮助下实现Viterbi 算法。到目前为止,我的测试表明并行程序的执行时间大约是顺序程序执行时间的 4 倍。这是我的代码:

#include <omp.h>
#include <stdio.h>
#include <time.h>

#define K 39 // num states
#define T 1500 // num obs sequence

int states[K];
double transition[K][K];
double emission[K][K];
double init_prob[K];
int observation[T];

using namespace std;

void generateValues()
{
    srand(time(NULL));

    for(int i=0; i<T; i++)
    {
        observation[i] = rand() % K;
    }

    for(int i=0; i<K; i++)
    {
        states[i] = i;
        init_prob[i] = (double)rand() / (double)RAND_MAX;
        for(int j=0;j<K;j++)
        {
            transition[i][j] = (double)rand() / (double)RAND_MAX;
            srand(time(NULL));
            emission[i][j] = (double)rand() / (double)RAND_MAX;
        }
    }
}

int* viterbi(int *S, double *initp, int *Y, double A[][K], double B[][K])
{
    double T1[K][T];
    int T2[K][T];

    #pragma omp parallel for
    for(int i=0; i<K; ++i)
    {
        T1[i][0] = initp[i];
        T2[i][0] = 0;
    }

    for(int i=1; i<T; ++i)
    {
        double max, temp;
        int argmax;

        #pragma omp parallel for private (max, temp, argmax)
        for(int j=0; j<K; ++j)
        {
            max = -1;

            #pragma omp parallel for
            for(int k=0; k<K; ++k)
            {
                temp = T1[k][i-1] * A[k][j] * B[k][Y[i-1]];

                if(temp > max)
                {
                    max = temp;
                    argmax = k;
                }
            }

            T1[j][i] = max;
            T2[j][i] = argmax;
        }
    }

    int Z[T];
    int X[T];   

    double max = -1, temp;
    #pragma omp parallel for
    for(int k=0; k<K; ++k)
    {
        temp = T1[k][T-1];

        if(temp > max)
        {           
            max = temp;
            Z[T-1] = k;
        }
    }

    X[T-1] = S[Z[T-1]];

    for(int i=T-1; i>0; --i)
    {
        Z[i-1] = T2[Z[i]][i];
        X[i-1] = S[Z[i-1]];
    }

    return X;
}

int* viterbiNoOmp(int *S, double *initp, int *Y, double A[][K], double B[][K]) // the same as before, minus the #pragma omp

int main()
{
    clock_t tStart;
    int *path;

    generateValues();
    double sumOmp = 0;
    for(int i=0;i<6;i++)
    {
        double start = omp_get_wtime();
        path = viterbi(states, init_prob, observation, transition, emission);
        double end = omp_get_wtime();
        sumOmp += end - start;
    }

    double sumNoOmp = 0;
    for(int i=0;i<6;i++)
    {
        tStart = clock();
        path = viterbiNoOmp(states, init_prob, observation, transition, emission);

        sumNoOmp += ((double)(clock() - tStart)/CLOCKS_PER_SEC);
    }

    for (int i=0;i<T;i++)
    {
        printf("%d, ", path[i]);
    }

    printf("\n\ntime With Omp: %f\ntime without Omp: %f", sumOmp/6, sumNoOmp/6);
    return 0;
}

我究竟做错了什么?

4

1 回答 1

0

首先,您在第一次测量中使用了该omp_get_wtime()功能,而在第二次测量中,您使用了clock().

两者都使用omp_get_wtime(),您会看到一些改进

其次,而不是使用sumNoOmp += ((double)(clock() - tStart)/CLOCKS_PER_SEC); 只是使用sumNoOmp = ((double)(clock() - tStart)/CLOCKS_PER_SEC);

现在让我们继续您的代码:尝试并行嵌套循环有点棘手尝试 #pragma omp parallel for仅用于外部循环并观察结果

于 2014-03-22T22:47:19.460 回答