https://d226lax1qjow5r.cloudfront.net/blog/blogposts/image-classifier-in-tensorflow-dr/tensorflow-image-classifier.png

Tensorflowで画像分類器を構築する

最終更新日 May 3, 2021

所要時間:2 分

この投稿では、Nexmo In-App Messagingと統合されたiOSアプリで、会話のメンバーから送信された画像を処理するための基本的な画像分類モデルを構築します。ユーザーが画像をアップロードすると、画像を説明するキャプションが表示されます。

Pythonを使って画像分類モデルを構築します。Pythonを使ったことがなかったり、機械学習の予備知識がなくても心配しないでください。

画像分類とは?

機械学習における画像分類とは、写真があって、機械学習モデルがその写真に写っている被写体が何かを見分けることである。例えば、犬の写真を撮れば、機械学習モデルは「これは犬だ」と言うことができる。

まず、機械学習モデルを構築するためには、それを訓練するためのデータが必要だ。

機械学習モデルは、モデルが学習するための学習データを使用する。まず、学習データを選択する必要がある。今回は CIFAIR-10データセットを使用する。

このデータセットには10クラスの画像が含まれており、1クラスあたり6000枚の画像がある。このデータセットは機械学習でよく使われるデータセットであり、我々のプロジェクトの良いスタートとなるだろう。データセットがかなり小さいので、モデルを素早く訓練できる。

このノートブックの運営

このノートブックは Google Colab.Colaboratoryは無料のJupyterノートブック環境で、セットアップの必要がなく、完全にクラウド上で動作します。

ノートブックを実行するには、Googleアカウントが必要です。

ノートブックの実行はとても簡単です。コードを含むすべてのセルの左側に実行ボタンがあります。実行ボタンをタップすると、コードが実行されます。キーボード・コマンド Shift次に Enter.

モデルの構築

まず、パッケージをインポートします。これらのパッケージはGoogle Colabにプリインストールされているので、インストールする必要はない。

import tensorflow as tf
from tensorflow import keras
import matplotlib.pyplot as plt
import numpy as np

TensorflowとKerasをTensorflowのフロントエンドとして使っていることに注目してほしい。 Kerasは、Tensorflowの冗長なメソッドを使うことなく、より簡単にモデルを構築できる素晴らしいフレームワークだ。

次に、CIFARデータセットをロードする。Kerasを使えば、データセットを簡単にダウンロードできる。

データセットを2つのグループに分ける。 (x_train, y_train)テスト用 (x_test, y_test).

データセットを分割することで、モデルはトレーニングセットから学習することができる。そしてモデルをテストするとき、テストセットを使ってどれだけ学習したかを確認したい。これにより、精度が得られます。

from keras.datasets import cifar10

(x_train, y_train), (x_test, y_test) = cifar10.load_data()
print('x_train shape:', x_train.shape)
print(x_train.shape[0], 'train samples')

print('y_train shape', y_train.shape)
print(x_test.shape[0], 'test samples')

print('x_test shape', x_test.shape)
print(y_test.shape[0], 'test samples')
Using TensorFlow backend.


Downloading data from https://www.cs.toronto.edu/~kriz/cifar-10-python.tar.gz
170500096/170498071 [==============================] - 75s 0us/step
x_train shape: (50000, 32, 32, 3)
50000 train samples
y_train shape (50000, 1)
10000 test samples
x_test shape (10000, 32, 32, 3)
10000 test samples

次に、いくつかの定数を宣言する。

  • batch_sizeはネットワークを通じて伝播されるサンプルの数である。

  • epochsは、完全なデータセットに対する学習の回数である。

  • class_namesはCIFAR-10データセットに含まれるすべてのラベルのリストである。

batch_size = 32 
epochs = 100
class_names = ["airplane","automobile","bird","cat","deer","dog","frog","horse","ship","truck"]

これらの定数は、後でモデルをCoreMLに変換するときに使う。

def plot_images(x, y, number_of_images=2):
  fig, axes1 = plt.subplots(number_of_images,number_of_images,figsize=(10,10))
  for j in range(number_of_images):
      for k in range(number_of_images):
          i = np.random.choice(range(len(x)))
          title = class_names[y[i:i+1][0][0]]
          axes1[j][k].title.set_text(title)
          axes1[j][k].set_axis_off()
          axes1[j][k].imshow(x[i:i+1][0])

まず、いくつかの画像を見てみよう。4つのランダムな画像とそれに対応するラベルをプロットする関数がある。

plot_images(x_train, y_train)

Image showing four small images and corresponding labels - ship, airplane, ship airplaneImage recognition Tensorflow CoreML

モデルの構築

では、簡単なモデルをセットアップしよう。ここでは コンボリューション, ドロップアウトそして 最大プーリング.

最終的には、ネットワークをフラットにして Reluを使用し、続いて ソフトマックス.

これで、ほとんどが0で埋め尽くされたベクトル(1次元行列)が得られる。

このようになる。

[0,0,0,0,0,0,1,0,0,0]

このベクトルは画像から与えられたラベルに対応する。 1の7番目はカエルである。 class_namesの7番目にある。


以下にネットワーク全体を示す。

model = tf.keras.Sequential()

model.add(tf.keras.layers.Conv2D(32, kernel_size=(3, 3), activation='relu', input_shape=(32, 32, 3)))
model.add(tf.keras.layers.Conv2D(64, kernel_size=(3, 3), activation='relu'))
model.add(tf.keras.layers.MaxPooling2D(pool_size=(2, 2)))
model.add(tf.keras.layers.Dropout(0.25))

model.add(tf.keras.layers.Conv2D(128, kernel_size=(3, 3), activation='relu'))
model.add(tf.keras.layers.MaxPooling2D(pool_size=(2, 2)))
model.add(tf.keras.layers.Conv2D(128, kernel_size=(3, 3), activation='relu'))
model.add(tf.keras.layers.MaxPooling2D(pool_size=(2, 2)))
model.add(tf.keras.layers.Dropout(0.25))

model.add(tf.keras.layers.Flatten())
model.add(tf.keras.layers.Dense(1024, activation='relu'))
model.add(tf.keras.layers.Dropout(0.5))
model.add(tf.keras.layers.Dense(10, activation='softmax'))

それだけだ!

モデルのトレーニング

まず、モデルをコンパイルして損失を求める。損失は、テスト中にモデルがどの程度うまくいったかを示す尺度である。損失が大きいということは、モデルの出来が悪いということです。

ここでは アダム・オプティマイザー機械学習に広く使われている確率的勾配降下法を拡張したアルゴリズムで、損失を計算する。

次に .fitを呼び出して、100エポック学習させる。これは全トレーニングデータセットを100回トレーニングすることを意味します。 batch_size32はネットワークを通して伝搬されるサンプルの数である。

そして、各エポック終了後に、以下の方法でその結果を確認する。 model.evaluate.これはモデルのスコア(数字が大きいほど良い)と損失(数字が小さいほど良い)を示してくれる。

なお、Colabでは15分ほどかかりました。もっと早く結果を見たい場合は、パラメータを epochsパラメータを 1または 2.ただし、精度はそれほど良くないだろう。

# Compile the model
model.compile(loss='categorical_crossentropy',
              optimizer=tf.keras.optimizers.Adam(lr=0.0001, decay=1e-6),
              metrics=['accuracy'])

# Train the model
model.fit(x_train / 255.0, tf.keras.utils.to_categorical(y_train),
          batch_size=batch_size,
          shuffle=True,
          epochs=epochs,
          validation_data=(x_test / 255.0, tf.keras.utils.to_categorical(y_test))
          )

# Evaluate the model
scores = model.evaluate(x_test / 255.0, tf.keras.utils.to_categorical(y_test))

print('Loss: %.3f' % scores[0])
print('Accuracy: %.3f' % scores[1])
Train on 50000 samples, validate on 10000 samples
Epoch 1/100
            #Omitted for readability
50000/50000 [==============================] - 30s 603us/step - loss: 0.1378 - acc: 0.9518 - val_loss: 0.7136 - val_acc: 0.8116
10000/10000 [==============================] - 2s 151us/step
Loss: 0.714
Accuracy: 0.812

最終的な精度は81%で、損失は0.7。

繰り返しになるが、精度はモデルが各画像をどれだけうまく分類できたかを示し、損失はモデルの予測がどれだけ悪かったかを示す。

詳しくは、Googleの機械学習クラッシュコースにある損失と精度の定義をご覧ください。 Googleの機械学習クラッシュコース。

モデルをCore MLに変換する

モデルをトレーニングした後、それを保存し、Core MLフォーマットに変換することができる。

WWDC 2018で発表されたCore MLは、iOS開発者がiOSアプリに多種多様な機械学習モデルを統合することを可能にします。ここでは、この技術をNexmo In-App Messagingで使用し、画像処理のための独自のディープラーニングを促進します。

まず、学習済みモデルを保存する必要がある。

model.save('cifar-model.h5')

coremltoolsを使い、モデルをStitchアプリが使える形式に変換する。


Core MLパッケージはColabにプリインストールされていません。 pip

!pip install coremltools
Collecting coremltools [?25l Downloading https://files.pythonhosted.org/packages/8f/ab/b4dea5ab2503f3e601052958985153cd41bd4f9a336fb74f6789151d976e/coremltools-0.8-py3.5-none-manylinux1_x86_64.whl (2.5MB) [K 100% |████████████████████████████████| 2.5MB 9.9MB/s [?25hRequirement already satisfied: protobuf>=3.1.0 in /usr/local/lib/python3.6/dist-packages (from coremltools) (3.6.0) Collecting six==1.10.0 (from coremltools) Downloading https://files.pythonhosted.org/packages/c8/0a/b6723e1bc4c516cb687841499455a8505b44607ab535be01091c0f24f079/six-1.10.0-py2.py3-none-any.whl Requirement already satisfied: numpy>=1.10.0 in /usr/local/lib/python3.6/dist-packages (from coremltools) (1.14.5) Requirement already satisfied: setuptools in /usr/local/lib/python3.6/dist-packages (from protobuf>=3.1.0->coremltools) (39.1.0) Installing collected packages: six, coremltools Found existing installation: six 1.11.0 Uninstalling six-1.11.0: Successfully uninstalled six-1.11.0 Successfully installed coremltools-0.8 six-1.10.0

上記から、パッケージがノートブックにインストールされたことがわかる。

次に、保存したモデルをCore MLに変換する。

Kerasを使ってモデルを学習したので、Core MLに変換するのはとても簡単だ。しかし、これはモデルの構築方法によって異なります。Core MLツールには、TensorflowやScikit Learnを含む他の機械学習パッケージで使用するための関数があります。詳しくは coremltools リポジトリを参照してください。

from keras.models import load_model  
import coremltools

model = load_model('cifar-model.h5')
coreml_model = coremltools.converters.keras.convert(model,
	input_names="image",
	image_input_names="image",
	image_scale=1/255.0,
	class_labels=class_names)

coreml_model.save('CIFAR.mlmodel')
    0 : conv2d_input, <keras.engine.topology.InputLayer object at 0x7fa7c829fac8>
    1 : conv2d, <keras.layers.convolutional.Conv2D object at 0x7fa7c829f358>
    2 : conv2d__activation__, <keras.layers.core.Activation object at 0x7fa7c75bf198>
    3 : conv2d_1, <keras.layers.convolutional.Conv2D object at 0x7fa7c80e40b8>
    4 : conv2d_1__activation__, <keras.layers.core.Activation object at 0x7fa7c75bf438>
    5 : max_pooling2d, <keras.layers.pooling.MaxPooling2D object at 0x7fa7c80e4550>
    6 : conv2d_2, <keras.layers.convolutional.Conv2D object at 0x7fa7c77434a8>
    7 : conv2d_2__activation__, <keras.layers.core.Activation object at 0x7fa7c73f9240>
    8 : max_pooling2d_1, <keras.layers.pooling.MaxPooling2D object at 0x7fa7c7743f28>
    9 : conv2d_3, <keras.layers.convolutional.Conv2D object at 0x7fa7c87ad1d0>
    10 : conv2d_3__activation__, <keras.layers.core.Activation object at 0x7fa7c7262dd8>
    11 : max_pooling2d_2, <keras.layers.pooling.MaxPooling2D object at 0x7fa7c7743f60>
    12 : flatten, <keras.layers.core.Flatten object at 0x7fa7c76fac50>
    13 : dense, <keras.layers.core.Dense object at 0x7fa7c76b42b0>
    14 : dense__activation__, <keras.layers.core.Activation object at 0x7fa7c71ff390>
    15 : dense_1, <keras.layers.core.Dense object at 0x7fa7c7670358>
    16 : dense_1__activation__, <keras.layers.core.Activation object at 0x7fa7c71ff898>

上の出力は、モデル内部のすべてのレイヤーを示している。これらは、この セル.

のパラメータを見てみよう。 convert関数のパラメータを見てみよう。ここでは、入力を imageinput_namesimage_input_namesパラメータにこうすることで、Core MLモデルがどのような入力(画像)を期待しているかを知ることができます。

次に image_scaleパラメータで0から1の間の数値にスケールダウンする。

次に class_labelsパラメータを class_names定数を設定する。

Xcodeでこのモデルを使うと、結果は Stringとなり、画像の予測ラベルに対応します。

さて、コアMLのモデルを見てみよう。

print(coreml_model)
input {
  name: "image"
  type {
    imageType {
      width: 32
      height: 32
      colorSpace: RGB
    }
  }
}
output {
  name: "output1"
  type {
    dictionaryType {
      stringKeyType {
      }
    }
  }
}
output {
  name: "classLabel"
  type {
    stringType {
    }
  }
}
predictedFeatureName: "classLabel"
predictedProbabilitiesName: "output1"

この inputは32x32ピクセルの画像で、出力は文字列です。 classLabel

次に、Google Colabパッケージを使ってmlmodelをローカルに保存し、ファイルをマシンにダウンロードする。

from google.colab import files
files.download('CIFAR.mlmodel')

Stitchアプリにモデルを組み込む

モデルを保存したら、それをアプリにインポートすることができる。これを行うには、先ほど保存したモデルをXcodeにドラッグするだけです。

showing the model dragged into xcodeCIFAR xcode

ターゲット・メンバーシップが選択されていることを確認し、モデルがターゲットに含まれていることを確認する。


次に、iOSアプリケーションでこのモデルを使うコードを書きます。

私たちの ステッチ・デモ・アプリケーションでは、ユーザーは既存の会話に写真をアップロードすることができます。

NexmoのIn-App Messagingは、ユーザーが会話のメンバーとして、以下のトリガーだけでなく、次のトリガーも可能にします。 TextEventsだけでなく ImageEvents既存の会話に写真をアップロードすることである。今回のサンプルでは、ユーザーがアップロードした写真の内容を予測してみます。

を観察する機能を ImageEventsを直接 ViewController に組み込むことができます。この方法の例は このサンプルのソースコード.

ViewController で、モデルをインスタンス化します。

let model = CIFAR()

では cellForRowAtPathメソッド内で eventImageEventであるかどうかをチェックし、そうであればImageEventから写真を表示します。そして、その画像を、32x32ピクセルのサイズで PixelBuffer32x32ピクセルのサイズに変換し、モデルに送り込みます。


なぜ画像を再サンプリングしなければならないかというと、モデルは32x32ピクセルの画像でトレーニングされているため、画像のサイズを変更しなければ、モデルは予測を行うことができないからです(Xcodeでは、画像サイズが正しくないというエラーが表示されます)。

func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
        let cell = tableView.dequeueReusableCell(withIdentifier: "cell", for: indexPath)

        let event = conversation?.events[indexPath.row]
        switch event {
        case is ImageEvent:
            //get the image from the ImageEvent
            let imageEvent = (event as! ImageEvent)
            guard let imagePath = imageEvent.path(of: IPS.ImageType.thumbnail), let image = UIImage(contentsOfFile: imagePath) else {
                break
            }
            cell.imageView?.image = image

            //convert the image to a pixelBuffer
            //using https://github.com/hollance/CoreMLHelpers.git
            if let pixelBuffer = image.pixelBuffer(width: 32, height: 32) {
                let input = CIFARInput(image: pixelBuffer)

                //perform the prediction
                if let output = try? model.prediction(input: input)  {
                    cell.textLabel?.text = (imageEvent.from?.name)! + " uploaded a photo of a \(output.classLabel)"
                }
                else {
                    cell.textLabel?.text = (imageEvent.from?.name)! + " uploaded a photo"
                }
            }
            break;
        
        default:
            cell.textLabel?.text = ""
        }

        return cell;
    }

モデルは classLabel.これは、モデルが予測した画像の名前となり、以下のラベルのいずれかとなります: "飛行機"、"自動車"、"鳥"、"猫"、"鹿"、"犬"、"カエル"、"馬"、"船"、"トラック"。

結論

予測結果を見ると、このモデルは10個のラベルしか認識できないことがわかる。完全なノートブックは GitHub.

これはデモには良いが、本番のアプリケーションには向かない。今後の投稿では、より多くのデータを使って画像認識モデルを構築することにしよう。人気のある ImageNetデータベースこのデータベースには14,197,122枚のラベル付き画像が含まれている。

150gbのダウンロードなので、ダウンロードしてトレーニングし、Stitchのデモアプリに統合する方法を見てみよう。

シェア:

https://a.storyblok.com/f/270183/150x150/a3d03a85fd/placeholder.svg
Tony Hungヴォネージの卒業生

IOSデベロッパーからデータサイエンス/機械学習愛好家に転身。機械学習とは何か、それをアプリケーションでどのように使うことができるかを理解してほしい。