AKARI Tech Blog

燈株式会社のエンジニア・開発メンバーによる技術ブログです

CoreMLで独自モデル導入入門

みなさんこんにちは!

3週目のAKARI Tech Blog担当になりました、
DX Solution 事業本部 Dev チームリーダーの三澤(拓真)が担当します!普段は画像・点群系のAIエンジニアをしています!

今回の記事では「iOS機械学習を扱うためのフレームワークであるCoreML」についてご紹介しようと思います!

TL;DR

1. Core MLとは?

iOS機械学習を扱うためのフレームワークとして、Core MLがあります。
iOS11で登場し、他のフレームワークと比べて扱いやすい点が特に評価されて人気が出ているようです。
後述する方法を用いてCoreML Modelを用意することで、Core ML経由でCPU, Neural Engineにアクセスできます。

https://developer.apple.com/documentation/coreml

2. 何がいいの?

じゃあ、Core MLを扱えて何がいいの?という話ですが、なんといってもオンデバイス機械学習(特に画像系)を気軽に扱えることだと思っています。
一般的に想像されるエッジデバイス(raspi, Jetson等)では軽量化されたモデルを動かしたり、onnx化したり…と色々あります。 しかし、iOSiPad OSで動かすには、一見ハードルが高そうに見えますよね。

Core MLを使えば、難しいことを考えずに動かせます!

また、iPhone, iPad自体は処理能力に加えてカメラやセンサー類も優秀ですので、画像系との相性がとてもいいと思います!

3. Core ML Modelの作成方法

CoreML Modelを作成する方法は2025年2月27日時点で以下の2つが主流だと思います!

  • CreateMLを使ってMac上で訓練する方法
  • coremltoolsを使って訓練済みモデルを変換する方法
    • coremltools 4.0からはonnx経由で変換することが非推奨になったので注意.
      • Pytorchモデルから直接coremlモデルに変換できます

3.1 CreateMLを使用する方法

iOSに限らず、私が知っている中で一番簡単にモデルを訓練できる方法だと思っているCreateMLですが、大まかな手順は以下です!

Xcodeを入手 (入手されていない方は手順2までに色々と手間がかかるかもしれませんが、今回は入っている前提で進めます)

② 左上のXcode > Open Developer Tool > CreateMLを選択

③ New Documentで訓練させたいタスクに対してのテンプレートを選択可能(今回はImage Classification)

④ ProjectNameを決めて作成

あとはtrain ,val, testでそれぞれデータを渡してあげるだけ!

これだけの手順で訓練から推論までできるCreateML、素晴らしいですよね。
個人的には、モデルのアーキテクチャや詳細なパラメータが抽象化されているおかげで経験が少ない人でも触れるようになっていることが魅力的に感じます。
ただ、普段からAI開発をしていて精度を求める人は次に紹介する方法でモデル変換をした方がいいと思います。

3.2 coremltoolsを使用する方法

すでに訓練済みのモデルをCoreML Modelとして扱いたい場合は、coremltoolsを使って変換することができます。

pythonを使ってpytorchのモデルを変換させてみる手順を紹介します!
今回、torchvisionで用意されている事前学習済みモデルを使おうと思っていますが、モデル自体がdictを返すため、そのままだとエラーが起きます。そのため、既存のモデルのWrapperを作成して受け取れる形式のmodelを作成します。

import coremltools as ct
import torch
import torchvision
import json

class WrappedSegmentationModel(torch.nn.Module):
    def __init__(self, model: torch.nn.Module):
        super(WrappedSegmentationModel, self).__init__()
        self.model = model
    
    def forward(self, x: torch.Tensor) -> torch.Tensor:
        return self.model(x)["out"]

model = torchvision.models.segmentation.deeplabv3_resnet50(pretrained=True)
model = WrappedSegmentationModel(model) # これがないとエラーが起きる
model.eval()

3.2.3 pytorchのモデルをtraceする

CoreML Modelに変換するために、モデルをTorchScriptの形式に変換する必要があります。
とは言ってもそんなに難しくなく、入力を定義して渡すだけでできます。

example_input = torch.rand(1, 3, 224, 224)
traced_model = torch.jit.trace(model, example_input, strict=False)

3.2.4 CoreML Modelに変換

あとはtraced_modelをCoreML Modelに変換するだけです!

labels_json = {"labels": ["background", "aeroplane", "bicycle", "bird", "board", "bottle", "bus", "car", "cat", "chair", "cow", "diningTable", "dog", "horse", "motorbike", "person", "pottedPlant", "sheep", "sofa", "train", "tvOrMonitor"]}

mlmodel = ct.convert(
    traced_model,
    inputs=[ct.ImageType(name="input", shape=example_input.shape, color_layout="RGB", scale=1/255.0, bias=[-2.1179, -2.0357, -1.8044])],
    outputs=[ct.TensorType(name="output")]
)

mlmodel.user_defined_metadata["com.apple.coreml.model.preview.type"] = "imageSegmenter"
mlmodel.user_defined_metadata["com.apple.coreml.model.preview.params"] = json.dumps(labels_json)

なんだ、これだけ?と思う方もいるかもしれませんが、調べてみると先駆者が少なくて絶望した方も多いかもしれません。 ちゃんとcoremltoolsのドキュメント(https://apple.github.io/coremltools/docs-guides/source/xcode-model-preview-types.html)を読み込む必要がありますが、特にハマりがちなポイントをいくつか紹介します!


ハマりポイント1 - 正規化の有無

さりげなくinputsでImageType を指定していますが、ネットで調べるとTensorTypeで書かれていることもあります。 iOSで扱う場合、どちらを指定しても動かせますが、画像系のモデルを動かすならImageType を指定することを推奨します。 それは、正規化をフローの中に組み込めるかどうか、です。

今回だとImageNetを訓練させた重みを使っているので、mean = [0.485, 0.456, 0.406], std = [0.229, 0.224, 0.225] という値で正規化されています。bias = - mean / std になるので、今回だとscale=1/255.0, bias=[-2.1179, -2.0357, -1.8044] を指定します。これを指定しないと、悲惨なことになります。

scale, biasの指定なし

なんだこりゃ。

scale, biasの指定あり
ImageTypeを指定することでうまくセグメンテーションされました!


ハマりポイント2 - .mlmodel vs .mlpackage

調べていると、多くの人がモデルの書き出しを.mlmodelで実施しています。
しかし、いくつか前のバージョンからmlpackageが出てきており、現在は.mlpackageが推奨されています。
調べてみると.mlpackageではプレビューが出ないなどの問題が見つかりますが、現在のバージョンではほとんど解決されているので安心してmlpackageを使いましょう!(最新のcoremltoolsではmlmodelを使うとエラーが出ました)


ハマりポイント3 - プレビューできない

CoreML Modelは、変換方法によってXCodeでプレビュー(推論)ができます。
ImageType同様、iOSで扱う場合にはプレビューを出さなくてもいいんですが、ちゃんと変換できたかの確認のために毎回アプリに組み込んで…としているととても時間がかかるので、プレビューを使うことをお勧めします。

しかし、プレビューを出すのにも実はいくつかの苦労が…
今回だと最後にさりげなく書いていたこの2行です。

mlmodel.user_defined_metadata["com.apple.coreml.model.preview.type"] = "imageSegmenter"
mlmodel.user_defined_metadata["com.apple.coreml.model.preview.params"] = json.dumps(labels_json)

これでpreviewのtypeとlabelを付与しています。これがないと、プレビューができません…

こんな感じでプレビューされる


3.2.5 コード全体

import coremltools as ct
import torch
import torchvision
import json

class WrappedSegmentationModel(torch.nn.Module):
    def __init__(self, model: torch.nn.Module):
        super(WrappedSegmentationModel, self).__init__()
        self.model = model
    
    def forward(self, x: torch.Tensor) -> torch.Tensor:
        return self.model(x)["out"]

model = torchvision.models.segmentation.deeplabv3_resnet50(pretrained=True)
model = WrappedSegmentationModel(model)
model.eval()

example_input = torch.rand(1, 3, 224, 224)
traced_model = torch.jit.trace(model, example_input, strict=False)
labels_json = {"labels": ["background", "aeroplane", "bicycle", "bird", "board", "bottle", "bus", "car", "cat", "chair", "cow", "diningTable", "dog", "horse", "motorbike", "person", "pottedPlant", "sheep", "sofa", "train", "tvOrMonitor"]}

mlmodel = ct.convert(
    traced_model,
    inputs=[ct.ImageType(name="input", shape=example_input.shape, color_layout="RGB", scale=1/255.0, bias=[-2.1179, -2.0357, -1.8044])],
    outputs=[ct.TensorType(name="output")]
)

mlmodel.user_defined_metadata["com.apple.coreml.model.preview.type"] = "imageSegmenter"
mlmodel.user_defined_metadata["com.apple.coreml.model.preview.params"] = json.dumps(labels_json)

mlmodel.save("DeepLabV3ResNet50.mlpackage")

4. その他のモデル活用

ここまで作り方を説明してきましたが、すでにCoreML Modelに変換されているものを使うという手もあります。

例えば、Appleのhuggingfaceに飛ぶと単眼深度推定、セマンティックセグメンテーション、画像分類、画像生成…など、いろいろなcoremlモデルが公開されています。

https://huggingface.co/apple

おそらく、一番手っ取り早いのはこれらのモデルを使うことだと思います。公式が出してることもあって、ちゃんと高速で精度も良さげです。

Depth Anything V2 Core MLをiOS上でリアルタイムに動かしている様子

他にも、huggingfaceなどで変換されたモデルがあったり、githubで変換するコードを置いていたりするので、それを活用する、という選択肢もあります。

まとめ

CoreMLは簡単なのに扱いやすいので、機械学習の選択肢にiOSを入れてみるのはどうでしょうか??

We’re Hiring!

燈では、iOSエンジニア/AIエンジニア/ソフトウェアエンジニアを、正社員もインターンのどちらも募集しております!

興味がある方は、ぜひカジュアル面談でお話しましょう!🔥

akariinc.co.jp

今回の記事を書いた燈メンバー🙌

www.wantedly.com