# 使用VGG19迁移学习实现图像风格迁移
一直想要做个图像风格迁移来玩玩的,感觉还是蛮有意思的。
所谓图像风格迁移,即给定内容图片A,风格图片B,能够生成一张具有A图片内容和B图片风格的图片C。
比如说,我们可以使用梵高先生的名画《星夜》 作为风格图片,来与其他图片生成具有《星夜》风格新图片。emmm,夭寿啦,机器帮你画世界名画啦。。。
举两个生成的例子:
均使用《星夜》作为风格图片(可以替换,我以《星夜》为例):

示例1:
网络上找到的一张风景图片。
内容图片:

生成图片:

生成图片的尺寸比较小,没办法,我的显卡太差了,尺寸大一点的话显卡内存不足。
**示例2:**
嗷嗷嗷,狼人嚎叫~
内容图片:

生成图片:

效果还凑合吧,可以接受。
下面记录实现过程。
## 一.获取预训练的vgg19模型
VGG19是Google DeepMind发表在ICLR 2015上的论文《VERY DEEP CONVOLUTIONAL NETWORK SFOR LARGE-SCALE IMAGE RECOGNITION》中提出的一种DCNN结构。
众所周知,CNN在图片处理上表现良好,VGG19提出后,也被用在图像处理上。我这里要用到的VGG19模型就是在imagenet数据集上预训练的模型。
一般认为,深度卷积神经网络的训练是对数据集特征的一步步抽取的过程,从简单的特征,到复杂的特征。
训练好的模型学习到的是对图像特征的抽取方法,所以在imagenet数据集上训练好的模型理论上来说,也可以直接用于抽取其他图像的特征,这也是迁移学习的基础。自然,这样的效果往往没有在新数据上重新训练的效果好,但能够节省大量的训练时间,在特定情况下非常有用。
预训练好的VGG19模型可以从这里下载,模型大小500M+。
## 二.模型编写
这里的模型基本上就是VGG19模型,只是稍微做了一些修改。
我们要从预训练的模型中,获取卷积层部分的参数,用于构建我们自己的模型。VGG19中的全连接层舍弃掉,这一部分对提取图像特征基本无用。
要注意的是,我这里提取出来的VGG参数全部是作为constant(即常量)使用的,也就是说,这些参数是不会再被训练的,在反向传播的过程中也不会改变。
另外,输入层要设置为Variable,我们要训练的就是这个。最开始输入一张噪音图片,然后不断地根据内容loss和风格loss对其进行调整,直到一定次数后,该图片兼具了风格图片的风格以及内容图片的内容。当训练结束时,输入层的参数就是我们生成的图片。
附一张VGG结构图:

这个代码里主要是定义VGG,至于LOSS在训练过程中进行说明。
`models.py`
```python
# -*- coding: utf-8 -*-
# @Time : 18-3-23 下午12:20
# @Author : AaronJny
# @Email : Aaron__7@163.com
import tensorflow as tf
import numpy as np
import settings
import scipy.io
import scipy.misc
class Model(object):
def __init__(self, content_path, style_path):
self.content = self.loadimg(content_path) # 加载内容图片
self.style = self.loadimg(style_path) # 加载风格图片
self.random_img = self.get_random_img() # 生成噪音内容图片
self.net = self.vggnet() # 建立vgg网络
def vggnet(self):
# 读取预训练的vgg模型
vgg = scipy.io.loadmat(settings.VGG_MODEL_PATH)
vgg_layers = vgg['layers'][0]
net = {}
# 使用预训练的模型参数构建vgg网络的卷积层和池化层
# 全连接层不需要
# 注意,除了input之外,这里参数都为constant,即常量
# 和平时不同,我们并不训练vgg的参数,它们保持不变
# 需要进行训练的是input,它即是我们最终生成的图像
net['input'] = tf.Variable(np.zeros([1, settings.IMAGE_HEIGHT, settings.IMAGE_WIDTH, 3]), dtype=tf.float32)
# 参数对应的层数可以参考vgg模型图
net['conv1_1'] = self.conv_relu(net['input'], self.get_wb(vgg_layers, 0))
net['conv1_2'] = self.conv_relu(net['conv1_1'], self.get_wb(vgg_layers, 2))
net['pool1'] = self.pool(net['conv1_2'])
net['conv2_1'] = self.conv_relu(net['pool1'], self.get_wb(vgg_layers, 5))
net['conv2_2'] = self.conv_relu(net['conv2_1'], self.get_wb(vgg_layers, 7))
net['pool2'] = self.pool(net['conv2_2'])
net['conv3_1'] = self.conv_relu(net['pool2'], self.get_wb(vgg_layers, 10))
net['conv3_2'] = self.conv_relu(net['conv3_1'], self.get_wb(vgg_layers, 12))
net['conv3_3'] = self.conv_relu(net['conv3_2'], self.get_wb(vgg_layers, 14))
net['conv3_4'] = self.conv_relu(net['conv3_3'], self.get_wb(vgg_layers, 16))
net['pool3'] = self.pool(net['conv3_4'])
net['conv4_1'] = self.conv_relu(net['pool3'], self.get_wb(vgg_layers, 19))
net['conv4_2'] = self.conv_relu(net['conv4_1'], self.get_wb(vgg_layers, 21))
net['conv4_3'] = self.conv_relu(net['conv4_2'], self.get_wb(vgg_layers, 23))
net['conv4_4'] = self.conv_relu(net['conv4_3'], self.get_wb(vgg_layers, 25))
net['pool4'] = self.pool(net['conv4_4'])
net['conv5_1'] = self.conv_relu(net['pool4'], self.get_wb(vgg_layers, 28))
net['conv5_2'] = self.conv_relu(net['conv5_1'], self.get_wb(vgg_layers, 30))
net['conv5_3'] = self.conv_relu(net['conv5_2'], self.get_wb(vgg_layers, 32))
net['conv5_4'] = self.conv_relu(net['conv5_3'], self.get_wb(vgg_layers, 34))
net['pool5'] = self.pool(net['conv5_4'])
return net
def conv_relu(self, input, wb):
"""
进行先卷积、后relu的运算
:param input: 输入层
:param wb: wb[0],wb[1] == w,b
:return: relu后的结果
"""
conv = tf.nn.conv2d(input, wb[0], strides=[1, 1, 1, 1], padding='SAME')
relu = tf.nn.relu(conv + wb[1])
return relu
def pool(self, input):
"""
进行max_pool操作
:param input: 输入层
:return: 池化后的结果
"""
return tf.nn.max_pool(input, ksize=[1, 2, 2, 1], strides=[1, 2, 2, 1], padding='SAME')
def get_wb(self, layers, i):
"""
从预训练好的vgg模型中读取参数
:param layers: 训练好的vgg模型
:param i: vgg指定层数
:return: 该层的w,b
"""
w = tf.constant(layers[i][0][0][0][0][0])
bias = layers[i][0][0][0][0][1]
b = tf.constant(np.reshape(bias, (bias.size)))
return w, b
def get_random_img(self):
"""
根据噪音和内容图片,生成一张随机图片
:return:
"""
noise_image = np.random.uniform(-20, 20, [1, settings.IMAGE_HEIGHT, settings.IMAGE_WIDTH, 3])
random_img = noise_image * settings.NOISE + self.content * (1 - settings.NOISE)
return random_img
def loadimg(self, path):
"""
加载一张图片,将其转化为符合要求的格式
:param path:
:return:
"""
# 读取图片
image = scipy.misc.imread(path)
# 重新设定图片大小
image = scipy.misc.imresize(image, [settings.IMAGE_HEIGHT, settings.IMAGE_WIDTH])
没有合适的资源?快使用搜索试试~ 我知道了~
使用VGG19迁移学习实现图像风格迁移.zip

共16个文件
jpg:8个
py:3个
png:3个

3 下载量 96 浏览量
2023-01-18
10:07:25
上传
评论
收藏 4.61MB ZIP 举报
温馨提示
这是一个使用预训练的VGG19网络完成图片风格迁移的项目,使用的语言为python,框架为tensorflow。 给定一张风格图片A和内容图片B,能够生成具备A图片风格和B图片内容的图片C。
资源推荐
资源详情
资源评论






















收起资源包目录




















共 16 条
- 1
资源评论


甜辣uu
- 粉丝: 7042
- 资源: 1105
上传资源 快速赚钱
我的内容管理 展开
我的资源 快来上传第一个资源
我的收益
登录查看自己的收益我的积分 登录查看自己的积分
我的C币 登录后查看C币余额
我的收藏
我的下载
下载帮助


安全验证
文档复制为VIP权益,开通VIP直接复制
