GFPGAN icon indicating copy to clipboard operation
GFPGAN copied to clipboard

I want export "GFPGANCleanv1-NoCE-C2.pth" to ONNX

Open jjxxmiin opened this issue 2 years ago • 6 comments

I want to use dynamic weights in F.conv2d in pytorch.

    def forward(self, x, style):
        b, c, h, w = x.shape  # c = c_in

        style = self.modulation(style).view(b, 1, c, 1, 1)
        weight = self.weight * style  # (b, c_out, c_in, k, k)
        weight = weight.view(b * self.out_channels, c, self.kernel_size, self.kernel_size)

        b, c, h, w = x.shape
        x = x.view(1, b * c, h, w)

        out = F.conv2d(x, weight, padding=self.padding, groups=b)
        out = out.view(b, self.out_channels, *out.shape[2:4])

        return out

However, only constant weights are supported in Barracuda.

How can I change F.conv2d?

jjxxmiin avatar Mar 23 '22 02:03 jjxxmiin

+1

kelisiya avatar Mar 24 '22 09:03 kelisiya

+1

hhuiwang avatar May 06 '22 12:05 hhuiwang

+1

1105135335 avatar Aug 05 '22 02:08 1105135335

same question

Zwei-Rakete avatar Aug 09 '22 00:08 Zwei-Rakete

+1

baher3d avatar Aug 14 '22 23:08 baher3d

+1

magicse avatar Aug 15 '22 14:08 magicse

Hi @jjeamin , here some research to convert GFPGANv1.3-to-ncnn

magicse avatar Sep 20 '22 08:09 magicse

This should be work, I covert operations on weight to input(x), then GFPGAN model will be constant. 这种方法实测有效,我将对weight的操作等效修改为对x的操作,这样卷积的权重就是固定参数,模型就会从动态转换为静态。

class ModulatedConv2d(nn.Module):
    def __init__(self,
                 in_channels,
                 out_channels,
                 kernel_size,
                 num_style_feat,
                 demodulate=True,
                 sample_mode=None,
                 eps=1e-8):
        super(ModulatedConv2d, self).__init__()
        self.in_channels = in_channels
        self.out_channels = out_channels
        self.kernel_size = kernel_size`
        self.demodula`te = demodulate
        self.sample_mode = sample_mode
        self.eps = eps

        # modulation inside each modulated conv
        self.modulation = nn.Linear(num_style_feat, in_channels, bias=True)
        # initialization
        default_init_weights(self.modulation, scale=1, bias_fill=1, a=0, mode='fan_in', nonlinearity='linear')

        self.weight = nn.Parameter(
            torch.randn(1, out_channels, in_channels, kernel_size, kernel_size) /
            math.sqrt(in_channels * kernel_size**2))
        self.padding = kernel_size // 2
        self.conv2d = nn.Conv2d(in_channels, out_channels, kernel_size, stride=1, padding=self.padding, bias=False)
        self.conv2d.weight.data = self.weight.view(1 * self.out_channels, self.in_channels,self.kernel_size,self.kernel_size)

    def forward(self, x, style):
        b, c, h, w = x.shape  # c = c_in
        # weight modulation
        style = self.modulation(style).view(b, c, 1, 1)
        x = x * style
        if self.demodulate:
            if self.sample_mode == 'upsample':
                x = F.interpolate(x, scale_factor=2, mode='bilinear', align_corners=False)
            elif self.sample_mode == 'downsample':
                x = F.interpolate(x, scale_factor=0.5, mode='bilinear', align_corners=False)
            x = self.conv2d(x)
            weight = self.weight * style
            demod = torch.rsqrt(weight.pow(2).sum([2, 3, 4]) + self.eps)
            out = x * demod.view(b, self.out_channels, 1, 1)
        else:
            if self.sample_mode == 'upsample':
                x = F.interpolate(x, scale_factor=2, mode='bilinear', align_corners=False)
            elif self.sample_mode == 'downsample':
                x = F.interpolate(x, scale_factor=0.5, mode='bilinear', align_corners=False)
            x = x.view(1, b * c, h, w)
            out = self.conv2d(x)

        out = out.view(b, self.out_channels, *out.shape[2:4])

        return out

Zwei-Rakete avatar Sep 20 '22 09:09 Zwei-Rakete

some test converting for stylegan2 test

magicse avatar Sep 20 '22 10:09 magicse

Here project with GFPGANv1.3.onnx gfpgan Link to model GFPGANv1.3.onnx.prototxt

magicse avatar Sep 21 '22 07:09 magicse

WOW Many Thanks!!!!

jjxxmiin avatar Sep 22 '22 01:09 jjxxmiin

This should be work, I covert operations on weight to input(x), then GFPGAN model will be constant. 这种方法实测有效,我将对weight的操作等效修改为对x的操作,这样卷积的权重就是固定参数,模型就会从动态转换为静态。

class ModulatedConv2d(nn.Module):
    def __init__(self,
                 in_channels,
                 out_channels,
                 kernel_size,
                 num_style_feat,
                 demodulate=True,
                 sample_mode=None,
                 eps=1e-8):
        super(ModulatedConv2d, self).__init__()
        self.in_channels = in_channels
        self.out_channels = out_channels
        self.kernel_size = kernel_size`
        self.demodula`te = demodulate
        self.sample_mode = sample_mode
        self.eps = eps

        # modulation inside each modulated conv
        self.modulation = nn.Linear(num_style_feat, in_channels, bias=True)
        # initialization
        default_init_weights(self.modulation, scale=1, bias_fill=1, a=0, mode='fan_in', nonlinearity='linear')

        self.weight = nn.Parameter(
            torch.randn(1, out_channels, in_channels, kernel_size, kernel_size) /
            math.sqrt(in_channels * kernel_size**2))
        self.padding = kernel_size // 2
        self.conv2d = nn.Conv2d(in_channels, out_channels, kernel_size, stride=1, padding=self.padding, bias=False)
        self.conv2d.weight.data = self.weight.view(1 * self.out_channels, self.in_channels,self.kernel_size,self.kernel_size)

    def forward(self, x, style):
        b, c, h, w = x.shape  # c = c_in
        # weight modulation
        style = self.modulation(style).view(b, c, 1, 1)
        x = x * style
        if self.demodulate:
            if self.sample_mode == 'upsample':
                x = F.interpolate(x, scale_factor=2, mode='bilinear', align_corners=False)
            elif self.sample_mode == 'downsample':
                x = F.interpolate(x, scale_factor=0.5, mode='bilinear', align_corners=False)
            x = self.conv2d(x)
            weight = self.weight * style
            demod = torch.rsqrt(weight.pow(2).sum([2, 3, 4]) + self.eps)
            out = x * demod.view(b, self.out_channels, 1, 1)
        else:
            if self.sample_mode == 'upsample':
                x = F.interpolate(x, scale_factor=2, mode='bilinear', align_corners=False)
            elif self.sample_mode == 'downsample':
                x = F.interpolate(x, scale_factor=0.5, mode='bilinear', align_corners=False)
            x = x.view(1, b * c, h, w)
            out = self.conv2d(x)

        out = out.view(b, self.out_channels, *out.shape[2:4])

        return out

did it work for converting to onnx and the sesults are equal to the torcch model?

zimenglan-sysu-512 avatar Jul 26 '23 06:07 zimenglan-sysu-512