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

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

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

У меня вопрос: что именно на графическом или аппаратном уровне вызывает такое значительное замедление?


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

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


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


ОБНОВЛЕНИЕ: отключение нетерпеливого выполнения в соответствии с приведенным ниже кодом не помогает. Однако поведение непоследовательно: иногда работа в графическом режиме значительно помогает, иногда - медленнее по сравнению с 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))

2 ответа

Решение

Изменение 8/1730/2020: TF2,3 наконец сделал это: во всех случаях бежать так быстро, или заметно быстрее, чем любой из предыдущих версий.

Более того, мое предыдущее обновление было несправедливо по отношению к TF; виноват мой GPU, в последнее время перегревается. Если вы видите восходящий график времени итераций, это надежный симптом. Наконец, прочтите заметку разработчика по Eager vs Graph.

Возможно, это мое последнее обновление этого ответа. Истинную статистику скорости вашей модели можете найти только вы на своем устройстве.


ОБНОВЛЕНИЕ 19.05.2020: TF 2.2 с использованием тех же тестов: только небольшое улучшение скорости Eager. Сюжеты для Large-Large Numpytrain_on_batchслучай ниже, ось X - последовательные итерации подгонки; мой графический процессор не на полную мощность, поэтому сомневаюсь, что он троттлинг, но итерации со временем становятся медленнее.

Как указано выше, Graph и Eager в 1,56 раза и 1,97 раза медленнее, чем их аналоги из TF1, соответственно. Не уверен, что буду отлаживать это дальше, так как я подумываю о переходе на Pytorch из-за плохой поддержки TensorFlow настраиваемых / низкоуровневых функций. Однако я открыл проблему, чтобы получить отзывы разработчиков.


ОБНОВЛЕНИЕ 18.02.2020: Я жим 2.1 и 2.1 каждую ночь; результаты неоднозначны. Все конфигурации, кроме одной (модель и размер данных), так же или намного быстрее, чем лучшие из TF2 и TF1. Тот, который медленнее, и значительно медленнее, - это большой-большой, особенно. в исполнении Graph (от 1,6 до 2,5 раз медленнее).

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

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


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


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

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


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

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

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

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


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

>> ДЕЛАТЬ:

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

>> НЕ:

  • fit() + numpy + keras для малых и средних моделей и данных

  • fit() + numpy + tf.keras + TF1 / TF2 + Жажда

  • train_on_batch() + numpy + keras + TF1 + нетерпеливый

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

    • Это включает в себя layers, models, optimizers, и связанный импорт использования "из коробки"; ops, utils и связанный с ними "частный" импорт - это нормально, но для уверенности проверьте наличие альтов и их использование вtf.keras

Обратитесь к коду внизу моего другого ответа для примера настройки тестирования. Приведенный выше список основан в основном на таблицах "ЭТАЛОННЫЕ МАРКИРОВКИ" в другом ответе.


ОГРАНИЧЕНИЯ перечисленных выше ДЕЙСТВИЙ И НЕЛЬЗЯ:

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

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

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

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

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

Введение в заблуждение в TF2; см. здесь.


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

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

ЗАПРОСЫ К TENSORFLOW DEVS:

  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.

  • 20.02.20 - результаты прогнозов тоже заслуживают жима; в TF2, например, время прогнозирования CPU может включать периодические всплески

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


ИТОГ ДЕЙСТВИЯ: иногда один быстрее, иногда другой, в зависимости от конфигурации. Что касается TF2 и TF1, то они в среднем примерно равны, но существенные различия в конфигурации действительно существуют, и TF1 превосходит TF2 чаще, чем наоборот. См. "ЭТАЛОННЫЙ МАРКИРОВАНИЕ" ниже.


ИГЕР В.С. ГРАФИК: суть всего этого ответа для некоторых: согласно моим тестам, энтузиазм TF2 медленнее, чем TF1. Подробности ниже.

Основное различие между ними состоит в том: График устанавливает вычислительную сеть активно, и выполняет, когда "сказал", - тогда как нетерпеливые выполняет все после создания. Но история здесь только начинается:

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

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

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

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


TF2 против TF1: цитируем соответствующие части разработчика TF, ответ Q. Скотта Чжу - с небольшим акцентом и переформулировкой:

С нетерпением среда выполнения должна выполнить операции и вернуть числовое значение для каждой строки кода Python. Природа одноэтапного выполнения делает его медленным.

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

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

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

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

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

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

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


Циклы обучения: в зависимости от (1) нетерпеливого против графика; (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 vs. tf.keras: каждый из четырех использует разные циклы поезда, хотя, возможно, не во всех возможных комбинациях. keras' fit, например, использует форму fit_loop, например training_arrays.fit_loop(), и это train_on_batch может использовать K.function(). tf.keras имеет более сложную иерархию, частично описанную в предыдущем разделе.


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

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

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

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


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


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

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

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


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

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

ПРОФИЛЕР:


ПРОФИЛЕР - Пояснение: IDE-профайлер Spyder 3.3.6.

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

  • % цифр, вычисленных по времени выполнения минус время сборки

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

УСЛОВИЯ ИСПЫТАНИЯ:

  • Выполненный код внизу с минимальным запуском фоновых задач
  • Графический процессор был "разогрет" за несколько итераций перед итерациями по времени, как предлагается в этом посте.
  • 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 == 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)
Другие вопросы по тегам