Taste of Tech Topics

Acroquest Technology株式会社のエンジニアが書く技術ブログ

自前の機械学習プログラムをSageMaker Python SDKを用いてAmazon SageMaker上で動かす

こんにちは。
3年目エンジニアの片岡@kamesansansansです。
最近AWS機械学習サービスであるSageMakerを使っています。
SageMakerは公式サンプルが充実していて、色々な機械学習を簡単に動かすことができます。
ただ、一通りサンプルを動かして、いざ自前の機械学習プログラムを動かそうと思うと、調べても資料があまりない!ということに気づきます。
試行錯誤しつつ自分で動かして、分からず結構苦労したので、そのノウハウをここにまとめました。

方法

SageMaker上で自前のモデルを作成する方法は2つあります。
①SageMaker Python SDKを使う
②自作のDockerコンテナを利用する

②は過去にこのブログで解説されているので、今回は①について解説します。
 http://acro-engineer.hatenablog.com/entry/2018/09/05/120000

①について、
PythonSDKを使って少しコードを変えることで自前のコードをSageMaker上で動かすことができます。
ChainerやTensorflowなど各フレームワークごとにやり方が決まっています。
https://docs.aws.amazon.com/ja_jp/sagemaker/latest/dg/frameworks.html
今回はChainerのコードをSageMaker上で動かしてみました。

大まかな流れ

下記の3つを準備して実行します。
1)学習させるデータ
2)学習を行うPythonソースコード
3)学習用のインスタンスを立ち上げ学習を起動するJupyter notebook

Chainerのexampleにあるimagenetを使った画像分類のソースコード(詳細は後述)を例に今回は説明します。
データセットはimagenetでは重いので、Caltech101を入力の型をあわせて使用しました。

1)学習させるデータ

まずはCaltech101のデータセットの準備です。ここはSageMaker関係ない一般的な部分ですね。
下記リンクの「画像の用意、教師データとテストデータ」を参考にデータのダウンロード、リサイズ、meanファイルの作成を行います。
https://qiita.com/rerere0101/items/fde1661df4a26f1d0626

下記のようなディレクトリ構成になるはずです。

(親ディレクトリ)   
 ├train.txt   
 ├test.txt 
 ├lobel.txt 
 └caltech101 
  ├accordion 
    image_0001.jpg 
    … 
  ├airplanes 
    image_0001.jpg 
     … 
  …


~~~
(下記は本データセットをSageMaker上で使用するときの特有の手順)
train.txt, test.txtは画像パスを下記のように変更します。
train.txtの中身

 /opt/ml/input/data/train/caltech101/accordion/image_0001.jpg 0 
 /opt/ml/input/data/train/caltech101/accordion/image_0002.jpg 0 

test.txtの中身

 /opt/ml/input/data/test/caltech101/accordion/image_0043.jpg 0 
 /opt/ml/input/data/test/caltech101/accordion/image_0044.jpg 0 

★注意点
 <画像のパス> <正解ラベル>
 という並びになりますが、データの呼び出しはS3からSageMakerインスタンスに呼び出された後に行われるため、パスはSageMakerインスタンスに置かれたときのパスを指定します。
 
 S3に置いた画像データセットは/opt/ml/input/data/以下にコピーされます。
 学習用の画像は/opt/ml/input/data/train, 評価用の画像は/opt/ml/input/data/test以下に置かれます。

 SageMakerインスタンスにどのようにコピーされるかの構成はこちらを参照ください。
  http://acro-engineer.hatenablog.com/entry/2018/09/05/120000
~~~


このセット(train.txt, test.txt, caltech101ディレクトリ)をS3に配置してください。

2)学習を行うPythonソースコード

Chainerのexampleにある下記のソースコードを使用してSageMaker対応を行いました。
https://github.com/chainer/chainer/blob/master/examples/imagenet/train_imagenet.py
名前はtrain_imagenet.pyですが、入力の型を合わせることによって、imagenet以外のデータセットでも使用することができます。
ただし、二箇所変更が必要です。

★変更箇所① S3のパスを学習を起動するJupyter Notebook側で指定するので受け口を作ります。
 下記をargparseで指定しているところに追記します。

    parser.add_argument('--output_data_dir', type=str, default=os.environ['SM_OUTPUT_DATA_DIR']) 
    parser.add_argument('--model-dir', type=str, default=os.environ['SM_MODEL_DIR']) 
    parser.add_argument('--train', type=str, default=os.environ['SM_CHANNEL_TRAIN']) 
    parser.add_argument('--test', type=str, default=os.environ['SM_CHANNEL_TEST']) 

次の引数を指定できるようにします。
・output_data_dir グラフ等生成物の出力ディレクト
・model-dir モデルの出力ディレクト
・train train画像のディレクト
・test test画像のディレクト

これに伴い、ソースコード内で同様の働きをしているもの(元々ソースコード内にあるtrainやval等)は書き換えます。

★変更箇所② データセットを指定する部分を変更します。
最初にargs.trainを呼び出す前(165行目より前)、に下記を入れます。

    # data setting 
    train = args.train + "/train.txt" 
    test = args.test + "/test.txt" 

学習を起動するJupyter NotebookではS3のバケットまでしか指定できないので、それ以降のファイル指定・操作は ソースコード側で行う必要があります。
ソースコード内でargs.trainやargs.test(元々はargs.val)で渡しているものはそれぞれtrain, testに書き換えましょう。

3)学習用のインスタンスを立ち上げ学習を起動するJupyter notebook

 https://github.com/awslabs/amazon-sagemaker-examples/blob/master/sagemaker-python-sdk/chainer_cifar10/chainer_single_machine_cifar10.ipynb
 上記を参考に作成します。

学習用のノートブックインスタンスには、以下のように配置します。
呼び出される側のプログラムはすべてsrcフォルダの中に入れておいてください。

学習起動Jupyter notebook 
src/
 └学習を行うPythonのソースコード

学習起動Jupyter notebookには下記のように書いていき、順に実行していきます。

sagemaker.session()の作成と、ロールの取得を行います。

import sagemaker
from sagemaker import get_execution_role
sagemaker_session = sagemaker.Session()

# Get a SageMaker-compatible role used by this Notebook Instance.
role = get_execution_role()

バケットとその後のパスを指定します。
imagenet_sagemaker以下に学習用データを置きました。

bucket = '<your-bucket-name>'
prefix = 'sagemaker/imagenet-chainer'
S3_INPUT_PATH = 's3://{0}/{1}/'.format(bucket, prefix)
print(S3_INPUT_PATH)

estimaterの作成を行います。
呼び出すプログラムをentry_pointで、プログラムを入れたフォルダをsource_dirで指定しました。
source_dirで指定したフォルダがそのままSageMakerインスタンスにコピーされます。
(なので、ソースコード以外にもSageMakerインスタンスにコピーしたいものがあればsource_dirに入れておけば、一緒にコピーすることができます。)
train_imagenet.py内で元々指定するようになっている引数はhyperparametersで指定します。

import subprocess
from sagemaker.chainer.estimator import Chainer

instance_type = 'ml.c4.xlarge'

chainer_estimator = Chainer(entry_point='train_imagenet.py', role=role, 
                            source_dir="src", 
                            train_instance_count=1,  
                            train_instance_type=instance_type, 
                            framework_version='5.0.0', 
                            hyperparameters={'arch': "mobilenet"}) 

学習を実行します。

train_input = "s3://20190225-sagemaker/sagemaker/imagenet-chainer/" 
test_input = "s3://20190225-sagemaker/sagemaker/imagenet-chainer/" 
chainer_estimator.fit({'train': train_input, 'test': test_input}) 

これで自前の機械学習コードをSageMaker上で動かすことができました。

ポイント

①データはすべてS3にあげる。パスを指定する場合はSageMakerインスタンスにコピーされた後の構成を意識する
②学習を行うソースコードはSageMakerの仕様に合わせる。
③ノートブックインスタンスからSageMakerインスタンスに送る学習用ソースコードは別ディレクトリにまとめておく。

まとめ

自前のソースコードをSageMaker上でPython SDKを用いて動かしてみました。
SageMaker特有の仕様もあり、最初は分からない部分もありましたが、分かってしまえば簡単に実行できるものだな、と思います。
この記事ではChainerを例に説明しましたが、ポイントを押さえて書くことで、他のフレームワークでも応用できると思います。

Acroquest Technologyでは、キャリア採用を行っています。


  • ディープラーニング等を使った自然言語/画像/音声/動画解析の研究開発
  • Elasticsearch等を使ったデータ収集/分析/可視化
  • マイクロサービス、DevOps、最新のOSSを利用する開発プロジェクト
  • 書籍・雑誌等の執筆や、社内外での技術の発信・共有によるエンジニアとしての成長

 
少しでも上記に興味を持たれた方は、是非以下のページをご覧ください。

Kaggle Masterと働きたい尖ったエンジニアWanted! - Acroquest Technology株式会社のエンジニア中途・インターンシップ・契約・委託の求人 - Wantedlywww.wantedly.com