14

ノートブックでopencv242+VS2010を使用しています。
OpenCVでGPUブロックの簡単なテストを試みましたが、GPUがCPUコードよりも100倍遅いことがわかりました。このコードでは、カラー画像をグレースケール画像に変換し、cvtColorの関数を使用します

これが私のコードです。PART1はCPUコード(test cpu RGB2GRAY)、PART2は画像をGPUにアップロード、PART3はGPU RGB2GRAY、PART4はCPURGB2GRAYです。私がとても不思議に思う3つのことがあります:

1私のコードでは、part1は0.3msですが、part4(part1とまったく同じです)は40msです!!!
2GPUに画像をアップロードするpart2は6000msです!!!
3 Part3(GPUコード)は11msですが、この単純な画像では非常に遅いです!

    #include "StdAfx.h"
    #include <iostream>
    #include "opencv2/opencv.hpp"
    #include "opencv2/gpu/gpu.hpp"
    #include "opencv2/gpu/gpumat.hpp"
    #include "opencv2/core/core.hpp"
    #include "opencv2/highgui/highgui.hpp"
    #include <cuda.h>
    #include <cuda_runtime_api.h>
    #include <ctime>
    #include <windows.h>

    using namespace std;
    using namespace cv;
    using namespace cv::gpu;

    int main()
    {
        LARGE_INTEGER freq;
        LONGLONG QPart1,QPart6;
        double dfMinus, dfFreq, dfTim;
        QueryPerformanceFrequency(&freq);
        dfFreq = (double)freq.QuadPart;

        cout<<getCudaEnabledDeviceCount()<<endl;
        Mat img_src = imread("d:\\CUDA\\train.png", 1);

        // PART1 CPU code~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
        // From color image to grayscale image.
        QueryPerformanceCounter(&freq);
        QPart1 = freq.QuadPart;
        Mat img_gray;
        cvtColor(img_src,img_gray,CV_BGR2GRAY);
        QueryPerformanceCounter(&freq);
        QPart6 = freq.QuadPart;
        dfMinus = (double)(QPart6 - QPart1);
        dfTim = 1000 * dfMinus / dfFreq;
        printf("CPU RGB2GRAY running time is %.2f ms\n\n",dfTim);

        // PART2 GPU upload image~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
        GpuMat gimg_src;
        QueryPerformanceCounter(&freq);
        QPart1 = freq.QuadPart;
        gimg_src.upload(img_src);
        QueryPerformanceCounter(&freq);
        QPart6 = freq.QuadPart;
        dfMinus = (double)(QPart6 - QPart1);
        dfTim = 1000 * dfMinus / dfFreq;
        printf("Read image running time is %.2f ms\n\n",dfTim);

        GpuMat dst1;
        QueryPerformanceCounter(&freq);
        QPart1 = freq.QuadPart;

        /*dst.upload(src_host);*/
        dst1.upload(imread("d:\\CUDA\\train.png", 1));

        QueryPerformanceCounter(&freq);
        QPart6 = freq.QuadPart;
        dfMinus = (double)(QPart6 - QPart1);
        dfTim = 1000 * dfMinus / dfFreq;
        printf("Read image running time 2 is %.2f ms\n\n",dfTim);

        // PART3~ GPU code~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
        // gpuimage From color image to grayscale image.
        QueryPerformanceCounter(&freq);
        QPart1 = freq.QuadPart;

        GpuMat gimg_gray;
        gpu::cvtColor(gimg_src,gimg_gray,CV_BGR2GRAY);

        QueryPerformanceCounter(&freq);
        QPart6 = freq.QuadPart;
        dfMinus = (double)(QPart6 - QPart1);
        dfTim = 1000 * dfMinus / dfFreq;
        printf("GPU RGB2GRAY running time is %.2f ms\n\n",dfTim);

        // PART4~CPU code(again)~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

        // gpuimage From color image to grayscale image.
        QueryPerformanceCounter(&freq);
        QPart1 = freq.QuadPart;
        Mat img_gray2;
        cvtColor(img_src,img_gray2,CV_BGR2GRAY);
        BOOL i_test=QueryPerformanceCounter(&freq);
        printf("%d \n",i_test);
        QPart6 = freq.QuadPart;
        dfMinus = (double)(QPart6 - QPart1);
        dfTim = 1000 * dfMinus / dfFreq;
        printf("CPU RGB2GRAY running time is %.2f ms\n\n",dfTim);

        cvWaitKey();
        getchar();
        return 0;
    }
4

5 に答える 5

29

上記のほとんどの答えは実際には間違っています。もちろん、20.000倍遅い理由は、「CPUクロック速度が速い」、「GPUにコピーする必要がある」ためではありません(受け入れられた回答)。これらは要因ですが、嫌なほど並行している問題に対して、はるかに多くの計算能力があるという事実を省略していると言うことによって。20.000xのパフォーマンスの違いは、後者が非常にばかげているためです。ここでの作者は、簡単ではない何かが間違っていることを知っていました。解決:

あなたの問題は、CUDAを初期化する必要があるということです!常に最初の画像に対して初期化され、木星と火星の配置にもよりますが、通常1〜10秒かかります。今これを試してみてください。計算を2回実行してから、両方の時間を計測します。この場合、速度が20.000xではなく、マグナタイドと同じオーダー内にあることがわかるでしょう。これはばかげています。この初期化について何かできますか?いいえ、私が知っていることではありません。それは障害です。

編集:投稿を読み直しました。あなたはあなたがノートブックで走っていると言います。それらはしばしばぼろぼろのGPUと公正なターボを備えたCPUを持っています。

于 2015-06-07T12:40:16.843 に答える
26

cvtColorはあまり作業を行っていません。灰色にするために必要なのは、平均3つの数値だけです。

CPUのcvColorコードはSSE2命令を使用して、一度に最大8ピクセルを処理します。また、TBBを使用している場合は、すべてのコア/ハイパースレッドを使用しているため、CPUはGPUの10倍のクロック速度で実行され、最終的には必要ありません。データをGPUにコピーして戻します。

于 2012-08-22T13:55:37.103 に答える
9

複数回実行してみてください...

-----------http://opencv.willowgarage.com/wiki/OpenCV%20GPU%20FAQパフォーマンスから 抜粋

なぜ最初の関数呼び出しが遅いのですか?

これは、初期化のオーバーヘッドが原因です。最初のGPU関数呼び出しで、CudaRuntimeAPIは暗黙的に初期化されます。また、一部のGPUコードは、最初の使用時にビデオカード用にコンパイルされます(ジャストインタイムコンパイル)。したがって、パフォーマンス測定のためには、ダミーの関数呼び出しを実行してから、時間テストを実行する必要があります。

アプリケーションがGPUコードを1回だけ実行することが重要な場合は、複数の実行にわたって永続的なコンパイルキャッシュを使用できます。詳細については、nvccのドキュメントをお読みください(CUDA_DEVCODE_CACHE環境変数)。

于 2012-09-24T05:36:31.897 に答える
1

cvtColourは小さな操作であり、GPUで実行することで得られるパフォーマンスの向上は、ホスト(CPU)とデバイス(GPU)間のメモリ転送時間よりもはるかに重要です。このメモリ転送の遅延を最小限に抑えることは、GPUコンピューティングの主要な課題です。

于 2013-06-12T03:17:59.400 に答える
0

どのGPUがありますか?

計算の互換性を確認してください。おそらくそれが理由です。

https://developer.nvidia.com/cuda-gpus

これは、CC1.3および2.0のバイナリイメージを備えたデバイスで実行する準備ができていることを意味します。すべての新しいプラットフォームでは、1.3のPTXコードがバイナリイメージにJITされます。CC 1.1および1.2を搭載したデバイスの場合、1.1のPTXはJITされます。CC 1.0を搭載したデバイスの場合、使用可能なコードはなく、関数は例外をスローします。JITコンパイルが最初に実行されるプラットフォームの場合、実行は遅くなります。

http://docs.opencv.org/modules/gpu/doc/introduction.html

于 2013-04-16T13:22:52.677 に答える