Статьи по TensorFlow | Лучшие практики для ввода данных TensorFlow

TensorFlow

"Введение«При обучении модели TensorFlow для достижения оптимальной эффективности обучения требуется эффективный процесс ввода данных, который подготавливает данные для следующего шага обучения до завершения текущего шага обучения. API tf.data может помочь нам построить этот гибкий и эффективный процесс ввода. Он содержит ряд операций преобразования данных, которые могут легко выполнять различную параллельную обработку входных данных. В этой статье эти операции преобразования будут подробно описаны.

неоптимизированный метод

Процесс обучения обычно включает следующие этапы:

  1. Откройте дескриптор файла ввода данных.

  2. Взять из файла определенную сумму (batch) Данные.

  3. Используйте извлеченные данные для обучения модели.

  4. Повторить шаги2-3пока обучение не будет завершено.

Когда процесс ввода данных не оптимизирован, затраты времени на каждую часть процесса обучения показаны на следующем рисунке:

未优化的时间开销

Видно, что в этой реализации синхронизации при получении данных из файла обучение модели находится в состоянии ожидания, а при обучении модели процесс ввода данных находится в состоянии ожидания. Общее время обучения представляет собой сумму времени, затрачиваемого каждой частью, что серьезно влияет на эффективность обучения, поэтому нам необходимо оптимизировать процесс ввода данных.

предварительная выборка данных

Операция предварительной выборки данных — это когда модель выполняет первыйsВо время пошагового обучения процесс ввода одновременно считывает первый шаг из файла.s+1Параллельная обработка обучающих данных, необходимых для шага. По сравнению с неоптимизированными методами предварительная выборка данных может сократить этапы обучения.2-3Совокупные накладные расходы времени уменьшаются до максимума между ними.

tf.data APIпри условииprefetchПреобразование для завершения операции предварительной выборки данных позволяет отделить время генерации данных от времени их потребления. Операция преобразования использует фоновый поток и внутренний буфер для предварительной выборки элементов из входного набора данных до поступления запросов данных, но нет гарантии, что предварительная выборка будет завершена.

Количество элементов данных для предварительной выборки должно быть равно (или больше) необходимому для одного шага обучения.batchразмер. Этот параметр является настраиваемым и может быть указан вручную или установлен наtf.data.experimental.AUTOTUNE, тогда количество предварительно выбранных элементов будет задано какtf.dataДинамическая настройка во время выполнения.

использоватьprefetchЗатраты времени на преобразованный процесс обучения показаны на следующем рисунке:

数据预取的时间开销

Видно, что время чтения данных и обучения перекрываются, тем самым уменьшая общие затраты времени.

Параллельное извлечение данных

В реальной учебной среде входные данные могут храниться в удаленной файловой системе, такой какHDFSсередина. Из-за некоторых различий между локальным и удаленным хранилищем процесс ввода данных, работающий локально, может работать не так, как ожидалось, при удаленном чтении данных, как показано ниже.

  1. Время чтения первого байта. Чтение первого байта файла из удаленного хранилища может занять на несколько порядков больше времени, чем чтение первого байта файла из локального хранилища, и обходится дороже.

  2. Пропускная способность при чтении данных. Хотя удаленное хранилище обычно обеспечивает большую совокупную пропускную способность, последовательное чтение одного файла может использовать лишь небольшую часть этой пропускной способности, а пропускная способность невысока.

Кроме того, когда исходные данные загружаются в память, также может потребоваться десериализация или расшифровка данных (например,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После преобразования накладные расходы времени показаны на следующем рисунке:

并行 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Функция применяется к каждой выборке данных, и хотя время ее выполнения мало, она может влиять на общую производительность синхронизации. пока вmapПрименить до конвертацииbatchСтоимость преобразованного набора данных показана на следующем рисунке:

向量化 map 的时间开销

можно увидетьmapФункция выполняется только один раз и применяется к1Кусокbatch, хотя время его выполнения будет больше, дополнительные затраты времени возникают только один раз, улучшая общую производительность времени.

Суммировать

TensorFlowПередовой опыт ввода данных включает следующие компоненты:

  1. использоватьprefetchПреобразуйте, чтобы совместить накладные расходы времени на производство и потребление данных.

  2. использоватьinterleaveПреобразование для распараллеливания чтения наборов данных.

  3. установивnum_parallel_callsпараметры для распараллеливанияmapконвертировать.

  4. использоватьcacheПреобразовать в1Кэшируйте данные в памяти или локальном хранилище во время тренировочных раундов.

  5. будет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

Меры предосторожности

  1. в настоящее время используетtf.dataПри использовании различных операций преобразования обратите внимание на порядок операций между ними, вообще говоря, меньший объем памяти означает лучший порядок преобразования.

  2. еслиmapРезультат преобразования слишком велик, чтобы поместиться в памяти.Другим компромиссом является разделение пользовательской функции обработки на две части (если ее можно разделить): одну для трудоемкой части, а другую для памяти. часть, Затем результат преобразования части, занимающей много времени, кэшируется, а результат преобразования части, потребляющей память, не кэшируется.

использованная литература

  1. Data Performance