왜 opencv 는 GPU 로 실현 하 는 것 이 CPU 로 실현 하 는 것 보다 느 립 니까?

5098 단어 opencvcuda
문제.
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 가 바 쁜 상 태 를 유지 하고 있다 는 뜻 이다.

좋은 웹페이지 즐겨찾기