百度360必应搜狗淘宝本站头条
当前位置:网站首页 > 编程字典 > 正文

神经风格迁移简介及实现

toyiye 2024-06-21 12:07 10 浏览 0 评论

使用Neural Style Transfer算法生成示例

介绍

神经网络在过去几年中已被广泛应用于图像识别。最酷的应用之一是Leon A. Gatys最初提出的神经风格迁移算法。该算法使用预训练的模型和简单的优化过程,将两个独立图像的风格和内容组合成一副图像。

使用神经风格迁移将内容和风格图像组合成单个图像

直觉

任何图像都可以被认为有两个组成部分:

  • 内容:图像中的对象及其空间排列
  • 风格:纹理,视觉图案和配色方案

让我们将我们想要复制的内容的图像定义为I_CONTENT,并将我们想要复制的风格图像定义为I_STYLE。然后,目标是生成一个内容为I_CONTENT且风格为I_STYLE的图像(I_TARGET)。

为了实现这一点,首先对一个最初填充随机像素的图像进行迭代修改,直到实现所需的内容和风格。

噪音图像转换为具有预定义图像的内容和风格特征的图像的迭代步骤

它是如何工作的?

我们可以看到,对最初有噪声的图像进行迭代修改以匹配所选图像的内容和风格。

但是,我们如何衡量两个图像之间的内容相似性或风格相似度呢?这就是预训练卷积神经网络(CNN)发挥作用的地方。

C???,S???和T???是层l的第i个特征映射的第j个激活,内容、风格和目标图像通过预训练网络传递。H,W和C指的是层l的高度,宽度和通道数。

内容损失

在用于对象检测的巨大图像数据集上训练的卷积神经网络(CNN)的高层学习,显式地识别和学习图像中对象(内容)表示,而不是学习精确的像素值。

因此,在较高层生成类似feature map激活的图像将具有类似的内容。形式上,我们可以将层l测得的内容损失定义为:

第1层图像X和Y之间的内容损失度量

这基本上是当通过卷积神经网络(CNN)时图像X和图像Y的各个激活之间的归一化平方误差。

风格损失

风格被测量为特定层处的不同feature map激活之间的相关性。这在Gram矩阵(G)中正式表示为::

Gram Matrix:当图像X通过时,捕获神经网络的第1层的不同feature map之间的相关性

G???捕获层l处第i个和第j个之间的feature map相关性,因此,第l层测得的风格损失定义为:

在层l处的图像X和Y之间测量的风格损失

请注意,可以在网络的不同层测量内容损失和风格损失,以形成最终的损失函数。

c?和s?是分别在第l层计算的内容和风格损失的权重。α和β分别是给予总体内容和风格损失的权重。

在最初的实现中,VGG-19被用作预训练的CNN,并且已经使用了内容和风格层的不同组合。

Python实现

步骤1:我们需要预训练的VGG19模型权重来计算每次迭代时的损失。我们将构建一个字典,将层名称映射到包含每层VGG19图层权重的张量。

import tensorflow as tf
from tensorflow import keras
import numpy as np
import os, shutil
import random
import matplotlib.pyplot as plt
import string
import cv2
from google.colab.patches import cv2_imshow
import scipy

model.layers包含每层的权重张量。

对于每个卷积层i,model.layers [i] .weights [0]有filter权重,model.layers [i] .weights [1]有偏差权重。

我们将提取这些值并将它们添加到字典weights_dict中。

def getModelWeightsAsDict():
 keras.backend.clear_session()
 tf.reset_default_graph()
 model = keras.applications.VGG19(input_shape=(IMAGE_SIZE,IMAGE_SIZE,3),include_top=False,weights='imagenet')
 
 with keras.backend.get_session() as sess:
 weights_dict = {}
 for i in range(len(model.layers)):
 weights_dict['layer_' + str(i)] = []
 for j in range(len(model.layers[i].weights)):
 weights_dict['layer_' + str(i)].append(sess.run(model.layers[i].weights[j]))
 tf.reset_default_graph()
 return weights_dict

第2步:我们将构建一个复制VGG19网络连接和权重的Tensorflow图。但是,我们将把输入张量设置为tf.Variable(),并使用步骤1中存储的权重定义图。这是因为我们不会训练网络的权值,我们只会修改输入张量来最小化定义的损失。

像以前一样,我们将对应于每一层的张量存储在字典中。

def get_nst_model(weights_dict):
 layers = {}
 image_shape = (IMAGE_SIZE,IMAGE_SIZE,3)
 layers['input'] = tf.Variable(initial_value=tf.initializers.random_normal().__call__((1,)+image_shape),expected_shape=(1,)+image_shape,
 name='nst_output',dtype=tf.float32)
 layers['conv1_1'] = tf.nn.relu(tf.nn.bias_add(tf.nn.convolution(layers['input'],weights_dict['layer_1'][0],padding='SAME',strides=(1,1)),
 weights_dict['layer_1'][1]))
 layers['conv1_2'] = tf.nn.relu(tf.nn.bias_add(tf.nn.convolution(layers['conv1_1'],weights_dict['layer_2'][0],padding='SAME',strides=(1,1)),
 weights_dict['layer_2'][1]))
 layers['pool1'] = tf.nn.avg_pool(layers['conv1_2'],ksize=(1,2,2,1),strides=(1,2,2,1),padding='VALID')
 layers['conv2_1'] = tf.nn.relu(tf.nn.bias_add(tf.nn.convolution(layers['pool1'],weights_dict['layer_4'][0],padding='SAME',strides=(1,1)),
 weights_dict['layer_4'][1]))
 layers['conv2_2'] = tf.nn.relu(tf.nn.bias_add(tf.nn.convolution(layers['conv2_1'],weights_dict['layer_5'][0],padding='SAME',strides=(1,1)),
 weights_dict['layer_5'][1]))
 layers['pool2'] = tf.nn.avg_pool(layers['conv2_2'],ksize=(1,2,2,1),strides=(1,2,2,1),padding='VALID')
 layers['conv3_1'] = tf.nn.relu(tf.nn.bias_add(tf.nn.convolution(layers['pool2'],weights_dict['layer_7'][0],padding='SAME',strides=(1,1)),
 weights_dict['layer_7'][1]))
 layers['conv3_2'] = tf.nn.relu(tf.nn.bias_add(tf.nn.convolution(layers['conv3_1'],weights_dict['layer_8'][0],padding='SAME',strides=(1,1)),
 weights_dict['layer_8'][1]))
 layers['conv3_3'] = tf.nn.relu(tf.nn.bias_add(tf.nn.convolution(layers['conv3_2'],weights_dict['layer_9'][0],padding='SAME',strides=(1,1)),
 weights_dict['layer_9'][1]))
 layers['conv3_4'] = tf.nn.relu(tf.nn.bias_add(tf.nn.convolution(layers['conv3_3'],weights_dict['layer_10'][0],padding='SAME',strides=(1,1)),
 weights_dict['layer_10'][1]))
 layers['pool3'] = tf.nn.avg_pool(layers['conv3_4'],ksize=(1,2,2,1),strides=(1,2,2,1),padding='VALID')
 layers['conv4_1'] = tf.nn.relu(tf.nn.bias_add(tf.nn.convolution(layers['pool3'],weights_dict['layer_12'][0],padding='SAME',strides=(1,1)),
 weights_dict['layer_12'][1]))
 layers['conv4_2'] = tf.nn.relu(tf.nn.bias_add(tf.nn.convolution(layers['conv4_1'],weights_dict['layer_13'][0],padding='SAME',strides=(1,1)),
 weights_dict['layer_13'][1]))
 layers['conv4_3'] = tf.nn.relu(tf.nn.bias_add(tf.nn.convolution(layers['conv4_2'],weights_dict['layer_14'][0],padding='SAME',strides=(1,1)),
 weights_dict['layer_14'][1]))
 layers['conv4_4'] = tf.nn.relu(tf.nn.bias_add(tf.nn.convolution(layers['conv4_3'],weights_dict['layer_15'][0],padding='SAME',strides=(1,1)),
 weights_dict['layer_15'][1]))
 layers['pool4'] = tf.nn.avg_pool(layers['conv4_4'],ksize=(1,2,2,1),strides=(1,2,2,1),padding='VALID')
 layers['conv5_1'] = tf.nn.relu(tf.nn.bias_add(tf.nn.convolution(layers['pool4'],weights_dict['layer_17'][0],padding='SAME',strides=(1,1)),
 weights_dict['layer_17'][1]))
 layers['conv5_2'] = tf.nn.relu(tf.nn.bias_add(tf.nn.convolution(layers['conv5_1'],weights_dict['layer_18'][0],padding='SAME',strides=(1,1)),
 weights_dict['layer_18'][1]))
 layers['conv5_3'] = tf.nn.relu(tf.nn.bias_add(tf.nn.convolution(layers['conv5_2'],weights_dict['layer_19'][0],padding='SAME',strides=(1,1)),
 weights_dict['layer_19'][1]))
 layers['conv5_4'] = tf.nn.relu(tf.nn.bias_add(tf.nn.convolution(layers['conv5_3'],weights_dict['layer_20'][0],padding='SAME',strides=(1,1)),
 weights_dict['layer_20'][1]))
 layers['pool5'] = tf.nn.avg_pool(layers['conv5_4'],ksize=(1,2,2,1),strides=(1,2,2,1),padding='VALID')
 
 return layers

第3步:让我们加载I_CONTENT和I_STYLE图像。我们将通过减去像素方式来预处理这些。

此外,我们定义save_image()函数,它接受模型输出图像,添加MEANS,将值剪辑到范围[0,255]并保存图像。

MEANS = np.array([123.68, 116.779, 103.939]).reshape((1,1,1,3)) 
def load_image(filename):
 
 image = cv2.imread(filename)
 image = cv2.resize(image,(IMAGE_SIZE,IMAGE_SIZE))
 cv2_imshow(image)
 image = cv2.cvtColor(image, cv2.COLOR_BGR2RGB)
 image = image.reshape((1,)+image.shape)
 
 image = image - MEANS
 return image
def save_image(image,filename):
 image = image + MEANS
 image = np.clip(image[0], 0, 255).astype('uint8')
 scipy.misc.imsave(filename, image)
 return image

第4步:让我们定义层(和相应的权重)来计算内容和风格损失。

CONTENT_LAYERS = [
 ('conv4_2', 1.0),
]
STYLE_LAYERS = [
 ('conv1_1', 0.2),
 ('conv2_1', 0.2),
 ('conv3_1', 0.2),
 ('conv4_1', 0.2),
 ('conv5_1', 0.2)
]

让我们定义损失项和优化器以最小化损失:

def getContentLoss(layers,content_target,content_layer_name): 
 m,H,W,C = content_target.shape
 return tf.reduce_sum(tf.pow(content_target-layers[content_layer_name],2))/(4.0*C*H*W)
# Calculate tensor for content loss
J_content = 0.0
with tf.Session() as sess:
 for content_layer_name, weight in CONTENT_LAYERS:
 content_layer = layers[content_layer_name]
 content_target = sess.run(content_layer,feed_dict={layers['input']:content_image})
 J_content = J_content + weight * getContentLoss(layers,content_target, content_layer_name)
print('Content loss defined...\n')
 
 
def getStyleLoss(layers,style_target,style_layer_name):
 m,H,W,C = style_target.shape
 style_target = tf.transpose(tf.reshape(style_target,[H*W,C]))
 gram_target = tf.matmul(style_target,tf.transpose(style_target)) 
 style_tensor = tf.transpose(tf.reshape(layers[style_layer_name],[H*W,C]))
 gram_tensor = tf.matmul(style_tensor,tf.transpose(style_tensor)) 
 return tf.reduce_sum(tf.pow(gram_tensor-gram_target,2))/(4.0*C*C*H*H*W*W)
 
# Calculate tensor for style loss
J_style = 0.0
with tf.Session() as sess:
 for style_layer_name, weight in STYLE_LAYERS:
 style_layer = layers[style_layer_name]
 style_target = sess.run(style_layer,feed_dict={layers['input']:style_image})
 J_style = J_style + weight * getStyleLoss(layers,style_target,style_layer_name)
print('Style loss defined...\n')
 
 
def getTotalLoss(J_content,J_style,alpha,beta):
 return J_content*alpha + J_style*beta
# Calculate tensor for total loss
J_total = getTotalLoss(J_content,J_style,alpha=alpha,beta=beta)
# Define loss optimizer
optimizer = tf.train.AdamOptimizer(learning_rate).minimize(J_total)

第5步:我们需要做的就是用白噪声图像初始化layer['input'] 并运行优化器。

每100次迭代,我们将使用可定义的路径前缀保存图像。这是在前面定义的save_image()函数中完成的。

我已将所有这些包装在函数run_style_transfer()中,您可以将文件路径传递给内容和风格图像,内容和风格权重(α和β),学习率和epochs数。

def run_style_transfer(content_image_filename,
 style_image_filename,
 initialImage=None,
 alpha=10,beta=1e-1,
 epochs=1200,
 learning_rate=5.0,
 prefix=None):
 
 if prefix is None:
 print('Output file prefix not defined...')
 return
 
 content_image = load_image(content_image_filename)
 style_image = load_image(style_image_filename)
 weights_dict = getModelWeightsAsDict()
 tf.reset_default_graph()
 layers = get_nst_model(weights_dict)
 print('Model graph generated...\n')
 
 # Calculate tensor for content loss
 J_content = 0.0
 with tf.Session() as sess:
 for content_layer_name, weight in CONTENT_LAYERS:
 content_layer = layers[content_layer_name]
 content_target = sess.run(content_layer,feed_dict={layers['input']:content_image})
 J_content = J_content + weight * getContentLoss(layers,content_target, content_layer_name)
 print('Content loss defined...\n')
 
 
 # Calculate tensor for style loss
 J_style = 0.0
 with tf.Session() as sess:
 for style_layer_name, weight in STYLE_LAYERS:
 style_layer = layers[style_layer_name]
 style_target = sess.run(style_layer,feed_dict={layers['input']:style_image})
 J_style = J_style + weight * getStyleLoss(layers,style_target,style_layer_name)
 print('Style loss defined...\n')
 
 J_total = getTotalLoss(J_content,J_style,alpha=alpha,beta=beta)
 optimizer = tf.train.AdamOptimizer(learning_rate).minimize(J_total)
 print('Losses defined...\n')
 
 print('Trainable variables:\n',tf.trainable_variables())
 
 with tf.Session() as sess:
 
 # Initialize image
 sess.run(tf.global_variables_initializer())
 if initialImage is not None:
 sess.run(layers['input'].assign(initialImage))
 else:
 sess.run(layers['input'].assign(generate_noise_image()))
 
 for epoch in range(epochs):
 epoch_loss, epoch_content_loss, epoch_style_loss, _ = sess.run([J_total,J_content,J_style,optimizer])
 if (epoch+1) % 100 == 0:
 generated_image = sess.run(layers['input'])
 generated_image = save_image(generated_image,prefix + '_' + str(epoch+1) + '.jpg')
 print('Loss after epoch %d: \nT: %f, \nC: %f, \nS: %f'%(epoch,epoch_loss,epoch_content_loss,epoch_style_loss))
 generated_image = cv2.cvtColor(generated_image, cv2.COLOR_RGB2BGR)
 cv2_imshow(generated_image)

设置GPU

# CHECK AND SETUP GPU
device_name = tf.test.gpu_device_name()
print('Found GPU at: {}'.format(device_name))
config = tf.ConfigProto()
config.gpu_options.allow_growth = True

调用的Python示例代码

# Example Usage
IMAGE_SIZE = 900
content_image_filename = './knight.jpg'
style_image_filename = './/patterned_leaves.jpg'
with tf.device('/gpu:0'):
 run_style_transfer(content_image_filename=content_image_filename,
 style_image_filename=style_image_filename,
 epochs=3000,
 alpha=18,
 beta=1e-1,
 learning_rate=10.0,
 prefix='knight-patterned_leaves')

将α设定在[10,20]范围内,β为~1e-1,学习率为~5.0。能够在大约1000次迭代中产生良好的结果。

相关推荐

为何越来越多的编程语言使用JSON(为什么编程)

JSON是JavascriptObjectNotation的缩写,意思是Javascript对象表示法,是一种易于人类阅读和对编程友好的文本数据传递方法,是JavaScript语言规范定义的一个子...

何时在数据库中使用 JSON(数据库用json格式存储)

在本文中,您将了解何时应考虑将JSON数据类型添加到表中以及何时应避免使用它们。每天?分享?最新?软件?开发?,Devops,敏捷?,测试?以及?项目?管理?最新?,最热门?的?文章?,每天?花?...

MySQL 从零开始:05 数据类型(mysql数据类型有哪些,并举例)

前面的讲解中已经接触到了表的创建,表的创建是对字段的声明,比如:上述语句声明了字段的名称、类型、所占空间、默认值和是否可以为空等信息。其中的int、varchar、char和decimal都...

JSON对象花样进阶(json格式对象)

一、引言在现代Web开发中,JSON(JavaScriptObjectNotation)已经成为数据交换的标准格式。无论是从前端向后端发送数据,还是从后端接收数据,JSON都是不可或缺的一部分。...

深入理解 JSON 和 Form-data(json和formdata提交区别)

在讨论现代网络开发与API设计的语境下,理解客户端和服务器间如何有效且可靠地交换数据变得尤为关键。这里,特别值得关注的是两种主流数据格式:...

JSON 语法(json 语法 priority)

JSON语法是JavaScript语法的子集。JSON语法规则JSON语法是JavaScript对象表示法语法的子集。数据在名称/值对中数据由逗号分隔花括号保存对象方括号保存数组JS...

JSON语法详解(json的语法规则)

JSON语法规则JSON语法是JavaScript对象表示法语法的子集。数据在名称/值对中数据由逗号分隔大括号保存对象中括号保存数组注意:json的key是字符串,且必须是双引号,不能是单引号...

MySQL JSON数据类型操作(mysql的json)

概述mysql自5.7.8版本开始,就支持了json结构的数据存储和查询,这表明了mysql也在不断的学习和增加nosql数据库的有点。但mysql毕竟是关系型数据库,在处理json这种非结构化的数据...

JSON的数据模式(json数据格式示例)

像XML模式一样,JSON数据格式也有Schema,这是一个基于JSON格式的规范。JSON模式也以JSON格式编写。它用于验证JSON数据。JSON模式示例以下代码显示了基本的JSON模式。{"...

前端学习——JSON格式详解(后端json格式)

JSON(JavaScriptObjectNotation)是一种轻量级的数据交换格式。易于人阅读和编写。同时也易于机器解析和生成。它基于JavaScriptProgrammingLa...

什么是 JSON:详解 JSON 及其优势(什么叫json)

现在程序员还有谁不知道JSON吗?无论对于前端还是后端,JSON都是一种常见的数据格式。那么JSON到底是什么呢?JSON的定义...

PostgreSQL JSON 类型:处理结构化数据

PostgreSQL提供JSON类型,以存储结构化数据。JSON是一种开放的数据格式,可用于存储各种类型的值。什么是JSON类型?JSON类型表示JSON(JavaScriptO...

JavaScript:JSON、三种包装类(javascript 包)

JOSN:我们希望可以将一个对象在不同的语言中进行传递,以达到通信的目的,最佳方式就是将一个对象转换为字符串的形式JSON(JavaScriptObjectNotation)-JS的对象表示法...

Python数据分析 只要1分钟 教你玩转JSON 全程干货

Json简介:Json,全名JavaScriptObjectNotation,JSON(JavaScriptObjectNotation(记号、标记))是一种轻量级的数据交换格式。它基于J...

比较一下JSON与XML两种数据格式?(json和xml哪个好)

JSON(JavaScriptObjectNotation)和XML(eXtensibleMarkupLanguage)是在日常开发中比较常用的两种数据格式,它们主要的作用就是用来进行数据的传...

取消回复欢迎 发表评论:

请填写验证码