HighPerformanceComputing
高性能计算(High performance computing, 缩写HPC)
指通常使用很多处理器(作为单个机器的一部分)
或者某一集群中组织的几台计算机(作为单个计 算资源操作)的计算系统和环境。
有许多类型的HPC 系统,其范围从标准计算机的大型集群,到高度专用的硬件。
大多数基于集群的HPC系统使用高性能网络互连,比如那些来自 InfiniBand 或 Myrinet 的网络互连。
基本的网络拓扑和组织可以使用一个简单的总线拓扑,
在性能很高的环境中,网状网络系统在主机之间提供较短的潜伏期,
所以可改善总体网络性能和传输速率。
博文末尾支持二维码赞赏哦 _
浮点运算和代码优化, 并行计算, Optimizer软件
卷积计算优化
目前,卷积的计算大多采用间接计算的方式,主要有以下三种实现方式:1、im2col + GEMM。
caffe等很多框架中都使用了这种计算方式,
原因是将问题转化为矩阵乘法后可以方便的使用很多矩阵运算库(如MKL、openblas、Eigen等)。
openblas
GEMM 普通矩阵乘法(General Matrix Multiplication)
2、FFT变换。
时域卷积等于频域相乘,因此可将问题转化为简单的乘法问题。
3、Winograd。
这种不太熟悉,据说在GPU上效率更高。
NNPACK就是FFT和Winograd方法的结合。上面三种方法执行效率都还不错,但对内存占用比较高,因为需要存储中间结果或者临时辅助变量。1、Strassen 算法:
分析 CNN 的线性代数特性,增加加法减少乘法,
这样降低了卷积运算的计算的复杂度(o(n^3) -> o(n^2.81)),
但是这种方法不适合在硬件里面使用,这里就不做详细的介绍了。2、 MEC:
一种内存利用率高且速度较快的卷积计算方法
MEC: Memory-efficient Convolution for Deep Neural Network 论文
博客解析
openblas GEMM 矩阵乘法优化
文章图片
最原始3个for循环 (矩阵比较小的时候,速度还能快一些,当矩阵大了的时候,一定会跌下去,cache缓存问题):
文章图片
矩阵分块,块复用,减少仿存,相当于减少内存访问:
文章图片
文章图片
操作寄存器,不是操作内存:
我可以申请一堆C 00,01这样的寄存器变量,在C语言中是register double,还有矩阵A的部分,也用寄存器变量。
当然B还是之前的方式,最后再写回C里面。
只是我们引入了寄存器变量,让更多的数据保存到寄存器里,而不是放到cache缓存里,来减轻cache的压力.
文章图片
B矩阵仿存,使用指针访问,
一开始先把对应的指针位置指好,每次计算的时候只要指针连续移动就好,而不是每次读一个位置重新算一遍,这样速度就会快一些。
文章图片
最里层循环展开:
在最里层循环,是不是可以展开成4次,在做这个的时候,我们可以降低整个循环这部分的开销,而且让它流水的情况更好。
文章图片
通过使用寄存器变量,使用了指针,在做了一定的底层循环展开之后,达到了红色线的性能:
文章图片
之后可以使用更大的分块,在进行寄存器,指针,展开优化。
在深度神经网络中 特指提高卷积计算方式的方法
0、小米 mace
代码
Mobile AI Compute Engine (MACE) 是一个专为移动端异构计算平台优化的神经网络计算框架。1、OpenVINO
Intel推出OpenVINO工具包,将计算机视觉带到物联网终端
OpenVINO(开放的视觉推理和神经网络优化)工具包
使开发人员能够在云上(如TensorFlow,MXNet和Caffe等流行款框架)构建和训练人工智能模型,
并将其部署到各种产品中。
Windows*
Linux* (supports Ubuntu*, CentOS*, and Yocto Project*)
Linux for FPGA 2、腾讯NCNN框架入门到应用
代码
3、FeatherCNN
代码
4、Tengine 高性能神经网络推理引擎
代码
5、百度MDL
代码
6、九言科技 绝影(Prestissimo)
代码
7、Google量化方法 r=S(q-Z)tfliteTensorFlow Lite
代码
8、英伟达 TensorRT , NVIDIA TensorRT是一种高性能神经网络推理(Inference)引擎
代码
英伟达 CUDA 和 TensorRT 代码实验
深度学习框架的并行优化方法小结
一 、 ncnn使用 ncnn_wiki 指南
在Ubuntu上安装使用NCNN 1. 下载编译源码
git clone https://github.com/Tencent/ncnn.git
下载完成后,需要对源码进行编译
修改CMakeLists.txt 文件 打开 一些文件的编译开关##############################################
add_subdirectory(examples)
# add_subdirectory(benchmark)
add_subdirectory(src)
if(NOT ANDROID AND NOT IOS)
add_subdirectory(tools)
endif()开始编译:
cd ncnn
mkdir build && cd build
cmake ..
make -j
make install执行完毕后我们可以看到:
Install the project...
-- Install configuration: "release"
-- Installing: /home/ruyiwei/code/ncnn/build/install/lib/libncnn.a
-- Installing: /home/ruyiwei/code/ncnn/build/install/include/blob.h
-- Installing: /home/ruyiwei/code/ncnn/build/install/include/cpu.h
-- Installing: /home/ruyiwei/code/ncnn/build/install/include/layer.h
-- Installing: /home/ruyiwei/code/ncnn/build/install/include/mat.h
-- Installing: /home/ruyiwei/code/ncnn/build/install/include/net.h
-- Installing: /home/ruyiwei/code/ncnn/build/install/include/opencv.h
-- Installing: /home/ruyiwei/code/ncnn/build/install/include/platform.h
查看生成了什么工具:
我们进入 ncnn/build/tools 目录下,如下所示,
我们可以看到已经生成了 ncnn2mem可执行文件,以及 caffe/caffe2ncnn 和 mxnet/mxnet2ncnn 可执行文件
caffe2ncnn的 作用是将caffe模型生成ncnn 模型
.prototxt >>> .param.caffemodel >>> .bin;
mxnet2ncnn 的作用是将 mxnet模型生成ncnn 模型;
ncnn2mem 是对ncnn模型进行加密。
drwxrwxr-x 6 wanyouwen wanyouwen40966月 21 00:13 ./
drwxrwxr-x 6 wanyouwen wanyouwen40966月 21 00:14 ../
drwxrwxr-x 3 wanyouwen wanyouwen40966月 21 00:13 caffe/
drwxrwxr-x 3 wanyouwen wanyouwen40966月 21 00:13 CMakeFiles/
-rw-rw-r-- 1 wanyouwen wanyouwen16066月 21 00:13 cmake_install.cmake
-rw-rw-r-- 1 wanyouwen wanyouwen71416月 21 00:13 Makefile
drwxrwxr-x 3 wanyouwen wanyouwen40966月 21 00:13 mxnet/
-rwxrwxr-x 1 wanyouwen wanyouwen 4775386月 21 00:13 ncnn2mem*
drwxrwxr-x 3 wanyouwen wanyouwen40966月 21 00:13 onnx
tensorflow2ncnn
而默认会生成 一个静态库build/src/libncnn.a 和一些可执行文件:
build/examples/squeezenet 分类模型
build/examples/fasterrcn检测模型
build/examples/ssd/ssdsqueezenet 检测模型
build/examples/ssd/ssdmobilenet检测模型
可以使用squeezenet进行测试,这里这是一个图像分类模型。
把模型和参数复制过来:
cp ../../examples/squeezen* .
进行检测:
./squeezenet cat.jpg
>>>
283 = 0.377605
281 = 0.247314
282 = 0.100278
这里只是输出了类别的编码,没有输出类别的字符串
需要修改examples/squeezenet.c文件
// Tencent is pleased to support the open source community by making ncnn available.
// https://opensource.org/licenses/BSD-3-Clause#include
#include
#include
#include
#include
#include // putText()
#include "net.h"#include
#include // 计时
long getTimeUsec()
{struct timeval t;
gettimeofday(&t,0);
return (long)((long)t.tv_sec*1000*1000 + t.tv_usec);
}static int detect_squeezenet(const cv::Mat& bgr, std::vector& cls_scores)
{
ncnn::Net squeezenet;
// 前向模型
squeezenet.load_param("squeezenet_v1.1.param");
// 模型框架
squeezenet.load_model("squeezenet_v1.1.bin");
// 权重参数// ncnn 用自己的数据结构 Mat 来存放输入和输出数据 输入图像的数据要转换为 Mat,依需要减去均值和乘系数
// 图片变形
ncnn::Mat in = ncnn::Mat::from_pixels_resize(bgr.data, ncnn::Mat::PIXEL_BGR, bgr.cols, bgr.rows, 227, 227);
// 各个通道均值
const float mean_vals[3] = {104.f, 117.f, 123.f};
in.substract_mean_normalize(mean_vals, 0);
// 图像减去均值归一化ncnn::Extractor ex = squeezenet.create_extractor();
ex.set_light_mode(true);
// 模型 提取器 ex.input("data", in);
// 执行前向网络,获得计算结果
ncnn::Mat out;
ex.extract("prob", out);
//提取 prob层的输出cls_scores.resize(out.w);
for (int j=0;
j& cls_scores, int topk, std::vector& index_result, std::vector score_result)
{
// partial sort topk with index
int size = cls_scores.size();
// 结果维度
std::vector< std::pair > vec;
vec.resize(size);
for (unsigned int i=0;
i;
i++)
{// 成对 值:id 这里id对于类别
vec[i] = std::make_pair(cls_scores[i], i);
}
// 排序
std::partial_sort(vec.begin(), vec.begin() + topk, vec.end(),
std::greater< std::pair >());
// print topk and score
for (int i=0;
i& labels)
{
FILE* fp = fopen(path.c_str(), "r");
//读取文件while(!feof(fp))
{
char str_b[1024];
//先读取 1024个字符
fgets(str_b, 1024, fp);
std::string str_block(str_b);
//转换成 string 方便操作if(str_block.length() > 0)
{
for (unsigned int i = 0;
i labels;
load_labels("synset_words.txt", labels);
std::vector cls_scores;
long time = getTimeUsec();
detect_squeezenet(m, cls_scores);
time = getTimeUsec() - time;
printf("detection time: %ld ms\n",time/1000);
std::vector index;
std::vector score;
print_topk(cls_scores, 3, index, score);
for(unsigned int i = 0;
i < index.size();
i++)
{
cv::putText(m, labels[index[i]], cv::Point(50, 50+30*i), CV_FONT_HERSHEY_SIMPLEX, 1.2, cv::Scalar(0, 100, 200), 2, 8);
}cv::imshow("result", m);
cv::imwrite("test_result.jpg", m);
cv::waitKey(0);
return 0;
}
把模型和参数复制过来:
cp ../../examples/squeezen* .
以及类别列表文件:
cp ../../examples/synset_words.txt .
进行检测:
./squeezenet cat.jpg
2. caffe网络模型转换为 ncnn模型 示例
caffe下Alexnet网络模型转换为NCNN模型
我们在测试的过程中需要 .caffemodel文件(模型参数文件)以及 deploy.prototxt文件(模型框架结构) ,
所以我们再将caffe模型转换为NCNN模型的时候,
同样也需要 .caffemodel以及deploy.prototxt这两个文件,为了方便,我们使用AlexNet为例讲解。
a. 下载 caffe 模型和参数
alexnet 的 deploy.prototxt 可以在这里下载 https://github.com/BVLC/caffe/tree/master/models/bvlc_alexnet
alexnet 的 .caffemodel 可以在这里下载 http://dl.caffe.berkeleyvision.org/bvlc_alexnet.caffemodel
b. 转换
由于NCNN提供的转换工具只支持转换新版的caffe模型,
所以我们需要利用caffe自带的工具将旧版的caffe模型转换为新版的caffe模型后,
再将新版本的模型转换为NCNN模型.旧版本caffe模型->新版本caffe模型->NCNN模型。
c. 旧版caffe模型转新版caffe模型
转换ncnn网络和模型
caffe 自带了工具可以把老版本的 caffe 网络和模型转换为新版(ncnn的工具只认识新版upgrade_net_proto_text [老prototxt] [新prototxt]
upgrade_net_proto_binary [老caffemodel] [新caffemodel]模型框架转换:
~/code/ncnn/build/tools$ ~/caffe/build/tools/upgrade_net_proto_text deploy.prototxt new_deplpy.prototxt
模型权重文件转换:
~/code/ncnn/build/tools$ ~/caffe/build/tools/upgrade_net_proto_binary bvlc_alexnet.caffemodel new_bvlc_alexnet.caffemodel上面的命令需要根据自己的caffe位置进行修改执行后,就可以生成新的caffe模型.因为我们每次检测一张图片,所以要对新生成的deploy.prototxt进行修改:第一个 dim 设为 1 一次输入的图片数量
layer {
name: "data"
type: "Input"
top: "data"
input_param { shape: { dim: 1 dim: 3 dim: 227 dim: 227 } }
}
d. 新版caffe模型转ncnn模型
./caffe/caffe2ncnn new_deplpy.prototxt new_bvlc_alexnet.caffemodel alexnet.param alexnet.bincaffe2ncnn的 作用是将caffe模型生成ncnn 模型
.prototxt >>> .param.caffemodel >>> .bin;执行上面命令后就可以生成NCNN模型需要的param 与bin 文件.
e. 对模型参数加密
./ncnn2mem alexnet.param alexnet.bin alexnet.id.h alexnet.mem.h
注意 alexnet.id.h alexnet.mem.h 为定义的文件名 头文件名 后面后生成
最后
alexnet.bi >>>alexnet.param.bin小
alexnet.id.h小
alexnet.mem.h较大
f. 模型载入
对于加密文件的读取也和原来不同,在源码中,非加密param读取方式为:
ncnn::Net net;
net.load_param("alexnet.param");
net.load_model("alexnet.bin");
加密param.bin读取方式为:
ncnn::Net net;
net.load_param_bin("alexnet.param.bin");
net.load_model("alexnet.bin");
mobileNET 分类网络示例 caffe 模型参数下载
2. 模型转换
先caffe old转换到新版本下
./../../tools/caffe_tools/upgrade_net_proto_text mobilenet_deploy.prototxt mobilenet_new.prototxt
./../../tools/caffe_tools/upgrade_net_proto_binary mobilenet.caffemodel mobilenet_new.caffemodel
caffe toncnn
./../../tools/caffe/caffe2ncnn mobilenet_new.prototxt mobilenet_new.caffemodel mobilenet-ncnn.param mobilenet-ncnn.bin
4. 修改检测源文件 新建 ncnn/examples/mobilenet.cpp
// Tencent is pleased to support the open source community by making ncnn available.
// https://opensource.org/licenses/BSD-3-Clause#include
#include
#include
#include
#include
#include // putText()
#include "net.h"#include
#include // 计时
long getTimeUsec()
{struct timeval t;
gettimeofday(&t,0);
return (long)((long)t.tv_sec*1000*1000 + t.tv_usec);
}static int detect_mobilenet(const cv::Mat& bgr, std::vector& cls_scores)
{
ncnn::Net mobilenet;
// 前向模型
mobilenet.load_param("mobilenet-ncnn.param");
// 模型框架
mobilenet.load_model("mobilenet-ncnn.bin");
// 权重参数
// 图片变形网络输入尺寸为 224*224 之前squeezenet为227
ncnn::Mat in = ncnn::Mat::from_pixels_resize(bgr.data, ncnn::Mat::PIXEL_BGR, bgr.cols, bgr.rows, 224, 224);
// 各个通道均值
const float mean_vals[3] = {104.f, 117.f, 123.f};
in.substract_mean_normalize(mean_vals, 0);
// 图像减去均值归一化ncnn::Extractor ex = mobilenet.create_extractor();
ex.set_light_mode(true);
// 模型 提取器 ex.input("data", in);
//数据输入层ncnn::Mat out;
ex.extract("prob", out);
//提取 prob层的输出cls_scores.resize(out.w);
for (int j=0;
j& cls_scores, int topk, std::vector& index_result, std::vector score_result)
{
// partial sort topk with index
int size = cls_scores.size();
// 结果维度
std::vector< std::pair > vec;
vec.resize(size);
for (unsigned int i=0;
i;
i++)
{// 成对 值:id 这里id对于类别
vec[i] = std::make_pair(cls_scores[i], i);
}
// 排序
std::partial_sort(vec.begin(), vec.begin() + topk, vec.end(),
std::greater< std::pair >());
// print topk and score
for (int i=0;
i& labels)
{
FILE* fp = fopen(path.c_str(), "r");
//读取文件while(!feof(fp))
{
char str_b[1024];
//先读取 1024个字符
fgets(str_b, 1024, fp);
std::string str_block(str_b);
//转换成 string 方便操作if(str_block.length() > 0)
{
for (unsigned int i = 0;
i labels;
load_labels("synset_words.txt", labels);
std::vector cls_scores;
long time = getTimeUsec();
detect_mobilenet(m, cls_scores);
time = getTimeUsec() - time;
printf("detection time: %ld ms\n",time/1000);
std::vector index;
std::vector score;
print_topk(cls_scores, 3, index, score);
for(unsigned int i = 0;
i < index.size();
i++)
{
cv::putText(m, labels[index[i]], cv::Point(50, 50+30*i), CV_FONT_HERSHEY_SIMPLEX, 1.2, cv::Scalar(0, 100, 200), 2, 8);
}cv::imshow("result", m);
cv::imwrite("test_result.jpg", m);
cv::waitKey(0);
return 0;
}
修改ncnn/examples/CMakeLists.txt 添加编译选项
add_executable(mobilenet mobilenet.cpp)
target_link_libraries(mobilenet ncnn ${OpenCV_LIBS})
5. 编译&运行
./mobilenet cat.jpg
mobileNET-SSD 检测网络示例 1. 训练 使用caffe-ssd mobilenet-v1 训练网络 得到网络权重参数
这里训练的效果不太好,是基于mobilenet的权重进行训练的,得到 caffe版本的模型和权重文件:
MN_ssd_33_deploy.prototxt
MN_ssd_33_iter_26000.caffemodel这里的是直接训练好的 mobilenet-ssd 检测效果还可以
其实可以基于这个权重进行训练:
也可以直接从这里下载
2. 模型转换
caffe_old -> caffe_new:
注意这里的caffe版本为 caffe-ssd的版本 否则有些层的类型不认识
caffe-ssd
upgrade_net_proto_text [老prototxt] [新prototxt]
upgrade_net_proto_binary [老caffemodel] [新caffemodel]模型框架转换:
~/code/ncnn/build/tools$ ../../tools/caffe_tools/upgrade_net_proto_text MN_ssd_33_deploy.prototxt ssdmobilenet.prototxt
模型权重文件转换:
~/code/ncnn/build/tools$ ../../tools/caffe_tools/upgrade_net_proto_binary MN_ssd_33_iter_26000.caffemodel ssdmobilenet.caffemodel 上面 对casse-ssd/build/tools 工具做了 符号链接
ln -s /home/wanyouwen/ewenwan/software/caffe-ssd/build/tools/ ./caffe_tools caffe -> ncnn
./../../tools/caffe/caffe2ncnn ssdmobilenet.prototxt ssdmobilenet.caffemodel mobilenet_ssd_voc_ncnn.param mobilenet_ssd_voc_ncnn.bin
caffe2ncnn的 作用是将caffe模型生成ncnn 模型
.prototxt >>> .param.caffemodel >>> .bin;执行上面命令后就可以生成NCNN模型需要的param 与bin 文件.
3. 修改检测源文件
// Tencent is pleased to support the open source community by making ncnn available.
//#include
#include
#include
#include
#include
#include
#include #include "net.h"#include
#include // 计时
long getTimeUsec()
{struct timeval t;
gettimeofday(&t,0);
return (long)((long)t.tv_sec*1000*1000 + t.tv_usec);
}//定义一个结果 结构体
struct Object{
cv::Rect rec;
//边框
int class_id;
//类别id
float prob;
//概率
};
// voc
const char* class_names[] = {"background",
"aeroplane", "bicycle", "bird", "boat",
"bottle", "bus", "car", "cat", "chair",
"cow", "diningtable", "dog", "horse",
"motorbike", "person", "pottedplant",
"sheep", "sofa", "train", "tvmonitor"};
static int detect_mobilenet(cv::Mat& raw_img, float show_threshold)
{
ncnn::Net ssdmobilenet;
/* 模型下载
* model isconverted from https://github.com/chuanqi305/MobileNet-SSD
* and can be downloaded from https://drive.google.com/open?id=0ByaKLD9QaPtucWk0Y0dha1VVY0U
*/
printf("loading net... \r\n");
// 原始图片尺寸
int img_h = raw_img.size().height;
int img_w = raw_img.size().width;
ssdmobilenet.load_param("mobilenet_ssd_voc_ncnn.param");
ssdmobilenet.load_model("mobilenet_ssd_voc_ncnn.bin");
int input_size = 300;
// 改变图像尺寸 到网络的输入尺寸
ncnn::Mat in = ncnn::Mat::from_pixels_resize(raw_img.data, ncnn::Mat::PIXEL_BGR, raw_img.cols, raw_img.rows, input_size, input_size);
// 去均值, 再归一化
const float mean_vals[3] = {127.5f, 127.5f, 127.5f};
const float norm_vals[3] = {1.0/127.5,1.0/127.5,1.0/127.5};
//in.substract_mean_normalize(mean_vals, norm_vals);
// 上面给的模型in.substract_mean_normalize(mean_vals, 0);
// 我自己训练的 没有进行归一化ncnn::Extractor ex = ssdmobilenet.create_extractor();
ex.set_light_mode(true);
//ex.set_num_threads(4);
//线程数量
ex.input("data", in);
printf("begin detecting... \r\n");
long time = getTimeUsec();
ncnn::Mat out;
ex.extract("detection_out", out);
//网络输出time = getTimeUsec() - time;
printf("detection time: %ld ms\n",time/1000);
// 打印总结果
printf("%d %d %d\n", out.w, out.h, out.c);
std::vector
4. 编译 make -j
5. 运行测试 ./ssdmobilenet person.jpg
这里如果没使用 新版本caffe格式可能会有错误:
find_blob_index_by_name data_splitncnn_6 failed
find_blob_index_by_name data_splitncnn_5 failed
find_blob_index_by_name data_splitncnn_4 failed
find_blob_index_by_name data_splitncnn_3 failed
find_blob_index_by_name data_splitncnn_2 failed
find_blob_index_by_name data_splitncnn_1 failed
find_blob_index_by_name data_splitncnn_0 failed
Segmentation fault
ssdsuqeezenet prototxt & caffemodel
// Tencent is pleased to support the open source community by making ncnn available.
//
#include
#include
#include
#include
#include #include "net.h"#include
#include // 计时
long getTimeUsec()
{struct timeval t;
gettimeofday(&t,0);
return (long)((long)t.tv_sec*1000*1000 + t.tv_usec);
}
///struct Object
{
cv::Rect_ rect;
int label;
float prob;
};
static int detect_squeezenet(const cv::Mat& bgr, std::vector
【caffe|神经网络高性能计算 卷积计算优化 openblas GEMM 矩阵乘法优化 ncnn mobileNet-ssd shueezeNet-ssd】
文章图片
推荐阅读
- C语言学习|第十一届蓝桥杯省赛 大学B组 C/C++ 第一场
- paddle|动手从头实现LSTM
- pytorch|使用pytorch从头实现多层LSTM
- 推荐系统论文进阶|CTR预估 论文精读(十一)--Deep Interest Evolution Network(DIEN)
- pytorch|YOLOX 阅读笔记
- 前沿论文|论文精读(Neural Architecture Search without Training)
- 联邦学习|【阅读笔记】Towards Efficient and Privacy-preserving Federated Deep Learning
- OpenCV|OpenCV-Python实战(18)——深度学习简介与入门示例
- 深度学习|深度学习笔记总结
- 《繁凡的深度学习笔记》|一文绝对让你完全弄懂信息熵、相对熵、交叉熵的意义《繁凡的深度学习笔记》第 3 章 分类问题与信息论基础(中)(DL笔记整理