2013-04-02 2 views
1

iPhone 용 접선 거리 기반 OCR 솔루션을 구현하고 있습니다.이 솔루션은 크기가 253x7 인 부동 소수점 행렬의 빠른 곱셈에 크게 의존합니다. 개념의 증거를 들어,이 같은 내 자신의 순진 매트릭스 루틴을 구현했습니다 : 당신이 볼 수 있듯이iOS BLAS - 프레임 워크 가난한 행렬 곱셈 성능 가속화

Matrix operator*(const Matrix& matrix) const { 
    if(cols != matrix.rows) throw "cant multiply!"; 

    Matrix result(rows, matrix.cols); 
    for(int i = 0; i < result.rows; i++){ 
     for(int j = 0; j < result.cols; j++){ 
      T tmp = 0; 
      for(int k = 0; k < cols; k++){ 
       tmp += at(i,k) * matrix.at(k,j); 
      } 
      result.at(i,j) = tmp; 
     } 
    } 

    return result; 
} 

, 그것은 아주 기본입니다. PoC가 잘 수행 된 후에는 Accelerate Framework의 행렬 곱셈 (아마도 SIMD 및 기타 고급 기능을 사용하여 무거운 작업을 수행 ...)을 통합하여 성능 제한을 추가로 밀어 올리려고했습니다.

Matrix operator*(const Matrix& m) const { 
    if(cols != m.rows) throw "cant multiply!"; 

    Matrix result(rows,m.cols); 

    cblas_dgemm(CblasRowMajor, CblasNoTrans, CblasNoTrans, rows, m.cols, cols, 1, matrix, cols, m.matrix, m.cols, 1, result.matrix, result.cols); 

    return result; 
} 

놀랍게도 (적어도 나를 위해) 위의 코드는 매트릭스를 곱하는 데 두 배의 시간이 걸렸습니다! 나는 double 대신 단일 정밀도를 사용하여 시도했다. 왜냐하면 CPU의 워드 크기 (32 비트 부동 소수점 대 32 비트 ARM의 64 비트 double)와 관련된 것이었지만 성능이 향상되지는 않았다.

내가 뭘 잘못하고 있니? 순진한 구현보다 눈에 띄는 성능 향상을 위해 253x7 매트릭스가 너무 작습니까?

+0

[MGMatrix] (https://github.com/ghenania/MGMatrix)를 보면, 정확히 필요한 것입니다. 이것은 vDSP를 기반으로하며 매우 간단한 인터페이스를 제안합니다. –

답변

0

기본적으로 그렇습니다. "x7"부분은 CBLAS의 가치가있는 오버 헤드를 만들기에는 너무 작습니다. CBLAS 함수가 제공하는 모든 유연성과 함께 함수 호출 비용은 백업하는 데 시간이 걸립니다. CblasNoTrans과 같은 옵션을 전달할 때마다 해당 옵션을 관리하기 위해 if()이 있다는 것을 기억하십시오. 특히 cblas_dgemm은 C에 누적되므로 이전 결과 요소를 읽고 곱하기를 적용한 다음 저장하기 전에 추가해야합니다. 그것은 많은 추가 작업입니다.

CBLAS 대신 vDSP 기능을 사용해 볼 수 있습니다. vDSP_mmul은 조금 더 단순하며 결과에 누적되지 않습니다. 작은 데이터 세트 (수천 개의 요소)에 vDSP_*으로 행운을 보냈습니다.

즉,이 경험은 순진한 C 구현이 작은 데이터 세트에서 매우 빠르다는 것입니다. 함수 호출을 피하는 것이 큰 이점입니다. 말하자면, 귀하의 at() 전화가 인라인되어 있는지 확인하십시오. 그렇지 않으면 루프에 많은 시간을 낭비하게됩니다. 포인터 추가를 사용하여 승수가 아닌 행렬을 연속적으로 이동하여 C 구현의 속도를 높일 수 있습니다 (임의 액세스에 대해 [] 통해 필요함). 이 매트릭스가 작을수록 가치가있을 수도 있고 없을 수도 있습니다. 당신은 약간의 프로파일을해야 할 것입니다. 어셈블러 출력을 보면 매우 유익합니다.

절대적으로 기기에서이 내용을 프로필해야합니다. 시뮬레이터의 성능은 부적합합니다. 시뮬레이터가 더 빠릅니다. 그것은 완전히 다릅니다. 시뮬레이터에서 격렬히 빠른 것은 디바이스에서 훨씬 느려질 수 있습니다.

+0

재미있는 것은 포인터 연산 (가로로 ++, 세로로 + = colSize)을 구현했지만 성능은 동일하게 유지되었습니다 ... 컴파일러가 매우 영리하거나 뭔가를 놓치고 있습니다. 완전하게 : D –

+0

컴파일러는 "배열을 걸을 때"를 인식하고이를 추가로 변환 할 수 있습니다. (회고 적으로 볼 때 흔히 볼 수있는 것처럼 보입니다.) 결과로 생성 된 어셈블러를 살펴보십시오. –

1

몇 가지 질문 : 어떤 크기의 행렬

  1. 253 365을 곱한? 말하자면, 253x7 * 7x1이라면, 범용적인 multiply 루틴은 코드 편집에 대부분의 시간을 할애 할 것이고, 순조로운 구현보다 빨리 만들 수있는 조정 된 라이브러리가 거의 없다. .

  2. 어떤 하드웨어를 사용하고 있으며 어떤 IOS 버전입니까? 특히 배정 밀도의 경우 이전 하드웨어 및 이전 버전의 iOS 버전은 성능면에서 제한적입니다. 예를 들어 Cortex-A8에서 배정도 산술 연산은 완전히 파이프 라인 처리되지 않으므로 순진한 구현을 수행하기 위해 라이브러리가 수행 할 수있는 작업은 거의 없습니다.다른 매트릭스 엄청나게 작은 아니며, 하드웨어가 최근의 경우, 버그를 제출하시기 바랍니다

은 (예기치 않게 낮은 성능 절대적으로 버그). 높은 종횡비를 가진 작은 매트릭스는 범용 행렬 곱하기에서 매우 빠르게 만들기는 어렵지만 파일을 저장하는 데는 여전히 좋은 버그입니다.

하드웨어/iOS 버전이 오래된 경우 어쨌든 Accelerate를 사용하는 것이 좋습니다. 새 하드웨어/소프트웨어에서 더 나은 성능을 발휘해야하기 때문입니다.

다른 행렬이 너무 작 으면 많은 작업이 수행되지 않을 수 있습니다. ARM에는 배정도 SIMD가 없으며 행렬이 너무 작아서 캐시 차단의 이점을 얻을 수 없으며 행렬 크기가 너무 작아서 루프 언 롤링으로 인해 많은 이점을 얻을 수 없습니다. 당신이 당신의 행렬이 될 것 사전를 알고있는 경우


정확히 완전히를 줄이기로 순진 구현 및 범용 라이브러리 모두보다 훨씬 더 잘 할 수있을 것입니다, * 7 배 ??? 253x7 행렬 곱셈의 내부 차원.

+0

곱셈 될 행렬은 253x7 곱하기 7x253입니다. 추가 프로파일 링을 통해 실행 시간의 상당 부분이 libBLAS에 의한 semaphore_destroy 및 semaphore_create 호출로 낭비된다는 것을 알았습니다 (그림보기 : [http://i48.tinypic.com/33u4s3b.png](html)]. i48.tinypic.com/33u4s3b.png)) 또한 iPhone 5에서 최신 iOS 6.1.2 –

+0

@ TamásZahola로이 코드를 테스트하고 있습니다. 버그 보고서를 제출하고 프로필을 포함하십시오. Accelerate가이 호출을 전혀 스레딩하지 않아야합니다. –

+0

이 경우 버그 보고서를 어디서 제출해야합니까? –