<SYSTEM_TASK:>
Given the following text description, write Python code to implement the functionality described below step by step
<END_TASK>
<USER_TASK:>
Description:
 Self-driving car Nanodegree - Term 1
Project 2
Step1:  Dataset
I used training dataset provided by Udacity. I use all 3 positions of camera with correction of 0.25 , i.e addition of 0.25 to steering angle for left-positioned camera and substraction of 0.25 for right-positioned camera.
I could have self-produced ore data but due to time constraint, I only used Udacity dataset
Moreover, after unable to complete a whole lap, I follow advice from forum and decided to randomly choose camera to select from
The dataset is split into 20% of test set. Also, the training set is shuffled before training
Loading Dataset
Step2:  Model Architecture and Training Strategy
First Model
In my first attempt, I used 9-layers network from end to end learning for self-driving cars by NVIDIA 
Pre-processing pipeline
Data augmentation
Step3:  Model Architecture Definition
Step4:  Model Training
For every time of training and parameter tunning, the model was tested by running it through the simulator and ensuring that the vehicle could stay on the track.
At epoch of 10, the training and validation loss both went down fast and I think they would converge if I'd have increased number of epoch (graph is plotted in the notebook. However, for this kind of regression problem, both trainning loss and accuracy do not seem to be useful, it is more important to test it on the simulator provided by Udacity. Therefore, I simply tune number of epoch until the vehicle run well on the track.
Final Model parameters
<ASSISTANT_TASK:>
Python Code:
import csv
from keras.models import Sequential
from keras.layers import Flatten, Dense, Convolution2D, Cropping2D, Lambda, Dropout
import numpy as np
import cv2
import matplotlib.pyplot as plt
from sklearn.model_selection import train_test_split
import sklearn
from keras.layers.pooling import MaxPooling2D
# Visualizations will be shown in the notebook.
%matplotlib inline
Explanation: Self-driving car Nanodegree - Term 1
Project 2: Behavior Cloning
In this project, We built and trained a convolutional neural network for end-to-end driving in a simulator, using TensorFlow and Keras. We used optimization techniques such as regularization and dropout to generalize the network for driving on multiple tracks. The model will output a steering angle to an autonomous vehicle.
The goals / steps of this project are the following:
* Use the simulator to collect data of good driving behavior 
* Design, train and validate a model that predicts a steering angle from image data
* Use the model to drive the vehicle autonomously around the first track in the simulator. The vehicle should remain on the road for an entire loop around the track.
* Summarize the results with a written report
Author : Tran Ly Vu
Github repo
Notebook
Python code
Files Submitted
My project includes the following files:
- src/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
- notebook containing notebook
- run1.mp4 containing sample video of driving the car in autonomous mode using trained model
Using the Udacity provided simulator and my drive.py file, I was able to test my model by driving autonomously around the track by executing:
python drive.py model.h5
Video of driving the car was generated by executing:
python drive.py model.h5 run1
python video.py run1 --fps 48
Importing packages
End of explanation
'''Read data'''
image_path = '../../../data'
# row in log path is IMG/<name>
driving_log_path = '../../../data/driving_log.csv'
rows = []
with open(driving_log_path) as csvfile:
    reader = csv.reader(csvfile)
    for row in reader:
        rows.append(row)
Explanation: Dataset
I used training dataset provided by Udacity. I use all 3 positions of camera with correction of 0.25 , i.e addition of 0.25 to steering angle for left-positioned camera and substraction of 0.25 for right-positioned camera.
I could have self-produced ore data but due to time constraint, I only used Udacity dataset
Moreover, after unable to complete a whole lap, I follow advice from forum and decided to randomly choose camera to select from
The dataset is split into 20% of test set. Also, the training set is shuffled before training
Loading Dataset
End of explanation
def append_data(col, images, measurement, steering_measurements):
    current_path = image_path + '/' + col.strip()
    
    image = cv2.imread(current_path)
    image = cv2.cvtColor(image, cv2.COLOR_BGR2RGB)
    images.append(np.asarray(image))
    steering_measurements.append(measurement)
    
    # random flipping
    flip_prob = np.random.random()
    if flip_prob > 0.5:
        image_flipped = np.fliplr(image)
        images.append(np.asarray(image_flipped))
        measurement_flipped = measurement * (-1)
        steering_measurements.append(measurement)
          
def images_and_measurements(sample):
    images = []
    steering_measurements = []
    for line in sample[0:]:
        measurement = float(line[3])
        ## random data
        camera = np.random.choice(['center', 'left', 'right'])
        if camera == 'center':
            col_center = line[0]
            append_data(col_center, images, measurement, steering_measurements)
        elif camera == 'left':
            col_left = line[1]
            append_data(col_left, images, measurement + 0.25, steering_measurements)
        else:
            col_right = line[2]
            append_data(col_right, images, measurement - 0.25, steering_measurements)
    return images, steering_measurements
def generator(samples, batch_size = 32):
    num_samples = len(samples)
    while 1:
        sklearn.utils.shuffle(samples)
        for offset in range(0, num_samples, batch_size):
            batch_samples = samples[offset:offset + batch_size]           
            images = []
            measurements = []
            for image, measurement in batch_samples:
                images.append(image)   
                measurements.append(measurement)
            # trim image to only see section with road
            x_train = np.array(images)
            y_train = np.array(measurements)
            yield sklearn.utils.shuffle(x_train, y_train)
## Print total number of data , including augmentation
X_total, y_total = images_and_measurements(rows[1:])
print("Number of image is: ", len(X_total))
print("Number of measurement is: ", len(y_total))
Explanation: Model Architecture and Training Strategy
First Model
In my first attempt, I used 9-layers network from end to end learning for self-driving cars by NVIDIA 
Pre-processing pipeline
Data augmentation: Fliping the image horizontal (from function append_data)
Cropping the image
Normalization and Mean centering
NVIDIA original model
|Layer   |type    |output filter/neurons|
|--------|--------|--------|
|1       |conv    |24      |
|2       |conv    |36      |
|3       |conv    |48      |
|4       |conv    |64      |
|5       |conv    |64      |
|6       |flattern|1164    |
|7       |relu    |100     |
|8       |relu    |50      |
|9       |relu    |10      |
|10      |relu    |1       |
Second Attempt
However, I detected overfitting in my first attempt, and hence i tried to improved the mode in second model by using regulation, i.e dropout
Pre-processing pipeline
        - Data augmentation: Fliping the image horizontal (from function append_data)
        - Cropping the image
        - Normalization and Mean centering
Modified NVIDIA model
|Layer   |type    |output filter/neurons|
|--------|--------|--------|
|1       |conv    |24      |
|        |dropout |        |
|2       |conv    |36      |
|        |dropout |        |
|3       |conv    |48      |
|        |dropout |        |
|4       |conv    |64      |
|5       |conv    |64      |
|6       |flattern|1164    |
|7       |relu    |100     |
|8       |relu    |50      |
|9       |relu    |10      |
|10      |relu    |1       |
End of explanation
model = Sequential()
#The cameras in the simulator capture 160 pixel by 320 pixel images., after cropping, it is 66x200
model.add(Cropping2D(cropping = ((74,20), (60,60)),input_shape=(160, 320, 3)))
model.add(Lambda(lambda x: x / 255.0 - 0.5, input_shape=(66, 200, 3)))
model.add(Convolution2D(24, 5, 5, subsample=(2,2), activation='relu'))
model.add(Dropout(.5))
model.add(Convolution2D(36, 5, 5, subsample=(2,2), activation='relu'))
model.add(Dropout(.5))
model.add(Convolution2D(48, 5, 5, subsample=(2,2), activation='relu'))
model.add(Dropout(.5))
model.add(Convolution2D(64, 3, 3, activation='relu'))
model.add(Convolution2D(64, 3, 3, activation='relu'))  
model.add(Flatten())
model.add(Dense(100))
model.add(Dense(50))
model.add(Dense(10))
model.add(Dense(1))
'''Training: using MSE for regression'''
model.compile(loss='mse', optimizer='adam')
Explanation: Model Architecture Definition
End of explanation
print('Training model')            
samples = list(zip(X_total, y_total))          
train_samples, validation_samples = train_test_split(samples, test_size = 0.2)
train_generator = generator(train_samples, batch_size = 32)
validation_generator = generator(validation_samples, batch_size = 32)
history_object = model.fit_generator(train_generator,
                                    samples_per_epoch = len(train_samples),
                                    validation_data = validation_generator,
                                    nb_val_samples = len(validation_samples),
                                    nb_epoch = 5, 
                                    verbose = 1)
print('Endding training, starting to save model')
model.save('../model.h5')
print(history_object.history.keys())
###plot the training and validation loss for each epoch
plt.plot(history_object.history['loss'])
plt.plot(history_object.history['val_loss'])
plt.title('model mean squared error loss')
plt.ylabel('mean squared error loss')
plt.xlabel('epoch')
plt.legend(['training set', 'validation set'], loc='upper right')
plt.show()
Explanation: Model Training
For every time of training and parameter tunning, the model was tested by running it through the simulator and ensuring that the vehicle could stay on the track.
At epoch of 10, the training and validation loss both went down fast and I think they would converge if I'd have increased number of epoch (graph is plotted in the notebook. However, for this kind of regression problem, both trainning loss and accuracy do not seem to be useful, it is more important to test it on the simulator provided by Udacity. Therefore, I simply tune number of epoch until the vehicle run well on the track.
Final Model parameters:
- Optimizer: Adam optimizer, so the learning rate was not tuned manually 
- Epoch: 5
- Batch size: 32
End of explanation
<END_TASK>