이런 종류의 질문은 되풀이되며 "MATLAB은 고도로 최적화 된 라이브러리를 사용합니다"또는 "MATLAB은 MKL을 사용합니다"보다 한 번만 스택 오버플로에서보다 명확하게 대답해야합니다.
역사:
행렬 곱셈 (매트릭스-벡터, 벡터-벡터 곱셈 및 많은 행렬 분해와 함께)은 선형 대수학에서 가장 중요한 문제입니다. 엔지니어들은 초기부터 컴퓨터의 이러한 문제를 해결해 왔습니다.
나는 역사에 대한 전문가는 아니지만, 당시에는 모두 간단한 루프로 FORTRAN 버전을 다시 작성했습니다. 그런 다음 대부분의 선형 대수 문제를 해결하기 위해 필요한 "커널"(기본 루틴)을 식별하면서 일부 표준화가 이루어졌습니다. 그런 다음 이러한 기본 작업은 BLAS (Basic Linear Algebra Subprograms)라는 사양으로 표준화되었습니다. 그런 다음 엔지니어는 코드에서 잘 테스트 된 표준 BLAS 루틴을 호출하여 작업을 훨씬 쉽게 수행 할 수 있습니다.
BLAS :
BLAS는 레벨 1 (스칼라-벡터 및 벡터-벡터 연산을 정의한 첫 번째 버전)에서 레벨 2 (벡터-매트릭스 연산)로 레벨 3 (매트릭스-매트릭스 연산)으로 발전했으며 점점 더 많은 "커널"을 제공하여 더 표준화되었습니다. 그리고 기본적인 선형 대수 연산의 더 많은. 원래 FORTRAN 77 구현은 Netlib 웹 사이트 에서 계속 사용할 수 있습니다 .
더 나은 성능을 향해 :
따라서 수년 동안 (특히 BLAS 레벨 1과 레벨 2 릴리스 : 80 년대 초) 하드웨어는 벡터 작업과 캐시 계층 구조의 출현으로 바뀌 었습니다. 이러한 발전으로 인해 BLAS 서브 루틴의 성능을 크게 향상시킬 수있었습니다. 다른 벤더들은 점점 더 효율적인 BLAS 루틴을 구현했습니다.
나는 모든 역사적 구현을 알지 못하지만 (저는 태어 났거나 어린 시절이 아니 었습니다) 2000 년대 초반 Intel MKL과 GotoBLAS가 가장 눈에 띄었습니다. Matlab은 매우 우수하고 최적화 된 BLAS 인 Intel MKL을 사용하며, 이는 귀하가 보는 뛰어난 성능을 설명합니다.
행렬 곱셈에 대한 기술적 세부 사항 :
그렇다면 왜 Matlab (MKL)이 dgemm
배정도 일반 행렬-행렬 곱셈 에서 그렇게 빠른가 ? 간단히 말하면 벡터화와 데이터 캐싱이 우수하기 때문입니다. 보다 복잡한 용어 : Jonathan Moore가 제공 한 기사를 참조하십시오 .
기본적으로 제공 한 C ++ 코드에서 곱셈을 수행 할 때 캐시 친화적 인 것은 아닙니다. 행 배열에 대한 포인터 배열을 만든 것으로 의심되므로 내부 루프에서 "matice2"의 k 번째 열에 대한 액세스 matice2[m][k]
가 매우 느립니다. 실제로에 액세스 할 때 matice2[0][k]
행렬 배열 0의 k 번째 요소를 가져와야합니다. 그런 다음 다음 반복에서는 matice2[1][k]
다른 배열 (배열 1)의 k 번째 요소 인에 액세스해야합니다 . 그런 다음 다음 반복에서 또 다른 배열에 액세스하는 등의 작업을 수행합니다. 전체 행렬 matice2
이 가장 높은 캐시 ( 8*1024*1024
바이트 크기)에 맞지 않기 때문에 프로그램은 주 메모리에서 원하는 요소를 가져와야합니다. 시각.
액세스가 연속적인 메모리 주소에 있도록 매트릭스를 전치하면 컴파일러가 캐시에서 전체 행을 동시에로드 할 수 있기 때문에 코드가 훨씬 더 빠르게 실행됩니다. 이 수정 된 버전을 사용해보십시오.
timer.start();
float temp = 0;
//transpose matice2
for (int p = 0; p < rozmer; p++)
{
for (int q = 0; q < rozmer; q++)
{
tempmat[p][q] = matice2[q][p];
}
}
for(int j = 0; j < rozmer; j++)
{
for (int k = 0; k < rozmer; k++)
{
temp = 0;
for (int m = 0; m < rozmer; m++)
{
temp = temp + matice1[j][m] * tempmat[k][m];
}
matice3[j][k] = temp;
}
}
timer.stop();
따라서 캐시 로컬 성이 코드 성능을 얼마나 크게 향상 시켰는지 확인할 수 있습니다. 이제 실제 dgemm
구현은이를 매우 광범위한 수준으로 활용합니다. TLB (Translation lookaside buffer, long short short : 효과적으로 캐시 할 수있는 것)의 크기로 정의 된 매트릭스 블록에 대해 곱셈을 수행하여 프로세서로 스트리밍합니다. 처리 할 수있는 데이터의 양입니다. 다른 측면은 벡터화입니다. 프로세서의 벡터화 된 명령어를 사용하여 최적의 명령어 처리량을 얻습니다. 실제로 크로스 플랫폼 C ++ 코드로는 할 수 없습니다.
마지막으로 Strassen 또는 Coppersmith-Winograd 알고리즘이 잘못되었다고 주장하는 사람들은 위에서 언급 한 하드웨어 고려 사항 때문에이 알고리즘을 실제로 구현할 수는 없습니다.