معمار نرم افزار، پژوهشگر یادگیری ماشین، زبان و بینایی کامپیوتر، عاشق سفر و خلق تجربیات جدید
چطوری کپچای سیستم گلستان رو با کمک یادگیری ماشین بشکنیم؟
همهی ما از کپچا (CAPTCHA) فراری ایم - همون تصاویر مزاحمی رو میگم که نوشته های درهم ریخته است و برای اینکه به فرم یا صفحه ای از سایت دسترسی داشته باشیم باید اونو تایپ کنیم. کپچاها برای تشخیص انسان از بات ها (همون برنامه های اتوماتیک) و معمولا برای جلوگیری از ورود به بخشی خاص، جلوگیری از پر کردن فرم ها یا کاهش برخی حملات طراحی شدند. جالبه بدونید در حال حاضر مدتی است که کپچاهای متنی محبوبیت خودشون رو از دست دادند و جای خودشون رو به کپچاهای تصویری یا موارد مشابه دادند.
سیستم گلستان رو تقریبا همه می شناسند. سیستم اتوماسیون معروف دانشگاه های ایران که پیدا کردن هر چیزی داخل اون نیازمند یک دوره دکتری تخصصی "زبانهای رسمی و روش های صوری" است!
توی این پست قصد داریم با رویکرد آموزشی و مرحله به مرحله، شکستن کپچای متنی سیستم گلستان رو با بهره گیری از قدرت یادگیری ماشین/عمیق و داده های آماری بررسی کنیم. توصیه میشه اگر دنبال دردسر نیستید این کار رو توی خونه امتحان نکنید? .
برای شروع ماجراجویی، اول نگاهی به فرم ورود سیستم گلستان به همراه تصویر کپچای متنی می اندازیم:
توی این صفحه یک تصویر جداگانه وجود داره که از طریق آدرس تصویر میشه بهش دسترسی داشت. بنابراین قدم اول ذخیره تعداد زیادی از این تصاویر هست تا با اون ها در مرحله بعد یک شبکه عصبی مصنوعی کانولوشنال (شبکه ای برای استخراج ویژگی ها از تصاویر و کلاس بندی) رو آموزش بدیم. نهایتا شبکه آموزش داده شده میتونه تصاویر ورودی رو به متن مورد نظر ترجمه کنه.
جمع آوری داده آموزشی
خُب، معمولا هر الگوریتم یادگیری ماشین برای آموزش نیازمند داده های زیادی هست. شکستن کپچا هم از این قاعده مستثنی نیست. بنابراین برای اینکه بتونیم یک کپچای متنی رو بشکنیم، نیازمند تعداد زیادی تصویر هستیم. برای اینکار یک اسکریپت ساده Shell میتونه چاره کار باشه.
این اسکریپت سعی میکنه تعداد زیادی از فایل های تصویر رو دانلود کنه و با فرمت gif. ذخیره کنه (فرمت فایل های خروجی کدی هست که کپچا رو در سیستم اصلی تولید میکنه).
حالا حدالامکان تصاویر ورودی به سیستم رو به ساده ترین شکل ممکن تبدیل می کنیم. بدین منظور سعی میکنیم تا نوشته پایین تصاویر رو حذف کنیم.
در این مطلب از کتابخونه OpenCV فریم ورک محبوب بینایی کامپیوتر و پردازش تصویر و زبان ++C برای پیش پردازش تصاویر استفاده خواهیم کرد (اگر علاقمندید این کتابخونه Python API داره و می تونید از اون هم استفاده کنید).
کد بالا بخش پایین تصویر ورودی رو حذف میکنه که به عنوان یک آرگومان دریافت شده. بنابراین تا اینجای کار داده های آموزشی برای سیستم یادگیری مون رو در اختیار داریم.
پیش پردازش تصاویر
سیستم تشخیص کپچای ما می تونه مطابق شکل از شبکه عصبی مصنوعی برای پردازش تصاویر و برای شناسایی متن تصویر تشکیل شده باشه که یک تصویر از کپچای متنی رو به عنوان ورودی دریافت کرده و جواب صحیح رو تولید میکنه.
با داشتن داده های آموزشی کافی، رویکرد کلی بالا پاسخ درستی تولید می کنه؛ یعنی فقط کافیه تعداد خیلی زیادی تصویر رو به یکی از لایه های شبکه عصبی کانولوشنال (Convolutional Neural Network) (احتمالا با یک معماری پیچیده و با تعداد لایه و پارامتر زیاد) که وظیفه پردازش تصویر رو داره بدیم و با یک لایه دیگه از شبکه عصبی که وظیفه پیش بینی در مورد کل تصویر رو داره مسئله رو حل کنیم. اما این رویکرد با کمی تغییرات پاسخ های بهتر با محاسبات کمتر رو تولید میکنه. پس سعی میکنیم به جای پیش بینی کل تصویر فقط یک حرف رو پیش بینی کنیم و تصویر رو به چند تصویر شامل حروف (یا اعداد) تبدیل کنیم. واضح هست که برای تعداد زیادی تصویر راه حل فتوشاپ توصیه نمیشه!
خوشبختانه کپچایی که ما قصد شکستن اون رو داریم از پنج حرف تشکیل میشه. بنابراین اگر بتونیم روشی برای جداکردن حروف در تصویر داشته باشیم، شبکه عصبی تنها نیاز داره تا یک حرف رو کلاس بندی (Classify) کنه. یک روش ساده شکستن تصویر افقی به پنج قسمت مساوی هست. اما اگر به نمونه های دریافت شده در تصویر دقت کنید، ممکنه به دلیل جمع شدن حروف در یک طرف، حروف به درستی قطعه بندی (Segmentation) نشن. بنابراین برای اینکه محل دقیق تقسیم بندی در تصویر رو پیدا کنیم، سعی میکنیم تا تجمع پیکسل های غیر سفید در تصویر رو پیدا کنیم (یا به صورت ساده تعداد پیکسل در هر خط عمودی رو بشماریم)، و از اونجاییکه بین حروف فاصله کمی وجود داره، تعداد پیکسل بیشتر با تقریب خوبی جای هر حرف در تصویر رو به ما نشون میده. بعد از اینکار یک الگوریتم خوشه بندی (Clustering) می تونه به طور موثر تصویر رو به پنج بخش مختلف تقسیم کنه.
ابتدا باید تصویر ورودی تبدیل به تصویر سیاه و سفید بشه و بخشی از نویز اون نیز حذف بشه تا مطمئن بشیم همه چیز به بهترین نحو ممکن انجام میشه.
کدهای بالا با پردازش تصویر، جادوی زیر رو انجام میده:
برای قطعه بندی تصاویر؛ یعنی برش تصویر به کاراکترهای جداگانه، ساده ترین روش استفاده از نمودار هیستوگرام (Histogram) و یافتن دسته هایی از پیکسل هاست که در جای خاصی تجمع دارند.
همون طور که در تصویر هم می بینید نقاطی که افت شدید مقدار داره، دقیقا مکان های متناظری هستند که باید تصویر برش داده بشه تا تصاویر کاراکترها استخراج بشند.
از اونجاییکه این روش با پیچیدگی هایی همراه هست، ما در اینجا با روش خوشه بندی k-means سعی میکنیم تا بهترین مکان برای جداسازی تصویر بعد از فیلتر رو پیدا کنیم. توی این روش از تصویر نهایی به شکل ماتریسی از صفر و یک ها (فقط نقاط سفید) که در مرحله قبل ایجاد کردیم، استفاده میکنیم. پنج نقطه اولیه تصادفی در ماتریس انتخاب میکنیم. با روش k-means سعی میکنیم نقاط درون تصویر رو به پنج خوشه (Cluster) تقسیم کنیم. نقطه مرکز هر خوشه، مرکز هر کاراکتر خواهد بود.
نتیجه کدهای بالا باورنکردنیه:
پردازش های بیشتری هم میشه روی تصویر انجام داد. مثلا برخی تصاویر که کنتراست (Contrast) کمتری دارند، قابلیت نرمال سازی و افزایش کنتراست رو دارند یا برای جداسازی از روش شمارش تجمعی، کاراکترهایی با طول های متفاوت رو جدا کرد. تا همین میزان پردازش برای ایجاد ورودی های شبکه عصبی؛ یعنی همون کاراکترهای جداگانه با اندازه ثابت، کافی است (اگر دوست دارید شما می تونید تا میزان دلخواه پردازش روی تصویر انجام بدید.).
ساخت و آموزش شبکه عصبی مصنوعی
از اونجاییکه ما فقط نیاز به تشخیص یک تصویر از حرف یا عدد داریم، نیازی به معماری پیچیده برای شبکه عصبی نداریم. شناسایی حروف یک مسئله بسیار ساده تر از تشخیص یک تصویر پیچیده (مثل تصاویری از سگ یا گربه که تنوع زیادی داره.) است. در اینجا ما برای حل مسئله شکستن کپچا از یک معماری شبکه عصبی مصنوعی با دو لایه کانولوشنال (Convolutional) همراه با Max Pooling و دو لایه تماما متصل (Fully-Connected) استفاده می کنیم. اگر شما این شبکه عصبی ها رو نمیشناسید نگران نباشید. در اینجا نیازی به پیاده سازی های سطح پایین نداریم. اگر علاقمند به یادگیری بیشتر در این زمینه هستید، ویکیپدیا یا این کتاب رو بررسی کنید.
برای سادگی آموزش در اینجا از TensorFlow؛ کتابخونه یادگیری ماشین گوگل، برای ایجاد شبکه استفاده خواهیم کرد. پیاده سازی این مدل به شکل زیر خواهد بود:
اگر بخش های دیگه کد رو هم به این مجموعه اضافه کنید و خوش شانس باشید خروجی زیر رو می بینید:
2018-04-25 11:45:45.927302: step 0, loss = 4.68 (2.0 examples/sec; 64.221 sec/batch)
2018-04-25 11:45:49.133065: step 10, loss = 4.66 (533.8 examples/sec; 0.240 sec/batch)
2018-04-25 11:45:51.397710: step 20, loss = 4.64 (597.4 examples/sec; 0.214 sec/batch)
2018-04-25 11:45:54.446850: step 30, loss = 4.62 (391.0 examples/sec; 0.327 sec/batch)
...
داده های آموزشی برای این شبکه نیازمند برچسب هستند، برای اینکار می تونید مدل رو ابتدا با مجموعه تصاویر EMNIST آموزش بدید و بعد با تصاویر اصلی استخراج شده آموزش رو انجام بدید. دقت این مدل رو میشه به ازای داده های ورودی اندازه گرفت، نمودارهای مختلف مثل دقت-سرعت رو در زمان اجرا با استفاده از داشبورد مربوطه رصد و بررسی کرد و کلی کار دیگه که می تونه دقت و سرعت مدل رو افزایش بده. با پیاده سازی مدل یادگیری عمیق، حالا ما می تونیم به صورت خودکار کپچای سیستم گلستان رو بشکنیم!
این مطلب به صورت کامل در گیت هاب در دسترس هست. همچنین اگر علاقمند به موضوعات هوش مصنوعی، یادگیری ماشین و بینایی کامپیوتر هستید می تونید من رو در توییتر دنبال کنید.
این ماجراجویی تموم شد. حالا نوبت شماست که دست به کار بشید، سیستم تشخیص کپچای دلخواهتون رو طراحی کنید و تجربیاتتون رو به اشتراک بذارید. به نظر شما راهکار جایگزین برای کپچاهای سنتی چه ویژگی هایی باید داشته باشه تا هوش مصنوعی نتونه اون رو بشکنه؟
مطلبی دیگر از این انتشارات
خلاقیت پلی به سوی نوآوری و اختراع
مطلبی دیگر از این انتشارات
آیا الگوریتم ها می توانند خلاقیت داشته باشند؟
مطلبی دیگر از این انتشارات
فضای ویژگی در یادگیری ماشین