iOS-SDK
简介
本文档介绍iOS飞桨开源模型SDK版本如何进行开发集成
系统支持
系统:
- 通用ARM: iOS 9.0及以上
硬件:支持 arm64 (Starndard architectures),暂不支持模拟器
SDK大小说明
- 模型资源文件大小影响 SDK 大小
- SDK 包及 IPA 安装包虽然比较大,但最终安装到设备后所占大小会缩小很多。这与 multi architechtures、bitcode 和 AppStore 的优化有关。
快速开始
文件结构说明
.EasyEdge-iOS-SDK
├── EasyDLDemo # Demo工程文件
├── LIB # 依赖库
├── RES
│ ├── easyedge # 模型资源文件夹
│ │ ├── model
│ │ ├── params
│ │ ├── label_list.txt
│ │ ├── infer_cfg.json
│ │ ├── conf.json
└── DOC # 文档
测试Demo
按如下步骤可直接运行 SDK 体验 Demo:
步骤一:用 Xcode 打开 EasyDLDemo/EasyDLDemo.xcodeproj
步骤二:配置开发者自己的签名
步骤三:连接手机运行,不支持模拟器
检测模型运行示例:
SDK使用说明
本节介绍如何将 SDK 接入开发者的项目中使用。
集成指南
步骤一:依赖库集成
步骤二:import <EasyDL/EasyDL.h>
依赖库集成
- 复制 LIB 目录至项目合适的位置
- 配置 Build Settings 中 Search paths: 以 SDK 中 LIB 目录路径为例
- Framework Search Paths:
${PROJECT_DIR}/../LIB/lib
- Header Search Paths:
${PROJECT_DIR}/../LIB/include
- Library Search Paths:
${PROJECT_DIR}/../LIB/lib
集成过程如出现错误,请参考 Demo 工程对依赖库的引用
调用流程示例
以通用ARM的图像分类预测流程为例,详细说明请参考后续章节:
NSError *err;
// step 1: 初始化模型
EasyDLModel *model = [[EasyDLModel alloc] initModelFromResourceDirectory:@"easyedge" withError:&err];
// step 2: 准备待预测的图像
UIImage *image = ...;
// step 3: 预测图像
NSArray *results = [model detectUIImage:image withFilterScore:0 andError:&err];
// step 4: 解析结果
for (id res in results) {
EasyDLClassfiData *clsData = (EasyDLClassfiData *) res;
NSLog(@"labelIndex=%d, labelName=%@, confidence=%f", clsData.category, clsData.label, clsData.accuracy);
}
初始化
// 示例
// 参数一为模型资源文件夹名称
EasyDLModel *model = [[EasyDLModel alloc] initModelFromResourceDirectory:@"easyedge" withError:&err];
模型资源文件夹需以 folder reference 方式加入 Xcode 工程,如
RES/easyedge
文件夹在 Demo 工程中表现为蓝色
预测图像
所有模型类型通过以下接口获取预测结果:
// 返回的数组类型不定
NSArray *results = [model detectUIImage:image withFilterScore:0 andError:&err];
返回的数组类型如下,具体可参考 EasyDLResultData.h
中的定义:
| 模型类型 | 类型 |
| --- | ---- |
| 图像分类 | EasyDLClassfiData |
| 物体检测/人脸检测 | EasyDLObjectDetectionData |
| 实例分割 | EasyDLObjSegmentationData |
| 姿态估计 | EasyDLPoseData |
| 文字识别 | EasyDLOcrData |
模型替换说明
模型资源文件位于 RES/easyedge 目录下,开发者可替换运行其他模型:
- model:模型网络结构文件,对应Paddle1.x的
__model__
,Paddle2.x的model.pdmodel
- params:模型网络参数文件,对应Paddle1.x的
__params__
,Paddle2.x的model.pdiparams
- label_list.txt:label文件
- infer_cfg.json:模型推理的预处理、后处理配置文件,具体见下
- conf.json:【非必需】Demo App 配置文件,建议配置 modelName,缺少不影响运行
infer_cfg.json说明
其中,非标记【必须】的可不填
{
"version": 1,
"model_info": {
"best_threshold": 0.3, // 默认0.3
"model_kind": 1, // 【必须】 1-分类,2-检测,6-实例分割,14-语义分割,401-人脸,402-姿态
},
"pre_process": { // 【必须】
// 归一化, 预处理会把图像 (origin_img - mean) * scale
"skip_norm": false, // 默认为false, 如果设置为true,不做mean scale处理
"mean": [123, 123, 123], // 【必须】
"scale": [0.017, 0.017, 0.017], // 【必须】
"color_format": "RGB", // BGR 【必须】
"channel_order": "CHW", // HWC
// 大小相关
"resize": [300, 300], // w, h 【必须】
"rescale_mode": "keep_size", // 默认keep_size, keep_ratio, keep_ratio2, keep_raw_size, warp_affine
"max_size": 1366, // keep_ratio 用。如果没有提供,则用 resize[0]
"target_size": 800, // keep_ratio 用。如果没有提供,则用 resize[1]
"raw_size_range": [100, 10000], // keep_raw_size 用
"warp_affine_keep_res": // warp_affine模式使用,默认为false
"center_crop_size": [224, 224], // w, h, 如果需要做center_crop,则提供,否则,无需提供该字段
"padding": false,
"padding_mode": "padding_align32", // 【非必须】默认padding_align32, 其他可指定:padding_fill_size
"padding_fill_size": [416, 416], // 【非必须】仅padding_fill_size模式下需要提供, [fill_size_w, fill_size_h], 这里padding fill对齐paddle detection实现,在bottom和right方向实现补齐
"padding_fill_value": [114, 114, 114] // 【非必须】仅padding_fill_size模式下需要提供
// 其他
"letterbox": true,
"ocr_rec_resize": [320, 48], // 【非必须】仅ocr需提供
"ocr_rec_batch_num": 6, // 【非必须】仅ocr需提供,默认为1
}
}
预处理的顺序如下(没有的流程自动略过):
- 灰度图 -> rgb图变换
- resize 尺寸变换
- center_crop
- rgb/bgr变换
- padding_fill_size
- letterbox(画个厚边框,填上黑色)
- chw/hwc变换
- 归一化:mean, scale
- padding_align32
rescale_mode说明:
- keep_size: 将图片缩放到resize指定的大小
- keep_ratio: 将图片按比例缩放,长边不超过max_size,短边不超过target_size
- keep_raw_size: 保持原图尺寸,但必须在raw_size_range之间
- warp_affine: 仿射变换,可以设置warp_affine_keep_res指定是否keep_res,在keep_res为false场景下,宽高通过resize字段指定
错误说明
SDK 的方法会返回 NSError,直接返回的 NSError 的错误码定义在 EasyDLDefine.h - EEasyDLErrorCode
中。NSError 附带 message (有时候会附带 NSUnderlyingError),开发者可根据 code 和 message 进行错误判断和处理。
FAQ
1. 如何多线程并发预测?
SDK内部已经能充分利用多核的计算能力。不建议使用并发来预测。
如果开发者想并发使用,请务必注意EasyDLModel
所有的方法都不是线程安全的。请初始化多个实例进行并发使用,如
- (void)testMultiThread {
UIImage *img = [UIImage imageNamed:@"1.jpeg"];
NSError *err;
EasyDLModel * model1 = [[EasyDLModel alloc] initModelFromResourceDirectory:@"easyedge" withError:&err];
EasyDLModel * model2 = [[EasyDLModel alloc] initModelFromResourceDirectory:@"easyedge" withError:&err];
dispatch_queue_t queue1 = dispatch_queue_create("testQueue", DISPATCH_QUEUE_CONCURRENT);
dispatch_queue_t queue2 = dispatch_queue_create("testQueue2", DISPATCH_QUEUE_CONCURRENT);
dispatch_async(queue1, ^{
NSError *detectErr;
for(int i = 0; i < 1000; ++i) {
NSArray * res = [model1 detectUIImage:img withFilterScore:0 andError:&detectErr];
NSLog(@"1: %@", res[0]);
}
});
dispatch_async(queue2, ^{
NSError *detectErr;
for(int i = 0; i < 1000; ++i) {
NSArray * res = [model2 detectUIImage:img withFilterScore:0 andError:&detectErr];
NSLog(@"2: %@", res[0]);
}
});
}
2. 编译时出现 Undefined symbols for architecture arm64: ...
- 出现
cxx11, vtable
字样:请引入libc++.tbd
- 出现
cv::Mat
字样:请引入opencv2.framework
- 出现
CoreML
,VNRequest
字样:请引入CoreML.framework
并务必#import <CoreML/CoreML.h>
3. 运行时报错 Image not found: xxx ...
请Embed具体报错的库。
4.编译时报错:Invalid bitcode version
这个可能是开发者使用的 Xcode 低于12导致,可以升级至12版本。