windows Caffe 动态库 静态库 编译教程

博主所在的教研室要使用Caffe实现机械臂的控制环节中的预测部分,其中涉及到了Caffe的编译以及LSTM层的添加到最终的caffe的动态库和静态库的编译及使用,整个过程一言难尽,特写此博客纪念。

首先是caffe的编译,网上的教程都是大同小异,我只配置了CPU版本的caffe,这里参考的是这位大神的博客,附上链接https://blog.youkuaiyun.com/zb1165048017/article/details/51355143万分感谢!

接下来由于我的工程中是用训练好的网络模型进行预测,需要在caffe里添加LSTM层,这也是非常麻烦且耗费时间的事情,这里参考的是另一位大神的博客,链接附上https://blog.youkuaiyun.com/zb1165048017/article/details/59112034感谢万分!

实际上将添加了LSTMcaffe编译好只是万里长征第一步,最重要的还是真正把caffe用起来,caffeWindows版本自带了一个分类网络工程给大家练手,具体教程可以看这位大神https://blog.youkuaiyun.com/qq_14845119/article/details/52541622,其中需要训练好的模型以及网络结构文件,这里给大家我的百度云:链接:https://pan.baidu.com/s/1wuCmeMsDMwuk8Rya21xBow 
提取码:gxq0 

但是我写这篇博客的主要目的还是记录一下libcaffe.lib以及libcaffe.dll的编译,我在网上搜索到的资料很少,所以写下这篇博客希望大家看完之后可以少走一些弯路。

这里再提醒大家一次,无论是动态库还是静态库的编译都是在你已经将caffe编译好的基础上进行的!

动态库编译!

其实下载下来的caffe已经为dll的创建铺垫了前95%的工作,我们需要的是将caffe中定义的函数接口导出,供客户端程序调用。c++编写dll的方法是在定义class的头文件中先添加宏定义,如下:

#ifdef  DLL_TEST_API
#else
#define DLL_TEST_API _declspec(dllimport)
#endif

Class DLL_TEST_API  CDLLTest
{

         Public:
                  CDLLTest();

                  ~CDLLTest();

                  int Add(int a, int b);

};

打开编译好的caffe中的include目录,找出文件Blob.hpp net.hpp caffe.pb.h(需要修改文件名)common.hpp io.hpp db.hpp benchmark.hpp upgrade.hpp signal_handler.hpp solver.hpp parallel.hpp math_functions.hpp syncedmem.hpp,按上述方法添加代码,这里举一个例子:

#ifndef CAFFE_UTIL_DB_HPP
#define CAFFE_UTIL_DB_HPP

#ifdef BUILD_DLL
#define OS_API __declspec(dllexport)
#else
#define OS_API __declspec(dllimport)
#endif
#include <string>

#include "caffe/common.hpp"
#include "caffe/proto/caffe_pb.h"

namespace caffe { namespace db {

enum Mode { READ, WRITE, NEW };

class OS_API Cursor {
 public:
  Cursor() { }
  virtual ~Cursor() { }
  virtual void SeekToFirst() = 0;
  virtual void Next() = 0;
  virtual string key() = 0;
  virtual string value() = 0;
  virtual bool valid() = 0;

  DISABLE_COPY_AND_ASSIGN(Cursor);
};

class Transaction {
 public:
  Transaction() { }
  virtual ~Transaction() { }
  virtual void Put(const string& key, const string& value) = 0;
  virtual void Commit() = 0;

  DISABLE_COPY_AND_ASSIGN(Transaction);
};

class OS_API DB {
 public:
  DB() { }
  virtual ~DB() { }
  virtual void Open(const string& source, Mode mode) = 0;
  virtual void Close() = 0;
  virtual Cursor* NewCursor() = 0;
  virtual Transaction* NewTransaction() = 0;

  DISABLE_COPY_AND_ASSIGN(DB);
};

OS_API DB* GetDB(DataParameter::DB backend);
OS_API DB* GetDB(const string& backend);

}  // namespace db
}  // namespace caffe

#endif  // CAFFE_UTIL_DB_HPP

 

这些加完代码还是远远不够的!你的网络中用到了哪些layer,就要在include/layers目录下找到相应的头文件,同样在其中添加上述宏定义。我修改了以下头文件input_layer.hpp embed_layer.hpp dropout_layer.hpp lstm_layer.hpp inner_product_layer.hpp softmax_layer.hpp slice_layer.hpp split_layer.hpp scale_layer.hpp eltwise_layer.hpp reducation_layer.hpp concat_layer.hpp recurrent.hpp。这里再举一个例子

#ifndef CAFFE_ELTWISE_LAYER_HPP_
#define CAFFE_ELTWISE_LAYER_HPP_
#ifdef BUILD_DLL
#define OS_API __declspec(dllexport)
#else
#define OS_API __declspec(dllimport)
#endif
#include <vector>

#include "caffe/blob.hpp"
#include "caffe/layer.hpp"
#include "caffe/proto/caffe.pb.h"

namespace caffe {

/**
 * @brief Compute elementwise operations, such as product and sum,
 *        along multiple input Blobs.
 *
 * TODO(dox): thorough documentation for Forward, Backward, and proto params.
 */
template <typename Dtype>
class OS_API EltwiseLayer : public Layer<Dtype> {
 public:
  explicit EltwiseLayer(const LayerParameter& param)
      : Layer<Dtype>(param) {}
  virtual void LayerSetUp(const vector<Blob<Dtype>*>& bottom,
      const vector<Blob<Dtype>*>& top);
  virtual void Reshape(const vector<Blob<Dtype>*>& bottom,
      const vector<Blob<Dtype>*>& top);

  virtual inline const char* type() const { return "Eltwise"; }
  virtual inline int MinBottomBlobs() const { return 2; }
  virtual inline int ExactNumTopBlobs() const { return 1; }

 protected:
  virtual void Forward_cpu(const vector<Blob<Dtype>*>& bottom,
      const vector<Blob<Dtype>*>& top);
  virtual void Forward_gpu(const vector<Blob<Dtype>*>& bottom,
      const vector<Blob<Dtype>*>& top);
  virtual void Backward_cpu(const vector<Blob<Dtype>*>& top,
      const vector<bool>& propagate_down, const vector<Blob<Dtype>*>& bottom);
  virtual void Backward_gpu(const vector<Blob<Dtype>*>& top,
      const vector<bool>& propagate_down, const vector<Blob<Dtype>*>& bottom);

  EltwiseParameter_EltwiseOp op_;
  vector<Dtype> coeffs_;
  Blob<int> max_idx_;

  bool stable_prod_grad_;
};

}  // namespace caffe

#endif  // CAFFE_ELTWISE_LAYER_HPP_

这里有一个问题,caffe.pb.h是根据src\caffe\proto\caffe.proto自动生成的,所以编译的时候还要把这个文件改名字,否则就把修改后的caffe.pb.h覆盖,我改成了caffe_pb.h.但是,只做这些改动还是不够,在caffe目录下的src\caffe\proto中的caffe.pb.cc文件也需要修改,因为其中定义了一些函数会在前面提到的一些层的头文件中使用,同样将上述宏定义加入caffe.pb.cc.

一定要记得在预处理器定义中添加BUILD_DLL.

最后再提醒大家不要忘了在配置属性中将配置类型改为dll.

现在右键libcaffe点击重新生成即可!生成的libcaffe.dll在build\x64\Debug/Release中。生成dll的同时还会生成一个libcaffe.lib,这与接下来要编译的静态库不同,它一般是一些索引信息,记录了dll中函数的入口和位置。

静态库编译!

有了动态库编译的经验,静态库编译起来就非常easy了。我们不需要在前面提到的头文件加那些接口定义,只需要在编译好的caffe基础上把设置中的配置属性——常规——配置类型中改为静态库编译即可。

现在右键libcaffe点击重新生成即可!可以发现现在生成的libcaffe.lib与动态库编译生成的lib大小差距悬殊,因为它的索引和实现都在其中。
 

有问题的铁汁可以在评论区一起分享,我会尽我所能为大家解答!

 

 

评论 8
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值