用Stanford NER训练自己的NER分类器

官方FAQ世界观:

关于训练自己的分类器的文档官方没有~~, 但可以看java doc啊, So总是有办法的; 比如至少可以看看CRFClassifierNERFeatureFactory这两个类.

训练数据集格式

tab-隔开的方式, word token一列, 分类标签一列; 不能使用空格隔开, 也不能有多余的tab; 一个空行表示分隔一个文档(document), 这里一个文档可以指一个句子或者一个段落, 一个文档不宜过大, 否则会浪费内存, 也可能导致别的计数问题;

假设现在要用简奥斯汀的小说来训练, 比如用Emma的第一章进行训练, 运行如下命令使得一个token一行:

java -cp stanford-ner.jar edu.stanford.nlp.process.PTBTokenizer jane-austen-emma-ch1.txt > jane-austen-emma-ch1.tok

// 用这条命令会找不到slf4j插件, 我的写法是:
// java -cp "*:lib/*" edu.stanford.nlp.process.PTBTokenizer jane-austen-emma-ch1.txt > jane-austen-emma-ch1.tok

然后添加标签, 添加标签的方法可以手动, 运行以下命令使得每个token都标记为’O’(即other类):

perl -ne 'chomp; print "$_\tO\n"' jane-austen-emma-ch1.tok > jane-austen-emma-ch1.tsv

或者下载官方给的标记了PERS类的input file, 可以在此基础上添加比如LOC等实体分类.

然后是测试数据, 可以下载Emma的[第二章]以及其标准分类(gold standard)

虽然所有配置都可以在命令行中指出, 但用properties文件会更方便:

# 训练数据位置
trainFile = jane-austen-emma-ch1.tsv

# 指定classifier保存的路径和文件名
# 末尾加 '.gz' 可以自动压缩分类器文件为.gz格式
serializeTo = ner-model.ser.gz

# 训练数据文件的结构说明, 告诉分类器那一列是word, 哪一行是分类结果
map = word=0,answer=1

# 指定用于分类器的特征
# 列出来的只有一部分, 更详细的去看 'NERFeatureFactory'类
useClassFeature=true
useWord=true
useNGrams=true
#no ngrams will be included that do not contain either the
#beginning or end of the word
noMidNGrams=true
useDisjunctive=true
maxNGramLeng=6
usePrev=true
useNext=true
useSequences=true
usePrevSequences=true
maxLeft=1
#the next 4 deal with word shape features
useTypeSeqs=true
useTypeSeqs2=true
useTypeySequences=true
wordShape=chris2useLC

可直接下载配置文件austen.prop, 运行:

java -cp stanford-ner.jar edu.stanford.nlp.ie.crf.CRFClassifier -prop austen.prop

模型至此已经训练好了, 可以用如下命令进行测试

java -cp stanford-ner.jar edu.stanford.nlp.ie.crf.CRFClassifier -loadClassifier ner-model.ser.gz -testFile jane-austen-emma-ch2.tsv

得到结果:

... ...
Mrs.    PERS    PERS
Weston  PERS    PERS
's  O   O
wedding-cake    O   O
in  O   O
their   O   O
hands   O   O
:   O   O
but O   O
Mr. PERS    PERS
Woodhouse   PERS    PERS
would   O   O
never   O   O
believe O   O
it  O   O
.   O   O

CRFClassifier tagged 1999 words in 1 documents at 6208.07 words per second.
         Entity P   R   F1  TP  FP  FN
           PERS 0.8205  0.7273  0.7711  32  7   12
         Totals 0.8205  0.7273  0.7711  32  7   12

其中, 第一列结果为输入的token, 第二列是标准分类(gold)结果, 第三列是分类器得到结果. 结果可以看出, 分类器可以准确地找出大部分的人名, 但不是所有; 主要原因在于训练数据规模和提取特征. 最后程序给出了precision, recall, F1.

总结来说, 使用Stanford NER来训练自己的NER分类器有三个点:

1) 准备训练集
2) 指定要使用的特征
3) 测试看效果

另外, 如果要使用自己提取的特征, 那么可以多增加一列特征, 然后在properties文件中指定特征所在列, 比如map= word=0, answer=1, mySpecialFeature=2. 但代码目前还不支持这么做, 要达到这样的目的需要直接改源码.

你可能感兴趣的:(NLP)