一、前言
歸一化技術(shù)的改進(jìn)是生成對抗網(wǎng)絡(luò)(Generative Adversarial Networks, GAN)中眾多改進(jìn)的一種,本文介紹常用于當(dāng)前GAN中的像素歸一化(Pixel normalization,或稱為像素規(guī)范化)和頻譜歸一化(Spectral normalization,或稱頻譜規(guī)范化),在高清圖片生成中,這兩種歸一化技術(shù)得到了廣泛使用,最后使用Tensorflow2實現(xiàn)像素歸一化和頻譜歸一化。
二、像素歸一化
像素歸一化詳解
像素歸一化是在ProGAN模型中提出的,ProGAN的作者放棄了批歸一化,并為生成器使用了自定義歸一化,即像素歸一化。
在ProGAN中進(jìn)行歸一化的目的是限制權(quán)重值,以防止其呈指數(shù)增長。較大的權(quán)重可能會增大信號幅度,并導(dǎo)致生成器與鑒別器之間的惡性競爭。像素歸一化將通道尺寸中每個像素位置(H, W)的特征進(jìn)行歸一化。如果張量是大小為(N, H, W, C)的批RGB圖像,則像素歸一化后任何像素的RGB矢量的大小將均為1。
像素歸一化實現(xiàn)
在Tensorflow2中,可以使用自定義層來實現(xiàn)像素歸一化:
from tensorflow.keras.layers import Layer
class PixelNorm(Layer):
def __init__(self, epsilon=1e-8):
super(PixelNorm, self).__init__()
self.epsilon = epsilon
def call(self, input_tensor):
return input_tensor / tf.math.sqrt(tf.reduce_mean(input_tensor ** 2, axis=-1, keepdims=True) + self.epsilon)
與其他歸一化不同,像素歸一化沒有任何可學(xué)習(xí)的參數(shù)。它僅由簡單的算術(shù)運算組成,因此計算效率很高。
三、頻譜歸一化
頻譜歸一化詳解
為了解釋頻譜歸一化,首先需要復(fù)習(xí)下線性代數(shù)的知識,以大致解釋什么是頻譜范數(shù)。
首先溫故下矩陣?yán)碚撝械奶卣髦岛吞卣飨蛄浚?/p>

其中 AA 是一個方陣,vv 是特征向量,而 \lambdaλ 是其特征值。
我們將使用一個簡單的示例來理解這些術(shù)語。假設(shè) vv 是關(guān)于位置 (x, y)(x,y) 的向量,而 AA 是線性變換:

如果將AA乘以vv,我們將獲得一個新的位置,其方向改變?nèi)缦拢?/p>

特征向量是將 A 應(yīng)用于向量時不會改變方向的向量。取而代之的是,它們可以僅通過標(biāo)量特征值 λ\lambdaλ 進(jìn)行縮放??梢杂卸鄠€特征向量—特征值對。最大特征值得平方根是矩陣的譜范數(shù)。對于非方矩陣,我們將需要使用數(shù)學(xué)算法(例如奇異值分解(singular value decomposition, SVD))來計算特征值,這在計算上可能會非常昂貴。
因此,采用冪迭代法可以加快計算速度,使其對于神經(jīng)網(wǎng)絡(luò)訓(xùn)練具有可行性。接下來,在TensorFlow中實現(xiàn)頻譜歸一化作為權(quán)重約束。
頻譜歸一化實現(xiàn)
頻譜歸一化數(shù)學(xué)算法可能看起來很復(fù)雜。但是,通常,算法實現(xiàn)比數(shù)學(xué)上看起來更簡單。
以下是執(zhí)行頻譜歸一化的步驟:
1、卷積層中的權(quán)重是一個4維張量,因此第一步是將其重塑為2D矩陣,在這里我們保留權(quán)重的最后一個維度。重塑后,權(quán)重的形狀為(H×W, C)。
2、用N(0,1)N(0,1)N(0,1)初始化向量uuu。
3、在for循環(huán)中,計算以下內(nèi)容:

4、計算頻譜范數(shù)為uTwv。
5、最后,將權(quán)重除以頻譜范數(shù)。
完整的代碼如下:
import tensorflow as tf
class SpectralNorm(tf.keras.constraints.Constraint):
def __init__(self, n_iter=5):
self.n_iter = n_iter
def call(self, input_weights):
w = tf.reshape(input_weights, (-1, input_weights.shape[-1]))
u = tf.random.normal((w.shape[0], 1))
for _ in range(self.n_iter):
v = tf.matmul(w, u, transpose_a=True)
v /= tf.norm(v)
u = tf.matmul(w, v)
u /= tf.norm(u)
spec_norm = tf.matmul(u, tf.matmul(w, v), transpose_a=True)
return input_weights/spec_norm
迭代次數(shù)是一個超參數(shù),一般情況下 5 次就足夠了。頻譜歸一化也可以實現(xiàn)為具有一個變量來保存向量 uu,而不是從隨機值開始的。這會將迭代次數(shù)減少到 1。實現(xiàn)頻譜歸一化,我們可以通過將其用作卷積核約束來應(yīng)用頻譜歸一化,如:
Conv2D(3,1,kernel_constraint = SpectralNorm())
來源:掘金