Итак, у меня есть код
tensors = [] //its filled with 3D float tensors
total = sum(tensors)
, если я изменю последнюю строку на
total = tf.add_n(tensors)
, тогда код создает тот же выход, но работает намного медленнее и скоро вызывает исключение из памяти. Что тут происходит? Может ли кто-нибудь объяснить, как питоны, построенные в функции sum, и tf.add_n взаимодействуют с массивом тензоров соответственно и почему сумма питонов, по-видимому, будет просто лучшей версией?
Встроенная функция sum () принимает только итерации и, следовательно, имеет преимущество использования генераторов в отношении профиля памяти.
Функция add_n () для тензора принимает список тензоров и похоже, сохраняют эту структуру данных во время обработки, основываясь на ее требовании для сравнения формы.
Когда вы используете
sum
, вы вызываете стандартный алгоритм python, который вызывает__add__
рекурсивно на элементах массива. Поскольку__add__
(или+
) действительно перегружен тензорами тензорного потока, он работает так, как ожидалось: он создает график, который может быть выполнен во время сеанса. Однако это не является оптимальным, поскольку вы добавляете столько операций, сколько есть элементов в вашем списке; Кроме того, вы выполняете порядок операции (добавьте первые два элемента, затем третий к результату и т. д.), что также не является оптимальным.В отличие от этого
add_n
- это специализированная операция для этого. Глядя на график, я действительно думаю:Однако, вопреки тому, что я думал ранее,
add_n
занимает больше памяти, потому что он ждет - и сохраняет - для всех входящих входов перед их сохранением. Если количество входов велико, то разница может быть существенной.Поведение, которое я ожидал от
add_n
, т. Е. Суммирование входов по мере их доступности, фактически достигнуто поtf.accumulate_n
. Это должно быть превосходной альтернативой, поскольку она занимает меньше памяти, чемadd_n
, но не обеспечивает соблюдение порядка суммирования, напримерsum
.Почему авторы тензорного потока -wavenet используется
sum
вместоtf.accumulate_n
? Конечно, поскольку до того, как эта функция не дифференцируема на TF < 1.7. Поэтому, если вам нужно поддерживать TF < 1.7 и - эффективная память, старый добрыйsum
на самом деле неплохой вариант.