Il est tout à fait possible d'utiliser un CNN pour faire des prédictions de séries temporelles que ce soit la régression ou la classification. Les CNN sont bons pour trouver des modèles locaux et, en fait, les CNN fonctionnent avec l'hypothèse que les modèles locaux sont pertinents partout. La convolution est également une opération bien connue dans les séries chronologiques et le traitement du signal. Un autre avantage par rapport aux RNN est qu'ils peuvent être très rapides à calculer car ils peuvent être parallélisés par opposition à la nature séquentielle RNN.
Dans le code ci-dessous, je vais démontrer une étude de cas où il est possible de prédire la demande d'électricité en R en utilisant des keras. Notez que ce n'est pas un problème de classification (je n'avais pas d'exemple à portée de main) mais il n'est pas difficile de modifier le code pour gérer un problème de classification (utilisez une sortie softmax au lieu d'une sortie linéaire et une perte d'entropie croisée).
L'ensemble de données est disponible dans la bibliothèque fpp2:
library(fpp2)
library(keras)
data("elecdemand")
elec <- as.data.frame(elecdemand)
dm <- as.matrix(elec[, c("WorkDay", "Temperature", "Demand")])
Ensuite, nous créons un générateur de données. Il est utilisé pour créer des lots de données de formation et de validation à utiliser pendant le processus de formation. Notez que ce code est une version plus simple d'un générateur de données trouvé dans le livre "Deep Learning with R" (et la version vidéo de celui-ci "Deep Learning with R in Motion") de publications manning.
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)
})
}
Ensuite, nous spécifions certains paramètres à transmettre à nos générateurs de données (nous créons deux générateurs, un pour la formation et un pour la validation).
lookback <- 72
lookahead <- 1
batch_size <- 168
ycol <- 3
Le paramètre de rétrospection est de savoir jusqu'où nous voulons regarder dans le passé et d'anticiper jusqu'où nous voulons prédire l'avenir.
Ensuite, nous séparons notre ensemble de données et créons deux générateurs:
train_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
)
Ensuite, nous créons un réseau de neurones avec une couche convolutionnelle et formons le modèle:
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
)
Enfin, nous pouvons créer du code pour prédire une séquence de 24 points de données en utilisant une procédure simple, expliquée dans les commentaires 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)
et le tour est joué:
Pas mal.