1. 程式人生 > >影象風格遷移原理

影象風格遷移原理

所謂影象風格遷移,是指利用演算法學習著名畫作的風格,然後再把這種風格應用到另外一張圖片上的技術。著名的影象處理應用Prisma是利用風格遷移技術,普通使用者的照片自動變換為具有藝術家風格的圖片。

一、影象風格遷移的原理

1、原始影象風格遷移的原理

  在學習原始的影象風格遷移之前,可以在先看看ImageNet影象識別模型VGGNet(微調(Fine-tune)原理)。事實上,可以這樣理解VGGNet的結構:前面的卷積層是從影象中提取“特徵”,而後面的全連線層把圖片的“特徵”轉換為類別概率。其中,VGGNet中的淺層(如conv1_1,conv1_2),提取的特徵往往是比較簡單的(如檢測點、線、亮度),VGGNet中的深層(如conv5_1,conv5_2),提取的特徵往往比較複雜(如有無人臉或某種特定物體)。

  VGGNet本意是輸入影象,提取特徵,並輸出影象類別。影象風格遷移正好與其相反,輸入的是特徵,輸出對應這種特徵的圖片,如下圖所示:

   

  具體來說,風格遷移使用卷積層的中間特徵還原出對應這種特徵的原始影象。如下圖所示,先選取一幅原始影象,經過VGGNet計算後得到各個卷積層的特徵。接下來,根據這些卷積層的特徵,還原出對應這種特徵的原始影象。

   

  下面的a、b、c、d、e分別為使用conv1_2、conv2_2、conv3_2、conv4_2、conv5_2的還原影象。可以發現:淺層的還原效果往往比較好,卷積特徵基本保留了所有原始影象中形狀、位置、顏色、紋理等資訊;深層對應的還原影象丟失了部分顏色和紋理資訊,但大體保留原始影象中物體的形狀和位置。

   

  還原影象的方法是梯度下降法。設原始影象為$\vec{p}$,期望還原的影象為$\vec{x}$(即自動生成的影象)。使用的卷積是第$l$層,原始影象$\vec{p}$在第$l$層的卷積特徵為$P_{ij}^{l}$。$i$表示卷積的第$i$個通道,$j$表示卷積的第$j$個位置。通常卷積的特徵是三維的,三維座標分別對應(高、寬、通道)。此處不考慮具體的高和寬,只考慮位置$j$,相當於把卷積“壓扁”了。比如一個10x10x32的卷積特徵,對應$1\leqslant i\leqslant 32$,$1\leqslant j\leqslant 100$。對於生成影象$\vec{x}$,同樣定義它在$l$層的卷積特徵為$F_{ij}^{l}$。

  有了上面這些符號後,可以寫出“內容損失”(Content Loss)。內容損失$L_{content}(\vec{p},\vec{x},l)$的定義是:

  $L_{content}(\vec{p},\vec{x},l)=\frac{1}{2}\sum\limits_{i,j}(F_{ij}^{l}-P_{ij}^{l})^{2}$

  $L_{content}(\vec{p},\vec{x},l)$描述了原始影象$\vec{p}$和生成影象$\vec{x}$在內容上的“差異”。內容損失越小,說明它們的內容越接近;內容損失越大,說明它們的內容差距也越大。先使用原始影象$\vec{p}$計算出它的卷積特徵$P_{ij}^{l}$,同時隨機初始化$\vec{x}$。接著,以內容損失$L_{content}(\vec{p},\vec{x},l)$為優化目標,通過梯度下降法逐步改變$\vec{x}$。經過一定步數後,得到的$\vec{x}$是希望的還原影象了。在這個過程中,內容損失$L_{content}(\vec{p},\vec{x},l)$應該是越來越小的。

  除了還原影象原本的“內容”之外,另一方面,還希望還原影象的“風格”。那麼,影象的“風格”應該怎麼樣來表示呢?一種方法是使用影象的卷積層特徵的Gram矩陣。

  Gram矩陣是關於一組向量的內積的對稱矩陣,例如,向量組$\vec{x_{1}}$,$\vec{x_{2}}$,...,$\vec{x_{n}}$的Gram矩陣是

  $\begin{bmatrix}
(\vec{x_{1}},\vec{x_{1}}) &(\vec{x_{1}},\vec{x_{2}}) &... &(\vec{x_{1}},\vec{x_{n}}) \\
(\vec{x_{2}},\vec{x_{1}}) & (\vec{x_{2}},\vec{x_{2}}) & ... & (\vec{x_{2}},\vec{x_{n}})\\
...& ...& ...&... \\
(\vec{x_{n}},\vec{x_{1}})& (\vec{x_{n}},\vec{x_{2}}) & ... & (\vec{x_{n}},\vec{x_{n}})
\end{bmatrix}$

  通常取內積為歐幾里得空間上的標準內積,即$(\vec{x_{i}},\vec{x_{j}}) = \vec{x_{i}}^{T}\vec{x_{j}}$。

  設卷積層的輸出為$F_{ij}^{l}$,那麼這個卷積特徵對應的Gram矩陣的第$i$行第$j$個元素定義為

  $G_{ij}^{l}=\sum\limits_{k}F_{ik}^{l}F_{jk}^{l}$

  設在第$l$層中,卷積特徵的通道數為$N_{l}$,卷積的高、寬乘積為$M_{l}$,那麼$F_{ij}^{l}$滿足$1\leqslant i\leqslant N_{l}$,$1\leqslant j\leqslant M_{l}$。G實際是向量組$F_{1}^{l}$,$F_{2}^{l}$,...,$F_{i}^{l}$,...,$F_{N_{l}}^{l}$的Gram矩陣,其中,其中$F_{i}^{l}=(F_{i1}^{l},F_{i2}^{l},...,F_{ij}^{l},...,F_{iM_{l}}^{l})$。

  此處數學符號較多,因此再舉一個例子來加深讀者對此Gram矩陣的理解。假設某一層輸出的卷積特徵為10x10x32,即它是一個寬、高均為10,通道數為32的張量。$F_{1}^{l}$表示第一個通道的特徵,它是一個100維的向量,$F_{2}^{l}$表示第二個通道的特徵,它同樣是一個100維的向量,它對應的Gram矩陣G是

  $\begin{bmatrix}
(F_{1}^{l})^{T}(F_{1}^{l}) & (F_{1}^{l})^{T}(F_{2}^{l}) & ... &(F_{1}^{l})^{T}(F_{32}^{l}) \\
(F_{2}^{l})^{T}(F_{1}^{l}) & (F_{2}^{l})^{T}(F_{2}^{l}) & ... & (F_{2}^{l})^{T}(F_{32}^{l})\\
...& ... &... &... \\
(F_{32}^{l})^{T}(F_{1}^{l})& (F_{32}^{l})^{T}(F_{2}^{l}) & ... & (F_{32}^{l})^{T}(F_{32}^{l})
\end{bmatrix}$

  Gram矩陣可以在一定程度上反映原始圖片中的“風格” 。仿照“內容損失”,還可以定義一個“風格損失”(Style Loss)。設原始影象為$\vec{a}$,要還原的風格影象為$\vec{x}$,先計算出原始影象某一次卷積的Gram矩陣為$A^{l}$,要還原的影象$\vec{x}$經過同樣的計算得到對應卷積層的Gram矩陣是$G^{l}$,風格損失定義為

  $L_{style}(\vec{p},\vec{x},l)=\frac{1}{4N_{l}^{2}M_{l}^{2}}\sum \limits_{i,j}(A_{ij}^{l}-G_{ij}^{l})^{2}$

  分母上的$4N_{l}^{2}M_{l}^{2}$是一個歸一化項,目的是防止風格損失的數量級相比內容損失過大。在實際應用中,常常利用多層而非一層的風格損失,多層的風格損失是單層風格損失的加權累加,即$L_{style}(\vec{p},\vec{x})=\sum \limits_{i}w_{l}L_{style}(\vec{p},\vec{x},l)$,其中$w_{l}$表示第$l$層權重。

  利用風格損失,可以還原出影象的風格了。如下圖所示,嘗試還原梵高的著名畫作《星空》的風格。

   

   

  其中,圖a是由conv1_1的風格損失還原的,圖b是由conv1_1,conv2_1兩層的風格損失還原的,圖c是由conv1_1,conv2_1,conv3_1,圖d為conv1_1,conv2_1,conv3_1,conv4_1風格損失還原的。使用淺層還原的“風格影象”的紋理尺度往往比較小,只保留了顏色和區域性的紋理(如圖a);組合深層、淺層還原出的“風格影象”更加真實且接近原圖片(如圖e)。
總結一下,到目前為止介紹了兩個內容:

  (1)利用內容損失還原影象內容。
  (2)利用風格損失還原影象風格。

  那麼,可不可以將內容損失和風格損失結合起來,在還原一張影象的同時還原另一張影象的風格呢?答案是肯定的,這是影象風格遷移的基本演算法。

  設原始的內容影象為$\vec{p}$,原始的風格影象為$\vec{a}$,待生成的影象為$\vec{x}$。希望$\vec{x}$可以保持內容影象$\vec{p}$的內容,同時具備風格影象$\vec{a}$的風格。因此組合$\vec{p}$的內容損失和$\vec{a}$的風格損失,定義總的損失函式為

  $L_{total}(\vec{p},\vec{a},\vec{x})=\alpha L_{content}(\vec{p},\vec{x})+\beta L_{style}(\vec{a},\vec{x})$

  $\alpha$,$\beta$是平衡兩個損失的超引數。如果$\alpha$偏大,還原的影象會更接近於$\vec{p}$中,如果$\beta$偏大,還原的影象會更接近$\vec{a}$。使用總的損失函式可以組合$\vec{p}$的內容和$\vec{x}$的風格,這實現了影象風格的遷移。部分還原的影象如下圖所示

   

  以上是原始的影象風格遷移的基本原理。事實上,原始的影象風格遷移速度非常慢,在CPU上生成一張圖片需要數十分鐘甚至幾個小時,即使在GPU上也需要數分鐘才能生成一張較大的圖片,這大大的限制了這項技術的使用場景。速度慢的原因在於,要使用總損失$L_{total}(\vec{p},\vec{a},\vec{x})$優化圖片$\vec{x}$,這意味著生成一張圖片需要幾百步梯度下降法的迭代,而每一步的迭代都需要耗費大量的時間。從另一個角度看,優化$\vec{x}$可以看作是一個“訓練模型”的過程,以往都是針對模型引數訓練,而這裡訓練的目標是圖片$\vec{x}$,而訓練模型一般都比執行訓練好的模型要慢很多。下面將會講到快速影象風格遷移,它把原來的“訓練”的過程變成了一個“執行”的過程,因此大大加快了生成風格話圖片的過程。

二、快速影象風格遷移的原理

  原始的影象風格遷移用一個損失$L_{total}(\vec{p},\vec{a},\vec{x})$來衡量$\vec{x}$是否成功組合了$\vec{p}$的內容和$\vec{a}$的風格。然後以$L_{total}(\vec{p},\vec{a},\vec{x})$為目標,用梯度下降法來逐步迭代$\vec{x}$。因為在生成影象的過程中需要逐步對$\vec{x}$做優化,所以速度比較慢。

  快速影象風格遷移的方法是:不使用優化的方法來逐步迭代生成$\vec{x}$,而是使用一個神經網路之間生成$\vec{x}$。對應的網路結構如下圖所示:

   

  整個系統由兩個神經網路組成,它們在圖中由兩個虛線框分別標出。左邊的是影象生成網路,右邊是損失網路。損失網路實際上是VGGNet,這與原始的風格遷移是一致的。同原始影象風格遷移一樣,利用損失網路來定義內容損失、風格損失。這個損失用來訓練影象生成網路。影象生成網路的職責是生成某一種風格的影象,它的輸入是一個影象,輸出同樣是一個影象。由於生成影象只需要在網路中計算一遍,所以速度比原始影象風格遷移提高很多。

  同樣使用數學符號嚴格地闡述上面地過程:設輸入的影象為$\vec{x}$,經過影象生成網路生成的影象為$\vec{y}$。$\vec{y}$在內容上應該與原始的內容影象$\vec{y}_{c}$接近,因此可以利用損失網路定義內容損失$L_{content}(\vec{y},\vec{y}_{c})$,內容損失使用的是VGG-16中的relu3_3層輸出的特徵,對應上圖中的$l_{feat}^{\phi ,relu3\_3}$。另一方面,我們還希望$\vec{y}$具有目標風格影象$\vec{y}_{s}$的風格,因此又可以定義一個風格損失$L_{total}(\vec{y},\vec{y}_{c},\vec{y}_{s})$。定義風格損失時使用了VGG-16的四個中間層relu1_2,relu2_2,relu3_3,relu4_3,對應圖中的$l_{style}^{\phi ,relu1\_2}$、$l_{style}^{\phi ,relu2\_2}$、$l_{style}^{\phi ,relu3\_3}$、$l_{style}^{\phi ,relu4\_3}$。同樣組合這兩個損失得到一個總損失$L_{total}(\vec{y},\vec{y}_{c},\vec{y}_{s})$。利用總損失可以訓練影象生成網路。訓練完成後直接使用影象生成網路生成影象。值得一提的是,在整個訓練過程中,一般只固定一種風格$\vec{y}_{s}$,而內容影象$\vec{y}_{c}$取和輸入$\vec{x}$一樣,即$\vec{y}_{s}$=$\vec{x}$。

  下面詳細的比較原始影象風格遷移與快速影象風格遷移。

   

  這篇部落格詳細介紹了原始影象風格遷移的基本原理,其中內容損失、風格損失兩種損失函式的定義尤為關鍵。接著還介紹了快速影象風格遷移的原理,以及它和原始影象風格遷移的對比。

&n