在iOS上通过ML Kit使用TensorFlow Lite模型进行推理

您可以使用ML Kit配合TensorFlow Lite模型执行在设备上的推理 。

ML Kit只能在运行iOS 9或更新版本的设备上使用TensorFlow Lite模型。

请参阅GitHub上的ML Kit快速入门示例,了解正在使用的此API的示例。

在开始之前

  1. 如果您还没有将Firebase添加到您的程序当中,那您可以从开始指南来开始您的工作。

  2. 将ML kit库放进您的Podfile中:

    1. pod 'Firebase/Core'
    2. pod 'Firebase/MLModelInterpreter'

​ 而后每次您要安装或者升级您的Pods的时候,请确保使用您的Xcode项目的.xcworkspace来打开它。

  1. 在您的程序中,引入Firebase:

    Swift:

    1. import Firebase

    Objective-C:

    1. @import Firebase;
  2. 转换您想要的TensorFlow模型为TensorFlow Lite(tflite)格式。请查看TOCO:TensorFlow Lite 优化转换器

托管或捆绑您的模型

在您的应用程序中使用TensorFlow Lite模型进行推理之前,您必须将该模型提供给ML Kit。ML Kit可以使用Firebase远程托管的,本地存储在设备上的或两者兼而有之的TensorFlow Lite模型。

通过在Firebase上托管模型并在本地支持,您可以确保在模型可用时使用最新版本的模型,但是当Firebase托管的模型不可用时,您的应用程序的ML功能仍可使用。

模型安全

无论您如何向ML Kit提供您的TensorFlow Lite模型,ML Kit都将它们以标准序列化protobuf格式存储在本地存储中。

理论上,这意味着任何人都可以复制你的模型。但是,实际上,大多数模型都是特定于应用程序的,并且通过优化进行混淆,以至于风险与拆分和重用代码的竞争对手相似。因而,在应用中使用自定义模型之前,您应该意识到这种风险。

在Firebase上托管的模型

要在Firebase上托管您的TensorFlow Lite模型,请执行以下操作:

  1. Firebase控制台ML Kit部分中,点击自定义标签。
  2. 点击添加自定义模型(或添加其他模型)。
  3. 指定将用于在Firebase项目中标识您的模型的名称,然后上传该.tflite文件。

将自定义模型添加到Firebase项目后,您可以使用指定的名称在应用中引用该模型。在任何时候,您都可以上传.tflite模型的新文件,然后您的应用将下载新模型,并在应用下次重新启动时开始使用它。您可以定义您的应用程序尝试更新模型所需的设备条件(请参阅下文)。

使模型可在本地使用

为了让您的TensorFlow Lite模型在本地可用,您可以将模型与应用程序捆绑在一起,也可以在运行时从您自己的服务器上下载模型。

要将TensorFlow Lite模型与您的应用程序捆绑在一起,请将该.tflite文件添加到您的Xcode项目中,注意选择复制捆绑软件资源。该.tflite文件将包含在应用程序包中,并可用于ML Kit。

如果您将模型托管在自己的服务器上,则可以在您应用程序的适当位置将模型下载到本地存储。然后,该模型将作为本地文件提供给ML Kit。

加载模型

要使用TensorFlow Lite模型进行推理,请首先指定.tflite文件的位置 。

如果您使用Firebase托管您的模型,请注册一个CloudModelSource对象,指定您上传模型时分配给模型的名称,以及最初ML Kit应该下载模型以及何时可用更新的条件。

Swift:

  1. let conditions = ModelDownloadConditions(wiFiRequired: true, idleRequired: true)
  2. let cloudModelSource = CloudModelSource(
  3. modelName: "my_cloud_model",
  4. enableModelUpdates: true,
  5. initialConditions: conditions,
  6. updateConditions: conditions
  7. )
  8. let registrationSuccessful = ModelManager.modelManager().register(cloudModelSource)

Objective-C:

  1. FIRModelDownloadConditions *conditions =
  2. [[FIRModelDownloadConditions alloc] initWithWiFiRequired:YES
  3. idleRequired:YES];
  4. FIRCloudModelSource *cloudModelSource =
  5. [[FIRCloudModelSource alloc] initWithModelName:@"my_cloud_model"
  6. enableModelUpdates:YES
  7. initialConditions:conditions
  8. updateConditions:conditions];
  9. BOOL registrationSuccess =
  10. [[FIRModelManager modelManager] registerCloudModelSource:cloudModelSource];

如果将模型与您的应用程序捆绑在一起,或者在运行时从您自己的主机下载模型,请注册一个LocalModelSource对象,指定.tflite模型的本地路径,并为本地源分配一个唯一名称,以在您的应用程序中识别它。

Swift:

  1. guard let modelPath = Bundle.main.path(
  2. forResource: "my_model",
  3. ofType: "tflite"
  4. ) else {
  5. // 不恰当的路径
  6. return
  7. }
  8. let localModelSource = LocalModelSource(modelName: "my_local_model",
  9. path: modelPath)
  10. let registrationSuccessful = ModelManager.modelManager().register(localModelSource)

Objective-C:

  1. NSString *modelPath = [NSBundle.mainBundle pathForResource:@"my_model"
  2. ofType:@"tflite"];
  3. FIRLocalModelSource *localModelSource =
  4. [[FIRLocalModelSource alloc] initWithModelName:@"my_local_model"
  5. path:modelPath];
  6. BOOL registrationSuccess =
  7. [[FIRModelManager modelManager] registerLocalModelSource:localModelSource];

然后,用Cloud源,本地源或两者兼有创建一个ModelOptions对象,并使用它来获取一个ModelInterpreter实例。如果您只有一个来源,请指定nil为您不使用的来源类型。

Swift:

  1. let options = ModelOptions(
  2. cloudModelName: "my_cloud_model",
  3. localModelName: "my_local_model"
  4. )
  5. let interpreter = ModelInterpreter(options: options)

Objective-C:

  1. FIRModelOptions *options = [[FIRModelOptions alloc] initWithCloudModelName:@"my_cloud_model"
  2. localModelName:@"my_local_model"];
  3. FIRModelInterpreter *interpreter = [FIRModelInterpreter modelInterpreterWithOptions:options];

如果您同时指定了云模型源和本地模型源,那么模型解释器将在云模型可用时使用云模型,如果云模型不可用,则会回退到本地模型。

指定模型的输入和输出

接下来,您必须通过创建ModelInputOutputOptions对象来指定模型输入和输出的格式 。

TensorFlow Lite模型将输入作为输出并生成一个或多个多维数组。这些数组包含UInt8Int32Int64,或Float32。您必须为ML Kit配置模型使用的数组的number和dimensions(“shape”)。

例如,一个图像分类模型可能需要输入一个1x640x480x3字节的数组,代表一个640x480真彩色(24位)图像,并产生一个1000个Float32值的列表,每个值决定了图像是处于概率模型预测的1000个类别中的一个成员类别中的概率。

Swift:

  1. let ioOptions = ModelInputOutputOptions()
  2. do {
  3. try ioOptions.setInputFormat(index: 0, type: .uInt8, dimensions: [1, 640, 480, 3])
  4. try ioOptions.setOutputFormat(index: 0, type: .float32, dimensions: [1, 1000])
  5. } catch let error as NSError {
  6. print("Failed to set input or output format with error: \(error.localizedDescription)")
  7. }

Objective-C:

  1. FIRModelInputOutputOptions *ioOptions = [[FIRModelInputOutputOptions alloc] init];
  2. NSError *error;
  3. [ioOptions setInputFormatForIndex:0
  4. type:FIRModelElementTypeUInt8
  5. dimensions:@[@1, @640, @480, @3]
  6. error:&error];
  7. if (error != nil) { return; }
  8. [ioOptions setOutputFormatForIndex:0
  9. type:FIRModelElementTypeFloat32
  10. dimensions:@[@1, @1000]
  11. error:&error];
  12. if (error != nil) { return; }

对输入数据进行推理

最后,要使用模型执行推理,请使用模型输入创建一个ModelInputs 对象,并将模型输入和模型的输入和输出选项传递给模型解释器的run(inputs:options:)方法。为获得最佳性能,请将模型输入作为DataNSData)对象传递。

Swift:

  1. let input = ModelInputs()
  2. do {
  3. var data: Data // or var data: Array
  4. // Store input data in `data`
  5. // ...
  6. try input.addInput(data)
  7. // 对输入的指数重复有必要
  8. } catch let error as NSError {
  9. print("Failed to add input: \(error.localizedDescription)")
  10. }
  11. interpreter.run(inputs: input, options: ioOptions) { outputs, error in
  12. guard error == nil, let outputs = outputs else { return }
  13. // 实现输出
  14. // ...
  15. }

Objective-C:

  1. FIRModelInputs *inputs = [[FIRModelInputs alloc] init];
  2. NSData *data; // Or NSArray *data;
  3. // ...
  4. [inputs addInput:data error:&error]; // 重复的必要
  5. if (error != nil) { return; }
  6. [interpreter runWithInputs:inputs
  7. options:ioOptions
  8. completion:^(FIRModelOutputs * _Nullable outputs,
  9. NSError * _Nullable error) {
  10. if (error != nil || outputs == nil) {
  11. return;
  12. }
  13. // 实现输出
  14. // ...
  15. }];

您可以通过调用output(index:)返回的对象的方法来获取输出。例如:

Swift:

  1. // Get first and only output of inference with a batch size of 1
  2. let probabilities = try? outputs.output(index: 0)

Objective-C:

  1. // Get first and only output of inference with a batch size of 1
  2. NSError *outputError;
  3. [outputs outputAtIndex:0 error:&outputError];

您如何使用输出取决于您使用的模型。例如,如果您正在执行分类,那么作为下一步,您可能会将结果的索引映射到它们所代表的标签。