1. بررسی اجمالی
در این آزمایشگاه با معماری کانولوشن مدرن آشنا می شوید و از دانش خود برای پیاده سازی یک convnet ساده اما موثر به نام "squeezenet" استفاده می کنید.
این آزمایشگاه شامل توضیحات نظری لازم در مورد شبکه های عصبی کانولوشن است و نقطه شروع خوبی برای توسعه دهندگان یادگیری عمیق است.
این آزمایشگاه قسمت 4 از سری "Keras on TPU" است. می توانید آنها را به ترتیب زیر یا به صورت مستقل انجام دهید.
- خطوط لوله داده با سرعت TPU: tf.data.Dataset و TFRecords
- اولین مدل کراس شما با آموزش انتقالی
- شبکه های عصبی کانولوشنال، با Keras و TPU
- [THIS LAB] convnet های مدرن، squeezenet، Xception، با Keras و TPU
چیزی که یاد خواهید گرفت
- برای تسلط بر سبک عملکردی Keras
- برای ساخت یک مدل با استفاده از معماری squeezenet
- برای استفاده از TPU ها به منظور آموزش سریع و تکرار معماری خود
- برای پیاده سازی افزایش داده ها با tf.data.dataset
- برای تنظیم دقیق یک مدل بزرگ از پیش آموزش دیده (Xception) روی TPU
بازخورد
اگر در این آزمایشگاه کد مشکلی مشاهده کردید، لطفاً به ما بگویید. بازخورد را می توان از طریق مسائل GitHub [ لینک بازخورد ] ارائه کرد.
2. شروع سریع Google Collaboratory
این آزمایشگاه از Google Collaboratory استفاده می کند و نیازی به تنظیم از طرف شما ندارد. Colaboratory یک پلت فرم نوت بوک آنلاین برای اهداف آموزشی است. آموزش رایگان CPU، GPU و TPU را ارائه می دهد.
میتوانید این نمونه دفترچه یادداشت را باز کنید و از چند سلول عبور کنید تا با Colaboratory آشنا شوید.
یک باطن 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. [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 یا بیشتر داشته باشید.
5. [INFO] شبکه های عصبی کانولوشنال
به طور خلاصه
اگر تمام عبارات پررنگ در پاراگراف بعدی قبلاً برای شما شناخته شده است، می توانید به تمرین بعدی بروید. اگر به تازگی با شبکه های عصبی کانولوشنال شروع کرده اید، لطفاً ادامه مطلب را بخوانید.
تصویر: فیلتر کردن یک تصویر با دو فیلتر متوالی از 4x4x3=48 وزن قابل یادگیری هر کدام.
یک شبکه عصبی کانولوشنال ساده در Keras به این صورت است:
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
در لایهای از یک شبکه کانولوشن، یک «نرون» مجموع وزنی پیکسلها را درست بالای آن، فقط در ناحیه کوچکی از تصویر انجام میدهد. این یک سوگیری اضافه می کند و مجموع را از طریق یک تابع فعال سازی تغذیه می کند، درست همانطور که یک نورون در یک لایه متراکم منظم انجام می دهد. سپس این عمل در کل تصویر با استفاده از وزن های مشابه تکرار می شود. به یاد داشته باشید که در لایه های متراکم، هر نورون وزن مخصوص به خود را داشت. در اینجا، یک "پچ" از وزن ها در هر دو جهت روی تصویر می لغزند (یک "پیچیدگی"). مقدار خروجی به اندازه پیکسل های تصویر است (هر چند در لبه ها مقداری padding لازم است). این یک عملیات فیلتر است، با استفاده از فیلتر 4x4x3=48 وزن.
با این حال، 48 وزنه کافی نخواهد بود. برای افزودن درجات آزادی بیشتر، همین عمل را با یک مجموعه وزنه جدید تکرار می کنیم. این مجموعه جدیدی از خروجی های فیلتر را تولید می کند. بیایید آن را یک "کانال" از خروجی ها بر اساس قیاس با کانال های R,G,B در تصویر ورودی بنامیم.
دو (یا بیشتر) مجموعه وزن را می توان با افزودن یک بعد جدید به عنوان یک تانسور خلاصه کرد. این شکل کلی تانسور وزنه را برای یک لایه کانولوشن به ما می دهد. از آنجایی که تعداد کانالهای ورودی و خروجی پارامتر هستند، میتوانیم لایههای کانولوشنال را انباشته و زنجیرهای کنیم.
تصویر: یک شبکه عصبی کانولوشن "مکعب" داده را به "مکعب" دیگر داده تبدیل می کند.
پیچیدگی های راه راه، حداکثر تجمع
با انجام کانولوشن ها با گام 2 یا 3، می توانیم مکعب داده به دست آمده را در ابعاد افقی آن نیز کوچک کنیم. دو روش متداول برای انجام این کار وجود دارد:
- پیچیدگی راه راه: یک فیلتر کشویی مانند بالا اما با گام> 1
- حداکثر ادغام: یک پنجره کشویی که عملیات MAX را اعمال می کند (معمولاً در وصله های 2x2 که هر 2 پیکسل تکرار می شود)
تصویر: لغزاندن پنجره محاسباتی با 3 پیکسل منجر به مقادیر کمتر خروجی می شود. کانولوشن های راه راه یا حداکثر ادغام (حداکثر در یک پنجره 2x2 کشویی با گام 2) راهی برای کوچک کردن مکعب داده در ابعاد افقی است.
C طبقهبندیکننده متحرک
در نهایت، یک سر طبقه بندی را با صاف کردن آخرین مکعب داده و تغذیه آن از طریق یک لایه متراکم و فعال شده با softmax متصل می کنیم. یک طبقه بندی کانولوشنال معمولی می تواند به شکل زیر باشد:
تصویر: یک طبقهبندی کننده تصویر با استفاده از لایههای کانولوشنال و سافت مکس. از فیلترهای 3x3 و 1x1 استفاده می کند. لایه های maxpool حداکثر گروه های 2x2 نقطه داده را می گیرند. سر طبقه بندی با یک لایه متراکم با فعال سازی softmax اجرا می شود.
در کراس
پشته کانولوشنال نشان داده شده در بالا را می توان در Keras به این صورت نوشت:
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'])
6. [اطلاعات جدید] معماری های کانولوشنال مدرن
به طور خلاصه
تصویر: یک "ماژول" کانولوشن. چه چیزی در این مرحله بهترین است؟ یک لایه max-pool به دنبال یک لایه کانولوشن 1x1 یا ترکیبی متفاوت از لایه ها؟ همه آنها را امتحان کنید، نتایج را به هم متصل کنید و اجازه دهید شبکه تصمیم بگیرد. در سمت راست: معماری کانولوشن " شروع " با استفاده از این ماژول ها.
در Keras، برای ایجاد مدل هایی که جریان داده می تواند به داخل و خارج منشعب شود، باید از سبک مدل "عملکردی" استفاده کنید. در اینجا یک مثال است:
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
در این تصویر، نتیجه دو فیلتر 3*3 متوالی را مشاهده می کنید. سعی کنید نقاط داده ای را که در نتیجه نقش داشته اند ردیابی کنید: این دو فیلتر 3x3 متوالی ترکیبی از یک منطقه 5x5 را محاسبه می کنند. این دقیقاً همان ترکیبی نیست که یک فیلتر 5x5 محاسبه می کند، اما ارزش امتحان کردن را دارد زیرا دو فیلتر 3x3 متوالی ارزان تر از یک فیلتر 5x5 منفرد هستند.
پیچش 1x1
از نظر ریاضی، یک کانولوشن "1x1" ضرب در یک ثابت است، مفهوم چندان مفیدی نیست. با این حال، در شبکههای عصبی کانولوشن، به یاد داشته باشید که فیلتر روی یک مکعب داده اعمال میشود، نه فقط یک تصویر دو بعدی. بنابراین، یک فیلتر "1x1" مجموع وزنی یک ستون 1x1 از داده ها را محاسبه می کند (تصویر را ببینید) و همانطور که آن را روی داده ها می کشید، ترکیبی خطی از کانال های ورودی به دست خواهید آورد. این در واقع مفید است. اگر کانالها را بهعنوان نتایج عملیات فیلتر کردن فردی در نظر بگیرید، بهعنوان مثال فیلتری برای «گوشهای نوکدار»، فیلتری دیگر برای «سبیلها» و سومی برای «چشمهای شکاف»، یک لایه کانولوشنال «1x1» در حال محاسبه چندگانه خواهد بود. ترکیبات خطی ممکن از این ویژگی ها، که ممکن است هنگام جستجوی یک "گربه" مفید باشد. علاوه بر این، لایه های 1x1 از وزنه های کمتری استفاده می کنند.
7. Squeezenet
یک راه ساده برای کنار هم قرار دادن این ایده ها در مقاله "Squeezenet" به نمایش گذاشته شده است. نویسندگان یک طرح ماژول کانولوشن بسیار ساده را پیشنهاد می کنند که تنها از لایه های کانولوشنال 1x1 و 3x3 استفاده می کند.
تصویر: معماری squeezenet بر اساس "ماژول های آتش". آنها یک لایه 1x1 را جایگزین می کنند که داده های دریافتی را در بعد عمودی "فشرده" می کند و به دنبال آن دو لایه کانولوشن 1x1 و 3x3 موازی که عمق داده ها را دوباره "بسط" می دهد.
دست در
در نوت بوک قبلی خود ادامه دهید و یک شبکه عصبی کانولوشنال الهام گرفته از 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 درصد دور از دسترس به نظر میرسد. زمان برای چند ترفند ارزان دیگر است.
عادی سازی دسته ای
هنجار دسته ای به مشکلات همگرایی که با آن مواجه هستید کمک می کند. در کارگاه بعدی توضیحات مفصلی در مورد این تکنیک ارائه خواهد شد، در حال حاضر، لطفاً با افزودن این خط بعد از هر لایه کانولوشن در شبکه خود، از جمله لایه های داخل تابع 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 با tf.data.Dataset API بسیار آسان است. یک تابع تبدیل جدید برای داده های خود تعریف کنید:
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
لطفا یک لحظه وقت بگذارید و این چک لیست را در ذهن خود مرور کنید.
8. Xception به خوبی تنظیم شده است
پیچیدگی های قابل تفکیک
روشی متفاوت برای اجرای لایههای کانولوشن اخیراً محبوبیت پیدا کرده است: پیچشهای قابل تفکیک با عمق. من می دانم، این یک لقمه است، اما مفهوم آن بسیار ساده است. آنها در Tensorflow و Keras به عنوان tf.keras.layers.SeparableConv2D
پیاده سازی شده اند.
یک کانولوشن قابل جداسازی نیز یک فیلتر را روی تصویر اجرا می کند اما از مجموعه وزن مجزایی برای هر کانال تصویر ورودی استفاده می کند. با یک "پیچیدگی 1x1" دنبال می شود، مجموعه ای از محصولات نقطه ای که منجر به مجموع وزنی کانال های فیلتر شده می شود. هر بار با وزنهای جدید، به همان اندازه که لازم باشد، نوترکیبی وزنی کانالها محاسبه میشود.
تصویر: پیچیدگی های قابل تفکیک. فاز 1: کانولوشن با یک فیلتر جداگانه برای هر کانال. فاز 2: نوترکیبی خطی کانال ها. با یک مجموعه وزنه جدید تکرار می شود تا به تعداد کانال های خروجی مورد نظر برسد. فاز 1 نیز می تواند تکرار شود، هر بار با وزنه های جدید، اما در عمل به ندرت چنین است.
کانولوشنهای جداشدنی در معماریهای اخیر شبکههای کانولوشن استفاده میشوند: MobileNetV2، Xception، EfficientNet. به هر حال، 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، نرخ یادگیری از طریق یک callback مشخص می شود که در آن می توانید نرخ یادگیری مناسب را برای هر دوره محاسبه کنید. 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
آنچه را پوشش داده ایم
- 🤔 پیچیدگی قابل تفکیک در عمق
- 🤓 جدول نرخ یادگیری
- 😈 تنظیم دقیق یک مدل از قبل آموزش دیده.
لطفا یک لحظه وقت بگذارید و این چک لیست را در ذهن خود مرور کنید.
9. تبریک می گویم!
شما اولین شبکه عصبی کانولوشنال مدرن خود را ساخته اید و آن را با دقت + 90% آموزش داده اید و به لطف TPU ها تنها در چند دقیقه آموزش های متوالی را تکرار می کنید. این 4 "Kera on TPU codelabs" را به پایان می رساند:
- خطوط لوله داده با سرعت TPU: tf.data.Dataset و TFRecords
- اولین مدل کراس شما با آموزش انتقالی
- شبکه های عصبی کانولوشنال، با Keras و TPU
- [THIS LAB] convnet های مدرن، squeezenet، Xception، با Keras و TPU
TPU ها در عمل
TPU ها و GPU ها در پلتفرم Cloud AI در دسترس هستند:
در نهایت، ما بازخورد را دوست داریم. لطفاً اگر چیزی در این آزمایشگاه اشتباه می بینید یا فکر می کنید باید بهبود یابد، به ما بگویید. بازخورد را می توان از طریق مسائل GitHub [ لینک بازخورد ] ارائه کرد.
|