96SEO 2026-02-20 10:18 0
解已经满天飞了但是本文给大家带来的是我在Seq2Seq思想上开发的一个模型和新的架构架构前面的文章已经说过很多次了其是专门为新手开发的而且为了方便大家使用只定义了一个文件方便大家复制粘贴架构功能包括结果可视化、支持单元预测、多元预测、模型拟合效果检测、预测未知数据、以及滚动长期预测功能。

Seq2Seq模型是一种处理序列数据的深度学习模型广泛用于机器翻译、语音识别和文本摘要等任务(也能用于时间序列)。
其核心思想是编码器-解码器。
需要注意得是本文的模型和结构均为自研在Seq2Seq的思想上进行了一定的扩展。
时间序列预测专栏基础知识数据分析机器学习深度学习Transformer创新模型
预测功能效果展示(不是测试集是预测未知数据所以图中没有对比的数据)-
损失截图(损失这里我先展示一个训练过程中的后面会自动生成损失图像)-
根据损失来看模型的拟合效果还是很好的但后面还是做了检验模型拟合效果的功能让大家真正的评估模型的效果。
这个结构是我发这么多基础模型里效果最好的模型拟合和测试集表现均为最好。
Seq2SeqSequence-to-Sequence模型是一种处理序列数据的深度学习模型广泛用于机器翻译、语音识别和文本摘要等任务。
其核心思想是将一个序列如一句话转换成另一个序列这两个序列的长度可以不同。
编码器-解码器架构Seq2Seq模型通常由两部分组成编码器和解码器。
编码器负责读取并理解输入序列将其转换成一个固定长度的上下文向量context
vector。
解码器则利用这个上下文向量生成目标序列其实最核心的就是这个下面都是具体的应用了。
循环神经网络RNN在传统的Seq2Seq模型中编码器和解码器通常是循环神经网络如LSTM或GRU。
RNN可以处理不同长度的输入序列并在其隐藏层保持序列的状态信息。
3.注意力机制Attention注意力机制是后来引入Seq2Seq模型的一项重要改进。
它允许模型在生成每个目标词时“关注”输入序列的不同部分从而提高了模型处理长句子时的效果和准确性。
长短期记忆网络LSTM/门控循环单元GRU为了解决RNN中的长期依赖问题LSTM和GRU这样的网络结构被引入。
它们能更好地捕捉序列中的长期依赖关系。
个人总结我个人觉得Seq2Seq模型就像是学习语言的人。
首先通过“编码器”理解输入的句子然后用“解码器”来表达新的句子。
就像我们学外语时先理解一句话的意思再用自己的语言表达出来。
加上“注意力机制”模型还能更聪明地关注输入句子中最重要的部分就好比我们在听别人说话时会注意对方重点强调的内容。
通过上面我们知道Seq2Seq的主要核心思想是编码器和解码器Seq2Seq一开始被发明出来是用于一些本文处理的但是本文是时间序列领域的文章所以我主要讲解一下编码器-解码器在时间序列领域的应用大家需要注意的是这里的编码器和解码器和Transformer当中的还不一样是有着根本的区别的。
Seq2Seq模型的编码器和解码器如下工作
处理时间序列输入编码器接收时间序列数据例如过去几天的股票价格或气温记录。
这些数据通常是连续的数值。
特征提取通过RNN(本文是用的GRU类似于LSTM和RNN以后也会单独出文章)网络编码器可以捕捉时间序列的特征和内在模式。
RNN通过其时间递归结构有效地处理时间序列数据中的时序依赖关系。
上下文向量编码器输出一个上下文向量该向量是输入时间序列的压缩表示包含了对过去数据的理解和总结。
解码器在时间序列领域的作用是基于编码器提供的信息来预测未来的时间序列数据。
初始状态和输入解码器的初始状态通常由编码器的最终状态设置。
解码器的第一个输入可能是序列的最后一个观测值或特殊标记我设置为解码器的输入是编码器的最后一个输出因为我觉得这个状态的过去信息是最足的。
逐步预测在每个时间步解码器基于当前状态和前一步的预测输出或初始输入来生成下一个时间点的预测值。
迭代更新解码器的输出用于更新其状态并作为下一个时间步的输入。
这个过程在生成整个预测序列期间重复进行。
总结在时间序列领域Seq2Seq模型的编码器-解码器结构使其能够有效处理具有复杂时间依赖性的序列数据。
编码器学习并压缩历史数据的关键信息而解码器则利用这些信息来预测未来的趋势和模式。
下面的图是我编码器-解码器的结构图其中包含了编码器Encoder和解码器Decoder的具体实现细节需要注意的是这个图和本文模型无关这里举出来只是为了让大家对编码器和解码器的流程有一个更清晰的认知。
下面是对这个图示的详细解释
vector转换为嵌入向量。
在此图中嵌入层将每个输入token转换为一个256维的向量。
UnitGRU是RNN的一种变体可以捕捉长期依赖关系同时缓解了传统RNN的梯度消失问题。
在此模型中每个时间步的GRU层接收前一时间步的隐藏状态和当前时间步的嵌入向量然后输出新的隐藏状态。
时间步t时间步是序列中的位置指示从t−2开始直至t0表示输入序列的处理进程。
T这可能表示当前处理的token位于输入序列的最后一个位置意味着编码器即将完成对输入序列的处理。
嵌入层解码器的嵌入层将一热编码的输出token转换为嵌入向量。
GRU层解码器的GRU层接收来自上一时间步的隐藏状态和当前时间步的嵌入向量或初始状态从编码器传来的上下文向量然后输出新的隐藏状态。
全连接层在每个时间步全连接层将GRU的输出转换为词汇表大小的向量这个向量包含了输出序列中下一个token的概率分布。
输出概率这是解码器产生的表示下一个可能输出token的概率分布。
时间步t在解码器部分时间步从t1开始直至tT1其中T可能表示目标序列的长度。
整个过程是这样的编码器读取输入序列的token并逐个更新其隐藏状态。
当编码器读取完所有的输入token后最后的隐藏状态ℎ0被传递到解码器作为其初始状态。
解码器从一个特殊的SOS
token开始逐步生成输出序列的token。
在每一步解码器基于当前的隐藏状态和上一步产生的token预测下一个token直到生成EOS
概念部分的就讲这么多网上有很多概念理解的好博客大家有兴趣都可以自己查找看看本文是实战博客内容不多讲啦~
本文是实战讲解文章上面主要是简单讲解了一下网络结构比较具体的流程还是很复杂的涉及到很多的数学计算下面我们来讲一讲模型的实战内容第一部分是我利用的数据集。
本文我们用到的数据集是ETTh1.csv该数据集是一个用于时间序列预测的电力负荷数据集它是
数据内容该数据集通常包含有关电力系统的多种变量如电力负荷、价格、天气情况等。
这些变量可以用于预测未来的电力需求或价格。
时间范围和分辨率数据通常按小时或天记录涵盖了数月或数年的时间跨度。
具体的时间范围和分辨率可能会根据数据集的版本而异。
help模型持续更新)parser.add_argument(-window_size,
pre_len)parser.add_argument(-pre_len,
dataparser.add_argument(-shuffle,
help是否打乱数据加载器中的数据顺序)parser.add_argument(-data_path,
help你的数据数据地址)parser.add_argument(-target,
help你需要预测的特征列这个值会最后保存在csv文件里)parser.add_argument(-input_size,
help你的特征个数不算时间那一列)parser.add_argument(-feature,
learningparser.add_argument(-lr,
help学习率)parser.add_argument(-drop_out,
help随机丢弃概率,防止过拟合)parser.add_argument(-epochs,
help训练轮次)parser.add_argument(-batch_size,
help批次大小)parser.add_argument(-save_path,
modelparser.add_argument(-hidden_size,
help隐藏层单元数)parser.add_argument(-kernel_sizes,
default3)parser.add_argument(-laryer_num,
deviceparser.add_argument(-use_gpu,
defaultTrue)parser.add_argument(-device,
optionparser.add_argument(-train,
defaultTrue)parser.add_argument(-test,
defaultTrue)parser.add_argument(-predict,
defaultTrue)parser.add_argument(-inspect_fit,
defaultTrue)parser.add_argument(-lr-scheduler,
为了大家方便理解文章中的参数设置我都用的中文所以大家应该能够更好的理解。
下面我在进行一遍讲解。
参数名称参数类型参数讲解1modelstr模型名称2window_sizeint时间窗口大小用多少条数据去预测未来的数据
pre_lenint预测多少条未来的数据4shufflestore_true是否打乱输入dataloader中的数据不是数据的顺序
data_pathstr你输入数据的地址6targetstr你想要预测的特征列
MS],多元预测多元,单元预测单元,多元预测单元9lrfloat学习率大小
batch_sizeint批次大小13svae_pathstr模型的保存路径
hidden_sizeint隐藏层大小15kernel_sizeint卷积核大小
layer_numintlstm层数17use_gpubool是否使用GPU
deviceintGPU编号19trainbool是否进行训练
inspect_fitbool是否进行检验模型22lr_schdulerbool是否使用学习率计划
复制粘贴到一个文件下并且按照上面的从参数讲解配置好参数即可运行~(极其适合新手和刚入门的读者)
torch.from_numpy(self.mean).type_as(data).to(data.device)
torch.from_numpy(self.std).type_as(data).to(data.device)
torch.from_numpy(self.mean).type_as(data).to(data.device)
torch.from_numpy(self.std).type_as(data).to(data.device)
使用Matplotlib绘制线图plt.figure()plt.figure(figsize(10,
显示图例plt.legend([Loss])plt.show()class
create_inout_sequences(input_data,
pre_len]inout_seq.append((train_seq,
StandardScaler()scaler.fit(true_data)train_data
scaler.transform(train_data)test_data_normalized
scaler.transform(test_data)valid_data_normalized
转化为深度学习模型需要的类型Tensortrain_data_normalized
torch.FloatTensor(train_data_normalized).to(device)test_data_normalized
torch.FloatTensor(test_data_normalized).to(device)valid_data_normalized
torch.FloatTensor(valid_data_normalized).to(device)#
create_inout_sequences(train_data_normalized,
create_inout_sequences(test_data_normalized,
create_inout_sequences(valid_data_normalized,
TimeSeriesDataset(train_inout_seq)test_dataset
TimeSeriesDataset(test_inout_seq)valid_dataset
TimeSeriesDataset(valid_inout_seq)#
drop_lastTrue)print(通过滑动窗口共有训练集数据,
len(train_loader))print(通过滑动窗口共有测试集数据,
len(test_loader))print(通过滑动窗口共有验证集数据,
len(valid_loader))print(创建数据加载器完成)return
bidirectionalFalse):super().__init__()self.sequence_len
hidden_sizeself.input_feature_len
input_feature_lenself.num_layers
rnn_num_layersself.rnn_directions
nn.GRU(num_layersrnn_num_layers,input_sizeinput_feature_len,hidden_sizehidden_size,batch_firstTrue,bidirectionalbidirectional)def
3:input_seq.unsqueeze_(2)gru_out,
gru_out.view(input_seq.size(0),
AttentionDecoderCell(nn.Module):def
hidden_size):super().__init__()#
prev_hidden)self.attention_linear
encoder_outputs)self.decoder_rnn_cell
nn.GRUCell(input_sizehidden_size,hidden_sizehidden_size,)self.out
F.softmax(self.attention_linear(attention_input),
dim-1).unsqueeze(1)attention_combine
encoder_output).squeeze(1)rnn_hidden
self.decoder_rnn_cell(attention_combine,
EncoderDecoderWrapper(nn.Module):def
teacher_forcing0.3):super().__init__()self.encoder
AttentionDecoderCell(input_size,
nn.Linear(input_size,output_size)def
self.encoder(input_seq)prev_hidden
torch.cuda.is_available():outputs
self.decoder_cell(encoder_output,
torch.optim.Adam(model.parameters(),
train_loader:optimizer.zero_grad()y_pred
labels)single_loss.backward()optimizer.step()losss.append(single_loss.detach().cpu().numpy())tqdm.write(f\t
len(losss)})results_loss.append(sum(losss)
len(losss))torch.save(model.state_dict(),
save_model.pth)time.sleep(0.1)#
保存模型print(f模型已保存,用时:{(time.time()
min)plot_loss_data(results_loss)def
加载模型进行预测lstm_model.load_state_dict(torch.load(save_model.pth))lstm_model.eval()
calculate_mae(pred.detach().numpy().cpu(),
np.array(labels.detach().cpu()))
真实值)losss.append(mae)print(验证集误差MAE:,
modelmodel.load_state_dict(torch.load(save_model.pth))model.eval()
calculate_mae(pred.detach().cpu().numpy(),np.array(label.detach().cpu()))
scaler.inverse_transform(pred.detach().cpu().numpy())label
scaler.inverse_transform(label.detach().cpu().numpy())for
range(len(pred)):results.append(pred[i][-1])labels.append(label[i][-1])plt.figure(figsize(10,
注意这里预测数据的起始x坐标是历史数据的最后一个点的x坐标plt.plot(results,
modelmodel.load_state_dict(torch.load(save_model.pth))model.eval()
scaler.inverse_transform(pred.detach().cpu().numpy())label
scaler.inverse_transform(label.detach().cpu().numpy())for
range(len(pred)):results.append(pred[i][-1])labels.append(label[i][-1])plt.figure(figsize(10,
注意这里预测数据的起始x坐标是历史数据的最后一个点的x坐标plt.plot(results,
state)plt.legend()plt.show()def
scaler.transform(df)tensor_pred
torch.FloatTensor(pre_data).to(device)tensor_pred
modelmodel.load_state_dict(torch.load(save_model.pth))model.eval()
scaler.inverse_transform(pred.detach().cpu().numpy())#
range(history_length)plt.figure(figsize(10,
注意这里预测数据的起始x坐标是历史数据的最后一个点的x坐标plt.plot(prediction_x,
labelPrediction)plt.axvline(history_length
argparse.ArgumentParser(descriptionTime
forecast)parser.add_argument(-model,
help模型持续更新)parser.add_argument(-window_size,
pre_len)parser.add_argument(-pre_len,
dataparser.add_argument(-shuffle,
help是否打乱数据加载器中的数据顺序)parser.add_argument(-data_path,
help你的数据数据地址)parser.add_argument(-target,
help你需要预测的特征列这个值会最后保存在csv文件里)parser.add_argument(-input_size,
help你的特征个数不算时间那一列)parser.add_argument(-feature,
learningparser.add_argument(-lr,
help学习率)parser.add_argument(-drop_out,
help随机丢弃概率,防止过拟合)parser.add_argument(-epochs,
help训练轮次)parser.add_argument(-batch_size,
help批次大小)parser.add_argument(-save_path,
modelparser.add_argument(-hidden_size,
help隐藏层单元数)parser.add_argument(-laryer_num,
deviceparser.add_argument(-use_gpu,
defaultTrue)parser.add_argument(-device,
optionparser.add_argument(-train,
defaultTrue)parser.add_argument(-test,
defaultTrue)parser.add_argument(-predict,
defaultTrue)parser.add_argument(-inspect_fit,
defaultTrue)parser.add_argument(-lr-scheduler,
实例化模型try:print(f开始初始化{args.model}模型)model
EncoderDecoderWrapper(args.input_size,
args.window_size).to(device)print(f开始初始化{args.model}模型成功)except:print(f开始初始化{args.model}模型失败)#
args.train:print(f开始{args.model}模型训练)train(model,
args.test:print(f开始{args.model}模型测试)test(model,
args.inspect_fit:print(f开始检验{args.model}模型拟合情况)inspect_model_fit(model,
args.predict:print(f预测未来{args.pre_len}条数据)predict(model,
我们配置好所有参数之后就可以开始训练模型了根据我前面讲解的参数部分进行配置不懂得可以评论区留言。
Seq2Seq(GRU)的预测效果图(这里我只预测了未来24个时间段的值为未来一天的预测值)-
同时我也可以将输出结果用csv文件保存但是功能还没有做我在另一篇informer的文章里实习了这个功能大家如果有需要可以评论区留言有时间我会移植过来最近一直在搞图像领域的文章因为时间序列看的人还是太少了。
另一篇文章链接-时间序列预测实战(十九)魔改Informer模型进行滚动长期预测科研版本结果可视化
将滚动预测结果生成了csv文件方便大家对比和评估以下是我生成的csv文件可以说是非常的直观。
(从下面的图片可以看出模型拟合的情况还行上一篇RNN的有一点过拟合了其实则会个表现还是很正常的)
到此本文的正式分享内容就结束了在这里给大家推荐我的时间序列专栏本专栏目前为新开的平均质量分98分后期我会根据各种最新的前沿顶会进行论文复现也会对一些老的模型进行补充目前本专栏免费阅读(暂时大家尽早关注不迷路~)如果大家觉得本文帮助到你了订阅本专栏关注后续更多的更新~
如果大家有不懂的也可以评论区留言一些报错什么的大家可以讨论讨论看到我也会给大家解答如何解决最后希望大家工作顺利学业有成
作为专业的SEO优化服务提供商,我们致力于通过科学、系统的搜索引擎优化策略,帮助企业在百度、Google等搜索引擎中获得更高的排名和流量。我们的服务涵盖网站结构优化、内容优化、技术SEO和链接建设等多个维度。
| 服务项目 | 基础套餐 | 标准套餐 | 高级定制 |
|---|---|---|---|
| 关键词优化数量 | 10-20个核心词 | 30-50个核心词+长尾词 | 80-150个全方位覆盖 |
| 内容优化 | 基础页面优化 | 全站内容优化+每月5篇原创 | 个性化内容策略+每月15篇原创 |
| 技术SEO | 基本技术检查 | 全面技术优化+移动适配 | 深度技术重构+性能优化 |
| 外链建设 | 每月5-10条 | 每月20-30条高质量外链 | 每月50+条多渠道外链 |
| 数据报告 | 月度基础报告 | 双周详细报告+分析 | 每周深度报告+策略调整 |
| 效果保障 | 3-6个月见效 | 2-4个月见效 | 1-3个月快速见效 |
我们的SEO优化服务遵循科学严谨的流程,确保每一步都基于数据分析和行业最佳实践:
全面检测网站技术问题、内容质量、竞争对手情况,制定个性化优化方案。
基于用户搜索意图和商业目标,制定全面的关键词矩阵和布局策略。
解决网站技术问题,优化网站结构,提升页面速度和移动端体验。
创作高质量原创内容,优化现有页面,建立内容更新机制。
获取高质量外部链接,建立品牌在线影响力,提升网站权威度。
持续监控排名、流量和转化数据,根据效果调整优化策略。
基于我们服务的客户数据统计,平均优化效果如下:
我们坚信,真正的SEO优化不仅仅是追求排名,而是通过提供优质内容、优化用户体验、建立网站权威,最终实现可持续的业务增长。我们的目标是与客户建立长期合作关系,共同成长。
Demand feedback