۱. دسته بندی جملات با استفاده از شبکه های عصبی کانولوشن


۱.۱. بخش اول : مفاهیم نظری مقاله

۱.۱.۱. مقدمه

دسته­ بندی متن 1 را می­ توان یکی از بخش های مهم پردازش زبان طبیعی دانست. این دسته بندی می تواند در زمینه های مختلفی انجام شود. مثلا تعیین عنوان یا ژانر مناسب برای متن، تشخیص هرزنامه 2 از بین ایمیل ها، تشخیص جنسیت نویسنده، تحلیل مثبت و منفی بودن یک نظر یا توییت، تعیین فیلد یک مقاله و بسیاری کاربردهای دیگر.
کلیت عملکرد این نوع روش ها به این ترتیب است که تعداد m متن و j کلاس داریم. به هر متن به صورت دستی یک برچسب کلاس نسبت داده شده است. به گونه ای که تمام المان های دیتاست، زوج های \left( { d }_{ i },{ c }_{ i } \right) هستند که { d }_{ i } متن i ام و { c }_{ i } برچسب کلاس متناظر با آن است. هدف ما این است که بعد از اتمام مرحله آموزش با دریافت { d }_{ x } جدید، مدل بتواند برچسب متناسب با آن را تشخیص دهد.
برای آموزش چنین مدلی می ­توانیم از هر یک از دسته­ بندهای کلاسیک از جمله بیز، ماشین بردار پشتیبان 3، شبکه ­های عصبی مصنوعی و ... استفاده کنیم. با گسترش یادگیری عمیق و به کارگیری آن در حوزه های مختلف، این روش در مسائل دسته بندی متن هم مورد استفاده قرار گرفته است [1][2]
در ادامه این گزارش به تعریف مسئله می پردازیم، در بخش سوم و چهارم مروری بر ادبیات و کارهای پیشین خواهیم داشت و برخی مفاهیم بنیادین را بررسی می کنیم. در بخش پنجم معماری پیشنهادی را شرح می دهیم و در بخش ششم جزییات دیتاست های به کار رفته در این پژوهش را بررسی می کنیم. دو بخش بعدی مربوط به آموزش و پیاده سازی مدل است و نهایتا با ارائه نتایج به دست آمده به این گزارش خاتمه می دهیم.


۱.۱.۲. تعریف مسئله

دسته بندی جمله 4 مشابه دسته بندی متن است که همان طور که پیش تر بیان شد در آن به هر جمله ، یک برچسب کلاس تعلق می گیرد. دسته بندی جملات می تواند بر اساس نوع جمله باشد و به کلاس های خبری، پرسشی، تعجبی و امری تقسیم بندی شود و یا بر اساس مفهوم و با توجه به مسئله در کلاس های متفاوتی دسته بندی شوند. مثلا نظرات کاربران در مورد یک محصول را به دو گروه منفی و مثبت تفکیک کند.
مقاله حاضر بر دسته بندی مفهومی جملات تمرکز کرده است. در مدل به کار رفته با استفاده از بردارهای واژگان از پیش آموزش دیده word2vec و همچنین شبکه های عصبی کانولوشن نتایج بسیار خوبی روی هفت مجموعه دادگان مختلف به دست آمده است. در بخش های بعد توضیحات مفصل تری در این زمینه خواهیم داد.


۱.۱.۳. مرور ادبیات و معرفی کارهای مرتبط پیشین

مدل های یادگیری عمیق در سال های اخیر توانسته اند نتایج بسیار درخشانی در حوزه تصویر و صوت کسب کنند. همچنین پژوهشگران در زمینه پردازش زبان طبیعی و بر روی بردار واژگان تحقیقات گسترده ای انجام داده اند. عملکرد بردار واژگان به این ترتیب است که با استفاده از روش های شبکه عصبی به ازای هر کلمه برداری به دست می آید که ابعاد آن بسیار کمتر از بردارV بعدی کلمه است.(V تعداد کلمات دیکشنری است) در چنین بازنمایشی کلماتی که از نظر مفهومی به هم نزدیکند در فضای برداری هم به هم نزدیک خواهند بود. نتایج این بردارهای واژگان مثل مجموعه word2vec و GloVe به صورت از پیش آموزش دیده 5 در دسترس است. [3][4]
از طرفی طبق پژوهش های اخیر، شبکه های عصبی کانولوشن که عمدتا در حوزه تصویر به کار می روند، می توانند در پردازش زبان هم به کار گرفته شوند و در بهبود نتایج موثر باشند. عملکرد این شبکه ها به این صورت است که با تعریف یک ماتریس به عنوان فیلتر و جابه جایی آن در سطح تصویر یا متن، ویژگی های محلی6 متفاوتی استخراج می شود که می تواند درمدل سازی جمله7 تجزیه معنایی8 و بازیابی پرس و جو 9 مورد استفاده قرار گیرد. [5][6][7]
با استفاده از این دو روش، یعنی بردارهای واژگان از پیش آموزش دیده و شبکه های عصبی کانولوشن، در این مقاله مدلی بر مبنای CNN و با استفاده از بردار واژگان word2vec آموزش داده شده است که دقت های به دست آمده از آن در مسئله دسته بندی متن از روش های قبلی بالاتر است.


۱.۱.۴. مفاهیم اولیه پیش نیاز

برای درک بهتر ساختار و ایده مقاله حاضر، ابتدا لازم است با چند مفهوم مهم که در این پژوهش به کار رفته، آشنا شویم. در ادامه مباحث convolution ، pooling ، dropout ، softmax و کانال را که در بخش معماری استفاده شده اند به طور مختصر بررسی خواهیم کرد.

  • ًconvolution
    ساده ترین روش برای بیان مفهوم کانولوشن یک پنجره لغزان است که به صورت یک ماتریس نمایش داده می شود. به این ماتریس کرنل 10، فیلتر یا استخراج گر ویژگی11 می گوییم. هر درایه کرنل یک عدد(ضریب) است و با جا به جایی کرنل، مقادیر ورودی، در ضریب متناظرشان در کرنل ضرب می شوند و حاصل جمع آنها به عنوان نتیجه در پاسخ درج می شود. [8]
    از کانولوشن میتوان برای شناسایی حاشیه در تصاویر یا فیلترهای مختلف دیگر استفاده کرد.CNN مجموعه ای از چند لایه کانولوشن است که بر روی خروجی آنها توابع فعالساز12 غیرخطی مثل ReLU و tanh اعمال می شود. فرمول زیر چگونگی عملکرد کانولوشن(K) بر روی ماتریس نمونه ورودی(I) را نشان می دهد. h و d وw به ترتیب ارتفاع، عمق و عرض فیلتر هستند.

    \mathrm{conv}(I, K)_{xy} = \sigma\left(b + \sum_{i=1}^h \sum_{j=1}^w \sum_{k=1}^d {K_{ijk} \cdot I_{x + i - 1, y + j - 1, k}}\right)

    شکل1:چگونگی عملکرد کانولوشن بر روی ماتریس ورودی

  • ًpooling
    لایه Pooling که معمولا بعد از لایه های پیچشی قرار میگیرد وظیفه نمونه برداری13 از داده های ورودی را دارد. این کار می تواند به روش های مختلفی انجام شود که معمول ترین آنها استفاده از عملگر ماکسیمم است. فیلتری با اندازه مشخص روی ورودی اعمال می شود. با جا به جایی فیلتر در هر پنجره، بزرگ ترین عدد انتخاب می شود. ماتریسی که در نهایت به عنوان خروجی ارائه می شود شامل بزرگترین داده ها در هر قاب است. تصویر زیر به خوبی عملکرد max-pooling و average-pooling را نشان می دهد. نکته مهمی که باید به آن توجه شود این است که جا به جایی فیلتر به گونه ای انجام می شود که هم پوشانی اتفاق نیفتد. [9]

    شکل2:چگونگی عملکرد دو نوع pooling که بیش از بقیه کاربرد دارند: max-pooling و average-pooling

  • ًdropout
    شبکه های عصبی کاملا متصل14 می توانند دچار بیش برازش15 شوند. برای جلوگیری از این مشکل، معمولا بعد از لایه های کاملا متصل یک لایه dropout قرار می دهند. عملکرد این لایه ها به این ترتیب است که به صورت تصادفی و با احتمال p خروجی برخی نورون ها را در محاسبات نادیده می گیرند. این ایده توسط آقای هینتون ارائه شد و در عمل باعث بهبود چشمگیر نتایج شد. دانستن همین کلیات از dropout برای این مقاله کافی است فلذا از بیان جزییات بیشتر صرف نظر می کنیم. [10]
    تصویر 3 که از مقاله اصلی گرفته شده است، عملکرد این تابع را به خوبی نشان می دهد.

    شکل3:چگونگی عملکرد dropout بر روی چند لایه کاملا-متصل

  • ًsoftmax
    تابع softmax یک بردار k بعدی مثل z ، که شامل اعداد حقیقی است، را به عنوان ورودی می گیرد و بردار k بعدی \sigma (z) که شامل اعداد در بازه [0,1] است را به عنوان خروجی می دهد به گونه ای که حاصل جمع این اعداد دقیقا 1 شود. به عبارت دیگر این تابع اعداد ورودی را به مقادیر احتمال آنها نگاشت می کند. نمایش ریاضی این عمل به صورت فرمول زیر است:

    \sigma (z)_{j} = \frac{e^{ z_{j} } }{ \sum_k^K e^{ z_{k} } }
    که در آن j=1,2,...,K است. توجه کنید که مخرج کسر صرفا برای نرمال سازی اعداد است. این تابع برخلاف ظاهر پیچیده، کارکرد بسیار ساده ای دارد که با ارائه مثالی ، شفاف تر خواهد شد. فرض کنید ورودی ما برداری با مقادیر [1, -2, 0] است و مسئله ماکلاس بندی هر داده در یکی از سه کلاس ماشین، موتور و هواپیماست. با اعمال تابع softmax بر این ورودی، مقادیر [0.7, 0.04, 0.26] حاصل می شود که در نتیجه آن، به داده ورودی برچسب «ماشین» تخصیص می یابد.[11][12]
    [1, -2, 0] \rightarrow [e^1, e^{-2}, e^0] = [2.71, 0.14, 1] \rightarrow [0.7, 0.04, 0.26]

  • کانال
    یکی دیگر از مفاهیمی که لازم است با آن آشنا شویم، کانال است. کانال ها در حقیقت "دید"16 های مختلف از داده ورودی واحد هستند. به عنوان مثال در حوزه تصویر عموما کانال های RGB (قرمز، سبز، آبی) داریم. می توان فیلترهای کانولوشن را با وزن های یکسان یا متفاوت بر کانال های مختلف اعمال کرد. اما این کانال ها در پردازش زبان طبیعی چه مفهومی دارند؟ می توانیم برای تعبیه متن های متفاوت، کانال های متفاوت داشته باشیم(مثلا word2vec و GloVe) و یا اینکه یک جمله، به زبان های مختلف وجود داشته باشد و هر زبان یک کانال باشد.[8]

  • جمع بندی و انتقال این مفاهیم به حوزه پردازش زبان طبیعی
    سوالی که همچنان باقی مانده است، این است که تمام این مفاهیم چگونه در حوزه پردازش زبان طبیعی به کار می روند؟ پاسخ ساده است. ورودی، به جای پیکسل های تصاویر، جملات یا متونی هستند که به صورت یک ماتریس نمایش داده می شوند. هر سطر ماتریس نمایانگر یک توکن(عموما یک واژه) است. به عبارت دیگر هر سطر یک بردار است که مختص یک واژه است. این بردار میتواند بازنمایش one-hot کلمه، یا بازنمایش تعبیه متن با ابعاد کمتر مثل word2vec یا GloVe باشد. پس برای یک جمله ده کلمه ای با تعبیه متن 100 بعدی، ماتریسی به ابعاد 100×10 به عنوان ورودی خواهیم داشت.
    تصویر زیر مجموعه این مفاهیم مطرح شده را به خوبی نشان می دهد. ماتریس سفید جمله ورودی ما است که یک جمله 7 کلمه ای با ابعاد تعبیه متن 5 است. بر روی این ورودی دو فیلتر با طول 4، دو فیلتر با طول 3 و دو فیلتر با طول 2 اعمال می شود. نتیجه حاصل از هر یک از فیلترها به صورت یک بردار در مرحله بعد نشان داده شده است. به این بردار نقشه ویژگی17 می گویند. در مرحله بعد maxpooling روی هر نقشه ویژگی اعمال می شود و بزرگترین مقدار بردار را برمی گرداند و نتایج آنها به هم متصل می شود و یک بردار به طول شش حاصل می شود. در نهایت یک تابع softmax روی کل بردار اعمال می شود و نتیجه کلاس بندی را به ما می دهد.[8][13]

معماری یک شبکه دسته بندی جمله. این مدل شامل لایه های پیچشی، pooling ، softmax و dropout است


۱.۱.۵. معماری شبکه

با دانستن مفاهیم بخش قبل، معرفی معماری شبکه بسیار ساده خواهد بود. ورودی مدل، به ازای هر جمله ی n کلمه ای، یک ماتریس n * k است که k ابعاد تعبیه متن به کار رفته است. این ماتریس از پشت سر هم قرار گرفتن18 بردار کلمات جمله یعنی { x }_{ i } های 1 تا n ساخته شده است که به صورت زیر نمایش داده می شود:

x_{1:n} = x_{1} \bigoplus x_{2} \bigoplus ... \bigoplus x_{n}

بر روی این لایه ورودی یک لایه پیچشی اعمال می شود که شامل فیلترهایی مثل w با اندازه h * k است. دقت کنید که طول فیلترها با اندازه تعبیه متن به کار رفته برابر است و تفاوت آنها در h (ارتفاع فیلترها) است. پس این فیلترها تنها در یک جهت بر روی ماتریس ورودی جا به جا می شوند. خروجی حاصل از اعمال این فیلترها، i ویژگی است که با فرمول زیر محاسبه می شوند:
c_{i} = f(w. x_{i:i+h-1} + b)

که در حقیقت f یک تابع فعال ساز غیر خطی است. با اعمال فیلتر ها به همه قاب های ممکن نقشه ی ویژگی به صورت زیر به دست می آید:
c = [ c_{1}, c_{2}, ... , c_{n-h+1}]

لایه بعد یک لایه max-pooling است که با اعمال بر روی هر نقشه ویژگی، بزرگترین مقدار آن بردار را انتخاب می کند. به عبارت دیگر خروجی این تابع \hat{c} = max \big\{c\big\} است. در نهایت بردار حاصل از این مرحله به یک لایه کاملا متصل وارد می شود و dropout و softmax روی آن اعمال می شود تا خروجی مدل یک توزیع احتمال معتبر باشد.
شکل 4 معماری مدل را به صورت نمادین به تصویر کشیده است. در بخش بعد در مورد مقادیر پارامترهای مدل، نظیر ابعاد تعبیه متن و اندازه و تعداد فیلترها توضیحاتی خواهیم داد.
شکل 4: معماری دو کاناله مورد استفاده برای دسته بندی جملات

پژوهشگر، چهار گونه متفاوت از معماری اصلی را معرفی کرده، که کلیات همه مشترک است و در جزییات با هم تفاوت هایی دارند. هر یک از این چهار نوع مدل بر روی همه مجموعه داده ها آموزش داده شده اند و نتایج بررسی شده است. این چهار مدل عبارتند از:

  • ًCNN-rand: معماری پایه + مقداردهی اولیه تصادفی به تمامی کلمات

  • ًCNN-static: معماری پایه + مقداردهی اولیه بردار کلمات به وسیله word2vec + در تمام مرحله آموزش این مقادیر ثابت اند و سایر پارامترهای مدل آپدیت می شوند.

  • ًCNN-non-static: مشابه مدل بالا + تمام مقادیر آپدیت می شوند.

  • ًCNN-multichannel: معماری پایه + استفاده از دو کانال مجزا + مقداردهی اولیه بردار کلمات هر دو کانال به وسیله word2vec + در تمام مرحله آموزش فقط مقادیر یکی از کانال ها آپدیت می شود و دیگری ثابت است.


۱.۱.۶. معرفی دادگان

مدل معرفی شده در این مقاله بر روی هفت دادگان مهم اعمال شده و نتایج به دست آمده به طور خلاصه در جدول 1 قابل مشاهده است. مجموعه های دادگان مورد استفاده عبارتند از:

  • نظرات در مورد فیلم ها (MR) : این مجموعه دادگان شامل 10662 نظر در مورد فیلم ها است که در دو کلاس مثبت و منفی دسته بندی شده اند(به طور تقریبا مساوی) این دادگان در دسترس عموم است.

  • درخت مفهومی استنفرد 1 (SST-1 ) : این مجموعه دادگان نسخه گسترش یافته دیتاست MR است که بخش آموزش، تست و ارزیابی آن به طور جداگانه ارائه شده است. این دیتاست شامل 11855 جمله است که در پنج کلاس بسیار منفی، منفی، ممتنع، مثبت و بسیار مثبت دسته بندی شده اند.

  • درخت مفهومی استنفرد 2 (SST-2 ) : مشابه نسخه قبلی با این تفاوت که نظرات ممتنع حذف شده اند. به علاوه اینکه تعداد کلاس ها به دو کلاس مثبت و منفی کاهش یافته است.

  • جملات فاعلی (Subj) : دسته بندی جملات موجود به دو گروه فاعلی و مفعولی.

  • انواع پرسش ها (TREC) : این دادگان شامل پرسش هایی است که در 6 گروه دسته بندی شده اند. کلاس های موجود عبارتند از: افراد، اماکن، اعداد، توصیفات، ابزارها و موجودیت ها. تعداد کل پرسش های این مجموعه 5952 سوال است.

  • نظرات مشتریان (CR): این مجموعه دادگان شامل نظرات کاربران در مورد محصولاتی مثل دوربین، موبایل و... است که در دو دسته مثبت و منفی تقسیم بندی شده اند.

  • دیتاست MPQA : از این دادگان برای تشخیص مثبت یا منفی بودن نظرات کاربران استفاده می شود که شامل 10606 جمله است.

جزییات ابعاد این مجموعه دادگان را می توانید در جدول زیر مشاهده کنید. c تعداد کلاس ها، l متوسط طول جملات، |V| سایز دیکشنری، |{ V }_{ pre }| تعداد واژه های بردار واژگان و Test سایز دادگان تست است. CV به این مفهوم است که از روش Cross Validation استفاده شده است.

Test { V }_{ pre } V N l c Data
CV 16448 18765 10662 20 2 MR
2210 16262 17836 11855 18 5 SST-1
1821 14838 16185 9613 19 2 SST-2
CV 17913 21323 10000 23 2 Subj
500 9125 9592 5952 10 6 TREC
CV 5046 5340 3775 19 2 CR
CV 6083 6246 10606 3 2 MPQA

جدول 1: اطلاعات مربوط به مجموعه دادگان

  • ًword2vec
    علاوه بر مجموعه دادگان ذکر شده، بهتر است توضیحاتی نیز در مورد بردار واژگان از پیش آموزش دیده word2vec مطرح کنیم. این پروژه توسط گوگل راه اندازی شده و با استفاده از پیکره های عظیم موجود اموزش دیده و بازنمایش برداری تعداد زیادی از کلمات را ارائه می دهد. بردارهای از پیش آموزش دیده این پژوهش در دسترس عموم است و می توان آنها را در بسیاری از کارهای NLP به کار برد. [14][15][16]
    اگر با استفاده از روش های کاهش ابعاد، بردار چند بعدی کلمات را در صفحه دو بعدی نمایش دهیم خواهیم دید که بسیاری از معانی موجود در واژگان را می توان در روابط بین بردارها نیز مشاهده کرد. مثلا رابطه بین فعل هایی با ریشه یکسان اما زمان های متفاوت و یا رابطه بین کشورها و پایتخت آنها. به تصویر زیر توجه کنید. شرح بیشتر این مبحث از چهارچوب این گزارش خارج است توصیه می شود برای مطالعه بیشتر در این حوزه به منابع انتهای گزارش رجوع شود.

    شکل 5: ارتباط بین واژگان در فضای برداری


۱.۱.۷. آموزش شبکه

برای تمامی دادگان به کار رفته در این پژوهش، مقادیر پارامترها به شرح زیر است:

  • اندازه فیلترها 3، 4 و 5 که هر یک از فیلترها با 100 وزن مختلف به کار رفته اند(مجموعا 300 نقشه ویژگی)

  • نرح dropout برابر 0.5

  • اندازه هر mini-batch برابر 50

  • برای دادگانی که مجموعه تست مجزا ندارند، 10 درصد از داده ها برای تست انتخاب شده است.(CV که پیش تر در بخش معرفی دادگان به آن اشاره شد)

  • در مرحله آموزش برای به روز کردن وزن ها از SGD 19و قاعده Adaddelta استفاده شده است.

  • تابع فعال ساز RELU در تمام لایه ها (به جز لایه آخر)

  • نرخ آموزش20 0.03


۱.۱.۸. پیاده سازی

پیاده سازی اصلی مقاله مورد بحث به زبان پایتون و با استفاده از ورژن 0.7 تیانو21 توسط شخص نویسنده انجام شده است. پس از انتشار مقاله، پیاده سازی های متفاوت دیگری با استفاده از ابزار های تنسورفلو22 و تورچ23 انجام شده که سورس کد آنها نیز در دسترس است.
نکته قابل ذکر دیگر اینکه در زمان انجام این پژوهش به دلیل عدم دسترسی محقق به GPU برخی مسائل از جمله تاثیر استفاده از تعبیه متن های دیگر مثل GloVe ، تاثیر اندازه و تعداد فیلترهای مختلف و k-max pooling بر عملکرد مدل بررسی نشده است. در سال 2015 در مقاله دیگری توسط ژانگ به بررسی دقیق تر این موارد پرداخته شده است . در دو جدول زیر نمونه هایی از این بررسی های تکمیلی ارائه شده است. برای جزییات دقیق تر به مرجع [13] مراجعه کنید.

non-static word2vec+GloVe-CNN non-static GloVe-CNN non-static word2vec-CNN Dataset
81.02 81.03 81.24 MR
45.98 45.65 47.08 SST-1
85.45 85.22 85.49 SST-2
93.66 93.64 93.20 Subj
91.37 90.38 91.54 TREC
84.65 84.33 83.92 CR
89.55 89.57 89.32 MPQA

جدول 2: تاثیر استفاده از بردارهای تعبیه متن مختلف word2vec و GloVe

Accuracy Multiple Region Size
81.65 (7)
81.24 (3,4,5)
81.28 (4,5,6)
81.57 (5,6,7)
81.69 (7,8,9)
81.52 (10,11,12)
81.53 (11,12,13)
81.43 (3,4,5,6)
81.62 (6,7,8,9)
81.63 (7,7,7)
81.73 (7,7,7,7)

جدول 3: تاثیر استفاده از فیلترهایی با اندازه و تعداد مختلف بر روی دقت مدل بر مجموعه دادگان MR


۱.۱.۹. نتایج

جدول زیر دقت حاصل از مدل فعلی را نشان می دهد و مقایسه بین این نتایج با مدل های پیشین نشان از برتری روش ما دارد . از این جدول می توان نتیجه گرفت که استفاده از بردارهای از پیش آموزش دیده می تواند منجر به بهبود نتایج شود.

Model MR SST-1 SST-2 Subj TREC CR MPQA
CNN-rand 76.1 45.0 82.7 89.6 91.2 79.8 83.4
CNN-static 81.0 45.5 86.8 93.0 92.8 84.7 89.6
CNN-non-static 81.5 48.0 87.2 93.4 93.6 84.3 89.5
CNN-multichannel 81.1 47.4 88.1 93.2 92.2 85.0 89.4
RAE 77.7 43.2 82.4 - - - 86.4
MV-RNN 79.0 44.4 82.9 - - - -
RNTN - 45.7 85.4 - - - -
DCNN - 48.5 86.8 - 93.0 - -
Paragraph-Vec - 48.7 87.8 - - - -
CCAE 77.8 - - - - - 87.2
Sent-Parser 79.5 - - - - - 86.3
NBSVM 79.4 - - 93.2 - 81.8 86.3
MNB 79.0 - - 93.6 - 80.0 86.3
G-Dropout 79.0 - - 93.4 - 82.1 86.1
F-Dropout 79.1 - - 93.6 - 81.9 86.3
Tree-CRF 77.3 - - - - 81.4 86.1
CRF-PR - - - - - 82.7 -
SVMs - - - - 95.0 - -

جدول 4: اطلاعات مربوط به دقت مدل های پیشنهادی و مقایسه آنها با مدل های پیشین

همان گونه که در جدول فوق مشاهده می شود مدل CNN-rand به تنهایی عملکرد چندان خوبی ندارد در حالی که مدل هایی که از بردارهای از پیش اموزش دیده استفاده کرده اند عملکرد بهتری دارند. در ادامه نتایج حاصله در دو گروه بررسی می شوند. اول مقایسه مدل های تک کاناله و چند کاناله24 و سپس مقایسه مدل های ایستا25 و غیرایستا.

  • تک کاناله در مقابل چند کاناله
    فرض اولیه ما بر این بود که مدل چندکاناله با جلوگیری از بیش برازش بهتر از مدل یک کاناله عمل می کند. به خصوص در مجموعه دادگانی با حجم کم. اما طبق نتایج به دست آمده این برتری خیلی قاطعانه نیست.

  • ایستا در مقابل غیر ایستا
    در مدل های غیر ایستا بردارهای واژگان در جریان آموزش آپدیت می شوند. به عنوان مثال شبیه ترین کلمات به بردار کلمه good در حالت ایستا کلمات great, bad, terrific و decent هستند در حالی که بعد از تکمیل آموزش شبیه ترین کلمات به آن nice, decent, solid و terrific هستند. از نظر مفهومی نیز کلمه good بیشتر به کلمه nice شباهت دارد تا great و این موضوع در نتایج حاصله مشهود است. همچنین در مورد کلمه bad درحالت ایستا good, terrible, horrible و lousy و در حالت غیرایستا کلمات terrible, horrible, lousy و stupid به عنوان شبیه ترین بردار به دست می آیند.


۱.۲. بخش دوم: پیاده سازی

در این بخش سعی داریم جزییاتی از پیاده سازی مقاله که به زبان پایتون و با استفاده از تنسورفلو انجام شده است را مختصرا شرح دهیم. سورس کد در این لینک در دسترس است. نحوه اجرای کد و لود کردن دادگان در لینک ذکر شده است و ما از بیان مجدد آن خودداری می کنیم.

۱.۲.۱. پیش پردازش داده

این بخش شامل 4 فعالیت اصلی است:

  • لود کردن داده های مثبت و منفی از متن خام دادگان.

  • تفکیک جملات، تبدیل حروف بزرگ به حروف کوچک، تفکیک وازگان، جداسازی علائم نگارشی و حذف فواصل بیش از دوتا که به مجموعه این اعمال اصطلاحا تمیز کردن26 داده می گویند.

  • تشخیص بلندترین جمله و افزودن توکن های pad به انتهای جملات کوتاه تر به منظور نرمال شدن طول تمام جملات.

  • ساخت مجموعه دیکشنری و تخصیص دادن یک شناسه متناسب برای هر کلمه. بدین ترتیب هر کلمه به صورت بردار one-hot در می اید.

۱.۲.۲. پیاده سازی مدل

همان گونه که در کد زیر مشاهده می کنید تعریف مدل ما در کلاس TextCNN انجام شده که پارامترهای مورد نیاز ورودی را دریافت می کند:

  • ً sequence_length :طول جملات که 59 است. همان گونه که پیش تر بیان شد، همه جملات را در مرحله پیش پردازش با افزودن توکن هایی، هم اندازه ی بلندترین جمله کردیم.

  • ًnum_classes :تعداد کلاس ها. که دو کلاس مثبت و منفی است.

  • ًvocab_size :اندازه دیکشنری. که در این دادگان 18765 است.

  • ًembedding_size : ابعاد تعبیه متن که 128 در نظر گرفته شده است.

  • ًfilter_sizes :ما از سه اندازه [3, 4, 5] استفاده کردیم.

  • ًnum_filters :تعداد فیلترها از هر اندازه 128 تا است.

برای تعریف متغیرها در تنسورفلو از دو مفهوم استفاده می شود: variable و placeholder . مورد اول برای تعریف پارامتر و مقدار دهی به آن استفاده می شود. placeholder ها زمانی استفاده می شوند که می خواهیم پارامترهایی را تعریف کنیم و در زمان اجرا27 مقادیر انها را مشخص کنیم. placeholder معمولا برای ورودی و خروجی و برچسب ها استفاده می شود. variable برای ماتریس وزن ها و بایاس و سایر پارامترها. در این بخش کد برای جملات ورودی و برچسب داده ها از placeholder استفاده شده است. همچنین برای مقدار احتمال تابع dropout که به صورت پیش فرض 0.5 در نظر گرفته شده است.

class TextCNN(object):
   def __init__(
      self, sequence_length, num_classes, vocab_size,
      embedding_size, filter_sizes, num_filters, l2_reg_lambda=0.0):
      self.input_x = tf.placeholder(tf.int32, [None, sequence_length], name="input_x")
     self.input_y = tf.placeholder(tf.float32, [None, num_classes], name="input_y")
     self.dropout_keep_prob = tf.placeholder(tf.float32, name="dropout_keep_prob")
  • ً(device("/cpu:0" : به طور پیش فرض تنسورفلو سعی می کند در صورت وجود GPU عمل ها را بر روی آن اجرا کند اما این دستور به ما اجازه می دهد که کد را بر روی cpu اجرا کنیم.

  • ًtf.name_scope : این تابع به ما این امکان را می دهد که تمام اعمال مرتبط با لایه embedding را در سوپرنودی 28 قرار دهیم به نام embedding . نتیجه این کار به ما ساختاری سلسله مراتبی 29 می دهد که در زمان مصور کردن 30 مدل و نتایج بسیار مفید است. مصورسازی در محیطی به نام تنسوربورد31 انجام می شود.

  • ًW : این متغیر ماتریس تعبیه متن مدل ماست که در طول فرایند آموزش یاد گرفته می شود.
    نتیجه لایه تعبیه متن تنسوری با ابعاد [None, sequence_length, embedding_size, 1] است.

with tf.device('/cpu:0'), tf.name_scope("embedding"):
        self.W = tf.Variable(
            tf.random_uniform([vocab_size, embedding_size], -1.0, 1.0),
            name="W")
        self.embedded_chars = tf.nn.embedding_lookup(self.W, self.input_x)
        self.embedded_chars_expanded = tf.expand_dims(self.embedded_chars, -1)

به منظور ساخت لایه پیچشی از conv2d استفاده می کنیم.در اینجا w ماتریس فیلتر ما و h نتیجه اعمال یک تابع غیرخطی بر خروجی لایه پیچشی است. خروجی این مرحله تنسوری با ابعاد [1, sequence_length - filter_size + 1, 1, 1] است. اعمال لایه max-pooling بر روی این خروجی تنسوری با ابعاد [batch_size, 1, 1, num_filters] نتیجه می دهد. چنین ماتریسی برای هر فیلتری به دست می آید و با ترکیب آنها به یک بردار با ابعاد [batch_size, num_filters_total] می رسیم.

pooled_outputs = []
    for i, filter_size in enumerate(filter_sizes):
        with tf.name_scope("conv-maxpool-%s" % filter_size):
            # Convolution Layer
            filter_shape = [filter_size, embedding_size, 1, num_filters]
            W = tf.Variable(tf.truncated_normal(filter_shape, stddev=0.1), name="W")
            b = tf.Variable(tf.constant(0.1, shape=[num_filters]), name="b")
            conv = tf.nn.conv2d(
                self.embedded_chars_expanded,
                W,
                strides=[1, 1, 1, 1],
                padding="VALID",
                name="conv")
            # Apply nonlinearity
            h = tf.nn.relu(tf.nn.bias_add(conv, b), name="relu")
            # Maxpooling over the outputs
            # h --> 4d
            pooled = tf.nn.max_pool(
                h,
                ksize=[1, sequence_length - filter_size + 1, 1, 1],
                strides=[1, 1, 1, 1],
                padding='VALID',
                name="pool")
            pooled_outputs.append(pooled)
    # Combine all the pooled features
    num_filters_total = num_filters * len(filter_sizes)
    self.h_pool = tf.concat(pooled_outputs, 3)
    self.h_pool_flat = tf.reshape(self.h_pool, [-1, num_filters_total])

برای اعمال لایه dropout تنها لازم است احتمال فعال بودن هر نورون را به عنوان ورودی به تابع tf.nn.dropout بدهیم که به طور پیش فرض 0.5 در نظر گرفته شده است. توجه کنید که این مقدار در هنگام تست 1 قرار می گیرد. به عبارتی تمام نورون ها در مرحله تست فعال اند و نورون غیرفعالی نداریم.

with tf.name_scope("dropout"):
        self.h_drop = tf.nn.dropout(self.h_pool_flat, self.dropout_keep_prob)

با ضرب کردن ماتریس ورودی در وزن ها و جمع آن با بایاس می توانیم برای هر داده مقداری به نام امتیاز32 محاسبه کنیم و برچسب کلاسی پیش بینی کنیم. (بزرگترین مقدار امتیاز می شود برچسب کلاس) همچنین می توان با استفاده از تابع softmax مقادیر امتیاز را به احتمال تبدیل کرد.

with tf.name_scope("output"):
        W = tf.get_variable(
            "W",
            shape=[num_filters_total, num_classes],
            initializer=tf.contrib.layers.xavier_initializer())
        b = tf.Variable(tf.constant(0.1, shape=[num_classes]), name="b")
        self.scores = tf.nn.xw_plus_b(self.h_drop, W, b, name="scores")
        self.predictions = tf.argmax(self.scores, 1, name="predictions")

با استفاده از مقادیر امتیاز محاسبه شده در بخش قبل مقدار زیان 33 را حساب می کنیم. زیان در حقیقت همان خطای شبکه ما است که سعی داریم مقدار آن را کمینه کنیم. در پیاده سازی حاضر از تابع زیان cross-entropy استفاده شده است. که برای هر کلاس مقدار زیان را محاسبه می کند و از نتایج میانگین میگیرد.
همچنین تعریف و محاسبه پارامتری به نام دقت34 و دنبال کردن مقادیر آن در طول پروسه آموزش می تواند مفید باشد.

with tf.name_scope("loss"):
        losses = tf.nn.softmax_cross_entropy_with_logits(logits=self.scores, labels=self.input_y)
        self.loss = tf.reduce_mean(losses) + l2_reg_lambda * l2_loss
with tf.name_scope("accuracy"):
        correct_predictions = tf.equal(self.predictions, tf.argmax(self.input_y, 1))
        self.accuracy = tf.reduce_mean(tf.cast(correct_predictions, "float"), name="accuracy")

۱.۲.۳. روند آموزش

تنسورفلو برای اجرای مدل از session استفاده می کند. هر session یک گراف را اجرا می کند. هر گراف شامل عمل ها 35 و تنسورهایی است. عمل ها همان نودهای گراف و تنسورها یال های آن هستند.

  • ًallow_soft_placement :اگر این گزینه فعال نباشد اجرای کد بر روی ماشینی بدون gpu می تواند منتج به خطا شود.

  • ًlog_device_placement : با فعال بودن این گزینه می توانیم تعیین کنیم اعمال ما بر روی چه دیوایسی اجرا شوند(cpu یا gpu).

with tf.Graph().as_default():
session_conf = tf.ConfigProto(
  allow_soft_placement=FLAGS.allow_soft_placement,
  log_device_placement=FLAGS.log_device_placement)
sess = tf.Session(config=session_conf)

سپس مقادیر شبکه مورد نظر ما تعیین می شوند و گراف ساخته می شود:

cnn = TextCNN(
        sequence_length=x_train.shape[1],
        num_classes=y_train.shape[1],
        vocab_size=len(vocab_processor.vocabulary_),
        embedding_size=FLAGS.embedding_dim,
        filter_sizes=list(map(int, FLAGS.filter_sizes.split(","))),
        num_filters=FLAGS.num_filters,
        l2_reg_lambda=FLAGS.l2_reg_lambda)

در مرحله بعد لازم است مشخص کنیم که برای بهینه سازی تابع زیان از چه روشی استفاده شود. ما از adam استفاده کرده ایم که در عمل هم بسیار خوب کار می کند. در اینجا train_op برای اعمال به روز رسانی وزن ها بر حسب مقادیر گرادیان های محاسبه شده تعریف شده است. در حقیقت هر بار اجرای train_op حکم یک گام در آموزش36 را دارد.
متغیر global_step این امکان را فراهم می سازد تا تنسورفلو به صورت اتوماتیک گام های آموزش را بشمارد. global_step با هر بار اجرای train_op یک واحد افزایش می یابد.

global_step = tf.Variable(0, name="global_step", trainable=False)
    optimizer = tf.train.AdamOptimizer(1e-3)
    grads_and_vars = optimizer.compute_gradients(cnn.loss)
    train_op = optimizer.apply_gradients(grads_and_vars, global_step=global_step)

یکی از مفاهیم کاربردی در تنسورفلو خلاصه برداری 37 است که به ما این امکان را می دهد تا مقادیر پارامترهای مهم را ذخیره و دنبال کنیم و آنها را مصور کنیم. نحوه استفاده از این امکان در قطعه کد زیر نمایش داده شده است.

# Summaries for loss and accuracy
    loss_summary = tf.summary.scalar("loss", cnn.loss)
    acc_summary = tf.summary.scalar("accuracy", cnn.accuracy)
    # Train Summaries
    train_summary_op = tf.summary.merge([loss_summary, acc_summary, grad_summaries_merged])
    train_summary_dir = os.path.join(out_dir, "summaries", "train")
    train_summary_writer = tf.summary.FileWriter(train_summary_dir, sess.graph)

مفهوم کاربردی دیگر مبحث نشان گذاری 38 است که در آن پارامترهای مدل ذخیره می شوند تا در آینده آموزش را از آن نقطه ادامه دهیم. نحوه استفاده از این امکان در قطعه کد زیر نمایش داده شده است.

# Checkpoint directory. Tensorflow assumes this directory already exists so we need to create it
    checkpoint_dir = os.path.abspath(os.path.join(out_dir, "checkpoints"))
    checkpoint_prefix = os.path.join(checkpoint_dir, "model")
    if not os.path.exists(checkpoint_dir):
        os.makedirs(checkpoint_dir)
    saver = tf.train.Saver(tf.global_variables(), max_to_keep=FLAGS.num_checkpoints)

پیش از این که بتوانیم مدل را اجرا کنیم نیاز داریم تا تمام مقداردهنده ها 39 را فعال کنیم و مقادیر اولیه پارامترها تخصیص داده شوند. این عمل با دستور زیر انجام می شود:

sess.run(tf.global_variables_initializer())

حال نیاز داریم هر یک گام آموزش را تعریف کنیم. هر گام شامل لود کردن یک بچ از دادگان، اجرای مدل بر روی دیتا، محاسبات تابع زیان و به روز رسانی مقادیر پارامترهاست.

def train_step(x_batch, y_batch):
        """
        A single training step
        """
        feed_dict = {
          cnn.input_x: x_batch,
          cnn.input_y: y_batch,
          cnn.dropout_keep_prob: FLAGS.dropout_keep_prob
        }
        _, step, summaries, loss, accuracy = sess.run(
            [train_op, global_step, train_summary_op, cnn.loss, cnn.accuracy],
            feed_dict)
        time_str = datetime.datetime.now().isoformat()
        print("{}: step {}, loss {:g}, acc {:g}".format(time_str, step, loss, accuracy))
        train_summary_writer.add_summary(summaries, step)

بعد از تعریف هر گام آموزش باید حلقه آموزش را تعریف کنیم. این حلقه شامل گردش بر روی بچ های مختلف داده و اجرای یک گام در هر بار است. در گام های خاصی از حلقه هم نیاز به خلاصه برداری یا نشان گذاری وجود دارد که در حلقه به انها اشاره شده است.

for batch in batches:
        x_batch, y_batch = zip(*batch)
        train_step(x_batch, y_batch)
        current_step = tf.train.global_step(sess, global_step)
        if current_step % FLAGS.evaluate_every == 0:
            print("\nEvaluation:")
            dev_step(x_dev, y_dev, writer=dev_summary_writer)
            print("")
        if current_step % FLAGS.checkpoint_every == 0:
            path = saver.save(sess, checkpoint_prefix, global_step=current_step)
            print("Saved model checkpoint to {}\n".format(path))

۱.۲.۴. مصورسازی

پس از آموزش مدل با پارامترهای پیش فرض بر روی داده های MR نمودار مقادیر تابع زیان و همچنین دقت به شکل زیر است. خط آبی مربوط به آموزش و خط قرمز مربوط به تست است. با توجه به اینکه مقدار دقت تست بسیار کمتر از دقت آموزش است می توان نتیجه گرفت که بیش برازش[^overfit] رخ داده است.

نمودار تغییرات مقدار تابع زیان

نمودار تغییرات دقت


۱.۳. مراجع

[1] Joachims, Thorsten. Learning to classify text using support vector machines: Methods, theory and algorithms. Kluwer Academic Publishers, 2002.
[2] Chen, Jingnian, Houkuan Huang, Shengfeng Tian, and Youli Qu. "Feature selection for text classification with Naïve Bayes." Expert Systems with Applications 36, no. 3 (2009): 5432-5435.
[3] Mikolov, Tomas, Ilya Sutskever, Kai Chen, Greg S. Corrado, and Jeff Dean. "Distributed representations of words and phrases and their compositionality." In Advances in neural information processing systems, pp. 3111-3119. 2013.
[4]Pennington, Jeffrey, Richard Socher, and Christopher Manning. "Glove: Global vectors for word representation." In Proceedings of the 2014 conference on empirical methods in natural language processing (EMNLP), pp. 1532-1543. 2014.
[5]W. Yih, X. He, C. Meek. 2014. Semantic Parsing for Single-Relation Question Answering. In Proceedings
of ACL 2014
.
[6]Y. Shen, X. He, J. Gao, L. Deng, G. Mesnil. 2014. Learning Semantic Representations Using Convolutional Neural Networks forWeb Search. In Proceedings of WWW 2014.
[7]N. Kalchbrenner, E. Grefenstette, P. Blunsom. 2014. A Convolutional Neural Network for Modelling Sentences. In Proceedings of ACL 2014.
[8][Online]. Available: http://www.wildml.com/2015/11/understanding-convolutional-neural-networks-for-nlp/. [Accessed 20 12 2017].
[9][Online]. Available: https://adeshpande3.github.io/A-Beginner%27s-Guide-To-Understanding-Convolutional-Neural-Networks-Part-2/. [Accessed 20 12 2017].
[10]Srivastava, Nitish, Geoffrey E. Hinton, Alex Krizhevsky, Ilya Sutskever, and Ruslan Salakhutdinov. "Dropout: a simple way to prevent neural networks from overfitting." Journal of machine learning research 15, no. 1 (2014): 1929-1958.
"Github,"[Online]. Available: http://cs231n.github.io/linear-classify/#softmax.[Accessed 20 12 2017].[11]
[12][Online]. Available: https://en.wikipedia.org/wiki/Softmax_function.. [Accessed 20 12 2017].
[13]Zhang, Ye, and Byron Wallace. "A sensitivity analysis of (and practitioners' guide to) convolutional neural networks for sentence classification." arXiv preprint arXiv:1510.03820(2015).
[14] "Github," [Online]. Available: https://github.com/dav/word2vec. [Accessed 20 12 2017].
[15][Online]. Available: https://blog.acolyer.org/2016/04/21/the-amazing-power-of-word-vectors/. [Accessed 20 12 2017].
[16][Online]. Available: https://code.google.com/archive/p/word2vec/. [Accessed 20 12 2017].


  1. Text Classification

  2. Spam

  3. Support Vector Machine (SVM)

  4. Sentence Classification

  5. Pretrained

  6. local feature

  7. Sentence Modeling

  8. Semantic Parsing

  9. Query Retrieval

  10. Kernel

  11. Feature extractor

  12. Activation Function

  13. subsampling

  14. fully-connected

  15. overfit

  16. view

  17. Feature map

  18. concatenate

  19. Stochastic Gradient Descend

  20. Learning Rate

  21. Theano

  22. Tensorflow

  23. Torch

  24. multichannel

  25. static

  26. data cleaning

  27. execute

  28. top-level node

  29. hierarchy

  30. visualize

  31. TensorBoard

  32. score

  33. loss

  34. accuracy

  35. operations

  36. training step

  37. summary

  38. checkpointing

  39. initializer