Цілком можливо використовувати CNN для прогнозування часових рядів, будь то регресія чи класифікація. CNN добре підходять до пошуку локальних зразків і насправді CNN працюють з припущенням, що локальні зразки актуальні скрізь. Також згортка - це добре відома операція в часових рядах та обробці сигналів. Ще одна перевага перед RNN полягає в тому, що вони можуть бути дуже швидкими для обчислення, оскільки вони можуть бути паралелізовані на відміну від послідовного характеру RNN.
У наведеному нижче коді я продемонструю тематичне дослідження, де можна передбачити попит на електроенергію в R за допомогою керас. Зауважте, що це не проблема класифікації (у мене не було зручного прикладу), але не важко змінити код для вирішення проблеми класифікації (використовуйте вихід softmax замість лінійного виводу та перехресну втрату ентропії).
Набір даних доступний у бібліотеці fpp2:
library(fpp2)
library(keras)
data("elecdemand")
elec <- as.data.frame(elecdemand)
dm <- as.matrix(elec[, c("WorkDay", "Temperature", "Demand")])
Далі ми створюємо генератор даних. Це використовується для створення пакетів даних про навчання та валідацію, які будуть використовуватися під час навчального процесу. Зауважимо, що цей код є більш спрощеною версією генератора даних, який можна знайти в книзі "Глибоке навчання з R" (і його відеоверсію "Deep Learning with R in Motion") з публікацій, що комплектуються.
data_gen <- function(dm, batch_size, ycol, lookback, lookahead) {
num_rows <- nrow(dm) - lookback - lookahead
num_batches <- ceiling(num_rows/batch_size)
last_batch_size <- if (num_rows %% batch_size == 0) batch_size else num_rows %% batch_size
i <- 1
start_idx <- 1
return(function(){
running_batch_size <<- if (i == num_batches) last_batch_size else batch_size
end_idx <- start_idx + running_batch_size - 1
start_indices <- start_idx:end_idx
X_batch <- array(0, dim = c(running_batch_size,
lookback,
ncol(dm)))
y_batch <- array(0, dim = c(running_batch_size,
length(ycol)))
for (j in 1:running_batch_size){
row_indices <- start_indices[j]:(start_indices[j]+lookback-1)
X_batch[j,,] <- dm[row_indices,]
y_batch[j,] <- dm[start_indices[j]+lookback-1+lookahead, ycol]
}
i <<- i+1
start_idx <<- end_idx+1
if (i > num_batches){
i <<- 1
start_idx <<- 1
}
list(X_batch, y_batch)
})
}
Далі ми вказуємо деякі параметри, які потрібно передавати в наші генератори даних (ми створюємо два генератори, один для навчання та один для перевірки).
lookback <- 72
lookahead <- 1
batch_size <- 168
ycol <- 3
Параметр ретроспективності - це те, наскільки в минулому ми хочемо виглядати, і як шукати прогноз, наскільки далеко в майбутньому ми хочемо передбачити.
Далі ми розділимо наш набір даних і створимо два генератори:
поїзд_dm <- dm [1: 15000,]
val_dm <- dm[15001:16000,]
test_dm <- dm[16001:nrow(dm),]
train_gen <- data_gen(
train_dm,
batch_size = batch_size,
ycol = ycol,
lookback = lookback,
lookahead = lookahead
)
val_gen <- data_gen(
val_dm,
batch_size = batch_size,
ycol = ycol,
lookback = lookback,
lookahead = lookahead
)
Далі ми створюємо нейронну мережу із звивистим шаром і тренуємо модель:
model <- keras_model_sequential() %>%
layer_conv_1d(filters=64, kernel_size=4, activation="relu", input_shape=c(lookback, dim(dm)[[-1]])) %>%
layer_max_pooling_1d(pool_size=4) %>%
layer_flatten() %>%
layer_dense(units=lookback * dim(dm)[[-1]], activation="relu") %>%
layer_dropout(rate=0.2) %>%
layer_dense(units=1, activation="linear")
model %>% compile(
optimizer = optimizer_rmsprop(lr=0.001),
loss = "mse",
metric = "mae"
)
val_steps <- 48
history <- model %>% fit_generator(
train_gen,
steps_per_epoch = 50,
epochs = 50,
validation_data = val_gen,
validation_steps = val_steps
)
Нарешті, ми можемо створити якийсь код для прогнозування послідовності з 24 точок даних, використовуючи просту процедуру, пояснену в коментарях R.
####### How to create predictions ####################
#We will create a predict_forecast function that will do the following:
#The function will be given a dataset that will contain weather forecast values and Demand values for the lookback duration. The rest of the MW values will be non-available and
#will be "filled-in" by the deep network (predicted). We will do this with the test_dm dataset.
horizon <- 24
#Store all target values in a vector
goal_predictions <- test_dm[1:(lookback+horizon),ycol]
#get a copy of the dm_test
test_set <- test_dm[1:(lookback+horizon),]
#Set all the Demand values, except the lookback values, in the test set to be equal to NA.
test_set[(lookback+1):nrow(test_set), ycol] <- NA
predict_forecast <- function(model, test_data, ycol, lookback, horizon) {
i <-1
for (i in 1:horizon){
start_idx <- i
end_idx <- start_idx + lookback - 1
predict_idx <- end_idx + 1
input_batch <- test_data[start_idx:end_idx,]
input_batch <- input_batch %>% array_reshape(dim = c(1, dim(input_batch)))
prediction <- model %>% predict_on_batch(input_batch)
test_data[predict_idx, ycol] <- prediction
}
test_data[(lookback+1):(lookback+horizon), ycol]
}
preds <- predict_forecast(model, test_set, ycol, lookback, horizon)
targets <- goal_predictions[(lookback+1):(lookback+horizon)]
pred_df <- data.frame(x = 1:horizon, y = targets, y_hat = preds)
і вуаля:
Не дуже погано.