Tensorflow加载Vgg预训练模型操作


Posted in Python onMay 26, 2020

很多深度神经网络模型需要加载预训练过的Vgg参数,比如说:风格迁移、目标检测、图像标注等计算机视觉中常见的任务。那么到底如何加载Vgg模型呢?Vgg文件的参数到底有何意义呢?加载后的模型该如何使用呢?

本文将以Vgg19为例子,详细说明Tensorflow如何加载Vgg预训练模型。

实验环境

GTX1050-ti, cuda9.0

Window10, Tensorflow 1.12

展示Vgg19构造

import tensorflow as tf
 
import numpy as np
import scipy.io
 
data_path = 'model/vgg19.mat' # data_path指下载下来的Vgg19预训练模型的文件地址
 
# 读取Vgg19文件
data = scipy.io.loadmat(data_path)
# 打印Vgg19的数据类型及其组成
print("type: ", type(data))
print("data.keys: ", data.keys())
 
# 得到对应卷积核的矩阵
weights = data['layers'][0]
# 定义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'
)
 
# 打印Vgg19不同卷积层所对应的维度
for i, name in enumerate(layers):
 kind = name[:4]
 if kind == 'conv':
  print("%s: %s" % (name, weights[i][0][0][2][0][0].shape))
 elif kind == 'relu':
  print(name)
 elif kind == 'pool':
  print(name)
 
 
代码输出结果如下:
type: <class 'dict'>
data.keys: dict_keys(['__header__', '__version__', '__globals__', 'layers', 'meta'])
 
conv1_1: (3, 3, 3, 64)
relu1_1
conv1_2: (3, 3, 64, 64)
relu1_2
pool1
conv2_1: (3, 3, 64, 128)
relu2_1
conv2_2: (3, 3, 128, 128)
relu2_2
pool2
conv3_1: (3, 3, 128, 256)
relu3_1
conv3_2: (3, 3, 256, 256)
relu3_2
conv3_3: (3, 3, 256, 256)
relu3_3
conv3_4: (3, 3, 256, 256)
relu3_4
pool3
conv4_1: (3, 3, 256, 512)
relu4_1
conv4_2: (3, 3, 512, 512)
relu4_2
conv4_3: (3, 3, 512, 512)
relu4_3
conv4_4: (3, 3, 512, 512)
relu4_4
pool4
conv5_1: (3, 3, 512, 512)
relu5_1
conv5_2: (3, 3, 512, 512)
relu5_2
conv5_3: (3, 3, 512, 512)
relu5_3
conv5_4: (3, 3, 512, 512)
relu5_4

那么Vgg19真实的网络结构是怎么样子的呢,如下图所示:

Tensorflow加载Vgg预训练模型操作

在本文,主要讨论卷积模块,大家通过对比可以发现,我们打印出来的Vgg19结构及其卷积核的构造的确如论文中给出的Vgg19结构一致。

构建Vgg19模型

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):
 return tf.nn.max_pool(input, ksize=(1, 2, 2, 1), strides=(1, 2, 2, 1),
   padding='SAME')
 
class 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'
 )
 
 def __init__(self, data_path):
  data = scipy.io.loadmat(data_path)
 
  self.weights = data['layers'][0]
 
 def feed_forward(self, input_image, scope=None):
  # 定义net用来保存模型每一步输出的特征图
  net = {}
  current = input_image
 
  with tf.variable_scope(scope):
   for i, name in enumerate(self.layers):
    kind = name[:4]
    if kind == 'conv':
     kernels = self.weights[i][0][0][2][0][0]
     bias = self.weights[i][0][0][2][0][1]
 
     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)
    # 在每一步都保存当前输出的特征图
    net[name] = current
 
  return net

在上面的代码中,我们定义了一个Vgg19的类别专门用来加载Vgg19模型,并且将每一层卷积得到的特征图保存到net中,最后返回这个net,用于代码后续的处理。

测试Vgg19模型

在给出Vgg19的构造模型后,我们下一步就是如何用它,我们的思路如下:

加载本地图片

定义Vgg19模型,传入本地图片

得到返回每一层的特征图

image_path = "data/test.jpg" # 本地的测试图片
 
image_raw = tf.gfile.GFile(image_path, 'rb').read()
# 一定要tf.float(),否则会报错
image_decoded = tf.to_float(tf.image.decode_jpeg(image_raw))
 
# 扩展图片的维度,从三维变成四维,符合Vgg19的输入接口
image_expand_dim = tf.expand_dims(image_decoded, 0)
 
# 定义Vgg19模型
vgg19 = VGG19(data_path)
net = vgg19.feed_forward(image_expand_dim, 'vgg19')
print(net)
 
代码结果如下所示:
{'conv1_1': <tf.Tensor 'vgg19_1/BiasAdd:0' shape=(1, ?, ?, 64) dtype=float32>,
 'relu1_1': <tf.Tensor 'vgg19_1/Relu:0' shape=(1, ?, ?, 64) dtype=float32>,
 'conv1_2': <tf.Tensor 'vgg19_1/BiasAdd_1:0' shape=(1, ?, ?, 64) dtype=float32>,
 'relu1_2': <tf.Tensor 'vgg19_1/Relu_1:0' shape=(1, ?, ?, 64) dtype=float32>,
 'pool1': <tf.Tensor 'vgg19_1/MaxPool:0' shape=(1, ?, ?, 64) dtype=float32>,
 'conv2_1': <tf.Tensor 'vgg19_1/BiasAdd_2:0' shape=(1, ?, ?, 128) dtype=float32>,
 'relu2_1': <tf.Tensor 'vgg19_1/Relu_2:0' shape=(1, ?, ?, 128) dtype=float32>,
 'conv2_2': <tf.Tensor 'vgg19_1/BiasAdd_3:0' shape=(1, ?, ?, 128) dtype=float32>,
 'relu2_2': <tf.Tensor 'vgg19_1/Relu_3:0' shape=(1, ?, ?, 128) dtype=float32>,
 'pool2': <tf.Tensor 'vgg19_1/MaxPool_1:0' shape=(1, ?, ?, 128) dtype=float32>,
 'conv3_1': <tf.Tensor 'vgg19_1/BiasAdd_4:0' shape=(1, ?, ?, 256) dtype=float32>,
 'relu3_1': <tf.Tensor 'vgg19_1/Relu_4:0' shape=(1, ?, ?, 256) dtype=float32>,
 'conv3_2': <tf.Tensor 'vgg19_1/BiasAdd_5:0' shape=(1, ?, ?, 256) dtype=float32>,
 'relu3_2': <tf.Tensor 'vgg19_1/Relu_5:0' shape=(1, ?, ?, 256) dtype=float32>,
 'conv3_3': <tf.Tensor 'vgg19_1/BiasAdd_6:0' shape=(1, ?, ?, 256) dtype=float32>,
 'relu3_3': <tf.Tensor 'vgg19_1/Relu_6:0' shape=(1, ?, ?, 256) dtype=float32>,
 'conv3_4': <tf.Tensor 'vgg19_1/BiasAdd_7:0' shape=(1, ?, ?, 256) dtype=float32>,
 'relu3_4': <tf.Tensor 'vgg19_1/Relu_7:0' shape=(1, ?, ?, 256) dtype=float32>,
 'pool3': <tf.Tensor 'vgg19_1/MaxPool_2:0' shape=(1, ?, ?, 256) dtype=float32>,
 'conv4_1': <tf.Tensor 'vgg19_1/BiasAdd_8:0' shape=(1, ?, ?, 512) dtype=float32>,
 'relu4_1': <tf.Tensor 'vgg19_1/Relu_8:0' shape=(1, ?, ?, 512) dtype=float32>,
 'conv4_2': <tf.Tensor 'vgg19_1/BiasAdd_9:0' shape=(1, ?, ?, 512) dtype=float32>,
 'relu4_2': <tf.Tensor 'vgg19_1/Relu_9:0' shape=(1, ?, ?, 512) dtype=float32>,
 'conv4_3': <tf.Tensor 'vgg19_1/BiasAdd_10:0' shape=(1, ?, ?, 512) dtype=float32>,
 'relu4_3': <tf.Tensor 'vgg19_1/Relu_10:0' shape=(1, ?, ?, 512) dtype=float32>,
 'conv4_4': <tf.Tensor 'vgg19_1/BiasAdd_11:0' shape=(1, ?, ?, 512) dtype=float32>,
 'relu4_4': <tf.Tensor 'vgg19_1/Relu_11:0' shape=(1, ?, ?, 512) dtype=float32>,
 'pool4': <tf.Tensor 'vgg19_1/MaxPool_3:0' shape=(1, ?, ?, 512) dtype=float32>,
 'conv5_1': <tf.Tensor 'vgg19_1/BiasAdd_12:0' shape=(1, ?, ?, 512) dtype=float32>,
 'relu5_1': <tf.Tensor 'vgg19_1/Relu_12:0' shape=(1, ?, ?, 512) dtype=float32>,
 'conv5_2': <tf.Tensor 'vgg19_1/BiasAdd_13:0' shape=(1, ?, ?, 512) dtype=float32>,
 'relu5_2': <tf.Tensor 'vgg19_1/Relu_13:0' shape=(1, ?, ?, 512) dtype=float32>,
 'conv5_3': <tf.Tensor 'vgg19_1/BiasAdd_14:0' shape=(1, ?, ?, 512) dtype=float32>,
 'relu5_3': <tf.Tensor 'vgg19_1/Relu_14:0' shape=(1, ?, ?, 512) dtype=float32>,
 'conv5_4': <tf.Tensor 'vgg19_1/BiasAdd_15:0' shape=(1, ?, ?, 512) dtype=float32>,
 'relu5_4': <tf.Tensor 'vgg19_1/Relu_15:0' shape=(1, ?, ?, 512) dtype=float32>}

本文提供的测试代码是完成正确的,已经避免了很多使用Vgg19预训练模型的坑操作,比如:给图片添加维度,转换读取图片的的格式等,为什么这么做的详细原因可参考我的另一篇博客:Tensorflow加载Vgg预训练模型的几个注意事项。

到这里,如何使用tensorflow读取Vgg19模型结束了,若是大家有其他疑惑,可在评论区留言,会定时回答。

好了,以上就是小编分享给大家的全部内容了,希望能给大家一个参考,也希望大家多多支持三水点靠木。

Python 相关文章推荐
基于Python socket的端口扫描程序实例代码
Feb 09 Python
Python批量提取PDF文件中文本的脚本
Mar 14 Python
点球小游戏python脚本
May 22 Python
学生信息管理系统Python面向对象版
Jan 30 Python
Python Pandas 箱线图的实现
Jul 23 Python
Django框架组成结构、基本概念与文件功能分析
Jul 30 Python
python datetime中strptime用法详解
Aug 29 Python
python super函数使用方法详解
Feb 14 Python
PyCharm 2020.2 安装详细教程
Sep 25 Python
Python中glob库实现文件名的匹配
Jun 18 Python
详解Python自动化之文件自动化处理
Jun 21 Python
使用opencv-python如何打开USB或者笔记本前置摄像头
Jun 21 Python
PyQt5如何将.ui文件转换为.py文件的实例代码
May 26 #Python
TensorFlow实现模型断点训练,checkpoint模型载入方式
May 26 #Python
python 日志模块 日志等级设置失效的解决方案
May 26 #Python
python3.7+selenium模拟淘宝登录功能的实现
May 26 #Python
TensorFlow固化模型的实现操作
May 26 #Python
Python 如何批量更新已安装的库
May 26 #Python
tensorflow 20:搭网络,导出模型,运行模型的实例
May 26 #Python
You might like
PHP 强制下载文件代码
2010/10/24 PHP
php基于websocket搭建简易聊天室实践
2016/10/24 PHP
thinkphp5 框架结合plupload实现图片批量上传功能示例
2020/04/04 PHP
如何让动态插入的javascript脚本代码跑起来。
2007/01/09 Javascript
javascript网页关键字高亮代码
2008/07/30 Javascript
Jquery 动态循环输出表格具体方法
2013/11/23 Javascript
深入理解JavaScript系列(44):设计模式之桥接模式详解
2015/03/04 Javascript
JS面向对象(3)之Object类,静态属性,闭包,私有属性, call和apply的使用,继承的三种实现方法
2016/02/25 Javascript
如何高效率去掉js数组中的重复项
2016/04/12 Javascript
jQuery配合coin-slider插件制作幻灯片效果的流程解析
2016/05/13 Javascript
JQuery中解决重复动画的方法
2016/10/17 Javascript
微信小程序实现动态设置placeholder提示文字及按钮选中/取消状态的方法
2017/12/14 Javascript
vue-cli3全面配置详解
2018/11/14 Javascript
Vue运用transition实现过渡动画
2019/05/06 Javascript
写一个Vue loading 插件
2020/11/09 Javascript
Python编码时应该注意的几个情况
2013/03/04 Python
使用python的chardet库获得文件编码并修改编码
2014/01/22 Python
python中随机函数random用法实例
2015/04/30 Python
Python实现二叉堆
2016/02/03 Python
Python使用functools模块中的partial函数生成偏函数
2016/07/02 Python
Python中防止sql注入的方法详解
2017/02/25 Python
python基础教程项目四之新闻聚合
2018/04/02 Python
快速解决PyCharm无法引用matplotlib的问题
2018/05/24 Python
django 发送邮件和缓存的实现代码
2018/07/18 Python
python3爬虫怎样构建请求header
2018/12/23 Python
python实现三维拟合的方法
2018/12/29 Python
PyQt5响应回车事件的方法
2019/06/25 Python
Django ORM 常用字段与不常用字段汇总
2019/08/09 Python
python selenium登录豆瓣网过程解析
2019/08/10 Python
Python程序控制语句用法实例分析
2020/01/14 Python
tensorflow实现对张量数据的切片操作方式
2020/01/19 Python
基于HTML5代码实现折叠菜单附源码下载
2015/11/27 HTML / CSS
企业精细化管理实施方案
2014/03/23 职场文书
博物馆观后感
2015/06/05 职场文书
银行求职信范文
2019/05/13 职场文书
十大公认最好看的动漫:《咒术回战》在榜,《钢之炼金术师》第一
2022/03/18 日漫