手把手教你在应用里用上iOS机器学习框架Core ML
2017年的WWDC上,苹果发布了Core ML这个机器学习框架。现在,开发者可以轻松的使用Core ML把机器学习功能集成到自己的应用里,让应用变得更加智能,给用户更牛逼的体验。
Core ML是做什么的
我们知道,机器学习的一个重要应用领域就是事先使用大量数据训练机器,让训练后的机器在面对从未见过的数据时能做出相应的判断。比如,学习大量病人体征数据后,预测疾病发生的概率;学习大量围棋对局后,面对一个陌生的棋局,知道在哪下棋赢的概率更高。
对机器的训练会产生一个关于特定问题的模型,对模型输入特定的数据,模型返回的判断的结果就是输出。Core ML实际做的事情是使用事先训练好的模型(trained model),在本地进行计算,最终返回结果。
应用和Core ML的交互流程大体如图所示:
从图上可以看出,真正智能的部分其实是这个事先训练好的模型(trained model),这个模型决定了最终判断的结果。苹果提供了一些转化好的Core ML格式的模型,我们也可以通过苹果提供的工具把自己在别的常用机器学习工具生成的模型转化为Core ML格式的模型。
集成Core ML
准备工作
目前只有Xcode9提供了Core ML支持,所以我们要到官网下一个最新版本,或者直接点这里下载。
我们使用苹果准备好的模型
Places205-GoogLeNet
,到官网或者点这里下载。Places205-GoogLeNet
用于识别图片里的场景,比如机场航站楼、卧室、森林等。我们要准备一些测试用的图片,我在百度图片用关键字『森林』随便找了下面这个图做测试。
正式开工
1. 添加Core ML框架
在Xcode里打开一个工程。在这里我们创建一个叫CoreMLDemo
的工程。在Build Phase
的Link Binary With Libraries
里,加上CoreML.framework
。
2. 添加模型文件
把之前下载好的模型文件GoogLeNetPlaces.mlmodel
拖到Xcode里,点击该文件能看到模型的详情。
@interface GoogLeNetPlacesInput : NSObject<MLFeatureProvider>
/// Input image of scene to be classified as RGB image buffer, 224 pixels wide by 224 pixels high
@property (readwrite, nonatomic) CVPixelBufferRef sceneImage;
- (instancetype)init NS_UNAVAILABLE;
- (instancetype)initWithSceneImage:(CVPixelBufferRef)sceneImage;
@end
/// Model Prediction Output Type
@interface GoogLeNetPlacesOutput : NSObject<MLFeatureProvider>
/// Probability of each scene as dictionary of strings to doubles
@property (readwrite, nonatomic) NSDictionary<NSString *, NSNumber *> * sceneLabelProbs;
/// Most likely scene label as string value
@property (readwrite, nonatomic) NSString * sceneLabel;
- (instancetype)init NS_UNAVAILABLE;
- (instancetype)initWithSceneLabelProbs:(NSDictionary<NSString *, NSNumber *> *)sceneLabelProbs sceneLabel:(NSString *)sceneLabel;
@end
/// Class for model loading and prediction
@interface GoogLeNetPlaces : NSObject
@property (readonly, nonatomic, nullable) MLModel * model;
- (nullable instancetype)initWithContentsOfURL:(NSURL *)url error:(NSError * _Nullable * _Nullable)error;
/// Make a prediction using the standard interface
/// @param input an instance of GoogLeNetPlacesInput to predict from
/// @param error If an error occurs, upon return contains an NSError object that describes the problem. If you are not interested in possible errors, pass in NULL.
/// @return the prediction as GoogLeNetPlacesOutput
- (nullable GoogLeNetPlacesOutput *)predictionFromFeatures:(GoogLeNetPlacesInput *)input error:(NSError * _Nullable * _Nullable)error;
/// Make a prediction using the convenience interface
/// @param sceneImage Input image of scene to be classified as RGB image buffer, 224 pixels wide by 224 pixels high:
/// @param error If an error occurs, upon return contains an NSError object that describes the problem. If you are not interested in possible errors, pass in NULL.
/// @return the prediction as GoogLeNetPlacesOutput
- (nullable GoogLeNetPlacesOutput *)predictionFromSceneImage:(CVPixelBufferRef)sceneImage error:(NSError * _Nullable * _Nullable)error;
@end
3. 添加Core ML调用代码
把测试图片拖到工程里,找个合适的地方开始写调用Core ML的代码。为了例子简单,我直接写在ViewController里了。
#import "GoogLeNetPlaces.h"
@implementation ViewController
...
- (NSString *)predictImageScene:(UIImage *)image {
GoogLeNetPlaces *model = [[GoogLeNetPlaces alloc] init];
NSError *error;
UIImage *scaledImage = [image scaleToSize:CGSizeMake(224, 224)];
CVPixelBufferRef buffer = [image pixelBufferFromCGImage:scaledImage];
GoogLeNetPlacesInput *input = [[GoogLeNetPlacesInput alloc] initWithSceneImage:buffer];
GoogLeNetPlacesOutput *output = [model predictionFromFeatures:input error:&error];
return output.sceneLabel;
}
...
@end
上面的代码都很简单,就不多解释了。代码里调用了两个给UIImage
新增的Category里的方法,他们是为了把图片转化成满足GoogLeNetPlaces
要求的对象,这不是文章的重点,就不多说了,详见代码。
找个合适的地方调用上面写的代码:
UIImage *image = [UIImage imageNamed:@"testImage"];
NSString *sceneLabel = [self predictImageScene:image];
NSLog(@"Scene label is: %@", sceneLabel);
完工,运行程序在输出里看结果:
Scene label is: bamboo_forest
虽然上面贴的代码不少,但是实际调用Core ML的只有predictImageScene
这一个方法里的两行,Core ML的使用已经不能更简单了。不知道是不是输入数据的问题,在测试过程中,我发现GoogLeNetPlaces
对图片场景的识别还有些问题,具体的还需要进一步研究看看。
对Core ML的调用只是把机器学习集成进iOS的第一步。无论是训练出更准确的模型,还是为用户设计出实际的应用场景,都还有巨大的想象空间,同时也有很长的路要走。
一起努力吧。
Demo的代码我已经上传到Github了,有兴趣的同学可以下下来玩玩。如果直接Clone代码到本地用Xcode9打开,可能会出现模型的类文件没生成,提示GoogLeNetPlaces.h文件找不到的情况。这可能是Xcode beta的问题,如果遇到就先自己创建个工程玩吧。
参考资料
Core ML官网
官方文档:Getting a Core ML Model
官方文档:Integrating a Core ML Model into Your App
重要经验八---UIImage转换为CVPixelBufferRef
相关文章:

Linux服务器安装JDK、Tomcat配置web网站
安装JDK cd /usr/java/jdk【打开目录】 tar -xvzf jdk-7u79-linux-x64.gz【解压安装包】 vi ~/.bashrc【编辑环境变量】############################export JAVA_HOME/usr/java/jdk/jdk1.7.0_79export JAVA_BIN$JAVA_HOME/binexport JAVA_LIB$JAVA_HOME/libexport CLASSPATH.…

sql help cs
using System;using System.Collections.Generic;using System.Linq;using System.Text;using System.Configuration;using System.Data;using System.Data.SqlClient;using System.Collections; /// <summary> /// SQLHelper 的摘要描述 /// </summary>publ…

Spring Cloud应用开发(一:使用Eureka注册服务)
1、搭建maven父工程; 注:在MyEclipse中,创建一个Maven父工程cloud,并在工程的pom.xml中添加Spring Cloud的版本依赖等信息。 2、搭建服务端工程。 注:在父工程cloud中,创建Maven子模块ms-spring-eureka-s…
SRWebSocket源码浅析(上)
2017-06-12 涂耀辉 Cocoa开发者社区一. 前言: WebSocket协议是基于TCP的一种新的网络协议。它实现了浏览器与服务器全双工(full-duplex)通信——可以通俗的解释为服务器主动发送信息给客户端。 区别于MQTT、XMPP等聊天的应用层协议,它是一个传输通讯协…

Mason 简单笔记
Mason的对象 ------------------------------- Request对象 Mason有两个全局预处理对象叫做:$r和$m $r是mod_perl的请求对象,它提供了Perl的API来执行Apache的请求。 $r->;uri #获得用户请求的地址 $r->;content_type #获得…

多级页表如何节省内存
在谈到多级页表的优势的时候,很多地方都是这么说的:32位地址空间的分页系统,如果页面大小为4KB,则每个进程可达1M个页,假设每个页表项占用4个字节,这样每个进程仅仅页表项就占用了4MB连续的内存空间。 那么…

Spring Cloud应用开发(二:实现服务间的调用)
1、搭建订单服务工程。 注:在父工程cloud中,创建Maven子模块ms-spring-eureka-server; 1.1、添加依赖,在pom文件中添加Eureka依赖; 1.2、写配置文件,在配置文件中添加Eureka服务实例的端口号、服务端地址等…

webSocket详解
前言 本文会用实例的方式,将iOS各种IM的方案都简单的实现一遍。并且提供一些选型、实现细节以及优化的建议。 注:文中的所有的代码示例,在github中都有demo: iOS即时通讯,从入门到“放弃”?(demo) 可以打…

2013多校第三场
hdu 4629 题意:给你n个三角形,问覆盖1~n次的面积各是多少,n < 50; 分析:取出所有端点和交点的x坐标,排序,然后对于每一段xi~xi1的范围的线段都是不相交的,所以组成的 面积要么是三角形&#…

React+Reflux博客实践
年初用ReactExpressMongodb写的一个简单的博客。分享给各位朋友参考。 前端:ReactReact RouterRefluxReact-BootstrapWebpack后端:Express(Node.js)Ejs(Index)Mongoose(mongodb) 博客Demo地址:http://itdotaerblog.herokuapp.comGithub Addre…

Spring Cloud应用开发(三:客户端的负载均衡)
1、Ribbon的使用 注:在石榴啊RestTemplate的方法上添加LoadBalanced注解,并在其执行方法中使用服务实例的名称即可; 1.1、添加LoadBalanced注解,在ms-spring-eureka-user工程引导类中的RestTemplate()方法…

SRWebSocket源码浅析(下)
接上文) 四. 接着来讲讲数据的读和写: 当建立连接成功后,就会循环调用这么一个方法: //读取http头部 - (void)_readHTTPHeader; { if (_receivedHTTPHeaders NULL) { //序列化的http消息 _receivedHTTPHeaders CFHTTPMessageCre…

(IOS)签名Demo
思路是将每一次按下屏幕的touch move时的点存到一个数组里,即一个数组相当于一个笔画;再将该代表笔画的数组保存到一个大数组中,每组每次touch的移动都历遍大数组和笔画数组,将点于点之间连接起来。 #import <UIKit/UIKit.h>…

debug运行可以,release运行报错的原因及修改方法
通常我们开发的程序有2种模式:Debug模式和Release模式在Debug模式下,编译器会记录很多调试信息,也可以加入很多测试代码,方便我们程序员测试,以及出现bug时的分析解决Release模式下,就没有上述那些调试信息,而且编译器也会自动优化一些代码,这样生成的程序性能是最优的,但是如果…

Spring Cloud应用开发(四:服务容错保护)
1、Spring Cloud Hystrix的使用 1.1、创建microservice-eureka-user-hystrix工程,并在其pom.xml中引入eureka和hystrix的依赖; 1.2、编写配置文件。在配置文件中添加Eureka服务实例的端口号,服务端地址等; 1.3、在工程主类Applic…

计量注册师考试一些关于期限、时间、机构的总结
1:有效期: 认证5年,基准5年,标准4年,机构授权3年,注册计量师注册证3年,制造、修理许可证3年。 提前量:标准考核提前6个月,注册计量师在有效期满前30工作日内提出申请延续…
TinyCrayon-iOS-SDK:强大到使人惊讶的 Mask 及切图工具库
原文链接:https://github.com/TinyCrayon/TinyCrayon-iOS-SDKTinyCrayon-iOS-SDK:强大到使人惊讶的 Mask 及切图工具库。# 为开源点赞# —— 由SwiftLanguage分享A smart and easy-to-use image masking and cutout SDK for mobile apps. TinyCrayon SDK…

Android之自定义AlertDialog无法监听控件
参考:http://www.cnblogs.com/511mr/archive/2011/10/21/2220253.html 要做一个自定义的弹出框,以前都是用一个Activity来实现,总觉得不是很好看,弹出的框有时候感觉有点大,所以上网查资料说,可以给AlertDi…

Spring Cloud应用开发(五:API网关服务)
1、使用Zuul构建API网关服务; 注:本服务涉及到3个工程,起作用分别如下: ms-spring-eureka-server工程:服务注册中心,端口为8761。ms-spring-eureka-order工程:服务提供者,需要启动…

多态---父指针指向子类对象(父类引用指向子类对象)
我们都知道,面向对象程序设计中的类有三大特性:继承,封装,多态,这个也是介绍类的时候,必须提到的话题,那么今天就来看一下OC中类的三大特性: 一、封装 封装就是对类中的一些字段&…
ARKit从入门到精通-ARKit工作原理及流程介绍
2017-06-15 坤小 Cocoa开发者社区转载请注明出处:http://www.jianshu.com/p/0492c7122d2f 1.1-写在前面的话 1.2-ARKit与SceneKit的关系 1.3-ARKit工作原理 1.3.1-ARSCNView与ARSession 1.3.2-ARWorldTrackingSessionConfiguration与ARFrame 1.4-ARKit工作完整流程 1…

【C语言也能干大事】第五讲 组合框控件,下拉列表
获得组合框控件的句柄HWND hwndCombo1 GetDlgItem(hwnd, IDC_COMBO1); 确定目前选项的索引 int curSel ComboBox_GetCurSel(hwndCombo1); 删除项 ComboBox_DeleteString(hwndCombo1, 2); 取得有多少项int getCount ComboBox_GetCount(hwndCombo1);TCHAR getcount[256];itoa(…

Spring Cloud应用开发(六:使用本地存储方式实现分布式配置管理 )
1、搭建Config Server; 1.1、创建配置中心工程microservice-config-server,并在其pom.xml中引入Config Server的依赖; 1.2、编写配置文件application.yml,添加服务端口号和存储属性等信息; 1.3、在scr/main/resources…

PL SQL笔记(三)
loopif credit_rating < 3 then..exit;end if; end loop; select to_char(sysdate, YYYY-MM-DD HH24:MI:SS) from dual; select cast(sysdate as timestamp) from dual; 复合类型数据 1.记录: declaretypeemp_record_typeis record(r_name emp.ename%type,r_job emp.job%typ…
iOS-仿膜拜贴纸滚动(物理仿真)
导读 简单用OC写了一个小球滚动效果; 类似平衡球. GitHub地址:https://github.com/wangliujiayou/WLBallView 欢迎Star. 膜拜滚动进入正题-(传感器) 传感器是一种感应\检测装置, 目前已经广泛应用于智能手机上,用于感应\检测设备周边的信息,不…

Redhat、centos安装配置postgresql
一.安装postgresql 本文仅以 redhat,postgresql9.4为例,使用yum方式进行介绍。 官网:http://www.postgresql.org/download/linux/redhat/ 1.下载postgresql的yum源 yum install http://yum.postgresql.org/9.4/redhat/rhel-6-x86_64/pgdg-red…

Spring Cloud应用开发(七:使用Git存储方式实现分布式配置管理 )
1、使用Git存储实现管理; 1.1、配置Git。在Git上创建microservice-study-config目录,并在目录中添加开发,预发布和测试的配置文件; 1.2、修改服务端配置文件。将microservice-config-server工程的配置文件中本地文件存储方式的配…

IOS 自定义相机, 使用 AVFoundation(附实现部分腾讯水印相机功能 demo)
原文链接:http://www.jianshu.com/p/c64bf543f16a这是一款使用 AVFoundation 自定义的相机,与系统原生相机有一样的外观但比系统的相机更好、更符合实际的开发需要、可以自己修改 UI、实现拍照、取消、闪光灯控制、前后摄像头控制、聚焦、放大缩小、拍照…

如何成为一个好的测试工程师(转载,大意)
对于测试功能是的两个不同观点:软实力和技术能力。 个人觉得技术能力80%可以被大众掌握,但是软实力是需要花费很多时间去培养和塑造的。一下几点也是能够衡量个人技能的一些标准: 1,沟通技能-口头和书面能力 与人的第一印象&#…

ubuntu下7z文件的解压方法
apt-get install p7zip-full 控制台会打出以下信息: 正在读取软件包列表... 完成正在分析软件包的依赖关系树 正在读取状态信息... 完成 建议安装的软件包: p7zip-rar下列【新】软件包将被安装: p7zip-full升级了 0 个软件包&…