error log | 日志或报错信息 | ログ
安卓端、不同硬件平台、相同系统大版本下:retinaface人脸检测相同Mat输入,模型推理输出不一致
context | 编译/运行环境 | バックグラウンド
Android应用开发工具:
Android Studio 3.5.2
Gradle:gradle-5.4.1-all
NDK:21.1.6352462
Cmake:3.6.4111459
ncnn:
commit id:2ef57a6204d24d3f527832cebb902f2f04df0cca
android lib build:Ubuntu 18.04/python 3.6.9/cmake 3.10.2/android-ndk-r21e
所有Android对比测试设备:
1、展锐SC9863A/Android 10.0
2、高通qcm2150/Android 10.0
3、麒麟Kirin970/Android 10.0
4、联发科天玑800U/Android 10.0
how to reproduce | 复现步骤 | 再現方法
1.编写人脸检测模型推理及日志记录代码
//读取本地图片
......
InputStream is = getActivity().getContentResolver().openInputStream(uri);
Bitmap mBitmap = BitmapFactory.decodeStream(is);
mBitmap = mBitmap.copy(Bitmap.Config.ARGB_8888, true);
......
//调用人脸检测模型native方法
......
......
AndroidBitmapInfo info;
AndroidBitmap_getInfo(env, obj_bitmap, &info);
int width = info.width;
int height = info.height;
if (info.format != ANDROID_BITMAP_FORMAT_RGBA_8888) {
return ret;
}
ncnn::Mat ncnn_img = ncnn::Mat::from_android_bitmap(env, obj_bitmap, ncnn::Mat::PIXEL_BGR2RGB);
pretty_print_into_file(ncnn_img, "ncnn_img");//输入ncnn mat数据打印
std::vector<FaceObject> finalBbox;
int status = mDetectRetinaFace->detect_retinaface(ncnn_img, finalBbox);//人脸检测模型推理
......
int DetectRetinaFace::detect_retinaface(const ncnn::Mat &ncnn_img, std::vector<FaceObject> &faceobjects) {
ncnn::Extractor ex = RetinaNet.create_extractor();
ex.input(faceDetect_opt_param_id::BLOB_data, ncnn_img);
std::vector<FaceObject> faceproposals;
//int status1 = get_faceproposals_stride8(ex, faceproposals);
ncnn::Mat score_blob, bbox_blob, landmark_blob;
int status1 = ex.extract(faceDetect_opt_param_id::BLOB_face_rpn_cls_prob_reshape_stride8, score_blob);
int status2 = ex.extract(faceDetect_opt_param_id::BLOB_face_rpn_bbox_pred_stride8, bbox_blob);
int status3 = ex.extract(faceDetect_opt_param_id::BLOB_face_rpn_landmark_pred_stride8, landmark_blob);
//输出3节点stride8 ncnn mat数据打印
pretty_print_into_file(score_blob, "face_detect_stride8_score_blob");
pretty_print_into_file(bbox_blob, "face_detect_stride8_bbox_blob");
pretty_print_into_file(landmark_blob, "face_detect_stride8_landmark_blob");
//int status2 = get_faceproposals_stride16(ex, faceproposals);
ncnn::Mat score_blob, bbox_blob, landmark_blob;
int status4 = ex.extract(faceDetect_opt_param_id::BLOB_face_rpn_cls_prob_reshape_stride16, score_blob);
int status5 = ex.extract(faceDetect_opt_param_id::BLOB_face_rpn_bbox_pred_stride16, bbox_blob);
int status6 = ex.extract(faceDetect_opt_param_id::BLOB_face_rpn_landmark_pred_stride16, landmark_blob);
//输出3节点stride16 ncnn mat数据打印
pretty_print_into_file(score_blob, "face_detect_stride16_score_blob");
pretty_print_into_file(bbox_blob, "face_detect_stride16_bbox_blob");
pretty_print_into_file(landmark_blob, "face_detect_stride16_landmark_blob");
//int status3 = get_faceproposals_stride32(ex, faceproposals);
ncnn::Mat score_blob, bbox_blob, landmark_blob;
int status7 = ex.extract(faceDetect_opt_param_id::BLOB_face_rpn_cls_prob_reshape_stride32, score_blob);
int status8 = ex.extract(faceDetect_opt_param_id::BLOB_face_rpn_bbox_pred_stride32, bbox_blob);
int status9 = ex.extract(faceDetect_opt_param_id::BLOB_face_rpn_landmark_pred_stride32, landmark_blob);
//输出3节点stride32 ncnn mat数据打印
pretty_print_into_file(score_blob, "face_detect_stride32_score_blob");
pretty_print_into_file(bbox_blob, "face_detect_stride32_bbox_blob");
pretty_print_into_file(landmark_blob, "face_detect_stride32_landmark_blob");
......
}
2.挑选一张带人脸的bmp格式图片作为待测试图
3.在不同设备上运行该应用代码,并观察结果输出
more | 其他 | その他
1、四台对比设备中:模型输入完全一致,展锐与联发科的输出数据完全一致,高通与麒麟的输出比较接近(误差小于0.1%),展锐/联发科与高通/麒麟存在较大差距(误差大于1%)
2、另外还发现一个现象,就是不同Android版本(5.1/7.1/8.1/10.0)之间读取相同bmp图片后通过ncnn库接口构造的模型输入存在一定差距,即以下对象
ncnn::Mat ncnn_img = ncnn::Mat::from_android_bitmap(env, obj_bitmap, ncnn::Mat::PIXEL_BGR2RGB);
pretty_print_into_file(ncnn_img, "ncnn_img");//输入ncnn mat数据打印,不同Android大版本上运行存在差距
测试图片与模型文件详见附件
bug_test_files.zip
2条答案
按热度按时间iih3973s1#
经分析,应该是不同安卓硬件平台对浮点指令集的支持存在差异,对于支持fp16的设备,ncnn会默认使用fp16精度来推理,不支持的则使用fp32来推理,所以造成了相同输入下的推理结果差异,如若保持不同硬件平台下的推理精度一致,除了需要使用bmp格式的图片数据来测试,还需要强制统一设定ncnn的精度类型,如
但这样做会降低性能,尤其对复杂模型来说,下降幅度较大,所以不推荐使用,最终在精度与性能之间只能做一个平衡考虑。
drnojrws2#
是的,faq文档中也有提到这个
https://github.com/Tencent/ncnn/wiki/FAQ-ncnn-produce-wrong-result#disable-fp16
经分析,应该是不同安卓硬件平台对浮点指令集的支持存在差异,对于支持fp16的设备,ncnn会默认使用fp16精度来推理,不支持的则使用fp32来推理,所以造成了相同输入下的推理结果差异,如若保持不同硬件平台下的推理精度一致,除了需要使用bmp格式的图片数据来测试,还需要强制统一设定ncnn的精度类型,如
但这样做会降低性能,尤其对复杂模型来说,下降幅度较大,所以不推荐使用,最终在精度与性能之间只能做一个平衡考虑。