はじまり
某ボードを使いこなすためにTensorFlow Liteを使う必要が出てきた。
手始めにTensorFlowのサンプルをTensorFlow Liteで変換しようとしたところ、
がっつりエラーになった。知識不足何とかしたい。
注意。
本記事はtfliteファイルを作るまでの備忘録なので、TensorFlow触った事のある人なら学びのある記事ではないです。
やる事
自分で作ったデータセットをtensorflowに食わせてtensorflow liteでコンバートする。
とりあえず作るモデルとしてはダック検出。手順をまとめるのが目的なので精度なんて二の次。
こういう画像をダックって判断するモデルが作りたい
準備
とりあえずpython3入れた後は必要なパッケージを入れてゆく
pip install tensorflow
pip install tensorflow_datasets
pip install matplotlib
pip install numpy
pip install h5py pyyaml
pip install pillow
データセットを作ろうとして失敗する
Adding a datasetを参考にデータセットを作成する。
とりあえず大事なのは
- tensorflow_datasets.public_api.core.GeneratorBaseBuilderを継承したクラス作る
- _info()オーバーライドする
- _split_generator()オーバーライドする
- _generate_example()オーバーライドする
import tensorflo_datasets.public_api as tfds
class DuckDataset(tfds.core.GeneratorBaseBuilder):
version = tfds.core.Version('0.1.0')
def _info(self):
return tfds.core.DatasetInfo(
builder=self,
description="special greatfull duckable dataset",
features=tfds.features.FeaturesDict({
"image_description": tfds.features.Text(),
"image": tfds.features.Image(),
"label": tfds.features.ClassLabel(num_classes=5),
}),
supervised_keys=("image", "label"),
urls="https://dataset-homepage.org",
citation=r"""@article{greatfull-duckable-dataset,
author={miyatama},"}""",
)
def _split_generators(self, dl_manager):
extract_path = "./datasets/"
return [
tfds.core.SplitGenerator(
name=tfds.Split.TRAIN
gen_kwargs={
"image_dir_path": os.path.join(extract_path, "train"),
"labels": os.path.join(extract_path, "train_labels.csv"),
}
),
tfds.core.SplitGenerator(
name=tfds.Split.TEST
gen_kwargs={
"image_dir_path": os.path.join(extract_path, "test"),
"labels": os.path.join(extract_path, "test_labels.csv"),
}
),
]
def _generate_examples(self, images_dir_path, labels):
image_paths = sorted([os.path.join(images_dir_path, filename)
for filename in tf.io.gfile.listdir(images_dir_path)])
if tf.io.gfile.exists(scenes_description_file):
scenes_json = json.load(tf.io.gfile.GFile(scenes_description_file))
else:
# if annotation file does not exist, we create empty annotations
scenes_json = {"scenes": [{"objects": []}] * len(image_paths)}
attrs = ["image_name", "label"]
for image_path, scene in zip(image_paths, scenes_json["scenes"]):
objects = scene["objects"]
fname = os.path.basename(image_path)
record = {
"image": image_path,
"file_name": fname,
"objects": [{attr: obj[attr] for attr in attrs} for obj in objects] # pylint: disable=g-complex-comprehension
}
yield fname, record
何回Adding a datasetを読んでも結局gfileに食わせるものが不明だったので、何となくラベルを返すようにした。
作ったクラスをどうやって使えばいいか悩んだのち、
Follow this guide to add a dataset to TFDS.
なる文言をみて心が折れる。
その他参考
データセットを作成する
とりあえず画像の用意する。
- datasets/duckディレクトリを作る
- Googleの画像検索開く
-
duck
と打ち込んで検索 - 適当にスクロール
- 右クリックしてWebページの完全保存
- できたフォルダの
image(x)
ファイルをimage_x.jpg
に名前変える - 同じ感じでjojoディレクトリと画像作る
で、画像を読み込んで学習に引き渡すまでは下記の様になる。
import tensorflow as tf
import numpy as np
from PIL import Image
import glob
folder = ["datasets/duck", "datasets/jojo"]
X = []
Y = []
def img(x):
y = Image.open(x)
y = y.convert("RGB")
y = y.resize((50, 50))
return np.asarray(y)
for index, name in enumerate(folder):
dir = "./" + name
files = glob.glob( dir + "/*.jpg")
for i, file in enumerate(files):
image = img(file)
X.append(image)
Y.append(index)
X = np.array(X) / 255
Y = np.array(Y)
学習させる
ココはもうTensorFlowのサンプルのまま。最初のFlattenだけ違う感じ。
model = tf.keras.models.Sequential([
tf.keras.layers.Flatten(input_shape=(50, 50, 3)),
tf.keras.layers.Dense(512, activation=tf.nn.relu),
tf.keras.layers.Dropout(0.2),
tf.keras.layers.Dense(2, activation=tf.nn.softmax)
])
model.compile(
optimizer='adam',
loss='sparse_categorical_crossentropy',
metrics=['accuracy'])
model.fit(X, Y, epochs=5)
model.save(
'duck_detect.h5',
include_optimizer=False)
tensorflow liteでコンバートする
いよいよ学習結果のモデルをコンバートしてゆく。
converter = tf.lite.TFLiteConverter.from_keras_model_file('duck_detect.h5')
tflite_model = converter.convert()
open('duck_detect.tflite', 'wb').write(tflite_model)
無事tfliteファイルが出来た
ふりかえり
TensorFlowのページ分かりやすいようで分かり辛い。
Follow this guide to add a dataset to TFDS.
— みやた@代打中 (@miyata080825) September 2, 2019
とのこと。終了。#声に出して読みたい1行目#TensorFlow