دقت مخلوط

مشاهده در TensorFlow.org در Google Colab اجرا شود مشاهده منبع در GitHub دانلود دفترچه یادداشت

بررسی اجمالی

دقت ترکیبی استفاده از هر دو نوع ممیز شناور 16 بیتی و 32 بیتی در یک مدل در طول آموزش است تا آن را سریعتر اجرا کند و از حافظه کمتری استفاده کند. با نگه‌داشتن بخش‌های خاصی از مدل در انواع 32 بیتی برای ثبات عددی، مدل زمان گام پایین‌تری خواهد داشت و از نظر معیارهای ارزیابی مانند دقت، به همان اندازه تمرین می‌کند. این راهنما نحوه استفاده از Keras را برای سرعت بخشیدن به مدل های خود شرح می دهد. استفاده از این API می تواند عملکرد را بیش از 3 برابر در GPU های مدرن و 60٪ در TPU ها بهبود بخشد.

امروزه اکثر مدل ها از float32 dtype استفاده می کنند که 32 بیت حافظه می گیرد. با این حال، دو نوع d با دقت کمتری وجود دارد، float16 و bfloat16، که هر کدام در عوض 16 بیت حافظه مصرف می کنند. شتاب دهنده های مدرن می توانند عملیات را در dtypes 16 بیتی سریعتر اجرا کنند، زیرا آنها دارای سخت افزار تخصصی برای اجرای محاسبات 16 بیتی هستند و dtypes 16 بیتی را می توان سریعتر از حافظه خواند.

پردازنده‌های گرافیکی NVIDIA می‌توانند عملیات‌ها را در float16 سریع‌تر از float32 و TPU‌ها در bfloat16 سریع‌تر از float32 اجرا کنند. بنابراین، این نوع d با دقت پایین‌تر باید تا حد امکان در آن دستگاه‌ها استفاده شود. با این حال، متغیرها و چند محاسبات به دلایل عددی همچنان باید در float32 باشند تا مدل با همان کیفیت آموزش ببیند. API دقیق مخلوط Keras به شما امکان می دهد از ترکیبی از float16 یا bfloat16 با float32 استفاده کنید تا از مزایای عملکرد float16/bfloat16 و مزایای ثبات عددی از float32 بهره مند شوید.

برپایی

import tensorflow as tf

from tensorflow import keras
from tensorflow.keras import layers
from tensorflow.keras import mixed_precision

سخت افزار پشتیبانی شده

در حالی که دقت ترکیبی روی اکثر سخت‌افزارها اجرا می‌شود، اما فقط سرعت مدل‌های پردازنده‌های گرافیکی اخیر NVIDIA و Cloud TPU را افزایش می‌دهد. پردازنده‌های گرافیکی NVIDIA از ترکیبی از float16 و float32 پشتیبانی می‌کنند، در حالی که TPU‌ها از ترکیبی از bfloat16 و float32 پشتیبانی می‌کنند.

در میان پردازنده‌های گرافیکی NVIDIA، آنهایی که دارای قابلیت محاسباتی 7.0 یا بالاتر هستند، بیشترین بهره را از دقت ترکیبی خواهند داشت، زیرا دارای واحدهای سخت‌افزاری ویژه به نام هسته‌های Tensor هستند که ضرب و کانولوشن ماتریس float16 را تسریع می‌کنند. پردازنده‌های گرافیکی قدیمی‌تر هیچ مزیتی برای عملکرد ریاضی برای استفاده از دقت مختلط ارائه نمی‌دهند، با این حال صرفه‌جویی در حافظه و پهنای باند می‌تواند برخی از سرعت‌ها را فعال کند. می‌توانید قابلیت محاسباتی برای GPU خود را در صفحه وب CUDA GPU NVIDIA جستجو کنید. نمونه‌هایی از پردازنده‌های گرافیکی که بیشترین بهره را از دقت ترکیبی می‌برند، شامل پردازنده‌های گرافیکی RTX، V100 و A100 می‌شوند.

با موارد زیر می توانید نوع GPU خود را بررسی کنید. این فرمان تنها در صورتی وجود دارد که درایورهای NVIDIA نصب شده باشند، بنابراین در غیر این صورت خطای زیر ایجاد می شود.

nvidia-smi -L
GPU 0: Tesla V100-SXM2-16GB (UUID: GPU-99e10c4d-de77-42ee-4524-6c41c4e5e47d)

تمام TPU های ابری از bfloat16 پشتیبانی می کنند.

حتی در CPUها و GPUهای قدیمی‌تر، جایی که انتظار افزایش سرعت وجود ندارد، APIهای دقیق ترکیبی همچنان می‌توانند برای آزمایش واحد، اشکال‌زدایی یا فقط برای آزمایش API استفاده شوند. با این حال، در CPU ها، دقت ترکیبی به طور قابل توجهی کندتر خواهد بود.

تنظیم خط مشی dtype

برای استفاده از دقت ترکیبی در Keras، باید یک tf.keras.mixed_precision.Policy ایجاد کنید، که معمولا به عنوان یک خط مشی dtype نامیده می شود . سیاست‌های Dtype لایه‌های dtypes را مشخص می‌کند. در این راهنما، شما یک خط‌مشی از رشته 'mixed_float16' و آن را به‌عنوان خط‌مشی جهانی تنظیم می‌کنید. این باعث می شود که لایه های ایجاد شده بعدی از دقت ترکیبی با ترکیبی از float16 و float32 استفاده کنند.

policy = mixed_precision.Policy('mixed_float16')
mixed_precision.set_global_policy(policy)
INFO:tensorflow:Mixed precision compatibility check (mixed_float16): OK
Your GPU will likely run quickly with dtype policy mixed_float16 as it has compute capability of at least 7.0. Your GPU: Tesla V100-SXM2-16GB, compute capability 7.0

به طور خلاصه، می‌توانید مستقیماً یک رشته را به set_global_policy ، که معمولاً در عمل انجام می‌شود.

# Equivalent to the two lines above
mixed_precision.set_global_policy('mixed_float16')

این خط مشی دو جنبه مهم یک لایه را مشخص می کند: dtype محاسبات لایه در آن انجام می شود و dtype متغیرهای یک لایه. در بالا، شما یک خط مشی mixed_float16 ایجاد کردید (یعنی یک خط مشی mixed_precision.Policy . ایجاد شده با ارسال رشته 'mixed_float16' به سازنده آن). با این خط مشی، لایه ها از محاسبات float16 و متغیرهای float32 استفاده می کنند. محاسبات در float16 برای عملکرد انجام می شود، اما متغیرها باید در float32 برای ثبات عددی نگهداری شوند. شما می توانید مستقیماً این ویژگی های خط مشی را پرس و جو کنید.

print('Compute dtype: %s' % policy.compute_dtype)
print('Variable dtype: %s' % policy.variable_dtype)
Compute dtype: float16
Variable dtype: float32

همانطور که قبلا ذکر شد، خط مشی mixed_float16 عملکرد پردازنده های گرافیکی NVIDIA با قابلیت محاسبه حداقل 7.0 را به میزان قابل توجهی بهبود می بخشد. این خط‌مشی روی دیگر GPUها و CPUها اجرا می‌شود اما ممکن است عملکرد را بهبود نبخشد. برای TPU ها، به جای آن باید از خط مشی mixed_bfloat16 استفاده شود.

ساخت مدل

بعد، بیایید شروع به ساخت یک مدل ساده کنیم. مدل‌های اسباب‌بازی بسیار کوچک معمولاً از دقت ترکیبی بهره نمی‌برند، زیرا سربار ناشی از زمان اجرا TensorFlow معمولاً بر زمان اجرا غالب است و هر گونه بهبود عملکرد در GPU را ناچیز می‌سازد. بنابراین، در صورت استفاده از GPU، اجازه دهید دو لایه بزرگ Dense با هر کدام 4096 واحد بسازیم.

inputs = keras.Input(shape=(784,), name='digits')
if tf.config.list_physical_devices('GPU'):
  print('The model will run with 4096 units on a GPU')
  num_units = 4096
else:
  # Use fewer units on CPUs so the model finishes in a reasonable amount of time
  print('The model will run with 64 units on a CPU')
  num_units = 64
dense1 = layers.Dense(num_units, activation='relu', name='dense_1')
x = dense1(inputs)
dense2 = layers.Dense(num_units, activation='relu', name='dense_2')
x = dense2(x)
The model will run with 4096 units on a GPU

هر لایه دارای یک خط مشی است و به طور پیش فرض از سیاست جهانی استفاده می کند. بنابراین، هر یک از لایه‌های Dense دارای خط مشی mixed_float16 ، زیرا قبلاً سیاست جهانی را روی mixed_float16 کرده‌اید. این باعث می شود که لایه های متراکم محاسبات float16 را انجام دهند و دارای متغیرهای float32 باشند. آنها برای انجام محاسبات float16 ورودی های خود را به float16 می ریزند که در نتیجه خروجی های آنها float16 می شود. متغیرهای آن‌ها float32 هستند و زمانی که لایه‌ها فراخوانی شوند برای جلوگیری از خطاهای ناشی از عدم تطابق dtype به float16 فرستاده می‌شوند.

print(dense1.dtype_policy)
print('x.dtype: %s' % x.dtype.name)
# 'kernel' is dense1's variable
print('dense1.kernel.dtype: %s' % dense1.kernel.dtype.name)
<Policy "mixed_float16">
x.dtype: float16
dense1.kernel.dtype: float32

بعد، پیش بینی های خروجی را ایجاد کنید. به طور معمول، شما می توانید پیش بینی های خروجی را به صورت زیر ایجاد کنید، اما این همیشه از نظر عددی با float16 پایدار نیست.

# INCORRECT: softmax and model output will be float16, when it should be float32
outputs = layers.Dense(10, activation='softmax', name='predictions')(x)
print('Outputs dtype: %s' % outputs.dtype.name)
Outputs dtype: float16

یک فعال سازی softmax در انتهای مدل باید float32 باشد. از آنجایی که خط مشی mixed_float16 است، فعال‌سازی softmax معمولاً دارای تانسورهای dtype float16 و خروجی float16 است.

با جدا کردن لایه‌های Dense و softmax و با ارسال dtype='float32' به لایه softmax می‌توان این مشکل را برطرف کرد:

# CORRECT: softmax and model output are float32
x = layers.Dense(10, name='dense_logits')(x)
outputs = layers.Activation('softmax', dtype='float32', name='predictions')(x)
print('Outputs dtype: %s' % outputs.dtype.name)
Outputs dtype: float32

dtype='float32' به سازنده لایه softmax، خط مشی dtype لایه را لغو می کند تا خط مشی float32 باشد که محاسبات را انجام می دهد و متغیرها را در float32 نگه می دارد. به طور معادل، شما می توانستید به جای آن dtype=mixed_precision.Policy('float32') ; لایه ها همیشه آرگومان dtype را به یک خط مشی تبدیل می کنند. از آنجایی که لایه Activation هیچ متغیری ندارد، متغیر dtype خط مشی نادیده گرفته می شود، اما dtype محاسبه شده خط مشی float32 باعث می شود softmax و خروجی مدل float32 شود.

افزودن سافت مکس float16 در وسط یک مدل خوب است، اما یک سافت مکس در انتهای مدل باید در float32 باشد. دلیل آن این است که اگر تانسور میانی که از Softmax به افت جریان می یابد float16 یا bfloat16 باشد، ممکن است مسائل عددی رخ دهد.

اگر فکر می‌کنید که با محاسبات float16 از نظر عددی پایدار نیست، می‌توانید dtype هر لایه را با عبور دادن dtype='float32' تا float32 باشد. اما معمولاً، این فقط در آخرین لایه مدل ضروری است، زیرا اکثر لایه‌ها دقت کافی با mixed_float16 و mixed_bfloat16 .

حتی اگر مدل به softmax ختم نشود، خروجی ها باید همچنان float32 باشند. در حالی که برای این مدل خاص غیر ضروری است، خروجی های مدل را می توان با موارد زیر به float32 ریخت:

# The linear activation is an identity function. So this simply casts 'outputs'
# to float32. In this particular case, 'outputs' is already float32 so this is a
# no-op.
outputs = layers.Activation('linear', dtype='float32')(outputs)

سپس مدل را تکمیل و کامپایل کنید و داده های ورودی تولید کنید:

model = keras.Model(inputs=inputs, outputs=outputs)
model.compile(loss='sparse_categorical_crossentropy',
              optimizer=keras.optimizers.RMSprop(),
              metrics=['accuracy'])

(x_train, y_train), (x_test, y_test) = keras.datasets.mnist.load_data()
x_train = x_train.reshape(60000, 784).astype('float32') / 255
x_test = x_test.reshape(10000, 784).astype('float32') / 255

این مثال داده های ورودی را از int8 به float32 فرستاد. شما به float16 کست نمی کنید زیرا تقسیم بر 255 روی CPU است، که عملیات float16 را کندتر از عملیات float32 اجرا می کند. در این مورد، تفاوت عملکرد ناچیز است، اما به طور کلی باید ریاضی پردازش ورودی را در float32 اجرا کنید اگر روی CPU اجرا شود. لایه اول مدل، ورودی‌ها را به float16 می‌فرستد، زیرا هر لایه ورودی‌های ممیز شناور را به نوع d محاسبه می‌کند.

وزن های اولیه مدل بازیابی می شوند. این امکان تمرین مجدد از ابتدا را با بارگذاری وزنه ها فراهم می کند.

initial_weights = model.get_weights()

آموزش مدل با Model.fit

بعد، مدل را آموزش دهید:

history = model.fit(x_train, y_train,
                    batch_size=8192,
                    epochs=5,
                    validation_split=0.2)
test_scores = model.evaluate(x_test, y_test, verbose=2)
print('Test loss:', test_scores[0])
print('Test accuracy:', test_scores[1])
Epoch 1/5
6/6 [==============================] - 2s 78ms/step - loss: 4.9609 - accuracy: 0.4132 - val_loss: 0.6643 - val_accuracy: 0.8437
Epoch 2/5
6/6 [==============================] - 0s 34ms/step - loss: 0.7752 - accuracy: 0.7789 - val_loss: 0.3098 - val_accuracy: 0.9175
Epoch 3/5
6/6 [==============================] - 0s 34ms/step - loss: 0.3620 - accuracy: 0.8848 - val_loss: 0.3149 - val_accuracy: 0.8969
Epoch 4/5
6/6 [==============================] - 0s 34ms/step - loss: 0.2998 - accuracy: 0.9066 - val_loss: 0.2988 - val_accuracy: 0.9068
Epoch 5/5
6/6 [==============================] - 0s 33ms/step - loss: 0.2298 - accuracy: 0.9285 - val_loss: 0.5062 - val_accuracy: 0.8414
313/313 - 0s - loss: 0.5163 - accuracy: 0.8392
Test loss: 0.5163048505783081
Test accuracy: 0.8392000198364258

توجه داشته باشید که مدل زمان هر مرحله را در گزارش ها چاپ می کند: به عنوان مثال، "25ms/step". ممکن است دوره اول کندتر باشد زیرا TensorFlow مدتی را صرف بهینه سازی مدل می کند، اما پس از آن زمان هر مرحله باید تثبیت شود.

اگر این راهنما را در Colab اجرا می کنید، می توانید عملکرد دقت ترکیبی را با float32 مقایسه کنید. برای انجام این کار، سیاست را از mixed_float16 به float32 در بخش "تنظیم خط مشی dtype" تغییر دهید، سپس تمام سلول ها را تا این مرحله دوباره اجرا کنید. در پردازنده‌های گرافیکی با قابلیت محاسباتی 7.X، باید شاهد افزایش قابل‌توجه زمان در هر مرحله باشید که نشان‌دهنده افزایش دقت ترکیبی مدل است. مطمئن شوید که خط مشی را به mixed_float16 و قبل از ادامه راهنما، سلول‌ها را دوباره اجرا کنید.

در پردازنده‌های گرافیکی با قابلیت محاسباتی حداقل 8.0 (GPUهای آمپر و بالاتر)، احتمالاً هنگام استفاده از دقت ترکیبی در مقایسه با float32، هیچ بهبود عملکردی در مدل اسباب‌بازی در این راهنما مشاهده نخواهید کرد. این به دلیل استفاده از TensorFloat-32 است که به طور خودکار از ریاضیات با دقت پایین تری در برخی عملیات های float32 مانند tf.linalg.matmul استفاده می کند. TensorFloat-32 برخی از مزایای عملکرد دقت مخلوط را هنگام استفاده از float32 ارائه می دهد. با این حال، در مدل‌های دنیای واقعی، به دلیل صرفه‌جویی در پهنای باند حافظه و عملیات‌هایی که TensorFloat-32 از آن‌ها پشتیبانی نمی‌کند، معمولاً شاهد بهبود عملکرد قابل توجهی از دقت ترکیبی خواهید بود.

اگر دقت ترکیبی را بر روی یک TPU اجرا کنید، در مقایسه با اجرای دقیق ترکیبی روی پردازنده‌های گرافیکی، به‌ویژه پردازنده‌های گرافیکی قبل از آمپر، افزایش عملکرد چندانی نخواهید داشت. این به این دلیل است که TPU ها عملیات خاصی را در bfloat16 در زیر هود انجام می دهند حتی با سیاست پیش فرض dtype float32. این شبیه به نحوه استفاده پردازنده های گرافیکی Ampere از TensorFloat-32 به طور پیش فرض است. در مقایسه با پردازنده‌های گرافیکی Ampere، TPUها معمولاً با دقت ترکیبی در مدل‌های واقعی، عملکرد کمتری دارند.

برای بسیاری از مدل‌های دنیای واقعی، دقت ترکیبی همچنین به شما امکان می‌دهد تا اندازه دسته‌ای را بدون تمام شدن حافظه دو برابر کنید، زیرا تانسورهای float16 نیمی از حافظه را می‌گیرند. اما این در مورد این مدل اسباب‌بازی صدق نمی‌کند، زیرا احتمالاً می‌توانید مدل را در هر نوع d اجرا کنید که در آن هر دسته شامل کل مجموعه داده MNIST از 60000 تصویر باشد.

جرم گیری از دست دادن

مقیاس گذاری ضرر تکنیکی است که tf.keras.Model.fit به طور خودکار با خط مشی mixed_float16 انجام می دهد تا از زیر جریان عددی جلوگیری کند. این بخش توضیح می‌دهد که مقیاس‌گذاری ضرر چیست و بخش بعدی نحوه استفاده از آن را با یک حلقه آموزشی سفارشی توضیح می‌دهد.

زیر آب و سرریز

نوع داده float16 دارای محدوده دینامیکی باریکی در مقایسه با float32 است. این بدان معناست که مقادیر بالای \(65504\) تا بی نهایت سرریز می شوند و مقادیر زیر \(6.0 \times 10^{-8}\) به صفر می رسند. float32 و bfloat16 دامنه دینامیکی بسیار بالاتری دارند به طوری که سرریز و زیر جریان مشکلی ندارند.

مثلا:

x = tf.constant(256, dtype='float16')
(x ** 2).numpy()  # Overflow
inf
x = tf.constant(1e-5, dtype='float16')
(x ** 2).numpy()  # Underflow
0.0

در عمل سرریز با float16 به ندرت اتفاق می افتد. علاوه بر این، جریان زیرین نیز به ندرت در طول پاس رو به جلو رخ می دهد. با این حال، در طول گذر به عقب، گرادیان ها می توانند به صفر برسند. جرم گیری از دست دادن تکنیکی برای جلوگیری از این زیرریزی است.

نمای کلی مقیاس بندی از دست دادن

مفهوم اصلی مقیاس‌بندی ضرر ساده است: به سادگی ضرر را در یک عدد بزرگ ضرب کنید، مثلاً \(1024\)، و مقدار مقیاس ضرر را دریافت می‌کنید. این باعث می‌شود که گرادیان‌ها با \(1024\) نیز مقیاس شوند، و احتمال underflow را تا حد زیادی کاهش می‌دهد. هنگامی که گرادیان های نهایی محاسبه شد، آنها را بر \(1024\) تقسیم کنید تا به مقادیر صحیح خود بازگردند.

شبه کد این فرآیند عبارت است از:

loss_scale = 1024
loss = model(inputs)
loss *= loss_scale
# Assume `grads` are float32. You do not want to divide float16 gradients.
grads = compute_gradient(loss, model.trainable_variables)
grads /= loss_scale

انتخاب مقیاس ضرر می تواند مشکل باشد. اگر مقیاس تلفات خیلی کم باشد، ممکن است شیب ها همچنان به صفر برسند. اگر خیلی زیاد باشد، مشکل برعکس رخ می دهد: گرادیان ها ممکن است تا بی نهایت سرریز شوند.

برای حل این مشکل، TensorFlow به صورت پویا مقیاس تلفات را تعیین می کند، بنابراین نیازی به انتخاب دستی ندارید. اگر از tf.keras.Model.fit استفاده می کنید، مقیاس ضرر برای شما انجام می شود بنابراین نیازی به انجام کار اضافی ندارید. اگر از یک حلقه آموزشی سفارشی استفاده می‌کنید، باید صریحاً از پوشش بهینه‌ساز ویژه tf.keras.mixed_precision.LossScaleOptimizer برای استفاده از مقیاس‌بندی ضرر استفاده کنید. این در بخش بعدی توضیح داده شده است.

آموزش مدل با یک حلقه آموزشی سفارشی

شما تاکنون با استفاده از tf.keras.Model.fit یک مدل کراس را با دقت ترکیبی آموزش داده اید. در مرحله بعد، از دقت ترکیبی با یک حلقه آموزشی سفارشی استفاده خواهید کرد. اگر قبلاً نمی دانید حلقه آموزشی سفارشی چیست، لطفاً ابتدا راهنمای آموزش سفارشی را بخوانید.

اجرای یک حلقه آموزشی سفارشی با دقت ترکیبی به دو تغییر نسبت به اجرای آن در float32 نیاز دارد:

  1. مدل را با دقت ترکیبی بسازید (شما قبلاً این کار را انجام داده اید)
  2. اگر از mixed_float16 استفاده می‌شود، صریحاً از مقیاس‌بندی ضرر استفاده کنید.

برای مرحله (2)، شما از کلاس tf.keras.mixed_precision.LossScaleOptimizer استفاده خواهید کرد که یک بهینه ساز را می پوشاند و مقیاس ضرر را اعمال می کند. به طور پیش فرض، به صورت پویا مقیاس ضرر را تعیین می کند، بنابراین مجبور نیستید یکی را انتخاب کنید. یک LossScaleOptimizer به صورت زیر بسازید.

optimizer = keras.optimizers.RMSprop()
optimizer = mixed_precision.LossScaleOptimizer(optimizer)

اگر بخواهید، می‌توانید یک مقیاس تلفات صریح را انتخاب کنید یا رفتار مقیاس‌بندی ضرر را سفارشی کنید، اما به شدت توصیه می‌شود که رفتار مقیاس‌بندی تلفات پیش‌فرض را حفظ کنید، زیرا مشخص شده است که در همه مدل‌های شناخته‌شده به خوبی کار می‌کند. اگر می‌خواهید رفتار مقیاس‌بندی ضرر را سفارشی کنید، به سند tf.keras.mixed_precision.LossScaleOptimizer مراجعه کنید.

سپس، شیء از دست دادن و tf.data.Dataset s را تعریف کنید:

loss_object = tf.keras.losses.SparseCategoricalCrossentropy()
train_dataset = (tf.data.Dataset.from_tensor_slices((x_train, y_train))
                 .shuffle(10000).batch(8192))
test_dataset = tf.data.Dataset.from_tensor_slices((x_test, y_test)).batch(8192)

سپس تابع مرحله آموزش را تعریف کنید. شما از دو روش جدید از بهینه‌ساز مقیاس ضرر برای مقیاس‌سازی ضرر و کاهش مقیاس گرادیان استفاده خواهید کرد:

  • get_scaled_loss(loss) : ضرر را در مقیاس ضرر ضرب می کند
  • get_unscaled_gradients(gradients) : فهرستی از گرادیان های مقیاس شده را به عنوان ورودی می گیرد و هر کدام را بر مقیاس از دست دادن تقسیم می کند تا مقیاس آنها را از بین ببرد.

این توابع باید به منظور جلوگیری از جریان زیر در شیب استفاده شوند. LossScaleOptimizer.apply_gradients سپس اگر هیچ یک از آنها Inf یا NaN نداشته باشند، گرادیان ها را اعمال می کند. همچنین مقیاس تلفات را به‌روزرسانی می‌کند، در صورتی که گرادیان‌ها دارای Inf یا NaN باشند، آن را به نصف کاهش می‌دهد و در غیر این صورت به طور بالقوه آن را افزایش می‌دهد.

@tf.function
def train_step(x, y):
  with tf.GradientTape() as tape:
    predictions = model(x)
    loss = loss_object(y, predictions)
    scaled_loss = optimizer.get_scaled_loss(loss)
  scaled_gradients = tape.gradient(scaled_loss, model.trainable_variables)
  gradients = optimizer.get_unscaled_gradients(scaled_gradients)
  optimizer.apply_gradients(zip(gradients, model.trainable_variables))
  return loss

LossScaleOptimizer احتمالاً از چند مرحله اول در شروع آموزش صرفنظر می کند. مقیاس ضرر از بالا شروع می شود تا بتوان مقیاس بهینه ضرر را به سرعت تعیین کرد. پس از چند مرحله، مقیاس ضرر تثبیت می شود و تعداد بسیار کمی از مراحل رد می شوند. این فرآیند به صورت خودکار اتفاق می افتد و بر کیفیت تمرین تاثیری نمی گذارد.

حالا مرحله تست را تعریف کنید:

@tf.function
def test_step(x):
  return model(x, training=False)

وزن های اولیه مدل را بارگیری کنید تا بتوانید از ابتدا دوباره آموزش دهید:

model.set_weights(initial_weights)

در نهایت حلقه آموزش سفارشی را اجرا کنید:

for epoch in range(5):
  epoch_loss_avg = tf.keras.metrics.Mean()
  test_accuracy = tf.keras.metrics.SparseCategoricalAccuracy(
      name='test_accuracy')
  for x, y in train_dataset:
    loss = train_step(x, y)
    epoch_loss_avg(loss)
  for x, y in test_dataset:
    predictions = test_step(x)
    test_accuracy.update_state(y, predictions)
  print('Epoch {}: loss={}, test accuracy={}'.format(epoch, epoch_loss_avg.result(), test_accuracy.result()))
Epoch 0: loss=4.869325160980225, test accuracy=0.7221999764442444
Epoch 1: loss=0.4893573224544525, test accuracy=0.878000020980835
Epoch 2: loss=0.36011582612991333, test accuracy=0.9440000057220459
Epoch 3: loss=0.27391332387924194, test accuracy=0.9318000078201294
Epoch 4: loss=0.247697651386261, test accuracy=0.933899998664856

نکات عملکرد GPU

در اینجا نکاتی در مورد عملکرد هنگام استفاده از دقت ترکیبی در پردازنده‌های گرافیکی آورده شده است.

حجم دسته خود را افزایش دهید

اگر کیفیت مدل را تحت تأثیر قرار نمی دهد، هنگام استفاده از دقت ترکیبی، سعی کنید با دو برابر اندازه دسته اجرا کنید. از آنجایی که تانسورهای float16 از نیمی از حافظه استفاده می‌کنند، این اغلب به شما امکان می‌دهد تا اندازه دسته خود را بدون تمام شدن حافظه دو برابر کنید. افزایش اندازه دسته به طور معمول باعث افزایش توان عملیاتی می شود، یعنی عناصر آموزشی در هر ثانیه که مدل شما می تواند روی آنها اجرا شود.

اطمینان از استفاده از هسته های تانسور GPU

همانطور که قبلا ذکر شد، پردازنده‌های گرافیکی مدرن NVIDIA از یک واحد سخت‌افزاری به نام Tensor Cores استفاده می‌کنند که می‌تواند ماتریس‌های float16 را خیلی سریع ضرب کند. با این حال، هسته‌های تانسور نیاز دارند که ابعاد خاصی از تانسورها مضرب 8 باشند. در مثال‌های زیر، یک آرگومان پررنگ است اگر و فقط اگر لازم باشد برای هسته‌های تانسور مضرب 8 باشد.

  • tf.keras.layers.Dense( units=64 )
  • tf.keras.layers.Conv2d( filters=48 ، kernel_size=7، stride=3)
    • و به طور مشابه برای سایر لایه های کانولوشن، مانند tf.keras.layers.Conv3d
  • tf.keras.layers.LSTM( units=64 )
    • و مشابه برای RNN های دیگر، مانند tf.keras.layers.GRU
  • tf.keras.Model.fit(epochs=2, batch_size=128 )

باید سعی کنید در صورت امکان از Tensor Cores استفاده کنید. اگر می‌خواهید بیشتر بدانید، راهنمای عملکرد یادگیری عمیق NVIDIA الزامات دقیق استفاده از Tensor Cores و همچنین سایر اطلاعات عملکرد مربوط به Tensor Core را شرح می‌دهد.

XLA

XLA کامپایلری است که می تواند عملکرد دقیق ترکیبی و همچنین عملکرد float32 را به میزان کمتری افزایش دهد. برای جزئیات به راهنمای XLA مراجعه کنید.

نکات عملکرد Cloud TPU

همانند پردازنده‌های گرافیکی، هنگام استفاده از Cloud TPU باید اندازه دسته خود را دو برابر کنید زیرا تانسورهای bfloat16 نیمی از حافظه را مصرف می‌کنند. دوبرابر کردن اندازه دسته ممکن است باعث افزایش توان آموزشی شود.

TPU ها برای دستیابی به عملکرد بهینه نیازی به تنظیم دقیق ترکیبی دیگر ندارند. آنها قبلاً به استفاده از XLA نیاز دارند. TPU ها از داشتن ابعاد خاصی که مضرب \(128\)هستند سود می برند، اما این به همان اندازه برای نوع float32 صدق می کند، همانطور که برای دقت ترکیبی صدق می کند. راهنمای عملکرد Cloud TPU را برای نکات کلی عملکرد TPU، که در مورد دقت ترکیبی و همچنین تانسورهای float32 اعمال می‌شود، بررسی کنید.

خلاصه

  • اگر از TPU یا GPU های NVIDIA با حداقل قابلیت محاسبه 7.0 استفاده می کنید، باید از دقت ترکیبی استفاده کنید، زیرا عملکرد را تا 3 برابر بهبود می بخشد.
  • می توانید از دقت ترکیبی با خطوط زیر استفاده کنید:

    # On TPUs, use 'mixed_bfloat16' instead
    mixed_precision.set_global_policy('mixed_float16')
    
  • اگر مدل شما به softmax ختم می شود، مطمئن شوید که float32 است. و صرف نظر از اینکه مدل شما به چه پایانی می رسد، مطمئن شوید که خروجی float32 است.

  • اگر از یک حلقه آموزشی سفارشی با mixed_float16 ، علاوه بر خطوط بالا، باید بهینه‌ساز خود را با tf.keras.mixed_precision.LossScaleOptimizer . سپس optimizer.get_scaled_loss را برای اندازه گیری از دست دادن و optimizer.get_unscaled_gradients را برای حذف مقیاس گرادیان ها فراخوانی کنید.

  • اگر دقت ارزیابی را کاهش ندهد، اندازه دسته آموزشی را دو برابر کنید

  • در پردازنده‌های گرافیکی، اطمینان حاصل کنید که بیشتر ابعاد تانسور مضربی از \(8\) تا عملکرد را به حداکثر برسانید.

برای مثال‌های بیشتر از دقت ترکیبی با استفاده از tf.keras.mixed_precision API، مخزن رسمی مدل‌ها را بررسی کنید. اکثر مدل‌های رسمی، مانند ResNet و Transformer ، با استفاده از --dtype=fp16 با دقت ترکیبی اجرا می‌شوند.