本文只介紹如何快速的使用CRF++做序列標注,對其中的原理和訓練測試參數不做介紹。
官網地址:CRF++: Yet Another CRF toolkit
主要完成如下功能:
輸入 -> "周傑倫是誰"
輸出 -> "[周傑倫:artist]是誰"
以下所有內容均為原創,如果覺得本教程不錯的話,點個贊再走唄~
一、資源准備
下載鏈接中的內容:
鏈接:https://pan.baidu.com/s/16iw3WBSHI1U5U1G_xbikDA 密碼:cfqi
該文件夾里面包含了以下內容:
1、CRF++-0.58.tar.gz,CRF++開源工具,這個是從CRF++官網上下載的。
2、data文件夾,訓練和測試需要的數據,這個是我自己寫的,其中:
- input文件夾,存放所需要的數據:
train_data.txt,訓練數據,這里只有幾條作為示例,實際工程中,需要上萬條數據;
test_data.txt,測試數據;
crf.template,特征模板。 - output文件夾 -> 輸出的模型和測試結果。
3、code文件夾,C++調用CRF++接口的代碼示例,這個是我自己寫的。
二、CRF++的編譯
按照如下命令進行:
tar zxvf CRF++-0.58.tar.gz
cd CRF++-0.58
./configure
make
sudo make install
這時候就編譯安裝成功了。
cd /usr/local/bin
cd /usr/local/lib
切換到上面這兩個目錄,bin目錄下可以看到crf_learn和crf_test兩個可執行程序,分別用於模型的訓練和測試; lib目錄下是生成的CRF++庫。
//備注1:CRF++-0.58/.libs,這個目錄下也有生成上述可執行程序和庫。
//備注2:如果不想安裝到上述目錄,或者沒有root權限,在configure的時候指定安裝目錄即可。
三、模型訓練
按照如下命令進行:
cd CRF++_tutorial/data
./train.sh
這樣,我們就得到了模型,即output/crf.mdl文件,這個文件是二進制的沒辦法查看。
train.sh腳本內容如下:
#/usr/local/bin/crf_learn: 前面編譯生成的crf++的訓練工具
#input/crf.template: 特征模板
#input/train_data.txt: 訓練數據
#output/crf.mdl: 訓練輸出的模型
export LD_LIBRARY_PATH=$LD_LIBRARY_PATH:/usr/local/lib
/usr/local/bin/crf_learn input/crf.template input/train_data.txt output/crf.mdl
訓練數據格式如下:
四、測試
按照如下命令進行:
cd CRF++_tutorial/data
./test.sh
這樣,我們就得到了預測的結果,即output/test_result.txt文件,可以打開看下預測結果。
test.sh腳本內容如下:
#/usr/local/bin/crf_test: 前面編譯生成的crf++的測試工具
#-m output/crf.mdl: train.sh腳本訓練輸出的crf模型
#input/test_data.txt: 測試數據
#-o output/test_result.txt: 輸出測試結果
export LD_LIBRARY_PATH=$LD_LIBRARY_PATH:/usr/local/lib
/usr/local/bin/crf_test -m output/crf.mdl input/test_data.txt -o output/test_result.txt
測試數據格式如下(testdata和traindata需要用相同的編碼格式,不然沒法解析):
測試結果如下,雖然訓練數據只有幾條,但測試結果還是挺准的哈:
五、C++接口調用示例
按照如下命令進行:
cd CRF++_tutorial/code
cmake .
make
./crf_test
程序輸出結果如下:
具體調用流程請參考CRF++_tutorial/code/main.cpp
代碼如下:
#include <iostream>
#include <string>
#include <vector>
#include "crfpp.h"
using namespace std;
int main()
{
//> 0.測試輸入
vector<string> query;
query.push_back("周");
query.push_back("傑");
query.push_back("倫");
query.push_back("是");
query.push_back("誰");
//> 1.模型加載
cout << ">>>>>> Begin to load crf++ model……" << endl;
CRFPP::Model* crf_model_ = CRFPP::createModel("-m ../data/output/crf.mdl -v 3");
cout << ">>>>>> Success to load crf++ model !" << endl;
//> 2.創建CRF++對象
CRFPP::Tagger* tagger = crf_model_->createTagger();
//> 3.add query
vector<string>::iterator it = query.begin();
for ( ; it != query.end(); it++){
tagger->add((*it).c_str());
}
//< 4.對query進行標注
if (!tagger->parse()){
cout << ">>>>>> Fail to parse !" << endl;
return -1;
}
//> 5.打印標注結果
cout << "標注結果: " << endl;
for (size_t i = 0; i < tagger->size(); i++){
cout << query[i] << " " << tagger->y2(i) << endl;
}
return 0;
}
from: https://zhuanlan.zhihu.com/p/39695509