{"metadata":{"kernelspec":{"language":"python","display_name":"Python 3","name":"python3"},"language_info":{"pygments_lexer":"ipython3","nbconvert_exporter":"python","version":"3.6.4","file_extension":".py","codemirror_mode":{"name":"ipython","version":3},"name":"python","mimetype":"text/x-python"}},"nbformat_minor":4,"nbformat":4,"cells":[{"cell_type":"markdown","source":"<p dir=\"rtl\" style=\"text-align: center;\"><span style=\"font-size: 24pt;\"><strong>یک نقاش دیجیتال شو!</strong></span></p>\n<p dir=\"rtl\" style=\"text-align: center;\"><span style=\"font-size: 18pt;\"><strong>به مانند مونه</strong></span></p>\n<p dir=\"rtl\" style=\"text-align: justify;\"><span style=\"color: #ff0000; font-size: 18pt;\"><strong>• GAN یا شبکه‌های متخاصم مولد</strong></span></p>\n<p dir=\"rtl\" style=\"text-align: justify;\"><span style=\"font-size: 14pt;\">یکی از معماری‌های یادگیری عمیق، <strong>شبکه‌های گن</strong> می‌باشند. شبکه‌هایی که در فارسی به آن‌ها <strong>متخاصم مولد</strong> می‌گویند. قابلیت اصلی این شبکه‌ها، <strong>تولید داده</strong> جدید است. یعنی ما با استفاده از شبکه‌های گن، می‌توانیم داده‌های کاملا جدید و متفاوت از هم تولید کنیم.</span></p>\n<p dir=\"rtl\" style=\"text-align: justify;\"><span style=\"font-size: 14pt;\">برای مشاهده اطلاعات بیشتر درباره این شبکه‌ها، به <a href=\"https://papers.nips.cc/paper/5423-ge...al-nets.pdf\">اینجا</a> مراجعه کنید.</span></p>\n<p dir=\"rtl\" style=\"text-align: justify;\"><span style=\"font-size: 14pt;\">از کاربردهای شبکه گن می‌توان به <a href=\"https://arxiv.org/abs/1710.10196\">ایجاد تصاویر جدید انسان</a>، <a href=\"https://arxiv.org/pdf/1708.05509\">ایجاد تصاویر کارتونی</a>، <a href=\"http://openaccess.thecvf.com/content_ICCV_2017/papers/Zhu_Unpaired_Image-To-Image_Translation_ICCV_2017_paper.pdf\">تبدیل تصاویر به یکدیگر</a>، <a href=\"https://openaccess.thecvf.com/content_ICCV_2017/papers/Zhang_StackGAN_Text_to_ICCV_2017_paper.pdf\">تبدیل متن به تصویر</a>، <a href=\"http://openaccess.thecvf.com/content_ECCVW_2018/papers/11133/Vasu_Analyzing_Perception-Distortion_Tradeoff_using_Enhanced_Perceptual_Super-resolution_Network_ECCVW_2018_paper.pdf\">بالا بردن وضوح تصاویر</a>، <a href=\"https://arxiv.org/pdf/1611.02200.pdf?source=post_page---------------------------\">تبدیل تصویر به اموجی</a>، <a href=\"https://ieeexplore.ieee.org/abstract/document/8296650/\">حدس ظاهر افراد در پیری</a>، <a href=\"https://openaccess.thecvf.com/content_ICCV_2019/papers/Zakharov_Few-Shot_Adversarial_Learning_of_Realistic_Neural_Talking_Head_Models_ICCV_2019_paper.pdf\">پویا سازی تصاویر ثابت</a> و ... بسیاری از کارکردهای دیگری که هر روز اثر آن را در زندگی خود می‌بینیم ولی خبر نداریم که گن‌ها در آن نقش دارند. </span><span style=\"font-size: 14pt;\">با استفاده از گن‌ها می‌توان روز به روز کاربردهای جدیدی که فکرش را هم نمی‌کردیم، ارائه داد.</span></p>\n<p dir=\"rtl\" style=\"text-align: justify;\"><span style=\"font-size: 14pt;\"><strong>• آتوانکودرها</strong></span></p>\n<p dir=\"rtl\" style=\"text-align: justify;\"><span style=\"font-size: 14pt;\">شاید مرحله قبل از گن‌ها را بتوان <strong>خودکدگذارها</strong> یا <strong>آتوانکودر</strong> عنوان کرد که روشی ساده‌تر از گن‌ها را برای تولید داده جدید دارند. در این شبکه‌ها مانند گن‌ها، از <strong>مدل‌سازی مولد</strong> استفاده می‌شود. در شبکه‌های معمولی، یک تصویر دریافت می‌شود و پس از چند مرحله، به اعدادی می‌رسیم که توصیفی از خصیصه‌های آن تصویر می‌باشند. در مدل‌سازی مولد، بنا داریم <strong>مسیری عکس این مراحل</strong> را پیمایش کنیم. در مدل‌سازی مولد با یک نسخه اولیه از تصویر مورد نظر شروع می‌کنیم و پس از طی مراحل، به تصویری که لازم داریم، می‌رسیم.</span></p>\n<p dir=\"rtl\" style=\"text-align: justify;\"><span style=\"font-size: 14pt;\">تصویر اولیه را عموما <strong>بردار نویز تصادفی</strong> هم می‌گویند. بردار نویز تصادفی را با Z عنوان می‌کنند، در یک <strong>فضای نهفته</strong> یا  latent space قرار دارد. فضای نهفته از فضای اصلی ما <strong>ابعاد کمتری</strong> دارد. به عنوان مثال فضای اصلی ما اگر تصاویر ما 28 در 28 پیکسل باشند، فضای نهفته ما می‌تواند 100 در یک می‌تواند باشد.</span></p>\n<p dir=\"rtl\" style=\"text-align: center;\"><span style=\"font-size: 14pt;\"><img class=\"alignleft size-full wp-image-26853\" src=\"https://i.ibb.co/GRmgd1s/autoencoder.png\" alt=\"\" width=\"624\" height=\"291\" /></span></p>\n<p dir=\"rtl\" style=\"text-align: justify;\"><span style=\"font-size: 14pt;\">Z یک برداری است که بازنمایی از داده را به <strong>صورت فشرده</strong> ارائه می‌کند. در خودکدگذارها به دنبال این هستیم که خروجی <strong>بسیار شبیه</strong> به ورودی ایجاد کنیم. یعنی تابع هزینه ما بر روی <strong>کاهش اختلاف ورودی و خروجی</strong> تمرکز دارد.</span></p>\n<p dir=\"rtl\" style=\"text-align: justify;\"><span style=\"font-size: 14pt;\">در این شبکه‌ها نیاز به داده برچسب خورده نداریم، یعنی <strong>غیرنظارتی</strong> عمل می‌کنند. لازم نیست که توضیح داده شود تصویر ورودی چه چیزی است، ما به دنبال <strong>بازنمایی</strong> آن هستیم.</span></p>\n<p dir=\"rtl\" style=\"text-align: justify;\"><span style=\"font-size: 14pt;\">کاربردهای شبکه‌های خودکدگذار عبارتند از: <strong>فشرده سازی، حذف نویز و رنگی کردن تصاویر، تولید داده و...</strong></span></p>\n<p dir=\"rtl\" style=\"text-align: justify;\"><span style=\"font-size: 14pt;\">برای تولید داده، <strong>بعد از آموزش شبکه</strong> می‌توان از <strong>دیکودر</strong> برای تولید داده استفاده کرد. اگر به دنبال تولید داده‌های جدید باشیم، از <strong>شبکه‌های خودکدگذار متغیر</strong> باید استفاده کنیم. به این دلیل که در خودکدگذارهای معمولی، داده تولیدی <strong>عینا مشابه</strong> داده ورودی است، ولی در خودکدگذار متغیر، از یک تابع توزیع گوسی برای تولید داده‌های جدید استفاده می‌شود.</span></p>\n<p dir=\"rtl\" style=\"text-align: justify;\"><span style=\"font-size: 14pt;\"><strong>نقص خودکدگذارها</strong> در تولید داده‌های شبیه به ورودی و <strong>واقعی نبودن</strong> تصاویر تولیدی است. به همین دلیل به دنبال راهکاری بوده‌ایم که این راهکار، همان گن‌ها می‌باشند.</span></p>\n<p dir=\"rtl\" style=\"text-align: justify;\"><span style=\"font-size: 14pt; color: #ff0000;\"><strong><span style=\"color: #ff0000; font-size: 18pt;\">• تاریخچه گن‌ها</span>\n</strong></span></p>\n<p dir=\"rtl\" style=\"text-align: justify;\"><span style=\"font-size: 14pt;\">شبکه‌های گن برای اولین بار بوسیله یان گودفلو در <a href=\"https://papers.nips.cc/paper/5423-ge...al-nets.pdf\">این مقاله</a> در سال 2014 معرفی شدند. قابلیت اصلی این شبکه‌ها، مدل‌سازی داده می‌باشد. در این شبکه‌ها، دو قسمت <strong>تولیدکننده(generator)</strong> و <strong>تمایزدهنده(discriminator) </strong>وجود دارد.</span></p>\n<p dir=\"rtl\" style=\"text-align: justify;\"><span style=\"font-size: 14pt;\"><strong>معماری این شبکه‌ها در شکل زیر آمده است:</strong></span></p>\n<p dir=\"rtl\" style=\"text-align: center;\"><span style=\"font-size: 14pt;\"><img class=\"alignleft size-full wp-image-26854\" src=\"https://i.ibb.co/c6sJmd0/Simple-Gan.jpg\" alt=\"\" width=\"624\" height=\"426\" /></span></p>\n<p dir=\"rtl\" style=\"text-align: justify;\"><span style=\"font-size: 14pt;\">همانطور که می‌بینید یک بخش به نام تولیدکننده وجود دارد. ورودی این بخش <strong>یک بردار نویز تصادفی بر روی داده‌های فضای نهفته</strong> است. <strong>خروجی تولید کننده</strong>، یک <strong>داده‌ دروغین 'X</strong> است. در ادامه، این نمونه‌های تقلبی، همراه با یک سری <strong>داده واقعی X</strong> وارد یک تمایزدهنده می‌شوند. در تمایز دهنده، تلاش بر این است که بتوانیم <strong>داده‌های دروغی را تشخیص بدهیم</strong>، اما در نهایت به حالتی باید برسیم که تمایز دهنده، در تشخیص داده‌های واقعی و دروغی با <strong>مشکل</strong> مواجه شود.</span></p>\n<p dir=\"rtl\" style=\"text-align: justify;\"><span style=\"font-size: 14pt;\">این به معنای این است که <strong>تمایزدهنده</strong> در شبکه‌های گن، <strong>در نهایت</strong> به حالتی می‌رسد که <strong>خطای آن بسیار بالا</strong> می‌شود و <strong>این نتیجه خوب شدن کار تولید کننده</strong> است. یعنی تولید کننده به حدی در تولید نمونه‌های تقلبی پیشرفت کرده است، که <strong>تمایز دهنده در تشخیص</strong> تقلبی و واقعی بودن نمونه‌ها، <strong>عاجز</strong> شده است.</span></p>\n<p dir=\"rtl\" style=\"text-align: justify;\"><span style=\"font-size: 14pt;\">تمایزدهنده دارای یک <strong>خطای دسته‌بندی</strong> (Classification loss) است که بر اساس آن خطا، دو مورد در شبکه <strong>کوک</strong> (tune) می‌شود:</span></p>\n<p dir=\"rtl\" style=\"text-align: justify;\"><span style=\"font-size: 14pt;\"><b>اول؛ </b>تمایزدهنده تا بتواند بهتر تصایر را تشخیص دهد.</span></p>\n<p dir=\"rtl\" style=\"text-align: justify;\"><span style=\"font-size: 14pt;\"><strong>دوم؛</strong> تولیدکننده تا بر اساس خطای تمایز دهنده متوجه شود چقدر درست عمل کرده است و تا چه حد نیاز به بهبود دارد.</span></p>\n<p dir=\"rtl\" style=\"text-align: justify;\"><span style=\"font-size: 14pt;\">در واقع<strong> آموزش تمایزدهنده و تولیدکننده</strong>، با <strong>پس‌انتشار خطا</strong> (BackPropagation) بر اساس خطای دسته‌بندی در <strong>تمایزدهنده</strong> انجام می‌شود.</span></p>\n<p dir=\"rtl\" style=\"text-align: justify;\"><span style=\"font-size: 14pt;\">پس دو شبکه تولیکننده و تمایزدهنده، <strong>دو وظیفه متضاد</strong> هم دارند و از آن‌ها با عنوان<strong> دزد و پلیس</strong> یاد می‌کنند که عملکردی بر اساس <strong>نظریه بازی</strong> دارند. به این معنا که، هر کدام در پی تخریب کار دیگری می‌باشند و <strong>تمایزدهنده</strong>  می‌خواهد <strong>مچ تولید کننده را بگیرد</strong> و <strong>تولیدکننده</strong> می‌خواهد تمایزدهنده را <strong>گول</strong> بزند.</span></p>\n<p dir=\"rtl\" style=\"text-align: justify;\"><span style=\"font-size: 14pt; color: #ff0000;\"><strong><span style=\"color: #ff0000; font-size: 18pt;\">• توابع هزینه در شبکه‌های گن</span></strong></span></p>\n<p dir=\"rtl\" style=\"text-align: justify;\"><span style=\"font-size: 14pt;\">در این معماری، <strong>دو تابع هزینه</strong> داریم: <strong>تابع هزینه شبکه تولیدکننده و تابع هزینه شبکه تمایزدهنده</strong>. برای مطالعه بیشتر توابع هزینه‌ها <a href=\"https://developers.google.com/machine-learning/gan/loss\">اینجا</a> را ببینید.</span></p>\n<p dir=\"rtl\" style=\"text-align: center;\"><span style=\"font-size: 14pt;\">J(G) , θ(G)</span></p>\n<p dir=\"rtl\" style=\"text-align: center;\"><span style=\"font-size: 14pt;\">J(D) , θ(D)</span></p>\n<p dir=\"rtl\" style=\"text-align: center;\"><span style=\"font-size: 14pt;\">J(G)             (θ(G), θ(D))</span></p>\n<p dir=\"rtl\" style=\"text-align: center;\"><span style=\"font-size: 14pt;\">J(D)             (θ(D), θ(G))</span></p>\n<p dir=\"rtl\" style=\"text-align: justify;\"><span style=\"font-size: 14pt;\"><strong>نکته‌؛ </strong>توابع هزینه در این معماری به پارامترهای شبکه خود و شبکه مقابل، ربط دارد. یعنی تابع هزینه تولیدکننده با پارامترهای شبکه تولیدکننده و پارامترهای شبکه تمایزدهنده ارتباط دارد و چنین حالتی را هم در تمایزدهنده داریم.</span></p>\n<p dir=\"rtl\" style=\"text-align: justify;\"><span style=\"font-size: 14pt;\"><strong>اما؛</strong> در فرآیند آموزش، هر کدام از شبکه‌ها <strong>فقط می‌توانند پارامترهای شبکه خود را دستکاری کنند</strong>. یعنی در تابع هزینه خود، 2 پارامتر دارند که از آن 2 پارامتر <strong>فقط یک پارامتر</strong> دست این شبکه است.</span></p>\n<p dir=\"rtl\" style=\"text-align: justify;\"><span style=\"font-size: 14pt;\"><strong>برای بهینه‌سازی تابع هزینه؛ </strong>همانطور که گفتیم بر اساس <strong>خطای دسته‌بندی تفیک تقلبی از واقعی در تمایزدهنده</strong> عمل می‌‌‌‌کنیم. در تمایزدهنده، به دنبال <strong>کمینه کردن</strong> این خطا هستیم و در تولیدکننده به دنبال <strong>بیشینه کردن</strong> این خطا می‌باشیم.</span></p>\n<p dir=\"rtl\" style=\"text-align: justify;\"><span style=\"font-size: 14pt;\"><strong>• تعادل نش</strong></span></p>\n<p dir=\"rtl\" style=\"text-align: justify;\"><span style=\"font-size: 14pt;\"><strong>نظریه بازی؛</strong> در اینجا به معنای این است که دو <strong>موجودیت یکتا</strong> دارای <strong>منافع متضاد</strong> با هم باشند و شبکه تولیدکننده و تمایزدهنده، هر کدام منافعشان بر خلاف هم می‌باشد. زمانی این دو شبکه به تعادل می‌رسند که ادامه کار، تفاوتی در نتیجه حاصل نکند و در اصطلاح به این حالت، <strong>تعادل نش</strong> می‌گویند.</span></p>\n<p dir=\"rtl\" style=\"text-align: justify;\"><span style=\"font-size: 14pt;\">زمانی که تولید کننده آن قدر خوب عمل کند که کارکرد تمایزدهنده شبیه حالتی شود که <strong>تصادفی یا 50/50</strong> عمل کند، در اینجا متوجه می‌شویم که آموزش شبکه دیگر فایده‌ای ندارد.</span></p>\n<p dir=\"rtl\" style=\"text-align: justify;\"><span style=\"font-size: 14pt; color: #ff0000;\"><strong><span style=\"color: #ff0000; font-size: 18pt;\">• آموزش در گن</span></strong></span></p>\n<p dir=\"rtl\" style=\"text-align: justify;\"><span style=\"font-size: 14pt;\"><strong>در تمایزدهنده؛ </strong></span><span style=\"font-size: 14pt;\">تعدادی داده اصلی <strong>X</strong> به همراه داده تقلبی <strong>'X</strong> وارد تمایزدهنده می‌شوند، <strong>خطای تفکیک</strong> محاسبه و از آن برای <strong>آموزش وزن‌های شبکه تمایزدهنده</strong>  کاهش خطای آن استفاده می‌شود. در حین آموزش شبکه تمایزدهنده، <span style=\"color: #ff6600;\"><strong>وزن‌های شبکه تولیدکننده ثابت می‌باشند.</strong></span></span></p>\n<p dir=\"rtl\" style=\"text-align: justify;\"><span style=\"font-size: 14pt;\"><strong>در تولیدکننده؛ </strong>تعدادی نمونه تقلبی <strong>'X</strong> با استفاده از <strong>بردار نویز تصادفی</strong> ایجاد می‌کنیم. با استفاده از خطای این نمونه‌ها که همان <strong>خطای تولید شده در تمایزدهنده</strong> است، به سراغ آموزش وزن‌های شبکه تولیدکننده و <strong>بیشینه کردن خطای شبکه تمایزدهنده</strong> می‌رویم. در حین آموزش شبکه تولیدکننده، <span style=\"color: #ff6600;\"><strong>وزن‌های شبکه تمایزدهنده ثابت می‌باشند.</strong></span></span></p>\n<p dir=\"rtl\" style=\"text-align: justify;\"><span style=\"font-size: 14pt;\"><strong>• نکات آموزش</strong></span></p>\n<p dir=\"rtl\" style=\"text-align: justify;\"><span style=\"font-size: 14pt;\"><strong>نرمال‌سازی:</strong> تصاویر ورودی عموما بین 1 و 1- قرار می‌گیرند.</span></p>\n<p dir=\"rtl\" style=\"text-align: justify;\"><span style=\"font-size: 14pt;\"><strong>نرمال‌سازی تکه‌ای:</strong> خروجی هر لایه در شبکه، نرمال می‌شود.</span></p>\n<p dir=\"rtl\" style=\"text-align: justify;\"><span style=\"font-size: 14pt;\"><strong>نسبت آموزش شبکه تمایزدهنده و تولیدکننده:</strong> شبکه تمایزدهنده عموما بیشتر از شبکه تولیدکننده آموزش می‌بیند.</span></p>\n<p dir=\"rtl\" style=\"text-align: justify;\"><span style=\"font-size: 14pt;\"><strong>تابع‌فعال‌ساز:</strong> در این شبکه‌ها به جای استفاده از رلو و مکس‌پولینگ، از <strong>لیکی‌رلو (LeakyRelu</strong>) استفاده می‌کنیم. یکی از مشکلات تابع رلو، <strong>مرگ‌رلو</strong> است که برخی از نورون‌ها می‌میرند و <strong>غیرفعال</strong> می‌شوند و برای تمامی ورودی‌ها،  <strong>صفر</strong> را در خروجی می‌دهند. در این حالت، هیچ گرادیانی جریان نمی‌یابد و در صورتی‌که تعداد نورون‌های غیرفعال در شبکه عصبی زیاد باشد، عملکرد مدل تحت تأثیر قرار می‌گیرد. برای حل این مشکل می‌توانیم از تابع لیکی‌رلو استفاده می‌کنیم.</span></p>\n<p dir=\"rtl\" style=\"text-align: center;\"><span style=\"font-size: 14pt;\"><img class=\"alignleft size-full wp-image-26855\" src=\"https://i.ibb.co/qk1KW9Q/Relu.png\" alt=\"\" width=\"453\" height=\"242\" /></span></p>\n<p dir=\"rtl\" style=\"text-align: justify;\"><span style=\"font-size: 14pt; color: #ff0000;\"><strong><span style=\"color: #ff0000; font-size: 18pt;\">• انواع گن</span></strong></span></p>\n<p dir=\"rtl\" style=\"text-align: justify;\"><span style=\"font-size: 14pt;\"><strong>• ساده</strong></span></p>\n<p dir=\"rtl\" style=\"text-align: justify;\"><span style=\"font-size: 14pt;\">در آن‌ها تولیدکننده و تمایزدهنده از شبکه‌های ساده عصبی استفاده می‌کنند.</span></p>\n<p dir=\"rtl\" style=\"text-align: justify;\"><span style=\"font-size: 14pt;\"><strong>• گن‌های پیچشی</strong></span></p>\n<p dir=\"rtl\" style=\"text-align: justify;\"><span style=\"font-size: 14pt;\">در این مدل از گن‌ها، در بخش تولیدکننده و تمایزدهنده از شبکه‌های عصبی <strong>کانولوشن</strong> استفاده می‌شود. در <strong>تولیدکننده</strong>، از عمل <strong>کانولوشن معکوس</strong> استفاده می‌شود. کانولوشن معکوس، در هر لایه، <strong>عملی عکس کانولوشن معمولی</strong> انجام می‌دهد. در لایه کانولوشن معمولی، یک ورودی را با <strong>Downsample</strong> کردن <strong>کوچک</strong> می‌کنیم، به این معنا که یک بازنمایی از کل ویژگی‌های درون ورودی به صورت خلاصه‌تر ایجاد کرده‌ایم. اما در کانولوشن معکوس، عملی خلاف روش بالا انجام می‌شود، یعنی <strong>Upsample</strong> می‌کنیم. در این حالت، <strong>خروجی از ورودی بزرگتر است</strong> و می‌توان گفت که از روی <strong>خصیصه‌ها</strong>، ما داده‌ای را <strong>تولید</strong> می‌کنیم.</span></p>\n<p dir=\"rtl\" style=\"text-align: justify;\"><span style=\"font-size: 14pt;\"><strong>در کانولوشن معکوس؛</strong> به جای این که چندین خانه را تبدیل به یک خانه کنیم، یعنی رابطه چند به یک داشته باشیم، <strong>رابطه یک به چند</strong> داریم! یعنی یک خانه را به چندین خانه تبدیل می‌کنیم تا <strong>بزرگ‌نمایی</strong> ایجاد شود. برای انجام این عملیات، از <strong>ماتریس اسپارس ترانهاده</strong> استفاده می‌شود.</span></p>\n<p dir=\"rtl\" style=\"text-align: justify;\"><span style=\"font-size: 14pt;\">در حالت عادی، از روی کرنل یک <strong>ماتریس اسپارس</strong> ایجاد می‌شود که ورودی در آن ضرب می‌شود و خروجی به دست می‌آید. حال برای بزرگنمایی، از<strong> ماتریس اسپارس ترانهاده</strong> استفاده می‌کنیم که سبب می‌شود <strong>به جای کوچک شدن ورودی، به یک خروجی بزرگتر</strong> برسیم.</span></p>\n<p dir=\"rtl\" style=\"text-align: justify;\"><span style=\"font-size: 14pt;\">پس در حالت کلی <strong>تولیدکننده</strong> با استفاده از <strong>upsample</strong> کردن، یک <strong>تصویر ایجاد</strong> می‌کند و <strong>تمایزدهنده</strong> با <strong>downsample</strong> کردن تصویر در پی <strong>تفکیک داده‌های دروغی</strong> از واقعی است.</span></p>\n<p dir=\"rtl\" style=\"text-align: justify;\"><span style=\"font-size: 14pt;\"><strong>• گن‌های شرطی</strong></span></p>\n<p dir=\"rtl\" style=\"text-align: justify;\"><span style=\"font-size: 14pt;\">در گن‌های شرطی، بر روی داده‌ها <strong>برچسب</strong> می‌زنیم، و با این کار می‌خواهیم در تولید داده‌ها <strong>کنترل بیشتری</strong> داشته باشیم. یعنی تعیین کنیم که داده تولیدی ما <strong>در کدام کلاس</strong> قرار داشته باشد. تولیدکننده یاد می‌گیرند که در کدام کلاس داده تولید کند و تمایزدهنده یاد می‌گیرد که داده‌های تولیدی در کلاس‌های مختلف را از هم تفکیک کند.</span></p>\n<p dir=\"rtl\" style=\"text-align: justify;\"><span style=\"font-size: 14pt;\">نکته گن‌های شرطی این است که یادگیری همچنان نظارت نشده است، به این دلیل که از برچسب‌ها فقط برای تشخیص دروغی و واقعی بودن استفاده می‌شوند و در یادگیری و بهبود وزن‌ها تاثیری ندارند.</span></p>\n<p dir=\"rtl\" style=\"text-align: justify;\"><span style=\"font-size: 14pt;\"><strong>• گن‌های چرخشی</strong></span></p>\n<p dir=\"rtl\" style=\"text-align: justify;\"><span style=\"font-size: 14pt;\">برای تولید تصاویر مونه و تبدیل به یک نقاش دیجیتال شدن، نیاز است تا از یک مدل خاص گن‌ها به نام <strong>گن چرخشی</strong> استفاده کنیم. در واقع ما برای ترجمه تصاویر به همدیگر و <strong>انتقال یک ویژگی از دامنه‌ منبع به دامنه مقصد</strong>، نیاز داریم از مدل چرخشی استفاده کنیم. این مدل از گن‌ها برای اولین بار در <a href=\"https://openaccess.thecvf.com/content_iccv_2017/html/Zhu_Unpaired_Image-To-Image_Translation_ICCV_2017_paper.html\">این مقاله</a> معرفی شدند.</span></p>\n<p dir=\"rtl\" style=\"text-align: justify;\"><span style=\"font-size: 14pt; color: #ff0000;\"><strong><span style=\"color: #ff0000; font-size: 18pt;\">• گن‌های چرخشی</span></strong></span></p>\n<p dir=\"rtl\" style=\"text-align: justify;\"><span style=\"font-size: 14pt;\">در گن‌های چرخشی،<strong> تبدیل تصویر به تصویر</strong> داریم و <strong>ورودی تولیدکننده، تصویر است</strong>. در واقع این شبکه‌ها را حالت خاصی از مدل گن شرطی می‌توان در نظر گرفت که بر روی ورودی، نظارت بیشتری داریم. یعنی <strong>تولید داده در تولیدکننده</strong> در یک <strong>دامنه خاص</strong> باید انجام شود.</span></p>\n<p dir=\"rtl\" style=\"text-align: justify;\"><span style=\"font-size: 14pt;\">در گن‌های‌ چرخشی، نیازی به <strong>وجود تصویر یکسان از هر دو دامنه نیست</strong>، به این معنا که اگر یک تصویر واقعی داشتیم، نیازی نیست <strong>عینا</strong> نقاشی مونه آن تصویر را داشته باشیم و کافی است فقط تصاویر واقعی و تصاویر مونه، <strong>بدون ارتباط</strong> به یکدیگر داشته‌ باشیم. همانطور که در این رقابت، از هر دو مدل تصویر یعنی هم تصاویر مونه و هم تصاویر معمولی، داده وجود دارد.</span></p>\n<p dir=\"rtl\" style=\"text-align: justify;\"><span style=\"font-size: 14pt;\"><strong>ثبات خطا؛</strong> گن‌های چرخشی از <strong> خطای ثبات چرخش (Cycle Lost Consistency</strong>) استفاده می‌کند تا <strong>بدون نیاز به داده‌های جفتی</strong>، بتوانیم مدل را آموزش دهیم. در مجموعه داده‌های جفت نشده، <strong>هیچ تبدیل معناداری از پیش تعریف شده ای وجود ندارد</strong> که تولیدکننده بتواند آن را بیاموزد، بنابراین <strong>آن را ایجاد</strong> خواهد کرد.</span></p>\n<p dir=\"rtl\" style=\"text-align: justify;\"><span style=\"font-size: 14pt;\">در این رقابت، یک تصویر واقعی به تولید کننده نقاشی مونه داده می‌شود و این تولیدکننده آن را به <strong>نقاشی مونه تقلبی</strong> تبدیل می‌کند و خروجی شبکه در این مرحله به یک تولیدکننده تصویر داده می‌شود و این تولید کننده باید آن را تبدیل به یک تصویر کند، این تصویر را <strong>تصویر دوار</strong> می‌گوییم.</span></p>\n<p dir=\"rtl\" style=\"text-align: justify;\"><span style=\"font-size: 14pt;\"><strong>بنابراین هدف یادگیری عبارت است از:</strong></span></p>\n<p dir=\"rtl\" style=\"text-align: justify;\"><span style=\"font-size: 14pt;\">نگاشت G:X→Y به گونه ای که تصویر G(X) از تصاویر Y قابل تشخیص نباشند.</span></p>\n<p dir=\"rtl\" style=\"text-align: justify;\"><span style=\"font-size: 14pt;\">نگاشت F:Y→X به گونه ای که تصویر F(Y) از تصاویر X قابل تشخیص نباشد.</span></p>\n<p dir=\"rtl\" style=\"text-align: justify;\"><strong><span style=\"font-size: 14pt;\">برای محاسبه خطای کل تولید‌کننده‌ها از موارد زیر استفاده می شود:</span></strong></p>\n<p dir=\"rtl\" style=\"text-align: justify;\"><span style=\"font-size: 14pt;\">خطای تولید کننده، خطای تولید تصویر دوار، خطای هویت</span></p>\n<p dir=\"rtl\" style=\"text-align: justify;\"><span style=\"font-size: 14pt;\"><strong>دو تولیدکننده داریم،</strong> یک تولید کننده تصویر و یک تولید کننده نقاشی مونه که در معماری <strong>U-Net</strong> کار را انجام می‌دهند.</span></p>\n<p dir=\"rtl\" style=\"text-align: justify;\"><span style=\"font-size: 14pt;\"><strong>تولیدکننده مونه</strong> یاد می گیرد که چگونه یک عکس را <strong>به نقاشی مونه</strong> تبدیل کند</span></p>\n<p dir=\"rtl\" style=\"text-align: justify;\"><span style=\"font-size: 14pt;\"><strong>تولیدکننده تصویر</strong> یاد می گیرد که چگونه نقاشی مونه را<strong> به تصویر</strong> تبدیل کند</span></p>\n<p dir=\"rtl\" style=\"text-align: justify;\"><span style=\"font-size: 14pt;\">از آنجایی که تصاویر <strong>جفت نیستند</strong>، استفاده از<strong> دو چرخه</strong> ضروری است</span></p>\n<p dir=\"rtl\" style=\"text-align: justify;\"><span style=\"font-size: 14pt;\"><strong>عکس ورودی -&gt; تولیدکننده مونه -&gt; نقاشی جعلی -&gt; تولیدکننده تصویر-&gt; تصویر دوار</strong></span></p>\n<p dir=\"rtl\" style=\"text-align: justify;\"><span style=\"font-size: 14pt;\"><strong>نقاشی ورودی -&gt; تولیدکننده تصویر-&gt; عکس جعلی -&gt; تولیدکننده مونه -&gt; مونه دوار</strong></span></p>\n<p dir=\"rtl\" style=\"text-align: justify;\"><span style=\"font-size: 14pt;\"><strong>دو تمایزدهنده هم داریم،</strong> یک تمایزدهنده مونه و یک تمایز دهنده تصویر که در معماری <strong>PatchGAN</strong> کار را انجام می‌دهند و سعی می کنند <strong>طبقه بندی کند</strong> که آیا هر تیکه در یک تصویر واقعی است یا جعلی.</span></p>\n<p dir=\"rtl\" style=\"text-align: justify;\"><span style=\"font-size: 14pt;\"><strong>تمایزدهنده نقاشی مونه</strong> یاد می‌گیرد که واقعی یا تقلبی بودن <strong>یک نقاشی مونه</strong> را از هم تفکیک کند، و برای <strong>بهبود تولیدکننده مونه</strong> کار می‌کند.</span></p>\n<p dir=\"rtl\" style=\"text-align: justify;\"><span style=\"font-size: 14pt;\"><strong>تمایزدهنده تصویر</strong> یاد می‌گیرد که واقعی یا جعلی بودن <strong>یک عکس</strong> را تشخیص دهد، و برای <strong>بهبود تولیدکننده تصویر</strong> کار می‌کند.</span></p>\n<p dir=\"rtl\" style=\"text-align: justify;\"><span style=\"font-size: 14pt;\">از آنجایی که تصاویر جفت نشده‌اند، برای محاسبه میزان خطای تمایزدهنده‌ها، هر یک از آنها دو بار اجرا می شود، یکی با یک تصویر واقعی و دیگری با تصویر جعلی تولید شده.</span></p>\n<p dir=\"rtl\" style=\"text-align: justify;\"><span style=\"font-size: 14pt; color: #ff0000;\"><strong><span style=\"color: #ff0000; font-size: 18pt;\">• معماری گن‌های چرخشی</span></strong></span></p>\n<p dir=\"rtl\" style=\"text-align: justify;\"><span style=\"font-size: 14pt;\">معماری این شبکه‌ها به شکل زیر است:</span></p>\n<p dir=\"rtl\" style=\"text-align: center;\"><img class=\"aligncenter size-full\" src=\"https://i.ibb.co/9vYH3PT/Model.jpg\" width=\"1517\" height=\"411\" /></p>\n<p dir=\"rtl\" style=\"text-align: center;\"><strong><span style=\"font-size: 10pt;\">منبع: <a href=\"https://arxiv.org/pdf/1703.10593.pdf\">مقاله معرفی گن‌های چرخشی</a></span></strong></p>\n<p dir=\"rtl\" style=\"text-align: justify;\"><span style=\"font-size: 14pt;\">به صورت خلاصه و به عنوان یک طرح کلی، مراحل زیر در هر مرحله از آموزش انجام خواهد شد:</span></p>\n<p dir=\"rtl\" style=\"text-align: justify;\"><span style=\"font-size: 14pt;\">با <strong>دو ورودی</strong> شروع می‌کنیم:</span></p>\n<p dir=\"rtl\" style=\"text-align: justify;\"><span style=\"font-size: 14pt;\"><strong>یک عکس (عکس ورودی)</strong></span></p>\n<p dir=\"rtl\" style=\"text-align: justify;\"><span style=\"font-size: 14pt;\"><strong>یک نقاشی مونه (مونه ورودی)</strong></span></p>\n<p dir=\"rtl\" style=\"text-align: justify;\"><span style=\"font-size: 14pt;\">عکس ورودی <strong>یکبار به مونه تقلبی</strong> تبدیل می‌شود و دوباره <strong>به یک عکس تبدیل</strong> می‌شود که به آن <strong>عکس دوار</strong> یا چرخش‌یافته می‌گوییم. از مونه تقلبی در این مرحله، برای تشخیص <strong>خطای تمایزدهنده مونه</strong> استفاده می‌شود و با یک مونه واقعی سنجیده می‌شود تا میزان خطا به دست بیاید. تصویر دوار تولید شده هم برای خطای چرخش استفاده می‌شود و با یک تصویر واقعی سنجیده می‌شود تا مشخص شود که <strong>چقدر در دوران دادن تصویر توانسته‌ایم به درستی به دامنه اصلی بازگردیم</strong>. یک خطای دیگر هم در اینجا به دست می‌آید و آن <strong>خطای تشخیص هویت</strong> است، به این معنا که می‌سنجیم تولیدکننده تصویر تا چه حد می‌تواند <strong>تشخیص بدهد تصویر در کدام دامنه قرار دارد</strong> و اگر به این تولیدکننده، به جای نقاشی مونه، تصویر واقعی دادیم آیا درک می‌کند که <strong>نباید کار خاصی</strong> روی تصویر انجام دهند و نیازی به ترجمه تصویر نیست؟ این کار خطای تشخیص هویت را نتیجه می‌دهد.</span></p>\n<p dir=\"rtl\" style=\"text-align: justify;\"><span style=\"font-size: 14pt;\">شبیه مراحل بالا برای ورود یک نقاشی و تبدیل آن به تصویر دروغی و مجددا تبدیل آن به یک مونه چرخش یافته یا دوار استفاده می‌شود. در این جا هم شبیه مراحل بالا انجام می‌شود. به تصویر زیر نگاه کنید و مراحل بالا و بسیاری مراحل دیگر را در آن خواهید دید. تلفیق این مراحل با هم سبب می‌شود که یک گن چرخشی ایجاد کننده تصاویر مونه بوجود بیاید.</span></p>\n<p dir=\"rtl\" style=\"text-align: center;\"><span style=\"font-size: 14pt;\"><img class=\"alignleft size-full wp-image-26856\" src=\"https://i.ibb.co/2ggwwW5/Cycle-GAN-Big-Picture.jpg\" alt=\"\" width=\"1386\" height=\"591\" /></span></p>\n<p dir=\"rtl\" style=\"text-align: justify;\"><span style=\"font-size: 14pt;\">در انتهای کار <strong>گرادیان‌ها با پس‌انتشار خطا محاسبه می‌شوند</strong> و آن‌ها به <strong>بهینه‌سازها</strong> برای ارتقا نتایج و تولید تصاویر مونه واقعی‌تر، اعمال می‌شوند.</span></p>","metadata":{}},{"cell_type":"markdown","source":"<p dir=\"rtl\" style=\"text-align: justify;\"><span style=\"font-size: 14pt; color: #ff0000;\"><strong><span style=\"color: #ff0000; font-size: 18pt;\">• نیازمندی‌ها</span></strong></span></p>\n<p dir=\"rtl\" style=\"text-align: justify;\"><span style=\"font-size: 18.6667px;\">ابتدا نیازمندی‌های کار را وارد می‌کنیم و بعد استفاده از TPU را تنظیم می‌کنیم.</span></p>","metadata":{}},{"cell_type":"code","source":"import tensorflow as tf\nfrom tensorflow import keras\nfrom tensorflow.keras import layers\nimport tensorflow_addons as tfa\n\nfrom kaggle_datasets import KaggleDatasets\nimport matplotlib.pyplot as plt\nimport numpy as np\n\ntry:\n    tpu = tf.distribute.cluster_resolver.TPUClusterResolver()\n    print('Device:', tpu.master())\n    tf.config.experimental_connect_to_cluster(tpu)\n    tf.tpu.experimental.initialize_tpu_system(tpu)\n    strategy = tf.distribute.experimental.TPUStrategy(tpu)\nexcept:\n    strategy = tf.distribute.get_strategy()\nprint('Number of replicas:', strategy.num_replicas_in_sync)\n\nAUTOTUNE = tf.data.experimental.AUTOTUNE\n    \nprint(tf.__version__)","metadata":{"_uuid":"d629ff2d2480ee46fbb7e2d37f6b5fab8052498a","_cell_guid":"79c7e3d0-c299-4dcb-8224-4455121ee9b0","execution":{"iopub.status.busy":"2022-02-17T07:13:55.969199Z","iopub.execute_input":"2022-02-17T07:13:55.969571Z","iopub.status.idle":"2022-02-17T07:14:04.489086Z","shell.execute_reply.started":"2022-02-17T07:13:55.969538Z","shell.execute_reply":"2022-02-17T07:14:04.488169Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"<p dir=\"rtl\" style=\"text-align: justify;\"><span style=\"font-size: 14pt; color: #ff0000;\"><strong><span style=\"color: #ff0000; font-size: 18pt;\">• پردازش داده‌ها</span></strong></span></p>\n<p dir=\"rtl\" style=\"text-align: justify;\"><span style=\"font-size: 18.6667px;\">ابتدا باید داده‌های مورد نیاز برای کار را خواند. در این رقابت علاوه بر تصاویر JPG از قالب TF هم استفاده می‌شود. TF یک قالب یا فرمت ساده برای ذخیره سازی دنباله‌ای از رکوردهای باینری است.</span></p>\n<p dir=\"rtl\" style=\"text-align: justify;\"><span style=\"font-size: 14pt;\">GCS حافظه ابری گوگل است که داده‌ها بر روی آن ذخیره شده است. برای دسترسی به این داده‌ها، باید کلید امنیتی از حساب کولب در گوگل، در Add-ons نوت‌بوک فعلی این رقابت مقدادهی شود.</span></p>","metadata":{}},{"cell_type":"code","source":"GCS_PATH = KaggleDatasets().get_gcs_path()","metadata":{"execution":{"iopub.status.busy":"2022-02-17T07:14:04.491161Z","iopub.execute_input":"2022-02-17T07:14:04.491932Z","iopub.status.idle":"2022-02-17T07:14:04.975268Z","shell.execute_reply.started":"2022-02-17T07:14:04.491887Z","shell.execute_reply":"2022-02-17T07:14:04.97455Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"<p dir=\"rtl\" style=\"text-align: justify;\"><span style=\"font-size: 14pt; color: #ff0000;\"></p>\n<p dir=\"rtl\" style=\"text-align: justify;\"><span style=\"font-size: 18.6667px;\">بررسی کلیدهای امنیتی و دسترسی به داده‌ها در GCS</span></p>","metadata":{}},{"cell_type":"code","source":"from kaggle_secrets import UserSecretsClient\nuser_secrets = UserSecretsClient()\nuser_credential = user_secrets.get_gcloud_credential()\nuser_secrets.set_tensorflow_credential(user_credential)","metadata":{"execution":{"iopub.status.busy":"2022-02-17T07:14:04.976421Z","iopub.execute_input":"2022-02-17T07:14:04.976783Z","iopub.status.idle":"2022-02-17T07:14:05.176857Z","shell.execute_reply.started":"2022-02-17T07:14:04.976754Z","shell.execute_reply":"2022-02-17T07:14:05.176019Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"<p dir=\"rtl\" style=\"text-align: justify;\"><span style=\"font-size: 14pt; color: #ff0000;\"></p>\n<p dir=\"rtl\" style=\"text-align: justify;\"><span style=\"font-size: 18.6667px;\">همانطور که گفتیم داده‌ها از رکوردهای TF خوانده می‌شوند</span></p>","metadata":{}},{"cell_type":"code","source":"MONET_FILENAMES = tf.io.gfile.glob(str(GCS_PATH + '/monet_tfrec/*.tfrec'))\nprint('Monet TFRecord Files:', len(MONET_FILENAMES))\n\nPHOTO_FILENAMES = tf.io.gfile.glob(str(GCS_PATH + '/photo_tfrec/*.tfrec'))\nprint('Photo TFRecord Files:', len(PHOTO_FILENAMES))","metadata":{"execution":{"iopub.status.busy":"2022-02-17T07:14:05.178349Z","iopub.execute_input":"2022-02-17T07:14:05.179295Z","iopub.status.idle":"2022-02-17T07:14:05.3371Z","shell.execute_reply.started":"2022-02-17T07:14:05.179247Z","shell.execute_reply":"2022-02-17T07:14:05.336372Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"<p dir=\"rtl\" style=\"text-align: justify;\"><span style=\"font-size: 14pt; color: #ff0000;\"><strong><span style=\"color: #ff0000; font-size: 18pt;\">• پیش‌پردازش</span></strong></span></p>\n<p dir=\"rtl\" style=\"text-align: justify;\"><span style=\"font-size: 14pt;\">تصاویر ارائه شده برای این رقابت، در سایز 256x256 هستند و نیازی به تغییر سایز آن‌ها نیست. همچنین این تصاویر در مد رنگی RGB قرار دارند، بنابراین کانال اولیه آن‌ها 3 است. همچنین باید تصاویر را نرمال کنیم، یعنی پیکسل‌های تصویر را به بازه [1, 1-] ببرسم.</span></p>\n<p dir=\"rtl\" style=\"text-align: justify;\"><span style=\"font-size: 14pt;\">همانطور که گفته بودیم، در حال مدلسازی مولد می‌باشیم و نیازی به استفاده از برچسب‌ها نداریم، بنابراین فقط عکس‌ها را از رکوردهای TF استخراج می‌کنیم.</span></p>","metadata":{}},{"cell_type":"code","source":"IMAGE_SIZE = [256, 256]\n\ndef decode_image(image):\n    image = tf.image.decode_jpeg(image, channels=3)\n    image = (tf.cast(image, tf.float32) / 127.5) - 1\n    image = tf.reshape(image, [*IMAGE_SIZE, 3])\n    return image\n\ndef read_tfrecord(example):\n    tfrecord_format = {\n        \"image_name\": tf.io.FixedLenFeature([], tf.string),\n        \"image\": tf.io.FixedLenFeature([], tf.string),\n        \"target\": tf.io.FixedLenFeature([], tf.string)\n    }\n    example = tf.io.parse_single_example(example, tfrecord_format)\n    image = decode_image(example['image'])\n    return image","metadata":{"execution":{"iopub.status.busy":"2022-02-17T07:14:05.339878Z","iopub.execute_input":"2022-02-17T07:14:05.340425Z","iopub.status.idle":"2022-02-17T07:14:05.349662Z","shell.execute_reply.started":"2022-02-17T07:14:05.340381Z","shell.execute_reply":"2022-02-17T07:14:05.348636Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"<p dir=\"rtl\" style=\"text-align: justify;\"><span style=\"font-size: 14pt;\">ایجاد تابعی که تصاویر را از فایل‌ها خارج کند. True بودن لیبل در این جا برای استفاده در نمایش عکس‌ها است و از برچسب‌ها در آموزش مدل استفاده‌ای نمی‌شود. <strong><code>filenames</code></strong>در آرگومان تابع در هنگام فراخوانی، تعیین می‌کند که تصاویر یا نقاشی‌ها نیاز داریم.</span></p>\n<p dir=\"rtl\" style=\"text-align: justify;\"><span style=\"font-size: 14pt;\"><strong><code>AUTOTUNE</code></strong> در این تیکه کد برای تنظیم نحوه موازی کاری استفاده می‌شود. تعداد عناصری که باید استخراج شوند می‌بایست برابر یا بیشتر از تعداد مورد نیاز در یک بچ در یک مرحله آموزشی باشد. می‌شود این مقدار را به صورت دستی تنظیم کرد یا آن را روی <strong><code>tf.data.AUTOTUNE</code></strong> تنظیم کنیم، که در زمان اجرای <strong><code>tf.data</code></strong> می‌خواهد که مقدار را به صورت پویا در حین اجرا تنظیم کند. <strong>اطلاعات بیشتر در <a href=\"https://www.tensorflow.org/guide/data_performance\">اینجا</a></strong></span></p>","metadata":{}},{"cell_type":"code","source":"def load_dataset(filenames, labeled=True, ordered=False):\n    dataset = tf.data.TFRecordDataset(filenames)\n    dataset = dataset.map(read_tfrecord, num_parallel_calls=AUTOTUNE)\n    return dataset","metadata":{"execution":{"iopub.status.busy":"2022-02-17T07:14:05.351043Z","iopub.execute_input":"2022-02-17T07:14:05.351294Z","iopub.status.idle":"2022-02-17T07:14:05.364518Z","shell.execute_reply.started":"2022-02-17T07:14:05.351266Z","shell.execute_reply":"2022-02-17T07:14:05.363572Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"<p dir=\"rtl\" style=\"text-align: justify;\"><span style=\"font-size: 14pt; color: #ff0000;\"></p>\n<p dir=\"rtl\" style=\"text-align: justify;\"><span style=\"font-size: 18.6667px;\">استفاده از تابع ایجاد شده در بالا برای خواندن تصاویر و نقاشی‌ها</span></p>","metadata":{}},{"cell_type":"code","source":"monet_ds = load_dataset(MONET_FILENAMES, labeled=True).batch(1)\nphoto_ds = load_dataset(PHOTO_FILENAMES, labeled=True).batch(1)","metadata":{"execution":{"iopub.status.busy":"2022-02-17T07:14:05.365821Z","iopub.execute_input":"2022-02-17T07:14:05.366084Z","iopub.status.idle":"2022-02-17T07:14:06.228256Z","shell.execute_reply.started":"2022-02-17T07:14:05.366046Z","shell.execute_reply":"2022-02-17T07:14:06.227327Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"<p dir=\"rtl\" style=\"text-align: justify;\"><span style=\"font-size: 14pt; color: #ff0000;\"><strong><span style=\"color: #ff0000; font-size: 18pt;\">• نمایش نمونه‌ها</span></strong></span></p>\n<p dir=\"rtl\" style=\"text-align: justify;\"><span style=\"font-size: 14pt;\">جداکردن نمونه‌هایی برای نمایش تصاویر و نقاشی‌ها و قراردادن آن‌ها در <strong><code>example_monet</code></strong> و <strong><code>example_photo</code></strong></span></p>","metadata":{}},{"cell_type":"code","source":"example_monet = next(iter(monet_ds))\nexample_photo = next(iter(photo_ds))","metadata":{"execution":{"iopub.status.busy":"2022-02-17T07:14:06.229532Z","iopub.execute_input":"2022-02-17T07:14:06.229849Z","iopub.status.idle":"2022-02-17T07:14:06.327252Z","shell.execute_reply.started":"2022-02-17T07:14:06.229816Z","shell.execute_reply":"2022-02-17T07:14:06.326387Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"<p dir=\"rtl\" style=\"text-align: justify;\"><span style=\"font-size: 14pt; color: #ff0000;\"></p>\n<p dir=\"rtl\" style=\"text-align: justify;\"><span style=\"font-size: 14pt;\">با استفاده از <strong>plt</strong> تعدادی از عکس‌ها و نقاشی‌ها را نمایش می‌دهیم. عدد 121 در  <span style=\"font-size: 18.6667px;\"><strong><code>plt.subplt(121)</code> </strong></span>نمایش دهنده تعداد سطر، ستون و ایندکس شروع نمایش است. <strong>برای اطلاعات بیشتر <a href=\"https://matplotlib.org/stable/api/_as_gen/matplotlib.pyplot.subplot.html\" target=\"_blank\" rel=\"noopener\">اینجا</a> را ببینید.</strong></span></p>","metadata":{}},{"cell_type":"code","source":"plt.subplot(121)\nplt.title('Photo')\nplt.imshow(example_photo[0] * 0.5 + 0.5)\n\nplt.subplot(122)\nplt.title('Monet')\nplt.imshow(example_monet[0] * 0.5 + 0.5)","metadata":{"execution":{"iopub.status.busy":"2022-02-17T07:14:06.329185Z","iopub.execute_input":"2022-02-17T07:14:06.329462Z","iopub.status.idle":"2022-02-17T07:14:06.722348Z","shell.execute_reply.started":"2022-02-17T07:14:06.329432Z","shell.execute_reply":"2022-02-17T07:14:06.721266Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"<p dir=\"rtl\" style=\"text-align: justify;\"><span style=\"font-size: 14pt; color: #ff0000;\"><strong><span style=\"color: #ff0000; font-size: 18pt;\">• ساخت تولیدکننده</span></strong></span></p>\n<p dir=\"rtl\" style=\"text-align: justify;\"><span style=\"font-size: 18.6667px;\">همانطور که گفتیم، در ساخت تولیدکننده از معماری <strong>U-Net </strong>در گن چرخشی خود استفاده می‌کنیم. برای ایجاد تولیدکننده، اول می‌بایست فرآیند <strong><code>downsample</code> </strong>و <strong><code>upsample</code> </strong>را تعریف کنیم.</span></p>\n<p dir=\"rtl\" style=\"text-align: justify;\"><span style=\"font-size: 14pt;\"><strong>• ایجاد تابع کاهش سایز:</strong></span></p>\n<p dir=\"rtl\" style=\"text-align: justify;\"><span style=\"font-size: 14pt;\"> ابتدا با <span style=\"font-size: 18.6667px;\"><strong><code>initializer</code> </strong></span>یک حالت شروع تصادفی برای کرنل خود تعیین می‌کنیم. <strong>اطلاعات بیشتر در <a href=\"https://www.tensorflow.org/api_docs/python/tf/random_normal_initializer\">اینجا</a>. </strong>در ادامه با <span style=\"font-size: 18.6667px;\"><strong><code>gamma_init</code> </strong></span>نحوه وزن دهی گاما در نرمال کردن را تصادفی تعیین می‌کنیم. <strong>اطلاعات بیشتر در <a href=\"https://www.tensorflow.org/addons/tutorials/layers_normalizations\">اینجا</a> و <a href=\"https://www.tensorflow.org/addons/api_docs/python/tfa/layers/InstanceNormalization\">اینجا</a></strong></span></p>\n<p dir=\"rtl\" style=\"text-align: justify;\"><span style=\"font-size: 14pt;\">در ادامه یک مدل سکوئنشیال ساخته، فیلتر، سایز کرنل، گام و پدینگ را تعیین می‌کنیم و شروع کرنل راهمان <span style=\"font-size: 18.6667px;\"><strong><code>initializer</code> </strong></span>که ایجاد کرده بودیم، تعیین می‌کنیم.</span></p>\n<p dir=\"rtl\" style=\"text-align: justify;\"><span style=\"font-size: 14pt;\">اگر به <strong>نرمال‌سازی نمونه‌ای</strong> یا <strong>InstanceNormalization</strong> نیاز داشته باشیم، به خروجی مدل قبل، این نرمال‌سازی را اضافه می‌کنیم. نرمال سازی نمونه‌ای مورد خاصی از <strong>نرمال‌سازی گروهی</strong> یا <strong>GroupNormalization</strong> است، در نرمال‌سازی گروهی، کانال ورودی به زیرگروه‌هایی تقسیم می‌شود و بر روی آن‌ها نرمال‌سازی انجام می‌شود، در حالت نرمال‌سازی نمونه‌ای، این زیر گروه‌ها به اندازه axis کانال می‌باشند. <strong>اطلاعات بیشتر <a href=\"https://www.tensorflow.org/addons/tutorials/layers_normalizations\">اینجا</a></strong> همانطور که در لینک می‌بینید، این نرمال‌سازی در انتقال استایل مانند این رقابت که تصاویر را مونه می‌خواهیم بکنیم، از موارد دیگر مانند <strong>نرمال‌سازی دسته‌ای</strong> <strong>BatchNormalization</strong> بهتر جواب می‌دهد.</span></p>\n<p dir=\"rtl\" style=\"text-align: justify;\"><span style=\"font-size: 14pt;\">با <span style=\"font-size: 18.6667px;\"><strong><code>use_bias=false</code></strong></span> استفاده از بایاس را غیرفعال می‌کنیم. در مواقعی که نرمال‌سازی گروهی یا نمونه‌ای داریم، می‌توان بایاس را در نظر نگرفت، به این دلیل که تاثیر آن در لایه‌های بعد نادیده گرفته می‌شود و عملا استفاده از آن بی‌فایده است.<strong> برای اطلاعات بیشتر <a href=\"https://arxiv.org/abs/1502.03167\">اینجا</a></strong></span></p>\n<p dir=\"rtl\" style=\"text-align: justify;\"><span style=\"font-size: 14pt;\">در آخر یک تابع فعال ساز لیکی‌رلو هم بر روی آن اعمال می‌کنیم.</span></p>\n<p dir=\"rtl\" style=\"text-align: justify;\"><span style=\"font-size: 14pt;\">برای استفاده از نرمال‌سازی نمونه‌ای باید از <strong>tfa</strong> یا TensorFlow Add-ons استفاده کنیم به این دلیل که این نرمال‌سازی در TensorFlow عادی وجود ندارد.</span></p>","metadata":{}},{"cell_type":"code","source":"OUTPUT_CHANNELS = 3\n\ndef downsample(filters, size, apply_instancenorm=True):\n    initializer = tf.random_normal_initializer(0., 0.02)\n    gamma_init = keras.initializers.RandomNormal(mean=0.0, stddev=0.02)\n\n    result = keras.Sequential()\n    result.add(layers.Conv2D(filters, size, strides=2, padding='same',\n                             kernel_initializer=initializer, use_bias=False))\n\n    if apply_instancenorm:\n        result.add(tfa.layers.InstanceNormalization(gamma_initializer=gamma_init))\n\n    result.add(layers.LeakyReLU())\n\n    return result","metadata":{"execution":{"iopub.status.busy":"2022-02-17T07:14:06.723696Z","iopub.execute_input":"2022-02-17T07:14:06.723949Z","iopub.status.idle":"2022-02-17T07:14:06.733708Z","shell.execute_reply.started":"2022-02-17T07:14:06.72392Z","shell.execute_reply":"2022-02-17T07:14:06.732685Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"<p dir=\"rtl\" style=\"text-align: justify;\"><span style=\"font-size: 14pt;\"><strong>• ایجاد تابع افزایش سایز:</strong></span></p>\n<p dir=\"rtl\" style=\"text-align: justify;\"><span style=\"font-size: 14pt;\">در ادامه تابع<span style=\"font-size: 18.6667px;\"><strong><code>upsample</code> </strong>کردن را ایجاد می‌کنیم. این تابع برخلاف <strong><code>downsample</code></strong> ابعاد و فیلترهای تصاویر را اضافه می‌کند. برای <strong><code>upsample</code></strong> همانطور که قبلا گفتیم از ماتریس کانولوشن ترانهاده استفاده می‌کنیم.</span></span></p>\n<p dir=\"rtl\" style=\"text-align: justify;\"><span style=\"font-size: 14pt;\">می‌توانیم <span style=\"font-size: 18.6667px;\"><strong><code>dropout</code></strong></span> بزنیم و در صورت استفاده نرخ آن 0.5 خواهد بود.</span></p>","metadata":{}},{"cell_type":"code","source":"def upsample(filters, size, apply_dropout=False):\n    initializer = tf.random_normal_initializer(0., 0.02)\n    gamma_init = keras.initializers.RandomNormal(mean=0.0, stddev=0.02)\n\n    result = keras.Sequential()\n    result.add(layers.Conv2DTranspose(filters, size, strides=2,\n                                      padding='same',\n                                      kernel_initializer=initializer,\n                                      use_bias=False))\n\n    result.add(tfa.layers.InstanceNormalization(gamma_initializer=gamma_init))\n\n    if apply_dropout:\n        result.add(layers.Dropout(0.5))\n\n    result.add(layers.ReLU())\n\n    return result","metadata":{"execution":{"iopub.status.busy":"2022-02-17T07:14:06.735194Z","iopub.execute_input":"2022-02-17T07:14:06.73545Z","iopub.status.idle":"2022-02-17T07:14:06.74379Z","shell.execute_reply.started":"2022-02-17T07:14:06.735421Z","shell.execute_reply":"2022-02-17T07:14:06.74323Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"<p dir=\"rtl\" style=\"text-align: justify;\"><span style=\"font-size: 14pt;\"><strong>• ساخت تولیدکننده:</strong></span></p>\n<p dir=\"rtl\" style=\"text-align: justify;\"><span style=\"font-size: 18.6667px;\">بعد از تعریف فرآیندهای کوچک‌سازی و بزرگ‌سازی ورودی‌ها که در تولیدکننده نیاز است، به سراغ ساخت تولیدکننده خود می‌رویم.</span></p>\n<p dir=\"rtl\" style=\"text-align: justify;\"><span style=\"font-size: 14pt;\">تولید کننده اول تصویر ورودی را کوچک‌نمایی می‌کند و بعد در حالی که شورتکات یا Skip Connection ایجاد کرده است، نتیجه مرحله قبل را بزرگنمایی می‌کند. عمل کردن به صورت شورتکات سبب می‌شود که در چنین مدلی که پیچیده و عمیق شده است از محوشدگی گرادیان‌ها با تجمیع خروجی یک لایه به ورودی چندین لایه به جای یک لایه، جلوگیری کنیم. این شورتکات‌های ایجاد شده وزن‌هایی که در بخش اول یادگرفته شده است را به بخش دوم منتقل می‌کند.<strong> برای اطلاعات بیشتر <a href=\"https://www.analyticsvidhya.com/blog/2021/08/all-you-need-to-know-about-skip-connections/\">اینجا</a></strong></span></p>\n<p dir=\"rtl\"><img class=\"aligncenter size-full\" src=\"https://i.ibb.co/Hd3N2Vh/Cycle-GAN-Unet-generator.jpg\" width=\"1280\" height=\"561\" /></p>\n<p dir=\"rtl\" style=\"text-align: justify;\"><span style=\"font-size: 14pt;\">در این جا خروجی لایه <strong><code>downsample</code></strong> به ورودی لایه <strong><code>upsample</code></strong> به صورت متقارن برده می‌شود.</span></p>","metadata":{}},{"cell_type":"code","source":"def Generator():\n    inputs = layers.Input(shape=[256,256,3])\n\n    # bs = batch size\n    down_stack = [\n        downsample(64, 4, apply_instancenorm=False), # (bs, 128, 128, 64)\n        downsample(128, 4), # (bs, 64, 64, 128)\n        downsample(256, 4), # (bs, 32, 32, 256)\n        downsample(512, 4), # (bs, 16, 16, 512)\n        downsample(512, 4), # (bs, 8, 8, 512)\n        downsample(512, 4), # (bs, 4, 4, 512)\n        downsample(512, 4), # (bs, 2, 2, 512)\n        downsample(512, 4), # (bs, 1, 1, 512)\n    ]\n\n    up_stack = [\n        upsample(512, 4, apply_dropout=True), # (bs, 2, 2, 1024)\n        upsample(512, 4, apply_dropout=True), # (bs, 4, 4, 1024)\n        upsample(512, 4, apply_dropout=True), # (bs, 8, 8, 1024)\n        upsample(512, 4), # (bs, 16, 16, 1024)\n        upsample(256, 4), # (bs, 32, 32, 512)\n        upsample(128, 4), # (bs, 64, 64, 256)\n        upsample(64, 4), # (bs, 128, 128, 128)\n    ]\n\n    initializer = tf.random_normal_initializer(0., 0.02)\n    last = layers.Conv2DTranspose(OUTPUT_CHANNELS, 4,\n                                  strides=2,\n                                  padding='same',\n                                  kernel_initializer=initializer,\n                                  activation='tanh') # (bs, 256, 256, 3)\n\n    x = inputs\n\n    # Downsampling through the model\n    skips = []\n    for down in down_stack:\n        x = down(x)\n        skips.append(x)\n\n    skips = reversed(skips[:-1])\n\n    # Upsampling and establishing the skip connections\n    for up, skip in zip(up_stack, skips):\n        x = up(x)\n        x = layers.Concatenate()([x, skip])\n\n    x = last(x)\n\n    return keras.Model(inputs=inputs, outputs=x)","metadata":{"execution":{"iopub.status.busy":"2022-02-17T07:14:06.744941Z","iopub.execute_input":"2022-02-17T07:14:06.745433Z","iopub.status.idle":"2022-02-17T07:14:06.757661Z","shell.execute_reply.started":"2022-02-17T07:14:06.745397Z","shell.execute_reply":"2022-02-17T07:14:06.75677Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"<p dir=\"rtl\" style=\"text-align: justify;\"><span style=\"font-size: 14pt;\"><strong>• ساخت تمایزدهنده:</strong></span></p>\n<p dir=\"rtl\" style=\"text-align: justify;\"><span style=\"font-size: 18.6667px;\">ت<span style=\"font-size: 14pt;\">مایزدهنده وظیفه دارد تشخیص دهد تصویر ورودی واقعی یا تقلبی است. معماری تمایزدهنده یک شبکه کانولوشنی از مدل PatchGAN است که به جای آن که در حالت کلی بگوید تصویر واقعی است یا خیر، درباره هر تیکه از تصویر تشخیص می‌دهد که آیا واقعی است یا خیر؟ </span></span></p>\n<p dir=\"rtl\" style=\"text-align: justify;\"><img class=\"size-full aligncenter\" src=\"https://i.ibb.co/V2M6vgy/Patch-GAN-discriminator.jpg\" width=\"1162\" height=\"382\" /></p>\n<p dir=\"rtl\" style=\"text-align: justify;\"><span style=\"font-size: 14pt;\"> در این جا هم یک انکودر داریم که <strong><code>downsample</code></strong> می‌کند و از لایه‌های در ادامه تشکیل شده است: </span><span style=\"font-size: 14pt;\">لایه کانولوشنی / </span><span style=\"font-size: 14pt;\">لایه نرمال‌سازی نمونه‌ایی که به بلاک اول اعمال نمی‌شود / </span><span style=\"font-size: 14pt;\">لایه لیکی‌رلو</span></p>\n<p dir=\"rtl\" style=\"text-align: justify;\"><span style=\"font-size: 14pt;\">خروجی در اینجا یک تیکه 30x30 است از تصویر ورودی است.</span></p>","metadata":{}},{"cell_type":"code","source":"def Discriminator():\n    initializer = tf.random_normal_initializer(0., 0.02)\n    gamma_init = keras.initializers.RandomNormal(mean=0.0, stddev=0.02)\n\n    inp = layers.Input(shape=[256, 256, 3], name='input_image')\n\n    x = inp\n\n    down1 = downsample(64, 4, False)(x) # (bs, 128, 128, 64)\n    down2 = downsample(128, 4)(down1) # (bs, 64, 64, 128)\n    down3 = downsample(256, 4)(down2) # (bs, 32, 32, 256)\n\n    zero_pad1 = layers.ZeroPadding2D()(down3) # (bs, 34, 34, 256)\n    conv = layers.Conv2D(512, 4, strides=1,\n                         kernel_initializer=initializer,\n                         use_bias=False)(zero_pad1) # (bs, 31, 31, 512)\n\n    norm1 = tfa.layers.InstanceNormalization(gamma_initializer=gamma_init)(conv)\n\n    leaky_relu = layers.LeakyReLU()(norm1)\n\n    zero_pad2 = layers.ZeroPadding2D()(leaky_relu) # (bs, 33, 33, 512)\n\n    last = layers.Conv2D(1, 4, strides=1,\n                         kernel_initializer=initializer)(zero_pad2) # (bs, 30, 30, 1)\n\n    return tf.keras.Model(inputs=inp, outputs=last)","metadata":{"execution":{"iopub.status.busy":"2022-02-17T07:14:06.759183Z","iopub.execute_input":"2022-02-17T07:14:06.759512Z","iopub.status.idle":"2022-02-17T07:14:06.774091Z","shell.execute_reply.started":"2022-02-17T07:14:06.759475Z","shell.execute_reply":"2022-02-17T07:14:06.773127Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"<p dir=\"rtl\" style=\"text-align: justify;\"><span style=\"font-size: 14pt;\"><strong>• تعیین تولیدکننده‌ها و تمیزدهنده‌ها:</strong></span></p>\n<p dir=\"rtl\" style=\"text-align: justify;\"><span style=\"font-size: 14pt;\">همانطور که در توضیحات ابتدایی گفتیم، مدل نهایی برای تبدیل تصاویر به نقاشی، شامل 2 بخش تولیدکننده و تمایزدهنده است که از از هر کدام 2 نمونه نیاز داریم، تولیدکننده و تمایزدهنده برای تبدیل تصاویر به نقاشی و نقاشی به تصاویر، بنابراین:</span></p>\n\n<ul dir=\"rtl\" style=\"text-align: justify;\">\n \t<li dir=\"rtl\"><span style=\"font-size: 14pt;\"><strong>تولیدکننده‌ها:</strong> که با <strong><code>monet_generator</code></strong>  و <strong><code>photo_generator</code></strong> نشان می‌دهیم و از نوع Generator قرار می‌دهیم.</span></li>\n \t<li dir=\"rtl\"><span style=\"font-size: 14pt;\"><strong>تمایزدهنده‌ها:</strong> که با <strong><code>monet_discriminator</code></strong> و <strong><code>photo_discriminator</code></strong> نشان می‌دهیم و از نوع Discriminator قرار می‌دهیم.</span></li>\n</ul>\n<p dir=\"rtl\" style=\"text-align: justify;\"><span style=\"font-size: 14pt;\"><strong><code>monet_generator</code></strong> یاد می‌گیرد که چگونه<strong> تصاویر را به نقاشی</strong> <strong>مونه</strong> تبدیل کند.</span></p>\n<p dir=\"rtl\" style=\"text-align: justify;\"><span style=\"font-size: 14pt;\"><strong><code>photo_generator</code></strong> یاد می‌گیرد که چگونه <strong>نقاشی‌ مونه را به تصاویر</strong> تبدیل کند.</span></p>\n<p dir=\"rtl\" style=\"text-align: justify;\"><span style=\"font-size: 14pt;\">به این دلیل که تصاویر <strong>جفت‌شده نیستند</strong> و از هر منظره هم تصویر واقعی و هم نقاشی مونه را نداریم، نیاز است که <strong>دو چرخه تبدیل تصاویر به یکدیگر</strong> داشته باشیم که تصویر را نهایی را همانطور که گفتیم، تصویر دوار یا Cycle Photo می‌گوییم. بنابراین چنین مراحلی خواهیم داشت:</span></p>\n\n<ul dir=\"rtl\" style=\"text-align: justify;\">\n \t<li style=\"list-style-type: none;\">\n<ul>\n \t<li style=\"list-style-type: none;\">\n<ul>\n \t<li><strong><span style=\"font-size: 14pt;\">Input Photo -&gt; G_MONET -&gt; Fake Monet -&gt; G_PHOTO -&gt; Cycle Photo</span></strong></li>\n \t<li><strong><span style=\"font-size: 14pt;\">Input Monet -&gt; G_PHOTO -&gt; Fake Photo -&gt; G_MONET -&gt; Cycle Monet  </span></strong></li>\n</ul>\n</li>\n</ul>\n</li>\n</ul>\n<p dir=\"rtl\" style=\"text-align: justify;\"><span style=\"font-size: 14pt;\"><strong><code>monet_discriminator</code></strong> یاد می‌گیرد که چگونه <strong>نقاشی‌های تقلبی مونه را از نمونه‌های واقعی تمایز دهد.</strong> بهبود یادگیری در تمایزدهنده مونه سبب می‌شود که تولیدکننده مونه مجبور شود نقاشی‌های تولیدی خود را بهتر کند تا تمایزدهنده نقاشی‌ها را به دردسر بیاندازد و این همان تئوری بازی است که از آن صحبت کردیم.</span></p>\n<p dir=\"rtl\" style=\"text-align: justify;\"><span style=\"font-size: 14pt;\"><strong><code>photo_discriminator</code></strong> یاد می‌گیرد که چ<strong>گونه تصاویر تقلبی را از نمونه‌های واقعی تمایز دهد.</strong> بهبود یادگیری در تمایزدهنده تصاویر سبب می‌شود که تولیدکننده تصاویر مجبور شود تصاویر تولیدی خود را بهتر کند تا تمایزدهنده تصاویر را به دردسر بیاندازد و این همان تئوری بازی است که از آن صحبت کردیم.</span></p>\n<p dir=\"rtl\" style=\"text-align: justify;\"><span style=\"font-size: 14pt;\">نکته مهم در این جا این است که <strong>به دلیل جفت نبودن تصاویر با یکدیگر، برای محاسبه خطای تمیزدهنده‌ها، هر کدام از آن‌ها دوبار محاسبه می‌شود،</strong> یکبار با نمونه‌ واقعی و بار دیگر با نمونه تقلبی تا بتوان خطای واقعی را به دست آورد و مقایسه کرد که تا چه حد تمایزدهنده خوب عمل می‌کنند.</span></p>","metadata":{}},{"cell_type":"code","source":"with strategy.scope():\n    monet_generator = Generator() # transforms photos to Monet-esque paintings\n    photo_generator = Generator() # transforms Monet paintings to be more like photos\n\n    monet_discriminator = Discriminator() # differentiates real Monet paintings and generated Monet paintings\n    photo_discriminator = Discriminator() # differentiates real photos and generated photos","metadata":{"execution":{"iopub.status.busy":"2022-02-17T07:14:06.776985Z","iopub.execute_input":"2022-02-17T07:14:06.777273Z","iopub.status.idle":"2022-02-17T07:14:15.833852Z","shell.execute_reply.started":"2022-02-17T07:14:06.777239Z","shell.execute_reply":"2022-02-17T07:14:15.833026Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"tf.keras.utils.plot_model(monet_generator, show_shapes=True, dpi=64)","metadata":{"execution":{"iopub.status.busy":"2022-02-17T07:14:15.835333Z","iopub.execute_input":"2022-02-17T07:14:15.835557Z","iopub.status.idle":"2022-02-17T07:14:16.987069Z","shell.execute_reply.started":"2022-02-17T07:14:15.83553Z","shell.execute_reply":"2022-02-17T07:14:16.9863Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"tf.keras.utils.plot_model(monet_discriminator, show_shapes=True, dpi=64)","metadata":{"execution":{"iopub.status.busy":"2022-02-17T07:14:16.988383Z","iopub.execute_input":"2022-02-17T07:14:16.988733Z","iopub.status.idle":"2022-02-17T07:14:17.145402Z","shell.execute_reply.started":"2022-02-17T07:14:16.988702Z","shell.execute_reply":"2022-02-17T07:14:17.144093Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"<p dir=\"rtl\" style=\"text-align: justify;\"><span style=\"font-size: 14pt;\">با توجه به این که هنوز تولیدکننده‌های ما آموزش ندیده‌اند، تصاویر تولیدی آن‌ها کیفیت خاصی ندارد که در ادامه می‌بینیم.</span></p>","metadata":{}},{"cell_type":"code","source":"to_monet = monet_generator(example_photo)\n\nplt.subplot(1, 2, 1)\nplt.title(\"Original Photo\")\nplt.imshow(example_photo[0] * 0.5 + 0.5)\n\nplt.subplot(1, 2, 2)\nplt.title(\"Monet-esque Photo\")\nplt.imshow(to_monet[0] * 0.5 + 0.5)\nplt.show()","metadata":{"execution":{"iopub.status.busy":"2022-02-17T07:14:17.147278Z","iopub.execute_input":"2022-02-17T07:14:17.147523Z","iopub.status.idle":"2022-02-17T07:14:17.811387Z","shell.execute_reply.started":"2022-02-17T07:14:17.147493Z","shell.execute_reply":"2022-02-17T07:14:17.810525Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"<p dir=\"rtl\" style=\"text-align: justify;\"><span style=\"font-size: 14pt; color: #ff0000;\"><strong><span style=\"color: #ff0000; font-size: 18pt;\">• ساخت مدل چرخشی</span></strong></span></p>\n<p dir=\"rtl\" style=\"text-align: justify;\"><span style=\"font-size: 14pt;\">کلاس CycleGan را که از <strong><code>keras.model</code></strong> به ارث برده شده است را ایجاد می‌کنیم. با این کار در انتها با <strong><code>fit</code></strong> مدل را آموزش می‌دهیم. با این روش استفاده از ظرفیت TPU بهینه می‌شود.</span></p>\n<p dir=\"rtl\" style=\"text-align: justify;\"><span style=\"font-size: 14pt;\"> در طول یادگیری در مدل، یکبار تصویر به نقاشی و دوباره به تصویر تبدیل می‌شود و تفاوت بین تصویری که با دومرحله چرخش به دست آمده است و تصویری که با گذر از یک تولیدکننده به دست آمده است، خطای ثبات چرخش می‌گویند. هدف ما این است که تصویر دو مرحله گذرداده شده که تصویر دوار می‌گویم یا تصویری که یک مرحله گذر داده شده است، یکسان باشد.</span></p>\n<p dir=\"rtl\" style=\"text-align: justify;\"><span style=\"font-size: 14pt;\">چنین تعریفی برای نقاشی‌ها هم صدق می‌کند.</span></p>\n<p dir=\"rtl\" style=\"text-align: justify;\"><strong><span style=\"font-size: 14pt;\">خطاهای آموزش در مرحله بعد تعریف می‌شوند.</span></strong></p>\n<p dir=\"rtl\" style=\"text-align: justify;\"><span style=\"font-size: 14pt;\">در اینجا دو تا مفهوم استفاده شده است:</span></p>\n\n<ul dir=\"rtl\" style=\"text-align: justify;\">\n \t<li dir=\"rtl\"><span style=\"font-size: 14pt;\"><strong>کلاس ارث‌بری شده از <code>Keras.Model</code></strong></span></li>\n \t<li dir=\"rtl\"><span style=\"font-size: 14pt;\"><strong>مفهوم <code>Gradient.Tape</code></strong></span></li>\n</ul>\n<p dir=\"rtl\" style=\"text-align: justify;\"><span style=\"font-size: 14pt;\">یکی از اصول اساسی کراس، <strong>افشای تدریجی پیچیدگی‌ها</strong> (progressive disclosure of complexity) است. باید بتوانید به صورت تدریجی وارد جریان‌های کاری سطح پایین‌تر بشوید. اگر عملکرد سطح بالای موجود دقیقاً با نیاز مورد استفاده شما تطابق ندارد، نباید از صخره سقوط کنید! باید بتوانید کنترل بیشتری بر روی جزئیات کوچک به دست آورید و در عین حال میزان مناسبی از راحتی در سطح بالاتر را حفظ کنید. طبق این اصل، شما همیشه باید قادر باشید تا به سطوح کاری زیرین کتابخانه به <strong>شیوه تدریجی</strong> دسترسی پیدا کنید. در واقع اگر مورد کار شما دقیقاً با تعریف‌های پایه‌ای کتابخانه نیست، برای رفع نیاز خود شما نباید از قله انتزاع به دره پیچیدگی‌های سطح پایین سقوط کنید. شما در هر مرحله باید بتوانید <strong>به آن مقداری از جزئیات که برای تغییر نیاز دارید</strong> دسترسی داشته باشید.</span></p>\n<p dir=\"rtl\" style=\"text-align: justify;\"><span style=\"font-size: 14pt;\">وقتی که می‌خواهید <strong><code>()fit</code></strong> را برای خودتان سفارشی کنید، باید مراحل آموزشی تابع کلاس <strong><code>Model</code></strong> را باطل و یا بهتر بگوییم بازنویسی کنید تا بتوانید با فراخوانی <strong><code>()fit</code></strong> به مانند قبل، الگوریتم‌های آموزشی خود را اجرا کنید. شما در عمل باید این تابع از کلاس <strong><code>Model</code></strong> را که مسئول اجرای قدم‌های آموزش مدل است را بازنویسی کنید. این تابع برای دسته یا batch از داده صدا زده می‌شود. پس از بازنویسی این تابع از کلاس <strong><code>Model</code></strong>، این تابع می‌تواند به طور معمول با کد شما صدا زده شود تا الگوریتم شخصی شما را روی داده اجرا کند تا آموزش شبکه انجام شود.<strong><a href=\"https://keras.io/guides/customizing_what_happens_in_fit/\"> اطلاعات بیشتر در اینجا</a></strong></span></p>\n<p dir=\"rtl\" style=\"text-align: justify;\"><span style=\"font-size: 14pt;\">وقتی که نیاز داریم حلقه‌های آموزش را از پایه و صفر بنویسیم، با استفاده از <strong><code>Gradient.Tape</code></strong> می‌توانیم کنترل هر چیز جزئی را هم در اختیار داشته باشیم. در اینجا یک الگوریتم آموزشی ایجاد کرده‌ایم اما نیاز داریم که از ویژگی‌هایی که fit به ما ارائه می‌کند هم بهره‌مند شویم، ویژگی‌هایی مانند callbacks و built-in distribution support و...</span></p>\n<p dir=\"rtl\" style=\"text-align: justify;\"><span style=\"font-size: 14pt;\">می‌توانیم از <strong><code>Gradient.Tape</code></strong> برای دنبال کردن عملیات‌ها استفاده کنیم تا بعدا گرادیان‌ها را محاسبه کنیم. در واقع با استفاده از این راهکار، گرادیان‌های تولید‌کننده‌ها و تمایزدهنده را حساب می‌کنیم و در Tape ذخیره می‌کنیم و در مراحل بعد این موارد را به بهینه‌سازها اعمال می‌کنیم. <strong> <a href=\"https://www.tensorflow.org/api_docs/python/tf/GradientTape\">اطلاعات بیشتر در اینجا</a></strong></span></p>\n<p dir=\"rtl\" style=\"text-align: justify;\"><span style=\"font-size: 14pt;\"><strong><code>lamdba_cycle=10</code></strong> در اینجا یک هایپرپامتر است و با استفاده از آن خطای ثبات چرخش را وزن‌دهی می‌کنیم و در ابتدای کار برابر 10 قرار می‌دهیم.<strong><a href=\"https://towardsdatascience.com/improving-the-efficiency-of-the-loss-function-in-cycle-consistent-adversarial-networks-808cca3669f0\">برای اطلاعات بیشتر در اینجا</a> </strong>و<span style=\"color: #ff0000;\"><a style=\"color: #ff0000;\" href=\"https://medium.com/analytics-vidhya/the-beauty-of-cyclegan-c51c153493b8\"><strong> اینجا</strong></a></span></span></p>\n<p dir=\"rtl\" style=\"text-align: justify;\"><span style=\"font-size: 14pt;\">در واقع هایپرپارامتر λ در فرمول زیر برای <strong>افزایش وزن و تاثیر خطای ثبات چرخش</strong> وارد می‌شود و در کد استفاده می‌گردد.</span></p>\n<p dir=\"rtl\" style=\"text-align: center;\"><img class=\"aligncenter \" src=\"https://i.ibb.co/CbSyR9z/formula.png\" width=\"426\" height=\"148\" /></p>\n<p dir=\"rtl\" style=\"text-align: justify;\"><span style=\"font-size: 14pt;\">در مقاله اصلی معرفی گن‌های چرخشی از خطای هویت <strong>صحبتی نشده است</strong> و به طور معمول، وزن این خطا در محاسبه خطای کلی، <strong>0.5λ</strong> تعیین می‌شود.</span></p>","metadata":{}},{"cell_type":"code","source":"class CycleGan(keras.Model):\n    def __init__(\n        self,\n        monet_generator,\n        photo_generator,\n        monet_discriminator,\n        photo_discriminator,\n        lambda_cycle=10,\n    ):\n        super(CycleGan, self).__init__()\n        self.m_gen = monet_generator\n        self.p_gen = photo_generator\n        self.m_disc = monet_discriminator\n        self.p_disc = photo_discriminator\n        self.lambda_cycle = lambda_cycle\n        \n    def compile(\n        self,\n        m_gen_optimizer,\n        p_gen_optimizer,\n        m_disc_optimizer,\n        p_disc_optimizer,\n        gen_loss_fn,\n        disc_loss_fn,\n        cycle_loss_fn,\n        identity_loss_fn\n    ):\n        super(CycleGan, self).compile()\n        self.m_gen_optimizer = m_gen_optimizer\n        self.p_gen_optimizer = p_gen_optimizer\n        self.m_disc_optimizer = m_disc_optimizer\n        self.p_disc_optimizer = p_disc_optimizer\n        self.gen_loss_fn = gen_loss_fn\n        self.disc_loss_fn = disc_loss_fn\n        self.cycle_loss_fn = cycle_loss_fn\n        self.identity_loss_fn = identity_loss_fn\n        \n    def train_step(self, batch_data):\n        real_monet, real_photo = batch_data\n        \n        with tf.GradientTape(persistent=True) as tape:\n            # photo to monet back to photo\n            fake_monet = self.m_gen(real_photo, training=True)\n            cycled_photo = self.p_gen(fake_monet, training=True)\n\n            # monet to photo back to monet\n            fake_photo = self.p_gen(real_monet, training=True)\n            cycled_monet = self.m_gen(fake_photo, training=True)\n\n            # generating itself\n            same_monet = self.m_gen(real_monet, training=True)\n            same_photo = self.p_gen(real_photo, training=True)\n\n            # discriminator used to check, inputing real images\n            disc_real_monet = self.m_disc(real_monet, training=True)\n            disc_real_photo = self.p_disc(real_photo, training=True)\n\n            # discriminator used to check, inputing fake images\n            disc_fake_monet = self.m_disc(fake_monet, training=True)\n            disc_fake_photo = self.p_disc(fake_photo, training=True)\n\n            # evaluates generator loss\n            monet_gen_loss = self.gen_loss_fn(disc_fake_monet)\n            photo_gen_loss = self.gen_loss_fn(disc_fake_photo)\n\n            # evaluates total cycle consistency loss\n            total_cycle_loss = self.cycle_loss_fn(real_monet, cycled_monet, self.lambda_cycle) + self.cycle_loss_fn(real_photo, cycled_photo, self.lambda_cycle)\n\n            # evaluates total generator loss\n            total_monet_gen_loss = monet_gen_loss + total_cycle_loss + self.identity_loss_fn(real_monet, same_monet, self.lambda_cycle)\n            total_photo_gen_loss = photo_gen_loss + total_cycle_loss + self.identity_loss_fn(real_photo, same_photo, self.lambda_cycle)\n\n            # evaluates discriminator loss\n            monet_disc_loss = self.disc_loss_fn(disc_real_monet, disc_fake_monet)\n            photo_disc_loss = self.disc_loss_fn(disc_real_photo, disc_fake_photo)\n\n        # Calculate the gradients for generator and discriminator\n        monet_generator_gradients = tape.gradient(total_monet_gen_loss,\n                                                  self.m_gen.trainable_variables)\n        photo_generator_gradients = tape.gradient(total_photo_gen_loss,\n                                                  self.p_gen.trainable_variables)\n\n        monet_discriminator_gradients = tape.gradient(monet_disc_loss,\n                                                      self.m_disc.trainable_variables)\n        photo_discriminator_gradients = tape.gradient(photo_disc_loss,\n                                                      self.p_disc.trainable_variables)\n\n        # Apply the gradients to the optimizer\n        self.m_gen_optimizer.apply_gradients(zip(monet_generator_gradients,\n                                                 self.m_gen.trainable_variables))\n\n        self.p_gen_optimizer.apply_gradients(zip(photo_generator_gradients,\n                                                 self.p_gen.trainable_variables))\n\n        self.m_disc_optimizer.apply_gradients(zip(monet_discriminator_gradients,\n                                                  self.m_disc.trainable_variables))\n\n        self.p_disc_optimizer.apply_gradients(zip(photo_discriminator_gradients,\n                                                  self.p_disc.trainable_variables))\n        \n        return {\n            \"monet_gen_loss\": total_monet_gen_loss,\n            \"photo_gen_loss\": total_photo_gen_loss,\n            \"monet_disc_loss\": monet_disc_loss,\n            \"photo_disc_loss\": photo_disc_loss\n        }","metadata":{"execution":{"iopub.status.busy":"2022-02-17T07:14:17.812847Z","iopub.execute_input":"2022-02-17T07:14:17.813095Z","iopub.status.idle":"2022-02-17T07:14:17.834301Z","shell.execute_reply.started":"2022-02-17T07:14:17.813067Z","shell.execute_reply":"2022-02-17T07:14:17.833254Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"<p dir=\"rtl\" style=\"text-align: justify;\"><span style=\"font-size: 14pt; color: #ff0000;\"><strong><span style=\"color: #ff0000; font-size: 18pt;\">• محاسبه توابع خطا</span></strong></span></p>\n<p dir=\"rtl\" style=\"text-align: justify;\"><span style=\"font-size: 18.6667px;\">تابع خطا تمایزدهنده تصاویر <strong>واقعی</strong> را با ماتریسی از <strong>یک‌ها</strong> و تصاویر <strong>تقلبی</strong> را با ماتریسی از <strong>صفرها</strong> مقایسه می‌کند. زمانی تمایزدهنده به خوبی عمل می‌کند که برای همه تصاویر واقعی یک و برای همه تصاویر تقلبی، صفر را نتیجه دهد. خطای تمایزدهنده، میانگین خطای تشخیص برای تصاویر واقعی و تصاویر تولید شده است.</span></p>\n<p dir=\"rtl\" style=\"text-align: justify;\"><span style=\"font-size: 14pt;\">در محاسبه خطای تولیدکننده و تمایزدهنده از BinaryCrossentropy استفاده می‌شود. </span></p>\n<p dir=\"rtl\" style=\"text-align: justify;\"><span style=\"font-size: 14pt;\">تابع خطای تمایزدهنده 2 ورودی دریافت می‌کند:</span></p>\n\n<ul dir=\"rtl\" style=\"text-align: justify;\">\n \t<li><span style=\"font-size: 14pt;\"><strong>در تمایز دادن تصاویر:</strong> الف) <strong>خروجی تمایزدهنده تصاویر</strong> که ورودی آن یک <strong>تصویر واقعی</strong> از مجموعه داده‌ها بود است. ب) <strong>خروجی تمایزدهنده تصاویر</strong> که ورودی آن یک <strong>تصویر تقلبی</strong> تولید شده بوسیله تولیدکننده تصویر بوده است.</span></li>\n \t<li><span style=\"font-size: 14pt;\"><strong>در تمایز دادن نقاشی‌ها:</strong> الف) <strong>خروجی تمایزدهنده مونه</strong> که ورودی آن یک <strong>نقاشی واقعی</strong> از مجموعه داده‌ها بود است. ب) <strong>خروجی تمایزدهنده مونه</strong> که ورودی آن یک <strong>نقاشی تقلبی</strong> تولید شده بوسیله تولیدکننده مونه بوده است.</span></li>\n</ul>\n<p dir=\"rtl\" style=\"text-align: justify;\"><span style=\"font-size: 14pt;\">در محاسبه <strong>خطای نهایی</strong> دو عنصر تاثیر می‌گذارند:</span></p>\n\n<ul dir=\"rtl\" style=\"text-align: justify;\">\n \t<li><span style=\"font-size: 14pt;\"><strong>خطای تشخیص نمونه‌های واقعی</strong> که از مقایسه تصاویر واقعی با ماتریسی از یک‌ها به دست می‌آید.</span></li>\n \t<li><span style=\"font-size: 14pt;\"><strong>خطای تشخیص نمونه‌های تولیدشده</strong> که از مقایسه تصاویر تقلبی با ماتریسی از صفرها به دست می‌آید.</span></li>\n</ul>\n<p dir=\"rtl\" style=\"text-align: justify;\"><strong><span style=\"font-size: 14pt;\">بنابراین خطای نهایی در تمایزدهنده‌ها، نصف مجموع خطای تشخیص نمونه‌های واقعی و خطای تشخیص نمونه‌های تولیدشده می‌باشد.</span></strong></p>","metadata":{}},{"cell_type":"code","source":"with strategy.scope():\n    def discriminator_loss(real, generated):\n        real_loss = tf.keras.losses.BinaryCrossentropy(from_logits=True, reduction=tf.keras.losses.Reduction.NONE)(tf.ones_like(real), real)\n\n        generated_loss = tf.keras.losses.BinaryCrossentropy(from_logits=True, reduction=tf.keras.losses.Reduction.NONE)(tf.zeros_like(generated), generated)\n\n        total_disc_loss = real_loss + generated_loss\n\n        return total_disc_loss * 0.5","metadata":{"execution":{"iopub.status.busy":"2022-02-17T07:14:17.835452Z","iopub.execute_input":"2022-02-17T07:14:17.835971Z","iopub.status.idle":"2022-02-17T07:14:17.851755Z","shell.execute_reply.started":"2022-02-17T07:14:17.835939Z","shell.execute_reply":"2022-02-17T07:14:17.85069Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"<p dir=\"rtl\" style=\"text-align: justify;\"><span style=\"font-size: 14pt;\"><strong>• محاسبه خطای تولید کننده:</strong></span></p>\n<p dir=\"rtl\" style=\"text-align: justify;\"><span style=\"font-size: 14pt;\">برای محاسبه خطای تولیدکننده باید به سه مفهوم توجه کنیم:</span></p>\n\n<ul dir=\"rtl\" style=\"text-align: justify;\">\n \t<li dir=\"rtl\"><span style=\"font-size: 14pt;\"><strong>خطای حریف</strong> یا Adversary loss که ناشی از <strong>خطای تمایزدهنده</strong> می‌باشد.</span></li>\n \t<li dir=\"rtl\"><span style=\"font-size: 14pt;\"><strong>خطای چرخه</strong> یا Cycle loss که بین <strong>تصویر ورودی</strong> ابتدایی با تصویر <strong>دوار نهایی</strong> محاسبه می‌شود.</span></li>\n \t<li dir=\"rtl\"><span style=\"font-size: 14pt;\"><strong>خطای تشخیص هویت</strong> یا Identity loss که بین <strong>تصویر ورودی</strong> و <strong>تصویر تولیدشده</strong> محاسبه می‌شود تا بفهمیم که آیا تولیدکننده متوجه می‌شود که اگر تصویر ورودی در دامنه نهایی قرار داشت، <strong>نباید تغییری روی آن اعمال کند؟</strong></span></li>\n</ul>\n<p dir=\"rtl\" style=\"text-align: justify;\"><span style=\"font-size: 14pt;\"><strong>در محاسبه خطای حریف باید این گونه عمل کنیم:</strong> </span></p>\n\n<ul dir=\"rtl\" style=\"text-align: justify;\">\n \t<li><span style=\"font-size: 14pt;\"><strong>در تشخیص این خطا در تولیدکننده مونه</strong>، تابع خطا در ورودی خود، خروجی حالت‌های <strong>نقاشی‌های تقلبی در تمایزدهنده</strong> مونه را دریافت می‌کند تا بسنجد تا چه میزان نقاشی‌های تقلبی کشف می‌شوند.</span></li>\n \t<li><span style=\"font-size: 14pt;\"><strong>در تشخیص این خطا در تولیدکننده تصاویر،</strong> تابع خطا در ورودی خود، خروجی حالت‌های <strong>تصاویر تقلبی در تمایزدهنده</strong> تصویر را دریافت می‌کند تا بسنجد تا چه میزان تصاویر تقلبی کشف می‌شوند.</span></li>\n</ul>\n<p dir=\"rtl\" style=\"text-align: justify;\"><span style=\"font-size: 14pt;\">تولیدکننده زمانی می‌فهمد که خوب عمل کرده است که تمایزدهنده به دردسر افتاده باشد و <strong>تصویری را تقلبی تشخیص ندهد</strong> که این تصویر تقلبی بتواند به عنوان ورودی برای تابع تشخیص خطا در تولیدکننده استفاده شود، در واقع برای <strong>همه ورودی‌ها</strong>، <strong>واقعی را تشخیص دهد!</strong></span></p>","metadata":{}},{"cell_type":"code","source":"with strategy.scope():\n    def generator_loss(generated):\n        return tf.keras.losses.BinaryCrossentropy(from_logits=True, reduction=tf.keras.losses.Reduction.NONE)(tf.ones_like(generated), generated)","metadata":{"execution":{"iopub.status.busy":"2022-02-17T07:14:17.853452Z","iopub.execute_input":"2022-02-17T07:14:17.853718Z","iopub.status.idle":"2022-02-17T07:14:17.864173Z","shell.execute_reply.started":"2022-02-17T07:14:17.853683Z","shell.execute_reply":"2022-02-17T07:14:17.863051Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"<p dir=\"rtl\" style=\"text-align: justify;\"><span style=\"font-size: 14pt;\"><strong>• خطای ثبات چرخش در تولیدکننده:</strong></span></p>\n<p dir=\"rtl\" style=\"text-align: justify;\"><span style=\"font-size: 14pt;\">همانطور که گفتیم، داده‌های آموزشی <strong>جفت شده نیستند</strong> و به همین دلیل برای آموزش مدل برای یادگیری نحوه نگاشت و تبدیل ورودی‌ها از دامنه مبدا به دامنه مقصد، یک نوع خاص از خطا با نام <strong>خطای ثبات چرخش</strong> معرفی می‌شود. </span></p>\n\n<div class=\"\" dir=\"rtl\" style=\"text-align: justify;\">\n<div class=\"cell border-box-sizing text_cell rendered\">\n<div class=\"inner_cell\">\n<div class=\"text_cell_render border-box-sizing rendered_html\"><strong><span style=\"font-size: 14pt;\">این چرخه شامل مراحل زیر است:</span></strong>\n<ul>\n \t<li><span style=\"font-size: 14pt;\">یک تصویر ورودی بوسیله یک تولیدکننده مونه به یک نقاشی تقلبی تبدیل می‌شود و این نقاشی تقلبی به عنوان یک ورودی برای تولیدکننده تصویر استفاده شده و این تولیدکننده تصویر آن را تبدیل به یک تصویر می‌کند که آن را تصویر دوار می‌گوییم.</span>\n<ul>\n \t<li><strong><span style=\"font-size: 14pt;\">Input Photo -&gt; G_MONET -&gt; Fake Monet -&gt; G_PHOTO -&gt; Cycle Photo</span></strong></li>\n</ul>\n</li>\n \t<li><span style=\"font-size: 14pt;\">یک نقاشی ورودی بوسیله یک تولیدکننده تصویر به یک تصویر تقلبی تبدیل می‌شود و این تصویر تقلبی به عنوان یک ورودی برای تولیدکننده نقاشی استفاده شده و این تولیدکننده نقاشی آن را تبدیل به یک نقاشی می‌کند که آن را نقاشی دوار می‌گوییم.</span>\n<ul>\n \t<li><strong><span style=\"font-size: 14pt;\">Input Monet -&gt; G_PHOTO -&gt; Fake Photo -&gt; G_MONET -&gt; Cycle Monet</span></strong></li>\n</ul>\n</li>\n</ul>\n<span style=\"font-size: 14pt;\">در واقع تصویر یا نقاشی دوار <strong>در انتهای هر مرحله</strong>، باید در <strong>دامنه ورودی باشد</strong> و به دنبال به دست آوردن خطای این تبدیل می‌باشیم که متوجه شویم تولیدکننده‌ها تا چه مقدار توانستند ویژگی‌ها را برای تبدیل دامنه‌ها به یکدیگر بیابند. پس ب<strong>رای محاسبه خطای ثبات چرخش</strong>، دو چیز باید<strong> اندازه گرفته شوند:</strong></span>\n<ul>\n \t<li style=\"list-style-type: none;\">\n<ul>\n \t<li><span style=\"font-size: 14pt;\"><strong>میانگین خطای مطلق برای تصاویر</strong>، که از محاسبه بین تصویر ورودی و تصویر دوار به دست می‌آید.</span></li>\n \t<li><span style=\"font-size: 14pt;\"><strong>میانگین خطای مطلق برای نقاشی‌ها،</strong> که از محاسبه بین نقاشی ورودی و نقاشی دوار به دست می‌آید.</span></li>\n</ul>\n</li>\n</ul>\n<span style=\"font-size: 14pt;\">خطای چرخشی در نهایت جمع این دو مقدار خواهد بود.</span>\n\n</div>\n</div>\n</div>\n</div>\n<p dir=\"rtl\" style=\"text-align: justify;\"><span style=\"font-size: 14pt;\">همین تعاریف هم برای خطای چرخشی کل قابل استفاده است.</span></p>","metadata":{}},{"cell_type":"code","source":"with strategy.scope():\n    def calc_cycle_loss(real_image, cycled_image, LAMBDA):\n        loss1 = tf.reduce_mean(tf.abs(real_image - cycled_image))\n\n        return LAMBDA * loss1","metadata":{"execution":{"iopub.status.busy":"2022-02-17T07:14:17.865333Z","iopub.execute_input":"2022-02-17T07:14:17.865585Z","iopub.status.idle":"2022-02-17T07:14:17.878155Z","shell.execute_reply.started":"2022-02-17T07:14:17.865553Z","shell.execute_reply":"2022-02-17T07:14:17.877267Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"<p dir=\"rtl\" style=\"text-align: justify;\"><span style=\"font-size: 14pt;\"><strong>• خطای تشخیص هویت:</strong></span></p>\n<p dir=\"rtl\" style=\"text-align: justify;\"><span style=\"font-size: 14pt;\">ما انتظار داریم که اگر به تولیدکننده نقاشی مونه یک نقاشی مونه را به عنوان ورودی دادیم، در خروجی <strong>تغییر زیادی را بر روی ورودی مشاهده نکنیم</strong> و به معنای این است که تولیدکننده باید تشخیص دهد هویت نمونه ورودی را و در صورتی که <strong>در دامنه مقصد</strong> بود، تغییری بر روی آن اعمال <strong>نکند</strong>.</span></p>\n<p dir=\"rtl\" style=\"text-align: justify;\"><span style=\"font-size: 14pt;\">بنابراین <strong>خطای تشخیص هویت</strong> بر اساس <strong>شباهت</strong> تصویر خروجی به ورودی عمل می‌کند.</span></p>\n\n<div class=\"\" dir=\"rtl\">\n<div class=\"cell border-box-sizing text_cell rendered\">\n<div class=\"inner_cell\">\n<div class=\"text_cell_render border-box-sizing rendered_html\">\n<ul style=\"text-align: justify;\">\n \t<li><span style=\"font-size: 14pt;\">این تابع 2 ورودی دریافت می‌کند،<strong> تصویر اصلی</strong> و <strong>تصویر تولید</strong> شده از روی تصویر اصلی که در همان دامنه تصویر اصلی است و باید <strong>تا حد ممکن به آن شبیه باشد.</strong></span>\n<ul>\n \t<li><span style=\"font-size: 14pt;\"><strong>برای خطای تولیدکننده مونه،</strong> مونه تولید شده و مونه ورودی محاسبه می‌شوند.</span></li>\n \t<li><span style=\"font-size: 14pt;\"><strong>برای خطای تولیدکننده تصویر،</strong> تصویر تولید شده و تصویر ورودی محاسبه می‌شوند.</span></li>\n</ul>\n</li>\n</ul>\n<p style=\"text-align: justify;\"><span style=\"font-size: 14pt;\">خطا در نهایت م<strong>یانگین خطای مطلق</strong> بین نمونه تولید شده بوسیله تولیدکننده و نمونه واقعی خواهد بود.</span></p>\n\n</div>\n</div>\n</div>\n</div>\n<div class=\"\" dir=\"rtl\" style=\"text-align: justify;\">\n<div class=\"cell border-box-sizing text_cell rendered\">\n<div class=\"inner_cell\">\n<div class=\"text_cell_render border-box-sizing rendered_html\">\n<ul>\n \t<li style=\"list-style-type: none;\"></li>\n</ul>\n</div>\n</div>\n</div>\n</div>","metadata":{}},{"cell_type":"code","source":"with strategy.scope():\n    def identity_loss(real_image, same_image, LAMBDA):\n        loss = tf.reduce_mean(tf.abs(real_image - same_image))\n        return LAMBDA * 0.5 * loss","metadata":{"execution":{"iopub.status.busy":"2022-02-17T07:14:17.879687Z","iopub.execute_input":"2022-02-17T07:14:17.879933Z","iopub.status.idle":"2022-02-17T07:14:17.891487Z","shell.execute_reply.started":"2022-02-17T07:14:17.879906Z","shell.execute_reply":"2022-02-17T07:14:17.890594Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"<p dir=\"rtl\" style=\"text-align: justify;\"><span style=\"font-size: 14pt; color: #ff0000;\"><strong><span style=\"color: #ff0000; font-size: 18pt;\">• آموزش گن‌چرشی</span></strong></span></p>\n<p dir=\"rtl\" style=\"text-align: justify;\"><span style=\"font-size: 14pt;\">نوبت به آموزش مدل رسیده است. در ابتدا <strong>بهینه‌سازها</strong> یا optimizers را برای تولیدکننده‌ها و تمایزدهنده‌ها تعیین می‌کنیم. برای بهینه‌ساز از <strong>Adam</strong> و <strong>نرخ یادیگیری 0.0002</strong> استفاده می‌کنیم. <strong>Adam بهترین الگوریتم بهینه‌سازی است</strong>. با Adam می‌توانید آموزش شبکه عصبی را در زمان کمتر و کارایی بالاتر انجام دهید. این روش بر اساس تکانه‌ها عمل می‌کند که <strong><code>beta_1</code></strong> تکانه اول است که در اینجا 0.5 تنظیم شده است.</span></p>","metadata":{}},{"cell_type":"code","source":"with strategy.scope():\n    monet_generator_optimizer = tf.keras.optimizers.Adam(2e-4, beta_1=0.5)\n    photo_generator_optimizer = tf.keras.optimizers.Adam(2e-4, beta_1=0.5)\n\n    monet_discriminator_optimizer = tf.keras.optimizers.Adam(2e-4, beta_1=0.5)\n    photo_discriminator_optimizer = tf.keras.optimizers.Adam(2e-4, beta_1=0.5)","metadata":{"execution":{"iopub.status.busy":"2022-02-17T07:14:17.893047Z","iopub.execute_input":"2022-02-17T07:14:17.89339Z","iopub.status.idle":"2022-02-17T07:14:17.9058Z","shell.execute_reply.started":"2022-02-17T07:14:17.893347Z","shell.execute_reply":"2022-02-17T07:14:17.905151Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"<p dir=\"rtl\" style=\"text-align: justify;\"><span style=\"font-size: 14pt;\">یک گن‌چرخشی ساخته و مدل را کامپایل می‌کنیم.</span></p>","metadata":{}},{"cell_type":"code","source":"with strategy.scope():\n    cycle_gan_model = CycleGan(\n        monet_generator, photo_generator, monet_discriminator, photo_discriminator\n    )\n\n    cycle_gan_model.compile(\n        m_gen_optimizer = monet_generator_optimizer,\n        p_gen_optimizer = photo_generator_optimizer,\n        m_disc_optimizer = monet_discriminator_optimizer,\n        p_disc_optimizer = photo_discriminator_optimizer,\n        gen_loss_fn = generator_loss,\n        disc_loss_fn = discriminator_loss,\n        cycle_loss_fn = calc_cycle_loss,\n        identity_loss_fn = identity_loss\n    )","metadata":{"execution":{"iopub.status.busy":"2022-02-17T07:14:17.907321Z","iopub.execute_input":"2022-02-17T07:14:17.907668Z","iopub.status.idle":"2022-02-17T07:14:17.974817Z","shell.execute_reply.started":"2022-02-17T07:14:17.907625Z","shell.execute_reply":"2022-02-17T07:14:17.973909Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"<p dir=\"rtl\" style=\"text-align: justify;\"><span style=\"font-size: 14pt;\">با استفاده از <strong><code>fit</code></strong> مدل را آموزش می‌دهیم. تعداد دفعات آموزش را 25 بار قرار می‌دهیم.</span></p>","metadata":{}},{"cell_type":"code","source":"cycle_gan_model.fit(\n    tf.data.Dataset.zip((monet_ds, photo_ds)),\n    epochs=5\n)","metadata":{"execution":{"iopub.status.busy":"2022-02-17T07:14:17.975983Z","iopub.execute_input":"2022-02-17T07:14:17.976319Z","iopub.status.idle":"2022-02-17T07:31:48.023663Z","shell.execute_reply.started":"2022-02-17T07:14:17.976286Z","shell.execute_reply":"2022-02-17T07:31:48.022622Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"<p dir=\"rtl\" style=\"text-align: justify;\"><span style=\"font-size: 14pt; color: #ff0000;\"><strong><span style=\"color: #ff0000; font-size: 18pt;\">• نمایش تصاویر تولیدی</span></strong></span></p>\n<p dir=\"rtl\" style=\"text-align: justify;\"><span style=\"font-size: 14pt;\">نقاشی‌های تولید شده را مشاهده می‌کنیم.</span></p>","metadata":{}},{"cell_type":"code","source":"_, ax = plt.subplots(5, 2, figsize=(12, 12))\nfor i, img in enumerate(photo_ds.take(5)):\n    prediction = monet_generator(img, training=False)[0].numpy()\n    prediction = (prediction * 127.5 + 127.5).astype(np.uint8)\n    img = (img[0] * 127.5 + 127.5).numpy().astype(np.uint8)\n\n    ax[i, 0].imshow(img)\n    ax[i, 1].imshow(prediction)\n    ax[i, 0].set_title(\"Input Photo\")\n    ax[i, 1].set_title(\"Monet-esque\")\n    ax[i, 0].axis(\"off\")\n    ax[i, 1].axis(\"off\")\nplt.show()","metadata":{"execution":{"iopub.status.busy":"2022-02-17T07:31:48.025508Z","iopub.execute_input":"2022-02-17T07:31:48.025759Z","iopub.status.idle":"2022-02-17T07:31:50.17691Z","shell.execute_reply.started":"2022-02-17T07:31:48.02573Z","shell.execute_reply":"2022-02-17T07:31:50.176148Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"<p dir=\"rtl\" style=\"text-align: justify;\"><span style=\"font-size: 14pt; color: #ff0000;\"><strong><span style=\"color: #ff0000; font-size: 18pt;\">• تولید فایل خروجی</span></strong></span></p>","metadata":{}},{"cell_type":"code","source":"import PIL\n! mkdir ../images","metadata":{"execution":{"iopub.status.busy":"2022-02-17T08:08:27.745502Z","iopub.execute_input":"2022-02-17T08:08:27.745859Z","iopub.status.idle":"2022-02-17T08:08:28.549685Z","shell.execute_reply.started":"2022-02-17T08:08:27.745827Z","shell.execute_reply":"2022-02-17T08:08:28.548863Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"i = 1\nfor img in photo_ds:\n    prediction = monet_generator(img, training=False)[0].numpy()\n    prediction = (prediction * 127.5 + 127.5).astype(np.uint8)\n    im = PIL.Image.fromarray(prediction)\n    im.save(\"../images/\" + str(i) + \".jpg\")\n    i += 1","metadata":{"execution":{"iopub.status.busy":"2022-02-17T08:08:33.744197Z","iopub.execute_input":"2022-02-17T08:08:33.744569Z","iopub.status.idle":"2022-02-17T08:42:08.445363Z","shell.execute_reply.started":"2022-02-17T08:08:33.744533Z","shell.execute_reply":"2022-02-17T08:42:08.444619Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"import shutil\nshutil.make_archive(\"/kaggle/working/images\", 'zip', \"/kaggle/images\")","metadata":{"execution":{"iopub.status.busy":"2022-02-17T08:51:39.952708Z","iopub.execute_input":"2022-02-17T08:51:39.953464Z","iopub.status.idle":"2022-02-17T08:51:44.132736Z","shell.execute_reply.started":"2022-02-17T08:51:39.953421Z","shell.execute_reply":"2022-02-17T08:51:44.132004Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"<p dir=\"rtl\" style=\"text-align: justify;\"><span style=\"font-size: 14pt; color: #ff0000;\"><strong><span style=\"color: #ff0000; font-size: 18pt;\">• بهبودها</span></strong></span></p>\n<p dir=\"rtl\" style=\"text-align: justify;\"><span style=\"font-size: 14pt;\">با بررسی موارد مشابه کدهای دیگر در این رقابت و هایپرپارامترهای موجود در مسئله، برای بهبود پیشنهادات زیر ارائه می‌شود:</span></p>\n\n<ul dir=\"rtl\" style=\"text-align: justify;\">\n \t<li style=\"text-align: justify;\"><strong><span style=\"font-size: 14pt;\">افزایش داده یا Augmentation: </span></strong><span style=\"font-size: 14pt;\">تصاویر مورد استفاده در این رقابت تعداد کمی دارند؛ 300 نقاشی مونه و 7038 تصویر که برای آموزش چنین شبکه‌ای کم می‌باشند، بنابراین می‌توان از آگمنت کردن داده‌ها استفاده کرد. برای این کار از <strong><code>random_crop</code></strong> و <strong><code>random_mirror</code></strong> استفاده می‌کنیم.</span></li>\n \t<li style=\"text-align: justify;\"><span style=\"font-size: 14pt;\"><strong>دیگ<span style=\"font-size: 14pt;\">ر هایپرپارامترها:</span></strong> برای بهبود نتایج می‌توان تغییراتی در هایپرپارمترهای دیگر مانند <strong>نرخ دراپ‌اوت، نرمال‌سازی نمونه‌ای، لیکی‌رلو</strong> و... اعمال کرد.</span></li>\n \t<li><span style=\"font-size: 14pt;\"><strong>متریکز مناسب:</strong> متریکز مناسب در شبکه‌های گن، <strong>FID</strong> یا Frechet Inception Distance است. در این رقابت، نتایج نهایی با همین متریکز محاسبه می‌شوند. در FID <strong>فاصله میان بردارهای ویژگی</strong> در تصاویر تولید شده و تصاویر تقلبی در دامنه یکسان <strong>سنجیده</strong> می‌شود و هرچقدر <strong>ویژگی‌های تصاویر تقلبی نزدیکتر به ویژگی‌های تصاویر واقعی باشد</strong>، FID عدد <strong>کمتری</strong> را حاصل می‌کند.</span></li>\n</ul>\n<p dir=\"rtl\" style=\"text-align: justify;\"><img class=\"aligncenter size-full\" src=\"https://i.ibb.co/2N3k4ZK/FID.png\" width=\"892\" height=\"371\" /></p>\n<p dir=\"rtl\" style=\"text-align: justify;\"><span style=\"font-size: 14pt;\">در نمودار بالا مشاهده می‌کنیم که در یک مونه‌ساز بهینه شده با تقویت داده، نرخ FID در هر مرحله <strong>کاهش</strong> پیدا می‌کند که در مرحله 13 تقریبا این نرخ ثابت می‌ماند.</span></p>\n<p dir=\"rtl\" style=\"text-align: justify;\"><img class=\"aligncenter size-full\" src=\"https://i.ibb.co/K5ZgkLt/Result.png\" width=\"1059\" height=\"371\" /></p>\n<p dir=\"rtl\" style=\"text-align: justify;\"><span style=\"font-size: 14pt;\">در نمودار بالا خطای تولیدکننده‌های نقاشی و تصویر و تمایزدهنده‌های نقاشی و تصویر را ملاحظه می‌کنید. علاوه بر آن، <strong>خطای ثبات چرخش</strong> را هم مشاهده می‌کنید که این خطا به مرور <strong>کاهش</strong> می‌یابد.</span></p>\n<p dir=\"rtl\" style=\"text-align: justify;\"><span style=\"color: #ff0000; font-size: 14pt;\"><strong>نتیجه نهایی:</strong> <span style=\"color: #000000;\">با بررسی موارد گفته و اعمال آن‌ها، نتیجه گرفتیم که تنظیمات فعلی بهترین تنظیمات برای هایپرپارمترها می‌باشد و اعمال تغییرات در آن‌ها به خطای تولیدکننده و تمایز‌دهنده اضافه می‌کند.</span></span></p>","metadata":{}}]}