SageMakerを利用してDeepRacerのモデルを学習する手順をまとめている。
基本的な手順は以下の公式ドキュメントにまとまっているものの、一部理解が足りていなかった部分を補足する内容をまとめている。
まだ理解の甘い部分、誤っている部分が多分に残っているが、今後理解を深めるための第一歩としてご容赦いただきたい。
目標
SageMakerを活用してDeepRacerのモデル学習を行い、DeepRacerにエントリーできるモデルが構築できることを目標とする。
これを足がかりとして、 AWSの各サービスへの理解の深化やより柔軟なDeepRacerのモデル構築を進めていきたい。
DeepRacerとは
自動運転のアプリケーションを構築することで、強化学習について学べるサービスである。
自動運転車に搭載するモデルに対して深層強化学習を適用し、学習したモデルばバーチャルレースなどのレースに出場させることができる。
あらゆるレベルのユーザが楽しめるように設計されており、初学者であっても報酬関数の設計のみで強化学習を体験することができる。
AWS DeepRacer コンソールというインターフェースも用意されており、
報酬関数の設計であれば環境構築のコストをかけずに参加できるようになっている。
今回はDeepRacerコンソールを使わずに、SageMakerを使ってモデルの学習を行なった。
SageMakerとは
SageMakerはフルマネージドの機械学習サービスである。
名前の通り機械学習モデルの構築を行う際に利用され、機械学習のあらゆるアルゴリズムが組み込まれており、簡単に機械学習を開始することができる。
学習や推論に必要なリソースを必要なときに必要な分だけプロビジョニングするため金銭的なコストも必要最低限に抑えられ、またフルマネージドのサービスであるため、保守運用等のコストも不要である。
Dockerコンテナを使用すると、独自のアルゴリズムを用いてモデルを構築することもできる。
RoboMakerとは
強化学習用のモデルの構築には、RoboMakerを組み合わせて使用する。
RoboMakerはシミュレーションを行うことができるサービスで、構築したモデルの走行をRoboMaker上でシミュレートし、その走行結果をSageMakerにフィードバックすることで強化学習を実現する。
SageMakerを利用するメリット
DeepRacerのモデル構築にSageMakerを使用することで、
- より柔軟な条件下でモデルを構築することができる。
- 走行データの情報量を増やすことができる。
2022/12/17日現在、DeepRacerコンソール上での学習では、学習の条件がある程度制限されている。
例えば、モデルの学習環境として、多数のコースが用意されているがコースごとに周回の方向が定められている。
ほとんどのコースが反時計回りとなっており、自分の場合、右折や右カーブの学習に苦労した。
ところがSageMaker・RoboMakerを使うとパラメータを調整することでシミュレーションの際の周回の方向を変更することができ、
学習の条件を柔軟に変更しながら、さまざまな状況で学習することが可能になる。
DeepRacerでは報酬関数を設計して自動走行車を作り上げていくが、その過程で走行ログの評価が必要になる。
報酬関数を設計し作り上げたモデルの走行ログを分析し、報酬関数の修正に活用していく。
これがDeepRacerの醍醐味の一つであると思う。
コンソール上の学習においても当然走行ログの取得はできるのだが、SageMaker (RoboMaker) を使用すると車から見えている画像データの取得をすることもできる。
DeepRacerのモデルは、車に搭載されているカメラで走行中の画像を取得し、その画像をもとに推論を行い次のアクションを決めているため、
走行ログの分析に画像を用い、モデルが何を見てアクションを決めているかなどを分析することで、報酬関数を設計するにあたり有用な情報が得られるのではないだろうか。
環境の構築
まずはモデルのトレーニングに必要となる環境を構築する。
- RoboMakerのシミュレーションアプリケーションの作成。
- SageMakerで使用するDockerイメージの作成。
- Kinesis Video Streamの作成。
モデルのアルゴリズム変更等を行わない限り、ここで作成したリソースは今後の学習において使いまわすことができる。
マルチユーザモードでDeepRacerをホストしている場合、これらのリソースはユーザ間で共有することができる。
RoboMakerシミュレーションアプリケーションの作成
RoboMakerアプリケーションの作成は、公開ECRからDeepRacer用のイメージを参照するだけである。
参照先の情報の通りであるため、詳細は省略する。
以下はboto3
を使用してアプリケーションを作成するコードの例である。
robomaker = boto3.client("robomaker")
robomaker.create_simulation_application(
name=app_name, # アプリケーション名
environment={"uri": "public.ecr.aws/k1d3r4z1/deepracer-sim-public:latest"},
simulationSoftwareSuite={"name": "SimulationRuntime"},
robotSoftwareSuite={"name": "General"}
)
SageMakerで使用するImageの作成
今回はCodeBuildを使用してイメージを構築した。
イメージのビルド時にdocker
コマンドを使用しているので、ビルドプロジェクトでは特権モードを有効化している。
イメージの構築に使用しているソースのディレクトリ構成は下記の通り。
./
├─ buildspec.yaml
└─ sagemaker/
├─ Dockerfile
└─ redis.conf
後掲のbuildspec.yaml
の通り、
RoboMakerのアプリケーション構築時に使用したイメージ (public.ecr.aws/k1d3r4z1/deepracer-sim-public
) からモデルのソースを取得している。
Dockerfile
とredis.conf
は、それぞれ基本的には下記を使用している。
-
Dockerfile
: https://github.com/aws-deepracer/aws-deepracer-workshops/blob/master/dpr401/Dockerfile -
redis.conf
: https://github.com/aws-deepracer/aws-deepracer-workshops/blob/master/dpr401/src/lib/redis.conf
ただし、redisの起動がうまくいかず学習画で止まっていたためredisの設定には変更を加えている。
Redisの3.2.0以降、Protected modeというものを導入しているようで(protected mode)、
これの無効化、あるいはパスワード認証を行う必要があるらしい。
redis.conf
に以下の修正を加えて、protected-modeを無効化している。
protected-mode no
修正を加えたredis.conf
をDockerイメージに反映させるため、Dockerfileにも修正を加えている。
COPY ./sagemaker/redis.conf /etc/redis/redis.conf
buildspec.yaml
CodeBuildで参照するbuildspec.yaml
の例である。
version: 0.2
env:
variables:
SIMULATION_IMAGE: public.ecr.aws/k1d3r4z1/deepracer-sim-public
SAGEMAKER_IMAGE: sagemaker-docker-cpu
IMAGE_TAG: latest
phases:
install:
on-failure: ABORT
commands:
- apt-get install -y jq
pre_build:
on-failure: ABORT
commands:
- AWS_ACCOUNT_ID=$(echo ${CODEBUILD_BUILD_ARN} | sed -E s/^.\*\(\[0-9\]\{12\}\).\*\$/\\1/)
- echo "${AWS_ACCOUNT_ID}:${AWS_DEFAULT_REGION}/${AWS_REGION}|${AWS_DEFAULT_REGION}"
- aws ecr get-login-password --region "${AWS_DEFAULT_REGION}" | docker login --username AWS --password-stdin "${AWS_ACCOUNT_ID}.dkr.ecr.${AWS_DEFAULT_REGION}.amazonaws.com"
- docker pull "${SIMULATION_IMAGE}"
- IMAGE_ID=$(docker images --format '{{ json . }}' | grep ${SIMULATION_IMAGE} | jq -r '.ID')
- CONTAINER_ID=$(docker run -d -t "${IMAGE_ID}")
- mkdir -p ./sagemaker/src/lib
- docker cp "${CONTAINER_ID}:/opt/amazon/markov" ./sagemaker/src/
- docker cp "${CONTAINER_ID}:/opt/amazon/rl_coach.patch" ./sagemaker/src/
- docker cp "${CONTAINER_ID}:/opt/ml/code/." ./sagemaker/src/lib/
build:
on-failure: ABORT
commands:
- docker build -t "${SAGEMAKER_IMAGE}" -f ./sagemaker/Dockerfile ./sagemaker
- docker tag "${SAGEMAKER_IMAGE}:latest" "${AWS_ACCOUNT_ID}.dkr.ecr.${AWS_DEFAULT_REGION}.amazonaws.com/${IMAGE_REPO_NAME_SAGEMAKER}:${IMAGE_TAG}"
- docker tag "${SAGEMAKER_IMAGE}:latest" "${AWS_ACCOUNT_ID}.dkr.ecr.${AWS_DEFAULT_REGION}.amazonaws.com/${IMAGE_REPO_NAME_SAGEMAKER}:latest"
post_build:
on-failure: ABORT
commands:
- docker push "${AWS_ACCOUNT_ID}.dkr.ecr.${AWS_DEFAULT_REGION}.amazonaws.com/${SAGEMAKER_IMAGE}:${IMAGE_TAG}"
- docker push "${AWS_ACCOUNT_ID}.dkr.ecr.${AWS_DEFAULT_REGION}.amazonaws.com/${SAGEMAKER_IMAGE}:latest"
モデルのトレーニング
SageMakerのジョブとRoboMakerのジョブを起動しモデルの学習を行う。
報酬関数とメタデータの定義
SageMakerとRoboMakerのジョブで参照する3ファイルをS3にアップロードする。
{s3-bucket}/
└─ {s3-prefix}/
├─ reward_function.py
├─ model_metadata.json
└─ training_param.yaml
-
reward_function.py
- 報酬関数を定義したPythonファイル。SageMakerとRoboMakerの両ジョブにて参照される。
-
model_metadata.json
- アクションスペースなどのモデルのメタデータを定義したJSONファイル。SageMakerとRoboMakerの両ジョブにて参照される。
-
training_param.yaml
- RoboMakerのジョブで利用する。報酬関数やメタデータファイルのパス、ログの出力先、SageMakerジョブ・Kinesis Video StreamのARNなどを指定する。
アクションスペースの定義
アクションスペースはメタデータファイルに定義する。
離散アクションスペース、連続アクションスペースでやや定義方法が変わるため、それぞれの例を以下に記載する。
離散アクションスペースの定義
"action_space"
をキーに、モデルがとりうる (ステアリング角, 速度)
の組の配列を指定する。
{
"action_space": [
{ "steering_angle": -30, "speed": 1.0 },
{ "steering_angle": -15, "speed": 1.0 },
{ "steering_angle": 0, "speed": 1.0 },
{ "steering_angle": 15, "speed": 1.0 },
{ "steering_angle": 30, "speed": 1.0 }
],
"sensor": [ "STEREO_CAMERAS" ],
"neural_network": "DEEP_CONVOLUTIONAL_NETWORK_SHALLOW"
}
連続アクションスペースの定義
"action_space"
をキーに、モデルがとりうるステアリング角の範囲、速度の範囲を指定する。
"action_space_type"
に連続アクションスペースである旨を示す"continuous"
を指定する。
{
"action_space": {
"steering_angle": { "high": 30, "low": -30 },
"speed": { "high": 4, "low": 2 }
},
"sensor": [ "FRONT_FACING_CAMERA", "SECTOR_LIDAR" ],
"neural_network": "DEEP_CONVOLUTIONAL_NETWORK_SHALLOW",
"version": "4",
"training_algorithm": "clipped_ppo",
"action_space_type": "continuous",
"preprocess_type": "GREY_SCALE",
"regional_parameters": [ "0", "0", "0", "0" ]
}
SageMakerジョブの作成
モデルの学習を行うSageMakerのジョブを作成する。
RoboMaker上のシミュレーション結果をフィードバックとして受け取り学習が開始されるため、RoboMakerのジョブがローンチされてから学習が開始される。
# ジョブ作成時に指定する
metric_definitions = [
{"Name": "reward-training", "Regex": "^Training>.*Total reward=(.*?),"},
{"Name": "ppo-surrogate-loss", "Regex": "^Policy training>.*Surrogate loss=(.*?),"},
{"Name": "ppo-entropy", "Regex": "^Policy training>.*Entropy=(.*?),"},
{"Name": "reward-testing", "Regex": "^Testing>.*Total reward=(.*?),"},
]
# ハイパーパラメータの設定
custom_hyperparameter = {
"s3_bucket": s3_bucket, # S3バケットの指定
"s3_prefix": s3_prefix, # S3プレフィクスの指定
"aws_region": aws_region,
"model_metadata_s3_key": f"s3://{s3_bucket}/{s3_prefix}/model_metadata.json",
"reward_function_s3_source": f"s3://{s3_bucket}/{s3_prefix}/reward_function.json",
"batch_size": "64",
"num_epochs": "10",
"stack_size": "1",
"lr": "0.0003",
"exploration_type": "Categorical",
"e_greedy_value": "1",
"epsilon_steps": "10000",
"beta_entropy": "0.01",
"discount_factor": "0.999",
"loss_type": "Huber",
"num_episodes_between_training": "20",
"max_sample_count": "0",
"sampling_frequency": "1",
# 学習済みモデルのバケットとプレフィクス
# "pretrained_s3_bucket": s3_bucket,
# "pretrained_s3_prefix": f"{s3_username}/deepracer-notebook-sagemaker-200729-202318",
}
# SageMakerジョブの作成
sagemaker = boto3.client("sagemaker", region_name=aws_region)
traning_job = sagemaker.create_training_job(
TrainingJobName=training_job_name,
HyperParameters=custom_hyperparameter,
AlgorithmSpecification={
"TrainingImage": f"{custom_image_uri}:latest",
"TrainingInputMode": "File",
'MetricDefinitions': metric_definitions
},
RoleArn=sagemaker_role,
OutputDataConfig={
"S3OutputPath": f"s3://{s3_bucket}/{s3_prefix}/train-output/",
},
ResourceConfig={
'InstanceType': instance_type,
'InstanceCount': 1,
'VolumeSizeInGB': 32
},
VpcConfig={
'SecurityGroupIds': deepracer_security_groups,
'Subnets': deepracer_subnets
},
StoppingCondition={
'MaxRuntimeInSeconds': job_duration_in_seconds
},
)
Kinesis Video Streamの作成
Kinesis Video Streamはシミュレーションジョブ数分作成し、各RoboMakerのジョブにストリーム名を指定する。
学習終了後はストリームの削除を行わないと、起動し続けてしまう。
aws --region {aws_region} kinesisvideo create-stream --stream-name {kvs_stream_name} --media-type video/h264 --data-retention-in-hours 24
RoboMakerジョブの作成
training_param.yaml
には、コースの指定やレースの種類などを指定し、RoboMakerのジョブにて参照する。
RoboMakerのジョブをローンチすることで学習が開始される。
ジョブのローンチのコードはこちらの通りなので省略する。
モデルのインポート
モデルの学習が完了すると、 DeepRacerコンソールからモデルをインポートすることができる。
ただし、インポートに必要なディレクトリの構成が決まっているようで (https://docs.aws.amazon.com/ja_jp/deepracer/latest/developerguide/deepracer-troubleshooting-service-migration-errors.html#s3-folder-structure) 、
それに従う必要がある。
出力の構成例を後掲しているが、ip
ディレクトリとmodel
ディレクトリが必要になるらしい。
また、残念ながら2022年12月17日現在マルチユーザモードで各ユーザがモデルをインポートする手段はないようで、マルチユーザモード下では管理者ユーザがユーザを指定してインポートする必要がある。
出力の構成例
s3://{buckket}/{prefix}/
└─ deepracer-training-sagemaker-*****-*****/
│
│ # モデルアーティファクト
├─ ip/
│ ├─ done
│ ├─ hyperparameters.json
│ └─ ip.json
├─ model/
│ ├─ .coach_checkpoint
│ ├─ .ready
│ ├─ {N}_Step-9605.ckpt.data-00000-of-00001
│ ├─ {N}_Step-9605.ckpt.index
│ ├─ {N}_Step-9605.ckpt.meta
│ ├─ deepracer_checkpoints.json
│ ├─ model_{N}.pb
│ └─ model_metadata.json
│
│ # ログデータ
├─ iteration-data/training/
│ ├─ camera-45degree/
│ │ └─ {N}-video.mp4
│ ├─ camera-pip/
│ │ └─ {N}-video.mp4
│ ├─ camera-topview/
│ │ └─ {N}-video.mp4
│ └─ training-simtrace/
│ └─ {N}-iteration.csv
├─ sim-y41231383h9g/2022-12-14T13-40-11.900Z_2e900cea-0679-4053-99aa-81f54f6cc29c/
│ ├─ gazebo-logs/server-11345/
│ │ ├─ default.log
│ │ └─ gzserver.log
│ └─ ros-logs/
│ ├─ 1fbeb178-7bb5-11ed-b6eb-0242a9fe0102/
│ │ ├─ agents_video_editor-6.log
│ │ ├─ car_reset_node-5.log
│ │ ├─ download_params_and_roslaunch_agent_node-2.log
│ │ ├─ master.log
│ │ ├─ racecar-controller_manager-2.log
│ │ ├─ racecar-racecar_spawn-1.log
│ │ ├─ roslaunch-712974d3eac6-1.log
│ │ ├─ roslaunch-712974d3eac6-435.log
│ │ ├─ rosout-1-stdout.log
│ │ ├─ rosout.log
│ └─ rl_coach_545_1671025341644.log
├─ train-output/deepracer-training-sagemaker--*****-*****/output/model.tar.gz
├─ INITIAL_S3_WRITE_KEY
│
│ # 入力
├─ customer_reward_function.py
├─ training_metrics.json
└─ training_params.yaml