
Ускорить скорость тренировок модели кераса со смешанной точностью в Tensorflow
13 августа 2025 г.Обзор контента
- Обзор
- Настраивать
- Поддерживаемое оборудование
- Установка политики DTYPE
- Создание модели
- Обучение модели с помощью модели.
- Масштабирование потерь
- Нижний поток и переполнение
- Обзор масштабирования потерь
- Обучение модели с помощью индивидуальной тренировочной петли
- Советы по производительности графического процессора
- Увеличение размера партии
- Обеспечение использования тензоров графического процессора используются
- Xla
- Облачные советы по производительности TPU
- Краткое содержание
Обзор
Смешанная точность-это использование 16-битных и 32-разрядных типов с плавающей точкой в модели во время обучения, чтобы она работала быстрее и использовала меньше памяти. Поддерживая определенные части модели в 32-разрядных типах для числовой стабильности, модель будет иметь более низкое время шага и обучение одинаково с точки зрения показателей оценки, таких как точность. В этом руководстве описывается, как использовать API -API -Precision Mixed Keras для ускорения ваших моделей. Использование этого API может повысить производительность более чем 3 раза на современных графических процессорах, 60% на TPU и более чем 2 раза на последних процессорах Intel.
Сегодня большинство моделей используют DTYPE Float32, который занимает 32 бита памяти. Тем не менее, существует два DTYPE с более низким характером, Float16 и BFLOAT16, каждый из которых занимает 16 бит памяти. Современные акселераторы могут выполнять операции быстрее в 16-битных DTYPE, так как они имеют специализированное оборудование для запуска 16-битных вычислений, а 16-битные DTYPE можно прочитать из памяти быстрее.
Графические процессоры NVIDIA могут выполнять операции в Float16 быстрее, чем в Float32, а TPU и поддерживающие процессоры Intel могут выполнять операции в BFLOAT16 быстрее, чем Float32. Следовательно, эти Dtypes с более низкой рецепцией следует использовать, когда это возможно на этих устройствах. Тем не менее, переменные и несколько вычислений все еще должны находиться в Float32 по числовым причинам, чтобы модель обучалась тому же качеству. API -API смешанного PERICE CERAS позволяет использовать смесь Float16 или BFLOAT16 с Float32, чтобы получить преимущества производительности от Float16/BFLOAT16 и преимуществ числовой стабильности от Float32.
Примечание:В этом руководстве термин «числовая стабильность» относится к тому, как на качество модели влияет использование DTYPE с более низким характером вместо более высокой точности DTYPE. Операция «численно нестабильна» в Float16 или BFLOAT16, если ее запуск в одном из этих DTYPE заставляет модель иметь худшую точность оценки или другие показатели по сравнению с выполнением операции в Float32.
Настраивать
import tensorflow as tf
from tensorflow import keras
from tensorflow.keras import layers
from tensorflow.keras import mixed_precision
Поддерживаемое оборудование
В то время как смешанная точность будет работать на большинстве аппаратных средств, она будет ускорить модели только на недавних графических процессорах NVIDIA, облачных TPU и недавних процессоров Intel. Поддержка GPU NVIDIA с использованием смесью Float16 и Float32, в то время как процессоры TPU и Intel поддерживают смесь BFLOAT16 и Float32.
Среди графических процессоров Nvidia те, у кого есть вычислительные возможности 7.0 или выше, будут наибольшей выгодой производительности от смешанной точности, потому что у них есть специальные аппаратные единицы, называемые ядрами тензора, для ускорения умножения матрицы Float16 и свертков. Старые графические процессоры не предлагают математической производительности для использования смешанной точности, однако экономия памяти и полосы пропускания может позволить некоторое ускорение. Вы можете найти возможность вычисления для своего графического процессора в Nvidia'sВеб -страница GPU CUDAПолем Примеры графических процессоров, которые больше всего выиграют от смешанной точности, включают RTX GPU, V100 и A100.
Среди процессоров Intel, начиная с процессоров Intel Xeon 4th Gen (кодовое имя Sapphire Rapids), будет наибольшей выгодой производительности от смешанной точности, поскольку они могут ускорить вычисления BFLOAT16 с использованием инструкций AMX (требуется TensorFlow 2.12 или более поздней версии).
Примечание:Если запустить это руководство в Google Colab, среда выполнения GPU обычно подключено к P100. P100 имеет возможность вычисления 6.0 и, как ожидается, не покажет значительного ускорения. При запуске времени выполнения процессора может быть замедление, так как время выполнения, вероятно, имеет процессор без AMX.
Вы можете проверить свой тип графического процессора со следующим. Команда существует только в том случае, если будут установлены драйверы NVIDIA, поэтому в противном случае следующая ошибка вынесет ошибку.
nvidia-smi -L
Все облачные TPU поддерживают BFLOAT16.
Даже на более старых процессорах Intel, других процессорах X86 без AMX и более старых графических процессоров, где не ожидается ускорения, смешанные API -интерцизионные API все еще могут использоваться для модульного тестирования, отладки или просто для того, чтобы попробовать API. Тем не менее, mixed_bfloat16 на процессорах без инструкций AMX и Mixed_float16 на всех процессорах x86 будут работать значительно медленнее.
Установка политики DTYPE
Чтобы использовать смешанную точность в керах, вам нужно создатьtf.keras.mixed_precision.Policy
, обычно называемый какDTYPE PolicyПолем Политики dtype указывают, что будут выполняться слои dtypes. В этом руководстве вы построите политику из строки'mixed_float16'
и установить его как глобальную политику. Впоследствии это приведет к созданию слоев для использования смешанной точности со смесью Float16 и Float32.
policy = mixed_precision.Policy('mixed_float16')
mixed_precision.set_global_policy(policy)
Вскоре, вы можете напрямую передать строку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)
Как упоминалось ранее,mixed_float16
Политика наиболее значительно повысит производительность на графических процессорах NVIDIA с вычислительными возможностями не менее 7,0. Политика будет работать на других графических процессорах и процессорах, но не может улучшить производительность. Для TPU и процессоров,mixed_bfloat16
Политика должна использоваться вместо этого.
Создание модели
Далее, давайте начнем создавать простую модель. Очень маленькие игрушечные модели, как правило, не получают выгоды от смешанной точности, потому что накладные расходы от времени выполнения TensorFlow обычно доминируют во время выполнения, что делает какое -либо улучшение производительности на графическом процессоре. Поэтому давайте построим два больших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)
Каждый уровень имеет политику и по умолчанию использует глобальную политику. Каждый изDense
Слои, следовательно, имеютmixed_float16
политика, потому что вы устанавливаете глобальную политику наmixed_float16
ранее. Это приведет к тому, что плотные слои выполняют вычисления Float16 и будут иметь переменные Float32. Они бросают свои входные данные в Float16, чтобы сделать вычисления Float16, что приводит к тому, что их выходы будут Float16 в результате. Их переменные Float32 и будут отменены в Float16, когда слои вызываются, чтобы избежать ошибок из -за несоответствий DTYPE.
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)
Далее создайте выходные прогнозы. Обычно вы можете создавать выходные прогнозы следующим образом, но это не всегда численно стабильно с 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)
Активация Softmax в конце модели должна быть Float32. Потому что политика dtypemixed_float16
Активация SoftMax обычно будет иметь тензоры Float16 вычислить DTYPE и выходные тензоры Float16.
Это может быть исправлено путем разделения плотных и софтмакс слоев и прохождения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)
Прохождениеdtype='float32'
к конструктору слоя SoftMax переопределяет политику DTYPE слоя, чтобы бытьfloat32
Политика, которая делает вычисления и сохраняет переменные в Float32. Эквивалентно, вы могли бы вместо этого пройтиdtype=mixed_precision.Policy('float32')
; Слои всегда конвертируют аргумент DTYPE в политику. Потому чтоActivation
У слоя нет переменных, переменная политики DTYPE игнорируется, но вычислительный DTYPE политики Float32 вызывает SoftMax, а вывод модели - Float32.
Добавление Float16 Softmax в середине модели хорошо, но Softmax в конце модели должен быть в Float32. Причина в том, что если промежуточный тензор, протекающий от Softmax к потере, равен Float16 или BFLOAT16, могут возникнуть числовые проблемы.
Вы можете переопределить dtype любого слоя, который будет плавать.dtype='float32'
Если вы думаете, что это не будет численно стабильным с вычислениями float16. Но, как правило, это необходимо только на последнем уровне модели, поскольку большинство слоев имеют достаточную точность с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 находится на процессоре, который выполняет операции Float16 медленнее, чем операции Float32. В этом случае разница в производительности незначительна, но в целом вы должны запустить математику для обработки ввода в Float32, если она работает на процессоре. Первый слой модели отбрасывает входы в Float16, так как каждый слой бросает входы с плавающей точкой в свой вычислительный DTYPE.
Начальные веса модели извлечены. Это позволит снова тренироваться с нуля, загрузив веса.
initial_weights = model.get_weights()
Обучение модели с помощью модели.
Далее тренируйте модель:
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])
Обратите внимание, что модель печатает время на шаг в журналах: например, «25 мс/шаг». Первая эпоха может быть медленнее, так как Tensorflow тратит некоторое время, оптимизируя модель, но впоследствии время на шаг должен стабилизироваться.
Если вы запускаете это руководство в Colab, вы можете сравнить производительность смешанной точности с Float32. Для этого измените политику сmixed_float16
кfloat32
В разделе «Установка политики DTYPE», затем повторил все ячейки до этого момента. На графических процессорах с возможностью вычислений 7.x вы должны увидеть значительное увеличение времени на шаг, что указывает на смешанную точность ускорила модель. Обязательно изменить политику наmixed_float16
и повторно затронуть клетки, прежде чем продолжить с руководством.
На графических процессорах с возможностью вычислений не менее 8,0 (графические процессоры Ampere и выше) вы, вероятно, не увидите улучшения производительности в модели игрушек в этом руководстве при использовании смешанной точности по сравнению с Float32. Это связано с использованиемTensorfloat-32, который автоматически использует более низкую точноtf.linalg.matmul
Полем Tensorfloat-32 дает некоторые преимущества производительности смешанной точности при использовании Float32. Тем не менее, в моделях реального мира вы по-прежнему будут испытывать значительные улучшения производительности из-за смешанной точности из-за экономии полосы пропускания памяти и OPS, которые Tensorfloat-32 не поддерживает.
Если вы запускаете смешанную точность на TPU, вы не увидите столько усилий производительности по сравнению с использованием смешанной точности на графических процессорах, особенно до графических процессоров. Это связано с тем, что TPU делают определенные OPS в BFLOAT16 под капотом даже с политикой DTYPE DTYPE по умолчанию Float32. Это похоже на то, как Ampere GPU используют Tensorfloat-32 по умолчанию. По сравнению с графическими процессорами AMPERE, TPU обычно видят меньше повышения производительности со смешанной точностью на реальных моделях.
Для многих реальных моделей Mixed Precision также позволяет удвоить размер партии, не испугая память, так как тензоры Float16 принимают половину памяти. Однако это не относится к этой модели игрушек, так как вы, вероятно, можете запустить модель в любом DTYPE, где каждая партия состоит из всего набора данных MNIST 60 000 изображений.
Масштабирование потерь
Масштабирование потерь - это метод, которыйtf.keras.Model.fit
автоматически работает сmixed_float16
Политика, чтобы избежать численного нижнего потока. В этом разделе описывается, что такое масштабирование потерь, и в следующем разделе описывается, как использовать его с помощью пользовательской учебной петли.
Примечание:При использованииmixed_bfloat16
Политика, нет необходимости делать масштабирование потерь.
Нижний поток и переполнение
Тип данных Float16 имеет узкий динамический диапазон по сравнению с Float32. Это означает, что значения выше будут переполнены до бесконечности, а значения ниже будут недооценены до нуля. Float32 и BFLOAT16 имеют гораздо более высокий динамический диапазон, так что переполнение и недостаточность не являются проблемой.
Например:
x = tf.constant(256, dtype='float16')
(x ** 2).numpy() # Overflow
x = tf.constant(1e-5, dtype='float16')
(x ** 2).numpy() # Underflow
На практике происходит переполнение Float16. Кроме того, нижний цвет также редко встречается во время переднего прохода. Однако во время обратного прохода градиенты могут недооцениваться до нуля. Масштабирование потерь - это метод предотвращения этого нижнего потока.
Обзор масштабирования потерь
Основная концепция масштабирования потерь проста: просто умножьте потери на какое -то большое количество, скажем, и вы получаетеШкала потерьценить. Это также приведет к масштабированию градиентов, что значительно снизит вероятность недостаточности. Как только окончательные градиенты вычисляются, разделите их, чтобы вернуть их к правильным значениям.
Псевдокод для этого процесса:
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:
- Создайте модель со смешанной точностью (вы уже сделали это)
- Явно используйте масштабирование потерь, если
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
s илиNaN
с Он также обновит шкалу потерь, вдвое и у градиентовInf
s илиNaN
S и потенциально увеличивает его иначе.
@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()))
Советы по производительности графического процессора
Вот несколько советов по производительности при использовании смешанной точности на графических процессорах.
Увеличение размера партии
Если это не влияет на качество модели, попробуйте запустить с двойным размером партии при использовании смешанной точности. Поскольку тензоры Float16 используют половину памяти, это часто позволяет удвоить размер партии, не испугая память. Увеличение размера партии обычно увеличивает обучающую пропускную способность, то есть элементы обучения в секунду, на которой ваша модель может работать.
Обеспечение использования тензоров графического процессора используются
Как упоминалось ранее, современные графические процессоры NVIDIA используют специальный аппаратный блок под названием Tensor Cores, который может очень быстро умножить матрицы Float16. Тем не менее, тензорные ядра требуют, чтобы определенные аспекты тензоров были кратными 8. В приведенных ниже примерах аргумент жирным шрифтом и только тогда, когда он должен быть кратным 8 для использования тензорных ядер.
- tf.keras.layers.dense (единицы = 64)
- tf.keras.layers.conv2d (Фильтры = 48, kernel_size = 7, stride = 3)
- Аналогично для других сверточных слоев, таких как tf.keras.layers.conv3d
- tf.keras.layers.lstm (единицы = 64)
- И аналогичный для других RNN, таких как tf.keras.layers.gru
- tf.keras.model.fit (эпохи = 2,batch_size = 128)
Вы должны попытаться использовать тензорные ядра, когда это возможно. Если вы хотите узнать больше,Руководство по производству производительности NVIDIAОписывает точные требования для использования тензоров ядер, а также другую информацию о производительности, связанная с ядро тензора.
Xla
XLA - это компилятор, который может дополнительно повысить смешанную точность, а также производительность float32 в меньшей степени. СмXla GuideДля получения подробной информации.
Облачные советы по производительности TPU
Как и в случае с графическими процессорами, вы должны попробовать удвоить размер партии при использовании облачных TPU, потому что тензоры BFLOAT16 используют половину памяти. Удвоение размера партии может увеличить пропускную способность обучения.
TPU не требуют никакой другой смешанной настройки, специфичной для точности, чтобы получить оптимальную производительность. Они уже требуют использования XLA. TPU получают выгоду от того, что определенные измерения являются кратными, но это в равной степени относится к типу Float32, как и для смешанной точности. ПроверитьРуководство по производительности Cloud TPUДля общих советов по производительности TPU, которые применяются как к смешанной точке, так и к тензорам Float32.
Краткое содержание
- Вы должны использовать смешанную точность, если вы используете TPUS, NVIDIA GPU с хотя бы вычислительной способностью 7.0 или процессорами Intel с поддержкой инструкций AMX, поскольку это улучшит производительность до 3X.
- Вы можете использовать смешанную точность со следующими линиями:
# On TPUs and CPUs, use 'mixed_bfloat16' instead
mixed_precision.set_global_policy('mixed_float16')
- Если ваша модель заканчивается в Softmax, убедитесь, что это Float32. И независимо от того, в чем заканчивается ваша модель, убедитесь, что вывод Float32.
- Если вы используете пользовательскую петлю обучения с
mixed_float16
, в дополнение к вышеуказанным линиям, вам нужно обернуть оптимизаторtf.keras.mixed_precision.LossScaleOptimizer
. Then calloptimizer.get_scaled_loss
чтобы масштабировать потерю, иoptimizer.get_unscaled_gradients
Чтобы не откровенен градиенты. - Если вы используете пользовательскую петлю обучения с
mixed_bfloat16
, Установка указанного выше Global_policy. - Удвоить размер обучения, если он не снижает точность оценки
- На графических процессорах убедитесь, что большинство тензорных размеров кратно для максимизации производительности
Для примера смешанной точности с использованиемtf.keras.mixed_precision
API, проверкафункции и классы, связанные с обучениемПолем Проверьте официальные модели, такие какТрансформатор, для деталей.
Первоначально опубликовано на
Оригинал