TensorFlow のオートエンコーダーと例
⚡ スマートサマリー
オートエンコーダーは、入力データをより小さな内部表現に圧縮し、その後再構築することで、ラベルなしで最も重要な特徴を学習します。このチュートリアルでは、TensorFlowで4つの全結合層を積み重ね、CIFAR-10の馬の画像を再構築します。
ディープラーニングにおけるオートエンコーダーとは何ですか?
An オートエンコーダー は、データコーディングを効率的に学習するためのツールです。 監督されない 方法。それは、 人工ニューラルネットワーク これは、ニューラルネットワークに信号ノイズを無視するように学習させることで、次元削減のためのデータセットの表現方法を学習するのに役立ちます。入力を再現するための優れたツールです。
簡単に言うと、この機械は例えば画像を入力として受け取り、それとよく似た画像を生成できます。この種のニューラルネットワークへの入力はラベル付けされていないため、ネットワークは教師なしで学習できます。より正確には、入力はネットワークによってエンコードされ、最も重要な特徴のみに焦点を当てます。これが、オートエンコーダーが次元削減に広く用いられている理由の一つです。さらに、オートエンコーダーは生成学習モデルの作成にも使用できます。例えば、ニューラルネットワークを顔画像のセットで学習させ、新しい顔画像を生成させることができます。
TensorFlow Autoencoder はどのように機能しますか?
オートエンコーダーの目的は、重要な特徴のみに焦点を当てて入力の近似値を生成することです。 入力をコピーして貼り付けて出力を生成する方法を単に学習すればよいのではないかと思うかもしれません。 実際、オートエンコーダは、単に出力をコピーするのとは異なる、データを表現するための新しい方法をネットワークに学習させる一連の制約です。
典型的なオートエンコーダーは、入力、内部表現、および出力(入力の近似値)で定義されます。学習は、内部表現に接続されたレイヤーで行われます。実際には、従来のニューラルネットワークに似た2つの主要なレイヤーブロックがあります。わずかな違いは、出力を含むレイヤーが入力と等しくなければならないことです。下の図では、元の入力がエンコーダーと呼ばれる最初のブロックに入力されます。この内部表現は、入力のサイズを圧縮(縮小)します。2番目のブロックでは、入力の再構築が行われます。これがデコードフェーズです。

モデルは損失関数を最小化することによって重みを更新します。 再構成出力が入力と異なる場合、モデルにはペナルティが課されます。
具体的には、50×50(つまり2,500ピクセル)の画像と、100個のニューロンからなる隠れ層が1つだけのニューラルネットワークを想像してみてください。学習は、入力画像の25分の1のサイズの特徴マップで行われます。つまり、ネットワークは、100個のニューロンからなるベクトルだけで2,500ピクセルの画像を再構築する方法を見つける必要があるということです。
スタック型オートエンコーダーの例
このオートエンコーダーチュートリアルでは、スタック型オートエンコーダーの使い方を学びます。そのアーキテクチャは、従来のニューラルネットワークに似ています。入力は隠れ層に送られ、圧縮(サイズ縮小)された後、再構成層に到達します。目的は、元の画像にできるだけ近い出力画像を生成することです。モデルは、制約条件(つまり、より低い次元)の下で、タスクを達成する方法を学習する必要があります。
現在、ディープラーニングにおけるオートエンコーダーは、主に画像のノイズ除去に用いられています。例えば、傷のついた画像でも、人間は内容を認識できます。ノイズ除去オートエンコーダーの基本的な考え方は、画像にノイズを加えることで、ネットワークにデータの背後にあるパターンを学習させるというものです。
オートエンコーダーのもう1つの有用なファミリー 深層学習 変分オートエンコーダーは、新しい画像を生成できるネットワークです。例えば、男性の画像を使ってネットワークを訓練すると、新しい顔画像を生成できます。
以下の表では、このチュートリアルで作成したスタック型オートエンコーダーを、他のよく見かけるオートエンコーダーのファミリーと並べて表示しています。これにより、それぞれのオートエンコーダーが追加する制約を簡単に比較できます。
| オートエンコーダータイプ | 制約が追加されました | 典型的な使用 |
|---|---|---|
| 不完全/積み重ね | 入力層よりも狭い符号化層 | 次元削減、特徴抽出trac生産 |
| ノイズ除去 | 入力にノイズを追加、クリーンターゲット | 画像と信号のクリーンアップ |
| スパース | 稼働ユニット数に対するペナルティ | 解釈可能な部分ベースの機能 |
| 変分 | 符号化層は確率分布を学習する | 新しいサンプルを生成する |
TensorFlow を使用してオートエンコーダーを構築する方法
このチュートリアルでは、画像を再構築するためのスタック型オートエンコーダーを構築する方法を学びます。
60000枚の32×32カラー画像を含むCIFAR-10データセットを使用します。オートエンコーダーデータセットは、トレーニング用50000枚とテスト用10000枚に既に分割されています。クラス数は最大10個です。
- 飛行機
- 自動車
- 鳥
- ネコ
- 鹿
- 犬
- カエル
- うま
- 船
- トラック
画像をダウンロードする必要があります CIFAR-10データセットページ アーカイブを解凍してください。cifar-10-batches-pyフォルダには、それぞれ10000枚の画像を含む5つのデータバッチがランダムな順序で格納されています。
モデルを構築してトレーニングする前に、いくつかのデータ処理を適用する必要があります。 次のように進めます。
- データをインポートする
- データを白黒形式に変換します
- すべてのバッチを追加する
- トレーニング データセットを構築する
- 画像ビジュアライザを構築する
バージョンノート: このチュートリアルのコードは TensorFlow 1.x を対象としています。TensorFlow 2 では tf.contrib モジュールは存在せず、プレースホルダー、セッション、初期化可能なイテレータは tf.compat.v1 の下にあります。インポート後に tf.compat.v1.disable_v2_behavior() を呼び出すと、リストを変更せずに実行する最も簡単な方法です。
画像の前処理
ステップ 1) データをインポートする
公式サイトによると、以下のコードでデータをアップロードできます。オートエンコーダーコードは、データとラベルを含む辞書にデータを読み込みます。なお、このコードは関数です。
import numpy as np import tensorflow as tf import pickle def unpickle(file): import pickle with open(file, 'rb') as fo: dict = pickle.load(fo, encoding='latin1') return dict
ステップ 2) データを白黒形式に変換します
簡単にするために、データをグレースケールに変換します。 つまり、カラー画像の場合は XNUMX 次元に対して XNUMX 次元のみです。 ほとんどのニューラル ネットワークは XNUMX 次元の入力でのみ機能します。
def grayscale(im): return im.reshape(im.shape[0], 3, 32, 32).mean(1).reshape(im.shape[0], -1)
ステップ 3) すべてのバッチを追加する
両方の関数が作成され、データセットが読み込まれたので、ループを使ってメモリ内のデータを追加できます。よく確認すると、解凍されたデータファイルは、1から5までの番号が付いたdata_batch_という名前になっています。これらのファイルをループ処理して、データに追記することができます。
このステップが完了すると、カラーデータがグレースケール形式に変換されます。ご覧のとおり、データの形状は50000×1024です。32×32ピクセルが1024に平坦化されます。
# Load the data into memory data, labels = [], [] ## Loop over the b for i in range(1, 6): filename = './cifar-10-batches-py/data_batch_' + str(i) open_data = unpickle(filename) if len(data) > 0: data = np.vstack((data, open_data['data'])) labels = np.hstack((labels, open_data['labels'])) else: data = open_data['data'] labels = open_data['labels'] data = grayscale(data) x = np.matrix(data) y = np.array(labels) print(x.shape) (50000, 1024)
注意: './cifar-10-batches-py/data_batch_' を実際のファイルの場所に変更してください。たとえば、 Windows マシンの場合、パスは filename = 'E:\cifar-10-batches-py\data_batch_' + str(i) になります。
ステップ 4) トレーニング データセットを構築する
トレーニングをより速く簡単にするために、馬の画像のみを使用してモデルをトレーニングします。馬にはラベルデータでラベル7が割り当てられています。CIFAR-10データセットのドキュメントに記載されているように、各クラスには5000枚の画像が含まれています。以下のTensorFlow Autoencoderの例の手順に示すように、データの形状を出力して、1024列で5,000枚の画像があることを確認できます。
horse_i = np.where(y == 7)[0]
horse_x = x[horse_i]
print(np.shape(horse_x))
(5000, 1024)
ステップ 5) 画像ビジュアライザを構築する
最後に、画像をプロットする関数を構築します。 オートエンコーダーから再構成されたイメージを印刷するには、この関数が必要になります。
画像を簡単に印刷するには、Matplotlibライブラリのimshow()関数を使用するのが良いでしょう。ただし、データの形状を1024から32×32(つまり画像形式)に変換する必要があることに注意してください。
# To plot pretty figures %matplotlib inline import matplotlib import matplotlib.pyplot as plt def plot_image(image, shape=[32, 32], cmap = "Greys_r"): plt.imshow(image.reshape(shape), cmap=cmap,interpolation="nearest") plt.axis("off")
この関数は 3 つの引数を取ります。
- 画像: 入力
- 形状: リスト、画像のサイズ
- Cmap: カラーマップを選択します。デフォルトはグレーです。
データセット内の最初の画像をプロットしてみることができます。 馬に乗った男性が見えるはずです。
plot_image(horse_x[1], shape=[32, 32], cmap = "Greys_r")
この呼び出しにより、以下のグレースケールのサムネイルが返され、1024個の値から32×32ピクセルの画像への形状変更が正しいことが確認できます。
データセット推定器の設定
さて、データセットの準備が整ったので、TensorFlow を使い始めましょう。モデルを構築する前に、TensorFlow のデータセット推定器を使用してネットワークにデータを供給してください。
TensorFlow エスティメーターを使用してデータセットを構築します。 心をリフレッシュするには、以下を使用する必要があります。
- from_tensor_slices
- 繰り返す
- バッチ
データセットを構築するための完全なコードは次のとおりです。
dataset = tf.data.Dataset.from_tensor_slices(x).repeat().batch(batch_size)
x は [None,n_inputs] の形状をしたプレースホルダーであることに注意してください。ネットワークに入力される画像の数がバッチサイズと同じであるため、最初の次元は None に設定されています。バッチサイズは実行時にのみ決定されます。詳細については、チュートリアルを参照してください。 TensorFlowによる線形回帰.
その後、イテレータを作成する必要があります。 このコード行がないと、データはパイプラインを通過しません。
iter = dataset.make_initializable_iterator() # create the iteratorfeatures = iter.get_next()
パイプラインの準備ができたので、最初の画像が以前と同じかどうか (つまり、馬に乗った男性) を確認できます。
バッチサイズを1に設定するのは、データセットに1つの画像だけを供給したいからです。print(sess.run(features).shape)でデータの次元を確認できます。これは(1, 1024)です。1は、1024個の値を持つ1つの画像が毎回供給されることを意味します。バッチサイズを2に設定すると、2つの画像がパイプラインを通過します。バッチサイズを変更しないでください。変更するとエラーが発生します。plot_image()関数には一度に1つの画像しか渡せないためです。
## Parameters n_inputs = 32 * 32 BATCH_SIZE = 1 batch_size = tf.placeholder(tf.int64) # using a placeholder x = tf.placeholder(tf.float32, shape=[None,n_inputs]) ## Dataset dataset = tf.data.Dataset.from_tensor_slices(x).repeat().batch(batch_size) iter = dataset.make_initializable_iterator() # create the iterator features = iter.get_next() ## Print the image with tf.Session() as sess: # feed the placeholder with data sess.run(iter.initializer, feed_dict={x: horse_x, batch_size: BATCH_SIZE}) print(sess.run(features).shape) plot_image(sess.run(features), shape=[32, 32], cmap = "Greys_r") (1, 1024)
このパイプラインは、NumPy行列から直接プロットされたものと同じライダーを返します。これは、プレースホルダー、イテレータ、およびバッチサイズが正しく接続されていることを証明しています。
ネットワークを構築する
ネットワークを構築する時が来ました。 スタック型オートエンコーダー、つまり複数の隠れ層を持つネットワークをトレーニングします。
ネットワークには、1024個の点(つまり、画像の形状である32×32)を持つ入力層が1つあります。
エンコーダーブロックは、300個のニューロンを持つ最上位の隠れ層と、150個のニューロンを持つ中央層で構成されます。デコーダーブロックはエンコーダーと対称的な構造です。ネットワークの構成は下の図で確認できます。なお、隠れ層と中央層の値は変更可能です。
オートエンコーダーの構築は、他の深層学習モデルと非常に似ています。
次の手順に従ってモデルを構築します。
- パラメータを定義する
- レイヤーを定義する
- アーキテクチャを定義する
- 最適化を定義する
- モデルを実行する
- モデルを評価する
前のセクションでは、モデルにデータを供給するパイプラインの作成方法を学習したので、データセットを再度作成する必要はありません。ここでは、4つの層を持つオートエンコーダーを構築します。初期化にはXavier初期化を使用します。これは、入力と出力の両方の分散に基づいて初期重みを設定する手法です。最後に、ELU活性化関数を使用します。損失関数はL2正則化によって正則化します。
ステップ1)パラメータを定義する
最初のステップでは、各層のニューロンの数、学習率、および正則化子のハイパーパラメーターを定義することを意味します。
その前に、部分関数をインポートします。これは、全結合層のパラメータを定義するためのより良い方法です。以下のコードは、オートエンコーダーアーキテクチャの値を定義します。前述のとおり、エンコーダーは2つの層で構成され、第1層には300個のニューロン、第2層には150個のニューロンがあります。これらの値は、n_hidden_1とn_hidden_2に格納されます。
学習率とL2ハイパーパラメータを定義する必要があります。これらの値はlearning_rateとl2_regに格納されます。
from functools import partial ## Encoder n_hidden_1 = 300 n_hidden_2 = 150 # codings ## Decoder n_hidden_3 = n_hidden_1 n_outputs = n_inputs learning_rate = 0.01 l2_reg = 0.0001
Xavier初期化手法は、estimator contribのオブジェクトxavier_initializerを使用して呼び出されます。同じestimator内で、l2_regularizerを使用して正則化項を追加できます。
## Define the Xavier initialization xav_init = tf.contrib.layers.xavier_initializer() ## Define the L2 regularizer l2_regularizer = tf.contrib.layers.l2_regularizer(l2_reg)
バージョンノート: tf.contrib は TensorFlow 2 で削除されました。直接の代替として、xavier_initializer() には tf.keras.initializers.GlorotUniform() が、l2_regularizer() には tf.keras.regularizers.l2() が使用されます。
ステップ2)レイヤーを定義する
密結合層のすべてのパラメータが設定されています。オブジェクト partial を使用して、すべてのパラメータを変数 dense_layer にパックできます。dense_layer は、呼び出しごとに ELU 活性化関数、Xavier 初期化関数、および L2 正則化関数を使用します。
## Create the dense layer
dense_layer = partial(tf.layers.dense,
activation=tf.nn.elu,
kernel_initializer=xav_init,
kernel_regularizer=l2_regularizer)
ステップ3)アーキテクチャを定義する
アーキテクチャの図を見ると、ネットワークは出力層を含む3つの層から構成されていることがわかります。以下のコードでは、適切な層を接続しています。たとえば、最初の層では、入力行列の特徴と300個の重みを含む行列との内積を計算します。内積が計算されると、出力はELU活性化関数に渡されます。この出力は次の層の入力となるため、hidden_2などを計算する際に使用します。同じ活性化関数を使用しているため、各層での行列乗算は同じです。最後の層である出力層には活性化関数が適用されないことに注意してください。これは、これが再構築された入力であるため、当然のことです。
## Make the mat mul hidden_1 = dense_layer(features, n_hidden_1) hidden_2 = dense_layer(hidden_1, n_hidden_2) hidden_3 = dense_layer(hidden_2, n_hidden_3) outputs = dense_layer(hidden_3, n_outputs, activation=None)
ステップ4)最適化を定義する
最後のステップはオプティマイザを構築することです。損失関数として平均二乗誤差(MSE)を使用します。線形回帰のチュートリアルを思い出していただければ、MSEは予測出力と実際のラベルの差で計算されることがお分かりいただけるでしょう。ここでは、モデルが入力の再構築を試みているため、ラベルが特徴量となります。したがって、予測出力と入力の二乗差の合計の平均を求めたいのです。TensorFlowでは、損失関数を次のようにコーディングできます。
loss = tf.reduce_mean(tf.square(outputs - features))
次に、損失関数を最適化する必要があります。勾配の計算にはAdamオプティマイザを使用します。目的関数は損失を最小化することです。
## Optimize
loss = tf.reduce_mean(tf.square(outputs - features))
optimizer = tf.train.AdamOptimizer(learning_rate)
train = optimizer.minimize(loss)
モデルをトレーニングする前にもう 150 つの設定を行います。 バッチ サイズ 150 を使用します。つまり、反復ごとに XNUMX 枚の画像をパイプラインにフィードします。 反復回数を手動で計算する必要があります。 これを行うのは簡単です:
1回に150枚の画像を渡したい場合、データセットに5000枚の画像があることがわかっている場合、反復回数は5000÷150になります。 Python 以下のコードを実行して、出力が33であることを確認してください。
BATCH_SIZE = 150 ### Number of batches : length dataset / batch size n_batches = horse_x.shape[0] // BATCH_SIZE print(n_batches) 33
ステップ5)モデルを実行する
最後に、モデルをトレーニングします。100エポックでモデルをトレーニングします。つまり、モデルは重みを最適化する際に、画像を100回見ることになります。
TensorFlowでモデルをトレーニングするためのコードは既にご存知でしょう。わずかな違いは、トレーニングを実行する前にデータをパイプ処理することです。こうすることで、モデルのトレーニングが高速化されます。
モデルが何かを学習している (つまり、損失が減少している) かどうかを確認するために、2 エポック後の損失を出力することに興味があります。 マシンのハードウェアに応じて、トレーニングには 5 ~ XNUMX 分かかります。
## Set params n_epochs = 100 ## Call Saver to save the model and re-use it later during evaluation saver = tf.train.Saver() with tf.Session() as sess: sess.run(tf.global_variables_initializer()) # initialise iterator with train data sess.run(iter.initializer, feed_dict={x: horse_x, batch_size: BATCH_SIZE}) print('Training...') print(sess.run(features).shape) for epoch in range(n_epochs): for iteration in range(n_batches): sess.run(train) if epoch % 10 == 0: loss_train = loss.eval() # not shown print("\r{}".format(epoch), "Train MSE:", loss_train) #saver.save(sess, "./my_model_all_layers.ckpt") save_path = saver.save(sess, "./model.ckpt") print("Model saved in path: %s" % save_path) Training... (150, 1024) 0 Train MSE: 2934.455 10 Train MSE: 1672.676 20 Train MSE: 1514.709 30 Train MSE: 1404.3118 40 Train MSE: 1425.058 50 Train MSE: 1479.0631 60 Train MSE: 1609.5259 70 Train MSE: 1482.3223 80 Train MSE: 1445.7035 90 Train MSE: 1453.8597 Model saved in path: ./model.ckpt
ステップ 6) モデルを評価する
モデルの学習が完了したので、次は評価を行います。/cifar-10-batches-py/ ファイルからテストセットをインポートする必要があります。
test_data = unpickle('./cifar-10-batches-py/test_batch') test_x = grayscale(test_data['data']) #test_labels = np.array(test_data['labels'])
注意: Windows マシンの場合、コードは test_data = unpickle(r”E:\cifar-10-batches-py\test_batch”) になります。
画像13(馬の画像)を印刷してみてください。
plot_image(test_x[13], shape=[32, 32], cmap = "Greys_r")
このグラフは、テストバッチが正しく読み込まれたこと、および画像13がモデルの学習に使用されたクラスに属していることを示しています。
モデルを評価するには、この画像のピクセル値を使用し、エンコーダーが画像を1024ピクセルに縮小した後、同じ画像を再構築できるかどうかを確認します。なお、異なる画像でモデルを評価する関数を定義します。このモデルは、馬の画像でのみより良い結果を示すはずです。
この関数は XNUMX つの引数を取ります。
- df: テストデータをインポートします
- image_number: インポートする画像を指定します
この機能は XNUMX つの部分に分かれています。
- 画像を正しい寸法(1、1024)に再形成します。
- モデルに目に見えない画像をフィードし、画像をエンコード/デコードします
- 実際の画像と再構成された画像を印刷します
def reconstruct_image(df, image_number = 1): ## Part 1: Reshape the image to the correct dimension i.e 1, 1024 x_test = df[image_number] x_test_1 = x_test.reshape((1, 32*32)) ## Part 2: Feed the model with the unseen image, encode/decode the image with tf.Session() as sess: sess.run(tf.global_variables_initializer()) sess.run(iter.initializer, feed_dict={x: x_test_1, batch_size: 1}) ## Part 3: Print the real and reconstructed image # Restore variables from disk. saver.restore(sess, "./model.ckpt") print("Model restored.") # Reconstruct image outputs_val = outputs.eval() print(outputs_val.shape) fig = plt.figure() # Plot real ax1 = fig.add_subplot(121) plot_image(x_test_1, shape=[32, 32], cmap = "Greys_r") # Plot estimated ax2 = fig.add_subplot(122) plot_image(outputs_val, shape=[32, 32], cmap = "Greys_r") plt.tight_layout() fig = plt.gcf()
評価関数が定義されたので、再構成された画像13を見てみましょう。
reconstruct_image(df =test_x, image_number = 13)
INFO:tensorflow:Restoring parameters from ./model.ckpt
Model restored.
(1, 1024)
図では、左側に元のテスト画像、右側にオートエンコーダーの出力画像が配置されているため、1024から150への圧縮後の細かいディテールの損失を容易に判断できます。




