Googleによって開発されている機械学習ライブラリであるTensorFlowで、one-hotエンコーディングをする方法について解説します。
Contents
one-hotエンコーディングとは
one-hotエンコーディングとは、ある次元のベクトルのうち1つだけが1で、他については全て0になるような表現に変換することを言います。変換されたベクトルはone-hot表現、one-hotベクトルといったように呼びます。
文章だといまいち分かりづらいかもしれませんので、以下の図で一例を見てみましょう。
上記例では、データがdata1~data5までの5つあり、それぞれにラベルが設定されている状況だと思ってください。データは、例えば画像や音声等、ラベルはそのデータの分類というようなイメージを持ってもらうと分かりやすいかと思います。このラベルをone-hotエンコーディングすることを考えてみます。
図の右側がラベルについてone-hotエンコーディングをした結果です。ベクトルの各列がそれぞれのラベルを意味しています。例えば、data1のラベルは2なので、2に該当する列のみ「1」で、他の列は「0」となる[0, 0, 1, 0]というone-hotベクトルとなります。1つだけ値があるという意味で「one-hot」といういうわけです。
ディープラーニングなどの機械学習では、こういったone-hotベクトルに変換して学習に使用することがよくあり、TensorFlowではone-hotエンコーディングをするための方法がいくつか用意されています。
以降では、TensorFlowでone-hotエンコーディングする方法について紹介します。
tf.one_hotを使用してone-hotエンコーディングする
基本的な使い方
TensorFlowでone-hotエンコーディングする際には、以下のようにtf.one_hotが使用できます。
import tensorflow as tf labels = tf.constant([2, 1, 3, 1, 0]) depth = 5 # one-hotエンコーディング tf.one_hot one_hot_tensor = tf.one_hot(labels, depth) print(one_hot_tensor)
【実行結果】 tf.Tensor( [[0. 0. 1. 0. 0.] [0. 1. 0. 0. 0.] [0. 0. 0. 1. 0.] [0. 1. 0. 0. 0.] [1. 0. 0. 0. 0.]], shape=(5, 5), dtype=float32)
labelsがエンコーディング対象のリストです。depthは、データのクラス数(ラベル数)に該当する数値です。結果の各行を見てみると確かにラベルの数値に該当する位置が1となっているone-hotベクトルとなっていることが分かるかと思います。
今回はラベルの数としては[0, 1, 2, 3]の4種類ですが、depth=5で指定していますので「4」もクラスとしてはある想定での変換になっています。そのため、いずれのone-hotエンコーディング結果でも4に該当する5列目は全て0になっていることが分かります。
このdepth引数は、指定をしない場合はエラーになるので注意してください。
depthがデータのクラス数より少ない場合
depthの指定がデータのクラス数(ラベル数)より少ない場合には、どのような結果となるかを以下の例で見ておきましょう。
import tensorflow as tf labels = tf.constant([2, 1, 3, 1, 0]) depth = 3 # one-hotエンコーディング tf.one_hot # (depthがデータのクラス数より少ない場合) one_hot_tensor = tf.one_hot(labels, depth) print(one_hot_tensor)
【実行結果】 tf.Tensor( [[0. 0. 1.] [0. 1. 0.] [0. 0. 0.] [0. 1. 0.] [1. 0. 0.]], shape=(5, 3), dtype=float32)
上記では、ラベルの数としては[0, 1, 2, 3]の4種類ですがdepth=3として指定してます。この場合、ラベル3に該当するone-hotベクトルでは、1にする列がないことになりますので結果は[0, 0, 0]となります。
on_value, off_valueによる値の指定
tf.one_hotの引数として、on_valueとoff_valueという引数があります。on_valueは、デフォルトの際で1が入る場所の数値を指定することができます。一方、off_valueは、0が入る場所の数値を指定することができます。
以下の例は、on_value=5.0、off_value=-1.0を指定した場合です。
import tensorflow as tf labels = tf.constant([2, 1, 3, 1, 0]) depth = 5 # one-hotエンコーディング tf.one_hot # (on_value, off_valueの指定) one_hot_tensor = tf.one_hot(labels, depth, on_value=5.0, off_value=-1.0) print(one_hot_tensor)
【実行結果】 tf.Tensor( [[-1. -1. 5. -1. -1.] [-1. 5. -1. -1. -1.] [-1. -1. -1. 5. -1.] [-1. 5. -1. -1. -1.] [ 5. -1. -1. -1. -1.]], shape=(5, 5), dtype=float32)
結果を見てみると、引数を指定しない時に1が設定された部分に「5.」、0が設定された場所に「-1.」が設定されることが分かるかと思います。on_value、off_valueは意図して値を指定したい場合に使用することができます。
tf.one_hotの公式ドキュメントはこちらを参照してください。
tf.keras.utils.to_categoricalを使用してone-hotエンコーディングする
基本的な使い方
TensorFlowの高水準APIであるKerasのtf.keras.utils.to_categoricalを以下のように使用することでもone-hotエンコーディングをすることが可能です。
import tensorflow as tf labels = tf.constant([2, 1, 3, 1, 0]) # one-hotエンコーディング tf.keras.utils.to_categorical one_hot_array = tf.keras.utils.to_categorical(labels) print(one_hot_array) print(type(one_hot_array))
【実行結果】 [[0. 0. 1. 0.] [0. 1. 0. 0.] [0. 0. 0. 1.] [0. 1. 0. 0.] [1. 0. 0. 0.]] <class 'numpy.ndarray'>
結果を見てみるとone-hotベクトルに変換できていることが分かります。tf.one_hotでは、クラス数に該当するdepthの指定が必要でしたが、tf.keras.utils.to_categoricalでは必要なく、含まれるデータから適切なサイズでone-hot表現を作成してくれます。
なお、返却値はNumPyの配列であるndarrayになります。また、tf.one_hotのようにon_value, off_valueの値を設定することはできません。
num_classesによるクラス数の指定
エンコーディングのクラス数(ラベル数)を指定する方法として、num_classesを使用することができます。tf.one_hotにおけるdepthに該当します。
import tensorflow as tf labels = tf.constant([2, 1, 3, 1, 0]) num_class = 5 # one-hotエンコーディング tf.keras.utils.to_categorical # (num_classesによるクラス数の指定) one_hot_array = tf.keras.utils.to_categorical(labels, num_classes=num_class) print(one_hot_array) print(type(one_hot_array))
【実行結果】 [[0. 0. 1. 0. 0.] [0. 1. 0. 0. 0.] [0. 0. 0. 1. 0.] [0. 1. 0. 0. 0.] [1. 0. 0. 0. 0.]] <class 'numpy.ndarray'>
ラベルの数としては[0, 1, 2, 3]の4種類ですが、num_classes=5で指定していますので「4」もクラスとしてはある想定での変換になっています。そのため、いずれのone-hotエンコーディング結果でも4に該当する5列目は全て0になっていることが分かります。
num_classesがデータのクラス数より少ない場合
num_classesの指定がデータのクラス数(ラベル数)より少ない場合には、どのような結果となるかを以下の例で見ておきましょう。
import tensorflow as tf labels = tf.constant([2, 1, 3, 1, 0]) num_class = 3 # one-hotエンコーディング tf.keras.utils.to_categorical # (num_classesによるクラス数の指定でデータのクラス数より少ない場合) one_hot_array = tf.keras.utils.to_categorical(labels, num_classes=num_class) print(one_hot_array) print(type(one_hot_array))
【実行結果】 IndexError: index 3 is out of bounds for axis 1 with size 3
この場合、tf.keras.utils.to_categoricalでは処理途中でエラーとなります。tf.one_hotでは足りない列の部分が無視された点と挙動が少し異なりますので覚えておきましょう。
tf.keras.utils.to_categoricalの公式ドキュメントはこちらを参照してください。
まとめ
Googleによって開発されている機械学習ライブラリであるTensorFlowで、one-hotエンコーディングをする方法について解説しました。
one-hotエンコーディングする方法としては、tf.one_hotとKerasに実装されているtf.keras.utils.to_categoricalを使用することができます。上記で紹介したように指定できる引数や挙動に少し違いがありますので注意しましょう。
ディープラーニングの実装としてTensorFlowを勉強するとKerasを使用した実装が多いですので、tf.keras.utils.to_categoricalを目にする方が多いのではないかなという印象です。機能としてはtf.one_hotの方が、on_valueやoff_valueの指定ができるなどより扱える幅が少し柔軟かなと思います。
one-hotエンコーディングは、機械学習でよく出てくる表現方法ですので、変換方法についてしっかり覚えておくとよいでしょう。
上記で紹介しているソースコードについてはgithubにて公開しています。参考にしていただければと思います。