摘要:作者使用實現(xiàn)了,并將其開源放在了上。在年的兩個問題上分別取得了第一名和第二名。的獲取方式是第層,形狀為,的獲取方式是第層,形狀為。每個卷積核可以看做是圖形的一種特征抽取。相關(guān)性的描述使用余弦相似性,而余弦相似性又正比于兩種特征的點積。
Neural Style是一個非常有意思的深度學(xué)習(xí)應(yīng)用:輸入一張代表內(nèi)容的圖片和一張代表風(fēng)格的圖片,深度學(xué)習(xí)網(wǎng)絡(luò)會輸出一張融合了這個風(fēng)格和內(nèi)容的新作品。
TensorFlow是Google開源的最流行的深度學(xué)習(xí)框架。作者anishathalye使用TensorFlow實現(xiàn)了Neural Style,并將其開源放在了GitHub上。本文對他的代碼進(jìn)行深入剖析。代碼請點這里。
Pretrained VGG-19 ModelVGG在2014年的 ILSVRC localization and classification 兩個問題上分別取得了第一名和第二名。VGG-19是其中的一個模型,官網(wǎng)上提供了預(yù)先訓(xùn)練好的系數(shù),經(jīng)常被業(yè)界用來做原始圖片的特征變換。
VGG-19是一個非常深的神經(jīng)網(wǎng)絡(luò),總共有19層,基本結(jié)構(gòu)如下:
前幾層為卷積和maxpool的交替,每個卷積包含多個卷積層,最后面再緊跟三個全連接層。具體而言,第一個卷積包含2個卷積層,第二個卷積包含2個卷積層,第三個卷積包含4個卷基層,第四個卷積包含4個卷積層,第五個卷積包含4個卷基層,所以一共有16個卷積層,加上3個全連接層,一共19層,因此稱為VGG-19模型。VGG-19的神經(jīng)網(wǎng)絡(luò)結(jié)構(gòu)如下表所示:
Neural Style只依賴于VGG-19的卷積層,需要使用神經(jīng)網(wǎng)絡(luò)層列舉如下:
VGG19_LAYERS = ( "conv1_1", "relu1_1", "conv1_2", "relu1_2", "pool1", "conv2_1", "relu2_1", "conv2_2", "relu2_2", "pool2", "conv3_1", "relu3_1", "conv3_2", "relu3_2", "conv3_3", "relu3_3", "conv3_4", "relu3_4", "pool3", "conv4_1", "relu4_1", "conv4_2", "relu4_2", "conv4_3", "relu4_3", "conv4_4", "relu4_4", "pool4", "conv5_1", "relu5_1", "conv5_2", "relu5_2", "conv5_3", "relu5_3", "conv5_4", "relu5_4" )
我們可以從MatCovNet下載頁獲取VGG-19模型預(yù)先訓(xùn)練好的模型系數(shù)文件。該文件為Matlab格式,我們可以使用Python的scipy.io進(jìn)行數(shù)據(jù)讀取。
該數(shù)據(jù)包含很多信息,我們需要的信息是每層神經(jīng)網(wǎng)絡(luò)的kernels和bias。kernels的獲取方式是data["layers"][0][第i層][0][0][0][0][0],形狀為[width, height, in_channels, out_channels],bias的獲取方式是data["layers"][0][第i層][0][0][0][0][0],形狀為[1,out_channels]。對于VGG-19的卷積,全部采用了3X3的filters,所以width為3,height為3。注意,這里面的層數(shù)i,指的是最細(xì)粒度的層數(shù),包括conv、relu、pool、fc各種操作。因此,i=0為卷積核,i=1為relu,i=2為卷積核,i=3為relu,i=4為pool,i=5為卷積核,……,i=37為全連接層,以此類推。VGG-19的pooling采用了長寬為2X2的max-pooling,Neural Style將它替換為了average-pooling,因為作者發(fā)現(xiàn)這樣的效果會稍微好一些。
VGG-19需要對輸入圖片進(jìn)行一步預(yù)處理,把每個像素點的取值減去訓(xùn)練集算出來的RGB均值。VGG-19的RGB均值可以通過np.mean(data["normalization"][0][0][0], axis=(0, 1)獲得,其取值為[ 123.68 116.779 103.939]。
綜上所述,我們可以使用下面的代碼vgg.py讀取VGG-19神經(jīng)網(wǎng)絡(luò),用于構(gòu)造Neural Style模型。
import tensorflow as tf import numpy as np import scipy.io def load_net(data_path): data = scipy.io.loadmat(data_path) mean = data["normalization"][0][0][0] mean_pixel = np.mean(mean, axis=(0,1)) weights = data["layers"][0] return weights, mean_pixel def net_preloaded(weights, input_image, pooling): net = {} current = input_image for i, name in enumerate(VGG19_LAYERS): kind = name[:4] if kind == "conv": kernels, bias = weights[i][0][0][0][0] # matconvnet: weights are [width, height, in_channels, out_channels] # tensorflow: weights are [height, width, in_channels, out_channels] kernels = np.transpose(kernels, (1, 0, 2, 3)) bias = bias.reshape(-1) current = _conv_layer(current, kernels, bias) elif kind == "relu": current = tf.nn.relu(current) elif kind == "pool": current = _pool_layer(current, pooling) net[name] = current return net def _conv_layer(input, weights, bias): conv = tf.nn.conv2d(input, tf.constant(weights), strides=(1, 1, 1, 1), padding="SAME") return tf.nn.bias_add(conv, bias) def _pool_layer(input, pooling): if pooling == "avg": return tf.nn.avg_pool(input, ksize=(1, 2, 2, 1), strides=(1, 2, 2, 1), padding="SAME") else: return tf.nn.max_pool(input, ksize=(1, 2, 2, 1), strides=(1, 2, 2, 1), padding="SAME") def preprocess(image, mean_pixel): return image - mean_pixel def unprocess(image, mean_pixel): return image + mean_pixelNeural Style
Neural Style的核心思想如下圖所示:
Part 1: Content Reconstruction基本思路如下:將content圖片p和一張隨機(jī)生成的圖片x,都經(jīng)過VGG-19的卷積網(wǎng)絡(luò)進(jìn)行特征變換,獲取某些層級輸出的特征變換結(jié)果,要求二者的差異最小。二者在l層的損失函數(shù)定義如下:
其中F_{ij}^l為隨機(jī)圖片的第i個卷積核filter在位置j的取值,P_{ij}^l為content圖片的第i個卷積核filter在位置j的取值。
計算content圖片的feature map邏輯實現(xiàn)如下:
# 參數(shù)說明 # network為VGG-19文件的路徑 # content為內(nèi)容圖片轉(zhuǎn)化得到的數(shù)組 # pooling為池化方式 CONTENT_LAYERS = ("relu4_2", "relu5_2") # paper原文只使用了relu4_2 content_features = {} shape = (1,) + content.shape # input shape: [batch, height, width, channels], only one image, so batch=1. # 獲取VGG-19的訓(xùn)練系數(shù),和RGB均值 vgg_weights, vgg_mean_pixel = vgg.load_net(network) # 計算Content圖片的feature map g = tf.Graph() with g.as_default(), g.device("/cpu:0"), tf.Session() as sess: # 構(gòu)造Computation Graph,feed為image,輸出的net包含了VGG-19每個層級的輸出結(jié)果 image = tf.placeholder("float", shape=shape) net = vgg.net_preloaded(vgg_weights, image, pooling) # 將content進(jìn)行預(yù)處理 content_pre = np.array([vgg.preprocess(content, vgg_mean_pixel)]) # 將預(yù)處理后的content_pre feed給Computation Graph,得到計算結(jié)果 for layer in CONTENT_LAYERS: content_features[layer] = net[layer].eval(feed_dict={image: content_pre})
計算隨機(jī)圖片的feature map,并計算content loss的邏輯實現(xiàn)如下:
# 參數(shù)說明 # image為隨機(jī)生成的圖片 # pooling為池化方式 # content_weight_blend為兩個content重構(gòu)層的占比,默認(rèn)為1,只使用更精細(xì)的重構(gòu)層relu4_2;更抽象的重構(gòu)層relu5_2占比為1-content_weight_blend. # content_weight為內(nèi)容損失的系數(shù) with tf.Graph().as_default(): net = vgg.net_preloaded(vgg_weights, image, pooling) content_layers_weights = {} content_layers_weights["relu4_2"] = content_weight_blend content_layers_weights["relu5_2"] = 1.0 - content_weight_blend content_loss = 0 content_losses = [] for content_layer in CONTENT_LAYERS: content_losses.append(content_layers_weights[content_layer] * content_weight * (2 * tf.nn.l2_loss(net[content_layer] - content_features[content_layer]) / content_features[content_layer].size)) content_loss += reduce(tf.add, content_losses)Part 2: Style Reconstruction
從數(shù)學(xué)上定義什么是風(fēng)格,是Neural Style比較有意思的地方。每個卷積核filter可以看做是圖形的一種特征抽取。風(fēng)格在這篇paper中被簡化為任意兩種特征的相關(guān)性。相關(guān)性的描述使用余弦相似性,而余弦相似性又正比于兩種特征的點積。于是風(fēng)格的數(shù)學(xué)定義被表示為神經(jīng)網(wǎng)絡(luò)層里filter i和filter j的點積,用G_{ij}^l表示。
與Content Reconstruction中的損失定義相似,我們把style圖片和隨機(jī)生成的噪點圖片經(jīng)過相同的VGG-19卷積網(wǎng)絡(luò)進(jìn)行特征變換,選出指定層級的filters。對每個層級,計算兩張圖片特征變換后$G_{ij}^l$的差異。
各個層級的加權(quán)和就是最后的style loss:
計算style圖片的feature map邏輯實現(xiàn)如下:
# 參數(shù)說明 # styles為風(fēng)格圖片集,可以為多張圖片 # style_blend_weights為風(fēng)格圖片集之間的權(quán)重 # style_layers_weights為不同神經(jīng)網(wǎng)絡(luò)層的權(quán)重 STYLE_LAYERS = ("relu1_1", "relu2_1", "relu3_1", "relu4_1", "relu5_1") style_shapes = [(1,) + style.shape for style in styles] style_features = [{} for _ in styles] # 計算style圖片的feature map for i in range(len(styles)): g = tf.Graph() with g.as_default(), g.device("/cpu:0"), tf.Session() as sess: image = tf.placeholder("float", shape=style_shapes[i]) net = vgg.net_preloaded(vgg_weights, image, pooling) style_pre = np.array([vgg.preprocess(styles[i], vgg_mean_pixel)]) for layer in STYLE_LAYERS: features = net[layer].eval(feed_dict={image: style_pre}) features = np.reshape(features, (-1, features.shape[3])) # features.shape[3] is the number of filters gram = np.matmul(features.T, features) / features.size style_features[i][layer] = gram
計算隨機(jī)圖片的feature map,并計算style loss的邏輯實現(xiàn)如下:
# style loss style_loss = 0 for i in range(len(styles)): style_losses = [] for style_layer in STYLE_LAYERS: layer = net[style_layer] _, height, width, number = map(lambda i: i.value, layer.get_shape()) size = height * width * number feats = tf.reshape(layer, (-1, number)) gram = tf.matmul(tf.transpose(feats), feats) / size style_gram = style_features[i][style_layer] style_losses.append(style_layers_weights[style_layer] * 2 * tf.nn.l2_loss(gram - style_gram) / style_gram.size) style_loss += style_weight * style_blend_weights[i] * reduce(tf.add, style_losses) # tv_loss # 注:The total variation (TV) loss encourages spatial smoothness in the generated image. It was not used by Gatys et al in their CVPR paper but it can sometimes improve the results; for more details and explanation see Mahendran and Vedaldi "Understanding Deep Image Representations by Inverting Them" CVPR 2015. tv_loss = ... loss = content_loss + style_loss + tv_loss train_step = tf.train.AdamOptimizer(learning_rate, beta1, beta2, epsilon).minimize(loss)
將上述代碼有序組合在一起后,可以得到Neural Style TensorFlow代碼的第二個關(guān)鍵文件stylize.py。
參考資料VGG-19主頁
MatConvNet
Neural Style Paper
TensorFlow Neural Style Github開源項目
Neural Style中文解讀
VGG中文解讀
文章版權(quán)歸作者所有,未經(jīng)允許請勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。
轉(zhuǎn)載請注明本文地址:http://specialneedsforspecialkids.com/yun/38631.html
摘要:作者微信號微信公眾號簡書地址我把這篇文章分為四個部分機(jī)器學(xué)習(xí),,和數(shù)學(xué)。在這篇文章中,我把每個主題的教程數(shù)量都是控制在五到六個,這些精選出來的教程都是非常重要的。每一個鏈接都會鏈接到別的鏈接,從而導(dǎo)致很多新的教程。 作者:chen_h微信號 & QQ:862251340微信公眾號:coderpai簡書地址:http://www.jianshu.com/p/2be3... showIm...
摘要:在這堂課中,學(xué)生將可以學(xué)習(xí)到深度學(xué)習(xí)的基礎(chǔ),學(xué)會構(gòu)建神經(jīng)網(wǎng)絡(luò),包括和等。課程中也會有很多實操項目,幫助學(xué)生更好地應(yīng)用自己學(xué)到的深度學(xué)習(xí)技術(shù),解決真實世界問題。 深度學(xué)習(xí)入門首推課程就是吳恩達(dá)的深度學(xué)習(xí)專項課程系列的 5 門課。該專項課程最大的特色就是內(nèi)容全面、通俗易懂并配備了豐富的實戰(zhàn)項目。今天,給大家推薦一份關(guān)于該專項課程的核心筆記!這份筆記只能用兩個字形容:全面! showImg(...
閱讀 713·2023-04-25 17:54
閱讀 2971·2021-11-18 10:02
閱讀 1132·2021-09-28 09:35
閱讀 649·2021-09-22 15:18
閱讀 2847·2021-09-03 10:49
閱讀 3051·2021-08-10 09:42
閱讀 2572·2019-08-29 16:24
閱讀 1254·2019-08-29 15:08