|
1、模型构建 def get_model
2、数据生成器 def batch_generator
3、开始训练网络 model.fit_generator
4、可视化 callbacks.TensorBoard plt.savefig('train_test_loss.jpg')
5、图像预处理 数据增强等都没有实现
根据车载摄像头的画面,自动判断如何打方向盘?使用端到端(end-to-end)的深度神经网络CNN
Data Generator:无需预先生成所有图像增强后的图像,会占用太多的硬盘空间,会增加读取硬盘文件所需的时间
数据driving_log.csv文件中右 center left right steering角度 throttle油门 brake刹车 speed速度
我们这里只用 center 和 steering角度
csv文件的读取:
data_path = 'F:\\AI_Study_dfy\\项目:自动驾驶之方向盘转动角度预测data\\'
with open(data_path + 'driving_log.csv', 'r') as csvfile:
file_reader = csv.reader(csvfile, delimiter=',')
log = []
for row in file_reader:
log.append(row)
log = np.array(log)
# 二维矩阵里面都是字符串
print(log.shape)
print(log.ndim)
print(log.dtype)
print(log[:5, :])
遇到问题:OpenCV无法读取中文路径
解决:http://www.ai111.vip/thread-861-1-1.html
- # -*- coding: utf-8 -*-
- __author__ = u'东方耀 微信:dfy_88888'
- __date__ = '2019/10/18 11:49'
- __product__ = 'PyCharm'
- __filename__ = 'train_dfy'
- import tensorflow as tf
- import numpy as np
- import torch as T
- from keras.layers import Conv2D, MaxPooling2D, Flatten, PReLU
- from keras.layers.core import Dense, Dropout, Activation
- from keras.optimizers import SGD, Adam
- from keras.models import Model, Sequential
- from keras import backend as K
- from keras.regularizers import l2
- import os.path
- import cv2
- import skimage.io as iio
- import csv
- import glob
- import pickle
- from sklearn.utils import shuffle
- from sklearn.model_selection import cross_validate
- from sklearn.model_selection import train_test_split
- import json
- from keras import callbacks
- import math
- import matplotlib.pyplot as plt
- SEED = 666
- print(tf.__version__)
- print(T.__version__)
- def get_model(shape):
- """
- 预测方向盘角度,以图像为输入,预测方向盘的转动角度
- :param shape: 图像尺寸 (128, 128, 3) NHC
- :return:
- """
- model = Sequential(name='dfy_seq_model')
- # 第一层需要指定input_shape 后面不需要
- model.add(Conv2D(filters=24, kernel_size=(5, 5), strides=(2, 2),
- padding='valid', data_format='channels_last', activation='relu', input_shape=shape))
- model.add(Conv2D(filters=36, kernel_size=(5, 5), strides=(2, 2),
- padding='valid', data_format='channels_last', activation='relu'))
- model.add(Conv2D(filters=48, kernel_size=(5, 5), strides=(2, 2),
- padding='valid', data_format='channels_last', activation='relu'))
- model.add(Conv2D(filters=64, kernel_size=(3, 3), strides=(1, 1),
- padding='valid', data_format='channels_last', activation='relu'))
- model.add(Conv2D(filters=64, kernel_size=(3, 3), strides=(1, 1),
- padding='valid', data_format='channels_last', activation='relu'))
- model.add(Flatten(data_format='channels_last'))
- model.add(Dense(units=1164, activation='relu'))
- model.add(Dense(units=100, activation='relu'))
- model.add(Dense(units=50, activation='relu'))
- model.add(Dense(units=10, activation='relu'))
- # 由于输出的角度是 (-pi/2, pi/2) 要选择好的激活函数
- model.add(Dense(units=1, activation='linear'))
- # compile: 1、指定优化器 2、损失函数
- model.compile(optimizer=Adam(learning_rate=0.001), loss='mean_squared_error')
- return model
- # 开始数据增强(基于现有样本数据产生新的更多的训练数据)
- def random_brightness(img, degree):
- """
- 随机调整输入图像的亮度,调整强度于0.1(变黑)和1(无变化)之间
- :param img: 输入图像
- :param degree: 输入图像对应的转动角度
- :return:
- """
- return (img, degree)
- def horizontal_flip(img, degree):
- """
- 按照50%的概率水平翻转图像
- :param img: 输入图像
- :param degree: 输入图像对应的转动角度
- :return:
- """
- pass
- return (img, degree)
- def left_right_random_swap(img_address, degree, degree_corr=1.0 / 4):
- """
- 随机从左、中、右图像中选择一张图像,并相应调整转动的角度
- :param img_address: 中间图像的文件路径
- :param degree: 中间图像对应的方向盘转动角度
- :param degree_corr: 方向盘转动角度调整的值
- :return:
- """
- return (img_address, degree)
- def discard_zero_steering(degrees, rate):
- """
- 从角度为0的index中随机选择部分index返回
- :param degrees: 输入的角度值
- :param rate: 丢弃率 rate=0.8 表示80%的index返回
- :return:
- """
- return degrees
- def image_transformation(img_address, degree, data_dir):
- # img_address, degree = left_right_random_swap(img_address, degree)
- # opencv 读出来的图像是 bgr的
- # print('开始读的图片地址(路径有中文):', data_dir+img_address)
- img = iio.imread(data_dir + img_address)
- # cvt convert 颜色空间的转换
- img = cv2.cvtColor(img, cv2.COLOR_BGR2RGB)
- # img, degree = random_brightness(img, degree)
- # img, degree = horizontal_flip(img, degree)
- return (img, degree)
- def batch_generator(x, y, batch_size, shape, training=True, data_dir='data/', discard_rate=0.95):
- """
- 产生批处理的数据Generator 高效读取数据
- Data Generator 无需预先生成所有图像增强后的图像,会占用太多的硬盘空间与增加读取硬盘文件所需的时间
- :param x: 图像文件路径list
- :param y: 方向盘的角度
- :param batch_size:
- :param shape: 输入图像的尺寸(HWC)
- :param training: True时产生训练数据 False时产生validation数据
- :param data_dir: 数据目录,包含一个IMG文件夹
- :param discard_rate: 随机丢弃角度=0的训练数据的比率
- :return:
- """
- if training:
- x, y = shuffle(x, y)
- rand_zero_idx = discard_zero_steering(y, rate=discard_rate)
- new_x = np.delete(x, rand_zero_idx, axis=0)
- new_y = np.delete(y, rand_zero_idx, axis=0)
- else:
- new_x = x
- new_y = y
- offset = 0
- while True:
- X = np.empty(shape=(batch_size, *shape))
- Y = np.empty(shape=(batch_size, 1))
- for example in range(batch_size):
- img_address, img_steering = new_x[example + offset], new_y[example + offset]
- if training:
- img, img_steering = image_transformation(img_address, img_steering, data_dir)
- else:
- img = iio.imread(data_dir + img_address)
- img = cv2.cvtColor(img, cv2.COLOR_BGR2RGB)
- # 先截取图像 后resize 再 归一化到[-0.5, 0.5]
- # [NHWC] 四维
- X[example, :, :, :] = cv2.resize(img[80:140, 0:320], (shape[0], shape[1])) / 255 - 0.5
- Y[example] = img_steering
- if (example + 1) + offset > len(new_y) - 1:
- # 达到了原来数据的尾部,从头开始
- x, y = shuffle(x, y)
- rand_zero_idx = discard_zero_steering(y, rate=discard_rate)
- new_x = x
- new_y = y
- new_x = np.delete(new_x, rand_zero_idx, axis=0)
- new_y = np.delete(new_y, rand_zero_idx, axis=0)
- offset = 0
- yield (X, Y) # 类似return 但有区别
- offset = offset + batch_size
- if __name__ == '__main__':
- data_path = 'F:\\AI_Study_dfy\\项目:自动驾驶之方向盘转动角度预测data\\'
- with open(data_path + 'driving_log.csv', 'r') as csvfile:
- file_reader = csv.reader(csvfile, delimiter=',')
- log = []
- for row in file_reader:
- log.append(row)
- log = np.array(log)
- # 二维矩阵里面都是字符串
- print(log.shape)
- print(log.ndim)
- print(log.dtype)
- print(log[:5, :])
- # 去掉第一行 表头数据
- log = log[1:, :]
- ls_imgs = glob.glob(data_path + 'IMG/*.jpg')
- print('一共有%d张图片(包括中间、左边、右边)' % len(ls_imgs))
- assert len(ls_imgs) == len(log) * 3, 'number of images does not match!'
- # 使用20%的数据作为测试数据集
- test_ratio = 0.2
- shape = (128, 128, 3)
- batch_size = 20
- # 所有的数据跑多少轮?epoch
- nb_epoch = 30
- # 中间摄像头的图片路径 str
- x_ = log[:, 0]
- # steering str---> float
- y_ = log[:, 3].astype(float)
- x_, y_ = shuffle(x_, y_)
- X_train, X_test, y_train, y_test = train_test_split(x_, y_, random_state=SEED, test_size=test_ratio)
- print('训练集大小:{}, 测试集大小:{}'.format(len(X_train), len(X_test)))
- steps_per_epoch = 20
- # 使得test数据集大小为batch_size的整数倍
- nb_test_samples = len(y_test) - len(y_test) % batch_size
- print('nb_test_samples size:', nb_test_samples)
- model = get_model(shape)
- # 生成模型结构汇总 挺好!
- print(model.summary())
- # 根据test loss保存最优模型
- save_best = callbacks.ModelCheckpoint(filepath='best_model.h5', monitor='val_loss', verbose=1,
- save_best_only=True, mode='min')
- # 如果训练连续patience=15(向后看多少步)val_loss did not improve(网络不收敛),提前结束训练
- # if (last_loss - current_loss) > min_delta 才算网络是在优化 否则表示loss没有在下降
- early_stop = callbacks.EarlyStopping(monitor='val_loss', min_delta=1e-5, patience=15, verbose=0, mode='auto')
- tb_callback = callbacks.TensorBoard(log_dir='./Graph', write_graph=True)
- callback_lists = [early_stop, save_best, tb_callback]
- # 开始训练网络
- history = model.fit_generator(
- generator=batch_generator(X_train, y_train, batch_size, shape, training=True, data_dir=data_path),
- steps_per_epoch=steps_per_epoch, validation_steps=nb_test_samples // batch_size,
- validation_data=batch_generator(X_test, y_test, batch_size, shape, training=False, data_dir=data_path),
- epochs=nb_epoch, verbose=1, callbacks=callback_lists)
- with open('./trainHistoryDict.pickle', 'wb') as file_pickle:
- pickle.dump(history.history, file_pickle)
- plt.plot(history.history['loss'])
- plt.plot(history.history['val_loss'])
- plt.title('model train vs test loss')
- plt.xlabel('epoch')
- plt.ylabel('loss')
- plt.legend(['train', 'test'], loc='upper right')
- plt.savefig('train_test_loss.jpg')
- # 模型保存
- with open('model.json', 'w') as f:
- f.write(model.to_json())
- model.save('model.h5')
- print('Done!')
复制代码
东方老师AI官网:http://www.ai111.vip
有任何问题可联系东方老师微信:dfy_88888
【微信二维码图片】
|
|