ترجمة دليل الشبكة العصبية العودية من Tensorflow.org. تناقش المادة كلاً من القدرات المدمجة لـ Keras / Tensorflow 2.0 للتشبيك السريع ، بالإضافة إلى إمكانية تخصيص الطبقات والخلايا. كما يتم النظر في حالات وحدود استخدام نواة CuDNN ، مما يسمح بتسريع عملية تعلم الشبكة العصبية.
الشبكات العصبية العودية (RNNs) هي فئة من الشبكات العصبية جيدة لنمذجة البيانات التسلسلية ، مثل السلاسل الزمنية أو اللغة الطبيعية.إذا كانت الطبقة RNN تستخدم بشكل تخطيطي حلقة for
للتكرار عبر تسلسل مرتب حسب الوقت ، أثناء التخزين في حالة داخلية ، يتم ترميز المعلومات حول الخطوات التي شاهدها بالفعل.تم تصميم Keras RNN API مع التركيز على:سهولة الاستخدام : المدمج في طبقات tf.keras.layers.RNN
، tf.keras.layers.LSTM
، tf.keras.layers.GRU
تسمح لك لبناء بسرعة نموذجا متكررة دون الحاجة إلى إجراء إعدادات التكوين معقدة.التخصيص السهل : يمكنك أيضًا تحديد الطبقة الخاصة بك من خلايا RNN (الجزء الداخلي من الحلقةfor
) مع السلوك المخصص واستخدامه مع طبقة مشتركة من `tf.keras.layers.RNN` (حلقة` for` نفسها). سيتيح لك ذلك وضع نماذج لأفكار البحث المختلفة بسرعة وبأسلوب مرن ، مع الحد الأدنى من التعليمات البرمجية.التركيب
from __future__ import absolute_import, division, print_function, unicode_literals
import collections
import matplotlib.pyplot as plt
import numpy as np
import tensorflow as tf
from tensorflow.keras import layers
بناء نموذج بسيط
تحتوي Keras على ثلاث طبقات RNN مضمنة:tf.keras.layers.SimpleRNN
، RNN متصل بالكامل بحيث يتم تمرير ناتج الخطوة الزمنية السابقة إلى الخطوة التالية.tf.keras.layers.GRU
، اقترح لأول مرة في المقالة دراسة العبارات باستخدام برنامج الترميز RNN للترجمة الآلية الإحصائيةtf.keras.layers.LSTM
، اقترح لأول مرة في مقال طويل الأمد الذاكرة قصيرة المدى
في أوائل عام 2015 ، قدمت Keras أول تطبيقات مفتوحة المصدر قابلة لإعادة الاستخدام Python و LSTM و GRU.فيما يلي مثال على Sequential
نموذج يعالج تسلسل الأعداد الصحيحة عن طريق تداخل كل عدد صحيح في ناقل 64-الأبعاد ، ثم معالجة تسلسلات المتجهات باستخدام طبقة LSTM
.model = tf.keras.Sequential()
model.add(layers.Embedding(input_dim=1000, output_dim=64))
model.add(layers.LSTM(128))
model.add(layers.Dense(10))
model.summary()
المخرجات والحالات
بشكل افتراضي ، يحتوي إخراج طبقة RNN على متجه واحد لكل عنصر. هذا المتجه هو إخراج آخر خلية RNN تحتوي على معلومات حول تسلسل الإدخال بأكمله. بُعد هذا الإخراج (batch_size, units)
، حيث units
يتوافق مع الوسيطة التي units
تم تمريرها إلى مُنشئ الطبقة.يمكن لطبقة RNN أيضًا إرجاع تسلسل الإخراج الكامل لكل عنصر (متجه واحد لكل خطوة) ، إذا حددت return_sequences=True
. البعد من هذا الناتج (batch_size, timesteps, units)
.model = tf.keras.Sequential()
model.add(layers.Embedding(input_dim=1000, output_dim=64))
model.add(layers.GRU(256, return_sequences=True))
model.add(layers.SimpleRNN(128))
model.add(layers.Dense(10))
model.summary()
بالإضافة إلى ذلك ، يمكن لطبقة RNN إرجاع حالتها (حالاتها) الداخلية النهائية.يمكن استخدام الحالات المرتجعة لاحقًا لاستئناف تنفيذ RNN أو لتهيئة RNN أخرى . يُستخدم هذا الإعداد عادةً في نموذج وحدة التشفير - التشفير ، بالتسلسل إلى التسلسل ، حيث يتم استخدام الحالة النهائية للمشفرة للحالة الأولية لمفكك الشفرة.لكي تقوم طبقة RNN بإعادة حالتها الداخلية ، قم بتعيين المعلمة return_state
على القيمة True
عند إنشاء الطبقة. لاحظ أن هناك LSTM
موتران لحالة الولاية GRU
وواحد فقط.لضبط الحالة الأولية للطبقة ، ما عليك سوى استدعاء الطبقة بحجة إضافية initial_state
.لاحظ أن البعد يجب أن يتطابق مع بُعد عنصر الطبقة ، كما في المثال التالي.encoder_vocab = 1000
decoder_vocab = 2000
encoder_input = layers.Input(shape=(None, ))
encoder_embedded = layers.Embedding(input_dim=encoder_vocab, output_dim=64)(encoder_input)
output, state_h, state_c = layers.LSTM(
64, return_state=True, name='encoder')(encoder_embedded)
encoder_state = [state_h, state_c]
decoder_input = layers.Input(shape=(None, ))
decoder_embedded = layers.Embedding(input_dim=decoder_vocab, output_dim=64)(decoder_input)
decoder_output = layers.LSTM(
64, name='decoder')(decoder_embedded, initial_state=encoder_state)
output = layers.Dense(10)(decoder_output)
model = tf.keras.Model([encoder_input, decoder_input], output)
model.summary()
طبقات RNN وخلايا RNN
توفر واجهة برمجة تطبيقات RNN ، بالإضافة إلى طبقات RNN المدمجة ، واجهات برمجة تطبيقات على مستوى الخلية. على عكس طبقات RNN ، التي تعالج حزم كاملة من تسلسلات الإدخال ، تعالج خلية RNN خطوة زمنية واحدة فقط.الخلية داخل دورة for
طبقة RNN. tf.keras.layers.RNN
يمنحك التفاف الخلية بطبقة طبقة قادرة على معالجة حزم تسلسل ، على سبيل المثال RNN(LSTMCell(10))
.رياضيا ، RNN(LSTMCell(10))
يعطي نفس النتيجة LSTM(10)
. في الواقع ، كان تنفيذ هذه الطبقة داخل TF v1.x فقط لإنشاء خلية RNN المقابلة ولفها في طبقة RNN. ومع ذلك، فإن استخدام طبقات جزءا لا يتجزأ من GRU
و LSTM
يسمح استخدام CuDNN التي يمكن أن تعطيك أداء أفضل.هناك ثلاث خلايا RNN مدمجة ، كل منها يتوافق مع طبقة RNN الخاصة به.tf.keras.layers.SimpleRNNCell
يطابق الطبقة SimpleRNN
.tf.keras.layers.GRUCell
يطابق الطبقة GRU
.tf.keras.layers.LSTMCell
يطابق الطبقة LSTM
.
إن استخلاص خلية مع فئة مشتركة tf.keras.layers.RNN
يجعل من السهل جدًا تنفيذ بنى RNN المخصصة لبحثك.مجموعة حفظ عبر الدفعة
عند معالجة تسلسلات طويلة (ربما لا حصر لها) ، قد ترغب في استخدام نمط الحالة عبر الدفعة .عادة ، يتم إعادة تعيين الحالة الداخلية لطبقة RNN مع كل حزمة بيانات جديدة (أي كل مثال يرى أن الطبقة يفترض أنها مستقلة عن الماضي). ستحافظ الطبقة على الحالة فقط طوال مدة معالجة هذا العنصر.ومع ذلك ، إذا كان لديك تسلسلات طويلة جدًا ، فمن المفيد تقسيمها إلى تسلسل أقصر ونقلها إلى طبقة RNN بدورها دون إعادة تعيين حالة الطبقة. وبالتالي ، يمكن للطبقة تخزين معلومات حول التسلسل بأكمله ، على الرغم من أنها سترى تتابعًا واحدًا فقط في كل مرة.يمكنك القيام بذلك عن طريق تعيين `stateful = True` في المُنشئ.إذا كان لديك التسلسل `s = [t0، t1، ... t1546، t1547]` ، يمكنك تقسيمه على سبيل المثال إلى:s1 = [t0, t1, ... t100]
s2 = [t101, ... t201]
...
s16 = [t1501, ... t1547]
ثم يمكنك معالجتها باستخدام:lstm_layer = layers.LSTM(64, stateful=True)
for s in sub_sequences:
output = lstm_layer(s)
عندما تريد تنظيف الحالة ، استخدم layer.reset_states()
.ملاحظة: في هذه الحالة ، يُفترض أن المثال i
في هذه الحزمة هو استمرار لمثال i
الحزمة السابقة. هذا يعني أن جميع الحزم تحتوي على نفس عدد العناصر (حجم العبوة). على سبيل المثال ، إذا كانت الحزمة تحتوي على [sequence_A_from_t0_to_t100, sequence_B_from_t0_to_t100]
، يجب أن تحتوي الحزمة التالية [sequence_A_from_t101_to_t200, sequence_B_from_t101_to_t200]
.
هنا مثال كامل:paragraph1 = np.random.random((20, 10, 50)).astype(np.float32)
paragraph2 = np.random.random((20, 10, 50)).astype(np.float32)
paragraph3 = np.random.random((20, 10, 50)).astype(np.float32)
lstm_layer = layers.LSTM(64, stateful=True)
output = lstm_layer(paragraph1)
output = lstm_layer(paragraph2)
output = lstm_layer(paragraph3)
lstm_layer.reset_states()
RNN ثنائي الاتجاه
بالنسبة للتسلسلات بخلاف السلاسل الزمنية (مثل النصوص) ، غالبًا ما يحدث أن نموذج RNN يعمل بشكل أفضل إذا كان يعالج التسلسل ليس فقط من البداية إلى النهاية ، ولكن أيضًا بالعكس. على سبيل المثال ، للتنبؤ بالكلمة التالية في الجملة ، غالبًا ما يكون من المفيد معرفة السياق حول الكلمة ، وليس فقط الكلمات الموجودة أمامها.يوفر Keras واجهة برمجة تطبيقات بسيطة لإنشاء شبكات RNN ثنائية الاتجاه: غلاف tf.keras.layers.Bidirectional
.model = tf.keras.Sequential()
model.add(layers.Bidirectional(layers.LSTM(64, return_sequences=True),
input_shape=(5, 10)))
model.add(layers.Bidirectional(layers.LSTM(32)))
model.add(layers.Dense(10))
model.summary()
تحت غطاء المحرك ، سيتم نسخ Bidirectional
طبقة RNN المنقولة go_backwards
وسيتم قلب حقل الطبقة المنسوخة حديثًا ، وبالتالي سيتم معالجة بيانات الإدخال بترتيب عكسي.سيكون خرج ` Bidirectional
RNN بشكل افتراضي هو مجموع ناتج الطبقة الأمامية وخرج الطبقة العكسية. إذا كنت بحاجة إلى سلوك دمج آخر ، على سبيل المثال تسلسل ، قم بتغيير المعلمة `merge_mode` في مُنشئ المجمّع` ثنائي الاتجاه`.تحسين الأداء و CuDNN Core في TensorFlow 2.0
في TensorFlow 2.0 ، يمكن استخدام طبقات LSTM و GRU المضمنة بشكل افتراضي نوى CuDNN إذا كان معالج الرسومات متاحًا. مع هذا التغيير ، تكون الطبقات السابقة keras.layers.CuDNNLSTM/CuDNNGRU
قديمة ، ويمكنك بناء نموذجك دون القلق بشأن المعدات التي ستعمل عليها.نظرًا لأن نواة CuDNN مبنية ببعض الافتراضات ، فإن هذا يعني أن الطبقة لن تتمكن من استخدام طبقة نواة CuDNN إذا قمت بتغيير الإعدادات الافتراضية لطبقات LSTM أو GRU المدمجة . على سبيل المثال- تغيير وظيفة
activation
من tanh
شيء آخر. - تغيير وظيفة
recurrent_activation
من sigmoid
شيء آخر. - الاستخدام
recurrent_dropout
> 0. - تعيينها
unroll
إلى True، والذي يسبب LSTM / GRU لتتحلل الداخلية tf.while_loop
في حلقة نشرها for
. - تعيين
use_bias
على خطأ. - استخدام الأقنعة عندما تكون بيانات الإدخال غير مبررة بشكل صحيح (إذا كان القناع يطابق البيانات الصحيحة المحاذاة بدقة ، فلا يزال من الممكن استخدام CuDNN. هذه هي الحالة الأكثر شيوعًا).
عند الإمكان استخدم نوى CuDNN
batch_size = 64
input_dim = 28
units = 64
output_size = 10
def build_model(allow_cudnn_kernel=True):
if allow_cudnn_kernel:
lstm_layer = tf.keras.layers.LSTM(units, input_shape=(None, input_dim))
else:
lstm_layer = tf.keras.layers.RNN(
tf.keras.layers.LSTMCell(units),
input_shape=(None, input_dim))
model = tf.keras.models.Sequential([
lstm_layer,
tf.keras.layers.BatchNormalization(),
tf.keras.layers.Dense(output_size)]
)
return model
تحميل مجموعة بيانات MNIST
mnist = tf.keras.datasets.mnist
(x_train, y_train), (x_test, y_test) = mnist.load_data()
x_train, x_test = x_train / 255.0, x_test / 255.0
sample, sample_label = x_train[0], y_train[0]
إنشاء مثيل من النموذج وتجميعه
لقد اخترنا sparse_categorical_crossentropy
كدالة للخسائر. ناتج النموذج له بعد [batch_size, 10]
. إجابة النموذج متجه عدد صحيح ، كل من الأرقام في النطاق من 0 إلى 9.model = build_model(allow_cudnn_kernel=True)
model.compile(loss=tf.keras.losses.SparseCategoricalCrossentropy(from_logits=True),
optimizer='sgd',
metrics=['accuracy'])
model.fit(x_train, y_train,
validation_data=(x_test, y_test),
batch_size=batch_size,
epochs=5)
قم ببناء نموذج جديد بدون نواة CuDNN
slow_model = build_model(allow_cudnn_kernel=False)
slow_model.set_weights(model.get_weights())
slow_model.compile(loss=tf.keras.losses.SparseCategoricalCrossentropy(from_logits=True),
optimizer='sgd',
metrics=['accuracy'])
slow_model.fit(x_train, y_train,
validation_data=(x_test, y_test),
batch_size=batch_size,
epochs=1)
كما ترى ، فإن النموذج المصمم باستخدام CuDNN أسرع بكثير في التدريب من النموذج باستخدام نواة TensorFlow المعتادة.يمكن استخدام نفس النموذج مع دعم CuDNN للإخراج في بيئة المعالج الواحد. tf.device
يشير التعليق التوضيحي ببساطة إلى الجهاز المستخدم. سيتم تشغيل النموذج بشكل افتراضي على وحدة المعالجة المركزية إذا لم يكن GPU متاحًا.لا داعي للقلق بشأن الأجهزة التي تعمل عليها. أليس هذا رائعا؟with tf.device('CPU:0'):
cpu_model = build_model(allow_cudnn_kernel=True)
cpu_model.set_weights(model.get_weights())
result = tf.argmax(cpu_model.predict_on_batch(tf.expand_dims(sample, 0)), axis=1)
print('Predicted result is: %s, target result is: %s' % (result.numpy(), sample_label))
plt.imshow(sample, cmap=plt.get_cmap('gray'))
RNN مع إدخال قائمة / قاموس ، أو إدخال متداخل
تتيح لك الهياكل المتداخلة تضمين المزيد من المعلومات في خطوة واحدة. على سبيل المثال ، قد يحتوي إطار الفيديو على إدخال صوت وفيديو في نفس الوقت. قد يكون حجم البيانات في هذه الحالة:[batch, timestep, {\"video\": [height, width, channel], \"audio\": [frequency]}]
في مثال آخر ، يمكن أن تحتوي البيانات المكتوبة بخط اليد على إحداثيات x و y لموضع القلم الحالي ، بالإضافة إلى معلومات الضغط. لذلك يمكن تمثيل البيانات على النحو التالي:[batch, timestep, {\"location\": [x, y], \"pressure\": [force]}]
ينشئ الكود التالي مثالاً لخلية RNN مخصصة تعمل مع مثل هذه المدخلات المنظمة.حدد خلية مستخدم تدعم الإدخال / الإخراج المتداخل
NestedInput = collections.namedtuple('NestedInput', ['feature1', 'feature2'])
NestedState = collections.namedtuple('NestedState', ['state1', 'state2'])
class NestedCell(tf.keras.layers.Layer):
def __init__(self, unit_1, unit_2, unit_3, **kwargs):
self.unit_1 = unit_1
self.unit_2 = unit_2
self.unit_3 = unit_3
self.state_size = NestedState(state1=unit_1,
state2=tf.TensorShape([unit_2, unit_3]))
self.output_size = (unit_1, tf.TensorShape([unit_2, unit_3]))
super(NestedCell, self).__init__(**kwargs)
def build(self, input_shapes):
input_1 = input_shapes.feature1[1]
input_2, input_3 = input_shapes.feature2[1:]
self.kernel_1 = self.add_weight(
shape=(input_1, self.unit_1), initializer='uniform', name='kernel_1')
self.kernel_2_3 = self.add_weight(
shape=(input_2, input_3, self.unit_2, self.unit_3),
initializer='uniform',
name='kernel_2_3')
def call(self, inputs, states):
input_1, input_2 = tf.nest.flatten(inputs)
s1, s2 = states
output_1 = tf.matmul(input_1, self.kernel_1)
output_2_3 = tf.einsum('bij,ijkl->bkl', input_2, self.kernel_2_3)
state_1 = s1 + output_1
state_2_3 = s2 + output_2_3
output = [output_1, output_2_3]
new_states = NestedState(state1=state_1, state2=state_2_3)
return output, new_states
قم ببناء نموذج RNN بإدخال / إخراج متداخل
دعونا نبني نموذج Keras يستخدم طبقة tf.keras.layers.RNN
وخلية مخصصة حددناها للتو.unit_1 = 10
unit_2 = 20
unit_3 = 30
input_1 = 32
input_2 = 64
input_3 = 32
batch_size = 64
num_batch = 100
timestep = 50
cell = NestedCell(unit_1, unit_2, unit_3)
rnn = tf.keras.layers.RNN(cell)
inp_1 = tf.keras.Input((None, input_1))
inp_2 = tf.keras.Input((None, input_2, input_3))
outputs = rnn(NestedInput(feature1=inp_1, feature2=inp_2))
model = tf.keras.models.Model([inp_1, inp_2], outputs)
model.compile(optimizer='adam', loss='mse', metrics=['accuracy'])unit_1 = 10
unit_2 = 20
unit_3 = 30
input_1 = 32
input_2 = 64
input_3 = 32
batch_size = 64
num_batch = 100
timestep = 50
cell = NestedCell(unit_1, unit_2, unit_3)
rnn = tf.keras.layers.RNN(cell)
inp_1 = tf.keras.Input((None, input_1))
inp_2 = tf.keras.Input((None, input_2, input_3))
outputs = rnn(NestedInput(feature1=inp_1, feature2=inp_2))
model = tf.keras.models.Model([inp_1, inp_2], outputs)
model.compile(optimizer='adam', loss='mse', metrics=['accuracy'])
تدريب النموذج على البيانات بشكل عشوائي
نظرًا لعدم وجود مجموعة بيانات جيدة لهذا النموذج ، فإننا نستخدم بيانات عشوائية تم إنشاؤها بواسطة مكتبة Numpy للتوضيح.input_1_data = np.random.random((batch_size * num_batch, timestep, input_1))
input_2_data = np.random.random((batch_size * num_batch, timestep, input_2, input_3))
target_1_data = np.random.random((batch_size * num_batch, unit_1))
target_2_data = np.random.random((batch_size * num_batch, unit_2, unit_3))
input_data = [input_1_data, input_2_data]
target_data = [target_1_data, target_2_data]
model.fit(input_data, target_data, batch_size=batch_size)
باستخدام الطبقة ، ما tf.keras.layers.RNN
عليك سوى تحديد المنطق الرياضي لخطوة واحدة داخل التسلسل ، وستتعامل الطبقة tf.keras.layers.RNN
مع تكرار التسلسل نيابة عنك. هذه طريقة قوية بشكل لا يصدق لنموذج سريع لأنواع جديدة من RNNs (مثل متغير LSTM).بعد التحقق ، ستظهر الترجمة أيضًا على Tensorflow.org. إذا كنت ترغب في المشاركة في ترجمة وثائق موقع Tensorflow.org إلى اللغة الروسية ، فيرجى الاتصال بشخص أو تعليقات. هي موضع تقدير أي تصحيحات وتعليقات.