آماده‌سازی سری زمانی برای مدل‌های یادگیری ماشین | Forecast با مدل Linear

آماده‌سازی سری زمانی برای مدل‌های یادگیری ماشین | Forecast با مدل Linear

توسط admin | گروه هوش مصنوعی | 1405/06/01

نظرات 0

آماده‌سازی سری زمانی برای مدل‌های یادگیری ماشین | Forecast با مدل Linear

کتاب
Hands-On Machine Learning with Scikit-Learn, Keras & TensorFlow
بخش منبع
Preparing the Data for Machine Learning Models; Forecasting Using a Linear Model; Simple RNN; Deep RNN; Multivariate Time Series; Several Time Steps Ahead; Sequence-to-Sequence
صفحات این PDF
16-29
صفحات چاپی کتاب
552-565
جایگاه در مجموعه
62 / Machine_Learning_405_06; parent: Machine_Learning_405_06_01.html

آماده‌سازی سری زمانی برای مدل‌های یادگیری ماشین

پس از ساخت دو Baseline یعنی Naive Forecasting و SARIMA، فصل به سراغ مدل‌های Machine Learning می‌رود. هدف این است که تعداد مسافران فردا با استفاده از ۸ هفتهٔ گذشته، یعنی ۵۶ روز، پیش‌بینی شود. در نتیجه هر Training Instance یک Window با طول ۵۶ دارد و Target مقدار بلافاصله بعد از آن Window است.

ساخت Window با timeseries_dataset_from_array()

Keras تابع کمکی tf.keras.utils.timeseries_dataset_from_array() را برای تبدیل یک سری به Dataset از Windowها فراهم می‌کند:

import tensorflow as tf

my_series = [0, 1, 2, 3, 4, 5]
my_dataset = tf.keras.utils.timeseries_dataset_from_array(
    my_series,
    targets=my_series[3:],
    sequence_length=3,
    batch_size=2
)

برای این مثال Windowهای [0,1,2]، [1,2,3] و [2,3,4] ساخته می‌شوند و Targetهای متناظر 3، 4 و 5 هستند.

ساخت Window با tf.data

روش انعطاف‌پذیرتر استفاده از Dataset.window() است. این متد ابتدا Datasetی از Datasetها می‌سازد و سپس با flat_map() می‌توان هر Window را به Tensor تبدیل کرد:

def to_windows(dataset, length):
    dataset = dataset.window(length, shift=1, drop_remainder=True)
    return dataset.flat_map(lambda window_ds: window_ds.batch(length))

dataset = to_windows(tf.data.Dataset.range(6), 4)
dataset = dataset.map(lambda window: (window[:-1], window[-1]))
dataset = dataset.batch(2)

این روش نسبت به Utility آماده پیچیده‌تر است، اما بعداً برای ساخت Targetهای Sequence-to-Sequence کنترل بیشتری می‌دهد.

تقسیم زمانی Train، Validation و Test

در Time Series معمولاً نباید داده را Random Split کرد؛ زیرا اطلاعات آینده ممکن است به Train نشت کند. در مثال کتاب، Rail Ridership به سه بازه تقسیم می‌شود و برای Scale مناسب بر یک میلیون تقسیم می‌گردد:

rail_train = df["rail"]["2016-01":"2018-12"] / 1e6
rail_valid = df["rail"]["2019-01":"2019-05"] / 1e6
rail_test  = df["rail"]["2019-06":] / 1e6

Windowهای Train Shuffle می‌شوند، اما ترتیب داخل هر Window حفظ می‌شود:

seq_length = 56
train_ds = tf.keras.utils.timeseries_dataset_from_array(
    rail_train.to_numpy(),
    targets=rail_train[seq_length:],
    sequence_length=seq_length,
    batch_size=32,
    shuffle=True,
    seed=42
)
valid_ds = tf.keras.utils.timeseries_dataset_from_array(
    rail_valid.to_numpy(),
    targets=rail_valid[seq_length:],
    sequence_length=seq_length,
    batch_size=32
)

Forecast با مدل Linear

ابتدا یک Dense Layer ساده با Huber Loss و Early Stopping آموزش داده می‌شود:

model = tf.keras.Sequential([
    tf.keras.layers.Dense(1, input_shape=[seq_length])
])

early_stopping_cb = tf.keras.callbacks.EarlyStopping(
    monitor="val_mae", patience=50, restore_best_weights=True)
opt = tf.keras.optimizers.SGD(learning_rate=0.02, momentum=0.9)
model.compile(loss=tf.keras.losses.Huber(), optimizer=opt, metrics=["mae"])
model.fit(train_ds, validation_data=valid_ds, epochs=500,
          callbacks=[early_stopping_cb])

Validation MAE حدود 37,866 است: بهتر از Naive Forecast، اما ضعیف‌تر از SARIMA.

Forecast با Simple RNN

ساده‌ترین RNN فقط یک Recurrent Neuron دارد:

model = tf.keras.Sequential([
    tf.keras.layers.SimpleRNN(1, input_shape=[None, 1])
])

Recurrent Layer در Keras ورودی 3D با Shape برابر [batch size, time steps, dimensionality] انتظار دارد. برای سری Univariate، Dimension آخر 1 است. مقدار None برای Time Steps یعنی مدل می‌تواند Sequenceهایی با طول‌های مختلف دریافت کند.

این مدل بسیار ضعیف است؛ فقط سه Parameter دارد و Output تابع tanh نیز به بازهٔ -1 تا +1 محدود می‌شود. راه‌حل این است که تعداد Recurrent Unitها را افزایش دهیم و یک Dense Output بدون Activation اضافه کنیم:

univar_model = tf.keras.Sequential([
    tf.keras.layers.SimpleRNN(32, input_shape=[None, 1]),
    tf.keras.layers.Dense(1)
])

این مدل Validation MAE حدود 27,703 می‌گیرد و از SARIMA نیز بهتر می‌شود.

Deep RNN

برای ساخت RNN عمیق، چند Recurrent Layer روی هم Stack می‌شوند. Layerهای میانی باید return_sequences=True داشته باشند تا خروجی سه‌بعدی همهٔ Time Stepها را به Layer بعدی بدهند.

15-10 - Deep RNN
شکل 15-10. Deep RNN
deep_model = tf.keras.Sequential([
    tf.keras.layers.SimpleRNN(32, return_sequences=True,
                              input_shape=[None, 1]),
    tf.keras.layers.SimpleRNN(32, return_sequences=True),
    tf.keras.layers.SimpleRNN(32),
    tf.keras.layers.Dense(1)
])

در این مثال Deep RNN حدود 31,211 MAE دارد؛ یعنی از Baselineها بهتر است، اما از مدل Shallower قبلی ضعیف‌تر است. بزرگ‌تر بودن Model همیشه به معنی بهتر بودن نیست.

سری زمانی چندمتغیره

Neural Networkها با تغییر کوچک می‌توانند Multivariate Time Series را پردازش کنند. برای پیش‌بینی Rail می‌توان Bus، Rail و نوع روز فردا را هم‌زمان وارد Model کرد. Day Type چون از قبل معلوم است، یک روز Shift می‌شود و سپس One-hot Encoding روی آن انجام می‌گیرد:

df_mulvar = df[["bus", "rail"]] / 1e6
df_mulvar["next_day_type"] = df["day_type"].shift(-1)
df_mulvar = pd.get_dummies(df_mulvar)

در نتیجه در هر Time Step پنج Feature داریم. تنها تغییر Model نسبت به حالت Univariate، Input Shape است:

mulvar_model = tf.keras.Sequential([
    tf.keras.layers.SimpleRNN(32, input_shape=[None, 5]),
    tf.keras.layers.Dense(1)
])

این Model به MAE حدود 22,062 می‌رسد. همچنین می‌توان با دو Output، Bus و Rail را هم‌زمان Forecast کرد. Multi-task Learning گاهی به‌دلیل Sharing Featureها و اثر Regularization بهتر عمل می‌کند، هرچند در این Dataset مدل اختصاصی برای هر Target کمی بهتر است.

پیش‌بینی چند Time Step آینده

برای Forecast چند روز آینده سه رویکرد اصلی بررسی می‌شود.

۱. Forecast تکراری یک Step

Model یک روز را پیش‌بینی می‌کند، Prediction به انتهای Input اضافه می‌شود و Model دوباره اجرا می‌شود. مشکل این روش این است که Errorها در Stepهای بعدی جمع می‌شوند.

15-11 - ۱. Forecast تکراری یک Step
شکل 15-11. ۱. Forecast تکراری یک Step
X = rail_valid.to_numpy()[np.newaxis, :seq_length, np.newaxis]
for step_ahead in range(14):
    y_pred_one = univar_model.predict(X)
    X = np.concatenate([X, y_pred_one.reshape(1, 1, 1)], axis=1)

۲. پیش‌بینی ۱۴ مقدار در یک Shot

می‌توان Output Layer را ۱۴ Unit کرد و Target را Vector چهارده‌روزه ساخت. این روش Error را مانند رویکرد قبلی انباشته نمی‌کند:

ahead_model = tf.keras.Sequential([
    tf.keras.layers.SimpleRNN(32, input_shape=[None, 5]),
    tf.keras.layers.Dense(14)
])

۳. مدل Sequence-to-Sequence

روش بهتر این است که در هر Time Step، Model نه فقط یک Forecast بلکه Vector شامل ۱۴ Forecast آینده تولید کند. در این حالت Loss برای Output تمام Time Stepها محاسبه می‌شود، بنابراین Gradientهای بیشتری به شبکه می‌رسند و مسیر Backpropagation در زمان کوتاه‌تر می‌شود. این موضوع Training را سریع‌تر و پایدارتر می‌کند.

def to_seq2seq_dataset(series, seq_length=56, ahead=14,
                       target_col=1, batch_size=32,
                       shuffle=False, seed=None):
    ds = to_windows(tf.data.Dataset.from_tensor_slices(series), ahead + 1)
    ds = to_windows(ds, seq_length).map(lambda S: (S[:, 0], S[:, 1:, 1]))
    if shuffle:
        ds = ds.shuffle(8 * batch_size, seed=seed)
    return ds.batch(batch_size)

seq2seq_model = tf.keras.Sequential([
    tf.keras.layers.SimpleRNN(32, return_sequences=True,
                              input_shape=[None, 5]),
    tf.keras.layers.Dense(14)
])

برای Forecast زمان t+1 MAE حدود 25,519 و برای t+14 حدود 34,322 است؛ هرچه Horizon دورتر می‌شود دقت افت می‌کند.

چرا Sequenceهای طولانی دشوارند؟

وقتی RNN روی Sequence بلند اجرا می‌شود، شبکهٔ Unrolled بسیار عمیق می‌شود. در نتیجه دو مشکل اصلی رخ می‌دهد: Gradient ناپایدار و فراموش شدن اطلاعات ابتدای Sequence. ReLU می‌تواند حتی باعث Exploding Output شود، زیرا Weightهای یکسان بارها در زمان استفاده می‌شوند. کاهش Learning Rate، Gradient Clipping، Dropout و Normalization می‌توانند کمک کنند. در بخش بعد به Layer Normalization، LSTM و GRU می‌رسیم.

امتیاز کاربران به این مقاله

☆☆☆☆☆

0 نفر امتیاز داده اند. میانگین: 0.0 از 5

 

0 نظر

نظر محترم شما در مورد مقاله های وب سایت برنامه نویسی و پایگاه داده

نظرات محترم شما در خدمات رسانی بهتر ما را یاری می نمایند. لطفا اگر مایل بودید یک نظر ما را مهمان فرمائید. آدرس ایمیل و وب سایت شما نمایش داده نخواهد شد.

0 / 500

اطلاعات تماس

  • آدرس:اصفهان-خیابان ام کلثوم غربی - بعد خیابان تخم چی - بیست متر بعد از پیتزا ننه شب - کوچه تعمیر گاه سمار زغالی - پلاک 354 - درب مشکی - طبقه هفتم
  • آدرس ایمیل:najafzade@gmail.com
  • وب سایت:http://www.a00b.com/
  • تلفن ثابت:(+98)9131253620
  • تلفن همراه:09131253620