Keras:複数の入力と混合データ入力を作成するためのニューラルネットワークモデル



Keras Neural Network Model



このチュートリアルの最初の部分では、簡単に復習します 混合データ コンセプトと Kerasは複数のタイプの入力データをどのように受け入れますか?
次に、住宅価格データセットとデータセットのディレクトリ構造を紹介します。
次に、次の方法を説明します。

  1. ディスクから値、カテゴリ、およびイメージタイプのデータをロードします。
  2. データはネットワークトレーニングのために前処理されます。
  3. マルチ入力Kerasネットワークに適用できるように、データを混合する準備をしてください。

データの準備ができたら、Kerasを使用してマルチ入力エンドツーエンドネットワークモデルを定義およびトレーニングする方法を学習します。
最後に、テストセットの複数の入力モデルと混合データモデルを使用してモデルを評価し、その結果をこのシリーズの以前の記事と比較します。



混合データとは何ですか?

画像
図1:柔軟なKerasディープラーニングフレームワークを使用して、混合データを個別に処理するためのCNNおよびMLPブランチを含む多入力モデルを定義できます。

混合データとは、異なるデータ型の入力データを同時に使用することを指します。
たとえば、私たちが病院で患者の健康を分類するシステムを開発するために働いている機械学習エンジニアであるとします。
患者の入力データには、次のような複数の種類があります。



  1. 数値/連続値 年齢、心拍数、血圧など
  2. カテゴリ値 、性別と民族性を含む
  3. 画像データ MRI、xチップなど。

私たちの機械学習モデルは、「データを混合」**して、患者の健康について(正確な)予測を行うことができなければなりません。

混合データを処理できる機械学習システムの開発は、データタイプごとにスケーリング、標準化、機能エンジニアリングなどの個別の前処理ステップが必要になる可能性があるため、非常に困難です。

混合データの処理は依然として非常にオープンな研究分野であり、特定のタスク/目的に大きく依存することがよくあります。



今日のチュートリアルでは、混合データを使用して、それに関連するいくつかの課題を理解できるようにします。

Kerasはどのように複数の入力を受け入れますか?

画像
図2:Kerasの機能APIは、シーケンシャルAPIよりも複雑なモデルを可能にします。このブログ投稿では、関数APIを使用して、住宅価格予測用の複数の入力データと混合データを含むモデルを作成します。

Kerasは、関数APIを介して複数の入力(または複数の出力)を処理できます。

以前、シーケンシャルAPIでSequentialクラスを使用しましたが、これとは対照的に、次のようなはるかに複雑で非シーケンシャルなモデルを定義するために使用できます。

  • 複数入力モデル
  • 複数出力モデル
  • モデルには複数の入力と複数の出力が含まれます
  • 有向非巡回グラフ
  • 共有レイヤーを使用したモデル

たとえば、単純なシーケンスニューラルネットワークを次のように定義できます。

model = Sequential() model.add(Dense(8, input_shape=(10,), activation='relu')) model.add(Dense(4, activation='relu')) model.add(Dense(1, activation='linear'))

ネットワークは、10個の入力を持つ単純なフィードフォワードニューラルネットワークであり、最初の隠れ層には8つのノードがあり、2番目の隠れ層には4つのノードがあり、最後の出力層は回帰に使用されます。

機能APIを使用してサンプルニューラルネットワークを定義できます。

inputs = Input(shape=(10,)) x = Dense(8, activation='relu')(inputs) x = Dense(4, activation='relu')(x) x = Dense(1, activation='linear')(x) model = Model(inputs, x)

このようにして、Sequentialクラスに依存しなくなりました。

Keras関数APIの能力を理解するために、複数の入力を受け入れるモデルを作成した次のコードについて考えてみます。

# define two sets of inputs inputA = Input(shape=(32,)) inputB = Input(shape=(128,)) # the first branch operates on the first input x = Dense(8, activation='relu')(inputA) x = Dense(4, activation='relu')(x) x = Model(inputs=inputA, outputs=x) # the second branch opreates on the second input y = Dense(64, activation='relu')(inputB) y = Dense(32, activation='relu')(y) y = Dense(4, activation='relu')(y) y = Model(inputs=inputB, outputs=y) # combine the output of the two branches combined = concatenate([x.output, y.output]) # apply a FC layer and then a regression prediction on the # combined outputs z = Dense(2, activation='relu')(combined) z = Dense(1, activation='linear')(z) # our model will accept the inputs of the two branches and # then output a single value model = Model(inputs=[x.input, y.input], outputs=z)

ここで、Kerasニューラルネットワークへの2つの入力を定義したことがわかります。

  • inputA:32次元
  • inputB:128次元

21〜23行目:単純な32〜8〜4のネットワークは、Keras関数APIを使用して定義されています。
26〜29行目:128〜64〜32〜4のネットワークを定義します。
32行目は、xとyの出力を組み合わせたものです。 xとyの出力はどちらも4次元であるため、これらを接続すると、8次元のベクトルが得られます。
次に、ライン36と37に2つの完全に接続されたレイヤーを適用します。最初のレイヤーには2つのノードがあり、次にReLUがアクティブ化され、2番目のレイヤーには線形アクティブ化レイヤーを持つノードが1つだけあります。
マルチ入力モデルを構築する最後のステップは、Modelオブジェクトを定義することです。

  • 2つの入力を受け入れる
  • 出力をFCレイヤーの出力として定義します(つまり、z)

Kerasを使用してモデルアーキテクチャを視覚化すると、次のようになります。
画像
図3:このモデルには2つの入力ブランチがあり、最終的にマージして出力を生成します。 Keras関数APIはこのタイプのアーキテクチャーを可能にし、想像できる他のアーキテクチャーを構築することができます。

モデルには2つの異なるブランチがあることに注意してください。

最初のブランチは128次元の入力を受け入れ、2番目のブランチは32次元の入力を受け入れます。これらのブランチは、接続前は互いに独立して実行され、接続後に値を出力します。
このチュートリアルの残りの部分では、Kerasを使用して多入力ネットワークを作成する方法を学習します。

住宅価格データセット

画像
図4:住宅価格データセットには、数値データ、カテゴリデータ、および画像データが含まれています。 Kerasを使用して、複数の入力データ型と混合データ型をサポートするモデルを構築し、この回帰モデルを使用して家の価値を予測します。

このシリーズの記事では、2016年にAhmedとMustafaによって発行された論文「視覚的およびテキスト的特徴からの推奨住宅価格」を使用しました( 視覚的およびテキスト的特徴からの住宅価格の見積もり )住宅価格データセット。

このデータセットには、535のサンプル住宅の数値データ、カテゴリデータ、および画像データが含まれています。

数値属性と分類属性は次のとおりです。

  1. 寝室の数
  2. 浴室の量
  3. エリア(エリア)
  4. 郵便番号

各家に合計4枚の写真が用意されています。

  1. 寝室
  2. バスルーム
  3. キッチン
  4. 家の前

このシリーズの最初の記事では、数値データとカテゴリデータに基づいてKeras回帰ネットワークをトレーニングする方法を学びました。
このシリーズの2番目の記事では、回帰にKerasCNNを使用する方法を学びました。
今日は、Kerasを使用して複数の入力データと混合データを処理します。

数値データ、カテゴリデータ、画像データを受け入れ、ネットワークの2つのブランチを定義して各タイプのデータを処理し、最後にこれらのブランチを組み合わせて最終的な住宅価格の予測を取得します。このようにして、Kerasで複数の入力データと混合データを処理できるようになります。

住宅価格データセットを取得する

ソースコードをダウンロードするには、ここをクリックしてください。 https://jbox.sjtu.edu.cn/l/NHfFZu

zipファイルを入手したら、ファイルが配置されているディレクトリに移動して、ファイルを抽出します。

$ cd path/to/zip $ unzip keras-multi-input.zip $ cd keras-multi-input

次に、次のコマンドを使用してデータセットをダウンロードできます。

$ git clone https://github.com/emanhamed/Houses-dataset

これで、住宅価格データセットは、このプロジェクトで使用するディレクトリであるkeras-multi-inputディレクトリにあるはずです。

プロジェクト構造

今日のプロジェクトがどのように編成されているか見てみましょう。

$ tree --dirsfirst --filelimit 10 . ├── Houses-dataset │ ├── Houses Dataset [2141 entries] │ └── README.md ├── pyimagesearch │ ├── __init__.py │ ├── datasets.py │ └── models.py └── mixed_training.py 3 directories, 5 files

Houses-datasetフォルダーには、このシリーズで使用する住宅価格データセットが含まれています。 mixed_training.pyスクリプトを実行する準備ができたら、データセットへのコマンドライン引数としてパスを指定するだけで済みます(これがどのように行われるかについては、結果のセクションで詳しく説明します)。

今日は、3つのPythonスクリプトを確認します。

  • Pyimagesearch / datasets.py:デジタルデータ、カテゴリデータ、画像データを読み込んで前処理します。

  • Pyimagesearch / models.py:多層パーセプトロン(MLP)と畳み込みニューラルネットワーク(CNN)が含まれています。これらのコンポーネントは、多入力混合データモデルの入力ブランチです。

  • Mixed_training.py:最初にトレーニングスクリプトが使用しますpyimagesearchモジュールはトレーニングデータセットをロードして分割し、データヘッダーを追加して、2つのブランチをネットワークに接続します。次に、モデルがトレーニングされ、評価されます。

数値データとカテゴリデータを読み込む

画像
図5:Pythonパッケージpandaを使用してCSV住宅データを読み取ります。

data .pyファイルを開き、次のコードを挿入します。

# import the necessary packages from sklearn.preprocessing import LabelBinarizer from sklearn.preprocessing import MinMaxScaler import pandas as pd import numpy as np import glob import cv2 import os def load_house_attributes(inputPath): # initialize the list of column names in the CSV file and then # load it using Pandas cols = ['bedrooms', 'bathrooms', 'area', 'zipcode', 'price'] df = pd.read_csv(inputPath, sep=' ', header=None, names=cols) # determine (1) the unique zip codes and (2) the number of data # points with each zip code zipcodes = df['zipcode'].value_counts().keys().tolist() counts = df['zipcode'].value_counts().tolist() # loop over each of the unique zip codes and their corresponding # count for (zipcode, count) in zip(zipcodes, counts): # the zip code counts for our housing dataset is *extremely* # unbalanced (some only having 1 or 2 houses per zip code) # so let's sanitize our data by removing any houses with less # than 25 houses per zip code if count <25: idxs = df[df['zipcode'] == zipcode].index df.drop(idxs, inplace=True) # return the data frame return df

行10-33 load_house_attributes functionで定義します。この関数は渡されますpanda of pd数値およびカテゴリデータは、CSVファイルとして設定された価格データから読み取られます。 13行目と14行目はread_csvです。

サンプル分布の不均一性に対応するために、生データをフィルタリングする必要があります。一部の郵便番号が1つまたは2つの家だけで表されている場合、25未満の家の郵便番号からすべてのレコードを削除します(23〜30行目)。郵便番号サンプルの不均一な分布の問題を軽減することができ、その結果、より正確なモデルが得られます。

今すぐ定義しましょうprocess_house_attributes関数:

def process_house_attributes(df, train, test): # initialize the column names of the continuous data continuous = ['bedrooms', 'bathrooms', 'area'] # performin min-max scaling each continuous feature column to # the range [0, 1] cs = MinMaxScaler() trainContinuous = cs.fit_transform(train[continuous]) testContinuous = cs.transform(test[continuous]) # one-hot encode the zip code categorical data (by definition of # one-hot encoding, all output features are now in the range [0, 1]) zipBinarizer = LabelBinarizer().fit(df['zipcode']) trainCategorical = zipBinarizer.transform(train['zipcode']) testCategorical = zipBinarizer.transform(test['zipcode']) # construct our training and testing data points by concatenating # the categorical features with the continuous features trainX = np.hstack([trainCategorical, trainContinuous]) testX = np.hstack([testCategorical, testContinuous]) # return the concatenated training and testing data return (trainX, testX)

この関数は渡されますscikit-learn of MinMaxScaler(行41-43)連続フィーチャに最小-最大スケーリングを適用します。
次に、pass scikit-learn of LabelBinarizer(47〜49行目)分類機能のワンホットエンコーディングを計算します。
次に、連続および分類された機能を結合して戻ります(53〜57行目)。

画像データセットの読み込み

画像
図6:モデルのブランチは画像を受け入れます-家からの4つの画像の平坦化された画像。平坦化された画像を数値、カテゴリデータ、別のブランチへの入力と組み合わせて使用​​すると、モデルはKerasフレームワークを使用して回帰し、家の価値を予測します。

次のステップは、入力画像をロードするためのa helper関数を定義することです。ここでも、data .pyファイルを開き、次のコードを挿入します。

def load_house_images(df, inputPath): # initialize our images array (i.e., the house images themselves) images = [] # loop over the indexes of the houses for i in df.index.values: # find the four images for the house and sort the file paths, # ensuring the four are always in the *same order* basePath = os.path.sep.join([inputPath, '{}_*'.format(i + 1)]) housePaths = sorted(list(glob.glob(basePath)))

load_house_imagesこの関数には3つの関数があります。

  1. 住宅価格データセットからすべての写真を読み込みます。各家に4枚の写真があることを思い出してください(図6)。
  2. 4枚の写真から1枚の平坦化された画像を生成します。平坦化された画像は、常に図に表示されている順序で配置されます。
  3. これらすべてのマスターマスクをリスト/配列に追加し、呼び出し元の関数に戻ります。

59行目から、panda dataframe with dataset inputPathを受け入れる関数を定義します。

次に続けます:

  • 画像リストを初期化し(61行目)、作成したすべてのフラット化された画像をこのリストに入力します。
  • データフレーム内の家をループして(64行目)、現在の家の4枚の写真(67行目と68行目)へのパスを取得します。

ループの内部を引き続き見ていきましょう。

# initialize our list of input images along with the output image # after *combining* the four input images inputImages = [] outputImage = np.zeros((64, 64, 3), dtype='uint8') # loop over the input house paths for housePath in housePaths: # load the input image, resize it to be 32 32, and then # update the list of input images image = cv2.imread(housePath) image = cv2.resize(image, (32, 32)) inputImages.append(image) # tile the four input images in the output image such the first # image goes in the top-right corner, the second image in the # top-left corner, the third image in the bottom-right corner, # and the final image in the bottom-left corner outputImage[0:32, 0:32] = inputImages[0] outputImage[0:32, 32:64] = inputImages[1] outputImage[32:64, 32:64] = inputImages[2] outputImage[32:64, 0:32] = inputImages[3] # add the tiled image to our set of images the network will be # trained on images.append(outputImage) # return our set of images return np.array(images)

これまでのところ、コードは上記の最初の目標を完了しています(家ごとに4つの画像)。

  • ループでは、次のことを行います。

    • 初期化を実行します(72行目と73行目)。私たちのinputImages各レコードの4枚の写真がリストとして含まれます。 our inputImages写真のステッチ画像になります(図6を参照)。

    • ループ4の写真(76行目):

      • 各写真をロード、サイズ変更、およびinputImages Mediumに添付します(79〜81行目)。
    • 4つの家の写真(87〜90行目)のタイル(ステッチ画像)を作成します。

      • 左上のバスルームの写真。
      • 右上隅の寝室の写真。
      • 右下隅の正面図。
      • キッチンは左下隅にあります。
    • ステッチを追加outputImage To images(94行目)。

  • ループから飛び出して、すべての画像をNumPy配列として返します(97行目)。

並べて表示された各画像は、図6のようになります(もちろん、オーバーレイテキストはありません)。 4枚の写真がつなぎ合わされていることがわかります(コードの動作をよりよく視覚化できるように、より大きな画像サイズを使用しました)。私たちのデジタル属性とカテゴリ属性が家を表すように、これらの4枚の写真(写真に並べて表示)は家の視覚的美学を表します。

多層パーセプトロン(MLP)と畳み込みニューラルネットワーク(CNN)を定義する

画像
図7:Kerasマルチ入力(ハイブリッドデータ)モデルには、数値/カテゴリデータを受け入れる1つのブランチ(左)と、4枚の写真ステッチで画像データを受け入れるもう1つのブランチ(右)があります。

これまで、複数のライブラリを使用してデータを慎重に処理してきました:Panda, scikit-learn, OpenCV, and NumPy
合格しましたdatasets.pyデータセットの2つのモードが整理され、前処理されます。

  • デジタルおよびカテゴリデータ
  • 画像データ

これを達成するために、私たちが使用するスキルは、経験と実践による少しのデバッグを通じて開発されます。これまで議論して使用してきたデータ処理技術は、プロジェクトの成功の鍵であるため、無視しないでください。

トピックを変更して、Keras関数APIを使用してマルチ入力およびハイブリッドデータネットワークを構築する方法について説明しましょう。

マルチ入力ネットワークを構築するには、次の2つのブランチが必要です。

  • 最初のブランチは、数値入力を処理する単純な多層パーセプトロン(MLP)です。
  • 2番目のブランチは、画像データを操作する畳み込みニューラルネットワークです。
  • 次に、これらのブランチを結合して、最終的なマルチ入力Kerasモデルを形成します。

次のセクションでは、最終的な接続された多入力モデルの構築を扱います。現在のタスクは、これら2つのブランチを定義することです。

オンmodels.pyファイル、次のコードを挿入します。

# import the necessary packages from keras.models import Sequential from keras.layers.normalization import BatchNormalization from keras.layers.convolutional import Conv2D from keras.layers.convolutional import MaxPooling2D from keras.layers.core import Activation from keras.layers.core import Dropout from keras.layers.core import Dense from keras.layers import Flatten from keras.layers import Input from keras.models import Model def create_mlp(dim, regress=False): # define our MLP network model = Sequential() model.add(Dense(8, input_dim=dim, activation='relu')) model.add(Dense(4, activation='relu')) # check to see if the regression node should be added if regress: model.add(Dense(1, activation='linear')) # return our model return model

カテゴリ/数値データは、単純な多層パーセプトロン(MLP)によって処理されます。
MLP by create_mlp 13〜24行目で定義されています。
私たちのMLPは単純です:

  • ReLUアクティベーションを備えた完全に接続された(高密度の)入力レイヤー(16行目)。
  • RELUアクティベーションを備えた完全に接続された隠れ層(17行目)。
  • 最後に、線形にアクティブ化されたオプションの回帰出力(20行目と21行目)。

最初の記事ではMLPの回帰出力を使用しましたが、この多入力混合データネットワークでは使用されていません。すぐにわかるように、デフォルトであっても、regress = Falseを明示的に設定します。 回帰は、後でマルチ入力混合データネットワーク全体の先頭で実行されます(図7の下部)

MLPブランチは24行目に戻ります。

図7によると、ネットワークの左上のブランチが構築されました。

それでは、ネットワークの右上隅であるCNNを定義しましょう。

def create_cnn(width, height, depth, filters=(16, 32, 64), regress=False): # initialize the input shape and channel dimension, assuming # TensorFlow/channels-last ordering inputShape = (height, width, depth) chanDim = -1 # define the model input inputs = Input(shape=inputShape) # loop over the number of filters for (i, f) in enumerate(filters): # if this is the first CONV layer then set the input # appropriately if i == 0: x = inputs # CONV => RELU => BN => POOL x = Conv2D(f, (3, 3), padding='same')(x) x = Activation('relu')(x) x = BatchNormalization(axis=chanDim)(x) x = MaxPooling2D(pool_size=(2, 2))(x)

create_cnnこの関数は画像データを処理し、次の5つのパラメーターを受け入れます。

  • 幅:入力画像の幅(ピクセル単位)。
  • 高さ:入力画像の高さ(ピクセル単位)。
  • 深さ:画像のチャンネル数を入力します。 RGBカラー画像の場合は3です。
  • フィルタ:大きくなる一連のフィルタ。これにより、ネットワークは機能の区別についてさらに学習できます。
  • 回帰:完全に接続された線形アクティベーションレイヤーが回帰のためにCNNに追加されるかどうかを示すブール値。

私たちのネットワークinputShape 29行目で定義されています。
モデルの入力が渡されますinputShape(33行目)が定義されています。
ここから、フィルターのトラバースを開始し、CONV => RELU> BN => POOLレイヤーのセットを作成します。これらのレイヤーは、ループの反復ごとに累積されます。

CNNネットワークブランチの構築を完了しましょう。

# flatten the volume, then FC => RELU => BN => DROPOUT x = Flatten()(x) x = Dense(16)(x) x = Activation('relu')(x) x = BatchNormalization(axis=chanDim)(x) x = Dropout(0.5)(x) # apply another FC layer, this one to match the number of nodes # coming out of the MLP x = Dense(4)(x) x = Activation('relu')(x) # check to see if the regression node should be added if regress: x = Dense(1, activation='linear')(x) # construct the CNN model = Model(inputs, x) # return the CNN return model

次のレイヤーをフラット化し(49行目)、抽出されたすべての特徴を1次元の特徴ベクトルに結合してから、BatchNormalizationとDropoutを使用して完全に接続されたレイヤーを追加します(50〜53行目)。

別の完全に接続された層を使用して、多層パーセプトロンからの4つのノード(57行目と58行目)を一致させます。一致するノードの数は必須ではありませんが、ブランチのバランスを取るのに役立ちます。

61行目と62行目で、回帰ノードが追加されているかどうかを確認し、必要に応じて追加します。実際、このブランチの終わりには戻りません。回帰は、多入力混合データネットワークの先頭で実行されます(図7の下部)。

最後に、モデルは、入力して組み立てるすべてのレイヤーで構成されます。 CNNブランチを呼び出し元の関数に戻すことができます(68行目)。

マルチ入力Kerasモデルの2つのブランチを定義したので、それらを組み合わせる方法を学びましょう!

Kerasからの複数の入力を使用する

これで、複数の入力データと混合データを処理できる最終的なKerasモデルを構築する準備が整いました。これは枝が集まる場所です-「魔法」が起こる場所です。
トレーニングもこのスクリプトで行われます。

名前を作成するmixed_training.py新しいファイルを開き、次のコードを挿入します。

# import the necessary packages from pyimagesearch import datasets from pyimagesearch import models from sklearn.model_selection import train_test_split from keras.layers.core import Dense from keras.models import Model from keras.optimizers import Adam from keras.layers import concatenate import numpy as np import argparse import locale import os # construct the argument parser and parse the arguments ap = argparse.ArgumentParser() ap.add_argument('-d', '--dataset', type=str, required=True, help='path to input dataset of house images') args = vars(ap.parse_args())

まず、必要なモジュールをインポートして、コマンドライン引数を解析しましょう。

  • datasets:私たちの3つの便利な機能は、家のデータセットからCSVデータをロード/処理し、家の写真をロード/前処理します。
  • models:MLPおよびCNN入力ブランチは、多入力ハイブリッドデータサービスとして機能します。
  • train_test_split:1つscikit-learnトレーニング/テストデータのセグメンテーションを構築する関数。
  • concatenate:複数の入力を受け入れる特別なKeras関数。
  • argparse:解析コマンドライン引数を処理しています。

15〜18行目には、解析する必要のあるコマンドライン引数があります。つまり、datasetは、価格データセットをダウンロードするためのパスです。

次に、数値/カテゴリデータと画像データをロードしましょう。

# construct the path to the input .txt file that contains information # on each house in the dataset and then load the dataset print('[INFO] loading house attributes...') inputPath = os.path.sep.join([args['dataset'], 'HousesInfo.txt']) df = datasets.load_house_attributes(inputPath) # load the house images and then scale the pixel intensities to the # range [0, 1] print('[INFO] loading house images...') images = datasets.load_house_images(df, args['dataset']) images = images / 255.0

ここでは、住宅価格データセットをpanda dataframeとしてロードします(23行目と24行目)。次に、画像をロードして[0,1]に拡大縮小します(29〜30行目)。
これらの関数の基本的な機能を思い出させる必要がある場合は、上記のload_house_attributes with load_house_images関数を必ず確認してください。
データが読み込まれたので、トレーニング/テストセグメンテーションを構築し、価格を調整して、プロパティのプロパティを処理します。

# partition the data into training and testing splits using 75% of # the data for training and the remaining 25% for testing print('[INFO] processing data...') split = train_test_split(df, images, test_size=0.25, random_state=42) (trainAttrX, testAttrX, trainImagesX, testImagesX) = split # find the largest house price in the training set and use it to # scale our house prices to the range [0, 1] (will lead to better # training and convergence) maxPrice = trainAttrX['price'].max() trainY = trainAttrX['price'] / maxPrice testY = testAttrX['price'] / maxPrice # process the house attributes data by performing min-max scaling # on continuous features, one-hot encoding on categorical features, # and then finally concatenating them together (trainAttrX, testAttrX) = datasets.process_house_attributes(df, trainAttrX, testAttrX)

トレーニングとテストは35行目と36行目で実施されました。データの75%をトレーニングに割り当て、データの25%をテストに割り当てました。

これに基づいて、トレーニングセットからそれを見つけます(41行目)maxPriceそれに応じてトレーニングとテストデータを調整します(42行目と43行目)。値データを[0,1]の範囲に調整すると、トレーニングと収束が向上します。

最後に、連続特徴の最小-最大スケーリングを実行し、分類特徴の熱エンコードを実行することにより、家のプロパティを処理し続けます。

process_house_attributesこの関数はこれらの操作を処理し、連続するカテゴリプロパティを結合して、結果を返します(48行目と49行目)。

魔法をかける準備はできましたか?
はい、嘘をつきました。コードの次のブロックには実際には「魔法」はありません!ただし、ネットワークブランチを接続して、マルチ入力Kerasネットワークを完成させます。

# create the MLP and CNN models mlp = models.create_mlp(trainAttrX.shape[1], regress=False) cnn = models.create_cnn(64, 64, 3, regress=False) # create the input to our final set of layers as the *output* of both # the MLP and CNN combinedInput = concatenate([mlp.output, cnn.output]) # our final FC layer head will have two dense layers, the final one # being our regression head x = Dense(4, activation='relu')(combinedInput) x = Dense(1, activation='linear')(x) # our final model will accept categorical/numerical data on the MLP # input and images on the CNN input, outputting a single value (the # predicted price of the house) model = Model(inputs=[mlp.input, cnn.input], outputs=x)

コードとモデルを整理したら、Kerasを使用して複数の入力を処理するのは非常に簡単です。

52行目と53行目で、mlpモデルとcnnモデルを作成します。 regress = Falseに注意してください-リターンヘッダーは62行目の後に表示されます。

次に、57行目に示すようにmlp出力とcnn出力を接続します。これをours combinedInputと呼びます。これはネットワークの他の部分への入力であるためです(図3に示すように、これはconcatenate_1、2つのブランチを一緒に)。

ネットワークの最後の層の結合された入力は、MLPおよびCNNブランチの8-4-1 FC層の出力に基づいています(両方のブランチが4次元FC層を出力するため、それらを結合して8を作成します) -次元ベクトル)。

4つのニューロンの完全に接続された層を修正しましたcombinedInputオン(61行目)。次に、 'lineractivationリターンヘッド(62行目)を追加します。その出力は予測価格です。

新しく形成されたモデルのコンパイル、トレーニング、評価を続けましょう。

# compile the model using mean absolute percentage error as our loss, # implying that we seek to minimize the absolute percentage difference # between our price *predictions* and the *actual prices* opt = Adam(lr=1e-3, decay=1e-3 / 200) model.compile(loss='mean_absolute_percentage_error', optimizer=opt) # train the model print('[INFO] training model...') model.fit( [trainAttrX, trainImagesX], trainY, validation_data=([testAttrX, testImagesX], testY), epochs=200, batch_size=8) # make predictions on the testing data print('[INFO] predicting house prices...') preds = model.predict([testAttrX, testImagesX])

私たちのモデルは 'mean_absolute_percentage_error'損失と1つを使用していますAdamオプティマイザーによってコンパイルされたオプティマイザーには、学習率の減衰があります(72行目と73行目)。

トレーニングは77〜80行目から始まります。これはモデルフィッティングと呼ばれます(つまり、所有権の重みがバックプロパゲーションと呼ばれるプロセスによって調整されます)。

テストデータセットを介して呼び出されますmodel.predict(行84)モデルによって予測されたモデル値を取得して、モデルを評価できます。

ここで評価してみましょう:

# compute the difference between the *predicted* house prices and the # *actual* house prices, then compute the percentage difference and # the absolute percentage difference diff = preds.flatten() - testY percentDiff = (diff / testY) * 100 absPercentDiff = np.abs(percentDiff) # compute the mean and standard deviation of the absolute percentage # difference mean = np.mean(absPercentDiff) std = np.std(absPercentDiff) # finally, show some statistics on our model locale.setlocale(locale.LC_ALL, 'en_US.UTF-8') print('[INFO] avg. house price: {}, std house price: {}'.format( locale.currency(df['price'].mean(), grouping=True), locale.currency(df['price'].std(), grouping=True))) print('[INFO] mean: {:.2f}%, std: {:.2f}%'.format(mean, std))

モデルを評価するために、絶対パーセンテージを計算し(89〜91行目)、それを使用して最終的なメトリックを導き出しました(95行目と96行目)。
これらのメトリック(価格平均の平均、価格標準偏差と絶対パーセンテージ、および標準偏差)は、適切な形式で端末に出力されます(行100〜103)。

複数の入力と混合データの結果

画像
図8:不動産価格の予測は難しい作業ですが、Kerasの多入力および混合入力回帰モデルでは、限られた住宅価格データセットで良好な結果が得られました。

最後に、混合データでマルチ入力ネットワークをトレーニングします。

準備ができていることを確認してください。

  1. このシリーズの最初のチュートリアルに従って、開発環境を構成します。
  2. このチュートリアルのソースコードを使用してください。
  3. 上記の「価格データセットの取得」セクションの手順を使用して、価格データセットをダウンロードします。

これに基づいて、ターミナルを開き、次のコマンドを実行してネットワークトレーニングを開始します。

$ python mixed_training.py --dataset Houses-dataset/Houses Dataset/ [INFO] training model... Train on 271 samples, validate on 91 samples Epoch 1/200 271/271 [==============================] - 2s 8ms/step - loss: 240.2516 - val_loss: 118.1782 Epoch 2/200 271/271 [==============================] - 1s 5ms/step - loss: 195.8325 - val_loss: 95.3750 Epoch 3/200 271/271 [==============================] - 1s 5ms/step - loss: 121.5940 - val_loss: 85.1037 Epoch 4/200 271/271 [==============================] - 1s 5ms/step - loss: 103.2910 - val_loss: 72.1434 Epoch 5/200 271/271 [==============================] - 1s 5ms/step - loss: 82.3916 - val_loss: 61.9368 Epoch 6/200 271/271 [==============================] - 1s 5ms/step - loss: 81.3794 - val_loss: 59.7905 Epoch 7/200 271/271 [==============================] - 1s 5ms/step - loss: 71.3617 - val_loss: 58.8067 Epoch 8/200 271/271 [==============================] - 1s 5ms/step - loss: 72.7032 - val_loss: 56.4613 Epoch 9/200 271/271 [==============================] - 1s 5ms/step - loss: 52.0019 - val_loss: 54.7461 Epoch 10/200 271/271 [==============================] - 1s 5ms/step - loss: 62.4559 - val_loss: 49.1401 ... Epoch 190/200 271/271 [==============================] - 1s 5ms/step - loss: 16.0892 - val_loss: 22.8415 Epoch 191/200 271/271 [==============================] - 1s 5ms/step - loss: 16.1908 - val_loss: 22.5139 Epoch 192/200 271/271 [==============================] - 1s 5ms/step - loss: 16.9099 - val_loss: 22.5922 Epoch 193/200 271/271 [==============================] - 1s 5ms/step - loss: 18.6216 - val_loss: 26.9679 Epoch 194/200 271/271 [==============================] - 1s 5ms/step - loss: 16.5341 - val_loss: 23.1445 Epoch 195/200 271/271 [==============================] - 1s 5ms/step - loss: 16.4120 - val_loss: 26.1224 Epoch 196/200 271/271 [==============================] - 1s 5ms/step - loss: 16.4939 - val_loss: 23.1224 Epoch 197/200 271/271 [==============================] - 1s 5ms/step - loss: 15.6253 - val_loss: 22.2930 Epoch 198/200 271/271 [==============================] - 1s 5ms/step - loss: 16.0514 - val_loss: 23.6948 Epoch 199/200 271/271 [==============================] - 1s 5ms/step - loss: 17.9525 - val_loss: 22.9743 Epoch 200/200 271/271 [==============================] - 1s 5ms/step - loss: 16.0377 - val_loss: 22.4130 [INFO] predicting house prices... [INFO] avg. house price: $533,388.27, std house price: $493,403.08 [INFO] mean: 22.41%, std: 20.11%

私たちの平均絶対パーセント誤差は非常に高く始まりましたが、トレーニングプロセス全体を通して減少し続けました。
トレーニングの最後に、テストセットの22.41%の絶対誤差が発生しました。これは、ネットワークの住宅価格の予測が平均で約22%低下することを意味します。

この結果を、このシリーズの以前の2つの記事と比較します。

  1. MLPは数値/カテゴリデータにのみ使用してください:26.01%
  2. CNNのみを使用した画像データ:56.91%
  3. 混合データを使用する:22.41%

ご覧のとおり、混合データを処理する方法は次のとおりです。

  1. デジタル/ lカテゴリデータと画像データを組み合わせる
  2. 複数の入力モデルでの混合データのトレーニング。
  3. より良いパフォーマンスモデルをもたらしました!

総括する

このチュートリアルでは、複数の入力を受け入れることができるKerasネットワークを定義する方法を学びました。

また、Kerasを使用して混合データを処理する方法も学びました。

これらの目標を達成するために、許容可能なマルチ入力ニューラルネットワークを定義します。

  • 数値データ
  • 分類データ
  • 画像データ

数値データの最小-最大は、トレーニング前に[0,1]の範囲にスケーリングされます。カテゴリデータはone-hotエンコードされています(結果の整数ベクトルが[0,1]の範囲内にあることを確認してください)。

次に、値とカテゴリのデータが連結されて、Kerasネットワークへの最初の入力を形成する特徴ベクトルになります。

画像データも[0、1]の範囲にスケーリングされます。このデータは、Kerasネットワークへの2番目の入力です。

モデルの1つのブランチには、厳密に完全に接続されたレイヤー(接続された数値データとカテゴリデータ用)が含まれ、マルチ入力モデルの2番目のブランチは本質的に小さな畳み込みニューラルネットワークです。

2つのブランチの出力を組み合わせて、出力を定義します(回帰予測)。

このようにして、複数の入力ネットワークをエンドツーエンドでトレーニングできるため、入力の1つだけを使用するよりも精度が高くなります。

翻訳元: Keras:AdrianRosebrockによる複数の入力と混合データ。