web-dev-qa-db-ja.com

構造化データのリカレントニューラルネットワークに悩む理由

私は[instances, time, features]という形の構造化データを使用して、Kerasでフィードフォワードニューラルネットワーク(FNN)とリカレントニューラルネットワーク(RNN)を開発しており、FNNとRNNのパフォーマンスは同じです(ただし、RNNはより多くの計算時間を必要とします) )。

また、シリーズの次の値はシリーズの前の値に依存しているため、RNNがFNNよりも優れていると予想した表形式のデータ(以下のコード)もシミュレートしました。ただし、どちらのアーキテクチャも正しく予測します。

NLPデータでは、RNNはFNNよりも優れていますが、表形式のデータではそうではありません。一般的に、RNNが表形式のデータでFNNよりも優れていると予想されるのはいつですか?具体的には、誰かがRNNがFNNよりも優れていることを示す表形式のデータを含むシミュレーションコードを投稿できますか?

ありがとうございました!私のシミュレーションコードが私の質問に理想的でない場合は、それを適応させるか、より理想的なものを共有してください!

from keras import models
from keras import layers

from keras.layers import Dense, LSTM

import numpy as np
import matplotlib.pyplot as plt

2つのフィーチャが10タイムステップにわたってシミュレーションされました。2番目のフィーチャの値は、前のタイムステップの両方のフィーチャの値に依存しています。

## Simulate data.

np.random.seed(20180825)

X = np.random.randint(50, 70, size = (11000, 1)) / 100

X = np.concatenate((X, X), axis = 1)

for i in range(10):

    X_next = np.random.randint(50, 70, size = (11000, 1)) / 100

    X = np.concatenate((X, X_next, (0.50 * X[:, -1].reshape(len(X), 1)) 
        + (0.50 * X[:, -2].reshape(len(X), 1))), axis = 1)

print(X.shape)

## Training and validation data.

split = 10000

Y_train = X[:split, -1:].reshape(split, 1)
Y_valid = X[split:, -1:].reshape(len(X) - split, 1)
X_train = X[:split, :-2]
X_valid = X[split:, :-2]

print(X_train.shape)
print(Y_train.shape)
print(X_valid.shape)
print(Y_valid.shape)

FNN:

## FNN model.

# Define model.

network_fnn = models.Sequential()
network_fnn.add(layers.Dense(64, activation = 'relu', input_shape = (X_train.shape[1],)))
network_fnn.add(Dense(1, activation = None))

# Compile model.

network_fnn.compile(optimizer = 'adam', loss = 'mean_squared_error')

# Fit model.

history_fnn = network_fnn.fit(X_train, Y_train, epochs = 10, batch_size = 32, verbose = False,
    validation_data = (X_valid, Y_valid))

plt.scatter(Y_train, network_fnn.predict(X_train), alpha = 0.1)
plt.xlabel('Actual')
plt.ylabel('Predicted')
plt.show()

plt.scatter(Y_valid, network_fnn.predict(X_valid), alpha = 0.1)
plt.xlabel('Actual')
plt.ylabel('Predicted')
plt.show()

LSTM:

## LSTM model.

X_lstm_train = X_train.reshape(X_train.shape[0], X_train.shape[1] // 2, 2)
X_lstm_valid = X_valid.reshape(X_valid.shape[0], X_valid.shape[1] // 2, 2)

# Define model.

network_lstm = models.Sequential()
network_lstm.add(layers.LSTM(64, activation = 'relu', input_shape = (X_lstm_train.shape[1], 2)))
network_lstm.add(layers.Dense(1, activation = None))

# Compile model.

network_lstm.compile(optimizer = 'adam', loss = 'mean_squared_error')

# Fit model.

history_lstm = network_lstm.fit(X_lstm_train, Y_train, epochs = 10, batch_size = 32, verbose = False,
    validation_data = (X_lstm_valid, Y_valid))

plt.scatter(Y_train, network_lstm.predict(X_lstm_train), alpha = 0.1)
plt.xlabel('Actual')
plt.ylabel('Predicted')
plt.show()

plt.scatter(Y_valid, network_lstm.predict(X_lstm_valid), alpha = 0.1)
plt.xlabel('Actual')
plt.ylabel('Predicted')
plt.show()

実際には、NLPでも、RNNとCNNはしばしば競争力があることがわかります。 Here's これをより詳細に示す2017年のレビューペーパー。理論上は、RNNが言語の完全な複雑さと順次性をより適切に処理できる場合があるかもしれませんが、実際には、より大きな障害は通常、ネットワークを適切にトレーニングすることであり、RNNは細心の注意が必要です。

機能する可能性のある別の問題は、バランスのとれた括弧の問題(文字列内の括弧のみ、または他の邪魔文字と一緒の括弧)のような問題を調べることです。これには、入力を順次処理していくつかの状態を追跡する必要があり、LSTMを使用してFFNを使用する方が学習しやすい場合があります。

更新:シーケンシャルに見える一部のデータは、実際にはシーケンシャルに処理する必要がない場合があります。たとえば、加算は可換であるため、追加する一連の数値を指定した場合でも、FFNはRNNと同様に機能します。これは、支配的な情報が逐次的な性質ではない多くの健康問題にも当てはまる可能性があります。毎年患者の喫煙習慣が測定されると仮定します。行動の観点からは、軌跡が重要ですが、患者が肺癌を発症するかどうかを予測している場合、予測は患者が喫煙した年数(主にFFNの最後の10年に限定される)によって支配されます。

したがって、おもちゃの問題をより複雑にし、データの順序を考慮する必要があります。データにスパイクがあったかどうかを予測したいが、スパイクの相対的な性質については絶対値を気にしない、ある種のシミュレートされた時系列。

Update2

RNNのパフォーマンスが向上するケースを示すようにコードを変更しました。その秘訣は、FFNよりもLSTMでより自然にモデル化される、より複雑な条件付きロジックを使用することでした。コードは以下のとおりです。 8列の場合、FFNは1分でトレーニングし、検証損失6.3に達します。 LSTMのトレーニングには3倍の時間がかかりますが、最終的な検証の損失は1.06の6分の1です。

列の数を増やすと、特により複雑な条件を追加した場合、LSTMの利点はますます大きくなります。16列の場合、FFNの検証による損失は19です(モデルがないため、トレーニング曲線をより明確に確認できます)データを即座に適合させることができます)。比較すると、LSTMのトレーニングには11倍の時間がかかりますが、検証の損失はFFNの30分の1の0.31です。さらに大きな行列をいじって、この傾向がどこまで続くかを確認できます。

from keras import models
from keras import layers

from keras.layers import Dense, LSTM

import numpy as np
import matplotlib.pyplot as plt
import matplotlib
import time

matplotlib.use('Agg')

np.random.seed(20180908)

rows = 20500
cols = 10

# Randomly generate Z
Z = 100*np.random.uniform(0.05, 1.0, size = (rows, cols))

larger = np.max(Z[:, :cols/2], axis=1).reshape((rows, 1))
larger2 = np.max(Z[:, cols/2:], axis=1).reshape((rows, 1))
smaller = np.min((larger, larger2), axis=0)
# Z is now the max of the first half of the array.
Z = np.append(Z, larger, axis=1)
# Z is now the min of the max of each half of the array.
# Z = np.append(Z, smaller, axis=1)

# Combine and shuffle.

#Z = np.concatenate((Z_sum, Z_avg), axis = 0)

np.random.shuffle(Z)

## Training and validation data.

split = 10000

X_train = Z[:split, :-1]
X_valid = Z[split:, :-1]
Y_train = Z[:split, -1:].reshape(split, 1)
Y_valid = Z[split:, -1:].reshape(rows - split, 1)

print(X_train.shape)
print(Y_train.shape)
print(X_valid.shape)
print(Y_valid.shape)

print("Now setting up the FNN")

## FNN model.

tick = time.time()

# Define model.

network_fnn = models.Sequential()
network_fnn.add(layers.Dense(32, activation = 'relu', input_shape = (X_train.shape[1],)))
network_fnn.add(Dense(1, activation = None))

# Compile model.

network_fnn.compile(optimizer = 'adam', loss = 'mean_squared_error')

# Fit model.

history_fnn = network_fnn.fit(X_train, Y_train, epochs = 500, batch_size = 128, verbose = False,
    validation_data = (X_valid, Y_valid))

tock = time.time()

print()
print(str('%.2f' % ((tock - tick) / 60)) + ' minutes.')

print("Now evaluating the FNN")

loss_fnn = history_fnn.history['loss']
val_loss_fnn = history_fnn.history['val_loss']
epochs_fnn = range(1, len(loss_fnn) + 1)
print("train loss: ", loss_fnn[-1])
print("validation loss: ", val_loss_fnn[-1])

plt.plot(epochs_fnn, loss_fnn, 'black', label = 'Training Loss')
plt.plot(epochs_fnn, val_loss_fnn, 'red', label = 'Validation Loss')
plt.title('FNN: Training and Validation Loss')
plt.legend()
plt.show()

plt.scatter(Y_train, network_fnn.predict(X_train), alpha = 0.1)
plt.xlabel('Actual')
plt.ylabel('Predicted')
plt.title('training points')
plt.show()

plt.scatter(Y_valid, network_fnn.predict(X_valid), alpha = 0.1)
plt.xlabel('Actual')
plt.ylabel('Predicted')
plt.title('valid points')
plt.show()

print("LSTM")

## LSTM model.

X_lstm_train = X_train.reshape(X_train.shape[0], X_train.shape[1], 1)
X_lstm_valid = X_valid.reshape(X_valid.shape[0], X_valid.shape[1], 1)

tick = time.time()

# Define model.

network_lstm = models.Sequential()
network_lstm.add(layers.LSTM(32, activation = 'relu', input_shape = (X_lstm_train.shape[1], 1)))
network_lstm.add(layers.Dense(1, activation = None))

# Compile model.

network_lstm.compile(optimizer = 'adam', loss = 'mean_squared_error')

# Fit model.

history_lstm = network_lstm.fit(X_lstm_train, Y_train, epochs = 500, batch_size = 128, verbose = False,
    validation_data = (X_lstm_valid, Y_valid))

tock = time.time()

print()
print(str('%.2f' % ((tock - tick) / 60)) + ' minutes.')

print("now eval")

loss_lstm = history_lstm.history['loss']
val_loss_lstm = history_lstm.history['val_loss']
epochs_lstm = range(1, len(loss_lstm) + 1)
print("train loss: ", loss_lstm[-1])
print("validation loss: ", val_loss_lstm[-1])

plt.plot(epochs_lstm, loss_lstm, 'black', label = 'Training Loss')
plt.plot(epochs_lstm, val_loss_lstm, 'red', label = 'Validation Loss')
plt.title('LSTM: Training and Validation Loss')
plt.legend()
plt.show()

plt.scatter(Y_train, network_lstm.predict(X_lstm_train), alpha = 0.1)
plt.xlabel('Actual')
plt.ylabel('Predicted')
plt.title('training')
plt.show()

plt.scatter(Y_valid, network_lstm.predict(X_lstm_valid), alpha = 0.1)
plt.xlabel('Actual')
plt.ylabel('Predicted')
plt.title("validation")
plt.show()
7
emschorsch