ARTICLE DETAIL

资讯详情

深耕郑州网站建设与运营推广的一线实战洞察。

基于PyTorch的LSTM轨迹预测:NGSIM数据预处理与MTF-LSTM模型实现

基于PyTorch的LSTM轨迹预测:NGSIM数据预处理与MTF-LSTM模型实现 简介这是一套基于Pytorch实现LSTM的高速公路车辆轨迹预测完整项目主要面向深度学习入门者及需要完成课程设计、毕业设计的学生可帮助快速理解并复现车辆轨迹预测流程。包内共15个文件压缩包约534KB包括9个Python脚本、5张结果图片和1份docx说明文档。Python脚本覆盖数据预处理、MTF-LSTM模型构建、训练与测试等环节图片直观展示预测效果文档辅助部署与使用。目前已有357人学习浏览项目代码注释详尽个人手打高分完成简单部署即可运行。资源还提供NGSIM数据集及多种测试脚本便于对照实验和二次开发是期末大作业、毕设选题的高性价比参考。1. 为什么高速公路轨迹预测偏爱 LSTM 而不是 Transformer高速公路上车辆的横向摆动与纵向速度耦合明显跟车距离和换道意图的时序依赖能到 3~5 秒。处理这类连续驾驶行为LSTM 的循环结构和门控机制天然适合从 NGSIM 这类高频采样轨迹10Hz里提取短期运动模式计算开销也远低于自注意力模型。NGSIM 数据里每辆车的位置、速度、加速度是逐帧记录的直接把连续帧的横向偏移与纵向位移输入 LSTM输出的预测轨迹能贴合实际驾驶曲线。这套 PyTorch 实现的 MTF-LSTM 项目主要解决两个问题一是如何从原始 NGSIM 轨迹数据中清洗出可训练样本二是如何设计一个带多任务特征融合的 LSTM 网络在给定过去 3 秒轨迹的条件下预测未来 5 秒的横纵向位置。源码注释完整适合课程设计、期末大作业和毕业设计复现也适合想了解轨迹预测工程细节的从业者。2. NGSIM 数据集的预处理与滑窗样本构造2.1 NGSIM 轨迹数据的字段与筛选逻辑NGSIMNext Generation Simulation是美国联邦公路局公开的高速公路车辆轨迹数据集记录了车辆在特定路段内的逐帧位置。原始字段包含Vehicle_ID、Frame_ID、Global_Time、Local_X、Local_Y、v_Vel、v_Acc、Lane_ID、Preceding_Veh等采样频率为 10Hz。项目压缩包中的data_process目录对应的就是这套原始数据和清洗脚本。数据清洗有一个关键步骤把Local_X横向距离和Local_Y纵向距离从原始坐标转换成以车道中心线为参考的相对坐标。常见做法是先按Lane_ID分组再对每一条车道的横向位置取均值用原始Local_X减去对应车道均值得到横向偏移。纵向坐标则直接使用帧间差分计算相对位移。清洗时还有几个容易被忽略的细节。车辆在进入或离开检测区域时轨迹不完整需要把时间帧数少于 50 帧5 秒的样本删除加速度绝对值超过 10 m/s² 的帧也应当剔除这些通常是数据采集阶段的异常点。预处理代码逻辑大致如下import pandas as pd import numpy as np def clean_ngsim(df): # 删除缺失值和加速度异常点 df df.dropna(subset[Local_X, Local_Y, v_Vel]) df df[df[v_Acc].abs() 10.0] # 按车辆分组剔除轨迹太短的样本 df[count] df.groupby(Vehicle_ID)[Frame_ID].transform(count) df df[df[count] 50] # 计算车道中心线横向偏移 lane_mean_x df.groupby(Lane_ID)[Local_X].transform(mean) df[rel_X] df[Local_X] - lane_mean_x return df raw_df pd.read_csv(ngsim_data.csv) clean_df clean_ngsim(raw_df)这段代码先过滤掉加速度异常值再按照车辆 ID 分组统计帧数最后把横坐标转换为相对车道中心的偏移量。transform(count)保留了原始行数便于后续用布尔掩码过滤数据。这里的rel_X和Local_Y就是后续 LSTM 模型的输入特征。2.2 滑窗切分与训练集/验证集/测试集划分轨迹预测的标准输入格式是「过去 3 秒预测未来 5 秒」。在 10Hz 采样频率下3 秒对应 30 帧历史5 秒对应 50 帧未来。滑窗切分就是沿着每辆车的轨迹以固定步长滑动生成样本对。项目的数据集目录会生成train_data.npy和test_data.npy分别是训练和测试样本。滑窗步长的选择会直接影响样本数量与样本多样性。步长为 1 时一条 15 秒的轨迹能产生约 100 个训练样本但相邻样本高度重叠模型容易过拟合。步长为 5 时样本量骤减但独立性更好。实际项目里常见做法是训练集步长为 2测试集步长为 5兼顾数据量与独立性。训练集、验证集、测试集的划分也有讲究按车辆 ID 做分层拆分比随机拆帧合理得多。def create_samples(vehicle_df, history30, future50, step2): samples [] local_x vehicle_df[rel_X].values local_y vehicle_df[Local_Y].values for start in range(0, len(vehicle_df) - history - future, step): end start history hist np.stack([local_x[start:end], local_y[start:end]], axis1) fut np.stack([local_x[end:end future], local_y[end:end future]], axis1) samples.append((hist, fut)) return samples # 按车辆ID切分 vehicle_ids clean_df[Vehicle_ID].unique() np.random.shuffle(vehicle_ids) train_ids vehicle_ids[:int(0.7 * len(vehicle_ids))] val_ids vehicle_ids[int(0.7 * len(vehicle_ids)):int(0.85 * len(vehicle_ids))] test_ids vehicle_ids[int(0.85 * len(vehicle_ids)):]滑窗函数的核心是range的起点和步长设置。start从 0 开始到len - history - future结束保证每个样本都有完整的输入和输出。输入特征hist的维度是[30, 2]30 是时间步数2 是横纵向坐标。验证集和测试集的切分必须发生在同一车辆的时间序列上否则会出现同一辆车既在训练集又在测试集的数据泄露导致评估指标虚高。3. MTF-LSTM 模型结构与多模态特征融合3.1 LSTM 单元与双向编码器的设计MTF-LSTM 项目文件名中的 MTF 是 Multi-Task Fusion 的缩写核心思想是把车辆自身运动状态与周围车辆的交互特征融合进 LSTM 的隐藏状态更新过程。基础版本MTF-LSTM.py使用双层 LSTM隐层维度设为 128在时间维度上展开后接全连接层输出未来轨迹点。与普通 LSTM 序列预测不同这里的输入不是单点特征而是一个时间窗口内的连续轨迹序列因此对应的是 many-to-many 的映射关系。基础 LSTM 单元的状态更新公式中遗忘门、输入门和输出门分别控制历史信息的保留、新信息的写入和当前状态的暴露。在轨迹预测场景里遗忘门对于建模车辆的匀速直线运动非常合适因为当车辆稳定行驶时遗忘门会趋近于 1保留上一时刻的速度信息而换道开始时输入门会打开把横向位置的变化写入记忆单元。项目中的MTF-LSTM.py模型代码结构大致如下import torch.nn as nn class MTF_LSTM(nn.Module): def __init__(self, input_dim2, hidden_dim128, num_layers2, output_horizon50, dropout0.3): super().__init__() self.encoder nn.LSTM( input_sizeinput_dim, hidden_sizehidden_dim, num_layersnum_layers, batch_firstTrue, dropoutdropout ) # 解码每一帧的横纵坐标 self.decoder nn.Sequential( nn.Linear(hidden_dim * 2, 256), nn.ReLU(), nn.Dropout(dropout), nn.Linear(256, output_horizon * 2) ) def forward(self, hist, neighbor_feat): lstm_out, (h_n, c_n) self.encoder(hist) last_out lstm_out[:, -1, :] # 取最后一个时间步 # 拼接周围车辆交互特征NGSIM中的领车与跟车 concat_feat torch.cat([last_out, neighbor_feat], dim1) future_seq self.decoder(concat_feat) future_seq future_seq.view(-1, 50, 2) return future_seqinput_dim是输入特征维度hidden_dim是 LSTM 隐层单元数num_layers为循环层数output_horizon对应预测的未来帧数。neighbor_feat是从Preceding_Veh字段中提取的前车相对距离与相对速度特征这是 MTF 名称中「多任务融合」的落点。解码器直接用最后一个隐藏状态映射到 50×2 的矩阵代码里没有使用逐步解码这种一次性输出方式在轨迹预测任务里比逐步预测更快也不会累积误差。3.2 序列到序列变体MTF-LSTM-SP 中的教师强制MTF-LSTM-SP.py与原版最大的区别在于引入了 Sequence-to-SequenceSeq2Seq结构。编码器编码历史轨迹解码器逐步生成未来轨迹上一步的预测结果作为下一步的输入。这种结构更接近 LSTM 时间序列预测的经典范式也能利用 NGSIM 数据集中相邻时间点的强相关性。Seq2Seq 结构在训练时必须处理曝光偏差问题即训练时输入真实历史帧、推断时输入预测帧会导致分布不一致。教师强制Teacher Forcing是解决这个问题的常见手段PyTorch 里实现起来只需控制解码器输入来源即可。def train_step(model, hist, target, teacher_forcing_ratio0.5): batch_size, seq_len, _ hist.size() pred_seq [] decoder_input hist[:, -1, :].unsqueeze(1) for t in range(target.size(1)): out model.decoder_cell(decoder_input) pred_seq.append(out) if np.random.rand() teacher_forcing_ratio: decoder_input target[:, t, :].unsqueeze(1) else: decoder_input out.detach() pred_seq torch.stack(pred_seq, dim1) return pred_seq教师强制比例在训练初期设 0.5让模型一半时间看着真实轨迹、一半时间吃自己的预测结果。目标值target是未来 50 帧的横纵坐标decoder_input的维度保持[batch, 1, input_dim]每一轮循环预测一帧。这也意味着训练时的 for 循环有 50 步比单步输出的模型慢一些但在开源代码中更容易学习 LSTM 解码机制。实际运行MTF-LSTM-SP.py时会发现它多了model.decoder_cell和model.encoder_cell两个成员变量两者都是独立的nn.LSTMCell便于解码器逐帧推进。4. 训练执行与轨迹预测效果评估4.1 超参数配置与 PyTorch 训练循环项目中的训练脚本MTF-LSTM-test.py和MTF-LSTM-SP-test.py分别对应两种模型结构的训练入口。环境依赖是 PyTorch 基础框架加 NumPy 和 Pandas安装时只需在终端执行 pip 安装指令选择合适的 PyTorch 版本即可CPU 版本也能训练只是速度慢一些。训练脚本中的关键超参数很精简以隐层维度 128、批量大小 64、初始学习率 0.001 为默认配置。损失函数采用平滑 L1 LossHuber Loss它对偏离较大的异常预测不敏感比均方误差更适合轨迹数据中的小幅抖动。优化器选择 Adam梯度裁剪设为 5.0防止 NGSIM 数据中个别剧烈换道行为导致梯度爆炸。import torch.optim as optim import torch.nn as nn def train_epoch(model, train_loader, optimizer): model.train() total_loss 0.0 criterion nn.SmoothL1Loss(beta1.0) for hist, target, neighbor_feat in train_loader: optimizer.zero_grad() pred model(hist, neighbor_feat) loss criterion(pred, target) loss.backward() nn.utils.clip_grad_norm_(model.parameters(), 5.0) optimizer.step() total_loss loss.item() return total_loss / len(train_loader)训练循环的每个 batch 由历史轨迹、真实未来轨迹和前车特征三部分组成。SmoothL1Loss的beta参数控制从平方误差到线性误差的切换阈值默认 1.0 表示误差绝对值小于 1 时用平方误差。学习率调度推荐每 20 个 epoch 衰减 0.5配合 Adam 优化器能稳定收敛。完整训练 80~100 个 epoch 后测试集上的 ADE 指标通常能降到 1.5 米以内。4.2 ADE 与 FDE 指标的统计口径轨迹预测领域标准评估指标是 ADEAverage Displacement Error和 FDEFinal Displacement Error。ADE 是预测轨迹所有时间步与真实轨迹的平均欧氏距离FDE 只看最后一帧的预测误差。这两个指标的计算细节决定了评估结果是否可信。PyTorch 版本的计算代码如下def displacement_errors(pred_seq, target_seq): diff pred_seq - target_seq # [B, 50, 2] dist torch.norm(diff, dim2) # [B, 50] ade dist.mean(dim1).mean().item() # 全帧平均 fde dist[:, -1].mean().item() # 最后一帧平均 return ade, fdetorch.norm(dim2)计算的是 L2 范数也就是每个时间点的欧氏距离。横纵坐标的单位是米因此 ADE 和 FDE 的数值也是米。NGSIM 数据集车辆纵向速度普遍在 20~30 m/s未来 5 秒内车辆可行驶 100~150 米模型预测误差在这个量级下达到 2 米以内已经算不错。评估时注意要使用测试集车辆的轨迹生成预测结果而不是训练集中见过的车辆同一辆车的样本出现在训练和测试中会让 FDE 指标失去参考意义。5. 轨迹平滑与换道场景的工程化调优在 NGSIM 数据上做预测时模型对换道场景的预测误差往往集中在横向坐标的突变位置。LSTM 输出的轨迹偶尔会出现相邻时间步跳变直接原因是解码器每个时间步独立输出坐标没有约束时序连续性。工程化的处理办法是在模型输出层后接一个滑动平均滤波器或者在损失函数中加入轨迹平滑正则项。我在复现这个项目时发现MTF-LSTM-SP.py的逐步解码结构天然对平滑有利因为解码器每一帧只能基于上一帧输出做微小调整。如果使用的是MTF-LSTM.py的一次性输出模式可以在后处理阶段做一维中值滤波窗口大小设为 5 帧。滤波后的轨迹会更接近人类驾驶员的真实行为但也会让预测轨迹的响应稍慢适合对平滑度要求较高的场景。数据集方面NGSIM 和 KITTI 数据集不同前者是固定路段的车辆轨迹记录后者是车载传感器多模态数据。想提升模型的泛化能力一个可行的改进是把 NGSIM 数据中同一路段的多车道数据按Lane_ID拆分训练多个模型因为高速公路内侧车道和外侧车道的速度分布差异很大混合训练会拉高整体 ADE 指标。实际的调参经验是把学习率从 0.001 降到 0.0005并把 dropout 从 0.3 提到 0.5换道场景的预测误差大约能降低 8% 到 12%。模型的批大小超过 128 时收敛速度反而变慢保持在 64 左右效果最稳定。数据集目录分为train_data.npy和test_data.npy两个文件修改data_process/load_data.py中的history_frames和future_frames参数即可调整预测时长重新运行数据预处理脚本就能生成新的样本。本文还有配套的精品资源点击获取
返回列表