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
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: ")
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.
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.
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')
Best Validation Accuracy: 0.9911