语言模型的形式
上文介绍的语言模型在效果上得到了非常好的效果,但是在生产环境速度偏慢,因此本文的目的有两个,意识较轻量级的语言模型的实验, 二是语言模型在下游任务中应用,语言模型本质上还是去发现语言文法中的潜在的关联关系,应用该方法理论上在文本的语义方面判断的任务会有很大帮助。
模型的应用 VAE
这里展示的是VAE在文本生成过程中加入了,lm_loss用来辅助文本生成,关于VAE的一些东西就不在这展开了,有时间单独更新吧。
loss 部分的代码:(lm_loss 是在原有基础上新加的loss)
xent_loss = K.sum(K.sparse_categorical_crossentropy(input_sentence, output), 1)
kl_loss = - 0.5 * K.sum(1 + z_log_var - K.square(z_mean) - K.exp(z_log_var), axis=-1)
lm_loss_layer = LM_loss_layer(word_dic, inpit_pad,name="loss_lm")
lm_loss_layer.trainable = False
lm_loss = lm_loss_layer(output)
vae_loss = K.mean(xent_loss + kl_loss + lm_loss)
lm_loss自定义层的关键代码
def call(self, x, mask=None):
data_shape = K.int_shape(x)
pad_shape = K.int_shape(self.pad_data)
word_len = data_shape[1] # 词序列的长度
pad_len = pad_shape[1]
pad_data = K.cast(self.pad_data, tf.int64)
pad_data_onehot = K.one_hot(indices=pad_data, num_classes=data_shape[-1])
lm_input = K.concatenate((pad_data_onehot, x), axis=1)
lm_out = self.lm_model(lm_input)
class_num = K.int_shape(lm_out)[-1]
lm_out = K.reshape(x=lm_out, shape=(-1, word_len + pad_len, class_num))
lm_out = K.max(lm_out, axis=-1)
res = -K.log(lm_out)
res = K.sum(res)
return res
实验结果比较demo:
电脑热的要死,有机会贴出个效果吧,理论上不会太好因为基础还是VAE的模型。
如果有实验的朋友,也可以把权重加到loss上。
有效的前提还是有一个好的LM,不然loss降低反而不通顺了。
模型的应用 NER
还有一个小的demo就是将语言模型应用到NER的任务中,之前对bert测试时发现效果不错,只是生产上速度比较慢,所以想用一个轻便的LM来代替,并且该LM可以按照需求自定义训练。这里贴上一些代码好了。
def build_model(self):
inpute_ = layers.Input((self.max_sentence_len,))
#lm embeding
inpit_pad = layers.Input(shape=(self.ngram,))
lm_embeding_layer = LM_embeding_layer()
emb_lm = lm_embeding_layer([inpute_,inpit_pad])
emb = layers.Embedding(input_dim=self.word_num, output_dim=128)(inpute_)
embedding_layer = layers.Concatenate(axis=-1)([emb, emb_lm])
model1_in = layers.Conv1D(filters=self.CONV_SIZE, kernel_size=2, activation="relu", padding="same")(
embedding_layer)
model1_in = layers.MaxPooling1D(pool_size=2, strides=1, padding="same")(model1_in)
model2_in = layers.Conv1D(self.CONV_SIZE, kernel_size=4, activation="relu", padding="same")(embedding_layer)
model2_in = layers.MaxPooling1D(pool_size=2, strides=1, padding="same")(model2_in)
model3_in = layers.Conv1D(self.CONV_SIZE, kernel_size=6, activation="relu", padding="same")(embedding_layer)
model3_in = layers.AveragePooling1D(pool_size=2, strides=1, padding="same")(model3_in)
merged = layers.concatenate([model1_in, model2_in, model3_in, embedding_layer], axis=-1) # merge
crf = CRF(self.class_num, sparse_target=False)
crf_res = crf(merged)
model = Model([inpute_, inpit_pad], crf_res)
adam = Adam(lr=0.001)
model.compile(optimizer=adam, loss=crf.loss_function, metrics=[crf.accuracy])
print(model.summary())
return model