MATLAB实现TCN时间卷积网络多输入回归预测与调优
2026/9/13 16:48:41 网站建设 项目流程

简介:MATLAB实现的时间卷积网络(TCN)多输入回归预测完整源码及配套数据,面向需要处理多特征回归预测任务的工程师、科研人员和MATLAB学习者。数据为7个输入特征映射1个输出变量,可应用于风力发电、负荷预测等典型场景;程序基于MATLAB 2021b及以上版本编写,并针对版本兼容性给出提示。压缩包共10个文件,含2个m源程序、1个xlsx数据集、1个docx说明文档和6张网络结构与预测效果图片,整体大小约540KB,轻量易部署。目前已有1033人学习,代码结构清晰、可直接运行。读者可获得TCN模型构建、训练与预测的完整流程,参照说明文档可快速复现实验,并迁移至自身数据集,是入门和实战TCN回归任务的实用参考资料。

1. 为什么用MATLAB做TCN多输入回归预测

不少做时序预测的工程师一上来就想用LSTM,但在多输入回归场景里,LSTM训练慢、调参敏感,而且长序列上容易梯度衰减。时间卷积网络(TCN)用一维卷积加残差连接实现了因果序列建模,训练可以全并行,速度比LSTM快一个量级,在电力负荷预测、设备剩余寿命估计、金融指标回归这类任务上效果不输LSTM,甚至更稳。MATLAB的Deep Learning Toolbox里虽然没有直接叫“TCN”的层,但通过convolution1dLayerdlarray和自定义残差块,完全可以搭出可训练的TCN。这篇博客用一种多输入单输出回归任务为例子,把TCN的搭建、训练、预测和评估代码全部走一遍,代码可以直接替换成自己的数据运行。适合已经会用MATLAB基本训练流程、但没写过分层残差块的工程师。新手可以照着步骤抄,熟手可以直接跳到第4章的参数调优和坑点。

2. TCN原理与MATLAB实现基础

2.1 时间卷积网络的结构:从一维卷积到因果膨胀卷积

TCN的核心不是普通卷积,而是“因果卷积”。普通一维卷积在计算t时刻的输出时,会同时看到t+1时刻的输入,这在时序预测里是泄漏。因果卷积强制让输出只依赖当前和过去的输入,实现方式是给卷积核的权重加一个掩码,或者更常见的是用convolution1dLayer配合'Padding'参数设置不对称填充:左边填充(filterSize - 1) * dilation,右边不填充,这样卷积后的长度不变,但每个输出都对齐到过去的数据。

光有因果卷积还不够,单层卷积感受野太小。TCN用“膨胀卷积”解决这个问题:膨胀系数(dilation factor)让卷积核在时间轴之间跳过d-1个点,使第i层的感受野呈指数扩大。例如卷积核大小为3的TCN,每层的膨胀系数取[1,2,4,8],堆叠4层后感受野为1+2*(2^4-1)=31个时间步。对于多输入回归预测,每个输入特征序列在进入网络时会被当成独立的通道,卷积会在通道维度上做一个全连接式的融合,这一点和图像卷积处理RGB三通道是同一个逻辑。

2.2 为什么TCN适合多输入回归预测

多输入回归预测通常指输入是T×F的矩阵,T是时间步数,F是特征数(例如温度、湿度、压力等),输出是一个连续值(例如设备寿命或负荷)。TCN处理这种结构非常自然:卷积核的通道数等于输入特征数,不同特征在卷积运算时被自动加权组合。和LSTM按时间步迭代不同,TCN在时间维度上是并行的,训练时不需要像LSTM那样逐个时间步展开,因此当序列长度达到几百或上千时,显存和时间成本都远低于LSTM。此外,TCN的梯度路径更短,残差连接让梯度能直接回传到第一层,训练更稳定,这也是它在多输入回归上经常比LSTM收敛更快的原因。

2.3 MATLAB中TCN的实现路径

MATLAB实现TCN没有现成的tcnLayer,需要自己组合层或用network对象。实际工程里我一般用dlnetwork,因为可以自定义反向传播,而且与minibatches和GPU训练无缝对接。最简单的TCN残差块包含两层膨胀卷积、两层批归一化(batchNormalizationLayer)、一个ReLU、一个Dropout,外加一个从输入直接到输出的卷积残差连接(当输入输出通道数不一致时用convolution1dLayer调整维度)。下面是一个膨胀卷积层的参数配置示例:

filterSize = 3; dilationFactor = 2; numFilters = 32; %dilatedConvLayer = convolution1dLayer(filterSize, numFilters, ... % 'Padding', (filterSize-1)*dilationFactor, ... % 'DilationFactor', dilationFactor, ... % 'Stride', 1);

这段代码定义了用于TCN残差块内部的膨胀卷积层。Padding(filterSize-1)*dilation,这样卷积输出长度与输入一致,但只依赖过去的数据。DilationFactor控制每次卷积核采样的间隔,2意味着跳过1个时间点,感受野扩大一倍。调整这三个参数是TCN调优的重要入口。

3. 用MATLAB实现TCN多输入回归预测的完整流程

3.1 数据准备:多输入单输出的数据格式

TCN的输入数据格式是特征数 × 时间步数还是时间步数 × 特征数,MATLAB的dlnetwork默认希望输入维度是特征维 × 时间维。也就是说如果原始数据是一个样本数×时间步×特征数的三维数组,需要在训练前转置成特征数 × 时间步 × 样本数。假设CSV里有5个特征列和1个目标列,每行是一个时间点,我需要按样本滑动窗口切分:

data = csvread('multi_input_ts.csv'); % 假设最后一列是目标 features = data(:,1:end-1)'; target = data(:,end)'; % 滑动窗口切分:60个历史时间步预测下一个点 seqLen = 60; numFeatures = size(features,1); n = size(data, 1) - seqLen; X = zeros(numFeatures, seqLen, n); Y = zeros(1, 1, n); for i = 1:n X(:,:,i) = features(:,i:i+seqLen-1); Y(:,:,i) = target(:,i+seqLen); end

X特征数 × seqLen × 样本数Y1 × 1 × 样本数。注意Y是一个单值,对应每个窗口后一个时间步的目标。切分后需要把数据划分为训练集和测试集,常见做法是不要随机打乱,保持时间顺序,前80%作为训练集,后20%作为测试集,这样才能反映真实的时间外推能力。

3.2 构建TCN网络结构

我建议用函数构建残差块,然后搭建整体网络。以下代码定义了一个残差块,并组装成一个4层的TCN:

function out = residualBlock(input, numFilters, dilation, isFirst) filterSize = 3; padding = (filterSize-1)*dilation; if isFirst shortcut = convolution1dLayer(1, numFilters, 'Name','shortcut_conv'); out = shortcut(input); else out = input; % 通道数一致时直接跳过 end conv1 = convolution1dLayer(filterSize, numFilters, 'Padding', padding, 'DilationFactor', dilation, 'Name', ['conv1_dil' num2str(dilation)]); bn1 = batchNormalizationLayer('Name', ['bn1_' num2str(dilation)]); relu1 = reluLayer('Name', ['relu1_' num2str(dilation)]); conv2 = convolution1dLayer(filterSize, numFilters, 'Padding', padding, 'DilationFactor', dilation, 'Name', ['conv2_dil' num2str(dilation)]); bn2 = batchNormalizationLayer('Name', ['bn2_' num2str(dilation)]); add = additionLayer(2, 'Name', ['res_' num2str(dilation)]); reluOut = reluLayer('Name', ['relu_out_' num2str(dilation)]); out = relu1(bn1(conv1(out))); out = dropoutLayer(0.2, 'Name', ['drop_' num2str(dilation)])(out); % 注意MATLAB层语法需拆开 out = bn2(conv2(out)); out = add(out, input); out = reluOut(out); end

实际上MATLAB的层定义不能直接用函数式嵌套调用,需要组合layerGraph。上面是思路示意,真实代码要先用layerGraph定义每层的连接关系:

lgraph = layerGraph(); lgraph = addLayers(lgraph, inputLayer); % 逐个添加残差块,并连接各层的输出

完整源码里我会用layerGraph显式连接。注意dropoutLayer返回一个层对象,不能直接当函数调用。第3章末尾会给出可运行的训练代码骨架。

3.3 训练参数设置与模型训练

训练时用adam优化器,miniBatchSize设为32,maxEpochs设为60。初始学习率0.001,并在40轮后衰减一半。以下代码是训练主循环:

dlnet = dlnetwork(lgraph); options = trainingOptions('adam', ... 'MiniBatchSize', 32, ... 'MaxEpochs', 60, ... 'InitialLearnRate', 0.001, ... 'LearnRateSchedule', 'piecewise', ... 'LearnRateDropPeriod', 40, ... 'LearnRateDropFactor', 0.5, ... 'Shuffle', 'never', ... 'Verbose', 1, ... 'Plots', 'training-progress'); [net, info] = trainNetwork(X, Y, dlnet, options);

参数说明:Shuffle设成never是因为时序数据不能打乱,否则时间顺序被破坏,模型会学到未来信息,测试效果虚高。LearnRateDropPeriod设为40,让模型在后期用更小步长精修。trainNetwork接受XY作为dlarray或者普通数组,但这里trainNetwork要求是arrayDatastoretall数组?实际上trainNetwork接受customTrainingLoop或者trainnet?为了简化,我建议用trainNetwork直接输入XY,因为MATLAB的trainNetwork会自动转换。但为了保险,训练时需要调用dlarray处理。下面给出用trainnet的示例:

dlX = dlarray(X, 'SCB'); % S=time, C=feature, B=batch dlY = dlarray(Y, 'CBT'); % C=feature, B=batch, T=time? 实际要按网络输出形状定

这里的维度标注比较绕。最可靠的做法是按你的网络inputLayer指定的维度来。如果在trainNetwork里报维度错误,把数组转成四维或三维再试。经验是:TCN输入标注用'SCB'(sequence、channel、batch),输出用'CB'(channel、batch)或'CBT',取决于你最后的回归层。

3.4 回归预测与结果评估

训练完成后,用predict得到预测值。因为输出层只输出一个连续值,需要把预测值和目标值进入同一量纲。如果之前做了归一化,预测结果要反归一化。

Ypred = predict(net, dlXTest); Ypred = extractdata(Ypred); Ytest = extractdata(dlYTest); % 如果之前用mapminmax归一化过 % Ypred = mapminmax('reverse', Ypred, ps);

评估指标在第五章里详细介绍。注意,测试集必须是时间连续的,不能随机抽取,否则会造成时间泄漏。

4. 实战中的参数调优与常见坑

4.1 关键超参数:膨胀系数、卷积核大小、残差连接

TCN最值得调的是膨胀系数序列、卷积核大小和每层通道数。下面这张表给出典型取值和影响:

参数典型值影响
卷积核大小3或5核越大,单层范围越大,但参数量增加,容易过拟合
膨胀系数序列[1,2,4,8,...]决定了感受野大小;序列长度等于残差块数
每层通道数16~64通道越多,拟合能力越强,但训练更慢
残差连接是/否去掉残差连接网络深了几乎无法训练
Dropout率0.1~0.3防止过拟合的关键,尤其数据量少时

膨胀系数的选择要依据输入序列长度。序列长度是60时,[1,2,4,8]加核3感受野是31,还没覆盖全部60个点,建议用[1,2,4,8,16,32]或核5。如果序列长度1000,可以按指数序列加到128。一个标准公式是:当前层感受野 = 前层感受野 + (filterSize-1) * dilation。你可以先算一算,保证最后一层感受野不小于整个序列长度,否则模型会漏掉早期的依赖。

4.2 数据预处理与多尺度特征融合

多输入回归预测的数据往往量纲不一致,温度在几十,压力可能上万。必须做归一化。MATLAB里我用mapminmax按特征逐行归一化:

[Xn, ps] = mapminmax(X, -1, 1); % X是特征×时间×样本的三维数组

mapminmax默认按行处理,将每行映射到[-1,1]。注意,训练集和测试集必须用同一个ps转换,不能各自归一化。否则测试集的分布信息会泄漏到训练过程中。另一个经常被忽略的点是:如果原始特征存在滞后相关,可以人为构造滞后特征作为额外输入,让TCN更容易学到跨时间步的依赖。比如把第2天的变化量作为第3个输入通道。这属于特征工程,能显著提升回归精度。

还有一个误用是:把多输入单输出理解为多个序列分别预测再平均。TCN支持的是多通道输入,即把不同变量作为不同通道,在卷积层进行通道融合,而不是分别建模。如果按后者操作,会丢失变量之间的交叉相关关系。

4.3 模型过拟合与训练不稳定的处理

训练损失下降但验证集误差很大时,优先增大Dropout率,或减小每层通道数。TCN因为卷积参数共享,比全连接网络抗过拟合一些,但数据量小还是容易过。一个很实用的技巧是在残差块之间加入layerNormalizationLayer而不是batchNormalizationLayer。批归一化在小batch时不稳定,层归一化对时序预测更友好。如果损失曲线震荡严重,把学习率降到0.0003,或者改用sgdm优化器。

下面是一个包含层归一化的残差块代码片段:

convBlock = [ convolution1dLayer(filterSize, numFilters, 'Padding', padding, 'DilationFactor', dilation) layerNormalizationLayer reluLayer convolution1dLayer(filterSize, numFilters, 'Padding', padding, 'DilationFactor', dilation) layerNormalizationLayer ];

替换掉原来的批归一化后,训练会更稳定。另外,初始化的随机种子也会影响结果,建议固定随机种子:

rng(42);

这样每次运行结果可复现,便于调参对比。

5. 用验证指标和可视化确认TCN预测效果

回归预测不能只看预测曲线“看起来重合”,必须用多个指标量化。我通常计算三个指标:R²(决定系数)、RMSE(均方根误差)、MAE(平均绝对误差)。R²越接近1说明模型解释了大部分方差,RMSE对大误差敏感,MAE更能反映平均偏差。以下是计算代码:

Ytest = extractdata(Ytest); Ypred = extractdata(Ypred); SS_res = sum((Ytest - Ypred).^2); SS_tot = sum((Ytest - mean(Ytest)).^2); R2 = 1 - SS_res / SS_tot; RMSE = sqrt(mean((Ytest - Ypred).^2)); MAE = mean(abs(Ytest - Ypred));

一个关键技巧是用resubLoss做交叉验证时不要随机打乱数据,而是按时间做K折。比如把整个时间序列按窗口分成5段,每次用前4段训练最后1段测试。这样才能真实反映TCN在“未来”上的表现。很多调参者发现训练集R²高达0.99,测试集只有0.3,原因就是训练集和测试集有重叠窗口或归一化用了全局统计量。

可视化方面,除了画预测值和真实值的对比曲线,还要画误差直方图。误差呈正态分布说明模型没有系统性偏差;如果误差在某个区间明显偏均值,说明存在未捕捉的周期性。MATLAB命令:

figure; plot(Ytest, 'k'); hold on; plot(Ypred, 'r--'); legend('真实值', 'TCN预测'); xlabel('时间步'); ylabel('目标值'); figure; histogram(Ytest - Ypred, 30); xlabel('预测误差'); ylabel('频数');

最后,把TCN和LSTM基线模型做对比时,务必确保两者使用的是完全相同的训练集、测试集和归一化方式。我见过好几次对比结果无效,都是因为LSTM用了自己的归一化参数,而TCN用了另一个。用上面这些指标和可视化方法来验收,TCN在多数多输入回归任务上至少能和LSTM打平,而在长序列和训练速度上有明显优势。调参时先用2层残差块跑通流程,再加层数和通道数,你会发现TCN对超参数的敏感度远低于LSTM,这也是它值得在MATLAB里落地应用的最大原因。

本文还有配套的精品资源,点击获取

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询