【问题标题】:How to add a CoreML model into a Swift package?如何将 CoreML 模型添加到 Swift 包中?
【发布时间】:2021-01-30 10:07:40
【问题描述】:

我正在尝试编写一个使用 CoreML 模型的 Swift 包。 我对 Swift 包的创建不是很熟悉,我无法让它工作。 以下是我根据迄今为止阅读的不同帖子所做的:

  1. 创建一个空包
$ mkdir MyPackage
$ cd MyPackage
$ swift package init
$ swift build
$ swift test
  1. 用 XCode 打开Package.swift 文件

  2. MyModel.mlmodel文件拖放到Sources/MyPackage文件夹中

当我在 XCode 中单击 MyModel.mlmodel 文件时,我在类名下显示以下消息:

Model is not part of any target. Add the model to a target to enable generation of the model class.

同样,如果我在终端中使用命令 swift build,我会收到以下消息:

warning: found 1 file(s) which are unhandled; explicitly declare them as resources or exclude from the target
    /Path/To/MyPackage/Sources/MyPackage/MyModel.mlmodel
  1. 为了解决这个问题,我在Package.swift文件中的目标资源中添加了MyModel
.target(
    name: "MyPackage",
    dependencies: [],
    resources: [.process("MyModel.mlmodel")]),

如果我现在使用命令 $ swift build,我将不再收到警告,并收到消息:

[3/3] Merging module MyPackage

但是当我在 XCode 中检查 MyModel.mlmodel 文件时,我在类名下显示以下消息:

Model class has not been generated yet.
  1. 为了解决这个问题,我在终端中使用了以下命令:
$ cd Sources/MyPackage 
$ xcrun coremlcompiler generate MyModel.mlmodel --language Swift . 

这会在 mlmodel 文件旁边生成一个 MyModel.swift 文件。

  1. 我将模型插入代码MyPackage.swift
import CoreML

@available(iOS 12.0, *)
struct MyPackage {
    var model = try! MyModel(configuration: MLModelConfiguration())
}
  1. 最后,在测试文件MyPackageTests.swift中,我创建了一个MyPackage的实例:
import XCTest
@testable import MyPackage

final class MyPackageTests: XCTestCase {
    func testExample() {
        if #available(iOS 12.0, *) {
            let foo = MyPackage()
        } else {
            // Fallback on earlier versions
        }
    }

    static var allTests = [
        ("testExample", testExample),
    ]
}

我得到以下错误(似乎没有找到CoreML模型):

Thread 1: Fatal error: Unexpectedly found nil while unwrapping an Optional value

我一定错过了什么…… 我希望我的描述足够清晰和详细。 感谢您的帮助!

【问题讨论】:

    标签: swift coreml swift-package-manager


    【解决方案1】:

    下面描述的解决方案对我有用。我希望它是正确的。

    MLModel 的转换

    MLModel 不能直接在 Swift 包中使用。首先需要转换。

    $ cd /path/to/folder/containg/mlmodel
    $ xcrun coremlcompiler compile MyModel.mlmodel .
    $ xcrun coremlcompiler generate MyModel.mlmodel . --language Swift
    

    第一个xcrun 命令将编译模型并创建一个名为MyModel.mlmodelc 的文件夹。 第二个xcrun 命令将生成一个MyModel.swift 文件。

    将模型添加到 Swift 包中

    我们认为 Swift 包已经存在并且位于/path/to/MyPackage/

    1. MyModel.mlmodelc文件夹和MyModel.swift文件复制到/path/to/MyPackage/Sources/MyPackage文件夹中
    2. 在文件Package.swift的目标资源中添加MyModel.mlmodelc
    .target(
        name: "MyPackage",
        dependencies: [],
            resources: [.process("MyModel.mlmodelc")]),
    

    实例化 MyModel

    在 Swift 代码中,只需创建 MyModel 的一个实例:

    let model = try? MyModel(configuration: MLModelConfiguration())
    

    或:

    let url = Bundle.module.url(forResource: "MyModel", withExtension: "mlmodelc")!
    let model = try? MyModel(contentsOf: url, configuration: MLModelConfiguration())
    

    疑难解答

    我一开始遇到Type 'MLModel' has no member '__loadContents' 错误。 这似乎是与 XCode 12 相关的错误。 我只是评论了导致问题的 2 个函数。

    请参阅herehere 了解更多信息。

    【讨论】:

      【解决方案2】:

      这行可能是出错的地方:var model = try! MyModel(configuration: MLModelConfiguration())

      由于您已将 mlmodel 文件添加到包中,因此尚未对其进行编译。我不是 Swift 包方面的专家,但我不相信 Xcode 现在会自动编译这个模型。当您打开编译后的应用程序包时,您可以自己看到这一点——其中是否有 mlmodel 文件或 mlmodelc 文件夹?

      您可能需要将 mlmodelc 添加到包中,而不是 mlmodel。您可以通过以下方式创建它:

      $ xcrun coremlcompiler compile MyModel.mlmodel . 
      

      接下来,在您的应用中,您需要按如下方式加载模型:

      let url = YourBundle.url(forResource: "MyModel", withExtension: "mlmodelc")!
      let model = try! MyModel(contentsOf: url, configuration: MLModelConfiguration())
      

      其中YourBundle 是对包含 mlmodelc 文件的包的引用(我猜它是 Swift 包的包)。

      【讨论】:

        猜你喜欢
        • 2019-09-21
        • 2020-08-25
        • 2019-10-18
        • 2014-03-13
        • 2017-09-23
        • 2021-04-09
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多