البرنامج التعليمي RNN (الشبكة العصبية المتكررة): مثال TensorFlow

⚡ ملخص ذكي

تُضيف الشبكات العصبية المتكررة حالة ذاكرة إلى الخلايا العصبية العادية، حيث تُعيد تغذية كل مُخرج كمدخل تالٍ، مما يسمح للنموذج بالتعلم من الترتيب. يشرح هذا الدليل كيفية بناء نموذج كهذا باستخدام TensorFlow والتنبؤ بسلسلة زمنية.

  • 🔘 حالة الذاكرة: تتلقى كل خلية عصبية متكررة المخرجات السابقة إلى جانب المدخلات الجديدة، وهذا ما يمنح الشبكة وعيها الزمني.
  • ☑️ شكل الإخراج: يؤدي تشغيل الشبكة التجريبية إلى إرجاع موتر (3، 2، 6): الدفعات، والخطوات الزمنية، والخلايا العصبية بهذا الترتيب.
  • قاعدة التجميع: يتم إعادة تشكيل مدخلات السلاسل الزمنية إلى ثلاثة أبعاد، وتكون مصفوفة التصنيفات هي نفس السلسلة ولكن تم إزاحتها فترة واحدة للأمام.
  • 🧪 الهيكل النموذجي: العناصر النائبة، وBasicRNNCell مغلفة في dynamic_rnn، وإسقاط كثيف، ثم متوسط ​​الخطأ التربيعي مع مُحسِّن Adam.
  • 🛠️ جولة تدريبية: يؤدي 1,500 دورة تدريبية على 120 خلية عصبية متكررة إلى انخفاض الخسارة من 502,893 إلى ما يقرب من 1,385.
  • 📉 الحد المعروف: تؤدي التسلسلات الطويلة إلى مشكلة تلاشي التدرج، والتي صُممت نماذج LSTM والمتغيرات البوابية لحلها.

الشبكة العصبية المتكررة (RNN)

لماذا نحتاج إلى شبكة عصبية متكررة (RNN)؟

تتيح لك الشبكة العصبية المتكررة (RNN) تصميم وحدات الذاكرة للاحتفاظ بالبيانات ونموذج التبعيات قصيرة المدى. كما أنها تستخدم في التنبؤ بالسلاسل الزمنية لتحديد ارتباطات البيانات وأنماطها. كما أنه يساعد على إنتاج نتائج تنبؤية للبيانات المتسلسلة من خلال تقديم سلوك مماثل للدماغ البشري.

هيكل شبكة اعصاب صناعية هي بسيطة نسبيًا وتعتمد بشكل أساسي على ضرب المصفوفات. في الخطوة الأولى، تُضرب المدخلات بأوزان عشوائية مبدئية، ثم تُحوّل باستخدام دالة تنشيط، وتُستخدم قيم المخرجات للتنبؤ. تُعطي هذه الخطوة فكرة عن مدى قرب الشبكة من الواقع.

المقياس المطبق هو الخسارة. فكلما زادت دالة الخسارة، كلما كان النموذج أغبى. لتحسين معرفة الشبكة، يلزم إجراء بعض التحسينات عن طريق تعديل أوزان الشبكة. الانحدار التدرجي العشوائي هو الطريقة المستخدمة لتغيير قيم الأوزان في الاتجاه الصحيح. بمجرد إجراء التعديل، يمكن للشبكة استخدام دفعة أخرى من البيانات لاختبار معرفتها الجديدة.

لحسن الحظ، انخفض الخطأ عن السابق، ولكنه لا يزال غير كافٍ. تُجرى عملية التحسين بشكل تكراري حتى يتم تقليل الخطأ إلى أدنى حد، أي لا يمكن استخلاص المزيد من المعلومات.tracتيد.

المشكلة في هذا النوع من النماذج هي أنه لا يحتوي على أي ذاكرة. وهذا يعني أن المدخلات والمخرجات مستقلة. بمعنى آخر، النموذج لا يهتم بما جاء من قبل. إنه يثير بعض التساؤلات عندما تحتاج إلى التنبؤ بالسلاسل الزمنية أو الجمل لأن الشبكة تحتاج إلى معلومات حول البيانات التاريخية أو الكلمات السابقة.

للتغلب على هذه المشكلة، تم تطوير نوع جديد من الهندسة المعمارية: الشبكة العصبية المتكررة (RNN فيما يلي)

ما هي الشبكة العصبية المتكررة (RNN)؟

الشبكة العصبية المتكررة (RNN) هي نوع من الشبكات العصبية الاصطناعية، حيث تشكل الروابط بين العقد المختلفة رسمًا بيانيًا موجهًا، مما يُضفي سلوكًا ديناميكيًا زمنيًا. وهي تُساعد في نمذجة البيانات المتسلسلة المُستمدة من الشبكات الأمامية. وتعمل بطريقة مشابهة للدماغ البشري لتقديم نتائج تنبؤية.

تبدو الشبكة العصبية المتكررة مشابهة تمامًا للشبكة العصبية التقليدية فيما عدا أنه يتم إضافة حالة الذاكرة إلى الخلايا العصبية. حساب تضمين الذاكرة بسيط.

تخيل نموذجًا بسيطًا يحتوي على عصبون واحد فقط يتغذى بمجموعة من البيانات. في الشبكة العصبية التقليدية، يُنتج النموذج المخرجات بضرب المدخلات في الوزن ودالة التنشيط. أما في الشبكة العصبية المتكررة (RNN)، فتُعاد هذه المخرجات إلى نفسها عددًا من المرات. نسميها خطوة زمنية مقدار الوقت الذي يصبح فيه الناتج مدخلاً لعملية ضرب المصفوفة التالية.

على سبيل المثال، في الصورة أدناه، يمكنك رؤية أن الشبكة تتكون من خلية عصبية واحدة. تقوم الشبكة بحساب ضرب المصفوفات بين المدخلات والوزن وإضافة اللاخطية مع وظيفة التنشيط. ويصبح الإخراج في t-1. هذا الإخراج هو مدخلات ضرب المصفوفة الثانية.

عصبون متكرر واحد يرسل مخرجه عند t-1 كمدخل لعملية الضرب التالية

الشبكة العصبية المتكررة (RNN)

أدناه، نقوم بترميز RNN بسيط في TensorFlow لفهم الخطوة وكذلك شكل الإخراج.

تتكون الشبكة من :

  • أربعة مدخلات
  • ستة خلايا عصبية
  • 2-خطوات زمنية

سيتم تشغيل الشبكة كما هو موضح في الصورة أدناه.

شبكة عصبية متكررة غير ملفوفة بأربعة مدخلات وستة عصبونات وخطوتين زمنيتين

تُسمى الشبكة "متكررة" لأنها تقوم بنفس العملية في كل مربع تنشيط. قامت الشبكة بحساب أوزان المدخلات والمخرجات السابقة قبل استخدام دالة التنشيط.

ملاحظة حول الإصدار: يستهدف الكود في هذا البرنامج التعليمي واجهة برمجة تطبيقات الرسم البياني TensorFlow 1.x. في TensorFlow 2.x، يستمر تشغيل نفس البرنامج النصي بعد ذلك. import tensorflow.compat.v1 as tf المزيد tf.disable_v2_behavior()لأن العناصر النائبة والجلسات ووحدة rnn_cell أصبحت الآن موجودة تحت tf.compat.v1. المكافئ الاصطلاحي 2.x هو tf.keras.layers.SimpleRNN.

import numpy as np
import tensorflow as tf
n_inputs = 4
n_neurons = 6
n_timesteps = 2
The data is a sequence of a number from 0 to 9 and divided into three batches of data.
## Data 
X_batch = np.array([
        [[0, 1, 2, 5], [9, 8, 7, 4]], # Batch 1
        [[3, 4, 5, 2], [0, 0, 0, 0]], # Batch 2
        [[6, 7, 8, 5], [6, 5, 4, 2]], # Batch 3
    ])

يمكننا بناء الشبكة باستخدام عنصر نائب للبيانات والمرحلة المتكررة والمخرجات.

تحديد العنصر النائب للبيانات

X = tf.placeholder(tf.float32, [None, n_timesteps, n_inputs])

هنا:

  • لا شيء: غير معروف وسيأخذ حجم الدفعة
  • n_timesteps: عدد المرات التي ترسل فيها الشبكة المخرجات إلى الخلية العصبية
  • n_inputs: عدد المدخلات لكل دفعة

تحديد الشبكة المتكررة

كما هو مذكور في الصورة أعلاه، تتكون الشبكة من 6 خلايا عصبية. ستقوم الشبكة بحساب منتجين نقطيين:

  • إدخال البيانات بالمجموعة الأولى من الأوزان (أي 6: يساوي عدد الخلايا العصبية)
  • المخرجات السابقة مع مجموعة ثانية من الأوزان (أي 6: بما يتوافق مع عدد المخرجات)

لاحظ أنه خلال عملية التغذية الأمامية الأولى، تكون قيم المخرجات السابقة مساوية للأصفار لأنه ليس لدينا أي قيمة متاحة.

الكائن المراد إنشاء RNN هو tf.contrib.rnn.BasicRNNCell مع الوسيطة num_units لتحديد عدد الإدخال

basic_cell = tf.contrib.rnn.BasicRNNCell(num_units=n_neurons)

الآن بعد أن تم تعريف الشبكة، يمكنك حساب المخرجات والحالات

outputs, states = tf.nn.dynamic_rnn(basic_cell, X, dtype=tf.float32)

يستخدم هذا الكائن حلقة داخلية لضرب المصفوفات بالعدد المناسب من المرات.

لاحظ أن العصبون المتكرر هو دالة لجميع مدخلات الخطوات الزمنية السابقة. هكذا تبني الشبكة ذاكرتها الخاصة. يمكن للمعلومات من الزمن السابق أن تنتشر في الزمن اللاحق. هذا هو سر الشبكة العصبية المتكررة.

## Define the shape of the tensor
X = tf.placeholder(tf.float32, [None, n_timesteps, n_inputs])
## Define the network
basic_cell = tf.contrib.rnn.BasicRNNCell(num_units=n_neurons)
outputs, states = tf.nn.dynamic_rnn(basic_cell, X, dtype=tf.float32)
init = tf.global_variables_initializer()
init = tf.global_variables_initializer()
with tf.Session() as sess:
    init.run()
    outputs_val = outputs.eval(feed_dict={X: X_batch})
print(states.eval(feed_dict={X: X_batch}))
[[ 0.38941205 -0.9980438   0.99750966  0.7892596   0.9978241   0.9999997 ]
 [ 0.61096436  0.7255889   0.82977575 -0.88226104  0.29261455 -0.15597084]
 [ 0.62091285 -0.87023467  0.99729395 -0.58261937  0.9811445   0.99969864]]

لأغراض التوضيح، اطبع قيم الحالة السابقة. يُظهر الناتج المطبوع أعلاه ناتج الحالة الأخيرة. الآن، اطبع جميع النواتج، ستلاحظ أن الحالات هي الناتج السابق لكل دفعة. أي أن الناتج السابق يحتوي على معلومات حول التسلسل بأكمله.

print(outputs_val)    
print(outputs_val.shape)    
[[[-0.75934666 -0.99537754  0.9735819  -0.9722234  -0.14234993
   -0.9984044 ]
  [ 0.99975264 -0.9983206   0.9999993  -1.         -0.9997506
   -1.        ]]

 [[ 0.97486496 -0.98773265  0.9969686  -0.99950117 -0.7092863
   -0.99998885]
  [ 0.9326837   0.2673438   0.2808514  -0.7535883  -0.43337247
    0.5700631 ]]

 [[ 0.99628735 -0.9998728   0.99999213 -0.99999976 -0.9884324
   -1.        ]
  [ 0.99962527 -0.9467421   0.9997403  -0.99999714 -0.99929446
   -0.9999795 ]]]
(3, 2, 6)

يعرض الرسم التوضيحي أدناه نفس الموتر المطبوع دفعةً تلو الأخرى.

موتر مخرجات الشبكة العصبية المتكررة المشروح، والذي يصنف الدفعات الثلاث، ومخرجات الخلايا العصبية الست، والشكل (3، 2، 6).

الإخراج له الشكل (3، 2، 6):

  • 3: عدد الدفعات
  • 2: عدد الخطوات الزمنية
  • 6: عدد الخلايا العصبية

إن تحسين الشبكة العصبية المتكررة مماثل للشبكة العصبية التقليدية. ستشاهد بمزيد من التفاصيل كيفية تحسين التعليمات البرمجية في الجزء التالي من هذا البرنامج التعليمي للشبكة العصبية المتكررة.

تطبيقات RNN

RNN لها استخدامات متعددة، خاصة عندما يتعلق الأمر بالتنبؤ بالمستقبل. في الصناعة المالية، يمكن أن تكون RNN مفيدة في التنبؤ بأسعار الأسهم أو علامة اتجاه سوق الأوراق المالية (أي إيجابي أو سلبي).

يعد RNN مفيدًا للسيارة ذاتية القيادة حيث يمكنها تجنب وقوع حادث سيارة من خلال توقع مسار السيارة.

تُستخدم RNN على نطاق واسع في تحليل النصوص والتعليق على الصور وتحليل المشاعر والترجمة الآلية. على سبيل المثال، يمكن للمرء استخدام مراجعة الفيلم لفهم الشعور الذي يشعر به المشاهد بعد مشاهدة الفيلم. تعد أتمتة هذه المهمة مفيدة للغاية عندما لا يكون لدى شركة الأفلام الوقت الكافي لمراجعة المراجعات وتصنيفها وتوحيدها وتحليلها. يمكن للآلة القيام بهذه المهمة بمستوى أعلى من الدقة.

حدود RNN

من الناحية النظرية، من المفترض أن تقوم RNN بحمل المعلومات عدة مرات. ومع ذلك، من الصعب جدًا نشر كل هذه المعلومات عندما تكون الخطوة الزمنية طويلة جدًا. عندما تحتوي الشبكة على عدد كبير جدًا من الطبقات العميقة، تصبح غير قابلة للتدريب. هذه المشكلة تسمى: تلاشي مشكلة التدرج. إذا كنت تتذكر، تقوم الشبكة العصبية بتحديث الوزن باستخدام خوارزمية النسب المتدرج. تصبح التدرجات أصغر عندما تتقدم الشبكة إلى الطبقات السفلية.

في الختام، تبقى التدرجات ثابتة، مما يعني عدم وجود مجال للتحسين. يتعلم النموذج من تغير التدرج، وهذا التغير يؤثر على مخرجات الشبكة. مع ذلك، إذا كان الفرق في التدرج ضئيلاً للغاية (أي إذا تغيرت الأوزان قليلاً)، فلن تتمكن الشبكة من التعلم، وبالتالي لن تتمكن من الحصول على أي نتيجة. لذلك، لا يمكن للشبكة التي تواجه مشكلة التدرج المتلاشي أن تتقارب نحو حل جيد.

تحسين LSTM

للتغلب على مشكلة تلاشي التدرج التي تواجه الشبكات العصبية المتكررة (RNN)، قام ثلاثة باحثين، هم هوكريتر وشميدهوبر وبنجيو، بتحسين هذه الشبكات باستخدام بنية تُسمى الذاكرة طويلة المدى (LSTM). باختصار، تُزوّد ​​LSTM الشبكة بمعلومات تاريخية ذات صلة بالأحداث الأخيرة. وتستخدم الآلة بنية محسّنة لاختيار المعلومات ونقلها إلى فترات زمنية لاحقة.

تتوفر بنية LSTM في TensorFlow، ضمن حزمة tf.contrib.rnn.LSTMCell. لكن LSTM خارج نطاق هذا الشرح. يمكنك الرجوع إلى المصدر الرسمي. توثيق لمزيد من المعلومات

في TensorFlow 2.x، يتم الوصول إلى تلك الخلية على النحو التالي: tf.compat.v1.nn.rnn_cell.LSTMCellبينما يستخدم الكود الجديد عادةً tf.keras.layers.LSTM أو البوابة الأخف وزناً tf.keras.layers.GRU، والتي تصل إلى دقة مماثلة باستخدام عدد أقل من المعلمات.

RNN في السلاسل الزمنية

في هذا الدرس التعليمي حول الشبكات العصبية المتكررة (RNN) باستخدام TensorFlow، ستستخدم شبكة عصبية متكررة مع بيانات السلاسل الزمنية. تعتمد السلاسل الزمنية على القيم السابقة، مما يعني أن القيم الماضية تتضمن معلومات مهمة يمكن للشبكة التعلم منها. تكمن فكرة التنبؤ بالسلاسل الزمنية في تقدير القيمة المستقبلية لسلسلة معينة، مثل سعر السهم، أو درجة الحرارة، أو الناتج المحلي الإجمالي، وما إلى ذلك.

قد يكون تحضير البيانات لشبكة Keras RNN والسلسلة الزمنية أمرًا صعبًا بعض الشيء. أولاً وقبل كل شيء، الهدف هو التنبؤ بالقيمة التالية للسلسلة، أي أنك ستستخدم المعلومات السابقة لتقدير القيمة عند t + 1. العلامة تساوي تسلسل الإدخال ويتم إزاحتها فترة واحدة للأمام. ثانيًا، يتم تعيين عدد الإدخالات على 1، أي ملاحظة واحدة لكل وقت. أخيرًا، تكون الخطوة الزمنية مساوية لتسلسل القيمة العددية. على سبيل المثال، إذا قمت بتعيين الخطوة الزمنية على 10، فسوف يعود تسلسل الإدخال عشر مرات متتالية.

انظر إلى الرسم البياني أدناه، لقد قمنا بتمثيل بيانات السلاسل الزمنية على اليسار وتسلسل الإدخال الوهمي على اليمين. يمكنك إنشاء دالة لإرجاع مجموعة بيانات ذات قيمة عشوائية لكل يوم من يناير 2001 إلى ديسمبر 2016

# To plot pretty figures
%matplotlib inline
import matplotlib
import matplotlib.pyplot as plt
import pandas as pd
def create_ts(start = '2001', n = 201, freq = 'M'):
    rng = pd.date_range(start=start, periods=n, freq=freq)
    ts = pd.Series(np.random.uniform(-18, 18, size=len(rng)), rng).cumsum()
    return ts
ts= create_ts(start = '2001', n = 192, freq = 'M')
ts.tail(5)

الناتج

2016-08-31    -93.459631
2016-09-30    -95.264791
2016-10-31    -95.551935
2016-11-30   -105.879611
2016-12-31   -123.729319
Freq: M, dtype: float64
ts = create_ts(start = '2001', n = 222)

# Left
plt.figure(figsize=(11,4))
plt.subplot(121)
plt.plot(ts.index, ts)
plt.plot(ts.index[90:100], ts[90:100], "b-", linewidth=3, label="A training instance")
plt.title("A time series (generated)", fontsize=14)

# Right
plt.subplot(122)
plt.title("A training instance", fontsize=14)
plt.plot(ts.index[90:100], ts[90:100], "b-", markersize=8, label="instance")
plt.plot(ts.index[91:101], ts[91:101], "bo", markersize=10, label="target", markerfacecolor='red')
plt.legend(loc="upper left")
plt.xlabel("Time")

plt.show()

سلسلة زمنية مُولَّدة على اليسار وحالة تدريب من عشر خطوات مع أهداف متغيرة على اليمين

يُظهر الجزء الأيمن من الرسم البياني جميع السلاسل الزمنية، بدءًا من عام ٢٠٠١ وحتى عام ٢٠١٩. لا جدوى من إدخال جميع البيانات في الشبكة، بل يجب إنشاء مجموعة بيانات بطول يساوي الخطوة الزمنية. ستكون هذه المجموعة هي المتغير X. أما المتغير Y فهو نفسه X ولكن بعد إزاحته بمقدار فترة زمنية واحدة (أي أنك تريد التنبؤ بالفترة t+1).

كلا المتجهين لهما نفس الطول. يمكنك رؤيته في الجزء الأيمن من الرسم البياني أعلاه. يمثل الخط القيم العشر لإدخال X، في حين أن النقاط الحمراء هي القيم العشر للملصق، Y. لاحظ أن التسمية تبدأ بفترة واحدة قبل X وتنتهي بفترة واحدة بعد ذلك.

قم ببناء RNN للتنبؤ بالسلاسل الزمنية في TensorFlow

الآن في تدريب RNN هذا، حان الوقت لبناء أول RNN الخاص بك للتنبؤ بالسلسلة أعلاه. تحتاج إلى تحديد بعض المعلمات الفائقة (معلمات النموذج، أي عدد الخلايا العصبية، وما إلى ذلك) للنموذج:

  • عدد المدخلات: 1
  • خطوة الوقت (النوافذ في السلسلة الزمنية): 10
  • عدد الخلايا العصبية: 120
  • عدد المخرجات: 1

ستتعلم شبكتك من سلسلة بيانات مدتها 10 أيام، وستحتوي على 120 عصبونًا متكررًا. تُدخل إلى النموذج بيانات يوم واحد. يمكنك تغيير القيم لمعرفة ما إذا كان النموذج قد تحسن.

قبل بناء النموذج، عليك تقسيم مجموعة البيانات إلى مجموعة تدريب ومجموعة اختبار. تحتوي مجموعة البيانات الكاملة على 222 نقطة بيانات؛ ستستخدم أول 201 نقطة لتدريب النموذج، وآخر 21 نقطة لاختباره.

بعد تحديد مجموعتي التدريب والاختبار، عليك إنشاء كائن يحتوي على الدُفعات. تحتوي هذه الدُفعات على قيم X وقيم Y. تذكر أن قيم X متأخرة بفترة واحدة. لذلك، ستستخدم أول 200 مشاهدة، وتكون الخطوة الزمنية 10. يجب أن يحتوي كائن X_batches على 20 دفعة بحجم 10×1. أما كائن y_batches فيحمل نفس شكل كائن X_batches، ولكن بفترة زمنية متقدمة.

الخطوة 1) إنشاء القطار والاختبار

أولاً، تقوم بتحويل السلسلة إلى ملف نمباي المصفوفة؛ ثم تقوم بتحديد النوافذ (أي عدد المرات التي ستتعلم منها الشبكة)، وعدد المدخلات والمخرجات وحجم مجموعة القطار كما هو موضح في مثال TensorFlow RNN أدناه.

series = np.array(ts)
n_windows = 20   
n_input =  1
n_output = 1
size_train = 201

بعد ذلك، يمكنك ببساطة تقسيم المصفوفة إلى مجموعتين من البيانات.

## Split data
train = series[:size_train]
test = series[size_train:]
print(train.shape, test.shape)
(201,) (21,)

الخطوة 2) قم بإنشاء الدالة لإرجاع X_batches وy_batches

لتسهيل الأمر، يمكنك إنشاء دالة تُرجع صفيفين مختلفين، أحدهما لـ X_batches والآخر لـ y_batches.

لنكتب دالة RNN TensorFlow لإنشاء الدُفعات.

لاحظ أن الدفعات X متأخرة بفترة واحدة (نأخذ القيمة t-1). يجب أن يكون لإخراج الدالة ثلاثة أبعاد. البعد الأول يساوي عدد الدفعات، والثاني حجم النوافذ، والأخير عدد المدخلات.

الجزء الصعب هو تحديد نقاط البيانات بشكل صحيح. بالنسبة لنقاط البيانات X، يمكنك اختيار الملاحظات من t = 1 إلى t = 200، بينما بالنسبة لنقطة البيانات Y، يمكنك إرجاع الملاحظات من t = 2 إلى 201. بمجرد حصولك على نقاط البيانات الصحيحة، يصبح من السهل إعادة التشكيل السلسلة.

لإنشاء الكائن باستخدام الدُفعات، تحتاج إلى تقسيم مجموعة البيانات إلى عشر دفعات متساوية الطول (أي 20). يمكنك استخدام طريقة إعادة التشكيل وتمرير -1 بحيث تكون السلسلة مشابهة لحجم الدفعة. القيمة 20 هي عدد الملاحظات لكل دفعة و1 هي عدد المدخلات.

عليك أن تفعل نفس الخطوة ولكن بالنسبة للملصق.

لاحظ أنه يجب عليك تعديل البيانات بعدد مرات التنبؤ المطلوبة. على سبيل المثال، إذا كنت ترغب في التنبؤ بفترة زمنية واحدة، فعليك تعديل السلسلة بمقدار 1. أما إذا كنت ترغب في التنبؤ بيومين، فعليك تعديل البيانات بمقدار 2.

x_data = train[:size_train-1]: Select all the training instance minus one day
X_batches = x_data.reshape(-1, windows, input): create the right shape for the batch e.g (10, 20, 1)
def create_batches(df, windows, input, output):
    ## Create X         
        x_data = train[:size_train-1] # Select the data
        X_batches = x_data.reshape(-1, windows, input)  # Reshape the data 
    ## Create y
        y_data = train[n_output:size_train]
        y_batches = y_data.reshape(-1, windows, output)
        return X_batches, y_batches

الآن بعد أن تم تعريف الوظيفة، يمكنك استدعاؤها لإنشاء الدُفعات كما هو موضح في مثال RNN أدناه.

X_batches, y_batches = create_batches(df = train,
                                      windows = n_windows,
                                      input = n_input,
                                      output = n_output)

يمكنك طباعة الشكل للتأكد من صحة الأبعاد.

print(X_batches.shape, y_batches.shape)
(10, 20, 1) (10, 20, 1)

تحتاج إلى إنشاء مجموعة اختبار تحتوي على دفعة واحدة فقط من البيانات و20 ملاحظة.

لاحظ أنه، إذا توقعت يومًا بعد يوم، فهذا يعني أن القيمة المتوقعة الثانية ستعتمد على القيمة الحقيقية لليوم الأول (t+1) لمجموعة بيانات الاختبار. والحقيقة هي أن القيمة الحقيقية سوف تعرف.

إذا كنت تريد التنبؤ بـ t+2 (أي قبل يومين)، فأنت بحاجة إلى استخدام القيمة المتوقعة t+1؛ إذا كنت تريد التنبؤ بـ t+3 (قبل ثلاثة أيام)، فستحتاج إلى استخدام القيمة المتوقعة t+1 وt+2. من المنطقي أنه من الصعب التنبؤ بدقة بعدد الأيام المقبلة.

X_test, y_test = create_batches(df = test, windows = 20,input = 1, output = 1)
print(X_test.shape, y_test.shape)
(10, 20, 1) (10, 20, 1)

حسنًا، حجم الدفعة الخاص بك جاهز، يمكنك بناء بنية RNN. تذكر أن لديك 120 خلية عصبية متكررة.

الخطوة 3) قم ببناء النموذج

لإنشاء النموذج، تحتاج إلى تحديد ثلاثة أجزاء:

  1. المتغير مع الموترات
  2. آر إن إن
  3. الخسارة والتحسين

الخطوة 3.1) المتغيرات

تحتاج إلى تحديد متغيرات X وy بالشكل المناسب. هذه الخطوة تافهة. الموتر له نفس البعد مثل الكائنات X_batches و y_batches.

على سبيل المثال، الموتر X هو عنصر نائب (راجع البرنامج التعليمي على مقدمة إلى TensorFlow لتحديث عقلك حول إعلان المتغير) له ثلاثة أبعاد:

  • ملاحظة: حجم الدفعة
  • عدد النوافذ: طول النوافذ. أي عدد المرات التي ينظر فيها النموذج إلى الوراء
  • n_input: عدد المدخلات

النتيجه هي:

tf.placeholder(tf.float32, [None, n_windows, n_input])
## 1. Construct the tensors
X = tf.placeholder(tf.float32, [None, n_windows, n_input])   
y = tf.placeholder(tf.float32, [None, n_windows, n_output])

الخطوة 3.2) قم بإنشاء RNN

في الجزء الثاني من مثال TensorFlow الخاص بـ RNN، تحتاج إلى تحديد بنية الشبكة. وكما في السابق، يمكنك استخدام الكائن BasicRNNCell وdynamic_rnn من مقدر TensorFlow.

## 2. create the model
basic_cell = tf.contrib.rnn.BasicRNNCell(num_units=r_neuron, activation=tf.nn.relu)   
rnn_output, states = tf.nn.dynamic_rnn(basic_cell, X, dtype=tf.float32)   

الجزء التالي أصعب بعض الشيء ولكنه يسمح بإجراء عمليات حسابية أسرع. تحتاج إلى تحويل إخراج التشغيل إلى طبقة كثيفة ثم تحويله مرة أخرى ليكون له نفس بُعد الإدخال.

stacked_rnn_output = tf.reshape(rnn_output, [-1, r_neuron])          
stacked_outputs = tf.layers.dense(stacked_rnn_output, n_output)       
outputs = tf.reshape(stacked_outputs, [-1, n_windows, n_output])  

الخطوة 3.3) إنشاء الخسارة والتحسين

يعتمد تحسين النموذج على المهمة التي تقوم بتنفيذها. في الدرس السابق حول سي ان انفي الدرس السابق، كان هدفك تصنيف الصور، أما في هذا الدرس التعليمي حول الشبكات العصبية المتكررة، فالهدف مختلف قليلاً. يُطلب منك التنبؤ بقيمة متغير مستمر مقارنةً بتصنيفه إلى فئة.

هذا الاختلاف مهم لأنه سيغير مشكلة التحسين. مشكلة التحسين للمتغير المستمر هي تقليل متوسط ​​مربع الخطأ. لإنشاء هذه المقاييس في TF، يمكنك استخدام:

tf.reduce_sum(tf.square(المخرجات - y))

ما تبقى من رمز RNN هو نفسه كما كان من قبل؛ يمكنك استخدام مُحسِّن Adam لتقليل الخسارة (على سبيل المثال، MSE):

tf.train.AdamOptimizer(learning_rate=learning_rate)

محسن.تقليل(الخسارة)

هذا كل شيء، يمكنك تجميع كل شيء معًا، ويكون النموذج الخاص بك جاهزًا للتدريب.

tf.reset_default_graph()
r_neuron = 120    

## 1. Construct the tensors
X = tf.placeholder(tf.float32, [None, n_windows, n_input])   
y = tf.placeholder(tf.float32, [None, n_windows, n_output])

## 2. create the model
basic_cell = tf.contrib.rnn.BasicRNNCell(num_units=r_neuron, activation=tf.nn.relu)   
rnn_output, states = tf.nn.dynamic_rnn(basic_cell, X, dtype=tf.float32)              

stacked_rnn_output = tf.reshape(rnn_output, [-1, r_neuron])          
stacked_outputs = tf.layers.dense(stacked_rnn_output, n_output)       
outputs = tf.reshape(stacked_outputs, [-1, n_windows, n_output])   

## 3. Loss + optimization
learning_rate = 0.001  
 
loss = tf.reduce_sum(tf.square(outputs - y))    
optimizer = tf.train.AdamOptimizer(learning_rate=learning_rate)         
training_op = optimizer.minimize(loss)                                          

init = tf.global_variables_initializer() 

ستقوم بتدريب النموذج باستخدام 1500 حقبة وطباعة الخسارة كل 150 تكرارًا. بمجرد تدريب النموذج، يمكنك تقييم النموذج في مجموعة الاختبار وإنشاء كائن يحتوي على التنبؤات كما هو موضح في مثال الشبكة العصبية المتكررة أدناه.

iteration = 1500 

with tf.Session() as sess:
    init.run()
    for iters in range(iteration):
        sess.run(training_op, feed_dict={X: X_batches, y: y_batches})
        if iters % 150 == 0:
            mse = loss.eval(feed_dict={X: X_batches, y: y_batches})
            print(iters, "\tMSE:", mse)
    
    y_pred = sess.run(outputs, feed_dict={X: X_test})
0 	MSE: 502893.34
150 	MSE: 13839.129
300 	MSE: 3964.835
450 	MSE: 2619.885
600 	MSE: 2418.772
750 	MSE: 2110.5923
900 	MSE: 1887.9644
1050 	MSE: 1747.1377
1200 	MSE: 1556.3398
1350 	MSE: 1384.6113

أخيرًا، في هذا البرنامج التعليمي لـ RNN Deep Learning، يمكنك رسم القيمة الفعلية للسلسلة بالقيمة المتوقعة. إذا تم تصحيح النموذج الخاص بك، فيجب وضع القيم المتوقعة فوق القيم الفعلية.

كما ترون، لا يزال النموذج بحاجة إلى تحسين. الأمر متروك لكم لتغيير المعلمات الفائقة مثل النوافذ، وحجم الدفعة، أو عدد الخلايا العصبية المتكررة.

plt.title("Forecast vs Actual", fontsize=14)
plt.plot(pd.Series(np.ravel(y_test)), "bo", markersize=8, label="Actual", color='green')
plt.plot(pd.Series(np.ravel(y_pred)), "r.", markersize=8, label="Forecast", color='red')
plt.legend(loc="lower left")
plt.xlabel("Time")

plt.show()

رسم بياني يوضح الفرق بين التوقعات والنتائج الفعلية، حيث تمثل النقاط الفعلية باللون الأخضر والنقاط المتوقعة باللون الأحمر.

توقعات مقابل الفعلي

الأسئلة الشائعة

ابدأ بنافذة تغطي دورة كاملة للنمط، ثم اضبطها. النوافذ الأطول توفر سياقًا أوسع، لكنها تبطئ التدريب وتزيد من تدهور التدرج. عشر خطوات مناسبة للسلسلة اليومية هنا؛ أما الموسمية الأسبوعية فتحتاج عادةً إلى أكثر من ذلك.

نعم، باستخدام طبقة وسيطة. استبدل الاستيراد بـ tensorflow.compat.v1 واستدعِ disable_v2_behavior()، لأن العناصر النائبة والجلسات وrnn_cell نُقلت إلى مساحة اسم التوافق. جديد TensorFlow ينبغي للمشاريع استخدام tf.keras.layers.SimpleRNN بدلاً من ذلك.

تقترح مساعدات الذكاء الاصطناعي أحجام النوافذ، وتكتشف حالات عدم تطابق الأشكال قبل التشغيل، وتصيغ شيفرة تحميل البيانات من مخطط. إنها تختصر حلقة التجربة والخطأ التي تهيمن على العمل في النماذج المتكررة، على الرغم من أن اختيارات المعلمات الفائقة النهائية لا تزال بحاجة إلى التحقق من صحتها على بيانات محجوزة.

يُجيد برنامج Copilot التعامل مع عمليات البناء المتكررة: كتل الجلسات، وقواميس التغذية، وطباعة الخسائر الدورية. تبقى أشكال الموترات وتحولات التصنيفات هي الجزء الأكثر خطورة، لذا تأكد دائمًا من أبعاد الدُفعة بنفسك قبل الوثوق بحلقة مُولّدة.

تتوقع الطبقات المتكررة (الدفعة، الخطوة الزمنية، الميزة). يُحدد إعادة التشكيل إلى (-1، النوافذ، المدخلات) للإطار عدد التسلسلات الموجودة، ومدى رجوع كل تسلسل، وعدد القيم الواردة في كل خطوة. يؤدي فقدان بُعد إلى خطأ في الترتيب.

تستخدم شبكة LSTM ثلاث بوابات بالإضافة إلى حالة خلية منفصلة؛ بينما تدمج شبكة GRU بوابتي النسيان والإدخال وتتجاهل حالة الخلية. تتدرب شبكة GRU بشكل أسرع مع عدد أقل من المعاملات، في حين تتفوق شبكة LSTM غالبًا في حالات التبعيات الطويلة جدًا.

تُقلل التنبؤات المستمرة من متوسط ​​مربع الخطأ، كما هو الحال في هذا الشرح باستخدام دالة reduce_sum of squareduals. يشمل تصنيف التسلسلات، مثل تصنيفات المشاعر أو مهام الصور التي تم تناولها في سي ان ان يستخدم هذا البرنامج التعليمي مفهوم الإنتروبيا المتقاطعة بدلاً من ذلك.

تهيمن نماذج المحولات على معالجة اللغة لأن الانتباه يتوزع بالتوازي عبر التسلسل. وتظل النماذج المتكررة منافسة في معالجة الإشارات المتدفقة، والتنبؤات أحادية المتغير القصيرة، والأجهزة ذات الذاكرة المنخفضة، حيث تُعد المعالجة خطوة واحدة في كل مرة ميزة وليست عائقًا.

تلخيص هذه التدوينة بـ: