つくってみよう!高火力コンピューティングでオリジナルAIサービス(3) ~オリジナル画像識別器 編~

さくらインターネットの伊東道明です。

本記事は、「つくってみよう!高火力コンピューティングでオリジナルAIサービス」という連載の第3回です。

第1回 画像識別器をダウンロードして使用する
第2回 画像識別器を使用したWebサービスを作成する
第3回 オリジナルの画像識別器を作成し,Webサービスに組み込む

前回は、ユーザからアップロードされた画像を学習済みの画像識別器に通して識別し、結果を返すWebサービスを作成しました。
今回は、自分で学習させたオリジナルの画像識別器を作成して、前回作成したWebサービスへ組み込んでみます。
本記事のソースコードは、https://github.com/palloc/AI-WebService/tree/master/source3 にまとまっています。

オリジナル画像識別器

オリジナルの画像識別器を作成するにあたり、まず、学習用のデータセットとして「fashion_mnist」という服や靴などファッション関係の画像がたくさん集められたデータセットのうち、「ドレス」「カバン」「Tシャツ」の3種類の画像をそれぞれ6000枚抽出したものを用意しました。今回は、この抽出したデータセットを使い、入力された画像が「ドレス」「カバン」「Tシャツ」のどれなのかを識別するモデルを作成します。

前準備

今回は、自前のデータセットを使うなどするため、 github のリポジトリを clone し、実行する形式で進めます。
まず、以下のコマンドで github のリポジトリをローカルに保存し、本記事で使用するディレクトリへ移動します。

$ git clone https://github.com/palloc/AI-WebService
$ cd AI-WebService/source3

次に、 Python の必要なパッケージをインストールします。

$ pip install h5py pillow

以上で前準備は終わりです。

識別器を作成するデータセット

今回用いるデータセットは、

data_set/

ディレクトリにあります。
Bag, Dress, T-shirt をそれぞれ見ていきましょう。

・Bag

 

 

 

 

・Dress

 

 

 

 

・T-shirt

 

 

 

 

 

画質はかなり悪いですが、私たち人間は十分識別できる画像だということが分かります。

ディープラーニングの構成

ディープラーニングでは、ニューラルネットワークと呼ばれるモデルの構成を決める必要があります。今回使用したニューラルネットワークは、全結合層というのを3層繋げたもので、活性化関数には ReLU 関数を用いています。ネットワークのコードは model.py に書かれています。本記事では、ディープラーニングの詳細は記事の都合上解説できないので、詳しく知りたい方はこちらのブログをご覧ください。

データセットの読み込み

今回用いるデータセットは、 png 形式で用意されています。それらをプログラムで読み込んで学習に用いることができる形にする必要があります。今回は、データセットを訓練データとテストデータに分けて、学習できる形式にする datasetGenerator 関数を data_converter.py 内に用意しました。 datasetGenerator 関数にディレクトリとラベルを渡すと、学習可能な形式でデータが返ってきます。

学習

作業ディレクトリ内の training.py にて行います。コードの詳細な解説は行いませんが、コメントである程度補足をしてあるので細かく知りたい方はご参考ください。

CPU 環境では、以下のコマンドで実行することができます。

$ python training.py

ですが、 CPU での学習は莫大な時間がかかってしまいます。そのため、 GPU 環境での実行をオススメします。

GPU 環境では、以下のコマンドで実行することができます。

$ python training.py -g 0

最後の 0 は適宜 GPU の管理番号に変えてください。基本的には 0 で動きます。実行し終わった後、ディレクトリ内に origin_model.pkl というファイルが生成されていると思います。これが先ほどの学習で作成したモデルです。前回の記事で作成した predictor.py では、 VGG の学習済みモデルを読み込んでいました。それを、今回は自分で作成したモデルに差し替えます。

predictor.py で変更した部分を見ていきましょう。

def load_model(gpu=-1):
    """
    モデルとラベルデータを読み込む関数
    """
    global model
    global labels

    # モデルをロード
    with open("origin_model.pkl", 'rb') as m:
        model = pickle.load(m)

    # GPUを使う場合の処理
    if gpu >= 0:
        chainer.cuda.get_device(gpu).use()
        model.to_gpu()

    # ラベルデータの読み込み
    labels = ["Bag", "T-shirt", "Dress"]

load_model関数では、先ほどの学習で作成したorigin_model.pklを読み込むようにし、ラベルを書き換えます。

def predict_image(image_filename):
    """
    画像を識別する関数
    """
    # --gpuオプションの指定状況を得るための引数パーサーを作成
    parser = argparse.ArgumentParser(description="識別器")
    parser.add_argument("--gpu", "-g", type=int, default=-1)
    args = parser.parse_args()
    
    # モデルの読み込み関数呼び出し
    load_model(gpu=args.gpu)

    # 画像とラベルデータの読み込み
    img = Image.open(image_filename).convert('L')
    img = img.resize((56, 56))
    img = np.asarray(img).astype(np.float32) / 255
    img = img.reshape((1, -1))

    # GPUを使う場合の処理
    if args.gpu >= 0:
        img = chainer.cuda.to_gpu(img)

    # 画像の識別
    pre = model.predictor(chainer.Variable(img))

    # 結果を確率に変換
    pre = F.softmax(pre)

    # 確率トップ5を抽出
    pre_data = zip(pre[0].data, labels)
    top5 = sorted(pre_data, key=lambda x: -x[0])[:5]

    return top5

前回使った VGG モデルは、画像を predict 関数内部で処理してくれたのですが、今回は自作モデルのため自分でサイズを変更したりする必要があります。今回作ったモデルは、入力が 56 * 56 の画像です。そのため、まずサイズを resize 関数で変更し、 numpy 配列に変換します。その際、 0 ~ 255 階調の色情報を 0 ~ 1 の間に変換するために、 255 で割っています。

次に、 GPU を使用する場合は numpy 配列にした画像を cuda が使える形にするために chainer.cuda.to_gpu 関数で画像の形式を変換します。そして、 predictor 関数で出力をもらった後、 softmax 関数に出力を通すと各ラベルの確率を得ることができます。

Webサーバーの実行

では、実際に Webサーバーを起動してみましょう。

前回の記事と同じく CPU 環境の方は以下のコマンドで起動します。

$ python server.py

GPU 環境の方は以下のコマンドで起動します。

$ python server.py -g 0

実際にアクセスして、以下の T-shirt 画像をアップロードしてみましょう。

 

 

 

 

 

すると、以下のような結果画面が出てくると思います。

正しく識別できていることがわかります。
是非様々な画像をアップロードして、精度などを確かめてください。

まとめ

本記事では自分のオリジナル識別器を組み込んだ Webサービスを作成しました。これで連載目標であるオリジナルAIサービスの作成は達成されました。

本連載を通して、機械学習を実際のサービスへ導入する方法の1例を紹介しました。この連載を元に、自分だけのオリジナルAIサービスを作成してみてください。