python - LSTM 模型的 Int8 量化。无论哪个版本,我都会遇到问题
问题描述
我想使用生成器来量化 LSTM 模型。
问题
我从这个问题开始,因为这是一篇很长的帖子。我实际上想知道您是否已经设法通过训练后量化来量化(int8)LSTM 模型。
我尝试了不同的 TF 版本,但总是遇到错误。以下是我的一些尝试。也许您看到我犯的错误或有建议。谢谢
工作部分
输入应为 (batch,1,45)。使用未量化模型运行推理运行良好。模型和 csv 可以在这里找到:
csv 文件:https:
//mega.nz/file/5FciFDaR#Ev33Ij124vUmOF02jWLu0azxZs-Yahyp6PPGOqr8tok模型文件: https ://mega.nz/file/UAMgUBQA#oK-E0LjZ2YfShPlhHN3uKg8t7bALc2VAONpFirwbmys
import tensorflow as tf
import numpy as np
import pathlib as path
import pandas as pd
def reshape_for_Lstm(data):
timesteps=1
samples=int(np.floor(data.shape[0]/timesteps))
data=data.reshape((samples,timesteps,data.shape[1])) #samples, timesteps, sensors
return data
if __name__ == '__main__':
#GET DATA
import pandas as pd
data=pd.read_csv('./test_x_data_OOP3.csv', index_col=[0])
data=np.array(data)
data=reshape_for_Lstm(data)
#LOAD MODEL
saved_model_dir= path.Path.cwd() / 'model' / 'singnature_model_tf_2.7.0-dev20210914'
model=tf.keras.models.load_model(saved_model_dir)
# INFERENCE
[yhat,yclass] = model.predict(data)
Yclass=[np.argmax(yclass[i],0) for i in range(len(yclass))] # get final class
print('all good')
变量的形状和数据类型data
是(20000,1,45), float64
哪里出错了
现在我想量化模型。但根据 TensorFlow 版本,我会遇到不同的错误。
我使用的代码选项合并如下:
converter=tf.lite.TFLiteConverter.from_saved_model('./model/singnature_model_tf_2.7.0-dev20210914')
converter.representative_dataset = batch_generator
converter.optimizations = [tf.lite.Optimize.DEFAULT]
converter.experimental_new_converter = False
#converter.target_spec.supported_ops = [tf.lite.OpsSet.TFLITE_BUILTINS_INT8]
converter.target_spec.supported_ops = [tf.lite.OpsSet.TFLITE_BUILTINS_INT8, tf.lite.OpsSet.TFLITE_BUILTINS]
#converter.target_spec.supported_ops = [tf.lite.OpsSet.TFLITE_BUILTINS, tf.lite.OpsSet.SELECT_TF_OPS]
#converter._experimental_lower_tensor_list_ops = False
converter.target_spec.supported_types = [tf.int8]
quantized_tflite_model = converter.convert()
TensorFlow 2.2
使用 Git 中经常建议的 TF 2.2,我遇到了 tflite 不支持的运算符。使用tf2.2 创建的模型来确保版本支持。这里只支持 TOCO 转换。
模型中的某些运算符不受标准 TensorFlow Lite 运行时的支持,也无法被 TensorFlow 识别。
该错误不取决于converter.target_spec.supported_ops
选项。因此,我找不到解决方案。allow_custom_ops 只会转移问题。那里有很多 git问题(只是一些 例子),但所有建议的选项都不起作用。
一种是尝试新的 MILR 转换器,然而,在 2.2 中,MILR 的仅整数转换尚未完成。
所以让我们尝试一个更新的版本
TensorFlow 2.5.0
然后我尝试了一个经过严格审查的版本。在这里,无论converter.target_spec.supported_ops
我使用 MLIR 转换运行以下错误:
in the calibrator.py
ValueError:解析模型失败:pybind11::init():工厂函数返回nullptr。
Git上的解决方案是使用TF==2.2.0版本。
使用 TOCO 转换,我收到以下错误:
tensorflow/lite/toco/allocate_transient_arrays.cc:181] 数组 StatefulPartitionedCall/StatefulPartitionedCall/model/lstm/TensorArrayUnstack/TensorListFromTensor 在所有图形转换运行后仍然没有已知的数据类型。致命的 Python 错误:中止
我没有找到有关此错误的任何信息。也许它在2.6中解决了
TensorFlow 2.6.0
在这里,无论converter.target_spec.supported_ops
我使用哪个,我都会遇到以下错误:
ValueError: 无法解析模型:仅支持具有单个子图的模型,模型有 5 个子图。
该模型是一个五层模型。所以似乎每一层都被视为一个子图。我没有找到关于如何将它们合并到一个子图中的答案。问题显然是 2.6.0并在 2.7 中得到解决所以,让我们尝试夜间构建。
TensorFlow 2.7-nightly(尝试 2.7.0-dev20210914 和 2.7.0-dev20210921)
这里我们必须使用 Python 3.7,因为不再支持 3.6
在这里我们必须使用
converter.target_spec.supported_ops = [tf.lite.OpsSet.TFLITE_BUILTINS, tf.lite.OpsSet.SELECT_TF_OPS]
然而,即使有人说
converter._experimental_lower_tensor_list_ops = False
应该设置,似乎没有必要。
这里的问题是,据我所知, tf.lite.OpsSet.SELECT_TF_OPS
调用calibrator.py
. 在期望特定的生成器数据calibrator.py
。从函数的第 93 行开始,生成器需要字典、列表或元组。在函数描述或tflite 类描述中,它声明数据集应该与模型的输入看起来相同。在我的情况下(大多数情况下)只是一个正确尺寸的 numpy 数组。representative_dataset
_feed_tensor()
tf.lite.RepresentativeDataset
在这里,我可以尝试将我的数据转换为元组,但是,这似乎不对。或者这实际上是要走的路?
非常感谢您阅读所有这些。如果我找到答案,我当然会更新帖子
解决方案
如果可能,您可以尝试修改您的 LSTM,以便将其转换为 TFLite 的融合 LSTM 运算符。https://www.tensorflow.org/lite/convert/rnn支持基本融合 LSTM 和 UnidirectionalSequenceLSTM 算子的全整数量化。