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

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

آمار در 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  شوند) و لایه های میانی کمی بیشتر تغییر کنند و لایه های نهایی به طبع بیشتر از هردو تغییر کند.

GRU & LSTM

Recurrent Neural Networks

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

در ادامه به بررسی شبکه های LSTM و GRU میپردازیم.

یادآوری:

شبکه ی RNNشامل تعدادی Hidden نورون است که این Hidden نورون ها تکرار میشوند به طوری که انگار در طول زمان باز و تکرار میشوند.

 

Notations:

X1,X2,….Xn   ورودی های شبکه هستند که به مرور زمان به شبکه میدهیم به طور مثال اگر بخواهیم کلمه کلمه  به شبکه بدهیم ابتدا X1 , … الی آخر پشت هم می آیند. این ورودی ها شامل یک سری وزن هستند که با Wax نمایش میدهیم و یک سری وزن که از state مرحله ی قبلی ورودی میگیرد که همان حافظه ی ما  و خروجی را تشکیل میداد .

a  : خلاصه ای از ورودی های قبلی است که دار ی حافظه است و براسا ورودی هی قبلی و ورودی فعلی تصمبم میگیرد.

Simple syntax RNN:

 

برای ساده تر شدن از این پس تنها یک بردار وزن برای ‌X و a خواهیم داشت که در کنار هم این دو Concatمیشوند.

در نهایت :

مشکل RNNها :

استفاده از این شبکه برای جملات کوتاه مشکلی ایجاد نمی کند.اما اگر جمله ی ما ادامه پیدا کند این شبکه نمیتواند به صورت Long Term جمله را حفظ کند و اصطلاحا مشکل Wanishing Gradiant به وجود میاید .

RNN Unit:

مطابق شکل  یک وزنی داریم که در concat شده ی ورودی و  stateقبلی ضرب میشود و به activation function داده میشوند که y hatما را تشکیل میدهد.

 

GRU:

برای حل مشکل Wanishing Gradiant  برای جملاتی مثل :

The cat, which already ate …, was full.

برای اینکه بدانیم در جای خالی با توجه به ضمیر چه چیزی به کار ببریم نیاز داریم حافظه ی طولانی تری داشته باشیم .

در gru به state که داریم c میگوییم که مخفف cell است .به عبارتی cهمان <a<t قبلی است .

بجای مشخص شدن stateجاری یک stateپیشنهادی داریم~C که کاندیدی برای stateجاری است که هنوز به صورت قطعی قرار نیست  stateجاری باشد.

ورودی جاری و state قبلی در هم concatشده و در وزن Wc ضرب میشوند.

GRU Simplified:

تفاوت با RNNساده :

یک سری گیت اضافه شده برای بررسی پذیرش کاندید state

برای بررسی آپدیت گیت یک activation function sigmoid داریم .(0:بروز نکن ,1:بروز کن)

رای تعیین <C<t اگر  Г آپدیت برابر با 1 بود بروز رسانی صورت میگیرد و اگر 0 باشد , کاندید state را نمیپذیرد و stateمرحله قبل را در نظر میگیرد.

Full Gru:

در Full GRU یک گیت جدید اضافه میکنیم  که بررسی میکند stateمرحله قبل چقدر به context جاری مربوط میشود.

activation function گیت جدید یک sigmoid است که مقدار 0 یا 1 برمیگرداند و تصمیم میگیرد حافظه قبلی چقدر به ورودی جاری مربوط میشود و براساس ورودی میتواند تصمیم بگیرد ,گیت حافظه را برای خروجی دادن این state در نظر بگیرد یا خیر.

LSTM:

شبکه‌های LSTM که خلاصه شده عبارت “Long Short Term Memory” هستند، نوع خاصی از شبکه‌های عصبی بازگشتی هستند که توانائی یادگیری وابستگی‌های بلندمدت را دارند و مشکل ‌wanishing gradiant حل کردند.این شبکه‌ها برای اولین بار توسط Hochreiter و Schmidhuber در سال ۱۹۹۷ معرفی شدند.

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

 

مقایسه بین LSTM و GRU

در lstm گیت Γr نداریم این گیت مشخص میکند چه میزان از حافظه را دخیل کند اگر 0 باشد به طور کلی اثر حافظه  را از بین میبرد,میتوان قرار داد اما ضروری نیست.

lstmدر مقایسه با gru تعداد گیت های بیشتری دارد. در lstm برای فراموش کردن هم یک گیت اضافه شده و مشخص میکند برای برای بازنویسی< C<t چه میزان کاندید state را تاثیر بدهیم به عبارتی چقدر بخاطر بسپرد و چقدر فراموش کند.

 

Bidirectional RNN:

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

 

Deep Rnn:

مطابق شکل state مرحله قبل که رسیده توی کروشه 1 در نظر گرفته شده یعنی برای لایه اول و برای هر لایه عدد کروشه متفاوت است .در هر مرحله state ایجاد میکنند و به مرحله ی بعدی میروند .میتوانیم این state را به یک softmax و یا sigmiodوصل کنیم .این state ها زمانی که شروع میشوند با 0 مقدار دهی میشوند ,لایه ها روی هم stack شده و یک شبکه دیپ ایجاد میکنند .y های خروجی قرار است برای ما چیزی حساب کنند در طول زمان X دریافت کرده اند و یک state خود yهم چند لایه است ,میتوانیم مستقل از دیپ بودن قبلش خروجی لایه را به یک شبکه cnnبدهیم :

 

استفاده از خروجی y :

تولید متن با شبکه بازگشتی LSTM در Keras

در این مثال به پیاده سازی یک شبکه lstm میپردازیم که بر روی کتاب فیلسوف آلمانی نیچه به صورت

character-level پیاده سازی شده.

ابتدا مجموعه داده را بارگذاری میکنیم:

 

توسط maxlen مشخص میکنیم به شبکه چند حرف چند حرف بدیم . در این مثال طول کلمات 60 تایی است و ممکن است  این 60 تا وسط کلمه تمام شود یا بیشنر از طول رشته ی ورودی باشد.

در for زیر کاراکتر 61 ام به عنوان label در نظر گرفته میشود.

توسط setنیز تعداد کاراکتر های یونیک را مشخص میکنیم.

 

ایجاد شبکه (Building the network)

 

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

 

و در نهایت ایجاد متن 

 

نمونه خروجی متن ایجاد شده :

multi-label classification in fastAI

در جلسات قبل با مفهوم multi label classification آشنا شده و یک نمونه از پیاده سازی آن را در فریم ورک کراس مشاهده کردیم.

Multi Label Classification

به طور خلاصه میتوان گفت در single label classification ما به طور همزمان تنها میتوانیم یک کلاس به عنوان پاسخ داشته باشیم مثلا گربه یا سگ اما در multi label classification میتوان همزمان چند جواب داشت مانند تصاویر ماهواره ای  که در آن ها میشود همزمان رودخانه، کوه، جنگل و … را مشاهده کرد.

پیاده سازی multi label classification در فریم ورک کراس برای ما محدودیت هایی به همراه داشت که مهمترین آن این است که در کراس ما باید به ازای هر label  یک پوشه داشته باشیم که این مسئله زمانی که تعداد کلاس های ما زیاد میشود و ما میخواهیم هربار ترکیبات مختلفی از این کلاس ها را به عنوان label‌ نهایی داشته باشیم برای ما مسئله ساز میشود.

ادامه خواندن multi-label classification in fastAI

Multi Label Classification

Multi Label Classification چیست ؟

می دانیم در  شبکه های کانولوشنی که دارای یک سری لایه ی میانی و لایه های ورودی و خروجی هستند ، در لایه های میانی اکثرا از Activation RELU  و در لایه ی خروجی از Activation  های Softmax  و Sigmoid   استفاده می شود.

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

Activation Softmax  زمانی استفاده می شود که بخواهیم بیش از 2 کلاس را تشخیص دهیم ، برای مثال وقتی میخواهیم 5 میوه را به شبکه آموزش دهیم در لایه ی آخر Activation Softmax را استفاده میکنیم که در واقع تبدیل Exponential عدد خروجی لایه ی آخر که مثلا میتواند به صورت اعداد 12- ، 10 ، 5 ، 2 و 6- باشد گرفته شده و با هم جمع میگردد و سپس هرکدام از این اعداد به این حاصل جمع تقسیم می شود ، که اعداد به دست آمده در بازه ی 0 تا 1 خواهند بود . عددی که بیشترین مقدار را داشته بیشترین مقدار را در این بازه خواهد داشت و عددی که کمترین مقدار را داشته کمترین مقدار را در این بازه خواهد داشت ، مثلا عدد 10 به معادل 0.95 میرسد و این نشان دهنده ی برنده بودن کلاس مربوط به این نورون خواهد بود .

اشکال توابع Sigmoid و RELU به این شکل می باشد :

اما تمام آنچه گفته شد مربوط به زمانی است که ما بخواهیم وجود یک Object  را تشخیص دهیم .

برای مثال در صورت داشتن یک عکس ماهواره ای که قصد داریم در آن تصویر وجود دریا و جنگل و … را بدانیم باید به شکل دیگری عمل کنیم ، و در واقع باید در لایه ی آخر نورون های مربوط به Object های موجود در تصویر True شده و نورون های مربوط به تصاویر غیر موجود در تصویر False شوند . به این نوع مسایل Multi Label Classification می گویند به عبات دیگر لایه ی اخر میتواند بیشتر از یک برنده داشته باشد و یا هیچ برنده ای نداشته باشد.


پیاده سازی Multi Label Classification در Keras :

برای پیاده سازی Multi Label Classification در Keras ابتدا کلاس های مورد نظر را import و پوشه ی دیتا ست مورد نظر را معرفی می کنیم.

 

 

Dataset مورد استفاده برای مساله ی مورد بررسی دارای پوشه هایی بدین شکل است که داخل هر کدام فولدر های Test  و Train  وجود دارند .

  • پوشه ی Black_jeans
  • پوشه ی Blue_jeans
  • پوشه ی Blue_shirt
  • پوشه ی Red_shirt

بدین ترتیب شبکه ی ما باید به شکلی بتواند تشخیص دهد که آیا در تصویر ورودی Jeans یا shirt  ویا رنگ آبی یا قرمز و یا مشکی وجود دارد یا خیر و چون در لایه ی اخر میتوانیم وجود بیش از یک Object را تشخیص دهیم ( آبی ، قرمز ، مشکی ، shirt و jeans ) این مساله ، مساله ی Multi Label Classification است . در واقع نورون های لایه ی اخر که هر کدام برای یکی از object های مورد نظر می باشند ،  باید به یک Sigmoid متصل شوند تا در صورت تشخیص آن شی در تصویر Fire  کنند.

مثلا در تصویر مقابل هم رنگ قرمز را داریم هم وجود Shirt پس باید در لایه ی اخر نورون های مربوط به رنگ قرمز و Shirt  که هرکدام به یک  Sigmoid  متصل هستند True شده و بقیه False شوند .

و یا اگر تصویر مقابل را که هیچ کدام از Object های shirt و jeans و red و blue و black در آن نیست به شبکه بدهیم در لایه ی آخر هیچ کدام از Sigmoid ها نباید Fire کنند.

همانطور که در کد زیر مشاهده مینمایید بعد از تنظیم مقدار Epochs  ، Learning Rate و Batch Size با استفاده از

میتوانیم تمام تصاویر موجود در دیتاست را در یک لیست به نام imagePaths  نگه  داریم . سپس آن را shuffle میکنیم تا عکس هایی که در یک پوشه بودند پشت هم قرار نگیرند.( دلیل اینکه از DataGenerator استفاده نمیکنیم این است که در Keras هر پوشه به منزله ی یک کلاس میباشد ولی در Multi Label Classification اینگونه نیست )

در مرحله ی بعد تمام عکس ها را خوانده و به سایز 96 در 96 ریسایز کرده و تابع mg_to_array را برایشان فراخانی می  کنیم، سپس آن ها را در لیست Data  میریزیم.

با استفاده از :

از کل آدرس پوشه ی در دیتا ست قسمت نام آن را برمی داریم ، سپس دو کلمه ی آن را از محل “_” جدا می کنیم و در یک لیست به نام Labels میریزیم.

در مرحبه بعد دیتا ها را نرمال می کنیم.

اگر لیست Labels را چاپ کنیم خواهیم دید که لیستی از دوتایی ها خواهد بود که این دوتایی ها نام پوشه هایی هستند که از محل “_” جدا کردیم .

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

 

 

 

 

در قسمت بعد از کتابخانه ی scikit-learn استفاده کردیم و با استفاده از MultiLabelBinarizer هر کدام از دوتایی های لیست Labels را به حالت 0 , 1 درآوردیم تا بجای هر کلاسی که در آن بود مقدار 1 و به جای هر کلاسی که آن را وجود نداشت مقدار 0 را قرار دهیم ، به علاوه نام کلاس ها را چاپ کردیم:

اگر لیست Labels را بعد از این عملیات چاپ کنیم آن را به این شکل مشاهده میکنیم :

 

 

 

 

سپس کلاس های موجود را چاپ میکنیم:

 

با استفاده از قطعه کد زیر از کل دیتا های موجود 80 درصد آن را برای Train و 20 درصد آن را برای Test برمیداریم :

سپس عملیات Augmentation را روی دیتا های خوانده شده انجام میدهیم :

شبکه ای با معماری زیر میسازیم :

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

سپس Optimizer Adam را با تنظیم کردن Learning Rate و کم کردن آن در هر epoch ( با تقسیم کردن بر شماره  epoch ) ایجاد میکنیم :

در مرحله آخر مدل را Compile و نمودار های مربوط به Accuracy و Loss در Train Data و Test Dataرا رسم میکنیم میکنیم :

در آخر مدل را با پسوند h5 و Label ها را به صورت Pickle File  ذخیره میکنیم .( اگر با فرمت Pickle.dumps در فایل بنویسیم یک آبجکت پایتونی را مستقیما در یک فایل میریزد و اگر Load آن را صدا بزنیم همان آبجکت پایتونی را Load  میکند .)

 


استفاده از مدل Save شده :

در ابتدا کتابخانه های مورد نیاز را Import میکنیم :

سپس عکسی را از ورودی خوانده ، آن را resize  میکنیم و نمایش میدهیم :

سپس عکس را به سایز 96 در 96 resize و با تقسیم بر 255 آن را نرمال میکنیم ، به علاوه تابع img_to_array را فراخانی کرده و بعد با exapnd_dim یک dimension به آن اضافه میکنیم ( چون به صورت دیفالت با batch کار می کند و با اضافه کردن یک dimension ، انگار به آن یک batch میدهیم که در واقع در آن یک عکس بیشتر نداریم )

آدرس مدل و Label ها را که به صورت Pickle File ذخیره کرده بودیم  ، مشخص میکنیم .

سپس مدل و Label ها را Load میکنیم :

عکس مورد نظر را به مدل می دهیم و از بالاترین احتمالات دوتای اول آن را روی عکس چاپ میکنیم .

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

که خروجی مطابق زیر خواهد داشت :

 

 

 

همانطور که مشاهده میکنید کلاس های red و shirt با بیشترین احتمالات درست تشخیص داده شده اند.

 

Batch Normalization و Learning Rate Decay

 

Batch Normalization

 

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

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

 

 

 

ادامه خواندن Batch Normalization و Learning Rate Decay

کار با تصاویر توسط ImageMagick

نویسندگان ‌: محیا مهدیان و محمد حسن ستاریان

imagemagick

ImageMagick یک مجموعه فوق‌العاده از کتابخانه (Libraries) و برنامه (Binaries) رایگان و متن‌باز و چندسکویی برای کار با تصاویر پیکسلی (Raster Graphics) و برداری (Vector Graphics) با امکانات فراوان برای نمایش، تبدیل، تغییر و ویرایش است و می‌تواند با بیش از ۲۰۰ فرمت مختلف تصویر کارکند. از این برنامه می‌توان از طریق رابط خط فرمان (CLI) و یا برنامه‌ های نوشته شده توسط کتابخانه‌های آن در زبان‌های دیگر استفاده کرد. برای آشنایی با ImageMagick تنها به این پست اکتفا نکرده و حتما مستندات آن را بخوانید.

برای مثال تمامی تغییرات زیر به راحتی با استفاده از خط فرمان قابل اعمال به تصاویر هستند:

ImageMagick examples

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

نصب

ImageMagick چندسکویی بوده و برای سیستم‌عامل‌های مختلف در دسترس است. برای استفاده از آن می‌توان از کتابخانه‌های آن برای زبان‌های مختلف من جمله C و ++C، پایتون، PHP و غیره استفاده کرد و یا برنامه‌های آماده (Binaries) آن را نصب و استفاده کرد.

ویندوز

برای نصب ImageMgick در ویندوز می‌توان فایل نصب (exe) آن را دریافت کرد و یا با استفاده از پکیج منیجر Chocolatey (از اینجا دریافت کنید) با وارد کردن دستور زیر در CMD آن را نصب کرد:

لینوکس

برای نصب ImageMagick روی لینوکس، از دستورات زیر استفاده می‌کنیم:

اطلاعات بیشتر

روش استفاده

استفاده از ImageMagick توسط رابط خط فرمان بسیار ساده است (لیست مثال‌های استفاده). قالب اجرای دستورات با استفاده از دستور magick --help  و magick -usage  به صورت زیر است (برای مشاهده کامل خروجی روی کد دوبار کلیک کنید):

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

در ویندوز تمامی عملیات‌ها با دستور magick  شروع و گاهی لازم است پس از دستور  magick  علمیات مربوطه نیز نوشته شود (لیست دستورات)، اما در لینوکس دستورات با اسم عملیات شروع می‌شوند.

پس توجه داشته باشیم دستورات به فرم magick convert  در لینوکس به صورت convert  استفاده خواهند شد.

همچنین ImageMagick از globbing برای آدرس‌دهی پشتیبانی می‌کند. بنابراین بجای تغییر چندین تصویر بجای دستور حلقه زیر:

از دستور زیر استفاده می‌کنیم:

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

دستورات

نمایش (Display)

برای نمایش تصویر می‌توان در ویندوز از دستور imdisplay  و در لینوکس از magick display  استفاده کرد.

تبدیل (Convert)

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

همچنین با استفاده از دستور convert  نیز می‌توان فرمت تصویر را تغییر داد و به علاوه این دستور می‌هواند تغییرات دیگری نیز در حین تغییر فرمت بدهد. برای مثال دستور زیر لبه‌های تصویر (که نتیجه اعمال فیلتر canny با سایز کرنل مشخص شده است) را در فایل خروجی ذخیره می‌کند:

canny filter

کاهش کیفیت (Reduce Quality)

از راه‌های فشرده‌سازی تصویر کاهش رزولوشن آن است با دستور زیر می‌توان درصد کیفیت تصویر خروجی را مشخص کرد. اینکار نیز با دستور convert  قابل انجام است:

تغییر سایز (Resize)

برای تغییر سایز تصویر می‌توان از دستور resize استفاده کرد. روش‌های دیگر مشخص کردن سایز خروجی را ببینید.

با استفاده از دستور mogrify نتیجه در خود تصویر ورودی ذخیره می‌شود بنابراین دیگر نیازی به مشخص کردن فایل خروجی نیست.

تصویر مختلط (Collage)

به کمک magick به سرعت و تنها با یک دستور می‌توانیم یک تصویر مختلط از چندین تصویر درست کنیم:

با اجرای خط اول تصویر خروجی کیفیت خوبی نخواهد داشت، دلیل آن مقادیر پیش‌فرض برای geometry  است که برابر ۱۲۰ پیکسل تنظیم شده. در خط دوم با وارد کردن مقدار مورد نظر برای geometry  گفته‌ایم سایز تصاویر تغییر نکنند و سایز حاشیه تصاویر را برابر ۱۰ پیکسل تنظیم کرده‌ایم.

بریدن تصویر (Cropping)

برای بریدن تصویر از طرفین می‌توان از دستور shave  استفاده کنیم:

دستور اول ۱۰ پیکسل از محور x و ۱۰ پیکسل از y از دو سمت تصویر را برش می‌دهد؛ دستور دوم تنها ۱۰ پیکسل از دوسمت محور x تصویر و دستور سوم ۲۰ پیکسل از دو سمت محور y تصویر  را بر می‌دهند.

shave command

برای بریدن ناحیه دلخواه از تصویر باید از دستور crop  استفاده کنیم. آدرس تصویر نوشته شده ( :rose ) آدرس عکس‌های نمونه قابل استفاده شناخته شده توسط magick است که برای تست می‌توان استفاده کرد.

دستور اول عکسی با سایز ۴۰ پیکسل در ۳۰ پیکسل تولید خواهد کرد که از مختصات ۱۰ در ۱۰ تا تصویر برش زده خواهد شد -درواقع برشی به طول ۴۰ پیکسل و عرض ۳۰ پیکسل از مختصات ۱۰ در ۱۰ از تصویر گرفته می‌شود؛ بدیهی است اگر ناحیه برش از تصویر بزرگتر باشد تنها قسمت برش خورده، تصویر خروجی خواهد بود- دستور دوم تصویری خروجی با حداکثر اندازه ۰ پیکسل در ۳۰ پیکسل خواهد داشت که نتیجه برش از مختصات ۴۰ در ۳۰ است، برای دستور سوم نیز تصویری خروجی برابر نتیجه برشی با اندازه ۴۰ پیکسل در ۳۰ از مختصات ۱۰- در ۱۰-  و دستور چهارم، تصویر خروجی ای از نتیجه برش تصویر به مساحت ۹۰ پیکسل در ۶۰ از مختصات ۱۰- در ۱۰- خواهد داشت؛ چون که این ناحیه شامل کل تصویر است تصویر خروجی با ورودی تفاوتی ندارد. در دستور پنجم که عکس خروجی نتیجه برش تصویر از مختصات ۹۰ در ۶۰ با سایز ۴۰ پیکسل در ۳۰ پیکسل خواهد بود، ناحیه برش هیچ قسمتی از عکس را شامل نمی‌شود، بنابراین عکسی خالی خواهد ساخت.

crop

چرخاندن (Rotation)

برای چرخواندن تصویر به صورت زیر عمل می‌کنیم. مقدار مثبت rotate  به معنی چرخش ساعتگرد و مقدار منفی آن به معنی چرخش پادساعتگرد است.:

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

توجه کنید که برای داشتن تصویر بدون پس‌زمینه، به فرمتی آن را ذخیره کنید که از کد رنگ آلفا پشتیبانی کند. برای مثال فرمت png  تصویر بدون پس‌زمینه را به درستی ذخیره می‌کند اما فرمت jpg  تصویر بدون پس‌زمینه را با پس‌زمینه سفید ذخیره می‌کند.

rotate

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