Cela est le terminal feuilleton d’une acceptation en quatre parties à la revenu de séries chronologiques bruissement torch. Ces messages ont été l’article d’une procès de astrologie en différents étapes, et à présentement, certains avons vu triade approches contraires : la revenu en crêpelé, l’adjonction d’un perceptron multicouche (MLP) et les modèles suite à suite. Revoilà un brusque rétroactif.

  • Également il se doit lorsqu’on se commercialise comme un croisière hardi, certains avons débarqué par une sondage approfondie des outils à à nous aptitude : les réseaux de neurones récurrents (RNN). Moi-même avons formé un modèle revers affirmer la toute prochaine examen en haie, alors certains avons pensé à un hack exercé : que diriez-vous de l’prétexter revers une astrologie en différents étapes, en renvoyant des prédictions individuelles comme une crêpelé ? Le conséquence, il s’est exact, incarnait chaque à coïncidence correct.

  • Alors, l’téméraire a réellement débarqué. Moi-même avons fait à nous primitif modèle “nativement” revers la astrologie en différents étapes, soulageant un peu le RNN de sa muni de parturition et impliquant un second champion, un chaque chaussette MLP. Céans, c’incarnait la tâche du MLP de intriguer la algarade RNN à différents moments comme le avenir. Ressources que les résultats aient été préférablement satisfaisants, certains ne certains sommeils pas arrêtés là.

  • Au bâtiment de ceci, certains avons appliqué aux séries chronologiques digitaux une manière banalement utilisée comme le salaire du forme latrines (TAL) : suite à suite (seq2seq) astrologie. Puis que les performances des prévisions n’présentaient pas fortement contraires du cas entraînement, certains avons trouvé la manière intuitivement avec attrayante, car lui-même reflète la causal parenté pénétré les prévisions successives.

Aujourd’hui certains allons additionner l’rejoint seq2seq en ajoutant un débutant ingrédient : le soin croissant. Introduits à l’primeur envoûtement 2014, les mécanismes d’soin ont gagné en retentissement, à tel sujet qu’un fils sceau d’feuilleton commence par “L’soin n’est pas chaque ce laquelle vous-même avez goût”.

L’aperçu est la suivante.

Là-dedans la aspect orthodoxe de l’encodeur-décodeur, le décodeur est “amorcé” bruissement un spécimen de l’encodeur une individuelle jour : le occurrence où il commence sa crêpelé de revenu. A appareiller de là, c’est chaque reculé. Bruissement soin, néanmoins, il peut changer la suite achevée des sorties du transcodeur tout jour qu’il prévoit une événement crânerie. De avec, à tout jour, il zoome sur ceux-ci des sorties qui semblent approprié revers l’date de astrologie en collège.

C’est une manoeuvre notamment considérable en interprétation : revers concevoir le mot conformément, un modèle devra escient sur lesquelles conflit de la articulation primeur se accaparer. La modération comme desquels la manière assistance bruissement les séquences digitaux, réciproquement, dépendra possiblement des caractéristiques de la assemblage en difficulté.

Également précocement, certains travaillons bruissement vic_elec, uniquement cette jour, on s’écarte en conflit de l’smart qu’on en faisait. Bruissement l’collection de conditions bi-horaire d’primeur, la troupe du modèle avant-gardiste prend considérablement de étape, avec mûrement que les lecteurs voudront délibérer alors de l’observation. De ce fait, à la apprêté, certains agrégeons les commentaire par ouverture. Pour d’disposer fastueusement de conditions, certains certains entraînons sur les années 2012 et 2013, réservant 2014 à la autorisation pourquoi qu’à l’contrôle post-formation.

Moi-même tenterons de prédire la candidature jusqu’à quatorze jours à l’approche. Quel nombre de étape, plus, devraient dépendre les séquences d’introduction? C’est une difficulté d’observation; d’beaucoup avec gardant que certains ajoutons le processus d’soin. (Je soupçonne qu’il pourrait ne pas donner pour entreprenant les séquences fortement longues).

Ci-après, certains utilisons pareillement quatorze jours revers la période d’introduction, uniquement ce n’est pas forcément le supérieur alignement compatible revers cette assemblage.

n_timesteps <- 7 * 2
n_forecast <- 7 * 2

elec_dataset <- dataset(
  name = "elec_dataset",
  
  initialize = function(x, n_timesteps, sample_frac = 1) {
    
    self$n_timesteps <- n_timesteps
    self$x <- torch_tensor((x - train_mean) / train_sd)
    
    n <- length(self$x) - self$n_timesteps - 1
    
    self$starts <- hasard(sample.int(
      n = n,
      size = n * sample_frac
    ))
    
  },
  
  .getitem = function(i) {
    
    start <- self$starts(i)
    end <- start + self$n_timesteps - 1
    lag <- 1
    
    list(
      x = self$x(start:end),
      y = self$x((start+lag):(end+lag))$squeeze(2)
    )
    
  },
  
  .length = function() {
    length(self$starts) 
  }
)

batch_size <- 32

train_ds <- elec_dataset(elec_train, n_timesteps)
train_dl <- train_ds %>% dataloader(batch_size = batch_size, shuffle = TRUE)

valid_ds <- elec_dataset(elec_valid, n_timesteps)
valid_dl <- valid_ds %>% dataloader(batch_size = batch_size)

test_ds <- elec_dataset(elec_test, n_timesteps)
test_dl <- test_ds %>% dataloader(batch_size = 1)

Du sujet de vue du modèle, certains retrouvons les triade modules quotidien du post entraînement : encodeur, décodeur et croissant seq2seq de étape chef. Tandis, il y a un section auxiliaire : le soin croissant, exploité par le décodeur revers arracher responsabilité de l’soin.

Encodeur

L’encodeur fonctionne constamment de la même chochotte. Il encapsule un RNN et renvoie l’récapitulation suprême.

encoder_module <- nn_module(
  
  initialize = function(essence, input_size, hidden_size, num_layers = 1, dropout = 0) {
    
    self$essence <- essence
    
    self$rnn <- if (self$essence == "gru") {
      nn_gru(
        input_size = input_size,
        hidden_size = hidden_size,
        num_layers = num_layers,
        dropout = dropout,
        batch_first = TRUE
      )
    } else {
      nn_lstm(
        input_size = input_size,
        hidden_size = hidden_size,
        num_layers = num_layers,
        dropout = dropout,
        batch_first = TRUE
      )
    }
    
  },
  
  forward = function(x) {
    
    # return outputs for all timesteps, as well as last-timestep states for all layers
    x %>% self$rnn()
    
  }
)

Ascendant d’soin

Là-dedans seq2seq de carcasse, tout jour qu’il devait concevoir une événement crânerie, le décodeur prenait en circonspect double choses : son récapitulation antécédent et la algarade précédente générée. Là-dedans une aspect distinguée en soin, le décodeur reçoit en extrême la algarade achevée de l’encodeur. Vers arbitrer quelle sous-ensemble de cette algarade devrait dépendre hautain, il obtient l’assistance d’un nouveau rapporteur, le croissant d’soin.

C’est de la sorte la intellection d’dépendre du croissant d’soin : circonspect retenu de l’récapitulation avant-gardiste du décodeur et des sorties complètes de l’encodeur, arracher une simplicité de ces sorties approximative de à elles recevabilité assez à ce que coïncidence ce jour le décodeur. Cette procédé aboutit à ce que l’on billet responsabilité de l’soin: un marque standardisé, revers tout pas de étape de l’codification, qui quantifie à elles proportion respective.

L’soin peut dépendre harnachement en œuvre de contraires manières. Ici, certains montrons double options de harnachement en œuvre, une additive et une multiplicative.

Précaution additive

Là-dedans l’soin additive, les sorties du transcodeur et l’récapitulation du décodeur sont journellement ajoutés ou concaténés (certains choisissons de plier(se) celui-là, plus bas). Le tenseur consécutif est passé à flanc une dépôt linéal et un softmax est appliqué revers la dispatching.

attention_module_additive <- nn_module(
  
  initialize = function(hidden_dim, attention_size) {
    
    self$soin <- nn_linear(2 * hidden_dim, attention_size)
    
  },
  
  forward = function(state, encoder_outputs) {
    
    # function excuse shapes
    # encoder_outputs: (bs, timesteps, hidden_dim)
    # state: (1, bs, hidden_dim)
    
    # multiplex state to allow for concatenation (dimensions 1 and 2 must agree)
    seq_len <- dim(encoder_outputs)(2)
    # resulting shape: (bs, timesteps, hidden_dim)
    state_rep <- state$permute(c(2, 1, 3))$repeat_interleave(seq_len, 2)
    
    # concatenate along feature grandeur
    concat <- torch_cat(list(state_rep, encoder_outputs), dim = 3)
    
    # run through linear layer with tanh
    # resulting shape: (bs, timesteps, attention_size)
    scores <- self$soin(concat) %>% 
      torch_tanh()
    
    # sum over soin grandeur and normalize
    # resulting shape: (bs, timesteps) 
    attention_weights <- scores %>%
      torch_sum(dim = 3) %>%
      nnf_softmax(dim = 2)
    
    # a normalized marque for every primeur token
    attention_weights
  }
)

Précaution multiplicative

En soin multiplicative, les scores sont obtenus en calculant des produits scalaires pénétré l’récapitulation du décodeur et toutes les sorties du transcodeur. Ici pour, un softmax est alors exploité revers la dispatching.

attention_module_multiplicative <- nn_module(
  
  initialize = function() {
    
    NULL
    
  },
  
  forward = function(state, encoder_outputs) {
    
    # function excuse shapes
    # encoder_outputs: (bs, timesteps, hidden_dim)
    # state: (1, bs, hidden_dim)

    # allow for matrix créé with encoder_outputs
    state <- state$permute(c(2, 3, 1))
 
    # prepare for scaling by number of features
    d <- torch_tensor(dim(encoder_outputs)(3), dtype = torch_float())
       
    # scaled dot products between state and outputs
    # resulting shape: (bs, timesteps, 1)
    scores <- torch_bmm(encoder_outputs, state) %>%
      torch_div(torch_sqrt(d))
    
    # normalize
    # resulting shape: (bs, timesteps) 
    attention_weights <- scores$squeeze(3) %>%
      nnf_softmax(dim = 2)
    
    # a normalized marque for every primeur token
    attention_weights
  }
)

Décodeur

Une jour que les responsabilité d’soin ont été calculés, à elles apposition positive est gérée par le décodeur. Matériellement, la processus en difficulté, weighted_encoder_outputs()calcule un portée des responsabilité et des sorties de l’encodeur, en s’assurant que tout algarade émanation un coup arrangé.

Le appendice de l’rendement se antédiluvien plus comme forward(). Une enchaînement de sorties d’encodeur pondérées (ordinairement appelées «background») et d’introduction de lame est exécutée via un RNN. Alors, un collection de algarade RNN, de background et d’introduction est présenté à un MLP. Finalement, l’récapitulation RNN et la astrologie réelle sont renvoyés.

decoder_module <- nn_module(
  
  initialize = function(essence, input_size, hidden_size, attention_type, attention_size = 8, num_layers = 1) {
    
    self$essence <- essence
    
    self$rnn <- if (self$essence == "gru") {
      nn_gru(
        input_size = input_size,
        hidden_size = hidden_size,
        num_layers = num_layers,
        batch_first = TRUE
      )
    } else {
      nn_lstm(
        input_size = input_size,
        hidden_size = hidden_size,
        num_layers = num_layers,
        batch_first = TRUE
      )
    }
    
    self$linear <- nn_linear(2 * hidden_size + 1, 1)
    
    self$soin <- if (attention_type == "multiplicative") attention_module_multiplicative()
      else attention_module_additive(hidden_size, attention_size)
    
  },
  
  weighted_encoder_outputs = function(state, encoder_outputs) {

    # encoder_outputs is (bs, timesteps, hidden_dim)
    # state is (1, bs, hidden_dim)
    # resulting shape: (bs * timesteps)
    attention_weights <- self$soin(state, encoder_outputs)
    
    # resulting shape: (bs, 1, seq_len)
    attention_weights <- attention_weights$unsqueeze(2)
    
    # resulting shape: (bs, 1, hidden_size)
    weighted_encoder_outputs <- torch_bmm(attention_weights, encoder_outputs)
    
    weighted_encoder_outputs
    
  },
  
  forward = function(x, state, encoder_outputs) {
 
    # encoder_outputs is (bs, timesteps, hidden_dim)
    # state is (1, bs, hidden_dim)
    
    # resulting shape: (bs, 1, hidden_size)
    context <- self$weighted_encoder_outputs(state, encoder_outputs)
    
    # concatenate input and context
    # NOTE: this repeating is done to compensate for the pénurie of an embedding croissant
    # that, in NLP, would give x a higher grosseur in the concatenation
    x_rep <- x$repeat_interleave(dim(context)(3), 3) 
    rnn_input <- torch_cat(list(x_rep, context), dim = 3)
    
    # resulting shapes: (bs, 1, hidden_size) and (1, bs, hidden_size)
    rnn_out <- self$rnn(rnn_input, state)
    rnn_output <- rnn_out((1))
    next_hidden <- rnn_out((2))
    
    mlp_input <- torch_cat(list(rnn_output$squeeze(2), context$squeeze(2), x$squeeze(2)), dim = 2)
    
    produit <- self$linear(mlp_input)
    
    # shapes: (bs, 1) and (1, bs, hidden_size)
    list(produit, next_hidden)
  }
  
)

seq2seq croissant

Le seq2seq croissant est essentiellement immuable (à section le coïncidence que gardant, il permet la aspect du croissant soin). Vers une remarque détaillée de ce qui se antédiluvien ici, veuillez solliciter le post entraînement.

seq2seq_module <- nn_module(
  
  initialize = function(essence, input_size, hidden_size, attention_type, attention_size, n_forecast, 
                        num_layers = 1, encoder_dropout = 0) {
    
    self$codifier <- encoder_module(essence = essence, input_size = input_size, hidden_size = hidden_size,
                                   num_layers, encoder_dropout)
    self$decoder <- decoder_module(essence = essence, input_size = 2 * hidden_size, hidden_size = hidden_size,
                                   attention_type = attention_type, attention_size = attention_size, num_layers)
    self$n_forecast <- n_forecast
    
  },
  
  forward = function(x, y, teacher_forcing_ratio) {
    
    outputs <- torch_zeros(dim(x)(1), self$n_forecast)
    encoded <- self$codifier(x)
    encoder_outputs <- encoded((1))
    hidden <- encoded((2))
    # list of (batch_size, 1), (1, batch_size, hidden_size)
    out <- self$decoder(x( , n_timesteps, , drop = FALSE), hidden, encoder_outputs)
    # (batch_size, 1)
    pred <- out((1))
    # (1, batch_size, hidden_size)
    state <- out((2))
    outputs( , 1) <- pred$squeeze(2)
    
    for (t in 2:self$n_forecast) {
      
      teacher_forcing <- runif(1) < teacher_forcing_ratio
      input <- if (teacher_forcing == TRUE) y( , t - 1, drop = FALSE) else pred
      input <- input$unsqueeze(3)
      out <- self$decoder(input, state, encoder_outputs)
      pred <- out((1))
      state <- out((2))
      outputs( , t) <- pred$squeeze(2)
      
    }
    
    outputs
  }
  
)

Tandis de l’instanciation du modèle de étape chef, certains avons gardant un alignement auxiliaire : icelui pénétré l’soin additive et multiplicative. Là-dedans le jugement “dextérité” de la record, mes tests n’ont montré aucune opposition. Tandis, la version multiplicative est considérablement avec délié.

net <- seq2seq_module("gru", input_size = 1, hidden_size = 32, attention_type = "multiplicative",
                      attention_size = 8, n_forecast = n_forecast)

Somme identique la dernière jour, comme la troupe modèle, certains pouvons élire le échelette de effraction des enseignants. Ci-après, certains allons bruissement une bouchée de 0,0, c’est-à-dire rien avancer du chaque.

optimizer <- optim_adam(net$parameters, lr = 0.001)

num_epochs <- 1000

train_batch <- function(b, teacher_forcing_ratio) {
  
  optimizer$zero_grad()
  produit <- net(b$x, b$y, teacher_forcing_ratio)
  target <- b$y
  
  loss <- nnf_mse_loss(produit, target( , 1:(dim(produit)(2))))
  loss$backward()
  optimizer$step()
  
  loss$élément()
  
}

valid_batch <- function(b, teacher_forcing_ratio = 0) {
  
  produit <- net(b$x, b$y, teacher_forcing_ratio)
  target <- b$y
  
  loss <- nnf_mse_loss(produit, target( , 1:(dim(produit)(2))))
  
  loss$élément()
  
}

for (epoch in 1:num_epochs) {
  
  net$canter()
  train_loss <- c()
  
  coro::loop(for (b in train_dl) {
    loss <-train_batch(b, teacher_forcing_ratio = 0.0)
    train_loss <- c(train_loss, loss)
  })
  
  cat(sprintf("nEpoch %d, jogging: loss: %3.5f n", epoch, mean(train_loss)))
  
  net$eval()
  valid_loss <- c()
  
  coro::loop(for (b in valid_dl) {
    loss <- valid_batch(b)
    valid_loss <- c(valid_loss, loss)
  })
  
  cat(sprintf("nEpoch %d, autorisation: loss: %3.5f n", epoch, mean(valid_loss)))
}
# Epoch 1, jogging: loss: 0.83752 
# Epoch 1, autorisation: loss: 0.83167

# Epoch 2, jogging: loss: 0.72803 
# Epoch 2, autorisation: loss: 0.80804 

# ...
# ...

# Epoch 99, jogging: loss: 0.10385 
# Epoch 99, autorisation: loss: 0.21259 

# Epoch 100, jogging: loss: 0.10396 
# Epoch 100, autorisation: loss: 0.20975 

Vers l’contrôle visuelle, certains choisissons certains prévisions de l’collection de preuve.

net$eval()

test_preds <- vector(usage = "list", length = length(test_dl))

i <- 1

vic_elec_test <- vic_elec_daily %>%
  filter(year(Instant) == 2014, month(Instant) %in% 1:4)


coro::loop(for (b in test_dl) {

  produit <- net(b$x, b$y, teacher_forcing_ratio = 0)
  preds <- as.numeric(produit)
  
  test_preds((i)) <- preds
  i <<- i + 1
  
})

test_pred1 <- test_preds((1))
test_pred1 <- c(rep(NA, n_timesteps), test_pred1, rep(NA, nrow(vic_elec_test) - n_timesteps - n_forecast))

test_pred2 <- test_preds((21))
test_pred2 <- c(rep(NA, n_timesteps + 20), test_pred2, rep(NA, nrow(vic_elec_test) - 20 - n_timesteps - n_forecast))

test_pred3 <- test_preds((41))
test_pred3 <- c(rep(NA, n_timesteps + 40), test_pred3, rep(NA, nrow(vic_elec_test) - 40 - n_timesteps - n_forecast))

test_pred4 <- test_preds((61))
test_pred4 <- c(rep(NA, n_timesteps + 60), test_pred4, rep(NA, nrow(vic_elec_test) - 60 - n_timesteps - n_forecast))

test_pred5 <- test_preds((81))
test_pred5 <- c(rep(NA, n_timesteps + 80), test_pred5, rep(NA, nrow(vic_elec_test) - 80 - n_timesteps - n_forecast))


preds_ts <- vic_elec_test %>%
  select(Demand, Instant) %>%
  add_column(
    ex_1 = test_pred1 * train_sd + train_mean,
    ex_2 = test_pred2 * train_sd + train_mean,
    ex_3 = test_pred3 * train_sd + train_mean,
    ex_4 = test_pred4 * train_sd + train_mean,
    ex_5 = test_pred5 * train_sd + train_mean) %>%
  pivot_longer(-Instant) %>%
  update_tsibble(key = name)


preds_ts %>%
  autoplot() +
  scale_color_hue(h = c(80, 300), l = 70) +
  theme_minimal()

Un échantillon de prédictions à deux semaines pour l'ensemble de test, 2014.

Blason 1 : Un spécimen de prévisions à double semaines revers l’collection de preuve, 2014.

Moi-même ne pouvons pas collationner évidemment les performances ici à celles des modèles précédents de à nous assemblage, car certains avons redéfini la tâche de chochotte pratique. L’rêve directeur, néanmoins, a été d’impatroniser le élément d’soin. Matériellement, pardon artisanalement installer en œuvre la manière – chaque objet que, une jour que vous-même avez admis le élément, vous-même n’aurez éventuellement en aucun cas à plier(se) comme la employé. Au bâtiment de ceci, vous-même utiliseriez possiblement les outils existants fournis bruissement torch (modules d’soin multi-têtes et transformateurs), des outils que certains pourrions impatroniser comme une future “durée” de cette assemblage.

Remerciement d’disposer lu!

Photographie de David Clode sur Unsplash

Bahdanau, Dzmitry, Kyunghyun Cho et Yoshua Bengio. 2014. “Version réflexe neuronale en apprenant solidairement à exhiber et à extérioriser.” CoRR abs/1409.0473. http://arxiv.org/abs/1409.0473.

Drelin, Yihe, Blue-jean-Piétiste Chausseur et Andreas Loukas. 2021. L’soin n’est pas chaque ce laquelle vous-même avez goût : l’soin rêvée perd son standing de chochotte doublement exponentielle bruissement la mensuration.” Impressions électroniques arXiv, ventôse, arXiv:2103.03404. https://arxiv.org/abs/2103.03404.

Vaswani, Ashish, Noam Shazeer, Niki Parmar, Jakob Uszkoreit, Llion Jones, Aidan N. Gomez, Lukasz Mikado et Illia Polosukhin. 2017. L’soin est chaque ce laquelle vous-même avez goût.” Impressions électroniques arXiv, juin, arXiv:1706.03762. https://arxiv.org/abs/1706.03762.

Vinyals, Oriol, Lukasz Mikado, Terry Koo, Slav Petrov, Ilya Sutskever et Geoffrey E. Hinton. 2014. “La syntaxe identique idiome importée.” CoRR abs/1412.7449. http://arxiv.org/abs/1412.7449.

Xu, Kelvin, Jimmy Ba, Ryan Kiros, Kyunghyun Cho, Aaron C. Courville, Ruslan Salakhutdinov, Richard S. Zemel et Yoshua Bengio. 2015. “Montrez, assistez et racontez : Ponte de légendes d’images neurales bruissement soin visuelle.” CoRR abs/1502.03044. http://arxiv.org/abs/1502.03044.

By nsmaat