Samouczek RNN ​​(rekurencyjna sieć neuronowa): przykład TensorFlow

⚡ Inteligentne podsumowanie

Rekurencyjne sieci neuronowe dodają stan pamięci do zwykłych neuronów, przekazując każde wyjście jako kolejne wejście, dzięki czemu model może uczyć się w określonej kolejności. W tym przewodniku zbudujemy taką sieć w TensorFlow i prognozujemy szereg czasowy.

  • 🔘 Stan pamięci: Każdy neuron rekurencyjny otrzymuje poprzednie dane wyjściowe wraz z nowymi danymi wejściowymi, co zapewnia sieci świadomość czasową.
  • ️ Kształt wyjściowy: Przebieg działania sieci zabawkowej zwraca tensor (3, 2, 6): partie, kroki czasowe i neurony w tej kolejności.
  • ✅ Zasada przetwarzania wsadowego: Dane wejściowe szeregów czasowych są przekształcane na trzy wymiary, a tablica etykiet to ta sama seria przesunięta o jeden okres do przodu.
  • 🧪 Szkielet modelu: Placeholdery, BasicRNNCell opakowany w dynamic_rnn, gęsta projekcja, następnie średni błąd kwadratowy z optymalizatorem Adam.
  • 🛠️. Bieg treningowy: 1,500 epok na 120 neuronach rekurencyjnych powoduje zmniejszenie straty z 502 893 do około 1,385.
  • 📉 Znany limit: Długie sekwencje wywołują problem zanikającego gradientu, który ma zostać rozwiązany za pomocą algorytmu LSTM i jego wariantów bramkowanych.

Rekurencyjna sieć neuronowa RNN

Dlaczego potrzebujemy rekurencyjnej sieci neuronowej (RNN)?

Rekurencyjna sieć neuronowa (RNN) umożliwia modelowanie jednostek pamięci w celu utrwalania danych i modelowania zależności krótkoterminowych. Jest również stosowany w prognozowaniu szeregów czasowych w celu identyfikacji korelacji i wzorców danych. Pomaga także w uzyskiwaniu wyników predykcyjnych dla danych sekwencyjnych, zapewniając podobne zachowanie jak ludzki mózg.

Struktura an Sztuczna sieć neuronowa jest stosunkowo prosty i polega głównie na mnożeniu macierzy. W pierwszym kroku dane wejściowe są mnożone przez początkowo losowe wagi i odchylenie, przekształcane za pomocą funkcji aktywacji, a wartości wyjściowe służą do prognozowania. Ten krok daje wyobrażenie o tym, jak bardzo sieć odbiega od rzeczywistości.

Zastosowaną metryką jest strata. Im wyższa funkcja straty, tym głupszy model. Aby poprawić wiedzę o sieci, konieczna jest pewna optymalizacja poprzez dostosowanie wag sieci. Metoda stochastycznego spadku gradientu jest stosowana w celu zmiany wartości wag w odpowiednim kierunku. Po dokonaniu dostosowania sieć może użyć kolejnej partii danych do przetestowania swojej nowej wiedzy.

Na szczęście błąd jest niższy niż poprzednio, ale wciąż niewystarczający. Etap optymalizacji jest wykonywany iteracyjnie, aż do zminimalizowania błędu, tj. do momentu, gdy nie można uzyskać więcej informacji.tracprzetrząsać.

Problem z tego typu modelem polega na tym, że nie ma on żadnej pamięci. Oznacza to, że wejście i wyjście są niezależne. Innymi słowy, model nie przejmuje się tym, co było wcześniej. Rodzi się pytanie, kiedy trzeba przewidzieć szeregi czasowe lub zdania, ponieważ sieć potrzebuje informacji o danych historycznych lub przeszłych słowach.

Aby przezwyciężyć ten problem, opracowano nowy typ architektury: rekurencyjną sieć neuronową (RNN)

Co to jest rekurencyjna sieć neuronowa (RNN)?

Rekurencyjna sieć neuronowa (RNN) to klasa sztucznych sieci neuronowych, w których połączenia między różnymi węzłami tworzą graf skierowany, co pozwala na dynamiczne zachowanie w czasie. Pomaga ona modelować dane sekwencyjne pochodzące z sieci sprzężenia zwrotnego. Działa podobnie do ludzkiego mózgu, dostarczając wyniki predykcyjne.

Rekurencyjna sieć neuronowa wygląda całkiem podobnie do tradycyjnej sieci neuronowej, z tą różnicą, że do neuronów dodawany jest stan pamięci. Obliczenia uwzględniające pamięć są proste.

Wyobraź sobie prosty model, w którym tylko jeden neuron pobiera partię danych. W tradycyjnej sieci neuronowej model generuje wynik poprzez pomnożenie danych wejściowych przez wagę i funkcję aktywacji. W sieci neuronowej (RNN) dane wyjściowe są wysyłane do siebie wielokrotnie. Nazywamy to krok czasu czas, w którym dane wyjściowe stają się danymi wejściowymi kolejnego mnożenia macierzy.

Na przykład na poniższym obrazku widać, że sieć składa się z jednego neuronu. Sieć oblicza mnożenie macierzy między wejściem a wagą i dodaje nieliniowość za pomocą funkcji aktywacji. Staje się wyjściem w t-1. Wynik ten jest wejściem drugiego mnożenia macierzy.

Pojedynczy neuron rekurencyjny wysyłający swoje wyjście w czasie t-1 z powrotem jako wejście kolejnego mnożenia

Powtarzalna sieć neuronowa (RNN)

Poniżej kodujemy prosty RNN w TensorFlow, aby zrozumieć krok i kształt wyniku.

Sieć składa się z:

  • Cztery wejścia
  • Sześć neuronów
  • 2-krotne kroki

Sieć będzie działać w sposób przedstawiony na poniższym obrazku.

Rozwinięty RNN z czterema wejściami, sześcioma neuronami i dwoma krokami czasowymi

Sieć nazywa się „rekurencyjną”, ponieważ wykonuje tę samą operację w każdym kwadracie aktywacji. Sieć obliczała wagi danych wejściowych i poprzedniego wyjścia przed użyciem funkcji aktywacji.

Uwaga dotycząca wersji: Kod w tym samouczku dotyczy interfejsu API graficznego TensorFlow 1.x. W TensorFlow 2.x ten sam skrypt nadal działa po… import tensorflow.compat.v1 as tf plus tf.disable_v2_behavior()ponieważ symbole zastępcze, sesje i moduł rnn_cell znajdują się teraz pod tf.compat.v1. Idiomatyczny odpowiednik 2.x to tf.keras.layers.SimpleRNN.

import numpy as np
import tensorflow as tf
n_inputs = 4
n_neurons = 6
n_timesteps = 2
The data is a sequence of a number from 0 to 9 and divided into three batches of data.
## Data 
X_batch = np.array([
        [[0, 1, 2, 5], [9, 8, 7, 4]], # Batch 1
        [[3, 4, 5, 2], [0, 0, 0, 0]], # Batch 2
        [[6, 7, 8, 5], [6, 5, 4, 2]], # Batch 3
    ])

Możemy zbudować sieć z symbolem zastępczym danych, etapem cyklicznym i wynikiem.

Zdefiniuj symbol zastępczy danych

X = tf.placeholder(tf.float32, [None, n_timesteps, n_inputs])

Tutaj:

  • Brak: nieznany i będzie odpowiadał wielkości partii
  • n_timesteps: Ile razy sieć będzie wysyłać dane wyjściowe z powrotem do neuronu
  • n_inputs: Liczba wejść na partię

Zdefiniuj sieć rekurencyjną

Jak widać na powyższym obrazku, sieć składa się z 6 neuronów. Sieć obliczy iloczyn dwukropkowy:

  • Dane wejściowe z pierwszym zestawem wag (tj. 6: równa liczbie neuronów)
  • Poprzednie wyjście z drugim zestawem wag (tj. 6: odpowiadające liczbie wyjść)

Należy zauważyć, że podczas pierwszego sprzężenia zwrotnego wartości poprzedniego wyjścia są równe zerom, ponieważ nie mamy dostępnej żadnej wartości.

Obiektem do zbudowania RNN jest tf.contrib.rnn.BasicRNNCell z argumentem num_units definiującym liczbę wejść

basic_cell = tf.contrib.rnn.BasicRNNCell(num_units=n_neurons)

Teraz, gdy sieć jest zdefiniowana, możesz obliczyć wyjścia i stany

outputs, states = tf.nn.dynamic_rnn(basic_cell, X, dtype=tf.float32)

Obiekt ten wykorzystuje pętlę wewnętrzną do mnożenia macierzy odpowiednią liczbę razy.

Należy zauważyć, że neuron rekurencyjny jest funkcją wszystkich danych wejściowych z poprzednich kroków czasowych. W ten sposób sieć buduje własną pamięć. Informacje z poprzedniego kroku czasowego mogą być propagowane w czasie przyszłym. To właśnie magia rekurencyjnej sieci neuronowej.

## Define the shape of the tensor
X = tf.placeholder(tf.float32, [None, n_timesteps, n_inputs])
## Define the network
basic_cell = tf.contrib.rnn.BasicRNNCell(num_units=n_neurons)
outputs, states = tf.nn.dynamic_rnn(basic_cell, X, dtype=tf.float32)
init = tf.global_variables_initializer()
init = tf.global_variables_initializer()
with tf.Session() as sess:
    init.run()
    outputs_val = outputs.eval(feed_dict={X: X_batch})
print(states.eval(feed_dict={X: X_batch}))
[[ 0.38941205 -0.9980438   0.99750966  0.7892596   0.9978241   0.9999997 ]
 [ 0.61096436  0.7255889   0.82977575 -0.88226104  0.29261455 -0.15597084]
 [ 0.62091285 -0.87023467  0.99729395 -0.58261937  0.9811445   0.99969864]]

Dla wyjaśnienia, drukujemy wartości z poprzedniego stanu. Powyższe dane wyjściowe przedstawiają dane wyjściowe z ostatniego stanu. Teraz, drukując wszystkie dane wyjściowe, zauważysz, że stany to poprzednie dane wyjściowe każdej partii. Oznacza to, że poprzednie dane wyjściowe zawierają informacje o całej sekwencji.

print(outputs_val)    
print(outputs_val.shape)    
[[[-0.75934666 -0.99537754  0.9735819  -0.9722234  -0.14234993
   -0.9984044 ]
  [ 0.99975264 -0.9983206   0.9999993  -1.         -0.9997506
   -1.        ]]

 [[ 0.97486496 -0.98773265  0.9969686  -0.99950117 -0.7092863
   -0.99998885]
  [ 0.9326837   0.2673438   0.2808514  -0.7535883  -0.43337247
    0.5700631 ]]

 [[ 0.99628735 -0.9998728   0.99999213 -0.99999976 -0.9884324
   -1.        ]
  [ 0.99962527 -0.9467421   0.9997403  -0.99999714 -0.99929446
   -0.9999795 ]]]
(3, 2, 6)

Poniższy adnotowany widok rozbija ten sam wydrukowany tensor na partie.

Adnotowany tensor wyjściowy RNN oznaczający trzy partie, sześć wyjść neuronowych i kształt (3, 2, 6)

Wynik ma postać (3, 2, 6):

  • 3: Liczba partii
  • 2: Numer kroku czasowego
  • 6: Liczba neuronów

Optymalizacja rekurencyjnej sieci neuronowej jest identyczna jak w przypadku tradycyjnej sieci neuronowej. Bardziej szczegółowo, jak optymalizować kod, zobaczysz w następnej części tego samouczka dotyczącego rekurencyjnej sieci neuronowej.

Zastosowania RNN

RNN ma wiele zastosowań, szczególnie jeśli chodzi o przewidywanie przyszłości. W branży finansowej RNN może być pomocny w przewidywaniu cen akcji lub oznak kierunku rynku akcji (tj. pozytywnego lub negatywnego).

RNN jest przydatny w samochodzie autonomicznym, ponieważ może uniknąć wypadku samochodowego, przewidując trajektorię pojazdu.

RNN jest szeroko stosowany w analizie tekstu, podpisach obrazów, analizie nastrojów i tłumaczeniu maszynowym. Recenzję filmu można na przykład wykorzystać do zrozumienia uczuć, jakie odczuwa widz po obejrzeniu filmu. Automatyzacja tego zadania jest bardzo przydatna, gdy wytwórnia filmowa nie ma wystarczająco dużo czasu na przeglądanie, oznaczanie, konsolidowanie i analizowanie recenzji. Maszyna może wykonać pracę z większą dokładnością.

Ograniczenia RNN

Teoretycznie RNN ma przenosić informacje do czasu. Jednak propagowanie wszystkich tych informacji, gdy krok czasowy jest zbyt długi, jest dość trudne. Kiedy sieć ma zbyt wiele głębokich warstw, staje się niemożliwa do nauczenia. Problem ten nazywa się: znikający problem z gradientem. Jeśli pamiętasz, sieć neuronowa aktualizuje wagę za pomocą algorytmu gradientu opadania. Gradienty stają się mniejsze, gdy sieć przechodzi do niższych warstw.

Podsumowując, gradienty pozostają stałe, co oznacza brak możliwości poprawy. Model uczy się na podstawie zmiany gradientu; zmiana ta wpływa na wynik sieci. Jeśli jednak różnica w gradiencie jest zbyt mała (tj. wagi zmieniają się nieznacznie), sieć nie może się niczego nauczyć, a tym samym na wynik. Dlatego sieć napotykająca problem znikającego gradientu nie może zbiegać się do dobrego rozwiązania.

Ulepszenie LSTM

Aby rozwiązać potencjalny problem zanikającego gradientu, z którym boryka się sieć neuronowa RNN, trzej badacze, Hochreiter, Schmidhuber i Bengio, udoskonalili sieć RNN, stosując architekturę zwaną pamięcią długoterminową (LSTM). W skrócie, LSTM dostarcza sieci istotne informacje z przeszłości, odnoszące się do czasów współczesnych. Maszyna wykorzystuje lepszą architekturę do selekcji i przenoszenia informacji do późniejszych okresów.

Architektura LSTM jest dostępna w TensorFlow, tf.contrib.rnn.LSTMCell. LSTM nie jest objęty zakresem tego samouczka. Możesz zapoznać się z oficjalną dokumentacja dalszych informacji

W TensorFlow 2.x do tej komórki dociera się jako tf.compat.v1.nn.rnn_cell.LSTMCell, podczas gdy nowy kod zwykle używa tf.keras.layers.LSTM lub z bramką zapalniczki tf.keras.layers.GRU, który osiąga porównywalną dokładność przy mniejszej liczbie parametrów.

RNN w szeregach czasowych

W tym samouczku dotyczącym sieci neuronowych TensorFlow RNN wykorzystasz sieć neuronową RNN z danymi szeregów czasowych. Szeregi czasowe są zależne od danych z przeszłości, co oznacza, że ​​wartości z przeszłości zawierają istotne informacje, z których sieć może się uczyć. Ideą stojącą za predykcją szeregów czasowych jest oszacowanie przyszłej wartości szeregu, na przykład ceny akcji, temperatury, PKB itd.

Przygotowanie danych dla Keras RNN i szeregów czasowych może być trochę trudne. Przede wszystkim celem jest przewidzenie następnej wartości szeregu, co oznacza, że ​​użyjesz informacji z przeszłości, aby oszacować wartość w t + 1. Etykieta jest równa sekwencji wejściowej i przesunięta o jeden okres do przodu. Po drugie, liczba danych wejściowych jest ustawiona na 1, tj. jedna obserwacja na czas. Na koniec, krok czasowy jest równy sekwencji wartości liczbowej. Na przykład, jeśli ustawisz krok czasowy na 10, sekwencja wejściowa zwróci dziesięć kolejnych razy.

Spójrz na poniższy wykres. Po lewej stronie przedstawiliśmy dane szeregów czasowych, a po prawej fikcyjną sekwencję wejściową. Tworzysz funkcję zwracającą zbiór danych z losową wartością dla każdego dnia od stycznia 2001 r. do grudnia 2016 r.

# To plot pretty figures
%matplotlib inline
import matplotlib
import matplotlib.pyplot as plt
import pandas as pd
def create_ts(start = '2001', n = 201, freq = 'M'):
    rng = pd.date_range(start=start, periods=n, freq=freq)
    ts = pd.Series(np.random.uniform(-18, 18, size=len(rng)), rng).cumsum()
    return ts
ts= create_ts(start = '2001', n = 192, freq = 'M')
ts.tail(5)

Wydajność

2016-08-31    -93.459631
2016-09-30    -95.264791
2016-10-31    -95.551935
2016-11-30   -105.879611
2016-12-31   -123.729319
Freq: M, dtype: float64
ts = create_ts(start = '2001', n = 222)

# Left
plt.figure(figsize=(11,4))
plt.subplot(121)
plt.plot(ts.index, ts)
plt.plot(ts.index[90:100], ts[90:100], "b-", linewidth=3, label="A training instance")
plt.title("A time series (generated)", fontsize=14)

# Right
plt.subplot(122)
plt.title("A training instance", fontsize=14)
plt.plot(ts.index[90:100], ts[90:100], "b-", markersize=8, label="instance")
plt.plot(ts.index[91:101], ts[91:101], "bo", markersize=10, label="target", markerfacecolor='red')
plt.legend(loc="upper left")
plt.xlabel("Time")

plt.show()

Wygenerowany szereg czasowy po lewej stronie i dziesięcioetapowy przykład szkoleniowy z przesuniętymi celami po prawej stronie

Prawa część wykresu przedstawia wszystkie serie. Rozpoczyna się ona w 2001 roku i kończy w 2019 roku. Nie ma sensu wprowadzać wszystkich danych do sieci, zamiast tego należy utworzyć partię danych o długości równej krokowi czasowemu. Ta partia będzie zmienną X. Zmienna Y jest taka sama jak X, ale przesunięta o jeden okres (tj. chcemy prognozować t+1).

Obydwa wektory mają tę samą długość. Widać to w prawej części powyższego wykresu. Linia reprezentuje dziesięć wartości wejścia X, podczas gdy czerwone kropki to dziesięć wartości etykiety Y. Należy pamiętać, że etykieta zaczyna się jeden okres przed X i kończy jeden okres po.

Zbuduj RNN, aby przewidzieć szeregi czasowe w TensorFlow

Teraz, w trakcie tego szkolenia RNN, nadszedł czas na zbudowanie pierwszego RNN, który będzie przewidywał powyższą serię. Należy określić pewne hiperparametry (parametry modelu, tj. liczbę neuronów itp.) dla modelu:

  • Liczba wejść: 1
  • Krok czasowy (okna w szeregu czasowym): 10
  • Liczba neuronów: 120
  • Liczba wyjść: 1

Twoja sieć będzie uczyć się na podstawie sekwencji 10 dni i będzie zawierać 120 neuronów rekurencyjnych. Podajesz modelowi jedno dane wejściowe, tj. jeden dzień. Możesz swobodnie zmieniać wartości, aby sprawdzić, czy model się poprawił.

Przed skonstruowaniem modelu należy podzielić zbiór danych na zbiór treningowy i testowy. Pełny zbiór danych zawiera 222 punkty danych; pierwszych 201 punktów użyjesz do trenowania modelu, a ostatnich 21 do jego przetestowania.

Po zdefiniowaniu zbioru treningowego i testowego należy utworzyć obiekt zawierający partie. W tych partiach znajdują się wartości X i Y. Należy pamiętać, że wartości X są opóźnione o jeden okres. Dlatego należy użyć pierwszych 200 obserwacji, a krok czasowy wynosi 10. Obiekt X_batches powinien zawierać 20 partii o rozmiarze 10*1. Obiekt y_batches ma taki sam kształt jak obiekt X_batches, ale z jednym okresem do przodu.

Krok 1) Utwórz pociąg i przetestuj

Przede wszystkim konwertujesz serię na a numpy tablica; następnie definiujesz okna (czyli liczbę czasów, w których sieć będzie się uczyć), liczbę danych wejściowych, wyjściowych i rozmiar zestawu treningowego, jak pokazano w poniższym przykładzie TensorFlow RNN.

series = np.array(ts)
n_windows = 20   
n_input =  1
n_output = 1
size_train = 201

Następnie wystarczy podzielić tablicę na dwa zbiory danych.

## Split data
train = series[:size_train]
test = series[size_train:]
print(train.shape, test.shape)
(201,) (21,)

Krok 2) Utwórz funkcję zwracającą X_batches i y_batches

Aby to ułatwić, możesz utworzyć funkcję zwracającą dwie różne tablice, jedną dla X_batches i jedną dla y_batches.

Napiszmy funkcję RNN TensorFlow, aby skonstruować partie.

Należy zauważyć, że partie X są opóźnione o jeden okres (bierzemy wartość t-1). Wyjście funkcji powinno mieć trzy wymiary. Pierwszy wymiar jest równy liczbie partii, drugi rozmiarowi okien, a ostatni liczbie danych wejściowych.

Trudną częścią jest prawidłowe wybranie punktów danych. Dla punktów danych X wybierasz obserwacje od t = 1 do t = 200, natomiast dla punktu danych Y zwracasz obserwacje od t = 2 do 201. Gdy masz już prawidłowe punkty danych, zmiana kształtu jest prosta Serie.

Aby skonstruować obiekt z partii, należy podzielić zbiór danych na dziesięć partii o równej długości (tj. 20). Możesz użyć metody reshape i przekazać -1, aby seria była podobna do wielkości partii. Wartość 20 to liczba obserwacji na partię, a 1 to liczba danych wejściowych.

Musisz wykonać ten sam krok, ale dla etykiety.

Pamiętaj, że musisz przesunąć dane o liczbę razy, którą chcesz prognozować. Na przykład, jeśli chcesz prognozować jeden raz do przodu, przesuń serię o 1. Jeśli chcesz prognozować dwa dni, przesuń dane o 2.

x_data = train[:size_train-1]: Select all the training instance minus one day
X_batches = x_data.reshape(-1, windows, input): create the right shape for the batch e.g (10, 20, 1)
def create_batches(df, windows, input, output):
    ## Create X         
        x_data = train[:size_train-1] # Select the data
        X_batches = x_data.reshape(-1, windows, input)  # Reshape the data 
    ## Create y
        y_data = train[n_output:size_train]
        y_batches = y_data.reshape(-1, windows, output)
        return X_batches, y_batches

Teraz, gdy funkcja jest zdefiniowana, możesz ją wywołać, aby utworzyć partie, jak pokazano w poniższym przykładzie RNN.

X_batches, y_batches = create_batches(df = train,
                                      windows = n_windows,
                                      input = n_input,
                                      output = n_output)

Możesz wydrukować kształt, aby upewnić się, że wymiary są prawidłowe.

print(X_batches.shape, y_batches.shape)
(10, 20, 1) (10, 20, 1)

Musisz utworzyć zbiór testowy zawierający tylko jedną partię danych i 20 obserwacji.

Należy pamiętać, że prognozujesz dni po dniach, co oznacza, że ​​druga przewidywana wartość będzie oparta na prawdziwej wartości z pierwszego dnia (t+1) testowego zbioru danych. Tak naprawdę, prawdziwa wartość będzie znana.

Jeśli chcesz prognozować t+2 (tj. dwa dni do przodu), musisz użyć przewidywanej wartości t+1; jeśli zamierzasz przewidzieć t+3 (trzy dni do przodu), musisz użyć przewidywanej wartości t+1 i t+2. Ma to sens, że trudno jest dokładnie przewidzieć t+n dni do przodu.

X_test, y_test = create_batches(df = test, windows = 20,input = 1, output = 1)
print(X_test.shape, y_test.shape)
(10, 20, 1) (10, 20, 1)

Dobrze, rozmiar Twojej partii jest gotowy, możesz zbudować architekturę RNN. Pamiętaj, masz 120 neuronów rekurencyjnych.

Krok 3) Zbuduj model

Aby utworzyć model, należy zdefiniować trzy części:

  1. Zmienna z tensorami
  2. RNN
  3. Strata i optymalizacja

Krok 3.1) Zmienne

Musisz określić zmienne X i Y o odpowiednim kształcie. Ten krok jest banalny. Tensor ma ten sam wymiar co obiekty X_batches i y_batches.

Na przykład tensor X jest symbolem zastępczym (sprawdź samouczek na Wprowadzenie do TensorFlow aby odświeżyć zdanie na temat deklaracji zmiennej) ma trzy wymiary:

  • Uwaga: wielkość partii
  • n_windows: Długość okien, czyli liczba razy, w których model przegląda się wstecz
  • n_input: Liczba wejść

Wynik to:

tf.placeholder(tf.float32, [None, n_windows, n_input])
## 1. Construct the tensors
X = tf.placeholder(tf.float32, [None, n_windows, n_input])   
y = tf.placeholder(tf.float32, [None, n_windows, n_output])

Krok 3.2) Utwórz RNN

W drugiej części tego przykładu RNN TensorFlow musisz zdefiniować architekturę sieci. Tak jak poprzednio, używasz obiektu BasicRNNCell i dynamic_rnn z estymatora TensorFlow.

## 2. create the model
basic_cell = tf.contrib.rnn.BasicRNNCell(num_units=r_neuron, activation=tf.nn.relu)   
rnn_output, states = tf.nn.dynamic_rnn(basic_cell, X, dtype=tf.float32)   

Następna część jest nieco trudniejsza, ale umożliwia szybsze obliczenia. Musisz przekształcić wynik uruchomienia w gęstą warstwę, a następnie przekonwertować go ponownie, aby miał ten sam wymiar co dane wejściowe.

stacked_rnn_output = tf.reshape(rnn_output, [-1, r_neuron])          
stacked_outputs = tf.layers.dense(stacked_rnn_output, n_output)       
outputs = tf.reshape(stacked_outputs, [-1, n_windows, n_output])  

Krok 3.3) Utwórz stratę i optymalizację

Optymalizacja modelu zależy od wykonywanego zadania. W poprzednim samouczku dotyczącym CNNTwoim celem była klasyfikacja obrazów, w tym samouczku RNN cel jest nieco inny. Twoim zadaniem jest dokonanie predykcji na zmiennej ciągłej w porównaniu z klasą.

Różnica ta jest istotna, ponieważ zmieni problem optymalizacji. Problem optymalizacji zmiennej ciągłej polega na minimalizacji błędu średniokwadratowego. Aby skonstruować te metryki w TF, możesz użyć:

tf.reduce_sum(tf.square(wyjścia – y))

Pozostała część kodu RNN jest taka sama jak poprzednio; używasz optymalizatora Adama, aby zmniejszyć straty (tj. MSE):

tf.train.AdamOptimizer(learning_rate=learning_rate)

optymalizator.minimize(strata)

To tyle, możesz wszystko spakować w jedną całość i Twój model jest gotowy do treningu.

tf.reset_default_graph()
r_neuron = 120    

## 1. Construct the tensors
X = tf.placeholder(tf.float32, [None, n_windows, n_input])   
y = tf.placeholder(tf.float32, [None, n_windows, n_output])

## 2. create the model
basic_cell = tf.contrib.rnn.BasicRNNCell(num_units=r_neuron, activation=tf.nn.relu)   
rnn_output, states = tf.nn.dynamic_rnn(basic_cell, X, dtype=tf.float32)              

stacked_rnn_output = tf.reshape(rnn_output, [-1, r_neuron])          
stacked_outputs = tf.layers.dense(stacked_rnn_output, n_output)       
outputs = tf.reshape(stacked_outputs, [-1, n_windows, n_output])   

## 3. Loss + optimization
learning_rate = 0.001  
 
loss = tf.reduce_sum(tf.square(outputs - y))    
optimizer = tf.train.AdamOptimizer(learning_rate=learning_rate)         
training_op = optimizer.minimize(loss)                                          

init = tf.global_variables_initializer() 

Będziesz trenował model przy użyciu 1500 epok i drukował stratę co 150 iteracji. Po wyszkoleniu modelu oceniasz go na zestawie testowym i tworzysz obiekt zawierający przewidywania, jak pokazano w poniższym przykładzie rekurencyjnej sieci neuronowej.

iteration = 1500 

with tf.Session() as sess:
    init.run()
    for iters in range(iteration):
        sess.run(training_op, feed_dict={X: X_batches, y: y_batches})
        if iters % 150 == 0:
            mse = loss.eval(feed_dict={X: X_batches, y: y_batches})
            print(iters, "\tMSE:", mse)
    
    y_pred = sess.run(outputs, feed_dict={X: X_test})
0 	MSE: 502893.34
150 	MSE: 13839.129
300 	MSE: 3964.835
450 	MSE: 2619.885
600 	MSE: 2418.772
750 	MSE: 2110.5923
900 	MSE: 1887.9644
1050 	MSE: 1747.1377
1200 	MSE: 1556.3398
1350 	MSE: 1384.6113

Wreszcie, w tym samouczku dotyczącym głębokiego uczenia się RNN, możesz wykreślić rzeczywistą wartość szeregu z wartością przewidywaną. Jeśli model zostanie poprawiony, wartości przewidywane należy nałożyć na wartości rzeczywiste.

Jak widać, model ma potencjał do poprawy. Od Ciebie zależy zmiana hiperparametrów, takich jak okna, rozmiar partii czy liczba neuronów rekurencyjnych.

plt.title("Forecast vs Actual", fontsize=14)
plt.plot(pd.Series(np.ravel(y_test)), "bo", markersize=8, label="Actual", color='green')
plt.plot(pd.Series(np.ravel(y_pred)), "r.", markersize=8, label="Forecast", color='red')
plt.legend(loc="lower left")
plt.xlabel("Time")

plt.show()

Wykres prognozy i rzeczywistości z zielonymi punktami rzeczywistymi i czerwonymi punktami przewidywanymi

Prognoza vs faktyczna

FAQ

Zacznij od okna obejmującego jeden pełny cykl wzorca, a następnie je dostosuj. Dłuższe okna uwzględniają więcej kontekstu, ale spowalniają proces uczenia i pogarszają zanik gradientu. Dziesięć kroków sprawdza się w przypadku serii dziennej; sezonowość tygodniowa zazwyczaj wymaga więcej.

Tak, z podkładką. Zastąp import tensorflow.compat.v1 i wywołaj disable_v2_behavior(), ponieważ symbole zastępcze, sesje i rnn_cell zostały przeniesione do przestrzeni nazw compat. Świeże TensorFlow projekty powinny zamiast tego używać tf.keras.layers.SimpleRNN.

Asystenci AI sugerują rozmiary okien, wykrywają niezgodności kształtów przed uruchomieniem i tworzą szkic kodu ładowania danych na podstawie schematu. Kompresują pętlę prób i błędów, która dominuje w pracy z modelami rekurencyjnymi, choć ostateczny wybór hiperparametrów nadal wymaga walidacji na podstawie danych wstrzymanych.

Copilot dobrze radzi sobie z powtarzalnym rusztowaniem: blokami sesji, słownikami kanałów i okresowym drukowaniem strat. Kształty tensorów i przesunięcie etykiet pozostają ryzykowną częścią, dlatego zawsze należy samodzielnie określić wymiary wsadu, zanim zaufa się wygenerowanej pętli.

Warstwy rekurencyjne oczekują (partia, krok czasowy, cecha). Przekształcenie na (-1, okna, dane wejściowe) informuje framework, ile sekwencji istnieje, jak daleko wstecz sięga każda z nich i ile wartości pojawia się w każdym kroku. Brak wymiaru powoduje błąd rangi.

LSTM wykorzystuje trzy bramki i oddzielny stan komórki; GRU łączy bramki „zapomnij” i „wejściową” oraz pomija stan komórki. GRU trenuje szybciej i z mniejszą liczbą parametrów, podczas gdy LSTM często wyprzedza w przypadku bardzo długich zależności.

Prognozy ciągłe minimalizują błąd średniokwadratowy, podobnie jak w tym przewodniku z funkcją reduce_sum of squared residuals. Klasyfikacja sekwencji, taka jak etykiety sentymentu lub zadania obrazkowe omówione w… CNN samouczek, zamiast tego używa entropii krzyżowej.

Transformatory dominują w pracy z językiem, ponieważ uwaga jest paralelizowana w obrębie sekwencji. Modele rekurencyjne pozostają konkurencyjne w przypadku sygnałów strumieniowych, krótkich prognoz jednowymiarowych i urządzeń o małej pamięci, gdzie przetwarzanie krok po kroku jest zaletą, a nie wąskim gardłem.

Podsumuj ten post następująco: