Skip to content

postagger_code_structure_analysis

徐伟 edited this page Aug 30, 2016 · 4 revisions

词性标注-MLP实现的结构分析

结构图

放大才能看得清

分析

设计存在的问题

在有Feature和无Feature的情况下,因为接口的不同(参数不同),我们设计了两套逻辑完全近似的结构。 特别是对ModelHandler,因为其仅仅就是完成一个功能的封装,但是因为模型接口的差异(输入输出数据形式的不同)而需要两个类,这是非常冗余的。这表明我们的接口存在一个重大的问题——数据抽象不够。试想,如果对于像Python这样的动态语言,不需要指定具体类型,那么我们可以把每种模型的数据都打成一个Dict,在ModelHandler中只需要传递这个参数即可,而让模型自身去处理自己的数据包。这样就能够维持接口的一致性。在C++中,要想完成这个功能,有两种实现方法,一种是用模板(这里也有两种考量,是把类型作为类的模板参数,还是作为函数的模板参数),一种是用动态绑定(多态)。如果用多态,我们首先要明白,容器是不能直接放派生类型的(只能放指向派生类型的指针或者智能指针),我们需要更多的开销(指针需要释放、智能指针每个多一个指针的内存消耗,当然其实相对模型占据的内存来说,这点根本不算什么),其次就是需要维护继承链。我们得有一个公共的基类,这其实也算是合理吧。不过总觉得这样一来,模块之间的耦合还是更强了。所以我觉得模板时更好的选择。这里因为数据本身与ModelHandler是无关的,所以设为函数的模板参数即可。以上,我们应该可以合并两个ModelHandler了。 再看有Feature和无Feature的Model关系:如UML图中标注,二者其实就是在数据成员和接口API上差了Feature这一成员;通过上述将数据抽象、模板化,API的差异已经没有了,而数据成员的差异,不就是用继承可以解决的。有Feature可以是无Feature类的派生,这从逻辑上也是可以说得通的——增加了特性。所以,我们可以将这两个彼此独立的Model变为一个继承关系,如此可以删去一些重复逻辑:包括大量的成员变量、成员变量的访问控制函数、输入数据的处理(有特征只需处理特征部分,其余部分由无特征模型完成);

尝试

感觉可以把各种Layer合并到另外一个类里——比如叫Graph吧,这样在Model中就完全是报错了模型的结构信息,由CNN的Model管理参数数据。再由Graph来完成模型结构的搭建、LOSS计算、预测序列等。这样的好处是,进一步减小了Model类的体积,防止了臃肿及复杂;同时分类了数据集的输入数据与模型训练数据间的关系——我们在Model与Graph间又可以分开数据包了,这样有利于replace_unk操作(因为要对一个const 的结构体做局部replace,需要copy整个结构体,而打散之后我们可以只更改需要replace的部分)。