【Tensorflow 2.0公式版チュートリアル】ワード埋め込み(word embedding)とGLoVe

11781 ワード

このチュートリアルでは、自然言語処理におけるワード埋め込み、すなわちword embeddingについて説明し、GLoVeプリトレーニングパラメータのロードについて説明します.
簡単に言えば、word embeddingは単語をベクトルに変換し、ニューラルネットワークの計算にさらに関与する.tensorflow 2.0では、tensorflow.keras.layers.Embeddingがこの機能を実現している.ここでembedding層は、行ベクトル乗行列の行列乗算を計算し、行ベクトルはonehot形式の単語であり、行列は重みであるため、本質的に重みの各行は意味空間における単語の特徴ベクトルを表し、この行列の行数は単語数である.
以下、簡単なテキスト分類例で具体的に説明します.データベースはIMDB映画評価感情分析を選択し、このデータtensorflowは公式ダウンロードと解析関数を提供する.
(train_sequences, train_labels), (test_sequences, test_labels) = tf.keras.datasets.imdb.load_data(num_words=word_num)
word_index = tf.keras.datasets.imdb.get_word_index()

ここでsequencesはシーケンス化の結果、すなわち単語の代わりに数字を用い、num_wordsパラメータは最大単語数であり、特に、0は空白文字を表し、後続の補位に用いられ、1は開始文字を表し、2は未知単語を表し、3は未使用の単語を表す.後続4は最高語周波数単語’the’であり、5およびその後は語周波数順に並べ替えられる.word_indexは単語から数字へのマッピング関係であり,このマッピングテーブルに‘the’が対応するピットが1であり,その後は特殊な処理が必要である.
tensorflowのデータを考慮してgoogleapisに置いた.comでは、ネットワークの状況が悪い環境では、まず公式からデータ:imdbをダウンロードすることもできます.npz,imdb_word_index.jsonは、上記のロード関数でpathパラメータを指定します.
sequencesをネットワークに入力する前に、指定した長さより小さい長さの前に0を補い、指定した長さより大きい切り取り後のセグメントを統一する必要があります.
train_sequences = pad_sequences(train_sequences, maxlen=max_len)
test_sequences = pad_sequences(test_sequences, maxlen=max_len)

このとき、ネットワークに入力されるテキストデータサイズは(batch_size, max_len)であり、Embedding層を介して(batch_size, max_len, embedding_dim)サイズの語埋め込みベクトルが得られ、embedding_dimは意味空間次元である.これにより,単純な全接続ネットワークを構築してテキストを分類することができる.
def Model():
    model = tf.keras.Sequential()
    model.add(Embedding(word_num, embedding_dim))
    model.add(GlobalAveragePooling1D())
    model.add(Dense(128, activation=tf.nn.relu))
    model.add(Dense(2, activation='softmax'))
    return model

そしてトレーニングを始めることができます
word_num = 10000
max_len = 256
embedding_dim = 100

# get model
model = Model()
model.summary()

# train
model.compile(optimizer='adam', loss='sparse_categorical_crossentropy', metrics=['accuracy'])
model.fit(train_sequences,
          train_labels,
          batch_size=512,
          epochs=10)

# test
test_loss, test_acc = model.evaluate(test_sequences, test_labels)
print(test_acc)

このとき、約87.1%の精度に達することができる.
さらに,Embedding層の重みはランダムに初期化されており,より良い結果を得るためにはword 2 vec,GLoVeなどの事前訓練の重みをロードする必要があるが,ここではGLoVeを例に挙げる.
GLoVeウェイトは公式からダウンロードできます.重みを考慮した各行は、意味空間における単語の特徴ベクトルを表すので、word_indexのマッピング関係を用いて付与することができる.
def get_embedding_weight(weight_path, word_index):
    # embedding_weight = np.zeros([word_num, embedding_dim])
    embedding_weight = np.random.uniform(-0.05, 0.05, size=[word_num, embedding_dim])
    cnt = 0
    with open(weight_path, 'r') as f:
        for line in f:
            values = line.split()
            word = values[0]
            if word in word_index.keys() and word_index[word] + 3 < word_num:
                """
                In tf.keras.dataset.imdb.load_data(), there are 4 special mark.
                : 0
                : 1
                : 2
                : 3
                So word_index loaded from offical file, "mdb_word_index.json", need to +3.
                """
                weight = np.asarray(values[1:], dtype='float32')
                embedding_weight[word_index[word] + 3] = weight
                cnt += 1
    print('matched word num: {}'.format(cnt))
    return embedding_weight


次に、Embeddingレイヤをインスタンス化するときに重みEmbedding(word_num, embedding_dim, weights=[embedding_weight])を指定します.私は実験でGLoVe_path = '/home1/dataset/GLoVe/glove.6B.100d.txt'を選択し、テストセットで88.2%の精度を達成することができます.ランダム初期化方式に比べて,プリトレーニングウェイトのロードは分類精度を向上させた.
本文はembedding層とGLoVeロードの簡単な教育のみを行うことを考慮して、最終的に達成した正確率は低い.コード内のスーパーパラメータとモデル自体は、より良い結果を達成するためにさらに調整することができる.完全なコードは私のgithubで見つけることができます.https://github.com/Apm5/tensorflow_2.0_tutorial/blob/master/RNN/simple_example.py