2024-12-23-将训练好的模型部署在嵌入式设备中
将训练好的模型部署在嵌入式设备中
1.模型转换与优化
首先,需要将训练好的模型转换成适合嵌入式设备的格式。例如,如果你的模型是在TensorFlow或PyTorch等框架上训练的,你可能需要将其转换为TensorRT或OpenVINO等可以在嵌入式设备上运行的格式。此外,你还需要对模型进行优化,例如通过量化、剪枝等方法减小模型的大小和计算复杂度,以便在资源有限的嵌入式设备上运行。下面以TensorFlow为例
模型转换:
首先需要使用TensorFlow Lite Converter将原始TensorFlow模型转换为TensorFlow Lite模型(.tflite格式)
import tensorflow as tf
# 转换模型
converter = tf.lite.TFLiteConverter.from_saved_model(saved_model_dir) # SavedModel目录的路径
tflite_model = converter.convert()
# 保存TF Lite模型
with open('model.tflite', 'wb') as f:
f.write(tflite_model)
模型量化:
在进行保存模型后需要对模型进行量化,以减小模型大小和推理时间,它通过降低模型参数的精度来实现,TensorFlow Lite支持将浮点数模型量化为8位整数模型,这可以显著减少模型的大小和运行时的计算复杂性。
TensorFlow Lite Converter 提供了内置的量化选项,如后训练量化(post-training quantization, PTQ)和量化感知训练(quantization-aware training, QAT)。
动态范围量化:
权重(float32) 会在训练后量化为 整型(int8),激活会在推断时动态量化,模型大小缩减至原来的四分之一
import tensorflow as tf
converter = tf.lite.TFLiteConverter.from_saved_model(saved_model_dir)
# 启动默认的 optimizations 来量化所有固定参数(权重)
converter.optimizations = [tf.lite.Optimize.DEFAULT] tflite_quant_model = converter.convert()
全整型量化:
整型量化是将32位浮点数 转换为8位定点数。这样可以缩减模型大小并加快推理速度,这对低功耗设备(如 )很有价值。仅支持整数的加速器(如 )也需要使用此数据格式。
converter = tf.lite.TFLiteConverter.from_keras_model(model)
converter.optimizations = [tf.lite.Optimize.DEFAULT] # 先启动默认的optimizations将模型权重进行量化
converter.representative_dataset = representative_data_gen # 使用代表数据集量化模型中间值
# 如果有任何的 ops不能量化,converter 将抛出错误
converter.target_spec.supported_ops = [tf.lite.OpsSet.TFLITE_BUILTINS_INT8]
# 将输入和输出tensors设置为int8 类型
converter.inference_input_type = tf.int8 # or tf.uint8
converter.inference_output_type = tf.int8 # or tf.uint8
tflite_model_quant = converter.convert()
float16量化:
TensorFlow Lite 支持在模型从 TensorFlow 转换到 TensorFlow Lite FlatBuffer 格式期间将权重转换为 16 位浮点值 。这样可以将模型的 大小缩减至原来的二分之一 。
import tensorflow as tf
converter = tf.lite.TFLiteConverter.from_saved_model(saved_model_dir)
converter.optimizations = [tf.lite.Optimize.DEFAULT]
converter.target_spec.supported_types = [tf.float16]
tflite_quant_model = converter.convert()
除去量化方式外,还有其它各种优化模型方法,如稀疏性优化,可以减少模型大小并提高执行效率。这特别适用于具有大量零权重的模型;操作符优化,TensorFlow Lite包含一个优化内核库,该库针对移动设备进行了优化。在转换过程中,原始TensorFlow曹祖偶会被映射到这些优化内核上,从而提高推理速度;模型剪枝,去除模型中不重要的连接或权重的技术,从而减少模型大小和计算复杂性。虽然 TensorFlow Lite Converter 本身不提供剪枝功能,但你可以在转换为 TensorFlow Lite 格式之前使用 TensorFlow 的剪枝 API。
2.测试TensorFlow Lite模型
在转换后,使用TensorFlow Lite Interpreter在桌面环境中测试模型的准确性和性能,以确保转换没有引入错误。
运行 TensorFlow Lite 模型涉及几个简单步骤:
- 将模型加载到内存中。
- 基于现有模型构建
Interpreter
。 - 设置输入张量值。(如果不需要预定义的大小,则可以选择调整输入张量的大小。)
- 调用推断。
- 读取
- 输出张量值。
下面代码中对定义模型、保存模型、转换模型、加载和使用TFLite模型的代码
import tensorflow as tf
# 定义一个继承自 tf.Module 的 TestModel 类
class TestModel(tf.Module):
def __init__(self):
# 调用父类的构造函数
super(TestModel, self).__init__()
# 使用 tf.function 装饰器定义一个名为 add 的方法,该方法接受一个特定形状的浮点数张量作为输入
@tf.function(input_signature=[tf.TensorSpec(shape=[1, 10], dtype=tf.float32)])
def add(self, x):
'''
一个简单的方法,接受单个输入 'x',并返回 'x + 4'。
'''
# 为了方便,将输出命名为 'result'
return {'result': x + 4}
# 指定保存模型的路径和TFLite文件的路径
SAVED_MODEL_PATH = 'content/saved_models/test_variable'
TFLITE_FILE_PATH = 'content/test_variable.tflite'
# 实例化 TestModel 类
module = TestModel()
# 使用 tf.saved_model.save 方法保存模型,同时指定一个签名(这里命名为 'my_signature')
tf.saved_model.save(
module, SAVED_MODEL_PATH,
signatures={'my_signature': module.add.get_concrete_function()})
# 使用 TFLiteConverter 从保存的模型中转换模型
converter = tf.lite.TFLiteConverter.from_saved_model(SAVED_MODEL_PATH)
# 执行转换
tflite_model = converter.convert()
# 将转换后的模型写入TFLite文件
with open(TFLITE_FILE_PATH, 'wb') as f:
f.write(tflite_model)
# 使用 TFLite Interpreter 加载TFLite模型
interpreter = tf.lite.Interpreter(TFLITE_FILE_PATH)
# 获取模型的签名运行器(这里模型只有一个签名,所以默认返回它)
my_signature = interpreter.get_signature_runner()
# 注意:下面的输入数据形状应该是 [1, 10],但代码中给的是 [1, 1],这是一个错误。
# 正确的输入应该是形状为 [1, 10] 的张量。
# 使用签名运行器进行推理,并传入输入数据(这里输入数据形状错误,需要修正)
# output = my_signature(x=tf.constant([1.0], shape=(1,1), dtype=tf.float32)) # 错误的输入形状
output = my_signature(x=tf.constant([1.0] * 10, shape=(1, 10), dtype=tf.float32)) # 正确的输入形状
# 'output' 是一个包含所有推理输出的字典
# 在这个例子中,我们只有一个输出 'result'
# 打印输出结果
print(output['result'])
在TensorFlow中,
SignatureDef
是SavedModel的一部分,它定义了模型的输入和输出,并允许用户指定如何通过TensorFlow Serving或TensorFlow Lite等工具来调用模型。一个
SignatureDef
包含一个或多个输入和输出的映射,每个映射都有一个唯一的名称和数据类型。
当你保存一个模型为SavedModel格式时,你可以定义一个或多个
SignatureDef
,每个
SignatureDef
代表模型的一个特定调用方式。这使得你可以为模型的不同用途或不同的输入/输出配置定义多个签名。
在TensorFlow Lite中,当你从SavedModel转换模型时,这些
SignatureDef
会被保留,并可以通过TFLite Interpreter的
get_signature_runner
方法来访问。这样,你就可以在TFLite中使用与在TensorFlow Serving中相同的模型签名。
简而言之,
SignatureDef
是模型的一个接口描述,它定义了如何通过特定的输入和输出来调用模型。这对于将模型部署到生产环境并使其易于被各种客户端和服务调用非常有用。
3.准备嵌入式设备环境
根据你的嵌入式设备(如NVIDIA Jetson系列、Raspberry、PI、Edge TPU设备等)安装必要的软件和库。这可能包括TensorFlow Lite runtime、解释器和其它依赖项。对于某些设备,可能需要交叉编译TensorFlow Lite解释器或使用预编译的二进制文件。拿STM32系列MCU举例,需要安装STM32CubeMX和STM32CubeIDE,这些都可以用于配置硬件和开发固件,同时需要安装TensorFLow Lite for Microcontrollers,主要在C++环境中开发,可以先使用python来转换和优化TensorFlow模型为TensorFlow Lite格式,以及生成用于STM32的C++代码。
4.集成模型到应用中
将优化后的模型集成到STM32应用中,这涉及到编写代码来加载模型、处理输入数据、运行推理以及处理输出数据。ensorFlow Lite为C++提供了API,因此可以使用C++编写这部分代码。
1、创建或导入项目
首先创建或导入一个新的项目,配置好硬件设置,如时钟、引脚分配、中断等。
2、集成 TensorFlow Lite库
将TensorFlow Lite for Microcontrollers库添加到项目中。这通常涉及将库的头文件和源文件包含到您的项目中。配置项目的构建系统,以确保库文件在编译时被正确链接。
3、加载模型
- 将转换和优化后的TensorFlow Lite模型文件(通常以
.tflite
为扩展名)添加到项目中。 - 编写代码来加载模型文件到内存中。TensorFlow Lite for Microcontrollers提供了用于加载模型的API。
4、处理输入数据
- 根据模型需求,编写代码来处理从传感器或其他数据源接收的输入数据。
- 输入数据可能需要进行预处理,如缩放、归一化或转换为模型所需的格式。
5、运行推理
- 使用TensorFlow Lite for Microcontrollers的API编写代码来运行模型推理。
- 这通常涉及将输入数据传递给模型,并接收模型的输出。
6、处理输出数据
- 编写代码来处理模型的输出数据,并将其转换为对您的应用有意义的信息。
- 输出数据可能需要进行后处理,如解码、阈值判断或转换为实际应用所需的格式。
7、集成到主循环
- 将推理代码集成到您的应用的主循环或事件处理逻辑中。
- 根据需要定期运行推理,或者响应特定事件或条件触发推理。
8、调试和测试
- 在STM32上进行调试和测试,确保模型正确加载、输入数据正确处理、推理正确运行以及输出数据正确解释。
- 使用调试工具检查内存使用情况、性能瓶颈等,并进行必要的优化。
5.在嵌入式设备上部署
最后,将应用部署到STM32设备上。这可能需要使用特定的开发工具链(如Keil、IAR等)来编译和烧录您的代码。在部署过程中,可能需要考虑如何管理设备的内存和处理器资源,以确保模型能够高效运行。
68747470733a2f2f62:6c6f672e6373646e2e6e65742f6d305f36333836373632382f:61727469636c652f64657461696c732f313336333136343937