از طریق منوی جستجو مطلب مورد نظر خود در وبلاگ را به سرعت پیدا کنید
پیشبینی سری زمانی با استفاده از LSTM با PyTorch در پایتون
سرفصلهای مطلب
داده های سری زمانی، همانطور که از نام آن پیداست، نوعی داده است که با زمان تغییر می کند. به عنوان مثال، دما در یک دوره زمانی 24 ساعته، قیمت محصولات مختلف در یک ماه، قیمت سهام یک شرکت خاص در یک سال. مدل های یادگیری عمیق پیشرفته مانند شبکه های حافظه کوتاه مدت بلند مدت (LSTM)، قادر به گرفتن الگوها در داده های سری زمانی هستند و بنابراین می توان از آنها برای پیش بینی روند آینده داده ها استفاده کرد. در این مقاله روش استفاده از الگوریتم LSTM برای پیش بینی های آینده با استفاده از داده های سری زمانی را خواهید دید.
در یکی از مقالات قبلی خود، روش انجام تجزیه و تحلیل سری های زمانی را با استفاده از LSTM در کتابخانه Keras به منظور پیش بینی قیمت سهام در آینده توضیح دادم. در این مقاله، ما از آن استفاده خواهیم کرد PyTorch کتابخانه که یکی از پرکاربردترین کتابخانه های پایتون برای یادگیری عمیق است.
قبل از ادامه، فرض بر این است که سطح متوسطی از زبان برنامه نویسی پایتون دارید و کتابخانه PyTorch را نصب کرده اید. همچنین، دانش مفاهیم اولیه یادگیری ماشین و مفاهیم یادگیری عمیق کمک خواهد کرد. اگر PyTorch را نصب نکرده اید، می توانید با موارد زیر این کار را انجام دهید pip دستور:
$ pip install pytorch
مجموعه داده و تعریف مشکل
مجموعه داده ای که ما استفاده خواهیم کرد همراه با کتابخانه Seaborn Python ساخته شده است. اجازه دهید import ابتدا کتابخانه های مورد نیاز و سپس خواهد شد import مجموعه داده:
import torch
import torch.nn as nn
import seaborn as sns
import numpy as np
import pandas as pd
import matplotlib.pyplot as plt
%matplotlib inline
اجازه دهید print لیست تمام مجموعه داده هایی که با کتابخانه Seaborn ساخته شده اند:
sns.get_dataset_names()
خروجی:
('anscombe',
'attention',
'brain_networks',
'car_crashes',
'diamonds',
'dots',
'exercise',
'flights',
'fmri',
'gammas',
'iris',
'mpg',
'planets',
'tips',
'titanic')
مجموعه داده ای که ما استفاده خواهیم کرد عبارت است از flights
مجموعه داده بیایید مجموعه داده را در برنامه خود بارگذاری کنیم و ببینیم چگونه به نظر می رسد:
flight_data = sns.load_dataset("flights")
flight_data.head()
خروجی:
مجموعه داده دارای سه ستون است: year
، month
، و passengers
. را passengers
ستون شامل تعداد کل مسافران مسافر در یک ماه مشخص است. بیایید شکل مجموعه داده خود را رسم کنیم:
flight_data.shape
خروجی:
(144, 3)
می توانید ببینید که 144 ردیف و 3 ستون در مجموعه داده وجود دارد، به این معنی که مجموعه داده شامل رکورد 12 سال سفر مسافران است.
وظیفه پیش بینی تعداد مسافرانی است که در 12 ماه گذشته سفر کرده اند روی 132 ماه اول به یاد داشته باشید که ما سابقه 144 ماهه داریم، به این معنی که داده های 132 ماه اول برای آموزش مدل LSTM ما استفاده می شود، در حالی که عملکرد مدل با استفاده از مقادیر 12 ماه گذشته ارزیابی می شود.
بیایید تعداد مسافرانی که در ماه سفر می کنند را ترسیم کنیم. اسکریپت زیر اندازه طرح پیش فرض را افزایش می دهد:
fig_size = plt.rcParams("figure.figsize")
fig_size(0) = 15
fig_size(1) = 5
plt.rcParams("figure.figsize") = fig_size
و این اسکریپت بعدی فرکانس ماهانه تعداد مسافران را ترسیم می کند:
plt.title('Month vs Passenger')
plt.ylabel('Total Passengers')
plt.xlabel('Months')
plt.grid(True)
plt.autoscale(axis='x',tight=True)
plt.plot(flight_data('passengers'))
خروجی:
خروجی نشان می دهد که در طول سال ها میانگین تعداد مسافرانی که از طریق هوایی سفر می کنند افزایش یافته است. تعداد مسافرانی که در طول یک سال سفر می کنند در نوسان است که منطقی است زیرا در تعطیلات تابستانی یا زمستانی تعداد مسافران مسافر نسبت به سایر قسمت های سال افزایش می یابد.
پیش پردازش داده ها
انواع ستون ها در مجموعه داده ما است object
، همانطور که توسط کد زیر نشان داده شده است:
flight_data.columns
خروجی:
Index(('year', 'month', 'passengers'), dtype='object')
اولین مرحله پیش پردازش، تغییر نوع است passengers
ستون به float
.
all_data = flight_data('passengers').values.astype(float)
حالا اگر شما print را all_data
آرایه NumPy، باید مقادیر نوع شناور زیر را ببینید:
print(all_data)
خروجی:
(112. 118. 132. 129. 121. 135. 148. 148. 136. 119. 104. 118. 115. 126.
141. 135. 125. 149. 170. 170. 158. 133. 114. 140. 145. 150. 178. 163.
172. 178. 199. 199. 184. 162. 146. 166. 171. 180. 193. 181. 183. 218.
230. 242. 209. 191. 172. 194. 196. 196. 236. 235. 229. 243. 264. 272.
237. 211. 180. 201. 204. 188. 235. 227. 234. 264. 302. 293. 259. 229.
203. 229. 242. 233. 267. 269. 270. 315. 364. 347. 312. 274. 237. 278.
284. 277. 317. 313. 318. 374. 413. 405. 355. 306. 271. 306. 315. 301.
356. 348. 355. 422. 465. 467. 404. 347. 305. 336. 340. 318. 362. 348.
363. 435. 491. 505. 404. 359. 310. 337. 360. 342. 406. 396. 420. 472.
548. 559. 463. 407. 362. 405. 417. 391. 419. 461. 472. 535. 622. 606.
508. 461. 390. 432.)
در مرحله بعد، مجموعه داده های خود را به مجموعه های آموزشی و آزمایشی تقسیم می کنیم. الگوریتم LSTM آموزش داده خواهد شد روی مجموعه آموزشی سپس از مدل برای پیش بینی استفاده می شود روی مجموعه تست پیش بینی ها با مقادیر واقعی در مجموعه تست برای ارزیابی عملکرد مدل آموزش دیده مقایسه می شوند.
132 رکورد اول برای آموزش مدل و 12 رکورد آخر به عنوان مجموعه تست استفاده خواهد شد. اسکریپت زیر داده ها را به مجموعه های آموزشی و آزمایشی تقسیم می کند.
test_data_size = 12
train_data = all_data(:-test_data_size)
test_data = all_data(-test_data_size:)
حالا بیایید print طول مجموعه تست و قطار:
print(len(train_data))
print(len(test_data))
خروجی:
132
12
اگر شما در حال حاضر print داده های تست، خواهید دید که حاوی 12 رکورد آخر از all_data
آرایه NumPy:
print(test_data)
خروجی:
(417. 391. 419. 461. 472. 535. 622. 606. 508. 461. 390. 432.)
مجموعه داده ما در حال حاضر عادی نیست. تعداد کل مسافران در سال های اولیه در مقایسه با تعداد کل مسافران سال های بعد به مراتب کمتر است. عادی سازی داده ها برای پیش بینی های سری زمانی بسیار مهم است. ما مقیاس بندی حداقل/حداکثر را انجام خواهیم داد روی مجموعه داده ای که داده ها را در محدوده معینی از مقادیر حداقل و حداکثر نرمال می کند. ما استفاده خواهیم کرد MinMaxScaler
کلاس از sklearn.preprocessing
ماژول برای مقیاس بندی داده های ما. برای جزئیات بیشتر در مورد اجرای مقیاسکننده حداقل/حداکثر، مراجعه کنید این لینک.
کد زیر با استفاده از مقیاسکننده min/max با حداقل و حداکثر مقادیر -1 و 1، دادههای ما را عادی میکند.
from sklearn.preprocessing import MinMaxScaler
scaler = MinMaxScaler(feature_range=(-1, 1))
train_data_normalized = scaler.fit_transform(train_data .reshape(-1, 1))
حالا بیایید print اولین 5 و 5 رکورد آخر از داده های عادی قطار ما.
print(train_data_normalized(:5))
print(train_data_normalized(-5:))
خروجی:
((-0.96483516)
(-0.93846154)
(-0.87692308)
(-0.89010989)
(-0.92527473))
((1. )
(0.57802198)
(0.33186813)
(0.13406593)
(0.32307692))
می بینید که مقادیر داده ها اکنون بین -1 و 1 هستند.
در اینجا ذکر این نکته ضروری است که نرمال سازی داده ها فقط اعمال می شود روی داده های آموزشی و نه روی داده های تست اگر نرمال سازی اعمال شود روی داده های تست، این احتمال وجود دارد که برخی از اطلاعات از مجموعه آموزشی به مجموعه تست نشت کند.
گام بعدی تبدیل مجموعه داده ما به تانسور است زیرا مدلهای PyTorch با استفاده از تانسور آموزش داده میشوند. برای تبدیل مجموعه داده به تانسور، به سادگی می توانیم مجموعه داده خود را به سازنده آن ارسال کنیم FloatTensor
شیء، همانطور که در زیر نشان داده شده است:
train_data_normalized = torch.FloatTensor(train_data_normalized).view(-1)
آخرین مرحله پیش پردازش تبدیل داده های آموزشی به دنباله ها و برچسب های مربوطه است.
شما می توانید از هر طول دنباله ای استفاده کنید و این به دانش دامنه بستگی دارد. با این حال، در مجموعه داده ما استفاده از طول دنباله 12 راحت است زیرا داده های ماهانه داریم و 12 ماه در سال وجود دارد. اگر دادههای روزانه داشتیم، طول دنباله بهتر 365 بود، یعنی تعداد روزهای یک سال. بنابراین، طول توالی ورودی برای آموزش را روی 12 قرار می دهیم.
train_window = 12
در مرحله بعد تابعی به نام تعریف می کنیم create_inout_sequences
. تابع داده های ورودی خام را می پذیرد و لیستی از تاپل ها را برمی گرداند. در هر تاپل، المان اول شامل فهرستی از 12 آیتم مربوط به تعداد مسافرانی است که در 12 ماه سفر می کنند، المان تاپل دوم شامل یک آیتم یعنی تعداد مسافران در ماه 12+1 خواهد بود.
def create_inout_sequences(input_data, tw):
inout_seq = ()
L = len(input_data)
for i in range(L-tw):
train_seq = input_data(i:i+tw)
train_label = input_data(i+tw:i+tw+1)
inout_seq.append((train_seq ,train_label))
return inout_seq
اسکریپت زیر را برای ایجاد دنباله ها و برچسب های مربوط به آموزش اجرا کنید:
train_inout_seq = create_inout_sequences(train_data_normalized, train_window)
اگر شما print طول train_inout_seq
لیست، خواهید دید که شامل 120 مورد است. این به این دلیل است که اگرچه مجموعه آموزشی شامل 132 عنصر است، طول دنباله آن 12 است، به این معنی که سکانس اول از 12 مورد اول تشکیل شده است و آیتم سیزدهم برچسب سکانس اول است. به همین ترتیب، سکانس دوم از آیتم دوم شروع می شود و به آیتم سیزدهم ختم می شود، در حالی که آیتم چهاردهم برچسب سکانس دوم است و به همین ترتیب روی.
حالا بیایید print 5 مورد اول از train_inout_seq
لیست:
train_inout_seq(:5)
خروجی:
((tensor((-0.9648, -0.9385, -0.8769, -0.8901, -0.9253, -0.8637, -0.8066, -0.8066,
-0.8593, -0.9341, -1.0000, -0.9385)), tensor((-0.9516))),
(tensor((-0.9385, -0.8769, -0.8901, -0.9253, -0.8637, -0.8066, -0.8066, -0.8593,
-0.9341, -1.0000, -0.9385, -0.9516)),
tensor((-0.9033))),
(tensor((-0.8769, -0.8901, -0.9253, -0.8637, -0.8066, -0.8066, -0.8593, -0.9341,
-1.0000, -0.9385, -0.9516, -0.9033)), tensor((-0.8374))),
(tensor((-0.8901, -0.9253, -0.8637, -0.8066, -0.8066, -0.8593, -0.9341, -1.0000,
-0.9385, -0.9516, -0.9033, -0.8374)), tensor((-0.8637))),
(tensor((-0.9253, -0.8637, -0.8066, -0.8066, -0.8593, -0.9341, -1.0000, -0.9385,
-0.9516, -0.9033, -0.8374, -0.8637)), tensor((-0.9077))))
می بینید که هر آیتم یک تاپل است که عنصر اول از 12 مورد از یک دنباله تشکیل شده است و عنصر تاپل دوم حاوی برچسب مربوطه است.
ایجاد مدل LSTM
ما داده ها را از قبل پردازش کرده ایم، اکنون زمان آموزش مدل ما است. ما یک کلاس تعریف می کنیم LSTM
، که از ارث می برد nn.Module
کلاس کتابخانه PyTorch برای مشاهده روش ایجاد یک مدل طبقه بندی با PyTorch آخرین مقاله من را بررسی کنید. آن مقاله به شما کمک می کند تا بفهمید در کد زیر چه اتفاقی می افتد.
class LSTM(nn.Module):
def __init__(self, input_size=1, hidden_layer_size=100, output_size=1):
super().__init__()
self.hidden_layer_size = hidden_layer_size
self.lstm = nn.LSTM(input_size, hidden_layer_size)
self.linear = nn.Linear(hidden_layer_size, output_size)
self.hidden_cell = (torch.zeros(1,1,self.hidden_layer_size),
torch.zeros(1,1,self.hidden_layer_size))
def forward(self, input_seq):
lstm_out, self.hidden_cell = self.lstm(input_seq.view(len(input_seq) ,1, -1), self.hidden_cell)
predictions = self.linear(lstm_out.view(len(input_seq), -1))
return predictions(-1)
اجازه دهید آنچه را که در کد بالا اتفاق می افتد خلاصه کنم. سازنده از LSTM
کلاس سه پارامتر را می پذیرد:
input_size
: مربوط به تعداد ویژگی های ورودی است. اگرچه طول توالی ما 12 است، اما برای هر ماه فقط 1 مقدار داریم، یعنی تعداد کل مسافران، بنابراین اندازه ورودی 1 خواهد بود.hidden_layer_size
: تعداد لایه های پنهان به همراه تعداد نورون های هر لایه را مشخص می کند. ما یک لایه از 100 نورون خواهیم داشت.output_size
: تعداد آیتم های موجود در خروجی، از آنجایی که می خواهیم تعداد مسافران را برای 1 ماه آینده پیش بینی کنیم، اندازه خروجی 1 خواهد بود.
بعد، در سازنده متغیرها را ایجاد می کنیم hidden_layer_size
، lstm
، linear
، و hidden_cell
. الگوریتم LSTM سه ورودی را می پذیرد: حالت پنهان قبلی، وضعیت سلول قبلی و ورودی فعلی. را hidden_cell
متغیر شامل حالت مخفی و سلول قبلی است. را lstm
و linear
از متغیرهای لایه برای ایجاد لایه های LSTM و خطی استفاده می شود.
درون forward
روش، input_seq
به عنوان یک پارامتر ارسال می شود که ابتدا از طریق lstm
لایه. خروجی از lstm
لایه حالت های مخفی و سلولی در مرحله زمانی فعلی به همراه خروجی است. خروجی از lstm
لایه به linear
لایه. تعداد مسافران پیش بینی شده در آخرین مورد ذخیره می شود predictions
لیست، که به تابع فراخوانی بازگردانده می شود.
مرحله بعدی ایجاد یک شی از the است LSTM()
کلاس، یک تابع ضرر و بهینه ساز را تعریف کنید. از آنجایی که ما در حال حل یک مشکل طبقه بندی هستیم، از آن استفاده خواهیم کرد از دست دادن آنتروپی متقابل. برای تابع بهینه ساز، از Adam Optimizer.
model = LSTM()
loss_function = nn.MSELoss()
optimizer = torch.optim.Adam(model.parameters(), lr=0.001)
اجازه دهید print مدل ما:
print(model)
خروجی:
LSTM(
(lstm): LSTM(1, 100)
(linear): Linear(in_features=100, out_features=1, bias=True)
)
آموزش مدل
ما مدل خود را برای 150 دوره آموزش خواهیم داد. اگر بخواهید می توانید دوره های بیشتری را امتحان کنید. ضایعات پس از هر 25 دوره چاپ می شود.
epochs = 150
for i in range(epochs):
for seq, labels in train_inout_seq:
optimizer.zero_grad()
model.hidden_cell = (torch.zeros(1, 1, model.hidden_layer_size),
torch.zeros(1, 1, model.hidden_layer_size))
y_pred = model(seq)
single_loss = loss_function(y_pred, labels)
single_loss.backward()
optimizer.step()
if i%25 == 1:
print(f'epoch: {i:3} loss: {single_loss.item():10.8f}')
print(f'epoch: {i:3} loss: {single_loss.item():10.10f}')
خروجی:
epoch: 1 loss: 0.00517058
epoch: 26 loss: 0.00390285
epoch: 51 loss: 0.00473305
epoch: 76 loss: 0.00187001
epoch: 101 loss: 0.00000075
epoch: 126 loss: 0.00608046
epoch: 149 loss: 0.0004329932
شما ممکن است مقادیر متفاوتی دریافت کنید زیرا به طور پیش فرض وزن ها به طور تصادفی در یک شبکه عصبی PyTorch مقداردهی اولیه می شوند.
پیشگویی
اکنون که مدل ما آموزش دیده است، می توانیم شروع به پیش بینی کنیم. از آنجایی که مجموعه آزمایشی ما حاوی دادههای مسافر برای 12 ماه گذشته است و مدل ما برای پیشبینی با طول دنباله 12 آموزش دیده است. ابتدا 12 مقدار آخر مجموعه آموزشی را فیلتر میکنیم:
fut_pred = 12
test_inputs = train_data_normalized(-train_window:).tolist()
print(test_inputs)
خروجی:
(0.12527473270893097, 0.04615384712815285, 0.3274725377559662, 0.2835164964199066, 0.3890109956264496, 0.6175824403762817, 0.9516483545303345, 1.0, 0.5780220031738281, 0.33186814188957214, 0.13406594097614288, 0.32307693362236023)
می توانید مقادیر بالا را با 12 مقدار آخر مقایسه کنید train_data_normalized
لیست داده ها
در ابتدا test_inputs
مورد شامل 12 مورد خواهد بود. داخل a for
حلقه این 12 مورد برای پیشبینی اولین مورد از مجموعه آزمایشی یعنی آیتم شماره 133 استفاده میشود. سپس مقدار پیشبینیشده به آن اضافه میشود. test_inputs
فهرست در طول تکرار دوم، دوباره از 12 مورد آخر به عنوان ورودی استفاده می شود و یک پیش بینی جدید انجام می شود که سپس به test_inputs
دوباره لیست کنید را for
حلقه 12 بار اجرا می شود زیرا 12 عنصر در مجموعه تست وجود دارد. در انتهای حلقه test_inputs
لیست شامل 24 مورد خواهد بود. 12 مورد آخر مقادیر پیش بینی شده برای مجموعه تست خواهند بود.
اسکریپت زیر برای پیش بینی استفاده می شود:
model.eval()
for i in range(fut_pred):
seq = torch.FloatTensor(test_inputs(-train_window:))
with torch.no_grad():
model.hidden = (torch.zeros(1, 1, model.hidden_layer_size),
torch.zeros(1, 1, model.hidden_layer_size))
test_inputs.append(model(seq).item())
اگر شما print طول test_inputs
لیست، خواهید دید که شامل 24 مورد است. 12 مورد پیش بینی شده آخر را می توان به صورت زیر چاپ کرد:
test_inputs(fut_pred:)
خروجی:
(0.4574652910232544,
0.9810629487037659,
1.279405951499939,
1.0621851682662964,
1.5830546617507935,
1.8899496793746948,
1.323508620262146,
1.8764172792434692,
2.1249167919158936,
1.7745600938796997,
1.7952896356582642,
1.977765679359436)
لازم به ذکر است که ممکن است بسته به وزنه هایی که برای تمرین LSTM استفاده می شود مقادیر متفاوتی بدست آورید.
از آنجایی که مجموعه داده را برای آموزش عادی کردیم، مقادیر پیشبینیشده نیز نرمال میشوند. ما باید مقادیر پیش بینی شده نرمال شده را به مقادیر پیش بینی شده واقعی تبدیل کنیم. ما میتوانیم این کار را با ارسال مقادیر نرمال شده به the انجام دهیم inverse_transform
روش شی مقیاسکننده min/max که برای عادیسازی مجموعه دادههایمان استفاده کردیم.
actual_predictions = scaler.inverse_transform(np.array(test_inputs(train_window:) ).reshape(-1, 1))
print(actual_predictions)
خروجی:
((435.57335371)
(554.69182083)
(622.56485397)
(573.14712578)
(691.64493555)
(761.46355206)
(632.59821111)
(758.38493103)
(814.91857016)
(735.21242136)
(739.92839211)
(781.44169205))
حالا بیایید مقادیر پیش بینی شده را در مقابل مقادیر واقعی رسم کنیم. به کد زیر نگاه کنید:
x = np.arange(132, 144, 1)
print(x)
خروجی:
(132 133 134 135 136 137 138 139 140 141 142 143)
در اسکریپت بالا لیستی ایجاد می کنیم که حاوی مقادیر عددی برای 12 ماه گذشته است. ماه اول دارای مقدار شاخص 0 است، بنابراین ماه آخر در شاخص 143 خواهد بود.
در اسکریپت زیر، تعداد کل مسافران 144 ماه را به همراه تعداد مسافران پیش بینی شده 12 ماه گذشته ترسیم می کنیم.
plt.title('Month vs Passenger')
plt.ylabel('Total Passengers')
plt.grid(True)
plt.autoscale(axis='x', tight=True)
plt.plot(flight_data('passengers'))
plt.plot(x,actual_predictions)
plt.show()
خروجی:
پیش بینی های انجام شده توسط LSTM ما با خط نارنجی نشان داده می شود. می بینید که الگوریتم ما خیلی دقیق نیست، اما همچنان توانسته است روند صعودی را برای تعداد کل مسافرانی که در 12 ماه گذشته سفر کرده اند همراه با نوسانات گاه به گاه ثبت کند. می توانید با تعداد بیشتری از دوره ها و با تعداد سلول های عصبی بالاتر در لایه LSTM تلاش کنید تا ببینید آیا می توانید عملکرد بهتری داشته باشید یا خیر.
برای اینکه دید بهتری از خروجی داشته باشیم میتوانیم تعداد واقعی و پیشبینیشده مسافران 12 ماه گذشته را به صورت زیر ترسیم کنیم:
plt.title('Month vs Passenger')
plt.ylabel('Total Passengers')
plt.grid(True)
plt.autoscale(axis='x', tight=True)
plt.plot(flight_data('passengers')(-train_window:))
plt.plot(x,actual_predictions)
plt.show()
خروجی:
باز هم پیشبینیها خیلی دقیق نیستند، اما الگوریتم توانست این روند را به تصویر بکشد که تعداد مسافران در ماههای آینده باید بیشتر از ماههای قبل با نوسانهای گاه به گاه باشد.
نتیجه
LSTM یکی از پرکاربردترین الگوریتم ها برای حل مسائل توالی است. در این مقاله روش پیش بینی های آینده را با استفاده از داده های سری زمانی با LSTM دیدیم. همچنین روش پیادهسازی LSTM با کتابخانه PyTorch و سپس روش رسم نتایج پیشبینیشده بر اساس مقادیر واقعی را مشاهده کردید تا ببینید الگوریتم آموزشدیده چقدر خوب عمل میکند.
(برچسبها به ترجمه)# python
منتشر شده در 1403-01-19 21:39:04