极智AI | ubuntu离线编译Caffe GPU及手写数字集(MNIST)识别

241 阅读3分钟

  携手创作,共同成长!这是我参与「掘金日新计划 · 8 月更文挑战」的第 10 天,点击查看活动详情

欢迎关注我的公众号 [极智视界],获取我的更多笔记分享

  大家好,我是极智视界,本文介绍一下 ubuntu 离线编译 Caffe GPU 及手写数字集(MNIST)识别。

  需已经安装好 CUDA 和 cudnn,故以下操作都是在此基础上进行离线编译 caffe 及深度学习入门 mnist 实践。

一、依赖安装

  确保安装好 Anaconda、OpenCv,验证 OpenCv 有没有安装好的方法,输入:

pkg-config opencv --modversion

  若正确输出版本号,则说明安装成功。也可查看 OpenCv 的安装路径,使用如下命令:

pkg-config opencv --libs

二、编译Caffe

1、下载caffe包

  网址:github.com/bvlc/caffe.… , 下载解压,将 caffe-master 重命名为 caffe。

2、修改配置文件Makefile.config及Makefile文件

cd caffe
cp Makefile.config.example Makefile.config

vim Makefile.config 

  输入hi,回车 进入编辑模式。

  修改如下:

  • USE_CUDNN=1的注释取消;
  • 修改OPENCV_VERSION := 3
  • 若使用CUDA 9.0以上,将 CUDA_ARCH :=中的 -gencode arch=compute_20,code=sm_20 \ -gencode arch=compute_20,code=sm_21 \ 给注释或者删除
  • 在原来 INCLUDE_DIRS := $(PYTHON_INCLUDE) /usr/local/include /usr/include/hdf5/serial LIBRARY_DIRS := $(PYTHON_LIB) /usr/local/lib /usr/lib 现在改成(64位系统):
    INCLUDE_DIRS := $(PYTHON_INCLUDE) /usr/local/include /usr/include/hdf5/serial /path/to/your/opencv/include LIBRARY_DIRS := $(PYTHON_LIB) /usr/local/lib /usr/lib /usr/lib/x86_64-linux-gnu/hdf5/serial /path/to/your/opencv/lib
Esc + : wq  回车
vim Makefile
  • NVCCFLAGS += -ccbin = $(CXX)-Xcompiler-fPIC $(COMMON_FLAGS) 替换为: NVCCFLAGS += -D_FORCE_INLINES -ccbin = $(CXX) -Xcompiler -fPIC $(COMMON_FLAGS)

3、编译

  依次执行下列命令:

make all -j8
make test -j8
make runtest -j8

  编译的时候要祈祷,我就是一开始因为 OpenCv 没有安装完整,导致 caffe 编译各种报错。

  若一切顺利,就大吉大利了。

  一般make 和 test 编译过了就能用了, runtest 可能会报错,不过还是能用,目前影响未知。

三、手写数字集(MNIST)识别

1、数据集下载

  因为是离线状态,故无法直接使用 caffe 自带的 caffe\data\mnist\get_mnist.sh 来获取样本数据。

  可以直接在网址下载数据集,百度搜索一下一大把。

  解压至 caffe\data\mnist\ 文件下,不出意外应该有四个数据文件,分别是测试集图片、测试集标签、训练集图片和训练集标签,如下: 在这里插入图片描述

2、转换格式

  下载的数据集为二进制格式,必须转换成 caffe 能识别的 lmdb 格式:

./examples/mnist/create_mnist.sh

  会在 /examples/mnist 目录下生成 mnist_train_lmdb 和 mnist_test_lmdb 文件夹。

3、训练

./examples/mnist/train_lenet.sh

  训练后,会在 examples/mnist 下生成四个文件,分别是迭代 5000 次和 10000 次的模型。

lenet_iter_5000.caffemodel
lenet_iter_5000.solverstate
lenet_iter_10000.caffemodel
lenet_iter_10000.solverstate

4、C++调用模型

工程目录结构:

  - mnist
  	 - data
  	 	- 1.bmp
  	 	- 3.bmp
  	 	- ...
   	 - include
 	 - lib
 	 - demo
 	 	- pro
 	 - models
 	 	- lenet_iter_10000.caffemodel
		- lenet_train_test.prototxt
 	 - 3rdparty
 	 	- opencv
 	 - src

  打开 lenet_train_test.prototxt

  将前面两个 data 层:

layer{
  name:"mnist"
  type:"Data"
  ...
}
layer{
  name:"mnist"
  type:"Data"
  ...
}

  替换成:

input:"data"
input_shape{
  dim:1 # batchsize
  dim:1 # number of channels
  dim: 28 # width
  dim: 28 # height
}

  将最后两个层 accuracyloss 层:

layer{
  name:"accuracy"
  type:"Accuracy"
  ...
}
layer{
  name:"loss"
  type:"SoftmaxWithLoss"
  ...
}

  替换成:

layer{
  name:"prob"
  type:"Softmax"
  bottom:"ip2"
  top:"prob"
}

  模型调用主代码:

#include <iostream>
#include <opencv2/opencv.hpp>
#include <opencv2/dnn.hpp>

// find best class
static void getMaxClass(const cv::Mat &probBlob, int *classId, double *classProb)
{
    cv::Mat probMat = probBlob.reshape(1, 1);
    cv::Point classNumber;
    cv::minMaxLoc(probMat, NULL, classProb, NULL, &classNumber);
    *classId = classNumber.x;
}

int main()
{
    std::string modelTxt = "../models/lenet_train_test.prototxt";
    std::string modelBin = "../models/lenet_iter_10000.caffemodel";
    cv::Mat img = cv::imread("../data/3.bmp");
    cv::Mat inputBlob = cv::dnn::blobFromImage(img, 0.00390625f, cv::Size(28, 28),cv::Scalar(), false);
    cv::dnn::Net net;
    try
    {
       net = cv::dnn::readNetFromCaffe(modelTxt, modelBin);
     }
    catch(cv::Exception &ee)
    {
       std::cerr << "Exception: " << ee.what() << std::endl;
       if(net.empty())
       {
          std::cout << "Can't load the network bt using the flowing files:" << std::endl;
          std::cout << "modelTxt: " << modelTxt << std::endl;
          std::cout << "modelBin: " << modelBin << std::endl;
          exit(-1);
        }
    }
    cv::Mat pred;
    net.setInput(inputBlob, "data");
    pred = net.forward("prob");
    std::cout << pred << std::endl;
    int classId;
    double classProb;
    getMaxClass(pred, &classId, &classProb);
    std::cout << "Best Class: " << classId << std::endl;   // 预测的数字
    std::cout << "Probability: " << classProb * 100 << std::endl;   // 概率
    return 0;
}

  好了,以上分享了 ubuntu 离线编译 Caffe GPU 及手写数字集(MNIST)识别。希望我的分享能对你的学习有一点帮助。


logo_show.gif