这次项目是大二老师给我的,具体什么时候做的,我已经忘记了,现在重温一下;
首先我们都知道Informer的图像如图1,但是我觉得太复杂了,我便将中间的两层做了删掉,并对他们自带的测试集做了些测试,发现他们在时间方面的差距并不大(甚至可以说微乎其微),至于效率方面,这个与测试集有关,笔者在自己的项目和原论文项目中小小的测试了几次,效率并没有多大差距,但是我的老师在一些时序预测项目中发现有一定差距,但是因为当时的时间限制,也没有做太多“计较”


我的老师当时问了几个问题:
- 模型结构上由5层->3层,可以降低复杂度和提高速度,降低的复杂度和提高的速度具体是多少,可以量化吗?
- 复杂度降低是因为减少了参数吗?那参数由多少降低到多少呢?
- 模型减少了2层,这两层具体作用是什么?(作用如果比较重要的话,去掉之后会不会对模型有什么影响?)如果不重要,去掉又可以有哪些好处?
- 为什么减少2层?
- 为什么增加激活函数splice,有什么好处?增加该激活函数之后,复杂度会增加吗?增加多少?
我做了相应的回答:
- 不同数据,时间降低不一样,所以不可以量化。
- 复杂度降低不是因为参数的减少,对比分析原来和现在的模型参数,其大小都为11.31M;参数没有减少,但是时间的减少是因为模型层数的减少,模型层数的减少,减少了整体时间和空间的使用。
- 一个是卷积层,另一个是编码层;
(1)卷积层会提取出更重要的数据;
(2)编码层会对卷积层提取出来的重要数据做自注意力机制等处理;
(3)这两个层都比较重要,数据通过这两个层,其序列长度会从L/2变为L/4,这样筛选了更重要的数据,但在筛选的过程中难免会多筛选一部分有用数据;当减少这两层后,模型的效果会减弱,为了达到原来的效果,需要一个新的方法来处理数据:希望让有用数据更有用或者维持不变,让无用数据的值接近为0而不对模型产生副作用。 - 减少两层主要是增加了有用数据的数量,由于原先Informer将长度L的序列转变为L/4,那么新模型只是将L转变为L/3,这样增加了有用数据的数量,使得模型更精确。
- 新模型将序列长度从L变为L/3,对比原来informer将序列长度从L变为L/4,有效数据在增加的同时,无效数据量也会增加,而Splice激活函数,可以使无效数据稳定在0左右(这是因为注意力机制的稀疏性),使有效数据做非线性变化,这样拉大了有效数据和无效数据的数值差距,使得最后的效果更显著;其次Splice激活函数左饱和,而右侧不饱和解决了梯度爆炸的问题并且加快了收敛的速度;其中有效数据指的是x>0,无效数据指的是x<0,重要数据指的是通过任意一卷积层而被筛选出的数据。
我在这里也给出Splice激活函数的图像


这是我的最终结果,每一个测试集跑了10次,平且去除最低和最高后平均的结果

从效果上来看,还不错,这是我的第一次小小的“成功”,因为时间、mse(均方误差)、mae(均值绝对误差)大部分要比论文好很多;
这篇文章仅仅记录一下我的大二下的第一次科研项目(重要的是,那个时候我前女友还陪着我)
关于实验源码,我不能公开,但是我可以将我的Splice激活函数的代码公开(其实有了公式,就算不公开,读者也能自己写出来):
class Splice(nn.Module):
def __init__(self):
super(Splice, self).__init__()Q
self.weight = nn.Parameter(torch.FloatTensor(1), requires_grad=True)
self.reset_parameters()
def reset_parameters(self):
self.weight.data.fill_(1.0)
def forward(self, input):
return exp(self.weight *input) / (1 + abs(input))
1.init(self)函数:
super(Splice, self).init() 是调用 nn.Module 的构造函数,这是 PyTorch 模块化设计的标准做法。它允许 Splice 继承所有 nn.Module 的功能。
self.weight = nn.Parameter(torch.FloatTensor(1), requires_grad=True)用来计算梯度。
* nn.Parameter 是 PyTorch 中专门用于存储需要梯度计算的参数的类。它本质上是一个 torch.Tensor,并且在模型训练时,会自动将其梯度计算包含在优化过程中。
* torch.Tensor 是 PyTorch 中的基础数据结构,用于存储和操作多维数组(即张量)。
* 这里初始化了一个单个浮点数的张量,即 torch.FloatTensor(1),意味着 weight 是一个大小为 1 的标量。
* requires_grad=True 确保在反向传播时计算梯度。
2.reset_parameters(self)函数:
self.weight.data.fill_(1.0) 用来将 self.weight 张量的值填充为 1.0,即将 weight 重置为 1。
* 虽然我在__init__(self)中设置了权重=1,但是为了保证初始化的一致性、代码的可拓展性、模型的安全性,我加了这个函数,去掉也没问题
* data 属性允许直接修改张量数据,而不触发梯度计算,避免不必要的反向传播影响。
3.forward(self, input)函数:
即上面展示的公式
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 全程不用写代码,我用AI程序员写了一个飞机大战
· DeepSeek 开源周回顾「GitHub 热点速览」
· 记一次.NET内存居高不下排查解决与启示
· MongoDB 8.0这个新功能碉堡了,比商业数据库还牛
· .NET10 - 预览版1新功能体验(一)