ホーム » Embedding

Embedding」カテゴリーアーカイブ

TensorFlow 2.0 : 上級 Tutorials : テキスト :- 単語埋め込み

TensorFlow 2.0 : 上級 Tutorials : テキスト :- 単語埋め込み (翻訳/解説)

翻訳 : (株)クラスキャット セールスインフォメーション
作成日時 : 11/09/2019

* 本ページは、TensorFlow org サイトの TF 2.0 – Advanced Tutorials – Text の以下のページを翻訳した上で
適宜、補足説明したものです:

* サンプルコードの動作確認はしておりますが、必要な場合には適宜、追加改変しています。
* ご自由にリンクを張って頂いてかまいませんが、sales-info@classcat.com までご一報いただけると嬉しいです。

 

無料セミナー開催中 クラスキャット主催 人工知能 & ビジネス Web セミナー

人工知能とビジネスをテーマにウェビナー (WEB セミナー) を定期的に開催しています。スケジュールは弊社 公式 Web サイト でご確認頂けます。
  • お住まいの地域に関係なく Web ブラウザからご参加頂けます。事前登録 が必要ですのでご注意ください。
  • Windows PC のブラウザからご参加が可能です。スマートデバイスもご利用可能です。

お問合せ : 本件に関するお問い合わせ先は下記までお願いいたします。

株式会社クラスキャット セールス・マーケティング本部 セールス・インフォメーション
E-Mail:sales-info@classcat.com ; WebSite: https://www.classcat.com/
Facebook: https://www.facebook.com/ClassCatJP/

 

テキスト :- 単語埋め込み

このチュートリアルは単語埋め込みを紹介します。それは小さいデータセット上でスクラッチから単語埋め込みを訓練し、そして埋め込みプロジェクター (= Embedding Projector) (下の画像で示されます) を使用してこれらの埋め込みを可視化する完全なコードを含みます。

 

テキストを数字として表現する

機械学習モデルは入力としてベクトル (数字の配列) を取ります。テキストで作業するとき、行わなければならない最初のことはモデルに供給する前に文字列を数字に変換する (or テキストを「ベクトル化」する) ストラテジーを考え出すことです。このセクションでは、それを行なうための 3 つのストラテジーを見ます。

 

One-hot エンコーディング

最初のアイデアとして、語彙の各単語を “one-hot” エンコードするかもしれません。センテンス “The cat sat on the mat” を考えます。このセンテンスの語彙 (or 一意の単語) は (cat, mat, on, sat, the) です。各単語を表わすために、語彙に等しい長さを持つゼロベクトルを作成してから、単語に対応するインデックス内に 1 を置きます。このアプローチは次の図で示されます。

センテンスのエンコーディングを含むベクトルを作成するために、それから各単語のための one-hot ベクトルを連結できるでしょう。

Key point: このアプローチは不十分です。one-hot エンコード・ベクトルは疎 (= スパース) です (つまり、殆どのインデックスはゼロです)。語彙に 10,000 単語を持つことを想像してください。各単語を one-hot エンコードするには、要素の 99.99% はゼロであるベクトルを作成するでしょう。

 

一意の数字を持つ各単語をエンコードする

私達が試して良い 2 番目のアプローチは一意の数字を使用して各単語をエンコードすることです。上の例を続けるのであれば、1 を “cat” に、2 を “mat” 等に割り当てることができるでしょう。それからセンテンス “The cat sat on the mat” を [5, 1, 4, 3, 5, 2] のような密ベクトルとしてエンコードできるでしょう。このアプローチは効率的です。疎ベクトルの代わりに、今では密なひとつ (そこでは総ての要素は満たされています) を持ちます。

けれども、このアプローチには 2 つの欠点があります :

  • 整数エンコーディングは恣意的 (= arbitrary) です (それは単語間のどのような関係も捕捉しません)。
  • 整数エンコーディングはモデルが解釈することは困難な可能性があります。例えば、線形分類器は各特徴について単一の重みを学習します。任意の 2 つの単語の類似性とそれらのエンコーディングの類似性の間に関係はありませんので、この特徴-重みの組み合わせは意味がありません。

 

単語埋め込み

単語埋め込みは効率的で、密な表現を使用する方法を与えてくれます、そこでは類似した単語は類似したエンコーディングを持ちます。重要なことは、このエンコーディングを手動で指定しなくてもかまわないことです。埋め込みは浮動小数点値の密ベクトルです (ベクトルの長さは貴方が指定するパラメータです)。埋め込みのための値を手動で指定する代わりに、それらは訓練可能なパラメータです (モデルが dense 層のための重みを学習するのと同じ方法で、訓練の間にモデルにより学習される重みです)。(小さいデータセットのための) 8-次元から、巨大なデータセットで作業するときの 1024 次元までの単語埋め込みを見ることは一般的です。高い次元の埋め込みは単語間のきめ細かい関係性を捕捉できますが、学習するためにより多くのデータを取ります。

上は単語埋め込みのための図です。各単語は浮動小数点値の 4-次元ベクトルとして表現されています。埋め込みを考えるもう一つの方法は「検索テーブル (= lookup table)」です。これらの重みが学習された後、各単語をそれがテーブルで対応する密ベクトルを検索することによりエンコードできます。

 

セットアップ

from __future__ import absolute_import, division, print_function, unicode_literals

import tensorflow as tf
from tensorflow import keras
from tensorflow.keras import layers

import tensorflow_datasets as tfds
tfds.disable_progress_bar()

 

埋め込み層を使用する

Keras は単語埋め込みを使用することを容易にします。Embedding 層を見てみましょう。

Embedding 層は整数インデックス (これは特定の単語を表します) から密ベクトル (それらの埋め込み) へマップする検索テーブルとして理解できます。埋め込みの次元 (or width) は、(Dense 層のニューロン数で実験するのとだいたい同じ方法で) 貴方の問題のために何が上手く動作するかを見るためにそれで実験できるパラメータです。

embedding_layer = layers.Embedding(1000, 5)

埋め込み層を作成するとき、埋め込めのための重みは (丁度任意の他の層のように) ランダムに初期化されます。訓練の間に、それらは逆伝播を通して徐々に調整されます。ひとたび訓練されれば、学習された単語埋め込みは単語間の類似性を大雑把にエンコードします (何故ならばそれらは貴方のモデルがその上で訓練された特定の問題のために学習されたからです)。

整数を埋め込み層に渡せば、結果は各整数を埋め込みテーブルからのベクトルで置き換えます :

If you pass an integer to an embedding layer,
the result replaces each integer with the vector from the embedding table:

result = embedding_layer(tf.constant([1,2,3]))
result.numpy()
array([[ 0.03075174,  0.01077418,  0.04825656, -0.02901061, -0.02860381],
       [-0.01487043,  0.03127805, -0.00348612,  0.00670124,  0.03629971],
       [ 0.0334234 , -0.02370602, -0.01366466, -0.02364613, -0.00822309]],
      dtype=float32)

テキストまたはシークエンス問題のために、Embedding 層は shape (samples, sequence_length) の整数の 2D tensor を取ります、そこでは各エントリは整数のシークエンスです。それは可変長のシークエンスを埋め込むことができます。上の埋め込み層に shapes (32, 10) (長さ 10 の 32 シークエンスのバッチ) あるいは (64, 15) (長さ 15 の 64 シークエンスのバッチ) を持つバッチを供給できるでしょう。

返される tensor は入力よりも 1 つ多い軸を持ち、埋め込みベクトルは新しい最後の軸に沿って並べられます。それに (2, 3) 入力バッチを渡すと出力は (2, 3, N) です。

result = embedding_layer(tf.constant([[0,1,2],[3,4,5]]))
result.shape
TensorShape([2, 3, 5])

入力としてシークエンスのバッチが与えられたとき、埋め込み層は shape (samples, sequence_length, embedding_dimensionality) の 3D 浮動小数点 tensor を返します。この可変長のシークエンスから固定表現に変換するために、様々な標準的なアプローチがあります。それを Dense 層に渡す前に RNN, Attention あるいは pooling 層を使用できるでしょう。このチュートリアルは pooling を使用します、何故ならばそれが最も単純だからです。Text Classification with an RNN チュートリアルは良い次のステップです。

 

スクラッチから埋め込みを学習する

このチュートリアルでは IMDB 映画レビュー上でセンチメント分類器を訓練します。この過程で、モデルはスクラッチから埋め込みを学習します。前処理されたデータセットを使用します。

テキストデータセットをスクラッチからロードするためには Loading text チュートリアル を見てください。

(train_data, test_data), info = tfds.load(
    'imdb_reviews/subwords8k', 
    split = (tfds.Split.TRAIN, tfds.Split.TEST), 
    with_info=True, as_supervised=True)
Downloading and preparing dataset imdb_reviews (80.23 MiB) to /home/kbuilder/tensorflow_datasets/imdb_reviews/subwords8k/0.1.0...
WARNING:tensorflow:From /home/kbuilder/.local/lib/python3.6/site-packages/tensorflow_datasets/core/file_format_adapter.py:209: tf_record_iterator (from tensorflow.python.lib.io.tf_record) is deprecated and will be removed in a future version.
Instructions for updating:
Use eager execution and: 
`tf.data.TFRecordDataset(path)`

WARNING:tensorflow:From /home/kbuilder/.local/lib/python3.6/site-packages/tensorflow_datasets/core/file_format_adapter.py:209: tf_record_iterator (from tensorflow.python.lib.io.tf_record) is deprecated and will be removed in a future version.
Instructions for updating:
Use eager execution and: 
`tf.data.TFRecordDataset(path)`

Dataset imdb_reviews downloaded and prepared to /home/kbuilder/tensorflow_datasets/imdb_reviews/subwords8k/0.1.0. Subsequent calls will reuse this data.

エンコーダ ( tfds.features.text.SubwordTextEncoder ) を得て、語彙を素早く見てみます。

語彙の “_” は空白を表します。語彙が (“_” で終わる) 全体単語 (whole words) とより大きい単語を構築するためにそれが使用できる部分単語 (= partial words) をどのように含むかに注意してください :

encoder = info.features['text'].encoder
encoder.subwords[:20]
['the_',
 ', ',
 '. ',
 'a_',
 'and_',
 'of_',
 'to_',
 's_',
 'is_',
 'br',
 'in_',
 'I_',
 'that_',
 'this_',
 'it_',
 ' /><',
 ' />',
 'was_',
 'The_',
 'as_']

映画レビューは異なる長さである可能性があります。レビューの長さを標準化するために padded_batch を使用します。

padded_shapes = ([None],())
train_batches = train_data.shuffle(1000).padded_batch(10, padded_shapes = padded_shapes)
test_batches = test_data.shuffle(1000).padded_batch(10, padded_shapes = padded_shapes)

インポートされたとき、レビューのテキストは整数エンコードされています (各整数は語彙内の特定の単語か単語部分 (= word-part) を表します)。trailing ゼロに注意してください、バッチは最大長のサンプルに (合わせて) パッドされているからです。

train_batch, train_labels = next(iter(train_batches))
train_batch.numpy()
array([[  62,   27,    9, ...,    0,    0,    0],
       [3923,   34, 1092, ...,    0,    0,    0],
       [  12,  180,   31, ...,    0,    0,    0],
       ...,
       [  12, 6981,   64, ...,    0,    0,    0],
       [ 147,    1, 2639, ...,    0,    0,    0],
       [ 693,   83,    4, ...,    0,    0,    0]])

 

単純なモデルを作成する

モデルを定義するために Keras Sequential API を使用します。この場合それは “Continuous bag of words” スタイルモデルです。

  • 次に Embedding 層は整数エンコードされた語彙を取り各単語インデックスのための埋め込みベクトルを検索します。これらのベクトルはモデルを訓練するときに学習されます。ベクトルは出力配列に次元を追加します。結果としての次元は : (batch, sequence, embedding) です。
  • 次に、GlobalAveragePooling1D 層はシークエンス次元に渡り平均することにより各サンプルのために固定長出力ベクトルを返します。これは可能な最も単純な方法の中で、モデルに可変長の入力を処理することを可能にします。
  • この固定長出力ベクトルは 16 隠れユニットを持つ完全結合 (Dense) 層を通してパイプされます。
  • 最後の層は単一出力ノードと密に結合されます。sigmoid 活性化関数を使用して、この値は 0 と 1 の間の float で、レビューがポジティブである確率 (or 確信度レベル) を表します。

警告: このモデルはマスキングを使用しませんので、ゼロ・パディングは入力の一部として使用されますので、パディング長は出力に影響を与えます。これを修正するには、masking and padding ガイド を見てください。

embedding_dim=16

model = keras.Sequential([
  layers.Embedding(encoder.vocab_size, embedding_dim),
  layers.GlobalAveragePooling1D(),
  layers.Dense(1, activation='sigmoid')
])

model.summary()
Model: "sequential"
_________________________________________________________________
Layer (type)                 Output Shape              Param #   
=================================================================
embedding_1 (Embedding)      (None, None, 16)          130960    
_________________________________________________________________
global_average_pooling1d (Gl (None, 16)                0         
_________________________________________________________________
dense (Dense)                (None, 1)                 17        
=================================================================
Total params: 130,977
Trainable params: 130,977
Non-trainable params: 0
_________________________________________________________________

 

モデルをコンパイルして訓練する

model.compile(optimizer='adam',
              loss='binary_crossentropy',
              metrics=['accuracy'])

history = model.fit(
    train_batches,
    epochs=10,
    validation_data=test_batches, validation_steps=20)
Epoch 1/10
2500/2500 [==============================] - 15s 6ms/step - loss: 0.6373 - accuracy: 0.6942 - val_loss: 0.0000e+00 - val_accuracy: 0.0000e+00
Epoch 2/10
2500/2500 [==============================] - 12s 5ms/step - loss: 0.4680 - accuracy: 0.8341 - val_loss: 0.3942 - val_accuracy: 0.8550
Epoch 3/10
2500/2500 [==============================] - 12s 5ms/step - loss: 0.3635 - accuracy: 0.8754 - val_loss: 0.3866 - val_accuracy: 0.8600
Epoch 4/10
2500/2500 [==============================] - 12s 5ms/step - loss: 0.3080 - accuracy: 0.8940 - val_loss: 0.3504 - val_accuracy: 0.8550
Epoch 5/10
2500/2500 [==============================] - 12s 5ms/step - loss: 0.2750 - accuracy: 0.9068 - val_loss: 0.3000 - val_accuracy: 0.8850
Epoch 6/10
2500/2500 [==============================] - 12s 5ms/step - loss: 0.2482 - accuracy: 0.9162 - val_loss: 0.3219 - val_accuracy: 0.8700
Epoch 7/10
2500/2500 [==============================] - 12s 5ms/step - loss: 0.2314 - accuracy: 0.9217 - val_loss: 0.2410 - val_accuracy: 0.9100
Epoch 8/10
2500/2500 [==============================] - 12s 5ms/step - loss: 0.2142 - accuracy: 0.9294 - val_loss: 0.2480 - val_accuracy: 0.9000
Epoch 9/10
2500/2500 [==============================] - 12s 5ms/step - loss: 0.2022 - accuracy: 0.9328 - val_loss: 0.2728 - val_accuracy: 0.9050
Epoch 10/10
2500/2500 [==============================] - 12s 5ms/step - loss: 0.1896 - accuracy: 0.9378 - val_loss: 0.3014 - val_accuracy: 0.8600

このアプローチで私達のモデルはおよそ 88% の検証精度に到達します (モデルは overfitting していることに注意してください、訓練精度はかなり高いです)。

import matplotlib.pyplot as plt

history_dict = history.history

acc = history_dict['accuracy']
val_acc = history_dict['val_accuracy']
loss = history_dict['loss']
val_loss = history_dict['val_loss']

epochs = range(1, len(acc) + 1)

plt.figure(figsize=(12,9))
plt.plot(epochs, loss, 'bo', label='Training loss')
plt.plot(epochs, val_loss, 'b', label='Validation loss')
plt.title('Training and validation loss')
plt.xlabel('Epochs')
plt.ylabel('Loss')
plt.legend()
plt.show()

plt.figure(figsize=(12,9))
plt.plot(epochs, acc, 'bo', label='Training acc')
plt.plot(epochs, val_acc, 'b', label='Validation acc')
plt.title('Training and validation accuracy')
plt.xlabel('Epochs')
plt.ylabel('Accuracy')
plt.legend(loc='lower right')
plt.ylim((0.5,1))
plt.show()
<Figure size 1200x900 with 1 Axes>
<Figure size 1200x900 with 1 Axes>

 

学習された埋め込みを取得する

次に、訓練の間に学習された単語埋め込みを取得しましょう。これは shape (vocab_size,embedding-dimension) の行列です。

e = model.layers[0]
weights = e.get_weights()[0]
print(weights.shape) # shape: (vocab_size, embedding_dim)
(8185, 16)

今は重みをディスクに書きます。Embedding Projector を使用するには、タブ区切りフォーマットで 2 つのファイルをアップロードします : (埋め込みを含む) ベクトルのファイル、そして (単語を含む) メタデータのファイルです。

encoder = info.features['text'].encoder
import io

encoder = info.features['text'].encoder

out_v = io.open('vecs.tsv', 'w', encoding='utf-8')
out_m = io.open('meta.tsv', 'w', encoding='utf-8')

for num, word in enumerate(encoder.subwords):
  vec = weights[num+1] # skip 0, it's padding.
  out_m.write(word + "\n")
  out_v.write('\t'.join([str(x) for x in vec]) + "\n")
out_v.close()
out_m.close()

このチュートリアルを Colaboratory で実行している場合、これらのファイルを貴方のローカルマシンにダウンロードするために次のスニペットを使用できます (or ファイルブラウザを使用します、View -> Table of contents -> File browser)。

try:
  from google.colab import files
except ImportError:
   pass
else:
  files.download('vecs.tsv')
  files.download('meta.tsv')

 

埋め込みを可視化する

私達の埋め込みを可視化するには、それらを埋め込みプロジェクターにアップロードします。

Embedding Projector をオープンします (これはローカルの TensorBoard インスタンスでも実行できます)。

  • “Load data” をクリックする
  • 上で作成された 2 つのファイルをアップロードする : vecs.tsv と meta.tsv.

貴方が訓練した埋め込みが今表示されます。単語をそれらに最も近い近傍を見つけるために検索することができます。例えば、”beautiful” を検索してみてください。”wonderful” のような近傍を見るかもしれません。

Note: 埋め込み層を訓練する前に重みがどのようにランダムに初期化されたかに依拠して、貴方の結果は少し異なるかもしれません。

Note: 実験的に、より単純なモデルを使用してより解釈可能な埋め込みを生成できるかもしれません。Dense(16) 層を削除して、モデルを再訓練し、そして埋め込みを再度可視化してみてください。

 

Next steps

このチュートリアルは小さいデータセット上でスクラッチからどのように単語埋め込みを訓練して可視化するかを示しました。

  • リカレント・ニューラルネットワークについて学習するためには、Keras RNN ガイド を見てください。
  • テキスト分類について更に学習するためには (全体的なワークフローを含み、そしてもし貴方がいつ埋め込み vs one-hot エンコーディングを使用するかについて関心があれば)、この実践的なテキスト分類 ガイド を勧めます。
 

以上



TensorFlow 機械学習ガイド : テキスト分類 (3) データの準備 (前処理)

TensorFlow 機械学習ガイド : テキスト分類 (3) データの準備 (前処理) (翻訳/解説)

翻訳 : (株)クラスキャット セールスインフォメーション
作成日時 : 08/22/2018

* 本ページは、developers.google.com サイトの Machine Learning Guides : Text classification の以下のページを
翻訳した上で適宜、補足説明したものです:

* サンプルコードの動作確認はしておりますが、必要な場合には適宜、追加改変しています。
* ご自由にリンクを張って頂いてかまいませんが、sales-info@classcat.com までご一報いただけると嬉しいです。

 

Step 3: データを準備する

データがモデルに供給できる前に、それはモデルが理解できるフォーマットに変換される必要があります。

最初に、集めたデータ・サンプルは特別な順序にあるかもしれません。テキストとラベル間の関係に影響するサンプルの順序に関連するどのような情報も望みません。例えば、データセットがクラスでソートされてから訓練/検証セットに分割されている場合、これらのセットはデータの全体的な分布の見本にはなりません。

モデルがデータ順序に影響されないことを確実にする単純なベストプラクティスは他に何かする前にデータを必ずシャッフルすることです。もしデータが既に訓練と検証セットに分割されている場合には、訓練データを変換するのと同じ方法で検証データを変換することを確実にしてください。分離した訓練と検証セットをまだ持たない場合には、シャッフル後にサンプルを分割することもできます ; 典型的には訓練のためにサンプルの 80% をそして検証のために 20% を使用します。

2 番目に、機械学習アルゴリズムは入力として数字を取ります。これはテキストを数値ベクトルに変換する必要があることを意味します。このプロセスには 2 つのステップがあります :

  1. トークン化 (=Tokenization): テキストを単語かより小さい部分テキストに分割します、これはテキストとラベル間の関係の良い一般化を可能にします。これはデータセットの「語彙 (= vocabulary)」を決定します (データに現れる一意なトークンの集合)。
  2. ベクトル化: これらのテキストを特性化するために良い数値尺度を定義します。

n-gram ベクトルとシークエンス・ベクトルの両者のためのこれら 2 つのステップをどのように遂行するか、そして特徴選択と正規化技術を使用してどのようにベクトル表現を最適化するかを見ましょう。

 

N-gram ベクトル [オプション A]

次のパラグラフでは、n-gram モデルのためのトークン化とベクトル化をどのように行なうかを見ます。特徴選択と正規化技術を使用して n-gram 表現をどのように最適化できるかもまたカバーします。

n-gram ベクトルでは、テキストは一意な n-gram: n 隣接トークン (典型的には、単語) のコレクションとして表わされます。テキスト The mouse ran up the clock を考えます。ここで、単語 unigram (n=1) は [‘the’, ‘mouse’, ‘ran’, ‘up’, ‘clock’] で、単語 bigram (n = 2) は [‘the mouse’, ‘mouse ran’, ‘ran up’, ‘up the’, ‘the clock’]、等々。

 

トークン化

単語 unigram + bigram へのトークン化が良い精度を提供する一方で、より少ない計算時間しかかからないことを私達は見出しました。

 

ベクトル化

テキスト・サンプルを n-gram にひとたび分割したならば、これらの n-gram を機械学習モデルが処理できる数値ベクトルに変える必要があります。下のサンプルは 2 つのテキストのために生成された unigram と bigram に割り当てられたインデックスを示します。

Texts: 'The mouse ran up the clock' and 'The mouse ran down'
Index assigned for every token:
  {'the': 7, 'mouse': 2, 'ran': 4, 'up': 10, 'clock': 0, 'the mouse': 9, 'mouse ran': 3,
  'ran up': 6, 'up the': 11, 'the clock': 8, 'down': 1, 'ran down': 5}

ひとたびインデックスが n-gram に割り当てられれば、典型的には次のオプションを使用してベクトル化します。

One-hot エンコーディング: 総てのサンプルテキストはテキスト内のトークンの存在か欠如を示すベクトルとして現れます。

'The mouse ran up the clock' = [1, 0, 1, 1, 1, 0, 1, 1, 1, 1, 1, 1]

カウント・エンコーディング: 総てのサンプルテキストはテキスト内のトークンのカウントを示すベクトルとして表わされます。unigram ‘the’ に対応する要素は 2 として表わされることに注意してください、何故ならば単語 “the” はテキスト内に 2 度現れるからです。

'The mouse ran up the clock' = [1, 0, 1, 1, 1, 0, 1, 2, 1, 1, 1, 1]

Tf-idf エンコーディング: 上の 2 つのアプローチが持つ問題は総ての文書で同様の頻度で現れる一般的な単語 (i.e., データセットのテキストサンプルに特に固有ではない単語) にペナルティが与えられないことです。例えば、”a” のような単語は総てのテキストで非常に頻繁に現れます。そのため他の意味のある単語よりもより高い “the” に対するトークンカウントは大して有用ではありません。

'The mouse ran up the clock' = [0.33, 0, 0.23, 0.23, 0.23, 0, 0.33, 0.47, 0.33, 0.23, 0.33, 0.33]
(Scikit-learn TdidfTransformer 参照)

多くの他のベクトル表現がありますが、上の 3 つは最も一般的に使用されます。

tf-idf エンコーディングは他の 2 つよりも精度 (平均で: 0.25-15% higher) の点で僅かにより良いことを私達は観察し、そして n-gram のベクトル化にこのメソッドを使用することを勧めます。けれども、それはより多くのメモリを占有して (何故ならばそれは浮動小数点表現を使用しますので) 計算するためにより多くの時間がかかることに留意してください、特に巨大なデータセットについて (ある場合には 2 倍の長さがかかるかもしれません)。

 

特徴選択

データセットのテキストの総てを単語 uni+bigram トークンに変換するとき、数万のトークンという結果で終わるかもしれません。これらのトークン/特徴の総てがラベル予測に寄与するわけではありません。従って、特定のトークンを破棄することができます、例えばデータセットに渡り極めて稀にしか出現しないものです。特徴の重要性を測定することもでき (各トークンがラベル予測にどの程度寄与するか)、そして最も情報を与える (= informative) トークンだけを含むことができます。

特徴と対応するラベルを取り特徴重要性スコアを出力する多くの統計関数があります。2 つの一般に使用される関数は f_classifchi2 です。私達の実験はこれらの関数の両者が同等に良く遂行することを示します。

より重要なことは、多くのデータセットに対して精度は 20,000 特徴あたりでピークに達します (Figure 6 参照)。この閾値を越えてより多くの特徴を追加しても殆ど寄与せずそして時に overfitting に繋がってパフォーマンスが低下さえします。

★ ここでのテストでは英語テキストだけを使用しました。特徴の理想的な数は言語により変化するかもしれません ; これは補足解析で調査されるでしょう。

Figure 6: Top K 特徴 vs 精度。データセットに渡り、精度は top 20K 特徴あたりで平坦化します。

 

正規化

正規化は総ての特徴/サンプルの値を小さくて類似の値に変換します。これは学習アルゴリズムにおける勾配降下の収束を単純化します。私達が見たことからは、データ前処理の間の正規化はテキスト分類問題において大した値を追加しないように見えます ; このステップをスキップすることを勧めます。

 
◆ 次のコードは上のステップの総てをまとめています :

  • テキスト・サンプルを単語 uni+bigram にトークン化し、
  • tf-idf エンコーディングでベクトル化して、
  • 2 回より少なく出現するトークンを捨てて特徴重要性を計算するために f_classif を使用することによりトークンのベクトルから top 20,000 特徴だけを選択します。
from sklearn.feature_extraction.text import TfidfVectorizer
from sklearn.feature_selection import SelectKBest
from sklearn.feature_selection import f_classif

# Vectorization parameters
# Range (inclusive) of n-gram sizes for tokenizing text.
NGRAM_RANGE = (1, 2)

# Limit on the number of features. We use the top 20K features.
TOP_K = 20000

# Whether text should be split into word or character n-grams.
# One of 'word', 'char'.
TOKEN_MODE = 'word'

# Minimum document/corpus frequency below which a token will be discarded.
MIN_DOCUMENT_FREQUENCY = 2

def ngram_vectorize(train_texts, train_labels, val_texts):
    """Vectorizes texts as n-gram vectors.

    1 text = 1 tf-idf vector the length of vocabulary of unigrams + bigrams.

    # Arguments
        train_texts: list, training text strings.
        train_labels: np.ndarray, training labels.
        val_texts: list, validation text strings.

    # Returns
        x_train, x_val: vectorized training and validation texts
    """
    # Create keyword arguments to pass to the 'tf-idf' vectorizer.
    kwargs = {
            'ngram_range': NGRAM_RANGE,  # Use 1-grams + 2-grams.
            'dtype': 'int32',
            'strip_accents': 'unicode',
            'decode_error': 'replace',
            'analyzer': TOKEN_MODE,  # Split text into word tokens.
            'min_df': MIN_DOCUMENT_FREQUENCY,
    }
    vectorizer = TfidfVectorizer(**kwargs)

    # Learn vocabulary from training texts and vectorize training texts.
    x_train = vectorizer.fit_transform(train_texts)

    # Vectorize validation texts.
    x_val = vectorizer.transform(val_texts)

    # Select top 'k' of the vectorized features.
    selector = SelectKBest(f_classif, k=min(TOP_K, x_train.shape[1]))
    selector.fit(x_train, train_labels)
    x_train = selector.transform(x_train).astype('float32')
    x_val = selector.transform(x_val).astype('float32')
    return x_train, x_val

n-gram ベクトル表現では、単語順序と文法について多くの情報を捨てます (せいぜい、n > 1 の時にある程度の部分的な順序情報を維持できるだけです)。これは bag-of-words アプローチと呼ばれます。この表現はロジスティック回帰、多層パーセプトロン、勾配ブースティング・マシン、サポートベクターマシンのような、順序を考慮しないモデルと連携して使用されます。

 

シークエンス・ベクトル [オプション B]

次のパラグラフでは、シークエンス・モデルのためのトークン化とベクトル化をどのように行なうかを見ます。特徴選択と正規化技術を使用してシークエンス表現をどのように最適化できるかもまたカバーします。

あるテキスト・サンプルについては、単語順序はテキストの意味に対して重要です。例えば、センテンス “I used to hate my commute. My new bike changed that completely” は順序正しく読むことによってのみ理解可能です。CNN/RNN のようなモデルはサンプルの単語の順序から意味を推論できます。これらのモデルのためには、テキストを順序を保持して、トークンのシークエンスとして表します。

 

トークン化

テキストは文字のシークエンスか、単語のシークエンスとして表わされます。単語レベル表現の使用が文字トークンよりもより良いパフォーマンスを提供することを見出しました。これはまた業界で追随される一般的な規範です。文字トークンの使用はテキストが多くのタイポを持つ場合に限り意味があり、これは通常は当てはまりません。

 

ベクトル化

ひとたびテキスト・サンプルを単語のシークエンスに変換したならば、これらのシークエンスを数値ベクトルに変える必要があります。下の例は 2 つのテキストのために生成された unigram に割り当てられたインデックスと、それから最初のテキストが変換されたトークン・インデックスのシークエンスです。

Texts: 'The mouse ran up the clock' and 'The mouse ran down'
Index assigned for every token: {'clock': 5, 'ran': 3, 'up': 4, 'down': 6, 'the': 1, 'mouse': 2}.
NOTE: 'the' occurs most frequently, so the index value of 1 is assigned to it.
Some libraries reserve index 0 for unknown tokens, as is the case here.
Sequence of token indexes: 'The mouse ran up the clock' = [1, 2, 3, 4, 1, 5]

トークン・シークエンスをベクトル化するために利用可能な 2 つのオプションがあります。

One-hot エンコーディング: シークエンスは n-次元空間の単語ベクトルを使用して表わされます、ここでn = 語彙のサイズです。この表現は文字としてトークン化しているとき、そして従って語彙が小さいときに素晴らしく動作します。単語としてトークン化しているときは、語彙は通常は数万のトークンを持ち、one-hot ベクトルを非常にスパースで非効率にします。例えば :

'The mouse ran up the clock' = [
  [0, 1, 0, 0, 0, 0, 0],
  [0, 0, 1, 0, 0, 0, 0],
  [0, 0, 0, 1, 0, 0, 0],
  [0, 0, 0, 0, 1, 0, 0],
  [0, 1, 0, 0, 0, 0, 0],
  [0, 0, 0, 0, 0, 1, 0]
]

単語埋め込み (= Word embeddings): 単語はそれらに関係する意味を持ちます。結果として、単語トークンを密ベクトル空間 (~ 数百の実数) 内で表わすことができます、そこでは位置と単語間の距離はそれらが意味的にどのように類似しているかを示します (Figure 7 参照)。この表現は単語埋め込み (= word embeddings)と呼ばれます。

Figure 7: 単語埋め込み (= Word embeddings)

 
シークエンス・モデルは最初の層としてそのような埋め込み層をしばしば持ちます。この層は訓練プロセスの間に単語インデックス・シークエンスを単語埋め込みベクトルに変えることを学習します、各単語インデックスが意味空間の単語の位置を表わす実数の密ベクトルにマップされるようにです (Figure 8 参照)。

Figure 8: 埋め込み層 (= Embedding layer)

 

特徴選択

データの総ての単語がラベル予測に寄与するわけではありません。語彙から稀だったり重要でない単語を捨てることで学習プロセスを最適化できます。実際に、最も頻度の高い 20,000 特徴の使用が一般に十分であることを私達は観察しました。これは n-gram モデルに対しても事実です (Figure 6 参照)。

シークエンス・ベクトル化の上のステップの総てをまとめましょう。次のコードはこれらのタスクを遂行します :

  • テキストを単語にトークン化する
  • top 20,000 トークンを使用して語彙を作成する
  • トークンをシークエンス・ベクトルに変換する
  • シークエンスを固定されたシークエンス長にパッドする
from tensorflow.python.keras.preprocessing import sequence
from tensorflow.python.keras.preprocessing import text

# Vectorization parameters
# Limit on the number of features. We use the top 20K features.
TOP_K = 20000

# Limit on the length of text sequences. Sequences longer than this
# will be truncated.
MAX_SEQUENCE_LENGTH = 500

def sequence_vectorize(train_texts, val_texts):
    """Vectorizes texts as sequence vectors.

    1 text = 1 sequence vector with fixed length.

    # Arguments
        train_texts: list, training text strings.
        val_texts: list, validation text strings.

    # Returns
        x_train, x_val, word_index: vectorized training and validation
            texts and word index dictionary.
    """
    # Create vocabulary with training texts.
    tokenizer = text.Tokenizer(num_words=TOP_K)
    tokenizer.fit_on_texts(train_texts)

    # Vectorize training and validation texts.
    x_train = tokenizer.texts_to_sequences(train_texts)
    x_val = tokenizer.texts_to_sequences(val_texts)

    # Get max sequence length.
    max_length = len(max(x_train, key=len))
    if max_length > MAX_SEQUENCE_LENGTH:
        max_length = MAX_SEQUENCE_LENGTH

    # Fix sequence length to max value. Sequences shorter than the length are
    # padded in the beginning and sequences longer are truncated
    # at the beginning.
    x_train = sequence.pad_sequences(x_train, maxlen=max_length)
    x_val = sequence.pad_sequences(x_val, maxlen=max_length)
    return x_train, x_val, tokenizer.word_index

 

ラベルのベクトル化

サンプルのテキストデータをどのように数値ベクトルに変換するかを見ました。同様のプロセスはラベルに適用されなければなりません。ラベルを範囲 [0, num_classes – 1] の値に単純に変換できます。例えば、3 クラスがあれば、それらを表わすために値 0, 1 と 2 を単に使用できます。内部的には、ネットワークはこれらの値を表わすために one-hot ベクトルを使用します (ラベル間の間違った関係を推定することを回避するため)。この表現はネットワークで使用する損失関数と最後の層の活性化関数に依拠します。これらについての次のセクションで更に学習します。

 

以上



TensorFlow (Hub) : Tutorials : ML at production scale : TF-Hub によるテキスト分類器の構築

TensorFlow (Hub) : Tutorials : ML at production scale : TF-Hub によるテキスト分類器の構築 (翻訳/解説)

翻訳 : (株)クラスキャット セールスインフォメーション
更新日時 : 07/16/2018 (v1.9)
作成日時 : 04/06/2018

* TensorFlow 1.9 でドキュメント構成が変わりましたので調整しました。
* 本ページは、TensorFlow の本家サイトの Tutorials – ML at production scale – How to build a simple text classifier with TF-Hub を
翻訳した上で適宜、補足説明したものです:

* ご自由にリンクを張って頂いてかまいませんが、sales-info@classcat.com までご一報いただけると嬉しいです。

 

無料セミナー開催中 クラスキャット主催 人工知能 & ビジネス Web セミナー

人工知能とビジネスをテーマにウェビナー (WEB セミナー) を定期的に開催しています。スケジュールは弊社 公式 Web サイト でご確認頂けます。
  • お住まいの地域に関係なく Web ブラウザからご参加頂けます。事前登録 が必要ですのでご注意ください。
  • Windows PC のブラウザからご参加が可能です。スマートデバイスもご利用可能です。

お問合せ : 本件に関するお問い合わせ先は下記までお願いいたします。

株式会社クラスキャット セールス・マーケティング本部 セールス・インフォメーション
E-Mail:sales-info@classcat.com ; WebSite: https://www.classcat.com/
Facebook: https://www.facebook.com/ClassCatJP/

 

 

TF-Hub は再利用可能なリソース、特に事前訓練された モジュール にパッケージングされた機械学習の専門技術を共有するためのプラットフォームです。このチュートリアルは2つの主要パートに体系化されます。

イントロダクション : TF-Hub でテキスト分類器を訓練する

合理的なベースラインの精度を持つ単純な感情分析器 (= sentiment classifier) を訓練するために TF-Hub テキスト埋め込みモジュールを利用します。それから私達のモデルが合理的であることを確認して精度を増すための改良を提案するために予測を解析します。

上級 : 転移学習解析

このセクションでは、estimator の精度上の効果を比較して転移学習の優位点と落とし穴を示すために各種の TF-Hub モジュールを使用します。

 

Getting started

データ

Mass et al からの Large Movie Review Dataset v1.0 タスクを解いてみます。データセットは 1 から 10 の正値によりラベル付けされた IMDB 映画レビューから成ります。タスクはレビューを negative か positive としてラベル付けすることです。

# Load all files from a directory in a DataFrame.
def load_directory_data(directory):
  data = {}
  data["sentence"] = []
  data["sentiment"] = []
  for file_path in os.listdir(directory):
    with tf.gfile.GFile(os.path.join(directory, file_path), "r") as f:
      data["sentence"].append(f.read())
      data["sentiment"].append(re.match("\d+_(\d+)\.txt", file_path).group(1))
  return pd.DataFrame.from_dict(data)

# Merge positive and negative examples, add a polarity column and shuffle.
def load_dataset(directory):
  pos_df = load_directory_data(os.path.join(directory, "pos"))
  neg_df = load_directory_data(os.path.join(directory, "neg"))
  pos_df["polarity"] = 1
  neg_df["polarity"] = 0
  return pd.concat([pos_df, neg_df]).sample(frac=1).reset_index(drop=True)

# Download and process the dataset files.
def download_and_load_datasets(force_download=False):
  dataset = tf.keras.utils.get_file(
      fname="aclImdb.tar.gz", 
      origin="http://ai.stanford.edu/~amaas/data/sentiment/aclImdb_v1.tar.gz", 
      extract=True)

  train_df = load_dataset(os.path.join(os.path.dirname(dataset), 
                                       "aclImdb", "train"))
  test_df = load_dataset(os.path.join(os.path.dirname(dataset), 
                                      "aclImdb", "test"))

  return train_df, test_df

# Reduce logging output.
tf.logging.set_verbosity(tf.logging.ERROR)

train_df, test_df = download_and_load_datasets()
train_df.head()
    Downloading data from http://ai.stanford.edu/~amaas/data/sentiment/aclImdb_v1.tar.gz
    84131840/84125825 [==============================] - 1s 0us/step
    84140032/84125825 [==============================] - 1s 0us/step

感情

極性

0

I just rented this today….heard lots of good…

1

0

1

Outrage is pretty good movie! Robert Culp was …

10

1

2

OK, as everyone has pointed out, this film is …

3

0

3

I am a current A.S.L. Student & was forced to …

4

0

4

Redundant, but again the case. If you enjoy th…

2

0

 

モデル

入力関数

Estimator フレームワーク は Pandas データフレームをラップする 入力関数 を提供します。

# Training input on the whole training set with no limit on training epochs.
train_input_fn = tf.estimator.inputs.pandas_input_fn(
    train_df, train_df["polarity"], num_epochs=None, shuffle=True)

# Prediction on the whole training set.
predict_train_input_fn = tf.estimator.inputs.pandas_input_fn(
    train_df, train_df["polarity"], shuffle=False)
# Prediction on the test set.
predict_test_input_fn = tf.estimator.inputs.pandas_input_fn(
    test_df, test_df["polarity"], shuffle=False)

 

特徴カラム

TF-Hub は、与えられたテキスト特徴上にモデルを適用して更にモジュールの出力を渡すような特徴カラムを提供します。このチュートリアルでは nnlm-en-dim128 モジュールを使用していきます。このチュートリアルの目的のために、最重要な事実は :

  • モジュールは入力として文字列の 1-D tensor の文のバッチを取ります。
  • モジュールは文の前処理に責任を負います (e.g. 句読点の除去とスペース上の分割)。
  • モジュールは任意の入力で動作します (e.g. nnlm-en-dim128 は語彙にない単語を ~20.000 バケツにハッシュします)。
embedded_text_feature_column = hub.text_embedding_column(
    key="sentence", 
    module_spec="https://tfhub.dev/google/nnlm-en-dim128/1")

 

Estimator

分類のために DNN Classifier を利用できます。

estimator = tf.estimator.DNNClassifier(
    hidden_units=[500, 100],
    feature_columns=[embedded_text_feature_column],
    n_classes=2,
    optimizer=tf.train.AdagradOptimizer(learning_rate=0.003))

 

訓練

合理的なステップ総量のために estimator を訓練します。

# Training for 1,000 steps means 128,000 training examples with the default
# batch size. This is roughly equivalent to 5 epochs since the training dataset
# contains 25,000 examples.
estimator.train(input_fn=train_input_fn, steps=1000);

 

予測

訓練とテストセットの両者に対して予測を実行します。

train_eval_result = estimator.evaluate(input_fn=predict_train_input_fn)
test_eval_result = estimator.evaluate(input_fn=predict_test_input_fn)

print "Training set accuracy: {accuracy}".format(**train_eval_result)
print "Test set accuracy: {accuracy}".format(**test_eval_result)
    Training set accuracy: 0.802160024643
    Test set accuracy: 0.792879998684

 

混同行列

誤分類の分布を理解するために混同行列を視覚的にチェックできます。

def get_predictions(estimator, input_fn):
  return [x["class_ids"][0] for x in estimator.predict(input_fn=input_fn)]

LABELS = [
    "negative", "positive"
]

# Create a confusion matrix on training data.
with tf.Graph().as_default():
  cm = tf.confusion_matrix(train_df["polarity"], 
                           get_predictions(estimator, predict_train_input_fn))
  with tf.Session() as session:
    cm_out = session.run(cm)

# Normalize the confusion matrix so that each row sums to 1.
cm_out = cm_out.astype(float) / cm_out.sum(axis=1)[:, np.newaxis]

sns.heatmap(cm_out, annot=True, xticklabels=LABELS, yticklabels=LABELS);
plt.xlabel("Predicted");
plt.ylabel("True");

 

更なる改良

  1. 感情上の回帰 : 各サンプルを極性クラスに割り当てるために分類器を使用しました。しかし私達は実際にはもう一つの利用可能なカテゴリカルな特徴を持ちます – 感情です。ここでクラスは実際にスケールを表して基礎値 (positive/negative) は連続的な範囲に上手くマップされるでしょう。分類 (DNN Classifier) の代わりに回帰 (DNN Regressor) を計算することでこのプロパティを活用できるでしょう。
  2. より巨大なモジュール : このチュートリアルのためにはメモリ消費を制限するために小さいモジュールを使用しました。より巨大な語彙と巨大な埋め込み空間を持つモジュールがあり、これらは追加の精度ポイントを与えるでしょう。
  3. パラメータ調整 : 学習率やステップ数のようなメタ・パラメータの調整により精度を改善できます、特に異なるモジュールを利用する場合にです。もし合理的な結果を得ることを望むのであれば検証セットは非常に重要です、何故ならばテストセットに上手く一般化することなしに訓練データを予測することを学習するモデルをセットアップすることは非常に容易だからです。
  4. より複雑なモデル : 各個々の単語を埋め込みそしてそれらを平均と結合することにより文埋め込みを計算するモジュールを使用しました。文の性質をより良く捕捉する sequential モジュール (e.g. Universal Sentence Encoder モジュール) もまた利用できます。あるいは2つかそれ以上の TF-Hub モジュールのアンサンブルです。
  5. 正則化 : overfitting を回避するためにある種の正則化を行なう optimizer を使用してみることができます、例えば Proximal Adagrad Optimizer です。

 

上級 : 転移学習解析

転移学習は訓練リソースをセーブして小さいデータセット上で訓練するときでさえも良いモデルの一般化を獲得することを可能にします。このパートでは、2つの異なる TF-Hub モジュールで訓練することによりこれを示します :

  • nnlm-en-dim128 – 事前訓練されたテキスト埋め込みモジュール、
  • random-nnlm-en-dim128 – テキスト埋め込みモジュール、これは nnlm-en-dim128 と同じ語彙とネットワークを持ちますが、重みは単にランダムに初期化されて実際のデータ上では決して訓練されていません。

そして2つのモードで訓練します :

  • 分類器のみを訓練する (i.e. モジュールはフリーズしています)、そして
  • モジュールと一緒に分類器を訓練する。

各種モジュールの使用がどのように精度に影響を与えられるかを見るために2つの訓練と評価を実行してみましょう。

def train_and_evaluate_with_module(hub_module, train_module=False):
  embedded_text_feature_column = hub.text_embedding_column(
      key="sentence", module_spec=hub_module, trainable=train_module)

  estimator = tf.estimator.DNNClassifier(
      hidden_units=[500, 100],
      feature_columns=[embedded_text_feature_column],
      n_classes=2,
      optimizer=tf.train.AdagradOptimizer(learning_rate=0.003))

  estimator.train(input_fn=train_input_fn, steps=1000)

  train_eval_result = estimator.evaluate(input_fn=predict_train_input_fn)
  test_eval_result = estimator.evaluate(input_fn=predict_test_input_fn)

  training_set_accuracy = train_eval_result["accuracy"]
  test_set_accuracy = test_eval_result["accuracy"]

  return {
      "Training accuracy": training_set_accuracy,
      "Test accuracy": test_set_accuracy
  }

results = {}
results["nnlm-en-dim128"] = train_and_evaluate_with_module(
    "https://tfhub.dev/google/nnlm-en-dim128/1")
results["nnlm-en-dim128-with-module-training"] = train_and_evaluate_with_module(
    "https://tfhub.dev/google/nnlm-en-dim128/1", True)
results["random-nnlm-en-dim128"] = train_and_evaluate_with_module(
    "https://tfhub.dev/google/random-nnlm-en-dim128/1")
results["random-nnlm-en-dim128-with-module-training"] = train_and_evaluate_with_module(
    "https://tfhub.dev/google/random-nnlm-en-dim128/1", True)

結果を見てみましょう。

pd.DataFrame.from_dict(results, orient="index")

訓練精度

テスト精度

nnlm-en-dim128

0.80176

0.79324

nnlm-en-dim128-with-module-training

0.94912

0.86996

random-nnlm-en-dim128

0.72244

0.67456

random-nnlm-en-dim128-with-module-training

0.76584

0.72180

既にあるパターンを見ることができますが、最初にテストセットのベースライン精度を確立するべきです – 下界は最も代表的なクラスのラベルだけを出力することで獲得できます :

estimator.evaluate(input_fn=predict_test_input_fn)["accuracy_baseline"]
0.5

最も代表的なクラスの割り当ては 50 % の精度を与えます。ここに気付くべき 2, 3 のことがあります :

  1. 多分驚くことに、モデルは固定された、ランダム埋め込みの上でも依然として学習できます。その理由は辞書の総ての単語がランダム・ベクトルにマップされた場合でさえも、estimator はその完全結合層を純粋に使用して空間を分割することができるからです。
  2. ランダム埋め込みを持つモジュールの訓練を許せば分類器だけの訓練とは反対に訓練とテスト精度の両者を増大します。
  3. 事前訓練された埋め込みを持つモジュールの訓練もまた両者の精度を増大させます。けれども訓練セット上の overfitting には注意してください。事前訓練されたモジュールの訓練は正則化をもってさえも危険であるかもしれません。埋め込み重みはもはや多様なデータ上で訓練された言語モデルを表しておらず、代わりにそれらは新しいデータセットの理想的な表現に収束するという意味でです。
 

以上



TensorFlow : Guide : ML Concepts : 埋め込み (Embedding)

TensorFlow : Guide : ML Concepts : 埋め込み (Embedding) (翻訳/解説)

翻訳 : (株)クラスキャット セールスインフォメーション
更新日時 : 07/14/2018
作成日時 : 09/10/2017

* 本ページは、TensorFlow 本家サイトの Guide – ML Concepts – Embedding を翻訳した上で
適宜、補足説明したものです:

* サンプルコードの動作確認はしておりますが、適宜、追加改変している場合もあります。
* ご自由にリンクを張って頂いてかまいませんが、sales-info@classcat.com までご一報いただけると嬉しいです。

 

無料セミナー開催中 クラスキャット主催 人工知能 & ビジネス Web セミナー

人工知能とビジネスをテーマにウェビナー (WEB セミナー) を定期的に開催しています。スケジュールは弊社 公式 Web サイト でご確認頂けます。
  • お住まいの地域に関係なく Web ブラウザからご参加頂けます。事前登録 が必要ですのでご注意ください。
  • Windows PC のブラウザからご参加が可能です。スマートデバイスもご利用可能です。

お問合せ : 本件に関するお問い合わせ先は下記までお願いいたします。

株式会社クラスキャット セールス・マーケティング本部 セールス・インフォメーション
E-Mail:sales-info@classcat.com ; WebSite: https://www.classcat.com/
Facebook: https://www.facebook.com/ClassCatJP/

 

イントロダクション

埋め込み (= embedding) は単語のような離散的な (= discrete, 別々の) オブジェクトから実数のベクトルへのマッピングです。例えば、英単語のための 300-次元埋め込みは以下を含むかもしれません :

blue:  (0.01359, 0.00075997, 0.24608, ..., -0.2524, 1.0048, 0.06259)
blues:  (0.01396, 0.11887, -0.48963, ..., 0.033483, -0.10007, 0.1158)
orange:  (-0.24776, -0.12359, 0.20986, ..., 0.079717, 0.23865, -0.014213)
oranges:  (-0.35609, 0.21854, 0.080944, ..., -0.35413, 0.38511, -0.070976)

埋め込みは離散した入力に機械学習を適用させてくれます。分類器、そしてより一般的にニューラルネットワークは密で連続的なベクトルで動作するように設計されています、そこではすべての値がオブジェクトが何であるかを定義するために寄与します。もし離散的なオブジェクトが離散的なアトム、e.g., 一意な id 数、として素朴にエンコードされるのであれば、それらは学習と一般化を阻害するでしょう。埋め込みを考える一つの方法はベクトルでないオブジェクトを機械学習のための有用な入力に変換する手段としてです。

埋め込みはまた機械学習の出力としても有用です。埋め込みはオブジェクトをベクトルにマップしますので、アプリケーションはベクトル空間における類似性 (e.g., ユークリッド距離やベクトル間の角度) をオブジェクトの類似性の堅牢で柔軟な尺度として利用できます。一つの共通的な利用方法は最近傍を見つけることです。上の同じ単語埋め込み (word embeddings) を使えば、例えば、各単語に対して3つの最近傍と相当する角度 (度単位) がここにあります :

blue:  (red, 47.6°), (yellow, 51.9°), (purple, 52.4°)
blues:  (jazz, 53.3°), (folk, 59.1°), (bluegrass, 60.6°)
orange:  (yellow, 53.5°), (colored, 58.0°), (bright, 59.9°)
oranges:  (apples, 45.3°), (lemons, 48.3°), (mangoes, 50.4°)

これはアプリケーションに、(45.3° 離れている) りんごとオレンジはある意味では (48.3° 離れている) レモンとオレンジよりも類似していることを伝えているでしょう。

 

埋め込みを訓練する

TensorFlow で単語埋め込みを訓練するためには、最初にテキストを単語(群)に分割して語彙の総ての単語に整数を割り当てる必要があります。これは既に行われたとし、word_ids はこれらの整数のベクトルだと仮定しましょう。例えば、文 “I have a cat.” は [“I”, “have”, “a”, “cat”, “.”] に分割されてそして相当する word_ids テンソルは shape [5] を持ち5つの整数から成ります。これらの word ids を埋め込むためには、次のように embedding variable を作成してtf.gather 関数を使用する必要があります :

word_embeddings = tf.get_variable(“word_embeddings”,
    [vocabulary_size, embedding_size])
embedded_word_ids = tf.gather(word_embeddings, word_ids)

この後、テンソル embedded_word_ids は私たちの例では shape [5, embedding_size] を持ち5つの単語のそれぞれに対する埋め込み (密ベクトル) を含みます。variable word_embeddings は学習されて訓練の最後には語彙の総ての単語に対する埋め込みを含みます。埋め込みは多くの方法で訓練できます、利用可能なデータに依存して。例えば、文の巨大なコーパスが与えられた場合、前の一つから次の単語を予想するためにリカレント・ニューラルネットワークを使用できるでしょう、あるいは多言語翻訳を行なうために2つのネットワークを訓練できるでしょう。これらのメソッドは 単語のベクタ表現・チュートリアル で説明されていますが、しかし総ての場合において上のような embedding variable があり、示したように、単語は tf.gather を使用して埋め込まれます。

 

埋め込みを可視化する

TensorBoard は、Embedding Projector (埋め込み投射器) と呼ばれる、埋め込みの対話的な可視化のための組み込みのビジュアライザーを持ちます。embedding projector は貴方のチェックポイント・ファイルから埋め込みを読み込みそしてそれらを 主成分分析 を使用して 3-次元に射影します。PCA の視覚的表現については、この記事 を見てください。貴方が利用できる他の非常に有用な射影は t-SNE です。

埋め込みで作業しているのであれば、データポイントにラベル/画像をアタッチすることを多分望むでしょう。各ポイントのラベルを含む メタデータ・ファイル を生成してそして Python API を使用するか手動で projector_config.pbtxt をチェックポイントと同じディレクトリに構築して保存するかをして projector を構成することによってこれを行なうことができます。

セットアップ

TensorBoard をどのように実行して必要な情報の総てをロギングしているかをどのように確かなものにするかについての徹底した情報は TensorBoard: 学習を視覚化する を見てください。

貴方の埋め込みを可視化するには、貴方が行なう必要がある3つのことがあります :

1) 貴方の埋め込みを保持する 2D テンソルをセットアップする。

embedding_var = tf.get_variable(....)

2) 定期的に貴方のモデル variable を LOG_DIR のチェックポイントに保存する。

saver = tf.train.Saver()
saver.save(session, os.path.join(LOG_DIR, "model.ckpt"), step)

3) (オプション) メタデータを貴方の埋め込みと関連付ける。

貴方の埋め込みに関連する任意のメタデータ (レベル、画像) を持つ場合、直接 LOG_DIR の projector_config.pbtxt (訳注: projector_config.proto) を保存するか、あるいは Python API を使用することで TensorBoard にそれについて知らせることができます。

例えば、次の projector_config.ptxt (訳注: 原文まま) は word_embedding テンソルを $LOG_DIR/metadata.tsv にストアされている metadata と関連付けます :

embeddings {
  tensor_name: 'word_embedding'
  metadata_path: '$LOG_DIR/metadata.tsv'
}

同じ config は次のコード・スニペットを使ってプログラムで生成できます :

from tensorflow.contrib.tensorboard.plugins import projector

# Create randomly initialized embedding weights which will be trained.
vocabulary_size = 10000
embedding_size = 200
embedding_var = tf.get_variable('word_embedding', [vocabulary_size, embedding_size])

# Format: tensorflow/tensorboard/plugins/projector/projector_config.proto
config = projector.ProjectorConfig()

# You can add multiple embeddings. Here we add only one.
embedding = config.embeddings.add()
embedding.tensor_name = embedding_var.name
# Link this tensor to its metadata file (e.g. labels).
embedding.metadata_path = os.path.join(LOG_DIR, 'metadata.tsv')

# Use the same LOG_DIR where you stored your checkpoint.
summary_writer = tf.summary.FileWriter(LOG_DIR)

# The next line writes a projector_config.pbtxt in the LOG_DIR. TensorBoard will
# read this file during startup.
projector.visualize_embeddings(summary_writer, config)

モデルを実行して埋め込みを訓練した後、TensorBoard を実行してそれにジョブの LOG_DIR をポイントさせてください。

tensorboard --logdir=LOG_DIR

それからトップ・ペインの Embeddings タブ上をクリックして適切な run を選択してください (もし一つ以上の run があれば)。

メタデータ

通常は埋め込みはそれに関連づけられたメタデータを持ちます (e.g. ラベル、画像)。メタデータはモデル・チェックポイントの外の別のファイルにストアされるべきです、何故ならばメタデータはモデルの訓練パラメータではないからです。フォーマットは最初の行がカラム・ヘッダ (ボールドで示されます) を含み続く行がメタデータ値を含む TSV ファイル (タブ・キャラクタは赤色で示されます) であるべきです :

Word\tFrequency
Airplane\t345
Car\t241

 
メインのデータファイルと共有される明示的なキーはありません; 代わりに、メタデータ・ファイルの順序は埋め込みテンソルの順序とマッチすることが仮定されています。換言すれば、最初の行はヘッダ情報でメタデータファイルの (i+1)-th 行は、チェックポイントの埋め込みテンソルの i-th 行に相当します。

Note:
TSV メタデータファイルが単一のカラムだけを持つならば、ヘッダ行を期待せずに、そして各行が埋め込みのラベルと仮定します。この例外を含むのは、一般に使用される “vocab file” フォーマットにに適合するからです。

画像

貴方の埋め込みに関連付けられた画像を持つのであれば、各データポイントの小さいサムネイルからなる単一の画像を生成する必要があるでしょう。これは スプライト画像 として知られています。スプライトは row-first 順でストアされたサムネイルで行とカラムの同じ数を持つべきです : 最初のデータポイントは左上隅に置かれて最後のデータポイントは右下隅です :

0 1 2
3 4 5
6 7  

上の例で最後の行は満たされる必要はありません。スプライトの具体的な例として、10,000 MNIST 数字 (100×100) の このスプライト画像 を見てください。

Note: 現時点では 8192px X 8192px までのスプライトをサポートしています。

(訳注: 参考のため MNIST のスプライト画像を張り付けておきます : )

スプライトを作成したら、Embedding Projector にそれをどこで見つけるか知らせる必要があります :

embedding.sprite.image_path = PATH_TO_SPRITE_IMAGE
# Specify the width and height of a single thumbnail.
embedding.sprite.single_image_dim.extend([w, h])

相互作用

Embedding Projector は3つのパネルを持ちます :

  1. 左上のデータ・パネル、ここでは彩色してポイントにラベル付けするための run (= 実行)、埋め込みテンソルそしてデータカラムを選択できます。
  2. 左下の Projections パネル、ここでは射影 (e.g. PCA, t-SNE) のタイプを選択します。
  3. 右側の Inspector パネル、ここでは特定のポイントを検索して最近傍のリストが見れます。

射影

Embedding Projector はデータセットの次元を削減する3つのメソッドを持ちます : 2つの線形と一つの非線形です。各メソッドは 2- または 3-次元ビューを作成するために使用できます。

主成分分析 次元を削減するための率直なテクニックは 主成分分析 (Principal Component Analysis, PCA) です。Embedding Projector は top 10 主成分を計算します。メニューは貴方にこれらの成分を2つまたは3つの任意の結合に射影させることを可能にします。PCA は線形射影で、大域的な幾何学を検証するのに効果的です。

t-SNE 人気のある非線形次元削減テクニックが t-SNE です。Embedding Projector は 2- と 3-次元両者の t-SNE ビューを提供します。アルゴリズムの各ステップでクライアント側アニメーティングでレイアウトが実行されます。t-SNE はしばしば何某かのローカル構造を保存するので、ローカル近傍の探索とクラスタを見つけるために有用です。高次元データの可視化に非常に有用ですが、t-SNE プロットは時々怪しげ (= mysterious) で誤解させやすいです。”how to use t-SNE effectively (t-SNE をどのように効果的に使用するか)” についてのこの 優れた記事 を見てください。

カスタム 空間における意味のある方向性を見つけるためにテキスト検索に基づく特殊な線形射影を構築することもできます。射影軸を定義するためには、2つの検索文字列または正規表現を入力してください。プログラムは (ポイントの) ラベルがこれらの検索に適合するポイントのセットの重心を計算し、射影軸としての重心間の差分ベクトルを使用します。

ナビゲーション

データセットを探求するために、2D または 3D モードで、自然なクリック & ドラッグという行動を使用してビューをズーム、回転、そしてパンにナビゲートすることができます。ポイントをクリックすると右ペインに最近傍の明示的な textual リストが現在のポイントへの距離と共に表示されます。最近傍ポイントそれ自体は射影上でハイライトされます。

クラスタにズームすることは何某かの情報を与えますが、ポイントのサブセットにビューを制限してそれらのポイント上だけで射影を実行することは時々更に有用です。それを行なうために、複数の方法でポイントを選択できます :

  1. ポイント上をクリック後、その最近傍もまた選択されます。
  2. 検索後、クエリーにマッチするポイントが選択されます。
  3. selection を有効にして、ポイント上をクリックしてドラッグすることは選択球 (= selection sphere) を定義します。

ポイントのセットの選択後、それらのポイントをそれら自身の上の更なる解析のために右側の Inspector ペインの “Isolate Points” ボタンで分離することができます。
 



単語埋め込みデータセットで “important” の最近傍の選択

カスタム射影によるフィルタリングの組み合わせはパワフルです。下で、私たちは “politics” の 100 最近傍をフィルタしてそれらを x 軸として “best” – “worst” ベクトルに射影しました。y 軸はランダムです。

右側には “ideas”, “science”, “perspective”, “journalism” を持ち、その一方左側では “crisis”, “violence” を “conflict” を持つことが見れます。

カスタム射影コントロール。

“politics” の近傍の “best” – “worst” ベクトルへのカスタム射影。

共同的な特徴

貴方の発見を共有するために、右下隅の bookmark パネルを使用して現在の (任意の射影の計算された座標を含む) 状態を小さいファイルに保存することができます。それから Projector はこれらのファイルの一つまたはそれ以上のセットにポイントされることが可能で、下のパネルを生成します。そして他のユーザはブックマークのシークエンスを通り歩くことができます。

 

Mini-FAQ

“埋め込み” は action ですか thing ですか? 両者です。人々はベクトル空間に単語を埋め込む (action) ことについてそして単語埋め込み (things) を生成することについて話します。両者に共通なのは離散したオブジェクトからベクトルへのマッピングとしての埋め込みの概念です。そのマッピングを作成または適用することは action ですが、マッピングそれ自身は thing です。

埋め込みは高次元ですか低次元ですか? 場合によります。単語と句の 300-次元ベクトル空間は、例えばですが、それが含むことができる数百万の単語と句と比較した時にはしばしば低次元 (そして密) と呼ばれます。しかし数学的にはそれは高次元で、人間の直感が 2- と 3- 次元空間について学ぶものとは劇的に異なる多くの特性を表示します。

埋め込みは埋め込み層と同じですか ? いいえ; 埋め込み層はニューラルネットワークの一部ですが、埋め込みはより一般的な概念です。

 
以上



AI導入支援 #2 ウェビナー

スモールスタートを可能としたAI導入支援   Vol.2
[無料 WEB セミナー] [詳細]
「画像認識 AI PoC スターターパック」の紹介
既に AI 技術を実ビジネスで活用し、成果を上げている日本企業も多く存在しており、競争優位なビジネスを展開しております。
しかしながら AI を導入したくとも PoC (概念実証) だけでも高額な費用がかかり取組めていない企業も少なくないようです。A I導入時には欠かせない PoC を手軽にしかも短期間で認知度を確認可能とするサービの紹介と共に、AI 技術の特性と具体的な導入プロセスに加え運用時のポイントについても解説いたします。
日時:2021年10月13日(水)
会場:WEBセミナー
共催:クラスキャット、日本FLOW(株)
後援:働き方改革推進コンソーシアム
参加費: 無料 (事前登録制)
人工知能開発支援
◆ クラスキャットは 人工知能研究開発支援 サービスを提供しています :
  • テクニカルコンサルティングサービス
  • 実証実験 (プロトタイプ構築)
  • アプリケーションへの実装
  • 人工知能研修サービス
◆ お問合せ先 ◆
(株)クラスキャット
セールス・インフォメーション
E-Mail:sales-info@classcat.com