判別器輸入通道使用 2 個通道與1個通道的差別

在圖像到圖像翻譯任務(例如您的字體風格轉換)中,判別器輸入通道的選擇取決於您希望判別器學習區分什麼。通常,使用 2 個通道 作為判別器的輸入是更常見且更合理的方法,原因如下:

使用 2 個通道 (拼接 A 和 B):

  • 學習聯合分佈: 判別器接收真實的 (input_A, target_B) 對和生成的 (input_A, fake_B) 對。它學習區分這兩種聯合分佈。這使得判別器能夠判斷生成的圖像 fake_B 是否不僅看起來像目標風格,而且是否與輸入圖像 input_A 在風格上是一致的
  • 更強的約束: 判別器可以學習輸入和輸出之間的依賴關係,這對於生成與輸入內容相關的風格化輸出非常重要。例如,在字體風格轉換中,判別器可以學習生成的目標字體風格應該保留輸入字體的結構。
  • 更符合任務目標: 您的目標是生成一個具有目標風格 B,但內容來自輸入 A 的圖像。因此,判別器需要評估生成的 fake_B 在給定 A 的情況下是否真實。

使用 1 個通道 (僅 B 或 fake_B):

  • 僅判斷圖像的真實性: 如果判別器只接收單個圖像(真實的 B 或生成的 fake_B),它只能學習判斷該圖像是否看起來像目標風格的真實樣本。它無法學習輸入 A 和輸出 B/fake_B 之間的關係。
  • 可能導致模式崩潰: 生成器可能會生成看起來逼真但與輸入 A 完全不相關的 fake_B,因為判別器只關注 fake_B 的風格真實性。
  • 忽略了條件資訊: 在條件生成任務中(以 A 為條件生成 B),忽略條件資訊(A)通常會導致生成結果不佳。

在您的代碼中:

您的 backward_D 方法中正確地將 real_Areal_B 拼接在一起作為真實樣本的輸入 (real_AB = torch.cat([self.real_A, self.real_B], 1)),並將 real_A 和生成的 fake_B 拼接在一起作為假樣本的輸入 (fake_AB = torch.cat([self.real_A, self.fake_B.detach()], 1))。這表明您的意圖是讓判別器學習聯合分佈。

因此,將判別器的第一個卷積層的輸入通道設置為 2 是正確且推薦的做法,以匹配您拼接後的輸入。這允許判別器學習輸入和輸出之間的關係,並更好地指導生成器生成符合任務要求的結果。

總結:

對於您的字體風格轉換任務,使用 2 個通道 作為判別器的輸入(通過拼接輸入圖像 A 和目標/生成圖像 B/fake_B)是更好的選擇,因為它可以讓判別器學習輸入和輸出之間的聯合分佈,並生成與輸入內容風格一致的結果。您在代碼中所做的拼接操作也支持了這一點。


好的,根據您提供的包含 Discriminator 類別的完整腳本,我們需要修改 Discriminator__init__ 方法,將第一個卷積層的 in_channels 參數設置為 2。

找到 Discriminator 類別的 __init__ 方法,並修改其第一個 nn.Conv2d 層的初始化:

Python

class Discriminator(nn.Module):
    def __init__(self, input_nc, embedding_num, ndf=64, norm_layer=nn.BatchNorm2d, blur=False):
        super(Discriminator, self).__init__()

        use_bias = norm_layer != nn.BatchNorm2d
        kw = 5
        padw = 2

        sequence = [
            nn.utils.spectral_norm(nn.Conv2d(2, ndf, kernel_size=kw, stride=2, padding=padw)), # 將 input_nc 改為 2
            nn.LeakyReLU(0.2, True)
        ]

        nf_mult = 1
        for n in range(1, 3):
            nf_mult_prev = nf_mult
            nf_mult = min(2 ** n, 8)
            sequence += [
                nn.utils.spectral_norm(nn.Conv2d(ndf * nf_mult_prev, ndf * nf_mult, kernel_size=kw, stride=2, padding=padw, bias=use_bias)),
                norm_layer(ndf * nf_mult),
                nn.LeakyReLU(0.2, True)
            ]

        sequence += [
            nn.utils.spectral_norm(nn.Conv2d(ndf * nf_mult, ndf * nf_mult, kernel_size=kw, stride=1, padding=padw, bias=use_bias)),
            norm_layer(ndf * nf_mult),
            nn.LeakyReLU(0.2, True)
        ]

        self.model = nn.Sequential(*sequence)
        self.global_pool = nn.AdaptiveAvgPool2d((4, 4))  # 自適應池化
        final_features = ndf * nf_mult * 4 * 4

        self.binary = nn.Linear(final_features, 1)
        self.category = nn.Linear(final_features, embedding_num)

        self.blur = blur
        if blur:
            self.gaussian_blur = T.GaussianBlur(kernel_size=3, sigma=1.0)

    def forward(self, input):
        if self.blur:
            input = self.gaussian_blur(input)

        features = self.model(input)
        features = self.global_pool(features)
        features = features.view(input.shape[0], -1)  # 展平成 batch x final_features

        binary_logits = self.binary(features)
        category_logits = self.category(features)
        return binary_logits, category_logits

修改說明:

Discriminator__init__ 方法中,將創建第一個卷積層的地方:

Python

nn.utils.spectral_norm(nn.Conv2d(input_nc, ndf, kernel_size=kw, stride=2, padding=padw)),

修改為:

Python

nn.utils.spectral_norm(nn.Conv2d(2, ndf, kernel_size=kw, stride=2, padding=padw)),

這樣,判別器的第一個卷積層就會期望接收 2 個輸入通道,與您在 backward_D 方法中拼接 real_Areal_B 後得到的 real_AB 的通道數相匹配,從而解決了 RuntimeError

請確保您在訓練腳本中使用的 Discriminator 類別是這個修改後的版本。

發佈留言

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