被标注的命名实体被放在《START》《END》范围中,并标出了实体的类别。接下来是对命名实体识别模型的训练,先上代码:
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.StringReader;
import java.util.Collections;
import opennlp.tools.namefind.NameFinderME;
import opennlp.tools.namefind.NameSample;
import opennlp.tools.namefind.NameSampleDataStream;
import opennlp.tools.namefind.TokenNameFinderModel;
import opennlp.tools.util.ObjectStream;
import opennlp.tools.util.PlainTextByLineStream;
import opennlp.tools.util.featuregen.AggregatedFeatureGenerator;
import opennlp.tools.util.featuregen.PreviousMapFeatureGenerator;
import opennlp.tools.util.featuregen.TokenClassFeatureGenerator;
import opennlp.tools.util.featuregen.TokenFeatureGenerator;
import opennlp.tools.util.featuregen.WindowFeatureGenerator;
/**
* 中文命名实体识别模型训练组件
*
* @author ddlovehy
*
*/
public class NamedEntityMultiFindTrainer {
// 默认参数
private int iterations = 80;
private int cutoff = 5;
private String langCode = “general”;
private String type = “default”;
// 待设定的参数
private String nameWordsPath; // 命名实体词库路径
private String dataPath; // 训练集已分词语料路径
private String modelPath; // 模型存储路径
public NamedEntityMultiFindTrainer() {
super();
// TODO Auto-generated constructor stub
}
public NamedEntityMultiFindTrainer(String nameWordsPath, String dataPath,
String modelPath) {
super();
this.nameWordsPath = nameWordsPath;
this.dataPath = dataPath;
this.modelPath = modelPath;
}
public NamedEntityMultiFindTrainer(int iterations, int cutoff,
String langCode, String type, String nameWordsPath,
String dataPath, String modelPath) {
super();
this.iterations = iterations;
this.cutoff = cutoff;
this.langCode = langCode;
this.type = type;
this.nameWordsPath = nameWordsPath;
this.dataPath = dataPath;
this.modelPath = modelPath;
}
/**
* 生成定制特征
*
* @return
*/
public AggregatedFeatureGenerator prodFeatureGenerators() {
AggregatedFeatureGenerator featureGenerators = new AggregatedFeatureGenerator(
new WindowFeatureGenerator(new TokenFeatureGenerator(), 2, 2),
new WindowFeatureGenerator(new TokenClassFeatureGenerator(), 2,
2), new PreviousMapFeatureGenerator());
return featureGenerators;
}
/**
* 将模型写入磁盘
*
* @param model
* @throws Exception
*/
public void writeModelIntoDisk(TokenNameFinderModel model) throws Exception {
File outModelFile = new File(this.getModelPath());
FileOutputStream outModelStream = new FileOutputStream(outModelFile);
model.serialize(outModelStream);
}
/**
* 读出标注的训练语料
*
* @return
* @throws Exception
*/
public String getTrainCorpusDataStr() throws Exception {
// TODO 考虑入持久化判断直接载入标注数据的情况 以及增量式训练
String trainDataStr = null;
trainDataStr = NameEntityTextFactory.prodNameFindTrainText(
this.getNameWordsPath(), this.getDataPath(), null);
return trainDataStr;
}
/**
* 训练模型
*
* @param trainDataStr
* 已标注的训练数据整体字符串
* @return
* @throws Exception
*/
public TokenNameFinderModel trainNameEntitySamples(String trainDataStr)
throws Exception {
ObjectStream《NameSample》 nameEntitySample = new NameSampleDataStream(
new PlainTextByLineStream(new StringReader(trainDataStr)));
System.out.println(“**************************************”);
System.out.println(trainDataStr);
TokenNameFinderModel nameFinderModel = NameFinderME.train(
this.getLangCode(), this.getType(), nameEntitySample,
this.prodFeatureGenerators(),
Collections.《String, Object》 emptyMap(), this.getIterations(),
this.getCutoff());
return nameFinderModel;
}
/**
* 训练组件总调用方法
*
* @return
*/
public boolean execNameFindTrainer() {
try {
String trainDataStr = this.getTrainCorpusDataStr();
TokenNameFinderModel nameFinderModel = this
.trainNameEntitySamples(trainDataStr);
// System.out.println(nameFinderModel);
this.writeModelIntoDisk(nameFinderModel);
return true;
} catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
return false;
}
}
}
注:
参数:iterations是训练算法迭代的次数,太少了起不到训练的效果,太大了会造成过拟合,所以各位可以自己试试效果;
cutoff:语言模型扫描窗口的大小,一般设成5就可以了,当然越大效果越好,时间可能会受不了;
langCode:语种代码和type实体类别,因为没有专门针对中文的代码,设成“普通”的即可,实体的类别因为我们想训练成能识别多种实体的模型,于是设置为“默认”。
说明:
prodFeatureGenerators()方法用于生成个人订制的特征生成器,其意义在于选择什么样的n-gram语义模型,代码当中显示的是选择窗口大小为5,待测命名实体词前后各扫描两个词的范围计算特征(加上自己就是5个),或许有更深更准确的意义,请大家指正;
trainNameEntitySamples()方法,训练模型的核心,首先是将如上标注的训练语料字符串传入生成字符流,再通过NameFinderME的train()方法传入上面设定的各个参数,订制特征生成器等等,关于源实体映射对,就按默认传入空Map就好了。
源代码开源在:https://github.com/Ailab403/ailab-mltk4j,test包里面对应有完整的调用demo,以及file文件夹里面的测试语料和已经训练好的模型。
评论
查看更多