こんにちは!
テービーテックの村松です。
本日は、こちらの続きをやっていこうかと思います。
ds-blog.tbtech.co.jp
前回は、前処理の単語にばらして綺麗に整えるところまで行いました。
《予定している前処理》
・余分な要素の排除
・小さな単位(文字・単語など)にバラバラにする←ここまで
・文字・単語のベクトル化(文字を数字にする)
今日は文字のベクトル化からやっていきましょう。
先にtargetデータの作成
##教師データの抜出し target = train.Sentiment.values #5クラス分類用にto-categoricalを使用してOne-Hot y_target = to_categorical(target) num_classes = y_target.shape[1]
データの分割
from sklearn.model_selection import train_test_split x_train, x_val, y_train, y_val =train_test_split(train_sentences,y_target,test_size=0.2,stratify=y_target) len(x_train), len(x_val), len(y_train), len(y_val)
##結果 (124848, 31212, 124848, 31212)
単語の辞書の作成
レビュー内で使われている単語のダブリを無くして使用されている単語の一覧を作ります。
ついでに単語を多く使っているフレーズの単語数を数えます。
unique_words = set() len_max = 0 for sent in tqdm(x_train): unique_words.update(sent) if(len_max<len(sent)): len_max = len(sent) print(len(list(unique_words))) print(len_max)
##結果 13734 48
x_train内で使われている単語は13,734種類、
一番単語が多いフレーズには48個の単語が使用されていることがわかりました。
これらを使って単語を数値化していきます。
単語を数値に変換
例として1フレーズ現在どんな感じか見ておきます。
x_train[0]
##結果 ['a', 'gobbler']
これがどんなふうに数値に変換されていくか確認していきましょう。
from keras.preprocessing.text import Tokenizer tokenizer = Tokenizer(num_words=len(list(unique_words))) tokenizer.fit_on_texts(list(x_train)) from keras.preprocessing import sequence x_train = tokenizer.texts_to_sequences(x_train) x_val = tokenizer.texts_to_sequences(x_val) x_test = tokenizer.texts_to_sequences(test_sentences) x_train[0]
##結果 [2, 8442]
辞書を元に単語ごとに数字が割り振られ、フレーズの単語を割り振られた数値に変換していきます。
今回は'a'は2に、'gobbler’は8422に変換されました。
さて、単語を数値に落とし込むことはできましたが、このままではまだ足りません。
LSTMは入力を同じ長さにしなくてはいけないとのことなので、一番使用単語の多いフレーズに合わせてパディングしていきます。
from keras.preprocessing import sequence x_train = sequence.pad_sequences(x_train, maxlen=len_max) x_val = sequence.pad_sequences(x_val, maxlen=len_max) x_test = sequence.pad_sequences(x_test, maxlen=len_max) x_train[0]
##結果 array([ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 8442], dtype=int32)
ひとまず、以上が前処理となります。
次は整えたデータを使って学習をしていきましょう。
モデルの作成
#モジュールのインポート from keras.layers import Dense,Dropout,Embedding,LSTM from keras.callbacks import EarlyStopping from keras.losses import categorical_crossentropy from keras.optimizers import Adam from keras.models import Sequential
過学習防止のためにこちらも用意しておきます。
early_stopping = EarlyStopping(min_delta = 0.001, mode = 'max', monitor='val_acc', patience = 2) callback = [early_stopping]
モデルの作成。
#KerasのLSTMを使用 model=Sequential() model.add(Embedding(len(list(unique_words)),300,input_length=len_max)) model.add(LSTM(128,dropout=0.5, recurrent_dropout=0.5,return_sequences=True)) model.add(LSTM(64,dropout=0.5, recurrent_dropout=0.5,return_sequences=False)) model.add(Dense(100,activation='relu')) model.add(Dropout(0.5)) model.add(Dense(num_classes,activation='softmax')) model.compile(loss='categorical_crossentropy',optimizer=Adam(lr=0.005),metrics=['accuracy']) model.summary()
##結果 Model: "sequential_2" _________________________________________________________________ Layer (type) Output Shape Param # ================================================================= embedding_1 (Embedding) (None, 48, 300) 4120200 _________________________________________________________________ lstm_1 (LSTM) (None, 48, 128) 219648 _________________________________________________________________ lstm_2 (LSTM) (None, 64) 49408 _________________________________________________________________ dense_1 (Dense) (None, 100) 6500 _________________________________________________________________ dropout_1 (Dropout) (None, 100) 0 _________________________________________________________________ dense_2 (Dense) (None, 5) 505 ================================================================= Total params: 4,396,261 Trainable params: 4,396,261 Non-trainable params: 0 _________________________________________________________________
学習
history=model.fit(x_train, y_train, validation_data=(x_val, y_val), epochs=6, batch_size=256, verbose=1, callbacks=callback)
##結果 Train on 124848 samples, validate on 31212 samples Epoch 1/6 124848/124848 [==============================] - 378s 3ms/step - loss: 0.7713 - accuracy: 0.6835 - val_loss: 0.8131 - val_accuracy: 0.6645 Epoch 2/6 124848/124848 [==============================] - 380s 3ms/step - loss: 0.7285 - accuracy: 0.6992 - val_loss: 0.8164 - val_accuracy: 0.6686 Epoch 3/6 124848/124848 [==============================] - 375s 3ms/step - loss: 0.7047 - accuracy: 0.7080 - val_loss: 0.8330 - val_accuracy: 0.6625 Epoch 4/6 124848/124848 [==============================] - 375s 3ms/step - loss: 0.6869 - accuracy: 0.7145 - val_loss: 0.8360 - val_accuracy: 0.6633 Epoch 5/6 124848/124848 [==============================] - 377s 3ms/step - loss: 0.6741 - accuracy: 0.7197 - val_loss: 0.8377 - val_accuracy: 0.6687 Epoch 6/6 124848/124848 [==============================] - 380s 3ms/step - loss: 0.6651 - accuracy: 0.7239 - val_loss: 0.8585 - val_accuracy: 0.6665
結果の可視化
#エポック数のカウント epoch_count = range(1, len(history.history['loss']) + 1) #精度と学習曲線 import matplotlib.pyplot as plt plt.plot(epoch_count, history.history['loss'], 'r--') plt.plot(epoch_count, history.history['val_loss'], 'b-') plt.legend(['Training Loss', 'Validation Loss']) plt.xlabel('Epoch') plt.ylabel('Loss') plt.show()
ううむ・・・まだ改良の余地がありそうですね。
ここで終わるのももったいないので、精度を上げるための工夫を凝らしていきましょうか。
私にしては長く3部構成になりますが、最後までお付き合いいただければ幸いです。