areal's profileiamcrfBlogLists Tools Help

Blog


    November 06

    crf++为什么浪费内存:都是stl惹的祸

    利用休假读了下crf++代码,特别是有关存储训练数据的内存结构部分。很久以前,我就通过匆匆扫过一遍的映像,认为crf++这部分的浪费非常严重。近期的阅读证实了这一观点。我还是用去年发布的0.44版。
    一般来说,系统训练需要缓存两部分的内容,一部分是关于训练数据的信息,主要包括特征的表达式以及相应的频率,另外一部分用来LBFGS训练的矩阵缓存,包括lambda权值向量。后面一部分内容是不可或缺的。如果要节省内存耗费,可以考虑把第一部分内容在记录到磁盘后,仅仅留下特征的代号和对应的频率信息在内存中。
    问题是,我发现, crf++没有这么做。所有的信息都保留在内存中,直到训练结束的时候一口气写入model文件。当然,crf++也不是什么都没有做。crf++在开始训练前,函数
    bool TaggerImpl::shrink()
      {
        CHECK_FALSE(feature_index_->buildFeatures(*this)) << feature_index_->what();
        std::vector <std::vector <const char *> >(x_).swap(x_);
        std::vector <std::vector <Node *> >(node_).swap(node_);
        std::vector <unsigned short int>(answer_).swap(answer_);
        std::vector <unsigned short int>(result_).swap(result_);
        return true;
      }
    中,
    第一句对特征进行编码,后边4句企图释放掉已经无用的训练数据缓存。taku使用了标准的swap方式来释放stl管理的内容。不幸的是,这些内存其实根本就没有得到释放。注释掉这4句后,内存的使用也不会增长。简单来说,这组内存没有得到释放。
     
    由于对stl不熟悉---实际上,我还不会用allocator---我使用标准c替代了相关部分。
    首先,我用一个简单的自己管理的char *代替了std::vector <const char *> > TaggerImpl::x_,结果期望中的内存强制释放马上获得了10%的内存减少。
    然后,我把model存盘分为两次,第一次在最开始的时候存下特征的表达式及其id,第二次在训练结束的时候存下lambda向量。在第一次存盘结束后,就释放掉特征表达式的缓存。这个缓存原始的crf++使用std::map <std::string, std::pair<int, unsigned int> > EncoderFeatureIndex::dic_;来管理的。我自己用标准c++ without stl重写了一个map。存盘结束后的内存释放又获得了10%的内存减少。
     
    现在,主要的问题是,虽然只是影响训练数据装载的速度,但是我自己写的map在插入数据的时候比stl的要慢10倍。难道我要去偷看一遍stl? 困挠中。。。
     
     
    November 05

    Accepted papers of SIGHAN-6

    仅有9篇,但是,bakeoff-4会带来28篇。。。

    Stochastic Dependency Parsing Based on A* Admissible Search
    Bor-shen Lin

    Mining Transliterations from Web Query Results: An Incremental Approach
    Jin-Shea Kuo, Haizhou Li, and Chih-Lung Lin

    Use of Event Types for Temporal Relation Identification in Chinese text
    Yuchang Cheng, Masayuki Asahara and Yuji Matsumoto

    Analyzing Chinese Synthetic Words with Tree-based Information and a Survey on Chinese Morphologically Derived Words
    Jia Lu, Masayuki Asahara and Yuji Matsumoto

    An Effective Hybrid Machine Learning Approach for Coreference Resolution
    Feiliang Ren and Jingbo Zhu

    Chinese Word Sense Disambiguation with PageRank and HowNet
    Jinghua Wang and Jianyi Liu

    Automatic Extraction of English-Chinese Transliteration Pairs using Dynamic Window and Tokenizer
    Jin Chengguo, Na Seung-Hoon, Kim Dong-Il and Lee Jong-Hyeok

    An Example-based Decoder for Spoken Language Machine Translation
    Wen-Han Chao, Zhou-Jun Li and Yue-Xin Chen

    Which Performs Better on In-Vocabulary Word Segmentation: Based on Word or Character?
    Zhenxing Wang, Changning Huang and Jingbo Zhu

    November 02

    pocket crf的二阶crf特征的结果及其讨论

    重复一下试验的设置。
    语料:ctb segmented corpus from bakeoff-4,
    训练语料 642246词
    测试语料 80700词
     
    6-标注集,b,b2,b3,m,e,s for each character in corpus
    6-特征模版:C_{-1}, C_0,C_1, C_{-1}C_0,C_0C_1,C_{-1}C_1
    一律用f-score度量结果
     
    运行的cpu是core duo T7600, 2.33G, 3.2G mem
     
    pocket crf ver 0.30 给出的结果
    (a) +1阶状态转移特征    %y[-1]%y[0]:                                                   0.949298
    (b) +1,2阶状态转移特征 %y[-1]%y[0]+%y[-2]%y[-1]%y[0]:                      0.949590
    (c) +1,2阶状态转移特征 %y[-1]%y[0]                              +%y[-2]%y[0]:  0.949636
    (d) +2阶状态转移特征                         +%y[-2]%y[-1]%y[0]:                   0.949661
     
    注意到,按照pocket crf的结果,2阶CRF对于分词学习的贡献微乎其微。(a)运行时间大约3小时,(b),(c),(d)大约运行20-24小时。
    内存使用,均为450M左右。
    crf++ ver 0.44 给出的结果
    (e) +1阶状态转移特征    %y[-1]%y[0]:                                                   0.963407
    运行时间,pocket crf和 crf++ 相当。内存使用,crf++在(e)上要1G。
    注:
    ctb语料的bakeoff-4官方结果最好成绩为0.9596
     
    我注意到,pocket crf生成的model文件远远小于crf++,大约只有后者的1/3。难道这就是 crf++ 保持精度领先的秘诀?
     
    pocket crf作者的blog
    上面报告了msra2005/bakeoff-2语料上的结果
    “ 原来是1order CRF, 训练5小时,消耗内存836M,测试结果0.959
    加了一个%y[-2]%y[0]模板,训练18小时,消耗内存988M,测试结果0.961
    我猜测,2阶crf之所以在作者报告的这一情形导致显著的改进的原因是n-gram学习在这一语料上没有达到性能饱和,msra2005语料上bakeoff-2的最好成绩是0.964,使用我上面的6-tag+6-feature templates,性能可以轻易达到0.972.
    作者的这一结果我理解为,当基线性能很低的时候,所获得改进不是实质性的。