一.引言
上篇我們已經把風格融入在一個網路之中,實現了訓練一次就可以轉換不同的圖片成我們訓練的風格,但是這樣還不夠,因為這樣每個風格都得訓練一個網路來轉換,太浪費了,那麼,我們有沒有辦法在同一個網路中訓練多個風格呢?
二.方法說明
在上篇我們已證實了<圖-圖>的網路結構是有辦法處理風格轉換問題的,所以在主要網路結構方向及 Loss 設計上是沒什麼問題的,那麼只要讓網路能夠記憶不同風格時的權重變化,是不是就能夠在同一個網路中實現多風格的轉換呢 ?
基於這個想法,Google Brain 2017 提出的 A Learned Representation For Artistic Style 便在網路結構中加入了 Conditional Instance Normalization 機制,使網路能夠儲存多組風格的參數。
接著我們來解析 Conditional Instance Normalization 機制,Conditional Instance Normalization(以下簡稱CIN)從名字上可以知道他是一種 Normalization 方法,Normalization 通常用於控制輸入層的均值和標準差,以此來避免訓練過程中的梯度消失或爆炸,而 Instance Normalization 指將每個樣本獨立正則化,對每個樣本的每個通道進行獨立的 Normalization,計算方式為:
其中 x 是輸入特徵,μ(x) 和 σ(x) 分別是該特徵在空間維度上的均值和標準差。
而CIN中,不僅進行Instance Normalization,而且對Normalization後的輸出進行風格特定的規模和偏移調整:
這裡,γs 和 βs 是學習得到的風格特定參數,其中索引 s 表示特定的風格。這使得網絡可以根據選擇的風格動態調整其行為,每種風格都有一組專屬的 γ 和 β 值。
在每個 Conv / Residual 後都增加 CIN 模組,建置網路時便可以在 Conv / Residual 階段預置多組 γ 及 β,可以用來訓練不同風格的表現形態,接下來我們就來實作看看。
三.實際演練
本次實作主要擴充上一篇的程式,所以與論文內細節可能不一樣,但核心 CIN 部分是完整復刻了,詳細模組如下,詳細可參考我的Github :
class CIN(nn.Module):
def __init__(self, num_features, num_styles):
super(CIN, self).__init__()
self.num_features = num_features
self.num_styles = num_styles
# 初始化風格特定的 gamma 和 beta
self.gamma = nn.Parameter(torch.ones(num_styles, num_features))
self.beta = nn.Parameter(torch.zeros(num_styles, num_features))
def forward(self, x, style_id):
"""
x: 輸入特徵,維度為 (N, C, H, W)
style_id: 表示風格的整數索引,維度為 (N,)
"""
# 獲取每個樣本的 gamma 和 beta
gamma = self.gamma[style_id].view(-1, self.num_features, 1, 1)
beta = self.beta[style_id].view(-1, self.num_features, 1, 1)
# 計算特徵的均值和標準差
mean = x.mean(dim=[2, 3], keepdim=True)
std = x.std(dim=[2, 3], keepdim=True)
# 應用條件實例正則化
normalized = (x - mean) / (std + 1e-5)
out = normalized * gamma + beta
return out
本次預置了4個sytle,然後訓練 0 : 壁畫風格 、 1 : 彩繪玻璃風格、2/3未訓練,結果如下,可以看到兩種風格確實分散在不同的參數組中,而2/3則保持一致(上篇的新媒體藝術風格太過廣泛,替代成風格較統一的彩繪玻璃風格)。
四.結語
這次擴展了上篇的程式,加入了 CIN 模組讓模型能夠記憶不同風格的參數組合,所以目前的模型已經能做到同時訓練多個風格,且訓練完後可以轉換不同的圖像到已訓練風格,接下來還能做什麼呢 ?人類是貪心的,這樣還不夠,如果我只要預訓練幾種風格,後續使用其他風格時,若模型也能根據我提供的風格圖轉換的話豈不美哉,所以下一篇便是要介紹該如何再進化。