移植基于darknet框架的yolo到arm,并且用openblas替代原始矩阵计算
darknet的代码很简洁,没有注释情况下的可读性也很强.
修改size_t为long long
经追踪,在yolo的读取模型过程中,使用了 sizeof(size_t) 作为fread和fwrite长度参数,导致算法在arm平台读取错位.把对应变量的类型和读取时的长度均修改为 long long 即可.
具体位置:
//darknet.h
typedef struct network{
int n;
int batch;
//size_t *seen;
long long *seen;
//parser.c
//void load_weights_upto(network *net, char *filename, int start, int cutoff)
//if ((major*10 + minor) >= 2 && major < 1000 && minor < 1000){
// fread(net->seen, sizeof(size_t), 1, fp);
if ((major*10 + minor) >= 2 && major < 1000 && minor < 1000){
fread(net->seen, sizeof(long long), 1, fp);
//void save_weights_upto(network *net, char *filename, int cutoff)
//fwrite(net->seen, sizeof(size_t), 1, fp);
fwrite(net->seen, sizeof(long long), 1, fp);
//network.c
//network *make_network(int n)
//net->seen = calloc(1, sizeof(size_t));
net->seen = calloc(1, sizeof(long long));
使用openblas加速
darknet支持nvidia的gpu加速,但是cpu版使用的是最原始的矩阵乘法而不是cpu计算库(可能作者觉得gpu才是未来).
由于公司的目标场景是arm平台,反而对cpu版比较看重,因此使用openblas进行加速.
首先是移植openblas,可在之前移植caffe的依赖库的文章中查看.
darknet中矩阵乘法的调用是通过gemm()函数实现的,因此只需要修改gemm函数的实现,不需要到卷积,全连接等层逐层修改.
- 添加openblas头文件.
- 替换gemm_cpu为cblas_sgemm.
- 在makefile中添加blas库的路径.
//gemm.c
#ifdef OPENBLAS
#include "cblas.h"
#endif
void gemm(int TA, int TB, int M, int N, int K, float ALPHA,
float *A, int lda,
float *B, int ldb,
float BETA,
float *C, int ldc)
{
#ifdef OPENBLAS
cblas_sgemm(CblasRowMajor, CblasNoTrans, CblasNoTrans, M, N, K, ALPHA, A, lda, B, ldb, BETA, C, ldc);
#else
gemm_cpu( TA, TB, M, N, K, ALPHA,A,lda, B, ldb,BETA,C,ldc);
#endif
}
Makefile
OPENBLAS=1
PS=0
ifeq ($(OPENBLAS),1)
ifeq ($(PS),0)
COMMON+= -I/usr/include/
CFLAGS+= -DOPENBLAS
LDFLAGS+= -L/usr/lib -lopenblas -lgfortran
else
COMMON+= -I/home/y/project/caffe_ps/src/OpenBLAS/install/include/
CFLAGS+= -DOPENBLAS
LDFLAGS+= -L/home/y/project/caffe_ps/src/OpenBLAS/install/lib -lopenblas
endif
endif