中国建设银行招标网站,南宁的公司有哪些,研磨材料 东莞网站建设,怎样监测熊掌号绑定成功网站1 问题起因和经过
半年前写了一个模型#xff0c;取得了不错的效果#xff08;简称项目文件1#xff09;#xff0c;于是整理了一番代码#xff0c;保存为了一个新的项目#xff08;简称项目文件2#xff09;。半年后的今天#xff0c;我重新训练这个整理过的模型取得了不错的效果简称项目文件1于是整理了一番代码保存为了一个新的项目简称项目文件2。半年后的今天我重新训练这个整理过的模型即项目文件2没有修改任何的超参数并且保持完全一致的随机种子但是始终无法完全复现出半年前项目文件1跑出来的结果按道理来说随机种子控制好后整个训练过程都应该能够复现第一个epoch的accuracy就应该对上。我找到项目文件1跑了跑能复现之前的训练结果。并且分别训练项目文件1和2的模型都能重复自己的训练结果而两个项目文件的结果无法对上。 花了半天的时间反复仔细检查数据集和训练超参数的设置后也没能看出项目文件2有什么毛病。非常奇怪为什么同样的模型、配置、服务器、随机种子在不同的项目文件中出现不同的结果实在想不通。 于是决定动手debug看看问题出在了哪里。 我发现第一个epoch的结果就对不上所以我猜测问题出在了模型的初始化上那初始化与什么相关呢很自然地我把问题聚焦在了随机种子上是不是没有有效固定住随机性所以我将两个项目文件构建model后的参数打印出来看了看发现完全不同 项目文件1中的部分打印结果
项目文件2中的部分打印结果
很明显地说明了一件事同样的随机种子在这两个项目文件中产生了完全不一样的初始化值 这个结果是违背我的常识的为什么会出现这样的情况 于是我 猜测是不是因为两个项目在同一服务器上发生了未知的冲突所以我copy了一份项目文件1为项目文件3然后跑项目文件3的初始化结果发现和项目文件1的初始化结果一致居然没问题那这个项目文件2怎么回事凭空出现了不同的初始化值 排除了项目冲突这个猜想后我把视野放在了模型本身上。我试着print(model)进行观察发现项目文件2相比项目文件1的模型架构多了一些参数这些参数是我当初在整理代码并补充新算法时补充定义的比如self.gamma Parameter(torch.randn((1, self.num_heads, 1, 1)))但是后面并没有真正用上这个参数。 于是我又有了一个新的猜想是不是因为多出来的这些新定义的参数导致在同一随机种子的设置下仍然出现不一致的初始化行为 顺着这个思路我给项目文件1做了如下简单的尝试直接给模型架构多定义一个模块但无需使用它看看初始化是否受影响。 这里我简单加了个nn.Linear()进去。 代码解释如下原本的架构为
class Attention(Module):Obtained from timm: github.com:rwightman/pytorch-image-modelsdef __init__(self, dim, num_heads8, attention_dropout0.1, projection_dropout0.1):super().__init__()self.num_heads num_headshead_dim dim // self.num_headsself.scale head_dim ** -0.5self.qkv Linear(dim, dim * 3, biasFalse)self.attn_drop Dropout(attention_dropout)self.proj Linear(dim, dim)self.proj_drop Dropout(projection_dropout)self.relu ReLU()self.eps 1e-8self.alpha Parameter(torch.ones(1, self.num_heads, 1, 1), requires_gradFalse)self.alpha.data.fill_(1.0)def forward(self, x):B, N, C x.shapeqkv self.qkv(x).reshape(B, N, 3, self.num_heads, C // self.num_heads).permute(2, 0, 3, 1, 4)q, k, v qkv[0], qkv[1], qkv[2]...我在init函数中多定义一行线性层后为
class Attention(Module):Obtained from timm: github.com:rwightman/pytorch-image-modelsdef __init__(self, dim, num_heads8, attention_dropout0.1, projection_dropout0.1):super().__init__()self.num_heads num_headshead_dim dim // self.num_headsself.scale head_dim ** -0.5self.qkv Linear(dim, dim * 3, biasFalse)self.attn_drop Dropout(attention_dropout)self.proj Linear(dim, dim)self.proj_drop Dropout(projection_dropout)self.relu ReLU()self.eps 1e-8self.alpha Parameter(torch.ones(1, self.num_heads, 1, 1), requires_gradFalse)self.alpha.data.fill_(1.0)self.linear Linear(dim, dim) # 这里是新加的模块但是无需使用def forward(self, x):B, N, C x.shapeqkv self.qkv(x).reshape(B, N, 3, self.num_heads, C // self.num_heads).permute(2, 0, 3, 1, 4)q, k, v qkv[0], qkv[1], qkv[2]...于是打印初始化参数得到
初始化的结果仍然改变了 看来果然是模型架构的不一致性导致了随机种子“失效”。
2 总结上述问题
两个项目文件看似模型、超参数、数据集、随机种子、服务器完全一致时发现训练时两者无法保持完全一致并且进一步发现两个项目文件在初始化模型参数时就不一致了。 而单独地重复训练每一个项目文件都能重复自身的结果。 直观感觉就是随机种子并没有有效地作用到另一个项目上是一个很奇怪的问题有点违背常识。
3 总结解决方案
训练过程不一致是表象实际上是模型初始化就不一致了。 如果想要用随机种子控制模型初始化参数完全一致就必须保证模型的架构完全一致 但凡在model类的init函数里多定义一个无用参数比如Linear都会改变整个初始化结果从而影响后面的训练进程应该是很微小的影响但是对于我们复现项目时扣细节来说会放大这个影响。
4 可能的解释
咨询了一些遇到过这个问题的同学大概有如下的可能的解释在模型的定义中加入了新的模块后不管是否真正使用都会影响初始化已控制了随机种子。因为加入了新的模块后整个初始化的顺序会发生改变于是就乱套了。随机种子只能保证你调用后生成的随机数列是一样的而在构建模型时的调用顺序是会随着模型架构的改变而改变的。