Estou tentando reconciliar meu entendimento dos LSTMs e apontado aqui neste post por Christopher Olah implementado no Keras. Estou seguindo o blog escrito por Jason Brownlee para o tutorial de Keras. O que mais me deixa confuso é,
- A remodelagem das séries de dados em
[samples, time steps, features]
e, - Os LSTMs com estado
Vamos nos concentrar nas duas perguntas acima com referência ao código colado abaixo:
# reshape into X=t and Y=t+1
look_back = 3
trainX, trainY = create_dataset(train, look_back)
testX, testY = create_dataset(test, look_back)
# reshape input to be [samples, time steps, features]
trainX = numpy.reshape(trainX, (trainX.shape[0], look_back, 1))
testX = numpy.reshape(testX, (testX.shape[0], look_back, 1))
########################
# The IMPORTANT BIT
##########################
# create and fit the LSTM network
batch_size = 1
model = Sequential()
model.add(LSTM(4, batch_input_shape=(batch_size, look_back, 1), stateful=True))
model.add(Dense(1))
model.compile(loss='mean_squared_error', optimizer='adam')
for i in range(100):
model.fit(trainX, trainY, nb_epoch=1, batch_size=batch_size, verbose=2, shuffle=False)
model.reset_states()
Nota: create_dataset pega uma sequência de comprimento N e retorna uma N-look_back
matriz da qual cada elemento é uma look_back
sequência de comprimento.
O que são etapas e recursos de tempo?
Como pode ser visto, o TrainX é uma matriz 3D com Time_steps e Feature sendo as duas últimas dimensões, respectivamente (3 e 1 neste código em particular). Com relação à imagem abaixo, isso significa que estamos considerando o many to one
caso, em que o número de caixas cor de rosa é 3? Ou significa literalmente que o comprimento da corrente é 3 (ou seja, são consideradas apenas 3 caixas verdes).
O argumento dos recursos se torna relevante quando consideramos séries multivariadas? por exemplo, modelar duas ações financeiras simultaneamente?
LSTMs com estado
Os LSTMs com estado indicam que salvamos os valores da memória da célula entre execuções de lotes? Se for esse o caso, batch_size
é um deles, e a memória é redefinida entre as execuções de treinamento. Suponho que isso esteja relacionado ao fato de que os dados de treinamento não são embaralhados, mas não sei como.
Alguma ideia? Referência da imagem: http://karpathy.github.io/2015/05/21/rnn-effectiveness/
Editar 1:
Um pouco confuso sobre o comentário de @ van sobre as caixas vermelhas e verdes serem iguais. Portanto, apenas para confirmar, as seguintes chamadas de API correspondem aos diagramas não desenrolados? Observando especialmente o segundo diagrama ( batch_size
foi escolhido arbitrariamente):
Edição 2:
Para as pessoas que fizeram o curso de aprendizado profundo da Udacity e ainda confundiram com o argumento time_step, consulte a seguinte discussão: https://discussions.udacity.com/t/rnn-lstm-use-implementation/163169
Atualizar:
Acontece que model.add(TimeDistributed(Dense(vocab_len)))
era o que eu estava procurando. Aqui está um exemplo: https://github.com/sachinruk/ShakespeareBot
Update2:
Resumi a maior parte do meu entendimento dos LSTMs aqui: https://www.youtube.com/watch?v=ywinX5wgdEU
fonte
Respostas:
Primeiro de tudo, você escolhe ótimos tutoriais ( 1 , 2 ) para começar.
O que significa Etapa do tempo :
Time-steps==3
em X.shape (Descrição da forma dos dados) significa que existem três caixas cor de rosa. Como em Keras, cada etapa requer uma entrada, portanto, o número de caixas verdes deve normalmente ser igual ao número de caixas vermelhas. A menos que você hackear a estrutura.muitos para muitos vs. muitos para um : no keras, existe um
return_sequences
parâmetro ao inicializarLSTM
ouGRU
ouSimpleRNN
. Quandoreturn_sequences
éFalse
(por padrão), é muitos para um, como mostrado na figura. Sua forma de retorno é(batch_size, hidden_unit_length)
, que representa o último estado. Quandoreturn_sequences
éTrue
, então é muitos para muitos . Sua forma de retorno é(batch_size, time_step, hidden_unit_length)
O argumento dos recursos se torna relevante : Argumento do recurso significa "Qual é o tamanho da sua caixa vermelha" ou qual é a dimensão de entrada em cada etapa. Se você deseja prever, digamos, 8 tipos de informações de mercado, poderá gerar seus dados com
feature==8
.Com estado : você pode procurar o código fonte . Ao inicializar o estado, se
stateful==True
, então, o estado do último treinamento será usado como estado inicial, caso contrário, ele gerará um novo estado. Ainda não ligueistateful
. No entanto, eu discordo de quebatch_size
só pode ser 1 quandostateful==True
.Atualmente, você gera seus dados com dados coletados. Como as informações de estoque estão chegando como fluxo, em vez de esperar um dia para coletar todas as seqüências, você deseja gerar dados de entrada on-line enquanto treina / prevê com a rede. Se você tiver 400 ações compartilhando a mesma rede, poderá configurar
batch_size==400
.fonte
stateful: Boolean (default False). If True, the last state for each sample at index i in a batch will be used as initial state for the sample of index i in the following batch.
lookback = 1
?stateful=True
: O tamanho do lote pode ser o que você quiser, mas você deve cumpri-lo. Se você construir o seu modelo com um tamanho de lote de 5, então todosfit()
,predict()
e métodos relacionados irá requerer um lote de 5. Note, porém, que este estado não será salvo commodel.save()
, o que pode parecer indesejável. No entanto, você pode adicionar manualmente o estado ao arquivo hdf5, se necessário. Mas, efetivamente, isso permite alterar o tamanho do lote, salvando e recarregando um modelo.Como complemento à resposta aceita, esta resposta mostra os comportamentos de keras e como obter cada imagem.
Comportamento geral de Keras
O processamento interno do keras padrão é sempre de muitos para muitos, como na figura a seguir (onde usei
features=2
pressão e temperatura, apenas como exemplo):Nesta imagem, aumentei o número de etapas para 5, para evitar confusão com as outras dimensões.
Para este exemplo:
Nossa matriz de entrada deve ter o formato de
(N,5,2)
:Entradas para janelas deslizantes
Freqüentemente, as camadas LSTM devem processar as seqüências inteiras. Dividir janelas pode não ser a melhor ideia. A camada possui estados internos sobre como uma sequência está evoluindo à medida que avança. O Windows elimina a possibilidade de aprender seqüências longas, limitando todas as sequências ao tamanho da janela.
Nas janelas, cada janela faz parte de uma longa sequência original, mas por Keras elas serão vistas como uma sequência independente:
Observe que, nesse caso, você possui inicialmente apenas uma sequência, mas a divide em várias seqüências para criar janelas.
O conceito de "o que é uma sequência" é abstrato. As partes importantes são:
Atingir cada caso com "camadas únicas"
Atingir o padrão de muitos para muitos:
Você pode conseguir muitos para muitos com uma camada LSTM simples, usando
return_sequences=True
:Conseguindo muitos para um:
Usando exatamente a mesma camada, o keras executará exatamente o mesmo pré-processamento interno, mas quando você usar
return_sequences=False
(ou simplesmente ignorar esse argumento), o keras descartará automaticamente as etapas anteriores à anterior:Conseguir um para muitos
Agora, isso não é suportado apenas pelas camadas keras LSTM. Você precisará criar sua própria estratégia para multiplicar as etapas. Existem duas boas abordagens:
stateful=True
para obter recorrentemente a saída de uma etapa e servi-la como a entrada da próxima etapa (necessidadesoutput_features == input_features
)Um para muitos com vetor de repetição
Para ajustar ao comportamento padrão do keras, precisamos de entradas em etapas; portanto, simplesmente repetimos as entradas pelo comprimento que queremos:
Compreendendo stateful = True
Agora vem um dos possíveis usos de
stateful=True
(além de evitar o carregamento de dados que não cabem na memória do computador de uma só vez)Stateful nos permite inserir "partes" das seqüências em etapas. A diferença é:
stateful=False
, o segundo lote contém novas seqüências inteiras, independentes do primeiro lotestateful=True
, o segundo lote continua o primeiro lote, estendendo as mesmas seqüências.É como dividir as seqüências nas janelas também, com essas duas principais diferenças:
stateful=True
verá essas janelas conectadas como uma única sequência longaEm
stateful=True
, cada novo lote será interpretado como continuando o lote anterior (até você ligarmodel.reset_states()
).Exemplo de entradas, o lote 1 contém as etapas 1 e 2, o lote 2 contém as etapas 3 a 5:
Observe o alinhamento dos tanques no lote 1 e no lote 2! É por isso que precisamos
shuffle=False
(a menos que estejamos usando apenas uma sequência, é claro).Você pode ter qualquer número de lotes, indefinidamente. (Para ter comprimentos variáveis em cada lote, use
input_shape=(None,features)
.Um para muitos com stateful = True
Para o nosso caso aqui, usaremos apenas 1 etapa por lote, porque queremos obter uma etapa de saída e torná-la uma entrada.
Observe que o comportamento na imagem não é "causado por"
stateful=True
. Forçaremos esse comportamento em um loop manual abaixo. Neste exemplo,stateful=True
é o que "nos permite" parar a sequência, manipular o que queremos e continuar de onde paramos.Honestamente, a abordagem de repetição é provavelmente a melhor escolha para este caso. Mas, como estamos analisando
stateful=True
, este é um bom exemplo. A melhor maneira de usar isso é o próximo caso "muitos para muitos".Camada:
Agora, vamos precisar de um loop manual para previsões:
Muitos para muitos com stateful = True
Agora, aqui, temos uma aplicação muito boa: dada uma sequência de entrada, tente prever suas futuras etapas desconhecidas.
Estamos usando o mesmo método do "um para muitos" acima, com a diferença de que:
Camada (o mesmo que acima):
Treinamento:
Vamos treinar nosso modelo para prever o próximo passo das seqüências:
Prever:
O primeiro estágio de nossa previsão envolve "ajustar os estados". É por isso que vamos prever a sequência inteira novamente, mesmo que já conheçamos essa parte:
Agora vamos ao loop, como no caso de um para muitos. Mas não redefina os estados aqui! . Queremos que o modelo saiba em qual etapa da sequência ele está (e sabe que está no primeiro novo passo por causa da previsão que acabamos de fazer acima)
Esta abordagem foi usada nestas respostas e arquivo:
Atingindo configurações complexas
Em todos os exemplos acima, mostrei o comportamento de "uma camada".
Obviamente, é possível empilhar muitas camadas umas sobre as outras, nem todas seguindo o mesmo padrão, e criar seus próprios modelos.
Um exemplo interessante que vem aparecendo é o "autoencoder" que possui um "muitos para um codificador" seguido por um "um para muitos" decodificador:
Codificador:
Decodificador:
Usando o método "repeat";
Autoencoder:
Treinar com
fit(X,X)
Explicações adicionais
Se você quiser detalhes sobre como as etapas são calculadas nos LSTMs ou detalhes sobre os
stateful=True
casos acima, poderá ler mais nesta resposta: Dúvidas sobre `Noções básicas sobre LSTMs do Keras`fonte
my_cell = LSTM(num_output_features_per_timestep, return_state=True)
, seguido por um loop dea, _, c = my_cell(output_of_previous_time_step, initial_states=[a, c])
Quando você tem sequências de retorno em sua última camada de RNN, não pode usar uma camada Densa simples, e sim TimeDistributed.
Aqui está um exemplo de código que pode ajudar outras pessoas.
words = keras.layers.Input (batch_shape = (Nenhum, self.maxSequenceLength), nome = "entrada")
fonte