run_meta = tf.RunMetadata()
enter codwith tf.Session(graph=tf.Graph()) as sess:
K.set_session(sess)
with tf.device('/cpu:0'):
base_model = MobileNet(alpha=1, weights=None, input_tensor=tf.placeholder('float32', shape=(1,224,224,3)))
opts = tf.profiler.ProfileOptionBuilder.float_operation()
flops = tf.profiler.profile(sess.graph, run_meta=run_meta, cmd='op', options=opts)
opts = tf.profiler.ProfileOptionBuilder.trainable_variables_parameter()
params = tf.profiler.profile(sess.graph, run_meta=run_meta, cmd='op', options=opts)
print("{:,} --- {:,}".format(flops.total_float_ops, params.total_parameters))
上記のコードを実行すると、以下の結果が得られました
1,137,481,704 --- 4,253,864
これは、このペーパーで説明されているフロップとは異なります。
mobilenet: https://arxiv.org/pdf/1704.04861.pdf
ShuffleNet: https://arxiv.org/pdf/1707.01083.pdf
論文に記載されている正確なフロップを計算する方法は?
tl; drあなたは実際に正しい答えを持っています!フロップと積和(紙から)を比較しているだけなので、2で割る必要があります。
Kerasを使用している場合、リストしたコードは少し複雑すぎます...
model
をコンパイルされたKerasモデルとします。次のコードでモデルのフロップに到達できます。
import tensorflow as tf
import keras.backend as K
def get_flops(model):
run_meta = tf.RunMetadata()
opts = tf.profiler.ProfileOptionBuilder.float_operation()
# We use the Keras session graph in the call to the profiler.
flops = tf.profiler.profile(graph=K.get_session().graph,
run_meta=run_meta, cmd='op', options=opts)
return flops.total_float_ops # Prints the "flops" of the model.
# .... Define your model here ....
print(get_flops(model))
しかし、私が自分のコンピューターで行った自分の例(Mobilenetではない)を見ると、印刷されたtotal_float_opsは2115でした =そして、flops
変数を単純に出力すると、次の結果が得られました。
[...]
Mul 1.06k float_ops (100.00%, 49.98%)
Add 1.06k float_ops (50.02%, 49.93%)
Sub 2 float_ops (0.09%, 0.09%)
total_float_ops
プロパティは、乗算、加算、および減算を考慮に入れます。
次に、MobileNetsの例を振り返り、ペーパーを簡単に見てみると、パラメーターの数に基づいたデフォルトのKeras実装であるMobileNetの実装が見つかりました。
表の最初のモデルは、得られた結果(4,253,864)と一致し、Mult-Addsは、得られたflops
結果の約半分です。したがって、正しい答えがあります。フロップをMult-Adds(積和またはMAC)と間違えただけです。
MACの数を計算する場合は、上記のコードの結果を2で割るだけです。
これはTF-2.1で私のために働いています:
def get_flops(model_h5_path):
session = tf.compat.v1.Session()
graph = tf.compat.v1.get_default_graph()
with graph.as_default():
with session.as_default():
model = tf.keras.models.load_model(model_h5_path)
run_meta = tf.compat.v1.RunMetadata()
opts = tf.compat.v1.profiler.ProfileOptionBuilder.float_operation()
# Optional: save printed results to file
# flops_log_path = os.path.join(tempfile.gettempdir(), 'tf_flops_log.txt')
# opts['output'] = 'file:outfile={}'.format(flops_log_path)
# We use the Keras session graph in the call to the profiler.
flops = tf.compat.v1.profiler.profile(graph=graph,
run_meta=run_meta, cmd='op', options=opts)
return flops.total_float_ops
上記のソリューションは2回実行できません。そうしないと、フロップは累積! (つまり、2回目に実行すると、output = flops_of_1st_call + flops_of_2nd_callが返されます。)次のコードは、これを回避するためにreset_default_graph
を呼び出します。
def get_flops():
session = tf.compat.v1.Session()
graph = tf.compat.v1.get_default_graph()
with graph.as_default():
with session.as_default():
with U.TimingManager('model load'):
model = keras.applications.mobilenet.MobileNet(
alpha=1, weights=None, input_tensor=tf.compat.v1.placeholder('float32', shape=(1, 224, 224, 3)))
run_meta = tf.compat.v1.RunMetadata()
opts = tf.compat.v1.profiler.ProfileOptionBuilder.float_operation()
# Optional: save printed results to file
# flops_log_path = os.path.join(tempfile.gettempdir(), 'tf_flops_log.txt')
# opts['output'] = 'file:outfile={}'.format(flops_log_path)
# We use the Keras session graph in the call to the profiler.
flops = tf.compat.v1.profiler.profile(graph=graph,
run_meta=run_meta, cmd='op', options=opts)
tf.compat.v1.reset_default_graph()
return flops.total_float_ops
@driedlerから変更、ありがとう!