0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 3 years have passed since last update.

言語処理100本ノック(2020)-85: 双方向RNN・多層化(Keras)

Last updated at Posted at 2021-12-02

言語処理100本ノック 2020 (Rev2)「第9章: RNN, CNN」85本目「双方向RNN・多層化」記録です。以前やったことあるし、Kerasの力で非常に簡単。過学習のまま結果を出していますが、途中で止めていれば前回ノックより結果良くなっています。
記事「まとめ: 言語処理100本ノックで学べることと成果」言語処理100本ノック 2015についてはまとめていますが、追加で差分の言語処理100本ノック 2020 (Rev2)についても更新します。

参考リンク

リンク 備考
85_双方向RNN・多層化.ipynb 回答プログラムのGitHubリンク
言語処理100本ノック 2020 第9章: RNN, CNN (PyTorchだけど)解き方の参考
【言語処理100本ノック 2020】第9章: RNN, CNN (PyTorchだけど)解き方の参考
まとめ: 言語処理100本ノックで学べることと成果 言語処理100本ノックまとめ記事

環境

GPUを使わないと厳しいので、Google Colaboratory使いました。Pythonやそのパッケージでより新しいバージョンありますが、新機能使っていないので、プリインストールされているものをそのまま使っています。

種類 バージョン 内容
Python 3.7.12 Google Colaboratoryのバージョン
google 2.0.3 Google Driveのマウントに使用
tensorflow 2.7.0 ディープラーニングの主要処理
nltk 3.2.5 Tokenの辞書作成に使用
pandas 1.1.5 行列に関する処理に使用
gensim 3.6.0 Google Newsデータセットの読込に使用

第8章: ニューラルネット

学習内容

深層学習フレームワークを用い,再帰型ニューラルネットワーク(RNN)や畳み込みニューラルネットワーク(CNN)を実装します.

85. 双方向RNN・多層化

順方向と逆方向のRNNの両方を用いて入力テキストをエンコードし,モデルを学習せよ.

\overleftarrow h_{T+1} = 0, \
\overleftarrow h_t = {\rm \overleftarrow{RNN}}(\mathrm{emb}(x_t), \overleftarrow h_{t+1}), \
y = {\rm softmax}(W^{(yh)} [\overrightarrow h_T; \overleftarrow h_1] + b^{(y)})


>ただし,$\overrightarrow h_t \in \mathbb{R}^{d_h}, \overleftarrow h_t \in \mathbb{R}^{d_h}$はそれぞれ,順方向および逆方向のRNNで求めた時刻$t$の隠れ状態ベクトル,${\rm \overleftarrow{RNN}}(x,h)$は入力$x$と次時刻の隠れ状態$h$から前状態を計算するRNNユニット,$W^{(yh)} \in \mathbb{R}^{L \times 2d_h}$は隠れ状態ベクトルからカテゴリを予測するための行列,$b^{(y)} \in \mathbb{R}^{L}$はバイアス項である.また,$[a; b]$はベクトル$a$と$b$の連結を表す。

>さらに,双方向RNNを多層化して実験せよ.

# 回答
## 回答結果
前回ノックとの精度比較です。**全データセットに対して精度が多少改善しています**。ただ、モデルを複雑にしたのでEaly Stoppingをしているため、38Epochで訓練終了にしています。前回ノックではEarly Stoppingしていないので、完全に平等な比較ではないです。

|データセット|Loss|正答率|
|:-:|:-:|:-:|
|訓練|0.384 :arrow_right: 0.374(-0.10)|86.7% :arrow_right: 86.8%(+0.1%)|
|検証|0.470 :arrow_right: 0.458(-0.12)|83.8% :arrow_right: 84.2%(+0.4%)|
|評価|0.446 :arrow_right: 0.423(-0.23)|85.1% :arrow_right: 85.3%(+0.2%)|

参考に評価データセットの結果です。

```:結果
42/42 [==============================] - 1s 12ms/step - loss: 0.4229 - acc: 0.8533
[0.422873854637146, 0.8532934188842773]

また、訓練時間が5分25秒から5分42秒へと微増。ただ、1 Epochの訓練時間は3倍程度に増えています。モデル複雑にしているので当然ですね。

回答プログラム 85_双方向RNN・多層化.ipynb

GitHubには確認用コードも含めていますが、ここには必要なものだけ載せています。

import numpy as np
import nltk
from gensim.models import KeyedVectors
import pandas as pd
import tensorflow as tf
from google.colab import drive

drive.mount('/content/drive')

BASE_PATH = '/content/drive/MyDrive/ColabNotebooks/ML/NLP100_2020/'
max_len = 0
vocabulary = []
w2v_model = KeyedVectors.load_word2vec_format(BASE_PATH+'07.WordVector/input/GoogleNews-vectors-negative300.bin.gz', binary=True)

def read_dataset(type_):
    global max_len
    global vocabulary
    df = pd.read_table(BASE_PATH+'06.MachineLearning/'+type_+'.feature.txt')
    df.info()
    sr_title = df['title'].str.split().explode()
    max_len_ = df['title'].map(lambda x: len(x.split())).max()
    if max_len < max_len_:
        max_len = max_len_
    if len(vocabulary) == 0:
        vocabulary = [k for k, v in nltk.FreqDist(sr_title).items() if v > 1]
    else:
        vocabulary.extend([k for k, v in nltk.FreqDist(sr_title).items() if v > 1])
    y = df['category'].replace({'b':0, 't':1, 'e':2, 'm':3})
    return df['title'], tf.keras.utils.to_categorical(y, dtype='int32')  # 4値分類なので訓練・検証・テスト共通でone-hot化


X_train, y_train = read_dataset('train')
X_valid, y_valid = read_dataset('valid')
X_test, y_test = read_dataset('test')

# setで重複削除し、タプル形式に設定
tup_voc = tuple(set(vocabulary))

print(f'vocabulary size before removing duplicates: {len(vocabulary)}')
print(f'vocabulary size after removing duplicates: {len(tup_voc)}')
print(f'sample vocabulary: {tup_voc[:10]}')
print(f'max length is {max_len}')

vectorize_layer = tf.keras.layers.TextVectorization(
 output_mode='int',
 vocabulary=tup_voc,
 output_sequence_length=max_len)

print(f'vocabulary size is {vectorize_layer.vocabulary_size()}')

embedding_dim = 300
hits = 0
misses = 0

embedding_matrix = np.zeros((vectorize_layer.vocabulary_size(), embedding_dim))
for i, word in enumerate(vectorize_layer.get_vocabulary()):
    try:
        embedding_matrix[i] = w2v_model.get_vector(word)
        hits += 1
        # Words not found in embedding index will be all-zeros.
        # This includes the representation for "padding" and "OOV"
    except:
        misses += 1
        if misses < 7:  # Show 6 words as example
            print(word)

print("Converted %d words (%d misses)" % (hits, misses))

embedding_layer = tf.keras.layers.Embedding(
    vectorize_layer.vocabulary_size(),
    embedding_dim,
    embeddings_initializer=tf.keras.initializers.Constant(embedding_matrix),
    trainable=False
)

model = tf.keras.models.Sequential()
model.add(tf.keras.Input(shape=(1,), dtype=tf.string))
model.add(vectorize_layer)
model.add(embedding_layer)
model.add(tf.keras.layers.Bidirectional(tf.keras.layers.GRU(50, return_sequences=True)))
model.add(tf.keras.layers.Bidirectional(tf.keras.layers.GRU(50)))
model.add(tf.keras.layers.Dense(4, activation='softmax'))
model.compile(loss='categorical_crossentropy', optimizer='sgd', metrics=['acc'])
model.summary()

model.fit(X_train, y_train, epochs=100, validation_data=(X_valid, y_valid),
          callbacks=[tf.keras.callbacks.EarlyStopping(patience=5, restore_best_weights=True)])

model.evaluate(X_test, y_test)

回答解説

双方向と多層化

Kerasだと非常に簡単です。Bidrectionalを加えて双方向にし、レイヤを2つ重ねるだけです。そして、1層目にはreturn_sequences=Trueを追加します(ここを忘れていたため、エラーが出て少し悩みました)。

model.add(tf.keras.layers.Bidirectional(tf.keras.layers.GRU(50, return_sequences=True)))
model.add(tf.keras.layers.Bidirectional(tf.keras.layers.GRU(50)))

Early Stopping

100Epochでは過学習がひどかったので、EalyStoppingのコールバック関数を使っています。検証Lossが下げ止まって5Epoch経ったら最良の結果を残すようにしています。

model.fit(X_train, y_train, epochs=100, validation_data=(X_valid, y_valid),
          callbacks=[tf.keras.callbacks.EarlyStopping(patience=5, restore_best_weights=True)])
0
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?