Neural Style Transfer

 Style Transferیکی از کاربردهای Deep Learning در هنر است که مشابه Deep Dream می‌باشد.

در این کاربرد یک عکس content و یک عکس style داریم. هدف این شکه ساختن عکسی است که image آن از عکس content و style آن از عکس style گرفته شده باشد. یعنی content را حفظ کرده و آنرا به سبک style ببرد.

به طور کلی به object ها content و به  .pattern,texture,color,. ها style گفته می‌شود.

نمونه ای از خروجی‌های این شبکه :

آن‌چه ConvNet ها یاد می‌گیرند

همان‌طور که میدانید لایه‌های اول به featureهای generalتر مانند خط و لبه و لایه‌های آخر ه feature‌های abstractتر حساس‌اند.

از visualization برای درک اینکه هر لایه چه تفسیری از image دارد، استفاده می‌شود. و این به عنوان hyper parameter برای style trafnsfer استفاده می‌شود. (برای مثال: استفاده از کدام لایه style را بهتر حفظ می‌کند.)

در مقاله Zeiler & Fergus سه متد درباره visualization معرفی شده است.

ادامه خواندن Neural Style Transfer

آشنایی با شبکه های عصبی بازگشتی – RNN

برای درک بهتر این مبحث ابتدا برخی از مساله هایی که با کمک RNN ها قابل حل است را بررسی می کنیم:

  • Music generation : در این نوع از مسائل ما به شبکه یک نت تصادفی (random token) و یا بخشی از یک موسیقی را می دهیم و شبکه ادامه آن موسیقی را برای ما تولید می کند.
  • Sentiment classification : در این مسائل شبکه با داده های افرادی که درباره موارد مختلف هم نظر و هم امتیاز داده اند آموزش می بیند تا بتواند پس از آن با مشاهده نظر هر کاربر با هر تعداد کلمه ای امتیازی که احتمالا وی به آن محصول می داده را مشخص کند.
  • DNA sequence analysis : در این نوع از مسائل معمولا یک رشته DNA نویزی به شبکه داده می شود تا شبکه نویزهای آن را حذف کند و رشته DNA سالم را تحویل بدهد. (کلیک کنید.)
  • Machine Translation : با کمک شبکه های RNN می توان این کار را به صورت دقیق تری از ترجمه لغت به لغت انجام داد. در اصل شبکه پس از آموزش باید بتواند عبارت ها با تعداد کلمات متفاوت را از یک زبان به زبان دیگر ترجمه کند.
  • Video activity recognition : در این نوع از مسائل تلاش می شود تا شبکه طوری آموزش ببیند که پس از مشاهده چندین فریم از یک فیلم بتواند فعالیتی که در آن صحنه اتفاق می افتد تشخیص دهد.
  • Name entity recognition : در تمامی زبان ها بسیاری از کلمات می توانند اسم خاص باشند یا نباشند. (مثلا روحانی یا Harry Potter) در این مسائل هدف آموزش شبکه ای است که بتواند اسامی خاص را در جملات تشخیص دهد.
  • Speech Recognition : در این مساله برای آموزش شبکه ای تلاش می شود که بتواند صدا یا گفتار را به متن یا نوشتار تبدیل کند.

ادامه خواندن آشنایی با شبکه های عصبی بازگشتی – RNN

تشخیص اشیا در تصویر با YOLO object detection

Object detection یا تشخیص شی در تصویر چیست ؟

تشخیص اشیا یک فناوری کامپیوتری است که در ارتباط با کامپیوتر ویژن و پردازش تصویر است که با شناسایی نمونه هایی از اشیاء معنایی یک کلاس خاص (مانند انسان ها، ساختمان ها و اتومبیل ها) در تصاویر و فیلم های دیجیتال مورد بررسی قرار می گیرد.

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

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

وظایف اصلی بینایی ماشین را می‌توان به موارد زیر تقسیم کرد:

  • شناسایی یا دسته‌بندی شیء: در شناسایی شیء، یک تصویر خام را تحویل می‌گیرید و باید تشخیص دهید که مربوط به کدام دسته می‌شود.
  • دسته‌بندی و مکان‌شناسی: در این حالت شما یک تصویر دارید که فقط یک شیء در آن وجود دارد و باید جای آن شیء را پیدا کنید. به این کار «مساله‌ مکان‌شناسی» نیز می‌گویند.
  • پیداکردن شیء: در این حالت شما باید موقعیت شیء در تصویر را پیدا کنید. این اشیا می‌توانند از کلاس‌های متفاوت باشند.
  • تقسیم‌بندی تصویر: تقسیم‌بندی تصویر وظیفه‌ سنگین‌تری است. در این حالت باید تمام پیکسل‌ها را بر اساس دسته‌ درست آن پیدا کنید.

 

روش ها و الگوریتم های موجود :

1 – روش های اولیه و سنتی :

در این روش ها مسئله را با رویکرد های ساده تری انجام میدهند. بعنوان مثال ابتدا تصویر را به یک شبکه سگمنتیشن داده و با روش های موجود به سگمنت کردن اشیا موجود در تصویر پرداخته و پس از مشخص شدن محدوده اشیا در تصویر هر کدام را جداگانه به یک شبکه دسته بند میدهیم تا کلاس آن نیز مشخص شود.
این روش ها زمان بر بوده و عملا برای تشخیص اشیا به صورت real time کارآمد نیستند. برای مثال روش selective search

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

2 – روش های مدرن و پیشرفته :

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

از جمله این روش ها و الگوریتم ها میتوان روش YOLO و SSD را نامبرد.

که در ادامه به بررسی آنها میپردازیم.

 

YOLO : You Only Look Once

کامل‌ترین سیستم‌ بلادرنگ (Real time) در یادگیری عمیق و حل مسائل تشخیص تصویر است. همان‌طور که در تصویر زیر مشاهده می‌کنید، این الگوریتم ابتدا تصویر را به بخش‌های مختلف تقسیم می‌کند و هر بخش را علامت‌گذاری می‌کند، سپس الگوریتم شناسایی را به صورت موازی برای تمامی این بخش‌ها اجرا می‌کند تا ببیند هر بخش به کدام دسته‌بندی تعلق می‌گیرد. بعد از شناسایی کامل اشیا، آن‌ها را به هم متصل می‌کند تا دو هر شیء اصلی یک جعبه باشد.

همه‌ این کارها به صورت موازی انجام می‌شوند؛ در نتیجه به صورت بلادرنگ است و می‌تواند تا 40 تصویر را در یک ثانیه پردازش کند. با اینکه این مدل کمی نسبت به RCNN عملکرد ضعیف‌تری دارد، ولی به دلیل بلادرنگ بودن آن، می‌توان از آن برای حل مشکلات روزانه استفاده کرد. در زیر تصویری از معماری YOLO را مشاهده می‌کنید.

نحوه تشخیص شی در تصویر توسط الگوریتم yolo :

در شبکه ی YOLO تصاویر به صورت فرضی به N در N ناحیه تقسیم می شوند. به ازای هر کدام از این نواحی فرض می شود که K شی امکان حضور دارند. شبکه به صورتی طراحی شده است که در نهایت به ازای تمامی نواحی امکان وجود اشیا در آن ناحیه ها – دسته ی آن شی و همچنین مختصات کادر دور شی را پیش بینی می کند.

با توجه به اینکه کادر دور هر شی ۴ مختصات دارد و همچنین دسته ی مورد نظر شی یک بردار C تایی هست و همین طور یک عدد برای احتمال وجود شی داریم پس به ازای هر شی یک تنزور (4 + 1 + C) تایی مورد نیاز است.

با توجه به اینکه فرض شد در هر تصویر N در N ناحیه وجود دارد و هر ناحیه احتمال حضور K شی به صورت بیشینه وجود دارد و هر شی نیز تزوری (4 + 1 + C) نیاز دارد پس در انتهای شبکه تنزوری KNN(C+1+4) وجود دارد که به پیشبینی کادر اشیا و احتمال آنها و دسته آنها می پردازد.

در نسخه نخست این شبکه پس از لایه های کانولوشن ویژگی ها خطی شده و به لایه های تمام متصل تحویل داده شده و در نهایت پیشبینی ها انجام می شوند در حالی که در نسخه های بعدی به جای ایجاد تنزوری به این ابعاد حجیم یک کرنل کانولوشن با ابعاد K(C+1+4) به نحوی بر روی ویژگی های آخرین لایه ی کانولوشن کانوالو می شود که ناحیه های ادراکی آن (Receptive Field) بر روی هر یک از N*N ناحیه از تصور ورودی قرار بگیرند و عملیات پیشبینی انجام شود.

 

تفاوت عمده این شبکه با شبکه ی RCNN این است که این شبکه به صورت سراسری (End-to-End) کار می کند و بحث تشخیص مکان اشیا را بدون نیاز به الگوریتم های بیرونی (Selective Search در RCNN) حل می کند و سرعت بسیار بالایی دارد و تماما با استفاده از شبکه های عصبی پیاده سازی شده و در نتیجه قابلیت موازی سازی بسیار مناسبی بر روی پردازنده هایی مثل GPU ها و FPGAها را داراست.

در فرایند اموزش شبکه yolo مختصات نقاطی را که میابد به صورت زیر تقسیم شده و با کاست فانکشن مناسب سعی در بهبود پبش بینی اشیا موجود در تصویر میکند

Cost function :

نتایج نهایی تشخیص اشیا روی تصویر توسط YOLO :

معرفی BERT، تحولی در NLP

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

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

این جا بود که استفاده از مدل های pre-trained به کمک افرادی آمد که از دیتا و قدرت پردازشی محدودی برخوردار بودند. شبکه هایی که با دیتای مسابقه Image Netآموزش داده شده اند، در اختیار همه قرار دارد و دیگر نیازی نیست که تمام مسیر را از اول طی کنیم. کافیست که یک شبکه را بر داریم و با استفاده از دو روش feature extraction و fine-tuning برای کار خودمان اختصاصی کنیم.

ولی اگر مسأله ما به تصویر مربوط نباشد چه؟ دیتای به این عظیمی برای متن را از کجا بیاوریم؟ چگونه شبکه را آموزش دهیم؟

برای استفاده از مدل های pre-trained در مسائلی که با متن سر و کار دارند، ابتدا به سراغ word embedding ها رفتیم. به ما کمک کردند و تغییر محسوسی در دقت شبکه ها ایجاد کردند. ولی اصلا عمیق نبودند و حاوی اطلاعات کمی بودند. کمک آن ها موثر ولی محدود بود.

در سال ۲۰۱۸ این مسیر برای مسأله های متنی یا به طور دقیق‌تر NLP نیز در دسترس قرار گرفت. شبکه بزرگی با دیتای زیاد (Wikipedia + BookCorpus) توسط مهندسان گوگل آموزش داده شد و در دسترس همه قرار گرفت. حالا یک شبکه بسیار قدرتمند برای بهره گیری در مسائل متنی در اختیار داریم. این شبکه Bidirectional Encoder Representations from Transformers یا BERT نام دارد. ادامه خواندن معرفی BERT، تحولی در NLP

Introduction to Word Embedding

Word Representation

Word embedding یکی از روش های represent کلمات است.که الگوریتم ما را قادر میسازد تا روابط و شباهت های بین کلمات را بصورت خودکار بفهمد. تا کنون ما برای تعریف زبان از یک دیکشنری 10000 تایی از کلمات استفاده میکردیم. و برای نشان دادن هر کلمه از یک بردار 1-hot استفاده میکردیم؛ برای مثال کلمه man کلمه 5391 در دیکشنری است و 1-hot vector آن را بصورت O5391 نشان میدهیم که index  5391 آن یک و بقیه صفر است و به همینصورت بقیه کلمات دیکشنری.

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

برای مثال:

مدل میتواند تشخیص دهد که در جای خالی کلمه juice را قرار دهد ولی اگر جمله بعدی را هم آموزش نداده باشیم نمیتواند juice را پیش بینی کند چون apple  و orange رابطه نزدیکی نسبت ب بقیه کلمات با هم ندارند.

ضرب داخلی بین هر دو وکتور 1-hot صفر است پس فاصله اقلیدسی بین همه آن ها یکسان است.

پس بجای 1-hot representation از featurized representation  برای هر کدام از کلمات دیکشنری استفاده میکنیم.

Featurized Representation: word embedding

به اینصورت که هر کلمه در دیکشنری به طور مثال 300، feature با نوع اعشاری دارد. مثل جنسیت، سلطنتی بودن، خوراکی بودن و… .برای هر کلمه یک وکتور 300 بعدی از کلمات در نظر میگیریم و آن را با e و index آن کلمه در دیکشنری نشان میدهیم. بطور مثال feature vector کلمه man را بصورت  نشان میدهیم.

اگر مثال قبلی را در نظر بگیریم میبینیم که apple و orange ، feature های شبیه به هم زیادی دارند که generalize بین این دو کلمه برای الگوریتممان راحت تر است.به این representation، word embeddings میگوییم.

برای تجسم word embedding از الگوریتم t-SNE استفاده میکنیم تا بعدهای بردار ویژگی را به دو بعد کاهش دهیم.


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

استفاده از word embeddings

با یک مثال از شناسایی اسم میبینیم که چطور از feature representation هایی که از هر کدوم از لغات استخراج کردیم استفاده کنیم.

Sally Johnson اسم یک شخص است. بعد از آموزش این جمله، مدل باید بداند که

“Robert Lin is an apple farmer” شامل Robert Lin به عنوان یک اسم است.

حالا اگر مدل را با جمله “Robert Lin is a durian cultivator” تست کنیم، شبکه باید اسم ها را تشخیص حتی با وجود اینکه کلمه durian را در طی آموزش ندیده باشد. این توانایی word representation است. الگوریتم هایی که از یادگیری به وسیله word embedding استفاده میکنند میتوانند میلیاردها لغت بدون برچسب را بررسی کند و بازنمایی آنهارا یاد بگیرد.

Transfer learning and word embedding
  1. یاد دادن word embedding از یک متن خیلی بزرگ ( 1 تا 100 میلیارد لغت)
    • یا دانلود embedding های از قبل اموزش داده شده
  2. میتونیم برای task دیگه ای ک خیلی کوچکتر است از transfer embedding استفاده کنیم.
  3. به عنوان قسمت اختیاری میتوانیم با افزودن داده های جدید، Word embedding رو finetune هم کنیم.

یک ویژگی مثبت word embedding نسبت به 1-hot کاهش ابعاد ورودی است. بردار 10000 بعدی 1-hot در مقایسه با بردار 300 بعدی ویژگی!

رابطه word embedding و face encoding

Word embedding رابطه جالبی با taskهای face recognition دارد:

در این مسئله ما هر کدام از تصاویر را به یک وکتور encode کردیم و شباهت این وکتورها را بررسی کردیم. در اینجا words encoding وembedding معنی مشابهی دارند.

در word embedding ما برای هر کدوم از کلماتی ک در دیکشنری وجود دارند یک representation داریم بر خلاف image encoding که ما هر تصویر جدید را به یک وکتور n بعدی map میکنیم.

خواص word embedding

یکی از خواص شگفت انگیز word embedding، analogy  (تناسب)  است.

جدول Word embedding زیر را در نظربگیرید:


میتونیم با استفاده از رابطه man ==> woman رابطه ؟؟ <== king  را هم استدلال کنیم؟

بردار e manو e womn از هم کم میکنیم که وکتور [-2  0  0  0] حاصل میشود. بهمین صورت برای بردار امبدینگ های king و queen بردار [-2  0  0  0] بدست میاید.این بردار را میتوانیم بردار جنسیت در نظر بگیریم!

مسئله را به صورت فرمول زیر مینویسیم:

بیان بالا را به صورت فرمول ریاضی میتوانیم بصورت زیر بنویسیم:

که بهترین جواب بردار امبدینگ queen است.

Cosine similarity:

میتوانیم از فاصله اقلیدسی هم به عنوان یک similarity function استفاده کنیم.

Embedding matrix

وقتی یک الگوریتم برای یادگیری word embedding پیاده سازی میکنیم، آنچه در نهایت یاد میگیرد یک ماتریس embedding است.

فرض کنید یک دیکشنری ده هزار کلمه ای داریم. الگوریتم یک ماتریس (300, 10000) بنام E میسازد.

با ضرب بردار 1-hot و ماتریس امبدینگ میتوان بردار امبدینگ را پیدا کرد.

ماتریس embedding در keras

طبقه بند متن برای نظرات فیلم ها با keras

در این مثال به پیاده سازی طبقه بند برای نظرات سایت imdbمیپردازیم.

دانلود کردن مجموعه داده imdb از datasetهای tensorflow

آرگومان num_words = 10000 ، برای ده هزار کلمه پرتکرار در دیتای اموزشی.

داده ها ب صورت یک آرایه از اعداد صحیح است که هر کدوم از این اعداد صحیح به یک واژه دلالت میکند و برچسب ها هم بصورت 1 برای نظرات مثبت و 0 برای نظرات منفی است.

با توجه به این که هر کدام از داده ها به صورت مجموعه ای از اعداد صحیح هستند، برای تبدیل دوباره به کلمات از یک تابع کمکی استفاده میکنیم:

آماده سازی داده
  • استفاده از 1-hot
  • استفاده از padding

که ما از مورد دوم استفاده میکنیم با ابعاد max_length * num_reviews.

برای مساوی کردن طول ها از pad_sequences استفاده میکنیم که طول طولانی ترین جمله را 256 در نظر میگیریم و اگر جمله کوچکتر ازین بود بقیه را با توکن <pad> پر میکنیم.

ایجاد مدل

در این مثال از rnn ها استفاده نکردیم و از یک شبکه dense ساده استفاده میکنیم.

برای loss function از binary_crossentropy  استفاده میکنیم.

آموزش مدل

ارزیابی مدل در دیتای تست

کشیدن نمودار accuracy  و loss

استفاده از history خود کراس

همانطور که میبینیم training loss کم شده ولی  validation loss ، overfit شده.

در این نمودار هم validation accuracy ، overfit شده.

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

  • استفاده از dropout
  • استفاده از یک embedding خوب pretrain شده
  • استفاده از شبکه های rnn
  • اسنفاده از early stopping

word2vec & glove

word2vec

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

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

می دانیم که context به nتعدادکلماتی که برای پیش بینی شبکه لازم است واین n تعداد هایپر پارامتر هستند.

مثلا در شکل بالا n = 4قرار داده ایم وبرای پیش بینی juice ،چهار کلمه قبل از آن را انتخاب کرده ایم این روشی است که در سال 2003توسطBengioمطرح گردیدودر حال حاضر روش های بهتری ارایه شده است که به آن ها می پردازیم.

 

بعنوان مثال در شکل بالا هدف این است که juice راپیش بینی کنیم وبراساس contextهای متفاوت که در شکل بالا اورده شده میتوان به این هدف رسید.(همان طورکه در شکل قبل Last 4 wordsرا مشاهده کردیم.)

روش 4words on left & right :در این روش علاوه بر 4کلمه قبل،4کلمه ی بعدی رو هم context در نظر میگیریم.

روش Last 1 word:یک کلمه مونده به targetروcontext در نظرمی گیریم.

روش Nearby 1 word: یک پنجره context را 5 تا کلمه ای یا 10 تایی قبل وبعد targetبرمیداریم وسپس از این پنجره بعنوان رندوم یک کلمه انتخاب می شود،که درمثال بالا glass به عنوان context به صورت رندوم انتخاب شده است.به این روش skip-grams گویندکه همان word2vec راتشکیل می دهد.این ایده خیلی ساده ای است ولی در نهایت embedding خوبی خواهیم داشت.

پس در این روش یکسری context و target داریم که با n تا کلمه قبل وبعد وبا انتخاب یک کلمه ازمیانn تا به صورت رندوم میتوان targetرا تشخیص داد.این ایده در 2013 توسط Micolov مطرح گردید.

در شکل بالا یک Fake Task داریم که اگر یک context را بدهیم target را پیش بینی خواهد کردمثلا در شکل بالا در پنجره های ابی رنگ context ودر سفید رنگ targetرا خواهیم داشت وپنجره اول دو کلمه quick ,brown هم targetهستند.درپنجره های دیگر شکل هایپر پارامتر های متفاوتی را بسته به سلیقه های کد نویسی متفاوت مشاهده می کنیم.دراین شکل چون وزن های شبکه بروز می شوند target هم میتواند دو مقدار داشته باشد وهیچ مشکلی پیش نمی اید چون هدف بدست اوردن بردارembedding بامعنی است.

 

در نهایت شبکه شکل بالا را خواهیم داشت که

input vector: بسته به دیکشنری سایزمتفاوتی دارد که در شکل بالا 10000تایی ست.

hidden layer:به یک لایه embeddingوصل می شودکه مقدارآن هایپرپارامتراست وچون googleاین مقدار را300درنظر گرفته ماهم همان مقدار را درنظر می گیریم.

output layer:بردار one-hotاست که 10000تا مقدار نورون داردکه هر کدام به ازای یک کلمه تنها یکی ازآن ها مقدار یک می شود.

در این taskکه در شکل بالا توضیح داده شد برخلاف لایه های FC های قدیم activation نمی گزاریم و برای هر چه راحت شدن وپیچیدگی کمتر liner استفاده کردیم.

به مدل زیر توجه کنید که

دراین مدل vocab size=10000 است که از context که orange است ودر دیکشنری شماره6257 را دارد،می خواهیم به target  که juice است ودر index=4834 است برسیم که در واقع از X به Y یک Mapping خواهیم داشت.

 Ocبرابر one hot کلمه ی c است که در یک بردار embedding رندوم ضرب می شود وec که embedding کلمه c است سپس از یک لایه softmax عبور می دهیم ودر نهایت کلمه predict شده به دست می اید.

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

برای حل  مشکل بالا ایده های زیر ارایه شده است:

استفاذه از softmax باینری یعنی برای رسیدن به 10000 تا داده یک درخت می سازیم وآن را به دو قسمت مساوی تقسیم میکنیم که هر شاخه درخت5000 داده خواهد داشت، برای یافتن داده ابتدا بررسی میکنیم در کدام شاخه درخت باید بگردیم سپس ان شاخه را ادامه ودر مرحله ی بعدی 2500 تا داده ی بعدی را بررسی میکنیم وهمین طوری میگردیم تا به کلمه نهایی برسیم که در شکل با رنگ بنفش نشان داده شده است با این روش سرعت بالا تر می رود.

ایده ی دیگر همانند درخت Decision Tree می توان بر اساس احتمالات درخت را چید وبعنوان مثال کلمات پر تکرار همانند the و a را در ابتدای درخت قرار داد وکلماتی که خیلی پر تکرار نیستند رو درانتهای درخت بگزاریم.

Negative Sampling

بازهم ایده های بالا مشکلاتی دارند وروش بهتری به نام Negative Sampling مطرح شد:

دراین روش کار را ساده تر کردیم چون قبلا برای softmax سختی محاسبه را داشتیم حال ان راتبدیل به sigmoid میکنیم، همانطور که در شکل بالا میبینیم لغت juice به صورت رندوم به عنوان target انتخاب و مقدارش در جدول یک می شود وبقیه ی حروف مقدار صفر را میگیرند.البته لازم به ذکر است که در این روش چون به صورت رندوم target انتخاب می شود ممکن است target اشتباه انتخاب شود وبا مشکل مواجه شویم،ولی چون دیتا ست بزرگی در اختیار داریم این مشکل در مراحل بعدتر حل می شود.

مدل تبدیل به شکل بالا می شود که یکی از کلمات context است وفقط یکی از بقیه کلمات بعنوان target انتخاب میشود ومقدار یک میگیرد پس درواقع یکsigmoid tag خواهیم داشت وبا دادن کلمه ی orange کلمه juiceحاصل می شود.اگر لغت king داده شود همان sigmoid مخصوص این کلمه خطا را برمیگرداند که متوجه میشویم این کلمه sampleنیست وغلط است.درواقع دراین مثال هر بار 5نورون سیگموید دخیل هستند وخطا ها را برمیگردانند.یعنی با دادن کلمه orange در شبکه تمام 10000نورون در شکل یک مقداری میگیرند وبرای انتخاب کلمه juice یا king برای خروجی هرکدام که مقدار بیشتری داشت بامقدارtarget مقایسه ودر نهایت انتخاب میشود و اختلاف این مقدار ها در شبکه backpropagat  میشود.

برای انتخاب کلمات براساس احتمالاتی که درجمله کلمات داشتند بیشترین راانتخاب میکردیم،حال میخواهیم کلماتی که در دیکشنری پرتکرار هستند نسبت به هم نزدیکتر باشند واحتمال بیشتری برای انتخاب داشته باشند.برای این روش مشکلی که داریم این است که کلمات پر تکرار همانند aو the و of همیشه پرتکرارهستند و negative هارا همیشه تشکیل خواهند دادپس کلمات پرتکرار با احتمال (f(Wi، احتمال بیشتری خواهند داشت.روش دیگر این است به تمام کلمات احتمال برابری را نسبت می دهیم ولی مشکل این روش این است که کلمات پرتکرار بهتر یاد گرفته نمی شود.

برای حل دو روش بالا فرمول (P(Wi مطرح شد که نسبت احتمال کلمات را نسبت به کلمات پرتکرار حفظ می کند وکلماتی که بیشترانتخاب می شدند احتمال بیشتری نسبت به کم تکرار ها خواهند گرفت.(برای درک فرمول ونسبت ها میتوانید تابع xبه توان 3/4وxرا باهم ببینید)

GloVe word vectors

gloveروشی برای word embedding درست کردن است دریک task است که بعدها این word embeddingبتواند مورد استفاده قرار بگیرد.این روش درسال 2014 توسط استندفوری ها مطرح شد.

به صورت کامل نمی توان گفت که gloveبهترازword2vecهست.

 

درجمله ای که در شکل بالا می بینیم همانطور که قبلا گفته شد یک context و target انتخاب می کردیم دراین روش الگوریتمی ساخته می شود که embeddingها را باروش ساده تر یاد بگیریم:

Xij=تعداددفعاتی که در کل دیتا ست context iام با context jام دیده شده است.

Xij=Xjiتنها در صورتی این دو باهم برابرندکه پنجره ای که برایcontextدر نظر گرفته می شود n لغت قبل وبعد را شامل شودمثلا یک لغت قبل وبعد یادرمثال های قبل 4لغت قبل وبعد را بعنوان پنجره contextدر نظر گرفته بودیم.

درفرمول بالا

ej= بردارembadding لغت ای که اندیس jدارد.

θi=وزن های پارامترهای یک نورون iهست.

(f(Xij=وزن (اطلاعات بیشتر در کورس deep learning nlp استندفوردجلسه سوم)

هدف به دست اوردن وابستگی بین iوjاست که log آن برابر تعداددفعاتی است که i و j با هم دیده شده اند.

در ابتدا هم i و j به ازای تمام کلمات minimize می شوند.

bi و bj هم بایاس هستند.

کاربرد(f(Xij :

  1. ممکن است دوکلمه ی i و j با هم دیده نشده باشند پس Xij=0 میشود ودر نهایت (log(0 تعریف نشده است ومی دانیم در برنامه نویسی برای محاسبه عبارت ریاضی اگر مقدار ابتدای صفر شود دیگر عبارت محاسبه نمی شود ومقدار صفر خواهد گرفت پس برای حل مشکل تعریف نشده بودن=0 (f(Xij می شود وبرنامه به ارورنمی خورد.
  2. همانند روش negative sampling با وجود (f(Xij برای کلمات پرتکرار وزن بیشتری نسبت میدهیم واحتمال انتخاب شدن ان ها را افزایش میدهیم وکلمات کم تکرار هم احتمال انتخاب شدنشان نیز کنترل میشود.

اگر پنجره context اندازه قبل وبعد از context برابری داشته باشندej و θi هردو یک چیز یکسانی را یادمیگیرندوهردو خواصیتی که می خواستیم را پیدا می کنند پس در فرمول نهایی میانگین این دو را در نظرمیگیریم.

دانلود word embedding از قبل آموزش داده شده توسط Glove

چون با مشکل کوچک بودن دیتا ست مواجه هستیم پس در این قسمت word embedding ازقبل اموزش داده شده ی glove را انتخاب میکنیم.

Pre-process the embeddings

ابتدا دیتا ست را دانلود میکنیم و ان را unzip کرده وسپس وکتورهای 100 بعدی این مجموعه را انتخاب می کنیم دراین مرحله ابتدا هر خط از دیتا ست را با line.split جدا کرده وخود لغت را از دیتاست که [value[0 دارد داخل word می ریزیم و [:values[1 که vectorهای تکرارword را تشکیل میدهندو در اینجا embadding_index را شامل می شوند.درنهایت فایل باز شده را  میبندیم.

در این گام یک ماتریس embedding vector را شامل می شود یعنی از فضای دیکشنری موجود به فضای embedding تبدیل کنیم.از قبل می دانیم max_word=10000 تا لغت پرکاربرد دیکشنری هست وبرای این ها ماتریس embedding vectorرا می سازیم که  (len=10000 , shap=(10000 ,100 است.

Define a model

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

Load the GloVe embeddings in the model

لایه ی embedding_matri را به صورت رندوم با تابع set_weighte وزن هایش را لود میکنیم.

trainable = False قرارمی دهیم چون در ابتدا خطا زیاد است و می خواهیم بردار pre_train را خراب نکند.

Train and evaluate

مدل را compile , fit کرده ودر نهایت مدل را save میکنیم.در نهایت با مشکل overfitting مواجه میشویم چون accuracy دیتای train=1و validation=0.57 میشود چون مدل شبکه به خوبی ساخته نشده وترتیب کلمات را یاد نمی گیرد.

 

دراینده با مباحث RNN ها خواهیم دید که perfomance را بهبود خواهیم داد.

 

 

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

آمار در 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 ذخیره می کند و شامل مواردی مانند پیوند ها، فهرست ها و جداول می باشد.

sequence to sequence Model

مدل seq2seq یکی از مدل های مورد استفاده در سیستم‌های تولید پاسخ است که می تواند احتمال تولید پاسخ مناسب را بیشینه کند.

مدل رمزنگار-رمزگشا LSTM (encoder-decoder) یک شبکه عصبی بازگشتی برای مسائلی است که یک دنباله را به دنباله دیگر نگاشت می‌کند. (یک دنباله به عنوان ورودی دریافت می کند و خروجی، دنباله دیگری است.) به همین دلیل به آن مدل seq2seq نیز گفته می‌شود. در مسائل seq2seq دنباله ورودی و خروجی می‌توانند دارای طول های متفاوتی باشند به همین دلیل این مسائل از اهمیت زیادی برخوردار بوده و چالش برانگیزند.

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

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

۱) رمزنگار (Encoder)

۲) رمزگشا (Decoder) 

شبکه رمزگشا(decoder)، خروجی (state) شبکه رمزنگار (encoder) را به عنوان ورودی دریافت می کند.

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

مثال : جمله فرانسوی زیر را در نظر بگیرید قصد داریم این جمله به عنوان  ورودی به Encoder بدهیم و معادل یا ترجمه آن را به انگلیسی از Decoder دریافت کنیم.

 

Image-captioning به روش Encoder-Decoder

با وارد کردن یک عکس به عنوان ورودی به یک شبکه  pretrained مثل (VGG16,AlexNet,…) و پس از استخراج ویژگی ها، لایه آخر که softmax می باشد را حذف می کنیم و لایه ماقبل آن (۴۰۹۶تایی) را به عنوان ورودی به شبکه بعدی (Decoder) می دهیم.

ماشین ترجمه ( Mashine translation )، به عنوان ساختمان یک مدل زبان شرطی (conditional language model) عمل می کند.خروجی هر مرحله، ورودی مرحله بعدی است که می خواهیم p  در آن به حداکثر مقدار برسد.

یک Mashine translation و یک language model  از نظر ساختار و کاربرد با یکدیگر فرقی ندارند و دو شبکه باهم برابر هستند. هر دو زبان مبدا را به عنوان ورودی دریافت می کنند و زبان مقصد را به عنوان خروجی تولید (generate) می کنند.تنها تفاوت آن ها در این است که language model یک وکتور ۰ را به عنوان ورودی اولیه می گیرد ولی Mashine translation ، خروجی (state) مرحله قبلی را به عنوان ورودی می گیرد.

مدل زبان شرطی، احتمال تولید جمله خروجی را به شرط دریافت جمله ورودی برمی گرداند.

الگوریتم حریصانه (greedy)

الگوریتم حریصانه  شبیه روش‌های پویا اغلب برای حل مسائل بهینه سازی استفاده می‌شوند.این الگوریتم بهترین انتخاب را با توجه به شرایط مسئله انجام می‌دهد به امید آنکه با ادامهٔ همین روش بهینه‌سازی انجام شود.,ولی در مدل زبان شرطی (Conditional Languge model) اغلب به پاسخ درستی نمی رسیم.

به عنوان مثال جمله ی فرانسوی زیر را در نظر بگیرید :

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

الگوریتم Beam Search

در این الگوریتم پارامتری به نام beam width داریم که به تعداد آن محتمل ترین ها را در مرحله اول برمیداریم به طول مثال همان طور که در شکل زیر می بینید فرض کنید یک دیکشنری ۱۰۰۰۰تایی داشته باشیم و B = ۳ باشد در این صورت ۳ کلمه را به عنوان محتمل ترین انتخاب می کنیم و احتمال آن را محاسبه می کنیم.

در مرحله بعد هر کدام از کلماتی که انتخاب کردیم از ۱۰۰۰۰تا کلمه دیگر باید کلمه محتمل بعدی را انتخاب کنند که در این حالت ۳۰۰۰۰تا حالت داریم  و این مراحل را تا جایی ادامه می دهیم که به <EOS> برسیم و احتمالات آن هارا محاسبه می کنیم.

این روش مشکلاتی نیز دارد. زمانی که تعدادی عدد بین ۰ و ۱ در هم ضرب شود عددی که به دست می آید آنقدر کوچک می شود که ممکن است کامپیوتر قادر به ذخیره سازی آن نباشد.(under flow رخ می دهد.)

برای حل این مشکل از تابع لگاریتم که روند افزایشی-صعودی دارد استفاده می کنیم.(تابع لگاریتم بین ۰ و ۱ مقادیر منفی دارد.)به صورت زیر  :در این مرحله هنوز وابسته به طول خروجی می باشد برای حل این مشکل تقسیم بر طول جمله می کنیم.(به صورت زیر)

اصلاحات روش Beam search

در production اعداد بیشتری را برای Beam width می گذاریم ولی در research اعداد کمتری می گذاریم.کوچک یا بزرگ گذاشتن Beam width هر کدام مزایا و معایبی دارد.

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

زمانی که Beam width را کوچک انتخاب کنیم احتمال اینکه به جواب درست برسیم کمتر است و فضای کمتری از مسئله را پوشش می دهد ولی سرعت آن بیشتر می باشد.برخلاف الگوریتم های BFS و DFS که بهترین ها را انتخاب می کنند این روش لزوما بهترین ها را انتخاب نمی کند.

آنالیز ارورهای روش Beam search

مثال:

جمله فرانسوی زیر را در نظر داشته باشید.ترجمه ی اول، ترجمه ی درست و ترجمه ی دوم، ترجمه ای است که شبکه تولید کرده است.

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

۱)RNN(تعداد دیتای آموزش دیده کم باشد.)

 ۲)Beam width(مقدار آن کم تعیین شده باشد.)

اگر حالت زیر پیش بیاید مشکل از مقدار Beam width می باشد و باید مقدار بیشتری را انتخاب کنیم. واگر حالت زیر پیش بیاید مشکل از RNN هاست و باید آن ها را اصلاح کنیم.

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

image-captioning

caption generation یا تولید یک توصیف به عنوان یک چالش در هوش مصنوعی مطرح شده است که در آن باید یک توصیف متنی برای یک عکس دلخواه داده شده به آن تولید کند .

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

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

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

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

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

  1. دیتاست عکس و عنوان یا توصیف
  2. آماده کردن داده عکس
  3. آماده کردن داده متن
  4. توسعه مدل یادگیری عمیق
  5. آموزش با loading پیشرفته
  6. ارزیابی مدل
  7. تولید عنوان یا زیرنویس جدید

نیازمندی های این آموزش :

  1. نصب محیط scipy ایده آل با pyhton 3
  2. نصب کراس ورژن 2.1.5 یا بالاتر با tensorflow یا theano backend
  3. نصب Scikit-Learn , NumPy , Pandas ,Matplotlib
دیتاست عکس و عنوان

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

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

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

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

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

این مجموعه  دارای مجموعه داده های از پش تعریف شده (6000 عکس) ، محموعه داده های توسعه داده شده (1000 عکس) و مجموعه داده آزمون (1000 عکس) است .

یک معیار برای ارزیابی مهارت مدل ، نمرات BLEU است . این معیار را در ادامه هنگام ارزیابی مدل بیشتر توضیح میدهیم .

آماده سازی دیتاست عکس

در اینجا از یک مدل از پیش آموزش داده شده برای تفسیر محتوای عکس استفاده شده است . مدل های زیادی برای انتخاب وجود دارند . در اینجا از مدل oxford visual geometry  یا VGG استفاده شده است .

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

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

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

این کار در VGG به همین صورت است با این تفتوت که در آنجا فقط یک بار انجام میگیرد .

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

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

keras ابزار هایی برای تغییر اندازه تصویر load شده دارد (مثلا 3 کانال 224 * 224 pixel image)

در زیر تابعی به اسم ()extract_features داریم با اسم دایرکتوری که میگیرد آن تصویر را load میکند ، آن را برای VGG آماده میکند ویژگی های پیش بینی شده از مدل VGG را جمع آوری میکند . ویژگی های تصویر یک بردار 1 بعدی 4096 تایی از عناصر است . این تابع یک دیکشنری از شناسه ی تصویر برای ویژگی های تصویر بر میگرداند .

 

این تابع را میتوان برای تهیه داده های تصویر برای آزمایش مدل هایمان صدا بزنیم ، سپس دیکشنری تولید شده را با نام features.pkl ذخیره کنیم . کد بصورت کامل تر :

 

آماده کردن داده متنی

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

 

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

سپس براساس لیست توضیحات عکس قدم برمیداریم . در زیر تابعی داریم به اسم ()load_descriptions تعریف شده است که یک دیکشنری از شناسه تصویر برای توضیحات برمیگرداند . هر شناسه تصویر به یک لیستی از یک یا چند توصیف متنی map میکند .

 

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

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

  1. تبدیل تمامی کلمات به حروف کوچک
  2. حذف تمامی نشانه ها
  3. حذف تمامی کلماتی که تک کاراکتر یا کمتر هستند (مثلا a)
  4. حذف کلمات شامل عدد

در زیر تابع ()clean_descriptions تعریف شده است که دیکشنری از شناسه ی تصاویر به توضیحات را میگیرد و با قدم برداشتن در طول هر توصیف آن را تمیز میکند .

 

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

 

 

در نهایت میتوان دیکشنری حاصل و توضیحات را در یک فایل جدید با نام descriptions.txt با یک شناسه تصویر و توضیحات در هر خط ذخیره کرد.

در زیر تابع ()save_descriptions را داریم که به عنوان ورودی یک دیکشنری حاوی mappinf شناسه ها به توضیحات و یک اسم فایل میگیرد و mappind را در آن فایل ذخیره میکند.

 

توسعه مدل یادگیری عمیق

در این بخش مدل یادگیری عمیق تعریف میشود و آن را در مجموعه داده های fit ، train میکنیم . این بخش اینگونه تقسیم میشود:

  1. بارگذاری داده
  2. تعریف مدل
  3. fit کردن مدل
  4. تکمیل مثال
بارگذاری داده

ابتدا باید داده های آماده شده عکس و متن را بارگذاری کنیم تا بتوانیم از آن در fit کردن مدل استفاده کنیم . تصمیم گرفتیم داده را روی همه عکس ها و متن های داده train آموزش دهیم . در حین آموزش تصمیم داریم کارایی مدل روی داده توسعه یافته را مانیتور کنیم و از آن برای تصمیم گیری اینکه چه زمان مدل ها را در فایل ذخیره کنیم ، استفاده کنیم . داده train و توسعه یافته به ترتیب در فایل های Flickr_8k.trainImages.txt و Flickr_8k.devImages.txt ذخیره شده است که هردو حاوی لیستی از نام های فایل عکس هاست . از این اسم فایل ها میتوانیم شناسه های تصاویر را استخراج کنیم و از این شناسه ها برای فیلتر کردن تصاویر و توضیحات برای هر مجموعه استفاده کنیم.

تابع ()load_set یک مجموعه از شناسه های داده شده از اسم فایل مجموعه های train و توسعه یافته را بارگذاری میکند .

 

در حال حاضر میتوانیم عکس ها و توصیفات را با استفاده از مجموعه از پیش تعریف شده شناسه های train یا توسعه یافته

در زیر تابع ()load_clean_description برای مجموعه ای از شناسه های داده شده توصیفات متن تمیز شده را از description.txt بارگذاری میکند  و یک دیکشنری از شناسه ها به لیستی از توصیفات متنی برمیگرداند .

مدلی که ما توسعه خواهیم داد یک توصیف یا عنوان را برای عکس داده شده تولید میکند و توصیف در هر لحظه زمانی یک عنوان ایجاد میشود . دنباله ای از کلمات قبلا تولید شده به عنوان ورودی ارائه میشود . بنابراین نیاز به یک کلمه اول برای اولین بار از فرایند تولید و یک آخرین کلمه برای سیگنال پایان توصیف داریم . بدین منظور از رشته “startseq” و “endseq” استفاده میکنیم . این نشانه ها به توصیفات بارگذاری شده اضافه میشوند . مهم است که قبل از اینکه متن را encode کنیم این کار را انجام دهیم تا token ها به درستی encode شوند .

 

در زیر تابعی داریم به نام ()load_photo_features که تمام مجموعه توصیفات عکس را بارگذاری میکند و زیر مجموعه ای از interest را برای یک مجموعه شناسه های عکس داده شده برمیگرداند . این کار خیلی کارآمد نیست با این وجود کار را سریع و اجرا را سریع میکند .

 

گام اول در رمزگذاری داده ها ، ایجاد یک mapping سازگار از کلمات مقادیر عدد صحیح منحصر به فرد است . keras کلاس tokenizer را فراهم میکند که میتواند این mapping را از داده ی توصیف بارگذاری شده ، یاد بگیرد .

در زیر تابع ()to_lines را تعریف میکنیم تا دیکشنری توصیفات را به یک لیستی از رشته ها تبدیل کنیم و تابع ()create_tokenizer هم یک tokenizer داده شده به متن توصیف عکس load شده را fit میکند .

 

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

 

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

تابع زیر به اسم ()build_sequences با توجه به tokenizer ، حداکثر طول sequence و دیکشنری از همه ی توصیفات و عکس ها ، داده را به جفت داده های ورودی/خروجی از داده برای آموزش مدل منتقل میکند.

متن ورودی به عنوان عدد صحیح encode میشود که به یک لایه word embedding داده میشود . ویژگی های عکس بطور مستقیم به قسمت های دیگری از مدل تغذیه میشوند . این مدل پیش بینی میکند که توزیع احتمالی بیش از همه کلمات در واژگان خواهد بود.

داده خروجی یک بردار one-hot از هر کلمه است .

 

ما باید حداکثر تعداد کلمات را در طولانی ترین caption محاسبه کنیم. بدین منظور تابع کمکی به نام ()max_length را تعریف میکنیم .

 

تعریف مدل

ما یک مدل یادگیری عمیق را بر اساس “مدل ادغام” توصیف میکنیم :

مدل را در 3 بخش تعریف میکنیم :

  1. استخراج ویژگی عکس : آن یک مدل از پیش آموزش داده شده  VGG -16 -layer روی دیتاست imageNet است . ما روی عکس ها پیش پردازشی با مدل VGG انجام دادیم (بدون لایه خروجی) و از ویژگی های استخراج شده پیش بینی شده توسط این مدل به عنوان ورودی استفاده خواهیم کرد .
  2. پردازنده Sequence : این یک لایه embedding برای کنترل ورودی متن است که توسط یک لایه شبکه عصبی بازگشتی LSTM دنبال میشود .
  3. Decoder : خروجی استخراج ویژگی و پردازنده sequence هردو یک آرایه با طول ثابت است . اینها با یکدیگر ترکیب شده و با یک لایه dense برای پیش بینی نهایی پردازش می شوند .

مدل استخراج ویژگی عکس ها انتظار دارد ویژگی های عکس ورودی  یک وکتور 4096 عنصری باشد . اینها توسط یک لایه dense برای تولید 256 عنصر مورد استفاده قرار میگیرند .

مدل پردازنده sequence انتظار دارد sequence های ورودی با یک طول از قبل تعریف شده (34 کلمه) که به یک لایه embedding که یک mask برای نادیده گرفتن مقادیر padded استفاده میکند ، fed میشود . این توسط یک لایه LSTM با 256 واحد حافظه دنبال میشود .

هر دو مدل ورودی یک آرایه 256 عنصری تولید میکند . علاوه بر این هر دو مدل ورودی از Regularization بصورت 50% dropout استفاده میکند . این کار در جهت کاهش overfitting روی دیتاست training ، باعث یادگیری سریع مدل میشود .

مدل decoder وکتور هایی از هردو مدل های ورودی را با استفاده از یک عملیات اضافه ادغام میکند . سپس به یک لایه نورون 256 تایی dense و بعد از آن به یک لایه dense خروجی نهایی که یک پیش بینی softmax را در طول همه ی واژگان خروجی برای کلمه بعدی در جمله ایجاد میکند ، میفرستد .

تابع ()define_model بصورت زیر تعریف میشود و مدل را آماده برای fit شدن برمیگرداند .

 

یک طرح برای مشاهده ساختار این شبکه برای درک بهتر در زیر آورده شده است :

fit کردن مدل

این مدل overfit های داده training را سریع یاد میگیرد به همین دلیل ما مهارت مدل آموزش داده شده را روی مجموعه داده های توسعه monitor خواهیم کرد. وقتی مهارت مدل در مجموعه داده توسعه در پایان یک epoch بهبود یافت ، ما کل مدل را در فایلی ذخیره میکنیم .

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

ما میتوانیم این کار را با تعریف یک ModelCheckpoint در کراس انجام دهیم آن را مشخص کنیم تا مینیمم loss را روی دیتاست validation داشته باشیم و مدل را در یک فایلی که هم training loss و هم validation loss دارد ذخیره میکنیم .

 

 

 

Cyclic-learning-rate and Stochastic Gradient Descent with Restarts

یافتن Learning Rate مناسب

مروری بر ایده learning rate decay

جلسه قبل راجع به راهکار learning rate decay صحبت کردیم.این راهکار بدین صورت بود که ابتدا با lr بزرگ شروع می کردیم و ذره ذره lr را کم میکردیم.چرا؟!چون در ابتدای آموزش شبکه که هنوز وزنهای شبکه خوب مقداردهی نشده اند و از global minimum  دور هستیم میتوانیم گامهای بلندی برداریم که این گامهای بلند هم در تسریع اموزش کمک میکند  و به اصطلاح زودتر همگرا میشویم وهم از گیر افتادن در local minimum ها جلوگیری میکنند.

اما رفته رفته با به روز شدن وزنها ماهم به global minimum نزدیکتر میشویم و بهتر است گامهایمان را محتاطانه تر یعنی کوتاهتر برداریم زیرا گامی بزرگ مارا از نقطه بهینه پرت خواهد کرد.

حال برای کم کردن lr بعضی از افراد به صورت exponential رفتار میکنند.مثلا هربار بعد از چند epoch آن را بر 10 تقسیم میکنند و بعضی دیگر به صورت خطی رفتار کرده و میگویند مثلا بعد از تعدادی epoch بر 2 تقسیم شود.

ایده cyclical learning rate

دراین ایده ابتدا از lr کوچکی شروع کرده و سپس در هر step(mini batch) آن را 2 برابر کرده تا به نقطه ای میرسیم که با اینکه کمترین loss  را دارد اما lr آن بزرگ بوده و مارا از global minimum  دور ساخته است.پس آن نقطه را نباید انتخاب کنیم وlr  موردنظر را ازیک پله عقبتر ینی از آن قسمتهایی که نزدیک به این نقطه (که دارای loss کمینه است) انتخاب میکنیم.

نقطه نشان داده شده در تصویر همان نقطه ی با loss کمینه و lr بزرگ است که نباید انتخاب کنیم.

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

ایده stochastic gradient descent with restarts

ممکن است ما مینیمم های زیادی داشته باشیم که تقریبا به یک اندازه برای ما تابع loss  را تعیین کنند ولی برای ما به اندازه ی یکسان اهمیت ندارند.یک سری robust تر هستند و سری دیگر اینطور نیستند.(ناپایدارند)

در این راهکار ابتدا یک lr  نسبتا زیادی را انتخاب میکنیم .سپس آن را به صورت کسینوسی کم میکنیم.به این صورت که اول یک مقداری lr اولیه میماند سپس کم میشود و باز مدتی با lr کاهش یافته باقی میماند سپس دوباره مثلا یک ایپاک میزند و lr را زیاد میکند.(به صورت کلی به صورت کسینوسی مدام lr را زیاد و کم میکنیم)

علت اینکار چیست؟!

فرض کنید ما به نقطه ای رسیدیم که loss آن کمینه است اما ما میخواهیم با انتخاب یک lr به جایی از این مساله برویم که هم loss کمینه بوده و هم آن نقطه نسبت به تغییرات جزیی robust تر(پایدارتر) باشد.پس با زیاد کردن lr  این احتمال به وجود می آید که از این قله ها بپریم به مکان های flat تر برویم.

چرا مکان های flat تر بهتر هستند؟

فرض کنید دیتای train و test ما از منابع متفاوتی باشند.در این صورت در قسمت هایی که تابع ما flat تر میباشد تغییرات جزیی تر بوده و احتمال یکی بودن loss داده های train  و  test با وجود تفاوتشان،بیشتر میباشد.پس با تغییرات جزیی loss  ما در زمان test  خراب نمیشود.

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

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

 

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

اما به دلیل overhead زیاد این ایده را جرمی هاوارد(نویسنده کتابخانه fastAI) پیاده سازی نکرده است.

در نقاط 1 و  2 و 3 شبکه های حاصل از وزنهای ذخیره شده را داریم.

ایده  transfer learning

هنگامی که مساله ما خیلی دورتر از مساله imagenet است به طوری که ویژگی های لایه ی اول نیز؛که ویژگی های پایه و عمومی و ساده بودند، به درد ما نمیخورد باید چه کار کرد؟

میدانیم که به هرصورت بودن وزنهای train شده بهتر از نبودنشان است(خیلی خیلی بهتر از وزنهای رندوم است.)

اما برای حل این  مساله چه کار میکنیم؟!لایه های شبکه را به 3 قسمت low level(لایه های ابتدایی کانولوشنالی) و medium level (لایه های میانی کانولوشنالی)و high level(fully connected ها)تقسیم میکنیم.سپس به هرکدام از این قسمت ها یک lr مجزا تخصیص میدهیم.(differential learning rate)

لایه های ابتدایی:با lr مثلا 00001/0

لایه های میانی:با lr مثلا 01/0

لایه های نهایی:با lr مثلا 1/0 (بعد از train کردن لایه های fully connected که خراب نکند.)

که این ایده بیانگر این است که لایه های ابتدایی کمتر تغییر کنند(کمتر train  شوند) و لایه های میانی کمی بیشتر تغییر کنند و لایه های نهایی به طبع بیشتر از هردو تغییر کند.