1.抽特征
一个query属不属于音乐,这和我们对音乐的理解有很大的关系,需要进行产品上的定义。如你会唱歌吗,刘德华,换一首音乐,如何让孩子爱上学习等,既可以属于音乐也可以不属于音乐。对音乐的理解最终落到标注数据上,继而来影响我们的打分模型给出高分或者低分。
我们对query进行了很多的清理、转换、知识查询、相似度计算、拼音转换、纠错、句型辅助等工作,所以要从里面找到对query是否归属于音乐领域有影响的特征。我们目前抽取了slot数、各slot抽取情况、slot的组合、整体相似度、资源热度、歌手职业、标签数、标签强度、主干query长度、音乐日志、句型得分、意图词得分等特征,特征还在增加。
服务为了配合抽特征的需要进行了改造,针对特定的deviceid,返回中间计算过程中的各特征值。
2.离线模型训练
在上机器学习模型前,我们是用人工规则来进行的打分,针对各种情况写了复杂的if-else,是一步步的决策过程,所以选打分模型时,自然选择了决策树(GBDT)。离线模型的训练使用了python xgboost。
标注数据:我们共标注了近5万条数据,音乐近2万,其他领域数据近3万做为反例。通过服务解析,将query转换成特征集,libsvm格式(label \t id:value \t id:value)。
0 0:0.0000 1:0.0000 2:0.0000 3:0.0000 4:0.0000 5:0.0000 6:0.5000 7:0.0000 .. 0 0:0.0000 1:0.0000 2:0.0000 3:0.0000 4:0.0000 5:0.0000 6:1.0000 7:0.0000 .. 1 0:1.0000 1:1.0000 2:0.0000 3:0.0000 4:1.0000 5:0.0000 6:0.7000 7:0.0000 ..
训练集/测试集拆分:训练集占数据集的比例一般为2/3 - 4/5,并且需要保证训练集/测试集中的类别平衡(正负比例和数据集中的一致)。我们随机抽取了1/5的数据作为测试集。
调节参数:xgboost支持对eta(学习率)、max_depth(树的最大深度)、lambda(L2正则化因子)等,使用了模拟退火对参数进行调优,给每个参数指定起取值范围、步长。训练过程中,每次随机选择一个参数对其增加或减小一个步长,训练一个模型算出其在测试集上的精度做为模型的评价值。
样本补充:测试调节过程中,会碰到一些case特征没有被学到(想让这一类case打分高,却打了低分),这时就人工补充一定量的这类数据到训练集中,再重新训练模型。我是对没有学到的case给重复增加了10条。
另外:
gbdt支持一个样本丢失部分特征,对于不存在的特征,我们进行了丢弃,以免干扰选择。
为了保证特征名和特征索引的一致,在离线训练的时候,把特征统一存在了一个文件中;在线服务抽取特征时用了枚举定义。更好的办法,可以写一个thrift定义,保证在线离线的统一。
3.在线使用
xgboost提供的java版xgboost4j需要依赖底层本地实现的支持,用的过程中windows没有编译成功。由于xgboot导出的模型有可读的文本版本,就使用了组里自实现的加载模型决策树java代码。
booster[0]: 0:[wholeSim<0.80175] yes=1,no=2,missing=1,gain=9265.91,cover=18714.5 1:[intentScore<0.95] yes=3,no=4,missing=3,gain=972.265,cover=12050.5 3:[tagSim<0.6795] yes=7,no=8,missing=7,gain=465.15,cover=11553.5 7:[rank<0.97265] yes=13,no=14,missing=13,gain=389.613,cover=11183.5
在模型打分后,保留了一些规则(如slot正向/负向得分,用于修复紧急case。
4.后续
后续会继续增加特征,另外想引入语言模型,对抽取的slot用entity名代替,然后来训练出一个word embedding或者其他的语言模型。
参考:http://xgboost.readthedocs.io/en/latest/python/python_intro.html#install-xgboost