AWSDeepRacerのローカルトレーニング 2021版(DeepRacer For Cloud) を最速で走らせてみる
AWS事業本部梶原@福岡オフィスです。AWS DeepRacerではMentaiko-DevelopersIOで参加しています。
AWS DeepRacerには昨年のre:Inventはオンライン大会の決勝にでたんですが、残念ながら初戦敗退してしまいました。 しかしながら先月の1月の2021 Pre-seasonでは、裏技テレポートして3位表彰台に上がってしまいました。(本選ではダメだよ 裏技まで使ったのにまたしても目の前にはぐぬぬぬ
気を取り直して、今年も本シーズンに向けてすでに予選が始まってます!
そして、今月上位10%以内に入るとPROリーグ選出、なんとAWSDeepRacerオリジナルジャケットが貰えるそうです!
公式通知 https://d1.awsstatic.com/deepracer/2021AWSDeepRacerPreSeasonTermsandConditions.pdf
WINNER DETERMINATION AND PRIZES: The top 10% of racers with the lowest total time will be announced on March 5, 2021 and will be promoted to the Pro division of the AWS DeepRacer League, described further below, and will win a DeepRacer racing jacket (the “Prize”).
ということで?、AWS DeepRacerを一番速く走らせれるのは僕なんだ!といきたいところですが
ちょっと現状世界の壁が厚いので
その前に、AWS上でAWS DeepRacerのローカルトレーニングを一番速く立ち上げてみたいと思います。
待望の?スポットインスタンスで CloudFormation一撃化 S3バケットもRoleもつけといた!
cloud-configで、AWS DeepRacer for Cloud のリポジトリももってきて、初期化処理までおまけだ!、もってけ!
しています。もうエンジンがかからないなんて言わせない。
「Developers, start your engines. 」
※※※ 注意 ※※※
去年に続きお約束です。
無料利用枠の対象外のリソースを作成しますので課金が発生します。トレーニングも通常長い時間がかかりますので、実際にトレーニングを行う場合はスポットインスタンスのご利用を強くお勧めします。
今回はスポットインスタンス起動込みのCloudFormationテンプレートを提供しています
また、今回ご紹介する、EC2でのAWS DeepRacer のローカルトレーニング方法はAWS ではサポートされていませんのでAWSへの問合せなどはお控えください。
https://aws.amazon.com/jp/deepracer/faqs/?nc1=h_ls
Q: AWS Cloud ではなく自分のコンピューターで、モデルをローカルにトレーニングすることはできますか?
現在のところ AWS DeepRacer ではローカルトレーニングはサポートされていません。
困った場合は AWS DeepRacer Community: https://deepracing.io/ などで(自分も参加しています)助けてもらえる事があるかもしれませんが、あくまで自己責任で実施ください。
また、2月は特に問題はないように見えますが、今後も含めて、ローカルトレーニングで作成したモデルで今後も参加できることは保証できません。
こんな状況なのですが、AWS DeepRacer Community の有志の方々でローカルトレーニングは日々、修正メンテされており、ほんと頭が上がりません、AWS DeepRacer Communityの皆さんにこの場を借りてお礼申し上げます。コロナ過が落ち着いたらラスベガスにお土産持っていきます。
AWS DeepRacerとは
おそらく、このページが必要になってる方は説明不要だと思うので詳細割愛します。
私見ですが、
車が好きでレースに参加していたら、気が付くと機械学習に詳しくなってラスベガスに行けてしまう?そんなサービスです。
Developsers.IOの特集カテゴリもございますので、ご参考ください
AWS DeepRacer – 特集カテゴリー –
https://dev.classmethod.jp/referencecat/aws-deepracer/
ローカルトレーニングとは
通常 AWS DeepRacerはAWSのコンソール上から、お手軽にモデルのトレーニングを開始、レースに参加できます。(無料利用枠もあります)
AWS DeepRacerは、AWSのマネージドサービスSageMaker, RoboMaker, S3, Kinesis等を組み合わせてAWSのコンソール上で実施できるようにサービスが提供されています。 AWS DeepRacerの構築内容などはAWSから公開されています。それを単独の環境(EC2やローカルのPCなど)でモデルのトレーニングを実行できるように有志によって作成されたのがローカルトレーニングになります。
主なモチベーションはコストメリットになりますが、やはりマネージドサービスを使わないことによるトレードオフが発生します。具体的にはメモリ不足、ストレージの空き容量などのハード面の管理、個人的に一番大きいと思っているのがモデルの履歴管理を自分でしないといけません。これがSageMakerやAWS DeepRacerのコンソールはよくできており、ローカルトレーニングをやっているとすぐモデルやハイパーパラメータが迷子になってしまいます。
とはいえ、ローカルトレーニング環境を触っていると、各サービスの連携やSageMaker,RoboMakerの実装方法などに詳しくなれます。そして自由にカスタマイズ(壊すこともよくありますが)もできます。
EC2でのAWS DeepRacerのローカルトレーニング環境構築
環境作成にあたり
AWS DeepRacer Community のローカルトレーニングdeepracer-for-cloud
https://aws-deepracer-community.github.io/deepracer-for-cloud/
の情報をもとに構築を行っています。
使用するリポジトリ
AWS DeepRacerのローカルトレーニングのリポジトリはいくつかありますが、以下のリポジトリを使用しています
https://github.com/aws-deepracer-community/deepracer-for-cloud
作成するリソース
S3バケット
項目 | 値 | 備考 |
---|---|---|
バケット名 | deepracer-for-cloud-${UniqueId} |
ここに、モデル等がアップロードされます また、トレーニング中も使用されます
セキュリティグループ
項目 | 値 | 備考 |
---|---|---|
名前 | deepracer-for-cloud-sg | |
SSH | 22 | 入力された接続元のみで制限 |
ビューア用 | 8100 | 入力された接続元のみで制限 |
ログ解析用 | 8888 | 入力された接続元のみで制限 |
EC2用のRole
項目 | 値 | 備考 |
---|---|---|
S3 | FullAccess | 作成したS3バケットへの読み書き |
AmazonKinesisVideoStreams | FullAccess | KinesisVideoStreamsへの読み書き |
SSM | AmazonSSMManagedInstanceCore | 基本不要ですがメンテナンス用です |
EC2インスタンス
項目 | 値 | 備考 |
---|---|---|
AMI | AWS Deep Learning AMI (Ubuntu 18.04) Version 40.0 (ami-0423232d1433f88e6) | 米国東部 (バージニア北部)us-east-1 以外は別の値を指定してください |
ディスク容量 | 150GB | 必要に応じて拡張してください |
EIP | aaa.bbb.ccc.ddd | EIPアドレスを割り当てています |
インスタンスタイプ | c5.2xlarge | GPU使用したい場合はG系のインスタンスを選択ください |
Role | S3, Kinesisへの権限をつけたRoleを付与しています | 作成したモデルをアップロードするために必要です。 |
スポットインスタンスで起動します。デフォルト設定ではオンデマンド価格設定のため、スポット価格の高騰にはご注意ください
環境構築
CloudFormatin 一撃
下記のリンクをポチっとして、スタックをデプロイするだけで、米国東部 (バージニア北部)us-east-1 で DeepRacer for cloud の初期設定まで終わったスポットインスタンスが起動します 初期化に少々時間がかかるので10分程度はお待ちください
テンプレートはこちら 各パラメータは下記です。
項目 | 値 | 備考 |
---|---|---|
ImageId | ami-072519eedc1730252 | Ubuntu 18.04 米国東部 (バージニア北部)以外は別の値を指定してください |
InstanceType | c5.2xlarge | gpuでしたいときはg4dn.2xlarge |
KeyName | キーペアを指定してください | |
SpotPrice | スポットインスタンスの価格を設定してください 指定なしはオンデマンド価格です | |
VolumeSize | 150 | S3にモデルは置かれるので十分だとおもいますが必要に応じて拡張を |
SourceIp | xx.xx.xx.xx/xx | アクセス制限もとのIPアドレスを指定してください |
環境初期設定
SSHで対象のインスタンスに接続して、以下コマンドを実行していきます。 AWS Deep Learning AMI (Ubuntu 18.04) を使用しているので ユーザ名は 'ubuntu'です。
作成したキーペアでSSHでアクセスできることを確認してください
なお、DeepRacer for Cloud で案内されているInstall時のコマンドはcloud-initで実施しており そのなかで、Dockerやらドライバやらやらすべて実施されます
git clone https://github.com/aws-deepracer-community/deepracer-for-cloud.git cd deepracer-for-cloud && ./bin/prepare.sh
そう、今回、環境構築はありません。ないんです! AWS DeepRacer Community の皆さんのおかげです。
なお、S3バケットを作ったり、Roleを作ったり、SGを作ったり、スポットインスタンスを作ったり、
cloud-configで初期化したりするCloudFormationの部分はちょっぴりほめてくれる方がいれば嬉しいです。
トレーニングの開始
てことで 一旦、報酬関数やハイパーパラメータ、トラックなどは変更せずに動作確認をおこなってみてください。
初回は起動は時間がかかる、また起動に失敗することもありますので、シミュレーション画面が見れなかった場合や、トレーニングが開始してない場合は一度トレーニングを終了し再度開始してください。
特にエラーが発生せず、ログが進みだして、シミュレーションが開始されれば成功です。
カスタムファイルのアップロード
$ cd deepracer-for-cloud/ $ dr-upload-custom-files Uploading files to s3://deepracer-for-cloud-XXXXXXXX/custom_files/ upload: custom_files/hyperparameters.json to s3://deepracer-for-cloud-XXXXXXXX/custom_files/hyperparameters.json upload: custom_files/model_metadata.json to s3://deepracer-for-cloud-XXXXXXXX/custom_files/model_metadata.json upload: custom_files/reward_function.py to s3://deepracer-for-cloud-XXXXXXXX/custom_files/reward_function.py
なお、dr-xxxコマンドが出ない場合は
$ source bin/activate.sh
で、読み込まれます
トレーニング開始
$ dr-start-training 省略 ## Stop physics after creating graph ## Creating session Creating regular session Checkpoint> Saving in path=['./checkpoint/agent/0_Step-0.ckpt']
ビューアー表示
$ dr-start-viewer Creating service deepracer-0-viewer_proxy
シミュレーション画面の確認
ブラウザでインスタンスに割り当てたパブリックIPにアクセスしてみます
http://aaa.bbb.ccc.ddd:8100
にアクセスしてみてください。
トレーニングの終了
以下コマンドを実行するとトレーニングが終了します
$ dr-stop-training
各種パラメータの設定
ここまでいけば、アクション、報酬関数、ハイパーパラメータ、トラックなどを変更してトレーニングを実施してみてください
詳しくは https://aws-deepracer-community.github.io/deepracer-for-cloud/reference.html
をご参照ください
作成したモデルのインポート
トレーニング中、今回作成したS3バケットを使用しているので、インポート時はそのバケットを指定します 特に変更しなければ、最終トレーニングしたものは
s3://deepracer-for-cloud-XXXXXXXX/rl-deepracer-sagemaker/
に保存されます。 ベストモデルなどをアップロードしたい場合は内容を変更してください
まとめ
ちょっと違う意味の最速でしたがいかがでしょうか?いい感じに活用してください。
なお、まだプレシーズンなので、ローカルトレーニングもこのまま無事動いて完走できることはないと思っています。
困った場合はAWS DeepRacerのコミュニティで声をかけてください。日本語チャンネルもあります。
では、仮想サーキットでお会いできるのを楽しみにしております。
おまけ
実は自宅PCでも以下Specで24H耐久レースでトレーニングをしています。今年はCPUを変更したいです。
項目 | 値 | 備考 |
---|---|---|
OS | Ubuntu 18.04 | |
CPU | Intel CPU Core i7-6700 | |
Memory | 48GB | |
GPU | Nvidia GPU RTX2060 Super |
参考情報
AWS DeepRacer Community Wiki - Local Training https://wiki.deepracing.io/Local_Training
AWS DeepRacer Community Wiki https://wiki.deepracing.io/Main_Page
deepracer-for-cloud https://aws-deepracer-community.github.io/deepracer-for-cloud/
テンプレートファイル
AWSTemplateFormatVersion: "2010-09-09" Parameters: ImageId: Description: Enter the AWS Deep Learning AMI (Ubuntu 18.04) AMI for the us-east-1 region. Type: String Default: ami-072519eedc1730252 InstanceType: Description: EC2 instance of type G3, G4, P2 or P3 - recommendation is g4dn.2xlarge - for GPU enabled training. C5 or M6 types - recommendation is c5.2xlarge - for CPU training. Type: String AllowedValues: - g3s.xlarge - g3.4xlarge - g4dn.xlarge - g4dn.2xlarge - g4dn.4xlarge - p2.xlarge - p3.2xlarge - c5.large - c5.xlarge - c5.2xlarge - c5.4xlarge Default: c5.2xlarge KeyName: Description: The name of the key pair. Type: AWS::EC2::KeyPair::KeyName Default: drfc-ec2-keypair SpotPrice: Description: The maximum price per unit hour that you are willing to pay for a Spot Instance. The default is the On-Demand price. Type: String Default: "" VolumeSize: Description: The size of the volume, in GiBs. Type: Number Default: 150 MinValue: 1 MaxValue: 16384 SourceIp: Description: Specify the CIDR block of the access source. Type: String Default: 192.168.1.1/32 AllowedPattern: (\d{1,3})\.(\d{1,3})\.(\d{1,3})\.(\d{1,3})/(\d{1,2}) Conditions: SpotPrice: !Not [!Equals [!Ref SpotPrice, ""]] Resources: DRfCS3Bucket: Type: AWS::S3::Bucket Properties: BucketName: !Sub - deepracer-for-cloud-${UniqueId} - UniqueId: !Select [0, !Split ['-', !Select [2, !Split [/, !Ref 'AWS::StackId']]]] DRfCSecurityGroup: Type: AWS::EC2::SecurityGroup Properties: GroupDescription: deepracer-for-cloud-sg GroupName: deepracer-for-cloud-sg SecurityGroupIngress: - Description: access to ssh CidrIp: !Ref SourceIp FromPort: 22 IpProtocol: tcp ToPort: 22 - Description: access to viewer CidrIp: !Ref SourceIp FromPort: 8100 IpProtocol: tcp ToPort: 8100 - Description: access to log-analysis CidrIp: !Ref SourceIp FromPort: 8888 IpProtocol: tcp ToPort: 8888 DRfCInstanceRole: Type: AWS::IAM::Role Properties: Policies: - PolicyDocument: Version: "2012-10-17" Statement: - Action: - s3:* Resource: - !Sub 'arn:${AWS::Partition}:s3:::${DRfCS3Bucket}' - !Sub 'arn:${AWS::Partition}:s3:::${DRfCS3Bucket}/*' Effect: Allow PolicyName: s3-deepracer-bucket-policy Path: / ManagedPolicyArns: - !Sub 'arn:${AWS::Partition}:iam::aws:policy/AmazonSSMManagedInstanceCore' # - !Sub 'arn:${AWS::Partition}:iam::aws:policy/AmazonVPCReadOnlyAccess' - !Sub 'arn:${AWS::Partition}:iam::aws:policy/AmazonKinesisVideoStreamsFullAccess' # - !Sub 'arn:${AWS::Partition}:iam::aws:policy/CloudWatchFullAccess ' AssumeRolePolicyDocument: Version: "2012-10-17" Statement: - Effect: Allow Principal: Service: - ec2.amazonaws.com Action: sts:AssumeRole DRfCInstanceRoleProfile: Type: AWS::IAM::InstanceProfile Properties: Roles: - !Ref DRfCInstanceRole DRfCLaunchTemplate: Type: AWS::EC2::LaunchTemplate Properties: LaunchTemplateData: InstanceMarketOptions: MarketType: spot SpotOptions: InstanceInterruptionBehavior: stop MaxPrice: !If [SpotPrice, !Ref SpotPrice, !Ref 'AWS::NoValue'] SpotInstanceType: persistent LaunchTemplateName: DRfCLaunchTemplate DRfCInstance: Type: AWS::EC2::Instance Properties: BlockDeviceMappings: - DeviceName: /dev/sda1 Ebs: VolumeSize: !Ref VolumeSize VolumeType: gp3 IamInstanceProfile: !Ref DRfCInstanceRoleProfile ImageId: !Ref ImageId InstanceType: !Ref InstanceType KeyName: !Ref KeyName LaunchTemplate: LaunchTemplateId: !Ref DRfCLaunchTemplate Version: !GetAtt DRfCLaunchTemplate.LatestVersionNumber SecurityGroupIds: - !GetAtt DRfCSecurityGroup.GroupId Tags: - Key: Name Value: DRfC UserData: !Base64 Fn::Sub: | #cloud-config repo_update: true repo_upgrade: all runcmd: - su - ubuntu -c "cd /home/ubuntu; git clone https://github.com/aws-deepracer-community/deepracer-for-cloud.git" - su - ubuntu -c "sed -i -e 's/^\DR_LOCAL_S3_BUCKET=bucket/DR_LOCAL_S3_BUCKET=${DRfCS3Bucket}/' /home/ubuntu/deepracer-for-cloud/defaults/template-system.env" - su - ubuntu -c "cd /home/ubuntu/deepracer-for-cloud; ./bin/prepare.sh" output : { all : '| tee -a /var/log/cloud-init-output.log' } DRfCEIP: Type: AWS::EC2::EIP Properties: InstanceId: !Ref DRfCInstance Tags: - Key: Name Value: DRfC CancelSpotInstanceRequestsLambda: Type: AWS::Lambda::Function Properties: Code: ZipFile: | import json import boto3 import cfnresponse def handler(event, context): try: print(event) params = dict([(k, v) for k, v in event['ResourceProperties'].items() if k != 'ServiceToken']) client = boto3.client('ec2') if event['RequestType'] == 'Create': response = client.describe_instances(**params) print(response) SpotInstanceRequestId = response['Reservations'][0]['Instances'][0]['SpotInstanceRequestId'] responseData = {} responseData['SpotInstanceRequestId'] = SpotInstanceRequestId cfnresponse.send(event, context, cfnresponse.SUCCESS, responseData, SpotInstanceRequestId) if event['RequestType'] == 'Delete': response = client.describe_instances(**params) print(response) SpotInstanceRequestId = response['Reservations'][0]['Instances'][0]['SpotInstanceRequestId'] response = client.cancel_spot_instance_requests( SpotInstanceRequestIds=[ SpotInstanceRequestId, ], ) print(response) responseData = {} responseData['SpotInstanceRequestId'] = SpotInstanceRequestId cfnresponse.send(event, context, cfnresponse.SUCCESS, responseData, SpotInstanceRequestId) if event['RequestType'] == 'Update': old_params = dict([(k, v) for k, v in event['OldResourceProperties'].items() if k != 'ServiceToken']) response = client.describe_instances(**old_params) print(response) SpotInstanceRequestId = response['Reservations'][0]['Instances'][0]['SpotInstanceRequestId'] response = client.cancel_spot_instance_requests( SpotInstanceRequestIds=[ SpotInstanceRequestId, ], ) print(response) response = client.describe_instances(**params) print(response) SpotInstanceRequestId = response['Reservations'][0]['Instances'][0]['SpotInstanceRequestId'] responseData = {} responseData['SpotInstanceRequestId'] = SpotInstanceRequestId cfnresponse.send(event, context, cfnresponse.SUCCESS, responseData, SpotInstanceRequestId) except Exception as e: print(e) cfnresponse.send(event, context, cfnresponse.FAILED, {}) Handler: index.handler MemorySize: 128 Role: !GetAtt AmazonEC2FullAccessRoleforLambda.Arn Runtime: python3.6 Timeout: 120 AmazonEC2FullAccessRoleforLambda: Type: AWS::IAM::Role Properties: AssumeRolePolicyDocument: Version: 2012-10-17 Statement: - Effect: Allow Principal: Service: lambda.amazonaws.com Action: sts:AssumeRole Path: / ManagedPolicyArns: - "arn:aws:iam::aws:policy/service-role/AWSLambdaBasicExecutionRole" - "arn:aws:iam::aws:policy/AmazonEC2FullAccess" CancelSpotInstanceRequests: Type: Custom::CancelSpotInstanceRequests Properties: ServiceToken: !GetAtt CancelSpotInstanceRequestsLambda.Arn InstanceIds: - !Ref DRfCInstance Outputs: DRfCS3BucketConsole: Value: !Sub "https://console.aws.amazon.com/s3/buckets/${DRfCS3Bucket}" DRfCEIP: Value: !Ref DRfCEIP DRfCViewerURL: Value: !Sub "http://${DRfCEIP}:8100/" DRfCLogAnalysisURL: Value: !Sub "http://${DRfCEIP}:8888/"