CJNANです。 前回のブログで、PAIの背景や特性をまとめてみました。
さて、これからはPAIを使って、Image Recognitionを実現する方法を紹介します。(勿論GPUインスタンスでも実現可能ですが、こうする場合は、事前にCUDAやTensorFlowの対応する必要がある)
Notice:
- 現時点(2018年8月21日)では、日本サイトでまだリリースされていないサービスですが、近い時期にリリースする予定がありますので、先走って、ご紹介します。
- 現時点(2018年8月21日)では、中国サイトのPAIしかGPUリソースを対応しませんので、本記事をトライしたい方は、中国アカウントでお試しください。
https://techblog.sbcloud.co.jp/2017/12/06/gpu_tensorflow/
https://techblog.sbcloud.co.jp/2018/08/20/pai/
はじめに
まず、PAIでDeep Learningをやる理由(メリット)を振り返しますと、
- クラウドによる初期導入コストの削減
- 大規模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の便利さが分かりますね。リリースしましたら、興味ある方はぜひ試して見てください。