Xiaobin-Rong / deepvqe

An unofficial implementation of DeepVQE proposed by Microsoft Corp.
62 stars 19 forks source link

有关StreamConvTranspose2d的一个问题 #5

Closed SherryYu33 closed 9 months ago

SherryYu33 commented 9 months ago
 DeConv = torch.nn.ConvTranspose2d(4, 4, (3,3), (1,2), padding=(0,1), dilation=(1,4), groups=4)
 SDC = StreamConvTranspose2d(4, 4, (3,3), (1,2), padding=(0,1), dilation=(1,4), groups=4)

流式的结果没问题

torch.Size([1, 4, 100, 17])
torch.Size([1, 4, 100, 17])
tensor(2.3842e-07)

但是我换成如下形式后

DeConv = torch.nn.ConvTranspose2d(4, 4, (3,3), (1,2), padding=(0,1))
SDC = StreamConvTranspose2d(4, 4, (3,3), (1,2), padding=(0,1))

结果就出现了巨大偏差,这是什么原因呢?谢谢!

torch.Size([1, 4, 100, 11])
torch.Size([1, 4, 100, 11])
tensor(2.1431)
Xiaobin-Rong commented 9 months ago

@SherryYu33

非常感谢你的反馈。我试验了这个偏差与 dilation 无关,只与 groups 有关。这个错误是由于我在 convert.py 代码里将 原model 中 ConvTranspose2d 的参数字典映射到 StreamConvTranspose2d 时犯了个错误(简单地根据 weight 的形状来做判决了)。现在我修改了convert.py 来针对 groups=1 和 ≠1 两种情况进行不同的 weight 映射处理。

然而,由于 pytorch 内部的 nn.Conv2d 和 nn.ConvTranspose2d 在参数形状这里有差异,前者的weight: (Cout, Cin/g, kw, kh), bias: (Cout);后者的weight: (Cin, Cout/g, kw, kh), bias: (Cin),所以在流式处理中用 nn.Conv2d 来代替 nn.ConvTranspose2d 事实上不能在所有情况下都正确。例如,

DeConv = torch.nn.ConvTranspose2d(4, 8, (3,3), (1,2), padding=(0,1), dilation=(1,4), groups=2)
    SDC = StreamConvTranspose2d(4, 8, (3,3), (1,2), padding=(0,1), dilation=(1,4), groups=2)
    convert_to_stream(SDC, DeConv)

将会导致以下报错:

RuntimeError: Error(s) in loading state_dict for StreamConvTranspose2d:
        size mismatch for ConvTranspose2d.weight: copying a param with shape torch.Size([4, 4, 3, 3]) from checkpoint, the shape in current model is torch.Size([8, 2, 3, 3]).

目前我还没想到一个好的解决方法,所幸一般模型里不会用到太复杂的情况。所以这里我直接在 StreamConvTranspose2s 中加了一个限制 groups==1 的语句。如果你有好的解决方案,欢迎提出,我将会合并到代码里面并声明你的贡献,谢谢!

SherryYu33 commented 9 months ago

@Xiaobin-Rong 谢谢您的解答!

SherryYu33 commented 9 months ago

@Xiaobin-Rong 您好! 目前如果把StreamConvTrasnpose2d放进一个Module中还是有点小错误,即如下形式:

class DecoderBlock1(nn.Module):
    def __init__(self, en_channels, in_channels, out_channels, kernel_size=(3, 3), stride=(1, 2)):
        super().__init__()
        self.deconv = StreamConvTranspose2d(in_channels, out_channels, kernel_size, stride=(1, 2), padding=(0, 1))
        ......

会报这个错 AttributeError: 'DecoderBlock1' object has no attribute 'deconv.ConvTranspose2d' 我目前简单粗暴地把convert_to_stream改成这样

def convert_to_stream(model_stream, model):
    state_dict = model.state_dict()
    new_state_dict = model_stream.state_dict()

    for key in model_stream.state_dict().keys():

        if key in state_dict.keys():
            new_state_dict[key] = state_dict[key]

        elif key.replace('Conv2d.', '') in state_dict.keys():
            new_state_dict[key] = state_dict[key.replace('Conv2d.', '')]

        elif key.replace('ConvTranspose2d.', '') in state_dict.keys():
            if key.endswith('weight'):
                new_state_dict[key] = torch.flip(state_dict[key.replace('ConvTranspose2d.', '')].permute([1,0,2,3]), dims=[-2,-1]) 
            else:
                new_state_dict[key] = state_dict[key.replace('ConvTranspose2d.', '')]

        else:
            raise(ValueError('key error!'))
    model_stream.load_state_dict(new_state_dict)

因为assert groups == 1了,所以这样暂时也没问题

Xiaobin-Rong commented 9 months ago

@SherryYu33

抱歉今天没有完全检验修改后代码的正确性。先按你目前这样修改吧,convert.py 里面对 groups 参数的获取目前确实是冗余的,去掉了也没关系。再次谢谢你的反馈!祝科研顺利!

SEMLLYCAT commented 8 months ago

@SherryYu33

非常感谢你的反馈。我尝试了这个偏差与膨胀无关,只与群体有关。这个错误是由于我在convert.py代码里将原模型中ConvTranspose2d的参数字典映射到StreamConvTranspose2d时犯了一个错误(简单地)根据权重的形状免费了)。现在我修改了convert.py来针对groups=1 和 ≠1 两种情况进行不同的权重映射处理。

然而,由于 pytorch 内部的 nn.Conv2d 和 nn.ConvTranspose2d 在参数形状上存在差异,先前的weight: (Cout, Cin/g, kw, kh),bias: (Cout);中部的weight: (Cin, Cout/g, kw, kh),偏差:(Cin),所以在流式处理中用 nn.Conv2d 来代替 nn.ConvTranspose2d 事实上不能在所有情况下都正确。例如,

DeConv = torch.nn.ConvTranspose2d(4, 8, (3,3), (1,2), padding=(0,1), dilation=(1,4), groups=2)
    SDC = StreamConvTranspose2d(4, 8, (3,3), (1,2), padding=(0,1), dilation=(1,4), groups=2)
    convert_to_stream(SDC, DeConv)

将会导致以下报错:

RuntimeError: Error(s) in loading state_dict for StreamConvTranspose2d:
        size mismatch for ConvTranspose2d.weight: copying a param with shape torch.Size([4, 4, 3, 3]) from checkpoint, the shape in current model is torch.Size([8, 2, 3, 3]).

目前我还没有想到一个好的解决方法,所幸一般模型里不会用到太复杂的情况。所以这里我直接在 StreamConvTranspose2s 中加了一个 groups==1 的语句。如果你有好的解决方案,欢迎提出,我将合并到代码里面并说明你的贡献,谢谢!

感谢作者的工作,请问目前ConvTranspose2d不同groups有新的解决方法吗

Xiaobin-Rong commented 8 months ago

@SEMLLYCAT @SherryYu33 我更新了 modules 里面的 convolution.py 和 convert.py,主要改动是将 StreamConvTranspose2d 直接用 nn.ConvTrabspose2d 来实现,而非原来的用 nn.Conv2d 实现。这样做比原来更简洁,而且避免了权重参数形状不一致的问题,因此对 groups 不为 1 的情况也能支持。 因为时间仓促,没有经过充分的测试,如在使用中有新的问题,欢迎再次反馈!

SherryYu33 commented 8 months ago

@Xiaobin-Rong 非常感谢您的工作!经过我的测试,和原先T维度截断的转置卷积结果也是一致的,并且groups也没有问题 再次感谢您的工作!

SEMLLYCAT commented 8 months ago

@SEMLLYCAT @SherryYu33 我更新了 modules 里面的 convolution.py 和 convert.py,主要改动是将 StreamConvTranspose2d 直接用 nn.ConvTrabspose2d 来实现,而非原来的用 nn.Conv2d 实现。这样做比原来更简洁,而且避免了权重参数形状不一致的问题,因此对 groups 不为 1 的情况也能支持。 因为时间仓促,没有经过充分的测试,如在使用中有新的问题,欢迎再次反馈!

非常感谢您的工作!目前验证正常,期待您更有优秀的作品。