3. TensorFlow Lite在车载座舱的部署与性能评估

任务目标

在车载座舱嵌入式设备(ARM Linux,如RK3588)上,将TensorFlow Lite模型部署为可调用的推理服务,并测量单次推理延迟与峰值内存占用,以评估该模型在目标硬件上的实时性是否满足座舱应用需求。

环境与依赖

  • 硬件:ARM64 Linux开发板(本文以RK3588为例),内存≥4GB
  • 系统依赖:cmake ≥ 3.16,g++ 支持C++17
  • 软件库:TensorFlow Lite 2.14.0(预编译静态库 libtensorflow-lite.a)
  • 模型文件:seat_adjust_model.tflite(输入1×6 float32,输出1×3 float32,量化类型为float32)

关键完整代码

以下C++代码完成模型加载、输入填充、推理执行、延迟统计与内存峰值测量,是部署评估的最小完整实现。

#include <cstdio>
#include <cstdlib>
#include <chrono>
#include <vector>
#include <string>
#include <fstream>
#include <sys/resource.h>
#include "tensorflow/lite/interpreter.h"
#include "tensorflow/lite/kernels/register.h"
#include "tensorflow/lite/model.h"
#include "tensorflow/lite/optional_debug_tools.h"

// 读取模型文件到内存
std::vector<char> loadModel(const std::string& path) {
    std::ifstream file(path, std::ios::binary | std::ios::ate);
    if (!file.is_open()) {
        fprintf(stderr, "无法打开模型文件: %s\n", path.c_str());
        exit(1);
    }
    std::streamsize size = file.tellg();
    file.seekg(0, std::ios::beg);
    std::vector<char> buffer(size);
    file.read(buffer.data(), size);
    return buffer;
}

// 获取当前进程峰值内存(KB)
long getPeakRSS() {
    struct rusage usage;
    getrusage(RUSAGE_SELF, &usage);
    return usage.ru_maxrss;
}

int main(int argc, char** argv) {
    if (argc != 3) {
        fprintf(stderr, "用法: %s <模型路径> <推理次数>\n", argv[0]);
        return 1;
    }
    const std::string model_path = argv[1];
    const int num_runs = atoi(argv[2]);
    if (num_runs <= 0) {
        fprintf(stderr, "推理次数必须为正整数\n");
        return 1;
    }

    // 1. 加载模型
    auto model_buffer = loadModel(model_path);
    auto model = tflite::FlatBufferModel::BuildFromBuffer(model_buffer.data(), model_buffer.size());
    if (!model) {
        fprintf(stderr, "模型构建失败\n");
        return 1;
    }

    // 2. 创建解释器
    tflite::ops::builtin::BuiltinOpResolver resolver;
    std::unique_ptr<tflite::Interpreter> interpreter;
    tflite::InterpreterBuilder(*model, resolver)(&interpreter);
    if (!interpreter) {
        fprintf(stderr, "解释器创建失败\n");
        return 1;
    }

    // 3. 配置与内存分配
    interpreter->SetNumThreads(2);
    if (interpreter->AllocateTensors() != kTfLiteOk) {
        fprintf(stderr, "张量内存分配失败\n");
        return 1;
    }

    // 4. 获取输入/输出张量
    int input_idx = interpreter->inputs()[0];
    int output_idx = interpreter->outputs()[0];
    TfLiteTensor* input_tensor = interpreter->tensor(input_idx);
    TfLiteTensor* output_tensor = interpreter->tensor(output_idx);

    // 5. 构造固定输入(模拟座椅调节请求:身高175cm,体重70kg,坐姿角度等6维特征)
    float input_data[6] = {175.0f, 70.0f, 105.0f, 32.0f, 0.5f, 0.8f};
    memcpy(input_tensor->data.f, input_data, 6 * sizeof(float));

    // 6. 预热(首次推理包含初始化开销,不计入统计)
    interpreter->Invoke();

    // 7. 正式推理计时
    double total_ms = 0.0;
    double min_ms = 1e9;
    double max_ms = 0.0;
    for (int i = 0; i < num_runs; ++i) {
        auto start = std::chrono::high_resolution_clock::now();
        if (interpreter->Invoke() != kTfLiteOk) {
            fprintf(stderr, "推理失败\n");
            return 1;
        }
        auto end = std::chrono::high_resolution_clock::now();
        double elapsed_ms = std::chrono::duration<double, std::milli>(end - start).count();
        total_ms += elapsed_ms;
        if (elapsed_ms < min_ms) min_ms = elapsed_ms;
        if (elapsed_ms > max_ms) max_ms = elapsed_ms;
    }

    // 8. 输出结果
    float* output_data = output_tensor->data.f;
    printf("推理输出: [%.2f, %.2f, %.2f]\n", output_data[0], output_data[1], output_data[2]);
    printf("推理次数: %d\n", num_runs);
    printf("平均延迟: %.3f ms\n", total_ms / num_runs);
    printf("最小延迟: %.3f ms\n", min_ms);
    printf("最大延迟: %.3f ms\n", max_ms);
    printf("峰值内存: %.2f MB\n", getPeakRSS() / 1024.0);

    return 0;
}

编译与运行

# 交叉编译(在x86主机上)
aarch64-linux-gnu-g++ -std=c++17 \
    -I/path/to/tensorflow-lite/include \
    -L/path/to/tensorflow-lite/lib \
    bench_inference.cpp -ltensorflow-lite -ldl -lpthread \
    -o bench_inference

# 拷贝到开发板后运行(100次推理)
./bench_inference seat_adjust_model.tflite 100

验证方法与判定标准

  • 功能正确性:程序输出3个float值,且数值范围在合理区间(如座椅前后位置、靠背角度、高度调节量),说明模型推理链路正常。
  • 延迟评估:观察平均延迟是否满足座舱实时性要求。若平均延迟 < 50ms,则可用于非安全关键的舒适性调节;若 < 10ms,则可用于交互反馈场景。
  • 内存评估:峰值内存应小于设备可用内存的30%(例如RK3588上4GB内存时,峰值应 < 1.2GB)。若超出,需考虑使用量化模型(int8)或减少输入维度。
  • 稳定性验证:连续运行100次无崩溃,且最大延迟不超过平均延迟的3倍,说明无异常抖动。

常见问题

  • 模型加载失败:确认模型文件路径正确,且为TFLite格式(非.pb或.onnx)。
  • 输出全为0:检查输入张量数据类型是否与模型要求一致(float32 vs int8)。
  • 延迟波动大:确认开发板CPU调频策略为performance模式,并关闭后台服务干扰。