最近学习BeautyGAN需要用到VGG16提取的feature map进行训练,简单学习了一些关于VGG16和feature map相关的内容。

VGG16网络结构

VGG16总共有16层,13个卷积层和3个全连接层,第一次经过64个卷积核的两次卷积,第二次经过两次128个卷积核卷积,第三次经过三层256卷积核卷积,第四次经过512个卷积核,每次卷积后进行一次pooling,最后经过三次全连接。

feature map是什么?

feature map可以理解为卷积网络从输入图片中提取出来的特征,层数越深,提取的特征越高级。

feature map的数量

feature map的数量和卷积核(filter)的数量有关。每一个卷积核提取一种特征,得到一个feature map。

feature map的作用

每一个feature map代表图片的一种特征,这些特征可以反映图片的内容。如BeautyGAN中,使用feature map进行人物身份保持。

feature map可视化

简单实现了feature map的可视化,输出VGG16每一层的feature map。

可以看到随着层数增加,feature map越来越抽象,可能看不到不过没关系,毕竟这些高级特征是给计算机识别的,不是给人识别的,果然越高级的东西越难懂。

VGG16的feature map结构及可视化

输入图片尺寸为361x361x3,VGG16每一层的feature map结构如下:

shape of layer conv1_1 is (361, 361, 64)
shape of layer conv1_2 is (361, 361, 64)
shape of layer pool1 is (181, 181, 64)
shape of layer conv2_1 is (181, 181, 128)
shape of layer conv2_2 is (181, 181, 128)
shape of layer pool2 is (91, 91, 128)
shape of layer conv3_1 is (91, 91, 256)
shape of layer conv3_2 is (91, 91, 256)
shape of layer conv3_3 is (91, 91, 256)
shape of layer pool3 is (46, 46, 256)
shape of layer conv4_1 is (46, 46, 512)
shape of layer conv4_2 is (46, 46, 512)
shape of layer conv4_3 is (46, 46, 512)
shape of layer pool4 is (23, 23, 512)
shape of layer conv5_1 is (23, 23, 512)
shape of layer conv5_2 is (23, 23, 512)
shape of layer conv5_3 is (23, 23, 512)
shape of layer pool5 is (12, 12, 512)

可视化结果如图,可以看到层数越深,feature map越抽象。

最后附上代码,可以输出每一层的特征图和所有特征子图,不过输出全部子图性能很差,不知道什么原因越到后面越慢,从昨晚开始跑了20个小时还没跑完conv4_3,开始几秒可以输出一幅,后面差不多1分钟才能输出一幅,怀疑是matplotlib.pyplot的问题,以后有时间再分析优化吧。重新分析了BeautyGAN论文,应该还是要把VGG16融合到GAN里,不能单独输出特征图再给GAN使用,因为BeautyGAN训练过程中生成器输出的“假”图也需要使用VGG16提取特征,所以二者必须在同一进程中执行,需要将两个模型合并或连接到一起。

# -*- coding:utf-8 -*-
import matplotlib
import numpy as np
import tensorflow as tf
import time
from PIL import Image
import matplotlib.pyplot as plt
import os# VGG 自带的一个常量,之前VGG训练通过归一化,所以现在同样需要作此操作
VGG_MEAN = [103.939, 116.779, 123.68]  # rgb 三通道的均值class VGGNet():"""创建 vgg16 网络 结构从模型中载入参数"""def __init__(self, data_dict):"""传入vgg16模型:param data_dict: vgg16.npy (字典类型)"""self.data_dict = data_dictdef get_conv_filter(self, name):"""得到对应名称的卷积层:param name: 卷积层名称:return: 该卷积层输出"""return tf.constant(self.data_dict[name][0], name='conv')def get_fc_weight(self, name):"""获得名字为name的全连接层权重:param name: 连接层名称:return: 该层权重"""return tf.constant(self.data_dict[name][0], name='fc')def get_bias(self, name):"""获得名字为name的全连接层偏置:param name: 连接层名称:return: 该层偏置"""return tf.constant(self.data_dict[name][1], name='bias')def conv_layer(self, x, name):"""创建一个卷积层:param x::param name::return:"""# 在写计算图模型的时候,加一些必要的 name_scope,这是一个比较好的编程规范# 可以防止命名冲突, 二可视化计算图的时候比较清楚with tf.name_scope(name):# 获得 w 和 bconv_w = self.get_conv_filter(name)conv_b = self.get_bias(name)# 进行卷积计算h = tf.nn.conv2d(x, conv_w, strides=[1, 1, 1, 1], padding='SAME')'''因为此刻的 w 和 b 是从外部传递进来,所以使用 tf.nn.conv2d()tf.nn.conv2d(input, filter, strides, padding, use_cudnn_on_gpu = None, name = None) 参数说明:input 输入的tensor, 格式[batch, height, width, channel]filter 卷积核 [filter_height, filter_width, in_channels, out_channels] 分别是:卷积核高,卷积核宽,输入通道数,输出通道数strides 步长 卷积时在图像每一维度的步长,长度为4padding 参数可选择 “SAME” “VALID”'''# 加上偏置h = tf.nn.bias_add(h, conv_b)# 使用激活函数h = tf.nn.relu(h)return hdef pooling_layer(self, x, name):"""创建池化层:param x: 输入的tensor:param name: 池化层名称:return: tensor"""return tf.nn.max_pool(x,ksize=[1, 2, 2, 1],  # 核参数, 注意:都是4维strides=[1, 2, 2, 1],padding='SAME',name=name)def fc_layer(self, x, name, activation=tf.nn.relu):"""创建全连接层:param x: 输入tensor:param name: 全连接层名称:param activation: 激活函数名称:return: 输出tensor"""with tf.name_scope(name, activation):# 获取全连接层的 w 和 bfc_w = self.get_fc_weight(name)fc_b = self.get_bias(name)# 矩阵相乘 计算h = tf.matmul(x, fc_w)#  添加偏置h = tf.nn.bias_add(h, fc_b)# 因为最后一层是没有激活函数relu的,所以在此要做出判断if activation is None:return helse:return activation(h)def flatten_layer(self, x, name):"""展平:param x: input_tensor:param name::return: 二维矩阵"""with tf.name_scope(name):# [batch_size, image_width, image_height, channel]x_shape = x.get_shape().as_list()# 计算后三维合并后的大小dim = 1for d in x_shape[1:]:dim *= d# 形成一个二维矩阵x = tf.reshape(x, [-1, dim])return xdef build(self, x_rgb):"""创建vgg16 网络:param x_rgb: [1, 224, 224, 3]:return:"""start_time = time.time()print('模型开始创建……')# 将输入图像进行处理,将每个通道减去均值r, g, b = tf.split(x_rgb, [1, 1, 1], axis=3)'''tf.split(value, num_or_size_split, axis=0)用法:value:输入的Tensornum_or_size_split:有两种用法:1.直接传入一个整数,代表会被切成几个张量,切割的维度有axis指定2.传入一个向量,向量长度就是被切的份数。传入向量的好处在于,可以指定每一份有多少元素axis, 指定从哪一个维度切割因此,上一句的意思就是从第4维切分,分为3份,每一份只有1个元素'''# 将 处理后的通道再次合并起来x_bgr = tf.concat([b - VGG_MEAN[0], g - VGG_MEAN[1], r - VGG_MEAN[2]], axis=3)#        assert x_bgr.get_shape().as_list()[1:] == [224, 224, 3]# 开始构建卷积层# vgg16 的网络结构# 第一层:2个卷积层 1个pooling层# 第二层:2个卷积层 1个pooling层# 第三层:3个卷积层 1个pooling层# 第四层:3个卷积层 1个pooling层# 第五层:3个卷积层 1个pooling层# 第六层: 全连接# 第七层: 全连接# 第八层: 全连接# 这些变量名称不能乱取,必须要和vgg16模型保持一致# 另外,将这些卷积层用self.的形式,方便以后取用方便self.conv1_1 = self.conv_layer(x_bgr, 'conv1_1')self.conv1_2 = self.conv_layer(self.conv1_1, 'conv1_2')self.pool1 = self.pooling_layer(self.conv1_2, 'pool1')self.conv2_1 = self.conv_layer(self.pool1, 'conv2_1')self.conv2_2 = self.conv_layer(self.conv2_1, 'conv2_2')self.pool2 = self.pooling_layer(self.conv2_2, 'pool2')self.conv3_1 = self.conv_layer(self.pool2, 'conv3_1')self.conv3_2 = self.conv_layer(self.conv3_1, 'conv3_2')self.conv3_3 = self.conv_layer(self.conv3_2, 'conv3_3')self.pool3 = self.pooling_layer(self.conv3_3, 'pool3')self.conv4_1 = self.conv_layer(self.pool3, 'conv4_1')self.conv4_2 = self.conv_layer(self.conv4_1, 'conv4_2')self.conv4_3 = self.conv_layer(self.conv4_2, 'conv4_3')self.pool4 = self.pooling_layer(self.conv4_3, 'pool4')self.conv5_1 = self.conv_layer(self.pool4, 'conv5_1')self.conv5_2 = self.conv_layer(self.conv5_1, 'conv5_2')self.conv5_3 = self.conv_layer(self.conv5_2, 'conv5_3')self.pool5 = self.pooling_layer(self.conv5_3, 'pool5')print('创建模型结束:%4ds' % (time.time() - start_time))# 指定 model 路径
vgg16_npy_pyth = './model/vgg16.npy'def read_img(img_name):"""读取图片:param img_name: 图片路径:return: 4维矩阵"""img = Image.open(img_name)np_img = np.array(img)  # 224, 224, 3# 需要传化 成 4 维np_img = np.asarray([np_img], dtype=np.int32)  # 这个函数作用不太理解 (1, 224, 224, 3)return np_imgdef save_feature_map(feature_batch, layer_name):"""创建特征子图,创建叠加后的特征图:param layer_name::param feature_batch: 一个卷积层所有特征图:return:"""feature_map = np.squeeze(feature_batch, axis=0)feature_map_combination = []#plt.figure()path = os.getcwd() + '\\data\\feature_maps\\' + layer_name + '\\'if not os.path.exists(path):os.makedirs(path)# 取出 featurn map 的数量num_pic = feature_map.shape[2]for i in range(0, num_pic):plt.imshow(feature_map[:, :, i])plt.savefig(path + str(i) + '.jpg')def save_feature_map_sum(feature_batch, layer_name):"""将每张子图进行相加:param layer_name::param feature_batch::return:"""feature_map = np.squeeze(feature_batch, axis=0)feature_map_combination = []# 取出 featurn map 的数量num_pic = feature_map.shape[2]# 将 每一层卷积的特征图,拼接层 5 × 5for i in range(0, num_pic):feature_map_split = feature_map[:, :, i]feature_map_combination.append(feature_map_split)# 按照特征图 进行 叠加代码feature_map_sum = sum(one for one in feature_map_combination)plt.imshow(feature_map_sum)path = os.getcwd() + '\\data\\feature_maps\\layer_sum\\'if not os.path.exists(path):os.makedirs(path)plt.savefig(path + layer_name + '.jpg')def get_feature_maps(img_path):# 读取 内容图像content_val = read_img(img_path)print('shape of image: ' + str(content_val.shape))content = tf.placeholder(tf.float32, shape=content_val.shape)# 载入模型, 注意:在python3中,需要添加一句: encoding='latin1'data_dict = np.load(vgg16_npy_pyth, encoding='latin1').item()# 创建图像的 vgg 对象vgg_for_content = VGGNet(data_dict)# 创建 每个 神经网络vgg_for_content.build(content)content_features = [vgg_for_content.conv1_1,vgg_for_content.conv1_2,vgg_for_content.pool1,vgg_for_content.conv2_1,vgg_for_content.conv2_2,vgg_for_content.pool2,vgg_for_content.conv3_1,vgg_for_content.conv3_2,vgg_for_content.conv3_3,vgg_for_content.pool3,vgg_for_content.conv4_1,vgg_for_content.conv4_2,vgg_for_content.conv4_3,vgg_for_content.pool4,vgg_for_content.conv5_1,vgg_for_content.conv5_2,vgg_for_content.conv5_3,vgg_for_content.pool5]init_op = tf.global_variables_initializer()with tf.Session() as sess:sess.run(init_op)content_features_result = sess.run([content_features],feed_dict={content: content_val})for i in range(0, len(content_features_result[0])):feature_batch = content_features_result[0][i]layer_name = str(content_features[i].name).split('/')[0].split(':')[0]print('shape of layer ' + layer_name + ' is ' + str(feature_batch[0].shape))# save_feature_map(feature_batch, layer_name)save_feature_map_sum(feature_batch, layer_name)get_feature_maps('./data/mk1.png')

【Deep Learning】VGG16之feature map学习笔记相关推荐

  1. AI:《DEEP LEARNING’S DIMINISHING RETURNS—深度学习的收益递减》翻译与解读

    AI:<DEEP LEARNING'S DIMINISHING RETURNS-深度学习的收益递减>翻译与解读 导读:深度学习的收益递减.麻省理工学院的 Neil Thompson 和他的 ...

  2. dive into deep learning 循环神经网络 RNN 部分 学习

    dive into deep learning 循环神经网络 RNN 部分 学习 到目前为止,我们遇到过两种类型的数据:表格数据和图像数据. 对于图像数据,我们设计了专门的卷积神经网络架构来为这类特殊 ...

  3. Partial Transfer Learning with Selective Adversarial Networks学习笔记

    Partial Transfer Learning with Selective Adversarial Networks学习笔记 文章目录 Partial Transfer Learning wit ...

  4. Deep Learning on Graphs: A Survey论文笔记

    Deep Learning on Graphs: A Survey 问题 术语表示 词汇说明 摘要信息 文章框架 主要内容 读出操作 什么是读出操作(readout operation) 读出操作要求 ...

  5. deep learning for the earth sciences 读书笔记

    第二章 learning unsuoerxised festure representations of remote sensing data with sparse convolutional 2 ...

  6. A Gentle Introduction to Deep Learning for Graphs 图深度学习的温和介绍

    文章目录 1.简介 2. 高级概述 2.1.数学符号 2.2.动机 2.3.大图 2.4.局部关系和信息的迭代处理 2.5.语境扩散的三种机制 3.构建块 3.1.邻域(邻居)聚集 3.2.池化 3. ...

  7. CVPR2020 Learning in the Frequency Domain学习笔记

    论文总结 为了解决CNN只能接受低分辨率的RGB图像,并且不改变现有的神经网络,论文提出了一种从频域上对图像进行reshape的方法,把原有图像压缩中的decoding环节里的IDCT过程去掉(计算量 ...

  8. What is Deep Learning?(什么是深度学习?)

    What is Deep Learning? 原文地址:https://machinelearningmastery.com/what-is-deep-learning/ 原文作者:Jason Bro ...

  9. Deep Learning Tuning Playbook(深度学习调参手册中译版)

    前言 由五名研究人员和工程师组成的团队发布了<Deep Learning Tuning Playbook>,来自他们自己训练神经网络的实验结果以及工程师的一些实践建议,目前在Github上 ...

最新文章

  1. LLVM 编译器和工具链技术
  2. 计算机网络:第三章 数据链路层
  3. 《javaScript100例|03》自写javaScript+CSS轮显效果
  4. struct stat结构体简介
  5. session实现机制_如何理解php session运行机制
  6. python int函数和二进制、八进制、十进制转换
  7. 火眼报告称2019年新出现500个新型恶意软件
  8. 分享Qt的面试题目(或许未来的我能用的上呢)_vortex_新浪博客
  9. teechart的addarray_用Teechart画二维成像图
  10. 2020年全球石英晶振行业现状、竞争格局及未来发展趋势分析,5G推动万物互联,带动行业需求「图」
  11. UiPath PDF操作
  12. 《一》微信小程序简介
  13. 两个小故事告诉你静下来的力量
  14. 改革40年致敬创业者:有梦想谁都了不起!
  15. mysql 按照年龄段分组查询
  16. mysql idb 恢复_mysql靠idb文件恢复数据
  17. 【HoloLens】启用Mixed Reality Portal混合现实门户
  18. android 如何编译.so,Android源码中编译自己的so库
  19. 三星S21 FE 参数配置 三星S21 FE评测
  20. Python脚本调用腾讯地图接口

热门文章

  1. 最初学习阶段有用没用的杂七杂八
  2. android资料转移到iphone,安卓手机内的资料如何转移到iPhone XS/XS Max?
  3. 地大武汉C语言考研真题,2021中国地质大学武汉考研历年真题专业目录
  4. 备份、文件分享、远程下载 海康Mage10轻NAS首发体验
  5. iPhone照片导入到Mac电脑方法
  6. 浅谈对java深拷贝与浅拷贝的理解
  7. Java怎么表示正无穷大和负无穷大
  8. Android项目:基于Android家庭理财系统手机软件设计(计算机毕业设计)
  9. JCJC错别字检测接口API测试说明文档
  10. 江苏大学计算机专业江苏排名,江苏大学专业排名情况