NLP(自然言語処理) sequential モデルを Functional APIに書き換える
これまでの記事では,sequential
モデルを用いてモデルを構築してきました。
model = Sequential()
model.add(LSTM(128, input_shape=(seq_length, 1)))
model.add(Dense(len(char_indices)+1, activation='softmax'))
sequential
モデルは単純な構造を持つため理解しやすいものですが,一つの入力と一つの出力しか持つことができません。
もし,複数の入力と出力を持つモデルを構築したい場合,Functional APIを用いる必要があります。
Functional API
ここでは,理解のためにsequential
モデルと同じ構造をFunctional APIで記述します。
input = Input(shape=(seq_length,1))
はじめに,入力層を設置します。LSTM層には(バッチサイズ,タイムステップ,入力次数)のテンソルを与えます。しかし,入力層にバッチサイズを指定する必要はなく,(タイムステップ,入力次数)を指定します。input
に入力層が格納されます。
lstm = LSTM(128,input_shape=(seq_length, 1))(input)
LSTM層を設置します。(input)
はLSTM層を入力層に接続させることを表しています。
output = Dense(len(char_indices)+1, activation='softmax')(lstm)
出力層を設置します。(lstm)
はDense層をLSTM層に接続させることを表しています。
model = Model(inputs=input, outputs=output)
最後にモデルを設置します。ここでは,input
を入力層,output
を出力層として指定しています。
例えば,出力層を2つ設置する場合,outputs=[output1, output2]
のように指定します。
sequentialモデルとFunctional API
結果的に,ここに示す2つのモデルは同じものです。
model = Sequential()
model.add(LSTM(128, input_shape=(seq_length, 1)))
model.add(Dense(len(char_indices)+1, activation='softmax'))
input = Input(shape=(seq_length,1))
lstm = LSTM(128,input_shape=(seq_length, 1))(input)
output = Dense(len(char_indices)+1, activation='softmax')(lstm)
model = Model(inputs=input, outputs=output)
全体のコードを示します。
import numpy as np
import sys
import io
import os
import stanza
os.environ['TF_CPP_MIN_LOG_LEVEL']='2'
from tensorflow import keras
from keras.models import Model
from keras.layers import Dense, LSTM, Input
from keras.optimizers import Adam
from keras.utils import np_utils
from keras.preprocessing import sequence
from keras.preprocessing.text import Tokenizer
from keras.preprocessing.sequence import TimeseriesGenerator
#read the text
with io.open('articles_u.txt', encoding='utf-8') as f:
text = f.read()
texts = text.replace('eos', 'eos\n').splitlines()
#make the dictionary
tokenizer = Tokenizer()
tokenizer.fit_on_texts(texts)
char_indices = tokenizer.word_index
#make the inverted dictionary
indices_char = dict([(value, key) for (key, value) in char_indices.items()])
np.save('voa_char_indices', char_indices)
np.save('voa_indices_char', indices_char)
#vectorization
texts = tokenizer.texts_to_sequences(texts)
texts = sequence.pad_sequences(texts, maxlen=30, padding="pre", truncating="post")
#make dataset
batch_size = 100
seq_length = 5
def train_generator(start, end):
while True:
for step in range((end - start) // batch_size):
x = []
y = []
for line in range(batch_size):
dataset = TimeseriesGenerator(
texts[start+step*batch_size+line],
texts[start+step*batch_size+line],
length=seq_length,
batch_size=1)
for batch in dataset:
X, Y = batch
x.extend(X[0])
y.extend(Y)
x = np.reshape(x,(25*batch_size,seq_length,1))
x = x / float(len(char_indices)+1)
y = np_utils.to_categorical(y, len(char_indices)+1)
yield x, y
#build the model
print('build the model....')
input = Input(shape=(seq_length,1))
lstm = LSTM(128,input_shape=(seq_length, 1))(input)
output = Dense(len(char_indices)+1, activation='softmax')(lstm)
model = Model(inputs=input, outputs=output)
optimizer = Adam(lr=0.01)
model.compile(loss='categorical_crossentropy', optimizer=optimizer, metrics=['accuracy'])
#training
train_val_rate = 0.8
train_start = 0
train_end = round(len(texts) * train_val_rate)
val_start = train_end + 1
val_end = len(texts)
model.fit(
train_generator(train_start, train_end),
steps_per_epoch=(train_end - train_start) // batch_size,
validation_data=train_generator(val_start, val_end),
validation_steps=(val_end - val_start) // batch_size,
epochs=100,
verbose=2)
#save the model
model.save('u_model.h5')
SNSでシェア