今日も窓辺でプログラム

外資系企業勤めのエンジニアが勉強した内容をまとめておくブログ

TensorBoardのEmbedding Visualizationで単語ベクトルたちを可視化してみる

はじめに

TensorFlowの0.12から、Embedding Visualizationという機能が追加されました。
単語や画像などを表現しているベクトルを可視化するためのツールです。

公式サイトの説明ページを開いてみてください。Embeddingが3次元空間にきれいに可視化されていて、しかもそれをマウスで自由に動かせる様子が見て取れます。

今回は、以前word2vecの手法で学習した単語ベクトルたちをEmbedding Visualizaationを使って可視化してみようと思います。

前提

下記の記事で実装したコードをそのまま使います。
今回の記事だけでコードが理解できない場合は、こちらの記事を読んでみてください。
www.madopro.net

上の記事では、小さなコーパスをもとに100次元の単語ベクトルを学習しました。
そのときはmatplotlibで可視化して、こんな感じのグラフを出力したりしていました。

必要なのは3つの変更だけ

Embedding visualizationを使うには、3つのステップが必要になります。

  1. 単語ベクトルの変数を用意する
  2. ログフォルダにモデルを保存する
  3. 可視化時に使うメタデータ(ラベルや画像など)を指定する

コード量にすると、GitHubの変更履歴を見てもらうと分かる通り、20行もないくらいです。

では、3つの変更について、1つずつ見ていきます。

単語ベクトル用の変数を用意

この部分は前回のコードですでにカバーされています。このような形で単語ベクトルに使うtf.Variableを用意していました。

# 単語ベクトルの変数を用意
embeddings = tf.Variable(
    tf.random_uniform([self.vocabulary_size, self.embedding_size], -1.0, 1.0))

具体的に単語ベクトルを学習する過程は前回の記事で解説しているので、今回省略します。

ログフォルダにモデルを保存する

通常モデルを保存するときと同様にtf.train.Saver()を使用してモデルを保存します。ただし、学習のイテレーションを回すごとに、そのステップ数を引数に与えてログフォルダに保存します。
私のコードだと、こんな感じになります。

saver = tf.train.Saver()

上のようにsaverを用意して、

# Embeddings Visualizationのために、モデルを保存
saver.save(sess, logdir + "/blog.ckpt", epoch)

saver.save()を使ってログフォルダにモデルを保存します。

メタデータの用意

メタデータの情報をログフォルダに保存

ラベルなどのメタデータは、tsvファイルに保存しておき、projectorというクラスを使ってメタデータのtsvファイルをモデルファイルを関連付けます。
具体的なコードは次のようになります。

# Embeddings Visualiationにラベルを追加
summary_writer = tf.summary.FileWriter(logdir)
config = projector.ProjectorConfig()
embedding = config.embeddings.add()
embedding.tensor_name = embeddings.name # 右辺のembeddingsはこの関数の最初で定義したtf.Variable
embedding.metadata_path = "./corpus/model/blog.metadata.tsv"
projector.visualize_embeddings(summary_writer, config)

コード中のembedding.tensor_nameでメタデータを付加する変数(tf.Variable)名を、embedding.metadata_pathに各ベクトルのメタデータが保存されているtsvファイルを指定します。
tsvファイルの作り方については次の節で説明するので、ここではとりあえずblog.metadata.tsvというファイル名だけを指定しておきます。

ちなみに、ログフォルダを見てみるとprojector_config.pbtxtというファイルが保存されていて、中身は次のようになっています。上記コードは、単純に変数名とメタデータのtsvファイルをこのファイルに書き込んでいるだけなんですかね。

embeddings {
  tensor_name: "Variable:0"
  metadata_path: "./corpus/model/blog.metadata.tsv"
}

メタデータ(単語ラベル)の用意

メタデータのtsvは1行目がヘッダー、2行目から順にembeddingの情報を格納していきます。tf.Variableの順番とtsvのメタデータの順番は一致させる必要があります。
今回の場合は、付加するメタデータは単語ラベルだけです。その場合は、tsvファイルのヘッダは省略できます。(詳細はこちら)

というわけで、単語ID順に単語ラベルをtsvファイルに保存するコードを書きます。私はこんな感じで書きました。

# Embeddings Visualizationで使うラベルをblog.metadata.tsvとして保存
# 上から単語ID順にラベルが入ったファイルを用意すればよい
sorted_dict = sorted(self.dictionary.items(), key=lambda x: x[1])
words = ["{}\n".format(x[0]) for x in sorted_dict]
with open("./corpus/model/blog.metadata.tsv", "w", encoding="utf-8") as f:
    f.writelines(words)
print("Embeddings metadata was saved to ./corpus/model/blog.metadata.tsv")

なんと、これだけでembedding visualizationが使える準備が整いました!

TensorBoardを起動して可視化してみる

では、さっそくTensorBoardを起動してみます。

tensorboard --logdir ./corpus/log

というようにモデルを保存したログフォルダを指定してtensorboardを起動し、http://localhost:6006/にアクセスします。

画面上の EMBEDDINGS というタブをクリックすると、このように3次元上に可視化されたword embeddingが表示されています。マウスでドラッグすると、座標がぐるぐる回転します。
画面の左下で、ベクトルをどのように3次元(もしくは2次元)に落とすかを設定できます。デフォルトはPCAです。
f:id:kanohk:20170118222306p:plain

画面上部のメニューにあるAというアイコンをクリックすると、点がラベルに置き換えられます*1。わお。
もちろん、これも回転します。結構感動しますよ。
f:id:kanohk:20170118222831p:plain

さらに、この点をひとつ選択すると、その近くに存在している点が強調されて表示されます。デフォルトでは近傍の100点が強調されますが、画面右のメニューで簡単に個数を変更できます。
f:id:kanohk:20170118223605p:plain

またこの画面の右側には、強調された点たちが元の空間ではどのくらい離れていたかも表示されています。

あと個人的に面白かったのは、3次元へ落とす方法をT-SNEにした場合です。T-SNEのイテレーションを回すごとに画面上の点がリアルタイムで動いていくのですが、3次元空間をうにょうにょ動き回る点たちを見てるとなんか楽しくなってきます。

ソースコード

今回のソースコードはこちらです。
github.com

前回のソースコードとの差分が、既に実装してあるembeddingを可視化するために必要なコードです。



関連記事

題材は違いますが、TensorBoardを使って損失関数などの可視化も行っています。
www.madopro.net

*1:日本語でも試してみたのですが、日本語はまだ正しく描画されないみたいです。。