理论上,由于权重具有固定大小,因此预测应该是恒定的。编译后如何恢复速度(无需删除优化器)?
答案 0 :(得分:11)
最终罪犯:self._experimental_run_tf_function = True
。是experimental。但这实际上还不错。
向任何TensorFlow开发人员阅读:清理代码。一团糟。而且它违反了重要的编码惯例,例如一个函数做一件事; _process_inputs
所做的 lot 多于“过程输入”,与_standardize_user_data
相同。 “我的报酬不够”-但是您要做付出的代价是,花费更多的时间来理解自己的东西,并且用户在您的“问题”页面中填入了一些错误,这些错误可以通过更清晰的代码来解决。
摘要:compile()
的使用仅慢了 个。
compile()
设置一个内部标志,该标志为predict
分配了不同的预测功能。该函数在每次调用时构造一个新图,相对于未编译,它会降低速度。但是,只有当培训时间比数据处理时间短得多时,差异才明显。如果我们增加模型大小至至少中等大小,则两者将相等。请参阅底部的代码。
数据处理时间的这种轻微增加远远超过了放大图形功能所能弥补的。由于仅保留一个模型图更为有效,因此放弃了一个预编译。 不过:如果您的模型相对于数据而言较小,那么最好不用compile()
进行模型推断。请参阅我的其他答案以找到解决方法。
我应该怎么做?
比较我在底部的代码中比较编译后的模型性能与未编译的模型性能。
predict
。predict
。是的,两者都是可能的,这取决于(1)数据大小; (2)型号尺寸; (3)硬件。底部的代码实际上显示了 compiled 模型更快,但是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()
中。 Relevant source code
(B):numpy.ndarray
,由convert_eager_tensors_to_numpy
返回。 Relevant source code和here
模型执行功能(例如预测)
(A):distribution function和here
(B):distribution function (different)和here
PROFILER :我的另一个答案“小模型”和此答案“中等模型”中的代码结果:
微型模型:1000次迭代,compile()
微型模型:1000次迭代,否 compile()
中等模型:10次迭代
文档(间接)对compile()
:source
与其他TensorFlow操作不同,我们不转换python 张量的数字输入。此外,将为每个生成一个新图 不同的python数值,例如调用
g(2)
和g(3)
生成两个新图
function
为每组唯一的输入实例化一个单独的图 形状和数据类型。例如,将产生以下代码片段 在三个不同的图形中进行跟踪,因为每个输入都有不同的 形状单个tf.function对象可能需要映射到多个计算图 在引擎盖下。仅当性能时才可见(跟踪图具有 计算和内存成本非零),但不应影响正确性 该程序的
COUNTEREXAMPLE :
from tensorflow.keras.layers import Input, Dense, LSTM, Bidirectional, Conv1D
from tensorflow.keras.layers import Flatten, Dropout
from tensorflow.keras.models import Model
import numpy as np
from time import time
def timeit(func, arg, iterations):
t0 = time()
for _ in range(iterations):
func(arg)
print("%.4f sec" % (time() - t0))
batch_size = 32
batch_shape = (batch_size, 400, 16)
ipt = Input(batch_shape=batch_shape)
x = Bidirectional(LSTM(512, activation='relu', return_sequences=True))(ipt)
x = LSTM(512, activation='relu', return_sequences=True)(ipt)
x = Conv1D(128, 400, 1, 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)
X = np.random.randn(*batch_shape)
timeit(model.predict, X, 10)
model.compile('adam', loss='binary_crossentropy')
timeit(model.predict, X, 10)
输出:
34.8542 sec
34.7435 sec
答案 1 :(得分:10)
更新:将实际答案发布为单独的答案;这篇文章包含补充信息
.compile()
设置了大部分TF / Keras图,包括损耗,度量,梯度,以及部分优化器及其权重-这可以确保明显的减速。
出乎意料的是,放慢的程度-在我自己的实验中是10倍,对于predict()
来说,它不会更新任何权重。查看TF2的源代码,图形元素似乎紧密地交织在一起,资源不一定“公平地”分配。
开发人员可能会忽略predict
对于未编译模型的性能,因为通常使用模型进行编译-但是在实践中,这是无法接受的差异。因为有一个简单的解决方法,这也有可能是“必要的邪恶”(见下文)。
这不是一个完整的答案,我希望有人可以在这里提供它-否则,我建议在TensorFlow上打开Github问题。 (OP具有; here)
解决方法:训练模型,保存其权重,无需编译即可重新构建模型,并加载权重。 不保存整个模型(例如model.save()
),因为它将加载已编译的模型-而是使用model.save_weights()
和model.load_weights()
。
解决方法2 :上面,但使用load_model(path, compile=False)
;建议信用:D. Möller
更新:为澄清起见,优化器未完全使用compile
实例化,包括weights
和updates
张量-这通过fit
首次调用拟合函数(train_on_batch
,model._make_train_function()
等)时完成。
因此观察到的行为更加奇怪。更糟糕的是,构建优化程序不会不会引发任何进一步的减速(请参见下文)-提示“图形大小”不是此处的主要解释。
编辑:在某些型号上,运行速度降低30倍。 TensorFlow,您做了什么。下面的示例:
from tensorflow.keras.layers import Input, Dense
from tensorflow.keras.models import Model
import numpy as np
from time import time
def timeit(func, arg, iterations):
t0 = time()
for _ in range(iterations):
func(arg)
print("%.4f sec" % (time() - t0))
ipt = Input(shape=(4,))
x = Dense(2, activation='relu')(ipt)
out = Dense(1, activation='sigmoid')(x)
model = Model(ipt, out)
X = np.random.randn(32,4)
timeit(model.predict, X, 1000)
model.compile('adam', loss='binary_crossentropy')
timeit(model.predict, X, 1000)
model._make_train_function() # build optimizer
timeit(model.predict, X, 1000)
输出:
0.9891 sec
29.785 sec
29.521 sec