首先是utility chunkingfeasel读取文件train.txt等经过处理后输出下一步程序所需要格式的文件train.tagged.在这段程序中,dataset, sequence, observation有一个与data类不同的定义.因为它们面向的是不同层次的同一批数据, 从整个模型的执行过程来说, 这一步其实就是特征生成的过程, 至于下面所讲的类feature, featuregen, 它们的作用是将特征封装成程序算法所需要的格式, 并且在封装过程中进行特征选择, 而真正意义上的特征生成就是chunkingfeasel所做的工作, 这一点要理解清楚.
接着:类data的dt对象封装train.tagged里的数据, 这段程序里, dataset, sequence, observation有另一个定义, 这也是主要的定义.在这一步同时还生成了依次存储所碰到的label, context predicate数据的map对象, 注意map对象在这里类似数据库, 它并不是按某程序块所需要的数据结构来存储数据的, 而只是把同一类的数据依次存入.生成的map对象有plbs2i, plbi2s, pcps2i, pcpi2s 还有自定义数据对象ptrndata
接下来的是类dictionary的dict对象, 虽然上面的数据已被封装, 但是只是初步封装, label与context predicates之间的关系也还没存储下来, 在dict对象里就做到了这一点.
接下来是类featuregen的对象, feature对象是featuregen的成员, 类featuregen里的成员包含了以下几个对象:
list<feature> features; 保存了所有的特征
vector<features*> sfeatures; 保存了所有的state features
vector<features> efeatures; 保存了所有的edge features
关于state特征有一点也要注意, 每一个context predicate就是一个特征, 每个特征的有一个唯一的idx:索引, 不仅如此, 其实每个特征的strid也是很特殊的, strid的值明确且详细的指出了当前这个特征的内容. 如”s1_b-np_w:2:the”指明了这时第一类state特征, context predicate 为w:2:the, label为b-np.
注意:ptrndata是封装了train.tagged数据的对象, 而ptrn是trainer的对象, 不要混淆了两个完全不同的对象.
Doublevector Doublematrix 是用于封装特定数据的自定义的新类.
接下来在主程序crf.cpp中看到
// create the trainer object
trainer trn;
// create the viterbi object
viterbi vtb;
// create the evaluation object
evaluation eval;
// create the CRF model
model mdl(&opt, &dt, &dict, &fgen, &trn, &vtb, &eval);
// create training log file
FILE * otrnlogf;
if (opt.is_logging) {
otrnlogf = fopen((opt.model_dir + opt.trainlog_file).c_str(), "w");
}
// saving dictionary
printf("saving the context predicate dictionary to file .../n");
dict.write_dict(omodelf);
printf("saving the dictionary completed./n/n");
// start to train the CRF model
printf("start to train the CRF model .../n/n");
mdl.train(otrnlogf);
首先准备好CRF模型所需要的训练与评估对象,然后在model类的mdl对象中调用,model类是一个控制类,在该类中创建了类trainer, 类Viterbi, 类evaluation的对象,真正的训练过程被封装在trainer.h, trainer.cpp, lbfgs.c中,训练的代码也是模块化的,不需要看其它地方的代码,evaluation的相关代码也是一样组织形式,其实整个程序都是这种采用了这种良好的组织方式。
暂时只写到这里,剩下的有待学习