LoginSignup
3
2

More than 3 years have passed since last update.

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

Posted at

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

方法

SageMaker Python SDKを使って少しコードを変えることで自前のコードを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を例に説明しましたが、ポイントを押さえて書くことで、他のフレームワークでも応用できると思います。

3
2
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
3
2