الكشف عن المشاعر في السياق في المحادثات النصية باستخدام الشبكات العصبية


في أيامنا هذه ، أصبح التحدث إلى وكلاء المحادثة روتينًا يوميًا ، ومن الأهمية بمكان بالنسبة لأنظمة الحوار أن تولد ردودًا تشبه الإنسان قدر الإمكان. كواحد من الجوانب الرئيسية ، ينبغي إيلاء الاهتمام الأساسي لتوفير استجابات واعية عاطفية للمستخدمين. في هذه المقالة ، سنقوم بوصف بنية الشبكة العصبية المتكررة لاكتشاف المشاعر في المحادثات النصية ، التي شاركت في SemEval-2019 المهمة 3 "EmoContext" ، أي ورشة عمل سنوية حول التقييم الدلالي. الهدف من المهمة هو تصنيف المشاعر (أي سعيدة وحزينة وغاضبة وغيرها) في مجموعة بيانات محادثة ثلاثية المنعطفات.

يتم تنظيم بقية المقال على النحو التالي. يقدم القسم 1 لمحة موجزة عن مهمة EmoContext والبيانات المقدمة. يركز القسمان 2 و 3 على النصوص السابقة للمعالجة وزخارف الكلمات ، وبالتالي. في القسم 4 ، وصفنا بنية نموذج LSTM المستخدم في تقديمنا. في الختام ، يتم تقديم الأداء النهائي لنظامنا ورمز المصدر. يتم تنفيذ النموذج في بيثون باستخدام مكتبة Keras.

1. بيانات التدريب


تركز المهمة 3 من برنامج SemEval-2019 "EmoContext" على اكتشاف المشاعر السياقية في المحادثة النصية. في EmoContext ، نظرًا إلى كلام مستخدم نصي جنبًا إلى جنب مع تحولي السياق في محادثة ، يجب علينا تصنيف ما إذا كانت عاطفة نطق المستخدم التالي "سعيدة" أو "حزينة" أو "غاضبة" أو "أخرى" (الجدول 1). لا يوجد سوى اثنين من المشاركين في المحادثة: شخص مجهول (Tuen-1 و Turn-3) و chatbot Ruuh المستندة إلى منظمة العفو الدولية (Turn-2). للحصول على وصف تفصيلي ، انظر ( Chatterjee et al. ، 2019 ).

جدول 1. أمثلة توضح مجموعة بيانات EmoContext ( Chatterjee et al. ، 2019 )
المستخدم (الدور الأول)وكيل المحادثة (الدور الأول)المستخدم (الدور الثاني)الطبقة الحقيقية
أنا مؤهل للتو للحصول على التدريب ناباردWOOT! هذا خبر عظيم. مبروك!بدأت أبكيسعيد
كيف تجرؤ على صفعة طفليإذا كنت تفسد سيارتي ، سأفعل ذلك لك أيضًامجرد محاولة للقيام بذلك مرة واحدةغاضب
لقد تأذيت أكثر منكأنت لم تقصد ذلك.قل انت تحبنيحزين
سأفعل الليل.حسنا. تبقي لي في حلقة.عدم إعطاء WhatsApp لا.آخرون

خلال المسابقة ، تمكنا من الوصول إلى 30160 نصوص ذات علامات إنسانية مقدمة من قبل منظمي المهام ، حيث يوجد حوالي 5000 عينة من فئة "غاضبة" و "حزينة" و "سعيدة" و 15000 لفئة "الآخرين" (الجدول 2). تمتلك مجموعات التطوير والاختبار ، التي تم توفيرها أيضًا من قبل المنظمين ، على عكس مجموعة القطار ، توزيعًا حقيقيًا ، وهو حوالي 4٪ لكل فصل عاطفي والباقي لفئة "الآخرين". البيانات المقدمة من Microsoft ويمكن العثور عليها في مجموعة LinkedIn الرسمية .

الجدول 2. توزيع تسمية فئة العاطفة في مجموعات البيانات ( Chatterjee et al.، 2019 ).
مجموعة البياناتسعيدحزينغاضبآخرونالمجموع
القطار
14.07 ٪
18.11 ٪
18.26 ٪
49.56٪
30160
ديف
5.15٪
4.54 ٪
5.45٪
84.86 ٪
2755
اختبار
5.16٪
4.54 ٪
5.41٪
84.90 ٪
5509
بعيد
33.33٪
33.33٪
33.33٪

900 ك

بالإضافة إلى هذه البيانات ، قمنا بجمع 900 ألف تغريدة إنجليزية من أجل إنشاء مجموعة بيانات بعيدة تضم 300 ألف تغريدة لكل مشاعر. لتشكيل مجموعة البيانات البعيدة ، اعتمدنا على استراتيجية Go et al. (2009) ، والذي بموجبه نربط التغريدات ببساطة مع وجود كلمات مرتبطة بالعاطفة مثل "#angry" ، "#annoyed" ، "# happy" ، "#sad ،" #sprised "، إلخ. استندت قائمة مصطلحات الاستعلام إلى شروط الاستعلام الخاصة بـ SemEval-2018 AIT DISC ( Duppada et al.، 2018 ).

مقياس الأداء الرئيسي لبرنامج EmoContext هو درجة F1 متناهية الصغر لثلاثة فصول عاطفية ، أي "حزين" و "سعيد" و "غاضب".

def preprocessData(dataFilePath, mode): conversations = [] labels = [] with io.open(dataFilePath, encoding="utf8") as finput: finput.readline() for line in finput: line = line.strip().split('\t') for i in range(1, 4): line[i] = tokenize(line[i]) if mode == "train": labels.append(emotion2label[line[4]]) conv = line[1:4] conversations.append(conv) if mode == "train": return np.array(conversations), np.array(labels) else: return np.array(conversations) texts_train, labels_train = preprocessData('./starterkitdata/train.txt', mode="train") texts_dev, labels_dev = preprocessData('./starterkitdata/dev.txt', mode="train") texts_test, labels_test = preprocessData('./starterkitdata/test.txt', mode="train") 

2. النصوص قبل المعالجة


قبل أي مرحلة تدريب ، تمت معالجة النصوص مسبقًا بواسطة أداة النص Ekphrasis (Baziotis et al.، 2017). تساعد هذه الأداة في إجراء تصحيح الإملاء وتطبيع الكلمات وتقسيمها وتسمح بتحديد الرموز المميزة التي يجب حذفها أو تطبيعها أو تعليقها بعلامات خاصة. استخدمنا التقنيات التالية لمرحلة ما قبل المعالجة.

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

بالإضافة إلى ذلك ، يوفر برنامج Emphasis الرمز المميز الذي يمكنه التعرف على معظم الرموز التعبيرية والرموز التعبيرية المعقدة مثل الكلمات الخاضعة للرقابة والمؤكد والمطوَّل بالإضافة إلى التواريخ والأوقات والعملات والمختصرات.

جدول 3. أمثلة ما قبل المعالجة النصية.
النص الأصلينص معالج مسبقا
أشعر أنني ... أنا اقتحام مليون قطعة <allcaps> أشعر بأنك </allcaps>. <تكرار> أنا اقتحام مليون قطعة
متعب و اشتقت لك جدا :‑(متعب و اشتقت لك جدا <sad>
يجب أن تلتزم بهذا: www.youtube.com/watch؟v=99myH1orbs4يجب أن تستمع إلى <elongated> لهذا: <url>
شقتي تعتني به. إيجاري حوالي 650 دولار.شقتي تعتني به. إيجاري هو حول <money>.

 from ekphrasis.classes.preprocessor import TextPreProcessor from ekphrasis.classes.tokenizer import SocialTokenizer from ekphrasis.dicts.emoticons import emoticons import numpy as np import re import io label2emotion = {0: "others", 1: "happy", 2: "sad", 3: "angry"} emotion2label = {"others": 0, "happy": 1, "sad": 2, "angry": 3} emoticons_additional = { '(^・^)': '<happy>', ':‑c': '<sad>', '=‑d': '<happy>', ":'‑)": '<happy>', ':‑d': '<laugh>', ':‑(': '<sad>', ';‑)': '<happy>', ':‑)': '<happy>', ':\\/': '<sad>', 'd=<': '<annoyed>', ':‑/': '<annoyed>', ';‑]': '<happy>', '(^ ^)': '<happy>', 'angru': 'angry', "d‑':": '<annoyed>', ":'‑(": '<sad>', ":‑[": '<annoyed>', '( ? )': '<happy>', 'x‑d': '<laugh>', } text_processor = TextPreProcessor( # terms that will be normalized normalize=['url', 'email', 'percent', 'money', 'phone', 'user', 'time', 'url', 'date', 'number'], # terms that will be annotated annotate={"hashtag", "allcaps", "elongated", "repeated", 'emphasis', 'censored'}, fix_html=True, # fix HTML tokens # corpus from which the word statistics are going to be used # for word segmentation segmenter="twitter", # corpus from which the word statistics are going to be used # for spell correction corrector="twitter", unpack_hashtags=True, # perform word segmentation on hashtags unpack_contractions=True, # Unpack contractions (can't -> can not) spell_correct_elong=True, # spell correction for elongated words # select a tokenizer. You can use SocialTokenizer, or pass your own # the tokenizer, should take as input a string and return a list of tokens tokenizer=SocialTokenizer(lowercase=True).tokenize, # list of dictionaries, for replacing tokens extracted from the text, # with other expressions. You can pass more than one dictionaries. dicts=[emoticons, emoticons_additional] ) def tokenize(text): text = " ".join(text_processor.pre_process_doc(text)) return text 

3. كلمة حفلات الزفاف


أصبحت الزخارف كلمة جزء أساسي من أي نهج التعلم العميق لأنظمة البرمجة اللغوية العصبية. لتحديد أنسب المتجهات لمهمة اكتشاف العواطف ، نجرب نماذج Word2Vec ( Mikolov et al. ، 2013 ) و GloVe ( Pennington et al.، 2014 ) و FastText ( Joulin et al.، 2017 ) بالإضافة إلى نماذج DataStories المدربة مسبقًا كلمة ناقلات ( Baziotis وآخرون ، 2017 ). المفهوم الرئيسي لـ Word2Vec هو تحديد موقع الكلمات ، التي تشترك في سياقات مشتركة في مجموعة التدريب ، على مقربة من مساحة المتجهات. يتعلم كل من نموذجي Word2Vec و Glove ترميزات هندسية للكلمات من معلومات حدوثهما المشترك ، ولكن في المقام الأول النموذج التنبؤي ، والنموذج الأخير هو نموذج قائم على العد. بمعنى آخر ، بينما يحاول Word2Vec التنبؤ بكلمة مستهدفة (بنية CBOW) أو سياق (هندسة تخطي غرام) ، أي لتقليل وظيفة الخسارة ، يحسب GloV متجهات الكلمات التي تقوم بتخفيض أبعاد في مصفوفة التكرار المشترك. يشبه FastText برنامج Word2Vec باستثناء حقيقة أنه يستخدم حرفًا n-gram من أجل تعلم متجهات الكلمات ، لذلك فهو قادر على حل مشكلة خارج المفردات.

لجميع التقنيات المذكورة أعلاه ، استخدمنا عربات التدريب الافتراضية المقدمة من قبل المؤلفين. نقوم بتدريب نموذج LSTM بسيط (خافت = 64) بناءً على كل من هذه الزخارف ومقارنة الفعالية باستخدام التحقق من الصحة. وفقًا للنتيجة ، أظهرت حفلات الزفاف التي تم تدريبها مسبقًا من DataStories أفضل متوسط ​​لدرجة F1.

لإثراء زخارف الكلمات المحددة مع الاستقطاب العاطفي للكلمات ، فإننا نعتبر أداء عبارة ما قبل التدريب البعيدة عن طريق صقل الزينة على مجموعة البيانات البعيدة المسمى تلقائيًا. تم توضيح أهمية استخدام التدريب المسبق في ( Deriu et al.، 201 7). نحن نستخدم مجموعة البيانات البعيدة لتدريب شبكة LSTM البسيطة لتصنيف التغريدات الغاضبة والحزينة والسعيدة. تم تجميد طبقة الزينة لأول حقبة تدريب من أجل تجنب حدوث تغييرات كبيرة في أوزان الزينة ، ثم تم تجميدها في الحقائب الخمسة التالية. بعد مرحلة التدريب ، تم حفظ الأعراس المضبوطة بدقة لمراحل التدريب الإضافية وإتاحتها للجمهور .

 def getEmbeddings(file): embeddingsIndex = {} dim = 0 with io.open(file, encoding="utf8") as f: for line in f: values = line.split() word = values[0] embeddingVector = np.asarray(values[1:], dtype='float32') embeddingsIndex[word] = embeddingVector dim = len(embeddingVector) return embeddingsIndex, dim def getEmbeddingMatrix(wordIndex, embeddings, dim): embeddingMatrix = np.zeros((len(wordIndex) + 1, dim)) for word, i in wordIndex.items(): embeddingMatrix[i] = embeddings.get(word) return embeddingMatrix from keras.preprocessing.text import Tokenizer embeddings, dim = getEmbeddings('emosense.300d.txt') tokenizer = Tokenizer(filters='') tokenizer.fit_on_texts([' '.join(list(embeddings.keys()))]) wordIndex = tokenizer.word_index print("Found %s unique tokens." % len(wordIndex)) embeddings_matrix = getEmbeddingMatrix(wordIndex, embeddings, dim) 

4. هندسة الشبكات العصبية


الشبكة العصبية المتكررة (RNN) هي مجموعة من الشبكات العصبية الاصطناعية المتخصصة في معالجة البيانات المتسلسلة. على النقيض من الشبكات العصبية التقليدية ، صُممت RRNs للتعامل مع البيانات المتسلسلة من خلال مشاركة أوزانها الداخلية التي تعالج التسلسل. لهذا الغرض ، يتضمن الرسم البياني لحساب RRNs دورات ، والتي تمثل تأثير المعلومات السابقة على الحاضر. امتدادًا لشبكات RNN ، تم تقديم شبكات الذاكرة طويلة المدى (LSTMs) في عام 1997 ( Hochreiter and Schmidhuber ، 1997 ). في LSTMs ترتبط الخلايا المتكررة بطريقة معينة لتجنب التلاشي وتنفجر مشاكل التدرج. LSTMs التقليدية تحافظ فقط على المعلومات من الماضي لأنها تعالج التسلسل في اتجاه واحد فقط. تجمع LSTMs ثنائية الاتجاه بين الإخراج من طبقتين LSTM مخفيتين تتحركان في اتجاهين متعاكسين ، حيث يتحرك أحدهما للأمام عبر الزمن ، والآخر يتحرك للخلف عبر الزمن ، مما يمكّن من التقاط المعلومات من كل من الدول السابقة والمستقبلية في وقت واحد ( Schuster و Paliwal ، 1997 ).


الشكل 1: بنية نسخة أصغر من العمارة المقترحة. وحدة LSTM للانعطاف الأول وللمنعطف الثالث لها أوزان مشتركة.

يقدم الشكل 1. نظرة عامة رفيعة المستوى على مقاربتنا. يتكون الهيكل المقترح للشبكة العصبية من وحدة التضمين ووحدتي LSTM ثنائية الاتجاه (خافتة = 64). تهدف وحدة LSTM السابقة إلى تحليل كلام المستخدم الأول (أي المنعطف الأول والثاني من المحادثة) والمقصود من الأخير تحليل كلام المستخدم الثاني (أي المنعطف الثاني). لا تتعلم هاتان الوحدتان فقط تمثيل ميزة الدلالة والعاطفة ، ولكن أيضًا كيفية التقاط ميزات المحادثة الخاصة بالمستخدم ، والتي تسمح بتصنيف المشاعر بدقة أكبر. في الخطوة الأولى ، يتم تغذية كل عبارة مستخدم في وحدة LSTM ثنائية الاتجاه مقابلة باستخدام حروف الكلمات المدربة مسبقًا. بعد ذلك ، يتم ربط خرائط الميزات الثلاثة هذه في متجه ميزة التسوية ، ثم يتم تمريرها إلى طبقة مخفية متصلة تمامًا (باهتة = 30) ، والتي تحلل التفاعلات بين المتجهات التي تم الحصول عليها. أخيرًا ، تستمر هذه الميزات خلال طبقة الإخراج مع وظيفة تنشيط softmax للتنبؤ بتسمية فئة نهائية. لتقليل التركيب الزائد ، تمت إضافة طبقات التنظيم ذات الضوضاء الغوسية بعد طبقة التضمين ، وأضيفت طبقات التسرب ( Srivastava et al. ، 2014 ) في كل وحدة LSTM (ع = 0.2) وقبل الطبقة المخفية المتصلة بالكامل (ع = 0.1).

 from keras.layers import Input, Dense, Embedding, Concatenate, Activation, \ Dropout, LSTM, Bidirectional, GlobalMaxPooling1D, GaussianNoise from keras.models import Model def buildModel(embeddings_matrix, sequence_length, lstm_dim, hidden_layer_dim, num_classes, noise=0.1, dropout_lstm=0.2, dropout=0.2): turn1_input = Input(shape=(sequence_length,), dtype='int32') turn2_input = Input(shape=(sequence_length,), dtype='int32') turn3_input = Input(shape=(sequence_length,), dtype='int32') embedding_dim = embeddings_matrix.shape[1] embeddingLayer = Embedding(embeddings_matrix.shape[0], embedding_dim, weights=[embeddings_matrix], input_length=sequence_length, trainable=False) turn1_branch = embeddingLayer(turn1_input) turn2_branch = embeddingLayer(turn2_input) turn3_branch = embeddingLayer(turn3_input) turn1_branch = GaussianNoise(noise, input_shape=(None, sequence_length, embedding_dim))(turn1_branch) turn2_branch = GaussianNoise(noise, input_shape=(None, sequence_length, embedding_dim))(turn2_branch) turn3_branch = GaussianNoise(noise, input_shape=(None, sequence_length, embedding_dim))(turn3_branch) lstm1 = Bidirectional(LSTM(lstm_dim, dropout=dropout_lstm)) lstm2 = Bidirectional(LSTM(lstm_dim, dropout=dropout_lstm)) turn1_branch = lstm1(turn1_branch) turn2_branch = lstm2(turn2_branch) turn3_branch = lstm1(turn3_branch) x = Concatenate(axis=-1)([turn1_branch, turn2_branch, turn3_branch]) x = Dropout(dropout)(x) x = Dense(hidden_layer_dim, activation='relu')(x) output = Dense(num_classes, activation='softmax')(x) model = Model(inputs=[turn1_input, turn2_input, turn3_input], outputs=output) model.compile(loss='categorical_crossentropy', optimizer='adam', metrics=['acc']) return model model = buildModel(embeddings_matrix, MAX_SEQUENCE_LENGTH, lstm_dim=64, hidden_layer_dim=30, num_classes=4) 

5. النتائج


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

أظهر النموذج الموضح في القسم السابق أفضل الدرجات في مجموعة بيانات dev ، لذلك تم استخدامه في مرحلة التقييم النهائية للمسابقة. في مجموعة بيانات الاختبار النهائي ، حققت درجة 72.59 ٪ من متوسط ​​F1 للصفوف العاطفية ، في حين كانت النتيجة القصوى بين جميع المشاركين 79.59 ٪. ومع ذلك ، هذا أعلى بكثير من الأساس الرسمي الذي أصدره منظمو المهام ، والذي كان 58.68 ٪.

تتوفر شفرة المصدر للنموذج وزخارف الكلمة في جيثب.
يمكن العثور على النسخة الكاملة من المقالة وورقة وصف المهمة في ACL Anthology.
توجد مجموعة بيانات التدريب في مجموعة المنافسة الرسمية في LinkedIn.

الاقتباس:

 @inproceedings{smetanin-2019-emosense, title = "{E}mo{S}ense at {S}em{E}val-2019 Task 3: Bidirectional {LSTM} Network for Contextual Emotion Detection in Textual Conversations", author = "Smetanin, Sergey", booktitle = "Proceedings of the 13th International Workshop on Semantic Evaluation", year = "2019", address = "Minneapolis, Minnesota, USA", publisher = "Association for Computational Linguistics", url = "https://www.aclweb.org/anthology/S19-2034", pages = "210--214", } 

Source: https://habr.com/ru/post/ar439850/


All Articles