pix2pix & cyclegan

به نام خدا

کلاس نوت – محمد حسین نیکی ملکی
مقدمه ای بر cyclegan & pix2pix

ساختار شبکه ای pix2pix از ساختار شبکه های شرطی GAN برای ساخت دیتا ها و تبدیل و generate کردن آن هااستفاده میکند .
فرض کنید تصاویری ورودی شبکه ما باینری شده و انتظار خروجی شبکه امان هم از همان جنس دیتا رنگی rgb باشد .طبیعتا انتظار داریم که generator در اینجا یاد بگیرد که چطور رمگ امیزی کند .و همچنین discriminator هم تلاش میکند تا تفاوت بین رنگی که generator تولید کرده و رنگ اصلی به نظر صحیح که در بین دیتاست ها بوده را محاسبه کند .

ساختار generator بصورت “encoder-decoder” است و pix2pix هم تقریبا مانند همین (در شکل پایین هم میبینید ) است .

مقادیر دایمنشن های هر لایه در کنار آن نوشته شده است .در اینجا ورودی شبکه ما یک 256*256*3 است و پس از اعمال تغییرات دوباره به همان شیپ ابتدایی در خروجی باز میگردد .
در اینجا generator ورودی هارا میگیرد وبا انکودر ها مقادیرش را کم میکند ( لازم به یاداوری است که انکودر محصولی از کانولوشن و اکتیویشن فانکشن مربوطه است .) همچنین در ادامه ی مسیر هم از دیکودر برای بازگشت ز مسیر استفاده میکنیم .
نکته : برای بهبود \رفورمنس شبکه و سرعت پردازش میتونیم از شبکه unet هم به جای encoder-decoder استفاده کنیم . شبکه unet در واقع همون encoder-decoder است اما بصورت موازی هر لایه encoder را به لایه decoder مربوطه اش متصل میکند و سودش در این است که ممکن است به برخی از لایه ها احتیاجی نداشته باشیم و از آنها ب\ریم و گذر نکنیم .
Descriminator :

کار descriminator این است که دو عکس یکی از ورودی و یکی از خروجی یا عکس هدف میگیرد و تصمیم میگیرد که ایا عکس دوم توسط generator ساخته شده است یا خیر .

ساختار DISCRIMINATOR شبیه به ENCODER-DECODER به نظر میرسد اما فرق دارد .

خروجی اش یک عکس ۳۰ در ۳۰ باینری است که مشخص میکند چقدر قسمت های مختلف عکس دوم به اول شبیه هستند . در پیاده سازی PIX2PIX هر پیکسل ۳۰ در ۳۰ به یک قسمت ۷۰ در ۷۰ عکس ورودی مپ میشود .

How to train :

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

cyclegans :

pipx2pix میتواند خروجی های بینظیری را تولید کند . چالش اصلی در قسمت ترین است . قسمت لیبل زدن و دو عکسی برای عملیات ترینینگ باید به ورودی شبکه بدهیم به عنوان x و y .
که ممکن است کار را برا ی ما بسیار سخت و گاها غیر ممکن کند.
به خاطر همین از سایکل گن ها استفاده میکنیم .
نکته اصلی انها این است که میتوانند بر اساس معماری pix2pix هم پیاده سازی بشوند اما به شما اجازه دهند که به دو مجموعه از تصاویر اشاره کنید و فراخوانی کنید .
در اینجا بعنوان مثال فرض کنید دو دسته عکس از ساحل دارید یکی در زمان صبح و دیگری در عصر هنگام غروب . سایکل گن میتواند یادبگیرد که چگونه عکس های مربوط به صبح را به عصر تبدیل کند و برعکس بدون آنکه نیاز باشد تا بصورت یک در یک مقابل هم قرارشان دهیم . دلیل اصلی که سایکل را تا این حد قدرتمند کرده پیاده سازی این فرضیه است که بطور کامل تبدیل رفت و برگشتی صورت میپذیرد که باعث میشود هردو جنریتور هم بطور همزمان تقویت شوند .

Loss function :

قدرت سایکل گن در این است که loss function ای برای هر سایکل رفت و برگشت ست میکند و آن را به عنوان یک optimizer اضافی در مسله قرار میدهد .
در این قسمت نحوه ی محاسبه ی loss function برای generator را میبینیم :


g_loss_G_disc = tf.reduce_mean((discY_fake — tf.ones_like(discY_fake)) ** 2)
g_loss_F_dicr = tf.reduce_mean((discX_fake — tf.ones_like(discX_fake)) ** 2)


g_loss_G_cycle = tf.reduce_mean(tf.abs(real_X — genF_back)) + tf.reduce_mean(tf.abs(real_Y — genG_back))
g_loss_F_cycle = tf.reduce_mean(tf.abs(real_X — genF_back)) + tf.reduce_mean(tf.abs(real_Y — genG_back))

در این قسمت نحوه ی محاسبه ی loss function برای discriminator را بررسی میکنیم :


DY_loss_real = tf.reduce_mean((DY — tf.ones_like(DY))** 2)
DY_loss_fake = tf.reduce_mean((DY_fake_sample — tf.zeros_like(DY_fake_sample)) ** 2)
DY_loss = (DY_loss_real + DY_loss_fake) / 2
DX_loss_real = tf.reduce_mean((DX — tf.ones_like(DX)) ** 2)
DX_loss_fake = tf.reduce_mean((DX_fake_sample — tf.zeros_like(DX_fake_sample)) ** 2)
DX_loss = (DX_loss_real + DX_loss_fake) / 2

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

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

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

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

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

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

 

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

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

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

Differential Operators

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

Image Gradient

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

Discrete Gradient

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

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

Partial Derivatives of an Image

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

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

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

Sobel Operator

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

Sobel Operator On Block Images

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

But In The Real World…

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

Finite Differences Responding to Noise

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

Gradients -> Edges

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

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

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