آموزش مقدماتی تنسورفلو

آمار در github :

تا 30 سپتامبر سال 2018 تنسرفلو با 111k استار و 68k فورک در رده اول قرار داشته است و این نشان می دهد استقبال از این کتابخانه بسیار زیاد است. یکی از دلایل استفاده از آن، این است که تنسرفلو کتابخانه ای است که برای deployment بسیار مناسب است. همچنین export اندروید و ios در آن بسیار راحت است. تنسرفلو برای محصول عملی و pytorch برای تست و مقاله دادن به کار می رود.

 

 

 

 

آمار جست و جو در گوگل:

 

 

 

 

این نمودار نشان می دهد میزان سرچ تنسرفلو روز به روز در حال افزایش است. دو کتابخانه ای که در رده ی دوم و سوم قرار دارند کراس و pytorch است.

مبانی تنسرفلو:

تنسرفلو فریم ورک یادگیری ژرف گوگل است که در نوامبر سال 2015 به صورت متن باز منتشر شده است. تنسرفلو می تواند عملیات محاسباتی بهینه و مشتق گیری را حساب کند، همچنین گرادیان گراف را به صورت اتوماتیک محاسبه می کند.

تنسور:

یک آرایه ی n بعدی را به اصطلاح tensor می گویند.

 

 

 

 

 

گراف جریان داده:

تنسرفلو برای این که بتواند توزیع پذیری داشته باشد و performance را بالا ببرد مدل برنامه نویسی graph base را ارائه داده و محاسبات را از اجرا جدا کرده است.

مثال: با توجه به شکل زیر دو نود برای input ، یک نود برای mul و یک نود برای add داریم. خروجی نود mul و add می توانند به یک نود add دیگر بروند. حالا می توانیم به input ها عدد بدهیم و خروجی را ببینیم.

 

 

 

 

گام اول: تعریف یک گراف محاسباتی (در این گراف هیچ عددی وجود ندارد)

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

مثال:

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

 

 

 

نکته: اگر به صورت صریح رئوس گراف محاسباتی را نام‌گذاری نکنید، تنسورفلو به صورت خودکار به آن‌ها نام نسبت می‌دهد. برای مثال در این جا به نود ها نام های x و y داده شده است.

هر زمان که به آن session اختصاص داده شود به x عدد 2 و به y عدد 3 را می دهد و خروجی 5 تولید می شود.

برنامه ساده استفاده از numpy :

 

 

 

 

بازنویسی با tensorflow :

()Tf.InteractiveSession : برای ساخت session است. می توانیم به آن ورودی دهیم و مشخص کنیم از چه مقدار از gpu استفاده کند. در صورتی که ورودی به آن داده نشود از کل gpu موجود استفاده می کند.

InteractiveSession سشنی است که در محیط های jupyter notebook و محیط هایی که تعاملی است استفاده می شود ولی چون overhead آن زیاد است برای deployment استفاده نمی شود و در آنجا session معمولی کاربرد دارد.

به جای np.zeros و np.ones ، tf.zeros و tf.ones قرار گرفته ولی سینتکس آن تغییری نکرده است.

به جای sum از tf.reduce_sum استفاده شده است (تاکید می کند که dimention در حال کوچک شدن است) همچنین به جای axis از reduction_indices استفاده می شود.

Eval : معمولا وقتی interactivesession داریم از eval استفاده می شود. eval سشن فعالی که وجود دارد را پیدا کرده و آن را اجرا می کند. چون eval را صدا زدیم آرایه ی [2. , 2.] را برمی گرداند و مشخص می کند datatype آن float32 است.

()Get_shape : یک TensorShape برمی گرداند که مثل tupple ها در پایتون رفتار می کنند.

سپس reshape شده و eval دوباره صدا زده می شود تا گراف اجرا شود.

مقایسه استفاده از numpy و tensorflow :

 

 

 

 

 

 

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

با فرض این که یک session فعال ساخته شده باشد اگر eval صدا زده شود ta اجرا می شود.

یک شیء session  محیطی که در آن اشیاء تنسور ارزیابی می شوند را کپسوله‌سازی می‌کند. یعنی بعد از ساختن گراف یک session می سازیم که این session اجازه می دهد اشیا داخل آن اجرا و evaluate شوند.

مثال:

Tf.constant یک عدد constant تعریف می کند. در این مثال از with block برای ساخت session استفاده شده که اصطلاحا به آن contex manager گفته می شود. وقتی یک session ساخته می شود باید حتما آن را  close کنیم اما وقتی از contex manager استفاده می شود بعد از خارج شدن از tab ، session خود به خود بسته می شود. برای اجرا شدن session از دستور sess.run استفاده شده که همان کار eval را انجام می دهد.

گراف که ساخته می شود چیزی مانند شکل زیر است:

 

 

 

 

 

 

 

 

بعد از این که session به آن اختصاص داده شد سخت افزار را در اختیار می گیرد و بعد از آن اصطلاحا عمل feed و fetch انجام می شود. جایی که input را می دهیم اصطلاحا به شبکه feed می شود و هر خروجی که بخواهیم را fetch می کنیم.

هر session منابعی را در اختیار می گیرد که gpu ، cpu و ram از مهم ترین آن هاست. این منابع پس از استفاده باید حتما آزاد شوند. همچنین می توانیم مشخص کنیم که هر session چه مقدار از این منابع را می تواند استفاده کند.

 

 

 

 

یک سینتکس دیگر این است که می توان از contex manager استفاده کرد. به این صورت که دستورات داخل indent نوشته می شود و هر وقت تمام شد خودش session را می بندد.

 

 

 

 

همچنین می توان از InteractiveSession استفاده کرد که فقط برای notebook کاربرد دارد.

 

 

 

مثال:

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

(x=tf.constant(2 و y=3 از لحاظ سینتکس هیچ فرقی باهم ندارند.

 

 

 

مثال:

چون خروجی خواسته شده op3 است که برابر با op2 به توان op1 است، نودی که به اسم useless نامگذاری شده در اجرا در نظر گرفته نمی شود و ارزیابی نمی شود بنابراین سربار اجرایی ندارد.

 

 

 

 

اگر به session.run یک لیست داده شود یک tupple برگردانده می شود.

بنابراین در این مثال نود useless هم نیاز به ارزیابی دارد.

Variable ها در تنسورفلو:

برای چیزی که معمولا قرار است train شود از variable ها استفاده می شود. هنگامی که مدل را آموزش می دهیم برای نگه داری پارامتر ها نیاز به تعریف متغیر داریم.  یعنی معمولا trainable هستند.

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

نکته: Weight و bios ها variable در نظر گرفته می شوند.

Varaiable ها در مواردی به کار می روند که نیاز به به روز رسانی متغیر باشد.

استفاده از کراس در تنسرفلو:

با دستور tf.keras میتوان بدون نصب کردن keras ، در محیط تنسورفلو به آن دسترسی داشت. کراس در محیط تنسورفلو function های بیشتری نیز دارد. برای مثال اگر بخواهیم چند ورودی و چند خروجی داشته باشیم یا از چند سرور ورودی بگیریم یا بخواهیم شبکه را به صورت multi gpu فیت کنیم می توانیم از api تنسورفلو به نام dataset استفاده کنیم.

مثال:

W1 یک contant است.

W2 یک variable است. (یک ماتریس 2 در 2 که از صفر پر شده)

اگر بخواهیم از variable ها استفاده کنیم حتما باید ابتدا آن ها را initialize کنیم. با دستور tf.initialize_all_variables() تمام variable هایی که تعریف کردیم initialize می شوند.

مقایسه variable و constant :

variable را می توان با ثابت ها (“name=”weights) یا مقادیر تصادفی (“name=”random_weights) مقداردهی اولیه کرد.

با نوشتن tf.global_variables_initializer تمام متغیر ها با مقادیر از قبل مشخص شده مقداردهی اولیه می شوند.

به روز رسانی یک متغیر:

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

یک متغیر به نام new_value تعریف شده که مجموع یک تنسور که داخل آن یک قرار دارد و تغییر نمی کند با state است. این متغیر معادل  new_value = state + 1 است.

در داخل update یک tf.assign تعریف شده که مقدار تنسور new_value را داخل state می ریزد و معادل state = new_value است.

سپس برای اجرا شدن operation های ساخته شده یک session ایجاد می شود.

با اجرای قطعه کد sess.run(tf.global_variables_initializer())  یک state با مقدار صفر ساخته می شود.

داخل فور update اجرا می شود که یک واحد به state اضافه می کند بنابراین خروجی این قطعه کد …,0,1,2,3 است.

پیاده سازی تنسرفلو (نت بوک 35: intro to tensorflow):

تعریف کتابخانه:

نمایش ورژن تنسرفلو:

ابتدا یک tf.constant سپس یک session ساخته شده است. خروجی این قطعه کد b’Hello, Tensorflow’ است. ( b نشان دهنده ی byte literal است.)

سپس دو constant دیگر با مقادیر3.0  و 4.0 ساخته شده. در داخل constant ها می توان نوع آن ها را مشخص کرد. datatype آن ها به صورت پیش فرض float32 است.

معمولا در فرایندtraining  از float های بزرگی استفاده می شود زیرا در عملیات به روز رسانی به ما کمک می کند. اما معمولا در inference وقتی کار با گراف تمام شد و فقط می خواهیم عکس را بگیریم و خروجی را ببینیم نیاز به دقت بالایی ندارد.

یکی از بهینه سازی هایی که در تنسورفلو انجام می شود این است که در گرافی که train شده float64 ها را برمی دارد و با یک int یا float کوچک تر جایگزین می کند تا حجم گراف پایین بیاید.

سپس session ایجاد شده را با دستور sess.close() می بندیم.

نمایش node1 و node2 قبل از ساختن session :

نمایش node1 و node2 بعد از ساختن session :

نکته: چون session جاری مشخص است هم می توانیم هم از eval و هم از sess.run استفاده کنیم.

مثال:

در ابتدا یک نود add تعریف شده است. با اجرای دستور (print(node3 اسم تنسور برگردانده می شود.

اما با اجرای دستور ((print(sess.run(node3 یک session ساخته شده و مقادیر node1 و node2 با هم جمع می شوند.

 

 

Fetch کردن (واکشی):

به قطعه کد ([result = sess.run([mul, intermed اصطلاحا fetch کردن می گویند. در واقع فراخوانی (sess.run(var در یک نشست مقدار آن متغیر را می دهد. می توان چندین متغیر را همزمان fetch کرد.

مثال:

در این کد نیز همانند قبل یک گراف ساخته شده است. دو constant به نام های input2 و input3 ، intermediate را ساختند. همچنین tf.mul یک نود است و با اجرای (sess.run(mul,intermed کل گراف ارزیابی می شود.

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

انواع تنسور های استفاده شده تا اینجا:

1. constant

2. variable

نحوه ورودی دادن بیرون از تنسرفلو:

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

مثال (ورودی با استفاده از numpy ):

روش دیگر استفاده از placeholder و feed dictionary است.

Placeholder : یک نوع تنسور هستند که منتظر ورودی اند.

در ابتدای ساخت گراف placeholder ها بر خلاف variable ها و constant ها هیچ مقداری ندارند و منتظر کاربر می مانند که آن ها را مقدار دهی کند.

دو placeholder با نام های input1 و input2 تعریف شده که نوع آن ها floate32 است.

ورودی های این گراف در حال حاضر مشخص نیستند. اگر بعد از ساختن session فقط sess.run() نوشته شود (عملیات fetch کردن)، متوجه نمی شود با چه مقداری باید مقداردهی اولیه را انجام دهد. در این جا باید از feed dictionary استفاده شود.

Feed dict مشخص می کند نود ساخته شده به چه placeholder هایی نیاز دارد و سپس این placeholder ها را به آن پاس می دهد.

 

 

این قطعه کد خروجی کد قبلی را در 3 ضرب کرده است.

 

 

 

 

ابتدا دو variable و یک placeholder تعریف شده است. Variable ها (w و b ) می توانند بعدا به روز شوند و placeholder ها (x ) باید از کاربر گرفته شوند.

سپس global_variables_initializer برای مقدار دهی متغیر ها صدا زده شده و بعد از آن linear_model با 1,2,3,4 فراخوانی شده است.

در این کد با اجرای sess.run(update) ابتدا خروجی یک است و هر بار که اجرا می شود یک واحد به آن اضافه می شود.

assign_add یک واحد به متغیر x اضافه می کند.

 

میانگین گیری (tf.reduce_mean):

 

ضرب ماتریسی (tf.reduce_mean):

matmul برای ضرب ماتریسی استفاده می شود.

 

بیشینه گیری (tf.argmax):

 

آموزش تنسربرد:

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

نصب و راه اندازی تنسربرد:

ابتدا باید پکیج تنسرفلو را با دستور pip install tensorflow روی پایتون نصب کنیم. سپس برای اجرا در در محل ذخیره کتابخانه تنسرفلو، دستور tensorboard –logdir asset را در ترمینال وارد می کنیم. این دستور نشان می دهد تنسربرد بر روی local host قابل دسترسی است.

 

 

 

 

 

 

نمایش گراف در تنسربرد:

 

 

 

 

 

مراحل:

ابتدا برنامه خود را تعریف کرده و متغیر ها را مقدار دهی می کنیم:

 

 

 

 

 

 

سپس یک summary برای ذخیره نتایج تعریف می کنیم:

 

 

 

 

در مرحله بعد یک session ساخته و برنامه نوشته شده را در تنسربرد نمایش می دهیم:

 

 

 

 

 

داشبورد های تنسربرد:

 

 

 

scalar:

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

 

 

 

 

histogram:

این داشبورد در تنسربرد نشان می دهد چگونه توزیع آماری تنسور در طول زمان متغیر است. این داده ها از طریق tf.summary.histogram نمایش داده می شوند.

 

 

 

 

 

 

distribution:

در این داشبورد از tf.summary.histogram استفاده می شود که درصد توزیع روی داده ها را نمایش می دهد.

 

 

 

 

 

 

graph:

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

 

 

 

 

 

image:

این داشبورد عکس هایی که با دستور tf.summary.image و در فرمت png ذخیره شده است را نمایش می دهد.

audio:

این داشبورد یک ابزار قوی برای تعبیه ویجت های صوتی برای مخاطبان است که از طریق tf.summary.audio نمایش داده می شود.

projector:

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

text:

این داشبورد متن را از طریق tf.summary.text ذخیره می کند و شامل مواردی مانند پیوند ها، فهرست ها و جداول می باشد.

مقدمه ای بر deep learning

مقدمه ای بر deep learning :

Image classification :

یکی از مبانی پایه در computer vision بحث classification اشیا و تصاویر است که تشخیص می دهد تصویری که به کامپیوتر داده شده چیست. (برای مثال  مشخص می کند تصویر گربه است یا نه)

چالش ها:

در واقع یک طیف پیوسته ای برای هر شی وجود دارد. برای مثال در گربه بین هر دو پیکسلی که ما می بینیم n پیکسل دیگر وجود دارد. همچنین رنگ ها هم طیف پیوسته ای دارند که برای کد کردن مجبوریم آن ها را در یک کانال( RGB (red, green, blue کد کنیم و عدد آن بسته به کامپیوتر و پیاده سازی ای که انجام می دهیم از 0 تا 255 متغیر است. بنابراین در این مرحله تعدادی از اطلاعات برای تبدیل از دنیای واقعی به محیط کامپیوتر که به آن semantic gap می گویند، از دست می رود.

 

چالش های دیگری هم وجود دارد. برای مثال الگوریتم (KNN (k-nearest neighbor  در دیتاست هدی performance خیلی خوبی داشت ولی در دنیای واقعی این گونه نیست و یک سری مشکلات ممکن است رخ دهد، مانند viewpoint validation ها به این معنی که اجسام را می توان از زاویه های مختلف دید و به همین دلیل الگوریتم KNN پاسخ گو  نیست.

Illumination :

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

Deformation :

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

Occlusion :

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

Background clutter :

اگر جسم در background محو شده باشد باز هم الگوریتم پیاده سازی شده باید بتواند آن را تشخیص دهد.

Intraclass variation :

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

Image classifier :

حالا باید مشخص کنیم چه الگوریتمی بهتر است تا این چالش ها برطرف شوند:

def predict(image):

     return class_label

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

بر خلاف sort کردن اعداد یا ماکزیمم گیری هیچ راه روشن و سریعی برای این گونه کلاس ها وجود ندارد و مجبوریم با راه حل های data-driven پیش برویم.

 

Data-driven approach :

ابتدا باید یک سری data و یک تابع train وجود داشته باشد که label ها به آن پاس داده می شوند. سپس بسته به نوع الگوریتم، طی یک فرآیند یادگیری یک مدل ساخته می شود که باید آن را ذخیره کنیم. بنابراین دفعه های بعد که عکس جدیدی به آن داده می شود می توان از یک تابع جدید به نام predict استفاده کرد که model و test_image به آن پاس داده می شود و دیگر نیازی به label نیست.

کد:

def train(train_images, train_labels):

    return model

def predict(model, test_images):

    return test_labels

K_Nearest Neighbor :

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

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

Neural network و deep learning

History :

از سال 2012 تا کنون deep learning روال رو به رشد چشمگیری داشته است.

تعداد مقالاتی که در رابطه با deep learning جمع آوری شده رشد بسیار زیادی داشته و این بدان معنی است که افراد زیادی وارد این فیلد شده اند.

 

 

 

 

دکتر Andrew ng ، استاد دانشگاه استنفورد، در 5 نوامبر 2017 در کنفرانس خود اعلام کرد تعداد مقالات در بحث deep learning بیش از حد زیاد شده اما با فقدان نیروی متخصص مواجه هستیم و طبق پیش بینی او یک انفجار در شغل های مربوط به deep learning و  neural networkایجاد می شود بنابراین وجود نیروی متخصص بیش از پیش ضروری است.

همچنین Andrej Karpathy ، مدیر هوش مصنوعی شرکت تسلا، در وبلاگ medium خود گفته است deep learning  و neural network نرم افزار ها را دچار تغییر و تحول زیادی می کند. (software2.0 )

 

Neural network کجا استفاده می شود؟

این شبکه ها در دیدن، شنیدن، خواندن متن و استنتاج آن (مانند dictionary translation ها) کاربرد دارند. همچنین برای کنترل کردن (برای مثال انجام بازی کامپیوتری) هم استفاده می شوند.

Neural network ها شبیه logo block یا building block هایی هستند که neural network practitioner (سازنده ی neural network ) می تواند از آن ها استفاده کند.

می توانیم هر شبکه ای که شناخته شده است را یک building block در نظر بگیریم و مشابه کار Andrej Karpathy این شبکه ها را به هم وصل کنیم. برای مثال یک شبکه داریم که image را به خوبی تشخیص می دهد و همچنین یک شبکه داریم که متن را خوب می فهمد. می توان این دو شبکه را پشت سر هم وصل کرد (اتصال یک شبکه CNN و یک سری شبکه RNN (این نوع شبکه برای dictionary ها استفاده می شود.))

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

ساده ترین neural network که در نظر گرفته شده neural network یک لایه است. (softmax )

برای مثال یک عکس 2 * 2 را در نظر بگیرید، اگر آن را starch کنیم 4 پیکسل به وجود می آید. فرض کنید سه کلاس خروجی داریم که به طور مثال مشخص می کند تصویر داده شده گربه، سگ و یا گوسفند است یعنی یک ماتریس 4 * 3 داریم. اگر این ماتریس 4 * 3 در یک ماتریس 1 * 4 ضرب شود 3 عدد برمی گرداندکه می تواند مشخص کند در آخر کدام کلاس انتخاب شده است. یک راه ساده تر این است که سطر اول را وزن های مربوط به کلاس cat ، سطر دوم را وزن های مربوط به کلاس dog و سطر سوم را وزن های مربوط به کلاس sheep در نظر بگیریم که به اضافه ی bios می شودد. Bios را می توان به حوزه ی 0 و 1 انتقال داد که این کار با softmax انجام می شود.

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

ارقام دست نویس هدی: (اعدادی که در کنکور سراسری بالای دفترچه به صورت دست نویس نوشته می شود.)

در واقع این ارقام ابتدا normalize شده، سپس background آن ها عوض و بعد از آن با روش های مناسب باینری شده است.

شبکه Dense :

شبکه ای است که در لایه ی اول خود 25 نورون دارد (چون عکس 5 * 5 است) و در لایه ی آخر چون 10 کلاس داریم 10 نورون

قرار می گیرد که از 0 تا 9 مشخص می شوند.

تعداد نورون های لایه ی وسط را باید خودمان مشخص کنیم که با چند نورون به performance بهتری می رسد.

در این نوع شبکه همه ی نورون ها به یکدیگر وصل می شوند که به آن fully connected یا همان dense می گویند.

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

کد:

Model=Sequential()

Model.add(Dense(64, activation=’relu’, input_dim=25))

Model.add(Dense(10, activation=’softmax’))

نمودار  relu

فرمول softmax :

تابع هزینه و روش بهینه سازی:

کد:

Model.compile(loss=’categorical_crossentropy’ , optimizer=’rmsprop’ , metrics= [‘accuracy’])

همانطور که پیش تر گفته شد با model.compile میزان loss مشخص می شود. معیار loss مقدار بد بودن شبکه را مشخصمی کند.

rmsprop  روش بهینه سازی است که نشان می دهد به ازای هر data چقدر با چیزی که می خواهیم شبکه predict کند فاصله داریم.

روش های دیگری نیز برای بهینه کردن وجود دارد مانند sgd ، momentum ، nag ، adagrad و … . در نهایت همه ی این روش ها شبکه را بهینه می کنند اما زمان بهینه کردن هم اهمیت زیادی دارد.

مقدمه‌ای بر پیاده سازی شبکه‌های عصبی ترتیبی در کراس

تعریف یک مدل ساده روی دیتاست هدی (ادامه):

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

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

Compile model :

Model.compile() :

در دستور compile تابع loss  معیار بد بودن شبکه را نشان می دهد و optimizer مشخص می کند چگونه باید آن را بهبود دهیم تا این معیار به مینیمم مقدار خود برسد.

کد:

model.compile (loss=’categorical_crossentropy,

optimizer=’rmsprop’

 metrics=[‘accuracy’])

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

با دستور fit این عملیات آغاز می شود.

نکته: دستور fit روی data های train صورت می گیرد.

آموش مدل با داده‌های آموزشی، تعیین سایز mini_batch و تعداد epoch:

Model.fit() :

x_train و y_train به عنوان پارامتر اول و پارامتر دوم به آن داده می شود.

epochs که به عنوان پارامتر سوم به آن داده شده است نشان می دهد شبکه باید چند بار data های موجود را مرور کند.

همچنین batch_size به عنوان پارامتر آخر مشخص می کند پس از دیدن چند data شروع به بهینه کردن مسئله کند.

برای مثال batch_size = 64 نشان می دهد به شصت و چهارمین data که برسد ، میانگین خطا ها را در نظر می گیرد و بر اساس این میانگین تابع را optimize می کند.

در فرمول C = Σ(y-a)2 / n  مقدار n  نشان دهنده ی batch_size است.

نکته: اعداد معروف batch_size (طبق گفته دکتر Andrew ng ،استاد دانشگاه استنفورد): 16 ، 32 ، 64 ، 128 ، 256 ، 512 و نهایتا 1024 است.

Batch_size یک hyper parameter است و بزرگ و کوچک بودن آن در فرآیند training تاثیر دارد.  همچنین این پارامتر روی سرعت همگرا شدن تاثیرگذار است. علاوه بر سرعت، هرچه سایز batch بزرگ تر باشد، نرمال سازی (batch_normalization)  بهتر است.

برای مثال اگر بخواهد هر کدام از data های هدی که می آید، شبکه را به روز کند دید کلی نسبت به شبکه ندارد. همچنین اگر بخواهد همه ی data ها را ببیند سپس بهینه ساری را انجام دهد، هزینه بالا می رود و سرعت پایین می آید بنابراین batch_size باید عددی بین یک و تعداد کل داده ها باشد که به آن mini_batch می گویند.

کد:

model.fit(x_train, y_train,

epochs=5,

( batch_size=64

وقتی کد را اجرا کنیم چون در کد های قبلی metric را accuracy تعریف کرده بودیم هر epoch که تمام می شود accuracy را اعلام می کند.

خروجی کد:

Epoch 1/5

1000/1000 [==============================] – 9s 9ms/step – loss: 0.2789 – acc: 0.9100

Epoch 2/5

1000/1000 [==============================] – 10s 10ms/step – loss: 0.2689 – acc: 0.9180

Epoch 3/5

1000/1000 [==============================] – 10s 10ms/step – loss: 0.2637 – acc: 0.9210

Epoch 4/5

1000/1000 [==============================] – 10s 10ms/step – loss: 0.2591 – acc: 0.9250

Epoch 5/5

1000/1000 [==============================] – 10s 10ms/step – loss: 0.2555 – acc: 0.9210

هرچه پایین تر می رود مقدار loss کمتر می شود. اگر بخواهیم loss کمتر و accuracy بیشتر شود می توانیم epoch را بیشتر کنیم.

ارزیابی مدل روی داده های آزمون:

در ارزیابی هم از accuracy استفاده می شود.

Model.evaluate() :

در دستور evaluate به جای x_train و y_train ، از x_test و y_test به عنوان پارامتر اول و دوم استفاده می شود.

خروجی این تابع یک tuple است که از loss و accuracy تشکیل شده و در واقع میزان loss و accuracy را در data های test نشان می دهد.

کد:

loss, acc = model.evaluate(x_test, y_test)

print(‘\nTesting loss: %.2f, acc: %.2f%%’%(loss, acc))

خروجی کد:

200/200 [==============================] – 0s 195us/step

Testing loss: 0.33, acc: 0.91%

پیش‌بینی داده‌های آموزشی: ( predicted class  )

از ابتدا تا اینجا یک مدل را به صورت sequential تعریف و معماری آن را مشخص کردیم، سپس روی آن بهینه سازی انجام دادیم و در آخر مدل را روی آن fit کردیم. حالا می توانیم روی همان مدل predicted class را صدا بزنیم.

data های test به عنوان پارامتر به predicted class داده می شود سپس predicted ها و true lable ها چاپ می شوند.

کد:

predicted_classes = model.predict_classes(x_test)

print(“predicted:”)

print(predicted_classes)

print(“True Label:”)

print(y_test_original)

خروجی کد:

predicted:

[7 2 3 8 5 5 4 7 3 2 0 8 8 0 2 9 3 6 7 4 0 3 6 3 9 2 7 5 2 9 2 5 5 8 9 2 5

1 4 8 8 4 2 2 1 2 7 9 0 3 7 2 7 5 2 9 8 2 9 8 8 6 6 6 7 6 2 4 2 4 4 5 9 1

8 4 0 5 6 2 4 3 2 7 7 7 7 1 8 1 7 8 7 7 8 9 7 2 3 1 0 2 9 6 3 5 5 0 0 9 6

7 9 3 9 9 8 7 9 2 5 2 5 5 9 6 9 2 0 3 7 9 5 2 9 0 4 1 8 2 2 3 5 2 9 3 8 2

7 0 9 9 0 7 6 7 4 0 9 3 7 0 7 4 9 4 7 3 4 1 5 6 7 9 1 3 5 4 5 7 4 1 3 3 1

1 4 3 8 9 6 7 7 2 3 0 1 4 9 5]

True Label:

[7 2 3 1 5 5 4 7 3 2 0 8 8 0 2 9 3 6 7 4 0 3 6 3 9 2 7 5 2 9 7 5 5 8 9 6 5

1 4 8 8 4 7 7 1 2 7 9 0 3 7 4 7 5 2 9 8 2 9 8 8 6 6 6 6 6 2 4 3 4 4 5 9 1

8 2 0 5 6 2 4 3 2 7 7 7 7 1 8 1 7 8 7 7 8 9 3 2 3 1 0 2 9 6 3 5 5 0 0 3 6

7 9 3 9 9 8 7 9 2 5 2 5 5 9 6 9 2 0 3 7 6 5 2 9 0 4 1 8 2 2 3 0 2 9 3 8 6

7 0 9 9 0 7 6 5 4 7 9 3 7 0 7 1 9 4 7 3 4 1 5 6 7 9 1 3 5 4 5 7 4 1 3 3 1

2 3 3 8 9 6 7 7 2 3 0 1 4 9 5]

نکته: یکی از روش های خوب machine learning این است که وقتی شبکه را train کردیم مشخص کنیم کدام data ها را اشتباه پیش بینی کرده است و سپس بر این اساس مدل را بهبود دهیم.