【TensorFlow-windows】(七) CNN之VGG-net的测试
主要内容:  
1.CNN之VGG-net的测试  
2.该实现中的函数总结
平台:  
1.windows 10 64位  
2.Anaconda3-4.2.0-Windows-x86_64.exe (当时TF还不支持python3.6,又懒得在高版本的anaconda下配置多个Python环境,于是装了一个3-4.2.0(默认装python3.5),建议装anaconda3的最新版本,TF1.2.0版本已经支持python3.6!)  
3.TensorFlow1.1.0
牛津大学计算机视觉组(Visual Geometry Group)出产的VGGnet是 ILSVRC 2014年 分类第二名,定位项目第一名,其VGG-16\VGG-19广泛应用于图像领域! 
论文《very deep convolutional networks for large-scale image recognition》 
特点就是多个小卷积核(3*3)的堆叠来替代大卷积核(5*5,7*7),减少参数的同时增加了特征提取的能力。
来看看论文中给了5个模型的基本情况: 
今天就用TF写一个VGG-16 ,上图红框中的那个,由于硬件问题,这里和Alex-net一样,只是做了一个前向和反向的耗时计算。(PS: GTX960m的 GPU(2G显存),没办法实现 batch_size为32,全连接层1为4096,全连接层2为4096个神经元的VGG网络,因此我修改了网络大小, batch_size为16, 全连接层1和2 都改为2048个神经元)
# -*- coding: utf-8 -*-
"""
Created on Mon Jun 12 16:36:43 2017
@author: ASUS
"""
from datetime import datetime
import math
import time
import tensorflow as tf
# 定义函数对卷积层进行初始化
# input_op : 输入数据
# name : 该卷积层的名字,用tf.name_scope()来命名
# kh,kw : 分别是卷积核的高和宽
# n_out : 输出通道数
# dh,dw : 步长的高和宽
# p : 是参数列表,存储VGG所用到的参数
# 采用xavier方法对卷积核权值进行初始化
def conv_op(input_op, name, kh, kw, n_out, dh, dw, p):
    n_in = input_op.get_shape()[-1].value # 获得输入图像的通道数
    with tf.name_scope(name) as scope:
        kernel = tf.get_variable(scope+'w',
            shape = [kh, kw, n_in, n_out], dtype = tf.float32,
            initializer = tf.contrib.layers.xavier_initializer_conv2d())
        #  卷积层计算
        conv = tf.nn.conv2d(input_op, kernel, (1, dh, dw, 1), padding = 'SAME')
        bias_init_val = tf.constant(0.0, shape = [n_out], dtype = tf.float32)
        biases = tf.Variable(bias_init_val, trainable = True, name = 'b')
        z = tf.nn.bias_add(conv, biases)
        activation = tf.nn.relu(z, name = scope)
        p += [kernel, biases]
        return activation
# 定义函数对全连接层进行初始化
# input_op : 输入数据
# name : 该全连接层的名字
# n_out : 输出的通道数
# p : 参数列表
# 初始化方法用 xavier方法
def fc_op(input_op, name, n_out, p):
    n_in = input_op.get_shape()[-1].value
    with tf.name_scope(name) as scope:
        kernel = tf.get_variable(scope+'w',
            shape = [n_in, n_out], dtype = tf.float32,
            initializer = tf.contrib.layers.xavier_initializer())
        biases = tf.Variable(tf.constant(0.1, shape = [n_out],
            dtype = tf.float32), name = 'b')
        activation = tf.nn.relu_layer(input_op, kernel,  #  ???????????????
            biases, name = scope)
        p += [kernel, biases]
        return activation 
# 定义函数 创建 maxpool层
# input_op : 输入数据
# name : 该卷积层的名字,用tf.name_scope()来命名
# kh,kw : 分别是卷积核的高和宽
# dh,dw : 步长的高和宽
def mpool_op(input_op, name, kh, kw, dh, dw):
    return tf.nn.max_pool(input_op, ksize = [1,kh,kw,1],
        strides = [1, dh, dw, 1], padding = 'SAME', name = name)
#---------------创建 VGG-16------------------
def inference_op(input_op, keep_prob):
    p = []
    # 第一块 conv1_1-conv1_2-pool1
    conv1_1 = conv_op(input_op, name='conv1_1', kh=3, kw=3,
                n_out = 64, dh = 1, dw = 1, p = p)
    conv1_2 = conv_op(conv1_1, name='conv1_2', kh=3, kw=3,
                n_out = 64, dh = 1, dw = 1, p = p)
    pool1 = mpool_op(conv1_2, name = 'pool1', kh = 2, kw = 2,
                dw = 2, dh = 2)
    # 第二块 conv2_1-conv2_2-pool2
    conv2_1 = conv_op(pool1, name='conv2_1', kh=3, kw=3,
                n_out = 128, dh = 1, dw = 1, p = p)
    conv2_2 = conv_op(conv2_1, name='conv2_2', kh=3, kw=3,
                n_out = 128, dh = 1, dw = 1, p = p)
    pool2 = mpool_op(conv2_2, name = 'pool2', kh = 2, kw = 2,
                dw = 2, dh = 2)
    # 第三块 conv3_1-conv3_2-conv3_3-pool3
    conv3_1 = conv_op(pool2, name='conv3_1', kh=3, kw=3,
                n_out = 256, dh = 1, dw = 1, p = p)
    conv3_2 = conv_op(conv3_1, name='conv3_2', kh=3, kw=3,
                n_out = 256, dh = 1, dw = 1, p = p)
    conv3_3 = conv_op(conv3_2, name='conv3_3', kh=3, kw=3,
                n_out = 256, dh = 1, dw = 1, p = p)
    pool3 = mpool_op(conv3_3, name = 'pool3', kh = 2, kw = 2,
                dw = 2, dh = 2)
    # 第四块 conv4_1-conv4_2-conv4_3-pool4
    conv4_1 = conv_op(pool3, name='conv4_1', kh=3, kw=3,
                n_out = 512, dh = 1, dw = 1, p = p)
    conv4_2 = conv_op(conv4_1, name='conv4_2', kh=3, kw=3,
                n_out = 512, dh = 1, dw = 1, p = p)
    conv4_3 = conv_op(conv4_2, name='conv4_3', kh=3, kw=3,
                n_out = 512, dh = 1, dw = 1, p = p)
    pool4 = mpool_op(conv4_3, name = 'pool4', kh = 2, kw = 2,
                dw = 2, dh = 2)
    # 第五块 conv5_1-conv5_2-conv5_3-pool5
    conv5_1 = conv_op(pool4, name='conv5_1', kh=3, kw=3,
                n_out = 512, dh = 1, dw = 1, p = p)
    conv5_2 = conv_op(conv5_1, name='conv5_2', kh=3, kw=3,
                n_out = 512, dh = 1, dw = 1, p = p)
    conv5_3 = conv_op(conv5_2, name='conv5_3', kh=3, kw=3,
                n_out = 512, dh = 1, dw = 1, p = p)
    pool5 = mpool_op(conv5_3, name = 'pool5', kh = 2, kw = 2,
                dw = 2, dh = 2)
    # 把pool5 ( [7, 7, 512] )  拉成向量
    shp  = pool5.get_shape()
    flattened_shape = shp[1].value * shp[2].value * shp[3].value
    resh1 = tf.reshape(pool5, [-1, flattened_shape], name = 'resh1')
    # 全连接层1 添加了 Droput来防止过拟合
    fc1 = fc_op(resh1, name = 'fc1', n_out = 2048, p = p)
    fc1_drop = tf.nn.dropout(fc1, keep_prob, name = 'fc1_drop')
    # 全连接层2 添加了 Droput来防止过拟合
    fc2 = fc_op(fc1_drop, name = 'fc2', n_out = 2048, p = p)
    fc2_drop = tf.nn.dropout(fc2, keep_prob, name = 'fc2_drop')
    # 全连接层3 加一个softmax求给类别的概率
    fc3 = fc_op(fc2_drop, name = 'fc3', n_out = 1000, p = p)
    softmax = tf.nn.softmax(fc3)
    predictions = tf.argmax(softmax, 1)
    return predictions, softmax, fc3, p
# 定义评测函数
def time_tensorflow_run(session, target, feed, info_string):
    num_steps_burn_in = 10
    total_duration = 0.0
    total_duration_squared = 0.0
    for i in range(num_batches + num_steps_burn_in):
        start_time = time.time()
        _ = session.run(target, feed_dict = feed)
        duration = time.time() - start_time
        if i >= num_steps_burn_in:
            if not i  % 10:
                print('%s: step %d, duration = %.3f' %
                    (datetime.now(), i-num_steps_burn_in, duration))
            total_duration += duration
            total_duration_squared += duration * duration
    mean_dur = total_duration / num_batches
    var_dur = total_duration_squared / num_batches - mean_dur * mean_dur
    std_dur = math.sqrt(var_dur)
    print('%s: %s across %d steps, %.3f +/- %.3f sec / batch' %(datetime.now(), info_string, num_batches, mean_dur, std_dur))
# 定义函数 运行网络
def run_benchmark():
    with tf.Graph().as_default():
        image_size = 224
        images = tf.Variable(tf.random_normal(
            [batch_size, image_size, image_size, 3],
            dtype = tf.float32, stddev = 1e-1))
        keep_prob = tf.placeholder(tf.float32)
        predictions, softmax, fc3, p = inference_op(images, keep_prob)
        # 创建session ,初始化参数
        init = tf.global_variables_initializer()
        sess = tf.Session()
        sess.run(init)
        # 评测  forward的耗时
        time_tensorflow_run(sess, predictions, {keep_prob: 1.0}, 'Forward')
        # 评测 forward 和 backward
        objective = tf.nn.l2_loss(fc3)
        gard = tf.gradients(objective, p)
        time_tensorflow_run(sess,gard,predictions, {keep_prob: 0.5}, 'Forward-backward')
batch_size = 16
num_batches = 100
run_benchmark() 函数总结(续上篇)
sess = tf.InteractiveSession() 将sess注册为默认的session  
tf.placeholder() , Placeholder是输入数据的地方,也称为占位符,通俗的理解就是给输入数据(此例中的图片x)和真实标签(y_)提供一个入口,或者是存放地。(个人理解,可能不太正确,后期对TF有深入认识的话再回来改~~)  
tf.Variable() Variable是用来存储模型参数,与存储数据的tensor不同,tensor一旦使用掉就消失  
tf.matmul() 矩阵相乘函数  
tf.reduce_mean 和tf.reduce_sum 是缩减维度的计算均值,以及缩减维度的求和  
tf.argmax() 是寻找tensor中值最大的元素的序号 ,此例中用来判断类别  
tf.cast() 用于数据类型转换  
————————————–我是分割线(一)———————————–  
tf.random_uniform 生成均匀分布的随机数  
tf.train.AdamOptimizer() 创建优化器,优化方法为Adam(adaptive moment estimation,Adam优化方法根据损失函数对每个参数的梯度的一阶矩估计和二阶矩估计动态调整针对于每个参数的学习速率)  
tf.placeholder “占位符”,只要是对网络的输入,都需要用这个函数这个进行“初始化”  
tf.random_normal 生成正态分布  
tf.add 和 tf.matmul 数据的相加 、相乘  
tf.reduce_sum 缩减维度的求和  
tf.pow 求幂函数  
tf.subtract 数据的相减  
tf.global_variables_initializer 定义全局参数初始化  
tf.Session 创建会话.  
tf.Variable 创建变量,是用来存储模型参数的变量。是有别于模型的输入数据的  
tf.train.AdamOptimizer (learning_rate = 0.001) 采用Adam进行优化,学习率为 0.001  
————————————–我是分割线(二)———————————–  
1. hidden1_drop = tf.nn.dropout(hidden1, keep_prob) 给 hindden1层增加Droput,返回新的层hidden1_drop,keep_prob是 Droput的比例  
2. mnist.train.next_batch() 来详细讲讲 这个函数。一句话概括就是,打乱样本顺序,然后按顺序读取batch_size 个样本 进行返回。  
具体看代码及其注释,首先要找到函数定义,在tensorflow\contrib\learn\python\learn\datasets 下的mnist.py  
————————————–我是分割线(三)———————————–  
1. tf.nn.conv2d(x, W, strides = [1, 1, 1, 1], padding =’SAME’)对于这个函数主要理解 strides和padding,首先明确,x是输入,W是卷积核,并且它们的维数都是4(发现strides里有4个元素没,没错!就是一一对应的)  
先说一下卷积核W也是一个四维张量,各维度表示的信息是:[filter_height, filter_width, in_channels, out_channels]
输入x,x是一个四维张量 ,各维度表示的信息是:[batch, in_height, in_width, in_channels]
strides里的每个元素就是对应输入x的四个维度的步长,因为第2,3维是图像的长和宽,所以平时用的strides就在这里设置,而第1,4维一般不用到,所以是1
padding只有两种取值方式,一个是 padding=[‘VALID’] 一个是padding=[‘SAME’]  
valid:采用丢弃的方式,只要移动一步时,最右边有超出,则这一步不移动,并且剩余的进行丢弃。如下图,图片长13,卷积核长6,步长是5,当移动一步之后,已经卷积核6-11,再移动一步,已经没有足够的像素点了,所以就不能移动,因此 12,13被丢弃。  
same:顾名思义,就是保持输入的大小不变,方法是在图像边缘处填充全0的像素  
————————————–我是分割线(四)———————————–  
1.tf.nn.l2_loss()是对一个Tensor对象求L2 norm,这里用来求权值的L2范数  
2.tf.add_to_collection(‘losses’, weight_loss), 把weight_loss 加到名为losses的loss中去  
3.tf.nn.lrn,做局部相应归一化,来看看函数的定义
lrn(input, depth_radius=None, bias=None, alpha=None, beta=None,name=None)
函数有6个输入,第一个自然是输入啦,2-5是LRN用到的参数,第一个是depth半径,bias alpha beta是相应的参数,来看看伪代码就清楚了
sqr_sum[a, b, c, d] = sum(input[a, b, c, d - depth_radius : d + depth_radius + 1] ** 2) 
  output = input / (bias + alpha * sqr_sum) ** beta 
2-5的参数是有默认值的,分别是5,1,1,0.5
3.tf.nn.sparse_softmax_cross_entropy_with_logits()就是计算交叉熵的,但是如果是一个batch的,得出的是一个向量,还需要配合tf.reduce_mean()才能计算得出最终的loss(标量)
4.tf.get_collection(‘losses’), 从一个集合中取出全部变量,返回的是一个列表,这里是把losses的都取出来,在上面把 weight_loss和输出层的loss都加到losses中了,这个函数就是把losses中的loss取出来
5.tf.add_n:把一个列表的东西都依次加起来 (Adds all input tensors element-wise.) 输入是一个list (inputs: A list of Tensor objects, each with same shape and type.)  
————————————–我是分割线(五)———————————–
1.t.get_shape().as_list() ,t是一个tensor,函数以list的形式返回 tensor的shape  
2.tf.name_scope(‘conv1’) as scope ,tf.name_scope是用来命名Variable的,print(parameters)可以看到命名  
3. tf.Graph().as_default()能够在这个上下文里面覆盖默认的图,测试了一下 不用这个也可以,但是用上好点,可能是避免冲突吧~ 
 ————————————–我是分割线(六)———————————– 
 1. tensor.get_shape()[-1].value 获得 倒数第一个维度上的维数 
 2. tf.get_variable(scope+’w’, 
            shape = [kh, kw, n_in, n_out], dtype = tf.float32, 
            initializer = tf.contrib.layers.xavier_initializer_conv2d()) 
  来看看函数定义:
def get_variable(name,
                 shape=None,
                 dtype=None,
                 initializer=None,
                 regularizer=None,
                 trainable=True,
                 collections=None,
                 caching_device=None,
                 partitioner=None,
                 validate_shape=True,
                 use_resource=None,
                 custom_getter=None):这下就清楚多了,除了第一个形参,其余都是带默认值的关键字参数,这样不根据参形参的顺序对参数赋值啦
3.tf.nn.relu_layer(input_op, kernel, biases, name = scope) 
这个函数把 卷积操作,加偏置操作,relu操作 集成在一块儿了,不过这个仅限于全连接层这种一维的层,因为输入必须是2D的,具体如下:
def relu_layer(x, weights, biases, name=None): 
 Args: 
    x: a 2D tensor.  Dimensions typically: batch, in_units 
    weights: a 2D tensor.  Dimensions typically: in_units, out_units 
    biases: a 1D tensor.  Dimensions: out_units 
    name: A name for the operation (optional).  If not specified 
      “nn_relu_layer” is used. 
  Returns: 
    A 2-D Tensor computing relu(matmul(x, weights) + biases). 
    Dimensions typically: batch, out_units.
【TensorFlow-windows】(七) CNN之VGG-net的测试的更多相关文章
- 【深度学习系列】用PaddlePaddle和Tensorflow实现经典CNN网络Vgg
		上周我们讲了经典CNN网络AlexNet对图像分类的效果,2014年,在AlexNet出来的两年后,牛津大学提出了Vgg网络,并在ILSVRC 2014中的classification项目的比赛中取得 ... 
- tensorflow windows
		conda create -n py35 python=3.5 activate py35 pip install --ignore-installed --upgrade https://stora ... 
- CNN tensorflow text classification CNN文本分类的例子
		from:http://deeplearning.lipingyang.org/tensorflow-examples-text/ TensorFlow examples (text-based) T ... 
- 基于Tensorflow + Opencv 实现CNN自定义图像分类
		摘要:本篇文章主要通过Tensorflow+Opencv实现CNN自定义图像分类案例,它能解决我们现实论文或实践中的图像分类问题,并与机器学习的图像分类算法进行对比实验. 本文分享自华为云社区< ... 
- Tensorflow object detection API(1)---环境搭建与测试
		参考: https://blog.csdn.net/dy_guox/article/details/79081499 https://blog.csdn.net/u010103202/article/ ... 
- Alink漫谈(七) : 如何划分训练数据集和测试数据集
		Alink漫谈(七) : 如何划分训练数据集和测试数据集 目录 Alink漫谈(七) : 如何划分训练数据集和测试数据集 0x00 摘要 0x01 训练数据集和测试数据集 0x02 Alink示例代码 ... 
- 【深度学习系列】用PaddlePaddle和Tensorflow实现经典CNN网络AlexNet
		上周我们用PaddlePaddle和Tensorflow实现了图像分类,分别用自己手写的一个简单的CNN网络simple_cnn和LeNet-5的CNN网络识别cifar-10数据集.在上周的实验表现 ... 
- TensorFlow Windows 安装
		欢迎大家关注我们的网站和系列教程:http://www.tensorflownews.com/,学习更多的机器学习.深度学习的知识! 本系列教程将手把手带您从零开始学习Tensorflow,并最终通过 ... 
- 猫狗识别-CNN与VGG实现
		本次项目首先使用CNN卷积神经网络模型进行训练,最终训练效果不太理想,出现了过拟合的情况.准确率达到0.72,loss达到0.54.使用预训练的VGG模型后,在测试集上准确率达到0.91,取得了不错的 ... 
随机推荐
- Caps_Locl exchang Esc
			vim ~/.Xmodmap 1 remove Lock = Caps_Lock 2 keysym Escape = ... 
- 从零开始学习OpenCL开发(一)架构【转】
			转自:http://blog.csdn.net/leonwei/article/details/8880012 多谢大家关注 转载本文请注明:http://blog.csdn.net/leonwei/ ... 
- [MySQL] xtrabakcup原理
			Xtrabackup InnoDB内部的Redo log, 也叫Transaction log file. 存储每一个InnoDB表纪录的修改日志. 当InnoDB启动时, InnoDB会检查数据文件 ... 
- C++多线程(POSIX)
			#include<iostream> #include<pthread.h> #include<ctime> #include<windows.h> u ... 
- (7)python tkinter-菜单栏
			菜单栏 Menu f = tkinter.Menu(root) root['menu']=f f.add_command(label='菜单')# f.add_command(label='关于') ... 
- java8 之CompletableFuture -- 如何构建异步应用
			什么是Future 接口 很多场景下,我们想去获取线程运行的结果,而通常使用execute方法去提交任务是无法获得结果的,这时候我们常常会改用submit方法去提交,以便获得线程运行的结果. 而sub ... 
- Break Number --AtCoder
			题目描述 Takahashi loves numbers divisible by 2.You are given a positive integer N. Among the integers b ... 
- centos7最新 mysq5.6 安装
			安装教程 1.下载mysql的repo源 wget http://repo.mysql.com/mysql-community-release-el7-5.noarch.rpm 可能遇见的问题: ... 
- Codeforces Round #324 (Div. 2) Kolya and Tanya 组合数学
			原题链接:http://codeforces.com/contest/584/problem/B 题意: 有3*n个人围成一个圈,每个人可以分配1到3个硬币,但是相邻为n的三个人的和不能是6,问你有多 ... 
- Apollo 分布式配置中心
			1. 介绍 Apollo(阿波罗)是携程框架部门研发的分布式配置中心,能够集中化管理应用不同环境.不同集群的配置,配置修改后能够实时推送到应用端,并且具备规范的权限.流程治理等特性,适用于微服务配置 ... 
