プログラミング

【iOS】Pythonで画像をAIで判別するiOSアプリを作ってみた!!

どうもなまこです。

今回はプログラミングを勉強して得たアウトプットを紹介したいと思います。

私はPythonをメインにプログラミングを勉強しています。Pythonと言えばAI開発でよく用いられている言語です。現代のAIでは主に機械学習とディープラーニングが使われています。

今回はディープラーニングの技術を使って写真を自動で判別するアプリを作ってみました。

この記事ではPythonを初めとして、NumPy、TensorFlowのライブラリを使用していきます。また、iOSのアプリを作成するため、swiftとXcodeを使用していきます。細かい解説はしませんが要望あれば記事を追加していく予定です。

作成するもの

今回は自動車、オートバイ、自転車、歩行者を写真で見分けるアプリを作成していきます。iOSでアプリを起動し、写真と撮ると自動車かオートバイか自転車か歩行者を判別し、何パーセントの確率で一致しているか表示するアプリを作成します。

用意するもの

なんか料理みたいになってきましたね。でも開発ってそんなものかも。

学習データ用の写真

ディープラーニングを使用するため、学習用のデータが必要になります。今回の場合自動車、オートバイ、自転車、歩行者の写真をそれぞれ300枚ずつ用意します。画像はただでさえ情報を持っているのでそこまでサイズの大きい画像でなくても十分に学習することができます。今回は150×150のサイズにリサイズして集めました。

自力で集めようとするとしんどいのでAPIを使ってダウンロードを自動化して集めました。詳細はここでは書きませんがネットで調べるとさまざまな方法ありますので割愛します。こちらも需要があれば追加していこうかと思います。

API(Application programming interface)とは簡単に言うとアプリケーションを簡単に使えるようにしてくれている方法・手法です

GPU搭載のPC

ディープラーニングさせるためには高性能なGPUがあるのが理想です。少々値段が高いのでGPU搭載のPCがない場合はGoogle ColaboratoryのGPUを利用するのも手です。私はMacbook Airを使用していますがクラウドのGPUを使用すれば十分に戦えます。Google ColaboratoryのGPUを使用する方法は過去の記事にも記載していますので参考にしてみてください。

低スペックPCでも機械学習やディープラーニングを利用できる方法機械学習やディープラーニングはプログラミング学習の中でも高スペックなマシンが要求されます。初期費用のハードルがあるため、とっつきにくい分野ですが、クラウドのサービスを利用することで安くお試しができます。そこそのスペックのPCでも機械学習やディープラーニングのコンテンツが利用できる方法をまとめてみました。...

画像をバイナリファイルにする

画像はそのままだと扱えないので画像扱うデータに変換します。car, bicycle, motorcycle, pedestrianの各フォルダに300枚づつ保管しているjpgファイルを見つけ出し、Pillowで読み出し、NumPyでバイナリファイルにしていきます。

0と1で表されるデータをバイナリといいます。画像も細かく言えば0と1で表現されるデータとなります

画像データをかさ増しする

同じ画像でも上下左右反転しても同一のものだと認識する必要があります。また、ディープラーニングはデータの数の多さが決めてとなるので、データをかさ増ししていきます。角度を少しすつ回転させたデータを作成します。さらに画像を反転したデータも追加していきました。

訓練データとテストデータに分ける

sklearnのモジュールを使って訓練データとテストデータを切り分けていきます。訓練データとテストデータをバイナリファイル(npyファイル)で保存します。

モデルを学習する時は必ず訓練データとテストデータを分けるようにします。全データで学習してしまうと学習したデータだけに適合するモデルができてしまうためです。
from PIL import Image
import os, glob
import numpy as np
from sklearn import model_selection

classes = ["car", "bicycle", "motorcycle", "pedestrian"]
num_class = len(classes)
image_size = 50
num_testdata = 50

# 画像の読み込み

X_train = []
X_test = []
Y_train = []
Y_test = []

for index, classlabel in enumerate(classes):
    photos_dir = "./" + classlabel
    files = glob.glob(photos_dir + "/*.jpg")
    for i, file in enumerate(files):
        if i >=300: break
        image = Image.open(file)
        image = image.convert("RGB")
        image = image.resize((image_size, image_size))
        data = np.asarray(image)
        if i < num_testdata:
            X_test.append(data)
            Y_test.append(index)
        else:
            for angle in range(-20, 20, 5):
                # 回転
                img_r = image.rotate(angle)
                data = np.asarray(img_r)
                X_train.append(data)
                Y_train.append(index)

                # 反転
                img_trans = image.transpose(Image.FLIP_LEFT_RIGHT)
                data = np.asarray(img_trans)
                X_train.append(data)
                Y_train.append(index)

X_train = np.array(X_train)
X_test = np.array(X_test)
y_train = np.array(Y_train)
y_test = np.array(Y_test)

xy = (X_train, X_test, y_train, y_test)
np.save("./vehicle_aug.npy", xy)

モデルを作成する

上記のバイナリファイルを使ってモデルを学習させていきます。

モデルを学習させる

畳み込みニューラルネットワーク(以後CNN)というものを使ってモデルを学習していきます。CNNについては以下のサイトを参考ください。

畳み込みニューラルネットワーク

活性関数はreluを使用していきます。

他のプログラムはロースペックのPCでもそれほど時間はかかりませんが、モデルを学習させるここからはGPU搭載のPCを使うのがおすすめです。Google ColaboratoryのGPUを拝借すれば数秒で学習が可能です。過去にアップした動画ですがいかに早く学習できるかわかることができます。

精度を上げるようにパラメータを調整する

Testの精度が6.5〜7割くらいであれば十分かと思います。精度が低い場合はエポックや学習率を変更して精度をあげていきます。

学習モデルをh5ファイルで保存する

学習モデルをh5ファイルに保存していきます。

from keras.models import Sequential
from keras.layers import Conv2D, MaxPooling2D
from keras.layers import Activation, Dropout, Flatten, Dense
from keras.utils import np_utils
import numpy as np
import keras

classes = ["car", "bicycle", "motorcycle", "pedestrian"]
num_class = len(classes)
image_size = 50

# メインの関数を定義する
def main():
    X_train, X_test, y_train, y_test = np.load("./vehicle_aug.npy", allow_pickle=True)
    X_train = X_train.astype("float") / 256
    X_test = X_test.astype("float") / 256
    y_train = np_utils.to_categorical(y_train, num_class)
    y_test = np_utils.to_categorical(y_test, num_class)

    model = model_train(X_train, y_train)
    model_eval(model, X_test, y_test)

def model_train(X, y):
    model = Sequential()
    model.add(Conv2D(32, (3,3), padding='same', input_shape=X.shape))
    model.add(Activation('relu'))
    model.add(Conv2D(32, (3,3)))
    model.add(Activation('relu'))
    model.add(MaxPooling2D(pool_size=(2,2)))
    model.add(Dropout(0.25))

    model.add(Conv2D(64, (3,3), padding='same'))
    model.add(Activation('relu'))
    model.add(Conv2D(64, (3,3)))
    model.add(Activation('relu'))
    model.add(MaxPooling2D(pool_size=(2,2)))
    model.add(Dropout(0.25))

    model.add(Flatten())
    model.add(Dense(512))
    model.add(Activation('relu'))
    model.add(Dropout(0.5))
    model.add(Dense(4))
    model.add(Activation('softmax'))

    opt = keras.optimizers.RMSprop(lr=0.0001, decay=1e-6)
    model.compile(
        loss='categorical_crossentropy',
        optimizer=opt,
        metrics=['accuracy']
    )

    model.fit(X, y, batch_size=32, epochs=100)

    # モデルの保存
    model.save('./vehicle_cnn_aug.h5')

    return model

def model_eval(model, X, y):
    scores = model.evaluate(X, y, verbose=1)
    print('Test Loss: ', scores[0])
    print('Test Accuracy: ', scores)


if __name__ == '__main__':
    main()

モデルを使ってアプリでデプロイする

Xcodeを使ってiOSアプリを作成していきます。Xcodeはswiftという言語で書く必要があります。学習モデルをh5ファイルで作成しましたが、そのままではiOSのアプリには使えません。学習モデルをiOSで使用できるmlmodelにしていく必要があります。

h5ファイルをmlmodelに変換する

CNNを使って学習モデルをh5ファイルにしましたが、そのままではiOSのアプリには使えないのでmlmodelファイルにしていきます。

import coremltools

coreml_model = coremltools.converters.keras.convert(
    'vehicle_cnn_aug.h5',
    input_names='image',
    image_input_names='image',
    output_names='Prediction',
    class_labels=['car', 'bycycle', 'motorcycle', 'pedestrian'],
)

coreml_model.save('./vehicle_cnn_aug.mlmodel')

mlmodelをviewcontrollerに組み込む

func imagePrediction(image: UIImage) {
        guard let model = try? VNCoreMLModel(for: vehicle_cnn_aug().model) else {
            fatalError("Model not found")
        }
        
        let request = VNCoreMLRequest(model: model) {
            [weak self] request, error in
            
            guard let results = request.results as? [VNClassificationObservation],
                let firstResult = results.first else {
                    fatalError("No results found")
            }
            
            DispatchQueue.main.async {
                self?.predictDisplay.text = "Accuracy: = \(Int(firstResult.confidence * 100))% \n\nラベル: \((firstResult.identifier))"
            }
        }
        
        guard let ciImage = CIImage(image: image) else {
            fatalError("Can't convert image.")
        }
        
        let imageHandler = VNImageRequestHandler(ciImage: ciImage)
        
        DispatchQueue.global(qos: .userInteractive).async {
            do {
                try imageHandler.perform([request])
            } catch {
                print("Error")
            }
        }
    }

実際にアプリを使ってみる

実際にアプリを起動して試してみようとしましたが、iOS13の時に作ったアプリでiOS14で動かそうとしたらバージョンの違いか起動しませんでしたOTL

前はできていたのに〜😭

coremltoolのバージョンの違いな気もするのでまたうまく行った段階で記事を更新できればと思います。

まとめ

iOSでアプリを作りましたがAndroidでも同様のアプリは作成可能です。Androidアプリの作成はまだしたことありませんがいつかチャレンジしてみたいと思います!!

ポイント
  • 画像データをバイナリファイルにして訓練データとテストデータに分ける
  • CNNを使って学習し、モデルをh5ファイル保存する
  • h5ファイルをiOSでも使えるようにmlmodelを作成する
  • mlmodelを使ってXcodeでアプリを作る

今後もこのように作ったものや学習したものとかを紹介できればと考えています。

COMMENT

メールアドレスが公開されることはありません。 * が付いている欄は必須項目です