Aidemy Blog

株式会社アイデミーのブログです。機械学習・ディープラーニング関連技術の活用事例や実装方法をまとめる技術記事や、キャリア記事等を発信しています

Udacityのデータセットを深層学習させて、自動運転をしてみた

f:id:ryoryo4138:20180611185223j:plain

Aidemy研修生 岡前です。

Using Deep Learning to Predict Steering Angles

なんか英語の方が響きがいい気がする。

やはり、"かっこいい"こと、"ワクワク"する事(大抵、激しく難しい)をやって、基礎のお勉強がやりたくてしょうがなくなりますよね。という事で、"自動運転"というビックワードに背伸びしてみました。 

対象者:

深層学習(CNN)で何ができるか知りたい人(とか)

記事を読了することで期待される成果:

なんか深層学習すごくね?って思える。(pythonとUnityも)

深層学習の具体的な使い方の一例を知ることができる。

概要:

UdacityのデータセットのPhase 2 dataCh2_002を使って、

画像とハンドルの正解データからハンドルの角度を回帰で求める。

次に、Unityでシュミレーションを作り、自動車を自動運転してみる。

github.com

目次:

  1. Modelを理解する
  2. データの前処理
  3. 深層学習(python)
  4. シュミレーション(Unity)
  5. 結果
  6. 発展
  7. 感想
  8. 環境

サクッと見たい方は4.深層学習から見てください。その後戻って1.2.3を見る形で大丈夫です。

1. Modelを理解する

まずはどのように機械学習をするモデルなのかを見てみましょう。

f:id:ryoryo4138:20180611183446p:plainf:id:ryoryo4138:20180611183454p:plain

2700万個ノードが繋がっていて、25万パラメータあるそうです。

これがEnd to End Learningの論文です。

https://arxiv.org/pdf/1604.07316.pdf

以下に、論文の内容をまとめたので軽く目を通すと、

4.以降のコードがわかりやすくなると思います。

1.論文名,著者,会社,出版年

End to End Learning for Self-Driving Cars,Mariusz Bojarski,NVIDIA,2016

2.論文の内容

自動車の走行時の正面の写真とハンドルの角度のみの正解データを使って、道路の特徴を学習して、舗装されていない道を含めた全ての道のハンドルの角度を回帰するモデルを提案している

3.研究背景

Computer Vision and Pattern Recognition(パターン認識)の自立走行の分野

4.研究目的

より少ないトレーニングデータと小さなシステムで、より精度の高いハンドルの角度を算出すること。

5.新規性

車線認識や、径路計画(自立移動技術)などは道の環境を場合分けして学習する必要があるが、end-to-end systemでは、同時に舗装されていない道や駐車場などのこれまで学習が難しかった全ての道をまとめて学習できる点。

6.結果

自動運転を実験した結果、高速道路や住宅街などの違いだけでなく、天気などの様々な条件で運転するのに、end-to-end systemは100時間未満のデータで十分であった。

 

つまり、このモデルを使うと、限られたデータしかなくても運転できるって事です!

なので、今回はハンドルのデータのみを使います。

 

3. データの前処理

2.1 インストール

先ほどのUdacityのURLの中の、

Phase 2 dataCh2_002をインストールします。

2.2 RAG BAGファイルをpngに変換する

rag bagファイルをpngに変換します。参考文献を載せておきます。

ja/rosbag/Tutorials/Exporting image and video data - ROS Wiki

2.3 画像を深層学習のモデルに合うように加工
# 画像の加工
def roi(img):
    #img =img[55:140,30:290]
    # img =img[40:img.shape[0]-25
    #img = img[60:140,40:280]
    return cv2.resize(img,(200,66), interpolation=cv2.INTER_AREA)

#画像を読み込む
def image_generator(path):
    fname = os.path.basename(path)
    img = plt.imread("center/"+fname)

    #Crop and Resize the image
    img = roi(img)
    #Reshape the image
    img = np.reshape(img,(3,66,200))
    return img

#画像を逐次処理
def batch_generator(file, batch_size=32, *args, **kwargs):
    images = []
    steering = []
    df = pd.read_csv(file)
    while True:
        for key, row in df.iterrows():
            try:
                # Reset generator if over bounds
                img = image_generator(row.fullpath.replace('jpg', 'png'))
            except Exception as e:
                # print(e)
                continue
            ster = row.angle
            images += [img.tolist()]
            steering += [ster]
            if len(images) == batch_size:
                yield np.array(images), np.array(steering)
                images = []
                steering = []

4. 深層学習

私は、3.に多くの時間を費やしました。初めてデータを扱う人は、多くの人が3.に時間がかかると思います。理由は、勉強する内容が次から次へと出てくるためです。私は、次回以降も含めた勉強だと思い、何日か頑張りました。(助けてもらいながらやりました。)

いよいよ、上記の構造を用いて,以下のコードでモデルをトレーニングします。

github https://github.com/RyosukeHonda/Behavioral-Cloning 

model.pyを参考にさせていただきました。

#Make dataset
train_data = batch_generator("train_round1.csv", batch_size=5)
val_data = batch_generator("evaluation.csv", batch_size=5)
#Nvidia Model
model = Sequential()
#model.add(Lambda(lambda x: x/255.0-0.5,input_shape=(3,66,200),name="Normalization"))
model.add(Conv2D(24, (5, 5), strides=(2,2), activation='relu', data_format='channels_first', name='Conv1', input_shape=(3, 66, 200)))
model.add(Conv2D(36, (5, 5), strides=(2,2), activation='relu', data_format='channels_first', name='Conv2'))
model.add(Conv2D(48, (5, 5), strides=(2,2), activation='relu', data_format='channels_first', name='Conv3'))
model.add(Conv2D(64, (3, 3), activation='relu', data_format='channels_first', name='Conv4'))
model.add(Conv2D(64, (3, 3), activation='relu', data_format='channels_first', name='Conv5'))
model.add(Flatten())
model.add(Dropout(0.4))
model.add(Dense(100, activation='relu', name='FC1'))
model.add(Dropout(0.5))
model.add(Dense(50, activation='relu', name='FC2'))
model.add(Dropout(0.5))
model.add(Dense(10, activation='relu', name='FC3'))
model.add(Dropout(0.5))
model.add(Dense(1, name='output'))
model.summary()
opt = Adam(lr=0.0001)

いざ終わって見ると、簡潔なコードですね。

5. シュミレーション(Unity)

ここからは、深層学習ではなく結果を確かめる段階です。これを元にUnityで自分で道を作ります。今回はシュミレーションをUnityで作るのは趣旨と外れてしまうので行わないことにしました。Youtubeに載っていた結果だけ引用します。

 

github.com

 

www.youtube.com

 

6. 結果

ハンドルの角度のみを正解データから、回帰してハンドルの角度を予測できるようになりました。

7. 発展

今回は、ハンドルの角度のみを正解データとしました。自動運転には他に速度やノイズ、自動車の位置などの様々なデータを分析します。そのモデルは、線形非線形の問題で重積分をしなくてはいけないため、理論が難しくなり、今回の趣旨である深層学習を使って"かっこいい"こと、"ワクワク"する事をやりたいというのと外れるため、やりませんでした。という事で発展として、3termで$2400のUdacityのコースをあげておきます。nano degreeが手に入るといえ、日本の学習への常識からすると高価だと思いました。

eu.udacity.com

8. 感想

深層学習はモデルがたくさんGit Hubにあるため、最初は大変ですが、慣れれば多くの面白いことができるのだと夢を膨らせました。一方で、論文を見て、そのモデルが作られた目的や先行研究などを理解していくことは今後に繋がりますし、モデルを理解することも結局エラーがどこにあるのかを発見するのに役立った部分もありました。

また、私自身が初めての深層学習のアウトプットであったことから、勉強時間を「初心者のため前提知識や背景を学ぶために投下している時間」と「自動運転をするために投下している時間」に分ける事で、毎日の勉強を振り返る事ができる、と初心者らしい気づきを書いて締めさせていただきます。

読んでいただきありがとうございました。

 

7. 環境

MacBook Pro (13-inch, 2016, Four Thunderbolt 3 Ports)

何を使えばいいのかを使用したコードを使って示しておきます。

import keras
from keras.layers.normalization import BatchNormalization
from keras.preprocessing.image import ImageDataGenerator
from keras.models import Sequential
from keras.layers import Dense, Dropout, Activation, Flatten,Lambda
from keras.layers.normalization import BatchNormalization
from keras.layers import Conv2D
from keras.layers.pooling import MaxPooling2D
from keras.preprocessing.image import load_img,img_to_array
from keras.optimizers import SGD, Adam, RMSprop
from keras.callbacks import EarlyStopping,History
from keras.preprocessing.image import load_img
from keras.models import load_model
import cv2
import numpy as np
import pandas as pd
import os
from numpy.random import randint
import matplotlib as plt