مقدمه‌ای بر شبکه‌های عصبی(2)

تا اینجا به دو مبحث درباره شبکه های عصبی پرداختیم. Activation function  برای تعیین عملکرد تابع خروجی و cost function  برای تعیین عملکرد بد شبکه. و برای بهبود عملکرد تابع مسائل بهینه سازی مطرح شد (مشتقات جزئی). اکنون به مسئله یادگیری(learning) شبکه میپردازیم.

Gradient Descent and Back-propagation

Gradient Descent

Gradient descent  یک الگوریتم بهینه سازی برای پیدا کردن مینیمم یک تابع است.

مثال : در این مسئله یک متغیر(w) داریم. و C  ، cost function  است.

یک وزن رندوم انتخاب میکنیم و مشتق c را نسبت به w محاسبه میکنیم. در نتیجه شیب به دست می آید. که جهت آن از روی علامتش مشخص می شود.

w را به سمت جهتی که به دست آوردیم، حرکت می دهیم. که در اینجا سمت راست است. یعنی باید w را بیشتر کنیم.

که با تکرار این کار در نهایت مقدار cost ، مینیمم می شود. در این نقطه مشتق یا شیب برابر با 0 است. با رسیدن به این مرحله نقطه بهینه پیدا می شود.

همان طور که دیدیم، پیدا کردن مینیمم برای فضای دو بعدی ساده بود. اما در فضاهای n بعدی این کار ساده نخواهد بود. و با شکل های پیچیده تری مواجه خواهیم شد.

پس با استفاده از gradient descent  میتوانیم بهترین پارامتر برای مینیمم کردن cost را به دست آوریم. برای مثال پیدا کردن بهترین مقادیر برای انتخاب وزن نورون های ورودی.

 

Backpropagation 

اگر شبکه بیش از دو لایه داشته باشد، فقط میتوانیم برای لایه ی آخر مشتق جزیی حساب کنیم. و برای بقیه لایه ها (لایه های وسط) این امکان را نداریم. اما میتوانیم تعیین کنیم که چه نورون هایی تاثیر بیشتری روی آنها داشته اند. به این الگوریتم backpropagation گفته می شود.

تابع cross entropy

one hot encoded

قبلا دیدیم که در شبکه تعدادی label  داشتیم. برای نشان دادن داده ی مربوط به آن label  به جای نشان دادن داده ، آن را به صورت one hot encoded  نمایش می دهیم. یعنی به تعداد کلاس های موجود 0 میگذاریم و عدد مربوط به کلاس را 1 میکنیم. یعنی به این شکل:

 

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

اما بهتر است برای بهتر شدن شبکه و بالا رفتن قطعیت آن همان گونه که بالاتر گفته شد، بهتر است یکی از خانه ها 1 شده و بقیه 0 باشند.

Cross entropy 

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

Tensorflow playground

Tensorflow playground یک visualization  برای آزمایش شبکه های عصبی است که از طرف سایت tensorflow  اراائه شده است. که میتوان در آن با data های مختلف شبکه را train کرد. میتوان برای شبکه به تعداد دلخواه hidden layer و نورون اضافه کرد. وزن ها نیز به صورت رندوم تعیین شده اند که قابل مشاهده و تغییر اند.

در قسمت بالای صفحه چند آیتم وجود دارد.

1.epoch: تعداد به روز رسانی های شبکه به ازای بررسی همه ی data ها را مشخص میکند.

2.learning rate

3.activation: نوع activation function را مشخص میکند که میتواند linear، sigmoid،tanh  یا relu باشد.

4.regularization: برای مینیمم کردن تابع cost، مجموع توان 2 تمام وزن ها و بایاس ها را محاسبه میکند و مقادیر آنها را محدود میکند تا خیلی بزرگ نباشند تا یک وزن زیاد نتواند تاثیر زیادی روی شبکه داشته باشد و قدرت بین شبکه تقسیم شود و داده را حفظ نکند. میتواند مقادیر none، L1 یا L2 را داشته باشد.

5.regularization rate

6.problem type: نوع الگوریتم را مشخص میکند که classification باشد یا regression.

در قسمت چپ صفحه نیز چند آیتم وجود دارد.

1.data: از این قسمت میتوان از بین انواع dataset های موجود یکی را انتخاب کرد که میزان سختی آن ها متفاوت است.

2.ratio of training to test data: نسبت دیتاهای test و train را مشخص میکند.

3.noise: میزان noise موجود در دیتا را مشخص میکند. که هرچه بالاتر باشد، نشان دهنده ی در هم آمیختن بیشتر data ها است.

4.batch size: تعداد داده هایی را مشخص میکند که شبکه بعد از بررسی آنها، عملیات optimization  را اجرا میکند.

مقدمه‌ای بر شبکه‌های عصبی(1)

آشنایی با پرسپترون:

شبکه های عصبی مصنوعی در واقع بر اساس زیست شناسی پیاده سازی شده اند. به نورون هایی که از نورون های مغز انسان شبیه سازی شده اند پرسپترون می گویند.

هر نورون در مغز انسان ها شامل سه بخش دندریت ها که ورودی های نورون می باشند و بدنه اصلی و اکسون ها که خروجی آن می باشد تشکیل شده است.

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

حال بیایید مثال ساده ای از چگونگی عملکرد آن را ببینیم.

ورودی های هر پرسپترون هرکدام معرف مقادیر یک ویژگی می باشند.

 

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

حال ورودی ها در وزن های خود ضرب می شوند تا مقدار تاثیر گذاری آن ورودی مشخص شود.

پس از ضرب ورودی ها در وزن های خود این مقادیر به تابع فعال در بدنه پرسپترون انتقال پیدا میکنند.

بیایید با یک تابع فعال ساده شروع کنیم.

تابع فعال: اگر مجموع ورودی ها مثبت شد خروجی یک و اگر منفی شد خروجی صفر می باشد.

اگر تمام ورودی ها صفر باشند چه مشکلی پیش می آید؟

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

حال نحوه نمایش ریاضی این پرسپترون را با هم بررسی کنیم.

برای مثال مجموعه دیتا هدی که تصاویر را به وکتور 25 تایی تبدیل کرده بودیم که معرف پیکسل های آن بود که ما به عنوان ویژگی های آن استفاده کردیم؛ اگر بخواهیم به عنوان ورودی یکی از داده ها را به یک پرسپترون برای آموزش بدهیم باید 25 عدد ورودی ویژگی و یک بایاس با مقدار یک برای پرسپترون در نظر گرفت.

همانطور که ما تعداد بسیار زیادی پرسپترون در شبکه خود داریم پس می توانیم این مدل را به صورت ماتریسی گسترش دهیم.

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

در شکل بالا به لایه بنفش رنگ لایه ورودی و به لایه قرمز رنگ لایه خروجی گفته می شود که prediction را مشخص می کند.

به لایه هایی هم که نه ورودی هستند و نه خروجی، لایه پنهان گفته می شود.

اگر تعداد لایه های پنهان بیش از 2 باشد شبکه به deep learning تبدیل می شود.

هر چه بیش تر در لایه پیش برویم بصورت انتزاعی تر باید نگاه کنیم؛ برای مثال اگر در لایه دوم شبکه می تواند خط را تشخیص دهد در لایه های بعدی می تواند اشکال متفاوتی را تشخیص دهد که از ترکیب خط های لایه ها قبلی می باشد.

برای درک بهتر این قسمت می توانید از این لینک استفاده کنید.

حال در مجموعه داده هدی اگر بخواهیم این شبکه را آموزش دهیم باید 25 عدد ورودی برای گرفتن ویژگی ها در نظر گرفت و 10 عدد پرسپترون برای خروجی در نظر گرفت که اگر وکتور 25 تایی عدد 2 را برای مثال به این شبکه دهیم باید شبکه عدد دو را به عنوان predict برگرداند که با روش oneHotEncoding باید ترتیب پرسپترون های خروجی به شکل 0010000000 باشد.

مثلا برای عدد 9 باید 0000000001 برگرداند.

 

حال بیایید کمی بیش تر درباره توابع فعال بحث کنیم:

در شروع توابع فعال ما یک تابع ساده بود که فقط قبول و یا عدم قبول یک مقدار را با برچسب های ۰ و ۱ مشخص می کرد.

یکی از مشکل های این تابع این است که تغییرات کوچک در خروجی آن تاثییری ندارد و اگر ورودی برای مثال از ۰/۹- به ۰/۱- تغییر کند برای آن تفاوتی نمی کند و در هر دو حالت ۰ برمی گرداند.

این تابع به دلیل اینکه مشتق های آن در همه ی نقاط ۰ می باشد در شبکه های پرسپترونی چند لایه جواب نمی دهد.

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

تابع مشابه دیگری نیز معرفی شد که به دلایل ریاضی محبوب تر از sigmoid می باشد:

این تابع tanh نام دارد.

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

یکی از مشکل های این تابع آن است که چون مشتق آن بین صفر و یک است در شبکه های چند لایه چون این مشتقات در هم ضرب می شوند در نهایت عددی بسیار نزدیک به صفر تولید می شود پس مناسب MLP نمی باشد.

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

این تابع ReLU نام دارد که چون مشتقش در محدوده بزرگتر از یک، ۱ می باشد مشکل تابع قبلی را ندارد.

شکل ریاضی این تابع:

max(0, Z)

در آینده به دلیل کارایی بالای دو تابع tanh و ReLU بیشتر تمرکز ما روی این دو تابع خواهد بود.

کتابخانه های deep learning بیشتر این توابع را پیاده سازی کردند پس نیازی نیست که نگران پیاده سازی این توابع باشیم.

طبقه بند K نزدیکترین همسایه در scikit-learn

مسائل machine learning  به سه دسته تقسم می شوند:

1.supervised

2.unsupervised

3.enforcement learning

اکنون به دسته ی اول یعنی supervised learning میپردازیم.

The k-Nearest Neighbor Classifier

این الگوریتم از دسته الگوریتم های supervised learning  است. که آن را با چند مثال بررسی خواهیم کرد.

مثال اول:  در اینجا تعدادی feature برای تعدادی از گل ها مشخص کرده ا یم. اندازه ی گلبرگ ها و روشنایی گلبرگ ها.با توجه به مقادیری از feature ها که هر گل دارد، و label  های آن، مکان آن در نمودار مشخص می شود.

اگر بخواهیم بگوییم عکس جدیدی که    label آن را نداشته ایم در کدام دسته از گل ها قرار میگیرد(یعنی در واقع بخواهیم کلاس آن را تعیین کنیم.)، طبق الگوریتم nearest neighbor به صورت زیر میکنیم:

فاصله عکس جدید را با تمام training dataset ها محاسبه میکنیم تا ببنیم به کدام یک نزدیک تر است. و label عکس جدید همان label  نزدیک ترین data خواهد بود.

مثال دوم: در اینجا سه کلاس مختلف و دو feature داریم. و برای تعیین کلاس داده جدید مانند مثال قبل عمل خواهیم کرد.

1-nearest neighbor

در این الگوریتم label داده جدید، همان label نزدیک ترین داده به آن خواهد شد و در آن کلاس قرار خواهد گرفت. مشکل این الگوریتم این است که اگر در داده ها noise داشته باشیم، الگوریتم به درستی عمل نمیکند کرد.و داده ها را در کلاس اشتباه قرار میدهد.

k-nearest neighbor

برای رفع مشکل ذکر شده از این الگوریتم استفاده می شود. که در آن به جای یک همسایه، چند همسایه در نظر گرفته می شوند. K تعداد همسایه ها را مشخص می کند و hyper parameter است. که در فرایند training مشخص نمی شود.

انتخاب مقدار k به مسئله بستگی دارد. و باید مقادیر مختلف آن را برای test data بررسی کرد. اما اگر مقدار آن را بر اساس test data تعیین کنیم، مشکلی که به وجود می آید این است که ممکن است این مقدار فقط روی داده هایی که داریم عملکرد خوبی داشته باشد. و روی داده های جدید به خوبی عمل نکند.

برای مثال در اینجا از این الگوریتم با 3 همسایه استفاده شده است.

از مشکلات این الگوریتم این است که اگر تعدادdata ها زیاد باشد، تعداد مقایسه ها بالا رفته و الگوریتم زمان بر می شود.

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

حال وارد بخش عملی ابن الگوریتم میشویم. در اینجا از سه کتابخانه استفاده می کنیم:

1.scipy : برای لود کردن فایل مطلب استفاده می شود.

2.matplotlib : برای کشیدن نمودار استفاده می شود.

3.scikit-learn: کتابخانه ای برای machine learning است و بیشتر در machine learning  سنتی و کلاسیک کاربرد دارد.

میتوانید به جای pip از کلمه ی conda استفاده کنید. (اگر از آناکوندا استفاده میکنید.)

ابتدا package  ها و function های مورد نیاز را import  میکنیم.

 

Load_hoda : تابعی است که قبلا نوشته بودیم. که یک tuple شامل 1000 عدد training data و 200 عدد test data  بر می گرداند.

ایجاد طبقه بند k-nn

در کتابخانه scikit-learn طبقه بند به این شکل ایجاد می شود.

عدد 3 در اینجا همان k است.

و از تابع fit برای ذخیره دیتا های  train استفاده شده است.

پیش بینی داده های آموزشی

متغیر: sample را برای مشخص کردن اولین خانه تعریف می کنیم.

طبق کد X یک لیست شامل یک خانه است که آن خانه لیستی شامل 25 خانه (یک عکس از 200 دیتای  test) است.

 : Predicted_classهمان کلاس تشخیص داده شده برای داده است.

Actual_class : کلاسی است که واقعا داده به آن تعلق دارد. که از روی y_test  که همان label ها هستند تشخیص داده می شود.

در اینجا به تابع predict یک vector 25 تایی دادیم، و در قسمت fit 1000 تا vector 25 تایی. یکvector اول با 1000 vector دوم مقایسه شده و فاصله ها محاسبه می شود. با داشتن label  هر 1000 vector آن ها را sort می کند. و نزدیک ترین ها را پیدا می کند. و با بررسی سه  تا از نزدیک ترین ها، label داده را پیدا می کند.

Predict probability

تابع predict_proba درصد احتمال تعلق x تعریف شده به هرکدام از کلاس ها را بر می گرداند. که در اینجا با k=3 سه حالت اتفاق می افتد. (1، 0.6، 0.3)

پیش بینی چندین داده آزمون

Pred_classes: همه ی 200 داده مربوط به test data است.

True_classes: همه ی کلاس های واقعی را شامل می شود.

ارزیابی

با استفاده از تابع آماده score می توانیم میزان performance را محاسبه کنیم. همانطور که مشاهده می شود performance  برابر با 96 درصد است. یعنی از 200 داده، 8 تای آن اشتباه تشخیص داده شده است.

آشکارسازی لبه(2)

در کد بالا از فیلتر Sobel  با کرنل 5*5 یک بار در راستای x  و یکبار در راستای y اعمال کردیم و یکبار هم با استفاده از bitwise_or( ) در هردو جهت x, y این کار را انجام دادیم. با استفاده از Laplacian( ) از فیلتر Laplacian استفاده کردیم و با استفاده از Canny( ) از فیلتر Canny استفاده کردیم که دو عددی که به عنوان ورودی مشخص شده در واقع threshold های بالا و پایین می باشد.

آشکارسازی لبه(1)

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

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

از لبه یابی می توان برای تشخیص تغییرات شدید در روشنایی که معمولا نشانه رویدادی مهم یا تغییر در محیط است، استفاده کرد. همچنین  می توان از لبه یابی در object recognition (تشخیص اشیا) و segmentation(جدا سازی عکس و تبدیل آن به چند عکس) و بینایی ماشین استفاده کرد.

 

برای مدل کردن لبه ها، می توان عکس ها را تابع فرض کرد.

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

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

Differential Operators

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

Image Gradient

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

Discrete Gradient

برای تابع دو بعدی f(x,y) مشتق جزیی برای x به صورت بالا می باشد

برای داده های گسسته می توان از فاصله های محدود و متناهی استفاده کرد(بجای ε)(با پیکسل کار می کنیم که یک داده گسسته است. یعنی فاصله را یک در نظر می گیریم)

Partial Derivatives of an Image

در تصویر بالا اگر مشتق جزیی نسبت به x باشد درواقع لبه ها در محور x را بر می گرداند. شکل کرنل هم بصورت یک متریس 1*2 می باشد که -1 بر روی پیکسل مورد نظر قرار می گیرد و 1 بر روی پیکسل جلویی(پیکسل فعلی – پیکسل جلویی). اگر هم که مشتق جزیی نسبت به محور y گرفته شود لبه ها در محور y را بر می گرداند. شکل کرنل  بصورت ماتریس 2*1 می باشد. -1 و 1 می تواند جا به جا شود.

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

معمولا فیلتر ها symmetric (به این مفهوم که تعداد سطر و ستون آن برابر و فرد می باشد ) هستند. در حالی که فیلتر سمت چپ در عکس بالا اینگونه نیست. در فیلتر سمت راست که symmetric است, میزان تغییرات نسبت به پیکسل قبلی و بعدی محسابه می شود و از آن میانگین گرفته می شود.

Sobel Operator

در این حالت اثر پیکسل های همسایه هم با کمک اعداد -1 و 1 در نظر گرفته می شود.

Sobel Operator On Block Images

در عکس بالا سمت راست، با مشخص کردن آستانه، بعضی از لبه ها که حاصل از تغییرات کمتر بودند حذف شده اند

But In The Real World…

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

Finite Differences Responding to Noise

هنگامی که نویز یک تصویر بیشتر می شود در واقع تعداد تغییراتی که لبه نیستند هم افزایش می یابد و باعث می شود که قسمت هایی که لبه نیستند هم در تصویر نهایی نمایش داده شوند.

Gradients -> Edges

برای اینکه لبه یابی با دقت بیشتری انجام شود مراحل زیر انجام می شود:

  • Smoothing: حذف نویز ها با کمک فیلترهایی مانند gaussian
  • Threshold: چه مقداری به بعد لبه حساب شود.
  • Thinning: اگر چند لبه در کنار هم و با فاصله کم وجود داشته باشد همه را یک لبه در نظر می گیریم.
  • Connect edge pixles
Canny Edge Operator
  1. استفاده از فیلتر Gaussian
  2. محاسبه گرادیان
  3. non-maximum suppression: همان عملیات thinning
  4. اگر که یک لبه را مانند یک خط در نظر بگیریم ممکن است که میزان تغییرا در طول این خط برابر نباشد و مثلا قسمتی از این خط پررنگ تر باشد یا بخاطر آستانه تعریف شده قسمتی از خط حذف شده باشد. می توانیم از دو آستانه استفاده کنیم که مثلا اگر میزان تغییرات از آستانه بزرگتر، بیشتر باشد حتما لبه است و اگر از آستانه کوچکتر، کمتر باشد اصلا لبه نیست ولی اگر بین دو آستانه باشد، بسته به اینکه پیکسل های اطراف آن، لبه هستند یا نه خودش می تواند لبه باشد یا نباشد. مثلا در همان خطی که گفته شد اگر جایی از خط قطع شده، آن را پر می کند.
The Canny Edge Detector’

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

تبدیل Affine و Perspective در OpenCV

get Perspective Transform

اگر بخواهیم یک تبدیل affine رو یک تصویر انجام بدهیم می توانیم از getPerspectiveTransform استفاده کنیم. به این صورت که مختصات چهار گوشه قسمتی از تصویر که می خواهیم تبدیل رو آن انجام شود را مشخص می کنیم (points_A) و همچنین مشخص می کنیم که می خواهیم این چهار نقطه رو چه نقاطی در تصویر جدید نگاشت شوند(points_B). تابع getPerspectiveTransform یک ماتریس 3*3 بر می گرداند که درواقع اگر هر کدام از چهار نقطه رو تصویر اصلی به فرم [xi, yi, 1] در این ماتریس ضرب شوند حاصل نقاط مورد نظر روی تصویر جدید خواهند بود که به فرم [ti*x’i, ti* y’i, ti] خواهد بود(مختصات تصویر جدید ‘x و ‘y می باشد و ti عدد ثابت است). حال برای اینکه تصویر جدید را ایجاد کنیم از getPerspectiveTransform استفاده می کنیم که به عنوان ورودی عکس اولیه و ماتریس تبدیل و اندازه عکس جدید را می گیرد و عکس جدید را برمی گرداند.

get Affine Transform

 

با استفاده از  getAffineTransform نیز می توان یک تبدیل affine انجام داد با این تفاوت که از سه نقطه استفاده می کنیم. طبق رابطه ی مشخص شده, حاصل getAffineTransform یک ماتریس 2*3 می باشد که اگر هر کدام از سه تقطه اولیه به فرم      [xi, yi, 1] در این ماتریس ضرب شوند حاصل نگاشت این نقاط در تصویر جدید به فرم [x’i, y’i] خواهد بود. با استفاده از warpAffine تصویر جدید به دست می اید که ورودی ان همان طول و عرض تصویر اصلی و تابع تبدیل(M) و تصویر اولیه می باشد.

مراحل یک پروژه یادگیری ماشین

در پست قبل با دسته‌بندی‌های اصلی الگوریتم‌های یادگیری ماشین آشنا شدیم. در این نوشته قصد داریم مطالب زیر را بررسی کنیم:

  • مراحلی که یک الگوریتم supervised و unsupervised باید طی کنند تا یادگیری آنها کامل شود
  • ارزیابی مدل حاصل از این الگوریتم ها
مراحل یک الگوریتم supervised machine learning:

  • Data acquisition(جمع آوری داده): جمع اوری داده های بسیار زیاد که شامل نامگذاری آنها نیز می شود.
  • Data cleaning(تمیز کردن داده): از بین بردن اختلال در داده

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

 Train Dataset (مجموعه داده یادگیری): برای یادگیری و راه اندازی الگوریتم از این مجموعه داده استفاده می شود

 Test Dataset (مجموعه داده تست): بعد از یادگیری از این مجموعه داده استفاده می کنیم تا میزان کارایی الگوریتم را بسنجیم. مجموعه داده یادگیری و  تست، به این دلیل از هم جدا می شوند که شاید الگوریتم، مجموعه یادگیری را حفظ کند.

  • Train Model (مدل یادگیری): با استفاده از مجموعه داده یادگیری، ویژگی هایی که الگوریتم از داده ها یاد گرفته، بصورت یک مدل در می آید.
  • Evaluate Model (مدل سنجشی): با استفاده از مجموعه داده تست، مدلی که ایجاد شده، ارزیابی می شود. این فرایند بازگشتی است. به این معنی که وقتی ایرادات مدل یادگیری مشخص شد، این مدل دوباره تنظیم می شود تا ایرادات قبلی رفع شود.
یک مدل دیگر برای الگوریتم  supervised learning:

در مدل قبلی برای supervised machine learning فرآیند بازگشتی بین مدل یادگیری و مدل تست، باعث ایجاد کارایی دروغین می شود. زیرا به کمک تغییر دادن پارامتر های مدل کاری می کنیم که الگوریتم روی مجموعه داده تست مشخص شده، نتیجه بهتری دهد درحالیکه ممکن است این نتیجه رو یک مجموعه داده تست جدید بدست نیاید.

برای اینکه کارایی بدست آمده واقعی باشد. مجموعه داده خود را به سه قسمت تقسیم می کنیم:

(یادگیری)Train – (پیشرفت) Development – (تست )Test

اینبار برای تنظیم کردن پارامتر ها به کمک رابطه بازگشتی بین مدل یادگیری و مدل تست , از مجموعه داده پیشرفت استفاده می کنیم. و برای ارزیابی نهایی از مجموعه داده تست استفاده می کنیم.

مراحل یک الگوریتم unsupervised machine learning:

در این الگوریتم ها مجموعه داده تست وجود ندارد و کل داده برای یادگیری استفاده می شود

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

Model Evaluation

در این قسمت به روش های ارزیابی الگوریتم هایی که در بالا توضیح داده شد می پردازیم.

ازیابی Supervised Learning:

Accuracy (دقت): تعداد پیش بینی درست از تعداد کل پیش بینی ها

Recall, Precision: در دقت پیش بینی انجام شده اینکه پیش بینی غلط واقعا مربوط به کدام نامگذاری است اهمیتی ندارد. ولی در Recall, Precision اهمیت دارد. مثلا برای تشخیص دادن غده ی سرطانی اینکه شخصی که سرطان دارد به اشتباه تشخیص داده شود که سرطان ندارد خیلی بدتر است تا اینکه حالت برعکس آن اتفاق بیفتد.

MAE, MSE, RMSE: برای regression(داده های پیوسته) استفاده می شود. نحوه کار آنها براساس میزان فاصله با جواب درست است. مثلا اگر بخواهیم قیمت یک خانه را با توجه به متراژ آن پیش بینی کنیم می توانیم از این معیار ها استفاده کنیم

ارزیابی Unsupervised Learning:

همانطور که گفته شد در قسمت supervised ارزیابی بسیار آسان تر است چون که دسته ها مشخص هستند و با توجه به این که دسته مشخص شده برای داده های تست درست است یا نه، می توانیم ارزیابی را انجام دهیم. ولی ارزیابی برای unsupervised آسان نیست. چون که الگوریتم با توجه به پارامتر هایی که خودش انتخاب می کند دسته بندی را انجام می دهد. شاید از نظر انسان همان داده ها بصورت دیگری دسته بندی شوند.

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

در مثال بالا با توجه به اینکه چه معیاری تعریف کنیم دسته بندی متفاوتی بدست می آید.

مقدمه ای بر یادگیری ماشین (Machine Learning)

به عنوان یکی از شاخه‌های وسیع و پرکاربرد هوش مصنوعی، یادگیری ماشین به تنظیم و اکتشاف شیوه‌ها و الگوریتم‌هایی می‌پردازد که بر اساس آنها رایانه‌ها و سامانه‌ها توانایی تعلّم و یادگیری پیدا می‌کنند.هدف یادگیری ماشین این است که کامپیوتر (در کلی‌ترین مفهوم آن) بتواند به تدریج و با افزایش داده‌ها کارایی بهتری در انجام وظیفه مورد نظر پیدا کند. گستره این وظیفه می‌تواند از تشخیص خودکار چهره با دیدن چند نمونه از چهره مورد نظر تا فراگیری شیوه گام‌برداری روبات‌های دوپا با دریافت سیگنال پاداش و تنبیه باشد. 

برخی از روش های یادگیری ماشین

الگوریتم های یادگیری ماشین اغلب به عنوان نظارت شده یا نظارت نشده و تقویتی دسته بندی می شوند.

1.یادگیری نظارت شده یا Supervised Learning :

الگوریتم های یادگیری ماشین تحت نظارت می توانند آنچه را که در گذشته آموخته شده است به منظور پیش بینی رویدادهای آینده با استفاده از مثال های برچسب گذاری شده برای داده های جدید اعمال کنند. با شروع فرایند تجزیه و تحلیل یک مجموعه داده‌ شناخته شده، الگوریتم یادگیری، یک تابع انتزاعی برای پیش بینی مقادیر خروجی تولید می کند. سیستم می تواند اهداف هر ورودی جدید را پس از آموزش کافی فراهم کند. الگوریتم یادگیری همچنین می تواند خروجی خود را با خروجی صحیحِ در نظر گرفته شده مقایسه کرده و به منظور تغییر مدل، خطای خود را پیدا کند. مسایل این روش به دو دسته Classification و Regression تقسیم بندی می شوند که در مسایل Regression متغیر خروجی مقادیر پیوسته را می گیرد و بیشتر این مسایل به تخمین زدن یا پیش بینی یک پاسخ مربوط است ولی در مسایل Classification متغیر خروجی کلاسی از برچسب ها (Labels) را می گیرد و بیشتر به تشخیص این که داده ها به کدام گروه ها یا کلاس ها تعلق دارند، می پردازد.

 

2.یادگیری بدون نظارت یا Unsupervised Learning :

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

 

 

3.یادگیری تقویتی یا Reinforcement Learning :

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

استفاده از وبکم در OpenCV

 نحوه فعال سازی و استفاده از وبکم در  opencv

به وسیله تابع ()VideoCapture وبکم را راه اندازی می کنیم که خروجی آن یک شی (object)  می باشد که در اینجا آن را در متغیر cap قرار داده ایم.

این شئ یک متد به نام ()read دارد که با فراخوانی آن وبکم فعال می شود و شروع به دریافت فریم ها از وبکم می‌کند.

خروجی تابع ()read نوع داده ای tuple در پایتون است که در اینجا آن را در متغیرهای frame و ret ذخیره کرده ایم.

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

به وسیله تابع ()cap.release هم می توان وبکم را آزاد کرده و در نتیجه وبکم خاموش می‌شود.

به کد زیر دقت کنید:

قاعدتا میتوان روی تصاویری که از وبکم دریافت میکنیم قبل از نمایش تغییراتی ایجاد کنیم. به دو مثال زیر دقت کنید.

مثال 1) نمایش در وبکم به صورت آینه ای یا برعکس (flip)

یادآوری:

تصویر اصلی

چرخش عمودی یا Vertical Flip

چرخش افقی یا Horizontal Flip

برای flip کردن تصاویر دریافتی از وبکم از تابع ()cv2.flip استفاده می کنیم که آرگومان اول تصاویر دریافتی است و آرگومان دوم نوع flip را مشخص می کند به این صورت که:

  • اگر صفر باشد: به صورت عمودی تصاویر را flip می کند.
  • اگر مثبت باشد:به صورت افقی تصاویر را flip می کند.
  • اگر منفی باشد:به صورت هم عمودی و هم افقی تصاویر را flip می کند.

 

مثال 2) نمایش تک کاناله با وبکم

در این کد ابتدا به اندازه طول و عرض فریم یک ماتریس با مقادیر صفر می سازیم سپس هر کانال رنگی که از وبکم دریافت می شود را جدا می کنیم و در نهایت هر کانال را به صورت جداگانه نمایش می دهیم؛ به این صورت که با تابع ()cv2.merge فقط همان کانال رنگی و به جای دو کانال دیگر همان ماتریس صفری که ساخته بودیم را به عنوان ورودی می دهیم.

 

عملیات مورفولوژی

Mathematical Morphology

دو عملیات اصلی در Mathematical Morphology وجود دارد :

  • Dilation ( انشعاب )
  • Erosion ( فرسایش – تحلیل )

همچنین یک سری عملیات ترکیبی نیز وجود دارد :

  • Opening and Closing
  • Thinning and Tickening
  • و ..

Dilation 

عمل Dilation تصویر باینری را بسط میدهد (Expand)  ، و همینطور علاوه بر گسترش دادن تصویر ، حفره های موجود در آن را از بین می برد و لبه های خراب را ترمیم می کند.

Erosion

عکس عملیات Dilation می باشد .
که تصویر باینری را تحلیل میدهد ، و در واقع تصویر را کوچک میکند و قسمت های اضافی را حذف می کند . ( Shrink )

 

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

نمونه هایی از این فیلتر ها :

 

 

انجام عملیات Dilation 

ورودی این عملیات تصویر باینری B و فیلتر S هستند.

انجام این عملیات از طریق حرکت فیلتر‌ S روی تصویر باینری و قرار دادن origin روی هر پیکسل میباشد . با قرار گرفتن origin در یک پیکسل از تصویر باینری و ضرب تک تک المان های فیلتر در پیکسل های نظیرشان و در نهایت با عمل OR ، پیکسل متناظر با origin ساخته می شود .

 

مثال متن باینری 

 

برای مثال براثر عمل Dilation روی متن باینری مقابل :

 

 

با استفاده از فیلتر  

 

تصویر حاصل بر اثر پر کردن حفره ها و نقاط خالی نوشته ، به این شکل در خواهد آمد :

 

 

مثال : بر اثر فرایند Dilation نتیجه عملیات به چه شکل خواهد بود ؟

 

انجام عملیات Erosion :

ورودی این عملیات تصویر باینری B و فیلتر S هستند.

انجام این عملیات از طریق حرکت فیلتر‌ S روی تصویر باینری و قرار دادن origin روی هر پیکسل میباشد . با قرار گرفتن origin در یک پیکسل از تصویر باینری و ضرب تک تک المان های فیلتر در پیکسل های نظیرشان و در نهایت با عمل AND ، پیکسل متناظر با origin ساخته می شود .

 

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

 

عملیات های Opening و Closing  

این دو عملیات از مهم ترین فرایندها روی تصاویر باینری هستند.

Opening : عملیات حاصل از یک Erosion و سپس  Dilation .

نمونه هایی از عملیات Opening 

مثال ۱ :

مثال ۲ :

اگر با استفاده از فیلترِ دیسک ۱۱ پیکسلی عملیات opening را روی تصویر اولیه داشته باشیم ، در تصویر وسط روی عکس اولیه Threshold زده شده و سپس با انجام عملیات Opening میبینیم تصویر سمت راست نتیجه می شود که بدون کوچک شدن سایز تصویر نویز ها حذف شده اند ( ابتدا Erosion برای حذف نویز ها و سپس  Dilation برای برگرداندن تصویر به سایز اولیه ) .

Closing : عملیات حاصل از یک Dilation و سپس  Closing .

نمونه هایی از عملیات Closing

مثال ۱ :

مثال ۲ :

همینطور در تصویر بالا میبینیم در تصویر وسطی روی عکس اولیه Threshold زده شده و سپس در تصویر نهایی (سمت راست) نتیجه ی عملیات Closing را میبینیم که بدون بزرگ شدن سایز تصویر حفره ها پر شدند ( ابتدا Dilation برای پر کردن حفره ها و سپس  Erosion برای برگرداندن تصویر به سایز اولیه ) .

نمونه هایی از عملیات Opening – Closing 

همانطور که میبینیم با عملیات opening بدون کوچک شدن تصویر نویز ها حذف شده ، و سپس روی تصویر حاصل عملیات closing صورت گرفته و بدون بزرگ شدن تصویر حفره ها پر شده اند.

 

بررسی Opening-Closing و عملیات های Dilationو Erosion در OpenCv

برای انجام فرایند های Erosion و Dilation و Opening  و Closing در OpenCv میتوانیم به این شکل عمل کنیم :

 

با انجام این عملیات ها بر روی عکس مقابل :

 

 

نتایج بدین شکل خواهند بود  :

Erosion :

Dilation :

Opening :

Closing :