閔大荒之旅(二) --- 熟悉熟悉環境

本次我所要完成的項目是 基於GPU加速的行人檢測系統

前言

GPU 加速的计算是利用一颗图形处理器 (GPU) 以及一颗 CPU 来加速科学、工程以及企业级应用程序。工业与学术界的数据科学家已将 GPU 用于机器学习以便在各种应用上实现开创性的改进,这些应用包括图像分类、视频分析、语音识别以及自然语言处理等等。我們實驗室的方向是無人駕駛,這個領域最近也是非常火熱,更有人直言三至五年無人駕駛將得以普及。而無人駕駛的必要條件之一就是要能快速、準確地識別出道路情況,相比於串行順序工作方式的CPU,那麼以多核並行計算的工作方式的GPU在運算速度方面將提供更大的優勢,這對於識別的實時性是非常有幫助的。

項目工作及環境
硬件:Jetson TK1
軟件:C++、OPENCV、ubuntu

項目分析
我在拿到項目任務之後進行了項目分析,將項目列爲以下兩個要點:
1.GPU加速 --- CUDA編程
2.行人檢測 --- SVM+HOG :OpenCV
實際上OpenCV for linux中就已經集成了CUDA的接口,在安裝好環境之後直接調用運行即可。
於是我將任務分解成如下幾個階段:
1.Jetson TK1的環境配置(包括CUDA、OPENCV以及熟悉linux)
2.SVM+HOG行人圖片檢測(CPU&opencv)
3.行人圖片檢測(GPU&opencv)
4.行人視頻檢測(CPU&GPU&opencv)
5.攝像頭事實檢測(附加)
 
一 TK1系统图形界面(ubuntu)设置以及CUDA环境搭建
 对于Jetson TK1环境的搭建与熟悉,主要是参照 http://www.linuxdiyf.com/linux/16885.htm & http://www.elinux.org/Jetson/Installing_CUDA 教程中的步骤。这里注意installer.sh只能运行一次,运行完之后,熟悉的(其实我不是很熟悉)ubuntu界面就出来了!
在完成好TK1的ubuntu界面设置后,主要是安装好CUDA环境。这里对CUDA做一个简要的介绍:CUDA是NVIDIA公司推出的一款通用并行计算框架,该架构能使GPU通过并行计算解决复杂的计算问题。简单的来说,CUDA就可以看做是一种编程语言,要想使用GPU计算,就得使用CUDA编程。
装好环境以后,我们可以利用nvcc进行CUDA自带samples的编译运行,如deviceQuery,我们可以看到CUDA的各种计算性能的参数,具体参数意义可以参考: http://blog.csdn.net/poisonchry/article/details/16332369 
二OpenCV的配置
 参考教程: http://www.myexception.cn/other/1829048.html
                   http://elinux.org/Jetson/Installing_OpenCV
注意:教程上说明OpenCV需要先配置好CUDA环境,这是因为OpenCV for Linux中直接提供了CUDA的接口,你只需要调用就行,这里就需要用到CUDA的环境。大部分的程序OpenCV中直接可以调用函数,但是若想要进一步优化程序或者实现更加高级的功能可能需要使用混合编程。
 
三尝试编写
初次接触ubuntu,对编程环境不是很熟悉,索性就用文本写程序,终端直接进行编译。在装好opencv之后,参见 http://www.myexception.cn/other/1829048.html博客末尾处对samples的调用,其中有一个CPU vs GPU的霍夫变换直线检测的程序,可以清楚直观地看到GPU的并行运算性能远远高于CPU,于是,我也想尝试一下,编写一个简单的opencv程序,canny处理图像,程序如下:
#include <cmath>
#include <iostream>

#include "opencv2/core/core.hpp"
#include "opencv2/highgui/highgui.hpp"
#include "opencv2/imgproc/imgproc.hpp"
#include "opencv2/gpu/gpu.hpp"

using namespace std;
using namespace cv;
using namespace cv::gpu;

int main(int argc, const char* argv[])
{
    Mat src, dst, edge, gray;
    double start = (double)getTickCount();
    src = imread("building.jpg");
    dst.create(src.size(), src.type());
    cvtColor(src, gray, COLOR_BGR2GRAY);
    Canny(gray, edge, 3, 9, 3);
    double t = ((double)getTickCount() - start)/getTickFrequency();
    cout << "the time is(cpu) : " << 1000 * t << " ms" << endl;

    GpuMat src_gpu(src);
    GpuMat dst_gpu, edge_gpu, gray_gpu;
    double start2 = (double)getTickCount();
    dst_gpu.create(src_gpu.size(), src_gpu.type());
    gpu::cvtColor(src_gpu, gray_gpu, COLOR_BGR2GRAY);
    gpu::Canny(gray_gpu, edge_gpu, 3, 9, 3);
    double t2 = ((double)getTickCount() - start2)/getTickFrequency();
    cout << "the time is(gpu) : " << 1000 * t2 << " ms" << endl;
    Mat temp;
    edge_gpu.download(temp);

    imshow("src", src);
    imshow("canny[cpu]", edge);
    imshow("canny[gpu]", temp);
    waitKey();
        
    return 0;
}
 于是得到比较时间:
竟然发现,gpu的运行时间要长于cpu,难道这说明gpu计算能力不如cpu?
在查阅资料以后,发现可能有这么一种解释,就是第一次调用CUDA接口需要耗费大量的时间,于是,将代码修改:
#include <cmath>
#include <iostream>

#include "opencv2/core/core.hpp"
#include "opencv2/highgui/highgui.hpp"
#include "opencv2/imgproc/imgproc.hpp"
#include "opencv2/gpu/gpu.hpp"
#include "cuda.h"
#include "cuda_runtime_api.h"


using namespace std;
using namespace cv;
using namespace cv::gpu;

int main(int argc, const char* argv[])
{
    cudaSetDevice(0);
    cudaFree(0);    
    Mat src, dst, edge, gray;
    double start = (double)getTickCount();
    src = imread("building.jpg");
    dst.create(src.size(), src.type());
    cvtColor(src, gray, COLOR_BGR2GRAY);
    Canny(gray, edge, 3, 9, 3);
    double t = ((double)getTickCount() - start)/getTickFrequency();
    cout << "the time is(cpu) : " << 1000 * t << " ms" << endl;

    GpuMat src_gpu(src);
    GpuMat dst_gpu, edge_gpu, gray_gpu;
    double start2 = (double)getTickCount();
    dst_gpu.create(src_gpu.size(), src_gpu.type());
    gpu::cvtColor(src_gpu, gray_gpu, COLOR_BGR2GRAY);
    gpu::Canny(gray_gpu, edge_gpu, 3, 9, 3);
    double t2 = ((double)getTickCount() - start2)/getTickFrequency();
    cout << "the time is(gpu) : " << 1000 * t2 << " ms" << endl;
    Mat temp;
    edge_gpu.download(temp);

    imshow("src", src);
    imshow("canny[cpu]", edge);
    imshow("canny[gpu]", temp);
    waitKey();
        
    return 0;
}
 实际上就是添加了一句CUDA的使用,让CUDA先被调用,这样第二次运算速度将快一些!
这里要注意,使用了CUDA的头文件以及函数,一定要确保ubuntu在指定路径下能搜寻得到.h文件和.so文件,并且在编译cpp文件时,要使用类似
g++ 文件名.cpp -l库名 -l库名··· -o 文件名,这样才能保证引入CUDA之后不报错。
但是,残酷的事实是,程序这么改对于结果而言并没有什么作用,gpu的时间还是要略大于cpu
在继续查阅资料之后,发现这么一种解释,对于小量计算而言,gpu的性能未必比cpu强,因为计算量太小,gpu根本用不上几个线程,其192个核的威力根本显现不出来,对于程序运行时间ms级的来说,完全没有必要使用gpu的并行计算,所以,在后面我将进一步地体会gpu并行计算的威力!
 
 

你可能感兴趣的:(閔大荒之旅(二) --- 熟悉熟悉環境)