語言模型的形式
上文介紹的語言模型在效果上得到了非常好的效果,但是在生產環境速度偏慢,因此本文的目的有兩個,意識較輕量級的語言模型的實驗, 二是語言模型在下游任務中應用,語言模型本質上還是去發現語言文法中的潛在的關聯關係,應用該方法理論上在文本的語義方面判斷的任務會有很大幫助。
模型的應用 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