Зачем беспокоиться о периодических нейронных сетях для структурированных данных? - PullRequest
0 голосов
/ 25 августа 2018

Я разрабатывал нейронные сети с прямой связью (FNN) и рекуррентные нейронные сети (RNN) в Керасе со структурированными данными формы [instances, time, features], и производительность FNN и RNN была одинаковой (за исключением того, что RNN требуют большего количества вычисленийвремя).

Я также смоделировал табличные данные (код ниже), где я ожидал, что RNN превзойдет FNN, потому что следующее значение в серии зависит от предыдущего значения в серии;однако обе архитектуры предсказывают правильно.

С данными НЛП я видел, что RNNs превосходят 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

Две функции были смоделированы в течение 10 временных шагов, где значение второй функции зависит отзначение обеих функций на предыдущем временном шаге.

## 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()

1 Ответ

0 голосов
/ 07 сентября 2018

На практике даже в НЛП вы видите, что RNN и CNN часто конкурентоспособны. Вот обзорная статья 2017 года, которая показывает это более подробно. Теоретически, это может быть тот случай, когда RNN лучше справляются со всей сложностью и последовательностью языка, но на практике большее препятствие обычно правильно обучает сеть, а RNN являются привередливыми.

Другая проблема, которая может иметь шанс на работу, заключается в том, чтобы посмотреть на проблему, подобную проблеме сбалансированных скобок (либо с простыми скобками в строках, либо с круглыми скобками вместе с другими символами отвлечения). Это требует последовательной обработки входных данных и отслеживания некоторого состояния, и его легче изучить с помощью LSTM, чем с FFN.

Обновление: Некоторые данные, которые выглядят последовательными, на самом деле могут не обрабатываться последовательно. Например, даже если вы предоставляете последовательность чисел для добавления, так как сложение коммутативно, FFN будет работать так же хорошо, как и RNN. Это также может относиться ко многим проблемам со здоровьем, когда доминирующая информация не носит последовательного характера. Предположим, что каждый год курение пациента измеряется. С поведенческой точки зрения траектория важна, но если вы прогнозируете, будет ли у пациента развиваться рак легкого, в прогнозе будет доминировать только количество лет, в течение которых пациент курил (может быть ограничено последними 10 годами для FFN).

Итак, вы хотите усложнить задачу с игрушкой и потребовать учета порядка данных. Может быть, это какой-то смоделированный временной ряд, в котором вы хотите предсказать, был ли скачок в данных, но вас не волнуют абсолютные значения, только относительный характер скачка.

Update2

Я изменил ваш код, чтобы показать случай, когда RNN работают лучше. Хитрость заключалась в том, чтобы использовать более сложную условную логику, которая более естественно моделируется в LSTM, чем FFN. Код ниже. Для 8 столбцов мы видим, что FFN обучается за 1 минуту и ​​достигает потери проверки 6,3. Тренировка LSTM занимает в 3 раза больше времени, но окончательная потеря в валидации в 6 раз ниже на 1,06.

По мере того, как мы увеличиваем количество столбцов, LSTM имеет все большее и большее преимущество, особенно если мы добавили более сложные условия в. Для 16 столбцов потери проверки FFN составляют 19 (и вы можете более четко увидеть тренировочную кривую в качестве модели). не может мгновенно соответствовать данным). Для сравнения LSTM тренируется в 11 раз дольше, но потери при проверке в 0,31 раза меньше, чем в FFN! Вы можете поиграть с еще большими матрицами, чтобы увидеть, насколько далеко эта тенденция будет расширяться.

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()
...