Behavioral Cloning Project
The goals / steps of this project are the following:
- Use the simulator to collect data of good driving behavior
- Build, a convolution neural network in Keras that predicts steering angles from images
- Train and validate the model with a training and validation set
- Test that the model successfully drives around track one without leaving the road
- Summarize the results with a written report
Here I will consider the rubric points individually and describe how I addressed each point in my implementation.
My project includes the following files:
- model.py containing the script to create and train the model
- drive.py for driving the car in autonomous mode
- model.h5 containing a trained convolution neural network
- Writeup file summarizing the results
Using the Udacity provided simulator and the drive.py file, the car can be driven autonomously around the track by executing
python drive.py model.h5
The model.py
file contains the code for training and saving the convolution neural network. The file shows the pipeline I used for training and validating the model, and it contains comments to explain how the code works. Data preprocessing is written in a seperate file called data_process.py
.
My model consists of a convolution neural network with 5x5 and 3x3 filter sizes and depths between 24 and 64 (model.py lines 12-34)
The model includes RELU layers to introduce nonlinearity between each convolutional layer, and the data is normalized in the model using a Keras lambda layer (code line 17).
The model was trained and validated on different data sets to ensure that the model was not overfitting. The model was tested by running it through the simulator and ensuring that the vehicle could stay on the track.
The model used an adam optimizer, so the learning rate was not tuned manually (model.py line 32).
Training data was chosen to keep the vehicle driving on the road. I used a combination of center lane driving, recovering from the left and right sides of the road. Also all 3 camera positions were used in training the model as well as flipping the images horizontally to have more data.
For details about how I created the training data, see the next section.
The overall strategy for deriving a model architecture was to find an architecture that would help the model extract the correct features from the input images and be able to assign and learn the steering angle that should be taken based on that image/frame.
My first step was to use a simple convolution neural network model of just one layer and two fully-connected layers. I tried it as an initial experement to see if my data preprocessing is working fine as well as the input to the model. As expected the output was horrible as the car drifted quickly out of the road and into the lake! Luckily it is just a simulator :D
In order to gauge how well the model was working, I split my image and steering angle data into a training and validation set. I found that my first model had a low mean squared error on the training set but a high mean squared error on the validation set. This implied that the model was overfitting.
To combat the overfitting, I modified the my dataset so that I could have more of it and to vary it as well. I started by taking the other camera angles as input as well and then I flipped all those images horizontally.
Then I used the model architecture mentioned in the next section as my main and final model. The mse was low for both training and validation.
The final step was to run the simulator to see how well the car was driving around track one. The vehicle is able to drive autonomously around the track without leaving the road. Mission accomplished! :D
The final model architecture (model.py lines 12-34) consisted of 5 convolution layers and 3 fully-connected layers. A model summary is as follows:
_________________________________________________________________
Layer (type) Output Shape Param #
=================================================================
lambda_1 (Lambda) (None, 160, 320, 3) 0
_________________________________________________________________
cropping2d_1 (Cropping2D) (None, 65, 320, 3) 0
_________________________________________________________________
conv2d_1 (Conv2D) (None, 31, 158, 24) 1824
_________________________________________________________________
conv2d_2 (Conv2D) (None, 14, 77, 36) 21636
_________________________________________________________________
conv2d_3 (Conv2D) (None, 5, 37, 48) 43248
_________________________________________________________________
conv2d_4 (Conv2D) (None, 3, 35, 64) 27712
_________________________________________________________________
conv2d_5 (Conv2D) (None, 1, 33, 64) 36928
_________________________________________________________________
flatten_1 (Flatten) (None, 2112) 0
_________________________________________________________________
dense_1 (Dense) (None, 100) 211300
_________________________________________________________________
dense_2 (Dense) (None, 50) 5050
_________________________________________________________________
dense_3 (Dense) (None, 10) 510
_________________________________________________________________
dense_4 (Dense) (None, 1) 11
=================================================================
Total params: 348,219
Trainable params: 348,219
Non-trainable params: 0
_________________________________________________________________
To capture good driving behavior, I first recorded two laps on track one using center lane driving. I then recorded the vehicle recovering from the left side and right sides of the road back to center so that the vehicle would learn to return back to the center of the lane in case in drifted outside of the center.
To augment the data sat, I also flipped images and angles thinking that this would help generalize the model better.
After the collection process, I then preprocessed this data by normalizing them and to be between -0.5 and 0.5 implying a 0 mean.
I finally randomly shuffled the data set and put 20% of the data into a validation set.
I used this training data for training the model. The validation set helped determine if the model was over or under fitting. The ideal number of epochs was 10 as evidenced by the continious decrease of the validation loss. I used an adam optimizer so that manually training the learning rate wasn't necessary.