Term 1 SDC: Car Behavioral Cloning Project
This repository contains files for the Behavioral Cloning Project
which demonstrates the power of deep neural networks and convolutional neural networks to clone driving behavior. Keras was used to train, validate and test an optimal driving model. The model will output a steering angle to an autonomous vehicle.
Structure
model.py
(script used to create and train the model)utils.py
(script used to support model.py)drive.py
(script to drive the car)model.h5
(a trained Keras model)vid/final.mp4
(a video of vehicle driving autonomously around the track for at least one full lap)Credit to the Udacity team for the resources. Probably the best project of all.
Download the simulator from Udacity: https://github.com/udacity/self-driving-car-sim
Install the following dependencies according to Udacity Starter Kit.
Note: upgrade to Keras 2.1.5
Drive the car using the pretrained model. Run python drive.py final_model.h5
To train a model
'data'
python model.py config.json
. config.json
might contain:
config_dict = {
'data': 'data/0929_data', 'augment_pipeline': True, 'model_dir': 'models',
'batch_size': 64, 'correction': 0.2, 'model_name': '1006_0929_augment', 'num_epoch': 20,
'train_steps': 2000, 'val_steps': 50, 'save_best_only': False
}
Inspired from @naokishibuya, the processing pipeline supports the model definition and adds
diversity to the training dataset. The result is detailed below
In training, all the effects and their intensities are randomized with < 0.5 probability to retain the original context.
Located in utils.py
, the batch_generator
will process the images and crunch them out in batches. Using Python generator which acts as a co-routine, this segment saves memory and makes the training operations more efficient.
The training batch is randomly sampled from the total training set by df.sample(batch_size)
. Augmentation techniques only applied during training,
not during validation/test
# Generator function
batch_size = config.get('batch_size', 64)
while 1:
feats = np.zeros((batch_size, IMAGE_HEIGHT, IMAGE_WIDTH, IMAGE_CHANNELS))
responses = np.zeros((batch_size))
batch_image = image_df.sample(batch_size)
batch_steer = steering_df[batch_image.index].reset_index(drop=True)
batch_image.reset_index(inplace=True, drop=True)
for i, row in batch_image.iterrows():
if is_training:
feats[i, :, :, :], responses[i] = image_pipeline(data_dir, row, batch_steer[i], augment=True, **config)
else:
feats[i, :, :, :], responses[i] = image_pipeline(data_dir, row, batch_steer[i], augment=False, **config)
yield feats, responses
I drove the track twice, one in anti-clockwise and turned around to go clockwise. This adds more diversity to the camera angles to be captured. One of the main tricks to teach the car to drive well is recovery from a hard or bad turns. In my additional data collection, I intentionally made bad turns and recover with sharp steers m
Below is the model parameters summarized by Keras model.summary()
. This is based on the Nvidia model that has been successful in self-driving tests. There are 252,219 weights parameters to train.
Layer types:
model.add(Lambda(lambda x: x/127.5 - 1.0, input_shape=INPUT_SHAPE, name='Normalization'))
elu
A few training features were used
Adam(lr=config.get('lr', 0.0001), decay=config.get('decay', 0.01))
fit_generator()
is called to utilize customized generators defined in utils.py
Observations:
Training screenshot:
As shown, the car could not make the first turn and ended up on the grass.
As shown, the car was able to complete about 70% of the track, but ended up in the river. Possible explanation is that the driving sample for that
particular segment might have not been shown to the model.
As shown, the car completed the track and final video is in vid/final.mp4
.