快速部署多版本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    

激活環境變量,接下來我們就可以愉快的使用我們的程序或者庫了。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章