Yolo移植及优化

 

移植基于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