A Neural Algorithm of Artistic Style 圖像風格轉換 - keras簡化版實現


前言

  • 深度學習是最近比較熱的詞語。說到深度學習的應用,第一個想到的就是Prisma App的圖像風格轉換。既然感興趣就直接開始干,讀了論文,一知半解;看了別人的源碼,才算大概了解的具體的實現,也驚嘆別人的奇思妙想。

聲明

  1. 代碼主要學習了【titu1994/Neural-Style-Transfer】
    的代碼,算是該項目部分的簡化版或者刪減版。這里做代碼的注解和解釋,也作為一個小玩具。
  2. 論文可以參考【A Neural Algorithm of Artistic Style】,網上也有中文的版本。
  3. 使用的工具:py34、keras1.1.2、theano0.8.2、GeForce GT 740M (CNMeM is disabled, cuDNN not available)。

實現原理

1. 總流程

  • 實現流程如下,可以看到這里總共分為5層,本次實驗使用vgg16模型實現的。

  • 如上,a有個別名是conv1_1,b是conv2_1,依次類推,c,d,e對應conv3_1conv4_1conv5_1;輸入圖片有風格圖片style image和內容圖片content image,輸出的是就是合成圖片,然后用合成圖片為指導訓練,但是訓練的對象不像是普通的神經網絡那樣訓練權值w和偏置項b,而是訓練合成圖片上的像素點,以達到損失函數不斷減少的效果。論文使用的是隨機的噪聲像素圖為初始合成圖,但是使用原始圖片會快一點。

2. 內容損失函數 - Content Loss

  • 下面是content loss函數的定義。

  • l代表第l層的特征表示,p是原始圖片,x是生成圖片。公式的含義就是對於每一層,原始圖片生成特征圖和生成圖片的特征圖的一一對應做平方差。

3. 風格損失函數 - style loss

  • 在定義風格損失函數之前首先定義一個Gram矩陣。

  • F是生成圖片的特征圖。上面式子的含義:Gram第i行,第j列的數值等於把生成圖在第l層的第i個特征圖與第j個特征圖分別拉成一維后相乘求和。

  • 上面是風格損失函數,Nl是指生成圖的特征圖數量,Ml是圖片寬乘高。a是指風格圖片,x是指生成圖片。G是生成圖的Gram矩陣,A是風格圖的Gram矩陣,wl是權重。

4. 總損失

  • 總損失函數如下,alphabeta比例為1*10^-3或更小。

代碼講解

1. 圖片預處理和還原

def preprocess_image(image_path):
    img = imread(image_path)
	// GPU顯存有限,這里使用400*400大小的圖片
    img = imresize(img, (400, 400)).astype('float32')

	// 這里要對RGB通道做預處理
	// 這里貌似是RGB的平均值,具體不清楚
    img = img[:, :, ::-1]
    img[:, :, 0] -= 103.939
    img[:, :, 1] -= 116.779
    img[:, :, 2] -= 123.68

    img = img.transpose((2, 0, 1)).astype("float32")
    img = np.expand_dims(img, axis=0)
    return img


def deprocess_image(x):
    x = x.reshape((3, 400, 400))
    x = x.transpose((1, 2, 0))

    x[:, :, 0] += 103.939
    x[:, :, 1] += 116.779
    x[:, :, 2] += 123.68

    x = x[:, :, ::-1]
    x = np.clip(x, 0, 255).astype('uint8')
    return x

2. content loss

def content_loss(base, combination):
    channel_dim = 0 if K.image_dim_ordering() == "th" else -1
    channels = K.shape(base)[channel_dim]
    size = 400 * 400

    multiplier = 1 / (2. * channels ** 0.5 * size ** 0.5)
    return multiplier * K.sum(K.square(combination - base))

3. style loss

def gram_matrix(x):
    assert K.ndim(x) == 3
    features = K.batch_flatten(x)
    gram = K.dot(features, K.transpose(features))
    return gram


def style_loss(style, combination):
    assert K.ndim(style) == 3
    assert K.ndim(combination) == 3

    S = gram_matrix(style)
    C = gram_matrix(combination)
    channels = 3
    size = 400 * 400
    return K.sum(K.square(S - C)) / (4. * (channels ** 2) * (size ** 2))

結果

輸入:

輸出:

分析

  1. 可以看出效果每一代都有進步,因為自己的顯卡渣,跑一代估計要1.5個小時,自己測試的時候總共跑了14個小時,不過這里有個技巧,就是可以把上一代的圖片繼續做輸入,這樣中途有什么事就可以停止。下次只要把上次輸出的圖片當輸入就可以。
  2. 因為是個小玩具,所以圖片的切割都是用ps切出來的。其他的什么mask都沒有實現。
  3. vgg16模型加載原項目的權值。
  4. 具體項目代碼可見【自己的github項目】上的代碼、權值文件和測試圖片,因為中途修改過,可能有些地方需要改過來,不過代碼比較簡單,估計很快就可以找到問題了。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM