행렬의 곱 연산으로 openBLAS cuBLAS 체감

Basic Linear Algebra Subprograms (BLAS) 행렬의 곱 연산이 C의 for 문으로 솔직하게 쓴 루틴에 비해 어느 정도인지 체감해 본다.

배경


  • 심층 학습의 구현을 이해해 가면서, 행렬의 곱 연산을 고속으로 실시하고 싶어졌다.
  • BLAS는 행렬의 곱 연산이 빠르다는 이야기를 보지만 실제로 사용해본 적은 없었다.

  • → 이번 BLAS의 성능을 체감해 본다.

    BLAS 정보



    아래의 웹사이트를 참고로 하고 있습니다.
    · Basic Linear Algebra Subprograms(Wikipedia)
    · BLAS의 간단한 사용법
    · CUDA Toolkit cuBLAS
    · 인텔(R) 수치 연산 라이브러리(MKL) 참조 설명서(PDF)

    openBLAS



    openBLAS는 멀티 스레드에서 CPU의 모든 코어를 사용하여 병렬 연산을 수행합니다.

    cuBLAS



    cuBLAS는 NVIDIA 그래픽 카드의 GPU에서 병렬 연산을 수행합니다.

    측정



    측정 내용


  • 행렬의 곱 연산 $ C = αAB + β C $ $ (A B C는 행렬, α β는 스칼라 값) $를 수행하는 gemm ()을 사용하여 측정합니다.
  • 한변 num 의 정방 행렬(아래 그림)에서, num 을 늘려 갔을 때의 소요 시간으로 비교한다.


  • 각 num으로 5회 측정하여 평균값을 플롯.

  • 결과



    그래프는 아래쪽이 좋고(소요시간이 짧음), 상측으로 갈수록 나쁘다(소요시간이 길다).


    (2017/5/5 추가)
    그래프만으로는 읽기 어렵기 때문에 num=2000일 때의 측정값을 나타냅니다.


    항목 이름
    num=2000시 소요시간(ms)
    C 루프 (col)를 1로 한 비율


    C 루프 (col)
    14902.36
    1.00

    C 루프 (행)
    17994.24
    0.83

    openBLAS (col)
    288.02
    51.74

    openBLAS (row)
    549.34
    27.13

    cublas
    20.52
    726.20

    cublasXt (bd=num)
    26.23
    568.23

    cublasXt (bd=num/2)
    32.84
    453.77


    · openBLAS는 C의 for 문의 솔직판에 비해 25 배 이상의 차이를 확인했습니다. openBLAS 놀랍습니다. 예상 이상이었습니다. C 의 for 문의 솔직판은 싱글 쓰레드이기 때문에, openBLAS 와의 차이는 4배~8배(코어수~하이퍼 쓰레드수) 정도일까라고 예상하고 있었습니다. 25배 이상의 차이가 있다고는.... 대단해.
    ・GPU의 병렬 연산 또한 대단하다. gefoce1050ti인 15K 원위의 보드에서도 솔직 C판에 비해 500배 이상의 차이를 확인할 수 있었습니다. 다음에 더 자세히 살펴 보겠습니다.

    환경




    품목
    내용


    CPU
    Intel(R) Core(TM) i7 CPU 920 @ 2.67GHz

    M/B
    GIGABYTE EX58-DS4

    메모리
    12GB

    그래픽 카드
    현인 지향 GF-GTX1050Ti-4GB/OC/SF

    OS
    우분투 16.04

    그래픽 드라이버
    nvidia-375

    CUDA
    8.0.61-1

    openBLAS
    0.2.18-1ubuntu1

    컴파일러
    gcc 우분투 5.4.0-6ubuntu1 ~ 16.04.4


    일상


  • C loop (col) , C loop (row) 컴파일시 최적화 옵션은 -O3

  • C의 for loop에서 솔직한 구현을 보여줍니다.

    C 루프 (col)


    #define MMCOL(X, di, i, j) ((X)[(j)*(di)+(i)])
    
        // C Loop (Col) 部分抜粋 
        // hst->A , hst->B , hst->C ともに num×num×sizeof(float) の メモリ領域
    
        gettimeofday(&st,NULL);
        for(int i=0;i<num;i++)
        {
            for(int j=0;j<num;j++)
            {
                float cc = 0.0;
                for(int k=0;k<num;k++)
                {
                    cc += MMCOL(hst->A,num,i,k) + MMCOL(hst->B,num,k,j);
                }
                MMCOL(hst->C,num,i,j) += cc;
            }
        }
    
        gettimeofday(&et,NULL);
    

    C 루프 (행)


    #define MMROW(X, dj, i, j) ((X)[(i)*(dj)+(j)])
    
        // C Loop (row) 部分抜粋 
        // hst->A , hst->B , hst->C ともに num×num×sizeof(float) の メモリ領域
        gettimeofday(&st,NULL);
        for(int i=0;i<num;i++)
        {
            for(int j=0;j<num;j++)
            {
                float cc = 0.0;
                for(int k=0;k<num;k++)
                {
                    cc += MMROW(hst->A,num,i,k) + MMROW(hst->B,num,k,j);
                }
                MMROW(hst->C,num,i,j) += cc;
            }
        }
        gettimeofday(&et,NULL);
    
    

    col , row 보충


  • C/C++ 언어에서는 행 우선(row Major)이지만, Fortran에서는 열 우선(Column Major).
  • BLAS 는 열 우선(Column Major).
  • openBLAS는 row Major도 사용할 수 있습니다.
  • cuBLAS는 Column Major 전용입니다.

  • BLAS 행렬의 곱 연산 사용법



    openBLSA에서는 cblas_sgemm 함수를, cuBLAS에서는 cublasSgemm 함수를 따릅니다. 어려울 것이라고 몸을 짓고 있었지만, 지금까지 망설임은 없을 것 같다.

    다음 번



    CUDA Toolkit cuBLAS 매뉴얼을 읽으면 cuBLAS를 확장 한 cuBLAS-XT가 나열됩니다.
    다음 번은 cuBLAS와 cuBLAS-XT의 차이, 어느 것을 사용하는 것이 좋은지의 관점에서 조사합니다.
    「cuBLAS와 cuBLAS-XT의 조사(그 1). 행렬의 곱 연산에서」
    "cuBLAS와 cuBLAS-XT의 조사 (그 2). 행렬의 곱 연산에서. 전치의 영향."

    좋은 웹페이지 즐겨찾기