Implement PilotNet using Keras (with tensorflow backend), with some modifications
In [1]:
import os
import pandas as pd
import numpy as np
from sklearn.utils import shuffle
In [2]:
import keras
from keras.models import Sequential
from keras.models import load_model
from keras.layers import Flatten, Dense
from keras.layers import BatchNormalization
from keras.layers import Conv2D
from keras.optimizers import SGD
from keras.preprocessing import image
from keras.preprocessing.image import ImageDataGenerator
from keras.callbacks import CSVLogger, ModelCheckpoint
In [3]:
# limit GPU memory usage
import tensorflow as tf
from keras.backend.tensorflow_backend import set_session
config = tf.ConfigProto()
config.gpu_options.per_process_gpu_memory_fraction = 0.75
set_session(tf.Session(config=config))
In [4]:
%ls ../data/csv/final
In [5]:
# define path variables
parent_path = os.path.dirname(os.getcwd())
data_path = os.path.join(parent_path, 'data')
img_front_dir_path = os.path.join(data_path, 'img', 'front')
model_path = os.path.join(parent_path, 'model')
log_path = os.path.join(model_path, 'log')
csv_dir_path = os.path.join(data_path, 'csv', 'final')
cur_file = 'v3'
train_file = os.path.join(csv_dir_path, cur_file + '_train.csv')
valid_file = os.path.join(csv_dir_path, cur_file + '_valid.csv')
# divide by a constant to bound output to [0,100]
OUTPUT_NORMALIZATION = 655.35
In [6]:
df_train = pd.read_csv(os.path.join(data_path, train_file))
print("%d rows" % df_train.shape[0])
df_train.head(3)
Out[6]:
In [7]:
df_val = pd.read_csv(os.path.join(data_path, valid_file))
print("%d rows" % df_val.shape[0])
df_val.head(3)
Out[7]:
In [8]:
def img_to_arr(p):
with image.load_img(p) as img:
img = image.img_to_array(img)
return img
# values computed from dataset sample.
def normalize(img):
img[:,:,0] -= 94.9449
img[:,:,0] /= 58.6121
img[:,:,1] -= 103.599
img[:,:,1] /= 61.6239
img[:,:,2] -= 92.9077
img[:,:,2] /= 68.66
return img
In [9]:
# define generator that loops through the data
def generator(df, batch_size, img_shape, should_shuffle):
# shuffle dataframe for each epoch
if should_shuffle:
df = shuffle(df)
img_list = df['front']
wheel_axis = df['wheel-axis']
# create empty batch
batch_img = np.zeros((batch_size,) + img_shape)
batch_label = np.zeros((batch_size, 1))
index = 0
while True:
for i in range(batch_size):
img_name = img_list[index]
arr = img_to_arr(os.path.join(img_front_dir_path, img_name))
batch_img[i] = normalize(arr)
batch_label[i] = wheel_axis[index] / OUTPUT_NORMALIZATION
index += 1
if index == len(img_list):
index = 0
yield batch_img, batch_label
In [10]:
input_shape = img_to_arr(os.path.join(img_front_dir_path, df_train['front'][0])).shape
batch_size = 160
train_steps = (df_train.shape[0] / batch_size) + 1
val_steps = (df_val.shape[0] / batch_size) + 1
print("input_shape: %s, batch_size: %d, train_steps: %d, val_steps: %d" %
(input_shape, batch_size, train_steps, val_steps))
In [11]:
train_batch = generator(df_train, batch_size, input_shape, True)
val_batch = generator(df_val, batch_size, input_shape, False)
In [12]:
# define PilotNet model, with batch normalization included.
def get_model(input_shape):
model = Sequential([
Conv2D(24, kernel_size=(5,5), strides=(2,2), activation='relu', input_shape=input_shape),
BatchNormalization(axis=1),
Conv2D(36, kernel_size=(5,5), strides=(2,2), activation='relu'),
BatchNormalization(axis=1),
Conv2D(48, kernel_size=(5,5), strides=(2,2), activation='relu'),
BatchNormalization(axis=1),
Conv2D(64, kernel_size=(3,3), strides=(1,1), activation='relu'),
BatchNormalization(axis=1),
Conv2D(64, kernel_size=(3,3), strides=(1,1), activation='relu'),
BatchNormalization(axis=1),
Flatten(),
Dense(100, activation='relu'),
BatchNormalization(),
Dense(50, activation='relu'),
BatchNormalization(),
Dense(10, activation='relu'),
BatchNormalization(),
Dense(1)
])
return model
model = get_model(input_shape)
sgd = SGD(lr=1e-3, decay=1e-4, momentum=0.9, nesterov=True)
model.compile(optimizer=sgd, loss="mse")
model.summary()
In [13]:
# or load from saved model
# model = load_model(os.path.join(model_path, 'v3-PilotNet_v1-029-0.0783.h5'))
In [14]:
# define callbacks
cur_model = cur_file + '-PilotNet_v2'
csv_logger = CSVLogger(os.path.join(log_path, cur_model + '.log'))
model_file_name= os.path.join(model_path, cur_model + '-{epoch:03d}-{val_loss:.5f}.h5')
checkpoint = ModelCheckpoint(model_file_name, verbose=0, save_best_only=True)
In [15]:
model.fit_generator(train_batch,
train_steps,
epochs=20,
verbose=1,
callbacks=[csv_logger, checkpoint],
validation_data=val_batch,
validation_steps=val_steps,
initial_epoch=0)
Out[15]:
In [ ]: