iOS MachineLearning 系列(15)—— 可进行个性化更新的CoreML模型

本文涉及的产品
模型在线服务 PAI-EAS,A10/V100等 500元 1个月
模型训练 PAI-DLC,5000CU*H 3个月
交互式建模 PAI-DSW,每月250计算时 3个月
简介: 上一篇文章,介绍了使用官方提供的CoreML模型来实现手写数字识别。其实,更多时候我们需要一个更加个性化的模型,对于手写图像来说,每个人的写法可能风格各异,如果可以在用户的使用过程中不断的更新模型,适应更加个性化的场景,就更完美了。幸运的是,CoreML正提供了这样的功能。我们可以创建一个可更新的模型来实现个性化Learning,同样,本文暂无设计模型的训练,我们通过官方的UpdatableDrawingClassifier模型来演示可更新模型的使用。

iOS MachineLearning 系列(15)—— 可进行个性化更新的CoreML模型

上一篇文章,介绍了使用官方提供的CoreML模型来实现手写数字识别。其实,更多时候我们需要一个更加个性化的模型,对于手写图像来说,每个人的写法可能风格各异,如果可以在用户的使用过程中不断的更新模型,适应更加个性化的场景,就更完美了。幸运的是,CoreML正提供了这样的功能。我们可以创建一个可更新的模型来实现个性化Learning,同样,本文暂无设计模型的训练,我们通过官方的UpdatableDrawingClassifier模型来演示可更新模型的使用。

1 - 关于UpdatableDrawingClassifier模型

UpdatableDrawingClassifier是Apple官方提供的一个训练好的并且支持更新迭代的手绘识别模型。其尺寸大小约为394KB,从其大小也可以看出,其本身并没太多的识别能力,我们需要在iOS应用内对其进行更新,使其能够识别个性化的手绘事物。

此处可以下载到此模型:

https://developer.apple.com/machine-learning/models/

首先,我们可以在Xcode中观察下模型的概要信息:

相比之前使用的MNIST模型,其多了Updates一栏。我们主要关注Predictions和Updates栏目,其中Predictions说明了使用模型预测时的参数和返回数据,Updates则说明了模型更新时的参数。如下图:

Predictions输入参数为图片(需要黑色背景,白色前景),输入有数据有两个,一个是字符串类型的最佳预测结果,一个是字典类型的可能的预测结果。

Updates输入参数为图片(需要黑色背景,白色前景),以及此图片对应的预测文本。

2 - UpdatableDrawingClassifier使用示例

以前面文章的手写数字为例,之前使用此模型进行预测,会发现其并不能识别出数字。下面我们尝试让其对此图像进行Learning。

首先定义两个模型操作类实例,分别用来承载原模型与更新后的模型:

// 更新后的模型
var updatedDrawingClassifier: UpdatableDrawingClassifier?
// 原模型
var baseDrawingClassifier: UpdatableDrawingClassifier?

其中UpdatableDrawingClassifier类是Xcode自动生成的,此类文件前一篇文章有过详细的介绍,这里不再赘述。

我们首先使用原始的模型对图像进行预测,如下:

baseDrawingClassifier = try! UpdatableDrawingClassifier(configuration: MLModelConfiguration())

// 未更新前的模型进行测试
let output = try! baseDrawingClassifier.prediction(input: UpdatableDrawingClassifierInput(drawingWith: UIImage(named: "3")!.cgImage!))
print("未更新前的预测:'\(output.label)'")

label.text = label.text!.appending("模型未更新前的预测结果:\(output.label)\n")

不出意外,你将得到“unknow”的结果。

下面我们让模型以此图像作为输入进行Learning,先定义一些要使用到的路径URL:

// 原模型路径
let defaultModelURL = UpdatableDrawingClassifier.urlOfModelInThisBundle
// 用户目录
let appDirectory = FileManager.default.urls(for: .applicationSupportDirectory,
                                                           in: .userDomainMask).first!
// 临时模型文件路径
lazy var tempUpdatedModelURL = appDirectory.appendingPathComponent("personalized_tmp.mlmodelc")
// 更新后的模型文件路径
lazy var updatedModelURL = appDirectory.appendingPathComponent("personalized.mlmodelc")

如下代码演示了对模型进行更新的过程:

// 定义预期的预测结果
let outputValue = MLFeatureValue(string: "手写数字3")
// 更新的输入参数名
let inputName = "drawing"  // 图片参数
let labelName = "label"    // 预测结果参数

// 获取模型的描述
let description = baseDrawingClassifier.model.modelDescription
// 获取输入参数的描述
let imageInputDescription = description.inputDescriptionsByName[inputName]!
// 获取图片约束字段
let imageConstraint = imageInputDescription.imageConstraint!
// 将图片封装成特征对象
let imageFeatureValue = try! MLFeatureValue(cgImage: UIImage(named: "3")!.cgImage!,
                                            constraint: imageConstraint)
// 组合预期结果与对应的特征对象
let dataPointFeatures: [String: MLFeatureValue] = [inputName: imageFeatureValue,
                                                   labelName: outputValue]
// 定义特征Provider对象
let provider = try! MLDictionaryFeatureProvider(dictionary: dataPointFeatures)

// 使用一组provider创建更新任务
let updateTask = try? MLUpdateTask(forModelAt: defaultModelURL,
                                   trainingData: MLArrayBatchProvider(array: [provider]),
                                   configuration: nil,
                                   completionHandler: updateModelCompletionHandler)
// 执行更新任务
updateTask!.resume()

需要注意,通常为了增加模型的预测能力,我们不会仅仅使用一组输入来进行更新,以手写数字为例,我们可以让用户多写几次同样的数字,再进行更新。代码中的updateModelCompletionHandler是更新的回调函数,实现如下:

func updateModelCompletionHandler(updateContext: MLUpdateContext) {
    saveUpdatedModel(updateContext)
    print("更新完成")
    
    // 重新预测
    updatedDrawingClassifier = try! UpdatableDrawingClassifier(contentsOf: updatedModelURL)
    let output = try! updatedDrawingClassifier.prediction(input: UpdatableDrawingClassifierInput(drawingWith: UIImage(named: "3")!.cgImage!))
    print("更新后的预测:'\(output.label)'")
    DispatchQueue.main.async {
        self.label.text = self.label.text!.appending("新的预测结果:\(output.label)\n")
    }
}

// 存储更新后的模型
func saveUpdatedModel(_ updateContext: MLUpdateContext) {
    let updatedModel = updateContext.model
    let fileManager = FileManager.default
    do {
        // Create a directory for the updated model.
        try fileManager.createDirectory(at: tempUpdatedModelURL,
                                        withIntermediateDirectories: true,
                                        attributes: nil)
        
        try updatedModel.write(to: tempUpdatedModelURL)
        _ = try fileManager.replaceItemAt(updatedModelURL,
                                          withItemAt: tempUpdatedModelURL)
    } catch let error {
        return
    }
}

运行代码效果如下图所示,可以看到对同样的图片,新的模型已经可以正确识别了。

最后,我们再来总结下可更新模型的使用流程:

  1. 准备要更新的物料数据,包括模型的输入数据,以及预期的输出数据。(通常提供一组)
  2. 将输入与预期结果对应起来创建MLDictionaryFeatureProvider对象。
  3. 通过一组MLDictionaryFeatureProvider对象来创建MLUpdateTask更新任务对象。
  4. 执行更新任务,并在回调中存储更新后的模型。
  5. 使用新的模型进行预测。

完整的示例代码可以在如下地址找到:

https://github.com/ZYHshao/MachineLearnDemo

目录
相关文章
|
7月前
|
机器学习/深度学习 PyTorch TensorFlow
iOS设备功能和框架: 什么是 Core ML?如何在应用中集成机器学习模型?
iOS设备功能和框架: 什么是 Core ML?如何在应用中集成机器学习模型?
185 0
|
机器学习/深度学习 人工智能 自然语言处理
iOS MachineLearning 系列(22)——将其他三方模型转换成CoreML模型
本篇文章将是本系列文章的最后一篇。本专题将iOS中有关Machine Learning的相关内容做了整体梳理。下面是专题中的其他文章地址,希望如果你有需要,本专题可以帮助到你。
364 0
|
数据可视化 数据挖掘 iOS开发
iOS MachineLearning 系列(21)——CoreML模型的更多训练模板
前面文章中,有介绍如何训练生成定制化需求的 CoreML 模型,以图像分类为例做了演示.
218 0
|
人工智能 数据挖掘 API
iOS MachineLearning 系列(20)—— 训练生成CoreML模型
本系列前面的文章详细的介绍了在iOS中与AI能力相关的API的使用,也介绍了如何使用训练好的CoreML模型来实现更强大的AI能力。然而,无论是成熟的API提供的能力,还是各种各样的三方模型,有时候都并不能满足某一领域内的定制化需求。当我们拥有很多的课训练数据,且需要定制化的AI能力时,其实就可以自己训练生成CoreML模型,将此定制化的模型应用到工程中去。
427 0
iOS MachineLearning 系列(20)—— 训练生成CoreML模型
|
自然语言处理 搜索推荐 iOS开发
iOS MachineLearning 系列(19)—— 分析文本中的问题答案
本篇文章将介绍Apple官方推荐的唯一的一个文本处理模型:BERT-SQuAD。此模型用来分析一段文本,并根据提供的问题在文本中寻找答案。需要注意,BERT模型不会生成新的句子,它会从提供的文本中找到最有可能的答案段落或句子。
199 0
iOS MachineLearning 系列(19)—— 分析文本中的问题答案
|
11天前
|
开发框架 前端开发 Android开发
安卓与iOS开发中的跨平台策略
在移动应用开发的战场上,安卓和iOS两大阵营各据一方。随着技术的演进,跨平台开发框架成为开发者的新宠,旨在实现一次编码、多平台部署的梦想。本文将探讨跨平台开发的优势与挑战,并分享实用的开发技巧,帮助开发者在安卓和iOS的世界中游刃有余。
|
2天前
|
Java 调度 Android开发
安卓与iOS开发中的线程管理差异解析
在移动应用开发的广阔天地中,安卓和iOS两大平台各自拥有独特的魅力。如同东西方文化的差异,它们在处理多线程任务时也展现出不同的哲学。本文将带你穿梭于这两个平台之间,比较它们在线程管理上的核心理念、实现方式及性能考量,助你成为跨平台的编程高手。
|
4天前
|
存储 前端开发 Swift
探索iOS开发:从新手到专家的旅程
本文将带您领略iOS开发的奇妙之旅,从基础概念的理解到高级技巧的掌握,逐步深入iOS的世界。文章不仅分享技术知识,还鼓励读者在编程之路上保持好奇心和创新精神,实现个人成长与技术突破。
|
18天前
|
安全 数据处理 Swift
深入探索iOS开发中的Swift语言特性
本文旨在为开发者提供对Swift语言在iOS平台开发的深度理解,涵盖从基础语法到高级特性的全面分析。通过具体案例和代码示例,揭示Swift如何简化编程过程、提高代码效率,并促进iOS应用的创新。文章不仅适合初学者作为入门指南,也适合有经验的开发者深化对Swift语言的认识。
38 9
|
14天前
|
设计模式 Swift iOS开发
探索iOS开发:从基础到高级,打造你的第一款App
【10月更文挑战第40天】在这个数字时代,掌握移动应用开发已成为许多技术爱好者的梦想。本文将带你走进iOS开发的世界,从最基础的概念出发,逐步深入到高级功能实现,最终指导你完成自己的第一款App。无论你是编程新手还是有志于扩展技能的开发者,这篇文章都将为你提供一条清晰的学习路径。让我们一起开始这段旅程吧!