왜 opencv 는 GPU 로 실현 하 는 것 이 CPU 로 실현 하 는 것 보다 느 립 니까?
OpenCV 의 GPU 모듈 을 통 해 기 존 코드 의 운행 효율 을 최적화 하려 고 좋 은 소망 을 품 고 코드 개작 작업 을 시작 했다.고 쳐 쓰 는 과정 이 순 조 롭 지 못 하여 많은 문제 에 부 딪 혔 다.예 를 들 어 gpu 모듈 이 제공 하 는 인 터 페 이 스 는 아버 지 를 매우 괴 롭 히 고 상당 부분 부동 소수점 유형 을 지원 하지 않 습 니 다 (histogram, integral 과 같은 자주 사용 하 는 것 은 지원 되 지 않 습 니 다).또한 한도 값 판단 이 있 는 곳 에 서 는 cpu 처 리 를 전송 해 야 합 니 다. gpu 함 수 는 모두 병행 처리 되 기 때문에 하나의 알고리즘 모듈 을 고 칠 때마다 운행 효율 을 테스트 해 보 세 요. 어떤 때 는 사람의 마음 을 진작 시 키 고 어떤 때 는 몽둥이 로 마 시 는 것 입 니 다. CPU 보다 더 느 립 니까?
일련의 구 글 을 통 해 마침내 원인 을 찾 았 다.
http://stackoverflow.com/questions/12074281/why-opencv-gpu-codes-is-slower-than-cpu
http://answers.opencv.org/question/1670/huge-time-to-upload-data-to-gpu/#1676
The first gpu function call is always takes more time, because CUDA initialize context for device. The following calls will be faster.
Programming Guide 의 CUDA C Runtime - Initialization 1 절 에 대한 설명 이 있 습 니 다.
전체 코드 의 첫 번 째 Gpuma 와 관련 된 문 구 는 이른바 first gpu function 입 니 다. 여기 서 CUDA 는 장치 컨 텍스트 를 초기 화 해 야 합 니 다. 이 조작 은 시간 이 많이 걸 립 니 다!
코드 시작 또는 클래스 의 구조 함수 에 가입:
Mat src1; src1 = Mat::zeros(cvSize(5,5),CV_16UC1);
GpuMat src2(src1);
src 1 은 초기 값 을 마음대로 부여 합 니 다. 관건 은 GpuMat 와 관련 된 작업 (다른 gpu 함수 도 가능) 을 호출 하 는 것 입 니 다. 그러면 세그먼트 코드 는 CUDA 의 초기 화 를 실현 합 니 다.실측 을 통 해 이곳 은 400 ms 를 소모 해 야 합 니 다!위 와 같이 간단 한 두 문장 임 에 도 불구 하고 전체 코드 의 첫 번 째 gpu 호출 작업 이 라면 CUDA 초기 화 를 기본 으로 실행 합 니 다!다른 기계 에 서 는 반드시 400 ms 가 아니 라 구체 적 인 PC 하드웨어 와 관련 이 있어 야 한다.
앞으로 의 gpu 작업 은 그렇게 느 리 지 않 지만 upload, download (메모리 와 메모리 의 데이터 전달) 와 관련 되면 시간 비용 은 모두 ms 단계 에 달 합 니 다!
한 마디 로 하면 GPU 의 병행 처 리 는 확실히 빠 르 지만 데이터 가 GPU 에 들 어 오 는 비용 이 너무 커서 코드 의 전체적인 효율 에 영향 을 미친다.
현재 항목 은 C + + 가 쓴 알고리즘 으로 dll 로 C \ # 호출 을 제공 합 니 다.당연한 것 은 gpu 의 조작 은 모두 C + + 의 인터페이스 I 함수 에 놓 여 있다.그 문제 가 발생 했 습 니 다. 매번 C \ # C + + 의 함 수 를 호출 할 때마다 CUDA 의 초기 화 를 실행 해 야 합 니 다. 400 ms 를 소모 하여 무의미 한 조작 에 있어 알고리즘 의 실시 간 요 구 를 참 을 수 없습니다!C \ # 에서 CUDA 를 초기 화하 지 않 는 한 가능 합 니까?또 합 리 적 인가요?
이제 야 알 겠 다. 왜 인터넷 에 opencv gpu 의 자원 이 별로 없 는 지, 사용 하 는 사람 이 많 지 않 잖 아. 정말 아버 지 를 속 이 는 거 야!이렇게 큰 폐단 은 정말 사용 하면 두 렵 습 니 다. 저 로 하여 금 그렇게 많은 시간 을 낭비 하여 최적화 시 켰 습 니 다. 알고리즘 의 주체 부분 이 많이 빨 라 졌 습 니 다. 원래 200 ms 였 는데 지금 은 100 ms 수준 에 이 르 렀 습 니 다. 그러나 이 구덩이 아버지의 CUDA 초기 화 400 ms 만으로 모든 성 과 를 상쇄 할 수 있 습 니 다!
앞으로 gpu 를 도입 하기 전에 본 알고리즘 의 현재 운행 효율 을 잘 살 펴 봐 야 합 니 다. 현재 운행 시간 이 CUDA 초기 화 에 소요 되 는 시간 보다 훨씬 커 야 도입 할 필요 가 있 습 니 다!확실히, 나 는 연 산 량 의 평 가 를 잘 하지 못 했 기 때문에 현재 알고리즘 의 연 산 량 은 gpu 를 전혀 사용 할 수 없다!
해결 조치
문제 1. CUDA 가 장치 컨 텍스트 를 초기 화 하 는 데 시간 이 많이 걸 립 니 다.
GpuMat 를 정의 하 는 등 프로그램 시작 부분 에서 CUDA 와 관련 된 작업 을 수행 할 수 있 습 니 다.
GpuMat a(10,10,CV_8U); // CUDA ,
첫 번 째 CUDA 문 구 는 시간 이 많이 걸 리 지만 이후 에는 모두 정상 으로 돌아 올 것 이다.문제 2. 방문 시간 (latency) 은 프로그램의 전체 효율 에 영향 을 미친다.
두 가지 경로: 데이터 가 CPU 와 GPU 사이 에서 전달 되 는 횟수 를 줄인다.연 산 량 이 매우 적은 부분 은 GPU 를 사용 하지 마라. 데이터 양 이 매우 많 고 순환 횟수 가 매우 많 을 때 만 GPU 를 사용한다.
전 자 는 가장 직접적인 수단 이 고 후 자 는 GPU 의 사용 원칙 으로 다음 과 같은 예 를 볼 수 있다.
각각 CPU 와 GPU 로 가우스 필 터 를 실현 하 다.
cv::GaussianBlur(img, img, Size(11, 11), 1.5, 1.0, cv::BORDER_REFLECT);
이상 은 CPU 코드 입 니 다. cv::cuda::registerPageLocked(img); //
gimg.upload(img); // GPU
cv::Ptr<:cuda::filter> gauss = cv::cuda::createGaussianFilter(CV_32F, CV_32F, Size(11, 11), 1.5, 0, cv::BORDER_DEFAULT,-1); //
gauss->apply(gimg, gimg); //
gimg.download(img); // CPU
cv::cuda::unregisterPageLocked(img); //
이상 은 GPU 의 코드 로 잠 금 페이지 는 데이터 가 CPU 와 GPU 사이 에서 전달 되 는 것 을 가속 화 할 수 있다.실행 결과: 고 스 필터 함수 의 시간 만 계산 합 니 다. GPU 는 CPU 의 1 / 3 ~ 1 / 2 이지 만, 방문 저장 시간 을 고려 하면 GPU 는 CPU 보다 더 느 립 니 다!
그러나 고 스 필 터 를 10 번 하면 GPU 의 장점 을 나 타 낼 수 있다.
cv::cuda::registerPageLocked(img); //
gimg.upload(img); // GPU
cv::Ptr<:cuda::filter> gauss = cv::cuda::createGaussianFilter(CV_32F, CV_32F, Size(11, 11), 1.5, 0, cv::BORDER_DEFAULT,-1); //
for(int i=0;i<10;i++)
gauss->apply(gimg, gimg); //
gimg.download(img); // CPU
cv::cuda::unregisterPageLocked(img); //
이상 은 10 회 필터 링 을 하 는 GPU 코드 이 며, CPU 코드 도 10 회 필터 링 을 수행 합 니 다.실행 결과: 제곱 시간 을 포함 하여 GPU 의 총 소 모 는 CPU 의 1 / 5 이 며, 100 번 의 필 터 를 실행 하면 1 / 10 입 니 다.
그러나 주의해 야 할 것 은 연산 량 은 집행 횟수 뿐만 아니 라 데이터 양 과 도 관련 이 있다 는 점 이다.도리 에 따 르 면 GPU 는 데이터 양 이 많 을 수록 유리 하지만 opencv 의 CUDA 모듈 에서 행렬 이 큰 데이터 (행렬 수가 많 음) 는 데이터 전달 시간 을 크게 증가 시 킬 것 이다. GpuMat 자체 가 행렬 크기 에 제한 이 있 기 때문에 CUDA 프로 그래 밍 을 사용 하여 데이터 와 스 레 드 를 합 리 적 으로 분배 하지 않 는 한 CUDA 병행 의 효율 을 제약 했다.opencv 자체 가 큰 행렬 에 무력 합 니 다.
-----------------------------------------------------------------------------------
다음 박문 은 CUDA 코드 최적화 에 대한 심도 있 는 토론 입 니 다.http://blog.csdn.net/gamesdev/article/details/17488237
이 박문 의 내용 은 아래 와 같다.
단일 스 레 드 를 실행 하 는 방법 은 의심 할 여지없이 매우 많은 병행 계산 자원 을 방치 할 것 이다. 우 리 는 반드시 다 중 스 레 드 를 사용 해 야 한다. 그러면 효율 이 대폭 향 상 될 것 이다.GPU 프로 그래 밍 에는 '숨 기기' (Hide) 라 는 개념 이 있다.액세스 메모리 나 차단 등 다른 원인 으로 인해 스 레 드 가 지연 되 지만 분 배 된 스 레 드 가 충분 하기 때문에 전체적으로 GPU 가 바 쁜 상 태 를 유지 하고 있다 는 뜻 이다.
이 내용에 흥미가 있습니까?
현재 기사가 여러분의 문제를 해결하지 못하는 경우 AI 엔진은 머신러닝 분석(스마트 모델이 방금 만들어져 부정확한 경우가 있을 수 있음)을 통해 가장 유사한 기사를 추천합니다:
ip camera android에 액세스하고 java를 사용하여 모니터에 표시그런 다음 PC에서 다운로드 폴더를 추출해야 합니다 그런 다음 프로젝트 폴더에 다운로드한 javacv 라이브러리를 추가해야 합니다. 먼저 라이브러리 폴더를 마우스 오른쪽 버튼으로 클릭한 다음 jar/폴더 추가를 선택...
텍스트를 자유롭게 공유하거나 복사할 수 있습니다.하지만 이 문서의 URL은 참조 URL로 남겨 두십시오.
CC BY-SA 2.5, CC BY-SA 3.0 및 CC BY-SA 4.0에 따라 라이센스가 부여됩니다.