[PYTHON] Implementieren Sie LSTM AutoEncoder mit Keras

1. Zuallererst

Dieser Artikel ist wie eine Fortsetzung von Implementieren von Keras LSTM Feed Forward mit Numpy. Implementieren Sie LSTM AutoEncoder mit Keras und versuchen Sie die binäre Klassifizierung anhand der erhaltenen Funktionen. Die Daten erzeugen zwei Sinuswellen mit unterschiedlichen Frequenzen und identifizieren diese.

2. Umwelt

3. Datenerstellung

3.1 Übersicht

Der folgende Artikel dient als Referenz für die Datengenerierung. Vielen Dank.

Dieses Mal haben wir die Datengenerierungsmethode für die binäre Klassifizierung ein wenig geändert. Bereiten Sie zwei Sinuswellen mit unterschiedlichen Frequenzen vor und lassen Sie sie identifizieren.

3.2 Code

Dies ist der Code zum Generieren der diesmal verwendeten Daten.

import pandas as pd
import numpy as np
import matplotlib.pyplot as plt

def make_data(random_factor, number_of_cycles, \
                timesteps, sampling_num_pair):
    """
    sampling_num_pair : 2 elements of tupple
Nummer, die in einem Zyklus abgetastet werden soll
        Ex. (20,80)
    """
    def _load_data(data, n_prev = 100):  
        """
        data should be pd.DataFrame()
        """
        docX, docY = [], []
        for i in range(len(data)-n_prev):
            docX.append(data.iloc[i:i+n_prev].as_matrix())
        alsX = np.array(docX)

        return alsX

    def _train_test_split(df, test_size=0.1, n_prev = 100):  
        """
        This just splits data to training and testing parts
        """
        ntrn = round(len(df) * (1 - test_size))
        ntrn = int(ntrn)
        X_train = _load_data(df.iloc[0:ntrn], n_prev)
        X_test = _load_data(df.iloc[ntrn:], n_prev)

        return X_train, X_test

    np.random.seed(0)

    sampling_num1, sampling_num2 = sampling_num_pair

    df1 = pd.DataFrame(np.arange(sampling_num1 * number_of_cycles + 1), columns=["t"])
    df1["sin_t"] = df1.t.apply(lambda x: np.sin(x * (2 * np.pi / sampling_num1)+ np.random.uniform(-1.0, +1.0) * random_factor))

    df2 = pd.DataFrame(np.arange(sampling_num2 * number_of_cycles + 1), columns=["t"])
    df2["sin_t2"] = df2.t.apply(lambda x: np.sin(x * (2 * np.pi / sampling_num2)+ np.random.uniform(-1.0, +1.0) * random_factor))

    X_train1, X_test1 = _train_test_split(df1[["sin_t"]], n_prev=timesteps) 
    X_train2, X_test2 = _train_test_split(df2[["sin_t2"]], n_prev=timesteps) 

    # concatenate X and make y
    X_train = np.r_[X_train1, X_train2]
    y_train = np.r_[np.tile(0, X_train1.shape[0]), np.tile(1, X_train2.shape[0])]

    X_test = np.r_[X_test1, X_test2]
    y_test = np.r_[np.tile(0, X_test1.shape[0]), np.tile(1, X_test2.shape[0])]

    return X_train, y_train, X_test, y_test

#Zufälliger Koeffizient
random_factor = 0.05
#Anzahl der zu generierenden Zyklen
number_of_cycles = 200
#Wie viele Punkte sollten in einem Zyklus abgetastet werden?
sampling_num_pair=(20,80)
#Die Länge des Fensters. Es wird die Länge einer Serie.
timesteps = 100

X_train, y_train, X_test, y_test = make_data(random_factor, number_of_cycles, timesteps, sampling_num_pair)
print("X_train.shape : ", X_train.shape) #X_train.shape :  (17802, 100, 1)
print("y_train.shape : ", y_train.shape) #y_train.shape :  (17802,)
print("X_test.shape : ", X_test.shape) #X_test.shape :  (1800, 100, 1)
print("y_test.shape : ", y_test.shape) #y_test.shape :  (1800,)

3.3 Handlung

Zeichnen wir die erzeugte Sinuswelle.

# make_Datenfunktion df1,Extrahiere df2 und zeichne es.
fig = plt.figure()
ax = fig.add_subplot(111)
ax.plot(df1["sin_t"][0:80], label="class0 sampling_num 20", color="red")
ax.plot(df2["sin_t2"][0:80], label="class1 sampling_num 80", color="blue")
ax.legend(loc="upper right")
fig.savefig("./sin_plot.png ")
plt.close("all")

sin_plot.png

Sie können sehen, dass class0 die vierfache Häufigkeit von class1 hat.

4. Modellbau

4.1 Übersicht

Ich habe auf The Keras Blog verwiesen, um das Modell zu erstellen. Es gab so etwas wie einen Hinweis im Kapitel des Sequenz-zu-Sequenz-Autoencoders, also habe ich ihn entsprechend hinzugefügt.

Das Originalpapier lautet Unüberwachtes Lernen von Videodarstellungen mithilfe von LSTMs. In diesem Artikel wird eine Bedingung (Übergabe der Eingabe in umgekehrter Reihenfolge zum Zeitpunkt der Decodierung) und eine Nichtbedingung (Übergabe von nichts) vorgeschlagen, aber dieses Mal implementieren wir die Bedingung.

4.2 Code

Definieren Sie das Modell des LSTM AutoEncoder. Dann trainiere und rekonstruiere den ursprünglichen X_train.

from keras.layers import Input, LSTM, RepeatVector, concatenate, Dense
from keras.models import Model

input_dim = 1
latent_dim = 10

# encode
inputs = Input(shape=(timesteps, input_dim))
encoded = LSTM(latent_dim, activation="tanh", recurrent_activation="sigmoid", return_sequences=False)(inputs)

#decode
hidden = RepeatVector(timesteps)(encoded)
reverse_input = Input(shape=(timesteps, input_dim))
hidden_revinput = concatenate([hidden, reverse_input])
decoded = LSTM(latent_dim, activation="tanh", recurrent_activation="sigmoid", return_sequences=True)(hidden_revinput)
decoded = Dense(latent_dim, activation="relu")(decoded)
decoded = Dense(input_dim, activation="tanh")(decoded)

# train
LSTM_AE = Model([inputs, reverse_input], decoded)
LSTM_AE.compile(optimizer='rmsprop', loss='mse')
X_train_rev = X_train[:,::-1,:]
LSTM_AE.fit([X_train, X_train_rev], X_train, epochs=30, batch_size=500, shuffle=True, validation_data=([X_train, X_train_rev], X_train))

X_hat = LSTM_AE.predict([X_train, X_train_rev])

Dieser Code fügt beim Decodieren eine vollständige Verbindungsschicht hinzu, bedeutet jedoch nichts Besonderes. Keras ist unglaublich! Sie können so einfach Ebenen hinzufügen! Es ist das Ergebnis des Spielens mit.

Als nächstes werden class0 und class1 in Klassen unterteilt, um zu sehen, wie sie von AutoEncoder neu konfiguriert werden.

def split_X(X, y):
    y_inv = np.abs(y - 1.)
    X_0 = X[y_inv.astype(bool),:,:]
    X_1 = X[y.astype(bool),:,:]
    return X_0, X_1

X_train_0, X_train_1 = split_X(X_train, y_train)
X_hat_0, X_hat_1 = split_X(X_hat, y_train)

print("X_train_0.shape : ", X_train_0.shape) #X_train_0.shape :  (3501, 100, 1)
print("X_train_1.shape : ", X_train_1.shape) #X_train_1.shape :  (14301, 100, 1)
print("X_hat_0.shape : ", X_hat_0.shape) #X_hat_0.shape :  (3501, 100, 1)
print("X_hat_1.shape : ", X_hat_1.shape) #X_hat_1.shape :  (14301, 100, 1)

4.3 Handlung

Zeichnen und überprüfen Sie, was von AutoEncoder rekonstruiert wurde.

#Rekonstruiert X._Mal sehen, wie der Zug aussieht
def plot_save(start_index, X_hat, X_train, X_class):
    fig = plt.figure()
    ax = fig.add_subplot(111)
    for i in np.arange(start_index,start_index+5):
        #Zeichnen Sie jeweils 5.
        ax.plot(X_hat[i,:,0], label="X hat", color="red")
        ax.plot(X_train[i,:,0], label="X train", color="blue")
    savename = "./AE_reconst_30ep_start_" + str(start_index) + "_cls" + str(X_class) + ".png "
    fig.savefig(savename)
    plt.close("all")

start_list = np.arange(0,len(X_train_0), 1000)
for start_index in start_list:
    plot_save(start_index, X_hat_0, X_train_0, X_class=0)

start_list = np.arange(0,len(X_train_1), 1000)
for start_index in start_list:
    plot_save(start_index, X_hat_1, X_train_1, X_class=1)

class0 AE_reconst_30ep_start_0_cls0.png

class1 AE_reconst_30ep_start_6000_cls1.png

Blau sind die Originaldaten und Rot sind die rekonstruierten. Dies sind diejenigen, die ich aus einer Reihe von Grundstücken ausgewählt habe. Alles war so.

Übrigens scheint es noch nicht konvergiert zu haben, daher denke ich, dass es eine bessere Annäherung sein wird, wenn Sie die Epoche verlängern, aber ich habe entschieden, dass dies in Bezug auf die Maschinenspezifikationen ausreicht. Übrigens dauerte es in 30 Epochen etwa 15 Minuten. (Mir wird wahrscheinlich gesagt, dass ich mein Bestes geben soll)

5. Extraktion erworbener Merkmale

5.1 Übersicht

Dies ist dasselbe wie Vorheriger Artikel. Extrahieren Sie den vom Encoder erhaltenen Merkmalsbetrag aus dem Modell.

5.2 Code

Definieren Sie die Funktion, die zum Extrahieren der Feature-Menge erforderlich ist.


def split_params(W, U, b):
    Wi = W[:,0:latent_dim]
    Wf = W[:,latent_dim:2*latent_dim]
    Wc = W[:,2*latent_dim:3*latent_dim]
    Wo = W[:,3*latent_dim:]

    print("Wi : ",Wi.shape)
    print("Wf : ",Wf.shape)
    print("Wc : ",Wc.shape)
    print("Wo : ",Wo.shape)

    Ui = U[:,0:latent_dim]
    Uf = U[:,latent_dim:2*latent_dim]
    Uc = U[:,2*latent_dim:3*latent_dim]
    Uo = U[:,3*latent_dim:]

    print("Ui : ",Ui.shape)
    print("Uf : ",Uf.shape)
    print("Uc : ",Uc.shape)
    print("Uo : ",Uo.shape)

    bi = b[0:latent_dim]
    bf = b[latent_dim:2*latent_dim]
    bc = b[2*latent_dim:3*latent_dim]
    bo = b[3*latent_dim:]
    print("bi : ",bi.shape)
    print("bf : ",bf.shape)
    print("bc : ",bc.shape)
    print("bo : ",bo.shape)

    return (Wi, Wf, Wc, Wo), (Ui, Uf, Uc, Uo), (bi, bf, bc, bo)


def calc_ht(params):
    x, latent_dim, W_, U_, b_ = params
    Wi, Wf, Wc, Wo = W_
    Ui, Uf, Uc, Uo = U_
    bi, bf, bc, bo = b_ 
    n = x.shape[0]

    ht_1 = np.zeros(n*latent_dim).reshape(n,latent_dim) #h_{t-1}Meint.
    Ct_1 = np.zeros(n*latent_dim).reshape(n,latent_dim) #C_{t-1}Meint.

    ht_list = []

    for t in np.arange(x.shape[1]):
        xt = np.array(x[:,t,:])
        it = sigmoid(np.dot(xt, Wi) + np.dot(ht_1, Ui) + bi)
        Ct_tilda = np.tanh(np.dot(xt, Wc) + np.dot(ht_1, Uc) + bc)
        ft = sigmoid(np.dot(xt, Wf) + np.dot(ht_1, Uf) + bf)
        Ct = it * Ct_tilda + ft * Ct_1
        ot = sigmoid( np.dot(xt, Wo) + np.dot(ht_1, Uo) + bo)
        ht = ot * np.tanh(Ct)
        ht_list.append(ht)
        ht_1 = ht
        Ct_1 = Ct

    ht = np.array(ht)
    return ht
    
def sigmoid(x):
    return 1.0 / (1.0 + np.exp(-x))
        

Eigentlich extrahieren.

W, U, b = LSTM_AE.layers[1].get_weights()
Ws, Us, bs = split_params(W, U, b)

params = [X_train, latent_dim, Ws, Us, bs]
ht_train = calc_ht(params)

params = [X_test, latent_dim, Ws, Us, bs]
ht_test = calc_ht(params)

LSTM_AE.layers [1] ist die Codierungs-LSTM-Schicht. Das Gewicht wird daraus extrahiert.

5.3 Handlung

ht_train ist eine Matrix von `(17802, 10)`, die eine 10-dimensionale Merkmalsgröße ist. Da die ursprüngliche Dimension 100 Dimensionen ist, die mit `` `timesteps = 100``` festgelegt wurden, wird sie von 100 Dimensionen auf 10 Dimensionen komprimiert. Lassen Sie uns dieses 10-dimensionale Merkmal vorerst zeichnen.

class0 hidden_two_class0_2.png

class1 hidden_two_class1_4.png

Ich bin mir nicht sicher. Da es sich um ein periodisches Signal handelt, wird es so aufgezeichnet, dass alle Bewegungen des Merkmalsbetrags in einem Zyklus angezeigt werden. Das allgemeine Verhalten ist ähnlich, aber es scheint, dass es anders sein kann, wenn Sie sich jedes einzelne ansehen. (Weil es schwierig ist, werde ich es nicht im Detail betrachten)

6. Identifizieren Sie anhand erworbener Funktionen

Klassifizieren wir class0 und class1 gemäß den von diesem LSTM AutoEncoder erfassten Funktionen. Lassen Sie uns vorerst die Tatsache beiseite legen, dass es nicht iid ist, und versuchen Sie es mit logistischer Regression.

from sklearn.linear_model import LogisticRegression 
from sklearn.metrics import accuracy_score
model = LogisticRegression(n_jobs=-1)
model.fit(ht_train, y_train)
y_hat_test = model.predict(ht_test)
accuracy_score(y_hat_test, y_test)
# 1.0

Die Genauigkeit für die Testdaten beträgt jetzt 1,0. Ich mache mir Sorgen, weil es zu teuer ist, aber es war ein Signal mit einer ganz anderen Wellenform. Ist es also so etwas?

7. Am Ende

――Ich habe zum ersten Mal mit Keras ein Modell gebaut, aber ich mache mir Sorgen, dass das, was ich tatsächlich im Inneren mache, zu vielschichtig ist und mit dem übereinstimmt, was ich tun möchte. Wenn ich nur die Ergebnisse betrachte, ist es wie erwartet, also würde ich gerne glauben, dass es getan ist. (Bitte sag mir) ――Wie verstehen und implementieren Menschen in der Community des maschinellen Lernens wie im Originalpapier das dort vorgeschlagene Modell, weil es nicht in mathematischen Formeln geschrieben ist? Ist die Idee des Rechengraphen weit verbreitet und wird durch Diagramme vermittelt? Oder ist es ein Problem, wenn man sich das Modell nicht einfach durch Lesen des Papiers vorstellen kann und es keine Reproduzierbarkeit gibt? Ich verstehe nicht wirklich. ――Weil Keras ein Rapper von Tendorflow ist, ist es natürlich, aber Menschen wie ich, die Tensolflow noch nie berührt haben, stoßen auf Schwierigkeiten, daher ist es möglicherweise vorerst besser, Tensorflow zu berühren.

Recommended Posts

Implementieren Sie LSTM AutoEncoder mit Keras
Implementieren Sie Keras LSTM Feed Forward mit Numpy
Implementieren Sie CVAE (Conditional Variational Autoencoder) im TensorFlow 2-System
Schreiben Sie DCGAN mit Keras
Hard-Swish mit Keras implementiert
Implementieren Sie XENO mit Python
Implementieren Sie sum in Python
Multivariates LSTM mit Keras
Implementieren Sie Traceroute in Python 3
Implementieren Sie BEGAN (Boundary Equilibrium Generative Adversarial Networks) mit Keras
Visualisieren Sie das Keras-Modell mit Python 3.5
Implementieren Sie die Follow-Funktion in Django
Implementiere die Timer-Funktion im Pygame
Implementieren Sie Style Transfer mit Pytorch
Implementieren Sie den rekursiven Abschluss in Go
Implementieren Sie Naive Bayes in Python 3.3
Implementieren Sie UnionFind (gleichwertig) in 10 Zeilen
Implementieren Sie alte Chiffren in Python
Implementieren Sie Redis Mutex in Python
Implementieren Sie die Erweiterung in Python
Implementieren Sie schnelles RPC in Python
Implementieren Sie den Dijkstra-Algorithmus in Python
Implementieren Sie den Slack Chat Bot in Python
Implementieren Sie den Gaußschen Prozess in Pyro
Implementieren Sie das Stacking-Lernen in Python [Kaggle]
Implementieren Sie einen tabellengesteuerten Test in Java
Implementieren Sie die Funktion power.prop.test von R in Python
Implementieren Sie Deep Learning / VAE (Variational Autoencoder)
Implementieren Sie einen Datumssetzer in Tkinter
Implementieren Sie das Singleton-Muster in Python
Lösung für ValueError in Keras imdb.load_data
Anfänger RNN (LSTM) | Versuchen Sie es mit Keras
Implementieren Sie die REST-API schnell in Python
Einfache Implementierung einer Regressionsanalyse mit Keras