In [1]:
import os
import sys
import pickle
import pandas
import csv

from PIL import Image
import numpy as np

import cv2

from sklearn.model_selection import train_test_split

import os
import json
import pickle
import pandas
from keras.models import Sequential
from keras.layers.core import Dense, Dropout, Activation, Flatten
from keras.layers import Convolution2D, MaxPooling2D, AveragePooling2D


Using TensorFlow backend.

In [2]:
#Cutting the image to the section, that holds the road information
def cut_images_to_arr(img_Center):
    arr_Center = np.array(img_Center)
    arr_Center = arr_Center[50:]
    return arr_Center

#Converting the RGB Image to an HLS Image
def convert_to_HLS(img):
    hls = cv2.cvtColor(img, cv2.COLOR_RGB2HLS)
    return hls

#Normalizing the input Image
def normalize_image(image_data):
    a = 0.01
    b = 0.99
    color_min = 0.0
    color_max = 255.0
    return a + ( ( (image_data - color_min) * (b - a) )/(color_max - color_min))

In [3]:
#Reading the driving log to match stearing information to Images
with open('./data/driving_log.csv', 'r') as f:
    reader = csv.reader(f)
    driving_list = list(reader)
    
X_train = []
y_train = []

#Preprocess all Images with cut/convert to HLS/Normalize
for i, row in enumerate(driving_list):
    if i == 0:
        print(row)
        continue
    #print(row)
    img_Center = Image.open('./data/' + row[0])

    img_Center = cut_images_to_arr(img_Center)
    #img_Center = convert_to_HLS(img_Center)
    img_Center = normalize_image(img_Center)

    X_train.append(img_Center)
    y_train.append(row[3])

X_train = np.array(X_train)

#shuffle and split Training Data into Train and Validation
X_train, X_val, y_train, y_val = train_test_split(
    X_train,
    y_train,
    test_size=0.2)

#Pickle Data Training and Validation Data to make reuse of it.
pickle_data = pickle.dumps(
    {
        'train_dataset': X_train,
        'train_labels': y_train,
        'val_dataset': X_val,
        'val_labels': y_val
    }, pickle.HIGHEST_PROTOCOL)

del X_train, X_val, y_train, y_val

pickle_size = sys.getsizeof(pickle_data)
print(pickle_size)

# Save the data for easy access
pickle_file = 'train_data.pickle'
exists = False

max_bytes = 2 ** 31 - 1

#Cut down Data to smaller protions, since pickle cant handle data bigger than 2**31-1 bytes.
while not exists:
    if not os.path.isfile(pickle_file):
        print('Pickle Train_data')
        try:
            with open(pickle_file, 'wb') as p_train_data:
                for idx in range(0, pickle_size, max_bytes):
                    p_train_data.write(pickle_data[idx:idx + max_bytes])

        except Exception as e:
            print('Unable to save data to', pickle_file, ':', e)
            raise

        print('Train_data in Pickle File.')
        exists = True
    else:
        print("Pickle Filename already in use. Choose another name: *.pickle")
        pickle_file = input("Enter: ")


['center', 'left', 'right', 'steering', 'throttle', 'brake', 'speed']
6788885515
Pickle Train_data
Train_data in Pickle File.

Keras Sequential Model

from keras.models import Sequential

# Create the Sequential model
model = Sequential()

The keras.models.Sequential class is a wrapper for the neural network model. Just like many of the class models in scikit-learn, it provides common functions like fit(), evaluate(), and compile(). We'll cover these functions as we get to them. Let's start looking at the layers of the model.

Keras Layer

A Keras layer is just like a neural network layer. It can be fully connected, max pool, activation, etc. You can add a layer to the model using the model's add() function. For example, a simple model would look like this:

from keras.models import Sequential
from keras.layers.core import Dense, Activation, Flatten

# Create the Sequential model
model = Sequential()

# 1st Layer - Add a flatten layer
model.add(Flatten(input_shape=(32, 32, 3)))

# 2nd Layer - Add a fully connected layer
model.add(Dense(100))

# 3rd Layer - Add a ReLU activation layer
model.add(Activation('relu'))

# 4th Layer - Add a fully connected layer
model.add(Dense(60))

# 5th Layer - Add a ReLU activation layer
model.add(Activation('relu'))

Keras will automatically infer the shape of all layers after the first layer. This means you only have to set the input dimensions for the first layer.

The first layer from above, model.add(Flatten(input_shape=(32, 32, 3))), sets the input dimension to (32, 32, 3) and output dimension to (3072=32*32*3). The second layer takes in the output of the first layer and sets the output dimenions to (100). This chain of passing output to the next layer continues until the last layer, which is the output of the model.

Train the Network

  1. Compile the network using adam optimizer and categorical_crossentropy loss function.
  2. Train the network for ten epochs and validate with 20% of the training data.

In [4]:
pickle_file = 'train_data.pickle'

bytes_in = bytearray(0)
max_bytes = 2 ** 31 - 1
input_size = os.path.getsize(pickle_file)

with open(pickle_file, 'rb') as p_train_data:
    for _ in range(0, input_size, max_bytes):
        bytes_in += p_train_data.read(max_bytes)
pickle_data = pickle.loads(bytes_in)
X_train = pickle_data['train_dataset']
y_train = pickle_data['train_labels']
X_val = pickle_data['val_dataset']
y_val = pickle_data['val_labels']
del pickle_data  # Free up memory

batch_size = 100
nb_classes = 1
nb_epoch = 35

X_train = X_train.astype('float32')
X_test = X_val.astype('float32')
print(X_train.shape[0], 'train samples')
print(X_val.shape[0], 'test samples')


#---Model-Definition:

input_shape = X_train.shape[1:]

model = Sequential()

#Start wird 4 Convolutiional Layers to recognize the image
model.add(Convolution2D(60, 5, 5, subsample=(5, 5), border_mode='same', input_shape=input_shape, activation='relu', dim_ordering='tf'))
model.add(Convolution2D(60, 2, 2, border_mode='same', input_shape=input_shape, activation='relu', dim_ordering='tf'))
model.add(MaxPooling2D(pool_size=(2, 2), border_mode='same', dim_ordering='tf'))
model.add(Convolution2D(60, 2, 2, border_mode='same', input_shape=input_shape, activation='relu', dim_ordering='tf'))
model.add(MaxPooling2D(pool_size=(2, 2), border_mode='same', dim_ordering='tf'))
model.add(Convolution2D(60, 6, 6, border_mode='same', input_shape=input_shape, activation='relu', dim_ordering='tf'))
model.add(MaxPooling2D(pool_size=(2, 2), border_mode='same', dim_ordering='tf'))
model.add(Dropout(0.25))

#Flatten the Matrix to a Vektor and run 3 RELU Layers
model.add(Flatten())
model.add(Dense(40, name="hidden1"))
model.add(Activation('relu'))
model.add(Dense(20, name="hidden2"))
model.add(Activation('relu'))
model.add(Dense(10, name="hidden3"))
model.add(Activation('relu'))
model.add(Dropout(0.5))
model.add(Dense(1, name="Steering_Angle"))

model.summary()

model.compile(loss='mean_squared_error', optimizer='adam', metrics=['accuracy'])
history = model.fit(X_train, y_train, batch_size=batch_size, nb_epoch=nb_epoch, verbose=1, validation_data=(X_val, y_val))

json_string = model.to_json()
with open('./model.json', 'w') as outfile:
    json.dump(json_string, outfile)

model.save_weights('./model.h5')


6428 train samples
1608 test samples
____________________________________________________________________________________________________
Layer (type)                     Output Shape          Param #     Connected to                     
====================================================================================================
convolution2d_1 (Convolution2D)  (None, 22, 64, 60)    4560        convolution2d_input_1[0][0]      
____________________________________________________________________________________________________
convolution2d_2 (Convolution2D)  (None, 22, 64, 60)    14460       convolution2d_1[0][0]            
____________________________________________________________________________________________________
maxpooling2d_1 (MaxPooling2D)    (None, 11, 32, 60)    0           convolution2d_2[0][0]            
____________________________________________________________________________________________________
convolution2d_3 (Convolution2D)  (None, 11, 32, 60)    14460       maxpooling2d_1[0][0]             
____________________________________________________________________________________________________
maxpooling2d_2 (MaxPooling2D)    (None, 6, 16, 60)     0           convolution2d_3[0][0]            
____________________________________________________________________________________________________
convolution2d_4 (Convolution2D)  (None, 6, 16, 60)     129660      maxpooling2d_2[0][0]             
____________________________________________________________________________________________________
maxpooling2d_3 (MaxPooling2D)    (None, 3, 8, 60)      0           convolution2d_4[0][0]            
____________________________________________________________________________________________________
dropout_1 (Dropout)              (None, 3, 8, 60)      0           maxpooling2d_3[0][0]             
____________________________________________________________________________________________________
flatten_1 (Flatten)              (None, 1440)          0           dropout_1[0][0]                  
____________________________________________________________________________________________________
hidden1 (Dense)                  (None, 40)            57640       flatten_1[0][0]                  
____________________________________________________________________________________________________
activation_1 (Activation)        (None, 40)            0           hidden1[0][0]                    
____________________________________________________________________________________________________
hidden2 (Dense)                  (None, 20)            820         activation_1[0][0]               
____________________________________________________________________________________________________
activation_2 (Activation)        (None, 20)            0           hidden2[0][0]                    
____________________________________________________________________________________________________
hidden3 (Dense)                  (None, 10)            210         activation_2[0][0]               
____________________________________________________________________________________________________
activation_3 (Activation)        (None, 10)            0           hidden3[0][0]                    
____________________________________________________________________________________________________
dropout_2 (Dropout)              (None, 10)            0           activation_3[0][0]               
____________________________________________________________________________________________________
Steering_Angle (Dense)           (None, 1)             11          dropout_2[0][0]                  
====================================================================================================
Total params: 221,821
Trainable params: 221,821
Non-trainable params: 0
____________________________________________________________________________________________________
Train on 6428 samples, validate on 1608 samples
Epoch 1/35
6428/6428 [==============================] - 140s - loss: 0.0166 - acc: 0.5423 - val_loss: 0.0167 - val_acc: 0.5442
Epoch 2/35
6428/6428 [==============================] - 106s - loss: 0.0166 - acc: 0.5423 - val_loss: 0.0168 - val_acc: 0.5442
Epoch 3/35
6428/6428 [==============================] - 103s - loss: 0.0166 - acc: 0.5423 - val_loss: 0.0167 - val_acc: 0.5442
Epoch 4/35
6428/6428 [==============================] - 103s - loss: 0.0166 - acc: 0.5423 - val_loss: 0.0167 - val_acc: 0.5442
Epoch 5/35
6428/6428 [==============================] - 103s - loss: 0.0166 - acc: 0.5423 - val_loss: 0.0167 - val_acc: 0.5442
Epoch 6/35
6428/6428 [==============================] - 104s - loss: 0.0166 - acc: 0.5423 - val_loss: 0.0167 - val_acc: 0.5442
Epoch 7/35
6428/6428 [==============================] - 107s - loss: 0.0166 - acc: 0.5423 - val_loss: 0.0167 - val_acc: 0.5442
Epoch 8/35
6428/6428 [==============================] - 106s - loss: 0.0166 - acc: 0.5423 - val_loss: 0.0168 - val_acc: 0.5442
Epoch 9/35
6428/6428 [==============================] - 103s - loss: 0.0166 - acc: 0.5423 - val_loss: 0.0167 - val_acc: 0.5442
Epoch 10/35
6428/6428 [==============================] - 103s - loss: 0.0166 - acc: 0.5423 - val_loss: 0.0167 - val_acc: 0.5442
Epoch 11/35
6428/6428 [==============================] - 103s - loss: 0.0166 - acc: 0.5423 - val_loss: 0.0167 - val_acc: 0.5442
Epoch 12/35
6428/6428 [==============================] - 103s - loss: 0.0166 - acc: 0.5423 - val_loss: 0.0167 - val_acc: 0.5442
Epoch 13/35
6428/6428 [==============================] - 103s - loss: 0.0166 - acc: 0.5423 - val_loss: 0.0167 - val_acc: 0.5442
Epoch 14/35
6428/6428 [==============================] - 103s - loss: 0.0166 - acc: 0.5423 - val_loss: 0.0167 - val_acc: 0.5442
Epoch 15/35
6428/6428 [==============================] - 104s - loss: 0.0166 - acc: 0.5423 - val_loss: 0.0167 - val_acc: 0.5442
Epoch 16/35
6428/6428 [==============================] - 103s - loss: 0.0166 - acc: 0.5423 - val_loss: 0.0167 - val_acc: 0.5442
Epoch 17/35
6428/6428 [==============================] - 103s - loss: 0.0166 - acc: 0.5423 - val_loss: 0.0167 - val_acc: 0.5442
Epoch 18/35
6428/6428 [==============================] - 103s - loss: 0.0166 - acc: 0.5423 - val_loss: 0.0167 - val_acc: 0.5442
Epoch 19/35
6428/6428 [==============================] - 103s - loss: 0.0166 - acc: 0.5423 - val_loss: 0.0167 - val_acc: 0.5442
Epoch 20/35
6428/6428 [==============================] - 103s - loss: 0.0166 - acc: 0.5423 - val_loss: 0.0168 - val_acc: 0.5442
Epoch 21/35
6428/6428 [==============================] - 103s - loss: 0.0166 - acc: 0.5423 - val_loss: 0.0167 - val_acc: 0.5442
Epoch 22/35
6428/6428 [==============================] - 103s - loss: 0.0166 - acc: 0.5423 - val_loss: 0.0167 - val_acc: 0.5442
Epoch 23/35
6428/6428 [==============================] - 104s - loss: 0.0166 - acc: 0.5423 - val_loss: 0.0167 - val_acc: 0.5442
Epoch 24/35
6428/6428 [==============================] - 103s - loss: 0.0166 - acc: 0.5423 - val_loss: 0.0167 - val_acc: 0.5442
Epoch 25/35
6428/6428 [==============================] - 104s - loss: 0.0166 - acc: 0.5423 - val_loss: 0.0168 - val_acc: 0.5442
Epoch 26/35
6428/6428 [==============================] - 104s - loss: 0.0166 - acc: 0.5423 - val_loss: 0.0167 - val_acc: 0.5442
Epoch 27/35
6428/6428 [==============================] - 104s - loss: 0.0166 - acc: 0.5423 - val_loss: 0.0167 - val_acc: 0.5442
Epoch 28/35
6428/6428 [==============================] - 103s - loss: 0.0166 - acc: 0.5423 - val_loss: 0.0167 - val_acc: 0.5442
Epoch 29/35
6428/6428 [==============================] - 103s - loss: 0.0166 - acc: 0.5423 - val_loss: 0.0167 - val_acc: 0.5442
Epoch 30/35
6428/6428 [==============================] - 103s - loss: 0.0166 - acc: 0.5423 - val_loss: 0.0167 - val_acc: 0.5442
Epoch 31/35
6428/6428 [==============================] - 103s - loss: 0.0166 - acc: 0.5423 - val_loss: 0.0167 - val_acc: 0.5442
Epoch 32/35
6428/6428 [==============================] - 103s - loss: 0.0166 - acc: 0.5423 - val_loss: 0.0168 - val_acc: 0.5442
Epoch 33/35
6428/6428 [==============================] - 103s - loss: 0.0166 - acc: 0.5423 - val_loss: 0.0167 - val_acc: 0.5442
Epoch 34/35
6428/6428 [==============================] - 104s - loss: 0.0166 - acc: 0.5423 - val_loss: 0.0167 - val_acc: 0.5442
Epoch 35/35
6428/6428 [==============================] - 103s - loss: 0.0166 - acc: 0.5423 - val_loss: 0.0167 - val_acc: 0.5442

Best Validation Accuracy: 0.9911