web-dev-qa-db-ja.com

Keras:マスキングとフラット化

マスクされた入力値を処理する単純なモデルを構築するのが困難です。私のトレーニングデータは、GPSトレースの可変長リスト、つまり各要素に緯度と経度が含まれているリストで構成されています。

70のトレーニング例があります

enter image description here

それらは可変長であるため、ゼロを埋め込んでいます。これは、これらのゼロ値を無視するようにKerasに指示するためです。

train_data = keras.preprocessing.sequence.pad_sequences(train_data, maxlen=max_sequence_len, dtype='float32', 
                                           padding='pre', truncating='pre', value=0)

enter image description here

次に、このような非常に基本的なモデルを作成します

model = Sequential()
model.add(Dense(16, activation='relu',input_shape=(max_sequence_len, 2)))
model.add(Flatten())
model.add(Dense(2, activation='sigmoid'))

以前の試行錯誤の後、Flattenレイヤーが必要であるか、モデルをフィッティングするとエラーがスローされることに気付きました

ValueError: Error when checking target: expected dense_87 to have 3 dimensions, but got array with shape (70, 2)

ただし、このFlattenレイヤーを含めると、Maskingレイヤーを使用できなくなり(埋め込みゼロを無視するため)、Kerasがこのエラーをスローします

TypeError: Layer flatten_31 does not support masking, but was passed an input_mask: Tensor("masking_9/Any_1:0", shape=(?, 48278), dtype=bool)

GitHubの問題とたくさんのQ/Aを読んで、広範囲にわたって検索しましたが、わかりません。

10
Philip O'Brien

マスキングはバグがあるようです。ただし、心配しないでください。0はモデルを悪化させることはありません。せいぜい効率が悪い。

純粋な密集や多分RNNではなく、たたみ込みアプローチを使用することをお勧めします。これは、GPSデータに対して非常にうまく機能すると思います。

次のコードを試してください:

from keras.preprocessing.sequence import pad_sequences
from keras import Sequential
from keras.layers import Dense, Flatten, Masking, LSTM, GRU, Conv1D, Dropout, MaxPooling1D
import numpy as np
import random

max_sequence_len = 70

n_samples = 100
num_coordinates = 2 # lat/long

data = [[[random.random() for _ in range(num_coordinates)]
         for y in range(min(x, max_sequence_len))]
        for x in range(n_samples)]

train_y = np.random.random((n_samples, 2))

train_data = pad_sequences(data, maxlen=max_sequence_len, dtype='float32',
                           padding='pre', truncating='pre', value=0)

model = Sequential()
model.add(Conv1D(32, (5, ), input_shape=(max_sequence_len, num_coordinates)))
model.add(Dropout(0.5))
model.add(MaxPooling1D())
model.add(Flatten())
model.add(Dense(2, activation='relu'))
model.compile(loss='mean_squared_error', optimizer="adam")
model.fit(train_data, train_y)
3
PascalVKooten

Flattenレイヤーを使用する代わりに、Global Poolingレイヤーを使用できます。

これらは、可変長を使用する機能を失うことなく、長さ/時間ディメンションを縮小するのに適しています。

したがって、Flatten()の代わりに、GlobalAveragePooling1DまたはGlobalMaxPooling1Dを試すことができます。

コードでsupports_maskingを使用していないため、注意して使用する必要があります。

平均的なものは、最大値よりも多くの入力を考慮します(したがって、マスクする必要がある値)。

最大値は長さから1つだけです。運が良ければ、すべての有用な値がマスクされた位置の値よりも高い場合、間接的にマスクが保持されます。おそらく、他のニューロンよりもさらに多くの入力ニューロンが必要になります。

そうは言っても、はい、Conv1DまたはRNN(LSTM)のアプローチを試してみてください。


マスク付きのカスタムプーリングレイヤーの作成

独自のプーリングレイヤーを作成することもできます(モデルの入力とプールするテンソルの両方を渡す機能的なAPIモデルが必要です)。

以下は、入力に基づいてマスクを適用する平均プーリングの実際の例です。

def customPooling(maskVal):
    def innerFunc(x):
        inputs = x[0]
        target = x[1]

        #getting the mask by observing the model's inputs
        mask = K.equal(inputs, maskVal)
        mask = K.all(mask, axis=-1, keepdims=True)

        #inverting the mask for getting the valid steps for each sample
        mask = 1 - K.cast(mask, K.floatx())

        #summing the valid steps for each sample
        stepsPerSample = K.sum(mask, axis=1, keepdims=False)

        #applying the mask to the target (to make sure you are summing zeros below)
        target = target * mask

        #calculating the mean of the steps (using our sum of valid steps as averager)
        means = K.sum(target, axis=1, keepdims=False) / stepsPerSample

        return means

    return innerFunc


x = np.ones((2,5,3))
x[0,3:] = 0.
x[1,1:] = 0.


print(x)

inputs = Input((5,3))
out = Lambda(lambda x: x*4)(inputs)
out = Lambda(customPooling(0))([inputs,out])

model = Model(inputs,out)
model.predict(x)
1
Daniel Möller