TensorFlow Lite C++中MobileNet-SSD v1模型输出解析问询
解析TensorFlow Lite MobileNet-SSD v1的C++输出
我来帮你梳理下这个问题——关于MobileNet-SSD v1模型的TFLite版本在C++里的输出解析,还有你对expit函数的疑问。
首先得明确这个模型的TFLite输出结构:
- 第一个输出(对应
results[0])是检测框的归一化坐标,格式为[y_min, x_min, y_max, x_max],数值范围在0到1之间 - 第二个输出(
results[1])是每个检测框对应各类别的原始预测值(logits),不是直接能用的置信度分数
关于expit函数的正确性
你用expit转换分数的逻辑其实是对的!因为MobileNet-SSD v1的分类分支输出的是未经过激活的logits,必须通过sigmoid函数(也就是expit,两者完全等价)转换成0-1之间的置信度,公式就是:
score = 1 / (1 + exp(-logit))
你可能觉得不对,大概率是其他细节没处理好,我给你列几个要注意的点:
关键细节要留意
- 匹配模型的实际维度:MobileNet-SSD v1的TFLite模型,
outputClasses的维度通常是[NUM_DETECTIONS, NUM_CLASSES],默认的Pascal VOC版本是20个目标类别+1个背景类,所以NUM_CLASSES应该是21,NUM_RESULTS一般是10或者20,要和你用的模型对应上 - 跳过背景类:索引0对应的是背景类,你代码里从j=1开始遍历是对的,不用管背景类的分数
- 过滤无效检测框:不是所有输出的框都是有效的,比如坐标超出0-1范围、宽高为负的框,要提前跳过;有些模型还会有第三个输出(
results[2]),是每个框的整体置信度,可以用来快速过滤低质量框
修正后的示例代码
// 先填充好输入数据 interpreter->Invoke(); const std::vector<int>& results = interpreter->outputs(); // 检测框坐标张量:形状为[NUM_RESULTS, 4],每个元素是[y_min, x_min, y_max, x_max] TfLiteTensor* outputLocations = interpreter->tensor(results[0]); // 类别logits张量:形状为[NUM_RESULTS, NUM_CLASSES] TfLiteTensor* outputClasses = interpreter->tensor(results[1]); // 部分模型会有第三个输出,存储每个框的整体置信度:[NUM_RESULTS] // TfLiteTensor* outputScores = interpreter->tensor(results[2]); float* classLogits = tflite::GetTensorData<float>(outputClasses); float* boxCoords = tflite::GetTensorData<float>(outputLocations); // 根据你的模型调整这两个值 const int NUM_RESULTS = 10; const int NUM_CLASSES = 21; for (int i = 0; i < NUM_RESULTS; ++i) { // 取出当前框的坐标 float yMin = boxCoords[i * 4 + 0]; float xMin = boxCoords[i * 4 + 1]; float yMax = boxCoords[i * 4 + 2]; float xMax = boxCoords[i * 4 + 3]; // 跳过无效框 if (xMin >= xMax || yMin >= yMax || xMin < 0 || yMin < 0 || xMax > 1 || yMax > 1) { continue; } // 遍历所有目标类别(跳过背景类) for (int j = 1; j < NUM_CLASSES; ++j) { float logit = classLogits[i * NUM_CLASSES + j]; // 用sigmoid转换为置信度分数 float score = 1.0f / (1.0f + exp(-logit)); // 只保留分数高于阈值的结果(比如0.5) if (score > 0.5f) { // 这里可以处理检测结果:比如把坐标转换成图像像素值,记录类别和分数 // 示例:xMin * imageWidth, yMin * imageHeight } } }
额外小技巧
如果你不确定模型的输出维度,可以用这段代码打印出来确认:
// 打印outputClasses的维度信息 for (int d = 0; d < outputClasses->dims->size; ++d) { std::cout << "维度 " << d << ": " << outputClasses->dims->data[d] << std::endl; }
内容的提问来源于stack exchange,提问作者Javier
相关产品推荐
相关产品推荐

