【Tensorflow】深度学习实战02——Tensorflow实现进阶的卷积网络(CIFAR-10) £神魔★判官ぃ 2022-05-26 10:13 176阅读 0赞 ## ## ## 【[fishing-pan][]:[https://blog.csdn.net/u013921430][https_blog.csdn.net_u013921430]转载请注明出处】 ## ## 前言 ## 之前使用Tensorflow实现了一个简单卷积神经网络用于手写数字识别,那是一个简单的卷积网络,今天按照书上的代码实现了使用卷积神经网络对CIFAR-10数据集的数据进行分类,这篇标题也就依照书上来取了。 ## 工程环境 ## **Win7+Tensorflow1.7.0+Python3.6** ## CIFAR-10数据集 ## CIFAR-10数据集包含60000张32\*32的彩色图像,(注意,彩色图像三通道的(RGB),主要是提醒非图像处理背景的同学,嘻嘻)。CIFAR-10一共有10类图片,每一类图片有6000张,有飞机,鸟,猫,狗等,而且其中没有任何重叠的情况(现实社会中肯定不止那么多类啦)。现在还有一个兄弟版本,CIFAR-100,里面有100类。 ## 本网络中用到的主要方法 ## ### 数据增广 ### 数据增广(Data Augmentation),主要用于数据集数量比较小的情况下。通过旋转、剪切、拉伸等一些操作将在保证图像基本特征不会改变的情况下,可以成倍数的增加样本数据量。 ### LRN ### local response normalization(局部响应归一化),局部响应归一化原理是仿造生物学上活跃的神经元对相邻神经元的抑制现象(侧抑制)。对局部神经元的活动创建竞争环境,使得其中响应比较大的值变得更大,抑制其他反馈较小的神经元,增强模型的泛化能力。原理公式如下; ![2018042913511074][] 可以将其简单理解成以空间中某一点的像素为中心,一点半径内所有点的像素值平方求和,然后用这一点的像素值除以和值,这样图像中像素值大的点的值相对于像素值小的点计算的值更大了。 LRN适合ReLU这种没有上限边界的激活函数,因为它会从附近多个卷积核的响应中挑选较大的反馈,但是不适合用于Sigmoid这种有固定边界且抑制了过大值的激活函数。 ### L2 正则化 ### L2 正则化就是在损失函数后添加一个正则项,这个正则项可以看做是损失函数的惩罚项。加入L2 正则项在进行训练迭代时,权重会下降的更快,最终权重值会比较小,模型更加稳定。在拟合过程中通常都倾向于让权值尽可能小,最后构造一个所有参数都比较小的模型。这样的模型能适应不同的数据集,在一定程度上避免了过拟合现象。 ![2018042916284778][] ## 构建卷积网络 ## ### 准备库文件 ### 在书上的介绍当中,需要首先下载Tensorflow Models的库,以便使用其中提供的CIFAR-10的库;语句如下; git clone https://github.com/tensorflow/models.git cd models/tutorials/image/cifar10 这段语句我在网上看到很多人在问这两行语句在Python中报错显示语法错误。原因很简单,这两行语句压根就不是Python的命令。这两行语句需要在Git软件中运行,软件[下载地址][Link 1]在这里,安装软件后运行指令下载Tensorflow Models。 这两行命令是用于下载库的,大小大概为930M,其实在后面的我们需要的库只有两个cifar10.py, cifar10\_input.py 打开这两个库会发现,他依赖的其他库都是tensorflow或者Python自带的库,也就是说我们下载了许多库文件,在这个项目中需要用到的就这两个。所以,我们完全不需要大费周章。 根据指令,打开github中Tensorflow Models内CIFAR-10的链接。 [https://github.com/tensorflow/models/tree/master/tutorials/image/cifar10][https_github.com_tensorflow_models_tree_master_tutorials_image_cifar10] 然后下载cifar10.py,cifar10\_input.py两个库文件,或者直接把其中内容复制到两个.py 文件,并且分别命名为cifar10.py, cifar10\_input.py。这样就搞定了。 如果你使用的编译器是Pcharm,那么你只需在两个库文件的共同的目录下创建新的文件并运行代码即可。若你的编译器是Spyder(tensorflow),那么你需要把你这两个库放置到这样一个路径下 **你的安装目录\\Python3.6\\envs\\tensorflow\\Lib\\site-packages** 如果你觉得不安全,也可以在这个目录下创建文件夹,将两个库文件放置到文件夹内,只是这样的话,你需要在插入库的时候加上文件夹的路径。 ### 构建网络 ### 经过上面的准备工作可以开始构建网络了,首先是载入需要使用的库; import cifar10,cifar10_input import tensorflow as tf import numpy as np import time 接着定义batch\_size、训练轮数max\_steps,以及下载CIFAR-10数据的默认路径。 #设置每次输入的batch_size(一次输入的图像数目),max_steps(训练轮数) batch_size=128 max_steps=3000 #下载cifar10数据存放的路径 data_dir='/tmp/cifar10_data/cifar-10-batches-bin' 定义权重函数,这里使用tf.truncated\_normal (截断的正态分布)初始化权重,然后对每个权重做L2正则化(防止过拟合),正则化项前的系数为wl。并且将所有的权重对应的正则化loss 项添加到名为‘lossses’的一个列表中。 ###定义权重的函数### #使用截断的正态分布初始化权重变量 #如果wl不为0,则对对于权重添加一个L2范数的正则化,且命名为'weight_loss', #然后将这个正则化部分添加到名为'losses'的collection中,方便后续调用; def variable_with_weight_loss(shape,stddev,wl): var=tf.Variable(tf.truncated_normal(shape,stddev=stddev)) if wl is not None: weight_loss=tf.multiply(tf.nn.l2_loss(var),wl,name='weight_loss') tf.add_to_collection('losses',weight_loss) return var 使用cifar-10类下载数据集,并且解压、展开到默认位置;再使用cifar10\_input类中的distorted\_input函数产生训练及测试需要使用的数据,函数返回的是封装好的tensor,每次执行都会生成一个batch\_size的数量的样本, ###下载数据### #这一行代码是用来下载和展开数据到data_dir所指的位置 cifar10.maybe_download_and_extract() #使用cifar10_input.py中的distorted_input函数产生训练需要使用的数据,返回的是已经封装好的tensor,每次执行都会生成一个batch_size的数量的样本。 images_train,labels_train=cifar10_input.distorted_inputs(data_dir=data_dir,batch_size=batch_size) #同上,使用cifar10_input.py中的input函数产生测试需要使用的数据,返回的是已经封装好的tensor; images_test,labels_test=cifar10_input.inputs(eval_data=True,data_dir=data_dir,batch_size=batch_size) 以下是cifar10\_input类中的distorted\_input函数的定义,其中IMAGE\_SIZE为24;在函数中对数据进行了Data Augmentation,包括随机水平旋转(tf.image.random\_flip\_left\_right),随机剪切(tf.random\_crop),设置随机的亮度与对比度(tf.image.random\_brightness、tf.image.random\_contrast),以及对数据进行标准化操作(tf.image.per\_image\_standardization,减去均值,除以方差)。由于数据增广操作需要耗费大量的CPU时间,distorted\_input函数使用了16个独立的线层进行任务加速,函数内部会产生线程池,在需要使用时会通过Tensorflow queue进行调度。 def distorted_inputs(data_dir, batch_size): """Construct distorted input for CIFAR training using the Reader ops. Args: data_dir: Path to the CIFAR-10 data directory. batch_size: Number of images per batch. Returns: images: Images. 4D tensor of [batch_size, IMAGE_SIZE, IMAGE_SIZE, 3] size. labels: Labels. 1D tensor of [batch_size] size. """ filenames = [os.path.join(data_dir, 'data_batch_%d.bin' % i) for i in xrange(1, 6)] for f in filenames: if not tf.gfile.Exists(f): raise ValueError('Failed to find file: ' + f) # Create a queue that produces the filenames to read. filename_queue = tf.train.string_input_producer(filenames) with tf.name_scope('data_augmentation'): # Read examples from files in the filename queue. read_input = read_cifar10(filename_queue) reshaped_image = tf.cast(read_input.uint8image, tf.float32) height = IMAGE_SIZE width = IMAGE_SIZE # Image processing for training the network. Note the many random # distortions applied to the image. # Randomly crop a [height, width] section of the image. distorted_image = tf.random_crop(reshaped_image, [height, width, 3]) # Randomly flip the image horizontally. distorted_image = tf.image.random_flip_left_right(distorted_image) # Because these operations are not commutative, consider randomizing # the order their operation. # NOTE: since per_image_standardization zeros the mean and makes # the stddev unit, this likely has no effect see tensorflow#1458. distorted_image = tf.image.random_brightness(distorted_image, max_delta=63) distorted_image = tf.image.random_contrast(distorted_image, lower=0.2, upper=1.8) # Subtract off the mean and divide by the variance of the pixels. float_image = tf.image.per_image_standardization(distorted_image) # Set the shapes of tensors. float_image.set_shape([height, width, 3]) read_input.label.set_shape([1]) # Ensure that the random shuffling has good mixing properties. min_fraction_of_examples_in_queue = 0.4 min_queue_examples = int(NUM_EXAMPLES_PER_EPOCH_FOR_TRAIN * min_fraction_of_examples_in_queue) print ('Filling queue with %d CIFAR images before starting to train. ' 'This will take a few minutes.' % min_queue_examples) # Generate a batch of images and labels by building up a queue of examples. return _generate_image_and_label_batch(float_image, read_input.label, min_queue_examples, batch_size, shuffle=True) 创建输入数据的placeholder,包括特征和label。 #创建输入图像和标签所需要的占位符(placeholder),batch_size是一次输入的图像数目,24*24是裁剪后的图像大小,3是图像的通道数(输入为彩色图) image_holder=tf.placeholder(tf.float32,[batch_size,24,24,3]) label_holder=tf.placeholder(tf.int32,[batch_size]) 创建第一个卷积层。使用variable\_with\_weight\_loss 函数创建卷积核的权重,第一个卷积层使用5x5大小的卷积核,有3个通道,一共有64个核,权重初始化时的标准差为0.05。第一个卷积层不进行L2 正则化,因此wl一项参数为0。然后使用tf.nn.conv2d 将输入数据与权重进行卷积,这里步长设为1,padding 模式为SAME。偏差bias 初始化为0,,最后使用ReLU作为激活函数进行非线性化。之后使用一个尺寸为3x3,步长为2x2的最大值池化,然后使用tf.nn.lrn 进行LRN处理。 ###创建第一个卷积层####这一层有64个节点 #调用variable_with_weight_loss函数创建第一个卷积核,大小为5*5,通道数为3,标准差为0.05,不设置权重损失; weight1=variable_with_weight_loss(shape=[5,5,3,64],stddev=5e-2,wl=0.0) #调用tf的卷积函数进行卷积操作,步长为1,边界等同 kernel1=tf.nn.conv2d(image_holder,weight1,[1,1,1,1],padding='SAME') #将bias全部初始化为0 bias1=tf.Variable(tf.constant(0.0,shape=[64])) #使用relu为激活函数 conv1=tf.nn.relu(tf.nn.bias_add(kernel1,bias1)) #对激活函数处理后的结果做一个最大值池化 pool1=tf.nn.max_pool(conv1,ksize=[1,3,3,1],strides=[1,2,2,1],padding='SAME') #对上面处理后的记过进行LRN处理。 #LRN全称是local response normalization(局部响应归一化),局部响应归一化原理是仿造生物学上活跃的神经元对相邻神经元的抑制现象(侧抑制)。 #对局部神经元的活动创建竞争环境,使得其中响应比较大的值变得更大,抑制其他反馈较小的神经元,增强模型的泛化能力。 #https://blog.csdn.net/sinat_21585785/article/details/75087768 norm1=tf.nn.lrn(pool1,4,bias=1.0,alpha=0.001/9.0,beta=0.75) 创建第二个卷积层。第二个卷积层有64个卷积核,bias全部初始化为0.1。与第一个卷积层不同的是,第二个卷积层先LRN处理再做最大值池化。 ###创建第二个卷积层###这一层有64个节点 weight2=variable_with_weight_loss(shape=[5,5,64,64],stddev=5e-2,wl=0.0) kernel2=tf.nn.conv2d(norm1,weight2,[1,1,1,1],padding='SAME') bias2=tf.Variable(tf.constant(0.1,shape=[64])) conv2=tf.nn.relu(tf.nn.bias_add(kernel2,bias2)) ###先进行LRN处理再做最大值池化 norm2=tf.nn.lrn(conv2,4,bias=1.0,alpha=0.001/9.0,beta=0.75) pool2=tf.nn.max_pool(norm2,ksize=[1,3,3,1],strides=[1,2,2,1],padding='SAME') 创建第一个全连接层。现将第二个卷积层的输出的每个样本都展开成一维向量。接着使用variable\_with\_weight\_loss 函数初始化全连接层的卷积核的权重,有384个节点,正态分布的标准差为0.04,偏差初始值为0.1;为了防止过拟合,给权重添加一个wl为0.04的L2 正则项约束。 ###创建全连接层### 这一层有384个节点 #首先将图像展开,这里的维度第一个是多少张图,第二个是根据图像大小确定的;然后使用get_shape()获取第二个维度,也就是图像大小 reshape=tf.reshape(pool2,[batch_size,-1]) dim=reshape.get_shape()[1].value ###第一个全连接层,有384个节点### weight3=variable_with_weight_loss(shape=[dim,384],stddev=0.04,wl=0.004) 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,wl=0.004) bias4=tf.Variable(tf.constant(0.1,shape=[192])) local4=tf.nn.relu(tf.matmul(local3,weight4)+bias4) ###第三个全连接层,有10个节点 weight5=variable_with_weight_loss(shape=[192,10],stddev=1/192.0,wl=0.0) bias5=tf.Variable(tf.constant(0.0,shape=[10])) 定义损失函数。在这一步中,使用的是tf.nn.sparse\_softmax\_cross\_entropy\_with\_logits 函数,这个函数将softmax的计算和 cross entropy loss 的计算合并了;然后使用tf.reduce\_mean 函数求均值,接着将平均后的损失函数也添加进入‘losses’列表,之后对列表求和,最终的结果就是添加了L2 loss的损失函数。 ###定义损失函数,将L2也加入其中### def loss(logits,labels): labels = tf.cast(labels, tf.int64) #使用softmax分类器,然后结合交叉熵作为损失函数 cross_entropy = tf.nn.sparse_softmax_cross_entropy_with_logits(logits = logits, labels = labels, name = 'cross_entropy_per_example') cross_entropy_mean = tf.reduce_mean(cross_entropy, name = 'cross_entropy') #将平均后的损失函数也添加进入‘losses’ tf.add_to_collection('losses', cross_entropy_mean) #tf.get_collection('losses'),将之前添加到列表losses中的内容输出成一个数组 #使用tf.add_n,将列表losses中的所有项求和; return tf.add_n(tf.get_collection('losses'), name = 'total_loss') 将logits 节点和label\_holder 传入loss 函数获得loss;优化损失函数时,优化器选择Adam Optimizer,学习率为0.001; ###调用loss求得正则化的损失函数 loss = loss(logits, label_holder) #使用Adam Optimizer优化模型,学习率为0.001; train_op = tf.train.AdamOptimizer(1e-3).minimize(loss) 计算准确率。使用tf.nn.in\_top\_k 函数比较logits的输出与label。 ##tf.nn.in_top_k()该函数首先将logits的输出排序,然后根据第三个参数选取排序的前N个,这里是1,就是选取第一个与label_holder进行对比; ##比如logits最大的是第五个,而label_holder也是5;那么输出为True; top_k_op = tf.nn.in_top_k(logits, label_holder, 1) 创建会话,初始化网络中全部的参数,并且启动图片数据增广的线程队列。 #创建会话 sess=tf.InteractiveSession() #初始化所有变量 tf.global_variables_initializer().run() ##启动线程 tf.train.start_queue_runners() 开始训练网络,每一个step 中都要获取一次images\_train和labels\_train,然后使用feed\_dict 将获得的数据传入到占位符中,再运行获得train\_op 和loss。这里没十次计算输出一次当前的loss、每秒钟训练的样本数量以及训练一个batch数据花的时间。 #开始训练,每个step中使用session的run方法执行images_train和labels_train的计算,获得一个batch的训练数据,再将数据传入train_op和loss计算; #每十个step计算并且输出当前的loss、每秒能训练的样本量,以及训练一个batch所花时间。 for step in range(max_steps): start_time = time.time() 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}) duration = time.time() - start_time if step % 10 == 0: examples_per_sec = batch_size / duration sec_per_batch = float(duration) format_str = ('step %d, loss = %.2f(%.1f examples/sec; %.3f sec/batch)') print(format_str % (step, loss_value, examples_per_sec, sec_per_batch)) 接下来在测试集上测试模型的准确率,测试集一共10000个样本,每次选择batch\_size 个样本,并且汇总对每个batch 分类的准确性,最后求平均值输出。 ##用含有10000张图片的测试集测试准确率,并且打印出来。 num_examples = 10000 import math num_iter = int(math.ceil(num_examples / batch_size)) true_count = 0 total_sample_count = num_iter * batch_size step = 0 while step < num_iter: 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 precision = true_count / total_sample_count print('precision @ 1 = %.3f' % precision) ### 网络结构表 ### <table> <tbody> <tr> <td> <p><strong><span style="color:#4f4f4f;">Layer </span><span style="color:#4f4f4f;">名称</span></strong></p> </td> <td> <p><strong><span style="color:#4f4f4f;">描</span><span style="color:#4f4f4f;"> </span><span style="color:#4f4f4f;">述</span></strong></p> </td> </tr> <tr> <td> <p><span style="color:#4f4f4f;">conv1</span></p> </td> <td> <p><span style="color:#4f4f4f;">卷积层和</span><span style="color:#4f4f4f;">ReLU</span><span style="color:#4f4f4f;">激活</span></p> </td> </tr> <tr> <td> <p><span style="color:#4f4f4f;">pool1</span></p> </td> <td> <p><span style="color:#4f4f4f;">最大值池化</span></p> </td> </tr> <tr> <td> <p><span style="color:#4f4f4f;">norm1</span></p> </td> <td> <p><span style="color:#4f4f4f;">LRN</span></p> </td> </tr> <tr> <td> <p><span style="color:#4f4f4f;">conv2</span></p> </td> <td> <p><span style="color:#4f4f4f;">卷积层和</span><span style="color:#4f4f4f;">ReLU</span><span style="color:#4f4f4f;">激活</span></p> </td> </tr> <tr> <td> <p><span style="color:#4f4f4f;">norm2</span></p> </td> <td> <p><span style="color:#4f4f4f;">LRN</span></p> </td> </tr> <tr> <td> <p><span style="color:#4f4f4f;">pool2</span></p> </td> <td> <p><span style="color:#4f4f4f;">最大值池化</span></p> </td> </tr> <tr> <td> <p><span style="color:#4f4f4f;">local3</span></p> </td> <td> <p><span style="color:#4f4f4f;">全连接层和</span><span style="color:#4f4f4f;">ReLU</span><span style="color:#4f4f4f;">激活函数</span></p> </td> </tr> <tr> <td> <p><span style="color:#4f4f4f;">local4</span></p> </td> <td> <p><span style="color:#4f4f4f;">全连接层和</span><span style="color:#4f4f4f;">ReLU</span><span style="color:#4f4f4f;">激活函数</span></p> </td> </tr> <tr> <td> <p><span style="color:#4f4f4f;">logits</span></p> </td> <td> <p><span style="color:#4f4f4f;">全连接层且输出模型结果</span></p> </td> </tr> </tbody> </table> ## 代码 ## 为了方便大家使用,在这里提供所有的代码 # -*- coding: utf-8 -*- """ Created on Fri Apr 27 09:14:52 2018 @author: most_pan """ import cifar10,cifar10_input import tensorflow as tf import numpy as np import time #设置每次输入的batch_size(一次输入的图像数目),max_steps(训练轮数) batch_size=128 max_steps=3000 #下载cifar10数据存放的路径 data_dir='/tmp/cifar10_data/cifar-10-batches-bin' ###定义权重的函数### #使用截断的正态分布初始化权重变量 #如果wl不为0,则对对于权重添加一个L2范数的正则化,且命名为'weight_loss', #然后将这个正则化部分添加到名为'losses'的collection中,方便后续调用; def variable_with_weight_loss(shape,stddev,wl): var=tf.Variable(tf.truncated_normal(shape,stddev=stddev)) if wl is not None: weight_loss=tf.multiply(tf.nn.l2_loss(var),wl,name='weight_loss') tf.add_to_collection('losses',weight_loss) return var ###下载数据### #这一行代码是用来下载和展开数据到data_dir所指的位置 cifar10.maybe_download_and_extract() #使用cifar10_input.py中的distorted_input函数产生训练需要使用的数据,返回的是已经封装好的tensor,每次执行都会生成一个batch_size的数量的样本。 images_train,labels_train=cifar10_input.distorted_inputs(data_dir=data_dir,batch_size=batch_size) #同上,使用cifar10_input.py中的input函数产生测试需要使用的数据,返回的是已经封装好的tensor; images_test,labels_test=cifar10_input.inputs(eval_data=True,data_dir=data_dir,batch_size=batch_size) #创建输入图像和标签所需要的占位符(placeholder),batch_size是一次输入的图像数目,24*24是裁剪后的图像大小,3是图像的通道数(输入为彩色图) image_holder=tf.placeholder(tf.float32,[batch_size,24,24,3]) label_holder=tf.placeholder(tf.int32,[batch_size]) ###创建第一个卷积层####这一层有64个节点 #调用variable_with_weight_loss函数创建第一个卷积核,大小为5*5,通道数为3,标准差为0.05,不设置权重损失; weight1=variable_with_weight_loss(shape=[5,5,3,64],stddev=5e-2,wl=0.0) #调用tf的卷积函数进行卷积操作,步长为1,边界等同 kernel1=tf.nn.conv2d(image_holder,weight1,[1,1,1,1],padding='SAME') #将bias全部初始化为0 bias1=tf.Variable(tf.constant(0.0,shape=[64])) #使用relu为激活函数 conv1=tf.nn.relu(tf.nn.bias_add(kernel1,bias1)) #对激活函数处理后的结果做一个最大值池化 pool1=tf.nn.max_pool(conv1,ksize=[1,3,3,1],strides=[1,2,2,1],padding='SAME') #对上面处理后的记过进行LRN处理。 #LRN全称是local response normalization(局部响应归一化),局部响应归一化原理是仿造生物学上活跃的神经元对相邻神经元的抑制现象(侧抑制)。 #对局部神经元的活动创建竞争环境,使得其中响应比较大的值变得更大,抑制其他反馈较小的神经元,增强模型的泛化能力。 norm1=tf.nn.lrn(pool1,4,bias=1.0,alpha=0.001/9.0,beta=0.75) ###创建第二个卷积层###这一层有64个节点 weight2=variable_with_weight_loss(shape=[5,5,64,64],stddev=5e-2,wl=0.0) kernel2=tf.nn.conv2d(norm1,weight2,[1,1,1,1],padding='SAME') bias2=tf.Variable(tf.constant(0.1,shape=[64])) conv2=tf.nn.relu(tf.nn.bias_add(kernel2,bias2)) ###先进行LRN处理再做最大值池化 norm2=tf.nn.lrn(conv2,4,bias=1.0,alpha=0.001/9.0,beta=0.75) pool2=tf.nn.max_pool(norm2,ksize=[1,3,3,1],strides=[1,2,2,1],padding='SAME') ###创建全连接层### 这一层有384个节点 #首先将图像展开,这里的维度第一个是多少张图,第二个是根据图像大小确定的;然后使用get_shape()获取第二个维度,也就是图像大小 reshape=tf.reshape(pool2,[batch_size,-1]) dim=reshape.get_shape()[1].value ###第一个全连接层,有384个节点### weight3=variable_with_weight_loss(shape=[dim,384],stddev=0.04,wl=0.004) 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,wl=0.004) bias4=tf.Variable(tf.constant(0.1,shape=[192])) local4=tf.nn.relu(tf.matmul(local3,weight4)+bias4) ###第三个全连接层,有10个节点 weight5=variable_with_weight_loss(shape=[192,10],stddev=1/192.0,wl=0.0) bias5=tf.Variable(tf.constant(0.0,shape=[10])) logits=tf.add(tf.matmul(local4,weight5),bias5) ###定义损失函数,将L2也加入其中### def loss(logits,labels): labels = tf.cast(labels, tf.int64) #使用softmax分类器,然后结合交叉熵作为损失函数 cross_entropy = tf.nn.sparse_softmax_cross_entropy_with_logits(logits = logits, labels = labels, name = 'cross_entropy_per_example') cross_entropy_mean = tf.reduce_mean(cross_entropy, name = 'cross_entropy') #将平均后的损失函数也添加进入‘losses’ tf.add_to_collection('losses', cross_entropy_mean) #tf.get_collection('losses'),将之前添加到列表losses中的内容输出成一个数组 #使用tf.add_n,将列表losses中的所有项求和; return tf.add_n(tf.get_collection('losses'), name = 'total_loss') ###调用loss求得正则化的损失函数 loss = loss(logits, label_holder) #使用Adam Optimizer优化模型,学习率为0.001; train_op = tf.train.AdamOptimizer(1e-3).minimize(loss) ##tf.nn.in_top_k()该函数首先将logits的输出排序,然后根据第三个参数选取排序的前N个,这里是1,就是选取第一个与label_holder进行对比; ##比如logits最大的是第五个,而label_holder也是5;那么输出为True; top_k_op = tf.nn.in_top_k(logits, label_holder, 1) #创建会话 sess=tf.InteractiveSession() #初始化所有变量 tf.global_variables_initializer().run() ##启动线程 tf.train.start_queue_runners() #开始训练,每个step中使用session的run方法执行images_train和label的计算,获得一个batch的训练数据,再将数据传入train_op和loss计算; #每十个step计算并且输出当前的loss、每秒能训练的样本量,以及训练一个batch所花时间。 for step in range(max_steps): start_time = time.time() 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}) duration = time.time() - start_time if step % 10 == 0: examples_per_sec = batch_size / duration sec_per_batch = float(duration) format_str = ('step %d, loss = %.2f(%.1f examples/sec; %.3f sec/batch)') print(format_str % (step, loss_value, examples_per_sec, sec_per_batch)) ##用含有10000张图片的测试集测试准确率,并且打印出来。 num_examples = 10000 import math num_iter = int(math.ceil(num_examples / batch_size)) true_count = 0 total_sample_count = num_iter * batch_size step = 0 while step < num_iter: 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 precision = true_count / total_sample_count print('precision @ 1 = %.3f' % precision) ### 运行结果展示 ### 我的显卡比较水,所以训练的比较慢。 ![20180429153213768][] ## 参考书籍 ## 《Tensorflow 实战》黄文坚等著; [fishing-pan]: https://my.csdn.net/ [https_blog.csdn.net_u013921430]: https://blog.csdn.net/u013921430 [2018042913511074]: /images/20220526/47038179c35949d4bb9672693add060e.png [2018042916284778]: /images/20220526/01cbb72bbeec4be4960136ab42bbfeaa.png [Link 1]: https://git-scm.com/downloads [https_github.com_tensorflow_models_tree_master_tutorials_image_cifar10]: https://github.com/tensorflow/models/tree/master/tutorials/image/cifar10 [20180429153213768]: /images/20220526/b58feeb4b794468ab5b1c520501dc935.png
还没有评论,来说两句吧...