开源中文分词工具探析(七):LTP
LTP是哈工大开源的一套中文语言处理系统,涵盖了基本功能:分词、词性标注、命名实体识别、依存句法分析、语义角色标注、语义依存分析等。
【开源中文分词工具探析】系列:
- 开源中文分词工具探析(一):ICTCLAS (NLPIR)
- 开源中文分词工具探析(二):Jieba
- 开源中文分词工具探析(三):Ansj
- 开源中文分词工具探析(四):THULAC
- 开源中文分词工具探析(五):FNLP
- 开源中文分词工具探析(六):Stanford CoreNLP
- 开源中文分词工具探析(七):LTP
1. 前言
同THULAC一样,LTP也是基于结构化感知器(Structured Perceptron, SP),以最大熵准则建模标注序列\(Y\)在输入序列\(X\)的情况下的score函数:
\]
其中,\(\Phi_s(Y,X)\)为本地特征函数。中文分词问题等价于给定\(X\)序列,求解score函数最大值对应的\(Y\)序列:
\]
2. 分解
以下源码分析基于版本3.4.0。
分词流程
分词流程与其他分词器别无二致,先提取字符特征,计算特征权重值,然后Viterbi解码。代码详见__ltp_dll_segmentor_wrapper::segment():
int segment(const char *str, std::vector<std::string> &words) {
ltp::framework::ViterbiFeatureContext ctx;
ltp::framework::ViterbiScoreMatrix scm;
ltp::framework::ViterbiDecoder decoder;
ltp::segmentor::Instance inst;
int ret = preprocessor.preprocess(str, inst.raw_forms, inst.forms,
inst.chartypes);
if (-1 == ret || 0 == ret) {
words.clear();
return 0;
}
ltp::segmentor::SegmentationConstrain con;
con.regist(&(inst.chartypes));
build_lexicon_match_state(lexicons, &inst);
extract_features(inst, model, &ctx, false);
calculate_scores(inst, (*model), ctx, true, &scm);
// allocate a new decoder so that the segmentor support multithreaded
// decoding. this modification was committed by niuox
decoder.decode(scm, con, inst.predict_tagsidx);
build_words(inst.raw_forms, inst.predict_tagsidx, words);
return words.size();
}
训练模型
模型文件cws.model包含了类别、特征、权重、内部词典(internal lexicon)等。我用Java 重写了模型解析,代码如下:
DataInputStream is = new DataInputStream(new FileInputStream(path));
char[] octws = readCharArray(is, 128);
// 1. read label
SmartMap label = readSmartMap(is);
int[] entries = readIntArray(is, label.numEntries);
// 2. read feature Space
char[] space = readCharArray(is, 16);
int offset = readInt(is);
int sz = readInt(is);
SmartMap[] dicts = new SmartMap[sz];
for (int i = 0; i < sz; i++) {
dicts[i] = readSmartMap(is);
}
// 3. read param
char[] param = readCharArray(is, 16);
int dim = readInt(is);
double[] w = readDoubleArray(is, dim);
double[] wSum = readDoubleArray(is, dim);
int lastTimestamp = readInt(is);
// 4. read internal lexicon
SmartMap internalLexicon = readSmartMap(is);
// read char array
private static char[] readCharArray(DataInputStream is, int length) throws IOException {
char[] chars = new char[length];
for (int i = 0; i < length; i++) {
chars[i] = (char) is.read();
}
return chars;
}
// read int array
private static int[] readIntArray(DataInputStream is, int length) throws IOException {
byte[] bytes = new byte[4 * length];
is.read(bytes);
IntBuffer intBuffer = ByteBuffer.wrap(bytes)
.order(ByteOrder.LITTLE_ENDIAN)
.asIntBuffer();
int[] array = new int[length];
intBuffer.get(array);
return array;
}
LTP共用到了15类特征,故sz为15;特征是采用Map表示,LTP称之为SmartMap,看代码本质上是一个HashMap。分词工具测评结果表明,LTP分词速度较THULAC要慢。究其原因,THULAC采用双数组Trie来表示模型,特征检索速度要优于LTP。
特征
LTP所用到的特征大致可分为以下几类:
- unigram字符特征 ch[-2], ch[-1], ch[0], ch[1], ch[2]
- bigram字符特征 ch[-2]ch[-1], ch[-1]ch[0],ch[0]ch[1],ch[1]ch[2]
- 字符类型特征 ct[-1], ct[0], ct[1]
- 词典属性特征 ch[0]是否为词典开始字符、中间字符、结束字符
源码见extractor.cpp:
Extractor::Extractor() {
// delimit feature templates
templates.push_back(new Template("1={c-2}"));
templates.push_back(new Template("2={c-1}"));
templates.push_back(new Template("3={c-0}"));
templates.push_back(new Template("4={c+1}"));
templates.push_back(new Template("5={c+2}"));
templates.push_back(new Template("6={c-2}-{c-1}"));
templates.push_back(new Template("7={c-1}-{c-0}"));
templates.push_back(new Template("8={c-0}-{c+1}"));
templates.push_back(new Template("9={c+1}-{c+2}"));
templates.push_back(new Template("14={ct-1}"));
templates.push_back(new Template("15={ct-0}"));
templates.push_back(new Template("16={ct+1}"));
templates.push_back(new Template("17={lex1}"));
templates.push_back(new Template("18={lex2}"));
templates.push_back(new Template("19={lex3}"));
}
#define TYPE(x) (strutils::to_str(inst.chartypes[(x)]&0x07))
data.set("c-2", (idx - 2 < 0 ? BOS : inst.forms[idx - 2]));
data.set("c-1", (idx - 1 < 0 ? BOS : inst.forms[idx - 1]));
data.set("c-0", inst.forms[idx]);
data.set("c+1", (idx + 1 >= len ? EOS : inst.forms[idx + 1]));
data.set("c+2", (idx + 2 >= len ? EOS : inst.forms[idx + 2]));
data.set("ct-1", (idx - 1 < 0 ? BOT : TYPE(idx - 1)));
data.set("ct-0", TYPE(idx));
data.set("ct+1", (idx + 1 >= len ? EOT : TYPE(idx + 1)));
data.set("lex1", strutils::to_str(inst.lexicon_match_state[idx] & 0x0f));
data.set("lex2", strutils::to_str((inst.lexicon_match_state[idx] >> 4) & 0x0f));
data.set("lex3", strutils::to_str((inst.lexicon_match_state[idx] >> 8) & 0x0f));
#undef TYPE
开源中文分词工具探析(七):LTP的更多相关文章
- 开源中文分词工具探析(三):Ansj
Ansj是由孙健(ansjsun)开源的一个中文分词器,为ICTLAS的Java版本,也采用了Bigram + HMM分词模型(可参考我之前写的文章):在Bigram分词的基础上,识别未登录词,以提高 ...
- 开源中文分词工具探析(四):THULAC
THULAC是一款相当不错的中文分词工具,准确率高.分词速度蛮快的:并且在工程上做了很多优化,比如:用DAT存储训练特征(压缩训练模型),加入了标点符号的特征(提高分词准确率)等. 1. 前言 THU ...
- 开源中文分词工具探析(五):FNLP
FNLP是由Fudan NLP实验室的邱锡鹏老师开源的一套Java写就的中文NLP工具包,提供诸如分词.词性标注.文本分类.依存句法分析等功能. [开源中文分词工具探析]系列: 中文分词工具探析(一) ...
- 开源中文分词工具探析(五):Stanford CoreNLP
CoreNLP是由斯坦福大学开源的一套Java NLP工具,提供诸如:词性标注(part-of-speech (POS) tagger).命名实体识别(named entity recognizer ...
- 开源中文分词工具探析(六):Stanford CoreNLP
CoreNLP是由斯坦福大学开源的一套Java NLP工具,提供诸如:词性标注(part-of-speech (POS) tagger).命名实体识别(named entity recognizer ...
- 中文分词工具探析(二):Jieba
1. 前言 Jieba是由fxsjy大神开源的一款中文分词工具,一款属于工业界的分词工具--模型易用简单.代码清晰可读,推荐有志学习NLP或Python的读一下源码.与采用分词模型Bigram + H ...
- 中文分词工具探析(一):ICTCLAS (NLPIR)
1. 前言 ICTCLAS是张华平在2000年推出的中文分词系统,于2009年更名为NLPIR.ICTCLAS是中文分词界元老级工具了,作者开放出了free版本的源代码(1.0整理版本在此). 作者在 ...
- 基于开源中文分词工具pkuseg-python,我用张小龙的3万字演讲做了测试
做过搜索的同学都知道,分词的好坏直接决定了搜索的质量,在英文中分词比中文要简单,因为英文是一个个单词通过空格来划分每个词的,而中文都一个个句子,单独一个汉字没有任何意义,必须联系前后文字才能正确表达它 ...
- Java实现敏感词过滤 - IKAnalyzer中文分词工具
IKAnalyzer 是一个开源的,基于java语言开发的轻量级的中文分词工具包. 官网: https://code.google.com/archive/p/ik-analyzer/ 本用例借助 I ...
随机推荐
- [ 中危 ] 发布处存在CSRF及CSRF设想
漏洞存在于菜品发布处,使用A账号在添加/发布菜品的时候拦截数据包,使用burpsuite构造 CSRF的POC,再用B账号打开该HTML POC ,生成菜品. 该CSRF400RMB,主要因为是核心业 ...
- Python常用模块--collections
collections是Python中一个非常强大的容器数据模块. 1.创建升级版的元组--namedtupe Python的元组(1,2,3)具有不可变性,但是单独的元组在无法满足现有需求时,可以使 ...
- Django 学习第八天——Django模型基础第三节
一.表关系的实现: 一对一:OneToOne(外键+唯一键) xxx = models.OneToOneField('关联的表',on_delete=models.CASCADE) 外键和一对一关系的 ...
- Linux使用nexus搭建maven私服
一.准备工作 系统:LINUX JDK:已安装(未安装详见jdk安装教程:http://www.cnblogs.com/muzi1994/p/5818099.html) ...
- raid 搭建
RAID几种常见的类型 RAID类型 最低磁盘个数 空间利用率 各自的优缺点 级 别 说 明 RAID0 条带卷 2+ 100% 读写速度快,不容错 RAID1 镜像卷 2 50% 读写速度一般,容错 ...
- Xamarin Essentials教程数据传输DataTransfer
Xamarin Essentials教程数据传输DataTransfer 通过数据传输功能,应用程序可以将文本或网址发送到其它的应用程序,这样就可以在应用程序之间共享数据,实现常见的分享功能.Xa ...
- Centos6.5部署Rsyslog+LogAnalyzer中文乱码解决
中文乱码 [root@log include]# pwd /zhang/app/loganalyzer-/src/include [root@log include]# vim functions_c ...
- Your ApplicationContext is unlikely to start due to a @ComponentScan of the default
问题:** WARNING ** : Your ApplicationContext is unlikely to start due to a @ComponentScan of the defau ...
- Sql的行列(纵横表)转换
1.行转列: 表结构和数据: DROP TABLE IF EXISTS `kj`; CREATE TABLE `kj` ( `姓名` ) DEFAULT NULL, `课程` ) DEFAULT NU ...
- Java并发编程(十四)-- 线程池实现原理
在上一章我们从宏观上介绍了ThreadPoolExecutor,本文将深入解析一下线程池的具体实现原理 原理解析 线程池状态 在ThreadPoolExecutor中定义了一个volatile变量,另 ...