Para RNNs (por exemplo, LSTMs e GRUs), a entrada da camada é uma lista de intervalos de tempo e cada intervalo de tempo é um tensor de recurso. Isso significa que você pode ter um tensor de entrada como este (na notação Pythonic):
# Input tensor to RNN
[
# Timestep 1
[ temperature_in_paris, value_of_nasdaq, unemployment_rate ],
# Timestep 2
[ temperature_in_paris, value_of_nasdaq, unemployment_rate ],
# Timestep 3
[ temperature_in_paris, value_of_nasdaq, unemployment_rate ],
...
]
Então, absolutamente, você pode ter vários recursos a cada passo do tempo. Na minha opinião, o clima é uma característica da série temporal: onde eu moro, isso acontece em função do tempo. Portanto, seria bastante razoável codificar as informações meteorológicas como um dos seus recursos em cada timestep (com uma codificação apropriada, como nublado = 0, ensolarado = 1 etc.).
Se você possui dados que não são de séries temporais, não faz sentido transmiti-los pelo LSTM. Talvez o LSTM funcione de qualquer maneira, mas mesmo se funcionar, provavelmente terá um custo de maior perda / menor precisão por tempo de treinamento.
Como alternativa, você pode introduzir esse tipo de informação "extra" em seu modelo fora do LSTM por meio de camadas adicionais. Você pode ter um fluxo de dados como este:
TIME_SERIES_INPUT ------> LSTM -------\
*---> MERGE ---> [more processing]
AUXILIARY_INPUTS --> [do something] --/
Então, você mesclaria suas entradas auxiliares nas saídas LSTM e continuaria sua rede a partir daí. Agora seu modelo é simplesmente multi-entrada.
Por exemplo, digamos que em seu aplicativo específico, você mantenha apenas a última saída da sequência de saída LSTM. Digamos que seja um vetor de comprimento 10. Sua entrada auxiliar pode ser seu clima codificado (portanto, escalar). Sua camada de mesclagem pode simplesmente anexar as informações meteorológicas auxiliares no final do vetor de saída LSTM para produzir um único vetor de comprimento 11. Mas você não precisa manter apenas o último timestep de saída do LSTM: se o LSTM produziu 100 timesteps, cada com um vetor de 10 vetores, você ainda pode adicionar informações meteorológicas auxiliares, resultando em 100 intervalos de tempo, cada um consistindo em um vetor de 11 pontos de dados.
A documentação do Keras em sua API funcional tem uma boa visão geral disso.
Em outros casos, como aponta o @horaceT, convém condicionar o LSTM em dados não temporais. Por exemplo, preveja o tempo amanhã, com o local. Nesse caso, aqui estão três sugestões, cada uma com positivo / negativo:
Faça com que o primeiro intervalo de tempo contenha seus dados de condicionamento, uma vez que "efetivamente" definirá o estado interno / oculto da sua RNN. Francamente, eu não faria isso por várias razões: seus dados de condicionamento precisam ter a mesma forma que o restante de seus recursos, dificulta a criação de RNNs com estado (em termos de ter muito cuidado em rastrear como você alimenta dados) na rede), a rede pode "esquecer" os dados de condicionamento com tempo suficiente (por exemplo, sequências longas de treinamento ou sequências longas de previsão), etc.
Inclua os dados como parte dos próprios dados temporais. Portanto, cada vetor de característica em um passo específico inclui "principalmente" dados de séries temporais, mas os dados de condicionamento são anexados ao final de cada vetor de característica. A rede aprenderá a reconhecer isso? Provavelmente, mas mesmo assim, você está criando uma tarefa de aprendizado mais difícil poluindo os dados da sequência com informações não sequenciais. Então, eu também desencorajaria isso.
Provavelmente, a melhor abordagem seria afetar diretamente o estado oculto da RNN no tempo zero. Essa é a abordagem adotada por Karpathy e Fei-Fei e por Vinyals et al . É assim que funciona:
- Para cada amostra de treinamento, leve suas variáveis de condição .x⃗
- Transforme / reformule suas variáveis de condição com uma transformação afim para colocá-las na forma correta como o estado interno do RNN: (esses e são pesos treináveis). Você pode obtê-lo com uma camada densa em keras.v⃗ = W x⃗ + b⃗ Wb⃗
- Para o primeiro timestep, adicione ao estado oculto da RNN ao calcular seu valor.v⃗
Essa abordagem é a mais "teoricamente" correta, uma vez que condiciona adequadamente o RNN em suas entradas não temporais, naturalmente resolve o problema de forma e também evita poluir os passos de entrada com informações adicionais não temporais. A desvantagem é que essa abordagem geralmente requer controle de arquitetura em nível de gráfico; portanto, se você estiver usando uma abstração de nível superior como Keras, será difícil implementá-la, a menos que adicione seu próprio tipo de camada.