天天看點

Keras實作NNLM神經網絡語言模型一、NNML的效果二、一些問題三、實作代碼及解釋四、最終效果

Keras實作NNLM神經網絡語言模型

  • 一、NNML的效果
  • 二、一些問題
  • 三、實作代碼及解釋
  • 四、最終效果

一、NNML的效果

較為權威的說法為:輸入詞序列,求出輸出值的機率值,表示根據輸入預測出下一個詞機率。

簡單的說:預測下一個詞

實作效果:感覺與索引差不多,唯一不同可能是詞向量的存在即索引該詞的機率

Keras實作NNLM神經網絡語言模型一、NNML的效果二、一些問題三、實作代碼及解釋四、最終效果

二、一些問題

參照的文章為金多:《神經網絡語言模型 NNLM (Keras實作)》連結: 神經網絡語言模型 NNLM (Keras實作).

總裁餘(餘登武):《NNLM語言模型python實作(例子:基于中文語料)》連結: NNLM語言模型python實作(例子:基于中文語料).

第一篇文章語料是英文的,而且代碼第44行後的一段有些繁瑣,看的頭疼;而第二篇文章沒有使用keras文本預處理方法。是以我試圖綜合這兩篇文章,利用keras文本預處理方法實作nnlm。在這一過程的發現之前學習中有些細節沒有掌握,是以記錄一下。

1、原本以為embedding中使用的是one-hot即如[[0,0,0,0,01],[0,0,0,1,0]這種張量形式。但是在跑代碼過程種,發現one-hot似乎不能嵌入embedding,embedding隻能嵌入索引即sequences這種字典索引結構的方式

Keras實作NNLM神經網絡語言模型一、NNML的效果二、一些問題三、實作代碼及解釋四、最終效果

或許這就是詞嵌入。

2、tokenizer 的作用

tokenizer = Tokenizer()

tokenizer.fit_on_texts(words)

無論是希望獲得one-hot編碼還是sequence都必須經過這一步,

因為token是分詞,必須要有字典,才能形成sequence序列,one-hot也可以直接得到,通過

from keras.preprocessing.text import one_hot
           

也可以,但是還是要指定詞彙表的大小,是以經過tokenizer是必須的,除非資料很少可以直接數出來如我目前的這段話sentences = [ “我愛你”, “李愛國”, “範冰心”],這樣就可以不用tokenizer,因為可以手動分詞

3、喂入資料的格式

上述那篇使用embedding的資料是生成器格式的,由于資料極少,之前試圖整個喂入,但是一緻報資料格式的問題,之後才發現embedding資料格式需要為2D張量,如果整個喂入就會變成3D張量,如果整個以2D張量形式喂入又會和embedding格式不一緻;除非向第二篇部落格一樣使用dense全連接配接層。

4、句子的預處理

英文會以空格隔開,而tokenizer的分詞也會如此,因而形如[ “我愛你”, “李愛國”, “範冰心”]在字典處理時需要拆成一個一個的字,

但在預測是标簽y=你、國、心,x= “我愛”, “李愛”, "範冰,

即分詞時

words = [word for words in sentences for word in list(words)]
tokenizer.fit_on_texts(words)
           

文本向量化時

for sentence in sentences:
    inputs = [[tokenizer.word_index[n] for n in sentence[:-1]]]
    targets = tokenizer.word_index[sentence[-1]]
           

三、實作代碼及解釋

# -*-  coding: utf-8 -*-
# Author: cao wang
# Datetime : 2020
# software: PyCharm
# 收獲:emebedding使用的是字典索引輸入,用one-hot不能用emebedding;x,y為一句号中的上下文,分詞必須在形成字典後
from keras.models import Sequential
from keras.layers import Dense, Embedding, LSTM
from keras.utils import np_utils
from keras.preprocessing import sequence
from keras.preprocessing.text import Tokenizer
import numpy as np

#文本
sentences = [ "我愛你", "李愛國", "範冰心"]
#分詞執行個體化
tokenizer = Tokenizer()
"""此處意在按照字來構造字典,否者就會按照以上三個字組成的詞構造句子如:{'我愛你': 1, '李愛國': 2, '範冰心': 3}"""
words = [word for words in sentences for word in list(words)]
tokenizer.fit_on_texts(words)
print(tokenizer.word_index)
#輸出為分詞後的字典{'愛': 1, '我': 2, '你': 3, '李': 4, '國': 5, '範': 6, '冰': 7, '心': 8}
#變成字典的索引,數字化
sequences = tokenizer.texts_to_sequences(words)
print(sequences)
#輸出為:[[2], [1], [3], [4], [1], [5], [6], [7], [8]]
word_length = 4#字長度,可以自行設定
dict_length = len(tokenizer.word_index)+1#字典長度

#将[ "我愛你", "李愛國", "範冰心"],變成inputs_sequence為我愛(注此處最終要變成索引)
def generate_data(sentences, word_length, dict_length):
    for sentence in sentences:
        #索引化,與之前不同在于分為x,y,之前是一個一個的字
        inputs = [[tokenizer.word_index[n] for n in sentence[:-1]]]
        targets = tokenizer.word_index[sentence[-1]]
        #y向量化,x進行裁剪
        y = np_utils.to_categorical([targets], dict_length)
        inputs_sequence = sequence.pad_sequences(inputs, maxlen=word_length)
        yield (inputs_sequence, y)
#模型
model = Sequential()
model.add(Embedding(dict_length, 128, input_length=word_length))
model.add(LSTM(128, return_sequences=False))
model.add(Dense(dict_length, activation='softmax'))
model.compile(loss='categorical_crossentropy', optimizer='adadelta')

for x, y in generate_data(sentences, word_length, dict_length):
    model.fit(x, y,epochs=1000)
    predict=model.predict(x)
    print("可能性:",predict)
    predict=np.argmax(predict,1)#求取最大值索引
    print("最大可能性的詞索引:",predict)
    print(sen[:2] for sen in sentences)
    """為了後面的反向索引預測的字,因為輸出的是字典索引,要輸出字就是反向找鍵"""
    number_dict = {str(w): i for i, w in tokenizer.word_index.items()}
    print("具體的詞:",number_dict[str(predict[0])])
           

四、最終效果

Keras實作NNLM神經網絡語言模型一、NNML的效果二、一些問題三、實作代碼及解釋四、最終效果

繼續閱讀