
Пользовательские петли обучения тензорфлоу
1 августа 2025 г.Обзор контента
- Используйте tf.distribute.strategy с пользовательскими петлями обучения
- Что сейчас поддерживается?
- Примеры и учебные пособия
- Другие темы
- Настройка переменной среды TF_CONFIG
- Что дальше?
Используйте tf.distribute.strategy с пользовательскими петлями обучения
Как показано выше, используяtf.distribute.Strategy
с керамиModel.fit
Требуется изменение только пару строк вашего кода. С немного большим усилием вы также можете использоватьtf.distribute.Strategy
с индивидуальными петлями обучения.
Если вам нужно больше гибкости и контроля над вашими петлями обучения, чем возможно с оценщикой или керами, вы можете написать пользовательские петли обучения. Например, при использовании GAN вы можете предпринять различное количество шагов генератора или дискриминатора каждый раунд. Точно так же рамки высокого уровня не очень подходят для обучения подкреплению.
Аtf.distribute.Strategy
Классы предоставляют основной набор методов для поддержки пользовательских петлей обучения. Использование их может потребовать незначительной реструктуризации кода изначально, но как только это будет сделано, вы сможете переключаться между графическими процессорами, TPU и несколькими машинами, просто изменяя экземпляр стратегии.
Ниже приведен краткий фрагмент, иллюстрирующий этот вариант использования для простого примера обучения с использованием той же модели керас, что и раньше.
Во -первых, создайте модель и оптимизатор внутри масштаба стратегии. Это гарантирует, что любые переменные, созданные с помощью модели и оптимизатора, являются зеркальными переменными.
with mirrored_strategy.scope():
model = tf.keras.Sequential([
tf.keras.layers.Dense(1, input_shape=(1,),
kernel_regularizer=tf.keras.regularizers.L2(1e-4))])
optimizer = tf.keras.optimizers.SGD()
Далее создайте набор данных ввода и вызовtf.distribute.Strategy.experimental_distribute_dataset
Распределить набор данных на основе стратегии.
dataset = tf.data.Dataset.from_tensors(([1.], [1.])).repeat(1000).batch(
global_batch_size)
dist_dataset = mirrored_strategy.experimental_distribute_dataset(dataset)
Затем определите один шаг обучения. Использоватьtf.GradientTape
Чтобы вычислить градиенты и оптимизатор для применения этих градиентов для обновления переменных вашей модели. Чтобы распределить этот шаг обучения, поместите его в функциюtrain_step
и передать этоtf.distribute.Strategy.run
вместе с входами набора данных, которые вы получили отdist_dataset
Создано ранее:
# Sets `reduction=NONE` to leave it to tf.nn.compute_average_loss() below.
loss_object = tf.keras.losses.BinaryCrossentropy(
from_logits=True,
reduction=tf.keras.losses.Reduction.NONE)
def train_step(inputs):
features, labels = inputs
with tf.GradientTape() as tape:
predictions = model(features, training=True)
per_example_loss = loss_object(labels, predictions)
loss = tf.nn.compute_average_loss(per_example_loss)
model_losses = model.losses
if model_losses:
loss += tf.nn.scale_regularization_loss(tf.add_n(model_losses))
gradients = tape.gradient(loss, model.trainable_variables)
optimizer.apply_gradients(zip(gradients, model.trainable_variables))
return loss
@tf.function
def distributed_train_step(dist_inputs):
per_replica_losses = mirrored_strategy.run(train_step, args=(dist_inputs,))
return mirrored_strategy.reduce(tf.distribute.ReduceOp.SUM, per_replica_losses,
axis=None)
Несколько других вещей, которые следует отметить в коде выше:
Вы использовали
tf.nn.compute_average_loss
Чтобы уменьшить потери прогнозирования в первом доме на скаляр.tf.nn.compute_average_loss
суммирует потерю за пример и делит сумму на глобальный размер партии. Это важно, потому что позже, после того как градиенты рассчитываются на каждой копии, они агрегируются по репликасуммированиеих.По умолчанию, глобальный размер партии принимается как
tf.get_strategy().num_replicas_in_sync * tf.shape(per_example_loss)[0]
Полем Это также может быть указано явно как аргумент ключевого словаglobal_batch_size=
Полем Без коротких партий по умолчанию эквивалентноtf.nn.compute_average_loss(..., global_batch_size=global_batch_size)
сglobal_batch_size
определено выше. (Для получения дополнительной информации о коротких партиях и о том, как избежать или обработать их, увидетьУчебное пособие по индивидуальному обучению.)Вы использовали
tf.nn.scale_regularization_loss
чтобы масштабировать потери регуляризации, зарегистрированные вModel
объект, если таковой имеется, по1/num_replicas_in_sync
также. Для тех потерь регуляризации, которые зависят от ввода, он падает на код моделирования, а не на пользовательскую петлю обучения, чтобы выполнить усреднение по размеру партии (!) (!); Таким образом, код моделирования может оставаться агностиком репликации, в то время как учебный цикл остается агностиком в том, как вычисляются потери регуляризации.Когда вы звоните
apply_gradients
В рамках стратегии распределения его поведение изменяется. В частности, перед применением градиентов на каждом параллельном экземпляре во время синхронной тренировки он выполняет сумму-все-повторные градиенты.Вы также использовали
tf.distribute.Strategy.reduce
API для объединения результатов, возвращенныхtf.distribute.Strategy.run
для отчетности.tf.distribute.Strategy.run
Возвращает результаты из каждой локальной копии в стратегии, и есть несколько способов потребления этого результата. Ты можешьreduce
их, чтобы получить агрегированную ценность. Вы также можете сделатьtf.distribute.Strategy.experimental_local_results
Чтобы получить список значений, содержащихся в результате, по одному на локальную копию.
Наконец, как только вы определите шаг обучения, вы можете перевернутьdist_dataset
и запустить обучение в цикле:
for dist_inputs in dist_dataset:
print(distributed_train_step(dist_inputs))
tf.Tensor(0.9024367, shape=(), dtype=float32)
tf.Tensor(0.8953863, shape=(), dtype=float32)
tf.Tensor(0.8884038, shape=(), dtype=float32)
tf.Tensor(0.88148874, shape=(), dtype=float32)
tf.Tensor(0.87464076, shape=(), dtype=float32)
tf.Tensor(0.86785895, shape=(), dtype=float32)
tf.Tensor(0.86114323, shape=(), dtype=float32)
tf.Tensor(0.8544927, shape=(), dtype=float32)
tf.Tensor(0.84790725, shape=(), dtype=float32)
tf.Tensor(0.841386, shape=(), dtype=float32)
tf.Tensor(0.83492863, shape=(), dtype=float32)
tf.Tensor(0.8285344, shape=(), dtype=float32)
tf.Tensor(0.82220304, shape=(), dtype=float32)
tf.Tensor(0.8159339, shape=(), dtype=float32)
tf.Tensor(0.8097264, shape=(), dtype=float32)
tf.Tensor(0.8035801, shape=(), dtype=float32)
tf.Tensor(0.79749453, shape=(), dtype=float32)
tf.Tensor(0.79146886, shape=(), dtype=float32)
tf.Tensor(0.785503, shape=(), dtype=float32)
tf.Tensor(0.779596, shape=(), dtype=float32)
tf.Tensor(0.77374756, shape=(), dtype=float32)
tf.Tensor(0.7679571, shape=(), dtype=float32)
tf.Tensor(0.7622242, shape=(), dtype=float32)
tf.Tensor(0.7565481, shape=(), dtype=float32)
tf.Tensor(0.75092846, shape=(), dtype=float32)
tf.Tensor(0.7453647, shape=(), dtype=float32)
tf.Tensor(0.73985624, shape=(), dtype=float32)
tf.Tensor(0.7344028, shape=(), dtype=float32)
tf.Tensor(0.7290035, shape=(), dtype=float32)
tf.Tensor(0.723658, shape=(), dtype=float32)
tf.Tensor(0.7183659, shape=(), dtype=float32)
tf.Tensor(0.71312654, shape=(), dtype=float32)
tf.Tensor(0.7079393, shape=(), dtype=float32)
tf.Tensor(0.70280397, shape=(), dtype=float32)
tf.Tensor(0.6977197, shape=(), dtype=float32)
tf.Tensor(0.69268626, shape=(), dtype=float32)
tf.Tensor(0.687703, shape=(), dtype=float32)
tf.Tensor(0.68276954, shape=(), dtype=float32)
tf.Tensor(0.67788523, shape=(), dtype=float32)
tf.Tensor(0.6730496, shape=(), dtype=float32)
tf.Tensor(0.66826224, shape=(), dtype=float32)
tf.Tensor(0.66352266, shape=(), dtype=float32)
tf.Tensor(0.6588302, shape=(), dtype=float32)
tf.Tensor(0.6541846, shape=(), dtype=float32)
tf.Tensor(0.6495853, shape=(), dtype=float32)
tf.Tensor(0.64503175, shape=(), dtype=float32)
tf.Tensor(0.6405235, shape=(), dtype=float32)
tf.Tensor(0.6360602, shape=(), dtype=float32)
tf.Tensor(0.6316412, shape=(), dtype=float32)
tf.Tensor(0.62726617, shape=(), dtype=float32)
tf.Tensor(0.6229345, shape=(), dtype=float32)
tf.Tensor(0.61864597, shape=(), dtype=float32)
tf.Tensor(0.6143999, shape=(), dtype=float32)
tf.Tensor(0.6101959, shape=(), dtype=float32)
tf.Tensor(0.60603356, shape=(), dtype=float32)
tf.Tensor(0.60191244, shape=(), dtype=float32)
tf.Tensor(0.597832, shape=(), dtype=float32)
tf.Tensor(0.5937919, shape=(), dtype=float32)
tf.Tensor(0.5897917, shape=(), dtype=float32)
tf.Tensor(0.585831, shape=(), dtype=float32)
tf.Tensor(0.58190924, shape=(), dtype=float32)
tf.Tensor(0.5780261, shape=(), dtype=float32)
tf.Tensor(0.57418114, shape=(), dtype=float32)
tf.Tensor(0.57037395, shape=(), dtype=float32)
tf.Tensor(0.5666041, shape=(), dtype=float32)
tf.Tensor(0.56287116, shape=(), dtype=float32)
tf.Tensor(0.55917484, shape=(), dtype=float32)
tf.Tensor(0.5555145, shape=(), dtype=float32)
tf.Tensor(0.55189, shape=(), dtype=float32)
tf.Tensor(0.54830086, shape=(), dtype=float32)
tf.Tensor(0.54474664, shape=(), dtype=float32)
tf.Tensor(0.54122704, shape=(), dtype=float32)
tf.Tensor(0.5377416, shape=(), dtype=float32)
tf.Tensor(0.5342899, shape=(), dtype=float32)
tf.Tensor(0.5308717, shape=(), dtype=float32)
tf.Tensor(0.5274865, shape=(), dtype=float32)
tf.Tensor(0.52413404, shape=(), dtype=float32)
tf.Tensor(0.52081394, shape=(), dtype=float32)
tf.Tensor(0.51752573, shape=(), dtype=float32)
tf.Tensor(0.5142692, shape=(), dtype=float32)
tf.Tensor(0.51104385, shape=(), dtype=float32)
tf.Tensor(0.50784945, shape=(), dtype=float32)
tf.Tensor(0.50468564, shape=(), dtype=float32)
tf.Tensor(0.50155205, shape=(), dtype=float32)
tf.Tensor(0.49844825, shape=(), dtype=float32)
tf.Tensor(0.4953741, shape=(), dtype=float32)
tf.Tensor(0.49232918, shape=(), dtype=float32)
tf.Tensor(0.4893132, shape=(), dtype=float32)
tf.Tensor(0.48632562, shape=(), dtype=float32)
tf.Tensor(0.4833664, shape=(), dtype=float32)
tf.Tensor(0.4804351, shape=(), dtype=float32)
tf.Tensor(0.47753143, shape=(), dtype=float32)
tf.Tensor(0.47465506, shape=(), dtype=float32)
tf.Tensor(0.47180572, shape=(), dtype=float32)
tf.Tensor(0.46898302, shape=(), dtype=float32)
tf.Tensor(0.4661867, shape=(), dtype=float32)
tf.Tensor(0.46341658, shape=(), dtype=float32)
tf.Tensor(0.4606722, shape=(), dtype=float32)
tf.Tensor(0.4579534, shape=(), dtype=float32)
tf.Tensor(0.4552598, shape=(), dtype=float32)
tf.Tensor(0.45259115, shape=(), dtype=float32)
tf.Tensor(0.44994718, shape=(), dtype=float32)
tf.Tensor(0.44732755, shape=(), dtype=float32)
tf.Tensor(0.44473216, shape=(), dtype=float32)
tf.Tensor(0.44216052, shape=(), dtype=float32)
tf.Tensor(0.4396125, shape=(), dtype=float32)
tf.Tensor(0.43708783, shape=(), dtype=float32)
tf.Tensor(0.4345862, shape=(), dtype=float32)
tf.Tensor(0.4321074, shape=(), dtype=float32)
tf.Tensor(0.42965108, shape=(), dtype=float32)
tf.Tensor(0.4272171, shape=(), dtype=float32)
tf.Tensor(0.42480516, shape=(), dtype=float32)
tf.Tensor(0.42241505, shape=(), dtype=float32)
tf.Tensor(0.42004645, shape=(), dtype=float32)
tf.Tensor(0.41769922, shape=(), dtype=float32)
tf.Tensor(0.41537297, shape=(), dtype=float32)
tf.Tensor(0.41306767, shape=(), dtype=float32)
tf.Tensor(0.41078293, shape=(), dtype=float32)
tf.Tensor(0.4085186, shape=(), dtype=float32)
tf.Tensor(0.4062744, shape=(), dtype=float32)
tf.Tensor(0.4040502, shape=(), dtype=float32)
tf.Tensor(0.40184572, shape=(), dtype=float32)
tf.Tensor(0.39966068, shape=(), dtype=float32)
tf.Tensor(0.3974949, shape=(), dtype=float32)
tf.Tensor(0.39534825, shape=(), dtype=float32)
tf.Tensor(0.39322042, shape=(), dtype=float32)
tf.Tensor(0.39111122, shape=(), dtype=float32)
tf.Tensor(0.3890205, shape=(), dtype=float32)
tf.Tensor(0.38694802, shape=(), dtype=float32)
tf.Tensor(0.38489357, shape=(), dtype=float32)
tf.Tensor(0.38285697, shape=(), dtype=float32)
tf.Tensor(0.38083804, shape=(), dtype=float32)
tf.Tensor(0.3788365, shape=(), dtype=float32)
tf.Tensor(0.37685227, shape=(), dtype=float32)
tf.Tensor(0.3748851, shape=(), dtype=float32)
tf.Tensor(0.37293482, shape=(), dtype=float32)
tf.Tensor(0.37100127, shape=(), dtype=float32)
tf.Tensor(0.36908418, shape=(), dtype=float32)
tf.Tensor(0.36718345, shape=(), dtype=float32)
tf.Tensor(0.3652989, shape=(), dtype=float32)
tf.Tensor(0.36343032, shape=(), dtype=float32)
tf.Tensor(0.36157757, shape=(), dtype=float32)
tf.Tensor(0.35974047, shape=(), dtype=float32)
tf.Tensor(0.3579188, shape=(), dtype=float32)
tf.Tensor(0.35611248, shape=(), dtype=float32)
tf.Tensor(0.3543213, shape=(), dtype=float32)
tf.Tensor(0.35254508, shape=(), dtype=float32)
tf.Tensor(0.3507837, shape=(), dtype=float32)
tf.Tensor(0.34903696, shape=(), dtype=float32)
tf.Tensor(0.34730473, shape=(), dtype=float32)
tf.Tensor(0.3455869, shape=(), dtype=float32)
tf.Tensor(0.3438832, shape=(), dtype=float32)
tf.Tensor(0.34219357, shape=(), dtype=float32)
tf.Tensor(0.3405178, shape=(), dtype=float32)
tf.Tensor(0.3388558, shape=(), dtype=float32)
tf.Tensor(0.3372074, shape=(), dtype=float32)
tf.Tensor(0.33557245, shape=(), dtype=float32)
tf.Tensor(0.33395082, shape=(), dtype=float32)
tf.Tensor(0.33234236, shape=(), dtype=float32)
tf.Tensor(0.33074695, shape=(), dtype=float32)
tf.Tensor(0.32916442, shape=(), dtype=float32)
tf.Tensor(0.3275946, shape=(), dtype=float32)
tf.Tensor(0.3260375, shape=(), dtype=float32)
tf.Tensor(0.3244928, shape=(), dtype=float32)
tf.Tensor(0.3229605, shape=(), dtype=float32)
tf.Tensor(0.32144046, shape=(), dtype=float32)
tf.Tensor(0.31993246, shape=(), dtype=float32)
tf.Tensor(0.3184365, shape=(), dtype=float32)
tf.Tensor(0.31695238, shape=(), dtype=float32)
tf.Tensor(0.31548, shape=(), dtype=float32)
tf.Tensor(0.31401917, shape=(), dtype=float32)
tf.Tensor(0.3125699, shape=(), dtype=float32)
tf.Tensor(0.31113195, shape=(), dtype=float32)
tf.Tensor(0.30970532, shape=(), dtype=float32)
tf.Tensor(0.3082898, shape=(), dtype=float32)
tf.Tensor(0.30688527, shape=(), dtype=float32)
tf.Tensor(0.3054917, shape=(), dtype=float32)
tf.Tensor(0.30410892, shape=(), dtype=float32)
tf.Tensor(0.3027368, shape=(), dtype=float32)
tf.Tensor(0.30137527, shape=(), dtype=float32)
tf.Tensor(0.3000242, shape=(), dtype=float32)
tf.Tensor(0.29868355, shape=(), dtype=float32)
tf.Tensor(0.29735315, shape=(), dtype=float32)
tf.Tensor(0.29603288, shape=(), dtype=float32)
tf.Tensor(0.29472268, shape=(), dtype=float32)
tf.Tensor(0.2934224, shape=(), dtype=float32)
tf.Tensor(0.29213202, shape=(), dtype=float32)
tf.Tensor(0.29085135, shape=(), dtype=float32)
tf.Tensor(0.28958035, shape=(), dtype=float32)
tf.Tensor(0.2883189, shape=(), dtype=float32)
tf.Tensor(0.28706694, shape=(), dtype=float32)
tf.Tensor(0.28582436, shape=(), dtype=float32)
tf.Tensor(0.28459102, shape=(), dtype=float32)
tf.Tensor(0.28336692, shape=(), dtype=float32)
tf.Tensor(0.2821518, shape=(), dtype=float32)
tf.Tensor(0.28094578, shape=(), dtype=float32)
tf.Tensor(0.27974862, shape=(), dtype=float32)
tf.Tensor(0.2785603, shape=(), dtype=float32)
tf.Tensor(0.27738073, shape=(), dtype=float32)
tf.Tensor(0.2762098, shape=(), dtype=float32)
В приведенном выше примере вы итералировали надdist_dataset
Чтобы внести свой вклад в ваше обучение. Вам также предоставленыtf.distribute.Strategy.make_experimental_numpy_dataset
Чтобы поддержать входные данные Numpy. Вы можете использовать этот API для создания набора данных перед вызовомtf.distribute.Strategy.experimental_distribute_dataset
Полем
Еще один способ итерации по вашим данным - явно использовать итераторы. Возможно, вы захотите сделать это, когда хотите запустить заданное количество шагов, а не итерация по всему набору данных. Вышеуказанная итерация теперь будет изменена, чтобы сначала создать итератор, а затем явно вызовnext
на нем, чтобы получить входные данные.
iterator = iter(dist_dataset)
for _ in range(10):
print(distributed_train_step(next(iterator)))
tf.Tensor(0.27504745, shape=(), dtype=float32)
tf.Tensor(0.2738936, shape=(), dtype=float32)
tf.Tensor(0.2727481, shape=(), dtype=float32)
tf.Tensor(0.27161098, shape=(), dtype=float32)
tf.Tensor(0.27048206, shape=(), dtype=float32)
tf.Tensor(0.26936132, shape=(), dtype=float32)
tf.Tensor(0.26824862, shape=(), dtype=float32)
tf.Tensor(0.26714393, shape=(), dtype=float32)
tf.Tensor(0.26604718, shape=(), dtype=float32)
tf.Tensor(0.26495826, shape=(), dtype=float32)
Это охватывает самый простой случай использованияtf.distribute.Strategy
API для распространения пользовательских петлей обучения.
Что сейчас поддерживается?
Обучение API |
|
|
|
|
|
---|---|---|---|---|---|
Пользовательская учебная петля | Поддерживается | Поддерживается | Поддерживается | Экспериментальная поддержка | Экспериментальная поддержка |
Примеры и учебные пособия
Вот несколько примеров использования стратегий распространения с пользовательскими петлями обучения:
- Учебник: Обучение с помощью индивидуальной тренировочной петли и
MirroredStrategy
Полем - Учебник: Обучение с помощью индивидуальной тренировочной петли и
MultiWorkerMirroredStrategy
Полем - Гид: Содержит пример индивидуальной тренировочной петли с
TPUStrategy
Полем - Учебник: Обучение сервера параметров с помощью пользовательской учебной петли и
ParameterServerStrategy
Полем - Tensorflow Model Gardenрепозиторийсодержащий коллекции современных моделей, реализованных с использованием различных стратегий.
Другие темы
Этот раздел охватывает некоторые темы, которые имеют отношение к множеству вариантов использования.
Настройка переменной среды TF_CONFIG
Для обучения с несколькими работниками, как упоминалось ранее, вам нужно настроить'TF_CONFIG'
Переменная среда для каждого бинарного запуска в вашем кластере. А'TF_CONFIG'
Переменная среда - это строка JSON, которая указывает, какие задачи представляют собой кластер, их адреса и роль каждой задачи в кластере. Аtensorflow/ecosystem
Repo предоставляет шаблон Kubernetes, который устанавливает'TF_CONFIG'
для ваших тренировочных задач.
Есть два компонента'TF_CONFIG'
: кластер и задача.
- Кластер предоставляет информацию о учебном кластере, который является диктом, состоящим из различных типов рабочих мест, таких как работники. При обучении с несколькими работниками обычно есть один работник, который берет на себя немного большую ответственность, например, сохранение контрольно-пропускного пункта и написание сводного файла для Tensorboard в дополнение к тому, что делает обычный работник. Такой работник называется «главным» работником, и обычно работник с индексом
0
назначается главным работником (на самом деле так и какtf.distribute.Strategy
реализован). - С другой стороны, задача предоставляет информацию о текущей задаче. Первый компонентный кластер одинакова для всех работников, а вторая задача компонента отличается для каждого работника и указывает тип и индекс этого работника.
Один пример'TF_CONFIG'
является:
os.environ["TF_CONFIG"] = json.dumps({
"cluster": {
"worker": ["host1:port", "host2:port", "host3:port"],
"ps": ["host4:port", "host5:port"]
},
"task": {"type": "worker", "index": 1}
})
Этот'TF_CONFIG'
указывает, что есть три работника и два"ps"
Задачи в"cluster"
вместе с их хозяевами и портами. А"task"
часть указывает роль текущей задачи в"cluster"
- Работник1
(второй работник). Допустимые роли в кластере"chief"
В"worker"
В"ps"
, и"evaluator"
Полем Там не должно быть"ps"
работа, кроме как при использованииtf.distribute.experimental.ParameterServerStrategy
Полем
Что дальше?
tf.distribute.Strategy
активно находится в стадии разработки. Попробуйте это и предоставьте ваш отзыв, используяGitHub выпускиПолем
Первоначально опубликовано на
Оригинал