言語処理100本ノック 2020 (Rev2)の「第9章: RNN, CNN」の81本目「RNNによる予測」記録です。今回は過去に私が経験したことのある内容の延長なので簡単です。RNNにはLSTMより軽いGRUを使っています(今回程度の内容であれば、十分なはず)。
記事「まとめ: 言語処理100本ノックで学べることと成果」に言語処理100本ノック 2015についてはまとめていますが、追加で差分の言語処理100本ノック 2020 (Rev2)についても更新します。
参考リンク
リンク | 備考 |
---|---|
81_RNNによる予測.ipynb | 回答プログラムのGitHubリンク |
言語処理100本ノック 2020 第9章: RNN, CNN | (PyTorchだけど)解き方の参考 |
【言語処理100本ノック 2020】第9章: RNN, CNN | (PyTorchだけど)解き方の参考 |
まとめ: 言語処理100本ノックで学べることと成果 | 言語処理100本ノックまとめ記事 |
【Keras入門(5)】単純なRNNモデル定義 | 前にKerasとRNN勉強したときの記事 |
【Keras入門(6)】単純なRNNモデル定義(最終出力のみ使用) | 前にKerasとRNN勉強したときの記事 |
【TensorFlow公式ガイド】単語の埋め込み | Embeddingのガイド |
【TensorFlow公式サンプル】トークンインデックスのシーケンスとしてテキストをエンコードする | Embeddingの使い方サンプル |
環境
後々GPUを使わないと厳しいので、Google Colaboratory使いました。Pythonやそのパッケージでより新しいバージョンありますが、新機能使っていないので、プリインストールされているものをそのまま使っています。
種類 | バージョン | 内容 |
---|---|---|
Python | 3.7.12 | Google Colaboratoryのバージョン |
2.0.3 | Google Driveのマウントに使用 | |
tensorflow | 2.7.0 | ディープラーニングの主要処理 |
nltk | 3.2.5 | Tokenの辞書作成に使用 |
pandas | 1.1.5 | 行列に関する処理に使用 |
第8章: ニューラルネット
学習内容
深層学習フレームワークを用い,再帰型ニューラルネットワーク(RNN)や畳み込みニューラルネットワーク(CNN)を実装します.
81. RNNによる予測
ID番号で表現された単語列$\boldsymbol{x} = (x_1, x_2, \dots, x_T)$がある.ただし,$T$は単語列の長さ,$x_t \in \mathbb{R}^{V}$は単語のID番号のone-hot表記である($V$は単語の総数である).再帰型ニューラルネットワーク(RNN: Recurrent Neural Network)を用い,単語列$\boldsymbol{x}$からカテゴリ$y$を予測するモデルとして,次式を実装せよ.
$
\overrightarrow h_0 = 0, \
\overrightarrow h_t = {\rm \overrightarrow{RNN}}(\mathrm{emb}(x_t), \overrightarrow h_{t-1}), \
y = {\rm softmax}(W^{(yh)} \overrightarrow h_T + b^{(y)})
$
ただし,$\mathrm{emb}(x) \in \mathbb{R}^{d_w}$は単語埋め込み(単語のone-hot表記から単語ベクトルに変換する関数),$\overrightarrow h_t \in \mathbb{R}^{d_h}$は時刻$t$の隠れ状態ベクトル,${\rm \overrightarrow{RNN}}(x,h)$は入力$x$と前時刻の隠れ状態$h$から次状態を計算するRNNユニット,$W^{(yh)} \in \mathbb{R}^{L \times d_h}$は隠れ状態ベクトルからカテゴリを予測するための行列,$b^{(y)} \in \mathbb{R}^{L}$はバイアス項である($d_w, d_h, L$はそれぞれ,単語埋め込みの次元数,隠れ状態ベクトルの次元数,ラベル数である).RNNユニット${\rm \overrightarrow{RNN}}(x,h)$には様々な構成が考えられるが,典型例として次式が挙げられる.
$
{\rm \overrightarrow{RNN}}(x,h) = g(W^{(hx)} x + W^{(hh)}h + b^{(h)})
$
ただし,$W^{(hx)} \in \mathbb{R}^{d_h \times d_w},W^{(hh)} \in \mathbb{R}^{d_h \times d_h}, b^{(h)} \in \mathbb{R}^{d_h}$はRNNユニットのパラメータ,$g$は活性化関数(例えば$\tanh$やReLUなど)である.
なお,この問題ではパラメータの学習を行わず,ランダムに初期化されたパラメータで$y$を計算するだけでよい.次元数などのハイパーパラメータは,$d_w = 300, d_h=50$など,適当な値に設定せよ(以降の問題でも同様である).
回答
回答結果
未学習状態なので、4値分類でほぼ同じ確率です。
array([[0.2583952 , 0.25148967, 0.22984934, 0.2602658 ]], dtype=float32)
回答プログラム 81_RNNによる予測.ipynb
GitHubには確認用コードも含めていますが、ここには必要なものだけ載せています。
import nltk
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/06.MachineLearning/'
max_len = 0
def get_vocabulary(type_):
global max_len
df = pd.read_table(BASE_PATH+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_
fdist = nltk.FreqDist(sr_title)
print(f'Top 3 tokens: {fdist.most_common(3)}')
return [k for k, v in fdist.items() if v > 1]
vocabulary = get_vocabulary('train')
vocabulary.extend(get_vocabulary('valid'))
vocabulary.extend(get_vocabulary('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'sample vocabulary: {vectorize_layer.get_vocabulary()[:10]}')
model = tf.keras.models.Sequential()
model.add(tf.keras.Input(shape=(1,), dtype=tf.string))
model.add(vectorize_layer)
model.add(tf.keras.layers.Embedding(vectorize_layer.vocabulary_size(), 300, mask_zero=True))
model.add(tf.keras.layers.GRU(50))
model.add(tf.keras.layers.Dense(4, activation='softmax'))
model.compile(loss='categorical_crossentropy', optimizer='sgd')
model.summary()
model.predict([['this is a pen']])
回答解説
以前KerasとRNNは以下の記事で書いたので解説をかなり割愛します。記事は少し古いですが、基本的に変わっていません。
Embedding
Ebmedding(単語埋め込み)についてです。
単語数をTextVectorization
のvocabulary_size
で取得しています。maskと未知語(UNK)も含まれる数をくれるので、mask_zero
をTrue
にしてもその値でOKです。
後にGPUを使うのでRNN(GRU)のパラメータはデフォルト値にしておきます。GPU使用注意点は公式tf.keras.layers.GRUに記載があります。
model = tf.keras.models.Sequential()
model.add(tf.keras.Input(shape=(1,), dtype=tf.string))
model.add(vectorize_layer)
model.add(tf.keras.layers.Embedding(vectorize_layer.vocabulary_size(), 300, mask_zero=True))
model.add(tf.keras.layers.GRU(50))
model.add(tf.keras.layers.Dense(4, activation='softmax'))
model.compile(loss='categorical_crossentropy', optimizer='sgd')
model.summary()
TensorFlow公式ガイド「単語の埋め込み」に記載がありますが、ローカルのTensorBoardまたはインターネット上のプロジェクターでEmbeddingの視覚化ができます。そのためのファイル出力方法もガイド内に記載があります。