Amazon Web Services ブログ

自律走行車の構築 パート 4: 自動運転の車で Apache MXNet と行動クローニングを使用

自律走行シリーズ 1 回目のブログでは、Donkey カーの構築と Amazon EC2 インスタンスでパイロットサーバーをデプロイしました。そして、2 回目のブログでは Donkey カーの運転を学び、Donkey カーが自律走行を学びました。3 回目のブログでは AWS IoT を使用して Donkey カーから AWS にテレメトリをストリーミングするプロセスをご紹介しました。

今回のブログでは、カーの運転を有効にするディープラーニングについて詳しく見ることにします。また、畳み込みニューラルネットワーク (CNN) を使用した行動クローニングの概念についても説明します。CNN は「前方には道がありますか、それともトラフィックコーンがありますか?」といったような、カーに対する質問に答えるなど、コンピュータビジョンタスクにおける最先端のモデリング技術として現れたものです。


1) AWS 自律走行車を構築し re:Invent の Robocar Rally でレースに参加
2) 自律走行車の構築 パート 2: 自律走行車の運転
3) 自律走行車の構築 パート 3: 自律走行車の接続
4) 自律走行車の構築 パート 4: 自動運転の車で Apache MXNet と行動クローニングを使用


P2 で Donkey のトレーニングデータをセットアップ

トレーニングの実行方法の詳細については、すでにシリーズ 2 回目のブログで説明しました。主なステップとコマンドを簡単に復習しておきましょう。

  1. Pi からデータを Amazon EC2 インスタンスにコピーするには
    $ rsync -rva --progress -e "ssh -i /path/to/key/DonkeyKP-us-east-1.pem" /home/pi/d2// ec2-user@ec2-your-ip.compute-1.amazonaws.com:~/d2/data/
  2. トレーニングプロセスを開始するには
    $ python ~/d2/manage.py train --model /path/to/myfirstpilot
  3. トレーニング済みのモデルを再び Pi へコピーするには
    $: rsync -rva --progress -e "ssh -i /path/to/key/DonkeyKP-us-east-1.pem" ec2-user@ec2-your-ip.compute-1.amazonaws.com:~/d2/models/ /home/pi/d2/models/

モデルの舞台裏

このセクションでは、モデルが学ぶ内容と独自で運転できる方法について説明します。現在の Donkey の構築には Keras がデフォルトのディープラーニングフレームワークとして使用されています。AWS は Apache MXNet や Gluon、PyTorch など他のフレームワークのサポートを追加する作業に取り組んでいます。このブログでは Apache MXNet を使用して、自動運転を有効にするモデルがどのように動作するのか詳しく見ることにします。以前にも触れましたが、AWS では行動クローニングという技術を使用してカーの自動運転を有効にします。基本的に、このモデルはトラックを運転した時に収集したトレーニングデータをもとに、運転することを学びました。データの大半が「クリーン」であることが大切です。つまり、この目的は意図した道を進むことなので、カーがトラックにいない状態または方向を間違えた場合などのイメージがトレーニングデータに多く含まれていないことが大切です。人がハンドルを握って道からそれないように運転する時と同じで、現状で与えられた状態で方向を定めるモデルを構築します。そうすることで問題を「入力イメージに従って運転するためのステアリング角度は?」といったようにモデリングすることができます。実際の運転状況にはアクセラレーションやトランスミッションギアといったコンポーネントが追加されるので、より複雑になります。まずはシンプルにしておくため、スロットルを一定の割合に設定してカーが運転できるようにすることから始めます。実際にやってみると、トレーニングデータ 25~30% のスロットルが Donkey カーには最適な速度であることが証明されました。

これを行うには畳み込みニューラルネットワーク (CNN) というディープラーニング技術を使用します。CNN はコンピュータビジョン問題において事実上のネットワークとして現れたものです。CNN は各ノードが受容フィールドと呼ばれる小さな枠と関連付けられた畳み込みレイヤーから成り立っています。これによりイメージ内にあるローカルの特徴を抽出することができます。「イメージにあるのは道ですか、それとも人ですか?」といった質問は、先に計算されたこうしたローカルの特徴を使用して、計算することができます。CNN がどのように機能するか説明した詳細情報はこちらをご覧ください。

データセット

このブログでは、トラックを 15 分ほど運転して収集したデータセットを使用します。先に説明したように、カーがトラックにいなかった場合のイメージを破棄してクリーンな状態にしました。Donkey ソフトウェアは「不適切」なイメージを削除するため、ブラウザベースの UI をすでに提供しています。 donkey tubclean <folder containing tubs>) です。これに似たトラックを運転しているカーのイメージのデータセットはこちらで入手できます。

CNN モデルの構築

im2rec.py ツールを使用し、イメージのデータセットをバイナリファイルに変換して処理速度を速くします。Apache MXNet の詳細についてはチュートリアルページをご覧ください。

import mxnet as mx
import numpy as np

data = mx.symbol.Variable(name="data")

body = mx.sym.Convolution(data=data, num_filter=24,  kernel=(5, 5), stride=(2,2)) 
body = mx.sym.Activation(data=body, act_type='relu', name='relu1')
body = mx.symbol.Pooling(data=body, kernel=(2, 2), stride=(2,2), pool_type='max')

body = mx.sym.Convolution(data=body, num_filter=32,  kernel=(5, 5), stride=(2,2))
body = mx.sym.Activation(data=body, act_type='relu')
body = mx.symbol.Pooling(data=body, kernel=(2, 2), stride=(2,2), pool_type='max')

flatten = mx.symbol.Flatten(data=body)

body = mx.symbol.FullyConnected(data=flatten, name='fc0', num_hidden=32)
body = mx.sym.Activation(data=body, act_type='relu', name='relu6')
body = mx.sym.Dropout(data=body, p=0.1)

body = mx.symbol.FullyConnected(data=body, name='fc1', num_hidden=16)
body = mx.sym.Activation(data=body, act_type='relu', name='relu7')

out = mx.symbol.FullyConnected(data=body, name='fc2', num_hidden=1)
out = mx.symbol.LinearRegressionOutput(data=out, name="softmax")

カーのハンドルの角度を決定する必要があるので、1 つの出力で線形回帰の出力レイヤーを使用します。トレーニングプロセスの進行を評価するには、評価メトリクスとして平均絶対誤差 (MAE) を使用することができます。角度間の距離はユークリッドシステムで説明できるので、損失の最適化には MAE が適切なメトリクスです。

モデルのトレーニング

トレーニング用のバイナリファイルは S3 バケットで利用可能です。

# Get Iterators

def get_iterators(batch_size, data_shape=(3, 120, 160)):
    train = mx.io.ImageRecordIter(
        path_imgrec         = 'train.rec', 
        data_name           = 'data',
        label_name          = 'softmax_label',
        batch_size          = batch_size,
        data_shape          = data_shape,
        shuffle             = True,
        rand_crop           = True,
        rand_mirror         = True)
    val = mx.io.ImageRecordIter(
        path_imgrec         = 'valid.rec',
        data_name           = 'data',
        label_name          = 'softmax_label',
        batch_size          = batch_size,
        data_shape          = data_shape,
        rand_crop           = False,
        rand_mirror         = False)
    return (train, val)

batch_size = 16
train_iter, val_iter = get_iterators(batch_size)

#Training

batch_size = 8
num_gpus = 1
num_epoch = 10
mod = mx.mod.Module(out, context=[mx.gpu(i) for i in range(num_gpus)])
mod.fit(train_data=train_iter, 
        eval_data=val_iter, 
        eval_metric='mae', 
        optimizer='adam',
        optimizer_params={'learning_rate': 0.0001},
        num_epoch=num_epoch,
        batch_end_callback = mx.callback.Speedometer(batch_size, 100),        
       )

評価とシミュレーター

モデルのトレーニングが完了したので、これをカーでデプロイし運転してみましょう。検証セットで見られる MAE のエラーが低いということは、このモデルが良くトレーニングされていて一般化されていることを意味しています。けれども、視覚的にデプロイする前にカーがどのように運転するか、より詳しく把握しておきたいところです。そこで、カーがトラックでどのように運転するかを示すシミュレーターをお見せしましょう。

import os	
import time
%matplotlib inline
from IPython import display
import matplotlib.patches as patches

PATH = 'trainingdata/'
all_files = sorted(os.listdir(PATH))
sym, arg_params, aux_params = mx.model.load_checkpoint('my-car', num_epoch)
mod = mx.mod.Module(symbol=sym) 
fig, ax = plt.subplots(1)
for fname in all_files:
    org_img = Image.open(PATH + fname)    
    img = np.array(org_img)
    img = np.swapaxes(img, 0, 2)
    img = np.swapaxes(img, 1, 2) 
    img = img[np.newaxis, :] 
    mod.forward(Batch(data=[mx.nd.array(img)]))
    exp = mod.get_outputs()[0].asnumpy()[0]
    angle = 180*exp
    left = 80 * exp + 80
    rect = patches.Rectangle((left, 85),20,30, angle=angle,
                             linewidth=2,edgecolor='r',facecolor='none')
    patch = ax.add_patch(rect)
    display.clear_output(wait=True)
    display.display(plt.gcf())
    plt.imshow(org_img)
    time.sleep(0.1)
    patch.remove()

まとめ

これで自動運転シリーズは完了です。re:Invent の Robocar Rally 2017 は、コンピュータから離れて実践環境でディープラーニング、自動運転カー、Amazon AI および IoT サービスを体験する 2 日間に渡るハッカソンです。会場でお会いしましょう!引き続き Donkey Car をチェックし、コミュニティにぜひご参加ください。