"Введение«При обучении модели TensorFlow для достижения оптимальной эффективности обучения требуется эффективный процесс ввода данных, который подготавливает данные для следующего шага обучения до завершения текущего шага обучения. API tf.data может помочь нам построить этот гибкий и эффективный процесс ввода. Он содержит ряд операций преобразования данных, которые могут легко выполнять различную параллельную обработку входных данных. В этой статье эти операции преобразования будут подробно описаны.
неоптимизированный метод
Процесс обучения обычно включает следующие этапы:
-
Откройте дескриптор файла ввода данных.
-
Взять из файла определенную сумму (
batch
) Данные. -
Используйте извлеченные данные для обучения модели.
-
Повторить шаги
2-3
пока обучение не будет завершено.
Когда процесс ввода данных не оптимизирован, затраты времени на каждую часть процесса обучения показаны на следующем рисунке:
Видно, что в этой реализации синхронизации при получении данных из файла обучение модели находится в состоянии ожидания, а при обучении модели процесс ввода данных находится в состоянии ожидания. Общее время обучения представляет собой сумму времени, затрачиваемого каждой частью, что серьезно влияет на эффективность обучения, поэтому нам необходимо оптимизировать процесс ввода данных.
предварительная выборка данных
Операция предварительной выборки данных — это когда модель выполняет первыйs
Во время пошагового обучения процесс ввода одновременно считывает первый шаг из файла.s+1
Параллельная обработка обучающих данных, необходимых для шага. По сравнению с неоптимизированными методами предварительная выборка данных может сократить этапы обучения.2-3
Совокупные накладные расходы времени уменьшаются до максимума между ними.
tf.data API
при условииprefetch
Преобразование для завершения операции предварительной выборки данных позволяет отделить время генерации данных от времени их потребления. Операция преобразования использует фоновый поток и внутренний буфер для предварительной выборки элементов из входного набора данных до поступления запросов данных, но нет гарантии, что предварительная выборка будет завершена.
Количество элементов данных для предварительной выборки должно быть равно (или больше) необходимому для одного шага обучения.batch
размер. Этот параметр является настраиваемым и может быть указан вручную или установлен наtf.data.experimental.AUTOTUNE
, тогда количество предварительно выбранных элементов будет задано какtf.data
Динамическая настройка во время выполнения.
использоватьprefetch
Затраты времени на преобразованный процесс обучения показаны на следующем рисунке:
Видно, что время чтения данных и обучения перекрываются, тем самым уменьшая общие затраты времени.
Параллельное извлечение данных
В реальной учебной среде входные данные могут храниться в удаленной файловой системе, такой какHDFS
середина. Из-за некоторых различий между локальным и удаленным хранилищем процесс ввода данных, работающий локально, может работать не так, как ожидалось, при удаленном чтении данных, как показано ниже.
-
Время чтения первого байта. Чтение первого байта файла из удаленного хранилища может занять на несколько порядков больше времени, чем чтение первого байта файла из локального хранилища, и обходится дороже.
-
Пропускная способность при чтении данных. Хотя удаленное хранилище обычно обеспечивает большую совокупную пропускную способность, последовательное чтение одного файла может использовать лишь небольшую часть этой пропускной способности, а пропускная способность невысока.
Кроме того, когда исходные данные загружаются в память, также может потребоваться десериализация или расшифровка данных (например,protobuf
форматированные данные), что также требует дополнительных вычислительных ресурсов. Конечно, эти накладные расходы существуют независимо от того, хранятся ли данные локально или удаленно, но если данные не эффективно предварительно извлекаются, удаленное чтение данных может сделать накладные расходы еще больше.
Чтобы смягчить влияние различных накладных расходов на извлечение данных,interleave
Преобразования можно использовать для распараллеливания загрузки данных, чтобы чередовать чтение содержимого нескольких файлов набора данных (например, чтениеTextLineDataset
наборы данных и т. д.). Среди них количество файлов, читаемых параллельно, можно определить поcycle_length
параметр для управления, указывая отcycle_length
файлы читаются с чередованием, а количество последовательно считанных выборок из каждого файла определяется выражениемblock_length
Управление параметрами, то есть чтение из файлаblock_length
После последовательных выборок чередование продолжает чтение из других файлов, а параллелизм чтения файлов определяетсяnum_parallel_calls
контроль параметров, сprefetch
Конвертировать как,interleave
Преобразование также поддерживаетсяtf.data.experimental.AUTOTUNE
настройки для делегирования используемого уровня параллелизмаtf.data
Динамически определяется во время выполнения.
interleave
Параметры преобразования по умолчанию делают его чередующимся чтением отдельных выборок из нескольких файлов данных по очереди, при этом затраты времени показаны на следующем рисунке:
можно увидетьinterleave
Образцы данных чередуются из двух наборов данных, но производительность не улучшается. И установивnum_parallel_calls
После установки параметров накладные расходы времени показаны на следующем рисунке:
Поскольку несколько файлов наборов данных могут быть загружены параллельно, время ожидания, необходимое для последовательного открытия файлов данных, сокращается, что, в свою очередь, снижает затраты времени на глобальное обучение.
Параллельное преобразование данных
При подготовке входных данных может потребоваться предварительная обработка исходных входных данных. к этому концуtf.data
при условииmap
Преобразования выполняют операции предварительной обработки данных, которые применяют определяемую пользователем функцию к каждому элементу входного набора данных. Поскольку входные элементы не зависят друг от друга, эта операция предварительной обработки можетCPU
Параллельное выполнение между ядрами.
иprefetch
иinterleave
Преобразование аналогично,map
Преобразование также обеспечиваетnum_parallel_calls
параметр для указания степени параллелизма, вы можете установить значение этого параметра самостоятельно, и он также поддерживаетtf.data.experimental.AUTOTUNE
настройки для делегирования используемого уровня параллелизмаtf.data
Динамически определяется во время выполнения.
для непревзойденногоmap
Преобразование, его накладные расходы показаны на следующем рисунке:
В настоящее время общие временные затраты на процесс обучения представляют собой сумму временных затрат и временных затрат на предварительную обработку других частей. при распараллеливанииmap
После преобразования накладные расходы времени показаны на следующем рисунке:
можно увидетьmap
Часть временных затрат перекрывается, что снижает временные затраты на глобальное обучение в целом.
кеш данных
cache
Преобразования могут кэшировать обработанный набор данных в памяти или в локальном хранилище, что позволяет избежатьepoch
Оба выполняют одни и те же операции (например, открытие файла и чтение данных). базовыйcache
Затраты времени на преобразование показаны на следующем рисунке:
можно увидеть в2
Кусокepoch
Поскольку набор данных кэшируется, экономятся затраты времени на открытие файла, чтение данных и предварительную обработку. Это потому, что вcache
Все операции над набором данных перед преобразованием будут выполняться только на первом1
Кусокepoch
выполняется, следующийepoch
будет использоваться напрямуюcache
Преобразование кэшированных данных.
еслиmap
Определяемые пользователем функции, используемые при преобразовании, требуют много времени.map
Применить после конвертацииcache
преобразование для уменьшения каждого последующегоepoch
обаmap
Накладные расходы времени на преобразование. Если определяемая пользователем функция увеличивает пространство, необходимое для хранения набора данных (сверх емкости кеша), ее можно применить после преобразования кеша.map
Преобразуйте или рассмотрите возможность предварительной обработки данных перед обучением, чтобы сократить использование ресурсов.
преобразование векторизованной карты
существуетmap
Вызов определяемой пользователем функции при преобразовании создает дополнительные накладные расходы, поэтому лучше всего векторизовать определяемую пользователем функцию (т. е. позволить ей обрабатывать пакет входных данных за раз), а затемmap
Применить до конвертацииbatch
трансформировать, такmap
преобразование будет применено к каждомуbatch
данные, а не отдельные данные.
для вmap
Применить после конвертацииbatch
Преобразованный набор данных, его временные затраты показаны на следующем рисунке:
можно увидетьmap
Функция применяется к каждой выборке данных, и хотя время ее выполнения мало, она может влиять на общую производительность синхронизации. пока вmap
Применить до конвертацииbatch
Стоимость преобразованного набора данных показана на следующем рисунке:
можно увидетьmap
Функция выполняется только один раз и применяется к1
Кусокbatch
, хотя время его выполнения будет больше, дополнительные затраты времени возникают только один раз, улучшая общую производительность времени.
Суммировать
TensorFlow
Передовой опыт ввода данных включает следующие компоненты:
-
использовать
prefetch
Преобразуйте, чтобы совместить накладные расходы времени на производство и потребление данных. -
использовать
interleave
Преобразование для распараллеливания чтения наборов данных. -
установив
num_parallel_calls
параметры для распараллеливанияmap
конвертировать. -
использовать
cache
Преобразовать в1
Кэшируйте данные в памяти или локальном хранилище во время тренировочных раундов. -
будет
map
Преобразованная векторизация пользовательской функции.
Код
Основываясь на приведенных выше рекомендациях, в этом разделе используетсяtf.data API
Что нужно сделатьTensorFlow
Построение входных данных. Конкретный код реализации выглядит следующим образом:
def make_dataset(input_pattern, shuffle_size, batch_size):
# map 解析函数,注意这里的向量化操作
def labeler(record):
fields = tf.io.decode_csv(
record,
record_defaults=['0'] * 32,
field_delim='\t',
)
data = tf.strings.to_number(fields[1:32], out_type=tf.int32)
label = tf.strings.to_number(fields[:1], out_type=tf.int32)
data = tf.transpose(data)
label = tf.transpose(label)
return data, label
filenames = tf.data.Dataset.list_files(input_pattern)
dataset = filenames.interleave(
lambda filename: tf.data.TextLineDataset(filename),
cycle_length=tf.data.experimental.AUTOTUNE,
num_parallel_calls=tf.data.experimental.AUTOTUNE,
)
dataset = dataset.repeat().shuffle(shuffle_size).batch(batch_size)
dataset = dataset.map(
lambda ex: labeler(ex),
num_parallel_calls=tf.data.experimental.AUTOTUNE,
).cache()
dataset = dataset.prefetch(buffer_size=tf.data.experimental.AUTOTUNE)
return dataset
Меры предосторожности
-
в настоящее время использует
tf.data
При использовании различных операций преобразования обратите внимание на порядок операций между ними, вообще говоря, меньший объем памяти означает лучший порядок преобразования. -
если
map
Результат преобразования слишком велик, чтобы поместиться в памяти.Другим компромиссом является разделение пользовательской функции обработки на две части (если ее можно разделить): одну для трудоемкой части, а другую для памяти. часть, Затем результат преобразования части, занимающей много времени, кэшируется, а результат преобразования части, потребляющей память, не кэшируется.