Vision Transfomer系列第二节---复现过程的Bugs记录
目录
- 报错cuda error
- loss始终下不去, attention矩阵size变成[b,b]
- loss还是下不去
- loss还还是下不去
- 训练正常验证报cuda out of memory
- 全数据训练时loss还还还是下不去
- 可视化时预测类别全乱套
- 总结
报错cuda error
原因:class2label生成过程中,遍历文件夹时候文件集内有无关文件,导致class2label变成了{‘daisy’: 0, ‘dandelion’: 1, ‘roses’: 2, ‘sunflowers’: 3, ‘tulips’: 5}
解决方法:加个非文件夹过滤(见dataset.py)
flowers_path = os.path.join(dataset_path, flower)
if os.path.isdir(flowers_path):
'''''''
loss始终下不去, attention矩阵size变成[b,b]
原因:我的mha输入要求是,[n, b, dim],实际输入是[b, n, dim],导致注意力查询错误
解决方法:调整维度顺序 (见model.py)
input = input.permute(1, 0, 2) #注意输入的维度顺序
input = self.blocks(input) # 自注意力
loss还是下不去
原因:使用view和reshape同时交换维度和改变形状,而不是提前使用transpose和permute交换维度.
前者可以改变数据形状[3,5,8]->[3,5,2,4],但是不能交换维度[3,8,5],如果用前者强制指定新维度会改变数据内容,而后者只交换维度参考.
所以建议view和reshape时候要慎重,先用transpose和permute交换好维度,在改变形状.
reshape相当于contiguous().view),建议用reshape就行了
transpose交换2个维度和permute交换多个维度,建议用permute就行了
解决方法:修改(见model.py)
# [b,n_h,tgt_len,d_h] -> [b,tgt_len,embed_dim]
output = output.permute(0, 2, 1, 3).contiguous().view(tgt_len, bsz, embed_dim)
loss还还是下不去
原因:nn.CrossEntropyLoss()已经内置softmax,预测输出无需外接sigmod激活
解决方法:预测输出无需外接sigmod激活
训练正常验证报cuda out of memory
相关的原始代码:
# 训练
loss = self.model.loss(**instance)
loss_sum += loss
loss.backward()
self.optimizer.step()
self.optimizer.zero_grad()
# 验证
self.model.eval()
loss, correct_num = self.model.predict(**instance)
loss_sum += loss
原因:经过测试,发现:
1.在验证时加上loss.backward()可以解决这个问题,训练删掉loss.backward()则训练会复现这个问题.
2.在验证时加上with torch.no_grad()也可以解决这个问题
3.每迭代一次,显存增加一些,直到爆表
后来发现根本原因在于loss_sum += loss有没有加loss.detach(),经过查看参考资料1和[2]
(https://blog.csdn.net/qq_43391414/article/details/120571920),明白loss本身是神经网络计算图的一部分,而loss_sum作为一个迭代之外的变量,每次的累加都被记录到计算图中,经测试loss_sum是一个迭代内变量则不会引发这个问题.
detach将新建一个脱离计算图的新变量(requires_grad=false),loss_sum也不会进入计算图中影响显存.
解决方法:loss_sum += loss.detach()
全数据训练时loss还还还是下不去
原因:norm很重要,重要的blocks不光中间需要,blocks的输入输出侧都需要!!!
解决方法:输出层加个norm,(因为我的每个block是’norm’, ‘self_attn’, ‘norm’, ‘ffn’)(见model.py)
def extract_feature(self, input):
# backbone + neck
# 位置编码
input = input + self.pos_embed.to(input)
# 注意力机制
input = input.permute(1, 0, 2) #注意输入的维度顺序
input = self.blocks(input) # 自注意力
input = self.norm(input)
input = input.permute(1, 0, 2)
return input
可视化时预测类别全乱套
原因:python每次读取文件夹的顺序是随机的,而我训练和测试要读两次文件夹确定类别和索引的关系,所以需要排序
解决方法:对文件夹排序(见dataset,py),或者直接训练时候就生成一个固定的class_label文件
flowers = os.listdir(dataset_path)
flowers = sorted(flowers) # 必须排序,否在每一次顺序不一样训练测试类别就会乱
总结
1.transfomer模型的训练收敛速度确实很慢,一个分类就需要训练好很多个epoch (花分类45epochs左右)
2.所以说看懂原理和代码还是远远不够的,复现起来还是有很多细节需要注意的,确实是纸上学来终觉浅,绝知此事要躬行