所谓“文本正则”,即将手写形式的文本转换成语音形式的文本。
例子:
- 手写:
A baby giraffe is 6ft tall and weighs 150lb.
- 语音:
A baby giraffe is six feet tall and weighs one hundred fifty pounds.
目前kernel上主要以收集大辞典的方法为主流。
基于RNN的方法在paper中提到说效果不佳。
token的所有类别:['PLAIN', 'PUNCT', 'DATE', 'LETTERS', 'CARDINAL', 'VERBATIM', 'DECIMAL', 'MEASURE', 'MONEY', 'ORDINAL', 'TIME', 'ELECTRONIC', 'DIGIT', 'FRACTION', 'TELEPHONE', 'ADDRESS']
。
其中,'PLAIN', 'PUNCT'
是输出和输入相同的类别。但训练数据中,只有'PUNCT'
的输出和输入完全相同,'PLAIN'
的输入和输出相同的个数是:7317175,总共个数是:7353693。比例是:0.995034059757458。这里后续需要继续调查。
在训练集中,'PLAIN', 'PUNCT'
所占的比例是0.931。
0.9937-198/489
使用kernel中提供的方法尝试了一下。大致上就是从训练语料中提取一个大辞典,这个词典包括所有词以及其映射。不同的方法引进了更多的额外训练语料。
0.9164
用xgboost训练了一个二分类器,判别某个token是不是属于'PLAIN'+'PUNCT'
。是则输入和输出相同,否则输出""
。得到这个准确率。
0.9835
用xgboost训练了一个三分类器,判别某个token是否属于'PLAIN', 'PUNCT'
还有其他。
最终发现还是要使用全分类器full_classifier
,即16个类别全都分全。然后针对每个类别手动设计normalize的过程full_replace
和replace_by_rule
。并使用test/test_one_class.py
一个一个类别调准确率。这一阶段准确率的提升主要来自对每个单独类别的normalize的优化。
准确率:0.9908->0.9921->0.9937->0.9942->0.9951->0.9954->0.9956
排名:75/554,已经进入铜牌区域,但也进入了瓶颈,单独类别的转换准确率很难找到大幅提升的改进点。
使用脚本full_replace_train.py
发现所有的训练数据,如果知道其分类,那么normalize的准确率是:9913201 / 9918441 = 0.9994716911659807
。也就是说,错误的数目只有5k+了,继续修改normalize上升空间有限。
转换思路,继续提高分类器的准确率。
根据对数据的分析,发现分类器有几类典型错误:
- 1.被误认为是
cardinal
的实际上的date
的年份。这类情况特征明显,长度是4的数字都判为date
即可。 - 2.被误认为是
plain
的实际上的electronic
的网站,比如baidu.com
之类的,写一个简单的规则判断。
上面总结的规则都集中在patch_classifier.py
脚本中,在分类器给出判定结果之后再跑一遍,作为对分类器的修正。
- 1.特征工程:token的长度;是否是一句话中第一个token。目前特征工程对模型准确率没有明显提升。
v2
。 - 2.调整权重:因为本次任务是非常unbalanced的分类任务,因此最好对于不同类别的数据,在计算loss的时候,采用不同的权重。
v3
。 - 3.调参:关键参数:
max_depth
,round_num
。v2
。
比赛第一天,新的测试数据发布。按照之前的模型跑一版,到0.9933,直接窜到第三名。也不知道可以坚挺多久。
使用大字典的方法跑了一个baseline:0.9893,用作后续提高的对比数据。
寻找错误大概从两个方向上去找:1.找分类器分错的类别。2.找normalizer没有换对的情况。
分类器分错的类别可以通过分类器输出的分类信心概率来获取。比如使用xgboost中的'objective': 'multi:softprob'
参数设定。检查prob值特别小的数据。
通过最终结果去找可以直接使用大字典跑出来的baseline去比较不同,但这个方法也不尽靠谱,不同的不一定错,相同的不一定对。但也可以从中观察,找到一些规律。
还可以直接在最终的结果中去找数字和特殊符号,一般是normalize失败的情况,这个方法可以查出来。
目前是0.9947。
今天是比赛最后一天,发现之前xgboost的参数设置有问题: 'nthread': -1
,直接删掉,因为默认值是最大值。果然重新运行之后cpu的8核满负荷运行。快了很多。
另外把之前的基于context的方法做了一下修正:之前每个token都会包括上一个token和下一个token。那么句子中的最后一个token的context会包含下一句的第一个token,句子的第一个token的context会包含上一句的最后一个token。这显然是不对的。因此在每句之间加入全0向量。忽略该向量本身,只是用于其他向量的context。
最后一天重新check所有类别的rule函数,发现还有不错的可改进空间。
还能继续改的:
ORDINAL
: 前面有没有the的问题。VERBATIM
:#
是hash-tag还是number的问题。
roman
:罗马数字和阿拉伯数字的转换。num2words
:文字和数字的转换,支持序数的数字。inflect
:单词复数形式的转换等。