[Object Detection][CoreML][TuriCreate][jupyter notebook][XamariniOS]自作の学習データで物体認識AIを学習させてスマホに移植

Yutaka_kun
LSC PSD
Published in
10 min readOct 22, 2021

タブレット・携帯端末で動く物体認識AIを作りたかったので、色々調べながら泥臭くやりました。途中「神の声」もかりながらやりましたが一応それっぽいものができたと思います。

サンプルAIを動かす

まずはそもそもスマホでAIなるものが動くかわからなかったので、サンプルモデルを探して動かしてみました。
appleのサイトからサンプルコードをクローンして、「BreakfastFinder」をビルドしてみると意外と簡単に動かせました。

AIの起動や処理のコードもそうですが

カメラの初期化
撮影画像をリアルタイムで処理をかけて画面に出力する

部分など結構そっちの方が勉強になりました。
ちなみに一行一行デバックで追って解読していったので、、ここだけで3日くらい潰れてます。

*私の指はバナナだそうです

サンプルデータでサンプルAIをトレーニングしてみる

AIがスマホで動くことが分かったので、今度はサンプルAIがサンプルデータで学習できるか調べてみます。

appleのサイトの説明にしたがってサンプルデータ(車と自転車)をダウンロードします。これは下記の通りにやればダウンロードできました。

$ mkdir -p ~/Downloads/ig02
$ cd ~/Downloads/ig02
$ curl https://lear.inrialpes.fr/people/marszalek/data/ig02/ig02-v1.0-bikes.zip > bikes.zip
$ curl https://lear.inrialpes.fr/people/marszalek/data/ig02/ig02-v1.0-cars.zip > cars.zip
$ unzip bikes.zip
$ mv readme.txt readme-bikes.txt
$ unzip cars.zip
$ rm bikes.zip cars.zip

Turi Createをインストールしておきます

pip install turicreate

Turi Createでサンプルデータの準備をします。基本的な流れはサイトの手順に従えばいけるとは思いますが、サイトのままではエラーが起きたので私の環境でうまく行ったコードを貼り付けておきます。
ちなみにjupyter notebookで実行するとやりやすいと思います。

import turicreate as tc
import os
ig02_path = 'Downloads/ig02'raw_sf = tc.image_analysis.load_images(ig02_path, recursive=True,
random_order=True)
info = raw_sf['path'].apply(lambda path: os.path.basename(path).split('.')[:2])info = info.unpack().rename({'X.0': 'name', 'X.1': 'type'})raw_sf = raw_sf.add_columns(info)raw_sf['label'] = raw_sf['name'].apply(lambda name: name.split('_')[0])del raw_sf['path']sf_images = raw_sf[raw_sf['type'] == 'image']
sf_masks = raw_sf[raw_sf['type'] == 'mask']
def mask_to_bbox_coordinates(img):
import numpy as np
mask = img.pixel_data
if mask.max() == 0:
return None

x0, x1 = np.where(mask.max(0))[0][[0, -1]]
y0, y1 = np.where(mask.max(1))[0][[0, -1]]
return {'x': (x0 + x1) / 2, 'width': (x1 - x0),
'y': (y0 + y1) / 2, 'height': (y1 - y0)}
sf_masks['coordinates'] = sf_masks['image'].apply(mask_to_bbox_coordinates)sf_masks = sf_masks.dropna('coordinates')sf_masks = sf_masks.pack_columns(['label', 'coordinates'],
new_column_name='bbox', dtype=dict)
sf_annotations = sf_masks.groupby('name',
{'annotations': tc.aggregate.CONCAT('bbox')})
sf = sf_images.join(sf_annotations, on='name', how='left')sf['annotations'] = sf['annotations'].fillna([])del sf['type']sf.save('ig02.sframe')

準備ができたので、トレーニングさせてみます。
トレーニングはサイトどおりに進めればできるはずです。
短いコードなので一応貼り付けておきます。

import turicreate as tcdata = tc.SFrame('ig02.sframe')train_data, test_data = data.random_split(0.8)model = tc.object_detector.create(train_data)predictions = model.predict(test_data)metrics = model.evaluate(test_data)

model.save('ig02.model')

model.export_coreml('Car_Bike_Detector.mlmodel')

作成されたCar_Bike_Detecter.mlmodelをBreakfastFinderのObjectDetecter.mlmodelと入れ替えてビルドします。
カメラで撮影すると車と自転車を認識できるようになりますが、精度は微妙です。もう少しちゃんと学習が必要のようです。この辺は1日もかからず突破しました。

自分で画像にラベル付けして学習データを準備する

何はともあれデータがあればAIを学習されられることが分かったので、自分で学習データを準備します。

画像のラベル付けが一番迷いました。アノテーションツールのLabelImageは使ったことがありますが、、アノテーションしたデータをどのような出力形式でエクスポートして.sframeにすればいいのか道筋がなかなか見えませんでした。

迷走していると「VoTTを使いなさい」という神のお告げがあったため、使ってみるとまあー使いやすいこと使いやすいこと。
ここからVoTTをインストールして、操作説明はこのサイトこのサイトを見れば誰でも使えます。

アノテーション後、”エクスポート設定”でプロバイダーを”コンマ区切り値(CSV)”に設定してCSVを出力します。

出力されるCSVはこんな感じ

先程のappleのサイトの手順に従ってCSVのデータを.sframeにしていきますが、サイトのコードだとうまく動かなかったので下記にコードを載せておきます。

import turicreate as tc
import os
IMAGES_DIR = '' //画像がある場所
csv_path = '' //CSVがある場所
csv_sf = tc.SFrame.read_csv(csv_path)def row_to_bbox_coordinates(row):
"""
Takes a row and returns a dictionary representing bounding
box coordinates: (center_x, center_y, width, height) e.g. {'x': 100, 'y': 120, 'width': 80, 'height': 120}
"""
return {'x': row['xmin'] + (row['xmax'] - row['xmin'])/2,
'width': (row['xmax'] - row['xmin']),
'y': row['ymin'] + (row['ymax'] - row['ymin'])/2,
'height': (row['ymax'] - row['ymin'])}
csv_sf['coordinates'] = csv_sf.apply(row_to_bbox_coordinates)del csv_sf['xmin'], csv_sf['xmax'], csv_sf['ymin'], csv_sf['ymax']csv_sf = csv_sf.rename({'image': 'name'})sf_images = tc.image_analysis.load_images(IMAGES_DIR, recursive=True,random_order=True)info = sf_images['path'].apply(lambda path: os.path.basename(path).split('/')[:1])info = info.unpack().rename({'X.0': 'name'})sf_images = sf_images.add_columns(info)del sf_images['path']csv_sf = csv_sf.pack_columns(['label', 'coordinates'], new_column_name='bbox', dtype=dict)sf_annotations = csv_sf.groupby('name',
{'annotations': tc.aggregate.CONCAT('bbox')})
sf = sf_images.join(sf_annotations, on='name', how='left')sf['annotations'] = sf['annotations'].fillna([])sf.save('mydata.sframe')

mydata.sframeを使ってモデルをトレーニングしてみる

ここはサイトのコードをそのまま使えばいけますが、短いので貼り付けておきます。

import turicreate as tcdata = tc.SFrame('mydata.sframe')train_data, test_data = data.random_split(0.8)model = tc.object_detector.create(train_data)predictions = model.predict(test_data)metrics = model.evaluate(test_data)model.save('mymodel.model')model.export_coreml('MyObjectDetector.mlmodel')

先程と同じ要領で、作成されたMyObjectDetecter.mlmodelをBreakfastFinderのObjectDetecter.mlmodelと入れ替えてビルドします。

これで自作したAIモデルをタブレット・携帯端末で動かせるはずです。

--

--

Yutaka_kun
LSC PSD
Editor for

Microbiology technician,Machine learning engineer(beginner)