مجموعه داده ای هدی

هدف این پروژه در ابتدا دسته بندی انواع مختلف اعداد دست نویس فارسی بر اساس شکل ظاهری و سپس طبقه‌بندی ارقام دستنویس ورودی به مشابه ترین گروه به منظور تشخیص رقم مربوطه است. برای دسته بندی ها از مجموعه ارقام دست نویس فارسی تهیه شده تا کنون بهره برده می شود و برای تشخیص شباهت عدد ورودی به هر کدام از دسته ها می‌توان از هریک از روش‌های طبقه‌بندی استفاده کرد. در این پروژه چند روش برای طبقه‌بندی ارقام که به نظر مناسب‌تر هستند بررسی و مقایسه شوند.

۱. مقدمه

اگر یک تصویر از عدد فارسی " ۷ " را - فارغ از خوش خط یا بد خط بودن نویسنده - درمقابل ما بگیرند و از ما بخواهد که تشخیص دهیم که این عدد کدام‌ یک از
اعداد را نشان می دهد ، پاسخ به این برای ما - انسان ها - بسیار آسان خواهد بود. اما اگر از ما بخواهند دو عدد ۳ رقمی را در هم ضربکنیم برای محاسبه آن احتمالا به زمان قابل توجهی و یک قلم و کاعذ نیاز خواهیم داشت. حال فرض کنیم یک ماشین در مقابل همین ۲ پرسش قرار گیرد. محاسبه ضرب دو عدد برای یک ماشین یک سوال بسیار آسان است در حالی که برای یک انسان بسیار زمان بر است. و در عین حال فهمیدن و تشخیص حرف " گ " برای یک ماشین (موجودیتی که تنها صفر و یک میفهمد) و تنها می‌تواند یک درک داده ای و سطح پایین از یک تصویر بر اساس رنگ ها و پیکسل هایش داشته باشد یک کار بسیار دشوار است.
تفاوت اصلی در نوع حل مساله در انسان ها و ماشین ها است. ماشین ها توانایی بسیار زیادی در محاسبه دارند اما انسان ها توانایی بسیار بالایی در یادگیری. نکته دیگری که از این مقایسه قابل برداشت است این است که یک انسان در نهایت می‌تواند حاصل ضرب دو عدد را محاسبه کند اما آیا یک مایشن هم تنها با تکیه بر قابلیت های محاسبه ای خود می‌تواند یک نوشته را بخواند؟ واقعیت این است نوشتن یک الگوریتم برای انجام عمل خواندن متن و تشخیص صحیح تک تک کاراکتر های آن، حداقل تا به امروز برای ما به عنوان برنامه ریز های ماشین ها امکان پذیر نبوده. علاوه بر این موضوع باید توجه داشت که توانایی یاد گرفتن عامل اصلی برتری انسان بر ماشین می‌باشد و همین موضوع ، یعنی قابلیت یادگیری انسان موجب شده که بتواند یک ضرب بسیار سخت را در نهایت انجام دهد اما یک کامپیوتر در یک زمان معقول نتواند به تنهایی یک حرف را تشخیص دهد. نتیجه کلی مقایسه بالا این کلیّت را در بر دارد که برای حل برخی از مسایل پیچیده باید به دنبال دسته ای کلی از الگوریتم ها باشیم که به کامپیوتر توانایی یادگیری آن مساله را ببخشد ، نه توانایی صرفا حل آنرا ، دقیقا مشابه مغز انسان.
این دسته از الگوریتم ها به الگوریتم های یادگیری ماشین (Machine Learning) معروف هستند.
یادگیری عمیق (Deep Learning) شاخه ای از این الگوریتم ها هستند که برای حل اینگونه مسایل استفاده میشوند.در یادگیری عمیق امید به جایگزینی استخراج ویژگی‌های تصویر به دست بشر با روش‌های کاملا خودکار بدون نظارت انسان وجود دارد. انگیزهٔ نخستین در بوجود آمدن این ساختار یادگیری از راه بررسی
ساختار عصبی در مغز انسان الهام گرفته شده است که در آن یاخته‌های عصبی با فرستادن پیام به یکدیگر درک را امکان‌پذیر می‌کنند.[1]
بسته به فرض‌های گوناگون در مورد نحوهٔ اتصال این یاخته‌های عصبی، مدل‌ها و ساختارهای مختلفی در این حوزه پیشنهاد و بررسی شده‌اند، هرچند که این مدل‌ها به صورت طبیعی در مغز انسان وجود ندارد و مغز انسان پیچیدگی‌های بیشتری را دارا است. این مدل‌ها نظیر شبکه عصبی عمیق(Deep Neural Network) و شبکه عصبی پیچیده (Convolutional Neural Network) پیشرفت‌های خوبی را در حوزه‌های پردازش زبان‌های طبیعی و پردازش تصویر ایجاد کرده‌اند.در حقیقت عبارت یادگیری عمیق، بررسی روش‌های تازه برای شبکه عصبی مصنوعی (Artificial Neural Network) است.[2]
ایده ی پشت حل این مسئله این است که تعداد زیادی از اعداد دست نوشته ( مثال های یادگیری) و سیستم ای که از این مثال ها یاد بگیرد را داسته باشیم . به عبارت دیگر شبکه عصبی مصنوعی از این مثال ها استفاده میکند تا اعداد دست نوشته را تشخیص دهد . هرچه تعداد مثال های دست نوشته بیشتر شود تشخیص‌ کامپیوتر بهتر و دقیق تر می شود .

۲. کارهای مرتبط

برای شروع ، نورون (neuron ) مصنوعی به نام پرسپترون (perceptron) را توضیخ می دهم. یک پرسپترون تعدادی ورودی باینری مثل x1 ، x2 ، ... دریافت میکند و یک خروجی باینری را تولید میکند. محققین برای محاسبه ی خروجی یک متغیر به اسم وزن (weight) تعریف کرده اند . W1 ، w2، ... به ترتیب میزان اهمیت هر ورودی را مشخص میکنند . خروجی‌ هر نورون با فرمول سیگما به دست می آید . به این صورت که اگر از مقدار آستانه (threshold) بیشتر باشد عدد ۱ و اگر‌ کمتر باشد عدد ۰ را بر میگرداند .

به نظر محتمل می‌آید که یک شبکه پیچیده از پرسپترون ها خروجی تقریباً دقیقی را تولید کنند . وزن هر ورودی در تعیین خروجی نقش بسیار مهمی دارد. به این صورت که در دفعه ی اول به صورت رندوم انتخاب وزن برای هر ورودی انجام می شود. در دفعات آینده با توجه به درست یا غلط بودن خروجی ، وزن ها با یک فرمول ریاضی تغییر پیدا میکنند . این تغییر انقدر انجام میشود تا وزن ها طوری باشند که خروجی صحت داشته باشد.

در این شبکه ، ستون اول پرسپترون ها ( که به آن لایه ی اول پرسپترون ها میگوییم) با در نظر گرفتن وزن هر ورودی تصمیم ساده ای را اتخاذ میکنند . پرسپترون ها در‌ لایه ی دوم با توجه به وزن خروجی بدست آمده از لایه ی اول خروجی را تعیین میکنند .
لایه ی دوم در حالت پیچیده تری نسبت به لایه ی اول تصمیم میگیرد و خروجی ای‌ نزدیک به واقعیت تولید میکند .
و در لایه ی سوم تصمیم گیری پیچیده تر و خروجی بیشتر به واقعیت نزدیک میشود.
با این روش پرسپترون هایی با تعداد لایه ی زیاد می توانند تصمیمات پیچیده تری را بگیرند.
حال میخواهیم توضیحاتی را که در‌ مورد پرسپترون ها دادیم ساده کنیم. اولین تغییر این است که به جای سیگما مینویسیم w.x .
تغییر دوم این است که عدد آستانه (threshold) را به طرف دیگر تساوی انتقال میدهیم و با چیزی که به عنوان perceptron bias ، شناخته میشود جایگزین می کنیم . (Bias = -threshold ) . نا مساوی را به صورت زیر بازنویسی میکنیم :


در این بخش سیگموید (sigmoid) را معرفی‌ میکنیم که بسیار شبیه به پرسپترون است. سیگموید هم درست مثل پرسپترون تعدادی وروذی دارد که بر عکس پرسپترون فقط‌ ۰ و ۱ را قبول نمی‌کند و هر عددی بین ۰ و ۱ را قبول میکند. همینطور مشابه پرسپترون ، نورونِ سیگموید هم برای هر ورودی وزن تعیین میکند و bias دارد . خروجی این نورون فقط ۰ یا ۱ نیست و تمامی اعداد بین ۰ و ۱ می‌تواند باشد . تابع سیگموید به صورت زیر تعریف میشود :


همواری تابع سیگموید است که بسیار حیاتی‌ است نه فرم دقیق آن . منظور از همواری سیگموید این است که با هر تغییر کوچک wj و bias تغییر کمی در خروجی نورون اتفاق می افتد .
چگونه از نورون سیگموید خروجی استخراج کنیم؟ به طور مشخص یک تفاوت بزرگ بین نورون های پرسپترون و سیگموید این است که خروجی‌ نورون های سیگموید فقط ۰ و ۱ نیست. هر خروجی ای بین ۰ و ۱ می توانند داشته باشند . این ویژگی سیگموید هم میتواند مفید باشد و هم آزار دهنده. برای مثال اگر بخواهیم تشخیص دهیم که آیا تصویر ورودی ۹ را نشان میدهد یا خیر اگر خروجی به صورت ۰ یا ۱ بود ، تشخیص‌ ساده تر میشد . اما برای تشخیص این عدد با نورونِ سیگموید باید شرط بگذاریم که اگر خروجی از ۰.۵ بیشتر بود عدد ۹ است و اگر کمتر بود عدد ۹ نیست . اگر برای تشخیص یک عدد در لایه ی آخر ۱۰ نورونِ سیگموید داشته باشیم ( هر نورون برای هر یک از ارقام ۰ تا‌ ۹ که برای هر ورودی وزن و هر نورون bias مخصوص به خود دارند ) جواب به این صورت انتخاب میشود که خروجی نورونی که از همه بزرگتر باشد . که این کار با استفاده از نورون های پرسپترون امکان پذیر نیست . ( از آنجایی که تمانی خروجی نورون های پرسپترون ۰ یا ۱ است) . [3] [4]

۳. آزمایش ها

برای پیاده سازی این پروژه از کتابخانه‌ی tensorflow استفاده شده است. یکی از دلایل استفاده از این کتابخانه سهولت مدیریت وزن‌ها و مقادیر نُرون ها در لایه‌های مختلف در شبکه‌های عصبی عمیق و یادگیری عمیق است.[5]

۳.۱. داده ها

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

۳.۲. پیاده سازی

شبکه عصبی پیاده سازی شده به شرح زیر است :
لایه‌ی ورودی دارای ۷۲۸ نرون است که به اندازه‌ی پیکسل های عکس است. سه عدد لایه‌ی مخفی پیاده سازی شده است که هر کدام ۲۵۶ نرون دارد. و در لایه‌ی آخر ۱۰ کلاس خروجی تعریف شده است که هر کدام نشانگر یکی از اعداد ۰ تا ۹ است.

نمای کلی از چیدمان لایه‌ها در شبکه

برای هر لایه ، وزن ها و bias ها به صورت تصادفی انتخاب می‌شوند و به مرور زمان در طی یادگیری وزن‌ها و bias ها طوری تنظیم می‌شوند که خروجی نزدیک به واقعیت شود و میزان خطا کمینه می‌شود.

۳.۳. توضیحات دقیق تر چگونگی پیاده سازی

هر نورون ضرب نقطه ای بین ورودی و وزن آن نرون را انجام می‌دهد و سپس با bias جمع می‌کند. خروجی بدست آمده به تابعی به نام ReLU داده می‌شود [7]. تابع ReLU به این صورت است که اگر ورودی آن از صفر کوچک تر باشد خروجی تابع صفر است و اگر ورودی آن از صفر بزرگ تر باشد خروجی برابر ورودی است.

برای اینکه چگونگی تغییر وزن ها مشخص شود باید پارامتری تعریف کنیم به نام Learning rate . برای اینکه دلیل اهمیت این پارامتر بیشتر مشخص شود نگاهی به عملکرد مغز انسان می اندازیم. همانطور که احتمالا بارها تجربه‌اش را داشته‌ایم ، هنگامی که برای اولین بار با یک مسئله‌ی جدید رو به رو می شویم حل آن مسئله به شدت دشوار به نظر می آید. در صورتی که اگر از قبل تمرین‌های ساده‌تر اما مشابه دیده بودیم حل آن مسئله آنقدر ها هم دشوار به نظر نمی رسید.
در مورد نرون ها هم همین‌گونه است باید به صورت تدریجی وزن ها تغییر کند تا به خروجی قابل اعتمادی دست یابیم. نتیجه کلی این است که:‌

در صورت کوچک بودن learning rate یادگیری قابل اعتماد تر است اما زمان بیشتری طول می‌کشد تا به کمینه تابع خطا برسیم.

با بزرگ بودن learning rate تغییرات در وزن ها بسیار زیاد می‌شود و این باعث می‌شود به تابع خطای کمینه نرسیم و جواب ها غیر‌قابل اعتماد می‌شود. در‌
این پروژه در ابتدا learning rate را ۰.۰۰۱ گذاشتیم و دیدیم که درصد درستی جواب ها ۹۲ بود. این عدد را به ۰.۰۰۴ افزایش دادیم و درصد درستی جواب به
۹۷ رسید. با افزایش این عدد به ۰.۰۰۵ درصد درستی جواب ها به ۹۴ درصد کاهش پیدا کرد.

در پیاده سازی این پروژه از تابع خطای cross-entropy استفاده شده است. این تابع صحت خروجی شبکه عصبی را می‌سنجد و فاصله‌ی آن با جواب درست را نشان می‌دهد. با استفاده از عکس ها و برچسب مربوط به هر عکس وزن ها و bias ها طوری تعیین شود که تابع خطای cross-entropy به حداقل برسد.

در پیاده سازی این پروژه از بهینه‌سازی به نام Adam استفاده شده است که در ابتدا از learning_rate تعریف شده استفاده می‌کند سپس در طی یادگیری این مقدار را تغییر می‌دهد. علاوه بر این نکته‌ی مهم این است که این تابع برای هر وزن از شبکه learning rate جدایی را اختصاص می‌دهد .به گفته‌ی نویسندگان مزایای اصلی این الگوریتم به شرح زیر است[8] :
۱- کم بودن حافظه‌ی مورد نیاز
۲- مناسب برای مسائلی که داده‌ی بزرگ دارند
۳- سادگی در پیاده سازی

در آخر برای تشخیص عدد از softmax استفاده می کنیم. تابع softmax خروجی های آخرین لایه‌ را می‌گیرد و آن‌ها را به اعدادی بین صفر و یک (مقدار احنمال یا امتیاز هر کلاس) تبدیل می‌کند و همچنین جمع تمام این اعداد ۱ می شود(عکس شماره ۱) . که ما در این جا با توجه به داشتن ۱۰ کلاسِ خروجی ۱۰ عدد بین صفر و یک داریم و از بین این اعداد بزرگترین آن‌ها معرف آن کلاس است(عکس شماره ۲).

۱

۲

نتیجه ی پیاده سازی :


همانطور که در عکس مشاهده میکنید در 30 مرحله (epoch) یادگیری صورت گرفته است .
در تصویر بالا مشاهده می کنید که 97 درصد از عکس ها درست تشخیص داده شده است.

کد مربوط به پیاده سازی این پروژه را می توانید در اینجا بیابید.

۴. بهبود نتایج

مهم ترین هدف در این بخش پیاده‌سازی سیستم با استفاده از شبکه‌های عصبی عمیق Convolutional، به همراه استفاده از مجموعه داده‌گان هدی است.

۵. کارهای آینده

۶. منابع

  1. Song,Hyun Ah, and Soo-Young Lee. "Hierarchical Representation Using NMF." Neural Information Processing. Springer Berlin Heidelberg, 2013.

  2. Ronan Collobert (May 6, 2011). "Deep Learning for Efficient Discriminative Parsing". videolectures.net. Ca. 7:45.

  3. Ian Goodfellow, Yoshua Bengio, and Aaron Courville Deep Learning

  4. http://neuralnetworksanddeeplearning.com/chap1.html

  5. http://www.tflearn.ir/1395/11/08/tensor/#

  6. http://yann.lecun.com/exdb/mnist/

  7. https://en.wikipedia.org/wiki/Rectifier_(neural_networks)

  8. Kingma, Diederik, and Jimmy Ba. "Adam: A method for stochastic optimization." arXiv preprint arXiv:1412.6980(2014).

**

۶.۱. پیوندهای مفید

رد شده

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

علیرضا نوریان

خوب هست که کدی رو پیدا کردید و عملکردش رو توضیح دادید.
بهتر بود که برای گرفتن نتایج بهتر هم تلاش می‌کردید، مثلا در همین مجموعه کدهایی که استفاده کردید، شبکه‌های convolutional رو هم برای این کار آموزش دادن.
در ضمن لطفا کدها رو در گیتهاب بذارید که بشه دید چه کردید.

رد شده

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

  1. در متن غلط املایی وجود دارد و در مواردی به نکات نگارشی توجه نشده است.

  2. بهتر است کلماتی که معادل انگلیسی آن ها در متن ذکر شده اند، در پاورقی نوشته شوند.

  3. در قسمت کارهای مرتبط، تعداد کمی الگوریتم معرفی شد و می بایست مقالات مرتبط بیشتری مطالعه می شد.