PAIで実現するImage Recognition

CJNANです。
前回のブログで、PAIの背景や特性をまとめてみました。

さて、これからはPAIを使って、Image Recognitionを実現する方法を紹介します。(勿論GPUインスタンスでも実現可能ですが、こうする場合は、事前にCUDAやTensorFlowの対応する必要がある)

Notice:

  1. 現時点(2018年8月21日)では、日本サイトでまだリリースされていないサービスですが、近い時期にリリースする予定がありますので、先走って、ご紹介します。
  2. 現時点(2018年8月21日)では、中国サイトのPAIしかGPUリソースを対応しませんので、本記事をトライしたい方は、中国アカウントでお試しください。

Alibaba CloudにGPUインスタンス登場!Tensorflowで機械学習を試す

Alibaba Cloudの機械学習サービスPAI

はじめに

まず、PAIでDeep Learningをやる理由(メリット)を振り返しますと、

  1. クラウドによる初期導入コストの削減
  2. 大規模GPUによる分散並列処理でリードタイム削減

そして、これからやりたいのは、PAIで画像認識モデルを作ること。
具体的な環境は下記にまとめました。

環境について

  • Platform:PAI、OSS(同じリージョン)
  • Language:Python2
  • Model: AlexNet(Alex Krizhevskyに敬意を捧げる)
  • Tools:TensorFlow、Jupyter notebook
  • DataSet:CIFAR-10
    (CNNやTensofFlowなどの説明についてはこちらでは割愛します)

データセットについて(CIFAR-10)

データセットを軽く説明をすると、CIFAR-10は32*32Pixelの画像6万枚を10クラス(airplane, automobile, bird, cat, deer, dog, frog, horse, ship, truck)に分けて、PythonのcPickle形式で提供されている画像認識用データセットです。

事前準備

データセットは5万枚の学習用TrainSetと一万枚のテスト用TestSetに分けます。TrainSetは更に5つのBatchに分けて、下記のように6つのファイルを用意して置きます。

データセットとコードを用意しましたので、トライしたい方はダウンロードして、自分のOSSにアップロードしてください。

https://sbchandson.oss-ap-northeast-1.aliyuncs.com/machine_learning/pai_image_recognition.zip

Notice:
PAIとOSSは必ず同じリージョンで作成してくだい。

<OSSとは>
https://jp.alibabacloud.com/help/doc-detail/31817.htm?spm=a21mg.l28256.b99.2.29301315JT89eU

<データとコード>
CIFAR-10:学習用データとテスト用画像の置き場
check_point:学習済みのモデルの置き場

プロジェクト作成

PAIのコンソールに入って、まず新しいプロジェクトを作成します。前回の記事も紹介したように、PAIはMaxCompute層の上で動いているから、PAIのプロジェクトを作成すると、自動に同じ名前のMaxComputeプロジェクトも作成されます。

注意する所は、Deep LearningなどGPUリソースが必要な場合は、GPUをオンにしてください。

OSSアクセス権限を付与する

PAIからOSSにアクセスするためには、OSSアクセス権限を付与する必要があります。PAIのコンソールから、左下のオプションに入って、「OSS Authorization」にチェックします。

そして、案内通りにチェックすると、簡単に権限設定ができると思います。下記のようになれば問題ないと思います。

Jupyter Notebook環境立ち上げ

PAIコンソールの左側からJupyter Notobook環境をワンクリックで立ち上げることができますので、それを使って、TensorFlowコード書きます。

まずは、Jupyter Notebookを立ち上げます。

作成するときにOSSのPathを設定しますが、設定されたPathはJupyter Notebookのルートになりますので、さっきOSSアップしたデータセットのPathを設定しておきます。コンピュータリソースのところでGPUを選びます。

確認すると、自動にJupyter環境が立ち上げますので、そこからIDEに入ります。これで、Jupyter Notebookの準備は全部揃いました。

学習コードの作成

JupyterからNoteを開いて、下記のコードを入力します。

<training.ipyn>

# -*- coding: utf-8 -*-
from __future__ import division, print_function, absolute_import

import tensorflow as tf

from six.moves import urllib
import tarfile

import tflearn
from tflearn.data_utils import shuffle, to_categorical
from tflearn.layers.core import input_data, dropout, fully_connected
from tflearn.layers.conv import conv_2d, max_pool_2d
from tflearn.layers.estimator import regression
from tflearn.data_preprocessing import ImagePreprocessing
from tflearn.data_augmentation import ImageAugmentation

from tensorflow.python.lib.io import file_io
import os
import sys
import numpy as np
import pickle
import argparse

FLAGS = None

def load_data(dirname, one_hot=False):
    X_train = []
    Y_train = []

    for i in range(1, 6):
        fpath = os.path.join(dirname, 'data_batch_' + str(i))
        data, labels = load_batch(fpath)
        if i == 1:
            X_train = data
            Y_train = labels
        else:
            X_train = np.concatenate([X_train, data], axis=0)
            Y_train = np.concatenate([Y_train, labels], axis=0)

    fpath = os.path.join(dirname, 'test_batch')
    X_test, Y_test = load_batch(fpath)

    X_train = np.dstack((X_train[:, :1024], X_train[:, 1024:2048],
                         X_train[:, 2048:])) / 255.
    X_train = np.reshape(X_train, [-1, 32, 32, 3])
    X_test = np.dstack((X_test[:, :1024], X_test[:, 1024:2048],
                        X_test[:, 2048:])) / 255.
    X_test = np.reshape(X_test, [-1, 32, 32, 3])

    if one_hot:
        Y_train = to_categorical(Y_train, 10)
        Y_test = to_categorical(Y_test, 10)

    return (X_train, Y_train), (X_test, Y_test)

#reporthook from stackoverflow #13881092
def reporthook(blocknum, blocksize, totalsize):
    readsofar = blocknum * blocksize
    if totalsize > 0:
        percent = readsofar * 1e2 / totalsize
        s = "\r%5.1f%% %*d / %d" % (
            percent, len(str(totalsize)), readsofar, totalsize)
        sys.stderr.write(s)
        if readsofar >= totalsize: # near the end
            sys.stderr.write("\n")
    else: # total size is unknown
        sys.stderr.write("read %d\n" % (readsofar,))

def load_batch(fpath):
    object = file_io.read_file_to_string(fpath)
    #origin_bytes = bytes(object, encoding='latin1')
    # with open(fpath, 'rb') as f:
    if sys.version_info > (3, 0):
        # Python3
        d = pickle.loads(object, encoding='latin1')
    else:
        # Python2
        d = pickle.loads(object)
    data = d["data"]
    labels = d["labels"]
    return data, labels

def main(_):
    dirname = os.path.join(FLAGS.buckets, "")
    (X, Y), (X_test, Y_test) = load_data(dirname)
    print("load data done")

    X, Y = shuffle(X, Y)
    Y = to_categorical(Y, 10)
    Y_test = to_categorical(Y_test, 10)

    # Real-time data preprocessing
    img_prep = ImagePreprocessing()
    img_prep.add_featurewise_zero_center()
    img_prep.add_featurewise_stdnorm()

    # Real-time data augmentation
    img_aug = ImageAugmentation()
    img_aug.add_random_flip_leftright()
    img_aug.add_random_rotation(max_angle=25.)

    # Convolutional network building
    network = input_data(shape=[None, 32, 32, 3],
                         data_preprocessing=img_prep,
                         data_augmentation=img_aug)
    network = conv_2d(network, 32, 3, activation='relu')
    network = max_pool_2d(network, 2)
    network = conv_2d(network, 64, 3, activation='relu')
    network = conv_2d(network, 64, 3, activation='relu')
    network = max_pool_2d(network, 2)
    network = fully_connected(network, 512, activation='relu')
    network = dropout(network, 0.5)
    network = fully_connected(network, 10, activation='softmax')
    network = regression(network, optimizer='adam',
                         loss='categorical_crossentropy',
                         learning_rate=0.001)

    # Train using classifier
    model = tflearn.DNN(network, tensorboard_verbose=0)
    model.fit(X, Y, n_epoch=50, shuffle=True, validation_set=(X_test, Y_test),
              show_metric=True, batch_size=96, run_id='cifar10_cnn')
    model_path = os.path.join(FLAGS.checkpointDir, "model.tfl")
    print(model_path)
    model.save(model_path)

if __name__ == '__main__':
    parser = argparse.ArgumentParser()
    parser.add_argument('--buckets', type=str, default='',
                        help='input data path')
    parser.add_argument('--checkpointDir', type=str, default='',
                        help='output model path')
    FLAGS, _ = parser.parse_known_args()
    tf.app.run(main=main)

<prediction.ipyn>

# -*- coding: utf-8 -*-
from __future__ import division, print_function, absolute_import

import tensorflow as tf

from six.moves import urllib
import tarfile

import tflearn
from tflearn.data_utils import shuffle, to_categorical
from tflearn.layers.core import input_data, dropout, fully_connected
from tflearn.layers.conv import conv_2d, max_pool_2d
from tflearn.layers.estimator import regression
from tflearn.data_preprocessing import ImagePreprocessing
from tflearn.data_augmentation import ImageAugmentation

from tensorflow.python.lib.io import file_io
import os
import sys
import numpy as np
import pickle
import argparse
import scipy
FLAGS = None

def load_data(dirname, one_hot=False):
    X_train = []
    Y_train = []

    for i in range(1, 6):
        fpath = os.path.join(dirname, 'data_batch_' + str(i))
        data, labels = load_batch(fpath)
        if i == 1:
            X_train = data
            Y_train = labels
        else:
            X_train = np.concatenate([X_train, data], axis=0)
            Y_train = np.concatenate([Y_train, labels], axis=0)

    fpath = os.path.join(dirname, 'test_batch')
    X_test, Y_test = load_batch(fpath)

    X_train = np.dstack((X_train[:, :1024], X_train[:, 1024:2048],
                         X_train[:, 2048:])) / 255.
    X_train = np.reshape(X_train, [-1, 32, 32, 3])
    X_test = np.dstack((X_test[:, :1024], X_test[:, 1024:2048],
                        X_test[:, 2048:])) / 255.
    X_test = np.reshape(X_test, [-1, 32, 32, 3])

    if one_hot:
        Y_train = to_categorical(Y_train, 10)
        Y_test = to_categorical(Y_test, 10)

    return (X_train, Y_train), (X_test, Y_test)

#reporthook from stackoverflow #13881092
def reporthook(blocknum, blocksize, totalsize):
    readsofar = blocknum * blocksize
    if totalsize > 0:
        percent = readsofar * 1e2 / totalsize
        s = "\r%5.1f%% %*d / %d" % (
            percent, len(str(totalsize)), readsofar, totalsize)
        sys.stderr.write(s)
        if readsofar >= totalsize: # near the end
            sys.stderr.write("\n")
    else: # total size is unknown
        sys.stderr.write("read %d\n" % (readsofar,))

def load_batch(fpath):
    object = file_io.read_file_to_string(fpath)
    #origin_bytes = bytes(object, encoding='latin1')
    # with open(fpath, 'rb') as f:
    if sys.version_info > (3, 0):
        # Python3
        d = pickle.loads(object, encoding='latin1')
    else:
        # Python2
        d = pickle.loads(object)
    data = d["data"]
    labels = d["labels"]
    return data, labels

def main(_):
    dirname = os.path.join(FLAGS.buckets, "")
    (X, Y), (X_test, Y_test) = load_data(dirname)
    print("load data done")

    X, Y = shuffle(X, Y)
    Y = to_categorical(Y, 10)
    Y_test = to_categorical(Y_test, 10)

    # Real-time data preprocessing
    img_prep = ImagePreprocessing()
    img_prep.add_featurewise_zero_center()
    img_prep.add_featurewise_stdnorm()

    # Real-time data augmentation
    img_aug = ImageAugmentation()
    img_aug.add_random_flip_leftright()
    img_aug.add_random_rotation(max_angle=25.)

    # Convolutional network building
    network = input_data(shape=[None, 32, 32, 3],
                         data_preprocessing=img_prep,
                         data_augmentation=img_aug)
    network = conv_2d(network, 32, 3, activation='relu')
    network = max_pool_2d(network, 2)
    network = conv_2d(network, 64, 3, activation='relu')
    network = conv_2d(network, 64, 3, activation='relu')
    network = max_pool_2d(network, 2)
    network = fully_connected(network, 512, activation='relu')
    network = dropout(network, 0.5)
    network = fully_connected(network, 10, activation='softmax')
    network = regression(network, optimizer='adam',
                         loss='categorical_crossentropy',
                         learning_rate=0.001)

    model = tflearn.DNN(network, tensorboard_verbose=0)
    model_path = os.path.join(FLAGS.checkpointDir, "model.tfl")
    print(model_path)
    model.load(model_path)

    predict_pic = os.path.join(FLAGS.buckets, "prediction.jpg")
    img_obj = file_io.read_file_to_string(predict_pic)
    file_io.write_string_to_file("prediction.jpg", img_obj)

    img = scipy.ndimage.imread("prediction.jpg", mode="RGB")

    # Scale it to 32x32
    img = scipy.misc.imresize(img, (32, 32), interp="bicubic").astype(np.float32, casting='unsafe')

    # Predict
    prediction = model.predict([img])
    print (prediction[0])
    print (prediction[0])
    num=['airplane','automobile','bird','cat','deer','dog','frog','horse','ship','truck']
    print ("This is a %s"%(num[prediction[0].tolist().index(max(prediction[0]))]))

if __name__ == '__main__':
    parser = argparse.ArgumentParser()
    parser.add_argument('--buckets', type=str, default='',
                        help='input data path')
    parser.add_argument('--checkpointDir', type=str, default='',
                        help='output model path')
    FLAGS, _ = parser.parse_known_args()
    tf.app.run(main=main)

そして、2つのファイルを選んで、Workspace(OSSのルート)に同期します。すると、OSSにコードファイルが現れます。

これで、データとコードの準備がすべて整えました。

Drag&DropでTensorFlowを実行する

次は、OSSデータの読み取るとコードの実行のみになります。

Training

  • Experimentsを作成して、ComponetsからDeep Learning中のRead OSS Bucketを取ってきます。
  • TensorFlow(V1.4)を取り入れ、下記のように、OSSからデータとコードファイルを指定します。Output Directoryはモデルの置き場になります。TensorFlowのTuningタブでGPUの詳細設定ができますが、試しとして、分散型の8カードを設定します。
  • 最後に2つのモジュールを線で結び付けて、プロジェクトを実行するだけです。

実行中に、TensorFlowモジュールを右クリックして、ログを確認することができます。実行完成するまで、大体30分以上かかります。最後に、指定したOSSのPathにモデルファイルが作れます。

あとは、待つだけ、、、、、

、、

、、

、、

完了!!!

8カードで1586s(26分)かかりましたね。

Prediction

さて、作ったモデルがうまく行けますかね、ワクワクw

Trainingと同じ方法で、今回はprediction.pyに指定して、実行します。Output DirectoryはモデルのPathに指定します。実行すると、事前に用意したテスト用画像のprediction結果が確認できます。

下記の一枚目は自分で飼っている子猫の写真ですw

うん、大丈夫そうですね。しかし、これだけでは、モデルが良いかどうかを評価できません。精度を確保するためには、後期のチューニングや、モデル評価が必要です。その内容については、本記事では割愛します。

PAIでは、この様な作業も一部をモジュール化してますので、作業がらくになれると思います。

まとめ

はい、ここまでがPAIで実現したImage Recognitionでした。

機械学習エンジニアなら、この文章を読むだけでも、PAIの便利さが分かりますね。リリースしましたら、興味ある方はぜひ試して見てください。

 

この記事をシェアする