| 3966 | } |
| 3967 | |
| 3968 | void TfLiteParserImpl::ParseDetectionPostProcess(size_t subgraphIndex, size_t operatorIndex) |
| 3969 | { |
| 3970 | CHECK_MODEL(m_Model, subgraphIndex, operatorIndex); |
| 3971 | |
| 3972 | const auto& operatorPtr = m_Model->subgraphs[subgraphIndex]->operators[operatorIndex]; |
| 3973 | |
| 3974 | auto inputs = GetInputs(m_Model, subgraphIndex, operatorIndex); |
| 3975 | auto outputs = GetOutputs(m_Model, subgraphIndex, operatorIndex); |
| 3976 | CHECK_VALID_SIZE(outputs.size(), 4); |
| 3977 | |
| 3978 | // Obtain custom options from flexbuffers |
| 3979 | auto custom_options = operatorPtr->custom_options; |
| 3980 | const flexbuffers::Map& m = flexbuffers::GetRoot(custom_options.data(), custom_options.size()).AsMap(); |
| 3981 | |
| 3982 | // Obtain descriptor information from tf lite |
| 3983 | DetectionPostProcessDescriptor desc; |
| 3984 | desc.m_MaxDetections = m["max_detections"].AsUInt32(); |
| 3985 | desc.m_MaxClassesPerDetection = m["max_classes_per_detection"].AsUInt32(); |
| 3986 | desc.m_NmsScoreThreshold = m["nms_score_threshold"].AsFloat(); |
| 3987 | desc.m_NmsIouThreshold = m["nms_iou_threshold"].AsFloat(); |
| 3988 | desc.m_NumClasses = m["num_classes"].AsUInt32(); |
| 3989 | desc.m_ScaleH = m["h_scale"].AsFloat(); |
| 3990 | desc.m_ScaleW = m["w_scale"].AsFloat(); |
| 3991 | desc.m_ScaleX = m["x_scale"].AsFloat(); |
| 3992 | desc.m_ScaleY = m["y_scale"].AsFloat(); |
| 3993 | |
| 3994 | if (!(m["use_regular_nms"].IsNull())) |
| 3995 | { |
| 3996 | desc.m_UseRegularNms = m["use_regular_nms"].AsBool(); |
| 3997 | } |
| 3998 | if (!(m["detections_per_class"].IsNull())) |
| 3999 | { |
| 4000 | desc.m_DetectionsPerClass = m["detections_per_class"].AsUInt32(); |
| 4001 | } |
| 4002 | |
| 4003 | if (desc.m_NmsIouThreshold <= 0.0f || desc.m_NmsIouThreshold > 1.0f) |
| 4004 | { |
| 4005 | throw InvalidArgumentException("DetectionPostProcessTFLiteParser: Intersection over union threshold " |
| 4006 | "must be positive and less than or equal to 1."); |
| 4007 | } |
| 4008 | |
| 4009 | armnn::TensorInfo anchorTensorInfo = InputTensorInfo(subgraphIndex, operatorIndex, 2); |
| 4010 | auto anchorTensorAndData = CreateConstTensorNonPermuted(inputs[2], anchorTensorInfo); |
| 4011 | |
| 4012 | auto layerName = fmt::format("DetectionPostProcess:{}:{}", subgraphIndex, operatorIndex); |
| 4013 | IConnectableLayer* layer = m_Network->AddDetectionPostProcessLayer(desc, anchorTensorAndData, |
| 4014 | layerName.c_str()); |
| 4015 | |
| 4016 | if (!layer) |
| 4017 | { |
| 4018 | throw NullPointerException(fmt::format("Layer {} pointer is null {}", |
| 4019 | operatorIndex, CHECK_LOCATION().AsString())); |
| 4020 | } |
| 4021 | |
| 4022 | // The model does not specify the output shapes. |
| 4023 | // The output shapes are calculated from the max_detection and max_classes_per_detection. |
| 4024 | unsigned int numDetectedBox = desc.m_MaxDetections * desc.m_MaxClassesPerDetection; |
| 4025 | m_OverriddenOutputShapes.push_back({ 1, numDetectedBox, 4 }); |
nothing calls this directly
no test coverage detected