كل ما تعرفه عن word2vec غير صحيح

يبدو التفسير الكلاسيكي لـ word2vec باعتباره بنية تخطي عياري سلبي في المقالة العلمية الأصلية وعدد لا يحصى من منشورات المدونة كما يلي:

while(1) { 1. vf = vector of focus word 2. vc = vector of focus word 3. train such that (vc . vf = 1) 4. for(0 <= i <= negative samples): vneg = vector of word *not* in context train such that (vf . vneg = 0) } 

في الواقع ، إذا كنت google [word2vec skipgram] ، فما نراه:


لكن كل هذه التطبيقات خاطئة .

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

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

في الواقع ، gensim هو تطبيق C الحقيقي الوحيد الذي أعرفه .

ج التنفيذ


تطبيق C في الواقع يدعم متجهين لكل كلمة . متجه واحد للكلمة قيد التركيز ، والثاني للكلمة في السياق. (يبدو مألوفًا؟ صحيح ، لقد استعار مطورو GloVe فكرة من word2vec دون ذكر هذه الحقيقة!)

التنفيذ في كود C مختص بشكل استثنائي:

  • يحتوي صفيف syn0 على تضمين المتجه للكلمة إذا syn0 ككلمة في التركيز. إليك تهيئة عشوائية .

     https://github.com/tmikolov/word2vec/blob/20c129af10659f7c50e86e3be406df663beff438/word2vec.c#L369 for (a = 0; a < vocab_size; a++) for (b = 0; b < layer1_size; b++) { next_random = next_random * (unsigned long long)25214903917 + 11; syn0[a * layer1_size + b] = (((next_random & 0xFFFF) / (real)65536) - 0.5) / layer1_size; } 
  • يحتوي صفيف syn1neg آخر على متجه الكلمة عندما يظهر ككلمة سياق. التهيئة هنا هي صفر .
  • أثناء التدريب (تخطي غرام ، عينة سلبية ، على الرغم من أن الحالات الأخرى هي نفسها تقريبا) ، نختار أولاً كلمة التركيز. يتم الحفاظ عليه طوال التدريب على الأمثلة الإيجابية والسلبية. يتم تجميع تدرجات ناقل التركيز في المخزن المؤقت وتطبيقها على كلمة التركيز بعد التدريب على كل من الأمثلة الإيجابية والسلبية.

     if (negative > 0) for (d = 0; d < negative + 1; d++) { // if we are performing negative sampling, in the 1st iteration, // pick a word from the context and set the dot product target to 1 if (d == 0) { target = word; label = 1; } else { // for all other iterations, pick a word randomly and set the dot //product target to 0 next_random = next_random * (unsigned long long)25214903917 + 11; target = table[(next_random >> 16) % table_size]; if (target == 0) target = next_random % (vocab_size - 1) + 1; if (target == word) continue; label = 0; } l2 = target * layer1_size; f = 0; // find dot product of original vector with negative sample vector // store in f for (c = 0; c < layer1_size; c++) f += syn0[c + l1] * syn1neg[c + l2]; // set g = sigmoid(f) (roughly, the actual formula is slightly more complex) if (f > MAX_EXP) g = (label - 1) * alpha; else if (f < -MAX_EXP) g = (label - 0) * alpha; else g = (label - expTable[(int)((f + MAX_EXP) * (EXP_TABLE_SIZE / MAX_EXP / 2))]) * alpha; // 1. update the vector syn1neg, // 2. DO NOT UPDATE syn0 // 3. STORE THE syn0 gradient in a temporary buffer neu1e for (c = 0; c < layer1_size; c++) neu1e[c] += g * syn1neg[c + l2]; for (c = 0; c < layer1_size; c++) syn1neg[c + l2] += g * syn0[c + l1]; } // Finally, after all samples, update syn1 from neu1e https://github.com/tmikolov/word2vec/blob/20c129af10659f7c50e86e3be406df663beff438/word2vec.c#L541 // Learn weights input -> hidden for (c = 0; c < layer1_size; c++) syn0[c + l1] += neu1e[c]; 

لماذا التهيئة العشوائية والصفر؟


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

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

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

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

لماذا أكتب هذا


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

لم أستطع أن أتخيل أن مؤلفي المنشور قاموا بتلفيق خوارزمية لا تعمل ، بينما التنفيذ يقوم بشيء مختلف تمامًا.

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

ليس لدي أي فكرة عن سبب عدم نشر المنشور والمقالات الأصلية على الإنترنت أي شيء عن الآلية الحقيقية لـ word2vec ، لذلك قررت نشر هذه المعلومات بنفسي.

وهذا ما يفسر أيضًا اختيار GloV الراديكالي لتعيين متجهات منفصلة للسياق السلبي - لقد فعلوا ما يفعله word2vec فقط ، لكنهم أخبروا الناس عنه :).

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

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


All Articles