解读完毕cifar_input.py再看这个程序cifar_train.py

源代码奉上

# CIFAR-10数据集训练
import sys
sys.path.append("models/tutorials/image/cifar10")
# 下载和读取CIFAR-10的类
import cifar10_input
import tensorflow as tf
import numpy as np
import time


# 训练轮数
max_steps = 30000
batch_size = 128


LEARNING_RATE_BASE=0.001
LEARNING_RATE_DECAY=0.99

MOVING_AVERAGE_DECAY=0.99

# 下载DIFAR-10数据的默认路径
data_dir = 'cifar10_data/cifar-10-batches-bin'

# L1正则会制造稀疏的特征,大部分无用特征的权重会被置0
# L2正则会让特征不过大,使得特征的权重比较均匀

# 使用正太分布初始化权重并添加L2正则化,使用w1控制L2损失的大小
def variable_with_weight_loss(shape, stddev, w1):
    # 从截断的(2个标准差以内)正态分布中输出随机值
    var = tf.Variable(tf.truncated_normal(shape, stddev=stddev))
    if w1 is not None:
        # l2_loss(var)*w1
        weight_loss = tf.multiply(tf.nn.l2_loss(var), w1, name='weight_loss')
        # 使用默认图
        tf.add_to_collection('losses', weight_loss)
    return var

# 从Alex的网站下载并解压到默认位置
#cifar10.maybe_download_and_extract()
# 使用Reader操作构造CIFAR训练需要的数据(特征及其对应的label)
# 并对数据进行了数据增强(水平翻转/随机对比度亮度/随机裁剪)以及数据的标准化
with tf.device('/cpu:0'):
    images_train, labels_train = cifar10_input.distorted_inputs(data_dir=data_dir,batch_size=batch_size)
# 使用Reader操作构建CIFAR评估的输入(裁剪图像中间24*24大小的块并进行数据标准化)
    images_test, labels_test =cifar10_input.inputs(eval_data=True, data_dir=data_dir, batch_size=batch_size)

# 输入图像占位符(24*24 3通道)
image_holder = tf.placeholder(tf.float32, [batch_size, 24, 24, 3])
# 输入标签占位符
label_holder = tf.placeholder(tf.int32, [batch_size])

# 卷积层1
# 32个5*5的卷积核3通道,不对第一个卷积层的权重加L2正则
weight1 = variable_with_weight_loss(shape=[5, 5, 3, 64], stddev=10e-4, w1=0.0)
# 卷积步长为1模式为SAME
kernel1 = tf.nn.conv2d(image_holder, weight1, [1, 1, 1, 1], padding='SAME')
# bias为0
bias1 = tf.Variable(tf.constant(0.0, shape=[64]))
# Adds bias to value
conv1 = tf.nn.relu(tf.nn.bias_add(kernel1, bias1))
# 最大池化 大小3*3步长2*2
pool1 = tf.nn.max_pool(conv1, ksize=[1, 3, 3, 1], strides=[1, 2, 2, 1], padding='SAME')
# 使用LRN对结果进行处理-Local Response Normalization-本地响应标准化
# 增强大的抑制小的,增强泛化能力
norm1 = tf.nn.lrn(pool1, 4, bias=1.0, alpha=0.001/9.0, beta=0.75)#按照网上说法好像没用

# 卷积层2
# 32个5*5的卷积核64通道,不加L2正则
weight2 = variable_with_weight_loss(shape=[5, 5, 64, 64], stddev=10e-2, w1=0.0)
# 卷积步长为1模式为SAME
kernel2 = tf.nn.conv2d(norm1, weight2, [1, 1, 1, 1], padding='SAME')
# bias为0.1
bias2 = tf.Variable(tf.constant(0.1, shape=[64]))
# Adds bias to value
conv2 = tf.nn.relu(tf.nn.bias_add(kernel2, bias2))
# LRN-本地响应标准化
norm2 = tf.nn.lrn(conv2, 4, bias=1.0, alpha=0.001/0.9, beta=0.75)
# 最大池化 大小3*3步长2*2
pool2 = tf.nn.max_pool(norm2, ksize=[1, 3, 3, 1], strides=[1, 2, 2, 1], padding='SAME')


# 卷积层23
# 64个5*5的卷积核64通道,不加L2正则
weight3 = variable_with_weight_loss(shape=[5, 5, 64, 128], stddev=10e-2, w1=0.0)
# 卷积步长为1模式为SAME
kernel3 = tf.nn.conv2d(pool2, weight3, [1, 1, 1, 1], padding='SAME')
# bias为0.1
bias3 = tf.Variable(tf.constant(0.1, shape=[128]))
# Adds bias to value
conv3 = tf.nn.relu(tf.nn.bias_add(kernel3, bias3))
# LRN-本地响应标准化
norm3 = tf.nn.lrn(conv3, 4, bias=1.0, alpha=0.001/0.9, beta=0.75)
# 最大池化 大小3*3步长2*2
pool3 = tf.nn.max_pool(norm2, ksize=[1, 3, 3, 1], strides=[1, 2, 2, 1], padding='SAME')



# 全连接层
# 将样本变成一维向量
reshape = tf.reshape(pool3, [batch_size, -1])
# 数据扁平化后的长度
dim = reshape.get_shape()[1].value
# weight初始化
weight3 = variable_with_weight_loss(shape=[dim, 384], stddev=0.04, w1=0.004)
# bias初始化
bias3 = tf.Variable(tf.constant(0.1, shape=[384]))
local3 = tf.nn.relu(tf.matmul(reshape, weight3) + bias3)

# 隐含节点数降为192
weight4 = variable_with_weight_loss(shape=[384, 192], stddev=0.04, w1=0.004)
bias4 = tf.Variable(tf.constant(0.1, shape=[192]))
local4 = tf.nn.relu(tf.matmul(local3, weight4) + bias4)

# 最终输出10分类,正太分布标准差设为上一隐含层节点数的倒数,不计入L2正则
weight5 = variable_with_weight_loss(shape=[192, 10], stddev=1/192.0, w1=0.0)
bias5 = tf.Variable(tf.constant(0.0, shape=[10]))
logits = tf.add(tf.matmul(local4, weight5), bias5)

global_step=tf.Variable(0,trainable=False)#初始化钟表0,使其为不可被训练更新

# 计算CNN的loss
def loss(logits, labels):
    labels = tf.cast(labels, tf.int64)




    # 计算logits和labels之间的稀疏softmax交叉熵
    cross_entropy = tf.nn.sparse_softmax_cross_entropy_with_logits(
        logits=logits, labels=labels, name='cross_entropy_per_example')
    # 计算cross_entropy均值
    cross_entropy_mean = tf.reduce_mean(cross_entropy, name='cross_entropy')
    # 将cross_entropy的loss添加到整体的loss里
    tf.add_to_collection('losses', cross_entropy_mean)
    # 将整体losses的collection中的全部loss求和
    return tf.add_n(tf.get_collection('losses'), name='total_loss')
    #加入滑动平均
# variable_averages = tf.train.ExponentialMovingAverage(
#         MOVING_AVERAGE_DECAY, global_step)
# variable_averages_op = variable_averages.apply(
#         tf.trainable_variables())  # 可更新的变量全部更新
# 将logits节点label_holder和传入loss函数获得最终的loss
loss = loss(logits, label_holder)
#加入学习率衰减
learning_rate=tf.train.exponential_decay(
        LEARNING_RATE_BASE,
        global_step,
        390,
        LEARNING_RATE_DECAY)

# 优化器选择Adam,学习率选1e-3
train_op = tf.train.AdamOptimizer(learning_rate).minimize(loss,global_step=global_step)
# with tf.control_dependencies([train_op, variable_averages_op]):
#     train_op = tf.no_op(name='loss')  # 保证train之前参数被刷新

# 求top k的准确率(默认top1即输出分数最高的一类)
top_k_op = tf.nn.in_top_k(logits, label_holder, 1)


# 创建默认的session()
sess = tf.InteractiveSession()
# 初始化全部的模型参数
tf.global_variables_initializer().run()

# 启动图片数据增强的线程队列
tf.train.start_queue_runners()

for step in range(max_steps):
    start_time = time.time()
    # 使用sess的run方法执行images_train和labels_train的计算
    image_batch, label_batch = sess.run([images_train, labels_train])
    _, loss_value = sess.run([train_op, loss],
              feed_dict={image_holder: image_batch, label_holder:label_batch})
    # 记录每个step的时间
    duration = time.time() - start_time
    if step % 10 == 0:
        # 每秒训练的样本数量
        examples_per_sec = batch_size / duration
        # 训练每个batch的时间
        sec_per_batch = float(duration)
        format_str = ('step %d, lass=%.2f (%.1f examples/sec; %.3f sec/batch)')
        print(step, loss_value, examples_per_sec, sec_per_batch)


# 测试集样本数量
num_examples = 10000
import math
# 总共多少个batch
num_inter = int(math.ceil(num_examples / batch_size))#math.ceil 向上取整
true_count = 0
total_sample_count = num_inter * batch_size
step = 0
while step < num_inter:
    # 使用sess的run方法获取images_test和labels_test的batch
    image_batch, label_batch = sess.run([images_test, labels_test])
    # 预测正确的样本数量
    predictions = sess.run([top_k_op], feed_dict={image_holder: image_batch,
                            label_holder: label_batch})
    # 汇总预测正确的结果
    true_count += np.sum(predictions)
    step += 1

# 准确率评测结果
prediction = true_count / total_sample_count
print ("precision @ 1 = %g" % (prediction))

开始解读 脚踏实地
也就是说 看了cifar_input解读以后 你给我数据集的二进制文件(.bin)我就可以把他进行预处理 然后怎么输入神经网络进行训练需要再次研读

1.导入工具

需要注意的是:
import sys
sys.path.append(“models/tutorials/image/cifar10”)

sys.path 包含输入模块的目录名列表。
获取指定模块搜索路径的字符串集合,可以将写好的模块放在得到的某个路径下,就可以在程序中import时正确找到。在import导入module_name时,就是根据sys.path的路径来搜索module.name,也可以自定义添加模块路径。
sys.path.append(“自定义模块路径”)

简而言之 我现在要导入比如之前的cifar_input文件,我得找到这个文件的目录 就是这个models/tutorials/image/cifar10
也就是 经过检验证明 如果你把cifar_input这个文件放在项目文件夹下第一级,那么不用这个语句也可以

import sys
sys.path.append("models/tutorials/image/cifar10")
# 下载和读取CIFAR-10的类
import cifar10_input
import tensorflow as tf
import numpy as np
import time

2.定义全局常量

当然啦 这里的指数衰减和滑动平均都是我自己加入的

# 训练轮数
max_steps = 30000
batch_size = 128


LEARNING_RATE_BASE=0.001
LEARNING_RATE_DECAY=0.99

MOVING_AVERAGE_DECAY=0.99

3.下载DIFAR-10数据的默认路径

也就是我之前在cifar_input里面需要的二进制bin文件所在的文件夹
因为在cifar_input.py里面有这么一步

filenames = [os.path.join(data_dir, ‘data_batch_%d.bin’ % i)
for i in xrange(1, 6)]

data_dir = 'cifar10_data/cifar-10-batches-bin'

4.定义生成权重矩阵的函数

1.解释weight_loss = tf.multiply(tf.nn.l2_loss(var), w1, name=‘weight_loss’)
tf.nn.l2_loss(x)利用L2范数来计算张量x的误差值
w1就是吴恩达课程的 入 具体为:
解读完毕cifar_input.py再看这个程序cifar_train.py
所以说tf.nn.l2_loss就是把权重矩阵的元素求平方和向加 w1则是控制前面的系数
tf.add_to_collection(‘losses’, weight_loss)则是把上面的正则项加入名字叫losses的列表里面,注意这里是一个列表
返回一个权重矩阵

# L1正则会制造稀疏的特征,大部分无用特征的权重会被置0
# L2正则会让特征不过大,使得特征的权重比较均匀

# 使用正太分布初始化权重并添加L2正则化,使用w1控制L2损失的大小
def variable_with_weight_loss(shape, stddev, w1):
    # 从截断的(2个标准差以内)正态分布中输出随机值
    var = tf.Variable(tf.truncated_normal(shape, stddev=stddev))
    if w1 is not None:
        # l2_loss(var)*w1
        weight_loss = tf.multiply(tf.nn.l2_loss(var), w1, name='weight_loss')
        # 使用默认图
        tf.add_to_collection('losses', weight_loss)
    return var

5.构造数据

with tf.device(’/cpu:0’)是使用了gpu进行运算下面缩进的节点
我觉得 如果你想在gpu运行所有的节点 还是需要把所有都缩进进去
记住以后都得这样!!!!!
2.
这里补充一下为什么要用placeholder

为什么要用placeholder?

Tensorflow的设计理念称之为计算流图,在编写程序时,首先构筑整个系统的graph,代码并不会直接生效,这一点和python的其他数值计算库(如Numpy等)不同,graph为静态的,类似于docker中的镜像。然后,在实际的运行时,启动一个session,程序才会真正的运行。这样做的好处就是:避免反复地切换底层程序实际运行的上下文,tensorflow帮你优化整个系统的代码。我们知道,很多python程序的底层为C语言或者其他语言,执行一行脚本,就要切换一次,是有成本的,tensorflow通过计算流图的方式,帮你优化整个session需要执行的代码,还是很有优势的。
所以placeholder()函数是在神经网络构建graph的时候在模型中的占位,此时并没有把要输入的数据传入模型,它只会分配必要的内存。等建立session,在会话中,运行模型的时候通过feed_dict()函数向占位符喂入数据。

# 从Alex的网站下载并解压到默认位置
#cifar10.maybe_download_and_extract()
# 使用Reader操作构造CIFAR训练需要的数据(特征及其对应的label)
# 并对数据进行了数据增强(水平翻转/随机对比度亮度/随机裁剪)以及数据的标准化
with tf.device('/cpu:0'):
    images_train, labels_train = cifar10_input.distorted_inputs(data_dir=data_dir,batch_size=batch_size)
# 使用Reader操作构建CIFAR评估的输入(裁剪图像中间24*24大小的块并进行数据标准化)
    images_test, labels_test =cifar10_input.inputs(eval_data=True, data_dir=data_dir, batch_size=batch_size)

# 输入图像占位符(24*24 3通道)
image_holder = tf.placeholder(tf.float32, [batch_size, 24, 24, 3])
# 输入标签占位符
label_holder = tf.placeholder(tf.int32, [batch_size])

6.定义卷积层和池化层

1.下面叙述一下向量化维度大小的变化
下面用bs表示batch_size
输入图片bs2424*3
先不考虑bs
weight1 = variable_with_weight_loss(shape=[5, 5, 3, 64], stddev=10e-4, w1=0.0)
表示生成5 * 5 * 3的卷积核,64个卷积核
kernel1 = tf.nn.conv2d(image_holder, weight1, [1, 1, 1, 1], padding=‘SAME’)
表示生成卷积层,进行卷积,24 * 24 * 3卷积5 53卷积 由于是padding=same,故大小不变,深度要变成卷积核的个数64 结果是24 *24 * 64
bias1 = tf.Variable(tf.constant(0.0, shape=[64]))
生成偏差64的一行数组
conv1 = tf.nn.relu(tf.nn.bias_add(kernel1, bias1))
将偏差加入卷积结果 结果是24 *24 * 64 不变
pool1 = tf.nn.max_pool(conv1, ksize=[1, 3, 3, 1], strides=[1, 2, 2, 1], padding=‘SAME’)
对conv1进行最大池化, 用same故进行补全,运用公式(n-f)/s+1 =(24-3)/2+1不整除所以补全为(25-3)/2+1=12 结果是12 *12 * 64
norm1 = tf.nn.lrn(pool1, 4, bias=1.0, alpha=0.001/9.0, beta=0.75)#按照网上说法好像没用
具体功能之后再解释 现在这个先认为不影响向量维度

12 12 64

weight2 = variable_with_weight_loss(shape=[5, 5, 64, 64], stddev=10e-2, w1=0.0)
表示生成5 * 5 * 64的卷积核,64个卷积核
kernel2 = tf.nn.conv2d(norm1, weight2, [1, 1, 1, 1], padding=‘SAME’)
表示生成卷积层,进行卷积,12 * 12 * 64卷积5 564卷积(必须保证卷积通道数也就是最后一个维度必须一样) 由于是padding=same,故大小不变 结果是12 *12 * 64
bias2 = tf.Variable(tf.constant(0.1, shape=[64]))
生成偏差
conv2 = tf.nn.relu(tf.nn.bias_add(kernel2, bias2))
加一个偏差 不影响 结果是12 *12 * 64
norm2 = tf.nn.lrn(conv2, 4, bias=1.0, alpha=0.001/0.9, beta=0.75)
暂时不用
pool2 = tf.nn.max_pool(norm2, ksize=[1, 3, 3, 1], strides=[1, 2, 2, 1], padding=‘SAME’)
对conv1进行最大池化, 用same,(12-3)/2+1填充 (13-3) /2+1=6 最后变成 6 * 6 * 64

6 6 64

最后这个第三层被我改了一下 忘记最开始源代码是什么了 不过没关系
就不一一写了 经过第三步变成
3 * 3 * 128

有个疑问就是 到底是先本地响应标准化还是先池化
这里补充一下本地响应标准化
大概就是提高泛化 减小过拟合 提高识别率1%-2%的一种trick
https://blog.****.net/hduxiejun/article/details/70570086仅了解

# 卷积层1
# 32个5*5的卷积核3通道,不对第一个卷积层的权重加L2正则
weight1 = variable_with_weight_loss(shape=[5, 5, 3, 64], stddev=10e-4, w1=0.0)
# 卷积步长为1模式为SAME
kernel1 = tf.nn.conv2d(image_holder, weight1, [1, 1, 1, 1], padding='SAME')
# bias为0
bias1 = tf.Variable(tf.constant(0.0, shape=[64]))
# Adds bias to value
conv1 = tf.nn.relu(tf.nn.bias_add(kernel1, bias1))
# 最大池化 大小3*3步长2*2
pool1 = tf.nn.max_pool(conv1, ksize=[1, 3, 3, 1], strides=[1, 2, 2, 1], padding='SAME')
# 使用LRN对结果进行处理-Local Response Normalization-本地响应标准化
# 增强大的抑制小的,增强泛化能力
norm1 = tf.nn.lrn(pool1, 4, bias=1.0, alpha=0.001/9.0, beta=0.75)#按照网上说法好像没用

# 卷积层2
# 32个5*5的卷积核64通道,不加L2正则
weight2 = variable_with_weight_loss(shape=[5, 5, 64, 64], stddev=10e-2, w1=0.0)
# 卷积步长为1模式为SAME
kernel2 = tf.nn.conv2d(norm1, weight2, [1, 1, 1, 1], padding='SAME')
# bias为0.1
bias2 = tf.Variable(tf.constant(0.1, shape=[64]))
# Adds bias to value
conv2 = tf.nn.relu(tf.nn.bias_add(kernel2, bias2))
# LRN-本地响应标准化
norm2 = tf.nn.lrn(conv2, 4, bias=1.0, alpha=0.001/0.9, beta=0.75)
# 最大池化 大小3*3步长2*2
pool2 = tf.nn.max_pool(norm2, ksize=[1, 3, 3, 1], strides=[1, 2, 2, 1], padding='SAME')


# 卷积层3
# 64个5*5的卷积核64通道,不加L2正则
weight3 = variable_with_weight_loss(shape=[5, 5, 64, 128], stddev=10e-2, w1=0.0)
# 卷积步长为1模式为SAME
kernel3 = tf.nn.conv2d(pool2, weight3, [1, 1, 1, 1], padding='SAME')
# bias为0.1
bias3 = tf.Variable(tf.constant(0.1, shape=[128]))
# Adds bias to value
conv3 = tf.nn.relu(tf.nn.bias_add(kernel3, bias3))
# LRN-本地响应标准化
norm3 = tf.nn.lrn(conv3, 4, bias=1.0, alpha=0.001/0.9, beta=0.75)
# 最大池化 大小3*3步长2*2
pool3 = tf.nn.max_pool(norm2, ksize=[1, 3, 3, 1], strides=[1, 2, 2, 1], padding='SAME')

7.定义全连接层

全连接第一层
1.
拉长向量
reshape = tf.reshape(pool3, [batch_size, -1])
上面做完所有卷积的结果是:
[[三维][三维][三维][三维][三维][三维][三维][三维]…一共batchsize个,所以是四维]也就是
[bs,3,3,128]这个形状
所以拉长向量拉成[batch_size, -1],-1表示自动计算,那么就是把3,3,128拉成一个行向列
[bs,1152]
2.
dim = reshape.get_shape()[1].value
找了很多地方没有专门的解释 其实是:
使用get_shape()[-1].value获取tensor的最后一维的长度,get_shape()[0].value获取tensor第一维的长度。
那么这里获得的就是你拉长的长度 也就是dim=3×3×128=1152
3.
weight3 = variable_with_weight_loss(shape=[dim, 384], stddev=0.04, w1=0.004)
使用了正则化 制造了384个节点 shape=[dim, 384]=[1152,384]
bias3 = tf.Variable(tf.constant(0.1, shape=[384]))
一个行向量384个数
local3 = tf.nn.relu(tf.matmul(reshape, weight3) + bias3)
所以[bs,1152]*[1152,384]=[bs,384] 这里不考虑bs 那么就是[384] 所以才能和bias相加

这里涉及到一个问题就是 , 什么时候考虑batchsize 什么时候不考虑 也就是说这个维度 什么时候加 什么时候不加:

考虑的:
1.图像占位符placeholder里面
2.把最后一步pool的结果reshape拉长成一行一行的形式的时候,但在全连接层里面就不考虑了

全连接第二层
weight4 = variable_with_weight_loss(shape=[384, 192], stddev=0.04, w1=0.004)
使用正则化 192个节点
bias4 = tf.Variable(tf.constant(0.1, shape=[192]))
local4 = tf.nn.relu(tf.matmul(local3, weight4) + bias4)
1 * 384和384 * 192得到了1 * 192 所以才能和bias相加

全连接第三层也就是输出层:
weight5 = variable_with_weight_loss(shape=[192, 10], stddev=1/192.0, w1=0.0)
bias5 = tf.Variable(tf.constant(0.0, shape=[10]))
logits = tf.add(tf.matmul(local4, weight5), bias5)

值得注意的是 输出层权重的标准差设为上一层隐含节点的导数(算是个trick)
最后输出十个类别 shape=10 说过在层里不考虑batchsize
所以logits是最后全链接层输出的初步结果

# 全连接层
# 将样本变成一维向量
reshape = tf.reshape(pool3, [batch_size, -1])
# 数据扁平化后的长度
dim = reshape.get_shape()[1].value
# weight初始化
weight3 = variable_with_weight_loss(shape=[dim, 384], stddev=0.04, w1=0.004)
# bias初始化
bias3 = tf.Variable(tf.constant(0.1, shape=[384]))
local3 = tf.nn.relu(tf.matmul(reshape, weight3) + bias3)

# 隐含节点数降为192
weight4 = variable_with_weight_loss(shape=[384, 192], stddev=0.04, w1=0.004)
bias4 = tf.Variable(tf.constant(0.1, shape=[192]))
local4 = tf.nn.relu(tf.matmul(local3, weight4) + bias4)

# 最终输出10分类,正太分布标准差设为上一隐含层节点数的倒数,不计入L2正则
weight5 = variable_with_weight_loss(shape=[192, 10], stddev=1/192.0, w1=0.0)
bias5 = tf.Variable(tf.constant(0.0, shape=[10]))
logits = tf.add(tf.matmul(local4, weight5), bias5)

8.定义求损失函数

1
global_step=tf.Variable(0,trainable=False)#初始化钟表0,使其为不可被训练更新
这是为了学习率衰减用的 如果没有可以不加
关于各种学习率衰减的trick点这里
2
#计算CNN的loss
定义的是计算loss的函数
cross_entropy = tf.nn.sparse_softmax_cross_entropy_with_logits(
logits=logits, labels=labels, name=‘cross_entropy_per_example’)
其中logits是个 128 * 10 ,labels如果看以后的输入的话是lableholder 是个 128 的行向量
这里的维度虽然不一样 但是用的是sparse softmax 是可以算交叉熵的 具体说明如下
解读完毕cifar_input.py再看这个程序cifar_train.py
之后的cross_entropy_mean = tf.reduce_mean(cross_entropy, name=‘cross_entropy’)是因为:
是因为batch里面每一个数代表一个交叉熵,求平均值把交叉熵平均起来,就是一个batch的平均loss

tf.add_to_collection(‘losses’, cross_entropy_mean)
之前经过定义一系列weight把每一个权重的正则损失项都放在了losses列表里面,这时再把这个batch的平均损失加入losses列表
4.
return tf.add_n(tf.get_collection(‘losses’), name=‘total_loss’)

tf.add_to_collection():把张量发到一起,并用同一个命名空间命名多个张量,将多个张量组合成一个list,没有返回值。
tf.get_collection(name) :将之前通过tf.add_to_collection()语句添加的张量集合,通过name参数提取出来,返回一个list。

意思是tf.add_to_collection()的作用是收集从而形成一个列表,而tf.get_collection是返回出来一个列表。这是两个不同的动作,一个动作是采集,一个动作是收获。
tf.add_n:把一个列表的东西都依次加起来

至此 已经定义了一个函数叫做loss 用来求一个batch的损失,返回一个batch的损失值

global_step=tf.Variable(0,trainable=False)#初始化钟表0,使其为不可被训练更新

# 计算CNN的loss
def loss(logits, labels):
    labels = tf.cast(labels, tf.int64)

    # 计算logits和labels之间的稀疏softmax交叉熵
    cross_entropy = tf.nn.sparse_softmax_cross_entropy_with_logits(
        logits=logits, labels=labels, name='cross_entropy_per_example')
    # 计算cross_entropy均值
    cross_entropy_mean = tf.reduce_mean(cross_entropy, name='cross_entropy')
    # 将cross_entropy的loss添加到整体的loss里
    tf.add_to_collection('losses', cross_entropy_mean)
    # 将整体losses的collection中的全部loss求和
    return tf.add_n(tf.get_collection('losses'), name='total_loss')
    #加入滑动平均

9.定义训练 保证参数刷新 求准确率

loss = loss(logits, label_holder)
刚定义的loss函数,输入的logits则是全连接层的输出,lable_holder是之前的占位符
2.
train_op = tf.train.AdamOptimizer(learning_rate).minimize(loss,global_step=global_step)
定义训练步骤 这里由于我加入了学习率衰减所以写了learning_rate,否则写一个0.001之类的数
由于我加入了学习率衰减所以global_step=global_step是为了刷新训练钟表
3.

求top k的准确率(默认top1即输出分数最高的一类)

top_k_op = tf.nn.in_top_k(logits, label_holder, 1)
这个是重要的!!!:用法点这个
https://blog.****.net/uestc_c2_403/article/details/73187915
值得注意的是 我现在的logits形式是 首先是有batch占一个维度的
[[0.2,0.3,0.4,0.5,0.6,0.7,0.8,0.9,0.6,0.5],
[0.5,0.7,0.4,0.8,0.1,0.5,0.8,0.6,0.5,0.1],


…]一共batch_size个]
而label是[5,0,6,7,8,4,9,1,0,7…batch_size个]
如果logits中的某一行d

# variable_averages = tf.train.ExponentialMovingAverage(
#         MOVING_AVERAGE_DECAY, global_step)
# variable_averages_op = variable_averages.apply(
#         tf.trainable_variables())  # 可更新的变量全部更新
# 将logits节点label_holder和传入loss函数获得最终的loss
loss = loss(logits, label_holder)
#加入学习率衰减
learning_rate=tf.train.exponential_decay(
        LEARNING_RATE_BASE,
        global_step,
        390,
        LEARNING_RATE_DECAY)

# 优化器选择Adam,学习率选1e-3
train_op = tf.train.AdamOptimizer(learning_rate).minimize(loss,global_step=global_step)
# with tf.control_dependencies([train_op, variable_averages_op]):
#     train_op = tf.no_op(name='loss')  # 保证train之前参数被刷新

# 求top k的准确率(默认top1即输出分数最高的一类)
top_k_op = tf.nn.in_top_k(logits, label_holder, 1)