(17-7-01)基于强化学习的自动驾驶系统:生成训练数据+训练模型
17.8 调用处理
在本节的内容中,将利用前面的功能模块和子函数依次实现数据采集、自编码器训练、专家数据收集、强化学习训练、DDPG智能体训练以及性能测试等功能。
17.8.1 生成训练数据
开发一个名为collect_data_autoencoder.py的Python脚本文件及其相关模块。该脚本的主要功能是采集与自动编码器训练相关的数据,并在模拟环境中生成相关数据后进行记录。其主要作用是为后续的深度学习模型训练及研究提供数据基础。
(1)模拟器数据:程序通过与模拟器的交互来获取以下类型的数据:
- 视觉信息:这些信息可以源自相机捕捉到的图像或帧。
- 传感器数据:这些数据源自车辆上安装的各种传感器装置(如激光雷达、GPS和惯性测量单元等)。
- 运动路径与行为特征:这些记录包括车辆在模拟环境中运动轨迹的信息、速度参数以及转向动作的数据。
(2)数据多样性:通过精心配置不同的行驶路线及重复次数,并在多变天气状况下进行模拟测试,从而获得丰富多样的训练数据集。这有助于提升自动编码器模型以全面掌握各类环境及驾驶情境为基础的能力。
(3)数据存储格式:当命令行参数--np被指定时,这些数据将被以图像或NumPy数组的形式进行保存。这将取决于用户的选项设置。通过这种方式,用户可以根据需求选择适合的数据存储格式。
文件collect_data_autoencoder.py的具体实现代码如下所示。
from argparse import ArgumentParser
from data.collect_data import main
from configuration.config import *
if __name__=='__main__':
argparser = ArgumentParser()
argparser.add_argument('--world-port', type=int, default=WORLD_PORT)
argparser.add_argument('--host', type=str, default=WORLD_HOST)
argparser.add_argument('--map', type=str, default=TRAIN_MAP, help="Load the map before starting the simulation")
argparser.add_argument('--weather', type=str, default='ClearNoon',
choices=['ClearNoon', 'ClearSunset', 'CloudyNoon', 'CloudySunset',
'WetNoon', 'WetSunset', 'MidRainyNoon', 'MidRainSunset',
'WetCloudyNoon', 'WetCloudySunset', 'HardRainNoon',
'HardRainSunset', 'SoftRainNoon', 'SoftRainSunset'],
help='Weather preset')
argparser.add_argument('--out_folder', type=str, default='./sensor_data', help="Output folder")
argparser.add_argument('--nb_frames', type=int, default=300, help="Number of frames to record per route")
argparser.add_argument('--nb_passes', type=int, default=7, help="Number of passes per route")
argparser.add_argument('--freq_save', type=int, default=5, help="Frequency of saving data (in steps)")
argparser.add_argument('-np', action='store_true', help='Save data as numpy arrays instead of images')
argparser.add_argument('--begin', type=int, default=0, help='Begin at this episode (for resuming)')
args = argparser.parse_args()
main(args)
对上述代码的具体说明如下:
(1)命令行参数解析:通过argparse模块生成了一个命令行参数解析器argparser,并配置了大量与数据收集相关的各种选项。这些选项包括:
--world-port: 模拟器使用的端口编号,默认设置为WORLD_PORT。
--host: 设备IP地址或设备IP地址,默认值对应WORLD_HOST。
--map: 要加载的具体场景配置文件名,默认设置为TRAIN_MAP。
--weather: 模拟器中的天气模式设置,默认选择'ClearNoon';可选模式列表见帮助文档。
--out_folder: 数据输出文件夹路径,默认位置位于./sensor_data目录下。
--nb_frames: 每个轨迹(trajectory)捕获到的状态采样点数量,默认值设定为300个。
--nb_passes: 每个轨迹通过的关键点数量或穿越次数,默认设置为7次。
--freq_save: 定期数据保存间隔(单位是步长),默认设置每隔5步保存一次数据。
--np: 是否使用NumPy数组格式存储数据;当此标志设置时将优先使用该格式而非图像格式进行存储。
--begin: 数据恢复时使用的起始路线编号(episode ID),默认值设为0表示从头开始恢复数据收集过程。
(2)解析终端参数:利用Python的argparse模块提取终端参数,并将处理结果赋值给args变量中。
在执行数据收集任务时,在调用main(args)函数的过程中将解析后的命令行参数args传送给该函数。位于data.collect_data模块内的一次操作负责启动模拟器并收集与自动编码器训练相关的数据。
17.8.2 训练模型
生成Python脚本train_autoencoder.py, 主要负责训练自编码器(Autoencoder或AutoencoderSEM)。该脚本旨在将CARLA仿真环境中获取的图像数据进行特征提取与表示。所采用的Autoencoder是一种无监督学习算法,在降维的同时也能进行有效的特征提取。其核心目标在于实现输入数据的重建,并提取具有代表性的特征。该脚本不仅包含自编码器模型的训练逻辑, 还涉及相关数据集处理的过程及所需的数据预处理步骤。具体实现代码如下所示
def main(args):
os.makedirs(args.dirpath, exist_ok=True)
img_size = [int(x) for x in args.img_size.split('x')] if args.img_size != 'default' else None
if args.split:
with open(args.split, 'rb') as f:
split = pickle.load(f)
train = split['train']
val = split['val']
else:
with open(args.file, 'rb') as f:
data = pickle.load(f)
stratify = [d[0] for d in data]
# Split data stratify by folder (different weather conditions)
train, val = train_test_split(data, test_size=args.val_size, random_state=42,
shuffle=True, stratify=stratify)
#Save split
with open(args.dirpath + '/split.pkl', 'wb') as f:
pickle.dump({'train': train, 'val': val}, f)
normalize_output = False if args.model == 'AutoencoderSEM' else True
train_dataset = AutoencoderDataset(train[:100], img_size, args.norm_input, args.low_sem, args.use_img_out, normalize_output)
val_dataset = AutoencoderDataset(val[:100], img_size, args.norm_input, args.low_sem, args.use_img_out, normalize_output)
train_loader = DataLoader(train_dataset, batch_size=args.batch_size, shuffle=True)
val_loader = DataLoader(val_dataset, batch_size=args.batch_size*2, shuffle=False)
img_size = tuple(train_dataset[0][0].shape[1:]) if img_size is None else img_size
num_classes = 14 if args.low_sem else 29
if args.model == 'Autoencoder':
model = Autoencoder(input_size=img_size, emb_size=args.emb_size, lr=args.lr, weights=(0.8, 0.1, 0.1),
use_additional_data=args.additional_data, out_ch=4 if args.use_img_out else 1)
elif args.model == 'AutoencoderSEM':
model = AutoencoderSEM(input_size=img_size, emb_size=args.emb_size, lr=args.lr, weights=(0.8, 0.1, 0.1),
use_additional_data=args.additional_data, num_classes=num_classes)
elif args.model == 'VAE':
model = VAE(input_size=img_size, emb_size=args.emb_size, lr=args.lr,
out_ch=4 if args.use_img_out else 1)
else:
raise ValueError('Model not found')
trainer = pl.Trainer(callbacks=[pl.callbacks.ModelCheckpoint(dirpath=args.dirpath, monitor='val_loss', save_top_k=1),
pl.callbacks.LearningRateMonitor(logging_interval='epoch'),
pl.callbacks.ModelCheckpoint(dirpath=args.dirpath, filename="{epoch}")],
accelerator=args.device,
max_epochs=args.epochs,
default_root_dir=args.dirpath)
trainer.fit(model, train_loader, val_loader, ckpt_path=args.pretrained)
if __name__=='__main__':
parser = ArgumentParser()
parser.add_argument('--file', type=str, default=AE_DATASET_FILE, help='dataset file')
parser.add_argument('--val_size', type=float, default=AE_VAL_SIZE, help='validation size')
parser.add_argument('--img_size', type=str, default=AE_IMG_SIZE, help='image size')
parser.add_argument('--norm_input', type=bool, default=AE_NORM_INPUT, help='Normalize input image')
parser.add_argument('--emb_size', type=int, default=AE_EMB_SIZE, help='embedding size')
parser.add_argument('--batch_size', type=int, default=AE_BATCH_SIZE, help='batch size')
parser.add_argument('--epochs', type=int, default=AE_EPOCHS, help='number of epochs')
parser.add_argument('--lr', type=float, default=AE_LR, help='learning rate')
parser.add_argument('--device', type=str, default='auto', help='device', choices=['auto', 'gpu', 'cpu'])
parser.add_argument('--dirpath', type=str, default=AE_DIRPATH, help='directory path to save the model')
parser.add_argument('--low_sem', type=bool, default=AE_LOW_SEM, help='Use low resolution semantic segmentation (14 classes)')
parser.add_argument('--use_img_out', type=bool, default=AE_USE_IMG_AS_OUTPUT, help='Use image as output (not used if model is VAE)')
parser.add_argument('--model', type=str, default=AE_MODEL, help='model', choices=['Autoencoder', 'AutoencoderSEM', 'VAE'])
parser.add_argument('--additional_data', type=bool, default=AE_ADDITIONAL_DATA, help='Use additional data (not used if model is VAE)')
parser.add_argument('--pretrained', type=str, default=AE_PRETRAINED, help='pretrained model')
parser.add_argument('--split', type=str, default=AE_SPLIT, help='split file')
args = parser.parse_args()
main(args)
对上述代码的具体说明如下所示:
- 定义主函数main(),该函数接收来自命令行的参数作为输入,包括数据集文件路径、模型超参数以及训练超参数等关键信息。在函数体内首先根据输入参数自动生成输出目录,并依据数据集进行样本分类处理。随后建立训练与验证数据集,并配置相应的数据加载器对象。接着根据指定的超参数选择合适的自编码器模型(Autoencoder或VAE)。最后利用PyTorch Lightning库中的Trainer实例来启动模型训练过程。
- 解析命令行参数:通过ArgumentParser模块解析程序运行时所需的必要输入参数。
- 调用主函数:在程序入口处(即if name=='main':语句)会先解析命令行参数并调用主函数执行训练任务。
