Translate

2019年1月31日木曜日

ブログ記事 「Learning to Drive Smoothly in Minuts」 を翻訳してみた

以下の文章はブログ記事 Learning to Drive Smoothly in Minuts を勝手に翻訳したものです。

このブログ記事のタイトルから..前に読んだ論文「Learn to Drive in a Day」 (勝手日本語訳はこちらに喧嘩売ってを意識してるんだろうなあ..きっと..

-----

Learning to Drive Smoothly in Minuts

小さなレーシングカー上で強化学習




Unityシミュレータのてれオペレーションコントロールパネルで動作中のDonkeycar

この記事では、自動運転レーシングカーを数分でトレーニングする方法と、その制御を円滑にする方法について説明します。この方法は、強化学習(RL)に基づいており、ここではシミュレーション(Donkey Car simulator)で提示されていますが、現実の世界に適用できるように設計されています。それは自動運転にフォーカスしている Wayve.ai というスタートアップの作業上でビルドしています。

この記事で使用されているコードとシミュレータはオープンソースで公開されています。詳細については、関連するGitHubレポジトリを確認してください。 :)(トレーニング済みのコントローラもダウンロード可能)


動画




GitHub リポジトリ: 結果の再現

[GitHub] Learning to Drive Smoothly in Minuts
https://github.com/araffin/learning-to-drive-in-5-minutes


はじめに:レージングカー競技


数年前の DIY Robocars を立ち上げ以来、数多くの自動運転レーシングカーの競技会が開催されています(例:Toulouse Robot Race、Iron Carなど  )。それらの目標はシンプルです:あなたはレーシングカーを持っていて、入力としてその搭載カメラからの画像だけを与えられて、トラックにとどまっている間できるだけ速く走行する。




DIY Robocarに触発されたDonkeyシミュレータの倉庫シーン

自動運転への挑戦は、ロボット工学に入門するための良い方法です。学習を容易にするために、オープンソースの自動運転プラットフォームである Donkey Car が開発されました。そのエコシステムでは、その小型ロボットを特色とする Unityシミュレータ があります。このDonkey Carベースで提案されているアプローチをテストします。


アウトライン


小規模な自動運転車の競技で使用されているさまざまな方法を簡単に検討した後、強化学習とは何かを提示してから、私たちのアプローチの詳細に入ります。



Arduino、Raspberry Pi、PiCamera を搭載した自動運転レーシングロボット


自動運転競技で使用される方法:ライン追跡と行動クローニング


強化学習を紹介する前に、まずRCカーの競技会で現在使用されているさまざまなソリューションについて簡単に説明します。

以前のブログ記事では、私は組み合わせて自律的に駆動するための最初のアプローチである、コンピュータビジョンとPIDコントローラについて説明しました。このアイデアはシンプルで多くの設定に適用できますが、それは(トラックの中心がどこにあるかを車に伝えるために)データの手動ラベリングを必要とします(手間のかかるラベリングは楽しいことではありません)。

他のアプローチとして、競合他社の多くは人間の運転手の行動を再現するために教師つき学習を利用しています。そのためには、人間は数周ほど車を手動で運転し、カメラ画像とそれに関連するジョイスティックからの制御入力を記録する必要があります。それから、モデルは人間の運転を再現するためにトレーニングされます。しかし、このテクニックは一般的に極めて悪いものであるため、実際には堅牢ではなく、均一な運転とトラックごとに再学習を要求されます。


強化学習(RL)とは?なぜ使用すべきなのか?


上記の問題を考慮すると、強化学習(RL:Reinforcement Learning)は興味深い代替方法のです。

強化学習の設定では、エージェント(またはロボット)はその環境に基づいて行動し、フィードバックとして報酬を受け取ります。それは肯定的な報酬(ロボットが何か良いことをした)または否定的な報酬(ロボットがペナルティを科されるべきである)であるかもしれません。

ロボットの目標は累積報酬を最大化することです。そうするために、それは世界との相互作用を通して、感覚による入力を行動にマッピングするいわゆるポリシー(あるいは振る舞い/コントローラ)を学びます。

私たちの場合、入力はカメラ画像で、アクションはスロットルとステアリングアングルです。そのため、車が軌道に乗ってその速度を最大にするように報酬をモデル化すれば、完了です。



stable-baselines:便利な強化学習ライブラリ

これが強化学習の美しさです、あなたはほんの少しの仮定(ここでは報酬関数を設計するだけ)を必要とします、そしてそれはあなたが望むものを直接最適化します(レースに勝つために軌道に早く行きます!)


注意 :これは、小さな自動運転車に強化学習についての最初のブログ記事はありません。しかし既存のアプローチと比較して、現在のテクニックは良質でなめらかなコントロールポリシを数分(数時間ではない)で(なめらかなコントローラのために5~10分、20分以内にとてもなめらかなコントローラを)学習します。

次に、私たちの方法の基礎である Wayve.ai アプローチを詳細に検討することから始めましょう。


1日で運転を学ぶーWayve.ai アプローチの重要な要素


Wayve.ai は、物理世界で自動運転車を単純な道路でトレーニングする方法を説明しています。このメソッドはいくつかの重要な要素で構成されています。



Wayve.ai アプローチ:1日で運転を学習する

最初に、彼らは画像をより低い次元の空間に圧縮するために特徴抽出器(ここではVariational Auto-EncoderまたはVAE)をトレーニングします。モデルは入力画像を再構築するようにトレーニングされていますが、情報を圧縮することを強制するボトルネックを含んでいます。

生データから関連情報を抽出するこのステップは、状態表現学習(SRL)と呼ばれ、私の主な研究テーマでした。それは特に検索スペースを減らすことを可能にし、それ故にトレーニングを加速させます。以下は、SRLとエンドツーエンドの強化学習、つまりピクセルから直接制御ポリシーを学習する方法の関係を示す図です。


注意:Auto Encoder をトレーニングすることは、有用な特徴を抽出するための唯一の解決策ではありません。例えば、インバースダイナミクスモデルをトレーニングすることもできます。



ポリシ学習からの特徴抽出の分離

2つ目の重要な要素は、入力としてVAE機能を使用してコントロールポリシを学習する、ディープ決定論的ポリシ勾配(DDPG)という名前のRLアルゴリズムの使用です。このポリシは各エピソードの後に更新されます。アルゴリズムの重要な側面のひとつとして、再生バッファと呼ばれるメモリを持つことです。記録され後で"再生"可能な環境で相互に再生バッファでやりとりを行います。そのため、車が世界とやり取りしない場合でも、このバッファから経験をサンプリングしてポリシを更新できます。


車は人間の介入前に走行したメータの数を最大にするようにトレーニングされています。そしてそれが最後の重要な要素です。自動車が道路から外れ始めるとすぐに、オペレータはエピソードを終了します。この早期終了は(Deep Mimicによって示されているように)本当に重要であり、車がタスクを解決するのに面白くない領域を探索するのを防ぎます。




ここまで、何も新しいものは提示していません。Wayve.ai アプローチを要約しただけです。以下は、基本テクニックに対して行った変更のすべてです。


数分で運転を学習ー最新のアプローチ


Wayve.ai のテクニックは原理的にはうまくいくかもしれませんが、それを自動運転RCカーに適用するために取り組む場合にはいくつかの問題があります。

まず、特徴抽出器(VAE)は各エピソードの後にトレーニングされるので、特徴の分布は定常的ではないことです。つまり、特徴量は時間の経過とともに変化し、ポリシトレーニングが不安定になる可能性があります。また、ラップトップで(GPUなしで)VAEをトレーニングするのは非常に遅いので、各エピソードの後にVAEを再トレーニングすることは避けたいと思います。

これら2つの問題に対処するために、私は事前にVAEをトレーニングし、私のコンピュータを保護するためにGoogle Colabノートブックを使用しました。このようにして、ポリシは固定機能抽出プログラムでトレーニングされます。

下の画像では、VAEが学んだことを探索します。私たちはその潜在空間を(スライダーを使って)ナビゲートし、再構成された画像を観察します。





VAEが学習した潜在空間を探る

その場合、DDPGは不安定であることが知られており(トレーニング中にそのパフォーマンスが壊滅的に低下する可能性があるという意味で)、調整するのは非常に困難です。幸いなことに、最近の Soft Actor-Critic(SAC)というアルゴリズムは同等の性能を持ち、調整がはるかに簡単です。


実験中に、PPO 、SAC、DDPGを試しました。DDPGとSACはいくつかのエピソードで最高の結果を出していましたが、SACは調整が簡単でした。

私がstable-baselinesのために記述し、stable-baselines内で最後に実装した、Soft Actor-Critic(SAC)実装を使用しました。(RLを使っている方は、ちょっと覗いてみることをおすすめします😋 )


[GitHub] hill-a/stable-baselines
https://github.com/hill-a/stable-baselines
Open AI baselines をフォークした、強化学習アルゴリズム群の実装

最後に、コントロールを滑らかにしてスピードを最大にするために、報酬機能とアクションスペースを更新しました。


報酬関数:早く走行しなさい、ただしトラック内にとどまりなさい!


ロボットカーには走行距離も(速度センサも)含まれていないため、走行したメータ数(速度も)を報酬として使用することはできません。

したがって、私は各タイムステップで「ライフボーナス」(すなわち、トラックにとどまることに対して+1の報酬)を与え、トラックを離れた場合「クラッシュペナルティ」(-10の報酬)を使ってロボットにペナルティを科すことにしました。さらに、あまりにも速く道路を外れることを罰することも有益であると思いました:スロットルに比例して追加の負の報酬がクラッシュペナルティに追加されます。

最後に、レーシングカーとしてできるだけ速く走りたいので、現在のスロットルに比例した「スロットルボーナス」を追加しました。 そのようにして、ロボットは軌道上にとどまり、同時にその速度を最大化しようとします。

まとめると、

ここで、w1 と w2 は目的のバランスをとることを可能にする単なる定数( w1 << 10 と w2 << 1 は2次目的であるため)。


不安定な制御を回避:なめらかに運転するための学習


世界は実際には確率的ではありません。
お気づきのとおり、ロボットが自発的に揺れ始めるのではありません。
RLアルゴリズムを接続しない限り。
- エモトドロフ



左:振動コントロール、右:提案手法によるなめらかなコントロール

あなたがこれまでに提示されたアプローチを適用するならば、それはうまくいくでしょう:車は軌道上にとどまり、速く走ろうとします。しかし、あなたはおそらく不安定なコントロールになってしまうでしょう。車は上の画像に示すように振動します。そうしないのはインセンティブがないからです。報酬を最大化しようとするだけです。

コントロールを円滑にするための解決策は、 *前のコマンド(ステアリングとスロットル)の履歴で入力を増やしながら、ステアリング角度の変化を制限する* ことです。そのように、あなたはステアリングに連続性を課します。

例として、現在の自動車の操舵角が0°で、突然90°に操縦しようとすると、連続性制約では、たとえば40°に操縦できるようになります。従って、2つの連続する操舵コマンド間の差は所与の範囲内に留まることになります。この追加の制約には、もう少しトレーニングが必要です。

私は満足のいく解決策を見つける前に、その問題を解決しようと数日を過ごしました。ここで私は試してみましたがうまくいきませんでした


  • 絶対ステアリングではなく出力相対ステアリング:低周波数の振動を生成
  • 連続性のペナルティを追加(ステアリングの大きな変更に対してロボットにペナルティを課す):ロボットは正しいことを最適化しません。ときどき動作しますが、軌道に乗らないようにします。そのペナルティのコストが低すぎる場合は、無視します。
  • 最大ステアリングを制限:最も急な方向転換では、車はこれ以上とどまることができなくなります。
  • いくつかの速度情報を与えるために複数のフレームを積み重ねる:より低い周波数の振動を生み出しました。


注意 :最近、ETHチューリッヒの研究者は、継続的でエネルギー効率の高い管理をするためにカリキュラム学習を使用することを提案しました。これは2番目の解決策になる可能性があります(ただし調整が少し困難です)。



アプローチのまとめ


私たちのアプローチでは、ポリシ学習を特徴抽出から切り離し、制御を円滑にするために制約を追加します。

まず、人間は車を手動で運転してデータを収集します(手動運転で約5分で10k枚の画像)。これらの画像はVAEをトレーニングするために使用されます。

それから、私達は探索エピソード(確率論的ポリシが使用される)とポリシトレーニング(費やされた時間を最適化するために、人間が車を軌道に戻す際に行われる)の間で交替します。

ポリシをトレーニングするために、画像はまずVAE(ここでは64次元の潜在空間)を使用して符号化され、行われた最後の10の動作(スロットルおよびステアリング)の履歴と連結され84次元の特徴ベクトルを生成する。

コントロールポリシは、ニューラルネットワーク(ReLUまたはELU活性化機能を有する32および16ユニットの2つの完全に接続された層)によって表されます。

このコントローラはステアリングアングルとスロットルを出力します。スロットルを一定の範囲内に収めるように制限し、現在と前のステアリング角の差も制限します。



結論


この記事では、カメラだけを使用して、数分でDonkeycarのためのなめらかなコントロールポリシを学習するためのアプローチを紹介しました。

この方法は現実の世界に適用されるように設計されおり、このプロジェクトにおける私の次のステップでもあります。実際のRCカーでアプローチをテストしました(下記参照)。これは Raspberry Pi で実行するためにVAEモデルを縮小することを必要とします(ポリシーネットワークは既にかなり小さい)。


wayve.ai アプローチは本物のRCカーでRoma Sokolov によって再現されました。しかしこの再現には、なめらかなコントロールのための最新の改良を含んでいませんでした。

これですべてです。コードをテストしたり、コメントしたり、質問したりすることを躊躇しないでください。共有はとても気にしています。


------

Donkey Carのデフォルトモデルは、教師あり学習ベースなのだけど、すでに強化学習の既存のアルゴリズムを複数用いて挑戦している人がおり、海外の研究速度の速さにあらためて驚かされた。

実際の自動運転車は、(運転しない)人や荷物を載せないと意味がないんだよなあ..

今まで振動(左右に振りながらの運転)には目をつぶってたけど、実現させるにはそれもクリアし無くてはならない要件の一つであることを思い出させてくれたよ..


ブログ記事「Supervised Racing」を翻訳してみた

以下の文章は ブログ記事 Supervised Racing  を勝手に翻訳したものです。

-----

Supervised Racing (監視されたレース)


前回の記事では、物理世界のマシンの制御からどのようにしてコンピュータに渡ってくるかについて解説しました。今回はさらに知性をあたえようとする話をします。もし人工知能が運転学習をやめるのではなく、継続してパーツをオンラインで組み付け指示することを学び、そして複製を始めるなら..まあそれについては、うん..

それがどれほど素晴らしいことであっても、そのような知性はありません。

Donkeycar AI (DonkeycarのAI)

デフォルトで搭載されている Donkeycar AIは、教師あり学習ベースのもので、CNNを使用しています。教師あり学習は、画像認識のような実用的なアプリケーションで現在使用されているおそらく最も一般的なタイプの深層学習です。

これは、ニューラルネットワークが入力とそれに対応する正しい出力からなるトレーニングデータを使用してトレーニングされることを意味します。Donkeycarのコンテキストでは、単一の入力(与えられた画像)に対して2つの出力(スロットルとアングル)を予測するようにソフトウェアを訓練することを意味します。

実際の実装は、内部でTensorFlowを呼び出す高レベル深層学習ライブラリKerasを使っています。



Recording (記録)

AIをトレーニングするための最初のステップはデータ収集です。Donkeycarソフトウェアには、カメラ画像とコントローラデータの両方を記録する機能が組み込まれています。渡しの場合は Bluetooth コントローラですべて設定しており、トレーニングは単一のボタンの背後にあります。記録モードが有効になっていると、カースピーカーからナイトライダーのテーマが再生されるようになっています。このようにしておけば、運転手は車の準備が整って録音中であることを確認できます。

記録モードがオンになっているとき、人間が手動運転します。通常では、手動運転の走行記録は速くてきれいな周回となっているでしょう。しかし私はは他のスタイルでも実験しました。通常は、最大スロットルを50%くらいにするために自動車側の設定でスロットル制限を使っているとおもいます。これは、想定外の急速な走行を防止したいという理由だけではなく、AIの運転方法が人間とまったく同じではないためです。トレーニングデータの低いながらも安定したスロットルは、より速い加速とコーナーへの惰行でトレーニングされた場合よりも速くAIを運転することにつながります。

トレーニングの結果、1分あたり約1200レコードを記録しました。1つの記録データは、車載カメラからの1フレームと、正確な瞬間から保存された値を含む1つのJSONファイルで構成されます。デフォルトでは、これらの値はステアリングアングルとスロットルですが、IMUからの加速度測定のような他のデータも含むように拡張することができます。


Training (トレーニング)

 十分なトレーニングデータが収集できたら、次は物理世界から離れてコンピューティングを行う時間です。デフォルト Donkeycar 環境では、データはニューラルネットワークをトレーニングするために直接使用されます。モデルのトレーニングと検証のためにデータが Keras に渡されます。トレーニングが開始されたら、私達はただ待つだけです。

このトレーニングステップは非常に不思議ですが、あなたが本当に理解しなければならないものではありません。そうだとしても、良いモデルを生み出すことができます。最新のGPUを使用している場合は、適切量のデータでモデルをトレーニングするのにそれほど長い時間はかかりません。また、CPUだけを使用していても、数時間でモデルのトレーニングを受けることができます。

トレーニング監視でも面白いこともあります。Kerasの出力内容を監視し、何が起こっているのかを把握することもできます。コマンドラインからの出力を見ることができますし、Tensorflow付属のTensorboardというグラフィカルツールもあります。Tensorboardの場合は、Webサーバが起動されるので、ブラウザでUIを開いて、何が起きているのかを確認できます。

主な出力は損失(loss)値です。それはモデルがどれほど正確な予測をするかを示しています。理論的にはゼロになればあなたのモデルは完璧となるはずですが、実際には損失値が小さすぎると、モデルは過剰に適合状態になります。Donkeycarコンテキストにおける過剰適合は、単に「その靴が画像上隅にあるときには、スロットル0.5とアングル0.8を使用する」ような適切でない学習をしてしまいます。もしあなたが靴を動かしたり、何かがトラックの上に影を落としたり、あるいは他のほんの少し細部が変わったりすると、モデルは混乱します。そのため、損失値をゼロにするのではなく、ネットワークの一般化(generalization)に取り掛かりたいと思います。

一般化(generalization)を評価するために、もう1つの損失値 (val_loss) があります。検証の喪失には至りません。検証データは、トレーニングが始まる前にデータセット全体から自動的に取り出されるデータセットの一部です。これまでモデルが見たことがないデータセットを使用してモデルを検証するためのものです。それはモデルのトレーニングには決して使われないので、実際に運転方法を知っており、単に関係のない外観を暗記していないならば、 Keras がテストのために「テストトラック」でモデルを適用すると考えることができます。悪い例えでいうと、評価セットは車が運転方法を知っているならテストするための異なるトラックであるといえます。val_loss 値が下がるにつれて、あなたのモデルは実世界に適応するために良くなっていきます。


Driving (運転)


学校が夏休みになったら、モデルファイルを自動車のコンピュータに移して、運転ソフトウェアを起動しましょう。このステップに必要なのは、ほぼそれだけです。AIにミニチュアシートベルトを締めさせ、私達は邪魔にならないようにする時間がきましたよ。

ソフトウェアの内部で起こることは前の記事で解説しましたが、要約するとカメラから画像フレームを取得してAIに入力しステアリングアングルとスロットル値を出力する高速ループとして構成しています。これらの値はステアリングサーボとモータの制御に使用されます。

この時点で、トレーニング済みAIモデルがどれほどうまく機能しているかは、普通に驚きではありませんか?このプロジェクト全体がブラックボックスであるニューラルネットワークに制御を与えることなので、あなたは一般的にAIが動作する理由を推測することしかできません。もちろん、時間が経てば何かが起こるのではないかと推論することを学びますが、実際に確認できる場合は稀です。

この単純なアーキテクチャの優れた点の1つは、RCカーに縛られないということです。プロジェクトの初期段階で、コントローラの入力や画面イメージを記録するユーティリティをいくつか作成し、エミュレートされたコントローラを使ってPCでドライビングゲームをプレイするようにAIをトレーニングしました。私はこの段階では助手席に着かないでしょうが、AIの自動運転は想像以上にうまくいきました。



Next steps (次のステップ)


人を模倣するこの最も単純な形のAIは、かなりうまく機能するかもしれませんが、それでもやはりほんの始まりにすぎません。私たちは十分に長い改善のアイデアのリストを持っています。私たちがすでに試したことのあるものもあります。

データ増強は、あなたが少しの変化でそれをコピーすることによってデータ量を増やすことができることを意味します。それは過剰適合を減らし、AIをより動的な環境で動作させます。我々はそれを試みました、そして結果と実行の両方を後で共有します。それは本当に違いを生むものです。

記録データを再生して手動で分析するためのテストベンチも構築しました。これは、レコーディングで問題を発見するためにも、モデルを車内にうつす前にAIによる推論を確認するためにも使用できます。

そして最後に、現在のニューラルネットワークアーキテクチャは、1つの画像のみを使用し、トレーニングデータの背後にある人間とまったく同じ運転スタイルを最適化しようと試みることを考えると、かなり制限されています。RCカーの運転経験が限られている私たちのチームは、速くてきれいなラップを走ることが実際にどれだけ難しいかに少し驚いています。その一方で、私たちは訓練されたAIがどれほどうまく機能しているかに非常に驚いています。同時に、誰もが強化学習について話しているように見えます。つまり、AIは自分自身を訓練し、最終的にはスキルで人間を打ち負かすでしょう。


-----

DonkeycarのAI部分をどうやって数式や難しいAI用語を使わないで説明するか頑張っているのがうかがえますが..

..やっぱりmanage.pyからソースを読むのが一番手っ取り早いでしょうね..

ブログ記事「Inside a Donkeycar」を翻訳してみた

以下の文章は Inside a Donkeycar を勝手に翻訳したものです。

----

Inside a Donkeycar (Donkeycarの内部)



そして、私はラジコンカーを買い、手動運転をAIに置き換えました。それほど難しいことではありませんでした。ですが、これが誰かが以前にそのようなことをした成果の一部であることを、私は信じられませんでした。少なくとも「PIDコントローラの後にいくつかの回線を設けて実現しているんだろうなあ」ということと「衝突検出をともなう何らかのランダム化された動作を使って実現してるのかな」といったことを疑っていました。そして実際のニューラルネットワークをスピードコントローラとステアリングサーボに直接接続し、カメラだけでトラックを周回できることを夢見たことは一度もありませんでした。
では、今すぐにみなさんと共有しましょう。
 

Physical world (物理の世界)


初めにAnttiがいました、そして、さりげなく「物理世界が私を病気にする」と言いました。 当時私たちが笑っていたことと同様に、ソフトウェアを作ることはハードウェアと比べてかなり簡単で速いことを私たちに理解させました。 しかしそれは、物事を動かすための最低限のレベルではなく、私たちの志望に関するものでした。 車を走らせるためだけに、ハードウェアはまったく複雑ではありません。
 

Radio controlled car (ラジコンカー)


標準のラジコンカーには、車輪を駆動するための1つのモータ(Brushed DC motor)と、前輪を回転させるための1つのサーボモータ(Steering servo)があります。さらに、電子スピードコントローラ(ESC:Electronic Speed Controller)、バッテリ(Battery)、ラジオ受信機(Radio receiver)があります。 ラジオ受信機は車内部の「運転手」なので、取り除きます。

 

Inside a computer (コンピュータの内部)


これはすべてdonkeycarというオープンソースプロジェクトから始まっており、ここではプロジェクトが推奨するハードウェアを使用しています。 推奨ハードウェアは、小さなコンピュータ、バッテリーバンク、広角カメラとサーボドライバボードで構成されています。

バッテリーバンクはコンピュータ用です。車輪を駆動するための他のバッテリを調整する(DC-DCコンバータによる電圧電流調整が必要)よりも、別のバッテリを使用する方が簡単だからです。

サーボドライバボードはおそらくこれらの中で最も目につく電子部品です。サーボドライバボードの目的はESCとサーボモータにラジオ受信機と同じ言語で話すことです。 具体的には、安価な専用ハードウェアを使用して正確なPWM信号を生成することです。

上記のように、私たちの志望レベルはかなり高く、私たちはすべてのために3Dプリントマウントを設計しました。 ダクトテープとジップタイすべて使用することができます。 サポートされている車を見つけることができれば、当然のことながら公式 Donkeycar をマウントできます。

 



Software (ソフトウェア)


Donkeycarは車を走らせるのに必要なすべてのソフトウェアを含む高レベルライブラリです。 これはPythonで書かれており、デスクトップ上でニューラルネットワークをトレーニングするための自動車用ソフトウェアとユーティリティの両方を含んでいます。 私たちはすぐにそれをあちこちで修正することになりましたが、コア部分がかなり有用であることがわかりました。

Parts (パーツ)



駆動ソフトウェアは、パーツという名前のモジュールから構築されています。 各パーツは、呼び出されるたびに入力を受け取り、出力を返します。 たとえば、PiCameraパーツはカメラからフレームを返し、PWMThrottleパーツはスロットルを入力として使用し、それを使用してモータを制御します。

Sonarのようなカスタムパーツはすでにいくつかあります。Sonarは、車の前の物体までの距離を測定し、「衝撃までの時間」も秒単位で返します。 それは別のカスタムパーツEBrakeで使用され、スロットルとインパクトに時間がかかるため、調整されたスロットル値が返されます。 衝突が避けられない場合は、衝突を避けるために速度を落とす必要があります。 それはまた私達のサブウーファの部分に接続されているので、車はクラッシュに近づくと叫びます。

 

Core loop (コアとなるループ)


パーツは運転ループで互いに接続されています。運転ループは、設定されたパーツを指定された順序で永久にループする組み込み関数です。 それは新しいアクションのために新しいパーツを実験することを容易にします。 次の図は、現在の運転ループを視覚化したものです。

Artificial Intelligence (人工知能)


人工知能とは一体何ですか? 私は個人的に、よくある命令型条件付きコードから魔法のような深層学習ソリューションまで使用されている用語定義を見たことがあるので、自動的には意味がないと言うことができます。 デフォルトのDonkeycarコンテキストでは、人工知能は入力として単一の画像を取り、出力として2つの数(スロットルとステアリング)を予測するようにトレーニングされたニューラルネットワークを意味します。 だからそれは魔法の対局にあります。 ある状況では、PIDに続くラインがニューラルネットワークを打ち負かす可能性がありますが、それを本当に素晴らしいものにしているのは、トレーニングデータから学習する能力です。 しかし、それとは対照的に、デバッグとそれを使った推論は本当に困難です。今後の投稿では人工知能のトレーニングについて紹介します。


--------

ようは、Donkeycarの内部の概説です。

Donkeycarは、
  • RCカーの受信機から先を切り取っている
  • 受信機から先を搭載コンピュータで代用
  • コンピュータ内は予め定義されたパーツ郡を順番に運転ループで実行している
  • 自動運転はAIを使っている
というものである、と紹介しています。

個人的には、こんなブログ記事を読んでもたもたしてるより、まず作って動かしてみたほうが手っ取り早く理解できるのに..と思ってますが..

2019年1月21日月曜日

Microsoft製のドローン・自動車シミュレータ AirSim を試す

Donkey CarにはDonkeyシミュレータというシミュレータソフトが付いているが、
Donkey Car以外では使用できない。
またDonkeyシミュレータは、コースが制限されており、ここで学習したモデルを実際の道路で走らせることはほぼできない。

最近すべてのメーカが自動運転車の実現を目指している
(もしくはそれに類する機能(自動ブレーキなど)の実現を目指している)
のは、素人でも推測可能だけど、
それならシミュレータソフトもいくつか出てきてもいいはずなんじゃないか
と思っていた。

だって、自動運転を認可するには
複数メーカの車が開発したモデルの性能評価を国はしなきゃいけないわけで
そうなると国ごとに標準シミュレータは開発しておかないとだめなんじゃないか、
と簡単に想像できるし...


で、どこかにはあるんじゃないかとおもいながらSlackを眺めていたら

でてきたよ

[GitHub] Microsoft/AirSim
https://github.com/Microsoft/AirSim



どうも自動車だけでなくドローンにも対応しているらしい..

バイナリのダウンロードはここからできるのだけど、
Windows版のバイナリは以下のシーンごとにダウンロードできるようになっている。

  • 市街地(動く車や歩行者がいる広い環境)
  • 住宅近隣(小都市近所ブロック)
  • 山の風景
  • アフリカ(起伏のある地形やアニメーションの動物)
  • 張家界(中国の張家界山)
  • 倉庫
  • 単純な迷路
  • 海岸線(マウイのハナ道路に似た短い区間)

ためしに住宅近隣シーンである AirSimNH.zip を落とす。
それぞれギガ単位(以上)のサイズがあるので、全部落とそうとすると相当時間がかかる。

unzipすると、AirSimNH\run.batが登場するのでこれを実行すると、ダイアログ画面が出てきて、はいを選択すると自動車、いいえを選択するとドローンのシミュレータ画面がたちあがる。
ドローンの方は、運転の仕方がいまいちよくわからないので自動車だけを試してみることにした。

自動車は上下左右のボタンで手動運転可能だ。



表示の変更は(Fn+)F1を押すとヘルプが出てくるので、こちらを読めばわかるとおもう。

とりあえず変なことになったらBackspaceを押せば最初の状態に戻るので、上下左右とBSだけ覚えておけばいい。

"シミュレータ"なので、キーボードからの手動運転だけでなくAPI経由でも可能だ。
上記GitHubにあるサンプルを動かしてみた。

自動車を選択してシミュレータの画面が出たら、以下のサンプルコードをpython3で実行する。

なお実行するには以下のパッケージを予めインストールする必要がある。


pip install msgpack-rpc-python
pip install airsim



import airsim
import time

client = airsim.CarClient()
client.confirmConnection()
client.enableApiControl(True)

car_controls = airsim.CarControls()

while True:
    car_state = client.getCarState()
    print("Speed %d, Gear %d" % (car_state.speed, car_state.gear))

    car_controls.throttle = 1
    car_controls.steering = 1
    client.setCarControls(car_controls)

    time.sleep(1)

    responses = client.simGetImages([
        airsim.ImageRequest(0, airsim.ImageType.DepthVis),
        airsim.ImageRequest(1, airsim.ImageType.DepthPlanner, True)
    ])
    print('Retrieved images: %d', len(responses))

    for response in responses:
        if response.pixels_as_float:
            print("Type %d, size %d" % (response.image_type, len(response.image_data_float)))
            airsim.write_pfm('py1.pfm', airsim.get_pfm_array(response))
        else:
            print("Type %d, size %d" % (response.image_type, len(response.image_data_uint8)))
            airsim.write_file('py1.png', response.image_data_uint8)

airsimのAPIを知らなくても、
眺めるだけで
1秒毎にスロットル、ステアリングに1を与え、
レスポンスをPNGファイル(白黒カメラ画像)とPFMファイル(同配列のシリアライズデータ)をカレントに出力するというサンプルだということがわかるとおもう。
#シミュレータ画面ではくるくる回って作にあたってしまう

複数の車を登場させることも可能だ。
Windowsの場合は一度シミュレータを動かすと、
C:\Users\<ユーザ名>\Document\AirSim フォルダ直下にsettings.jsonファイルができているので、これを以下のように変更して、サンプルコードを動かせばいい。
(こちらのコードはC:\tempを先に作っておかないと動作しない)


{
 "SettingsVersion": 1.2,
 "SimMode": "Car",
 
 "Vehicles": {
  "Car1": {
    "VehicleType": "PhysXCar",
    "X": 4, "Y": 0, "Z": -2
  },
  "Car2": {
    "VehicleType": "PhysXCar",
    "X": -4, "Y": 0, "Z": -2
  }
    }
}

# -*- coding: utf-8 -*-
import airsim

import time
import os
import numpy as np


# connect to the AirSim simulator 
client = airsim.CarClient()
client.confirmConnection()
client.enableApiControl(True, "Car1")
client.enableApiControl(True, "Car2")

car_controls1 = airsim.CarControls()
car_controls2 = airsim.CarControls()


for idx in range(3):
    # get state of the car
    car_state1 = client.getCarState("Car1")
    print("Car1: Speed %d, Gear %d" % (car_state1.speed, car_state1.gear))
    car_state2 = client.getCarState("Car2")
    print("Car1: Speed %d, Gear %d" % (car_state2.speed, car_state2.gear))

    # go forward
    car_controls1.throttle = 0.5
    car_controls1.steering = 0.5
    client.setCarControls(car_controls1, "Car1")
    print("Car1: Go Forward")

    car_controls2.throttle = 0.5
    car_controls2.steering = -0.5
    client.setCarControls(car_controls2, "Car2")
    print("Car2: Go Forward")
    time.sleep(3)   # let car drive a bit


    # go reverse
    car_controls1.throttle = -0.5
    car_controls1.is_manual_gear = True
    car_controls1.manual_gear = -1
    car_controls1.steering = -0.5
    client.setCarControls(car_controls1, "Car1")
    print("Car1: Go reverse, steer right")
    car_controls1.is_manual_gear = False; # change back gear to auto
    car_controls1.manual_gear = 0  

    car_controls2.throttle = -0.5
    car_controls2.is_manual_gear = True
    car_controls2.manual_gear = -1
    car_controls2.steering = 0.5
    client.setCarControls(car_controls2, "Car2")
    print("Car2: Go reverse, steer right")
    car_controls2.is_manual_gear = False; # change back gear to auto
    car_controls2.manual_gear = 0  
    time.sleep(3)   # let car drive a bit


    # apply breaks
    car_controls1.brake = 1
    client.setCarControls(car_controls1, "Car1")
    print("Car1: Apply break")
    car_controls1.brake = 0 #remove break

    car_controls2.brake = 1
    client.setCarControls(car_controls2, "Car2")
    print("Car2: Apply break")
    car_controls2.brake = 0 #remove break
    time.sleep(3)   # let car drive a bit
    
    # get camera images from the car
    responses1 = client.simGetImages([
        airsim.ImageRequest("0", airsim.ImageType.DepthVis),  #depth visualization image
        airsim.ImageRequest("1", airsim.ImageType.Scene, False, False)], "Car1")  #scene vision image in uncompressed RGBA array
    print('Car1: Retrieved images: %d' % (len(responses1)))
    responses2 = client.simGetImages([
        airsim.ImageRequest("0", airsim.ImageType.Segmentation),  #depth visualization image
        airsim.ImageRequest("1", airsim.ImageType.Scene, False, False)], "Car2")  #scene vision image in uncompressed RGBA array
    print('Car2: Retrieved images: %d' % (len(responses2)))

    for response in responses1 + responses2:
        filename = 'c:/temp/car_multi_py' + str(idx)

        if response.pixels_as_float:
            print("Type %d, size %d" % (response.image_type, len(response.image_data_float)))
            airsim.write_pfm(os.path.normpath(filename + '.pfm'), airsim.get_pfm_array(response))
        elif response.compress: #png format
            print("Type %d, size %d" % (response.image_type, len(response.image_data_uint8)))
            airsim.write_file(os.path.normpath(filename + '.png'), response.image_data_uint8)
        else: #uncompressed array
            print("Type %d, size %d" % (response.image_type, len(response.image_data_uint8)))
            img1d = np.fromstring(response.image_data_uint8, dtype=np.uint8) #get numpy array
            img_rgba = img1d.reshape(response.height, response.width, 4) #reshape array to 4 channel image array H X W X 4
            img_rgba = np.flipud(img_rgba) #original image is flipped vertically
            img_rgba[:,:,1:2] = 100 #just for fun add little bit of green in all pixels
            airsim.write_png(os.path.normpath(filename + '.greener.png'), img_rgba) #write to png 


#restore to original state
client.reset()

client.enableApiControl(False)

こっちはすぐにブレーキを掛けているものだから、シミュレータ画面上ではピクリとも動かないのでとてもつまらないが..



あとはAPIをVehicleフレームワーク上で動作するようにPartクラスをつくるだけで、Donkey Carの学習モデルをこのシミュレータで試すこともできるようになる。


なお、気象APIで雨を降らせることのできる機能はpypi上のパッケージバージョンでは未対応なので、リポジトリ最新をダウンロードして手動インストール(pip install -e .)を実行しないとだめらしい(執筆時点:2019年1月21日)。

既存アプリケーションをK8s上でコンテナ化して動かす場合の設計注意事項メモ

既存アプリをK8sなどのコンテナにして動かすには、どこを注意すればいいか..ちょっと調べたときの注意事項をメモにした。   1. The Twelve Factors (日本語訳からの転記) コードベース   バージョン管理されている1つのコードベースと複数のデプロイ 依存関係 ...