Construire un LSTM polyvalent et multitâches avec Keras

Préambule

je travaille actuellement sur un problème D'apprentissage automatique où nous sommes chargés d'utiliser les données passées sur les ventes de produits afin de prédire les volumes des ventes à l'avenir (afin que les magasins peuvent mieux planifier leurs stocks). Nous avons essentiellement des séries chronologiques, où pour chaque produit nous savons combien d'unités ont été vendues à quels jours. Nous avons aussi des informations comme le temps qu'il faisait, s'il y avait un jour férié, si l'un des produits était en vente, etc.

nous avons été en mesure de modéliser cela avec un certain succès en utilisant un MLP avec des couches denses, et juste en utilisant une approche de fenêtre coulissante pour inclure les volumes de ventes des jours environnants. Toutefois, nous croyons que nous serons en mesure d'obtenir de bien meilleurs résultats grâce à une approche fondée sur des séries chronologiques comme le modèle LSTM.

Données

les données que nous possédons sont essentiellement les suivantes:

enter image description here

( EDIT: pour plus de clarté, la colonne "Temps" dans l'image ci-dessus n'est pas correct. Nous avons des entrées une fois par jour, pas une fois par mois. Mais sinon, la structure est la même!)

ainsi les données X sont de forme:

(numProducts, numTimesteps, numFeatures) = (50 products, 1096 days, 90 features)

et les données Y sont de forme:

(numProducts, numTimesteps, numTargets) =  (50 products, 1096 days, 3 binary targets)

enter image description here

donc nous avons des données pour trois ans (2014, 2015, 2016) et nous voulons nous entraîner sur ce sujet afin de faire des prédictions pour 2017. (Bien sûr, ce n'est pas 100% vrai, puisque nous avons effectivement des données jusqu'à Octobre 2017, mais nous allons juste ignorer que pour l'instant)

Problème

je voudrais construire un LSTM dans Keras qui me permet de faire ces prédictions. Il y a quelques endroits où je suis coincé. Donc, j'ai six questions concrètes (je sais que l'on est censé essayer de limiter un poteau de débordement de piles à une question, mais ceux-ci sont tous entrelacés).

tout D'abord, Comment découper mes données pour les lots ? Puisque j'ai trois années complètes, est-ce qu'il est logique de simplement passer par trois lots, à chaque fois de taille un an? Ou est-ce plus logique de faire des lots plus petits (disons 30 jours) et aussi d'utiliser des fenêtres coulissantes? I. e. au lieu de 36 lots de 30 jours chacun, j'utilise 36 * 6 lots de 30 jours chacun, à chaque fois coulissante avec 5 jours? Ou est-ce que ce N'est pas vraiment la façon dont LSTMs devrait être utilisé? (Notez qu'il y a beaucoup de saisonnalité dans les données, donc je dois aussi prendre ce genre de tendance à long terme).

Deuxièmement, est-ce logique d'utiliser return_sequences=True ici? En d'autres termes, je garde mes données de Y comme (50, 1096, 3) de sorte que (pour autant que je l'ai compris) Il ya un prédiction à chaque pas de temps pour lequel une perte peut être calculée par rapport aux données de la cible? Ou est-ce que je serais mieux avec return_sequences=False , de sorte que seule la valeur finale de chaque lot est utilisée pour évaluer la perte (c.-à-d. SI en utilisant des lots annuels, puis en 2016 pour le produit 1, nous évaluons par rapport à la valeur de décembre 2016 de (1,1,1) ).

Troisièmement comment traiter les 50 produits différents? ils sont différents, mais encore fortement corrélés et nous avons vu avec d'autres approches (par exemple un MLP avec de simples fenêtres de temps) que les résultats sont meilleurs quand tous les produits sont considérés dans le même modèle. Quelques idées qui sont actuellement sur la table:

  • changement de la variable cible n'est pas seulement de 3 variables, mais 3 * 50 = 150; soit, pour chaque produit il y a trois objectifs, qui sont formés simultanément.
  • diviser les résultats après la couche LSTM en 50 denses les réseaux, qui prennent en entrée les sorties du LSTM, ainsi que certaines fonctionnalités spécifiques à chaque produit - c'est-à-dire que nous avons un réseau multi-tâches avec 50 fonctions de perte, que nous optimisons ensuite ensemble. Serait-ce un fou?
  • considérer un produit comme une seule observation, et inclure des caractéristiques spécifiques du produit déjà à la couche LSTM. N'utilisez que cette couche, suivie d'une couche supérieure de taille 3 (pour les trois cibles). Passez chaque produit dans un lot distinct.

Quatrièmement, comment traiter les données de validation ? Normalement, je garderais juste un échantillon choisi au hasard pour valider contre, mais ici nous devons garder l'ordre de temps en place. Donc je suppose que le mieux est de garder quelques mois de côté?

Cinquièmement, et c'est la partie qui est probablement la plus claire pour moi - comment puis-je utiliser les résultats réels pour effectuer des prédictions ? Disons J'ai utilisé return_sequences=False et je me suis formé sur les trois années en trois lots (chaque fois Jusqu'en novembre) dans le but de former le modèle pour prédire la prochaine valeur (déc.2014, déc. 2015, Déc. 2016). Si je veux utiliser ces résultats en 2017, comment cela fonctionne réellement? Si je l'ai bien compris, la seule chose que je puisse faire dans ce cas-ci est d'alimenter le modèle de tous les points de données pour janvier à Novembre 2017 et cela me donnera une prédiction pour décembre 2017. Est-ce exact? Cependant, si je devais utiliser return_sequences=True , puis formé sur toutes les données jusqu'en décembre 2016, serais-je alors en mesure d'obtenir une prédiction pour Janvier 2017 en donnant au modèle les caractéristiques observées en janvier 2017? Ou dois-je également lui donner les 12 mois avant Jan 2017? Qu'en est-il de février 2017, dois-je en outre donner la valeur pour 2017, plus un autre 11 mois avant cela? (Si on dirait que je suis confus, c'est parce que je le suis!)

enfin, selon la structure que je devrais utiliser, comment faire C'est dans Keras ? Ce que j'ai à l'esprit en ce moment est quelque chose du genre: (bien que ce soit pour un seul produit, ne résout donc pas avoir tous les produits dans le même modèle):

Keras code

trainX = trainingDataReshaped #Data for Product 1, Jan 2014 to Dec 2016
trainY = trainingTargetReshaped
validX = validDataReshaped #Data for Product 1, for ??? Maybe for a few months?
validY = validTargetReshaped    

numSequences = trainX.shape[0]
numTimeSteps = trainX.shape[1]
numFeatures = trainX.shape[2]

numTargets = trainY.shape[2]

model = Sequential()
model.add(LSTM(100, input_shape=(None, numFeatures), return_sequences=True)) 
model.add(Dense(numTargets, activation="softmax"))    

model.compile(loss=stackEntry.params["loss"],
      optimizer="adam",
      metrics=['accuracy'])

history = model.fit(trainX, trainY,
            batch_size=30,
            epochs=20,
            verbose=1,
            validation_data=(validX, validY))               

predictX  = predictionDataReshaped #Data for Product 1, Jan 2017 to Dec 2017

prediction=model.predict(predictX)
20
demandé sur Marcin Możejko 2017-10-26 10:07:32

3 réponses

:

tout d'abord, comment découper mes données pour les lots? Depuis que j'ai trois années complètes, est-ce qu'il est logique de simplement passer à travers trois lots, chaque fois de taille un an? Ou est-il plus logique de faire des petits lots (30 jours) et aussi à l'aide de fenêtres coulissantes? I. e. au lieu de 36 lots de 30 jours chacun, j'utilise 36 * 6 lots de 30 chaque jour, chaque fois glissant avec 5 jours? Ou n'est-ce pas vraiment le façon LSTMs doit être utilisé? (À noter qu'il est tout à fait un peu de la saisonnalité dans les données, je dois attraper ce genre de long terme tendance).

honnêtement-modéliser de telles données est quelque chose de vraiment difficile. Tout d'abord - je ne vous conseillerais pas d'utiliser LSTM s car ils sont plutôt conçus pour capturer un peu de type différent de données (par exemple NLP ou speech où il est vraiment important de modéliser les dépendances à long terme - pas la saisonnalité) et ils ont besoin d'un grand nombre de données pour être appris. Je préférerais vous conseiller d'utiliser soit GRU ou SimpleRNN qui sont beaucoup plus faciles à apprendre et devraient être mieux pour votre tâche.

quand il s'agit de batching - je vous conseillerais certainement d'utiliser une technique de fenêtre fixe car il finira par produire beaucoup plus de points de données que de nourrir une année entière ou un mois entier. Essayez de définir un nombre de jours comme paramètre meta qui sera aussi optimisé en utilisant différentes valeurs dans l'entraînement et en choisissant la plus appropriée.

quand il s'agit de saisonnalité - bien sûr, c'est un cas mais:

  • vous pourriez avoir beaucoup trop peu de points de données et d'années collectées pour fournir une bonne estimation des tendances saisonnières,
  • L'utilisation de tout type de réseau de neurones récurrents pour capturer de telles saisonnalités est une vraiment mauvais idée.

ce que je vous conseille de faire à la place est:

  • essayez d'ajouter des caractéristiques saisonnières (par exemple, la variable mois, la variable jour, une variable qui est définie pour être vrai s'il ya un certain jour férié ce jour - là ou combien de jours Il ya à la prochaine fête importante-il s'agit d'une salle où vous pourriez être vraiment créatif)
  • utilisez un agrégat données de l'année dernière comme une caractéristique - vous pourriez, par exemple, alimenter les résultats de l'année dernière ou agrégations d'entre eux comme moyenne courante des résultats de l'année dernière, maximum, minimum-etc.

Deuxièmement, est-il raisonnable d'utiliser return_sequences=True ici? Dans autrement dit, je garde mes données Y telles quelles (50, 1096, 3) de sorte que (pour autant que Je l'ai compris) il y a une prédiction à chaque pas de temps pour lequel une perte peut-elle être calculée par rapport aux données cibles? Ou serais-je mieux off avec return_sequences=Faux, de sorte que seule la valeur finale de chaque lot est utilisé pour évaluer la perte (c'est à dire si l'aide annuelle lots, puis en 2016 pour le produit 1, nous évaluons par rapport à la valeur de (1,1,1)).

utilisant return_sequences=True pourrait être utile, mais seulement dans les cas suivants:

  1. Lorsqu'une LSTM donnée (ou une autre couche récurrente) sera suivie d'une autre couche récurrente.
  2. dans un scénario-quand vous alimentez une série originale décalée comme un sortie par ce que vous apprenez simultanément un modèle dans différentes fenêtres de temps,etc.

de La manière décrite dans un deuxième point pourrait être une approche intéressante, mais garder l'esprit dans l'esprit qu'il pourrait être un peu difficile à mettre en œuvre car vous devrez réécrire votre modèle afin d'obtenir une production de résultats. Ce qui pourrait aussi être plus difficile est que vous aurez besoin de tester votre modèle contre de nombreux types d'instabilités de temps - et une telle approche pourrait rendre totalement irréalisable.

Troisièmement, comment traiter les 50 produits différents? Ils sont différents, mais toujours fortement corrélés et nous avons vu avec d'autres les approches (par exemple un MLP avec de simples fenêtres de temps) que le les résultats sont meilleurs quand tous les produits sont considérés comme le même modèle. Quelques idées qui sont actuellement sur la table:

  • changement de la variable cible n'est pas seulement de 3 variables, mais 3 * 50 = 150, c'est-à-dire que pour chaque produit il y a trois cibles, toutes formées simultanément.
  • divise les résultats après la couche LSTM en 50 réseaux denses, qui prennent comme entrée les sorties du LSTM, plus certaines fonctionnalités qui sont spécifiques à chaque produit - c'est-à-dire que nous obtenons un réseau multi-tâches avec 50 fonctions de perte, que nous optimisons ensuite ensemble. Serait-ce fou?
  • considérer un produit comme une seule observation, et inclure les caractéristiques spécifiques au produit déjà à la couche LSTM. Utilisez seulement cette couche suivi d'une couche d'ouput de taille 3 (pour les trois cibles). Pousser par chaque produit dans un lot séparé.

j'opterais certainement pour un premier choix, mais avant de fournir une explication détaillée, je vais discuter des inconvénients des 2e et 3e choix:

  • dans la deuxième approche: il ne serait pas fou mais vous perdrez un beaucoup de corrélations entre les produits cibles,
  • dans la troisième approche: vous perdrez beaucoup de modèles intéressants se produisant dans les dépendances entre les différentes séries chronologiques.

avant d'arriver à mon choix - discutons encore une autre question - redondances dans votre ensemble de données. Je suppose que vous avez 3 sortes de caractéristiques:

  • produits spécifiques (disons qu'il y en a "m")
  • caractéristiques générales - disons qu'il est 'n`.

Maintenant vous avez la table de taille (timesteps, m * n, products) . Je le transformerais en tableau de forme (timesteps, products * m + n) car les caractéristiques générales sont les mêmes pour tous les produits. Cela vous sauvera beaucoup de mémoire et vous permettra également de vous alimenter en réseau récurrent (gardez à l'esprit que les couches récurrentes de keras n'ont qu'une seule dimension de fonctionnalité - alors que vous en aviez deux - product et feature ).

Alors pourquoi la première approche est la meilleure à mon avis? Parce qu'il tire profit de nombreuses dépendances intéressantes des données. Bien sûr - cela pourrait nuire au processus de formation - mais il y a une astuce facile à surmonter: réduction dimensionnelle . Vous pouvez par exemple former PCA sur votre vecteur de 150 Dimensions et le réduire à une taille beaucoup plus petite - grâce à ce que vous avez vos dépendances modélisées par PCA et votre sortie a beaucoup plus faisable taille.

Quatrièmement, comment traiter les données de validation? Normalement, je voudrais juste garder un échantillon choisi au hasard pour la validation, mais ici, nous besoin de garder l'ordre de l'heure en place. Donc je suppose que le mieux est de il suffit de garder quelques mois de côté?

C'est une question très importante. De mon expérience - vous devez tester votre solution contre de nombreux types d'instabilités afin de assurez-vous qu'il fonctionne bien. Donc quelques règles que vous devez garder à l'esprit:

  • il devrait y avoir aucun chevauchement entre vos séquences d'entraînement et les séquences d'essai. Si tel était le cas, vous obtiendriez une valeur valide à partir d'un ensemble d'essais transmis à un modèle pendant la formation.
  • vous devez tester la stabilité de temps de modèle contre de nombreuses sortes de dépendances de temps.

le dernier point pourrait être un peu vague - donc pour vous fournir quelques exemples:

  • stabilité de l'année - validez votre modèle en l'entraînant en utilisant chaque combinaison possible de deux ans et mettez-le à l'essai sur un hold-out un (e.g. 2015, 2016 contre 2017, 2015 contre 2016, etc.)- cela vous montrera comment les changements d'année affecte votre modèle,
  • stabilité des prédictions futures - formez votre modèle sur un sous-ensemble de semaines/mois/années et le tester en utilisant une semaine/mois / année suivante résultat (e.g. former le janvier 2015, janvier 2016 et janvier 2017 et le tester en utilisant février 2015, Février 2016, février 2017 données, etc.)
  • mois de la stabilité - train modèle lors de la tenue d'un certain mois dans un ensemble de test.

bien sûr - vous pouvez essayer de tenir encore un autre aboutissants.

Cinquièmement, et c'est la partie qui est probablement la plus claire pour moi - comment puis-je utiliser les résultats réels pour effectuer des prédictions? Disons que j'ai utilisé return_sequences=False et je me suis entraîné sur les trois années dans trois les lots (chaque fois, jusqu'à Novembre) avec l'objectif de la formation le modèle de prédire la valeur suivante (déc.2014, déc. 2015, Déc. 2016). Si je veux l'utilisation de ces résultats en 2017, comment cela fonctionne réellement? Si Je bien compris, la seule chose que je peux faire dans ce cas est pour ensuite alimenter le modèle tous les points de données pour Jan À Nov 2017 et it vous me rendrez une prédiction pour décembre 2017. Est-ce exact? Cependant, si je devais utiliser return_sequences=Vrai, alors formés sur toutes les données jusqu'à Décembre 2016, puis - je obtenir une prédiction pour Jan 2017 juste en donnant au modèle les caractéristiques observées en janvier 2017? Ou dois-je donnez-lui aussi les 12 mois avant Jan 2017? Qu'en est-il de février 2017, ai-je en outre besoin de donner la valeur pour 2017, plus un autre 11 mois avant cela? (Si c' on dirait que je suis confus, c'est parce que je suis!)

cela dépend de la façon dont vous avez construit votre modèle:

  • si vous avez utilisé return_sequences=True vous devez le réécrire pour avoir return_sequence=False ou tout simplement en prenant la sortie et en considérant seulement la dernière étape du résultat,
  • si vous avez utilisé une fenêtre fixe-alors vous devez juste alimenter une fenêtre avant la prédiction au modèle,
  • si vous avez utilisé une longueur variable - vous pourriez alimenter n'importe quel Pas de temps en cours de votre période de prédiction que vous voulez (mais je vous conseille de nourrir au moins 7 jours en cours).

    enfin, en fonction de la structure que je dois utiliser, Comment puis-je le faire dans Keras? Ce que j'ai à l'esprit en ce moment est quelque chose dans le sens suivant: (bien que ce serait pour un seul produit, ne résout donc pas d'avoir tous les produits dans le même modèle)

Ici - plus d'infos sur quel type de modèle que vous avez choisi est nécessaire.

11
répondu Marcin Możejko 2017-11-01 18:38:41

Question 1

il y a plusieurs approches pour ce problème. Celui que vous proposez semble être une fenêtre coulissante.

Mais en fait, vous n'avez pas besoin de trancher la dimension de temps, vous pouvez entrer tous les 3 ans à la fois. Vous pouvez trancher la dimension des produits, dans le cas où votre lot devient trop grand pour la mémoire et la vitesse.

vous pouvez travailler avec un seul tableau avec la forme (products, time, features)

Question 2

Oui, il est logique d'utiliser return_sequences=True .

Si j'ai bien compris votre question, vous avez y prédictions pour chaque jour, non?

Question 3

C'est vraiment une question ouverte. Toutes les approches ont leurs avantages.

mais si vous envisagez de mettre toutes les caractéristiques du produit ensemble, étant ces caractéristiques de nature différente, vous devriez probablement élargir toutes les fonctions possibles, comme s'il y avait un gros-chaud vecteur en considérant toutes les caractéristiques de tous les produits.

si chaque produit a des caractéristiques indépendantes qui s'appliquent seulement à lui - même, l'idée de créer des modèles individuels pour chaque produit ne me semble pas insensé.

vous pourriez également chose de faire le Produit id une entrée vectorielle one-hot, et utiliser un seul modèle.

Question 4

selon l'approche vous choisissez, vous pouvez:

  • Diviser certains produits comme les données de validation
  • laisser la dernière partie des étapes de temps comme données de validation
  • essayer une méthode de validation croisée en laissant des longueurs différentes pour l'entraînement et le test (plus les données d'essai sont longues, Plus l'erreur est grande, cependant, vous pourriez vouloir recadrer ces données d'essai pour avoir une longueur fixe)

Question 5

Il peut y avoir de nombreuses approches.

il y a des approches où vous utilisez des fenêtres coulissantes. Vous entraînez votre modèle pour des durées fixes.

et il y a des approches où vous entraînez les couches LSTM avec toute la longueur. Dans ce cas, vous devez d'abord prédire toute la partie connue, puis commencer à prédire la partie inconnue.

ma question: Est-ce que les données X sont connues pour la période où vous devez prédire Y ? De X est également inconnue dans cette période, Donc vous devez également prédire X ?

Question 6

je vous recommande de jeter un oeil à cette question et sa réponse: Comment traiter la prévision de séries chronologiques en plusieurs étapes dans multivariée LSTM dans keras

Voir aussi ce cahier qui parvient à démontrer l'idée: https://github.com/danmoller/TestRepo/blob/master/TestBookLSTM.ipynb

dans ce carnet, cependant, j'ai utilisé une approche qui met X et Y comme entrées. Et nous prédisons les futurs X et Y.

vous pouvez essayer de créer un modèle (si c'est le cas) seulement pour prédire X. Puis un deuxième modèle pour prédire Y à partir de X.

dans un autre cas (si vous avez déjà toutes les données X, Pas besoin de prédire X), vous pouvez créer un modèle qui prédit seulement Y de X. (Vous continueriez à suivre une partie de la méthode dans le carnet, où vous prédisez d'abord le Y déjà connu juste pour faire s'ajuster votre modèle à l'endroit où dans la séquence il est, puis vous prédisez l'Inconnu Y) -- ceci peut être fait en une seule entrée X pleine longueur (qui contient le x de formation Au début et le x de test à la fin).

réponse Bonus

savoir quelle approche et quel type de modèle choisir est probablement la réponse exacte à gagner la compétition... donc, il n'y a pas de meilleure réponse à cette question, chaque concurrent essaie de trouver cette réponse.

4
répondu Daniel Möller 2017-11-01 18:29:37

suite aux deux réponses déjà fournies, je pense que vous devriez avoir un oeil à cet article par Amazon Research sur la prévision des ventes en utilisant LSTMs pour voir comment ils traitent les questions que vous avez mentionnées:

https://arxiv.org/abs/1704.04110

en outre, je dois également souligner qu'une régularisation appropriée est extrêmement importante lors de l'utilisation des réseaux récurrents, car leur capacité à s'équiper peut être vraiment spectaculaire. Vous pourriez vouloir jeter un coup d'oeil à "abandon variable récurrente" comme décrit dans cet article

https://arxiv.org/abs/1512.05287

Note: Ceci a déjà été implémenté dans Tensorflow!

0
répondu Martin Keller 2017-11-07 09:04:04