Keras LSTM dengan seri waktu 1D

10

Saya sedang belajar cara menggunakan Keras dan saya sudah cukup berhasil dengan dataset berlabel menggunakan contoh-contoh pada Chollet's Deep Learning for Python . Kumpulan data adalah ~ 1000 Time Series dengan panjang 3125 dengan 3 kelas potensial.

Saya ingin melampaui lapisan Dense dasar yang memberi saya tingkat prediksi sekitar 70% dan buku ini membahas tentang lapisan LSTM dan RNN.

Semua contoh tampaknya menggunakan kumpulan data dengan beberapa fitur untuk setiap rentang waktu dan saya berjuang untuk mengetahui bagaimana mengimplementasikan data saya sebagai hasilnya.

Jika misalnya, saya memiliki Time Series 1000x3125, bagaimana cara memasukkannya ke dalam sesuatu seperti lapisan SimpleRNN atau LSTM? Apakah saya kehilangan beberapa pengetahuan mendasar tentang apa yang dilakukan lapisan ini?

Kode saat ini:

import pandas as pd
import numpy as np
import os
from keras.models import Sequential
from keras.layers import Dense
from keras.layers import LSTM, Dropout, SimpleRNN, Embedding, Reshape
from keras.utils import to_categorical
from keras import regularizers
from sklearn.model_selection import train_test_split
import matplotlib.pyplot as plt

def readData():
    # Get labels from the labels.txt file
    labels = pd.read_csv('labels.txt', header = None)
    labels = labels.values
    labels = labels-1
    print('One Hot Encoding Data...')
    labels = to_categorical(labels)

    data = pd.read_csv('ts.txt', header = None)

    return data, labels

print('Reading data...')
data, labels = readData()

print('Splitting Data')
data_train, data_test, labels_train, labels_test = train_test_split(data, labels)

print('Building Model...')
#Create model
model = Sequential()
## LSTM / RNN goes here ##
model.add(Dense(3, activation='softmax'))

model.compile(loss='categorical_crossentropy', optimizer='adam', metrics=['accuracy'])

print('Training NN...')
history = model.fit(data_train, labels_train, epochs=1000, batch_size=50,
    validation_split=0.25,verbose=2)

results = model.evaluate(data_test, labels_test)

predictions = model.predict(data_test)

print(predictions[0].shape)
print(np.sum(predictions[0]))
print(np.argmax(predictions[0]))

print(results)

acc = history.history['acc']
val_acc = history.history['val_acc']
epochs = range(1, len(acc) + 1)

plt.plot(epochs, acc, 'bo', label='Training acc')
plt.plot(epochs, val_acc, 'b', label='Validation acc')
plt.title('Training and Validation Accuracy')
plt.xlabel('Epochs')
plt.ylabel('Loss')
plt.legend()
plt.show()
pengguna1147964
sumber

Jawaban:

10

Lapisan LSTM membutuhkan data dengan bentuk yang berbeda.

Dari uraian Anda, saya memahami dataset awal memiliki 3125 baris dan 1000 kolom, di mana setiap baris adalah satu langkah waktu. Variabel target kemudian harus memiliki 3125 baris dan 1 kolom, di mana setiap nilai dapat menjadi salah satu dari tiga nilai yang mungkin. Jadi sepertinya Anda melakukan masalah klasifikasi. Untuk memeriksa ini dalam kode, saya akan melakukan:

>>> X.shape
(3125, 1000)

>>> y.shape
(1000,)

Kelas LSTM mengharuskan setiap sampel tunggal terdiri dari 'blok' waktu. Katakanlah Anda ingin memiliki 100 langkah waktu. Ini berarti X[0:100]adalah sampel input tunggal, yang sesuai dengan variabel target di y[100]. ini berarti ukuran jendela Anda (alias jumlah step-time atau jumlah lag) sama dengan 100. Seperti yang dinyatakan di atas, Anda memiliki 3125 sampel, jadi N = 3125. Untuk membentuk blok pertama, kami sayangnya harus membuang 100 sampel pertama y, karena kami tidak dapat membentuk seluruh blok 100 dari data yang tersedia (kami akhirnya membutuhkan titik data sebelumnya X[0]).

Dengan semua ini, sebuah LSTM mengharuskan Anda untuk mengirimkan kumpulan bentuk (N - window_size, window_size, num_features), yang diterjemahkan menjadi (3125 - 100, 100, 1000)== (3025, 100, 1000).

Membuat blok waktu ini sedikit merepotkan, tapi buat fungsi yang bagus sekali, lalu simpan :)

Ada lebih banyak pekerjaan yang harus dilakukan, mungkin melihat contoh yang lebih mendalam dari penjelasan saya di atas di sini ... atau membaca dokumentasi LSTM , (atau lebih baik lagi, kode sumber! ).

Model terakhir akan cukup sederhana (berdasarkan kode Anda):

#Create model
model = Sequential()
model.add(LSTM(units=32, activation='relu',
               input_shape=(100, 1000))    # the batch size is neglected!
model.add(Dense(3, activation='softmax'))

model.compile(loss='categorical_crossentropy', optimizer='adam',
              metrics=['accuracy'])

Lihat dokumentasi tentang bentuk input untuk Sequentialmodel . Pada dasarnya dikatakan bahwa kita tidak perlu menentukan jumlah batch dalam input_shape. Ini dapat dilakukan dengan mis. batch_size=50, Jika Anda mengharuskannya menjadi nomor tetap.

Saya tahu input_shapeargumennya tidak ada dalam dokumentasi untuk LSTM, tetapi kelas itu sendiri berasal dari RNN, yang pada gilirannya mewarisi dari Layer- sehingga akan dapat menggunakan informasi yang Anda berikan.

Satu tip terakhir: jika Anda berencana menambahkan beberapa layer LSTM ('menumpuk' mereka), maka Anda perlu menambahkan satu argumen lagi untuk semua kecuali yang terakhir LSTM , yaitu, the return_sequences=True.

n1k31t4
sumber
Terima kasih atas balasan komprehensif Dexter (!). Mengenai komentar Anda tentang ukuran batch, apakah batch_size ditentukan dalam argumen model.fit parameter hiper yang berbeda dibandingkan dengan membuat batch kustom saya sendiri? Saya berhasil mendapatkan kode saya untuk setidaknya berjalan dengan membentuk kembali data saya dari matriks 1000x3125 menjadi matriks 3D menggunakan data = np.reshape (data, (1000,1,3125)). Ini biarkan saya menjalankan LSTM dengan input_shape (1.3125) tapi sekali lagi, saya tidak begitu yakin apa yang saya lakukan. Sekali lagi, terima kasih banyak atas jawabannya. Saya akan melihat tautan yang Anda berikan dan mempelajari jawaban Anda lagi.
user1147964
Sama-sama! Ya, Anda mengerti, jika Anda keluar batch_sizesaat mendefinisikan model, itu akan diambil dari argumen yang sama di dalam model.fit(). Anda harus membentuk kembali untuk mendapatkan (3025, 100, 1000), yang berarti 3025 batch, masing-masing dari 100 (baris) tanda waktu dan 1000 (kolom) variabel. Menggunakan np.reshapeakan sayangnya tidak bekerja untuk ini (Anda akan mendapatkan error), karena fakta bahwa Anda akan memiliki tumpang tindih data ... bentuk akhir memiliki lebih banyak data dari input. 3025x100x1000> 3125x1000 - np.reshapetidak suka karena ambigu. Saya sarankan hanya mengulang dataset, 1 loop = 1 sampel.
n1k31t4
Saya pikir saya agak bingung di sini dan bisa jadi karena saya mungkin secara tidak sengaja telah melakukan proses batching. Saya akan menggunakan nilai-nilai spesifik di sini. Saya mencicipi 3 pengukuran berbeda pada 6,25 kHz selama kurang lebih 3 menit, menghasilkan 3 seri waktu 1093750. Ini menghasilkan matriks 3x1093750. Saya kemudian membagi setiap TS menjadi selisih 0,5 detik, menghasilkan matriks 1050x3125. Saya secara teknis bisa menyusun kembali ini menjadi matriks 3D dengan dimensi 3x350x3125. Ini memberi saya 350, "batch" panjang. Pembentukan ulang Anda tampaknya menghasilkan lebih banyak nilai. Terima kasih atas tanggapannya lagi. Maaf
user1147964
Sekadar menambahkan, membaca tautan pertama yang Anda poskan membuat saya berpikir saya mengubah bentuk sesuatu dengan benar. Maaf jika saya kehilangan sesuatu yang jelas tetapi di sini mereka mulai dengan panjang TS 5000, dan mengubahnya menjadi matriks 3D dengan dimensi [1 25 200].
user1147964
Dibandingkan dengan metode di tautan Anda, cara saya akan membuat lebih banyak sampel. Ini karena saya menggunakan semacam jendela 'bergulir'. Lihatlah penggambaran ini . Mereka tidak menggunakan jendela bergulir . Membuat 3 menit menjadi potongan berukuran 350x0.5 tidak masalah (mungkin tidak diperlukan - seberapa sering Anda memprediksi?), Setiap potongan harus berukuran 3x3125. "Saya bisa merestrukturisasi ini menjadi matriks 3D dengan dimensi 3x350x3125" - ini terdengar lebih baik, tetapi setelah membuat pemisahan saya harapkan 350x3x3125 (350 bongkahan 3x3125). Masing-masing potongan ini kemudian dapat diproses seperti yang saya jelaskan.
n1k31t4