TensorFlow中cnn-cifar10样例代码详解

TensorFlow是一个支持分布式的深度学习框架,在Google的推动下,它正在变得越来越普及。我最近学了TensorFlow教程上的一个例子,即采用CNNcifar10数据集进行分类。在看源代码的时候,看完后有一种似懂非懂的感觉,又考虑到这个样例涵盖了tensorflow的大部分语法知识,包括QueueRunners机制、Tensorboard可视化和多GPU数据并行编程等。“纸上得来终觉浅,绝知此事要躬行”,于是我便照着自己的理解和记忆来重新编程实现一遍,实现过程中也遇到了一些问题,在这里把我对程序的详细的理解和遇到的问题记录下来,本着“知其然,知其所以然”的标准,程序中的注释更加侧重于对‘为什么这一行代码要这样写’的解读,以供以后参考(关于卷积神经网络相关的理论部分,网上有很多了,这里就不做太多介绍)

一个标准的机器学习程序,应该包括数据输入、定义模型本身、模型训练和模型性能测试四大部分,可以分成四个.py文件。

(一)数据输入部分(input_dataset.py

       从概念上来说,这部分主要是关于数据管道(data pipe)的构建,数据流向为“二进制文件->文件名队列->数据队列->读取出的data-batch”。数据块用于输入到深度学习网络中,进行信息的forward propagation,这部分在定义模型本身部分讨论。在定义整个数据管道的时候,会使用到TensorFlow的队列机制,这部分在之前的博文“TensorFlow读取二进制文件数据到队列”中进行了详细讲述。另外,读原数据文件的时候,要结合文件本身的格式,相信编写过c语言读取二进制文件的程序的朋友,对这应该再熟悉不过了,具体的代码如下,

[python]  view plain  copy
  1. # -*- coding: utf-8 -*-  
  2. import os  
  3. import tensorflow as tf  
  4. # 原图像的尺度为32*32,但根据常识,信息部分通常位于图像的中央,这里定义了以中心裁剪后图像的尺寸  
  5. fixed_height = 24  
  6. fixed_width = 24  
  7. # cifar10数据集的格式,训练样例集和测试样例集分别为50k和10k  
  8. train_samples_per_epoch = 50000  
  9. test_samples_per_epoch = 10000  
  10. data_dir='./cifar-10-batches-bin' # 定义数据集所在文件夹路径  
  11. batch_size=128 #定义每次参数更新时,所使用的batch的大小  
  12.    
  13. def read_cifar10(filename_queue):  
  14.     # 定义一个空的类对象,类似于c语言里面的结构体定义  
  15.     class Image(object):  
  16.         pass  
  17.     image = Image()  
  18.     image.height=32  
  19.     image.width=32  
  20.     image.depth=3  
  21.     label_bytes = 1  
  22.     image_bytes = image.height*image.width*image.depth  
  23.     Bytes_to_read = label_bytes+image_bytes  
  24.     # 定义一个Reader,它每次能从文件中读取固定字节数  
  25.     reader = tf.FixedLengthRecordReader(record_bytes=Bytes_to_read)   
  26.     # 返回从filename_queue中读取的(key, value)对,key和value都是字符串类型的tensor,并且当队列中的某一个文件读完成时,该文件名会dequeue  
  27.     image.key, value_str = reader.read(filename_queue)   
  28.     # 解码操作可以看作读二进制文件,把字符串中的字节转换为数值向量,每一个数值占用一个字节,在[0, 255]区间内,因此out_type要取uint8类型  
  29.     value = tf.decode_raw(bytes=value_str, out_type=tf.uint8)   
  30.     # 从一维tensor对象中截取一个slice,类似于从一维向量中筛选子向量,因为value中包含了label和feature,故要对向量类型tensor进行'parse'操作      
  31.     image.label = tf.slice(input_=value, begin=[0], size=[label_bytes])# begin和size分别表示待截取片段的起点和长度  
  32.     data_mat = tf.slice(input_=value, begin=[label_bytes], size=[image_bytes])  
  33.     data_mat = tf.reshape(data_mat, (image.depth, image.height, image.width)) #这里的维度顺序,是依据cifar二进制文件的格式而定的  
  34.     transposed_value = tf.transpose(data_mat, perm=[120]) #对data_mat的维度进行重新排列,返回值的第i个维度对应着data_mat的第perm[i]维  
  35.     image.mat = transposed_value      
  36.     return image      
  37.       
  38. def get_batch_samples(img_obj, min_samples_in_queue, batch_size, shuffle_flag):  
  39. ''''' 
  40. tf.train.shuffle_batch()函数用于随机地shuffling 队列中的tensors来创建batches(也即每次可以读取多个data文件中的样例构成一个batch)。这个函数向当前Graph中添加了下列对象: 
  41. *创建了一个shuffling queue,用于把‘tensors’中的tensors压入该队列; 
  42. *一个dequeue_many操作,用于根据队列中的数据创建一个batch; 
  43. *创建了一个QueueRunner对象,用于启动一个进程压数据到队列 
  44. capacity参数用于控制shuffling queue的最大长度;min_after_dequeue参数表示进行一次dequeue操作后队列中元素的最小数量,可以用于确保batch中 
  45. 元素的随机性;num_threads参数用于指定多少个threads负责压tensors到队列;enqueue_many参数用于表征是否tensors中的每一个tensor都代表一个样例 
  46. tf.train.batch()与之类似,只不过顺序地出队列(也即每次只能从一个data文件中读取batch),少了随机性。 
  47. '''  
  48.     if shuffle_flag == False:  
  49.         image_batch, label_batch = tf.train.batch(tensors=img_obj,   
  50.                                                   batch_size=batch_size,   
  51.                                                   num_threads=4,   
  52.                                                   capacity=min_samples_in_queue+3*batch_size)  
  53.     else:  
  54.         image_batch, label_batch = tf.train.shuffle_batch(tensors=img_obj,   
  55.                                                           batch_size=batch_size,   
  56.                                                           num_threads=4,   
  57.                                                           min_after_dequeue=min_samples_in_queue,  
  58.                                                           capacity=min_samples_in_queue+3*batch_size)                                                      
  59.     tf.image_summary('input_image', image_batch, max_images=6#输出预处理后图像的summary缓存对象,用于在session中写入到事件文件中                                                      
  60.     return image_batch, tf.reshape(label_batch, shape=[batch_size])       
  61.                                          
  62. def preprocess_input_data():  
  63. '''''这部分程序用于对训练数据集进行‘数据增强’操作,通过增加训练集的大小来防止过拟合'''  
  64.     filenames = [os.path.join(data_dir, 'data_batch_%d.bin' % i) for i in range(16)]  
  65.     #filenames =[os.path.join(data_dir, 'test_batch.bin')]  
  66.     for f in filenames: #检验训练数据集文件是否存在  
  67.         if not tf.gfile.Exists(f):  
  68.             raise ValueError('fail to find file:'+f)      
  69.     filename_queue = tf.train.string_input_producer(string_tensor=filenames) # 把文件名输出到队列中,作为整个data pipe的第一阶段  
  70.     image = read_cifar10(filename_queue) #从文件名队列中读取一个tensor类型的图像  
  71.     new_img = tf.cast(image.mat, tf.float32)  
  72.     tf.image_summary('raw_input_image', tf.reshape(new_img, [132323]))#输出预处理前图像的summary缓存对象  
  73.     new_img = tf.random_crop(new_img, size=(fixed_height, fixed_width, 3)) #从原图像中切割出子图像  
  74.     new_img = tf.image.random_brightness(new_img, max_delta=63#随机调节图像的亮度  
  75.     new_img = tf.image.random_flip_left_right(new_img) #随机地左右翻转图像  
  76.     new_img = tf.image.random_contrast(new_img, lower=0.2, upper=1.8#随机地调整图像对比度  
  77.     final_img = tf.image.per_image_whitening(new_img) #对图像进行whiten操作,目的是降低输入图像的冗余性,尽量去除输入特征间的相关性  
  78.       
  79.     min_samples_ratio_in_queue = 0.4  #用于确保读取到的batch中样例的随机性,使其覆盖到更多的类别、更多的数据文件!!!  
  80.     min_samples_in_queue = int(min_samples_ratio_in_queue*train_samples_per_epoch)   
  81.     return get_batch_samples([final_img, image.label], min_samples_in_queue, batch_size, shuffle_flag=True)  

(二)模型本身定义部分(forward_prop.py

       定义模型本身,也就是确定出网络结构(Graph),使得输入信号流在该图中进行forward propagation。在本样例中定义的网络结构为“输入层->卷积层->池化层->规范化层->卷积层->规范化层->池化层->全连接层->全连接层->softmax输出层”。与其他的深度网络模型不同,这里引入了规范化层,原因是Relu(rectified linear unit)激活函数会把输入激励映射到[0, infinite],详细的代码及其解释如下,

[python]  view plain  copy
  1. # -*- coding: utf-8 -*-  
  2. import tensorflow as tf  
  3. import input_dataset  
  4. #外部引用input_dataset文件中定义的hyperparameters  
  5. height = input_dataset.fixed_height  
  6. width = input_dataset.fixed_width  
  7. train_samples_per_epoch = input_dataset.train_samples_per_epoch  
  8. test_samples_per_epoch = input_dataset.test_samples_per_epoch  
  9.    
  10. # 用于描述训练过程的常数  
  11. moving_average_decay = 0.9999     # The decay to use for the moving average.  
  12. num_epochs_per_decay = 350.0      # 衰减呈阶梯函数,控制衰减周期(阶梯宽度)  
  13. learning_rate_decay_factor = 0.1  # 学习率衰减因子  
  14. initial_learning_rate = 0.1       # 初始学习率  
  15.    
  16. def variable_on_cpu(name, shape, dtype, initializer):  
  17.     with tf.device("/cpu:0"):  #一个 context manager,用于为新的op指定要使用的硬件  
  18.         return tf.get_variable(name=name,   
  19.                                shape=shape,   
  20.                                initializer=initializer,  
  21.                                dtype=dtype)      
  22.    
  23. def variable_on_cpu_with_collection(name, shape, dtype, stddev, wd):  
  24.     with tf.device("/cpu:0"):   
  25.         weight = tf.get_variable(name=name,   
  26.                                  shape=shape,   
  27.                                  initializer=tf.truncated_normal_initializer(stddev=stddev, dtype=dtype))  
  28.         if wd is not None:  
  29.             weight_decay = tf.mul(tf.nn.l2_loss(weight), wd, name='weight_loss')  
  30.             tf.add_to_collection(name='losses', value=weight_decay)           
  31.         return weight  
  32.           
  33. def losses_summary(total_loss):  
  34. #通过使用指数衰减,来维护变量的滑动均值。当训练模型时,维护训练参数的滑动均值是有好处的。在测试过程中使用滑动参数比最终训练的参数值本身,  
  35.     #会提高模型的实际性能(准确率)。apply()方法会添加trained variables的shadow copies,并添加操作来维护变量的滑动均值到shadow copies。average  
  36.     #方法可以访问shadow variables,在创建evaluation model时非常有用。  
  37. #滑动均值是通过指数衰减计算得到的。shadow variable的初始化值和trained variables相同,其更新公式为  
  38. # shadow_variable = decay * shadow_variable + (1 - decay) * variable  
  39.     average_op = tf.train.ExponentialMovingAverage(decay=0.9#创建一个新的指数滑动均值对象  
  40.     losses = tf.get_collection(key='losses')# 从字典集合中返回关键字'losses'对应的所有变量,包括交叉熵损失和正则项损失  
  41.     # 创建‘shadow variables’,并添加维护滑动均值的操作  
  42.     maintain_averages_op = average_op.apply(losses+[total_loss])#维护变量的滑动均值,返回一个能够更新shadow variables的操作  
  43.     for i in losses+[total_loss]:  
  44.         tf.scalar_summary(i.op.name+'_raw', i) #保存变量到Summary缓存对象,以便写入到文件中  
  45.         tf.scalar_summary(i.op.name, average_op.average(i)) #average() returns the shadow variable for a given variable.  
  46.     return maintain_averages_op  #返回损失变量的更新操作  
  47.       
  48. def one_step_train(total_loss, step):  
  49.     batch_count = int(train_samples_per_epoch/input_dataset.batch_size) #求训练块的个数   
  50.     decay_step = batch_count*num_epochs_per_decay #每经过decay_step步训练,衰减lr  
  51.     lr = tf.train.exponential_decay(learning_rate=initial_learning_rate,  
  52.                                     global_step=step,  
  53.                                     decay_steps=decay_step,  
  54.                                     decay_rate=learning_rate_decay_factor,  
  55.                                     staircase=True)  
  56.     tf.scalar_summary('learning_rate', lr)  
  57.     losses_movingaverage_op = losses_summary(total_loss)  
  58.     #tf.control_dependencies是一个context manager,控制节点执行顺序,先执行control_inputs中的操作,再执行context中的操作  
  59.     with tf.control_dependencies(control_inputs=[losses_movingaverage_op]):  
  60.         trainer = tf.train.GradientDescentOptimizer(learning_rate=lr)  
  61.         gradient_pairs = trainer.compute_gradients(loss=total_loss) #返回计算出的(gradient, variable) pairs  
  62.     gradient_update = trainer.apply_gradients(grads_and_vars=gradient_pairs, global_step=step) #返回一步梯度更新操作  
  63.     #num_updates参数用于动态调整衰减率,真实的decay_rate =min(decay, (1 + num_updates) / (10 + num_updates)   
  64.     variables_average_op = tf.train.ExponentialMovingAverage(decay=moving_average_decay, num_updates=step)  
  65.     # tf.trainable_variables() 方法返回所有`trainable=True`的变量,列表结构  
  66.     maintain_variable_average_op = variables_average_op.apply(var_list=tf.trainable_variables())#返回模型参数变量的滑动更新操作  
  67.     with tf.control_dependencies(control_inputs=[gradient_update, maintain_variable_average_op]):  
  68.         gradient_update_optimizor = tf.no_op() #Does nothing. Only useful as a placeholder for control edges  
  69.     return gradient_update_optimizor                      
  70.       
  71. def network(images):  
  72. #这一部分主要调用几个常见函数,在上一篇博客‘TensorFlow实现卷积神经网络’中有详细介绍,这里就不再赘述~  
  73.     with tf.variable_scope(name_or_scope='conv1') as scope:  
  74.         weight = variable_on_cpu_with_collection(name='weight',   
  75.                                                  shape=(55364),   
  76.                                                  dtype=tf.float32,   
  77.                                                  stddev=0.05,  
  78.                                                  wd = 0.0)  
  79.         bias = variable_on_cpu(name='bias', shape=(64), dtype=tf.float32, initializer=tf.constant_initializer(value=0.0))  
  80.         conv1_in = tf.nn.conv2d(input=images, filter=weight, strides=(1111), padding='SAME')  
  81.         conv1_in = tf.nn.bias_add(value=conv1_in, bias=bias)  
  82.         conv1_out = tf.nn.relu(conv1_in)   
  83.           
  84.     pool1 = tf.nn.max_pool(value=conv1_out, ksize=(1331), strides=(1221), padding='SAME')  
  85.       
  86.     norm1 = tf.nn.lrn(input=pool1, depth_radius=4, bias=1.0, alpha=0.001/9.0, beta=0.75)  
  87.       
  88.     with tf.variable_scope(name_or_scope='conv2') as scope:  
  89.         weight = variable_on_cpu_with_collection(name='weight',   
  90.                                  shape=(556464),   
  91.                                  dtype=tf.float32,   
  92.                                  stddev=0.05,  
  93.                                  wd=0.0)  
  94.         bias = variable_on_cpu(name='bias', shape=(64), dtype=tf.float32, initializer=tf.constant_initializer(value=0.1))  
  95.         conv2_in = tf.nn.conv2d(norm1, weight, strides=(1111), padding='SAME')  
  96.         conv2_in = tf.nn.bias_add(conv2_in, bias)  
  97.         conv2_out = tf.nn.relu(conv2_in)   
  98.       
  99.     norm2 = tf.nn.lrn(input=conv2_out, depth_radius=4, bias=1.0, alpha=0.001/9.0, beta=0.75)  
  100.       
  101.     pool2 = tf.nn.max_pool(value=norm2, ksize=(1331), strides=(1221), padding='SAME')  
  102.     # input tensor of shape `[batch, in_height, in_width, in_channels]  
  103.     reshaped_pool2 = tf.reshape(tensor=pool2, shape=(-16*6*64))  
  104.       
  105.     with tf.variable_scope(name_or_scope='fully_connected_layer1') as scope:  
  106.         weight = variable_on_cpu_with_collection(name='weight',   
  107.                                                  shape=(6*6*64384),   
  108.                                                  dtype=tf.float32,  
  109.                                                  stddev=0.04,  
  110.                                                  wd = 0.004)  
  111.         bias = variable_on_cpu(name='bias', shape=(384), dtype=tf.float32, initializer=tf.constant_initializer(value=0.1))  
  112.         fc1_in = tf.matmul(reshaped_pool2, weight)+bias  
  113.         fc1_out = tf.nn.relu(fc1_in)  
  114.       
  115.     with tf.variable_scope(name_or_scope='fully_connected_layer2') as scope:  
  116.         weight = variable_on_cpu_with_collection(name='weight',   
  117.                                                  shape=(384192),   
  118.                                                  dtype=tf.float32,  
  119.                                                  stddev=0.04,  
  120.                                                  wd=0.004)  
  121.         bias = variable_on_cpu(name='bias', shape=(192), dtype=tf.float32, initializer=tf.constant_initializer(value=0.1))  
  122.         fc2_in = tf.matmul(fc1_out, weight)+bias  
  123.         fc2_out = tf.nn.relu(fc2_in)      
  124.       
  125.     with tf.variable_scope(name_or_scope='softmax_layer') as scope:  
  126.         weight = variable_on_cpu_with_collection(name='weight',   
  127.                                                  shape=(19210),   
  128.                                                  dtype=tf.float32,  
  129.                                                  stddev=1/192,  
  130.                                                  wd=0.0)  
  131.         bias = variable_on_cpu(name='bias', shape=(10), dtype=tf.float32, initializer=tf.constant_initializer(value=0.0))  
  132.         classifier_in = tf.matmul(fc2_out, weight)+bias  
  133.         classifier_out = tf.nn.softmax(classifier_in)  
  134.     return classifier_out  
  135.    
  136. def loss(logits, labels):   
  137.     labels = tf.cast(x=labels, dtype=tf.int32)  #强制类型转换,使符合sparse_softmax_cross_entropy_with_logits输入参数格式要求  
  138.     cross_entropy_loss = tf.nn.sparse_softmax_cross_entropy_with_logits(logits=logits, labels=labels, name='likelihood_loss')  
  139.     cross_entropy_loss = tf.reduce_mean(cross_entropy_loss, name='cross_entropy_loss'#对batch_size长度的向量取平均      
  140.     tf.add_to_collection(name='losses', value=cross_entropy_loss) #把张量cross_entropy_loss添加到字典集合中key='losses'的子集中    
  141.     return tf.add_n(inputs=tf.get_collection(key='losses'), name='total_loss'#返回字典集合中key='losses'的子集中元素之和  

(三)模型训练部分(train.py)

       模型训练的实质就是一个“参数寻优”的过程,最常见的优化算法是mini-batch的随机梯度下降法(mini-batch是相对于online learning而言的),寻找使得损失函数值最小的模型参数。为了防止过拟合,这里的损失函数包含了正则化项,具体的代码解释如下,

扫描二维码关注公众号,回复: 1937908 查看本文章
[python]  view plain  copy
  1. # -*- coding: utf-8 -*-  
  2. import input_dataset  
  3. import forward_prop  
  4. import tensorflow as tf  
  5. import os  
  6. import numpy as np  
  7.    
  8. max_iter_num = 100000 #设置参数迭代次数  
  9. checkpoint_path = './checkpoint' #设置模型参数文件所在路径  
  10. event_log_path = './event-log' #设置事件文件所在路径,用于周期性存储Summary缓存对象  
  11.    
  12. def train():  
  13.     with tf.Graph().as_default():    #指定当前图为默认graph  
  14.         global_step = tf.Variable(initial_value=0, trainable=False)#设置trainable=False,是因为防止训练过程中对global_step变量也进行滑动更新操作  
  15.         img_batch, label_batch = input_dataset.preprocess_input_data()#输入图像的预处理,包括亮度、对比度、图像翻转等操作  
  16.         # img_batch, label_batch = input_dataset.input_data(eval_flag=False)  
  17.         logits = forward_prop.network(img_batch) #图像信号的前向传播过程  
  18.         total_loss = forward_prop.loss(logits, label_batch) #计算损失  
  19.         one_step_gradient_update = forward_prop.one_step_train(total_loss, global_step) #返回一步梯度更新操作  
  20.         #创建一个saver对象,用于保存参数到文件中  
  21.         saver = tf.train.Saver(var_list=tf.all_variables()) #tf.all_variables return a list of `Variable` objects          
  22.         all_summary_obj = tf.merge_all_summaries()#返回所有summary对象先merge再serialize后的的字符串类型tensor  
  23.         initiate_variables = tf.initialize_all_variables()          
  24. #log_device_placement参数可以记录每一个操作使用的设备,这里的操作比较多,就不需要记录了,故设置为False  
  25.         with tf.Session(config=tf.ConfigProto(log_device_placement=False)) as sess:  
  26.             sess.run(initiate_variables)  #变量初始化             
  27.             tf.train.start_queue_runners(sess=sess) #启动所有的queuerunners  
  28.             Event_writer = tf.train.SummaryWriter(logdir=event_log_path, graph=sess.graph)   
  29.             for step in range(max_iter_num):  
  30.                 _, loss_value = sess.run(fetches=[one_step_gradient_update, total_loss])  
  31.                 assert not np.isnan(loss_value) #用于验证当前迭代计算出的loss_value是否合理  
  32.                 if step%10 == 0:  
  33.                     print('step %d, the loss_value is %.2f' % (step, loss_value))  
  34.                 if step%100 == 0:  
  35.                     # 添加`Summary`协议缓存到事件文件中,故不能写total_loss变量到事件文件中,因为这里的total_loss为普通的tensor类型  
  36.                     all_summaries = sess.run(all_summary_obj)  
  37.                     Event_writer.add_summary(summary=all_summaries, global_step=step)  
  38.                 if step%1000 == 0 or (step+1)==max_iter_num:  
  39.                     variables_save_path = os.path.join(checkpoint_path, 'model-parameters.bin'#路径合并,返回合并后的字符串  
  40.                     saver.save(sess, variables_save_path, global_step=step)#把所有变量(包括moving average前后的模型参数)保存在variables_save_path路径下                   
  41. if __name__ == '__main__':  
  42.     train()                  

(四)模型性能评估部分(evaluate.py

       机器学习模型训练好之后,要在测试数据集上进行测试,从而判断模型的性能,常见的性能指标有准确率、召回率等。顺便提及一下,有的机器学习模型在训练时,会把数据集分成三部分,训练集(training dataset,正则集(validation dataset)和测试集(test dataset,正则集的作用也是为了防止过拟合,但我们这里通过对模型参数正则化来防止过拟合,因此就不用像这样划分数据集了,具体的代码及解释如下,

[python]  view plain  copy
  1. # -*- coding: utf-8 -*-  
  2. import tensorflow as tf  
  3. import input_dataset  
  4. import forward_prop  
  5. import train  
  6. import math  
  7. import numpy as np  
  8.    
  9. def eval_once(summary_op, summary_writer, saver, predict_true_or_false):  
  10.     with tf.Session() as sess:  
  11. #从checkpoint文件中返回checkpointstate模板  
  12.         checkpoint_proto = tf.train.get_checkpoint_state(checkpoint_dir=train.checkpoint_path)  
  13.         if checkpoint_proto and checkpoint_proto.model_checkpoint_path:  
  14.             saver.restore(sess, checkpoint_proto.model_checkpoint_path)#恢复模型变量到当前session中  
  15.         else:  
  16.             print('checkpoint file not found!')  
  17.             return  
  18.         # 启动很多线程,并把coordinator传递给每一个线程      
  19.         coord = tf.train.Coordinator() #返回一个coordinator类对象,这个类实现了一个简单的机制,可以用来coordinate很多线程的结束  
  20.         try:  
  21.             threads = [] #使用coord统一管理所有线程  
  22.             for queue_runner in tf.get_collection(key=tf.GraphKeys.QUEUE_RUNNERS):  
  23.                 threads.extend(queue_runner.create_threads(sess, coord=coord, daemon=True, start=True))  
  24. #计算测试数据块的个数,并向上取整  
  25.             test_batch_num = math.ceil(input_dataset.test_samples_per_epoch/input_dataset.batch_size)  
  26.             iter_num = 0  
  27.             true_test_num = 0  
  28. #这里使用取整后的测试数据块个数,来计算测试样例的总数目,理论上这样算测试样例总数会偏大啊,暂时还未理解???  
  29.             total_test_num = test_batch_num*input_dataset.batch_size  
  30.               
  31.             while iter_num<test_batch_num and not coord.should_stop():  
  32.                 result_judge = sess.run([predict_true_or_false])  
  33.                 true_test_num += np.sum(result_judge)  
  34.                 iter_num += 1  
  35.             precision = true_test_num/total_test_num  
  36.             print("The test precision is %.3f"  % precision)  
  37.         except:  
  38.             coord.request_stop()  
  39.         coord.request_stop()  
  40.         coord.join(threads)  
  41.                   
  42. def evaluate():  
  43.     with tf.Graph().as_default() as g:  
  44.         img_batch, labels = input_dataset.input_data(eval_flag=True)#读入测试数据集  
  45.         logits = forward_prop.network(img_batch)#使用moving average操作前的模型参数,计算模型输出值  
  46. #判断targets是否在前k个predictions里面,当k=1时等价于常规的计算正确率的方法,sess.run(predict_true_or_false)会执行符号计算  
  47.         predict_true_or_false = tf.nn.in_top_k(predictions=logits, targets=labels, k=1)  
  48.         #恢复moving average操作后的模型参数  
  49.         moving_average_op = tf.train.ExponentialMovingAverage(decay=forward_prop.moving_average_decay)  
  50. #返回要恢复的names到Variables的映射,也即一个map映射。如果一个变量有moving average,就使用moving average变量名作为the restore  
  51. # name, 否则就使用变量名  
  52.         variables_to_restore = moving_average_op.variables_to_restore()  
  53.         saver = tf.train.Saver(var_list=variables_to_restore)  
  54.           
  55.         summary_op = tf.merge_all_summaries() #创建序列化后的summary对象  
  56. #创建一个event file,用于之后写summary对象到logdir目录下的文件中  
  57.         summary_writer = tf.train.SummaryWriter(logdir='./event-log-test', graph=g)  
  58.         eval_once(summary_op, summary_writer, saver, predict_true_or_false)  

另外,在自己编写程序的过程中,出现了一些错误提示,在这里一并记录下来,供以后参考,

(1)"SyntaxError: positional argument follows keyword argument"

错误原因:在python中向子函数传递参数时,实参或者全部用关键字参数;或者全部用定位参数;当同时使用关键字参数和定位参数时,一定是定位参数在前,关键字参数在后,样例如下,

              def test(a, b, c):

                  return a+b+c

            则以下三种调用方式均正确,

            test(1,2,c=3)

            test(1,2,3)  

            test(a=1, b=2, c=3) 

(2)语句"with tf.Graph.as_default()"出现错误“TypeError: as_default() missing 1 required positional argument: 'self'

错误原因:应该为tf.Graph().as_default()

(3)打开tensorboard时提示“inner server error

错误原因:在我的电脑上开启了lantern代理,导致启动tensorboard时服务器出错

(4)错误提示“TypeError: int() argument must be a string, a bytes-like object or a number, not 'Variable'

错误原因:tf.get_variable()中的shape参数不能为tensor类型,可以区别下面的两种情况来理解

情况1: reshape = tf.reshape(pool2, [batch_size, -1])

     dim = reshape.get_shape()[1].value  #reshape.get_shape()[1]dimension类型tensor,取其value属性会得到int类型数值

情况2 reshaped_pool2 = tf.reshape(tensor=pool2, shape=(batch_size, -1))

dim = tf.shape(reshaped_pool2)[1]   #dimtensor类型

又因为tf.get_variable(name, shape=[dim, 384], initializer=initializer, dtype=dtype)函数中,shape参数必须为ndarray类型

(5)在每次迭代时,打印出的损失值过大,如下所示,

    step 0, the loss_value is 22439.82

    step 10, the loss_value is 6426354679171382723219403309056.00

    

    错误原因:设置权值参数w时,标准差取了一个过大的constant,

     如设置weight = tf.get_variable(name=name, shape=shape, initializer=tf.truncated_normal_initializer(stddev=0.5, dtype=dtype))

(6)本程序在tensorflow0.8.0版本下也是可以运行的,只不过需要把tf.train.batchtf.train.shuffle_batch函数中的关键字tensors改成tensor_list

(7)错误提示“UnboundLocalError: local variable 'CONSTANT' referenced before assignment

错误原因:可以参见下面这段代码

CONSTANT = 0  

def modifyConstant() :  

         print CONSTANT  

      CONSTANT += 1

在函数内部修改了变量CONSTANTPython认为CONSTANT是局部变量,而print CONSTANT又在CONSTANT += 1之前,所以会发生这种错误。

如果必须在函数内部访问并修改全局变量,应该使用关键字global在函数内声明变量CONSTANT

(8)要注意区别tf.reshape()tf.transpose()函数,前者是按照数据的存储先后顺序重新调整tensor的尺寸,而后者是从空间角度进行维度的旋转。

参考资料:https://www.tensorflow.org/versions/r0.11/tutorials/deep_cnn/index.html#convolutional-neural-networks

猜你喜欢

转载自blog.csdn.net/maweifei/article/details/80724659