对Tensorflow中权值和feature map的可视化详解


Posted in Python onJune 14, 2018

前言

Tensorflow中可以使用tensorboard这个强大的工具对计算图、loss、网络参数等进行可视化。本文并不涉及对tensorboard使用的介绍,而是旨在说明如何通过代码对网络权值和feature map做更灵活的处理、显示和存储。本文的相关代码主要参考了github上的一个小项目,但是对其进行了改进。

原项目地址为(https://github.com/grishasergei/conviz)。

本文将从以下两个方面进行介绍:

卷积知识补充

网络权值和feature map的可视化

1. 卷积知识补充

为了后面方便讲解代码,这里先对卷积的部分知识进行一下简介。关于卷积核如何在图像的一个通道上进行滑动计算,网上有诸多资料,相信对卷积神经网络有一定了解的读者都应该比较清楚,本文就不再赘述。这里主要介绍一组卷积核如何在一幅图像上计算得到一组feature map。

以从原始图像经过第一个卷积层得到第一组feature map为例(从得到的feature map到再之后的feature map也是同理),假设第一组feature map共有64个,那么可以把这组feature map也看作一幅图像,只不过它的通道数是64, 而一般意义上的图像是RGB3个通道。为了得到这第一组feature map,我们需要64个卷积核,每个卷积核是一个k x k x 3的矩阵,其中k是卷积核的大小(假设是正方形卷积核),3就对应着输入图像的通道数。下面我以一个简单粗糙的图示来展示一下图像经过一个卷积核的卷积得到一个feature map的过程。

对Tensorflow中权值和feature map的可视化详解

如图所示,其实可以看做卷积核的每一通道(不太准确,将就一下)和图像的每一通道对应进行卷积操作,然后再逐位置相加,便得到了一个feature map。

那么用一组(64个)卷积核去卷积一幅图像,得到64个feature map就如下图所示,也就是每个卷积核得到一个feature map,64个卷积核就得到64个feature map。

对Tensorflow中权值和feature map的可视化详解

另外,也可以稍微换一个角度看待这个问题,那就是先让图片的某一通道分别与64个卷积核的对应通道做卷积,得到64个feature map的中间结果,之后3个通道对应的中间结果再相加,得到最终的feature map,如下图所示:

对Tensorflow中权值和feature map的可视化详解

可以看到这其实就是第一幅图扩展到多卷积核的情形,图画得较为粗糙,有些中间结果和最终结果直接用了一样的子图,理解时请稍微注意一下。下面代码中对卷积核进行展示的时候使用的就是这种方式,即对应着输入图像逐通道的去显示卷积核的对应通道,而不是每次显示一个卷积核的所有通道,可能解释的有点绕,需要注意一下。通过下面这个小图也许更好理解。

对Tensorflow中权值和feature map的可视化详解

图中用红框圈出的部分即是我们一次展示出的权重参数。

2. 网络权值和feature map的可视化

(1) 网络权重参数可视化

首先介绍一下Tensorflow中卷积核的形状,如下代码所示:

weights = tf.Variable(tf.random_normal([filter_size, filter_size, channels, filter_num]))

前两维是卷积核的高和宽,第3维是上一层feature map的通道数,在第一节(卷积知识补充)中,我提到了上一层的feature map有多少个(也就是通道数是多少),那么对应着一个卷积核也要有这么多通道。第4维是当前卷积层的卷积核数量,也是当前层输出的feature map的通道数。

以下是我更改之后的网络权重参数(卷积核)的可视化代码:

from __future__ import print_function

#import tensorflow as tf
import numpy as np
import matplotlib.pyplot as plt
import matplotlib.cm as cm
import os
import visualize_utils


def plot_conv_weights(weights, plot_dir, name, channels_all=True, filters_all=True, channels=[0], filters=[0]):
 """
 Plots convolutional filters
 :param weights: numpy array of rank 4
 :param name: string, name of convolutional layer
 :param channels_all: boolean, optional
 :return: nothing, plots are saved on the disk
 """

 w_min = np.min(weights)
 w_max = np.max(weights)

 # make a list of channels if all are plotted
 if channels_all:
 channels = range(weights.shape[2])

 # get number of convolutional filters
 if filters_all:
 num_filters = weights.shape[3]
 filters = range(weights.shape[3])
 else:
 num_filters = len(filters)

 # get number of grid rows and columns
 grid_r, grid_c = visualize_utils.get_grid_dim(num_filters)

 # create figure and axes
 fig, axes = plt.subplots(min([grid_r, grid_c]),
    max([grid_r, grid_c]))

 # iterate channels
 for channel_ID in channels:
 # iterate filters inside every channel
 if num_filters == 1:
  img = weights[:, :, channel_ID, filters[0]]
  axes.imshow(img, vmin=w_min, vmax=w_max, interpolation='nearest', cmap='seismic')
  # remove any labels from the axes
  axes.set_xticks([])
  axes.set_yticks([])
 else:
  for l, ax in enumerate(axes.flat):
  # get a single filter
  img = weights[:, :, channel_ID, filters[l]]
  # put it on the grid
  ax.imshow(img, vmin=w_min, vmax=w_max, interpolation='nearest', cmap='seismic')
  # remove any labels from the axes
  ax.set_xticks([])
  ax.set_yticks([])
 # save figure
 plt.savefig(os.path.join(plot_dir, '{}-{}.png'.format(name, channel_ID)), bbox_inches='tight')

原项目的代码是对某一层的权重参数或feature map在一个网格中进行全部展示,如果参数或feature map太多,那么展示出来的结果中每个图都很小,很难看出有用的东西来,如下图所示:

对Tensorflow中权值和feature map的可视化详解

所以我对代码做了些修改,使得其能显示任意指定的filter或feature map。

代码中,

w_min = np.min(weights)
w_max = np.max(weights)

这两句是为了后续显示图像用的,具体可查看matplotlib.pyplot的imshow()函数进行了解。

接下来是判断是否显示全部的channel(通道数)或全部filter。如果是,那就和原代码一致了。若不是,则画出函数参数channels和filters指定的filter来。

再往下的两句代码是画图用的,我们可能会在一个图中显示多个子图,以下这句是为了计算出大图分为几行几列比较合适(一个大图会尽量分解为方形的阵列,比如如果有64个子图,那么就分成8 x 8的阵列),代码细节可在原项目中的utils中找到。

grid_r, grid_c = visualize_utils.get_grid_dim(num_filters)

实际画图时,如果想要一个图一个图的去画,需要单独处理一下。如果还是想在一个大图中显示多个子图,就按源代码的方式去做,只不过这里可以显示我们自己指定的那些filter,而不是不加筛选地全部输出。主要拿到数据的是以下这句代码:

img = weights[:, :, channel_ID, filters[l]]

剩下的都是是画图相关的函数了,本文就不再对画图做更多介绍了。

使用这段代码可视化并保存filter时,先加载模型,然后拿到我们想要可视化的那部分参数,之后直接调用函数就可以了,如下所示:

with tf.Session(graph=tf.get_default_graph()) as sess: 
 init_op = tf.group(tf.global_variables_initializer(), tf.local_variables_initializer())
 sess.run(init_op)
 saver.restore(sess, model_path)

 with tf.variable_scope('inference', reuse=True):
  conv_weights = tf.get_variable('conv3_1_w').eval()
  visualize.plot_conv_weights(conv_weights, dir_prefix, 'conv3_1')

这里并没有对filter进行额外的指定,在feature map的可视化中,我会给出相关例子。

(2) feature map可视化

其实feature map的可视化与filter非常相似,只有细微的不同。还是先把完整代码贴上。

def plot_conv_output(conv_img, plot_dir, name, filters_all=True, filters=[0]):
 w_min = np.min(conv_img)
 w_max = np.max(conv_img)

 # get number of convolutional filters
 if filters_all:
 num_filters = conv_img.shape[3]
 filters = range(conv_img.shape[3])
 else:
 num_filters = len(filters)

 # get number of grid rows and columns
 grid_r, grid_c = visualize_utils.get_grid_dim(num_filters)

 # create figure and axes
 fig, axes = plt.subplots(min([grid_r, grid_c]),
    max([grid_r, grid_c]))

 # iterate filters
 if num_filters == 1:
 img = conv_img[0, :, :, filters[0]]
 axes.imshow(img, vmin=w_min, vmax=w_max, interpolation='bicubic', cmap=cm.hot)
 # remove any labels from the axes
 axes.set_xticks([])
 axes.set_yticks([])
 else:
 for l, ax in enumerate(axes.flat):
  # get a single image
  img = conv_img[0, :, :, filters[l]]
  # put it on the grid
  ax.imshow(img, vmin=w_min, vmax=w_max, interpolation='bicubic', cmap=cm.hot)
  # remove any labels from the axes
  ax.set_xticks([])
  ax.set_yticks([])
 # save figure
 plt.savefig(os.path.join(plot_dir, '{}.png'.format(name)), bbox_inches='tight')

代码中和filter可视化相同的部分就不再赘述了,这里只讲feature map可视化独特的方面,其实就在于以下这句代码,也就是要可视化的数据的获得:

img = conv_img[0, :, :, filters[0]]

神经网络一般都是一个batch一个batch的输入数据,其输入的形状为

image = tf.placeholder(tf.float32, shape = [None, IMAGE_SIZE, IMAGE_SIZE, 3], name = "input_image")

第一维是一个batch中图片的数量,为了灵活可以设置为None,Tensorflow会根据实际输入的数据进行计算。二三维是图片的高和宽,第4维是图片通道数,一般为3。

如果我们想要输入一幅图片,然后看看它的激活值(feature map),那么也要按照以上维度以一个batch的形式进行输入,也就是[1, IMAGE_SIZE, IMAGE_SIZE, 3]。所以拿feature map数据时,第一维度肯定是取0(就对应着batch中的当前图片),二三维取全部,第4维度再取我们想要查看的feature map的某一通道。

如果想要可视化feature map,那么构建网络时还要动点手脚,定义计算图时,每得到一组激活值都要将其加到Tensorflow的collection中,如下:

tf.add_to_collection('activations', current)

而实际进行feature map可视化时,就要先输入一幅图片,然后运行网络拿到相应数据,最后把数据传参给可视化函数。以下这个例子展示的是如何将每个指定卷积层的feature map的每个通道进行单独的可视化与存储,使用的是VGG16网络:

visualize_layers = ['conv1_1', 'conv1_2', 'conv2_1', 'conv2_2', 'conv3_1', 'conv3_2', 'conv3_3', 'conv4_1', 'conv4_2', 'conv4_3', 'conv5_1', 'conv5_2', 'conv5_3']

with tf.Session(graph=tf.get_default_graph()) as sess: 
 init_op = tf.group(tf.global_variables_initializer(), tf.local_variables_initializer())
 sess.run(init_op)
 saver.restore(sess, model_path)

 image_path = root_path + 'images/train_images/sunny_0058.jpg'
 img = misc.imread(image_path)
 img = img - meanvalue
 img = np.float32(img)
 img = np.expand_dims(img, axis=0)

 conv_out = sess.run(tf.get_collection('activations'), feed_dict={x: img, keep_prob: 1.0})
 for i, layer in enumerate(visualize_layers):
  visualize_utils.create_dir(dir_prefix + layer)
  for j in range(conv_out[i].shape[3]):
  visualize.plot_conv_output(conv_out[i], dir_prefix + layer, str(j), filters_all=False, filters=[j])

 sess.close()

其中,conv_out包含了所有加入到collection中的feature map,这些feature map在conv_out中是按卷积层划分的。

最终得到的结果如下图所示:

对Tensorflow中权值和feature map的可视化详解

第一个文件夹下的全部结果:

对Tensorflow中权值和feature map的可视化详解

以上这篇对Tensorflow中权值和feature map的可视化详解就是小编分享给大家的全部内容了,希望能给大家一个参考,也希望大家多多支持三水点靠木。

Python 相关文章推荐
Python函数式编程指南(二):从函数开始
Jun 24 Python
Python脚本暴力破解栅栏密码
Oct 19 Python
使用Python脚本和ADB命令实现卸载App
Feb 10 Python
Python登录注册验证功能实现
Jun 18 Python
Python Pandas 获取列匹配特定值的行的索引问题
Jul 01 Python
python 类的继承 实例方法.静态方法.类方法的代码解析
Aug 23 Python
python自动化unittest yaml使用过程解析
Feb 03 Python
使用Keras预训练好的模型进行目标类别预测详解
Jun 27 Python
Python基于mediainfo批量重命名图片文件
Dec 29 Python
详解win10下pytorch-gpu安装以及CUDA详细安装过程
Jan 28 Python
Python Pytorch查询图像的特征从集合或数据库中查找图像
Apr 09 Python
Python爬虫 简单介绍一下Xpath及使用
Apr 26 Python
TensorFlow的权值更新方法
Jun 14 #Python
python字符串常用方法
Jun 14 #Python
tensorflow 输出权重到csv或txt的实例
Jun 14 #Python
修复 Django migration 时遇到的问题解决
Jun 14 #Python
tensorflow 获取模型所有参数总和数量的方法
Jun 14 #Python
tensorflow 获取变量&打印权值的实例讲解
Jun 14 #Python
利用python对Excel中的特定数据提取并写入新表的方法
Jun 14 #Python
You might like
php格式化工具Beautify PHP小小BUG
2008/04/24 PHP
深入探讨PHP中的内存管理问题
2011/08/31 PHP
php错误、异常处理机制(补充)
2012/05/07 PHP
php使用标签替换的方式生成静态页面
2015/05/21 PHP
Yii2框架中一些折磨人的坑
2019/12/15 PHP
jquery 实现返回顶部功能
2014/11/17 Javascript
jquery实现的缩略图预览滑块实例
2015/06/25 Javascript
详解JS中Array对象扩展与String对象扩展
2016/01/07 Javascript
Vuejs中使用markdown服务器端渲染的示例
2017/11/22 Javascript
详解node child_process模块学习笔记
2018/01/24 Javascript
详解vue2.0监听属性的使用心得及搭配计算属性的使用
2018/07/18 Javascript
基于nodejs的雪碧图制作工具的示例代码
2018/11/05 NodeJs
详解vue-cli中使用rem,vue自适应
2019/05/06 Javascript
新手快速入门微信小程序组件库 iView Weapp
2019/06/24 Javascript
JavaScript HTML DOM 元素 (节点)新增,编辑,删除操作实例分析
2020/03/02 Javascript
Javascript摸拟自由落体与上抛运动原理与实现方法详解
2020/04/08 Javascript
使用Typescript开发微信小程序的步骤详解
2021/01/12 Javascript
python实现的防DDoS脚本
2011/02/08 Python
python练习程序批量修改文件名
2014/01/16 Python
python获取文件后缀名及批量更新目录下文件后缀名的方法
2014/11/11 Python
Python使用scrapy采集数据过程中放回下载过大页面的方法
2015/04/08 Python
python 获取一个值在某个区间的指定倍数的值方法
2018/11/12 Python
python中seaborn包常用图形使用详解
2019/11/25 Python
python计算Content-MD5并获取文件的Content-MD5值方式
2020/04/03 Python
Opencv常见图像格式Data Type及代码实例
2020/11/02 Python
芬兰汽车配件商店:Autonvaraosat24
2017/01/30 全球购物
Java TransactionAPI (JTA) 主要包含几部分
2012/12/07 面试题
CSS实现fullpage.js全屏滚动效果的示例代码
2021/03/24 HTML / CSS
应用电子技术专业个人求职信
2013/09/21 职场文书
广告学专业推荐信范文
2013/11/23 职场文书
爱国主义电影观后感
2015/06/18 职场文书
党员观看《筑梦中国》心得体会
2016/01/18 职场文书
2019教师的学习计划
2019/06/25 职场文书
那些美到让人窒息的诗句,值得你收藏!
2019/08/20 职场文书
pytorch 运行一段时间后出现GPU OOM的问题
2021/06/02 Python
Nginx实现负载均衡的项目实践
2022/03/18 Servers