Ahogrammer

Deep Dive Into NLP, ML and Cloud

Object2vecの新機能を使って文の分散表現を計算する

前回の記事では、日本語文の分散表現を計算するためのデータセットを作成した。

hironsan.hatenablog.com

今回は、先日、SageMakerのObject2vecに追加された機能を使って文の分散表現を計算する。追加された機能には、ネガティブサンプリングの自動化、重み共有、学習の高速化が含まれている。いったん分散表現を計算できると、それを使って文をクラスタリングしたり、分類や回帰といった下流のタスクで使うことができる。

ここで、Object2vecのアーキテクチャについて簡単に説明しておこう。AWSの公式ブログによると、Object2vecのアーキテクチャは以下のようになっている。

f:id:Hironsan:20190510083542p:plain
参照: https://aws.amazon.com/jp/blogs/machine-learning/introduction-to-amazon-sagemaker-object2vec/

まず、モデルには2つのエンコーダが存在し、これらを使って入力を固定長のベクトルに変換している。その後、Comparatorを使ってベクトルの連結や積を計算し、その結果を元にラベルを予測するということを行う。このモデルにより、文の分散表現を得られたり、ユーザ・アイテム行列から分散表現を得ることができる。

今回行う文の分散表現の計算では、片方のエンコーダに文S、もう一方のエンコーダに文SのコンテキストCを入力する。コンテキストというのは要するに文Sの周辺文のことを指している。Word2vecを学習する際に、ある単語とその周囲の単語を入力して学習させたが、それと同じ考え方を使って学習させることになる。つまり、コンテキストが似ているなら文Sも似ているだろうから、近いベクトルになるでしょうということだ。

ここまでで、Object2vecの説明を簡単にしたので、ここからは実際に触っていく。

準備

まずは、SageMakerでインスタンスを起動する必要がある。その際に、以下のリポジトリをクローンする設定にしておく。

github.com

インスタンスを起動すると、リポジトリをクローンした状態になっているので、notebooks/object2vec_document_embedding.ipynbを開く。そうすると、ノートブックが開く。

f:id:Hironsan:20190510080342p:plain
Example notebook

これで準備は完了。あとは、動かすだけだが、ポイントだけ解説。

処理の流れ

大まかな処理の流れは以下のようになっている。

  1. ボキャブラリ作成
  2. 単語のインデックス化
  3. データの作成
  4. 学習
  5. デプロイ

この辺は一般的な自然言語処理と変わらない。

特徴的な点として、データを作成する際にポジティブサンプルだけ用意すれば済む点を挙げられる。以前はユーザ側でネガティブサンプルを用意してObject2vecに与えなければならなかったのだが、先日追加された機能により、ポジティブサンプルだけ用意すれば、あとはSageMaker側でネガティブサンプルを用意してくれるようになった。

ネガティブサンプルを生成させるために重要なのが、ハイパーパラメータに与えているnegative_sampling_rateオプション。ここに、ネガティブサンプル数を設定することで、指定したサイズ分のネガティブサンプルを自動的に用意してくれるようになった。

hyperparameters['negative_sampling_rate'] = 3

negative_samling_rate以外には以下の機能が追加されている。

hyperparameters['tied_token_embedding_weight'] = "true"
hyperparameters['comparator_list'] = "hadamard"
hyperparameters['token_embedding_storage_type'] = 'row_sparse'

tied_token_embedding_weightは2つのエンコーダで重みを共有するパラメータ、comparator_listはエンコーダから出力されたベクトルの組み合わせ方を指定するパラメータ、token_embedding_storage_typeは学習を高速化するパラメータとなっている。ハイパーパラメータの詳細は Object2Vec Hyperparameters を参照すると良い。ちなみに、記事を執筆している時点では日本語版のドキュメントには新しく追加されたハイパーパラメータの説明は載っていないので注意。

デプロイ

学習が終わったモデルはデプロイして使うことができる。

doc2vec_model = doc2vec.create_model(
                        serializer=json_serializer,
                        deserializer=json_deserializer,
                        content_type='application/json')

predictor = doc2vec_model.deploy(initial_instance_count=1, instance_type='ml.m4.xlarge')

予測はpredictメソッドを使って行う。

sent = '今日 の 昼食 は うどん だっ た'
sent_tokens = tokenizer.texts_to_sequences([sent])
payload = {'instances': [{'in0': sent_tokens[0]}]}
result = predictor.predict(payload)
print(result)

予測をすると、以下のように入力に対応した分散表現を得ることができる。

{
  "predictions": [
    {"embeddings":[0.057368703186511,0.030703511089086,0.099890425801277,0.063688032329082,0.026327300816774,0.003637571120634,0.021305780857801,0.004316598642617,0.0,0.003397724591195,0.0,0.000378780066967,0.0,0.0,0.0,0.007419463712722]},
  ]
}

分類や回帰の場合と分散表現を得る場合では、predictに与えるフォーマットが若干違うので注意が必要。詳細は以下のドキュメントを参照。

docs.aws.amazon.com

参考資料

文の分散表現を計算するためのデータセットを作って公開する

先日、SageMakerのObject2vecに新機能が追加された。機能としては、ネガティブサンプリングの自動化、重み共有、学習の高速化といった機能が追加されており、以下のNotebookから試すことができる。このNotebookでは英文の分散表現の計算、モデルのデプロイ、文書検索への応用を扱っている。

github.com

機能の使い方を知るだけなら、上のNotebookを実行すればいいのだが、単に写経するだけでは面白くない。そういうわけで、日本語のデータセットを作成して、文の分散表現を学習できるようにしてみた。データセットは以下のリポジトリからダウンロードできる。

github.com

データセットについて簡単に説明しておこう。

データセットの説明

データセットは、以下の論文を参考に作成した。

論文では英語版Wikipediaからデータセットを作成しているが、この部分を日本語Wikipediaの2018年12月20日に置き換えている。論文と同様、Wikiextractorを使って各記事からリストや図などを除いたPlainテキストだけを抽出して作成した。トータルの記事数は1,132,813であり、異なり語の数は2,420,073になった。

データセットの形式としては、1行に1記事を格納し、文はタブで区切っている。分かち書きには、MeCabとIPADICを使っている。

ニューヨーク 市 の 建築 ニューヨーク 市 の 建築 ...<tab>
...

おわりに

今回はデータセットの作成まで行なった。実際の学習については次の記事で行うことにする。

Jupyter NotebookがGitHub上で表示されない時にすること

機械学習に携わる人であればJupyter Notebookは頻繁に使うツールであり、共有するときにはGitHubを使うのが一般的だろう。GitHubにはブラウザ上でNotebookをレンダリングする機能があり、地味に便利なのだが、ときたまレンダリングされないNotebookが存在する。今回はそんなときに使えるTipsを紹介。

結論から言うと、nbviewerにNotebookのリンクを貼り付ける。

たとえば、以下のように表示されないNotebookがあったとする。

f:id:Hironsan:20190505115111p:plain
表示されないNotebook

この場合、このNotebookのURLをコピーしてnbviewerに貼り付ける。

f:id:Hironsan:20190505115311p:plain
nbviewerにリンクを貼り付ける

貼り付けた後、「Go」を押すとNotebookの内容がレンダリングされる。

f:id:Hironsan:20190505115412p:plain
レンダリングされたNotebook

Chrome拡張のOpen in nbviewerを入れておくと、1クリックでnbviewer上で開けて効率が良い。

欠点は、プライベートリポジトリにあるNotebookには使えないという点。

追記

開いたNotebookをそのまま実行したい場合は、Open in Colabを使うと、Colaboratoryで開けて便利だと思います。