前言
因爲剛在公司接手了一個使用crf++做對象識別的項目,該項目之前一直不能在windows上運行(crf++需要配置相應的環境,並且如
果想和JAVA整合需要用swig來封裝動態鏈接庫形成JNI接口),而且也缺乏日誌,所以就想直接配置出windows的開發調試環境,在網
上搜索了很多前輩的方法,很受啓發,但是也有一些語焉不詳的地方讓我入了不少坑,所以在此準備將Linux的Crf+java整合方法和
windows的Crf+java環境配置方法都整理出來,也爲自己之後的留用,也爲給有同樣需求的同學提供一些小小的幫助。
配置步驟
1.windows
軟件環境 win10 + crf++0.58win32 + jdk1.7.0._45(win32) + swigwin3.0.10 + swig-3.0.12 + visual studio2017(crf和swig之類的
東西會在末尾打包留種的)
Tip:關於爲什麼使用32位的jdk是因爲crf++0.58只有linux版本和win32版本的,如果用64位的jdk的話在加載libcrfpp.dll的時候容易出現Can't load IA
32-bit .dll on a AMD 64-bit platform的問題,當然不是說不能搞,只不過爲了方便起見,博主還是直接安裝了一個32位的jdk,關於win上安裝多個jdk有
時候會出現改環境變量不好使的情況,這個時候可以檢查下 控制面板-》java-》java-》查看 在裏面設置運行時環境設置,如果還不好使的話你
C:\Windows\System32\目錄下絕對有java.exe,javaw.exe,javaws.exe這些文件,直接刪掉就好,這個操作的詳細描述請戳
由於CRF++是用c++編寫的條件隨機場工具,爲了在JAVA爲主體的程序中使用的話就應該使用JNI技術對java進行擴展,並將CRF++編譯爲可供java
調用的動態鏈接庫。SWIG可以幫我們將C++編寫的CRF++和JAVA系統進行聯合。
首先將 XXX\CRF++-0.58\sdk(windows版) 目錄下的crfpp.h,libcrfpp.lib兩個文件拷貝出來放在一個單獨的文件夾裏,在將XXX\CRF++-0.58\swig
下的CRFPP.i和version.h拷貝出來放在同樣的目錄下,這個時候這個目錄的截圖是這樣的。![]()
打開CRFPP.i,在倒數第二行的地方將%include ../crfpp.h 改爲 %include crfpp.h 因爲他們現在都在同一個文件夾下了嘛。
之後我們需要使用win版的swig了,直接解壓就可以用,你也可以將swig的swig.exe添加進環境變量,這樣不需要每次使用都再輸一大串的地址。
如果配置了swig環境變量 swig –c++ -java -package org.anon.crfpp CRFPP.i (-package 後面的包名自己隨便起的啦)
沒配的話就給一個全路徑咯 /d/crf++Env/swig3.0.10win/swigwin-3.0.10/swig.exe -c++ -java -package com.anon.crfpp /d/crf++Env/sdkCol/CRFPP.i
(我是在git bash裏執行的,cmd的自己轉下路徑格式)
然後在我們的文件夾中可以看到以下文件。![]()
*.java就是swig生成的調用文件,測試類可以去linux版的crf++0.58下的java目錄下拷貝出test.java類,將這些類拷進一個項目中。
接下來就是最容易出錯也是最麻煩的環節了,我們要編譯一個dll動態鏈接庫,在這裏我使用的是Visual studio 2017,當然任何版本的都是可以的,
在項目配置嚮導這裏記得要選擇dll,附件選項選上空項目即可,要不然會有一堆然並卵的東西生成。
接下來我們將生成的CRFPP_wrap.cxx(和*.java一起生成的)文件拷貝入CRFPP項目中,放在源文件下
這個時候你可以試着右鍵項目,生成一下,會報錯誤如下
這是因爲我們編譯dll還需要JDK中jni.h的幫助,這個時候我們可以對項目進行少許配置。
右鍵工程點擊屬性 配置屬性-》VC++目錄中進行如下配置
將包含目錄中添加你使用的jdk的include目錄( xxx\java\jdk_1.7.0_45win32\include) ,和include下的32win目錄(xxx\java\jdk_1.7.0_45win32
\include\win32)。
在庫目錄下添加win版的crf++的sdk文件夾,也就是libcrfpp.lib的目錄(xxx\crf++Env\CRF++-0.58\sdk)。
網上有的博客說這樣就可以生成成功了,大家可以試一下,反正我配置到這一步沒有生成成功,報之下的錯誤
如果你到這一步能生成成功那很Nice,不能的話那就接着按之下的步驟進行配置。
依舊是右鍵項目,屬性,鏈路器下的常規再配置下附加庫目錄,
接着還沒完,在鏈路器下的輸入里加上libcrfpp.lib,編輯裏直接輸就可以
OK,全部配置流程走完了。build一下試試。
果不其然的生成成功了,但是請注意這個時候是Debug模式生成的dll,這個時候我們要再調到Release模式生成一遍dll,使用release的dll去進行
JAVA整合調用。對的,是不是又報錯了?那是因爲Release和debug的屬性是兩套,再練一遍熟下手吧,我也是爲你好![大笑]()
接下來就是和JAVA項目整合了,在項目裏建一個文件夾,我比較習慣取名lib,將剛生成的dll文件和win版的CRF++0.58目錄下的 libcrfpp.dll都拷入文
件夾下。
然而工作並沒有結束,我們要在JRE System Library裏添加入lib的配置路徑,右鍵點擊JRE System Library 然後build Path ->configure build path
將之前的lib文件夾目錄配置入Native library location中,如下所示
然後運行test.java 的main方法,不過記得之前將他讀取的模型路徑改變一下![]()
如果沒有模型的話在附件裏找就行,友情提供一個。
然後當你滿懷激動的心情運行的時候,他偏偏有可能報這個錯![]()
這是因爲我們的dll庫並不叫CRFPP,而是叫CRFPP_demo,我們load的library應該是和這個dll庫同名的,然後我們很無奈的改了loadLibrary的參數
以後,他很有可能還會報一個錯。
這句話的意思是找不到依賴的dll包,感覺這個有很多種解決方案,有人說可以直接在C:\Windows\System32文件夾下加入libcrfpp.dll就好,但是我嘗
試的並沒有什麼效果,同樣嘗試了感覺沒什麼效果的可以再加一行load庫的代碼如下。然後運行成功
這是在eclipse下的crfpp配置,IDEA下的其實也差不多,有人想配的話照着這個流程來就行,實在出不來了給我留言我更新下,windows佔的篇幅太
多了,有一些坑沒有全部列出來,如果有哪些坑以上沒有涉及到可以留言,我再更新(畢竟win下坑還是蠻多的)。
2.Linux
軟件環境 CentOS release 6.9 (Final),CRF++0.58,pcre-8.32.tar.gz,swig3.0.12, java version "1.8.0_111".
首先確認一點,你的jdk如果是openjdk的話你需要刪除它,安裝正常的jdk,就是打印java -version出現信息是如下這樣的jdk
java version "1.8.0_111"
Java(TM) SE Runtime Environment (build 1.8.0_111-b14)
Java HotSpot(TM) 64-Bit Server VM (build 25.111-b14, mixed mode)
卸載方法自行百度,jdk安裝方法也不多說了,都很簡單。
tar -zxvf CRF++-0.58.tar.gz 解壓
然後cd進去三步走起
./configure
make
make install
如果沒有安裝g++會報錯應該,安裝的命令是:yum install -y gcc-c++
如果三步進行完了我們就可以開始訓練自己的模型了,正好也測試下crf++到底好不好使。
在訓練模型的時候需要模板和語料,這個大家可以自己上網找一下,我在附加中也會提供一些簡單的僅供測試的語料和模板,關於模板和
模型之類的知識不是本文討論的重點,大家可以自行查閱相關文章。
訓練模型 crf_learn segment_template train.data test.model -t (segment_template是模板,train.data是訓練語料,test.model
是生成的模型名字, -t的意思是生成可讀的模型,可用於深入理解CRF模型)
如果報以下錯誤
crf_learn: error while loading shared libraries: libcrfpp.so.0: cannot open shared object file:
No such file or directory
則修改/etc/ld.so.conf文件,加入
include /usr/local/lib,執行/sbin/ldconfig -v,刷新LIB庫,再試試就好用了。
然後用生成的模型來標註下測試語料,
crf_test -m seg_1_test.model test.data > result.txt (-m 後面選擇要使用的模型,test.data是要標註的語料,result.txt是標註結
果,本文提供的測試語料是簡單的BMES標註,只爲熟悉流程。train.data和result.txt的內容應該是一樣的,你也可以找一些其他的測試語料來測
試模型的標註效果。PS:本文語料選擇中石化新聞網)。
OK,測試CRF運行無誤以後我們開始用swig整合JNI接口聯合JAVA。
tar -zxvf swig-3.0.12.tar.gz 使用命令解壓swig,然後cd進入swig目錄。
將pcre-8.32.tar.gz拷貝入swig目錄,在目錄下依次執行
./Tools/pcre-build.sh
./configure
make
make install
然後可以用swig -version查看版本
顯示版本則證明swig安裝成功,這個時候我們開始使用swig將crf++封裝爲JNI接口。
cd CRF++-0.58/swig/ 進入CRF下的swig目錄。
make
然後再進入crf下的java目錄 cd ../java/
make
這個時候報錯了,找不到jni.h
打開文件CRFPP_wrap.cxx,找到這一行 :
#include <jni.h> ,將這一行改爲:
#include "jni.h"
然後,到java的安裝目錄下,將這兩個文件(jni.h,jni_md.h)拷貝到
/crf0.58/java目錄下。
然後make,編譯成功
這個時候一般來講運行java test是不會直接就成功的,我們還需要對test.java做一些修改。
![]()
這個時候就把這裏的model路徑換成之前我們生成的model路徑。wq保存退出再make
很多人會發現然而這並沒有什麼用,該報錯還是報錯,那麼依序執行以下命令
cp libCRFPP.so/lib
cp libCRFPP.so/lib64
cp libCRFPP.so/usr/lib
cp libCRFPP.so/usr/lib64
chmod 775 /usr/lib64/libCRFPP.so
然後執行下列命令:
cd /usr/local/lib
cp libcrfpp.so.0 /usr/lib64
最後不要忘了回到CRF++0.58的java目錄下。
再試下java test。再沒結果給我留言
![]()