基于多任务学习与注意力机制的MATLAB交通流量预测系统实现

📅 发布时间:2026/9/20 1:43:34
基于多任务学习与注意力机制的MATLAB交通流量预测系统实现
简介面向智能交通与深度学习交叉领域的研究者、工程师及研究生这是一份基于多任务学习MTL的交通流量预测MATLAB完整项目实例聚焦多路段、多步长联合预测涵盖数据预处理、滑窗切片、邻域聚合、轻量自注意力、不确定性加权损失及动态训练策略可服务于短时流量预测、信号灯优化与拥堵预警等场景。压缩包内为1个docx文档大小仅66KB以文档形式承载完整程序、GUI设计与代码详解目录结构清晰便于按模块复现。该资源目前已有111人学习浏览适合具备一定MATLAB与机器学习基础、希望掌握时空序列多任务建模及工程化部署方法的读者。通过调试参数与观察可视化结果可深入理解共享编码器与任务专属头架构并快速迁移其中的模块化代码框架与部署思路。1. 交通流量预测中的多任务困境与注意力机制的价值交通流量预测从来不是一个单输出问题。现实中一个路口或路段的预测往往同时要回答“未来15分钟流量是多少”和“未来1小时会不会拥堵”这两个高度相关但性质不同的问题。更常见的场景是同一套模型要同时预测多个相邻断面的流量因为单断面预测即使准确也难以为信号灯协同控制提供完整输入。用独立模型分别处理这些任务不仅参数冗余还丢掉了任务之间的共享特征预测在非平稳时段特别容易漂移。这正是多任务学习MTL在交通流量预测中变得热门的原因——用硬参数共享或软参数共享把相关任务绑进同一个网络让梯度在任务间互相“加权”。但MTL有一个明显代价多个任务对共享层的特征需求并不总是一致极端情况下会互相干扰导致该学陡峭变化的没学到。解决办法就是在共享特征和任务输出之间插入注意力机制让网络自己决定每个任务该提取哪一段时空特征。这套组合在近期论文里已经大量验证但绝大多数开源的实现是PyTorch或TensorFlowMATLAB环境下能跑通的完整参考非常少。本文要做的就是直接补上这个空档在MATLAB中用深度学习工具箱Deep Learning Toolbox实现一个基于多任务学习与注意力机制的交通流量预测系统包含可运行的完整MATLAB代码、训练流程、GUI界面设计思路和参数调优方法。内容按“设计原理 → MATLAB实现 → 网络训练与评估 → GUI封装 → 注意力可视化验证”这条线走完。2. 多任务学习与注意力机制在流量预测中的设计原理2.1 交通流量预测为什么需要多任务学习交通流量数据天然存在多尺度、多相关性的特征。以城市主干路为例某个断面的流量不仅与自身历史流量相关还受上下游断面流量、时段特征早高峰、晚高峰、天气和事件信息影响。单任务模型预测未来多个时间步的流量相当于让一个输出头承担所有预测压力模型必须在一组特征里同时编码“近期的突变”和“长期的趋势”这对有限容量的网络来说很难兼顾。多任务学习用统一的共享网络提取基础特征再针对不同任务分支出不同的输出头。预测系统的典型任务组合有下面这些。任务名输出目标损失函数任务类型主任务多步流量预测未来6个时间步流量均方误差MSE或Huber损失回归辅助任务1拥堵状态分级畅通/缓行/拥堵三分类交叉熵损失分类辅助任务2流量变化趋势上升/平稳/下降三分类交叉熵损失分类辅助任务3峰值时段判定未来是否出现流量峰值二分类损失分类辅助任务在损失函数中以加权形式参与梯度回传。训练初期辅助任务帮助共享层快速学到有区分度的交通特征训练后期主任务主导精细调优。这种方式比单纯增大主任务网络容量更稳定尤其在小样本场景下能显著降低过拟合。2.2 注意力机制如何解决多任务共享特征冲突多任务模型的问题在于不同任务对特征的要求并不总是一致。回归主任务需要保留连续、平滑的流量细节而拥堵状态分类需要的是“可区分”的离散特征。共享层生成的同一组特征图直接输入不同任务的输出层必然造成信息竞争。注意力机制在这里承担的就是一个特征重标定的角色。常用的方案有两种。通道注意力如SENet对特征图的每个通道计算权重保留与当前任务相关的通道抑制无关通道时序注意力则在时间步维度上计算权重让模型聚焦于与预测目标最相关的历史时间窗口。在实际实现中我更推荐两者结合但先不引入过多结构先从时序注意力开始再逐步叠加通道注意力逐项看指标变化。时序注意力层的计算流程是把LSTM输出的每个时间步的隐状态h_t通过一个全连接层映射为标量分数再经softmax归一化为权重最后对时间步做加权求和。公式表达为e_t v^T tanh(W_h h_t b) a_t softmax(e_t) c Σ a_t h_t其中c是注意力加权后的上下文向量代替LSTM最后一个时间步的隐状态送到任务输出层。对多任务结构来说每个任务分支可以各有自己的注意力参数这样主任务可以聚焦于最近几个时间步拥堵分类可以聚焦于整个时间窗口的累积状态特征冲突问题在机制上得到缓解。2.3 网络结构总体设计硬参数共享的时空多任务架构常见做法是采用硬参数共享结构即底层共享顶层任务分支独立。网络整体结构如下。2.3.1 输入层结构输入张量维度为 [N, T, F]N表示样本数T表示时间窗口长度例如12个时间步即过去1小时如果步长为5分钟F表示每个时间步的特征数包括目标断面历史流量、上游流量、下游流量、时段编码等。MATLAB中组织数据时维度顺序常写成 [T, F, 1, N]即第四维是样本维。2.3.2 共享特征提取层共享部分采用卷积加LSTM的组合。先用一维卷积捕捉断面间的空间相关性再用LSTM捕捉时间依赖。一维卷积的核大小可以解释为同时考虑多少个相邻断面比如kernel_size3表示提取左右各一个邻居的信息。2.3.3 任务分支层任务分支从LSTM输出的时序特征中各自提取上下文向量。每个分支包含一个注意力模块、一个全连接层和一个输出层。主任务输出未来6个时间步的回归值辅助任务输出类别概率。这种设计的优点是任务数量扩展容易新增一个预测任务只需复制分支层并改输出维度。硬参数共享让整体参数量接近单任务模型的1.2到1.5倍但任务数达到3个以上时效果和效率都明显优于单任务模型。3. MATLAB实现MTL与注意力机制的核心代码3.1 数据准备与预处理流程使用MATLAB进行交通流量预测数据预处理占据整个工作量的40%以上。要处理的关键点包括缺失值填充、异常值平滑、归一化、序列样本生成。以某断面15分钟粒度的流量数据为例原始数据是一个向量长度假设为L20000个时间点。先做中值滤波去除传感器毛刺和瞬时丢包造成的大幅跳变。然后用滑动窗口生成样本窗口长度T12预测步长H6。下面这段代码展示数据加载和样本生成的完整流程。%% 数据加载与样本生成 function [XTrain, YTrainRes, YTrainCls, XTest, YTestRes] prepareTrafficData(filePath) % 读取CSV格式的流量数据列格式为: timestamp, flow, upstream_flow, downstream_flow rawData readmatrix(filePath); flow rawData(:, 2); upFlow rawData(:, 3); downFlow rawData(:, 4); % 缺失值线性插值 for i 1:length(flow) if isnan(flow(i)) flow(i) (flow(max(i-1,1)) flow(min(i1, length(flow)))) / 2; end end % 中值滤波去除毛刺窗口大小为5 flowSmooth medfilt1(flow, 5); % 构造特征矩阵目标断面、上下游断面、时间戳编码小时正弦余弦 hourOfDay mod(1:length(flow), 96); % 十五分钟粒度一天96个点 timeFeat [sin(2*pi*hourOfDay/96), cos(2*pi*hourOfDay/96)]; features [flowSmooth, upFlow, downFlow, timeFeat]; % 共5个特征 % 归一化按列操作 mu mean(features); sigma std(features); featuresNorm (features - mu) ./ (sigma 1e-8); % 滑动窗口生成样本 T 12; % 回看窗口长度 H 6; % 预测步长 totalSamples length(flow) - T - H 1; X zeros(T, size(featuresNorm,2), 1, totalSamples); YRes zeros(totalSamples, H); YCls zeros(totalSamples, 3); for i 1:totalSamples X(:, :, 1, i) featuresNorm(i:iT-1, :); futureFlow flow(iT:iTH-1); YRes(i, :) futureFlow; % 构造拥堵状态标签平均流量阈值法 avgFlow mean(futureFlow); if avgFlow 30 YCls(i, :) [1 0 0]; % 畅通 elseif avgFlow 60 YCls(i, :) [0 1 0]; % 缓行 else YCls(i, :) [0 0 1]; % 拥堵 end end % 按8:2划分训练集和测试集 splitIdx round(totalSamples * 0.8); XTrain X(:, :, :, 1:splitIdx); YTrainRes YRes(1:splitIdx, :); YTrainCls YCls(1:splitIdx, :); XTest X(:, :, :, splitIdx1:end); YTestRes YRes(splitIdx1:end, :); end归一化参数mu和sigma从训练集计算后用于测试集这个细节需要特别注意。代码中的标签构造采用绝对阈值实际应用中应根据具体路段的流量分布统计出分位数再定阈值。3.2 定义多任务残差网络结构MATLAB实现网络结构有两条路线。路线一是使用Deep Network Designer图形化搭建路线二是用dlnetwork以程序化方式定义网络支持自定义层、多输入输出和自定义训练循环。多任务学习必须走路线二因为标准trainNetwork函数要求单一损失函数。下面是构建网络的函数。%% 构建多任务注意力网络dlnetwork方式 function net buildMTLAttentionNetwork(inputSize, numTasks, hiddenSize) % inputSize: 特征维度 % numTasks: 任务数量主任务辅助任务 % hiddenSize: LSTM隐藏单元数 layers [ featureInputLayer(inputSize, Normalization, none, Name, input) % 一维卷积提取空间特征 convolution1dLayer(3, 32, Padding, same, Name, conv1) reluLayer(Name, relu1) convolution1dLayer(3, 32, Padding, same, Name, conv2) reluLayer(Name, relu2) % LSTM层提取时序特征 lstmLayer(hiddenSize, OutputMode, sequence, Name, lstm) % 全连接映射到更高维空间 fullyConnectedLayer(64, Name, fc_shared) reluLayer(Name, relu_shared) ]; lgraph layerGraph(layers); net dlnetwork(lgraph); end注意inputSize是单个时间步的特征维度LSTM层的OutputMode设置为sequence而不是last这样后面才能接注意力机制。dlnetwork在MATLAB R2021b及以后版本中支持直接作为网络容器使用包含层图的结构。3.3 实现通道与空间注意力层MATLAB实现自定义层有两种方式。一是继承nnet.layer.Layer并定义predict和backward方法二是使用更轻量的方式在训练循环中直接用dlarray和深度学习函数计算注意力不封装成独立层。这里采用第二种方式更灵活调试成本低。下面是时序注意力计算函数。%% 时序注意力机制实现 function [context, attWeights] temporalAttention(h, W, b, v) % h: LSTM输出序列维度 [hiddenSize, T, 1, N] % W: 注意力权重矩阵 [attentionSize, hiddenSize] % b: 偏置 [attentionSize, 1] % v: 注意力向量 [attentionSize, 1] [hiddenSize, T, ~, N] size(h); % 把序列维度展平方便矩阵运算 hReshaped reshape(h, hiddenSize, T*N); % 对每个时间步计算注意力分数 temp W * hReshaped b; % [attentionSize, T*N] temp tanh(temp); scores v * temp; % [1, T*N] scores reshape(scores, T, N); % softmax归一化得到注意力权重 attWeights softmax(scores, 1); % 沿时间维归一化 % 加权求和得到上下文向量 hReshaped2 reshape(h, hiddenSize, T*N); attReshaped reshape(attWeights, 1, T*N); context hReshaped2 * attReshaped; % [hiddenSize, N] context reshape(context, hiddenSize, 1, 1, N); end这段代码中softmax沿时间维度归一化上下文向量是LSTM所有时间步隐状态的加权求和。注意力权重attWeights在训练后可以提取出来做可视化观察模型关注的历史时间窗口。3.4 自定义训练循环与多任务损失函数多任务学习必须使用自定义训练循环原因是需要在每个iteration分别计算不同任务的损失并组合。主任务使用Huber损失对异常流量值更鲁棒辅助分类任务使用交叉熵损失组合方式为加权和。下面给出完整的训练循环核心代码。%% 多任务训练循环 function [net, trainInfo] trainMTLModel(net, XTrain, YTrainRes, YTrainCls, options, classLabels) numEpochs options.NumEpochs; miniBatchSize options.MiniBatchSize; initialLearnRate options.InitialLearnRate; learnRateDropFactor 0.5; learnRateDropPeriod 15; % 获取网络可训练参数 params net.Learnables; % 初始化Adam优化器状态 averageGrad []; averageSqGrad []; numObservations size(XTrain, 4); numIterationsPerEpoch floor(numObservations / miniBatchSize); % 损失权重 lambdaMain 1.0; % 主任务权重 lambdaCls 0.3; % 拥堵分类辅助任务权重 lambdaTrend 0.2; % 趋势分类辅助任务权重 % 创建趋势标签从回归标签导出 YTrainTrend createTrendLabels(YTrainRes); for epoch 1:numEpochs % 每个epoch打乱数据 idx randperm(numObservations); XTrainShuffled XTrain(:, :, :, idx); YTrainResShuffled YTrainRes(idx, :); YTrainClsShuffled YTrainCls(idx, :); YTrainTrendShuffled YTrainTrend(idx, :); % 计算当前epoch的学习率 if mod(epoch, learnRateDropPeriod) 0 initialLearnRate initialLearnRate * learnRateDropFactor; end for i 1:numIterationsPerEpoch batchIdx (i-1)*miniBatchSize1 : i*miniBatchSize; % 构造mini-batch dlarray XBatch XTrainShuffled(:, :, :, batchIdx); XBatch dlarray(XBatch, SSCB); YResBatch YTrainResShuffled(batchIdx, :); YClsBatch YTrainClsShuffled(batchIdx, :); YTrendBatch YTrainTrendShuffled(batchIdx, :); % 前向传播和损失计算 [loss, grads] dlfeval(modelLoss, net, XBatch, ... YResBatch, YClsBatch, YTrendBatch, ... lambdaMain, lambdaCls, lambdaTrend); % Adam更新参数 [params, averageGrad, averageSqGrad] adamupdate(params, grads, ... averageGrad, averageSqGrad, i, initialLearnRate); net.Learnables params; end % 每个epoch结束后评估验证集损失 if mod(epoch, 5) 0 fprintf(Epoch %d, Loss: %.4f\n, epoch, extractdata(loss)); end end trainInfo struct(FinalLoss, extractdata(loss)); end %% 多任务损失函数 function [loss, grads] modelLoss(net, X, YRes, YCls, YTrend, lambdaMain, lambdaCls, lambdaTrend) % 前向传播共享层 LSTM features forward(net, X); % features 维度 [featureDim, T, 1, N]需要解包LSTM输出 % 分离各层输出这里以lstm输出为例实际需要从中间层提取 dlnet net; % 获取LSTM层的输出 lstmOut predict(dlnet, X, Outputs, lstm); % 应用时序注意力 W dlarray(randn(32, size(lstmOut,1)) * 0.01); b dlarray(zeros(32, 1)); v dlarray(randn(32, 1) * 0.01); [contextVec, ~] temporalAttention(lstmOut, W, b, v); % 主任务输出层回归预测未来6步 mainOut fullyconnect(contextVec, dlarray(randn(6, size(contextVec,1)) * 0.01), dlarray(zeros(6, 1))); mainLoss huberLoss(mainOut, YRes); % 拥堵分类任务 clsOut fullyconnect(contextVec, dlarray(randn(3, size(contextVec,1)) * 0.01), dlarray(zeros(3,1))); clsLoss crossentropy(clsOut, YCls, TargetCategories, independent); % 趋势分类任务 trendOut fullyconnect(contextVec, dlarray(randn(3, size(contextVec,1)) * 0.01), dlarray(zeros(3,1))); trendLoss crossentropy(trendOut, YTrend, TargetCategories, independent); % 加权组合损失 loss lambdaMain * mainLoss lambdaCls * clsLoss lambdaTrend * trendLoss; % 自动微分求梯度 grads dlgradient(loss, net.Learnables); endmodelLoss函数中我刻意用随机初始化权重展示结构真实训练时需要把任务分支的权重纳入net.Learnables统一管理。MATLAB的dlgradient要求损失必须是可微的交叉熵对softmax输出可微Huber损失在|delta|1时使用线性项可微性没问题。多任务梯度回传会自动计算每个分支对共享层的梯度之和等价于梯度加权。这里提到了交叉熵作为辅助任务损失的一部分是分类任务的常见选择。4. 网络训练评估与GUI可视化系统设计4.1 训练参数与超参数设置建议超参数设置直接决定多任务模型训练的稳定性。以下参数组合是在交通流量预测场景下比较稳妥的起步值。超参数建议值说明时间窗口T123小时15分钟粒度太短丢失周期信息太长引入噪声预测步长H61.5小时交通管理通常关注未来1-2小时LSTM隐藏单元64到128超过128容易过拟合且训练慢注意力维度32通常是hiddenSize的1/4到1/2MiniBatchSize128到256取决于GPU显存MATLAB默认为128初始学习率0.001Adam优化器建议0.001起步学习率衰减每15轮减半后期精细收敛损失权重lambda1.0 / 0.3 / 0.2主任务权重最大辅助任务按需调节训练时监控的关键指标是验证集主任务MAPE。如果MAPE不降反升而训练集下降说明过拟合应该增大L2正则化强度或减少LSTM单元数。如果主任务损失和辅助任务损失交替上升下降说明任务间梯度冲突可以把辅助任务权重各调低一半。4.2 使用MATLAB App Designer构建预测系统GUIMATLAB中构建GUI的常见做法是使用App Designer而不是传统的guide。App Designer生成的代码可读性更高尤其适合把训练好的模型封装成交互式预测工具。GUI的核心功能模块包括加载模型文件、选择数据时间段、点击预测、显示预测结果和注意力热力图。下面给出一个简化版的设计思路和核心回调代码。classdef TrafficFlowPredictorApp matlab.apps.AppBase properties (Access public) UIFigure matlab.ui.Figure LoadModelBtn matlab.ui.control.Button PredictBtn matlab.ui.control.Button ResultAxes matlab.ui.control.UIAxes AttAxes matlab.ui.control.UIAxes DatePicker matlab.ui.control.DatePicker model dlnetwork % 训练好的模型 XData double % 输入数据缓存 end methods (Access private) function onLoadModel(app, ~) [file, path] uigetfile(*.mat, 选择训练好的模型文件); if file 0, return; end data load(fullfile(path, file)); app.model data.net; % 网络 app.XData data.XTest; % 测试数据 uialert(app.UIFigure, 模型加载成功, 提示); end function onPredict(app, ~) % 取最近12个时间步的数据 x app.XData(:, :, :, end); x dlarray(x, SSCB); % 前向传播 features predict(app.model, x); % 提取LSTM输出并计算注意力 lstmOut predict(app.model, x, Outputs, lstm); % 应用注意力参数从模型文件中加载 [~, attW] temporalAttention(lstmOut, app.W, app.b, app.v); % 绘制预测结果和注意力热力图 plotPrediction(app, attW); end end end回调函数中模型文件的保存格式需要提前约定训练完成后用save(trainedMTLModel.mat, net, W, b, v, XTest, YTestRes)保存。4.3 模型部署与导出MATLAB代码模型训练完成后部署方式有两种。第一种是直接把训练好的dlnetwork保存为.mat文件后续在MATLAB环境中加载使用适合研究和算法验证场景。第二种是导出为C代码或ONNX格式适合集成到信号控制系统中。MATLAB的exportONNXNetwork函数支持将dlnetwork导出为ONNX但包含自定义层时需要额外处理我一般在导出前把注意力层手动展开为标准层。如果是部署到实时系统需要特别注意输入数据预处理方式与训练时的完全一致包括归一化的mu/sigma和窗口滑动步长。GUI中用到的模型文件要附带一个README说明各字段的含义这个格式统一后换新模型也不用改GUI代码。5. 注意力权重可视化验证模型学到了什么注意力机制相比传统LSTM最大的优势是可以解释性验证。训练完成后把测试集样本输入模型提取注意力权重矩阵画成热力图观察模型在不同交通状态下关注的时间模式。可视化代码实现如下。%% 注意力权重可视化 function visualizeAttention(net, W, b, v, XTest, YTestRes, sampleIdx) % 选取一个测试样本 x XTest(:, :, :, sampleIdx); x dlarray(x, SSCB); % 前向传播获取LSTM输出 lstmOut predict(net, x, Outputs, lstm); lstmOut extractdata(lstmOut); % 计算注意力权重 [~, attW] temporalAttention(dlarray(lstmOut), ... dlarray(W), dlarray(b), dlarray(v)); attW extractdata(attW); % 绘制注意力权重随时间的分布 figure(Name, 注意力可视化, Position, [100 100 900 400]); subplot(2, 1, 1); bar(1:12, attW, FaceColor, [0.2 0.4 0.8]); xlabel(时间步过去12个点间隔15分钟); ylabel(注意力权重); title(时序注意力权重分布); % 绘制真实流量和模型注意力叠加图 subplot(2, 1, 2); trueFlow YTestRes(sampleIdx, :); plot(13:18, trueFlow, -o, LineWidth, 1.5); hold on; % 用颜色深浅表示注意力强的历史时间步 for t 1:12 c [attW(t)/max(attW), 0.3, 0.5]; plot(t, lstmOut(1, t, 1, 1), o, Color, c, MarkerFaceColor, c); end legend({未来真实流量, 历史LSTM状态颜色越深注意力越高}); xlabel(时间步); ylabel(值); end可视化结果通常能观察到明显的模式在拥堵形成阶段注意力集中在最近3到5个时间步因为拥堵是持续累积的结果最近的数据携带最丰富的状态信息在平峰阶段注意力分布相对均匀模型需要对更长时间窗口做平均。如果发现注意力权重几乎完全集中在某一个时间步权重超过0.6说明模型退化为只看单点信息需要增大注意力维度或增加正则化。另一种验证方法是把注意力权重替换为均匀分布对比预测误差的变化。如果MAPE上升超过5%说明注意力机制确实在起作用如果几乎不变说明注意力模块没有学到有效模式通常需要增大注意力维度或改变特征组合。这种可视化在论文中可以直接作为说明模型有效性的证据。多任务学习和注意力机制的实际效果最终还是要在自己的路段数据上对比单任务基线才能确认。本文还有配套的精品资源点击获取