Cet article est comme une suite de Implémentation de Keras LSTM Feed Forward avec numpy. Implémentez LSTM AutoEncoder avec Keras et essayez la classification binaire à partir des fonctionnalités obtenues. Les données génèrent deux ondes de péché avec des fréquences différentes et les identifient.
L'article suivant est utilisé comme référence pour la génération de données. Je vous remercie.
Cette fois, nous avons légèrement modifié la méthode de génération de données pour la classification binaire. Préparez deux ondes de péché avec des fréquences différentes et laissez-les être identifiées.
C'est le code pour générer les données utilisées cette fois.
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
Nombre à échantillonner en un cycle
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
#Coefficient aléatoire
random_factor = 0.05
#Nombre de cycles à générer
number_of_cycles = 200
#Combien de points doivent être échantillonnés en un cycle?
sampling_num_pair=(20,80)
#La longueur de la fenêtre. Cela devient la longueur d'une série.
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,)
Tracons l'onde de péché générée
# make_fonction de données df1,Extrayez df2 et tracez-le.
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")
Vous pouvez voir que class0 a quatre fois la fréquence de class1.
J'ai fait référence au Blog Keras pour créer le modèle. Il y avait quelque chose comme un indice dans le chapitre de l'autoencodeur séquence-à-séquence, donc je l'ai ajouté le cas échéant.
L'article original est Apprentissage non supervisé des représentations vidéo à l'aide de LSTM. Cet article propose du conditionnel (passer l'entrée dans l'ordre inverse au moment du décodage) et inconditionnel (ne rien transmettre), mais cette fois nous implémentons le conditionnel.
Définissez le modèle de LSTM AutoEncoder. Ensuite, entraînez et reconstruisez le X_train original.
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])
Ce code ajoute une couche de connexion complète lors du décodage, mais cela ne signifie rien de particulier. Keras est incroyable! Vous pouvez ajouter des couches si facilement! C'est le résultat de jouer avec.
Ensuite, class0 et class1 sont divisés en classes pour voir comment ils sont reconfigurés par AutoEncoder.
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)
Tracez et vérifiez ce qui a été reconstruit par AutoEncoder.
#Reconstruit X_Voyons à quoi ressemble le train
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):
#Placer 5 chacun.
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
class1
Le bleu correspond aux données d'origine et le rouge aux données reconstruites. Ce sont ceux que j'ai choisis parmi un certain nombre de parcelles. Tout était comme ça.
Au fait, il semble que cela n'ait pas encore convergé, donc je pense que ce sera une meilleure approximation si vous augmentez l'époque, mais j'ai décidé que cela suffisait en termes de spécifications de la machine. En passant, cela a pris environ 15 minutes à 30 époques. (On me dira probablement de faire de mon mieux)
C'est la même chose que Article précédent. Extraire la quantité de caractéristiques obtenue par l'encodeur du modèle
Définissez la fonction requise pour extraire la quantité d'objets.
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}Veux dire.
Ct_1 = np.zeros(n*latent_dim).reshape(n,latent_dim) #C_{t-1}Veux dire.
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))
En fait extraire.
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] est la couche d'encodage LSTM. Le poids en est extrait.
ht_train est une matrice de (17802, 10)
, qui est une quantité de caractéristiques à 10 dimensions.
Étant donné que la dimension d'origine est de 100 dimensions définies avec
timesteps = 100 '' ', elle est compressée de 100 dimensions à 10 dimensions.
Tracons cette caractéristique en 10 dimensions pour le moment.
class0
class1
Je ne suis pas sûr. Puisqu'il s'agit d'un signal périodique, il est tracé de sorte que tous les mouvements du montant de la caractéristique dans un cycle soient affichés. Le comportement général est similaire, mais il semble qu'il puisse être différent si vous regardez chacun d'eux. (Parce que c'est difficile, je ne vais pas le regarder en détail)
Classifions class0 et class1 en fonction des fonctionnalités acquises par cet AutoEncoder LSTM. Pour l'instant, mettons de côté le fait que ce n'est pas iid, et essayons la régression logistique.
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
La précision des données de test est désormais de 1,0. Je suis inquiet parce que c'est trop cher, mais c'était un signal avec une forme d'onde très différente, alors est-ce quelque chose comme ça?
«J'ai construit un modèle pour la première fois avec Keras, mais je crains que ce que je fais réellement à l'intérieur soit trop complexe et corresponde à ce que je veux faire. En ne regardant que les résultats, c'est comme prévu, alors j'aimerais croire que c'est fait. (S'il vous plaît dites-moi) ――Comme pour l'article original, comment les membres de la communauté d'apprentissage automatique comprennent-ils et mettent-ils en œuvre le modèle qui y est proposé parce qu'il n'est pas écrit dans des formules mathématiques? L'idée de graphe informatique est-elle répandue et véhiculée par des diagrammes? Ou est-ce un problème si le modèle ne peut pas être imaginé simplement en lisant l'article et qu'il n'y a pas de reproductibilité? Je ne comprends pas vraiment. ――Parce que Keras est un rappeur de tendorflow, c'est naturel, mais les humains comme moi qui n'ont jamais touché tensolflow rencontrent des difficultés, il vaut peut-être mieux toucher tensorflow pour le moment.
Recommended Posts