Zrozumienie Keras LSTMs

Staram się pogodzić moje zrozumienie LSTMs i wskazał tutaj w ten post przez Christopher Olah zaimplementowane w Keras. Jestem po blog napisany przez Jason Brownlee dla keras tutorial. To, co mnie głównie myli, to:

  1. przekształcanie serii danych na [samples, time steps, features] i,
  2. stateful LSTMs

Skupmy się na dwóch powyższych pytaniach z odniesieniem do kodu wklejonego poniżej:

# 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()

Uwaga: create_dataset przyjmuje sekwencję długości n i zwraca tablicę N-look_back, której każdy element jest sekwencją długości look_back.

Czym są kroki i funkcje czasu?

Jak widać TrainX jest tablicą 3-D z Time_steps i Feature będącymi odpowiednio dwoma ostatnimi wymiarami (3 i 1 w tym kodzie). Czy w odniesieniu do poniższego obrazka oznacza to, że rozważamy przypadek many to one, w którym liczba różowych pudełek wynosi 3? A może dosłownie oznacza to, że długość łańcucha wynosi 3 (tj. uwzględniono tylko 3 zielone pola). Tutaj wpisz opis obrazka

Czy argument funkcji staje się istotny, gdy rozważamy szereg wielowymiarowy? np. modelowanie dwóch akcji finansowych jednocześnie?

Stateful LSTMs

Czy stateful LSTMs oznacza, że zapisujemy wartości pamięci komórki między seriami? Jeśli tak jest, batch_size jest jeden, a pamięć jest resetowana między treningami, więc po co mówić, że jest stanowa. Zgaduję, że to ma związek do tego, że dane treningowe nie są tasowane, ale nie jestem pewien, jak.

Jakieś pomysły? Odniesienie do obrazu: http://karpathy.github.io/2015/05/21/rnn-effectiveness/

Edit 1:

Trochę zmieszany komentarz @ van o tym, że czerwone i zielone pola są równe. Czy poniższe wywołania API odpowiadają rozwiniętym diagramom? Szczególnie zauważając, że drugi diagram (batch_size był arbitralnie wybrany.): Tutaj wpisz opis obrazka Tutaj wpisz opis obrazka

Edit 2:

Dla osób, które ukończyły kurs głębokiego uczenia Udacity i nadal są zdezorientowane co do argumentu time_step, spójrz na następującą dyskusję: https://discussions.udacity.com/t/rnn-lstm-use-implementation/163169

Aktualizacja:

Okazało się, że właśnie tego szukałem. Oto przykład: https://github.com/sachinruk/ShakespeareBot

Update2:

Mam podsumowałem większość mojego zrozumienia LSTMs tutaj: https://www.youtube.com/watch?v=ywinX5wgdEU

Author: Sachin_ruk, 2016-08-02

3 answers

Po pierwsze, wybierasz świetne tutoriale(1,2) na początek.

Co oznacza etap czasowy: Time-steps==3 w X. kształt (opisujący kształt danych) oznacza, że są trzy różowe pola. Ponieważ w Keras każdy krok wymaga wprowadzenia, dlatego liczba zielonych pól powinna być zwykle równa liczbie czerwonych pól. Chyba, że zhakujesz strukturę.

Many to many vs. many to one: W keras istnieje parametr return_sequences podczas inicjalizacji LSTM lub GRU lub SimpleRNN. Jeśli return_sequences jest False (Domyślnie), to jest wiele do jednego, Jak pokazano na rysunku. Jego return shape to (batch_size, hidden_unit_length), które reprezentują ostatni stan. Gdy return_sequences jest True, to jest wiele do wielu . Jego zwrotny kształt to (batch_size, time_step, hidden_unit_length)

Czy argument feature staje się istotny : argument Feature oznacza "jak duże jest twoje czerwone pole" lub jaki jest wymiar wejściowy każdego kroku. Jeśli chcesz przewidzieć na podstawie, powiedzmy, 8 rodzajów informacji rynkowych, to możesz wygenerować swoje dane za pomocą feature==8.

Stateful : możesz wyszukać kod źródłowy. Podczas inicjalizacji stanu, if stateful==True, stan z ostatniego treningu zostanie użyty jako stan początkowy, w przeciwnym razie wygeneruje on nowy stan. Jeszcze nie włączyłem stateful. Nie zgadzam się jednak z tym, że {[14] } Może być tylko 1, gdy stateful==True.

Obecnie generujesz swoje dane za pomocą zebranych danych. Obraz Twoje informacje giełdowe przychodzą jako strumień, a nie czekając na dzień, aby zebrać wszystkie sekwencyjne, chciałbyś wygenerować dane wejściowe online podczas treningu / Przewidywania z siecią. Jeśli masz 400 akcji współdzielących tę samą sieć, możesz ustawić batch_size==400.

 89
Author: Van,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2016-08-03 08:09:59

Jako uzupełnienie zaakceptowanej odpowiedzi, ta odpowiedź pokazuje zachowania kerasa i jak osiągnąć każdy obraz.

Ogólne zachowanie Kerasa

Keras jest jedną z najbardziej rozpoznawalnych i najbardziej rozpoznawalnych postaci keras w historii keras.]}

ManyToMany

Na tym obrazku zwiększyłem liczbę kroków do 5, aby uniknąć pomylenia z innymi wymiarami.

Do tego przykład:

  • mamy zbiorniki na olej N
  • spędziliśmy 5 godzin podejmując działania co godzinę (kroki czasowe)
  • zmierzyliśmy dwie cechy:
    • Ciśnienie P
    • Temperatura T

Nasza tablica wejściowa powinna mieć kształt (N,5,2):

        [     Step1      Step2      Step3      Step4      Step5
Tank A:    [[Pa1,Ta1], [Pa2,Ta2], [Pa3,Ta3], [Pa4,Ta4], [Pa5,Ta5]],
Tank B:    [[Pb1,Tb1], [Pb2,Tb2], [Pb3,Tb3], [Pb4,Tb4], [Pb5,Tb5]],
  ....
Tank N:    [[Pn1,Tn1], [Pn2,Tn2], [Pn3,Tn3], [Pn4,Tn4], [Pn5,Tn5]],
        ]

Wejścia do okien przesuwnych

Często warstwy LSTM mają przetwarzać całe sekwencje. Dzielenie okien może nie być najlepszym pomysłem. Warstwa ma wewnętrzne mówi o tym, jak Sekwencja ewoluuje w miarę postępów. Okna eliminują możliwość uczenia się długich sekwencji, ograniczając wszystkie sekwencje do rozmiaru okna.

W systemie Windows każde okno jest częścią długiej oryginalnej sekwencji, ale przez Kerasa będą one postrzegane jako niezależna Sekwencja.]}
        [     Step1    Step2    Step3    Step4    Step5
Window  A:  [[P1,T1], [P2,T2], [P3,T3], [P4,T4], [P5,T5]],
Window  B:  [[P2,T2], [P3,T3], [P4,T4], [P5,T5], [P6,T6]],
Window  C:  [[P3,T3], [P4,T4], [P5,T5], [P6,T6], [P7,T7]],
  ....
        ]

Zauważ, że w tym przypadku masz początkowo tylko jedną sekwencję, ale dzielisz ją na wiele sekwencji, aby utworzyć System windows.

Pojęcie " co jest sekwencja " jest abstrakcyjna. Ważne części to:

  • możesz mieć partie z wieloma pojedynczymi sekwencjami
  • to, co sprawia, że sekwencje są sekwencjami, to to, że ewoluują w krokach (Zwykle krokach czasowych)

Osiągnięcie każdego przypadku z "pojedynczymi warstwami"

Osiągnięcie standardu many to many:

StandardManyToMany

Możesz osiągnąć wiele do wielu za pomocą prostej warstwy LSTM, używając return_sequences=True:
outputs = LSTM(units, return_sequences=True)(inputs)

#output_shape -> (batch_size, steps, units)

Osiągnięcie wielu do jeden:

Keras używa dokładnie tej samej warstwy, ale kiedy użyjesz return_sequences=False (lub po prostu zignorujesz ten argument), keras automatycznie odrzuci kroki poprzednie do ostatniego:

Manytoon

outputs = LSTM(units)(inputs)

#output_shape -> (batch_size, units) --> steps were discarded, only the last was returned

Osiągnięcie jednego do wielu

Teraz nie jest to obsługiwane przez same warstwy keras LSTM. Będziesz musiał stworzyć własną strategię, aby pomnożyć kroki. Istnieją dwa dobre podejścia:

  • Create a stałe wejście wielostopniowe przez powtórzenie tensora
  • W tym celu należy wykonać następujące czynności, aby wykonać jeden krok i podać go jako dane wejściowe następnego kroku (needs output_features == input_features)

Jeden do wielu z wektorem powtórzeń

Aby dopasować się do standardowego zachowania keras, potrzebujemy wejść w krokach, więc po prostu powtarzamy wejścia dla żądanej długości:]}

OneToManyRepeat

outputs = RepeatVector(steps)(inputs) #where inputs is (batch,features)
outputs = LSTM(units,return_sequences=True)(outputs)

#output_shape -> (batch_size, steps, units)

Understanding stateful = True

Teraz przychodzi jeden z możliwych w przeciwieństwie do innych komputerów, które nie są w stanie zmieścić się w pamięci komputera]}

Stateful pozwala nam wprowadzać" części " sekwencji etapami. Różnica wynosi:

  • W stateful=False druga partia zawiera zupełnie nowe sekwencje, niezależne od pierwszej partii
  • W stateful=True druga partia kontynuuje pierwszą partię, rozszerzając te same sekwencje.

To jak dzielenie sekwencji również w windows, z tymi dwoma głównymi różnice:

  • te okna nie nakładają się!!
  • stateful=True będzie widzieć te okna połączone jako jedną długą sekwencję

W stateful=True każda nowa partia będzie interpretowana jako kontynuacja poprzedniej partii(dopóki nie wywołasz model.reset_states()).

  • Sekwencja 1 w partii 2 będzie kontynuowana Sekwencja 1 w partii 1.
  • Sekwencja 2 w partii 2 będzie kontynuowana Sekwencja 2 w partii 1.
  • Sekwencja n w partii 2 będzie kontynuowana Sekwencja n w Seria 1.

Przykład wejść, partia 1 zawiera kroki 1 i 2, partia 2 zawiera kroki 3 do 5:

                   BATCH 1                           BATCH 2
        [     Step1      Step2        |    [    Step3      Step4      Step5
Tank A:    [[Pa1,Ta1], [Pa2,Ta2],     |       [Pa3,Ta3], [Pa4,Ta4], [Pa5,Ta5]],
Tank B:    [[Pb1,Tb1], [Pb2,Tb2],     |       [Pb3,Tb3], [Pb4,Tb4], [Pb5,Tb5]],
  ....                                |
Tank N:    [[Pn1,Tn1], [Pn2,Tn2],     |       [Pn3,Tn3], [Pn4,Tn4], [Pn5,Tn5]],
        ]                                  ]

Zauważ wyrównanie czołgów w partii 1 i partii 2! Dlatego potrzebujemy shuffle=False (o ile oczywiście nie używamy tylko jednej sekwencji).

Możesz mieć dowolną liczbę partii, w nieskończoność. (Aby mieć zmienne długości w każdej partii, użyj input_shape=(None,features).

Jeden do wielu z stateful = True

W naszym przypadku użyjemy tylko 1 kroku na batch, ponieważ chcemy uzyskać jeden krok wyjściowy i uczynić go wejściowym.

Proszę zauważyć, że zachowanie na zdjęciu nie jest "spowodowane" stateful=True. Wymusimy to zachowanie w poniższej pętli ręcznej. W tym przykładzie stateful=True jest tym, co "pozwala" nam zatrzymać sekwencję, manipulować tym, co chcemy i kontynuować od miejsca, w którym się zatrzymaliśmy.

OneToManyStateful

Szczerze mówiąc, podejście powtórzeniowe jest prawdopodobnie lepszym wyborem w tym przypadku. Ale skoro patrzymy na stateful=True, to dobry przykład. Najlepszym sposobem wykorzystania tego jest następny przypadek "wiele do wielu".

Warstwa:

outputs = LSTM(units=features, 
               stateful=True, 
               return_sequences=True, #just to keep a nice output shape even with length 1
               input_shape=(None,features))(inputs) 
    #units = features because we want to use the outputs as inputs
    #None because we want variable length

#output_shape -> (batch_size, steps, units) 

Teraz będziemy potrzebować pętli ręcznej do przewidywania:

input_data = someDataWithShape((batch, 1, features))

#important, we're starting new sequences, not continuing old ones:
model.reset_states()

output_sequence = []
last_step = input_data
for i in steps_to_predict:

    new_step = model.predict(last_step)
    output_sequence.append(new_step)
    last_step = new_step

 #end of the sequences
 model.reset_states()

Many to many with stateful = True

Teraz, tutaj, mamy bardzo ładne zastosowanie: biorąc pod uwagę sekwencję wejściową, spróbuj przewidzieć jego przyszłe nieznane kroki.

Używamy tej samej metody jak w "jeden do wielu" powyżej, z tą różnicą, że:]}
  • użyjemy sekwencji sam w sobie być dane docelowe, o krok do przodu
  • znamy część sekwencji (więc odrzucamy tę część wyników).

ManyToManyStateful

Warstwa (taka sama jak wyżej):

outputs = LSTM(units=features, 
               stateful=True, 
               return_sequences=True, 
               input_shape=(None,features))(inputs) 
    #units = features because we want to use the outputs as inputs
    #None because we want variable length

#output_shape -> (batch_size, steps, units) 

Szkolenie:

Będziemy trenować nasz model, aby przewidzieć następny krok sekwencji:]}
totalSequences = someSequencesShaped((batch, steps, features))
    #batch size is usually 1 in these cases (often you have only one Tank in the example)

X = totalSequences[:,:-1] #the entire known sequence, except the last step
Y = totalSequences[:,1:] #one step ahead of X

#loop for resetting states at the start/end of the sequences:
for epoch in range(epochs):
    model.reset_states()
    model.train_on_batch(X,Y)

Przewidywanie:

[33]}pierwszy etap naszego przewidywania polega na "ustawieniu Stanów". Dlatego zamierzamy przewidzieć cała sekwencja ponownie, nawet jeśli znamy już tę jej część:
model.reset_states() #starting a new sequence
predicted = model.predict(totalSequences)
firstNewStep = predicted[:,-1:] #the last step of the predictions is the first future step

Teraz przechodzimy do pętli jak w przypadku jeden do wielu. Ale nie Resetuj Stanów tutaj!. Chcemy, aby model wiedział, w którym kroku sekwencji jest (i wie, że jest to pierwszy nowy krok ze względu na prognozę, którą przed chwilą wykonaliśmy)

output_sequence = [firstNewStep]
last_step = firstNewStep
for i in steps_to_predict:

    new_step = model.predict(last_step)
    output_sequence.append(new_step)
    last_step = new_step

 #end of the sequences
 model.reset_states()

To podejście zostało użyte w tych odpowiedziach i pliku:

Osiąganie złożonych konfiguracji

We wszystkich powyższych przykładach pokazałem zachowanie "jednej warstwy".

Można oczywiście układać wiele warstw jeden na drugim, niekoniecznie Wszystkie według tego samego wzoru, i tworzyć własne modele.

Jeden ciekawy przykład, który pojawił się jest "autoencoder", który ma koder "wiele do jednego", a następnie dekoder "Jeden do wielu": {]}

Encoder:

inputs = Input((steps,features))

#a few many to many layers:
outputs = LSTM(hidden1,return_sequences=True)(inputs)
outputs = LSTM(hidden2,return_sequences=True)(outputs)    

#many to one layer:
outputs = LSTM(hidden3)(outputs)

encoder = Model(inputs,outputs)

Dekoder:

Używając metody "powtórz";

inputs = Input((hidden3,))

#repeat to make one to many:
outputs = RepeatVector(steps)(inputs)

#a few many to many layers:
outputs = LSTM(hidden4,return_sequences=True)(outputs)

#last layer
outputs = LSTM(features,return_sequences=True)(outputs)

decoder = Model(inputs,outputs)

Autoencoder:

inputs = Input((steps,features))
outputs = encoder(inputs)
outputs = decoder(outputs)

autoencoder = Model(inputs,outputs)

Pociąg z fit(X,X)

 42
Author: Daniel Möller,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2018-07-24 13:32:41

Gdy masz return_sequences w ostatniej warstwie RNN nie możesz użyć prostej gęstej warstwy zamiast tego użyj TimeDistributed.

Oto przykładowy fragment kodu, który może pomóc innym.

Słowa = keras.warstwy.Input (batch_shape=(None, self.maxSequenceLength), name = "input")

    # Build a matrix of size vocabularySize x EmbeddingDimension 
    # where each row corresponds to a "word embedding" vector.
    # This layer will convert replace each word-id with a word-vector of size Embedding Dimension.
    embeddings = keras.layers.embeddings.Embedding(self.vocabularySize, self.EmbeddingDimension,
        name = "embeddings")(words)
    # Pass the word-vectors to the LSTM layer.
    # We are setting the hidden-state size to 512.
    # The output will be batchSize x maxSequenceLength x hiddenStateSize
    hiddenStates = keras.layers.GRU(512, return_sequences = True, 
                                        input_shape=(self.maxSequenceLength,
                                        self.EmbeddingDimension),
                                        name = "rnn")(embeddings)
    hiddenStates2 = keras.layers.GRU(128, return_sequences = True, 
                                        input_shape=(self.maxSequenceLength, self.EmbeddingDimension),
                                        name = "rnn2")(hiddenStates)

    denseOutput = TimeDistributed(keras.layers.Dense(self.vocabularySize), 
        name = "linear")(hiddenStates2)
    predictions = TimeDistributed(keras.layers.Activation("softmax"), 
        name = "softmax")(denseOutput)  

    # Build the computational graph by specifying the input, and output of the network.
    model = keras.models.Model(input = words, output = predictions)
    # model.compile(loss='kullback_leibler_divergence', \
    model.compile(loss='sparse_categorical_crossentropy', \
        optimizer = keras.optimizers.Adam(lr=0.009, \
            beta_1=0.9,\
            beta_2=0.999, \
            epsilon=None, \
            decay=0.01, \
            amsgrad=False))
 0
Author: Sanjay Krishna,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2018-04-25 09:05:36