快速部署多版本linux,多版本库管理技巧--caffe,pytorch,caffe2,mxnet,tensorflow

发现问题

目前来看,anaconda里面的库虽然提供的全,但是当编译程序进行link时,会容易报未定义的引用,如

‘boost::re_detail_106700::cpp_regex_traits_implementation<char>::transform(char const*, char const*) const’未定义的引用

这个原因根本在于我们自己linux使用的GCC版本与anaconda的库不一致导致的。因为编译器不一致,编译选项也不一致。一般容易出现的错误就是 -std=c++11 ,GLIBCXX_USE_CXX11_ABI这些错误。其实解决的方法还是比较直接,哪个库有问题,就直接自己编译,然后再install到anaconda的envs中。

引言

最近在做多平台linux系统部署问题,之前由于编译的pytorch,mxnet,tensorflow或者caffe,均使用的系统中的库,所以形成了单独的linux发行版编译后无法跨linux平台使用。然后最近发现anaconda其实是包管理系统,而且是跨linux平台的,centos,ubuntu,deepin均可以运行统一的anaconda环境。

下面是对anaconda的一些介绍:深表感谢

Anaconda、Miniconda、Conda、pip的相互关系。

如果你想要跳过这篇文章,并得到讨论的要点,你可以阅读每个标题以及下面的摘要。

认为#1:Conda是一个发行版,不是一个软件包管理器

  现实:Conda是一个包管理器;Anaconda是一个发行包。虽然Conda与Anaconda一起包装,但两者是具有不同目标的不同实体。
  软件发布包是预先构建和预配置的包的集合,其可以在系统上安装和使用。包管理器是自动化安装,更新和删除包的过程的工具。 Conda,其“conda install”,“conda update”和“conda remove”子命令,完全属于第二个定义:它是一个包管理器。
  也许这里的混乱来自于Conda紧密耦合到两个软件分发:Anaconda和Miniconda的事实。 Anaconda软件在PyData生态系统中的完整分布,包括Python本身以及几百个第三方开源项目的二进制文件。 Miniconda本质上是一个conda环境的安装程序,只包含Conda及其依赖项,以便您可以从头开始安装所需的。
  但不要弄错误:Conda与Anaconda / Miniconda不同,Python本身(如果你愿意)可以自行安装。

认为#2:Conda是一个Python包管理器

  现实:Conda是一种通用包管理系统,旨在构建和管理任何语言的任何类型的软件。因此,它也适用于Python包。
  因为conda来自于Python(更具体地说是PyData)社区,许多人错误地认为它基本上是一个Python包管理器。情况并非如此:conda旨在管理任何软件堆栈中的包和依赖关系。在这个意义上,它不像pip,更像是apt或yum等跨平台版本。
  如果你使用conda,你已经可以利用许多非Python包;以下命令将列出您环境中的那些:
  $ conda search –canonical | grep -v ‘py\d\d’
  在我的系统上,有350个结果:这些是我的Conda / Python环境中的包,这些包基本上是由Python-only工具(如pip和virtualenv)无法管理的。

认为#3:Conda和pip是直接竞争对手

  现实:Conda和pip服务于不同的目的,并且只在一小部分任务中直接竞争:即在孤立的环境中安装Python包。
  Pip代表Pip Installs Packages,是Python的官方认可的包管理器,最常用于安装在Python包索引(PyPI)上发布的包。 pip和PyPI都由Python包装管理局(PyPA)管理和支持。
  简而言之,pip是Python包的通用管理器; conda是一个与语言无关的跨平台环境管理器。对于用户,最显着的区别可能是这样的:pip在任何环境中安装python包; conda安装在conda环境中的任何包装。如果你正在做的是在孤立的环境中安装Python包,conda和pip + virtualenv大多是可互换的,模数依赖处理和包可用性的一些差异。通过隔离环境(conda-env或virtualenv),您可以在其中安装软件包,而无需修改您的系统Python安装。
  即使放弃认为#2,如果我们专注于只是安装Python包,conda和pip服务不同的受众和不同的目的。 如果你想在现有的系统Python安装中管理Python包,conda不能帮助你:通过设计,它只能在conda环境中安装包。 如果你想说,使用依赖于外部依赖的许多Python包(NumPy,SciPy和Matplotlib是常见的例子),同时以一种有意义的方式跟踪这些依赖,pip不能帮助你:它 管理Python包和只有Python包。
  Conda和pip不是竞争对手,而是侧重于不同用户组和使用模式的工具。

认为#4:在第一个地方创造conda是不负责任和分裂

  现实:Conda的创作者将Python的标准包装推向了极限十多年,并且只有在明确了它是唯一合理的前进道路时才创造了第二个工具。
  根据Python的哲学,在Python做任何事情“应该有一个,最好只有一个明显的方式来做”。那么为什么conda的创建者会通过引入一种新的方式来安装Python包呢?为什么他们没有贡献回Python社区并改进pip来克服它的缺陷?
  事实证明,这正是他们所做的。在2012年之前,PyData / SciPy生态系统的开发人员很大程度上在Python社区开发的包管理解决方案的约束下工作。早在2001年,NumPy项目就试图使它处理NumPy分布的复杂要求。他们将大部分的NETLIB绑定到一个单一的Python包(你可能知道这是SciPy),实际上创建一个分发为python包,以规避Python的分发工具不能用任何有意义的方式管理这些额外的Python依赖。为了阅读一些关于这些痛点的细节以及如何导致Conda,我建议Travis Oliphant的2013年博客文章。
  但是为什么Conda的创作者不和Python包装人员谈谈,一起找出这些挑战呢?事实证明,他们谈了。
  Conda的创始来自Guido van Rossum先生在2012年首届PyData聚会上发表演讲;在一个关于包装困难的问题上,他告诉我们,当谈到包装,“真的听起来像你的需求是相当大的Python社区,你只是更好地建立自己的”的讨论)。即使在遵循这个来自BDFL的建议的情况下,PyData社区继续与核心Python开发人员的对话和协作的主题:另一个公开的例子是CPython核心开发人员Nick Coghlan邀请在SciPy 2014主题演讲(见视频here )。他做了一个很好的演讲,在软件分发的“未解决问题”的背景下具体讨论了pip和conda,并提到了具有适合特定用户需求的多种分发方式的价值。
  Conda不是分裂的,Nick和其他人在Python包装管理局正式认可conda作为Python代码的许多重要的重新分发器之一,并且正在努力更好地使这些工具与Python包索引无缝地工作。

认为#5:conda不能使用virtualenv,所以它对我的工作流没有用

现实:你实际上可以在一个virtualenv中安装(一些)conda包,但更好的是使用Conda自己的环境管理器:它与pip完全兼容,并且比virtualenv有几个优点。
  virtualenv / venv是允许用户创建与pip一起使用的隔离的Python环境的实用程序。 Conda有自己的内置环境管理器,可以与conda和pip无缝工作,并且事实上比virtualenv / venv有几个优点:
  conda环境集成了不同Python版本的管理,包括Python本身的安装和更新。 Virtualenvs必须在现有的,外部管理的Python可执行文件上创建。
  conda环境可以跟踪非python依赖;例如无缝管理依赖性和基本工具(如LAPACK或OpenSSL)的并行版本
  而不是构建在符号链接上的环境 - 这破坏了virtualenv的隔离,并且对于非Python依赖关系有时可能是脆弱的 - conda-envs是单个可执行路径中的真正隔离环境。
  虽然virtualenvs与conda软件包不兼容,但conda环境与pip软件包完全兼容。第一个conda安装pip,然后你可以pip安装任何可用的包在那个环境中。您甚至可以在conda环境文件中显式地列出pip包,这意味着完整的软件堆栈可以从单个环境元数据文件完全重现。
  也就是说,如果你想在你的virtualenv中使用conda,它是可能的:
  $ virtualenv test_conda
  $ source test conda/bin/activate
  $ pip install conda
  $ conda install numpy
  这将在您的virtualenv中安装conda的MKL启用的NumPy包。 我不会推荐这个:我找不到这个功能的文档,并且结果似乎相当脆弱 - 例如,试图conda更新python内的virtualenv失败在一个非常不起眼和不可恢复的方式,看起来与 符合连接virtualenv的架构。 这似乎不是conda和virtualenv之间的一些根本不兼容,而是与构建过程中的一些细微不一致有关,因此是潜在可固定的(例如,参见conda Issue 1367和anaconda Issue 498)。
  如果你想避免这些困难,一个更好的想法是pip安装conda,然后创建一个新的conda环境中安装conda包。 对于习惯于使用pip / virtualenv / venv命令语法的人来说,conda文档包括conda和pip / virtualenv命令之间的转换表。

认为#6:现在pip使用wheels,conda不再需要

  现实:wheels只是提出conda发展的许多挑战之一,而wheels有弱点,Conda的二进制文件解决。
  驱动Conda创建的一个困难是,pip可以只分发源代码,而不是预编译的二进制分发,这对于构建诸如NumPy和SciPy的扩展重模块的用户来说尤其具有挑战性。 Conda以自己的方式解决了这个问题后,pip本身增加了对轮子的支持,这是一个二进制格式,旨在解决pip中的这个难题。有了这个问题在共同的工具,解决Conda早期采纳者现在应该回到pip?
  不必要。跨平台二进制文件的分发只是conda中解决的许多问题之一。编译的二进制文件聚焦了conda的另一个重要部分:有意义地跟踪非Python依赖关系的能力。因为pip的依赖关系跟踪只限于Python包,所以在轮子中这样做的主要方法是将发布的依赖包版本与Python包二进制包捆绑在一起,这使得更新这样的依赖很痛苦(最近OpenSSL的安全更新)。此外,conda包括一个真正的依赖解析器,一个pip目前缺乏的组件。
  对于科学用户,conda还允许将构建链接到优化的线性代数库,Continuum使用其自由提供的MKL启用的NumPy / SciPy。 Conda甚至可以分发非Python构建需求,例如gcc,这大大简化了在其分发的预编译二进制代码上构建其他包的过程。如果你试图使用pip的轮子,你最好希望你的系统有编译器和设置兼容那些用来最初构建的问题的车轮。

认为#7:conda不开源;它被绑定到一个营利公司,可以开始收取服务,只要他们想要

  现实:conda(包管理器和构建系统)是100%开源,Anaconda(发行版)也几乎在那里。
  在开放源代码世界中,有一些对营利性实体的根本不信任,而Anaconda是由Continuum Analytics创建的,而且是大型企业产品的一个免费组件,这使得一些人担心。
  让我们抛开一个事实,Continuum是,在我看来,是少数几家公司真正做开放软件正确的方式(一个话题另一个时间)。忽略这一点,事实是,Conda本身 - 包管理器,提供以跨平台方式构建,分发,安装,更新和管理软件的实用程序 - 是100%开源,可在GitHub和BSD许可。即使对于Anaconda(发行版),EULA只是一个标准的BSD许可证,用于创建Anaconda的工具链也是100%开源。总之,当使用Conda时,没有必要担心知识产权问题。
  如果Anaconda / Miniconda发行版仍然担心,放心:你不需要安装Anaconda或Miniconda来获得conda,虽然这些是方便的使用途径。正如我们上面所看到的,你可以“pip install conda”通过PyPI安装它,而无需Continuum的网站。

认为#8:但Conda包本身是封闭的,对不对?

现实:虽然conda的默认渠道尚未完全开放,有一个由社区主导的努力(Conda-Forge)使conda包装和分销完全开放。
  从历史上看,默认conda通道的软件包构建过程没有尽可能开放,并且获取构建更新的过程主要依赖于在Continuum上知道某人。谣言是,这主要是因为原始的conda包创建过程没有像今天一样明确和精简。
  但这正在改变。 Continuum正在努力打开他们的包装食谱,并且我被告知,500多个包装中只有几十个仍然需要移植。这些少数食谱是Anaconda分布中唯一不完全开放的剩余部分。
  如果这还不够,那么在2016年初推出的一个新的以社区为主导的项目,而不是Continuum附属项目,名为conda-forge,包含用于为任何软件包创建社区驱动的构建的工具。软件包通过github保持开放状态,二进制文件使用免费CI工具自动构建,如TravisCI for Mac OSX构建,AppVeyor for Windows构建和CircleCI for Linux构建。每个包的所有元数据都位于Github存储库中,并且通过合并Github pull请求(这是conda-forge中包更新的示例)完成包更新。
  Conda-forge完全是社区为基础的,由社区主导,虽然conda-forge可能还不够成熟,无法完全替代默认的conda渠道,Continuum的创始人已经公开表示,这是他们会支持的方向。你可以在Wes McKinney的最近的博客文章,conda-forge和PyData的CentOS时期更多地了解conda-forge的承诺。

认为#9:好的,但如果Continuum Analytics不折腾了,conda不会再工作了吗?

  现实:没有,Conda本质上,Continuum Analytics公司通过提供免费托管构建工件为社区服务。所有软件分发都需要由某人,甚至PyPI托管。
  的确,即使是conda-forge也将其软件包发布到http://anaconda.org/,这是一个由Continuum Analytics拥有和维护的网站。但在Conda没有什么需要这个网站。事实上,conda中的自定义渠道的创建是有详细记录的,没有什么可阻止某人建立和托管自己的私人分布使用Conda作为包管理器(conda索引是相关的命令)。考虑到conda食谱的开放性和构建系统conda-forge,如果你有理由这样做不会很难反映你自己的服务器上的所有conda-forge。
  如果你仍然担心Continuum Analytics - 一个营利公司 - 通过托管conda包为社区服务,你应该也同样担心Rackspace - 一个盈利的公司 - 通过托管Python包索引服务社区。在这两种情况下,一个营利性公司都是社区包裹管理系统目前表现形式的一部分。但在任何情况下,该公司的灭亡都会威胁到构建和分发系统的底层架构,这是完全自由和开源的。如果Rackspace或Continuum消失,社区只需为其依赖的开放式分配找到另一个主机和/或财务赞助者。

认为#10:每个人都应该放弃(conda | pip)和使用(pip | conda)!

  现实:pip和conda服务于不同的需求,我们应该更少关注他们如何竞争,更多地关注他们如何一起工作。
  正如在神话#2中提到的,Conda和pip是不同的项目,不同的目标读者:pip在任何环境中安装python包; conda安装在conda环境中的任何包装。考虑到在Python的禅意中提出的崇高理想,人们可能希望pip和conda可以以某种方式组合,所以将有一个而且只有一个明显的方式安装包。
  但这永远不会发生。这两个项目的目标太不同了。除非pip项目被广泛地重新定义,否则它永远不能有意义地安装和跟踪conda所做的所有非Python包:该架构是Python特定的(正确)以Python为重点。 Pip与PyPI一起旨在成为一个灵活的出版物和分发平台以及Python软件包的管理器,并且它的表现非常出色。
  同样,除非conda包被广泛重新定义,它将永远不会取代pip / PyPI作为Python代码的一般发布和分发平台。在其核心,conda关注在多个平台上健壮地运行复杂的多语言软件栈所需的详细依赖关系跟踪类型。 conda的存储库中的每个安装工件都绑定到一个确切的依赖链:通过设计,它不会允许你替换Jython for Python给定的包。你当然可以使用conda来构建一个Jython软件栈,但是每个包都需要一个新的特定于Jython的安装工件 - 这就是为了保持conda用户所依赖的严格依赖链所需要的。 Pip在这里更灵活,但一旦成本是它无法精确定义和解决依赖关系conda。
  最后,对pip和conda的关注完全错过了大量的Python代码的目的设计的重新分配器。从平台特定的软件包管理器,如apt,yum,macports和homebrew到像bento,buildout,hashdist和spack这样的跨平台工具,有很多特定的包装解决方案,旨在安装Python(和其他)特定用户。对于我们来说,像Python包装管理局那样,不是作为pip / PyPI的竞争对手,而是作为下游工具,可以利用所有开发和维护pip,PyPI的所有人的英勇努力,这将是更有成果的,和相关工具链。
  到哪里去?
  因此,似乎我们剩下两种不同的包装解决方案,但是对于许多Python用户来说,它们具有广泛的重叠(即在隔离环境中安装Python包时)。那么社会应该从这里走?我认为我们可以做的主要事情是确保项目(1)尽可能一起工作,和(2)相互学习有点。
  Conda
  如上所述,conda已经有一个完全打开的工具链,并且处于一个稳定的趋势,完全开放的包(但不完全在那里)。一个明显的方向是通过conda-forge推进社区发展和维护conda堆栈,或许最终使用它来代替conda当前的默认通道。
  在我们推进这一点时,我相信,conda和conda-forge社区可以从模仿Python包装管理局的明确和开放的治理模式中受益。例如,PyPA有一个开放的治理模式,明确的目标,新的发展和功能的清晰的路线图,以及明确的沟通和讨论的渠道,以及从根本上社区监督完整的pip / PyPI系统。
  另一方面,对于conda和conda-forge,代码(以及很快所有的配方)是开放的,但是系统的治理和控制模型远不够明确。鉴于conda的重要性,特别是在PyData社区,它将有益于所有这一点澄清这一点 - 也许在NumFOCUS组织的保护下。
  话虽如此,参与conda-forge的人告诉我,核心团队目前正在解决这个问题,包括生成管理文件,行为准则和加强提案框架。
  PyPI / pip
  虽然Python包索引似乎有其治理的秩序,有一些方面的conda / conda伪造,我认为将有益于它。例如,目前大多数Python包可以通过几个步骤加载到conda-forge:
  在网络上的某个地方发布公共代码版本(在github,bitbucket,PyPI等)
  创建指向此代码并列出依赖关系的配方/元数据文件
  在conda-forge / staged-recipes上打开一个pull请求
  就是这样。一旦pull请求合并,在Windows,OSX和Linux上的二进制版本将自动创建并加载到conda-forge通道。此外,通过github透明地管理和更新软件包,其中软件包更新可以由合作者审核,并在CI系统上线之前进行测试。
  我发现这个过程比发布到PyPI的(通过比较相对不透明的和手动的)过程更好,这主要由在本地终端处私人工作的单个用户来完成。也许PyPI可以利用conda-forge的现有构建系统,并创建一个选项来自动构建多平台轮和源分发,并在一个透明的命令中自动推送到PyPI。这绝对是一种可能性。

部署

看完上诉介绍,我们知道anaconda其实是包管理工具,而且是独立于发行版的。所以我们编译pytorch(其实官方编译pytorch的文档就是这样做的,之前都没注意用意),或者caffe,所依赖的第三方库实际都可以使用anaconda里面的,而且安装第三库是直接使用conda install 安装,如安装opencv,protobuf:

conda install libopencv
conda install libprotobuf=3.5

注意的是: =3.5 可以指定版本,不然默认安装的就是最新的版本。

编译通用版本pytorch,libtorch

下面以编译pytorch的C++ 的libtorch为例子进行讲解;

  1. 首先安装miniconda,miniconda比较小,但是anaconda的第三包比较多,不过编译c++的库不需要python包,所以推荐使用miniconda。
    bash ./Miniconda.sh			
  1. 根据官网教程安装必须组件,
conda install numpy pyyaml mkl mkl-include setuptools cmake cffi typing
  1. 如果有cuda,先安装cuda,cudnn;再通过conda安装cuda组件:
# Add LAPACK support for the GPU if needed
conda install -c pytorch magma-cuda92 # or [magma-cuda80 | magma-cuda91] depending on your cuda version
  1. 如果未使用source activate which conda
使用 export CMAKE_PREFIX_PATH=${CONDA_PREFIX:-"$(dirname $(which conda))/../"} 指定
  1. 编译
    python setup.py install
  1. 编译完成后,在
pytorch源码目录/torch/lib/tmp_install
  1. 下面找到c++的install文件;

通过miniconda编译的pytorch,可以在任意的linux,通过使用移植该miniconda的pytorch envs。

Tips:将编译好的libtorch直接复制到miniconda的pytorch 目录下,后续可以直接使用该envs下面的库和头文件。这样可以方便编译自己的库和程序。

编译通用版本caffe

所以使用Anaconda包管理主要是用于解决底层依赖库的问题,包括caffe的第三方库,如果官方有提供的库,例如mxnet,pytorch中的libtorch,甚至都不要自己编译,直接使用anaconda包管理中 软件包,大大降低了部署的难度。

Caffe 安装教程:

  1. 配置生成一个名为caffe的envs。
create -n caffe python=2.7 或者3.6
source activate caffe        #进入caffe这个envs
  1. 安装caffe的第三方依赖:

(特殊说明:由于caffe的分化,以及一直未得到官方更新问题,下面第三方库制定了的版本最好按照我测试过的版本进行安装,或者直接使用 conda search package,如conda search libprotobuf,选择安装最低版本)

使用atlas:

conda install libprotobuf=2.5 leveldb=1.18 snappy libopencv hdf5 libboost
conda install gflags=2.1.2 glog lmdb atlas

使用mkl(如果使用Intel的CPU,推荐使用MKL,使用CPU运算时速度最快):

conda install libprotobuf=2.5 leveldb=1.18 snappy libopencv hdf5 libboost
conda install gflags=2.1.2 glog lmdb mkl mkl-include

使用openblas:

conda install libprotobuf=2.5 leveldb=1.18 snappy libopencv hdf5 libboost
conda install gflags=2.1.2 glog lmdb openblas
  1. 针对caffe目录下的Cmakelist.txt,我们需要指定第三方库的位置.下面是经过测试的Cmakelist.txt,红字部分为增加路径。
cmake_minimum_required(VERSION 2.8.7)
if(POLICY CMP0046)
  cmake_policy(SET CMP0046 NEW)
endif()
if(POLICY CMP0054)
  cmake_policy(SET CMP0054 NEW)
endif()





# ---[ Caffe project
project(Caffe C CXX)

# ---[ Caffe version
set(CAFFE_TARGET_VERSION "1.0.0" CACHE STRING "Caffe logical version")
set(CAFFE_TARGET_SOVERSION "1.0.0" CACHE STRING "Caffe soname version")
add_definitions(-DCAFFE_VERSION=${CAFFE_TARGET_VERSION})

# ---[ Using cmake scripts and modules
list(APPEND CMAKE_MODULE_PATH ${PROJECT_SOURCE_DIR}/cmake/Modules)

include(ExternalProject)
include(GNUInstallDirs)

include(cmake/Utils.cmake)
include(cmake/Targets.cmake)
include(cmake/Misc.cmake)
include(cmake/Summary.cmake)
include(cmake/ConfigGen.cmake)

# ---[ Options
caffe_option(CPU_ONLY  "Build Caffe without CUDA support" ON) # TODO: rename to USE_CUDA
caffe_option(USE_CUDNN "Build Caffe with cuDNN library support" ON IF NOT CPU_ONLY)
caffe_option(USE_NCCL "Build Caffe with NCCL library support" OFF)
caffe_option(BUILD_SHARED_LIBS "Build shared libraries" ON)
caffe_option(BUILD_python "Build Python wrapper" ON)
set(python_version "2" CACHE STRING "Specify which Python version to use")
caffe_option(BUILD_matlab "Build Matlab wrapper" OFF IF UNIX OR APPLE)
caffe_option(BUILD_docs   "Build documentation" ON IF UNIX OR APPLE)
caffe_option(BUILD_python_layer "Build the Caffe Python layer" ON)
caffe_option(USE_OPENCV "Build with OpenCV support" ON)
caffe_option(USE_LEVELDB "Build with levelDB" ON)
caffe_option(USE_LMDB "Build with lmdb" ON)
caffe_option(ALLOW_LMDB_NOLOCK "Allow MDB_NOLOCK when reading LMDB files (only if necessary)" OFF)
caffe_option(USE_OPENMP "Link with OpenMP (when your BLAS wants OpenMP and you get linker errors)" OFF)

# This code is taken from https://github.com/sh1r0/caffe-android-lib
caffe_option(USE_HDF5 "Build with hdf5" ON)

# ---[ Caffe version
set(CAFFE_TARGET_VERSION "1.0.0" CACHE STRING "Caffe logical version")
set(CAFFE_TARGET_SOVERSION "1.0.0" CACHE STRING "Caffe soname version")
add_definitions(-DCAFFE_VERSION=${CAFFE_TARGET_VERSION})

#重点:::::::请在这里把自己的anaconda的envs——caffe路径设置在这里,下面是我的路径,请务必更改
set(ENVS_INCLUDE /home/shining/ProgramFiles/miniconda3/envs/caffe/include)
set(ENVS_LIB /home/shining/ProgramFiles/miniconda3/envs/caffe/lib)
set(ENVS_EXECUTABLE /home/shining/ProgramFiles/miniconda3/envs/caffe/bin)
#3rdparty path
#GLOG
set(GLOG_INCLUDE_DIR ${ENVS_INCLUDE} )
set(GLOG_LIBRARY ${ENVS_LIB}/libglog.so)
#set(GLOG_LIBRARIES ${ENVS_LIB})
#set(GLOG_LIBRARY_DIRS ${ENVS_LIB})

#HDF5
set(HDF5_INCLUDE_DIRS   ${ENVS_INCLUDE})
set(HDF5_LIBRARIES  ${ENVS_LIB}/libhdf5.so  ${ENVS_LIB}/libhdf5_cpp.so ${ENVS_LIB}/libhdf5_fortran.so)
set(HDF5_HL_LIBRARIES  ${ENVS_LIB}/libhdf5_hl.so)

#glags
set(GFLAGS_INCLUDE_DIR   ${ENVS_INCLUDE})
set(GFLAGS_LIBRARY ${ENVS_LIB}/libgflags.so )


#atlas
set(Atlas_CLAPACK_INCLUDE_DIR  ${ENVS_INCLUDE})
set(Atlas_CBLAS_INCLUDE_DIR  ${ENVS_INCLUDE})
set(Atlas_CBLAS_LIBRARY ${ENVS_LIB}/libcblas.so)
set(Atlas_BLAS_LIBRARY ${ENVS_LIB}/libblas.so)
set(Atlas_LAPACK_LIBRARY ${ENVS_LIB}/liblapack.so)

#levelDB
set(LevelDB_INCLUDE  ${ENVS_INCLUDE})
set(LevelDB_LIBRARY ${ENVS_LIB}/libleveldb.so)


#lmdb
set(LMDB_INCLUDE_DIR  ${ENVS_INCLUDE})
set(LMDB_LIBRARIES ${ENVS_LIB}/liblmdb.so)

#protobuf
set(PROTOBUF_INCLUDE_DIR  ${ENVS_INCLUDE})
#set(PROTOBUF_LITE_LIBRARIES ${ENVS_LIB}/libprotobuf-lite.so)
set(Protobuf_LIBRARY  ${ENVS_LIB}/libprotobuf-lite.so ${ENVS_LIB}/libprotoc.so ${ENVS_LIB}/libprotobuf.so)
#set(PROTOBUF_PROTOC_LIBRARIES ${ENVS_LIB}/libprotoc.so)
set(PROTOBUF_PROTOC_EXECUTABLE ${ENVS_EXECUTABLE}/protoc)

#boost
set(Boost_INCLUDE_DIR   ${ENVS_INCLUDE})
set(Boost_LIBRARIES  ${ENVS_LIB})

#MKL
set(MKL_INCLUDE_DIR  ${ENVS_INCLUDE})
set(MKL_LIBRARIES ${ENVS_LIB}/libmkl_avx2.so           
${ENVS_LIB}/libmkl_avx.so          
${ENVS_LIB}/libmkl_core.so         
${ENVS_LIB}/libmkl_def.so          
${ENVS_LIB}/libmkl_intel_ilp64.so  
${ENVS_LIB}/libmkl_intel_lp64.so    
${ENVS_LIB}/libmkl_mc3.so           
${ENVS_LIB}/libmkl_mc.so           
${ENVS_LIB}/libmkl_rt.so           
${ENVS_LIB}/libmkl_sequential.so    
${ENVS_LIB}/libmkl_vml_avx2.so      
${ENVS_LIB}/libmkl_vml_avx.so       
${ENVS_LIB}/libmkl_vml_cmpt.so      
${ENVS_LIB}/libmkl_vml_def.so       
${ENVS_LIB}/libmkl_vml_mc2.so       
${ENVS_LIB}/libmkl_vml_mc3.so       
${ENVS_LIB}/libmkl_vml_mc.so)

#openblas
SET(OpenBLAS_INCLUDE_DIR  ${ENVS_INCLUDE})
SET(OpenBLAS_LIB ${ENVS_LIB})

#snappy
set(Snappy_INCLUDE_DIR  ${ENVS_INCLUDE})
set(Snappy_LIBRARIES ${ENVS_LIB}/libsnappy.so)

# message("-- Warning: LIBCXX = ${LIBCXX}")
# if(LIBCXX STREQUAL "libstdc++11")
#     add_definitions(-D_GLIBCXX_USE_CXX11_ABI=1)
# 如果最后link报protocbuf错误请添加该指令
add_definitions(-D_GLIBCXX_USE_CXX11_ABI=0)
# endif()

# ---[ Dependencies
include(cmake/Dependencies.cmake)

# ---[ Flags
if(UNIX OR APPLE)
  set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fPIC -Wall")
endif()

caffe_set_caffe_link()

if(USE_libstdcpp)
  set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -stdlib=libstdc++")
  message("-- Warning: forcing libstdc++ (controlled by USE_libstdcpp option in cmake)")
endif()

# ---[ Warnings
caffe_warnings_disable(CMAKE_CXX_FLAGS -Wno-sign-compare -Wno-uninitialized)

# ---[ Config generation
configure_file(cmake/Templates/caffe_config.h.in "${PROJECT_BINARY_DIR}/caffe_config.h")

# ---[ Includes
set(Caffe_INCLUDE_DIR ${PROJECT_SOURCE_DIR}/include)
set(Caffe_SRC_DIR ${PROJECT_SOURCE_DIR}/src)
include_directories(${PROJECT_BINARY_DIR})

# ---[ Includes & defines for CUDA

# cuda_compile() does not have per-call dependencies or include pathes
# (cuda_compile() has per-call flags, but we set them here too for clarity)
#
# list(REMOVE_ITEM ...) invocations remove PRIVATE and PUBLIC keywords from collected definitions and include pathes
if(HAVE_CUDA)
  # pass include pathes to cuda_include_directories()
  set(Caffe_ALL_INCLUDE_DIRS ${Caffe_INCLUDE_DIRS})
  list(REMOVE_ITEM Caffe_ALL_INCLUDE_DIRS PRIVATE PUBLIC)
  cuda_include_directories(${Caffe_INCLUDE_DIR} ${Caffe_SRC_DIR} ${Caffe_ALL_INCLUDE_DIRS})

  # add definitions to nvcc flags directly
  set(Caffe_ALL_DEFINITIONS ${Caffe_DEFINITIONS})
  list(REMOVE_ITEM Caffe_ALL_DEFINITIONS PRIVATE PUBLIC)
  list(APPEND CUDA_NVCC_FLAGS ${Caffe_ALL_DEFINITIONS})
endif()

# ---[ Subdirectories
add_subdirectory(src/gtest)
add_subdirectory(src/caffe)
add_subdirectory(tools)
add_subdirectory(examples)
add_subdirectory(python)
add_subdirectory(matlab)
add_subdirectory(docs)

# ---[ Linter target
add_custom_target(lint COMMAND ${CMAKE_COMMAND} -P ${PROJECT_SOURCE_DIR}/cmake/lint.cmake)

# ---[ pytest target
if(BUILD_python)
  add_custom_target(pytest COMMAND python${python_version} -m unittest discover -s caffe/test WORKING_DIRECTORY ${PROJECT_SOURCE_DIR}/python )
  add_dependencies(pytest pycaffe)
endif()

# ---[ uninstall target
configure_file(
    ${CMAKE_CURRENT_SOURCE_DIR}/cmake/Uninstall.cmake.in
    ${CMAKE_CURRENT_BINARY_DIR}/cmake/Uninstall.cmake
    IMMEDIATE @ONLY)

add_custom_target(uninstall
    COMMAND ${CMAKE_COMMAND} -P
    ${CMAKE_CURRENT_BINARY_DIR}/cmake/Uninstall.cmake)

# ---[ Configuration summary
caffe_print_configuration_summary()

# ---[ Export configs generation
caffe_generate_export_configs()


#检查libcaffe.so 的link路径是否设置到miniconda的envs中
message("Caffe_INCLUDES: ${Caffe_INCLUDE_DIRS}")
message("Caffe_LINKER_LIBS: ${Caffe_LINKER_LIBS}")

其中添加的代码包括:

#重点:::::::请在这里把自己的anaconda的envs——caffe路径设置在这里,下面是我的路径,请务必更改
#重点:::::::请在这里把自己的anaconda的envs——caffe路径设置在这里,下面是我的路径,请务必更改
set(ENVS_INCLUDE /home/shining/ProgramFiles/miniconda3/envs/caffe/include)
set(ENVS_LIB /home/shining/ProgramFiles/miniconda3/envs/caffe/lib)
set(ENVS_EXECUTABLE /home/shining/ProgramFiles/miniconda3/envs/caffe/bin)
#3rdparty path
#GLOG
set(GLOG_INCLUDE_DIR ${ENVS_INCLUDE} )
set(GLOG_LIBRARY ${ENVS_LIB}/libglog.so)
#set(GLOG_LIBRARIES ${ENVS_LIB})
#set(GLOG_LIBRARY_DIRS ${ENVS_LIB})

#HDF5
set(HDF5_INCLUDE_DIRS   ${ENVS_INCLUDE})
set(HDF5_LIBRARIES  ${ENVS_LIB}/libhdf5.so  ${ENVS_LIB}/libhdf5_cpp.so ${ENVS_LIB}/libhdf5_fortran.so)
set(HDF5_HL_LIBRARIES  ${ENVS_LIB}/libhdf5_hl.so)

#glags
set(GFLAGS_INCLUDE_DIR   ${ENVS_INCLUDE})
set(GFLAGS_LIBRARY ${ENVS_LIB}/libgflags.so )


#atlas
set(Atlas_CLAPACK_INCLUDE_DIR  ${ENVS_INCLUDE})
set(Atlas_CBLAS_INCLUDE_DIR  ${ENVS_INCLUDE})
set(Atlas_CBLAS_LIBRARY ${ENVS_LIB}/libcblas.so)
set(Atlas_BLAS_LIBRARY ${ENVS_LIB}/libblas.so)
set(Atlas_LAPACK_LIBRARY ${ENVS_LIB}/liblapack.so)

#levelDB
set(LevelDB_INCLUDE  ${ENVS_INCLUDE})
set(LevelDB_LIBRARY ${ENVS_LIB}/libleveldb.so)


#lmdb
set(LMDB_INCLUDE_DIR  ${ENVS_INCLUDE})
set(LMDB_LIBRARIES ${ENVS_LIB}/liblmdb.so)

#protobuf
set(PROTOBUF_INCLUDE_DIR  ${ENVS_INCLUDE})
#set(PROTOBUF_LITE_LIBRARIES ${ENVS_LIB}/libprotobuf-lite.so)
set(Protobuf_LIBRARY  ${ENVS_LIB}/libprotobuf-lite.so ${ENVS_LIB}/libprotoc.so ${ENVS_LIB}/libprotobuf.so)
#set(PROTOBUF_PROTOC_LIBRARIES ${ENVS_LIB}/libprotoc.so)
set(PROTOBUF_PROTOC_EXECUTABLE ${ENVS_EXECUTABLE}/protoc)

#boost
set(Boost_INCLUDE_DIR   ${ENVS_INCLUDE})
set(Boost_LIBRARIES  ${ENVS_LIB})

#MKL
set(MKL_INCLUDE_DIR  ${ENVS_INCLUDE})
set(MKL_LIBRARIES ${ENVS_LIB}/libmkl_avx2.so           
${ENVS_LIB}/libmkl_avx.so          
${ENVS_LIB}/libmkl_core.so         
${ENVS_LIB}/libmkl_def.so          
${ENVS_LIB}/libmkl_intel_ilp64.so  
${ENVS_LIB}/libmkl_intel_lp64.so    
${ENVS_LIB}/libmkl_mc3.so           
${ENVS_LIB}/libmkl_mc.so           
${ENVS_LIB}/libmkl_rt.so           
${ENVS_LIB}/libmkl_sequential.so    
${ENVS_LIB}/libmkl_vml_avx2.so      
${ENVS_LIB}/libmkl_vml_avx.so       
${ENVS_LIB}/libmkl_vml_cmpt.so      
${ENVS_LIB}/libmkl_vml_def.so       
${ENVS_LIB}/libmkl_vml_mc2.so       
${ENVS_LIB}/libmkl_vml_mc3.so       
${ENVS_LIB}/libmkl_vml_mc.so)

#openblas
SET(OpenBLAS_INCLUDE_DIR  ${ENVS_INCLUDE})
SET(OpenBLAS_LIB ${ENVS_LIB})

#snappy
set(Snappy_INCLUDE_DIR  ${ENVS_INCLUDE})
set(Snappy_LIBRARIES ${ENVS_LIB}/libsnappy.so)

# message("-- Warning: LIBCXX = ${LIBCXX}")
# if(LIBCXX STREQUAL "libstdc++11")
#     add_definitions(-D_GLIBCXX_USE_CXX11_ABI=1)
# 如果最后link报protocbuf错误请添加该指令
add_definitions(-D_GLIBCXX_USE_CXX11_ABI=0)
# endif()

该增加的代码功能主要是实现指定第三方库的路径。

#检查libcaffe.so 的link路径是否设置到miniconda的envs中
message("Caffe_INCLUDES: ${Caffe_INCLUDE_DIRS}")
message("Caffe_LINKER_LIBS: ${Caffe_LINKER_LIBS}")

该代码主要是用于检查liacaffe.so的链接库是否正常。

需要说明的是:由于libprotobuf,conda使用的版本编译器与我们的主机GCC版本可能不一致, 一般是5.X与4.X的大版本不同引起的。 综上,使用与编译Cafffe一致的GCC 4.9编译glog,gflags,boost库能够起作用的真正原因已经找到。

    add_definitions(-D_GLIBCXX_USE_CXX11_ABI=0)

上面这段话,非常重要,不然编译时会报link错误。

  1. 编译:
    cd 到caffe的根目录,使用下面指令进行编译
mkdir build
cd build
cmake ..

当然我们如果需要更改编译选项,可通过增加cmake命令参数,如:

cmake -DCMAKE_BUILD_TYPE=Release -DCPU_ONLY=ON -DBLAS=MKL ..

或者使用cmake-gui进行直接配置。
6. make install,将编译好的库安装在指定路径(默认是caffe/build/install下面)

部署到其他linux平台:

打包

假设我们一般是依赖caffe或者libtorch进行二次开发,所以想自己编译的库,对库的依赖请指定所使用的conda的envs和编译通过的caffe或者libtorch,为了方便指定路径,推荐将编译好的caffe或者libtorch库直接拷贝到conda的envs的include ,lib,share下面。推荐使用cmake进行编译开发,当然QT和直接编写makefile也均可以。只不过注意link和include路径,别一不小心指到系统的库。
当我们编译好自己的库后,准备打包发布。使用下面指令将我们的conda的envs进行打包。下面是tar指令的示例:
    压缩
    tar -cvf jpg.tar *.jpg //将目录里所有jpg文件打包成jpg.tar 
    tar -czf jpg.tar.gz *.jpg   //将目录里所有jpg文件打包成jpg.tar后,并且将其用gzip压缩,生成一个gzip压缩过的包,命名为jpg.tar.gz
     tar -cjf jpg.tar.bz2 *.jpg //将目录里所有jpg文件打包成jpg.tar后,并且将其用bzip2压缩,生成一个bzip2压缩过的包,命名为jpg.tar.bz2
    tar -cZf jpg.tar.Z *.jpg   //将目录里所有jpg文件打包成jpg.tar后,并且将其用compress压缩,生成一个umcompress压缩过的包,命名为jpg.tar.Z
    rar a jpg.rar *.jpg //rar格式的压缩,需要先下载rar for linux
    zip jpg.zip *.jpg //zip格式的压缩,需要先下载zip for linux
    解压
    tar -xvf file.tar //解压 tar包
    tar -xzvf file.tar.gz //解压tar.gz
    tar -xjvf file.tar.bz2   //解压 tar.bz2
    tar -xZvf file.tar.Z   //解压tar.Z
    unrar e file.rar //解压rar
    unzip file.zip //解压zip
所以我们只需要使用,
```
tar czvf run.tar.gz  /home/shining/ProgramFiles/miniconda/envs/run #/home/shining/ProgramFiles/miniconda/envs/caffe 为anaconda的绝对路径
```

将conda的envs进行打包,注意请务必打包好后部署,直接拷贝文件夹,会出现link库找不到,这是因为拷贝可能无法拷贝软链接。

在其他平台运行:

假设我们的包run.tar.gz解压在/root下面, 这样包的路径就是/root/run
将包的lib路径和bin路径添加到环境变量中,使得我们的可执行程序或者库生效。使用如下指令添加:
    sudo vi /etc/profile
把下面的路径添加进去:
    export PATH=/root/run/bin${PATH:+:${PATH}}
    export LD_LIBRARY_PATH=/root/run/lib${LD_LIBRARY_PATH:+:${LD_LIBRARY_PATH}}
保存并退出。使用
    source /etc/profile    

激活环境变量,接下来我们就可以愉快的使用我们的程序或者库了。

发布了45 篇原创文章 · 获赞 21 · 访问量 5万+

猜你喜欢

转载自blog.csdn.net/xxradon/article/details/86080589