通过在完整的成对比较中预先计算编码输出,比预期的加速更小
Smaller speedup than expected by precomputing encoded output in full pairwise comparison
我正在构建一个神经网络来预测成对比较的结果。在合并和计算下游部分的结果之前,相同的编码器网络应用于两个输入。在我的用例中,我正在计算一组给定元素的所有成对预测,因此预测的数量增长非常快,因此我有兴趣加快预测过程。
天真地进行完整的成对预测集涉及在每个元素上一遍又一遍地计算编码器网络的结果。由于编码器网络大于下游部分(合并 + 下游层),我认为在每个输入元素上预先计算编码器网络的结果,然后只计算这些编码值的下游会导致显着的加速。然而,这并不是我在实践中发现的。对于下面在 Colab (CPU) 和我的机器 (CPU) 上的示例,我可以节省 10-15% 的运行时间,而如果您考虑的话,我预计会节省 50% 左右的时间层数,如果你从参数的角度考虑,甚至更多。
我觉得我遗漏了一些东西,无论是在实现中还是 tensorflow/keras 已经做了某种魔法(缓存?)给定网络结构从而导致较小的收益?
import numpy as np # numpy will be used for mgrid to compute all the pairs of the input
import tensorflow as tf
# Encoder Network
input_a = tf.keras.Input(shape=(10,4))
x = tf.keras.layers.Flatten()(input_a)
x = tf.keras.layers.Dense(100, activation='relu')(x)
x = tf.keras.layers.Dense(20, activation='relu')(x)
x = tf.keras.layers.Dense(10, activation='relu')(x)
upstream_network = tf.keras.Model(input_a, x)
# Downstream network, from merge to final prediction
input_downstream_a = tf.keras.Input(shape = upstream_network.layers[-1].output_shape[1:])
input_downstream_b = tf.keras.Input(shape = upstream_network.layers[-1].output_shape[1:])
x = tf.keras.layers.subtract([input_downstream_a, input_downstream_b])
x = tf.keras.layers.Dense(20, activation='relu')(x)
x = tf.keras.layers.Dense(1, activation='sigmoid')(x)
downstream_network = tf.keras.Model((input_downstream_a, input_downstream_b), x)
# Full network
input_full_a = tf.keras.Input(shape=(10,4))
input_full_b = tf.keras.Input(shape=(10,4))
intermed_a = upstream_network(input_full_a)
intermed_b = upstream_network(input_full_b)
res = downstream_network([intermed_a, intermed_b])
full_network = tf.keras.Model([input_full_a, input_full_b], res)
full_network.compile(loss='binary_crossentropy')
# Experiment
population = np.random.random((300, 10, 4))
# %%timeit 10
# 1.9s on Colab CPU
indices = np.mgrid[range(population.shape[0]), range(population.shape[0])].reshape(2, -1)
full_network.predict([population[indices[0]], population[indices[1]]])
# %%timeit 10
# 1.7s on Colab CPU
out = upstream_network.predict(population)
indices = np.mgrid[range(population.shape[0]), range(population.shape[0])].reshape(2, -1)
downstream_network.predict([out[indices[0]], out[indices[1]]])
首先你无法测试时间,使用小输入人口,你可以尝试更大的输入大小600, 700, 800, 但即便如此, 预测时间也不会增加很多。
在你的情况下,我建议使用 predict_on_batch
而不是 predict
,因为它不会将你的输入分成 n 批,这很耗时任务,如果您的数据可以装入 google colab memory
,predict_on_batch
更合理
full_network.predict_on_batch([population[indices[0]], population[indices[1]]])
使用您的测试用例 (300, 10, 4)
- predict_on_batch
array([[0.5 ],
[0.5022318 ],
[0.47754446],
...,
[0.50507313],
[0.4884554 ],
[0.5 ]], dtype=float32)
time: 216 ms
我正在构建一个神经网络来预测成对比较的结果。在合并和计算下游部分的结果之前,相同的编码器网络应用于两个输入。在我的用例中,我正在计算一组给定元素的所有成对预测,因此预测的数量增长非常快,因此我有兴趣加快预测过程。
天真地进行完整的成对预测集涉及在每个元素上一遍又一遍地计算编码器网络的结果。由于编码器网络大于下游部分(合并 + 下游层),我认为在每个输入元素上预先计算编码器网络的结果,然后只计算这些编码值的下游会导致显着的加速。然而,这并不是我在实践中发现的。对于下面在 Colab (CPU) 和我的机器 (CPU) 上的示例,我可以节省 10-15% 的运行时间,而如果您考虑的话,我预计会节省 50% 左右的时间层数,如果你从参数的角度考虑,甚至更多。
我觉得我遗漏了一些东西,无论是在实现中还是 tensorflow/keras 已经做了某种魔法(缓存?)给定网络结构从而导致较小的收益?
import numpy as np # numpy will be used for mgrid to compute all the pairs of the input
import tensorflow as tf
# Encoder Network
input_a = tf.keras.Input(shape=(10,4))
x = tf.keras.layers.Flatten()(input_a)
x = tf.keras.layers.Dense(100, activation='relu')(x)
x = tf.keras.layers.Dense(20, activation='relu')(x)
x = tf.keras.layers.Dense(10, activation='relu')(x)
upstream_network = tf.keras.Model(input_a, x)
# Downstream network, from merge to final prediction
input_downstream_a = tf.keras.Input(shape = upstream_network.layers[-1].output_shape[1:])
input_downstream_b = tf.keras.Input(shape = upstream_network.layers[-1].output_shape[1:])
x = tf.keras.layers.subtract([input_downstream_a, input_downstream_b])
x = tf.keras.layers.Dense(20, activation='relu')(x)
x = tf.keras.layers.Dense(1, activation='sigmoid')(x)
downstream_network = tf.keras.Model((input_downstream_a, input_downstream_b), x)
# Full network
input_full_a = tf.keras.Input(shape=(10,4))
input_full_b = tf.keras.Input(shape=(10,4))
intermed_a = upstream_network(input_full_a)
intermed_b = upstream_network(input_full_b)
res = downstream_network([intermed_a, intermed_b])
full_network = tf.keras.Model([input_full_a, input_full_b], res)
full_network.compile(loss='binary_crossentropy')
# Experiment
population = np.random.random((300, 10, 4))
# %%timeit 10
# 1.9s on Colab CPU
indices = np.mgrid[range(population.shape[0]), range(population.shape[0])].reshape(2, -1)
full_network.predict([population[indices[0]], population[indices[1]]])
# %%timeit 10
# 1.7s on Colab CPU
out = upstream_network.predict(population)
indices = np.mgrid[range(population.shape[0]), range(population.shape[0])].reshape(2, -1)
downstream_network.predict([out[indices[0]], out[indices[1]]])
首先你无法测试时间,使用小输入人口,你可以尝试更大的输入大小600, 700, 800, 但即便如此, 预测时间也不会增加很多。
在你的情况下,我建议使用 predict_on_batch
而不是 predict
,因为它不会将你的输入分成 n 批,这很耗时任务,如果您的数据可以装入 google colab memory
predict_on_batch
更合理
full_network.predict_on_batch([population[indices[0]], population[indices[1]]])
使用您的测试用例 (300, 10, 4)
- predict_on_batch
array([[0.5 ],
[0.5022318 ],
[0.47754446],
...,
[0.50507313],
[0.4884554 ],
[0.5 ]], dtype=float32)
time: 216 ms