/var/log/messages

Oct 21, 2018 - 11 minute read - Comments - MachineLearning

Building a Text Classification Model With Tensorflow Hub and Estimators

以下なドキュメントを機械翻訳したので以下に控えを。

あと、gist が以下です。

We often see transfer learning applied to computer vision models, but what about using it for text classification? Enter TensorFlow Hub, a library for enhancing your TF models with transfer learning. Transfer learning is the process of taking the weights and variables of a pre-existing model that has already been trained on lots of data and leveraging it for your own data and prediction task.

私たちはコンピュータビジョンモデルに適用される伝達学習をしばしば見ていますが、それをテキスト分類に使用するとどうなりますか? TensorFlow Hubは、トランスファーラーニングを使用してTFモデルを強化するためのライブラリです。 トランスファーラーニングは、既に多数のデータを訓練した既存のモデルの重みと変数を取得し、それを自分のデータや予測タスクに活用するプロセスです。

One of the many benefits of transfer learning is that you don’t need to provide as much of your own training data as you would if you were starting from scratch. But where do these pre-existing models come from? That’s where TensorFlow Hub comes in handy: it provides a whole repository of existing model checkpoints for various types of models — images, text, and more. In this post, I’ll walk you through building a model to predict the genre of a movie from its description using a TensorFlow Hub text module.

トランスファーラーニングの多くの利点の1つは、スクラッチから始める場合と同じくらい自分のトレーニングデータを提供する必要はないということです。 しかし、これらの既存のモデルはどこから来たのですか? TensorFlow Hub は便利な機能です。画像、テキストなど、さまざまな種類のモデルに既存のモデルチェックポイントのリポジトリ全体を提供します。 この記事では、TensorFlow Hub テキストモジュールを使用して、その説明からムービーのジャンルを予測するモデルを構築する方法を説明します。

You can run this model in the browser with zero setup using Colab.

Import and preprocessing data

For this model we’ll use this awesome public domain movie dataset from Kaggle. It has data on over 45,000 movies. There’s lots of data on each movie, but to keep things simple we’ll use only the movies description (called “overview”) in this dataset, and its genres. Here’s a preview of the dataset in Kaggle:

このモデルでは、Kaggleのこの素晴らしいパブリックドメインムービーデータセットを使用します。 それは45,000以上の映画に関するデータを持っています。 各ムービーにはたくさんのデータがありますが、このデータセットではムービーの説明(「概要」と呼ばれる)とそのジャンルだけを使います。 Kaggleのデータセットのプレビューは次のとおりです。

https://cdn-images-1.medium.com/max/2000/0*zIWLNgbqZlD-9dyR

First, we’ll import the libraries we’ll be using to build this model:

import numpy as np
import pandas as pd

import tensorflow as tf
import tensorflow_hub as hub

from sklearn.preprocessing import MultiLabelBinarizer

I’ve made the CSV file from this dataset available in a public Cloud Storage bucket. We can run the following command to download the data to our Colab instance and read it as a Pandas dataframe:

このデータセットのCSVファイルを公開クラウドストレージバケットで利用できるようにしました。 次のコマンドを実行して、Colabインスタンスにデータをダウンロードし、それをPandasデータフレームとして読み込むことができます。

!wget 'https://storage.googleapis.com/movies_data/movies_metadata.csv'
data = pd.read_csv('movies_metadata.csv')

descriptions = data['overview']
genres = data['genres']

To keep things simple, we’ll limit the possible genres to the following:

top_genres = ['Comedy', 'Thriller', 'Romance', 'Action', 'Horror', 'Crime', 'Documentary', 'Adventure', 'Science Fiction']

We’ll limit our dataset to movies with non-empty descriptions in those genres and then we can split our data into training and testing sets using an 80% / 20% train / test split:

これらのジャンルでは空の記述がない映画にデータセットを限定し、80%/ 20%の列車/テスト分割を使用してデータをトレーニングセットとテストセットに分けることができます。

train_size = int(len(descriptions) * .8)

train_descriptions = descriptions[:train_size]
train_genres = genres[:train_size]

test_descriptions = descriptions[train_size:]
test_genres = genres[train_size:]

Building our embedding layer with TF Hub

Creating an embedding with TF Hub uses a surprisingly small amount of code. Our model will only have one feature (the description) and it’ll be represented as an embedding column. Text embeddings provide a way to represent pieces of text in vector space, so that similar words or sentences are closer together in the embedding space (you can read more about them here). You can build text embedding vectors from scratch using entirely your own data. TF Hub simplifies this process by providing text embeddings that have already been trained on a variety of text data.

TF Hubを使った埋め込みの作成は、驚くほど少量のコードを使用します。 私たちのモデルは1つの機能(説明)しか持たず、埋め込み列として表現されます。 テキストの埋め込みは、ベクトル空間のテキスト部分を表現する方法を提供し、同様の単語や文章が埋め込みスペースに接近するようにします(ここでそれらについて詳しく読むことができます)。 独自のデータを使用して、テキスト埋め込みベクターを最初から構築することができます。 TF Hubは、すでにさまざまなテキストデータに訓練されたテキスト埋め込みを提供することで、このプロセスを簡素化します。

For English text, TF Hub provides a variety of embeddings trained on different kinds of text data:

  • Universal sentence encoder: for longer form text inputs
  • ELMo: deep embeddings trained on the 1B Word Benchmark
  • Neural Network Language Model embeddings: trained on Google News
  • Word2vec: trained on Wikipedia

英語のテキストの場合、TF Hubはさまざまな種類のテキストデータに対して訓練されたさまざまな埋め込みを提供します:

  • ユニバーサルセンテンスエンコーダー:より長い形式のテキスト入力用
  • ELMo:1BのWordベンチマークで徹底的に埋め込まれた埋め込み
  • ニューラルネットワーク言語モデル埋め込み:Googleニュースで訓練
  • Word2vec:Wikipediaで訓練を受けた

The pre-trained text embeddings you choose is a hyperparameter in your model, so it’s best to experiment with different ones and see which one yields the highest accuracy. Start with the model that was trained on text closest to yours. Since our movie descriptions are longer inputs, I found I got the highest accuracy with the universal sentence encoder embeddings. This will encode our descriptions into high dimensional text vectors. Note that this particular model is quite large and will take up 1 GB.

We can use hub.text_embedding_column to create a feature column for this layer in one line of code, passing it the name of our layer (“movie_descriptions”) and the URL of the TF Hub model we’ll be using:

あなたが選択した事前に訓練されたテキストの埋め込みは、モデルのハイパーパラメータであるため、異なるものを試して、どれが最高の精度をもたらすかを確認するのが最善です。 あなたに最も近いテキストに訓練されたモデルから始めましょう。 私たちのムービー記述は入力が長いため、ユニバーサルセンテンスエンコーダーの埋め込みで最高の精度を得ました。 これにより、我々の記述を高次元のテキストベクトルに符号化する。 この特定のモデルはかなり大きく、1 GBを占めることに注意してください。

hub.text_embedding_columnを使用して、このレイヤーのフィーチャー列をコードの1行に作成し、レイヤーの名前(「movie_descriptions」)と使用するTFハブモデルのURLを渡すことができます。

description_embeddings = hub.text_embedding_column(
  "movie_descriptions", 
  module_spec="https://tfhub.dev/google/universal-sentence-encoder/2"
)

Note that it may take some time to run this cell since it’s downloading the pre-trained embeddings.

The best part about this is that we don’t need to do any preprocessing to feed our text descriptions into the pre-trained word embeddings. If we were building this model from scratch we’d need to convert our descriptions into vectors ourselves, but with the TF Hub column we can pass our description strings directly to the model.

事前に訓練された埋め込みをダウンロードしているので、このセルを実行するには時間がかかることに注意してください。

これに関する最も重要な点は、事前に訓練された単語埋め込みにテキスト記述を供給するために前処理を行う必要がないことです。 このモデルを最初から構築する場合は、記述を自分自身のベクトルに変換する必要がありますが、TF Hub列では、説明文字列を直接モデルに渡すことができます。

Turning labels into multi-hot encodings

Since a movie often has multiple genres, our model will return multiple possible labels for each movie. Our genres are currently a list of strings for each movie (like [‘Action’, ‘Adventure’]). Since each label needs to be the same length, we’ll transform these lists into multi-hot vectors of 1s and 0s corresponding to the genres present in a particular description. The multi-hot vector for an Action and Adventure movie would look like the following:

ムービーには複数のジャンルがあることが多いため、このモデルではムービーごとに複数のラベルが返されます。 私たちのジャンルは現在、各映画のためのストリングのリストです([‘Action’、 ‘Adventure’など))。 各ラベルは同じ長さである必要があるため、これらのリストを特定の記述に存在するジャンルに対応する1と0のマルチホットベクトルに変換します。 アクションとアドベンチャームービーのマルチホットベクトルは、次のようになります。

# Genre lookup, each genre corresponds to an index
top_genres = ['Comedy', 'Thriller', 'Romance', 'Action', 'Horror', 'Crime', 'Documentary', 'Adventure', 'Science Fiction']

# Multi-hot label for an action and adventure movie
[0 0 0 1 0 0 0 1 0]

To transform our string labels into multi-hot vectors in just a few lines of code we’ll use a scikit learn utility called MultiLabelBinarizer:

数行のコードで文字列ラベルをマルチホットベクトルに変換するには、MultiLabelBinarizerというscikit学習ユーティリティを使用します。

encoder = MultiLabelBinarizer()
encoder.fit_transform(train_genres)
train_encoded = encoder.transform(train_genres)
test_encoded = encoder.transform(test_genres)
num_classes = len(encoder.classes_)

You can print encoder.classes_ to see a list of all the string classes your model is predicting.

encoder.classes_を印刷すると、モデルが予測しているすべての文字列クラスのリストが表示されます。

Building and training a DNNEstimator model

For our model we’ll use a DNNEstimator to build a deep neural net that returns a multi-hot vector, since each movie can have 0 or more possible labels (this is different from a model where each input has exactly one label). The first parameter we pass to our DNNEstimator is called a head, and defines the type of labels our model should expect. Since we want our model to output multiple labels, we’ll use multi_label_head here:

私たちのモデルでは、DNNEstimatorを使ってマルチホットベクトルを返すディープニューラルネットを構築します。それぞれのムービーは0以上の可能なラベルを持つことができます(これは、各入力が正確に1つのラベルを持つモデルとは異なります)。 DNNEstimatorに渡す最初のパラメータは頭部と呼ばれ、モデルが期待するラベルの種類を定義します。 モデルに複数のラベルを出力したいので、ここではmulti_label_headを使用します:

multi_label_head = tf.contrib.estimator.multi_label_head(
    num_classes,
    loss_reduction=tf.losses.Reduction.SUM_OVER_BATCH_SIZE
)

We can now pass this in when we instantiate our DNNEstimator. The hidden_units param indicates how many layers we’ll have in our network. This model has 2 layers, the first has 64 neurons and the second has 10. Number of layers and layer size is a hyperparameter so you should try out different values to see what works best for your dataset. Finally, we pass our feature columns to the Estimator. In this case we only have one (the description), and we’ve already defined it as a TF Hub embedding column above so we can pass that here as a list:

DNNEstimatorをインスタンス化するときにこれを渡すことができます。 hidden_unitsパラメータは、ネットワークにいくつのレイヤがあるかを示します。 このモデルには2つのレイヤーがあり、最初のレイヤーには64のニューロンがあり、2番目のレイヤーには10のレイヤーとレイヤーがあります。レイヤーとレイヤーの数はハイパーパラメーターなので、異なる値を試してデータセットに最適なものを調べる必要があります。 最後に、フィーチャー列を見積もりに渡します。 この例では1つ(説明)しか持っていません。TFハブの埋め込み列として既に定義されていますので、リストとしてここに渡すことができます:

estimator = tf.contrib.estimator.DNNEstimator(
    head=multi_label_head,
    hidden_units=[64,10],
    feature_columns=[description_embeddings]
)

We’re almost ready to train the model. Before we can train our estimator instance, we need to define our training input function. An input function connects our data to the model. Here we’ll use a numpy_input_fn and feed our data to our model as numpy arrays:

我々はモデルを訓練する準備がほぼ整っている。 見積もりインスタンスをトレーニングする前に、訓練入力関数を定義する必要があります。 入力関数は、データをモデルに接続します。 ここでは、numpy_input_fnを使用し、データをモデルにnumpy配列として送ります:

# Format our data for the numpy_input_fn
features = {
  "descriptions": np.array(train_descriptions)
}
labels = np.array(train_encoded)

train_input_fn = tf.estimator.inputs.numpy_input_fn(
    features, 
    labels, 
    shuffle=True, 
    batch_size=32, 
    num_epochs=20
)

The batch_size and num_epochs parameters in our input function are both hyperparameters. batch_size tells our model how many examples will be passed to our model during one iteration, and num_epochs is the number of times our model will go through the entire training set.

Time to train our model. We can do this with one line of code:

入力関数のbatch_sizeとnum_epochsパラメータはいずれもハイパーパラメータです。 batch_sizeは、私たちのモデルに、1回の反復中にモデルに渡されるサンプルの数を示し、num_epochsは、モデルがトレーニングセット全体を通過する回数を示します。

私たちのモデルを訓練する時間。 1行のコードでこれを行うことができます:

estimator.train(input_fn=train_input_fn)

To evaluate the accuracy of our model, we create an eval input_function with our test data, and call estimator.evaluate():

モデルの精度を評価するために、テストデータでeval input_functionを作成し、estimator.evaluate()を呼び出します。

eval_input_fn = tf.estimator.inputs.numpy_input_fn({"descriptions": np.array(test_descriptions).astype(np.str)}, test_encoded.astype(np.int32), shuffle=False)

estimator.evaluate(input_fn=eval_input_fn)

This model achieved 91.5% AUC, and 74% precision / recall. Your results may vary slightly.

このモデルは、91.5%のAUCおよび74%の精度/リコールを達成した。 結果は若干異なる場合があります。

Generating predictions on our trained model

Time for the best part: generating predictions on data our model hasn’t seen before. First, let’s set up an array of a few descriptions (I grabbed these from IMDB):

最も重要な部分の時間:私たちのモデルが以前には見たことのないデータに対する予測を生成する。 まず、いくつかの説明の配列を設定しましょう(IMDBからこれらを取得しました)。

raw_test = [
    "An examination of our dietary choices and the food we put in our bodies. Based on Jonathan Safran Foer's memoir.", # Documentary
    "A teenager tries to survive the last week of her disastrous eighth-grade year before leaving to start high school.", # Comedy
    "Ethan Hunt and his IMF team, along with some familiar allies, race against time after a mission gone wrong." # Action, Adventure
]

We’ll then define our prediction input function and call predict():

次に、予測入力関数を定義し、predict() を呼び出します。

predict_input_fn = tf.estimator.inputs.numpy_input_fn({"descriptions": np.array(raw_test).astype(np.str)}, shuffle=False)

results = estimator.predict(predict_input_fn)

Finally, we can iterate through the results and display the top 2 genres found for each movie along with their confidence values:

最後に、結果を繰り返し、各ムービーで見つかった上位2つのジャンルを信頼度とともに表示できます。

for movie_genres in results:
  top_2 = movie_genres['probabilities'].argsort()[-2:][::-1]
  for genre in top_2:
    text_genre = encoder.classes_[genre]
    print(text_genre + ': ' + str(round(movie_genres['probabilities'][genre] * 100, 2)) + '%')

Our model is able to tag all of the movie descriptions above correctly.

Get Started

Want to start building your own model with TF Hub? Check out the documentation and tutorials. You can find the full code for the model outlined here on GitHub or Colab. In a future post, I’ll cover how to export this model for serving on TensorFlow Serving, or Cloud ML Engine — and build an app that generates predictions on new descriptions.

If you have questions or feedback, let me know on Twitter @SRobTweets.

TF Hubで独自のモデルを構築したいですか? ドキュメントとチュートリアルをチェックしてください。 GitHubまたはColabでここで概説したモデルの完全なコードを見つけることができます。 今後の記事では、このモデルをTensorFlow ServingやCloud ML Engineで公開する方法を説明し、新しい説明で予測を生成するアプリを構築します。

Introducing TnsorFlow Hub python の print

comments powered by Disqus