وبلاگ رسانگار
با ما حرفه ای باشید

سرور مجازی NVMe

حل مسائل توالی با LSTM در Keras

0 23
زمان لازم برای مطالعه: 17 دقیقه


در این مقاله، روش انجام پیش بینی سری های زمانی را که برای حل مسائل توالی استفاده می شود، یاد خواهید گرفت.

پیش‌بینی سری‌های زمانی به نوع مشکلاتی اشاره می‌کند که در آنها باید یک نتیجه را پیش‌بینی کنیم روی ورودی های وابسته به زمان یک مثال معمولی از داده های سری زمانی، داده های بازار سهام است که در آن قیمت سهام با زمان تغییر می کند. به همین ترتیب، دمای ساعتی یک مکان خاص نیز تغییر می کند و همچنین می تواند به عنوان داده سری زمانی در نظر گرفته شود. داده‌های سری زمانی اساساً دنباله‌ای از داده‌ها هستند، از این رو مسائل سری زمانی اغلب به عنوان مسائل توالی نامیده می‌شوند.

شبکه های عصبی مکرر (RNN) ثابت شده است که به طور موثر مسائل توالی را حل می کند. به ویژه، شبکه حافظه کوتاه مدت بلند مدت (LSTM)، که یک گونه از RNN است، در حال حاضر در حوزه های مختلفی برای حل مسائل توالی استفاده می شود.

انواع مسائل دنباله ای

مشکلات توالی را می توان به طور کلی به دسته های زیر دسته بندی کرد:

  1. یک به یک: جایی که یک ورودی و یک خروجی وجود دارد. مثال معمولی از مشکل توالی یک به یک حالتی است که شما یک تصویر دارید و می خواهید یک برچسب واحد برای تصویر پیش بینی کنید.
  2. چند به یک: در مسائل توالی چند به یک، دنباله ای از داده ها را به عنوان ورودی داریم و باید یک خروجی را پیش بینی کنیم. طبقه بندی متن یک مثال اصلی از مسائل توالی چند به یک است که در آن یک دنباله ورودی از کلمات داریم و می خواهیم یک برچسب خروجی را پیش بینی کنیم.
  3. یک به چند: در مسائل توالی یک به چند، یک ورودی واحد و یک توالی خروجی داریم. یک مثال معمولی یک تصویر و توضیحات مربوط به آن است.
  4. چند به چند: مشکلات توالی چند به چند شامل یک ورودی دنباله و یک خروجی توالی است. به عنوان مثال، قیمت سهام 7 روز به عنوان ورودی و قیمت سهام در 7 روز آینده به عنوان خروجی. چت بات ها نیز نمونه ای از مشکلات توالی چند به چند هستند که در آن یک دنباله متن ورودی و دنباله متنی دیگر خروجی است.

این مقاله قسمت 1 از مجموعه است. در این مقاله خواهیم دید که چگونه می توان از LSTM و انواع مختلف آن برای حل مسائل توالی یک به یک و چند به یک استفاده کرد. در قسمت بعدی این مجموعه روش حل مسائل توالی یک به چند و چند به چند را خواهیم دید. ما با کتابخانه Keras پایتون کار خواهیم کرد.

پس از مطالعه این مقاله، می توانید مشکلاتی مانند پیش بینی قیمت سهام، پیش بینی آب و هوا و غیره را بر اساس حل کنید. روی داده های تاریخی از آنجایی که متن نیز دنباله ای از کلمات است، دانش به دست آمده در این مقاله می تواند برای حل وظایف پردازش زبان طبیعی مانند طبقه بندی متن، تولید زبان و غیره نیز مورد استفاده قرار گیرد.

مشکلات توالی یک به یک

همانطور که قبلاً گفتم، در مسائل توالی یک به یک، یک ورودی و یک خروجی وجود دارد. در این بخش دو نوع مشکل توالی را مشاهده خواهیم کرد. ابتدا روش حل مسائل توالی یک به یک را با یک ویژگی واحد و سپس خواهیم دید که چگونه مسائل توالی یک به یک را با چندین ویژگی حل کنیم.

مشکلات توالی یک به یک با یک ویژگی واحد

در این بخش، روش حل یک مسئله توالی یک به یک را خواهیم دید که هر مرحله زمانی دارای یک ویژگی واحد است.

اول بیایید import کتابخانه های مورد نیازی که در این مقاله از آنها استفاده می کنیم:

from numpy import array
from keras.preprocessing.text import one_hot
from keras.preprocessing.sequence import pad_sequences
from keras.models import Sequential
from keras.layers.core import Activation, Dropout, Dense
from keras.layers import Flatten, LSTM
from keras.layers import GlobalMaxPooling1D
from keras.models import Model
from keras.layers.embeddings import Embedding
from sklearn.model_selection import train_test_split
from keras.preprocessing.text import Tokenizer
from keras.layers import Input
from keras.layers.merge import Concatenate
from keras.layers import Bidirectional

import pandas as pd
import numpy as np
import re

import matplotlib.pyplot as plt

ایجاد مجموعه داده

در این مرحله بعدی مجموعه داده ای را که قرار است برای این بخش استفاده کنیم آماده می کنیم.

X = list()
Y = list()
X = (x+1 for x in range(20))
Y = (y * 15 for y in X)

print(X)
print(Y)

در اسکریپت بالا 20 ورودی و 20 خروجی ایجاد می کنیم. هر ورودی شامل یک مرحله زمانی است که به نوبه خود شامل یک ویژگی واحد است. هر مقدار خروجی است 15 برابر مقدار ورودی مربوطه. اگر اسکریپت بالا را اجرا کنید، باید مقادیر ورودی و خروجی را مطابق شکل زیر مشاهده کنید:

(1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20)
(15, 30, 45, 60, 75, 90, 105, 120, 135, 150, 165, 180, 195, 210, 225, 240, 255, 270, 285, 300)

ورودی لایه LSTM باید به شکل سه بعدی باشد (نمونه ها، مراحل زمانی، ویژگی ها). نمونه ها تعداد نمونه ها در داده های ورودی است. ما 20 نمونه در ورودی داریم. گام های زمانی تعداد گام های زمانی در هر نمونه است. ما 1 مرحله زمانی داریم. در نهایت، ویژگی ها با تعداد ویژگی ها در هر مرحله زمانی مطابقت دارند. ما یک ویژگی در هر مرحله زمانی داریم.

می توانیم داده های خود را از طریق دستور زیر تغییر شکل دهیم:

X = array(X).reshape(20, 1, 1)

راه حل از طریق LSTM ساده

اکنون می توانیم مدل ساده LSTM خود را با یک لایه LSTM ایجاد کنیم.

model = Sequential()
model.add(LSTM(50, activation='relu', input_shape=(1, 1)))
model.add(Dense(1))
model.compile(optimizer='adam', loss='mse')
print(model.summary())

در اسکریپت بالا، یک مدل LSTM با یک لایه LSTM از 50 نورون و relu توابع فعال سازی می توانید ببینید که شکل ورودی (1،1) است زیرا داده های ما دارای یک مرحله زمانی با یک ویژگی هستند. اجرای اسکریپت بالا خلاصه زیر را چاپ می کند:

Layer (type)                 Output Shape              Param #
=================================================================
lstm_16 (LSTM)               (None, 50)                10400
_________________________________________________________________
dense_15 (Dense)             (None, 1)                 51
=================================================================
Total params: 10,451
Trainable params: 10,451
Non-trainable params: 0

حال بیایید مدل خود را آموزش دهیم:

model.fit(X, Y, epochs=2000, validation_split=0.2, batch_size=5)

ما مدل خود را برای 2000 دوره با اندازه دسته 5 آموزش می دهیم. شما می توانید هر عددی را انتخاب کنید. زمانی که مدل آموزش داده شد، می‌توانیم پیش‌بینی کنیم روی یک نمونه جدید

فرض کنید می خواهیم خروجی را برای ورودی 30 پیش بینی کنیم. خروجی واقعی باید 30 x 15 = 450 باشد. بیایید ببینیم چه مقداری به دست می آوریم. ابتدا باید داده های آزمایشی خود را به شکل مناسب یعنی شکل سه بعدی، همانطور که توسط LSTM انتظار می رود، تبدیل کنیم. اسکریپت زیر خروجی عدد 30 را پیش بینی می کند:

test_input = array((30))
test_input = test_input.reshape((1, 1, 1))
test_output = model.predict(test_input, verbose=0)
print(test_output)

من یک مقدار خروجی گرفتم 437.86 که کمی کمتر از 450 است.

توجه داشته باشید: ذکر این نکته ضروری است که خروجی هایی که با اجرای اسکریپت ها به دست می آورید با من متفاوت خواهد بود. این به این دلیل است که شبکه عصبی LSTM وزن ها را با مقادیر تصادفی و مقادیر شما مقداردهی اولیه می کند. اما به طور کلی، نتایج نباید تفاوت زیادی داشته باشد.

راه حل از طریق Stacked LSTM

بیایید اکنون یک LSTM پشته‌ای ایجاد کنیم و ببینیم آیا می‌توانیم نتایج بهتری بگیریم. مجموعه داده ثابت خواهد ماند، مدل تغییر خواهد کرد. به اسکریپت زیر نگاه کنید:

model = Sequential()
model.add(LSTM(50, activation='relu', return_sequences=True, input_shape=(1, 1)))
model.add(LSTM(50, activation='relu'))
model.add(Dense(1))
model.compile(optimizer='adam', loss='mse')
print(model.summary())

در مدل فوق دو لایه LSTM داریم. توجه کنید، اولین لایه LSTM دارای پارامتر است return_sequences، که تنظیم شده است True. هنگامی که دنباله بازگشت به True، خروجی حالت پنهان هر نورون به عنوان ورودی لایه LSTM بعدی استفاده می شود. خلاصه مدل فوق به شرح زیر است:

_________________________________________________________________
Layer (type)                 Output Shape              Param #
=================================================================
lstm_33 (LSTM)               (None, 1, 50)             10400
_________________________________________________________________
lstm_34 (LSTM)               (None, 50)                20200
_________________________________________________________________
dense_24 (Dense)             (None, 1)                 51
=================================================================
Total params: 30,651
Trainable params: 30,651
Non-trainable params: 0
________________________

در مرحله بعد، باید مدل خود را همانطور که در اسکریپت زیر نشان داده شده است آموزش دهیم:

history = model.fit(X, Y, epochs=2000, validation_split=0.2, verbose=1, batch_size=5)

پس از آموزش مدل، دوباره پیش بینی خواهیم کرد روی نقطه داده تست یعنی 30.

test_input = array((30))
test_input = test_input.reshape((1, 1, 1))
test_output = model.predict(test_input, verbose=0)
print(test_output)

من خروجی 459.85 گرفتم که بهتر از 437 است، عددی که از طریق یک لایه LSTM به دست آوردیم.

مشکلات توالی یک به یک با چندین ویژگی

در بخش آخر، هر نمونه ورودی دارای یک گام زمانی بود که هر مرحله زمانی دارای یک ویژگی بود. در این بخش خواهیم دید که چگونه می‌توان مسائل توالی یک به یک را که در آن گام‌های زمانی ورودی دارای چندین ویژگی هستند، حل کرد.

ایجاد مجموعه داده

بیایید ابتدا مجموعه داده خود را ایجاد کنیم. به اسکریپت زیر نگاه کنید:

nums = 25

X1 = list()
X2 = list()
X = list()
Y = list()

X1 = ((x+1)*2 for x in range(25))
X2 = ((x+1)*3 for x in range(25))
Y = (x1*x2 for x1,x2 in zip(X1,X2))

print(X1)
print(X2)
print(Y)

در اسکریپت بالا، ما سه لیست ایجاد می کنیم: X1، X2، و Y. هر لیست دارای 25 عنصر است، به این معنی که حجم کل نمونه 25 است. Y شامل خروجی می باشد. X1، X2، و Y لیست ها در زیر چاپ شده است:

(2, 4, 6, 8, 10, 12, 14, 16, 18, 20, 22, 24, 26, 28, 30, 32, 34, 36, 38, 40, 42, 44, 46, 48, 50)
(3, 6, 9, 12, 15, 18, 21, 24, 27, 30, 33, 36, 39, 42, 45, 48, 51, 54, 57, 60, 63, 66, 69, 72, 75)
(6, 24, 54, 96, 150, 216, 294, 384, 486, 600, 726, 864, 1014, 1176, 1350, 1536, 1734, 1944, 2166, 2400, 2646, 2904, 3174, 3456, 3750)

هر عنصر در لیست خروجی اساساً حاصل ضرب عناصر مربوطه در فهرست است X1 و X2 لیست ها به عنوان مثال، عنصر دوم در لیست خروجی 24 است که حاصلضرب عنصر دوم در لیست است. X1 یعنی 4 و عنصر دوم در لیست X2 یعنی 6.

ورودی از ترکیبی از X1 و X2 لیست ها، که در آن هر لیست به عنوان یک ستون نشان داده می شود. اسکریپت زیر ورودی نهایی را ایجاد می کند:

X = np.column_stack((X1, X2))
print(X)

در اینجا خروجی است:

(( 2  3)
 ( 4  6)
 ( 6  9)
 ( 8 12)
 (10 15)
 (12 18)
 (14 21)
 (16 24)
 (18 27)
 (20 30)
 (22 33)
 (24 36)
 (26 39)
 (28 42)
 (30 45)
 (32 48)
 (34 51)
 (36 54)
 (38 57)
 (40 60)
 (42 63)
 (44 66)
 (46 69)
 (48 72)
 (50 75))

اینجا X متغیر شامل مجموعه ویژگی های نهایی ما است. می توانید ببینید که شامل دو ستون یعنی دو ویژگی در هر ورودی است. همانطور که قبلاً صحبت کردیم، باید ورودی را به یک شکل 3 بعدی تبدیل کنیم. ورودی ما دارای 25 نمونه است که هر نمونه از 1 مرحله زمانی و هر مرحله زمانی شامل 2 ویژگی است. اسکریپت زیر ورودی را تغییر شکل می دهد.

X = array(X).reshape(25, 1, 2)

راه حل از طریق LSTM ساده

ما اکنون آماده آموزش مدل های LSTM خود هستیم. بیایید ابتدا یک مدل لایه تک LSTM را همانطور که در بخش قبل انجام دادیم توسعه دهیم:

model = Sequential()
model.add(LSTM(80, activation='relu', input_shape=(1, 2)))
model.add(Dense(10, activation='relu'))
model.add(Dense(1))
model.compile(optimizer='adam', loss='mse')
print(model.summary())

در اینجا لایه LSTM ما شامل 80 نورون است. ما دو لایه متراکم داریم که لایه اول شامل 10 نورون و لایه متراکم دوم که به عنوان لایه خروجی نیز عمل می کند شامل 1 نورون است. خلاصه مدل به شرح زیر است:

Layer (type)                 Output Shape              Param #
=================================================================
lstm_38 (LSTM)               (None, 80)                26560
_________________________________________________________________
dense_29 (Dense)             (None, 10)                810
_________________________________________________________________
dense_30 (Dense)             (None, 1)                 11
=================================================================
Total params: 27,381
Trainable params: 27,381
Non-trainable params: 0
_________________________________________________________________
None

اسکریپت زیر مدل را آموزش می دهد:

model.fit(X, Y, epochs=2000, validation_split=0.2, batch_size=5)

بیایید مدل آموزش دیده خود را آزمایش کنیم روی یک نقطه داده جدید نقطه داده ما دو ویژگی خواهد داشت، یعنی (55،80) خروجی واقعی باید 55 x 80 = 4400 باشد. بیایید ببینیم الگوریتم ما چه چیزی را پیش بینی می کند. اسکریپت زیر را اجرا کنید:

test_input = array((55,80))
test_input = test_input.reshape((1, 1, 2))
test_output = model.predict(test_input, verbose=0)
print(test_output)

من در خروجی 3263.44 گرفتم که با خروجی واقعی فاصله زیادی دارد.

راه حل از طریق Stacked LSTM

بیایید اکنون یک LSTM پیچیده تر با چندین LSTM و لایه های متراکم ایجاد کنیم و ببینیم که آیا می توانیم پاسخ خود را بهبود دهیم:

model = Sequential()
model.add(LSTM(200, activation='relu', return_sequences=True, input_shape=(1, 2)))
model.add(LSTM(100, activation='relu', return_sequences=True))
model.add(LSTM(50, activation='relu', return_sequences=True))
model.add(LSTM(25, activation='relu'))
model.add(Dense(20, activation='relu'))
model.add(Dense(10, activation='relu'))
model.add(Dense(1))
model.compile(optimizer='adam', loss='mse')
print(model.summary())

خلاصه مدل به شرح زیر است:

_________________________________________________________________
Layer (type)                 Output Shape              Param #
=================================================================
lstm_53 (LSTM)               (None, 1, 200)            162400
_________________________________________________________________
lstm_54 (LSTM)               (None, 1, 100)            120400
_________________________________________________________________
lstm_55 (LSTM)               (None, 1, 50)             30200
_________________________________________________________________
lstm_56 (LSTM)               (None, 25)                7600
_________________________________________________________________
dense_43 (Dense)             (None, 20)                520
_________________________________________________________________
dense_44 (Dense)             (None, 10)                210
_________________________________________________________________
dense_45 (Dense)             (None, 1)                 11
=================================================================
Total params: 321,341
Trainable params: 321,341
Non-trainable params: 0

مرحله بعدی آموزش مدل و تست آن است روی نقطه داده آزمون یعنی (55،80).

برای بهبود دقت، اندازه دسته را کاهش می‌دهیم و از آنجایی که مدل ما اکنون پیچیده‌تر است، می‌توانیم تعداد دوره‌ها را نیز کاهش دهیم. اسکریپت زیر مدل LSTM را آموزش می دهد و پیش بینی می کند روی نقطه داده تست

history = model.fit(X, Y, epochs=1000, validation_split=0.1, verbose=1, batch_size=3)

test_output = model.predict(test_input, verbose=0)
print(test_output)

در خروجی، مقدار 3705.33 را دریافت کردم که هنوز کمتر از 4400 است، اما بسیار بهتر از مقدار قبلی 3263.44 با استفاده از یک لایه LSTM منفرد است. می‌توانید با ترکیب‌های مختلف لایه‌های LSTM، لایه‌های متراکم، اندازه دسته‌ای و تعداد دوره‌ها بازی کنید تا ببینید آیا نتایج بهتری می‌گیرید یا خیر.

مشکلات توالی چند به یک

در بخش های قبلی روش حل مسائل یک به یک توالی با LSTM را دیدیم. در یک مسئله توالی یک به یک، هر نمونه از یک مرحله زمانی واحد از یک یا چند ویژگی تشکیل شده است. داده هایی با یک مرحله زمانی واحد را نمی توان به معنای واقعی داده های توالی در نظر گرفت. ثابت شده است که شبکه های عصبی متصل متراکم با داده های تک مرحله ای عملکرد بهتری دارند.

داده های دنباله واقعی شامل چندین مرحله زمانی است، مانند قیمت های بازار سهام در 7 روز گذشته، یک جمله حاوی کلمات متعدد و غیره. روی.

در این بخش روش حل مسائل توالی چند به یک را خواهیم دید. در مسائل توالی چند به یک، هر نمونه ورودی بیش از یک مرحله زمانی دارد، با این حال خروجی از یک عنصر تشکیل شده است. هر مرحله زمانی در ورودی می تواند یک یا چند ویژگی داشته باشد. ما با مسائل توالی چند به یک که دارای یک ویژگی هستند شروع می کنیم، و سپس خواهیم دید که چگونه می توان مسائل چند به یک را حل کرد که در آن گام های زمانی ورودی دارای چندین ویژگی هستند.

مشکلات توالی چند به یک با یک ویژگی واحد

بیایید ابتدا مجموعه داده را ایجاد کنیم. مجموعه داده ما شامل 15 نمونه خواهد بود. هر نمونه دارای 3 مرحله زمانی خواهد بود که هر مرحله زمانی از یک ویژگی واحد یعنی یک عدد تشکیل شده است. خروجی هر نمونه، مجموع اعداد در هر یک از سه مرحله زمانی خواهد بود. به عنوان مثال، اگر نمونه ما شامل دنباله 4،5،6 باشد، خروجی 4 + 5 + 6 = 10 خواهد بود.

ایجاد مجموعه داده

بیایید ابتدا لیستی از اعداد صحیح از 1 تا 45 ایجاد کنیم. از آنجایی که ما 15 نمونه در مجموعه داده خود می خواهیم، ​​لیستی از اعداد صحیح حاوی 45 عدد صحیح اول را تغییر شکل می دهیم.

X = np.array((x+1 for x in range(45)))
print(X)

در خروجی باید 45 عدد صحیح اول را ببینید:

( 1  2  3  4  5  6  7  8  9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24
 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45)

با استفاده از تابع زیر می‌توانیم آن را به تعدادی نمونه، مراحل زمانی و ویژگی‌ها تغییر شکل دهیم:

X = X.reshape(15,3,1)
print(X)

اسکریپت بالا لیست را تبدیل می کند X به شکل 3 بعدی با 15 نمونه، 3 مرحله زمانی و 1 ویژگی. اسکریپت بالا همچنین داده های تغییر شکل داده شده را چاپ می کند.

((( 1)
  ( 2)
  ( 3))

 (( 4)
  ( 5)
  ( 6))

 (( 7)
  ( 8)
  ( 9))

 ((10)
  (11)
  (12))

 ((13)
  (14)
  (15))

 ((16)
  (17)
  (18))

 ((19)
  (20)
  (21))

 ((22)
  (23)
  (24))

 ((25)
  (26)
  (27))

 ((28)
  (29)
  (30))

 ((31)
  (32)
  (33))

 ((34)
  (35)
  (36))

 ((37)
  (38)
  (39))

 ((40)
  (41)
  (42))

 ((43)
  (44)
  (45)))

ما داده های ورودی خود را به فرمت مناسب تبدیل کرده ایم، اکنون بردار خروجی خود را ایجاد می کنیم. همانطور که قبلاً گفتم، هر عنصر در خروجی برابر با مجموع مقادیر در مراحل زمانی در نمونه ورودی مربوطه خواهد بود. اسکریپت زیر بردار خروجی را ایجاد می کند:

Y = list()
for x in X:
    Y.append(x.sum())

Y = np.array(Y)
print(Y)

آرایه خروجی Y به نظر می رسد این است:

(  6  15  24  33  42  51  60  69  78  87  96 105 114 123 132)

راه حل از طریق LSTM ساده

حال بیایید مدل خود را با یک لایه LSTM ایجاد کنیم.

model = Sequential()
model.add(LSTM(50, activation='relu', input_shape=(3, 1)))
model.add(Dense(1))
model.compile(optimizer='adam', loss='mse')

اسکریپت زیر مدل ما را آموزش می دهد:

history = model.fit(X, Y, epochs=1000, validation_split=0.2, verbose=1)

هنگامی که مدل آموزش داده شد، می توانیم از آن برای پیش بینی استفاده کنیم روی نقاط داده تست بیایید خروجی دنباله اعداد 50،51،52 را پیش بینی کنیم. خروجی واقعی باید 50 + 51 + 52 = 153 باشد. اسکریپت زیر نقاط تست ما را به یک شکل 3 بعدی تبدیل می کند و سپس خروجی را پیش بینی می کند:

test_input = array((50,51,52))
test_input = test_input.reshape((1, 3, 1))
test_output = model.predict(test_input, verbose=0)
print(test_output)

من 145.96 در خروجی گرفتم که حدود 7 امتیاز کمتر از مقدار واقعی خروجی 153 است.

راه حل از طریق Stacked LSTM

حالا بیایید یک مدل پیچیده LSTM با چندین لایه ایجاد کنیم و ببینیم آیا می‌توانیم نتایج بهتری بگیریم. اسکریپت زیر را برای ایجاد و آموزش یک مدل پیچیده با چندین LSTM و لایه های متراکم اجرا کنید:

model = Sequential()
model.add(LSTM(200, activation='relu', return_sequences=True, input_shape=(3, 1)))
model.add(LSTM(100, activation='relu', return_sequences=True))
model.add(LSTM(50, activation='relu', return_sequences=True))
model.add(LSTM(25, activation='relu'))
model.add(Dense(20, activation='relu'))
model.add(Dense(10, activation='relu'))
model.add(Dense(1))
model.compile(optimizer='adam', loss='mse')

history = model.fit(X, Y, epochs=1000, validation_split=0.2, verbose=1)

حالا بیایید مدل خود را آزمایش کنیم روی دنباله آزمون یعنی 50، 51، 52:

test_output = model.predict(test_input, verbose=0)
print(test_output)

پاسخی که من در اینجا گرفتم 155.37 است که بهتر از نتیجه 145.96 است که قبلاً دریافت کردیم. در این صورت از 153 فقط 2 امتیاز اختلاف داریم که پاسخ واقعی است.

راه حل از طریق دو جهته LSTM

LSTM دو طرفه نوعی LSTM است که از ترتیب ورودی از هر دو جهت جلو و عقب یاد می گیرد. تفسیر توالی نهایی، الحاق هر دو پاس یادگیری رو به جلو و عقب است. بیایید ببینیم که آیا می توانیم با LSTM های دو طرفه نتایج بهتری بگیریم یا خیر.

اسکریپت زیر یک مدل LSTM دو طرفه با یک لایه دو طرفه و یک لایه متراکم ایجاد می کند که به عنوان خروجی مدل عمل می کند.

from keras.layers import Bidirectional

model = Sequential()
model.add(Bidirectional(LSTM(50, activation='relu'), input_shape=(3, 1)))
model.add(Dense(1))
model.compile(optimizer='adam', loss='mse')

اسکریپت زیر مدل را آموزش می دهد و پیش بینی می کند روی دنباله آزمون که 50، 51 و 52 است.

history = model.fit(X, Y, epochs=1000, validation_split=0.2, verbose=1)
test_output = model.predict(test_input, verbose=0)
print(test_output)

نتیجه ای که من گرفتم 152.26 است که فقط کسری از نتیجه واقعی کمتر است. بنابراین، می‌توان نتیجه گرفت که برای مجموعه داده ما، LSTM دوطرفه با تک لایه عملکرد بهتری از LSTMهای تک لایه و LSTMهای یک طرفه انباشته دارد.

مشکلات توالی چند به یک با چندین ویژگی

در یک مسئله توالی چند به یک، ورودی داریم که در آن هر مرحله زمانی از چندین ویژگی تشکیل شده است. خروجی می تواند یک مقدار واحد یا چند مقدار باشد، یکی در هر ویژگی در مرحله زمانی ورودی. در این بخش به هر دو مورد خواهیم پرداخت.

ایجاد مجموعه داده

مجموعه داده ما شامل 15 نمونه خواهد بود. هر نمونه شامل 3 مرحله زمانی خواهد بود. هر time-step دو ویژگی خواهد داشت.

بیایید دو لیست ایجاد کنیم. یکی شامل مضرب های 3 تا 135 یعنی 45 عنصر در کل خواهد بود. لیست دوم شامل مضربی از 5، از 1 تا 225 خواهد بود. لیست دوم همچنین شامل 45 عنصر در کل خواهد بود. اسکریپت زیر این دو لیست را ایجاد می کند:

X1 = np.array((x+3 for x in range(0, 135, 3)))
print(X1)

X2 = np.array((x+5 for x in range(0, 225, 5)))
print(X2)

در خروجی زیر می توانید محتویات لیست را مشاهده کنید:

(  3   6   9  12  15  18  21  24  27  30  33  36  39  42  45  48  51  54
  57  60  63  66  69  72  75  78  81  84  87  90  93  96  99 102 105 108
 111 114 117 120 123 126 129 132 135)
(  5  10  15  20  25  30  35  40  45  50  55  60  65  70  75  80  85  90
  95 100 105 110 115 120 125 130 135 140 145 150 155 160 165 170 175 180
 185 190 195 200 205 210 215 220 225)

هر یک از لیست های بالا نشان دهنده یک ویژگی در نمونه زمانی است. مجموعه داده انبوه را می توان با پیوستن به دو لیست مانند شکل زیر ایجاد کرد:

X = np.column_stack((X1, X2))
print(X)

خروجی مجموعه داده های جمع آوری شده را نشان می دهد:

 (  6  10)
 (  9  15)
 ( 12  20)
 ( 15  25)
 ( 18  30)
 ( 21  35)
 ( 24  40)
 ( 27  45)
 ( 30  50)
 ( 33  55)
 ( 36  60)
 ( 39  65)
 ( 42  70)
 ( 45  75)
 ( 48  80)
 ( 51  85)
 ( 54  90)
 ( 57  95)
 ( 60 100)
 ( 63 105)
 ( 66 110)
 ( 69 115)
 ( 72 120)
 ( 75 125)
 ( 78 130)
 ( 81 135)
 ( 84 140)
 ( 87 145)
 ( 90 150)
 ( 93 155)
 ( 96 160)
 ( 99 165)
 (102 170)
 (105 175)
 (108 180)
 (111 185)
 (114 190)
 (117 195)
 (120 200)
 (123 205)
 (126 210)
 (129 215)
 (132 220)
 (135 225))

ما باید داده های خود را به سه بعدی تغییر شکل دهیم تا بتوان از آنها توسط LSTM استفاده کرد. ما در مجموع 45 ردیف و دو ستون در مجموعه داده خود داریم. ما مجموعه داده خود را به 15 نمونه، 3 مرحله زمانی و دو ویژگی تغییر شکل می دهیم.

X = array(X).reshape(15, 3, 2)
print(X)

شما می توانید 15 نمونه را در خروجی زیر مشاهده کنید:

(((  3   5)
  (  6  10)
  (  9  15))

 (( 12  20)
  ( 15  25)
  ( 18  30))

 (( 21  35)
  ( 24  40)
  ( 27  45))

 (( 30  50)
  ( 33  55)
  ( 36  60))

 (( 39  65)
  ( 42  70)
  ( 45  75))

 (( 48  80)
  ( 51  85)
  ( 54  90))

 (( 57  95)
  ( 60 100)
  ( 63 105))

 (( 66 110)
  ( 69 115)
  ( 72 120))

 (( 75 125)
  ( 78 130)
  ( 81 135))

 (( 84 140)
  ( 87 145)
  ( 90 150))

 (( 93 155)
  ( 96 160)
  ( 99 165))

 ((102 170)
  (105 175)
  (108 180))

 ((111 185)
  (114 190)
  (117 195))

 ((120 200)
  (123 205)
  (126 210))

 ((129 215)
  (132 220)
  (135 225)))

خروجی نیز دارای 15 مقدار مربوط به 15 نمونه ورودی خواهد بود. هر مقدار در خروجی، مجموع دو مقدار مشخصه در سومین مرحله زمانی هر نمونه ورودی خواهد بود. به عنوان مثال، سومین مرحله زمانی نمونه اول دارای ویژگی های 9 و 15 است، بنابراین خروجی 24 خواهد بود. به طور مشابه، دو مقدار ویژگی در مرحله زمانی سوم نمونه دوم 18 و 30 هستند. خروجی مربوطه 48 خواهد بود و به همین ترتیب روی.

اسکریپت زیر بردار خروجی را ایجاد و نمایش می دهد:

( 24  48  72  96 120 144 168 192 216 240 264 288 312 336 360)

بیایید اکنون این مشکل توالی چند به یک را از طریق LSTMهای ساده، انباشته و دو طرفه حل کنیم.

راه حل از طریق LSTM ساده

model = Sequential()
model.add(LSTM(50, activation='relu', input_shape=(3, 2)))
model.add(Dense(1))
model.compile(optimizer='adam', loss='mse')
history = model.fit(X, Y, epochs=1000, validation_split=0.2, verbose=1)

مدل آموزش دیده است. ما یک نقطه داده آزمایشی ایجاد می کنیم و سپس از مدل خود برای پیش بینی استفاده می کنیم روی نقطه آزمون

test_input = array(((8, 51),
                    (11,56),
                    (14,61)))

test_input = test_input.reshape((1, 3, 2))
test_output = model.predict(test_input, verbose=0)
print(test_output)

مجموع دو ویژگی سومین مرحله زمانی ورودی 14 + 61 = 75 است. مدل ما با یک لایه LSTM 73.41 را پیش بینی کرد که بسیار نزدیک است.

راه حل از طریق Stacked LSTM

اسکریپت زیر یک LSTM انباشته را آموزش می دهد و پیش بینی می کند روی نقطه ی امتحان:

model = Sequential()
model.add(LSTM(200, activation='relu', return_sequences=True, input_shape=(3, 2)))
model.add(LSTM(100, activation='relu', return_sequences=True))
model.add(LSTM(50, activation='relu', return_sequences=True))
model.add(LSTM(25, activation='relu'))
model.add(Dense(20, activation='relu'))
model.add(Dense(10, activation='relu'))
model.add(Dense(1))
model.compile(optimizer='adam', loss='mse')

history = model.fit(X, Y, epochs=1000, validation_split=0.2, verbose=1)

test_output = model.predict(test_input, verbose=0)
print(test_output)

خروجی من 71.56 است که از LSTM ساده بدتر است. به نظر می رسد LSTM انباشته ما بیش از حد مناسب است.

راه حل از طریق دو جهته LSTM

در اینجا اسکریپت آموزشی برای LSTM دو جهته ساده به همراه کدی که برای پیش بینی استفاده می شود، آمده است روی نقطه داده تست:

from keras.layers import Bidirectional

model = Sequential()
model.add(Bidirectional(LSTM(50, activation='relu'), input_shape=(3, 2)))
model.add(Dense(1))
model.compile(optimizer='adam', loss='mse')

history = model.fit(X, Y, epochs=1000, validation_split=0.2, verbose=1)
test_output = model.predict(test_input, verbose=0)
print(test_output)

خروجی 76.82 است که تقریباً نزدیک به 75 است. باز هم به نظر می رسد LSTM دو طرفه از بقیه الگوریتم ها بهتر عمل می کند.

تا کنون ما بر اساس مقادیر تک پیش‌بینی کرده‌ایم روی مقادیر چند ویژگی از مراحل زمانی مختلف. مورد دیگری از توالی های چند به یک وجود دارد که در آن می خواهید یک مقدار برای هر ویژگی در مرحله زمانی پیش بینی کنید. به عنوان مثال، مجموعه داده ای که ما در این بخش استفاده کردیم دارای سه مرحله زمانی است و هر مرحله زمانی دارای دو ویژگی است. ممکن است بخواهیم مقادیر فردی را برای هر سری ویژگی پیش بینی کنیم. مثال زیر روشن می کند، فرض کنید ورودی زیر را داریم:

(((  3   5)
  (  6  10)
  (  9  15))

در خروجی، ما یک مرحله زمانی با دو ویژگی مانند شکل زیر می خواهیم:

(12, 20)

می بینید که مقدار اول در خروجی ادامه سری اول و مقدار دوم ادامه سری دوم است. ما می‌توانیم چنین مشکلاتی را با تغییر تعداد نورون‌ها در لایه متراکم خروجی به تعداد مقادیر ویژگی‌هایی که در خروجی می‌خواهیم حل کنیم. با این حال، ابتدا باید بردار خروجی خود را به روز کنیم Y. بردار ورودی ثابت می ماند:

Y = list()
for x in X:
    new_item = list()
    new_item.append(x(2)(0)+3)
    new_item.append(x(2)(1)+5)
    Y.append(new_item)

Y = np.array(Y)
print(Y)

اسکریپت بالا یک بردار خروجی به روز شده ایجاد می کند و آن را چاپ می کند روی را console، خروجی به صورت زیر است:

(( 12  20)
 ( 21  35)
 ( 30  50)
 ( 39  65)
 ( 48  80)
 ( 57  95)
 ( 66 110)
 ( 75 125)
 ( 84 140)
 ( 93 155)
 (102 170)
 (111 185)
 (120 200)
 (129 215)
 (138 230))

بیایید اکنون شبکه های LSTM ساده، پشته ای و دو طرفه خود را آموزش دهیم روی مجموعه داده ما اسکریپت زیر یک LSTM ساده را آموزش می دهد:

model = Sequential()
model.add(LSTM(50, activation='relu', input_shape=(3, 2)))
model.add(Dense(2))
model.compile(optimizer='adam', loss='mse')

history = model.fit(X, Y, epochs=1000, validation_split=0.2, verbose=1)

گام بعدی این است که مدل خود را آزمایش کنیم روی نقطه داده تست اسکریپت زیر یک نقطه داده آزمایشی ایجاد می کند:

test_input = array(((20,34),
                    (23,39),
                    (26,44)))

test_input = test_input.reshape((1, 3, 2))
test_output = model.predict(test_input, verbose=0)
print(test_output)

خروجی واقعی (29، 45) است. مدل ما (29.089157، 48.469097) را پیش بینی می کند که بسیار نزدیک است.

بیایید اکنون یک LSTM انباشته را آموزش دهیم و خروجی را برای نقطه داده آزمایشی پیش بینی کنیم:

model = Sequential()
model.add(LSTM(100, activation='relu', return_sequences=True, input_shape=(3, 2)))
model.add(LSTM(50, activation='relu', return_sequences=True))
model.add(LSTM(25, activation='relu'))
model.add(Dense(10, activation='relu'))
model.add(Dense(2))
model.compile(optimizer='adam', loss='mse')

history = model.fit(X, Y, epochs=500, validation_split=0.2, verbose=1)

test_output = model.predict(test_input, verbose=0)
print(test_output)

خروجی (29.170143، 48.688267) است که باز هم بسیار نزدیک به خروجی واقعی است.

در نهایت، ما می توانیم LSTM دو طرفه خود را آموزش دهیم و پیش بینی کنیم روی نقطه آزمون:

from keras.layers import Bidirectional

model = Sequential()
model.add(Bidirectional(LSTM(50, activation='relu'), input_shape=(3, 2)))
model.add(Dense(2))
model.compile(optimizer='adam', loss='mse')

history = model.fit(X, Y, epochs=1000, validation_split=0.2, verbose=1)
test_output = model.predict(test_input, verbose=0)
print(test_output)

خروجی (29.2071، 48.737988) است.

می توانید یک بار دیگر ببینید که LSTM دو طرفه دقیق ترین پیش بینی را انجام می دهد.

نتیجه

شبکه های عصبی ساده برای حل مسائل توالی مناسب نیستند زیرا در مسائل توالی علاوه بر ورودی فعلی، باید ورودی های قبلی را نیز پیگیری کنیم. شبکه های عصبی با نوعی حافظه برای حل مسائل توالی مناسب تر هستند. LSTM یکی از این شبکه هاست.

در این مقاله دیدیم که چگونه می توان از انواع مختلف الگوریتم LSTM برای حل مسائل توالی یک به یک و چند به یک استفاده کرد. این قسمت اول مقاله است. در قسمت دوم روش حل مسائل توالی یک به چند و چند به چند را خواهیم دید. همچنین مکانیسم رمزگذار-رمزگشایی را که بیشتر برای ایجاد ربات‌های گفتگو استفاده می‌شود، مطالعه خواهیم کرد. تا اون موقع کدنویسی مبارک 🙂

(برچسب‌ها به ترجمه)# python



منتشر شده در 1403-01-20 12:02:04

امتیاز شما به این مطلب
دیدگاه شما در خصوص مطلب چیست ؟

آدرس ایمیل شما منتشر نخواهد شد.

لطفا دیدگاه خود را با احترام به دیدگاه های دیگران و با توجه به محتوای مطلب درج کنید