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

يوضح الشكل الخلية A ، والتي يتم إدخال بيانات عنصر التسلسل فيها وكذلك الحالة غير مذكورة هنا . في الإخراج ، الخلية A يعطي الحالة و نتيجة الحساب .
في الممارسة العملية ، يتم تقسيم تسلسل البيانات عادةً إلى تتابعات بطول ثابت معين ويتم تمريرها إلى الحساب بواسطة مجموعات فرعية كاملة (مجموعات). وبعبارة أخرى ، فإن الخطوات التالية هي أمثلة للتعلم. المدخلات والمخرجات وحالات الخلية لشبكة متكررة هي سلاسل من الأرقام الحقيقية. لحساب المدخلات من الضروري استخدام حالة لم تكن نتيجة عملية حسابية على تسلسل بيانات معين. وتسمى هذه الحالات الدول الأولية. إذا كان التسلسل طويلًا بما يكفي ، فمن المنطقي الحفاظ على سياق العمليات الحسابية في كل تكرار. في هذه الحالة ، من الممكن إرسال آخر حالة محسوبة في التسلسل السابق كحالة أولية. إذا لم يكن التسلسل طويلاً أو كانت السلسلة التالية هي الجزء الأول ، فيمكنك تهيئة الحالة الأولية باستخدام الأصفار.
في الوقت الحالي ، لتدريب الشبكات العصبية في كل مكان تقريبًا ، يتم استخدام خوارزمية الانتشار الخلفي للأخطاء . يتم فحص نتيجة الحساب على مجموعة من الأمثلة المرسلة (في حالتنا ، مجموعة من الإجابات) مقارنة بالنتيجة المتوقعة (البيانات المحددة). يُطلق على الفرق بين القيم الفعلية والقيم المتوقعة خطأ ويتم نشر هذا الخطأ إلى أوزان الشبكة في الاتجاه المعاكس. وبالتالي ، تتكيف الشبكة مع البيانات المصنفة ، وكقاعدة عامة ، فإن نتيجة هذا التعديل تعمل بشكل جيد مع البيانات التي لم تستوفها الشبكة في أمثلة التدريب الأولية (فرضية التعميم).
في حالة وجود شبكة متكررة ، لدينا العديد من الخيارات التي يجب على المخرجات أخذها في الاعتبار. سنصف هنا شيئين رئيسيين:
- يمكنك مراعاة الخطأ من خلال مقارنة إخراج الخلية الأخيرة من اللاحقة بالإخراج المتوقع. هذا يعمل بشكل جيد لمهمة التصنيف. على سبيل المثال ، نحتاج إلى تحديد التلوين العاطفي للتغريدة. للقيام بذلك ، نختار تغريدات ونضع علامة عليها في ثلاث فئات: سلبية وإيجابية ومحايدة. سيكون ناتج الخلية ثلاثة أرقام - وزن الفئات. سيتم وضع علامة على التغريدات أيضًا بثلاثة أرقام - احتمالات تغريدة تنتمي إلى الفئة المقابلة. بعد حساب الخطأ على مجموعة فرعية من البيانات ، يمكنك نشره من خلال الإخراج أو الحالة كما تريد.
- يمكنك قراءة الخطأ على الفور عند مخرجات حساب الخلية لكل عنصر من العناصر التالية. هذا مناسب تمامًا لمهمة التنبؤ بالعنصر التالي في التسلسل من العناصر السابقة. يمكن استخدام هذا النهج ، على سبيل المثال ، في مشكلة تحديد الحالات الشاذة في سلسلة زمنية من البيانات أو في مهمة التنبؤ بالحرف التالي في النص ، من أجل توليدها بعد ذلك. انتشار الخطأ هو ممكن أيضا من خلال الدول أو المخرجات.
على عكس شبكة عصبية متصلة بشكل كامل ، فإن الشبكة العودية عميقة بمعنى أن الخطأ لا ينتشر فقط من مخرجات الشبكة إلى أوزانها ، ولكن أيضًا إلى اليسار ، من خلال الاتصالات بين الولايات. وبالتالي يتم تحديد عمق الشبكة حسب طول فترة اللاحقة. لنشر الخطأ من خلال حالة الشبكة العودية ، هناك خوارزمية خاصة. ميزته هي أن تدرجات الأوزان تتكاثر مع بعضها البعض ، عندما ينتشر الخطأ من اليمين إلى اليسار. إذا كان الخطأ الأولي أكبر من الوحدة ، ونتيجة لذلك ، يمكن أن يصبح الخطأ كبيرًا جدًا. على العكس ، إذا كان الخطأ الأولي أقل من الوحدة ، فعندئذٍ قد يتلاشى الخطأ في مكان ما في بداية التسلسل. يسمى هذا الوضع في نظرية الشبكات العصبية كاروسيل الخطأ القياسي. من أجل تجنب مثل هذه الحالات أثناء التدريب ، تم اختراع خلايا خاصة لا تحتوي على مثل هذه العيوب. أول خلية من هذا القبيل كانت LSTM ، والآن هناك مجموعة واسعة من البدائل ، منها GRU الأكثر شعبية.
يمكن العثور على مقدمة جيدة لشبكات التكرار في هذه المقالة . مصدر آخر معروف هو مقال من مدونة أندريه كاربتي.
تحتوي مكتبة Tensorflow على العديد من الفئات والوظائف لتنفيذ الشبكات العودية. فيما يلي مثال على إنشاء شبكة متكررة ديناميكية تستند إلى خلية من نوع GRU:
cell = tf.contrib.rnn.GRUCell(dimension) outputs, state = tf.nn.dynamic_rnn(cell, input, sequence_length=input_length, dtype=tf.float32)
في هذا المثال ، يتم إنشاء خلية GRU ، والتي يتم استخدامها بعد ذلك لإنشاء شبكة متكررة ديناميكية. يتم إرسال موتر بيانات الإدخال والأطوال الفعلية للخطابات إلى الشبكة. يتم تحديد بيانات الإدخال دائمًا بواسطة ناقل من الأرقام الحقيقية. لقيمة واحدة ، على سبيل المثال ، رمز رمز أو كلمة ، ما يسمى التضمين - تعيين هذا الرمز لبعض تسلسل الأرقام. تقوم وظيفة إنشاء شبكة متكررة ديناميكية بإرجاع زوج من القيم: قائمة بمخرجات الشبكة لجميع قيم التسلسل وآخر حالة محسوبة. كمدخل ، تأخذ الوظيفة خلية ، وبيانات الإدخال ، وموتر طول التتابع.
تختلف الشبكة العودية الديناميكية عن الشبكة الثابتة من حيث أنها لا تنشئ شبكة من خلايا الشبكة للخطوة التالية (في مرحلة تحديد الرسم البياني للحساب) ، ولكنها تطلق الخلايا على المدخلات ديناميكيًا أثناء حساب الرسم البياني على بيانات الإدخال. لذلك ، تحتاج هذه الوظيفة إلى معرفة أطوال بيانات الإدخال لإيقافها في الوقت المناسب.
توليد نماذج تعتمد على شبكات التكرار
توليد شبكات التكرار
في وقت سابق ، نظرنا في طريقتين لحساب أخطاء الشبكات العودية: في المخرج الأخير أو في جميع النواتج لسلسلة معينة. هنا نعتبر مشكلة توليد التتابعات. يعتمد تدريب شبكة المولد على الطريقة الثانية لما سبق.
بمزيد من التفصيل ، نحاول تدريب شبكة متكررة للتنبؤ بالعنصر التالي في التسلسل. كما ذكر أعلاه ، فإن إخراج خلية في شبكة عودية هو مجرد سلسلة من الأرقام. هذا المتجه ليس ملائمًا جدًا للتعلم ، لذلك يقدم مستوى آخر ، يستقبل هذا المتجه عند الإدخال ، وعند الإخراج يعطي وزن التنبؤات. يُسمى هذا المستوى مستوى الإسقاط ويسمح لك بمقارنة إخراج الخلية في عنصر معين من التسلسل بالإخراج المتوقع في البيانات ذات التسمية.
لتوضيح ذلك ، ضع في اعتبارك مهمة إنشاء نص يتم تمثيله كسلسلة من الأحرف. يساوي طول متجه الإخراج لمستوى الإسقاط حجم الأبجدية للنص المصدر. لا يتجاوز حجم الأبجدية عادة 150 حرفًا ، إذا قمت بحساب أحرف اللغتين الروسية والإنجليزية ، وكذلك علامات الترقيم. إخراج مستوى الإسقاط هو ناقل بطول الحروف الأبجدية ، حيث يتوافق كل رمز مع موضع معين في هذا المتجه - فهرس هذا الرمز. البيانات المُعلَّمة أيضًا عبارة عن ناقل يتألف من أصفار ، حيث يقف المرء في موضع الشخصية التالية للتسلسل.
للتدريب ، نستخدم تسلسلين للبيانات:
- تسلسل من الأحرف في النص المصدر ، يتم في البداية إضافة حرف خاص لا يمثل جزءًا من النص المصدر. يشار إليها عادةً باسم go .
- تسلسل أحرف النص المصدر كما هو ، دون إضافات.
مثال للنص "غسلت أمي الإطار":
['<go>', '', '', ', '', ' ', '', '', '', '', ' ', '', '', '', ''] ['', '', ', '', ' ', '', '', '', '', ' ', '', '', '', '']
للتدريب ، عادة ما يتم تشكيل حافلات صغيرة ، تتكون من عدد صغير من الأمثلة. في حالتنا ، هذه سلاسل يمكن أن تكون ذات أطوال مختلفة. يستخدم الكود الموضح أدناه الطريقة التالية لحل مشكلة أطوال مختلفة. من بين العديد من الأسطر الموجودة في minipackage ، يتم حساب الحد الأقصى للطول. تمتلئ جميع الخطوط الأخرى بحرف خاص (الحشو) بحيث تكون جميع الأمثلة الموجودة في minipacket متماثلة الطول. في نموذج التعليمات البرمجية أدناه ، يتم استخدام سلسلة اللوحة كحرف من هذا القبيل. أيضًا ، من أجل الجيل الأفضل ، في نهاية المثال ، أضف رمز نهاية الجملة - eos . وبالتالي ، في الواقع ، ستبدو البيانات من المثال مختلفة بعض الشيء:
['<go>', '', '', ', '', ' ', '', '', '', '', ' ', '', '', '', '', '<eos>', '<pad>', '<pad>', '<pad>'] ['', '', ', '', ' ', '', '', '', '', ' ', '', '', '', '', '<eos>', '<pad>', '<pad>', '<pad>', '<pad>']
يتم تغذية التسلسل الأول لإدخال الشبكة ، ويستخدم التسلسل الثاني كبيانات موسومة. ويستند التدريب التنبؤ على تحويل التسلسل الأصلي حرف واحد إلى اليسار.
التدريب والبيض
التدريب
خوارزمية التعلم بسيطة للغاية. لكل عنصر من عناصر تسلسل الإدخال ، نقوم بحساب متجه الإخراج لمستوى الإسقاط الخاص به ومقارنته بالمستوى المحدد. والسؤال الوحيد هو كيفية حساب الخطأ. يمكنك استخدام الجذر التربيعي لمتوسط الخطأ ، ولكن لحساب الخطأ في هذه الحالة ، من الأفضل استخدام إنتر إنتر . توفر مكتبة Tensorflow العديد من الوظائف لحسابها ، على الرغم من أنه لا يوجد شيء يوقف تنفيذ صيغة الحساب مباشرة في الكود.
من أجل الوضوح ، نقدم بعض التدوينات. بواسطة symbol_id ، سنشير إلى معرف الرمز (الرقم التسلسلي في الأبجدية). رمز المصطلح هنا تعسفي إلى حد ما ويعني ببساطة عنصرًا من الحروف الأبجدية. قد لا تحتوي الأبجدية على رموز ، ولكن تحتوي على كلمات أو حتى بعض السمات الأكثر تعقيدًا. سيتم استخدام المصطلح symbol_embedding للدلالة على ناقل الأرقام المطابق لعنصر معين من الحروف الأبجدية. بشكل عام ، يتم تخزين مجموعات الأرقام هذه في جدول حجم يطابق حجم الأبجدية.
يوفر Tensorflow ميزة تتيح لك الوصول إلى جدول التضمين واستبدال مؤشرات الأحرف بنواقل التضمين الخاصة بها. أولاً ، نحدد متغيرًا لتخزين الجدول:
embedding_table = tf.Variable(tf.random_uniform([alphabet_size, embedding_size]))
بعد ذلك ، يمكنك تحويل التنسرات الإدخال إلى التنسرات التضمين:
input_embeddings = tf.nn.embedding_lookup(embedding_table, input_ids)
نتيجة استدعاء الوظيفة عبارة عن موتر من نفس البعد الذي تم نقله إلى المدخلات ، ولكن كنتيجة لذلك ، يتم استبدال جميع مؤشرات الأحرف بتسلسل التضمين المقابل.
تفرخ
لحساب ، تحتاج خلية شبكة عودية إلى حالة والحرف الحالي. نتيجة الحساب هي خروج وحالة جديدة. إذا قمنا بتطبيق مستوى الإسقاط على المخرجات ، فيمكننا الحصول على متجه للأوزان حيث يمكن اعتبار الوزن في الموضع المقابل (مشروطًا جدًا) كاحتمال ظهور هذا الرمز في الموضع التالي بالتسلسل.
يمكن استخدام استراتيجيات متنوعة لتحديد الرمز التالي بناءً على متجه الوزن الناتج عن مستوى الإسقاط:
- استراتيجية البحث الجشع. في كل مرة نختار فيها الرمز بأعلى وزن ، أي على الأرجح في هذا الموقف ، ولكن ليس بالضرورة الأكثر ملاءمة في سياق التسلسل بأكمله.
- استراتيجية لاختيار أفضل تسلسل (بحث شعاع). لا نختار رمزًا في وقت واحد ، ولكن نتذكر عدة أشكال من أكثر الرموز احتمالًا. بعد حساب كل هذه الخيارات لجميع عناصر التسلسل الذي تم إنشاؤه ، نختار أكثر تسلسل محتمل من الأحرف ، مع مراعاة سياق التسلسل بأكمله. عادةً ما يتم تحقيق ذلك عن طريق مصفوفة يكون عرضها مساوياً لطول التسلسل ، والارتفاع إلى عدد المتغيرات لتوليد الحروف (عرض بحث الحزمة). بعد اكتمال إنشاء متغيرات التسلسل ، يتم استخدام أحد المتغيرات لخوارزمية Viterbi لتحديد التسلسل الأكثر احتمالًا.
Tensorflow مكتبة نوع نظام seq2seq
بالنظر إلى ما تقدم ، من الواضح أن تنفيذ النماذج التوليفية القائمة على شبكات التكرار هو مهمة صعبة إلى حد ما بالنسبة للتشفير. لذلك ، بطبيعة الحال ، تم اقتراح النظم الطبقية لتسهيل حل هذه المشكلة. أحد هذه الأنظمة يسمى seq2seq ، ثم نصف وظائف أنواعها الرئيسية.
ولكن ، قبل كل شيء ، بضع كلمات عن اسم المكتبة. اسم seq2seq هو اختصار التسلسل إلى التسلسل (من التسلسل إلى التسلسل). تم اقتراح الفكرة الأصلية لتوليد تسلسل لتطبيق نظام الترجمة. تم تغذية تسلسل إدخال الكلمات لإدخال شبكة عودية ، تسمى التشفير في هذا النظام. كان إخراج هذه الشبكة العودية هو حالة حساب الخلية على الحرف الأخير من التسلسل. تم تقديم هذه الحالة باعتبارها الحالة الأولية للشبكة العودية الثانية ، وحدة فك الترميز ، والتي تم تدريبها على توليد الكلمة التالية. تم استخدام الكلمات كرموز في كلتا الشبكتين. تم نشر الأخطاء على الديكور إلى المشفر من خلال الحالة المرسلة. كان متجه الحالة نفسه في هذا المصطلح يسمى متجه الفكر. تم استخدام العرض التقديمي المتوسط في نماذج الترجمة التقليدية ، وكقاعدة عامة ، كان رسمًا بيانيًا يمثل هيكل نص الإدخال للترجمة. قام نظام الترجمة بإنشاء نص الإخراج استنادًا إلى هذه البنية الوسيطة.
في الواقع ، فإن تنفيذ seq2seq في Tensorflow ينتمي إلى جزء وحدة فك الترميز ، دون التأثير على برنامج التشفير. لذلك ، سيكون من الصواب استدعاء مكتبة 2seq ، ولكن قوة التقليد والقصور الذاتي في التفكير هنا سادت بوضوح على المنطق السليم.
النوعان الرئيسيان في مكتبة seq2seq هما:
- الطبقة المساعد .
- الطبقة فك .
حدد مطورو المكتبة هذه الأنواع بناءً على الاعتبارات التالية. دعونا ننظر في عملية التعلم وعملية التوليد ، التي وصفناها أعلاه ، من زاوية مختلفة قليلاً.
للتدريب تحتاجه:
- لكل حرف ، قم بتمرير حساب الحالة الحالية وتضمين الحرف الحالي.
- تذكر حالة الإخراج والإسقاط المحسوبة للإخراج.
- الحصول على الحرف التالي في التسلسل وانتقل إلى الخطوة 1.
بعد ذلك ، يمكنك البدء في حساب الأخطاء من خلال مقارنة نتائج العمليات الحسابية مع الأحرف التالية من التسلسل.
لتوليد ذلك ضروري:
- لكل حرف ، قم بتمرير حساب الحالة الحالية وتضمين الحرف الحالي.
- تذكر حالة الإخراج والإسقاط المحسوبة للإخراج.
- احسب الحرف التالي كحد أقصى لمؤشرات مستوى الإسقاط وانتقل إلى الخطوة 1.
كما يتبين من الوصف ، الخوارزميات متشابهة جدًا. لذلك ، قرر مطورو المكتبة تغليف الإجراء للحصول على الحرف التالي في فئة Helper. للتدريب ، هذا مجرد قراءة الحرف التالي من التسلسل ، ولإنشاءه ، حدد الشخصية ذات الوزن الأقصى (بالطبع ، للبحث الجشع).
وفقًا لذلك ، تطبق فئة Helper الأساسية أسلوب next_inputs للحصول على الحرف التالي من الحالة والحالة ، وكذلك طريقة العينة للحصول على مؤشرات الأحرف من مستوى الإسقاط. لتنفيذ التدريب ، يتم توفير فئة TrainingHelper ، ولتنفيذ التوليد باستخدام طريقة البحث الجشع ، يتم توفير فئة GreedyEmbeddingHelper . لسوء الحظ ، لا يتناسب نموذج بحث الحزمة مع نظام النوع ، لذلك ، يتم تطبيق فئة BeamSearchDecoder من الفئة الخاصة في المكتبة الخاصة بهذا. لا تستخدم المساعد.
توفر الفئة Decoder واجهة لتنفيذ وحدة فك ترميز. في الواقع ، يقدم الفصل طريقتين:
- التهيئة للتهيئة في بداية العمل.
- خطوة لتنفيذ خطوة التعلم أو جيل. يتم تحديد محتوى هذه الخطوة بواسطة المساعد المطابق.
تطبق المكتبة فئة BasicDecoder ، والتي يمكن استخدامها في التدريب والتربية مع مساعدي التدريب و GreedyEmbeddingHelper. هذه الفئات الثلاثة عادة ما تكون كافية لتنفيذ نماذج الجيل على أساس شبكات التكرار.
أخيرًا ، يتم استخدام وظائف dynamic_decode لتنظيم المرور عبر تسلسل إدخال أو تسلسل تم إنشاؤه.
بعد ذلك ، سننظر في مثال توضيحي ، يوضح طرق إنشاء نماذج توليد لأنواع مختلفة من مكتبة seq2seq.
مثال توضيحي
بادئ ذي بدء ، ينبغي أن يقال أن جميع الأمثلة يتم تنفيذها في بيثون 2.7. يمكن العثور على قائمة بالمكتبات الإضافية في ملف requirements.txt.
كمثال توضيحي ، فكر في جزء من بيانات مسابقة تطبيع النص - مسابقة اللغة الروسية التي أجرتها Google في Kaggle في عام 2017. كان الغرض من هذه المسابقة هو تحويل النص الروسي إلى شكل مناسب للقراءة. تم تقسيم نص المسابقة إلى تعبيرات مكتوبة. تم تحديد بيانات التدريب في ملف CSV من النموذج التالي:
"sentence_id","token_id","class","before","after" 0,0,"PLAIN","","" 0,1,"PLAIN","","" 0,2,"PLAIN","","" 0,3,"DATE","1862 "," " 0,4,"PUNCT",".","." 1,0,"PLAIN","","" 1,1,"PLAIN","","" 1,2,"PLAIN","","" 1,3,"PLAIN","","" 1,4,"PLAIN","","" 1,5,"PLAIN","","" 1,6,"PLAIN","","" 1,7,"PLAIN","","" 1,8,"PLAIN","","" 1,9,"PUNCT",".","." ...
في المثال أعلاه ، تعبير "النوع DATE" مثير للاهتمام ؛ حيث يتم ترجمة "1862" إلى "ألف وثمانمائة وثانية وستين عامًا". للتوضيح ، نأخذ بعين الاعتبار بيانات النوع DATE فقط كأزواج من النموذج (التعبير من قبل ، التعبير بعد). بداية ملف البيانات:
before,after 1862 , 1811 , 12 2013, 15 2013, 1905 , 17 2014, 7 2010 , 1 , 1843 , 30 2007 , 1846 , 1996 , 9 , ...
سنقوم ببناء نموذج التوليد باستخدام مكتبة seq2seq ، حيث سيتم تنفيذ برنامج التشفير على مستوى الرمز (أي أن عناصر الأبجدية هي رموز) ، وسوف تستخدم وحدة فك ترميز الكلمات الأبجدية. نموذج التعليمة البرمجية ، مثل البيانات ، متاح في المستودع على جيثب .
تنقسم بيانات التدريب إلى ثلاث مجموعات فرعية: train.csv و test.csv و dev.csv ، للتدريب والاختبار وإعادة التحقق ، على التوالي. البيانات موجودة في دليل البيانات. يتم تطبيق ثلاثة نماذج في المستودع: seq2seq_greedy.py و seq2seq_attention.py و seq2seq_beamsearch.py. هنا ننظر إلى رمز نموذج البحث الجشع الأساسي.
تستخدم جميع الطرز فئة المقدر لتنفيذها. يتيح لك استخدام هذه الفئة تبسيط عملية الترميز دون تشتيت الانتباه عن طريق الأجزاء غير النموذجية. على سبيل المثال ، ليست هناك حاجة إلى تنفيذ دورة نقل البيانات للتدريب ، وإنشاء جلسات للعمل مع Tensorflow ، والتفكير في نقل البيانات إلى Tensorboard ، إلخ. يتطلب مقدّر وظيفتين فقط لتنفيذه: لنقل البيانات وللبناء نموذج. تستخدم الأمثلة أيضًا فئة Dataset لتمرير البيانات للمعالجة. هذا التطبيق الحديث أسرع بكثير من القواميس التقليدية لنقل بيانات النموذج feed_dict.
النظر في رمز توليد البيانات للتدريب والتوليد.
def parse_fn(line_before, line_after):
تُستخدم دالة input_fn لإنشاء مجموعة من البيانات التي ينتقلها مقدّر بعد ذلك إلى التدريب والتوليد. يتم تعيين نوع البيانات أولاً. هذا هو زوج من النموذج ((تسلسل التشفير ، الطول) ، (تسلسل وحدة فك التشفير ، تسلسل وحدة فك التشفير مع بادئة ، طول)). يتم استخدام السلسلة "" كبادئات ، وينتهي كل تسلسل مشفر بكلمة خاصة "". أيضًا ، نظرًا لحقيقة أن التتابعات (كل من المدخلات والمخرجات) لها طول غير متكافئ ، يتم استخدام رمز الحشو ذي القيمة "".
يقرأ رمز إعداد البيانات ملف البيانات ، ويقسم سلسلة التشفير إلى أحرف ، وسلسلة فك الشفرة إلى كلمات ، باستخدام مكتبة nltk لهذا الغرض. الصف الذي تمت معالجته بهذه الطريقة هو مثال على بيانات التدريب. تنقسم المجموعة التي تم إنشاؤها إلى حزم صغيرة ، ويتم استنساخ كمية البيانات وفقًا لعدد مرات التدريب (كل فترة عبارة عن مسار بيانات واحد).
العمل مع القواميس
يتم تخزين القواميس كقائمة في الملفات ، سطر واحد لكلمة أو حرف واحد. لبناء القواميس ، استخدم البرنامج النصي build_vocabs.py. توجد القواميس التي تم إنشاؤها في دليل البيانات كملفات للنموذج vocab. *. Txt.
رمز لقراءة القواميس:
هنا ، على الأرجح ، تكون دالة index_table_from_file مثيرة للاهتمام ، حيث تقوم بقراءة عناصر القاموس من ملف ، والمعلمة num_oov_buckets الخاصة بها هي عدد السلال خارج المفردات. بشكل افتراضي ، هذا الرقم يساوي واحدًا ، أي كل الكلمات التي ليست في القاموس لها نفس الفهرس مساو لحجم القاموس + 1. لدينا ثلاث كلمات غير معروفة: "" ، "" و "" ، والتي نريد أن يكون لها فهارس مختلفة. لذلك ، قم بتعيين هذه المعلمة إلى الرقم ثلاثة. لسوء الحظ ، يجب عليك قراءة ملف الإدخال مرة أخرى للحصول على عدد الكلمات في القاموس كوقت ثابت لإعداد الرسم البياني للطراز.
ما زلنا بحاجة إلى إنشاء جدول لتطبيق التضمين - _source_embedding ، وكذلك ترجمة سلاسل الكلمات إلى سلاسل المعرفات:
تنفيذ التشفير
بالنسبة إلى المشفر ، سنستخدم شبكة تكرارية ثنائية الاتجاه مع عدة مستويات. , , .
GRU, MultiRNNCell, , rnn.Cell. ,
sequence_length — , , .
, , , . , 128, 256. , , 128. .
. بسبب , , bidirectional_dynamic_rnn, , . , . , .. . , , . , , .
, . .
TrainingHelper + BasicDecoder.
.
GreedyEmbeddingHelper "", "". . , , dynamic_decode . , , . , , .
, seq2seq.
, , sequence_mask.
Adam , .
optimizer = tf.train.AdamOptimizer(learning_rate=params.get('lr', .001)) grads, vs = zip(*optimizer.compute_gradients(loss)) grads, gnorm = tf.clip_by_global_norm(grads, params.get('clip', .5)) train_op = optimizer.apply_gradients(zip(grads, vs), global_step=tf.train.get_or_create_global_step())
. 0.9 . , , , . , .
24 1944 1 2003 1992 . 11 1927 1969 1 2016 1047 1863 17 22 2014
. — , — , — .
, — . . , ( ), . . , .
الخاتمة
seq2seq. , , . , .
. Tensorflow , , . , , . , . , , padding , embedding ? , , . — . , , . , , , . , . , , , , .