目录
附录1:blas、lapack、cblas在Ubuntu上的安装
1.确保机器上安装了gfortran编译器,如果没有安装的话,可以使用
附录2:在Ubuntu18.04 Arm64架构下编译和运行c#程序
目的
目的是使用边缘主机运行yolov4.
过程
因为边缘主机架构为aarch64的arm64架构,所以很多x86x64架构下的应用没办法使用。
我使用的这款机器说明书名称为NE1008N1边缘智算小站,我就叫他边缘主机了,因为搭载的是英伟达的JetsonNano后边简称jn,所以去网上查资料准备安装环境,网上说jn拿到的时候一般已经安装好cuda,opencv等深度学习环境,但是我找了一圈没找到,可能是浪潮那边弄掉了吧。所以这种情况下只能自己搭建环境,这里记录一下过程,以便自己后边迁移。
1.opencv
这里使用的是opencv3.3.1版本,github下载后使用mv 命令移动到 /usr/local/opencv中,使用unzip解压。
因为安装opencv要一些依赖的环境,这里直接贴上先:
sudo apt-get install build-essential
sudo apt-get install cmake git libgtk2.0-dev pkg-config libavcodec-dev libavformat-dev libswscale-dev
sudo apt-get install python-dev python-numpy libtbb2 libtbb-dev libjpeg-dev libpng-dev libtiff5-dev libdc1394-22-dev # 处理图像所需的包
sudo apt-get install libavcodec-dev libavformat-dev libswscale-dev libv4l-dev liblapacke-dev
sudo apt-get install libxvidcore-dev libx264-dev # 处理视频所需的包
sudo apt-get install libatlas-base-dev gfortran # 优化opencv功能
sudo apt-get install ffmpeg
这里我也遇到了一些问题,不知道是边缘主机的问题还是怎么,因为我一拿到机器就替换了apt-get的源,后边在使用suao apt-get update的时候会一直报错http 404说是找不到目的源,清华和阿里云都试过了,最后还是还原成了边缘主机一开始的源,这里上个图
还原之后,update就没问题了,以上那些依赖包也可以下载了。
接下来就是编译opencv,首先cd到opencv的目录中,注意这里都是sudo,不使用的话会报错permission的问题。
cd opencv
sudo mkdir build
cd build
sudo cmake -D CMAKE_BUILD_TYPE=Release -D CMAKE_INSTALL_PREFIX=/usr/local ..
make install
接下来就是cmake遇到的问题了,我执行cmake命令的时候,居然没有成功,后来查了很多资料说是gcc,g++的问题,我随即按照指示去把我的gcc,g++从7降到了5,但是还是不行。
这里提一下, 有的人cmake失败了,把build删除后重新弄一遍就可以了,我始终不行的。
cd ..
sudo rm -r build
sudo mkdir build
cd build
最后很离谱的就是想起来去upgrade一下,后来居然可以了。
sudo apt-get update
sudo apt-get upgrade
cmake这关终于过去了。
后面就是make,在make的时候也遇到了一些问题。
第一个问题就是进行到百分之60左右的时候报错找不到glib.h,我已经使用了命令安装了glib2.0-dev,正常的情况下你在,/usr/include目录下应该可以看到glib2.0这个文件夹,但是我的就是没有,每次安装还是提示我已经是最新的了。
sudo apt-get install libglib2.0-dev
这里还去下载了deb文件和源码文件来使用,都无果,最后的解决方法还是,卸载,更新,重新下,然后就有了。
sudo apt-get remove libglib2.0-dev
sudo apt-get update
sudo apt-get install libglib2.0-dev
cd /usr/include
有了之后,重新cmake然后make,这次终于不报错找不到glib.h了。
第二个问题就是编译的时候报错:
undefined reference to `cblas_sgemm(CBLAS_ORDER, CBLAS_TRANSPOSE, CBLAS_TRANSPOSE, int, int, int, float, float const, int, float const, int, float, float*, int)
这个报错要感谢下边这个文章 https://blog.csdn.net/dbdxnuliba/article/details/106895321 但是在编译lapack时,报错了,最终编译lapack时按照的是这边文章https://blog.csdn.net/mlnotes/article/details/9676269
这里我在下边附录中记录一下这个过程。
这个问题解决后又重新cmake然后make,这次没有报错了。成功的编译成功,执行sudo make install后,opencv就编译完成了。
下面就是把opencv配置到环境中。
sudo /bin/bash -c 'echo "/usr/local/lib" > /etc/ld.so.conf.d/opencv.conf'
sudo ldconfig
最后运行测试。
测试我在build下面新建了opencv_test文件夹,cd进去后,创建了opencv_test.cpp文件。
sudo mkdir opencv_test
cd opencv_test
sudo gedit opencv_test.cpp
测试文件如下:
#include "opencv2/core.hpp"
#include "opencv2/imgproc.hpp"
#include "opencv2/highgui.hpp"
#include "opencv2/videoio.hpp"
#include <iostream>
using namespace cv;
using namespace std;
int main()
{
cout << "Built with OpenCV " << CV_VERSION << endl;
VideoCapture video;
video.open("rtsp://admin:admin123@192.168.1.116:554/h264/ch1/main/av_stream");
if(!video.isOpened())
{
cout << "open video file failed. " << endl;
return -1;
}
while(true)
{
Mat frame;
video>>frame;
if(!frame.empty())
{
imshow("video", frame);
}
if(waitKey(30) == 27)
{
break;
}
}
return 0;
}
然后创建CMakeLists.txt文件。
sudo gedit CMakeLists.txt
文件内容如下:
project(opencv_test)
find_package(OpenCV REQUIRED)
add_executable(opencv_test opencv_test.cpp)
target_link_libraries(opencv_test ${OpenCV_LIBS})
然后编译执行。
sudo cmake .
sudo make
sudo ./opencv_test
执行的测试的以后遇到了一些问题。
第一个问题就是报错找不到gtk,可能是因为你没有正确安装gtk2.0-dev,安装正常后重新编译没有报错了。
第二个问题就是报错:
Gtk-Message:Failed to load module "canberra-gtk-module"
执行命令后解决。
sudo apt-get install libcanberra-gtk-module
至此opencv的编译和测试就完成了。
2.darknet
首先下载darknet源码
git clone https://github.com/AlexeyAB/darknet.git
下载完成后,解压,进入文件夹
cd darknet
gedit Makefile
找到Makefile文件,打开后先将GPU=1,OPENCV=1,然后修改ARCH后的参数和你的GPU有关,此处我的是72。
which nvcc
然后将Makefile文件中的nvcc路径改为查到的路径。保存即可。
sudo make -j8
编译完成后,进行测试。
图片测试命令:
./darknet detect yolo4/yolov4.cfg yolo4/yolov4.weights data/dog.jpg
视频测试命令:
./darknet detector demo cfg/coco.data yolo4/yolov4.cfg yolo4/yolov4.weights data/test.mp4
如果遇到报错例如,文件无法打开等问题,这大概率是因为你的cfg或data文件是从windows拷贝来的,所以需要修改一下文件格式。
vi ./yolov4.cfg
:set ff=unix
如果遇到报错例如,no kernal image is available for execution on the device,这大概率是因为在编译前你的arch设置错误,确定后重新编译,再次运行。
这里,检测一张768x576的图片的时间大约为1300毫秒左右吗,检测视频的fps为2.5左右,可见效率并不理想,将继续做优化。
3.TensorRT
因为在不适用tensorrt的情况下跑yolo的确太吃力了,所以这里实验下接入tensorrt后,看看检测效率会不会有提升。
首先检查你的jetson上有没有装好tensorrt,这里可以使用jtop工具,很实用,这里附上安装使用教程:
https://blog.csdn.net/chongzi865458/article/details/102789374/
可以看到下部的info,里面包含了jetson的信息,其中就有tensorrt,大多数人应该这里都显示了版本号,所以是已经安装好的,我的显示NOT_INSTALLED,所以你还要看看你的/usr/lib/aarch64-linux-gnu/下有没有libnvinfer.so,libnvinfer.so.7,libnvinfer.so.7.1.3等链接库文件,有的说明你的tensorrt也是安装好的,如果没有,那么就使用如下命令进行安装:
sudo apt-get install tensorrt
这里可能会遇到科学上网的问题,但是其实你所需要的包在普通网络下就可以下载完,我是在下载samples的时候,下不动导致失败,所以就没有使用samples,但是/usr/lib/aarch64-linux-gnu/下已经存在需要的文件。
确定tensorrt安装好之后,这里要说下我的jtop一眼无法显示出tensorrt版本,依然是NOT_INSTALLED,没关系后边不耽误使用。
到了这里附上一篇干货:https://github.com/enazoe/yolo-tensorrt
darket下可以接入tensorrt,按照指定操作就可以运行,这里注意要把类型从INT8改为FP32,因为使用INT8会使用图像矫正,会报错。
这里附下权重文件:https://share.weiyun.com/dcMV5hG1
核心代码在modules中,配置文件在configs中,测试代码在samples中,这里附上一个实时视频的测试文件:
#include "class_timer.hpp"
#include "class_detector.h"
#include "opencv2/core.hpp"
#include "opencv2/imgproc.hpp"
#include "opencv2/highgui.hpp"
#include "opencv2/videoio.hpp"
#include <memory>
#include <thread>
#include <iostream>
using namespace cv;
using namespace std;
int main()
{
Config config_v3;
config_v3.net_type = YOLOV3;
config_v3.file_model_cfg = "../configs/yolov3.cfg";
config_v3.file_model_weights = "../configs/yolov3.weights";
config_v3.calibration_image_list_file_txt = "../configs/calibration_images.txt";
config_v3.inference_precison =FP32;
config_v3.detect_thresh = 0.5;
Config config_v3_tiny;
config_v3_tiny.net_type = YOLOV3_TINY;
config_v3_tiny.detect_thresh = 0.7;
config_v3_tiny.file_model_cfg = "../configs/yolov3-tiny.cfg";
config_v3_tiny.file_model_weights = "../configs/yolov3-tiny.weights";
config_v3_tiny.calibration_image_list_file_txt = "../configs/calibration_images.txt";
config_v3_tiny.inference_precison = FP32;
Config config_v4;
config_v4.net_type = YOLOV4;
config_v4.file_model_cfg = "../configs/yolov4.cfg";
config_v4.file_model_weights = "../configs/yolov4.weights";
config_v4.calibration_image_list_file_txt = "../configs/calibration_images.txt";
config_v4.inference_precison =FP32;
config_v4.detect_thresh = 0.5;
Config config_v4_tiny;
config_v4_tiny.net_type = YOLOV4_TINY;
config_v4_tiny.detect_thresh = 0.5;
config_v4_tiny.file_model_cfg = "../configs/yolov4-tiny.cfg";
config_v4_tiny.file_model_weights = "../configs/yolov4-tiny.weights";
config_v4_tiny.calibration_image_list_file_txt = "../configs/calibration_images.txt";
config_v4_tiny.inference_precison = FP32;
Config config_v5;
config_v5.net_type = YOLOV5;
config_v5.detect_thresh = 0.5;
config_v5.file_model_cfg = "../configs/yolov5-4.0/yolov5s.cfg";
config_v5.file_model_weights = "../configs/yolov5-4.0/yolov5s.weights";
config_v5.calibration_image_list_file_txt = "../configs/calibration_images.txt";
config_v5.inference_precison = FP32;
std::unique_ptr<Detector> detector(new Detector());
detector->init(config_v4_tiny);
VideoCapture video;
video.open("rtsp://admin:admin123@192.168.1.116:554/h264/ch1/main/av_stream");
if(!video.isOpened())
{
cout << "open video file failed. " << endl;
return -1;
}
std::vector<BatchResult> batch_res;
Timer timer;
while(true)
{
Mat frame;
video>>frame;
std::vector<cv::Mat> batch_img;
if(!frame.empty())
{
batch_img.push_back(frame);
timer.reset();
detector->detect(batch_img, batch_res);
timer.out("detect");
for (int i=0;i<batch_img.size();++i)
{
for (const auto &r : batch_res[i])
{
std::cout <<"batch "<<i<< " id:" << r.id << " prob:" << r.prob << " rect:" << r.rect << std::endl;
cv::rectangle(batch_img[i], r.rect, cv::Scalar(255, 0, 0), 2);
std::stringstream stream;
stream << std::fixed << std::setprecision(2) << "id:" << r.id << " score:" << r.prob;
cv::putText(batch_img[i], stream.str(), cv::Point(r.rect.x, r.rect.y - 5), 0, 0.5, cv::Scalar(0, 0, 255), 2);
}
cv::imshow("image"+std::to_string(i), batch_img[i]);
}
cv::waitKey(10);
}
if(waitKey(30) == 27)
{
break;
}
}
}
这里测试yolo4的detect时间大约为110ms左右,tiny版本大约为20ms左右,相比于不使用tensorrt的一秒3帧已经很不错了。
附录1:blas、lapack、cblas在Ubuntu上的安装
1.确保机器上安装了gfortran编译器,如果没有安装的话,可以使用
sudo apt-get install gfortran
2.下载blas, cblas, lapack 源代码
这些源码都可以在 http://www.netlib.org 上找到,下载并解压。这里提供我安装时的下载链接
http://www.netlib.org/blas/blas.tgz
http://www.netlib.org/blas/blast-forum/cblas.tgz
http://www.netlib.org/lapack/lapack-3.4.2.tgz
解压之后会有三个文件夹,BLAS-3.8.0, CBLAS, lapack-3.4.2
3.这里就是具体的编译步骤(一定要按照顺序)
tar xvf blas.tgz #解压三个文件
1)编译blas
进入BLAS文件夹,执行以下几条命令
gfortran -c -O3 *.f # 编译所有的 .f 文件,生成 .o文件 注意这里的不是零3 而是大写的O
ar rv libblas.a *.o # 链接所有的 .o文件,生成 .a 文件
sudo cp libblas.a /usr/local/lib # 将库文件复制到系统库目录
##################################################################
#如果上面代码有问题,可以试试下面的编译方法
gfortran -c -O3 -fPIC *.f # 编译所有的 .f 文件,生成 .o文件 加上了-fPIC
gcc -shared *.o -fPIC -o libblas.so
cp libblas.so /usr/local/lib/
ar rv libblas.a *.o # 链接所有的 .o文件,生成 .a 文件
su cp libblas.a /usr/local/lib # 将库文件复制到系统库目录
2)编译cblas
进入CBLAS文件夹,首先根据你自己的计算机平台,将目录下某个 Makefile.XXX 复制为 Makefile.in , XXX表示计算机的平台,如果是Linux,那么就将Makefile.LINUX 复制为 Makefile.in,然后执行以下命令
cp ../BLAS-3.8.0/libblas.a testing # 将上一步编译成功的 libblas.a 复制到 CBLAS目录下的testing子目录
make # 编译所有的目录
sudo cp lib/cblas_LINUX.a /usr/local/lib/libcblas.a # 将库文件复制到系统库目录下
3)编译 lapack以及lapacke
这一步比较麻烦,首先当然是进入lapack-3.4.2文件夹,然后根据平台的特点,将INSTALL目录下对应的make.inc.XXX 复制一份到 lapack-3.4.2目录下,并命名为make.inc, 这里我复制的是 INSTALL/make.inc.gfortran,因为我这里用的是gfortran编译器。
修改lapack-3.4.2/Makefile, 因为lapack以来于blas库,所以需要做如下修改
#修改~!
#lib: lapacklib tmglib
lib: blaslib variants lapacklig tmglib
接下来编译
make # 编译所有的lapack文件
cd lapacke # 进入lapacke 文件夹,这个文件夹包含lapack的C语言接口文件
make # 编译lapacke
cp include/*.h /usr/local/include #将lapacke的头文件复制到系统头文件目录
cd .. #返回到 lapack-3.4.2 目录
cp *.a /usr/local/lib # 将生成的所有库文件复制到系统库目录
这里的头文件包括: lapacke.h, lapacke_config.h, lapacke_mangling.h, lapacke_mangling_with_flags.h lapacke_utils.h
生成的库文件包括:liblapack.a, liblapacke.a, librefblas.a, libtmglib.a
至此cblas和lapack就成功安装到你的电脑上了。
附录2:在Ubuntu18.04 Arm64架构下编译和运行c#程序
1.安装SDK
首先需要在系统中安装.Net的SDK,网址如下:
https://docs.microsoft.com/zh-cn/dotnet/core/install/linux
按照指引进行安装,注意:
这里选择手动安装。
按照指引就可以安装完成并将dotnet写入到环境变量中。
2.安装Visual Studio Code
直接进入vscode官网选择对应版本安装即可。
这里进入vscode后会提示安装c#的扩展,这里不用安装,因为扩展不支持aarch架构。
3.测试
打开终端输入:
$ dotnet new console -o testconsole
$ code testconsole
这时会有一个新的vscode窗口出现,在vscode终端中输入:
$ dotnet restore
$ dotnet run
程序即可运行。