Windows 環境下Java調用CRF++詳解


1.步驟一覽

image

2.步驟詳情

2.1.環境准備

Swig(Simplified Wrapper and Interface Generator)下載,Windows操作系統直接解壓即可使用

CRF++(Yet Another CRF toolkit)下載,CRF++-0.58zip和CRF++-0.58.tar.gz兩個版本最好都下載,方便我們后續操作

VS2013下載,本文用的是試用版

 

2.2.Swig包裝CRF++

2.2.1.包裝文件准備

用Swig包裝CRF++主要用到以下源文件,CRF++-0.58.zip\CRF++-0.58\sdk\crfpp.h, CRF++-0.58.zip\CRF++-0.58\sdk\libcrfpp.lib

還需要一個SWIG接口文件,接口文件CRFPP.i我們直接從CRF++-0.58.tar.gz\CRF++-0.58\swig目錄下解壓拷貝出來,順便也將version.h拷出來,與其它原文件放在一起。目錄結構如下:

image

現在來看一下接口文件里的內容

%module CRFPP
%include exception.i
%{
#include "crfpp.h"
%}

%newobject surface;

%exception {
  try { $action }
  catch (char *e) { SWIG_exception (SWIG_RuntimeError, e); }
  catch (const char *e) { SWIG_exception (SWIG_RuntimeError, (char*)e); }
}

%feature("notabstract") CRFPP::Model;
%feature("notabstract") CRFPP::Tagger;
%ignore CRFPP::createModel;
%ignore CRFPP::createModelFromArray;
%ignore CRFPP::createTagger;
%ignore CRFPP::getTaggerError;
%ignore CRFPP::getLastError;

%extend CRFPP::Model { Model(const char *arg); }
%extend CRFPP::Tagger { Tagger(const char *arg); }

%{

void delete_CRFPP_Model (CRFPP::Model *t) {
  delete t;
  t = 0;
}

CRFPP::Model* new_CRFPP_Model(const char *arg) {
  CRFPP::Model *tagger = CRFPP::createModel(arg);
  if (!tagger) throw CRFPP::getLastError();
  return tagger;
}

void delete_CRFPP_Tagger (CRFPP::Tagger *t) {
  delete t;
  t = 0;
}

CRFPP::Tagger* new_CRFPP_Tagger (const char *arg) {
  CRFPP::Tagger *tagger = CRFPP::createTagger(arg);
  if (!tagger) throw CRFPP::getLastError();
  return tagger;
}

%}

%include crfpp.h
%include version.h
由於CRFF.i文件和crfpp.h位於同一目錄,故將倒數第二行更改。另外如果沒有version.h文件,把最后一行%include version.h刪去即可

 

2.2.2包裝文件

在命令行cmd下執行:C:\swigwin-2.0.12\swig.exe -c++ -java -package com.ibugs.crfpp D:\CRF++-0.58\sdk\CRFPP.i

其中C:\swigwin-2.0.12\swig.exe 為Swig的解壓目錄,D:\CRF++-0.58\sdk\CRFPP.i為CRFPP.i放置目錄。另外-package com.ibugs.crfpp,設置編譯后java文件的包名,包名大家可以自己設定。執行后會生成以下文件,其中CRFPP_wrap.cxx包裝文件為編譯動態鏈使用;*.java文件在調用java項目中引入。

image

 

2.3.編譯動態鏈庫

2.3.1.創建DLL工程

在VS新建DLL項目工程,

image

image

千萬要將Application type設置為DLL,這樣就將工程建好了。然后將CRFPP_wrap.cxx復制到工程中即可

image

2.3.2.編譯動態鏈庫

直接右鍵工程Build,好像出錯了。

image

錯誤信息提示找不到jni.h文件。jni.h文件為jdk安裝目錄自帶庫,那我們就要配置包含目錄。右鍵工程Properties打開如下,並在C/C++>>General>>Additional Include Directories添加包含目錄

image

再來Build一下吧,很不幸又出錯了

image

錯誤信息提示找不到相應的函數,在sdk目錄下還有一個libcrfpp.lib包,把它拷入項目中來。然后Build,好像這次真的成功啦image

在項目物理目錄中可以看到生成的動態鏈庫文件

image

2.4.總算可以實例了

建立一個Java項目,目錄結構如下:其中包名和Swig包裝設定的包名一致,將Swig生成的相應Java文件拷入項目中;同時將生成的動態鏈庫CRFPP.dll放入lib目錄中,其中libcrfpp.dll文件在CRF++-0.58.zip\目錄下

image

測試文件test.java,可以從CRF++-0.58.tar.gz\CRF++-0.58\swig目錄獲得,如下:

package com.ibugs.crfpp;

public class test {

public static void main(String[] argv) {
    
  //Tagger tagger = new Tagger("-m W://model -v 3 -n2");
  Tagger tagger = new Tagger("-m D://CRF++-0.58/CRF++-0.58/chinese/model -v 3 -n2");
  
  // clear internal context
  tagger.clear();

  // add context
  tagger.add("Confidence NN");
  tagger.add("in IN");
  tagger.add("the DT");
  tagger.add("pound NN");
  tagger.add("is VBZ");
  tagger.add("widely RB");
  tagger.add("expected VBN");
  tagger.add("to TO");
  tagger.add("take VB");
  tagger.add("another DT");
  tagger.add("sharp JJ");
  tagger.add("dive NN");
  tagger.add("if IN");
  tagger.add("trade NN");
  tagger.add("figures NNS");
  tagger.add("for IN");
  tagger.add("September NNP");

  System.out.println("column size: " + tagger.xsize());
  System.out.println("token size: " + tagger.size());
  System.out.println("tag size: " + tagger.ysize());

  System.out.println("tagset information:");
  for (int i = 0; i < tagger.ysize(); ++i) {
    System.out.println("tag " + i + " " + tagger.yname(i));
  }

  // parse and change internal stated as 'parsed'
  if (!tagger.parse())
    return;

  System.out.println("conditional prob=" + tagger.prob()
                     + " log(Z)=" + tagger.Z());

  for (int i = 0; i < tagger.size(); ++i) {
    for (int j = 0; j < tagger.xsize(); ++j) {
        System.out.print(tagger.x(i, j) + "\t");
    }
    System.out.print(tagger.y2(i) + "\t");
    System.out.print("\n");

    System.out.print("Details");
    for (int j = 0; j < tagger.ysize(); ++j) {
      System.out.print("\t" + tagger.yname(j) + "/prob=" + tagger.prob(i,j)
                       + "/alpha=" + tagger.alpha(i, j)
                       + "/beta=" + tagger.beta(i, j));
    }
    System.out.print("\n");
  }

  // when -n20 is specified, you can access nbest outputs
  System.out.println("nbest outputs:");
  for (int n = 0; n < 10; ++n) {
    if (! tagger.next()) break;
    System.out.println("nbest n=" + n + "\tconditional prob=" + tagger.prob());
    // you can access any information using tagger.y()...
  }
  System.out.println("Done");
  
  System.out.println();
}

static {
  try {
 //System.loadLibrary(CRFPP);
    System.loadLibrary("./lib/libcrfpp);
    System.loadLibrary("./lib/CRFPP");
  } catch (UnsatisfiedLinkError e) {
    System.err.println("Cannot load the example native code.\nMake sure your LD_LIBRARY_PATH contains \'.\'\n" + e);
    e.printStackTrace();
    System.exit(1);
  }
}

}

需要修改代碼

指定模板文件:Tagger tagger = new Tagger("-m W://model -v 3 -n2");  ==〉 Tagger tagger = new Tagger("-m D://CRF++-0.58/CRF++-0.58/chinese/model -v 3 -n2"); 其中model為指定的模板文件

指定動態鏈庫文件:System.loadLibrary("CRFPP");  ==〉System.loadLibrary("./lib/libcrfpp); System.loadLibrary("./lib/CRFPP");

總算可以結束啦,執行java程序吧!祝你好運沒有其它什么錯誤。

 

另外,可以將Swig工具嵌入到VS中執行,在Tools工具條添加外部工具

image

image

其中的Arguments:-c++ -java -package com.ibugs.crfpp $(ItemFileName)$(ItemExt)

執行時,將CRFPP.i文件拷入工程中並選中,在Tools找到Swig點擊即執行

image

 

3.小結

Java調用C++語言其實並不難,關鍵是不熟悉整個流程。

搞了半天好像自己編譯的CRFPP.dll沒太大的作用,直接在工程中引用CRF++-0.58.zip\目錄下libcrfpp.dll即可


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM