Unexpected Inference Time and Model Size for TensorFlow Lite and Pruned Models
还没有人认领这个 Issue。
评估
- 难度
- 4/5
- 预计耗时
- 3-5 天
- 新手友好度
- 25/100
- Issue 类型
- 缺陷
- 描述清晰度
- 需要澄清
- 活跃度
- 停滞
- 技术栈
- keras, python
调研方向
从已发布的 create_tflite_model、create_pruned_model、create_quant_model 和 get_saved_model1 入口点开始,然后使用 TensorFlow 2.16.1 运行最小 SqueezeNet 示例。比较原始、Lite、pruned 和 quantized artifact 及其推理测量结果,包括 Flex delegate path。完成的标准是:隔离并记录所报告的大小和时间观察结果的原因,并提供可复现的测量结果。
由索引模型根据 Issue 内容生成。
描述
I converted my TensorFlow models (.h5 format) to TensorFlow Lite, including quantized and pruned versions.
Note: my model is squeezenet
Script to Save Lite Model:
def create_tflite_model(original_model):
converter = tf.lite.TFLiteConverter.from_keras_model(original_model)
converter.target_spec.supported_ops = [tf.lite.OpsSet.TFLITE_BUILTINS, tf.lite.OpsSet.SELECT_TF_OPS]
lite_model = converter.convert()
return lite_model
def save_tflite_model(model, method):
path_ = "../Lite"
tflite_models_dir = pathlib.Path(path_)
tflite_models_dir.mkdir(exist_ok=True, parents=True)
namee = f"{method}.tflite"
tflite_model_file = tflite_models_dir / namee
tflite_model_file.write_bytes(model)
lite_model = create_tflite_model(original_model)
save_tflite_model(lite_model, "lite")
Script to Create Pruned Version:
def create_pruned_model(original_model, data):
x_train, x_val, x_test, y_train, y_val, y_test = data
batch_size = 64
epochs = 200
prune_low_magnitude = tfmot.sparsity.keras.prune_low_magnitude
num_samples = x_train.shape[0]
end_step = np.ceil(num_samples / batch_size).astype(np.int32) * epochs
pruning_params = {
'pruning_schedule': tfmot.sparsity.keras.PolynomialDecay(initial_sparsity=0.30,
final_sparsity=0.60,
begin_step=0,
end_step=end_step,
frequency=100)
}
model_for_pruning = prune_low_magnitude(original_model, **pruning_params)
model_for_pruning.compile(optimizer=tf.keras.optimizers.legacy.Adam(learning_rate=0.001, beta_1=0.9),
loss=keras.losses.SparseCategoricalCrossentropy(from_logits=True),
metrics=[tf.keras.metrics.SparseCategoricalAccuracy(name='accuracy')])
callbacks = [
keras.callbacks.EarlyStopping(monitor='val_accuracy', patience=10, restore_best_weights=True, verbose=0),
tfmot.sparsity.keras.UpdatePruningStep(),
SparsityLoggingCallback(log_frequency=1)
]
model_for_pruning.fit(x_train, y_train,
batch_size=batch_size, epochs=epochs, validation_data=(x_val, y_val),
callbacks=callbacks)
model_for_export = tfmot.sparsity.keras.strip_pruning(model_for_pruning)
pruned_model = create_tflite_model(model_for_export)
return pruned_model
pruned_model = create_pruned_model(original_model, data)
save_tflite_model(pruned_model, "pruned")
Script to Create Quantized Version:
def create_quant_model(original_model):
converter = tf.lite.TFLiteConverter.from_keras_model(original_model)
converter.optimizations = [tf.lite.Optimize.DEFAULT]
converter.target_spec.supported_ops = [tf.lite.OpsSet.TFLITE_BUILTINS, tf.lite.OpsSet.SELECT_TF_OPS]
dynamic_range_quant_model = converter.convert()
return dynamic_range_quant_model
quant_model = create_quant_model(original_model)
save_tflite_model(quant_model, "quantized")
I compared the performance of the original, Lite, quantized, and pruned models in terms of validation accuracy, inference time, and model size. For model size, I used gzip for all models.
My Questions:
- Inference Time:
- I observe that: Original model > Lite model = Pruned model > Quantized model
- Question 1 : Why does the pruned model have the same inference time as the Lite model? I expect from pruned model to have less inference time than lite model.
- Model Size:
- I observe that: Original model = Lite model > Pruned model > Quantized model
- Question 2: Why does the Lite model have the same size as the original model? I expect from it to be less than original one.
Update:
I installed TensorFlow Flex to support operations not natively supported by TensorFlow Lite. I have provided a minimal, non-working example to illustrate my second question about model size: Why does the Lite model have the same size as the original model? I expected it to be smaller than the original.
I am unsure how to resolve this issue. Interestingly, when I perform the same steps with a simple CNN model, it works perfectly (Lite is smaller than Original and the code works without error). However, it fails with this SqueezeNet example.
import tensorflow as tf
from tensorflow.keras.models import Model
from tensorflow.keras.layers import Input, Conv2D, MaxPooling2D, Concatenate, Add, GlobalAveragePooling2D, Dropout
from tensorflow.keras import backend as K
import os
import tempfile
import zipfile
import pathlib
import numpy as np
from tensorflow.keras.utils import register_keras_serializable
# Function to print library versions
def print_library_versions():
print(f"TensorFlow Version: {tf.__version__}")
# Print library versions
print_library_versions()
# Model definition functions
def SqueezeNetSimple(input_shape, num_classes, use_bypass=False, dropout_rate=None):
input_img = Input(shape=input_shape)
x = Conv2D(16, (3, 3), activation='relu', padding='same', name='conv1')(input_img)
x = MaxPooling2D(pool_size=(2, 2), name='maxpool1')(x)
x = create_fire_module(x, 8, name='fire2')
x = create_fire_module(x, 8, name='fire3', use_bypass=use_bypass)
if dropout_rate: x = Dropout(dropout_rate)(x)
x = Conv2D(num_classes, (1, 1), activation='relu', padding='same', name='conv2')(x)
x = GlobalAveragePooling2D(name='avgpool2')(x)
return Model(inputs=input_img, outputs=x)
def create_fire_module(x, nb_squeeze_filter, name, use_bypass=False):
nb_expand_filter = 4 * nb_squeeze_filter
squeeze = Conv2D(nb_squeeze_filter, (1, 1), activation='relu', padding='same', name='%s_squeeze' % name)(x)
expand_1x1 = Conv2D(nb_expand_filter, (1, 1), activation='relu', padding='same', name='%s_expand_1x1' % name)(squeeze)
expand_3x3 = Conv2D(nb_expand_filter, (3, 3), activation='relu', padding='same', name='%s_expand_3x3' % name)(squeeze)
axis = -1 if K.image_data_format() == 'channels_last' else 1
x_ret = Concatenate(axis=axis, name='%s_concatenate' % name)([expand_1x1, expand_3x3])
if use_bypass:
x_ret = Add(name='%s_concatenate_bypass' % name)([x_ret, x])
return x_ret
# Function to get gzipped model size
def get_gzipped_model_size(model_name):
_, zipped_file = tempfile.mkstemp('.zip')
with zipfile.ZipFile(zipped_file, 'w', compression=zipfile.ZIP_DEFLATED) as f:
f.write(model_name)
return os.path.getsize(zipped_file) # Size in bytes
# Function to save TFLite model
def save_tflite_model(model, a):
path_ = "../source"
tflite_models_dir = pathlib.Path(path_)
tflite_models_dir.mkdir(exist_ok=True, parents=True)
namee = f"squeezenet_opportunity_{a}_sil.tflite"
tflite_model_file = tflite_models_dir / namee
tflite_model_file.write_bytes(model)
print("Model saved: ", namee)
return tflite_model_file
# Function to create and save TFLite model
def get_saved_model1(model_dir, a):
converter = tf.lite.TFLiteConverter.from_saved_model(model_dir)
converter.target_spec.supported_ops = [
tf.lite.OpsSet.TFLITE_BUILTINS,
tf.lite.OpsSet.SELECT_TF_OPS
]
# Disable resource variables
converter.experimental_enable_resource_variables = False
# Enable debugging and detailed logging
converter.experimental_new_converter = True
converter.experimental_new_quantizer = True
lite_model = converter.convert()
model_path = save_tflite_model(lite_model, a)
return model_path
# Example data (replace with your actual data)
x_train = np.random.rand(100, 30, 45, 1)
y_train = np.random.randint(0, 5, 100) # Dummy labels for 5 classes
num_classes = 5
# Create the simplified model
model = SqueezeNetSimple(x_train.shape[1:], num_classes, use_bypass=True, dropout_rate=0.5)
# Compile the model
model.compile(optimizer='adam', loss='sparse_categorical_crossentropy', metrics=['accuracy'])
# Train the model with dummy data
model.fit(x_train, y_train, epochs=1, batch_size=16) # Adjust epochs and batch_size as needed
# Save the model in TensorFlow SavedModel format
saved_model_path = '../models/Original/squeezenet/saved_squeezenet_simple'
tf.saved_model.save(model, saved_model_path)
# Convert the SavedModel to TFLite
model_path = get_saved_model1(saved_model_path, "m1_simple")
print("Model name: ", model_path)
print("Model size: ", os.path.getsize(model_path))
print("Model size gzip: ", get_gzipped_model_size(model_path))
print("The end")
# Load TFLite model and allocate tensors with Flex delegate
def load_tflite_model_with_flex(model_path, flex_delegate_path):
try:
interpreter = tf.lite.Interpreter(model_path=model_path,
experimental_delegates=[tf.lite.experimental.load_delegate(flex_delegate_path)])
interpreter.allocate_tensors()
return interpreter
except Exception as e:
print(f"Failed to load delegate: {e}")
return None
# Specify the correct path to the Flex delegate library
flex_delegate_path = 'bazel-bin/tensorflow/lite/delegates/flex/libtensorflowlite_flex_delegate.so'
if not os.path.exists(flex_delegate_path):
raise FileNotFoundError(f"Flex delegate library not found at {flex_delegate_path}")
interpreter1 = load_tflite_model_with_flex(model_path, flex_delegate_path)
if interpreter1:
# Test the model on random input data
input_details = interpreter1.get_input_details()
output_details = interpreter1.get_output_details()
input_shape = input_details[0]['shape']
input_data = np.array(np.random.random_sample(input_shape), dtype=np.float32)
interpreter1.set_tensor(input_details[0]['index'], input_data)
interpreter1.invoke()
output_data = interpreter1.get_tensor(output_details[0]['index'])
print("Output from model 1: ", output_data)
print("The end")
This is the output i got (I use macbook pro with m3 pro chip):
(tf_env) username@User-MBP source % python myscript.py
TensorFlow Version: 2.16.1
7/7 ━━━━━━━━━━━━━━━━━━━━ 1s 8ms/step - accuracy: 0.0782 - loss: 3.1644
WARNING: All log messages before absl::InitializeLog() is called are written to STDERR
W0000 00:00:1719010068.685977 2618997 tf_tfl_flatbuffer_helpers.cc:390] Ignored output_format.
W0000 00:00:1719010068.686002 2618997 tf_tfl_flatbuffer_helpers.cc:393] Ignored drop_control_dependency.
2024-06-22 01:47:48.686209: I tensorflow/cc/saved_model/reader.cc:83] Reading SavedModel from: ../models/Original/squeezenet/saved_squeezenet_simple
2024-06-22 01:47:48.687045: I tensorflow/cc/saved_model/reader.cc:51] Reading meta graph with tags { serve }
2024-06-22 01:47:48.687053: I tensorflow/cc/saved_model/reader.cc:146] Reading SavedModel debug info (if present) from: ../models/Original/squeezenet/saved_squeezenet_simple
2024-06-22 01:47:48.696450: I tensorflow/compiler/mlir/mlir_graph_optimization_pass.cc:388] MLIR V1 optimization pass is not enabled
2024-06-22 01:47:48.697860: I tensorflow/cc/saved_model/loader.cc:234] Restoring SavedModel bundle.
2024-06-22 01:47:48.735235: I tensorflow/cc/saved_model/loader.cc:218] Running initialization op on SavedModel bundle at path: ../models/Original/squeezenet/saved_squeezenet_simple
2024-06-22 01:47:48.746486: I tensorflow/cc/saved_model/loader.cc:317] SavedModel load for tags { serve }; Status: success: OK. Took 60277 microseconds.
2024-06-22 01:47:48.756733: I tensorflow/compiler/mlir/tensorflow/utils/dump_mlir_util.cc:268] disabling MLIR crash reproducer, set env varMLIR_CRASH_REPRODUCER_DIRECTORYto enable.
loc(fused["ReadVariableOp:", "functional_1_1/conv1_1/Reshape/ReadVariableOp@__inference_serving_default_3237"]): error: missing attribute 'value'
LLVM ERROR: Failed to infer result type(s).
zsh: abort python myscript.py
- 主要语言
- Python
- 星标
- 1.6k
- 派生
- 349
- PR 合并指标
- 30 天内没有已合并 PR
环境准备
- 没有 Dockerfile 或 Docker Compose 文件
- 没有 Pull Request 模板
- 阅读贡献指南
从这里开始
- 先读完整个 Issue,再读项目的贡献指南。
- 在 Issue 下留言说明你要接手 —— 这能避免两个人做同样的事。
- Fork 仓库,在一个分支上完成修改。
- 提交 Pull Request,并在描述里引用这个 Issue 编号。
tensorflow/model-optimization 的其他 Issue
-
难度 2/5 1-3 小时 新手友好度 74/100
tensorflow/model-optimization#1301 · 1 条评论 ·
-
bug
难度 4/5 3-5 天 新手友好度 48/100
tensorflow/model-optimization#1272 ·
-
bug
难度 3/5 1-2 天 新手友好度 50/100
tensorflow/model-optimization#1270 · 2 条评论 ·
-
bug
难度 2/5 1-3 小时 新手友好度 48/100
tensorflow/model-optimization#1241 ·
-
bug
难度 4/5 3-5 天 新手友好度 35/100
tensorflow/model-optimization#1182 · 1 条评论 ·
查看 tensorflow/model-optimization 的全部 Issue
相似的 Issue
-
难度 2/5 1-3 小时 新手友好度 72/100
-
bug
难度 1/5 1 小时以内 新手友好度 88/100
qgis/QGIS-Plugins-Website#459 ·
-
bug severity:medium
难度 2/5 1-3 小时 新手友好度 78/100
维护者通常 2 天内回复
-
bot-found bug priority: P3
难度 2/5 1-3 小时 新手友好度 84/100
madenvel/KalinkaPlayer#179 ·
-
难度 2/5 1-3 小时 新手友好度 68/100
ls1intum/edutelligence#1098 ·
维护者通常 1 天内回复