alikarimi120
alikarimi120
خواندن ۴ دقیقه·۳ سال پیش

پیاده سازی اولین شبکه عصبی برای طبقه بندی تصاویر با استفاده از پایتورچ (قسمت اول)

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

کتابخانه PyTorch
کتابخانه PyTorch

کتابخانه PyTorch از محبوب ترین کتابخانه های حوزه یادگیری عمیق هست که از معماری CUDA برای محاسبه روی کارت های گرافیکی استفاده میکنه.

این کتابخانه به دو هدف استفاده میشه : 1- معادل کتابخانه NumPy هست با این تفاوت که میشه محاسبات رو روی GPU و سایر دستگاه های مشابه انجام داد 2 - ابزاری به نام automatic differentiation داره که به ما کمک میکنه شبکه های عصبی رو پیاده سازی کنیم


نصب کتابخانه Torch و کتابخانه جانبی TorchVison :

برای نصب PyTorch می تونید به صفحه PyTorch مراجعه کنید و با توجه به پیکربندی سیستمون و با توجه به package manager پایتون شما که آیا pip هست یا Conda و آیا می خواهید روی CPU نصب کنید یا روی GPU اجرا کنید ، یک دستورالعمل نصب آماده میکنه که با استفاده از اون کار نصب رو انجام می دید.

نحوه انتخاب گزینه های مورد نیاز برای نصب کتابخانه PyTorch
نحوه انتخاب گزینه های مورد نیاز برای نصب کتابخانه PyTorch

سنگ بنای PyTorch تنسور است. در پایتورچ تنسور رو برای ذخیره کردن و بیان کردن ورودی و خروجی های مدل استفاده می کنیم و همینطور وزن ها و پارامترهای مدل رو توی تنسور قرار میدیم. به طور واضح میشه گفت تنسور معادل NumPy array هست با این تفاوت که می تونیم روی GPU قرار بدیم.

برای مقدار دهی اولیه تنسور روش های متفاوتی وجود داره:

1- ساخت تنسور از رو لیست:

https://gist.github.com/alikarimi120/ea04261f6c1933aa13c9b5e6f85981b9

2- ساخت تنسور از روی NumPy array که بسیار پرکاربرد است و در آینده استفاده آن را خواهید دید:

شما می تونید از روی تنسور عکس این عمل رو هم انجام بدید و یک NumPy array بسازید.

https://gist.github.com/alikarimi120/1d0421818078b70f9e1248af1b578640

3- ساخت تنسور از روی تنسور دیگه هم بسیار پر استفاده هست، نکته ای که وجود داره این هست که علاوه بر اینکه می تونیم مقدار رو از تنسور کپی کنیم، ویژگی ها نظیر نوغ مقادیر داخل تنسور و همینطور ابعاد تنسور رو هم می تونیم کپی کنیم. راه های مختلفی برای این کار وجود داره . برای نمونه درنظر بگیرید ما تنسور x_data را تعریف کردیم می تونیم یک تنسور جدید به نام x_ones با ویژگی های تنسور x_data تعریف کنیم.

https://gist.github.com/alikarimi120/3b7f56281cc99639dbb1a6df4e192cb6

4 - برای تعریف تنسور 0 یا 1 یا رندوم می تونیم از shape هم استفاده کنیم و با استفاده از shape دلخواه تنسور رو بسازیم.

برای مشخص کردن این موضوع می تونیم از دستور .to استفاده کنیم، با دستور cuda_is_avaliable چک می کنیم که آیا GPU ای روی دستگاه وجود دارد یا خیر و اگر وجود داشت تنسور به روی CUDA منتقل میشه. اگه نه به صورت پیش فرض روی CPU باقی بماند.

https://gist.github.com/alikarimi120/f3a75973c6c3bcf31aae91af0b17061d

نکته بعدی این هست که ما در بحث NumPy مفهوم Slicing داشتیم اینجا هم همچین قابلیتی به طور کامل برقرار است. پیشنهاد میکنم اگه با بحث slicing آشنایی ندارید این مطلب رو بخونید.

https://gist.github.com/alikarimi120/90bf04391e17f6d731586abb8e951bbd

دو دستور پر کاربرد برای ترکیب دو تنسور وجود داره ، دستور torch.cat دو یا چند تنسور رو به هم متصل میکنه. اینجا سه نسخه از تنسور 4 در 4 رو به هم چسباندیم، چسباندن می تواند روی سطرها یا ستون ها انجام شود و با استفاده از آرگومان dim می توانیم این موضوع را کنترل کنیم.

https://gist.github.com/alikarimi120/a023d183881082f72418e437ca839f17

به جز cat دستور Stack هم وجود داره که شبیه cat هست ولی یک بعد جدیدی ایجاد میکنه، مثلا وقتی تنسورهای 4 در 4 رو برای چسباندن استفاده می کنیم یک بعد سوم جدیدی ساخته میشه و یک تنسور 3 در 4 در 4 خواهیم داشت.

https://gist.github.com/alikarimi120/264b92f212a67f279e109594ee597781

عملیات های مختلفی نظیر ضرب مولفه به مولفه رو می تونید روی تنسورها انجام بدید. تنسورها با ابعاد یکسان رو به صورت مولفه ای می تونید ضرب کنید که برای این کار از تابع mul می تونید استفاده کنید یا اگر از * استفاده کنیم هم فرآیند ضرب مولفه ای انجام میشه. دقت کنید اینجا ستاره برای ضرب مولفه به مولفه است نه ضرب ماتریسی!

https://gist.github.com/alikarimi120/264b92f212a67f279e109594ee597781

برای ضرب ماتریسی از تابع matmul استفاده کنید، میشه از اپراتور @ هم استفاده کرد و ضرب ماتریسی رو انجام داد.

https://gist.github.com/alikarimi120/23309f118e095199db252649569dc2ce

فرآیندهای In-Place در پایتورچ حائز اهمیت هست. در چنین شرایطی ماتریس جدیدی ایجاد نمیشه معمولا این توابع آخر اسمشون یک Underline دارن. مثلا add_ ، در چنین تابعی عملیات روی همان ماتریس انجام میشه و ماتریس جدیدی ایجاد نمیشه! به عبارتی عملیات In-place انجام میشه و حافظه کمتری انجام میشه چون ماتریس جدیدی ایجاد میشه. اما توصیه میکنم از این عملیات استفاده نکنید چون معمولا تو Automatic differentiation به مشکل می خورید!

https://gist.github.com/alikarimi120/2e75b0437956f328051b987d53def589

سه ویژگی مهم تنسورها : نوع، ابعاد و اینکه تنسور روی چه دستگاهی اجرا می شود، منظور این هست که قرار هست روی CPU اجرا بشود یا قرار است روی GPU اجرا شود.


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

شاید از این پست‌ها خوشتان بیاید