1. بررسی اجمالی
در این آزمایشگاه، شما یاد خواهید گرفت که چگونه شبکه های عصبی کانولوشنال خود را از ابتدا با Keras و Tensorflow 2 بسازید، آموزش دهید و تنظیم کنید. این کار اکنون با استفاده از قدرت TPU ها در عرض چند دقیقه انجام می شود. شما همچنین چندین رویکرد از یادگیری انتقال بسیار ساده تا معماریهای کانولوشنال مدرن مانند Squeezenet را بررسی خواهید کرد. این آزمایشگاه شامل توضیحات تئوری در مورد شبکه های عصبی است و نقطه شروع خوبی برای توسعه دهندگان یادگیری عمیق است.
خواندن مقالات یادگیری عمیق می تواند سخت و گیج کننده باشد. اجازه دهید نگاهی عملی به معماری های شبکه عصبی کانولوشنال مدرن داشته باشیم.
چیزی که یاد خواهید گرفت
- برای استفاده از Keras و Tensor Processing Units (TPUs) برای ساخت سریعتر مدل های سفارشی خود.
- برای استفاده از tf.data.Dataset API و فرمت TFRecord برای بارگذاری موثر داده های آموزشی.
- برای تقلب 😈، به جای ساختن مدل های خود، از یادگیری انتقال استفاده کنید.
- برای استفاده از سبک های مدل متوالی و کاربردی Keras.
- برای ساخت طبقهبندیکننده Keras خود با لایه softmax و از دست دادن آنتروپی متقابل.
- برای تنظیم دقیق مدل خود با انتخاب خوبی از لایه های کانولوشن.
- برای کشف ایدههای معماری convnet مدرن مانند ماژولها، ادغام میانگین جهانی و غیره.
- برای ساختن یک convnet ساده مدرن با استفاده از معماری Squeezenet.
بازخورد
اگر در این آزمایشگاه کد مشکلی مشاهده کردید، لطفاً به ما بگویید. بازخورد را می توان از طریق مسائل GitHub [ لینک بازخورد ] ارائه کرد.
2. شروع سریع Google Colaboratory
این آزمایشگاه از Google Collaboratory استفاده می کند و نیازی به تنظیم از طرف شما ندارد. میتوانید آن را از Chromebook اجرا کنید. لطفاً فایل زیر را باز کنید و سلول ها را اجرا کنید تا با نوت بوک های Colab آشنا شوید.
یک باطن TPU را انتخاب کنید
در منوی Colab، Runtime > Change runtime type و سپس TPU را انتخاب کنید. در این آزمایشگاه کد از یک TPU (واحد پردازش تنسور) قدرتمند استفاده میکنید که برای آموزش سختافزاری تسریع شده پشتیبانی میشود. اتصال به زمان اجرا به طور خودکار در اولین اجرا انجام می شود، یا می توانید از دکمه "اتصال" در گوشه سمت راست بالا استفاده کنید.
اجرای نوت بوک
با کلیک بر روی یک سلول و استفاده از Shift-ENTER سلول ها را یکی یکی اجرا کنید. همچنین می توانید کل نوت بوک را با Runtime > Run all اجرا کنید
فهرست مطالب
همه نوت بوک ها دارای فهرست مطالب هستند. می توانید آن را با استفاده از فلش سیاه سمت چپ باز کنید.
سلول های پنهان
برخی از سلول ها فقط عنوان خود را نشان می دهند. این یک ویژگی نوت بوک مخصوص Colab است. می توانید روی آنها دوبار کلیک کنید تا کد داخل آن را ببینید اما معمولاً چندان جالب نیست. به طور معمول توابع پشتیبانی یا تجسم. هنوز باید این سلول ها را اجرا کنید تا توابع داخل آن تعریف شوند.
احراز هویت
این امکان برای Colab وجود دارد که به سطلهای خصوصی Google Cloud Storage شما دسترسی داشته باشد، مشروط بر اینکه با یک حساب مجاز احراز هویت کنید. قطعه کد بالا یک فرآیند احراز هویت را راه اندازی می کند.
3. [INFO] واحدهای پردازش تانسور (TPU) چیست؟
به طور خلاصه
کد آموزش مدل بر روی TPU در Keras (و در صورت در دسترس نبودن TPU بر روی GPU یا CPU باز می گردد):
try: # detect TPUs
tpu = tf.distribute.cluster_resolver.TPUClusterResolver.connect()
strategy = tf.distribute.TPUStrategy(tpu)
except ValueError: # detect GPUs
strategy = tf.distribute.MirroredStrategy() # for CPU/GPU or multi-GPU machines
# use TPUStrategy scope to define model
with strategy.scope():
model = tf.keras.Sequential( ... )
model.compile( ... )
# train model normally on a tf.data.Dataset
model.fit(training_dataset, epochs=EPOCHS, steps_per_epoch=...)
ما امروز از TPU ها برای ساخت و بهینه سازی یک طبقه بندی گل با سرعت های تعاملی (دقیقه در هر دوره آموزشی) استفاده خواهیم کرد.
چرا TPU ها؟
پردازندههای گرافیکی مدرن حول محورهای قابل برنامهریزی سازماندهی شدهاند، معماری بسیار انعطافپذیری که به آنها اجازه میدهد تا کارهای مختلفی مانند رندر سه بعدی، یادگیری عمیق، شبیهسازی فیزیکی و غیره را انجام دهند. واحد ضرب ماتریس و برتری در هر کاری که ضرب ماتریس بزرگ غالب است، مانند شبکه های عصبی.
تصویر: یک لایه شبکه عصبی متراکم به عنوان ضرب ماتریس، با دستهای از هشت تصویر که در یک شبکه عصبی پردازش میشوند. لطفاً ضرب در یک خط x ستون را اجرا کنید تا بررسی کنید که واقعاً مجموع وزنی تمام مقادیر پیکسل های یک تصویر را انجام می دهد. لایههای کانولوشنال را میتوان به صورت ضربهای ماتریسی نیز نشان داد، اگرچه کمی پیچیدهتر است ( توضیح در اینجا، در بخش 1 ).
سخت افزار
MXU و VPU
یک هسته TPU v2 از یک واحد ضرب ماتریس (MXU) ساخته شده است که ضرب ماتریس را اجرا می کند و یک واحد پردازش برداری (VPU) برای همه کارهای دیگر مانند فعال سازی، سافت مکس و غیره. VPU محاسبات float32 و int32 را انجام می دهد. از سوی دیگر، MXU در فرمت ممیز شناور با دقت ترکیبی 16-32 بیتی کار می کند.
نقطه شناور دقیق مخلوط و bfloat16
MXU ضرب های ماتریس را با استفاده از ورودی های bfloat16 و خروجی های float32 محاسبه می کند. انباشته های میانی با دقت float32 انجام می شود.
آموزش شبکه عصبی معمولاً در برابر نویز ایجاد شده توسط کاهش دقت ممیز شناور مقاوم است. مواردی وجود دارد که نویز حتی به همگرایی بهینه ساز کمک می کند. دقت ممیز شناور 16 بیتی به طور سنتی برای سرعت بخشیدن به محاسبات استفاده می شود، اما فرمت های float16 و float32 محدوده های بسیار متفاوتی دارند. کاهش دقت از float32 به float16 معمولاً منجر به جریان بیش از حد و زیر جریان می شود. راهحلهایی وجود دارد، اما معمولاً برای کارکرد float16، کار اضافی لازم است.
به همین دلیل است که گوگل فرمت bfloat16 را در TPU ها معرفی کرد. bfloat16 یک float32 کوتاه شده است که دقیقاً همان بیت های توان و محدوده float32 را دارد. این به این واقعیت اضافه میشود که TPUها ضربهای ماتریس را با دقت مختلط با ورودیهای bfloat16 اما خروجیهای float32 محاسبه میکنند، به این معنی است که معمولاً برای بهرهمندی از دستاوردهای عملکرد کاهش دقت، هیچ تغییری در کد لازم نیست.
آرایه سیستولیک
MXU ضرب ماتریس را در سخت افزار با استفاده از معماری به اصطلاح "آرایه سیستولیک" پیاده سازی می کند که در آن عناصر داده از طریق آرایه ای از واحدهای محاسباتی سخت افزاری جریان می یابند. (در پزشکی، "سیستولیک" به انقباضات قلب و جریان خون، در اینجا به جریان داده ها اشاره دارد.)
عنصر اصلی ضرب ماتریس، حاصل ضرب نقطه ای بین خطی از یک ماتریس و ستونی از ماتریس دیگر است (به شکل بالای این بخش مراجعه کنید). برای ضرب ماتریسی Y=X*W، یک عنصر حاصل به صورت زیر خواهد بود:
Y[2,0] = X[2,0]*W[0,0] + X[2,1]*W[1,0] + X[2,2]*W[2,0] + ... + X[2,n]*W[n,0]
در یک GPU، میتوان این محصول نقطهای را در یک «هسته» GPU برنامهریزی کرد و سپس آن را روی هر تعداد «هسته» که به صورت موازی در دسترس است اجرا کرد تا هر مقدار ماتریس حاصل را بهطور همزمان محاسبه کرد. اگر ماتریس حاصل 128x128 بزرگ باشد، به 128x128=16K "هسته" نیاز دارد که معمولا امکان پذیر نیست. بزرگترین پردازنده های گرافیکی حدود 4000 هسته دارند. از طرف دیگر یک TPU از حداقل سخت افزار برای واحدهای محاسباتی در MXU استفاده می کند: فقط bfloat16 x bfloat16 => float32
multiply-accumulator، هیچ چیز دیگری. اینها آنقدر کوچک هستند که یک TPU می تواند 16 هزار عدد از آنها را در MXU 128x128 پیاده سازی کند و این ضرب ماتریس را در یک حرکت پردازش کند.
تصویر: آرایه سیستولیک MXU. عناصر محاسباتی چند انباشته هستند. مقادیر یک ماتریس در آرایه بارگذاری می شوند (نقاط قرمز). مقادیر ماتریس دیگر از طریق آرایه جریان می یابد (نقاط خاکستری). خطوط عمودی مقادیر را به بالا منتشر می کنند. خطوط افقی مجموع جزئی را منتشر می کنند. به عنوان یک تمرین به کاربر سپرده می شود تا تأیید کند که با جریان داده در آرایه، نتیجه ضرب ماتریس از سمت راست را دریافت می کنید.
علاوه بر آن، در حالی که محصولات نقطه ای در یک MXU محاسبه می شوند، مبالغ میانی به سادگی بین واحدهای محاسباتی مجاور جریان می یابد. آنها نیازی به ذخیره و بازیابی در/از حافظه یا حتی یک فایل رجیستر ندارند. نتیجه نهایی این است که معماری آرایه سیستولیک TPU دارای مزیت چگالی و توان قابل توجهی است، و همچنین مزیت سرعت غیر قابل چشم پوشی نسبت به GPU، هنگام محاسبه ضرب ماتریس دارد.
Cloud TPU
هنگامی که یک " Cloud TPU v2" را در Google Cloud Platform درخواست می کنید، یک ماشین مجازی (VM) دریافت می کنید که دارای یک برد TPU متصل به PCI است. برد TPU دارای چهار تراشه TPU دو هسته ای است. هر هسته TPU دارای یک VPU (واحد پردازش برداری) و یک MXU 128x128 (واحد ضرب ماتریکس) است. سپس این "Cloud TPU" معمولاً از طریق شبکه به VM درخواست کننده متصل می شود. بنابراین تصویر کامل به این صورت است:
تصویر: ماشین مجازی شما با یک شتاب دهنده "Cloud TPU" متصل به شبکه. "Cloud TPU" خود از یک VM با یک برد TPU متصل به PCI با چهار تراشه TPU دو هسته ای بر روی آن ساخته شده است.
غلاف های TPU
در مراکز داده گوگل، TPU ها به یک اتصال محاسباتی با کارایی بالا (HPC) متصل هستند که می تواند آنها را به عنوان یک شتاب دهنده بسیار بزرگ جلوه دهد. گوگل آنها را پاد می نامد و می توانند تا 512 هسته TPU v2 یا 2048 هسته TPU v3 را در بر گیرند.
تصویر: یک غلاف TPU v3. بردها و قفسه های TPU از طریق اتصال HPC متصل می شوند.
در طول آموزش، شیب ها بین هسته های TPU با استفاده از الگوریتم کاهش همه رد و بدل می شوند ( توضیح خوبی در مورد همه کاهش در اینجا ). مدلی که آموزش می بیند می تواند با آموزش در اندازه های بزرگ از سخت افزار بهره مند شود.
تصویر: همگام سازی گرادیان ها در طول آموزش با استفاده از الگوریتم کاهش همه جانبه در شبکه HPC مش حلقوی دوبعدی Google TPU.
نرم افزار
آموزش اندازه دسته بزرگ
اندازه دسته ای ایده آل برای TPU ها 128 مورد داده در هر هسته TPU است، اما سخت افزار در حال حاضر می تواند استفاده خوبی از 8 مورد داده در هر هسته TPU نشان دهد. به یاد داشته باشید که یک Cloud TPU دارای 8 هسته است.
در این آزمایشگاه کد، از Keras API استفاده خواهیم کرد. در Keras، دسته ای که مشخص می کنید اندازه دسته جهانی برای کل TPU است. دسته های شما به طور خودکار به 8 تقسیم می شوند و روی 8 هسته TPU اجرا می شوند.
برای نکات عملکردی بیشتر به راهنمای عملکرد TPU مراجعه کنید. برای اندازههای دستهای بسیار بزرگ، ممکن است در برخی از مدلها به مراقبت خاصی نیاز باشد، برای جزئیات بیشتر به LARSOptimizer مراجعه کنید.
زیر کاپوت: XLA
برنامه های تنسورفلو نمودارهای محاسباتی را تعریف می کنند. TPU به طور مستقیم کد پایتون را اجرا نمی کند، بلکه نمودار محاسباتی تعریف شده توسط برنامه تنسورفلو شما را اجرا می کند. در زیر هود، کامپایلری به نام XLA (کامپایلر جبر خطی تسریع شده) نمودار Tensorflow گره های محاسباتی را به کد ماشین TPU تبدیل می کند. این کامپایلر همچنین بسیاری از بهینهسازیهای پیشرفته را روی کد و چیدمان حافظه شما انجام میدهد. با ارسال کار به TPU، کامپایل به طور خودکار انجام می شود. شما مجبور نیستید XLA را به صراحت در زنجیره ساخت خود قرار دهید.
تصویر: برای اجرا بر روی TPU، نمودار محاسباتی تعریف شده توسط برنامه Tensorflow ابتدا به یک نمایش XLA (کامپایلر جبر خطی تسریع شده) ترجمه می شود، سپس توسط XLA به کد ماشین TPU کامپایل می شود.
استفاده از TPU در Keras
TPU ها از طریق Keras API از Tensorflow 2.1 پشتیبانی می شوند. پشتیبانی Keras روی TPU ها و TPU pod ها کار می کند. در اینجا یک مثال است که روی TPU، GPU(ها) و CPU کار می کند:
try: # detect TPUs
tpu = tf.distribute.cluster_resolver.TPUClusterResolver.connect()
strategy = tf.distribute.TPUStrategy(tpu)
except ValueError: # detect GPUs
strategy = tf.distribute.MirroredStrategy() # for CPU/GPU or multi-GPU machines
# use TPUStrategy scope to define model
with strategy.scope():
model = tf.keras.Sequential( ... )
model.compile( ... )
# train model normally on a tf.data.Dataset
model.fit(training_dataset, epochs=EPOCHS, steps_per_epoch=...)
در این قطعه کد:
-
TPUClusterResolver().connect()
TPU را در شبکه پیدا می کند. بدون پارامتر در اکثر سیستمهای Google Cloud کار میکند (کارهای پلتفرم هوش مصنوعی، همکاری، Kubeflow، ماشینهای مجازی یادگیری عمیق که از طریق ابزار «ctpu up» ایجاد شدهاند). این سیستم ها به لطف یک متغیر محیطی TPU_NAME می دانند که TPU آنها کجاست. اگر یک TPU را با دست ایجاد میکنید، TPU_NAME env را تنظیم کنید. var روی ماشین مجازی که از آن استفاده میکنید، یاTPUClusterResolver
با پارامترهای صریح فراخوانی کنید:TPUClusterResolver(tp_uname, zone, project)
-
TPUStrategy
بخشی است که توزیع و الگوریتم همگام سازی گرادیان "همه کاهش" را پیاده سازی می کند. - استراتژی از طریق یک محدوده اعمال می شود. مدل باید در محدوده استراتژی () تعریف شود.
- تابع
tpu_model.fit
یک شی tf.data.Dataset را برای ورودی برای آموزش TPU انتظار دارد.
وظایف رایج انتقال TPU
- در حالی که راههای زیادی برای بارگذاری دادهها در یک مدل Tensorflow وجود دارد، برای TPUها، استفاده از
tf.data.Dataset
API مورد نیاز است. - TPU ها بسیار سریع هستند و دریافت داده ها اغلب در هنگام اجرا روی آنها به گلوگاه تبدیل می شود. ابزارهایی وجود دارد که می توانید برای شناسایی تنگناهای داده و سایر نکات عملکردی در راهنمای عملکرد TPU استفاده کنید.
- اعداد int8 یا int16 به عنوان int32 در نظر گرفته می شوند. TPU سخت افزار اعداد صحیحی ندارد که با کمتر از 32 بیت کار کند.
- برخی از عملیات Tensorflow پشتیبانی نمی شوند. لیست اینجاست . خبر خوب این است که این محدودیت فقط برای کد آموزشی اعمال می شود، یعنی عبور به جلو و عقب از مدل شما. همچنان می توانید از تمام عملیات Tensorflow در خط لوله ورودی داده خود استفاده کنید زیرا روی CPU اجرا می شود.
-
tf.py_func
در TPU پشتیبانی نمی شود.
4. بارگذاری داده ها
ما با مجموعه داده ای از تصاویر گل کار خواهیم کرد. هدف این است که یاد بگیرید آنها را به 5 نوع گل دسته بندی کنید. بارگذاری داده ها با استفاده از tf.data.Dataset
API انجام می شود. ابتدا اجازه دهید API را بشناسیم.
دست در دست
لطفاً نوتبوک زیر را باز کنید، سلولها را اجرا کنید (Shift-ENTER) و دستورالعملها را هر جا که برچسب "WORK REQUIRED" را مشاهده کردید دنبال کنید.
Fun with tf.data.Dataset (playground).ipynb
اطلاعات تکمیلی
درباره مجموعه داده "گل".
مجموعه داده در 5 پوشه سازماندهی شده است. هر پوشه حاوی گلهایی از یک نوع است. پوشه ها به نام گل های آفتابگردان، دیزی، قاصدک، لاله و گل رز هستند. داده ها در یک سطل عمومی در Google Cloud Storage میزبانی می شوند. گزیده:
gs://flowers-public/sunflowers/5139971615_434ff8ed8b_n.jpg
gs://flowers-public/daisy/8094774544_35465c1c64.jpg
gs://flowers-public/sunflowers/9309473873_9d62b9082e.jpg
gs://flowers-public/dandelion/19551343954_83bb52f310_m.jpg
gs://flowers-public/dandelion/14199664556_188b37e51e.jpg
gs://flowers-public/tulips/4290566894_c7f061583d_m.jpg
gs://flowers-public/roses/3065719996_c16ecd5551.jpg
gs://flowers-public/dandelion/8168031302_6e36f39d87.jpg
gs://flowers-public/sunflowers/9564240106_0577e919da_n.jpg
gs://flowers-public/daisy/14167543177_cd36b54ac6_n.jpg
چرا tf.data.Dataset؟
Keras و Tensorflow مجموعه دادهها را در تمام عملکردهای آموزشی و ارزیابی خود میپذیرند. هنگامی که داده ها را در یک مجموعه داده بارگیری می کنید، API تمام عملکردهای رایجی را که برای داده های آموزش شبکه عصبی مفید است ارائه می دهد:
dataset = ... # load something (see below)
dataset = dataset.shuffle(1000) # shuffle the dataset with a buffer of 1000
dataset = dataset.cache() # cache the dataset in RAM or on disk
dataset = dataset.repeat() # repeat the dataset indefinitely
dataset = dataset.batch(128) # batch data elements together in batches of 128
AUTOTUNE = tf.data.AUTOTUNE
dataset = dataset.prefetch(AUTOTUNE) # prefetch next batch(es) while training
در این مقاله میتوانید نکات عملکرد و بهترین روشهای Dataset را بیابید. مستندات مرجع اینجاست .
مبانی tf.data.Dataset
داده ها معمولاً در چندین فایل، در اینجا تصاویر می آیند. می توانید مجموعه داده ای از نام فایل ها را با فراخوانی ایجاد کنید:
filenames_dataset = tf.data.Dataset.list_files('gs://flowers-public/*/*.jpg')
# The parameter is a "glob" pattern that supports the * and ? wildcards.
سپس یک تابع را برای هر نام فایل "نقشه" می گذارید که معمولاً فایل را به داده های واقعی در حافظه بارگذاری و رمزگشایی می کند:
def decode_jpeg(filename):
bits = tf.io.read_file(filename)
image = tf.io.decode_jpeg(bits)
return image
image_dataset = filenames_dataset.map(decode_jpeg)
# this is now a dataset of decoded images (uint8 RGB format)
برای تکرار روی یک مجموعه داده:
for data in my_dataset:
print(data)
مجموعه داده تاپل ها
در یادگیری نظارت شده، یک مجموعه داده آموزشی معمولاً از جفت داده های آموزشی و پاسخ های صحیح ساخته می شود. برای اجازه دادن به این کار، تابع رمزگشایی میتواند تاپلها را برگرداند. سپس مجموعه داده ای از تاپل ها خواهید داشت و با تکرار بر روی آن، تاپل ها برگردانده می شوند. مقادیر بازگشتی تانسورهای Tensorflow هستند که آماده مصرف توسط مدل شما هستند. برای مشاهده مقادیر خام می توانید .numpy()
را روی آنها فراخوانی کنید:
def decode_jpeg_and_label(filename):
bits = tf.read_file(filename)
image = tf.io.decode_jpeg(bits)
label = ... # extract flower name from folder name
return image, label
image_dataset = filenames_dataset.map(decode_jpeg_and_label)
# this is now a dataset of (image, label) pairs
for image, label in dataset:
print(image.numpy().shape, label.numpy())
نتیجه گیری: بارگذاری یک به یک تصاویر کند است!
همانطور که روی این مجموعه داده تکرار می کنید، خواهید دید که می توانید چیزی در حدود 1-2 تصویر در ثانیه بارگذاری کنید. که خیلی کند است! شتابدهندههای سختافزاری که برای آموزش استفاده خواهیم کرد، میتوانند چندین برابر این میزان را حفظ کنند. به بخش بعدی بروید تا ببینید چگونه به این هدف خواهیم رسید.
راه حل
این دفترچه راه حل است. اگر گیر کرده اید می توانید از آن استفاده کنید.
Fun with tf.data.Dataset (solution).ipynb
آنچه را پوشش داده ایم
- 🤔 tf.data.Dataset.list_files
- 🤔 tf.data.Dataset.map
- 🤔 مجموعه داده تاپل ها
- 😀 تکرار از طریق مجموعه داده ها
لطفا یک لحظه وقت بگذارید و این چک لیست را در ذهن خود مرور کنید.
5. بارگذاری سریع داده ها
شتابدهندههای سختافزاری واحد پردازش تنسور (TPU) که ما در این آزمایشگاه استفاده خواهیم کرد، بسیار سریع هستند. چالش اغلب این است که داده ها را به اندازه کافی سریع تغذیه کنید تا آنها را مشغول نگه دارید. Google Cloud Storage (GCS) قادر است توان عملیاتی بسیار بالایی را حفظ کند، اما مانند همه سیستمهای ذخیرهسازی ابری، راهاندازی یک اتصال هزینهای را برای شبکه به عقب و جلو دارد. بنابراین، ذخیره داده های ما به صورت هزاران فایل فردی ایده آل نیست. ما قصد داریم آنها را در تعداد کمتری فایل دسته بندی کنیم و از قدرت tf.data.Dataset برای خواندن از چندین فایل به صورت موازی استفاده کنیم.
خواندن از طریق
کدی که فایل های تصویری را بارگیری می کند، اندازه آنها را به اندازه معمول تغییر می دهد و سپس آنها را در 16 فایل TFRecord ذخیره می کند در دفترچه یادداشت زیر است. لطفا سریع آن را بخوانید. اجرای آن ضروری نیست زیرا داده های با قالب بندی مناسب TFRecord برای بقیه بخش کد ارائه می شود.
Flower pictures to TFRecords.ipynb
طرح داده ایده آل برای توان عملیاتی GCS بهینه
فرمت فایل TFRecord
فرمت فایل ترجیحی Tensorflow برای ذخیره داده ها، فرمت TFRecord مبتنی بر پروتوباف است. سایر قالبهای سریالسازی نیز کار میکنند، اما میتوانید یک مجموعه داده را از فایلهای TFRecord مستقیماً با نوشتن بارگیری کنید:
filenames = tf.io.gfile.glob(FILENAME_PATTERN)
dataset = tf.data.TFRecordDataset(filenames)
dataset = dataset.map(...) # do the TFRecord decoding here - see below
برای عملکرد بهینه، توصیه می شود از کدهای پیچیده تر زیر برای خواندن همزمان از چندین فایل TFRecord استفاده کنید. این کد از N فایل به صورت موازی خوانده می شود و ترتیب داده ها را به نفع سرعت خواندن نادیده می گیرد.
AUTOTUNE = tf.data.AUTOTUNE
ignore_order = tf.data.Options()
ignore_order.experimental_deterministic = False
filenames = tf.io.gfile.glob(FILENAME_PATTERN)
dataset = tf.data.TFRecordDataset(filenames, num_parallel_reads=AUTOTUNE)
dataset = dataset.with_options(ignore_order)
dataset = dataset.map(...) # do the TFRecord decoding here - see below
برگه تقلب TFRecord
سه نوع داده را می توان در TFRecords ذخیره کرد: رشته های بایت (لیست بایت ها)، اعداد صحیح 64 بیتی و شناورهای 32 بیتی. آنها همیشه به عنوان لیست ذخیره می شوند، یک عنصر داده منفرد لیستی با اندازه 1 خواهد بود. می توانید از توابع کمکی زیر برای ذخیره داده ها در TFRecords استفاده کنید.
نوشتن رشته های بایت
# warning, the input is a list of byte strings, which are themselves lists of bytes
def _bytestring_feature(list_of_bytestrings):
return tf.train.Feature(bytes_list=tf.train.BytesList(value=list_of_bytestrings))
نوشتن اعداد صحیح
def _int_feature(list_of_ints): # int64
return tf.train.Feature(int64_list=tf.train.Int64List(value=list_of_ints))
نوشتن شناور است
def _float_feature(list_of_floats): # float32
return tf.train.Feature(float_list=tf.train.FloatList(value=list_of_floats))
نوشتن یک TFRecord با استفاده از راهنماهای بالا
# input data in my_img_bytes, my_class, my_height, my_width, my_floats
with tf.python_io.TFRecordWriter(filename) as out_file:
feature = {
"image": _bytestring_feature([my_img_bytes]), # one image in the list
"class": _int_feature([my_class]), # one class in the list
"size": _int_feature([my_height, my_width]), # fixed length (2) list of ints
"float_data": _float_feature(my_floats) # variable length list of floats
}
tf_record = tf.train.Example(features=tf.train.Features(feature=feature))
out_file.write(tf_record.SerializeToString())
برای خواندن دادهها از TFRecords، ابتدا باید طرحبندی رکوردهایی را که ذخیره کردهاید اعلام کنید. در اعلان، می توانید به هر فیلد نامگذاری شده به عنوان یک لیست با طول ثابت یا یک لیست با طول متغیر دسترسی داشته باشید:
خواندن از TFRecords
def read_tfrecord(data):
features = {
# tf.string = byte string (not text string)
"image": tf.io.FixedLenFeature([], tf.string), # shape [] means scalar, here, a single byte string
"class": tf.io.FixedLenFeature([], tf.int64), # shape [] means scalar, i.e. a single item
"size": tf.io.FixedLenFeature([2], tf.int64), # two integers
"float_data": tf.io.VarLenFeature(tf.float32) # a variable number of floats
}
# decode the TFRecord
tf_record = tf.io.parse_single_example(data, features)
# FixedLenFeature fields are now ready to use
sz = tf_record['size']
# Typical code for decoding compressed images
image = tf.io.decode_jpeg(tf_record['image'], channels=3)
# VarLenFeature fields require additional sparse.to_dense decoding
float_data = tf.sparse.to_dense(tf_record['float_data'])
return image, sz, float_data
# decoding a tf.data.TFRecordDataset
dataset = dataset.map(read_tfrecord)
# now a dataset of triplets (image, sz, float_data)
کدهای مفید:
خواندن عناصر داده واحد
tf.io.FixedLenFeature([], tf.string) # for one byte string
tf.io.FixedLenFeature([], tf.int64) # for one int
tf.io.FixedLenFeature([], tf.float32) # for one float
خواندن لیست عناصر با اندازه ثابت
tf.io.FixedLenFeature([N], tf.string) # list of N byte strings
tf.io.FixedLenFeature([N], tf.int64) # list of N ints
tf.io.FixedLenFeature([N], tf.float32) # list of N floats
خواندن تعداد متغیری از اقلام داده
tf.io.VarLenFeature(tf.string) # list of byte strings
tf.io.VarLenFeature(tf.int64) # list of ints
tf.io.VarLenFeature(tf.float32) # list of floats
یک VarLenFeature یک بردار پراکنده را برمی گرداند و یک مرحله اضافی پس از رمزگشایی TFRecord لازم است:
dense_data = tf.sparse.to_dense(tf_record['my_var_len_feature'])
همچنین امکان داشتن فیلدهای اختیاری در TFRecords وجود دارد. اگر هنگام خواندن یک فیلد یک مقدار پیشفرض را مشخص کنید، در صورت عدم وجود فیلد، مقدار پیشفرض به جای خطا برگردانده میشود.
tf.io.FixedLenFeature([], tf.int64, default_value=0) # this field is optional
آنچه را پوشش داده ایم
- 🤔 اشتراک گذاری فایل های داده برای دسترسی سریع از GCS
- 😓 نحوه نوشتن TFRecords. (شما قبلاً نحو را فراموش کرده اید؟ اشکالی ندارد، این صفحه را به عنوان یک برگه تقلب نشانک کنید)
- 🤔 بارگیری یک مجموعه داده از TFRecords با استفاده از TFRecordDataset
لطفا یک لحظه وقت بگذارید و این چک لیست را در ذهن خود مرور کنید.
6. [INFO] طبقه بندی شبکه عصبی 101
به طور خلاصه
اگر تمام عبارات پررنگ در پاراگراف بعدی قبلاً برای شما شناخته شده است، می توانید به تمرین بعدی بروید. اگر تازه شروع به یادگیری عمیق کرده اید، خوش آمدید و لطفاً ادامه دهید.
برای مدلهایی که بهعنوان دنبالهای از لایهها ساخته میشوند، Keras API متوالی را ارائه میکند. برای مثال، یک طبقهبندیکننده تصویر با استفاده از سه لایه متراکم میتواند در Keras به صورت زیر نوشته شود:
model = tf.keras.Sequential([
tf.keras.layers.Flatten(input_shape=[192, 192, 3]),
tf.keras.layers.Dense(500, activation="relu"),
tf.keras.layers.Dense(50, activation="relu"),
tf.keras.layers.Dense(5, activation='softmax') # classifying into 5 classes
])
# this configures the training of the model. Keras calls it "compiling" the model.
model.compile(
optimizer='adam',
loss= 'categorical_crossentropy',
metrics=['accuracy']) # % of correct answers
# train the model
model.fit(dataset, ... )
شبکه عصبی متراکم
این ساده ترین شبکه عصبی برای طبقه بندی تصاویر است. از "نورون" ساخته شده است که در لایه ها چیده شده اند. لایه اول داده های ورودی را پردازش می کند و خروجی های آن را به لایه های دیگر تغذیه می کند. به آن "متراکم" می گویند زیرا هر نورون به تمام نورون های لایه قبلی متصل است.
شما می توانید با صاف کردن مقادیر RGB تمام پیکسل های آن در یک بردار طولانی و استفاده از آن به عنوان ورودی، یک تصویر را به چنین شبکه ای وارد کنید. این بهترین تکنیک برای تشخیص تصویر نیست، اما بعداً آن را بهبود خواهیم داد.
نورون ها، فعال سازی ها، RELU
یک "نورون" مجموع وزنی همه ورودی های خود را محاسبه می کند، مقداری به نام "سوگیری" را اضافه می کند و نتیجه را از طریق به اصطلاح "تابع فعال سازی" تغذیه می کند. وزن و سوگیری در ابتدا ناشناخته است. آنها به صورت تصادفی مقداردهی اولیه می شوند و با آموزش شبکه عصبی بر روی بسیاری از داده های شناخته شده "یاد می گیرند".
محبوب ترین تابع فعال سازی RELU برای واحد خطی اصلاح شده نام دارد. این یک تابع بسیار ساده است همانطور که در نمودار بالا می بینید.
فعال سازی سافت مکس
شبکه بالا با یک لایه 5 نورونی به پایان می رسد زیرا ما گل ها را به 5 دسته (رز، لاله، قاصدک، دیزی، آفتابگردان) طبقه بندی می کنیم. نورون ها در لایه های میانی با استفاده از تابع فعال سازی کلاسیک RELU فعال می شوند. در آخرین لایه، می خواهیم اعدادی بین 0 و 1 را محاسبه کنیم که نشان دهنده احتمال گل رز، لاله و غیره است. برای این کار از یک تابع فعال سازی به نام softmax استفاده می کنیم.
اعمال softmax بر روی یک بردار با گرفتن نمایی هر عنصر و سپس نرمال سازی بردار انجام می شود، معمولاً با استفاده از هنجار L1 (مجموع مقادیر مطلق) به طوری که مجموع مقادیر به 1 می رسد و می توان آنها را به عنوان احتمال تفسیر کرد.
از دست دادن آنتروپی متقابل
اکنون که شبکه عصبی ما پیشبینیهایی را از تصاویر ورودی تولید میکند، باید میزان خوب بودن آنها را اندازهگیری کنیم، یعنی فاصله بین آنچه که شبکه به ما میگوید و پاسخهای صحیح، که اغلب «برچسبها» نامیده میشوند. به یاد داشته باشید که ما برچسب های درستی برای تمام تصاویر موجود در مجموعه داده داریم.
هر فاصله ای کار می کند، اما برای مشکلات طبقه بندی، به اصطلاح "فاصله آنتروپی متقابل" موثرترین است. ما این را تابع خطا یا "از دست دادن" خود می نامیم:
نزول گرادیان
"آموزش" شبکه عصبی در واقع به معنای استفاده از تصاویر و برچسب های آموزشی برای تنظیم وزن ها و سوگیری ها به گونه ای است که تابع تلفات متقابل آنتروپی را به حداقل برساند. در اینجا نحوه کار آن است.
آنتروپی متقاطع تابعی از وزن ها، بایاس ها، پیکسل های تصویر تمرینی و کلاس شناخته شده آن است.
اگر مشتقات جزئی آنتروپی متقاطع را نسبت به همه وزنها و همه بایاسها محاسبه کنیم، یک "gradient" به دست میآوریم که برای تصویر، برچسب و ارزش فعلی وزنها و بایاسها محاسبه میشود. به یاد داشته باشید که ما میتوانیم میلیونها وزن و سوگیری داشته باشیم، بنابراین محاسبه گرادیان کار زیادی به نظر میرسد. خوشبختانه، تنسورفلو این کار را برای ما انجام می دهد. ویژگی ریاضی یک گرادیان این است که به سمت بالا اشاره می کند. از آنجایی که می خواهیم به جایی برویم که آنتروپی متقاطع کم است، در جهت مخالف می رویم. وزن ها و سوگیری ها را با کسری از گرادیان به روز می کنیم. سپس همین کار را بارها و بارها با استفاده از دسته های بعدی تصاویر و برچسب های آموزشی در یک حلقه آموزشی انجام می دهیم. امیدواریم که این به جایی برسد که آنتروپی متقاطع حداقل باشد، اگرچه هیچ چیزی منحصر به فرد بودن این حداقل را تضمین نمی کند.
مینی بچینگ و تکانه
شما میتوانید گرادیان خود را فقط بر روی یک تصویر مثال محاسبه کنید و وزنها و بایاسها را فوراً بهروزرسانی کنید، اما انجام این کار روی دستهای از مثلاً 128 تصویر، گرادیانی به دست میدهد که محدودیتهای اعمالشده توسط تصاویر نمونههای مختلف را بهتر نشان میدهد و بنابراین احتمالاً همگرا میشود. به سمت راه حل سریعتر اندازه مینی بچ یک پارامتر قابل تنظیم است.
این تکنیک، که گاهی اوقات "نزول گرادیان تصادفی" نامیده میشود، یک مزیت عملیتر دیگر نیز دارد: کار با دستهها همچنین به معنای کار با ماتریسهای بزرگتر است و معمولاً بهینهسازی آنها روی GPU و TPU آسانتر است.
با این حال، همگرایی همچنان می تواند کمی آشفته باشد و حتی اگر بردار گرادیان صفر باشد، می تواند متوقف شود. آیا این بدان معناست که ما حداقلی را پیدا کرده ایم؟ نه همیشه. یک مولفه گرادیان می تواند بر روی حداقل یا حداکثر صفر باشد. با یک بردار گرادیان با میلیونها عنصر، اگر همه آنها صفر باشند، احتمال اینکه هر صفر با یک حداقل و هیچ یک از آنها به نقطه حداکثر مطابقت داشته باشد بسیار کم است. در فضایی با ابعاد مختلف، نقاط زین بسیار رایج هستند و ما نمی خواهیم در آنها توقف کنیم.
تصویر: یک نقطه زین. گرادیان 0 است اما در همه جهات حداقل نیست. (اشاره به تصویر ویکیمدیا: توسط Nicoguaro - Own Work, CC BY 3.0 )
راه حل این است که مقداری حرکت به الگوریتم بهینه سازی اضافه شود تا بتواند بدون توقف از نقاط زین عبور کند.
واژه نامه
دسته ای یا مینی دسته ای : آموزش همیشه بر روی دسته ای از داده ها و برچسب های آموزشی انجام می شود. انجام این کار به همگرایی الگوریتم کمک می کند. بعد "دسته ای" معمولاً اولین بعد تانسورهای داده است. برای مثال یک تانسور شکل [100، 192، 192، 3] حاوی 100 تصویر 192x192 پیکسل با سه مقدار در هر پیکسل (RGB) است.
از دست دادن آنتروپی متقابل : یک تابع تلفات ویژه که اغلب در طبقهبندیکنندهها استفاده میشود.
لایه متراکم : لایه ای از نورون ها که در آن هر نورون به تمام نورون های لایه قبلی متصل است.
ویژگی ها : ورودی های یک شبکه عصبی گاهی اوقات "ویژگی" نامیده می شود. هنر فهمیدن اینکه کدام بخش از یک مجموعه داده (یا ترکیبی از قطعات) باید به شبکه عصبی وارد شود تا پیشبینیهای خوبی داشته باشیم، «مهندسی ویژگی» نامیده میشود.
برچسب ها : نام دیگری برای "کلاس ها" یا پاسخ های صحیح در یک مشکل طبقه بندی نظارت شده
نرخ یادگیری : کسری از گرادیان که توسط آن وزنها و سوگیریها در هر تکرار از حلقه آموزشی بهروز میشوند.
logits : خروجی های لایه ای از نورون ها قبل از اعمال تابع فعال سازی "logits" نامیده می شوند. این اصطلاح از "عملکرد لجستیک" با نام "تابع سیگموئید" می آید که در گذشته محبوب ترین تابع فعال سازی بود. "خروجی های نورون قبل از عملکرد لجستیک" به "logits" کوتاه شد.
ضرر : تابع خطا در مقایسه خروجی های شبکه عصبی با پاسخ های صحیح
نورون : مجموع وزنی ورودی های خود را محاسبه می کند، بایاس اضافه می کند و نتیجه را از طریق یک تابع فعال سازی تغذیه می کند.
کدگذاری تک داغ : کلاس 3 از 5 به صورت بردار 5 عنصری کدگذاری می شود، همه صفرها به جز سومی که 1 است.
relu : واحد خطی اصلاح شده یک تابع فعال سازی محبوب برای نورون ها.
sigmoid : یکی دیگر از عملکردهای فعال سازی که قبلاً محبوب بود و هنوز هم در موارد خاص مفید است.
softmax : یک تابع فعالسازی ویژه که بر روی یک بردار عمل میکند، اختلاف بین بزرگترین مؤلفه و سایر مؤلفهها را افزایش میدهد، و همچنین بردار را با مجموع 1 نرمال میکند تا بتوان آن را به عنوان بردار احتمالات تفسیر کرد. به عنوان آخرین مرحله در طبقه بندی کننده ها استفاده می شود.
تانسور : یک "تانسور" مانند یک ماتریس است اما دارای تعداد دلخواه ابعاد است. تانسور یک بعدی یک بردار است. یک تانسور دو بعدی یک ماتریس است. و سپس می توانید تانسورهایی با ابعاد 3، 4، 5 یا بیشتر داشته باشید.
7. آموزش انتقال
برای مشکل طبقه بندی تصویر، لایه های متراکم احتمالا کافی نیستند. ما باید در مورد لایه های کانولوشن و روش های زیادی که می توانید آنها را مرتب کنید یاد بگیریم.
اما ما همچنین می توانیم میانبر را انتخاب کنیم! شبکه های عصبی کانولوشن کاملاً آموزش دیده برای دانلود در دسترس هستند. ممکن است آخرین لایه آنها، سر طبقه بندی softmax را بریده و آن را با لایه خود جایگزین کنید. تمام وزنه ها و سوگیری های آموزش دیده به همان شکلی که هستند باقی می مانند، شما فقط لایه softmax را که اضافه می کنید دوباره آموزش می دهید. این تکنیک یادگیری انتقال نامیده میشود و به طرز شگفتانگیزی، تا زمانی کار میکند که مجموعه دادهای که شبکه عصبی روی آن از قبل آموزش داده شده است به اندازه کافی به شما نزدیک باشد.
دست در دست
لطفاً نوتبوک زیر را باز کنید، سلولها را اجرا کنید (Shift-ENTER) و دستورالعملها را هر جا که برچسب "WORK REQUIRED" را مشاهده کردید دنبال کنید.
Keras Flowers transfer learning (playground).ipynb
اطلاعات تکمیلی
با یادگیری انتقال، هم از معماری شبکه عصبی کانولوشنال پیشرفته که توسط محققان برتر توسعه یافته است و هم از پیش آموزش روی مجموعه داده عظیمی از تصاویر بهره میبرید. در مورد ما، ما از یک شبکه آموزش دیده در ImageNet، یک پایگاه داده از تصاویر حاوی بسیاری از گیاهان و صحنه های بیرونی، که به اندازه کافی به گل ها نزدیک است، یادگیری را انتقال خواهیم داد.
تصویر: با استفاده از یک شبکه عصبی کانولوشنال پیچیده، که قبلاً آموزش داده شده است، به عنوان جعبه سیاه، فقط سر طبقه بندی را بازآموزی می کند. این یادگیری انتقالی است. بعداً خواهیم دید که این ترتیبات پیچیده لایه های کانولوشن چگونه کار می کنند. فعلاً مشکل شخص دیگری است.
آموزش انتقال در کراس
در Keras می توانید یک مدل از پیش آموزش دیده از مجموعه tf.keras.applications.*
را نمونه برداری کنید. برای مثال MobileNet V2 یک معماری کانولوشنال بسیار خوب است که از نظر اندازه معقول باقی می ماند. با انتخاب include_top=False
، مدل از پیش آموزش دیده را بدون لایه سافت مکس نهایی آن دریافت می کنید تا بتوانید مدل خود را اضافه کنید:
pretrained_model = tf.keras.applications.MobileNetV2(input_shape=[*IMAGE_SIZE, 3], include_top=False)
pretrained_model.trainable = False
model = tf.keras.Sequential([
pretrained_model,
tf.keras.layers.Flatten(),
tf.keras.layers.Dense(5, activation='softmax')
])
همچنین به تنظیمات pretrained_model.trainable = False
توجه کنید. وزن ها و سوگیری های مدل از پیش آموزش دیده را منجمد می کند تا فقط لایه softmax خود را آموزش دهید. این معمولاً شامل وزن های نسبتاً کمی است و می تواند به سرعت و بدون نیاز به مجموعه داده بسیار بزرگ انجام شود. با این حال، اگر دادههای زیادی دارید، یادگیری انتقال میتواند با pretrained_model.trainable = True
حتی بهتر عمل کند. سپس وزنه های از قبل تمرین شده مقادیر اولیه عالی را ارائه می دهند و همچنان می توانند توسط تمرین تنظیم شوند تا بهتر با مشکل شما سازگار شوند.
در نهایت، به لایه Flatten()
توجه کنید که قبل از لایه متراکم softmax شما قرار داده شده است. لایه های متراکم روی بردارهای مسطح داده کار می کنند، اما نمی دانیم که آیا این همان چیزی است که مدل از پیش آموزش دیده برمی گرداند یا خیر. به همین دلیل باید صاف کنیم. در فصل بعد، همانطور که به معماری های کانولوشنال می پردازیم، فرمت داده ای را که توسط لایه های کانولوشن بازگردانده شده است، توضیح خواهیم داد.
با این روش باید دقتی نزدیک به 75% داشته باشید.
راه حل
این دفترچه راه حل است. اگر گیر کرده اید می توانید از آن استفاده کنید.
Keras Flowers transfer learning (solution).ipynb
آنچه را پوشش داده ایم
- 🤔 نحوه نوشتن طبقه بندی کننده در کراس
- 🤓 با آخرین لایه softmax و از دست دادن آنتروپی متقابل پیکربندی شده است
- 😈 آموزش انتقالی
- 🤔 آموزش اولین مدل شما
- 🧐 به دنبال از دست دادن و دقت آن در حین تمرین
لطفا یک لحظه وقت بگذارید و این چک لیست را در ذهن خود مرور کنید.
8. [INFO] شبکه های عصبی کانولوشن
به طور خلاصه
اگر تمام اصطلاحات جسورانه در پاراگراف بعدی برای شما شناخته شده باشد ، می توانید به تمرین بعدی بروید. اگر تازه با شبکه های عصبی Convolutional شروع کرده اید ، لطفاً بخوانید.
تصویر: فیلتر کردن یک تصویر با دو فیلتر پی در پی ساخته شده از 4x4x3 = 48 وزن قابل یادگیری هر کدام.
اینگونه است که یک شبکه عصبی ساده در کراس به نظر می رسد:
model = tf.keras.Sequential([
# input: images of size 192x192x3 pixels (the three stands for RGB channels)
tf.keras.layers.Conv2D(kernel_size=3, filters=24, padding='same', activation='relu', input_shape=[192, 192, 3]),
tf.keras.layers.Conv2D(kernel_size=3, filters=24, padding='same', activation='relu'),
tf.keras.layers.MaxPooling2D(pool_size=2),
tf.keras.layers.Conv2D(kernel_size=3, filters=12, padding='same', activation='relu'),
tf.keras.layers.MaxPooling2D(pool_size=2),
tf.keras.layers.Conv2D(kernel_size=3, filters=6, padding='same', activation='relu'),
tf.keras.layers.Flatten(),
# classifying into 5 categories
tf.keras.layers.Dense(5, activation='softmax')
])
model.compile(
optimizer='adam',
loss= 'categorical_crossentropy',
metrics=['accuracy'])
شبکه های عصبی حلقوی 101
در یک لایه از یک شبکه حلقوی ، یک "نورون" مبلغ وزنی از پیکسل ها را دقیقاً بالای آن ، در یک منطقه کوچک از تصویر انجام می دهد. این یک تعصب را اضافه می کند و جمع را از طریق یک عملکرد فعال سازی تغذیه می کند ، دقیقاً همانطور که یک نورون در یک لایه متراکم معمولی انجام می شود. سپس این عمل در کل تصویر با استفاده از همان وزنه ها تکرار می شود. به یاد داشته باشید که در لایه های متراکم ، هر نورون وزن خود را داشت. در اینجا ، یک "پچ" از وزنه ها از هر دو جهت در تصویر می چرخد ("یک" حل "). خروجی به همان اندازه مقادیر زیادی دارد که پیکسل ها در تصویر وجود دارد (برخی از بالشتک ها در لبه ها لازم است). این یک عمل فیلتر است ، با استفاده از فیلتر 4x4x3 = 48 وزن.
با این حال ، 48 وزن کافی نخواهد بود. برای افزودن درجه های بیشتر آزادی ، ما همان عمل را با مجموعه جدیدی از وزنه ها تکرار می کنیم. این مجموعه جدیدی از خروجی های فیلتر را تولید می کند. بیایید آن را "کانال" از خروجی ها به قیاس با کانال های R ، G ، B در تصویر ورودی بنامیم.
دو (یا بیشتر) وزن را می توان با اضافه کردن یک بعد جدید به عنوان یک تانسور خلاصه کرد. این به ما شکل عمومی تانسور وزنه ها را برای یک لایه حلقوی می بخشد. از آنجا که تعداد کانال های ورودی و خروجی پارامترهایی هستند ، می توانیم شروع به جمع آوری و زنجیر کردن لایه های حلزونی کنیم.
تصویر: یک شبکه عصبی حلقوی "مکعب" داده ها را به "مکعب" های دیگر داده ها تبدیل می کند.
پیچش های قدم ، حداکثر استخر
با انجام پیچیدگی ها با قدم 2 یا 3 ، می توانیم مکعب داده حاصل را در ابعاد افقی آن کوچک کنیم. دو روش مشترک برای انجام این کار وجود دارد:
- Convolution Strided: یک فیلتر کشویی مانند بالا اما با یک قدم> 1
- حداکثر استخر: یک پنجره کشویی با استفاده از حداکثر عمل (به طور معمول در تکه های 2x2 ، هر 2 پیکسل تکرار می شود)
تصویر: کشویی پنجره محاسبات توسط 3 پیکسل منجر به مقادیر خروجی کمتری می شود. پیچش های قدم یا جمع آوری حداکثر (حداکثر در یک پنجره 2x2 که توسط 2 گام به حرکت در می آید) راهی برای کوچک کردن مکعب داده در ابعاد افقی است.
c طبقه بندی کننده onVolutional
سرانجام ، ما با صاف کردن آخرین مکعب داده و تغذیه آن از طریق یک لایه متراکم و فعال شده با نرم ، یک سر طبقه بندی را وصل می کنیم. یک طبقه بندی کننده حلقوی معمولی می تواند به این شکل باشد:
تصویر: طبقه بندی کننده تصویر با استفاده از لایه های Convolutional و SoftMax. از فیلترهای 3x3 و 1x1 استفاده می کند. لایه های Maxpool حداکثر گروه های داده 2x2 را به خود اختصاص می دهد. سر طبقه بندی با یک لایه متراکم با فعال سازی SoftMax اجرا می شود.
در کراس
پشته حلقوی که در بالا نشان داده شده است را می توان در کروها مانند این نوشت:
model = tf.keras.Sequential([
# input: images of size 192x192x3 pixels (the three stands for RGB channels)
tf.keras.layers.Conv2D(kernel_size=3, filters=32, padding='same', activation='relu', input_shape=[192, 192, 3]),
tf.keras.layers.Conv2D(kernel_size=1, filters=32, padding='same', activation='relu'),
tf.keras.layers.MaxPooling2D(pool_size=2),
tf.keras.layers.Conv2D(kernel_size=3, filters=32, padding='same', activation='relu'),
tf.keras.layers.Conv2D(kernel_size=1, filters=32, padding='same', activation='relu'),
tf.keras.layers.MaxPooling2D(pool_size=2),
tf.keras.layers.Conv2D(kernel_size=3, filters=32, padding='same', activation='relu'),
tf.keras.layers.Conv2D(kernel_size=1, filters=32, padding='same', activation='relu'),
tf.keras.layers.MaxPooling2D(pool_size=2),
tf.keras.layers.Conv2D(kernel_size=3, filters=32, padding='same', activation='relu'),
tf.keras.layers.Conv2D(kernel_size=1, filters=32, padding='same', activation='relu'),
tf.keras.layers.MaxPooling2D(pool_size=2),
tf.keras.layers.Conv2D(kernel_size=3, filters=16, padding='same', activation='relu'),
tf.keras.layers.Conv2D(kernel_size=1, filters=8, padding='same', activation='relu'),
tf.keras.layers.Flatten(),
# classifying into 5 categories
tf.keras.layers.Dense(5, activation='softmax')
])
model.compile(
optimizer='adam',
loss= 'categorical_crossentropy',
metrics=['accuracy'])
9. Convnet سفارشی شما
دست
بگذارید یک شبکه عصبی حلقوی را از ابتدا بسازیم و آموزش دهیم. استفاده از TPU به ما امکان می دهد خیلی سریع تکرار کنیم. لطفاً نوت بوک زیر را باز کنید ، سلول ها را اجرا کنید (شیفت-ورودی) و در هر کجا که یک برچسب "کار مورد نیاز" را مشاهده می کنید ، دستورالعمل ها را دنبال کنید.
Keras_Flowers_TPU (playground).ipynb
هدف این است که دقت 75 ٪ مدل یادگیری انتقال را ضرب و شتم کنیم. این مدل یک مزیت داشت ، که از قبل در مجموعه داده های میلیون ها تصویر از قبل آموزش داده شده است ، در حالی که ما فقط در اینجا 3670 تصویر داریم. آیا می توانید حداقل با آن مطابقت داشته باشید؟
اطلاعات تکمیلی
چند لایه ، چقدر بزرگ؟
انتخاب اندازه لایه بیشتر از یک علم است. شما باید تعادل مناسب بین داشتن پارامترهای بیش از حد و بیش از حد (وزن و تعصب) را پیدا کنید. با وزن بسیار کمی ، شبکه عصبی نمی تواند پیچیدگی شکل های گل را نشان دهد. با تعداد بسیار زیاد ، می تواند مستعد ابتلا به "بیش از حد" باشد ، یعنی متخصص در تصاویر آموزشی و قادر به تعمیم نیست. با پارامترهای زیادی ، مدل نیز برای آموزش آهسته خواهد بود. در Keras ، عملکرد model.summary()
ساختار و تعداد پارامتر مدل شما را نشان می دهد:
Layer (type) Output Shape Param #
=================================================================
conv2d (Conv2D) (None, 192, 192, 16) 448
_________________________________________________________________
conv2d_1 (Conv2D) (None, 192, 192, 30) 4350
_________________________________________________________________
max_pooling2d (MaxPooling2D) (None, 96, 96, 30) 0
_________________________________________________________________
conv2d_2 (Conv2D) (None, 96, 96, 60) 16260
_________________________________________________________________
...
_________________________________________________________________
global_average_pooling2d (Gl (None, 130) 0
_________________________________________________________________
dense (Dense) (None, 90) 11790
_________________________________________________________________
dense_1 (Dense) (None, 5) 455
=================================================================
Total params: 300,033
Trainable params: 300,033
Non-trainable params: 0
_________________________________________________________________
چند نکته:
- داشتن چندین لایه چیزی است که باعث می شود شبکه های عصبی "عمیق" مؤثر باشند. برای این مشکل ساده تشخیص گل ، 5 تا 10 لایه معنی دارد.
- از فیلترهای کوچک استفاده کنید. به طور معمول فیلترهای 3x3 در همه جا خوب هستند.
- فیلترهای 1x1 نیز می توانند استفاده شوند و ارزان هستند. آنها واقعاً چیزی را "فیلتر" نمی کنند بلکه ترکیب های خطی کانال ها را محاسبه می کنند. آنها را با فیلترهای واقعی جایگزین کنید. (اطلاعات بیشتر در مورد "1x1 Connolutions" در بخش بعدی.)
- برای یک مشکل طبقه بندی مانند این ، DownSample به طور مکرر با لایه های حداکثر استخر (یا حلقوی با قدم> 1). شما اهمیتی نمی دهید که گل کجاست ، فقط این که یک گل رز یا قاصدک است بنابراین از دست دادن اطلاعات X و Y مهم نیست و فیلتر کردن مناطق کوچکتر ارزان تر است.
- تعداد فیلترها معمولاً شبیه به تعداد کلاسها در انتهای شبکه می شود (چرا؟ به ترفند "متوسط استخر متوسط" در زیر مراجعه کنید). اگر به صدها کلاس طبقه بندی می کنید ، تعداد فیلتر را به تدریج در لایه های متوالی افزایش دهید. برای مجموعه داده های گل با 5 کلاس ، فیلتر کردن تنها با 5 فیلتر کافی نخواهد بود. به عنوان مثال 32 می توانید از همان تعداد فیلتر در اکثر لایه ها استفاده کنید و آن را تا انتها کاهش دهید.
- لایه (های) متراکم نهایی گران است. این/آنها می توانند وزن بیشتری نسبت به همه لایه های حلقوی ترکیب شده داشته باشند. به عنوان مثال ، حتی با خروجی بسیار معقول از آخرین مکعب داده از نقاط داده 24x24x10 ، یک لایه متراکم 100 نورون هزینه 24x24x10x100 = 576،000 وزن دارد! سعی کنید متفکر باشید ، یا میانگین جهانی را امتحان کنید (به تصویر زیر مراجعه کنید).
استخر متوسط جهانی
به جای استفاده از یک لایه متراکم گران قیمت در انتهای یک شبکه عصبی حلقوی ، می توانید داده های ورودی "مکعب" را به همان تعداد قسمت هایی که کلاس دارید ، تقسیم کنید ، مقادیر آنها را به طور متوسط و از طریق یک عملکرد فعال سازی SoftMax تغذیه کنید. این روش ساخت سر طبقه بندی 0 وزن دارد. در کروس ، نحو tf.keras.layers.GlobalAveragePooling2D().
راه حل
در اینجا نوت بوک راه حل است. اگر گیر کرده اید می توانید از آن استفاده کنید.
Keras_Flowers_TPU (solution).ipynb
آنچه را پوشش داده ایم
- 🤔 با لایه های حلقوی بازی کرد
- 🤓 با حداکثر استخر ، گام ها ، متوسط استخر جهانی ، ...
- 😀 در یک مدل دنیای واقعی سریع ، در TPU تکرار شد
لطفاً لحظه ای از این لیست چک را در ذهن خود طی کنید.
10. [اطلاعات] معماری های مدرن حلقوی
به طور خلاصه
تصویر: "ماژول" حلقوی. چه چیزی در این مرحله بهترین است؟ یک لایه حداکثر استخر و به دنبال آن یک لایه حلقوی 1x1 یا ترکیبی متفاوت از لایه ها؟ همه آنها را امتحان کنید ، نتایج را جمع کنید و به شبکه اجازه دهید تصمیم بگیرد. در سمت راست: معماری حلقوی " شروع " با استفاده از چنین ماژول ها.
در کروس ، برای ایجاد مدلهایی که جریان داده ها می توانند در داخل و خارج شاخه شوند ، باید از سبک مدل "کاربردی" استفاده کنید. در اینجا یک مثال است:
l = tf.keras.layers # syntax shortcut
y = l.Conv2D(filters=32, kernel_size=3, padding='same',
activation='relu', input_shape=[192, 192, 3])(x) # x=input image
# module start: branch out
y1 = l.Conv2D(filters=32, kernel_size=1, padding='same', activation='relu')(y)
y3 = l.Conv2D(filters=32, kernel_size=3, padding='same', activation='relu')(y)
y = l.concatenate([y1, y3]) # output now has 64 channels
# module end: concatenation
# many more layers ...
# Create the model by specifying the input and output tensors.
# Keras layers track their connections automatically so that's all that's needed.
z = l.Dense(5, activation='softmax')(y)
model = tf.keras.Model(x, z)
سایر ترفندهای ارزان قیمت
فیلترهای کوچک 3x3
در این تصویر ، نتیجه دو فیلتر 3x3 متوالی را مشاهده می کنید. سعی کنید ردیابی کنید که نقاط داده به نتیجه کمک کرده است: این دو فیلتر 3x3 متوالی ، ترکیبی از یک منطقه 5x5 را محاسبه می کنند. دقیقاً همان ترکیب نیست که یک فیلتر 5x5 محاسبه می کند اما ارزش تلاش دارد زیرا دو فیلتر 3x3 متوالی ارزان تر از یک فیلتر 5x5 واحد هستند.
1x1 پیچش؟
از نظر ریاضی ، یک حلقوی "1x1" ضرب توسط یک مفهوم ثابت است ، نه یک مفهوم بسیار مفید. با این حال ، در شبکه های عصبی حلقوی ، به یاد داشته باشید که این فیلتر روی یک مکعب داده اعمال می شود ، نه فقط یک تصویر 2D. بنابراین ، یک فیلتر "1x1" یک مقدار وزنی از ستون 1x1 داده را محاسبه می کند (به تصویر مراجعه کنید) و در حالی که آن را در داده ها می کشید ، ترکیبی خطی از کانال های ورودی را بدست می آورید. این در واقع مفید است. اگر از کانال ها به عنوان نتایج عملیات فیلتر فردی فکر می کنید ، به عنوان مثال یک فیلتر برای "گوشهای برجسته" ، دیگری برای "سوت ها" و یک سوم برای "چشم های شکاف" ، سپس یک لایه حلقوی "1x1" چندین محاسبه می کند ترکیب خطی ممکن از این ویژگی ها ، که ممکن است هنگام جستجوی "گربه" مفید باشد. در بالای آن ، لایه های 1x1 از وزن کمتری استفاده می کنند.
11. squeezenet
یک روش ساده برای جمع کردن این ایده ها در مقاله "squeezenet" به نمایش گذاشته شده است. نویسندگان با استفاده از لایه های حلقوی 1x1 و 3x3 ، یک طراحی ماژول کاملاً ساده را پیشنهاد می کنند.
تصویر: معماری Squeezenet بر اساس "ماژول های آتش". آنها یک لایه 1x1 را جایگزین می کنند که داده های ورودی را در بعد عمودی و به دنبال آن دو لایه موازی 1x1 و 3x3 که دوباره عمق داده ها را "گسترش می دهند" "فشرده می کند.
دست
در نوت بوک قبلی خود ادامه دهید و یک شبکه عصبی Convolutional با الهام از Squeezenet ایجاد کنید. شما باید کد مدل را به "سبک کاربردی" Keras تغییر دهید.
Keras_Flowers_TPU (playground).ipynb
اطلاعات اضافی
برای این تمرین برای تعریف یک عملکرد یاور برای یک ماژول squeezenet مفید خواهد بود:
def fire(x, squeeze, expand):
y = l.Conv2D(filters=squeeze, kernel_size=1, padding='same', activation='relu')(x)
y1 = l.Conv2D(filters=expand//2, kernel_size=1, padding='same', activation='relu')(y)
y3 = l.Conv2D(filters=expand//2, kernel_size=3, padding='same', activation='relu')(y)
return tf.keras.layers.concatenate([y1, y3])
# this is to make it behave similarly to other Keras layers
def fire_module(squeeze, expand):
return lambda x: fire(x, squeeze, expand)
# usage:
x = l.Input(shape=[192, 192, 3])
y = fire_module(squeeze=24, expand=48)(x) # typically, squeeze is less than expand
y = fire_module(squeeze=32, expand=64)(y)
...
model = tf.keras.Model(x, y)
هدف این بار رسیدن به دقت 80 ٪ است.
چیزهایی که باید امتحان کنید
با یک لایه حلقوی واحد شروع کنید ، سپس با " fire_modules
" دنبال کنید ، متناوب با لایه های MaxPooling2D(pool_size=2)
. شما می توانید با 2 تا 4 لایه جمع آوری حداکثر در شبکه و همچنین با 1 ، 2 یا 3 ماژول آتش متوالی بین لایه های حداکثر استخر آزمایش کنید.
در ماژول های آتش ، پارامتر "فشار" معمولاً باید از پارامتر "گسترش" کوچکتر باشد. این پارامترها در واقع تعداد فیلترها هستند. آنها به طور معمول می توانند از 8 تا 196 متغیر باشند. شما می توانید با معماری ها آزمایش کنید که در آن تعداد فیلترها به تدریج از طریق شبکه افزایش می یابد ، یا معماری های ساده که در آن همه ماژول های آتش سوزی دارای تعداد فیلترها هستند.
در اینجا یک مثال است:
x = tf.keras.layers.Input(shape=[*IMAGE_SIZE, 3]) # input is 192x192 pixels RGB
y = tf.keras.layers.Conv2D(kernel_size=3, filters=32, padding='same', activation='relu')(x)
y = fire_module(24, 48)(y)
y = tf.keras.layers.MaxPooling2D(pool_size=2)(y)
y = fire_module(24, 48)(y)
y = tf.keras.layers.MaxPooling2D(pool_size=2)(y)
y = fire_module(24, 48)(y)
y = tf.keras.layers.GlobalAveragePooling2D()(y)
y = tf.keras.layers.Dense(5, activation='softmax')(y)
model = tf.keras.Model(x, y)
در این مرحله ، ممکن است متوجه شوید که آزمایشات شما به خوبی پیش نمی رود و هدف 80 ٪ دقت از راه دور به نظر می رسد. زمان برای چند ترفند ارزان تر.
عادی سازی دسته ای
Norm Batch به مشکلات همگرایی که تجربه می کنید کمک خواهد کرد. در کارگاه بعدی توضیحات مفصلی در مورد این تکنیک وجود خواهد داشت ، در حال حاضر ، لطفاً با اضافه کردن این خط پس از هر لایه حلقوی در شبکه ، از آن به عنوان یک یاور جعبه سیاه "جادویی" استفاده کنید ، از جمله لایه های داخل عملکرد Fire_Module شما:
y = tf.keras.layers.BatchNormalization(momentum=0.9)(y)
# please adapt the input and output "y"s to whatever is appropriate in your context
پارامتر حرکت باید از مقدار پیش فرض آن از 0.99 به 0.9 کاهش یابد زیرا مجموعه داده ما اندک است. فعلاً هرگز به این جزئیات توجه نکنید.
افزایش داده ها
شما با افزایش داده ها با تحولات آسان مانند تلنگر چپ و راست اشباع ، چند درصد بیشتر به دست می آورید:
این کار در TensorFlow با API tf.data.dataset بسیار آسان است. یک تابع تحول جدید را برای داده های خود تعریف کنید:
def data_augment(image, label):
image = tf.image.random_flip_left_right(image)
image = tf.image.random_saturation(image, lower=0, upper=2)
return image, label
سپس از آن در شما در تحول نهایی داده ها استفاده کنید (سلول "مجموعه داده های آموزش و اعتبار سنجی" ، عملکرد "get_batched_dataset"):
dataset = dataset.repeat() # existing line
# insert this
if augment_data:
dataset = dataset.map(data_augment, num_parallel_calls=AUTO)
dataset = dataset.shuffle(2048) # existing line
فراموش نکنید که افزایش داده را اختیاری و اضافه کردن کد لازم برای اطمینان از اینکه فقط مجموعه داده های آموزشی تقویت شده است . برای تقویت مجموعه داده های اعتبار سنجی منطقی نیست.
80 ٪ دقت در 35 دوره باید در دسترس باشد.
راه حل
در اینجا نوت بوک راه حل است. اگر گیر کرده اید می توانید از آن استفاده کنید.
Keras_Flowers_TPU_squeezenet.ipynb
آنچه را پوشش داده ایم
- 🤔 مدل های "سبک کاربردی"
- 🤓 معماری Squeezenet
- 🤓 افزایش داده با tf.data.datset
لطفاً لحظه ای از این لیست چک را در ذهن خود طی کنید.
12. Xception خوب تنظیم شده است
پیچش های قابل تفکیک
اخیراً یک روش متفاوت برای اجرای لایه های حلقوی محبوبیت زیادی پیدا کرده است: پیچیدگی های قابل تفکیک. می دانم ، این یک لقمه است ، اما مفهوم بسیار ساده است. آنها در Tensorflow و Keras به عنوان tf.keras.layers.SeparableConv2D
اجرا می شوند.
یک حلقوی قابل جدا شدن همچنین یک فیلتر را روی تصویر اجرا می کند اما از مجموعه ای از وزنهای مشخص برای هر کانال از تصویر ورودی استفاده می کند. این با "1x1 Convolution" دنبال می شود ، یک سری از محصولات DOT که منجر به جمع وزنی کانال های فیلتر شده می شود. هر بار با وزنهای جدید ، به عنوان بسیاری از نوترکیب های وزنی کانال ها در صورت لزوم محاسبه می شوند.
تصویر: پیچش های قابل تفکیک. فاز 1: پیچش با یک فیلتر جداگانه برای هر کانال. فاز 2: نوترکیب خطی کانال ها. با مجموعه جدیدی از وزنه ها تکرار می شود تا تعداد مورد نظر کانال های خروجی حاصل شود. فاز 1 نیز می تواند تکرار شود ، با وزن های جدید هر بار اما در عمل به ندرت چنین است.
از پیچش های جداگانه در جدیدترین معماری های شبکه های حلقوی استفاده می شود: mobilenetv2 ، xception ، کارآمد. به هر حال ، mobilenetv2 همان چیزی است که قبلاً برای یادگیری انتقال استفاده کرده اید.
آنها ارزان تر از پیچش های معمولی هستند و به نظر می رسد که در عمل به همان اندازه مؤثر هستند. در اینجا تعداد وزن برای مثال نشان داده شده در بالا آمده است:
لایه حلقوی: 4 x 4 x 3 x 5 = 240
لایه حلقوی جداگانه: 4 x 4 x 3 + 3 x 5 = 48 + 15 = 63
این به عنوان یک تمرین برای خواننده باقی مانده است تا از تعداد ضرب های مورد نیاز برای استفاده از هر سبک از مقیاس لایه های حلقوی به روشی مشابه محاسبه کند. پیچش های قابل تفکیک کوچکتر و بسیار محاسباتی مؤثر هستند.
دست
از نوت بوک زمین بازی "انتقال یادگیری" مجدداً راه اندازی کنید اما این بار Xception را به عنوان مدل از پیش آموزش انتخاب کنید. Xception فقط از پیچیدگی های قابل تفکیک استفاده می کند. تمام وزن ها را قابل آموزش بگذارید. ما به جای استفاده از لایه های از پیش آموزش داده شده به این ترتیب ، وزن های از پیش آموزش داده شده را روی داده های خود تنظیم خواهیم کرد.
Keras Flowers transfer learning (playground).ipynb
هدف: دقت> 95 ٪ (نه ، به طور جدی ، ممکن است!)
این تمرین نهایی است ، به کار کمی بیشتر کد و کار علوم داده نیاز دارد.
اطلاعات اضافی در مورد تنظیم دقیق
Xception در مدل های استاندارد از پیش آموزش در Tf.Keras.Application موجود است.* فراموش نکنید که این بار تمام وزن ها را قابل آموزش بگذارید.
pretrained_model = tf.keras.applications.Xception(input_shape=[*IMAGE_SIZE, 3],
include_top=False)
pretrained_model.trainable = True
برای به دست آوردن نتایج خوب هنگام تنظیم دقیق یک مدل ، باید به نرخ یادگیری توجه کنید و از یک برنامه نرخ یادگیری با یک دوره رمپ استفاده کنید. مثل این:
شروع با نرخ یادگیری استاندارد ، وزن های از پیش آموزش داده شده مدل را مختل می کند. شروع به تدریج آنها را حفظ می کند تا زمانی که مدل روی داده های شما بسته شود ، قادر به تغییر آنها به روشی معقول است. پس از سطح شیب دار ، می توانید با یک میزان یادگیری ثابت یا به صورت نمایی در حال فروپاشی ادامه دهید.
در کروس ، نرخ یادگیری از طریق پاسخ به تماس مشخص می شود که در آن می توانید نرخ یادگیری مناسب را برای هر دوره محاسبه کنید. Keras نرخ یادگیری صحیح را برای هر دوره به بهینه ساز منتقل می کند.
def lr_fn(epoch):
lr = ...
return lr
lr_callback = tf.keras.callbacks.LearningRateScheduler(lr_fn, verbose=True)
model.fit(..., callbacks=[lr_callback])
راه حل
در اینجا نوت بوک راه حل است. اگر گیر کرده اید می توانید از آن استفاده کنید.
07_Keras_Flowers_TPU_xception_fine_tuned_best.ipynb
آنچه را پوشش داده ایم
- 🤔 حلقوی عمیق
- 🤓 برنامه های نرخ یادگیری
- 😈 تنظیم دقیق یک مدل از پیش آموزش داده شده.
لطفاً لحظه ای از این لیست چک را در ذهن خود طی کنید.
13. تبریک!
شما اولین شبکه عصبی مدرن Convolutional خود را ساخته اید و آن را به 90 ٪ + دقت آموزش داده اید ، و در تمرینات پی در پی فقط در چند دقیقه به لطف TPU ها تکرار می شود.
TPU در عمل
TPU و GPU در Vertex AI Google Cloud در دسترس هستند:
- در یادگیری عمیق VM
- در نوت بوک های Vertex AI
- در ورتکس هوش مصنوعی شغل شغل
سرانجام ، ما عاشق بازخورد هستیم. لطفاً اگر چیزی را در این آزمایشگاه می بینید یا فکر می کنید باید بهبود یابد ، به ما بگویید. بازخورد را می توان از طریق مسائل GitHub [ پیوند بازخورد ] ارائه داد.
|