圖像生成-ICCV2019-SinGAN: Learning a Generative Model from a Single Natural Image
文章目錄
- 圖像生成-ICCV2019-SinGAN: Learning a Generative Model from a Single Natural Image
- 主要創新點
- 模型架構圖
- 生成器
- 生成器源碼
- 判別器
- 判別器源碼
- 損失函數
- 需要源碼講解的私信我
SinGAN 通過多尺度全卷積 GAN 金字塔結構,從單張自然圖像中學習內部 patch 分布,無需條件輸入即可生成多樣化、高質量的新圖像,并適用于廣泛的圖像處理任務。
論文鏈接:SinGAN: Learning a Generative Model from a Single Natural Image
源碼鏈接:/tamarott/SinGAN
主要創新點
- 單圖像內部統計學習:SinGAN 通過多尺度 patch-GAN 層次結構,從單張圖像中學習其內部統計信息,而不是依賴于整個數據庫中的圖像樣本
- 多尺度結構捕獲圖像特征:每個 patch-GAN 負責捕獲圖像在不同尺度下的 patch 分布,能夠同時學習全局結構(如大物體的排列)和細節紋理信息。
- 突破傳統紋理生成:與傳統的紋理生成方法不同,SinGAN 不僅局限于生成紋理圖像,而是處理更復雜的自然圖像結構,能夠生成具有全局一致性和細節多樣性的高質量圖像。
- 多尺度生成器金字塔: SinGAN 使用多尺度生成器金字塔
{G0, ..., GN}
,每個生成器在不同尺度上生成與對應下采樣版本圖像相符的真實圖像樣本,通過對抗訓練實現生成器和判別器的博弈。生成過程從粗糙尺度開始,逐步通過各生成器添加細節,并通過上采樣前一尺度的生成圖像細化全局結構,同時確保噪聲在每個尺度上得到充分利用。
模型架構圖
主要由一下幾部分組成:
- 生成器:對于生成器是由下往上訓練的,生成器采用五個全卷積層來實現,對于不同層次生成器接收到的東西也隨著層數遞增也不一樣的,不同層次輸入的圖像大小也不一樣,其實就是和StyleGan的原理是一樣的,對應于StyleGan的潛在向量空間latent。
- 判別器:判別器和生成器一樣的, 根據尺度不一樣而一一對應,判別器就是要把生成器生成的判別為假,真的判別為真
- 多層次噪聲優化 : 對于生成器會隨機初始化一個噪聲輸入到生成器的中,噪聲對于圖像的影響也會很大,通常的做法是統計整個數據集的一些特征來對噪聲進行初始化,本文中是對于下一層次生成的圖像和噪聲來拼接生成,來補充噪聲的信息。
生成器
多尺度生成器金字塔:模型包含一個由生成器組成的金字塔 {G0, …, GN},每個生成器 Gn 對應于圖像的一個尺度 xn,其中 xn 是通過因子 rn 對原始圖像 x 進行下采樣得到的。生成器 Gn 的任務是生成與圖像 xn 中的 patch 分布相符的真實圖像樣本。
生成過程:圖像生成從最粗的尺度(GN)開始,并通過每個生成器逐步到達最精細的尺度。在每個尺度上,生成器 Gn 通過與對應尺度的判別器 Dn 進行對抗訓練,學習生成與訓練圖像 xn 中的 patch 區分不出的樣本。
細節添加:在生成過程中,每個生成器不僅生成新的細節,還將前一個尺度的生成圖像 ?xn+1 上采樣到當前尺度后,與當前的噪聲 zn 一起輸入到卷積層中。這個操作確保了每個尺度上的細節添加和圖像的結構細化。
噪聲和圖像合成:每個生成器的輸入包括隨機噪聲 zn 和上采樣后的前一尺度圖像 ?xn+1。生成器通過卷積層進行殘差學習,生成缺失的細節,最終得到當前尺度的圖像輸出 ?xn。
自適應生成大小:由于生成器是全卷積的,它們能夠在測試時生成任意大小和縱橫比的圖像,只需調整噪聲圖的維度。
生成器源碼
class GeneratorConcatSkip2CleanAdd(nn.Module):def __init__(self, opt):super(GeneratorConcatSkip2CleanAdd, self).__init__()self.is_cuda = torch.cuda.is_available() # 判斷是否有 GPUN = opt.nfc # 初始化卷積層輸出通道數# 定義頭部卷積層,處理輸入圖像self.head = ConvBlock(opt.nc_im, N, opt.ker_size, opt.padd_size, 1) self.body = nn.Sequential() # 存儲中間卷積層# 構建中間層for i in range(opt.num_layer - 2):N = int(opt.nfc / pow(2, (i + 1))) # 每層輸出通道數逐步減少block = ConvBlock(max(2 * N, opt.min_nfc), max(N, opt.min_nfc), opt.ker_size, opt.padd_size, 1)self.body.add_module('block%d' % (i + 1), block) # 添加到 body 中# 定義尾部卷積層,用于輸出最終圖像self.tail = nn.Sequential(nn.Conv2d(max(N, opt.min_nfc), opt.nc_im, kernel_size=opt.ker_size, stride=1, padding=opt.padd_size),nn.Tanh() # 使用 Tanh 激活函數輸出圖像)def forward(self, x, y):# 經過頭部卷積層處理輸入 xx = self.head(x)# 通過中間卷積層x = self.body(x)# 通過尾部卷積層生成圖像x = self.tail(x)# 根據 y 和 x 的尺寸差值進行裁剪,確保兩者尺寸相同ind = int((y.shape[2] - x.shape[2]) / 2)y = y[:, :, ind:(y.shape[2] - ind), ind:(y.shape[3] - ind)]# 將生成的圖像與輸入 y 相加return x + y
判別器
判別器與生成器的關系:
- 每個生成器
Gn
都配有一個對應的判別器Dn
,目的是通過對比生成圖像與真實圖像之間的差異,指導生成器改進生成的圖像。- 判別器
Dn
的目標是判別每個輸入圖像塊是“真實”圖像塊(來自原始圖像xn
)還是“偽造”圖像塊(由生成器生成的圖像塊)。- 損失函數:
- 判別器使用 WGAN-GP 損失(Wasserstein GAN with Gradient Penalty)來訓練,以確保訓練過程的穩定性。通過計算生成樣本和真實圖像樣本在各自圖像塊上的判別結果,最終得出一個平均的判別分數。
- 判別器的損失不僅針對單個圖像塊,還針對整個圖像進行定義,這有助于學習整個圖像的結構,特別是邊界條件,而不僅僅是關注圖像的局部區域。
判別器源碼
class WDiscriminator(nn.Module):def __init__(self, opt):super(WDiscriminator, self).__init__()self.is_cuda = torch.cuda.is_available() # 檢查是否有可用的GPUN = int(opt.nfc) # 初始通道數self.head = ConvBlock(opt.nc_im, N, opt.ker_size, opt.padd_size, 1) # 第一層卷積塊self.body = nn.Sequential() # 中間層,包含多個卷積塊for i in range(opt.num_layer - 2): # 添加多層卷積塊,num_layer指定總層數N = int(opt.nfc / pow(2, (i + 1))) # 根據層數逐漸減少通道數block = ConvBlock(max(2 * N, opt.min_nfc), max(N, opt.min_nfc), opt.ker_size, opt.padd_size, 1) # 創建每一層卷積塊self.body.add_module('block%d' % (i + 1), block) # 添加每一層卷積塊到序列self.tail = nn.Conv2d(max(N, opt.min_nfc), 1, kernel_size=opt.ker_size, stride=1, padding=opt.padd_size) # 輸出層,1個輸出通道def forward(self, x):x = self.head(x) # 通過第一層卷積塊x = self.body(x) # 通過中間層的多個卷積塊x = self.tail(x) # 通過輸出層return x # 返回最終的輸出