簡體   English   中英

TensorFlow:有沒有辦法測量模型的 FLOPS?

[英]TensorFlow: Is there a way to measure FLOPS for a model?

我能得到的最接近的例子是在這個問題中找到的: https ://github.com/tensorflow/tensorflow/issues/899

使用這個最小的可重現代碼:

import tensorflow as tf
import tensorflow.python.framework.ops as ops 
g = tf.Graph()
with g.as_default():
  A = tf.Variable(tf.random_normal( [25,16] ))
  B = tf.Variable(tf.random_normal( [16,9] ))
  C = tf.matmul(A,B) # shape=[25,9]
for op in g.get_operations():
  flops = ops.get_stats_for_node_def(g, op.node_def, 'flops').value
  if flops is not None:
    print 'Flops should be ~',2*25*16*9
    print '25 x 25 x 9 would be',2*25*25*9 # ignores internal dim, repeats first
    print 'TF stats gives',flops

但是,返回的 FLOPS 始終為 None。 有沒有辦法具體測量 FLOPS,尤其是 PB 文件?

我想以 Tobias Schnek 的回答為基礎,並回答最初的問題:如何從pb文件中獲取 FLOP。

使用 TensorFlow 1.6.0 運行 Tobias answer 的第一段代碼

g = tf.Graph()
run_meta = tf.RunMetadata()
with g.as_default():
    A = tf.Variable(tf.random_normal([25,16]))
    B = tf.Variable(tf.random_normal([16,9]))
    C = tf.matmul(A,B)

    opts = tf.profiler.ProfileOptionBuilder.float_operation()    
    flops = tf.profiler.profile(g, run_meta=run_meta, cmd='op', options=opts)
    if flops is not None:
        print('Flops should be ~',2*25*16*9)
        print('TF stats gives',flops.total_float_ops)

我們得到以下輸出:

Flops should be ~ 7200
TF stats gives 8288

那么,為什么我們得到的是8288而不是預期的結果7200=2*25*16*9 [a]呢? 答案在於張量AB的初始化方式。 使用高斯分布初始化會花費一些 FLOP。 通過更改AB的定義

    A = tf.Variable(initial_value=tf.zeros([25, 16]))
    B = tf.Variable(initial_value=tf.zeros([16, 9]))

給出預期的輸出7200

通常,網絡的變量在其他方案中使用高斯分布進行初始化。 大多數時候,我們對初始化 FLOP 不感興趣,因為它們在初始化期間完成一次,並且不會在訓練或推理期間發生。 那么,如何在不考慮初始化 FLOP 的情況下獲得 FLOP 的確切數量

pb凍結圖形 pb文件計算 FLOP 實際上是 OP 的用例。

以下片段說明了這一點:

import tensorflow as tf
from tensorflow.python.framework import graph_util

def load_pb(pb):
    with tf.gfile.GFile(pb, "rb") as f:
        graph_def = tf.GraphDef()
        graph_def.ParseFromString(f.read())
    with tf.Graph().as_default() as graph:
        tf.import_graph_def(graph_def, name='')
        return graph

# ***** (1) Create Graph *****
g = tf.Graph()
sess = tf.Session(graph=g)
with g.as_default():
    A = tf.Variable(initial_value=tf.random_normal([25, 16]))
    B = tf.Variable(initial_value=tf.random_normal([16, 9]))
    C = tf.matmul(A, B, name='output')
    sess.run(tf.global_variables_initializer())
    flops = tf.profiler.profile(g, options = tf.profiler.ProfileOptionBuilder.float_operation())
    print('FLOP before freezing', flops.total_float_ops)
# *****************************        

# ***** (2) freeze graph *****
output_graph_def = graph_util.convert_variables_to_constants(sess, g.as_graph_def(), ['output'])

with tf.gfile.GFile('graph.pb', "wb") as f:
    f.write(output_graph_def.SerializeToString())
# *****************************


# ***** (3) Load frozen graph *****
g2 = load_pb('./graph.pb')
with g2.as_default():
    flops = tf.profiler.profile(g2, options = tf.profiler.ProfileOptionBuilder.float_operation())
    print('FLOP after freezing', flops.total_float_ops)

產出

FLOP before freezing 8288
FLOP after freezing 7200

[a]通常矩陣乘法的 FLOP 是乘積 AB 的 mq(2p -1),其中A[m, p]B[p, q]但 TensorFlow 出於某種原因返回 2mpq。 已打開一個問題以了解原因。

有點晚了,但也許它可以幫助將來的一些游客。 對於您的示例,我成功測試了以下代碼段:

g = tf.Graph()
run_meta = tf.RunMetadata()
with g.as_default():
    A = tf.Variable(tf.random_normal( [25,16] ))
    B = tf.Variable(tf.random_normal( [16,9] ))
    C = tf.matmul(A,B) # shape=[25,9]

    opts = tf.profiler.ProfileOptionBuilder.float_operation()    
    flops = tf.profiler.profile(g, run_meta=run_meta, cmd='op', options=opts)
    if flops is not None:
        print('Flops should be ~',2*25*16*9)
        print('25 x 25 x 9 would be',2*25*25*9) # ignores internal dim, repeats first
        print('TF stats gives',flops.total_float_ops)

也可以將探查器與Keras結合使用,如以下代碼片段:

import tensorflow as tf
import keras.backend as K
from keras.applications.mobilenet import MobileNet

run_meta = tf.RunMetadata()
with tf.Session(graph=tf.Graph()) as sess:
    K.set_session(sess)
    net = MobileNet(alpha=.75, input_tensor=tf.placeholder('float32', shape=(1,32,32,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))

我希望我能幫上忙!

上述方法不再適用於 TF2.0,因為探查器方法已被棄用並移至compat.v1下。 看起來這個功能仍然需要實現。

以下是 Github 上的一個問題: https ://github.com/tensorflow/tensorflow/issues/32809

另一個用戶發布了一個答案。 它已被 mod 刪除,因此無法恢復。 但它確實解決了問題,並且比其他答案更好。 所以我在這里重復一遍。


您可以使用以下 pip 包來獲取一些基本信息,例如模型的內存要求,沒有。 參數,觸發器等

https://pypi.org/project/model-profiler

它會輸出類似

型號簡介 價值 單元
選定的 GPU ['0', '1'] GPU ID
失敗次數 0.30932349055999997 BFLOPs
GPU 內存要求 7.4066760912537575 國標
模型參數 138.357544 百萬
模型權重所需的內存 527.7921447753906 MB

用法

[從圖書館網站逐字復制]

from tensorflow.keras.applications import VGG16

model = VGG16(include_top=True)

from model_profiler import model_profiler

Batch_size = 128
profile = model_profiler(model, Batch_size)

print(profile)

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM