固定平滑卷積層(Fixed Smooth Convolutional Layer)FixedConvTranspose2d

為了在您的 U-Net 架構中避免 CNN 中常見的棋盤格失真(checkerboard artifacts),您可以考慮以下方法:


使用固定平滑卷積層(Fixed Smooth Convolutional Layer)

Kinoshita 和 Kiya 提出了一種固定平滑卷積層,透過使用具有可控平滑度的固定濾波器,來防止由轉置卷積(ConvTranspose2d)或下採樣操作引起的棋盤格失真。​這種方法不僅能消除失真,還能提升模型性能。​他們的實驗顯示,將固定平滑卷積層應用於各種 CNN 架構(如 VGG8、ResNet-18、ResNet-101)和生成對抗網絡(GANs)中,能有效提高分類和生成性能 。

FixedConv2dFixedConvTranspose2d 替換您現有的上採樣層:​

from fixed_smooth_conv import FixedConvTranspose2d

# 替換原有的 ConvTranspose2d
upconv = FixedConvTranspose2d(in_channels, out_channels, kernel_size=4, stride=2, padding=1)

以下是 FixedConvTranspose2d 的完整 PyTorch 實作,旨在透過固定的平滑濾波器來減少轉置卷積(ConvTranspose2d)所產生的棋盤格失真(checkerboard artifacts):

import torch
import torch.nn as nn
import torch.nn.functional as F

class FixedConvTranspose2d(nn.Module):
    def __init__(self, in_channels, out_channels, kernel_size=4, stride=2, padding=1, bias=False, mode='avg'):
        super(FixedConvTranspose2d, self).__init__()
        self.mode = mode
        self.stride = stride
        self.padding = padding
        self.kernel_size = kernel_size

        # 使用固定權重的轉置卷積層
        self.fixed_weight = self._create_fixed_weight(in_channels, out_channels, kernel_size, mode)
        self.register_buffer('weight', self.fixed_weight)
        self.bias = None
        if bias:
            self.bias = nn.Parameter(torch.zeros(out_channels))

    def _create_fixed_weight(self, in_channels, out_channels, kernel_size, mode):
        if mode == 'avg':
            # 建立平均濾波器
            weight = torch.ones(out_channels, in_channels, kernel_size, kernel_size)
            weight /= kernel_size * kernel_size
        elif mode == 'gaussian':
            # 建立高斯濾波器
            def gaussian_kernel(size, sigma=1.0):
                coords = torch.arange(size).float() - size // 2
                grid = coords.unsqueeze(0) ** 2 + coords.unsqueeze(1) ** 2
                kernel = torch.exp(-grid / (2 * sigma ** 2))
                kernel /= kernel.sum()
                return kernel

            kernel = gaussian_kernel(kernel_size)
            weight = kernel.expand(out_channels, in_channels, kernel_size, kernel_size).clone()
        else:
            raise ValueError(f"Unsupported mode: {mode}")
        return weight

    def forward(self, x):
        return F.conv_transpose2d(
            x,
            self.weight,
            bias=self.bias,
            stride=self.stride,
            padding=self.padding
        )

這個類別提供了兩種模式:avg(平均濾波器)和 gaussian(高斯濾波器),您可以根據需求選擇適合的模式。這些固定的濾波器有助於在上採樣過程中減少棋盤格失真。

要將此類別整合到您的 UNet 架構中,您可以在上採樣的部分替換原本的 ConvTranspose2dFixedConvTranspose2d。例如,在 UnetSkipConnectionBlock 中,您可以這樣修改:

if self.up_mode == 'conv':
    upconv = FixedConvTranspose2d(inner_nc * 2, outer_nc, kernel_size=4, stride=2, padding=1, bias=use_bias, mode='avg')

這樣的修改將有助於減少模型在生成圖像時出現的棋盤格失真,提升生成圖像的品質。

如果您需要進一步的協助來整合這個類別到您的完整 UNet 架構中,請隨時告訴我。


平均濾波器(average filter)和高斯濾波器(Gaussian filter)都是常用於影像平滑的濾波器,但它們的行為與效果有一些關鍵差異,以下是詳細比較:


1. 濾波權重分布

濾波器權重分布說明
平均濾波器每個像素權重一樣所有鄰近像素均等影響中心像素,等於做區域平均。
高斯濾波器中心像素權重高,越遠越小按照高斯分佈加權,中心像素對結果影響最大。更符合自然圖像模糊。

2. 平滑效果與邊界保持

特性平均濾波器高斯濾波器
邊界保持能力弱,容易模糊邊緣較強,對邊界模糊較少
去除雜訊效果對隨機雜訊有效,但模糊整體影像更自然地去雜訊,細節保留較多

3. 計算效率

特性平均濾波器高斯濾波器
速度更快,簡單平均運算略慢,需加權運算(但可用 separable kernel 加速)
實作簡單度非常簡單稍微複雜(需要生成高斯核)

4. 視覺比較範例(簡化說明)

假設 3×3 濾波器:

  • 平均濾波器權重: 1/9 1/9 1/9 1/9 1/9 1/9 1/9 1/9 1/9
  • 高斯濾波器權重(σ=1 範例): 1 2 1 2 4 2 ← 除以 16 正規化後 1 2 1

應用建議

情境建議使用
快速去雜訊但不重視細節平均濾波器
去雜訊又希望保留邊緣與細節高斯濾波器
用於 上採樣反卷積(避免棋盤格)高斯濾波更自然

需要我幫你實作 FixedConvTranspose2d 中加入 gaussian 模式的自動核生成功能嗎?也可以根據指定的 kernel size 和 sigma 來調整。


為了解決 staircase artifact(樓梯狀失真) 問題,建議使用 gaussian 模式的平滑濾波器,原因如下:


🎯 為什麼 Gaussian 比 Average 好?

特性平均濾波器(Average)高斯濾波器(Gaussian)
🎢 抑制 staircase artifact一定程度可抑制,但可能導致過度模糊✅ 更有效平滑高頻震盪,並保留自然邊緣
👁️ 模糊感模糊感較重,且對所有像素影響相等✅ 中心權重大,模糊較自然,減少不必要的邊緣損失
📈 實際應用中的觀察在 ConvTranspose2d 後加平均濾波,有時仍殘留棋盤格感✅ 高斯濾波更穩定,效果佳且常見於 super-resolution 等研究中

推薦:使用 Gaussian smoothing 解決 staircase

  • 若你使用 ConvTranspose2d 作為上採樣方式:
    • 加入 FixedConvTranspose2d(mode='gaussian') 可顯著降低棋盤格。
    • 📐 可進一步調整 kernel_size(例如 5 或 7)與 sigma(例如 1.0–2.0)以最佳化效果。

🛠️ 額外建議:

  • 若仍有 artifact,可加上:
    • 🔹 blur 後再 residual skip(跳連接)
    • 🔹 或搭配 pixelshuffle + blur 混合策略(hybrid upsampling)
    • 🔹 或加 anti-aliasing 卷積(如 BlurPool

需要我幫你在你的 FixedConvTranspose2d 裡加入 gaussian 核生成功能 + 範例程式碼嗎?


你可以在 UnetSkipConnectionBlockup_mode 中增加新的模式,例如:'fixedconv',搭配 FixedConvTranspose2d 使用。以下是擴充的範例,包含 FixedConvTranspose2d 的實作與整合方式:


🔧 1. 定義 FixedConvTranspose2d

class FixedConvTranspose2d(nn.Module):
    def __init__(self, in_channels, out_channels, kernel_size=4, stride=2, padding=1, mode='avg'):
        super(FixedConvTranspose2d, self).__init__()
        self.stride = stride
        self.mode = mode
        self.upsample = nn.Upsample(scale_factor=stride, mode='nearest')
        self.kernel_size = kernel_size
        self.pad = padding

        if mode == 'avg':
            kernel = torch.ones(out_channels, in_channels, kernel_size, kernel_size)
        elif mode == 'gaussian':
            base = torch.tensor([[1., 2., 1.],
                                 [2., 4., 2.],
                                 [1., 2., 1.]])
            base /= base.sum()
            kernel = base[None, None, :, :].repeat(out_channels, in_channels, 1, 1)
        else:
            raise ValueError(f"Unsupported mode: {mode}")

        self.register_buffer('weight', kernel)

    def forward(self, x):
        x = self.upsample(x)
        x = F.pad(x, (self.pad, self.pad, self.pad, self.pad), mode='reflect')
        return F.conv2d(x, self.weight, groups=1)

🔁 2. 在 UnetSkipConnectionBlock 增加支援

在所有 up_mode 的判斷中新增一個分支:

elif self.up_mode == 'fixedconv':
    upconv = FixedConvTranspose2d(inner_nc * 2 if not innermost else inner_nc,
                                   outer_nc, kernel_size=3, stride=2, padding=1, mode='avg')
    upnorm = norm_layer(outer_nc)
    self.up = nn.Sequential(uprelu, upconv, upnorm)

最終你的 up_mode 判斷就可以支援 'conv''upsample''pixelshuffle''fixedconv',甚至 'hybrid'


✅ 使用方式

model = UNetGenerator(up_mode='fixedconv')

你也可以選擇將 'fixedconv' 做為 'hybrid' 中的一部分,例如只在特定層使用。


有需要我幫你加到現有 script 的每個區塊嗎?我可以直接幫你 patch 完整版本。

發佈留言

發佈留言必須填寫的電子郵件地址不會公開。 必填欄位標示為 *