Почему TensorFlow 2 намного медленнее, чем TensorFlow 1?

137

Многие пользователи указали, что это причина перехода на Pytorch, но мне еще предстоит найти оправдание / объяснение для того, чтобы пожертвовать самым важным практическим качеством, скоростью и стремлением к исполнению.

Ниже приведена производительность бенчмаркинга кода, TF1 по сравнению с TF2, где TF1 работает на 47–276% быстрее .

Мой вопрос: что на уровне графики или аппаратного обеспечения приводит к такому значительному замедлению?


Ищу подробный ответ - уже знаком с широкими понятиями. Соответствующий Git

Спецификации : CUDA 10.0.130, cuDNN 7.4.2, Python 3.7.4, Windows 10, GTX 1070


Результаты тестов :


ОБНОВЛЕНИЕ : отключение Eager Execution согласно приведенному ниже коду не помогает. Поведение, однако, противоречиво: иногда работа в графическом режиме значительно помогает, в других случаях она работает медленнее, чем в Eager.

Поскольку разработчики TF нигде не появляются, я сам исследую этот вопрос - могу следить за прогрессом в связанной проблеме Github.

ОБНОВЛЕНИЕ 2 : тонны экспериментальных результатов, чтобы поделиться, вместе с объяснениями; должно быть сделано сегодня.


Код теста :

# use tensorflow.keras... to benchmark tf.keras; used GPU for all above benchmarks
from keras.layers import Input, Dense, LSTM, Bidirectional, Conv1D
from keras.layers import Flatten, Dropout
from keras.models import Model
from keras.optimizers import Adam
import keras.backend as K
import numpy as np
from time import time

batch_shape = (32, 400, 16)
X, y = make_data(batch_shape)

model_small = make_small_model(batch_shape)
model_small.train_on_batch(X, y)  # skip first iteration which builds graph
timeit(model_small.train_on_batch, 200, X, y)

K.clear_session()  # in my testing, kernel was restarted instead

model_medium = make_medium_model(batch_shape)
model_medium.train_on_batch(X, y)  # skip first iteration which builds graph
timeit(model_medium.train_on_batch, 10, X, y)

Используемые функции :

def timeit(func, iterations, *args):
    t0 = time()
    for _ in range(iterations):
        func(*args)
    print("Time/iter: %.4f sec" % ((time() - t0) / iterations))

def make_small_model(batch_shape):
    ipt   = Input(batch_shape=batch_shape)
    x     = Conv1D(128, 400, strides=4, padding='same')(ipt)
    x     = Flatten()(x)
    x     = Dropout(0.5)(x)
    x     = Dense(64, activation='relu')(x)
    out   = Dense(1,  activation='sigmoid')(x)
    model = Model(ipt, out)
    model.compile(Adam(lr=1e-4), 'binary_crossentropy')
    return model

def make_medium_model(batch_shape):
    ipt   = Input(batch_shape=batch_shape)
    x     = Bidirectional(LSTM(512, activation='relu', return_sequences=True))(ipt)
    x     = LSTM(512, activation='relu', return_sequences=True)(x)
    x     = Conv1D(128, 400, strides=4, padding='same')(x)
    x     = Flatten()(x)
    x     = Dense(256, activation='relu')(x)
    x     = Dropout(0.5)(x)
    x     = Dense(128, activation='relu')(x)
    x     = Dense(64,  activation='relu')(x)
    out   = Dense(1,   activation='sigmoid')(x)
    model = Model(ipt, out)
    model.compile(Adam(lr=1e-4), 'binary_crossentropy')
    return model

def make_data(batch_shape):
    return np.random.randn(*batch_shape), np.random.randint(0, 2, (batch_shape[0], 1))
OverLordGoldDragon
источник
Вы когда-нибудь использовали такой инструмент cProfile для анализа того, какая часть делает их такими разными?
zihaozhihao
@zihaozhihao у меня есть , хотя не для этого конкретно; По предыдущей ссылке и написанию собственного оптимизатора я уже знаком с различиями в вызовах, но не понимаю, почему один медленнее, чем другой, и ни один эксперт, не относящийся к TF, не может понять это из источника, который, помимо запутанный беспорядок, не документирует относительные характеристики. Требуется информация на уровне графики / аппаратного обеспечения, которую профилировщики не предоставят (насколько я могу их использовать)
OverLordGoldDragon
одинаковая версия одинакова в обоих тестах?
19
Ой .... Если бы одна старая Keras была уже значительно медленнее, чем PyTorch, представьте себе сейчас.
Даниэль Мёллер
проблема масштабируется с размером модели? Вы также пытались запустить тот же тест на других ОС?
Okawo

Ответы:

76

ОБНОВЛЕНИЕ 18/02/2020 : я на скамейке 2,1 и 2,1 ночи; результаты смешанные. Все конфиги, кроме одного (модель и размер данных), работают так же быстро или намного быстрее, чем лучшие из TF2 и TF1. Тот, который медленнее и медленнее, это Large-Large - esp. в исполнении графика (от 1,6x до 2,5x медленнее ).

Кроме того, существуют огромные различия в воспроизводимости между Graph и Eager для большой модели, которую я тестировал, - которую нельзя объяснить случайностью / вычислительным параллелизмом. В настоящее время я не могу представить воспроизводимый код для этих утверждений в зависимости от времени, поэтому я настоятельно рекомендую протестировать его для своих собственных моделей.

Еще не открыли Git-проблему, но я прокомментировал оригинал - пока нет ответа. Я обновлю ответ (ы), как только прогресс будет достигнут.


Вердикт : нет , если вы знаете, что делаете. Но если вы этого не сделаете , это может стоить вам очень дорого - в среднем на несколько обновлений графического процессора и в худшем случае на несколько графических процессоров.


НАСТОЯЩИЙ ОТВЕТ : имеет целью дать общее описание проблемы, а также рекомендации о том, как выбрать конфигурацию обучения, соответствующую вашим потребностям. Подробное низкоуровневое описание, включающее все результаты сравнительного анализа + используемый код, см. В моем другом ответе.

Я буду обновлять свой ответ (ы) с дополнительной информацией, если я узнаю что-нибудь - можете добавить / пометить этот вопрос для справки.


РЕЗЮМЕ ВЫПУСКА : как подтвердил разработчик TensorFlow Q. Скотт Чжу, TF2 сфокусировал разработку на стремлении к исполнению и тесной интеграции с Keras, что включало быстрые изменения в источнике TF, в том числе на уровне графов. Преимущества: значительно расширенные возможности обработки, распространения, отладки и развертывания. Стоимость некоторых из них, однако, скорость.

Дело, однако, довольно сложнее. Это не только TF1 против TF2 - факторы, приводящие к значительным различиям в скорости поезда, включают в себя:

  1. TF2 против TF1
  2. Режим Eager vs. Graph
  3. keras против tf.keras
  4. numpyпротив tf.data.Datasetпротив ...
  5. train_on_batch() против fit()
  6. GPU против CPU
  7. model(x)против model.predict(x)против ...

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


ЧТО МНЕ ДЕЛАТЬ? В настоящее время единственный способ - провести эксперимент для конкретной модели, данных и оборудования. Ни одна отдельная конфигурация не всегда будет работать лучше, но есть и то, что нужно, а что нет, чтобы упростить поиск:

>> DO:

  • train_on_batch()+ numpy+ tf.keras+ TF1 + Eager / Graph
  • train_on_batch()+ numpy+ tf.keras+ TF2 + График
  • fit()+ numpy+ tf.keras+ TF1 / TF2 + График + большая модель и данные

>> НЕ

  • fit()+ numpy+ kerasдля малых и средних моделей и данных
  • fit()+ numpy+ tf.keras+ TF1 / TF2 + Eager
  • train_on_batch()+ numpy+ keras+ TF1 + Eager

  • [Major] tf.python.keras ; он может работать в 10-100 раз медленнее и с большим количеством ошибок; больше информации

    • Это включает в себя layers, models, optimizers, и связанные с «вне коробки» импорта использования; Операции, утилиты и связанные с ними «частные» импорта - это хорошо, но, чтобы быть уверенным, проверьте наличие альтернатив и убедитесь, что они используются вtf.keras

Обратитесь к коду внизу моего другого ответа для примера настройки бенчмаркинга. Приведенный выше список основан главным образом на таблицах «ЭТАЛОНОВ» в другом ответе.


ОГРАНИЧЕНИЯ вышеупомянутых ДЕЙСТВИЙ И НЕ:

  • Этот вопрос называется «Почему TF2 намного медленнее, чем TF1?», И хотя его тело явно касается тренировок, вопрос не ограничивается этим; Логический вывод также подвержен значительным различиям в скорости, даже в пределах одной и той же версии TF, импорта, формата данных и т. д. - см. этот ответ .
  • RNN, вероятно, заметно изменят сетку данных в другом ответе, поскольку они были улучшены в TF2
  • Используются в основном модели Conv1Dи Dense- без RNN, разреженных данных / целей, входов 4 / 5D и других настроек
  • Входные данные ограничены numpyи tf.data.Dataset, в то время как существует много других форматов; см другой ответ
  • GPU был использован; результаты будут отличаться на процессоре. Фактически, когда я задал вопрос, моя CUDA не была должным образом настроена, и некоторые результаты были основаны на CPU.

Почему TF2 пожертвовал самым практичным качеством, скоростью и энергичным исполнением? Понятно, что нет - график все еще доступен. Но если вопрос «зачем вообще стремиться»:

  • Превосходная отладка : вы, вероятно, сталкивались с множеством вопросов, спрашивающих «как мне получить выходные данные промежуточного уровня» или «как я проверяю веса»; с нетерпением, это (почти) так же просто, как .__dict__. График, напротив, требует знакомства со специальными внутренними функциями, что значительно усложняет весь процесс отладки и самоанализа.
  • Более быстрое прототипирование : согласно идеям, аналогичным приведенным выше; более быстрое понимание = больше времени осталось для фактического DL.

КАК ВКЛЮЧИТЬ / ОТКЛЮЧИТЬ EAGER?

tf.enable_eager_execution()  # TF1; must be done before any model/tensor creation
tf.compat.v1.disable_eager_execution() # TF2; above holds

ДОПОЛНИТЕЛЬНАЯ ИНФОРМАЦИЯ :

  • Осторожнее с _on_batch()методами в TF2; согласно разработчикам TF, они все еще используют более медленную реализацию, но не намеренно - то есть это должно быть исправлено. Смотрите другой ответ для деталей.

ПРОСИТ ТЕНСОРФУЛЕВЫЕ УСТРОЙСТВА :

  1. Пожалуйста, исправьте train_on_batch()и аспект производительности, вызывая fit()итеративно; пользовательские петли поезда важны для многих, особенно для меня.
  2. Добавьте документацию / документальное упоминание об этих различиях производительности для осведомленности пользователей.
  3. Улучшена общая скорость выполнения, чтобы не подскакивать на Pytorch.

БЛАГОДАРНОСТИ : Спасибо


ОБНОВЛЕНИЯ :

  • 14.11.19 - нашел модель (в моем реальном приложении), которая работает медленнее на TF2 для всех * конфигураций с входными данными Numpy. Различия составляли 13-19%, в среднем 17%. Различия между kerasи tf.keras, тем не менее, были более резкими: 18-40% , в среднем. 32% (оба TF1 и 2). (* - кроме Eager, для которого TF2 OOM'd)

  • 17.11.19 - разработчики обновили on_batch()методы в последнем коммите , заявив, что они улучшили скорость - будут выпущены в TF 2.1 или доступны сейчас как tf-nightly. Поскольку я не могу запустить последний, откладываю скамейку до 2.1.

  • 2/20/20 - прогнозирование производительности также стоит на скамейке запасных; например, в TF2 время прогнозирования ЦП может включать периодические пики
OverLordGoldDragon
источник
3
Как насчет fit_generator? ... Я практически никогда не хочу, train_on_batchи управление собственным циклом обучения между партиями является огромным, огромным препятствием, которого следует избегать даже при больших затратах.
19
@ ely Это еще предстоит проверить, как отмечалось в моем другом ответе - но, если что-то и произойдет, я предполагаю, что это потребует fitнебольшой дополнительной обработки данных. Что касается железнодорожных циклов, я написал свой собственный, который в конечном итоге превратился в своего рода API; fit_generatorне хватает самоанализа, настраиваемости и сохранения / загрузки - так что для меня это абсолютный нету. Со временем я опубликую свой учебный цикл на Github.
OverLordGoldDragon
Отсутствие самоанализа и настраиваемости - особенность для меня, а не ошибка. IDK, на что ссылается комментарий сохранения / загрузки? Промежуточное сохранение / загрузка во время цикла, не контролируемого генератором данных? (Я также лично рад, что полагаюсь только на обратные вызовы, и вижу необходимость в дальнейшей настройке как запах кода из-за того, что мой цикл обучения спроектирован неправильно).
19
@ely Это не просто, но это необходимо для обучения со сложными конвейерами входных данных, целевыми функциями и конфигурациями моделей не-API (например, ансамблями). Самоанализ является обязательным для многих целей отладки и разработки функций. Отсутствие внешнего сохранения / загрузки, а также паузность и возобновляемость контура поезда для дорогих в вычислительном отношении моделей - кошмар. Независимо от того, в конечном счете, зависит от ваших конкретных потребностей и не по теме; самый верный способ проверить производительность с fit_generatorвашим приложением - это проверить.
OverLordGoldDragon
47

ЭТОТ ОТВЕТ : стремится предоставить подробное, графическое / аппаратное описание проблемы - включая циклы поезда TF2 против TF1, процессоры ввода данных и выполнения в режиме Eager vs. Graph. Сводка проблемы и рекомендации по ее решению см. В моем другом ответе.


РЕЗУЛЬТАТ ПРОИЗВОДИТЕЛЬНОСТИ : иногда один быстрее, иногда другой, в зависимости от конфигурации. Что касается TF2 против TF1, то в среднем они примерно на одном уровне, но существенные различия на основе конфигурации существуют, и TF1 превосходит TF2 чаще, чем наоборот. Смотрите «СРАВНЕНИЕ» ниже.


EAGER VS. GRAPH : смысл всего этого ответа для некоторых: согласно моему тестированию, TF2 медленнее, чем TF1. Подробности дальше вниз.

Принципиальное различие между ними заключается в следующем: Graph активно настраивает вычислительную сеть и выполняет ее, когда «ей говорят», тогда как Eager выполняет все при создании. Но история только начинается здесь:

  • Eager НЕ лишен Graph , и на самом деле он может быть главным образом Graph, вопреки ожиданиям. То, чем он в значительной степени является, является выполненным графом - это включает в себя веса модели и оптимизатора, составляющие большую часть графика.

  • Eager перестраивает часть собственного графа при исполнении ; Непосредственное следствие того, что Graph не полностью построен - смотрите результаты профилировщика. Это накладные расходы.

  • Eager медленнее с Numpy входами ; согласно этому Git-комментарию и коду, входные данные Numpy в Eager включают накладные расходы на копирование тензоров из CPU в GPU. Проходя через исходный код, различия в обработке данных очевидны; Eager напрямую передает Numpy, а Graph передает тензоры, которые затем оцениваются Numpy; не уверен в точном процессе, но последний должен включать оптимизацию на уровне GPU

  • TF2 Eager медленнее, чем TF1 Eager - это ... неожиданно. Смотрите результаты сравнительного анализа ниже. Различия варьируются от незначительных до значительных, но они последовательны. Не уверен, почему это так - если разработчик TF уточнит, обновит ответ.


TF2 против TF1 : цитирование соответствующих частей разработчика TF, Q. Scott Zhu's, ответ - с моим акцентом и переписыванием:

В нетерпении, среда выполнения должна выполнить операции и вернуть числовое значение для каждой строки кода Python. Характер выполнения одного шага приводит к его замедлению .

В TF2 Keras использует функцию tf.function для построения своего графика для обучения, оценки и прогнозирования. Мы называем их «функцией исполнения» для модели. В TF1 «функцией выполнения» был FuncGraph, который разделял некоторый общий компонент как функцию TF, но имел другую реализацию.

Во время этого процесса мы как-то оставили неправильную реализацию для train_on_batch (), test_on_batch () и Forext_on_batch () . Они по-прежнему численно корректны , но функция выполнения для x_on_batch - это чисто функция Python, а не функция Python, заключенная в tf.function. Это вызовет медлительность

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

С последним предложением последнего абзаца выше и последним пунктом нижеследующего абзаца:

Чтобы преодолеть медлительность в активном режиме, у нас есть функция @ tf.function, которая превратит функцию python в граф. При подаче числового значения, такого как массив np, тело функции tf.f конвертируется в статический график, оптимизируется и возвращает конечное значение, которое является быстрым и должно иметь производительность, аналогичную режиму графика TF1.

Я не согласен - согласно моим результатам профилирования, которые показывают, что обработка входных данных в Eager значительно медленнее, чем в Graph. Кроме того, не уверены, tf.data.Datasetв частности, но Eager неоднократно вызывает несколько одинаковых методов преобразования данных - см. Профилировщик.

И, наконец, связанный коммит dev: значительное количество изменений для поддержки циклов Keras v2 .


Петли поезда : в зависимости от (1) Eager vs. Graph; (2) формат входных данных, в которых обучение будет продолжаться по отдельному циклу поезда - в TF2 _select_training_loop(), training.py , один из:

training_v2.Loop()
training_distributed.DistributionMultiWorkerTrainingLoop(
              training_v2.Loop()) # multi-worker mode
# Case 1: distribution strategy
training_distributed.DistributionMultiWorkerTrainingLoop(
            training_distributed.DistributionSingleWorkerTrainingLoop())
# Case 2: generator-like. Input is Python generator, or Sequence object,
# or a non-distributed Dataset or iterator in eager execution.
training_generator.GeneratorOrSequenceTrainingLoop()
training_generator.EagerDatasetOrIteratorTrainingLoop()
# Case 3: Symbolic tensors or Numpy array-like. This includes Datasets and iterators 
# in graph mode (since they generate symbolic tensors).
training_generator.GeneratorLikeTrainingLoop() # Eager
training_arrays.ArrayLikeTrainingLoop() # Graph

Каждый из них обрабатывает распределение ресурсов по-разному и влияет на производительность и возможности.


Петли поезда: fitпротив train_on_batch, kerasпротивtf.keras : каждая из четырех использует разные петли поезда, хотя, возможно, не во всех возможных комбинациях. keras' fit, например, использует форму fit_loop, например training_arrays.fit_loop(), и ее train_on_batchможно использовать K.function(). tf.kerasимеет более сложную иерархию, частично описанную в предыдущем разделе.


Обучающие циклы: документация - соответствующая исходная документация по некоторым различным методам выполнения:

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

function создает отдельный график для каждого уникального набора входных форм и типов данных .

Один объект tf.function может потребоваться отобразить на несколько графов вычислений под капотом. Это должно быть видно только как производительность (трассировка графиков имеет ненулевые вычислительные затраты и стоимость памяти )


Процессоры ввода данных : аналогично вышеописанному, процессор выбирается индивидуально в зависимости от внутренних флагов, установленных в соответствии с конфигурациями времени выполнения (режим выполнения, формат данных, стратегия распределения). Самый простой случай с Eager, который работает напрямую с массивами Numpy. Для некоторых конкретных примеров, смотрите этот ответ .


РАЗМЕР МОДЕЛИ, РАЗМЕР ДАННЫХ:

  • Является решающим; ни одна конфигурация не увенчалась всеми моделями и размерами данных.
  • Размер данных относительно размера модели важен; для небольших данных и модели могут преобладать издержки при передаче данных (например, с процессора на графический процессор). Аналогичным образом, небольшие служебные процессоры могут работать медленнее для больших данных convert_to_tensorв зависимости от времени преобразования данных (см. «ПРОФИЛЬЕР»).
  • Скорость различается в зависимости от цикла обработки данных и обработки входных данных разными способами.

ЭТАЛОНЫ : измельченное мясо. - Документ Word - Электронная таблица Excel


Терминология :

  • числа без% - все секунды
  • % рассчитывается как (1 - longer_time / shorter_time)*100; обоснование: нас интересует , какой фактор один быстрее другого; shorter / longerна самом деле нелинейное отношение, не полезно для прямого сравнения
  • Определение знака%:
    • TF2 против TF1: +если TF2 быстрее
    • GvE (Graph против Eager): +если график быстрее
  • TF2 = TensorFlow 2.0.0 + Keras 2.3.1; TF1 = TensorFlow 1.14.0 + Keras 2.2.5

PROFILER :


PROFILER - Объяснение : Spyder 3.3.6 IDE профилировщик.

  • Некоторые функции повторяются в гнездах других; следовательно, трудно отследить точное разделение между функциями «обработки данных» и «обучения», поэтому будет некоторое совпадение - как это выражено в самом последнем результате.

  • % вычисленных значений во время выполнения минус время сборки

  • Время сборки вычисляется путем суммирования всех (уникальных) сред выполнения, которые были вызваны 1 или 2 раза
  • Время поезда вычисляется путем суммирования всех (уникальных) сред выполнения, которые были названы таким же количеством раз, что и количество итераций, и временем выполнения некоторых их гнезд
  • Функции , к сожалению , профилируются в соответствии с их оригинальными именами (то есть _func = funcбудут профилироваться как func), которые смешиваются во время сборки - следовательно, необходимо исключить это

ИСПЫТАТЕЛЬНАЯ СРЕДА :

  • Выполненный код внизу с минимальным количеством фоновых задач
  • GPU был «прогрет» за несколько итераций до синхронизации, как предлагается в этом посте.
  • CUDA 10.0.130, cuDNN 7.6.0, TensorFlow 1.14.0 и TensorFlow 2.0.0, построенные из исходного кода, плюс Anaconda
  • Python 3.7.4, Spyder 3.3.6 IDE
  • GTX 1070, Windows 10, 24 ГБ оперативной памяти DDR4 2,4 МГц, процессор i7-7700HQ 2,8 ГГц

МЕТОДОЛОГИЯ :

  • Ориентир «маленькая», «средняя» и «большая» модель и размеры данных
  • Исправлено количество параметров для каждого размера модели, независимо от размера входных данных.
  • «Большая» модель имеет больше параметров и слоев
  • «Большие» данные имеют более длинную последовательность, но такие же batch_sizeиnum_channels
  • Модели используют только Conv1D, Dense«Обучающиеся» слои; RNN, которых избегают для каждой реализации TF. различия
  • Всегда запускал один поезд, подходящий за пределами цикла бенчмаркинга, чтобы опустить построение модели и графика оптимизатора
  • Не использовать разреженные данные (например layers.Embedding()) или разреженные цели (например,SparseCategoricalCrossEntropy()

ОГРАНИЧЕНИЯ : «полный» ответ объяснил бы каждый возможный цикл поезда и итератор, но это, безусловно, выходит за рамки моих временных возможностей, несуществующей зарплаты или общей необходимости. Результаты так же хороши, как методология - интерпретировать с открытым разумом.


КОД :

import numpy as np
import tensorflow as tf
import random
from termcolor import cprint
from time import time

from tensorflow.keras.layers import Input, Dense, Conv1D
from tensorflow.keras.layers import Dropout, GlobalAveragePooling1D
from tensorflow.keras.models import Model
from tensorflow.keras.optimizers import Adam
import tensorflow.keras.backend as K
#from keras.layers import Input, Dense, Conv1D
#from keras.layers import Dropout, GlobalAveragePooling1D
#from keras.models import Model 
#from keras.optimizers import Adam
#import keras.backend as K

#tf.compat.v1.disable_eager_execution()
#tf.enable_eager_execution()

def reset_seeds(reset_graph_with_backend=None, verbose=1):
    if reset_graph_with_backend is not None:
        K = reset_graph_with_backend
        K.clear_session()
        tf.compat.v1.reset_default_graph()
        if verbose:
            print("KERAS AND TENSORFLOW GRAPHS RESET")

    np.random.seed(1)
    random.seed(2)
    if tf.__version__[0] == '2':
        tf.random.set_seed(3)
    else:
        tf.set_random_seed(3)
    if verbose:
        print("RANDOM SEEDS RESET")

print("TF version: {}".format(tf.__version__))
reset_seeds()

def timeit(func, iterations, *args, _verbose=0, **kwargs):
    t0 = time()
    for _ in range(iterations):
        func(*args, **kwargs)
        print(end='.'*int(_verbose))
    print("Time/iter: %.4f sec" % ((time() - t0) / iterations))

def make_model_small(batch_shape):
    ipt   = Input(batch_shape=batch_shape)
    x     = Conv1D(128, 40, strides=4, padding='same')(ipt)
    x     = GlobalAveragePooling1D()(x)
    x     = Dropout(0.5)(x)
    x     = Dense(64, activation='relu')(x)
    out   = Dense(1,  activation='sigmoid')(x)
    model = Model(ipt, out)
    model.compile(Adam(lr=1e-4), 'binary_crossentropy')
    return model

def make_model_medium(batch_shape):
    ipt = Input(batch_shape=batch_shape)
    x = ipt
    for filters in [64, 128, 256, 256, 128, 64]:
        x  = Conv1D(filters, 20, strides=1, padding='valid')(x)
    x     = GlobalAveragePooling1D()(x)
    x     = Dense(256, activation='relu')(x)
    x     = Dropout(0.5)(x)
    x     = Dense(128, activation='relu')(x)
    x     = Dense(64,  activation='relu')(x)
    out   = Dense(1,   activation='sigmoid')(x)
    model = Model(ipt, out)
    model.compile(Adam(lr=1e-4), 'binary_crossentropy')
    return model

def make_model_large(batch_shape):
    ipt   = Input(batch_shape=batch_shape)
    x     = Conv1D(64,  400, strides=4, padding='valid')(ipt)
    x     = Conv1D(128, 200, strides=1, padding='valid')(x)
    for _ in range(40):
        x = Conv1D(256,  12, strides=1, padding='same')(x)
    x     = Conv1D(512,  20, strides=2, padding='valid')(x)
    x     = Conv1D(1028, 10, strides=2, padding='valid')(x)
    x     = Conv1D(256,   1, strides=1, padding='valid')(x)
    x     = GlobalAveragePooling1D()(x)
    x     = Dense(256, activation='relu')(x)
    x     = Dropout(0.5)(x)
    x     = Dense(128, activation='relu')(x)
    x     = Dense(64,  activation='relu')(x)    
    out   = Dense(1,   activation='sigmoid')(x)
    model = Model(ipt, out)
    model.compile(Adam(lr=1e-4), 'binary_crossentropy')
    return model

def make_data(batch_shape):
    return np.random.randn(*batch_shape), \
           np.random.randint(0, 2, (batch_shape[0], 1))

def make_data_tf(batch_shape, n_batches, iters):
    data = np.random.randn(n_batches, *batch_shape),
    trgt = np.random.randint(0, 2, (n_batches, batch_shape[0], 1))
    return tf.data.Dataset.from_tensor_slices((data, trgt))#.repeat(iters)

batch_shape_small  = (32, 140,   30)
batch_shape_medium = (32, 1400,  30)
batch_shape_large  = (32, 14000, 30)

batch_shapes = batch_shape_small, batch_shape_medium, batch_shape_large
make_model_fns = make_model_small, make_model_medium, make_model_large
iterations = [200, 100, 50]
shape_names = ["Small data",  "Medium data",  "Large data"]
model_names = ["Small model", "Medium model", "Large model"]

def test_all(fit=False, tf_dataset=False):
    for model_fn, model_name, iters in zip(make_model_fns, model_names, iterations):
        for batch_shape, shape_name in zip(batch_shapes, shape_names):
            if (model_fn is make_model_large) and (batch_shape is batch_shape_small):
                continue
            reset_seeds(reset_graph_with_backend=K)
            if tf_dataset:
                data = make_data_tf(batch_shape, iters, iters)
            else:
                data = make_data(batch_shape)
            model = model_fn(batch_shape)

            if fit:
                if tf_dataset:
                    model.train_on_batch(data.take(1))
                    t0 = time()
                    model.fit(data, steps_per_epoch=iters)
                    print("Time/iter: %.4f sec" % ((time() - t0) / iters))
                else:
                    model.train_on_batch(*data)
                    timeit(model.fit, iters, *data, _verbose=1, verbose=0)
            else:
                model.train_on_batch(*data)
                timeit(model.train_on_batch, iters, *data, _verbose=1)
            cprint(">> {}, {} done <<\n".format(model_name, shape_name), 'blue')
            del model

test_all(fit=True, tf_dataset=False)
OverLordGoldDragon
источник
Я не уверен, что ваш код правильный. Я думаю, что ваши модели всегда работают в графическом режиме, так как вы вызываете model.compileбез run_eagerly=Trueаргументов. В активном режиме вы можете запустить часть своего кода в графическом режиме, используя tf.function. Поэтому я думаю, что реализация по умолчанию compileсостоит в том, чтобы создавать вычислительный граф вместо того, чтобы активно его запускать из соображений производительности. Также обратите внимание, что если ваша модель является сверточной, то вы не увидите ускорения в графическом режиме, поскольку взаимодействие с Python минимально. Если вы выполняете много математических операций, это может иметь большое значение (также в использовании памяти).
user2781994
@OverLordGoldDragon, но в TF 2 активный режим по умолчанию, но model.compileбез run_eagerly=Trueобеспечения режима графика, или нет?
user2781994
@OverLordGoldDragon Я согласен , что не все импортированные методы работы в графическом режиме , но я думаю , что либо model.compileили model.fitдолжен гарантировать , что обучение проходит в графическом режиме внутри.
user2781994
@OverLordGoldDragon TRUE - «tf.keras.Model.compile принимает три важных аргумента: ... Кроме того, чтобы убедиться, что модель обучается и оценивает с нетерпением, вы можете убедиться, что передали run_eagerly=Trueв качестве параметра для компиляции». (source tenorflow.org/guide/keras/overview ) Поэтому я, если вы не пройдете run_eagerly=Trueмодель, МОЖЕТ работать в графическом режиме. Я не уверен, что является решающим фактором, но почему он не работает в графическом режиме, если он более эффективен, чем стремиться.
user2781994
Хотите больше доказательств? :) «По умолчанию мы попытаемся скомпилировать вашу модель в статический график, чтобы обеспечить наилучшую производительность при выполнении». ( github.com/tensorflow/tensorflow/blob/r2.0/tensorflow/python/… )
user2781994