BERT based sentence scenario detector

前两天用简单的多层感知器搭建了一个Word-level的detector模型。在模型的最后一次是用来Softmax,将Output Layer进行了分类。

对于场景识别这个问题,我目前先规定了可选的类别(比如Forest/ Ocean/ River/ College/ Suburb/ etc.)。这样一方面来说,可以简化detector的工作流程,另外也比较适应我们组目前的资源情况(识别场景之后需要提取事先准备好的Background,如果提取出了新的element也是无法获取到background resource的)。

上周我的想法是先使用Word embedding将Sentence转化为Sequence,然后使用Bi-LSTM或者直接使用Linear CRF对Sequence进行Sequence Tagging,以提取Sentence中涉及场景的Word。最后通过Word-level detector分析所选的Word,得到Sentence-level Scenario。

不过经过实验我发现,由于我手上只有不到500个短篇的儿童故事,还是没有标注的那种。就算我全部拿来进行标注,也只能生成不到5000个Phases。因为Labeler的资源比较紧张,我先用第一版的词表Detector模型生成了Labeling data,丢到CRF里面之后发现出了Person-entities,其他的类别基本无法有效识别出来。

于是这种方法暂时宣告失败。

周五晚上在公司发呆,突然觉得可以试一试力大砖飞的方法,直接使用Sentence-level embedding来作为Input。在这个模型里加入了CNN Layer,但其实单靠Dense Full connect Layer就已经可以在这个数据集上达到同样的效果了。

# 模型构建
model = Sequential([
Conv1D(filters=5, kernel_size=5, strides=1, padding='valid', input_shape=(768, 1), name="Convolution_Layer_1"),
AveragePooling1D(pool_size=5, strides=1, padding="valid", name="Pooling_Layer_1"),

Conv1D(filters=5, kernel_size=5, strides=1, padding='valid', name="Convolution_Layer_2"),
AveragePooling1D(pool_size=5, strides=1, padding="valid", name="Pooling_Layer_2"),

Flatten(name="Flatten_Layer"),

Dense(256, input_dim=3760, name="Dense_Layer_1"),
Activation('relu'),
Dropout(0.1),

Dense(32, input_dim=256, name="Dense_Layer_2"),
Activation('relu'),
Dropout(0.1),

Dense(11, input_dim=32, name="Dense_Layer_3"),
Activation('softmax'),
])


通用场景识别器

今天是新年第一天上班,然后想到这周只用上三天班就很开心。

由于Sequence Tagging需要大量的标注数据,我这边暂时没有数据源,所以今天下午就先用现有的标注数据集做了一个场景Softmax分类器。

原理十分简单,使用Word2vec (之后可能会考虑换成BERT,但是这两天BERT在我这里表现还不是很理想,所以先用顺手的工具搭建一下Demo)生成词向量。之后通过标注数据集合,将词表里所有的词分成以下几个大类(类别可以由具体的使用场景确定,我这里的分类主要是为了适配童话故事的情况)。

# 模型构建
model = Sequential([
Dense(32, input_dim=200),
Activation('relu'),
Dropout(0.1),

Dense(16, input_dim=32),
Activation('relu'),

Dense(9, input_dim=32),
Activation('softmax'),
])

用Keras搭建了一个最简单的多层感知机,加上Dropout,开始喂数据。最后可以达到96%左右的Accuracy,算是基本可以使用了。

 test loss:  0.09276254528926478
test accuracy: 0.9666666666666667

现在这套模型已经可以识别任意词的场景类别了。下一步就是使用Sequence Tagging找出描述场景的位置了。

隐含语义分析

最近在做NLP的一些工作。

遇到的问题是:Precisely detect scenario/weather/time/etc in a paragraph-level document.

对于这个问题,我作为一个NLP外行,首先想到的思路是建立相应的词表,然后对每一个Sentence进行Tagging。在完成Coding的工作后,在测试中效果还是可以的(毕竟用Word2Vec聚类建立了好大一份词表)。但主要的问题是Overtrigger,这个模型无法区分那些地方才是真正描述Target的,更无法理解一词多义的情况。

于是在第一版模型可以基本Cover住下游业务需求之后,我Mentor对Precision有了进一步的要求(手动GG)。

在想了好几天之后(其实主要时间都用来划水),我想了一个不太成熟的方案,先记下来等元旦过完了回来再和Mentor讨论一下:

  • 使用TF-IDF-Based Sequenced List取代完整的Word Segment List。
  • 使用BERT取代Word2vec进行Word Embedding。
  • 尝试使用Latent Semantic Analysis,进行第一轮无监督学习,总而获取到Sentence-level的Tagging information(说到底,还不是因为没有Labeler)。
  • 使用SVD左矩阵反推Word-level Influence Factor,生成NER training data(这一步的话,为了保证模型质量,估计还是得请Labeler帮忙看一下。这个样子的话,比从什么都没有标注要轻松一些)。
  • 尝试双向LSTM训练隐含序列,或者直接通过BERT Pre Trained Model 产出Word Embedding(反正BERT的Embedding是自带Context的,啦啦啦)。
  • 使用线性链的条件随机场进行Sequence Tagging。这一步的话,参考目前的NER模型,在Location/Person/Organization上有95+的F1

如果这几个流程可以按照预期来进行的话,那效果应该还是不错的。