Теоретически прогноз должен быть постоянным, поскольку веса имеют фиксированный размер. Как мне вернуть скорость после компиляции (без необходимости удалять оптимизатор)?
См. Связанный эксперимент: https://nbviewer.jupyter.org/github/off99555/TensorFlowExperiment/blob/master/test-prediction-speed-after-compile.ipynb?flush_cache=true
python
performance
tensorflow
keras
jupyter-notebook
off99555
источник
источник
fit
безcompile
; Оптимизатор даже не существует для обновления весов.predict
может использоваться безfit
илиcompile
как описано в моем ответе, но разница в производительности не должна быть такой значительной - отсюда и проблема.Ответы:
UPDATE - 1/15/2020 : текущая лучшая практика для небольших объемов партий должны кормить входы модели непосредственно - то есть
preds = model(x)
, и если слои ведут себя по- разному на поезда / вывода,model(x, training=False)
. Для последнего коммита это теперь задокументировано .Я не тестировал их, но в обсуждении Git также стоит попробовать
predict_on_batch()
- особенно с улучшениями в TF 2.1.ULTIMATE Виновник :
self._experimental_run_tf_function = True
. Это экспериментально . Но это на самом деле не плохо.Любой читатель TensorFlow, читающий: очистите свой код . Это беспорядок. И это нарушает важные методы кодирования, такие как одна функция выполняет одну вещь ;
_process_inputs
делает намного больше, чем «входные данные процесса», то же самое для_standardize_user_data
. «Я не заплатил достаточно» , - но вы делаете оплату, в дополнительное время , потраченного понимание своего собственного материала, а также пользователи , заполняющих страницу Проблемы , связанные с ошибками проще решить с более ясным кодом.РЕЗЮМЕ : это немного медленнее
compile()
.compile()
устанавливает внутренний флаг, который назначает другую функцию прогнозированияpredict
. Эта функция создает новый граф при каждом вызове, замедляя его по сравнению с некомпилированным. Однако разница проявляется только тогда, когда время в поезде намного меньше времени обработки данных . Если мы увеличим размер модели по крайней мере до среднего, оба станут равными. Смотрите код внизу.Это небольшое увеличение времени обработки данных более чем компенсируется усиленной графикой. Поскольку более эффективно хранить только один граф модели, один прекомпилятор отбрасывается. Тем не менее : если ваша модель мала по сравнению с данными, вам лучше не делать
compile()
вывод из модели. Смотрите мой другой ответ для обходного пути.ЧТО МНЕ ДЕЛАТЬ?
Сравните производительность модели скомпилированной и не скомпилированной, как в коде внизу.
predict
на скомпилированной модели.predict
на некомпилированной модели.Да, оба варианта возможны, и это будет зависеть от (1) размера данных; (2) размер модели; (3) аппаратное обеспечение. Код внизу на самом деле показывает, что скомпилированная модель работает быстрее, но 10 итераций - небольшой пример. См. "Обходные пути" в моем другом ответе для "с практическими рекомендациями".
ДЕТАЛИ :
Это заняло некоторое время для отладки, но было весело. Ниже я опишу ключевых преступников, которых я обнаружил, приведу соответствующую документацию и покажу результаты профилировщика, которые привели к окончательному узкому месту.
(
FLAG == self.experimental_run_tf_function
для краткости)Model
по умолчанию создает экземпляр сFLAG=False
.compile()
устанавливает его вTrue
.predict()
включает в себя приобретение функции прогнозирования,func = self._select_training_loop(x)
predict
иcompile
, все другие флаги таковы, что:FLAG==True
->func = training_v2.Loop()
FLAG==False
->func = training_arrays.ArrayLikeTrainingLoop()
Истинный виновник :
_process_inputs()
составляет 81% времени выполнения . Его основной компонент?_create_graph_function()
, 72% выполнения . Этот метод даже не существует для (B) . Однако использование модели среднего размера_process_inputs
составляет менее 1% времени выполнения . Код внизу и результаты профилирования следуют.ПРОЦЕССОРЫ ДАННЫХ :
(A) :,
<class 'tensorflow.python.keras.engine.data_adapter.TensorLikeDataAdapter'>
используется в_process_inputs()
. Соответствующий исходный код(B) :,
numpy.ndarray
возвращаетсяconvert_eager_tensors_to_numpy
. Соответствующий исходный код и здесьФУНКЦИЯ ИСПОЛНЕНИЯ МОДЕЛИ (например, прогноз)
(A) : функция распределения , а здесь
(Б) : функция распределения (разная) , а здесь
PROFILER : результаты для кода в моем другом ответе «маленькая модель» и в этом ответе «средняя модель»:
Крошечная модель : 1000 итераций,
compile()
Крошечная модель : 1000 итераций, нет
compile()
Средняя модель : 10 итераций
ДОКУМЕНТАЦИЯ (косвенно) о влиянии
compile()
: источникаКонтрпример :
Выходы :
источник
compile()
?ОБНОВЛЕНИЕ : увидеть фактический ответ опубликован в виде отдельного ответа; этот пост содержит дополнительную информацию
.compile()
устанавливает большую часть графика TF / Keras, включая потери, метрики, градиенты, и частично оптимизатор и его веса - что гарантирует заметное замедление.Что является неожиданным, так это степень замедления - в 10 раз в моем собственном эксперименте и для
predict()
, который не обновляет вес. Изучая исходный код TF2, элементы графа кажутся тесно переплетенными, а ресурсы не обязательно распределяются «справедливо».Возможный упущение разработчиками
predict
производительности в отношении некомпилированной модели, поскольку модели обычно используются скомпилированными, но на практике это недопустимое различие. Также возможно, что это «необходимое зло», поскольку существует простой обходной путь (см. Ниже).Это не полный ответ, и я надеюсь, что кто-то может предоставить его здесь - если нет, я бы предложил открыть проблему Github на TensorFlow. (ОП есть; здесь )
Обходной путь : обучите модель, сохраните ее веса , пересоберите модель без компиляции, загрузите веса. Вы не сохранить всю модель (например
model.save()
), так как она будет загружайте скомпилирована - вместо того, чтобы использоватьmodel.save_weights()
иmodel.load_weights()
.Обходной путь 2 : выше, но используйте
load_model(path, compile=False)
; предложение кредита: Д. МёллерОБНОВЛЕНИЕ : уточнить, оптимизатор не в полной мере экземпляры с
compile
, в том числе ееweights
иupdates
тензоров - это сделано , когда первый вызов функции фитинга производится (fit
,train_on_batch
и т.д.), с помощьюmodel._make_train_function()
.Таким образом, наблюдаемое поведение еще более странно. Хуже того, создание оптимизатора не вызывает дальнейших замедлений (см. Ниже) - предположение, что «размер графика» здесь не является основным объяснением.
РЕДАКТИРОВАТЬ : на некоторых моделях, 30-кратное замедление . TensorFlow, что ты наделал? Пример ниже:
Выходы :
источник
model.fit()
сравнении с динамическим циклом с активным выполнением, чтобы увидеть, не слишком ли велика потеря производительности ...load_model(name, compile=False)
, это проще, чем сохранение / загрузка весов и воссоздание модели.