所以我有一些代码
private String createOrderSummary(Editable userEnteredString, int price, boolean isWhippedCreamBoxChecked, boolean isChocalateBoxChecked) {
String priceMessage = "Name:" + userEnteredString + "\nAdd whipped cream?" + isWhippedCreamBoxChecked + "\nAdd chocalate?" + isChocalateBoxChecked + "\nQuantity:" + quantity + "\nTotal:$" + price + "\nThank you!\n";
return priceMessage;
如果我将最后一行更改为
tensors = [] //its filled with 3D float tensors
total = sum(tensors)
然后代码生成相同的输出,但运行速度要慢得多,很快就会导致 内存异常。这里发生了什么?有人可以解释一下sum函数中的pythons和tf.add_n分别与一系列张量相互作用,以及为什么pythons sum看起来只是一个更好的版本?
答案 0 :(得分:1)
当你使用sum
时,你调用一个标准的python算法,在数组的元素上递归调用__add__
。由于__add__
(或+
)确实在tensorflow的张量上超载,因此它按预期工作:它创建一个可在会话期间执行的图形。但是,它并不是最优的,因为您添加了与列表中的元素一样多的操作;另外,您正在执行操作的顺序(添加前两个元素,然后将第三个元素添加到结果中,依此类推),这也不是最佳的。
相比之下,add_n
是一种专门的操作。看图表真的说明了我的想法:
import tensorflow as tf
with tf.variable_scope('sum'):
xs = [tf.zeros(()) for _ in range(10)]
sum(xs)
with tf.variable_scope('add_n'):
xs = [tf.zeros(()) for _ in range(10)]
tf.add_n(xs)
然而 - 与我之前的想法相反 - add_n
占用更多内存,因为它在存储之前等待 - 并存储 - 所有输入输入。如果输入数量很大,则差异可能很大。
我期望add_n
的行为,即输入的可用总和,实际上是由tf.accumulate_n
实现的。这应该是更好的选择,因为它比add_n
占用更少的内存,但不强制执行sum
之类的求和顺序。
为什么tensorflow-wavenet的作者使用sum
代替tf.accumulate_n
?当然因为在此之前这个功能不可区分TF< 1.7。所以,如果你必须支持TF< 1.7 和具有内存效率,良好的旧sum
实际上是一个很好的选择。
答案 1 :(得分:0)
sum() built-in只接受迭代,因此似乎可以获得在内存配置文件方面使用生成器的优势。
张量的add_n() function采用张量列表,并且在整个处理过程中似乎保留了数据结构,这是基于形状比较的要求。
In [29]: y = [1,2,3,4,5,6,7,8,9,10]
In [30]: y.__sizeof__()
Out[30]: 120
In [31]: x = iter(y)
In [32]: x.__sizeof__()
Out[32]: 32