1. 程式人生 > >TensorFlow中cnn-cifar10樣例程式碼詳解

TensorFlow中cnn-cifar10樣例程式碼詳解

       TensorFlow是一個支援分散式的深度學習框架,在Google的推動下,它正在變得越來越普及。我最近學了TensorFlow教程上的一個例子,即採用CNN對cifar10資料集進行分類。在看原始碼的時候,看完後有一種似懂非懂的感覺,又考慮到這個樣例涵蓋了tensorflow的大部分語法知識,包括QueueRunners機制、Tensorboard視覺化和多GPU資料並行程式設計等。“紙上得來終覺淺,絕知此事要躬行”,於是我便照著自己的理解和記憶來重新程式設計實現一遍,實現過程中也遇到了一些問題,在這裡把我對程式的詳細的理解和遇到的問題記錄下來,本著“知其然,知其所以然”的標準,程式中的註釋更加側重於對‘為什麼這一行程式碼要這樣寫’的解讀,以供以後參考(關於卷積神經網路相關的理論部分,網上有很多了,這裡就不做太多介紹)。

一個標準的機器學習程式,應該包括資料輸入、定義模型本身、模型訓練和模型效能測試四大部分,可以分成四個.py檔案。

(一)資料輸入部分(input_dataset.py)

       從概念上來說,這部分主要是關於資料管道(data pipe)的構建,資料流向為“二進位制檔案->檔名佇列->資料佇列->讀取出的data-batch”。資料塊用於輸入到深度學習網路中,進行資訊的forward propagation,這部分在定義模型本身部分討論。在定義整個資料管道的時候,會使用到TensorFlow的佇列機制,這部分在之前的博文“TensorFlow讀取二進位制檔案資料到佇列”中進行了詳細講述。另外,讀原資料檔案的時候,要結合檔案本身的格式,相信編寫過c語言讀取二進位制檔案的程式的朋友,對這應該再熟悉不過了,具體的程式碼如下,

# -*- coding: utf-8 -*-
import os
import tensorflow as tf
# 原影象的尺度為32*32,但根據常識,資訊部分通常位於影象的中央,這裡定義了以中心裁剪後圖像的尺寸
fixed_height = 24
fixed_width = 24
# cifar10資料集的格式,訓練樣例集和測試樣例集分別為50k和10k
train_samples_per_epoch = 50000
test_samples_per_epoch = 10000
data_dir='./cifar-10-batches-bin' # 定義資料集所在資料夾路徑
batch_size=128 #定義每次引數更新時,所使用的batch的大小
 
def read_cifar10(filename_queue):
    # 定義一個空的類物件,類似於c語言裡面的結構體定義
    class Image(object):
        pass
    image = Image()
    image.height=32
    image.width=32
    image.depth=3
    label_bytes = 1
    image_bytes = image.height*image.width*image.depth
    Bytes_to_read = label_bytes+image_bytes
    # 定義一個Reader,它每次能從檔案中讀取固定位元組數
    reader = tf.FixedLengthRecordReader(record_bytes=Bytes_to_read) 
    # 返回從filename_queue中讀取的(key, value)對,key和value都是字串型別的tensor,並且當佇列中的某一個檔案讀完成時,該檔名會dequeue
    image.key, value_str = reader.read(filename_queue) 
    # 解碼操作可以看作讀二進位制檔案,把字串中的位元組轉換為數值向量,每一個數值佔用一個位元組,在[0, 255]區間內,因此out_type要取uint8型別
    value = tf.decode_raw(bytes=value_str, out_type=tf.uint8) 
    # 從一維tensor物件中擷取一個slice,類似於從一維向量中篩選子向量,因為value中包含了label和feature,故要對向量型別tensor進行'parse'操作    
    image.label = tf.slice(input_=value, begin=[0], size=[label_bytes])# begin和size分別表示待擷取片段的起點和長度
    data_mat = tf.slice(input_=value, begin=[label_bytes], size=[image_bytes])
    data_mat = tf.reshape(data_mat, (image.depth, image.height, image.width)) #這裡的維度順序,是依據cifar二進位制檔案的格式而定的
    transposed_value = tf.transpose(data_mat, perm=[1, 2, 0]) #對data_mat的維度進行重新排列,返回值的第i個維度對應著data_mat的第perm[i]維
    image.mat = transposed_value    
    return image    
    
def get_batch_samples(img_obj, min_samples_in_queue, batch_size, shuffle_flag):
'''
tf.train.shuffle_batch()函式用於隨機地shuffling 佇列中的tensors來建立batches(也即每次可以讀取多個data檔案中的樣例構成一個batch)。這個函式向當前Graph中添加了下列物件:
*建立了一個shuffling queue,用於把‘tensors’中的tensors壓入該佇列;
*一個dequeue_many操作,用於根據佇列中的資料建立一個batch;
*建立了一個QueueRunner物件,用於啟動一個程序壓資料到佇列
capacity引數用於控制shuffling queue的最大長度;min_after_dequeue引數表示進行一次dequeue操作後佇列中元素的最小數量,可以用於確保batch中
元素的隨機性;num_threads引數用於指定多少個threads負責壓tensors到佇列;enqueue_many引數用於表徵是否tensors中的每一個tensor都代表一個樣例
tf.train.batch()與之類似,只不過順序地出佇列(也即每次只能從一個data檔案中讀取batch),少了隨機性。
'''
    if shuffle_flag == False:
        image_batch, label_batch = tf.train.batch(tensors=img_obj, 
                                                  batch_size=batch_size, 
                                                  num_threads=4, 
                                                  capacity=min_samples_in_queue+3*batch_size)
    else:
        image_batch, label_batch = tf.train.shuffle_batch(tensors=img_obj, 
                                                          batch_size=batch_size, 
                                                          num_threads=4, 
                                                          min_after_dequeue=min_samples_in_queue,
                                                          capacity=min_samples_in_queue+3*batch_size)                                                    
    tf.image_summary('input_image', image_batch, max_images=6) #輸出預處理後圖像的summary快取物件,用於在session中寫入到事件檔案中                                                    
    return image_batch, tf.reshape(label_batch, shape=[batch_size])     
                                       
def preprocess_input_data():
'''這部分程式用於對訓練資料集進行‘資料增強’操作,通過增加訓練集的大小來防止過擬合'''
    filenames = [os.path.join(data_dir, 'data_batch_%d.bin' % i) for i in range(1, 6)]
    #filenames =[os.path.join(data_dir, 'test_batch.bin')]
    for f in filenames: #檢驗訓練資料集檔案是否存在
        if not tf.gfile.Exists(f):
            raise ValueError('fail to find file:'+f)    
    filename_queue = tf.train.string_input_producer(string_tensor=filenames) # 把檔名輸出到佇列中,作為整個data pipe的第一階段
    image = read_cifar10(filename_queue) #從檔名佇列中讀取一個tensor型別的影象
    new_img = tf.cast(image.mat, tf.float32)
    tf.image_summary('raw_input_image', tf.reshape(new_img, [1, 32, 32, 3]))#輸出預處理前影象的summary快取物件
    new_img = tf.random_crop(new_img, size=(fixed_height, fixed_width, 3)) #從原影象中切割出子影象
    new_img = tf.image.random_brightness(new_img, max_delta=63) #隨機調節影象的亮度
    new_img = tf.image.random_flip_left_right(new_img) #隨機地左右翻轉影象
    new_img = tf.image.random_contrast(new_img, lower=0.2, upper=1.8) #隨機地調整影象對比度
    final_img = tf.image.per_image_whitening(new_img) #對影象進行whiten操作,目的是降低輸入影象的冗餘性,儘量去除輸入特徵間的相關性
    
    min_samples_ratio_in_queue = 0.4  #用於確保讀取到的batch中樣例的隨機性,使其覆蓋到更多的類別、更多的資料檔案!!!
    min_samples_in_queue = int(min_samples_ratio_in_queue*train_samples_per_epoch) 
    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],詳細的程式碼及其解釋如下,

# -*- coding: utf-8 -*-
import tensorflow as tf
import input_dataset
#外部引用input_dataset檔案中定義的hyperparameters
height = input_dataset.fixed_height
width = input_dataset.fixed_width
train_samples_per_epoch = input_dataset.train_samples_per_epoch
test_samples_per_epoch = input_dataset.test_samples_per_epoch
 
# 用於描述訓練過程的常數
moving_average_decay = 0.9999     # The decay to use for the moving average.
num_epochs_per_decay = 350.0      # 衰減呈階梯函式,控制衰減週期(階梯寬度)
learning_rate_decay_factor = 0.1  # 學習率衰減因子
initial_learning_rate = 0.1       # 初始學習率
 
def variable_on_cpu(name, shape, dtype, initializer):
    with tf.device("/cpu:0"):  #一個 context manager,用於為新的op指定要使用的硬體
        return tf.get_variable(name=name, 
                               shape=shape, 
                               initializer=initializer,
                               dtype=dtype)    
 
def variable_on_cpu_with_collection(name, shape, dtype, stddev, wd):
    with tf.device("/cpu:0"): 
        weight = tf.get_variable(name=name, 
                                 shape=shape, 
                                 initializer=tf.truncated_normal_initializer(stddev=stddev, dtype=dtype))
        if wd is not None:
            weight_decay = tf.mul(tf.nn.l2_loss(weight), wd, name='weight_loss')
            tf.add_to_collection(name='losses', value=weight_decay)         
        return weight
        
def losses_summary(total_loss):
#通過使用指數衰減,來維護變數的滑動均值。當訓練模型時,維護訓練引數的滑動均值是有好處的。在測試過程中使用滑動引數比最終訓練的引數值本身,
    #會提高模型的實際效能(準確率)。apply()方法會新增trained variables的shadow copies,並新增操作來維護變數的滑動均值到shadow copies。average
    #方法可以訪問shadow variables,在建立evaluation model時非常有用。
#滑動均值是通過指數衰減計算得到的。shadow variable的初始化值和trained variables相同,其更新公式為
# shadow_variable = decay * shadow_variable + (1 - decay) * variable
    average_op = tf.train.ExponentialMovingAverage(decay=0.9) #建立一個新的指數滑動均值物件
    losses = tf.get_collection(key='losses')# 從字典集合中返回關鍵字'losses'對應的所有變數,包括交叉熵損失和正則項損失
    # 建立‘shadow variables’,並新增維護滑動均值的操作
    maintain_averages_op = average_op.apply(losses+[total_loss])#維護變數的滑動均值,返回一個能夠更新shadow variables的操作
    for i in losses+[total_loss]:
        tf.scalar_summary(i.op.name+'_raw', i) #儲存變數到Summary快取物件,以便寫入到檔案中
        tf.scalar_summary(i.op.name, average_op.average(i)) #average() returns the shadow variable for a given variable.
    return maintain_averages_op  #返回損失變數的更新操作
    
def one_step_train(total_loss, step):
    batch_count = int(train_samples_per_epoch/input_dataset.batch_size) #求訓練塊的個數 
    decay_step = batch_count*num_epochs_per_decay #每經過decay_step步訓練,衰減lr
    lr = tf.train.exponential_decay(learning_rate=initial_learning_rate,
                                    global_step=step,
                                    decay_steps=decay_step,
                                    decay_rate=learning_rate_decay_factor,
                                    staircase=True)
    tf.scalar_summary('learning_rate', lr)
    losses_movingaverage_op = losses_summary(total_loss)
    #tf.control_dependencies是一個context manager,控制節點執行順序,先執行control_inputs中的操作,再執行context中的操作
    with tf.control_dependencies(control_inputs=[losses_movingaverage_op]):
        trainer = tf.train.GradientDescentOptimizer(learning_rate=lr)
        gradient_pairs = trainer.compute_gradients(loss=total_loss) #返回計算出的(gradient, variable) pairs
    gradient_update = trainer.apply_gradients(grads_and_vars=gradient_pairs, global_step=step) #返回一步梯度更新操作
    #num_updates引數用於動態調整衰減率,真實的decay_rate =min(decay, (1 + num_updates) / (10 + num_updates) 
    variables_average_op = tf.train.ExponentialMovingAverage(decay=moving_average_decay, num_updates=step)
    # tf.trainable_variables() 方法返回所有`trainable=True`的變數,列表結構
    maintain_variable_average_op = variables_average_op.apply(var_list=tf.trainable_variables())#返回模型引數變數的滑動更新操作
    with tf.control_dependencies(control_inputs=[gradient_update, maintain_variable_average_op]):
        gradient_update_optimizor = tf.no_op() #Does nothing. Only useful as a placeholder for control edges
    return gradient_update_optimizor                    
    
def network(images):
#這一部分主要呼叫幾個常見函式,在上一篇部落格‘TensorFlow實現卷積神經網路’中有詳細介紹,這裡就不再贅述~
    with tf.variable_scope(name_or_scope='conv1') as scope:
        weight = variable_on_cpu_with_collection(name='weight', 
                                                 shape=(5, 5, 3, 64), 
                                                 dtype=tf.float32, 
                                                 stddev=0.05,
                                                 wd = 0.0)
        bias = variable_on_cpu(name='bias', shape=(64), dtype=tf.float32, initializer=tf.constant_initializer(value=0.0))
        conv1_in = tf.nn.conv2d(input=images, filter=weight, strides=(1, 1, 1, 1), padding='SAME')
        conv1_in = tf.nn.bias_add(value=conv1_in, bias=bias)
        conv1_out = tf.nn.relu(conv1_in) 
        
    pool1 = tf.nn.max_pool(value=conv1_out, ksize=(1, 3, 3, 1), strides=(1, 2, 2, 1), padding='SAME')
    
    norm1 = tf.nn.lrn(input=pool1, depth_radius=4, bias=1.0, alpha=0.001/9.0, beta=0.75)
    
    with tf.variable_scope(name_or_scope='conv2') as scope:
        weight = variable_on_cpu_with_collection(name='weight', 
                                 shape=(5, 5, 64, 64), 
                                 dtype=tf.float32, 
                                 stddev=0.05,
                                 wd=0.0)
        bias = variable_on_cpu(name='bias', shape=(64), dtype=tf.float32, initializer=tf.constant_initializer(value=0.1))
        conv2_in = tf.nn.conv2d(norm1, weight, strides=(1, 1, 1, 1), padding='SAME')
        conv2_in = tf.nn.bias_add(conv2_in, bias)
        conv2_out = tf.nn.relu(conv2_in) 
    
    norm2 = tf.nn.lrn(input=conv2_out, depth_radius=4, bias=1.0, alpha=0.001/9.0, beta=0.75)
    
    pool2 = tf.nn.max_pool(value=norm2, ksize=(1, 3, 3, 1), strides=(1, 2, 2, 1), padding='SAME')
    # input tensor of shape `[batch, in_height, in_width, in_channels]
    reshaped_pool2 = tf.reshape(tensor=pool2, shape=(-1, 6*6*64))
    
    with tf.variable_scope(name_or_scope='fully_connected_layer1') as scope:
        weight = variable_on_cpu_with_collection(name='weight', 
                                                 shape=(6*6*64, 384), 
                                                 dtype=tf.float32,
                                                 stddev=0.04,
                                                 wd = 0.004)
        bias = variable_on_cpu(name='bias', shape=(384), dtype=tf.float32, initializer=tf.constant_initializer(value=0.1))
        fc1_in = tf.matmul(reshaped_pool2, weight)+bias
        fc1_out = tf.nn.relu(fc1_in)
    
    with tf.variable_scope(name_or_scope='fully_connected_layer2') as scope:
        weight = variable_on_cpu_with_collection(name='weight', 
                                                 shape=(384, 192), 
                                                 dtype=tf.float32,
                                                 stddev=0.04,
                                                 wd=0.004)
        bias = variable_on_cpu(name='bias', shape=(192), dtype=tf.float32, initializer=tf.constant_initializer(value=0.1))
        fc2_in = tf.matmul(fc1_out, weight)+bias
        fc2_out = tf.nn.relu(fc2_in)    
    
    with tf.variable_scope(name_or_scope='softmax_layer') as scope:
        weight = variable_on_cpu_with_collection(name='weight', 
                                                 shape=(192, 10), 
                                                 dtype=tf.float32,
                                                 stddev=1/192,
                                                 wd=0.0)
        bias = variable_on_cpu(name='bias', shape=(10), dtype=tf.float32, initializer=tf.constant_initializer(value=0.0))
        classifier_in = tf.matmul(fc2_out, weight)+bias
        classifier_out = tf.nn.softmax(classifier_in)
    return classifier_out
 
def loss(logits, labels): 
    labels = tf.cast(x=labels, dtype=tf.int32)  #強制型別轉換,使符合sparse_softmax_cross_entropy_with_logits輸入引數格式要求
    cross_entropy_loss = tf.nn.sparse_softmax_cross_entropy_with_logits(logits=logits, labels=labels, name='likelihood_loss')
    cross_entropy_loss = tf.reduce_mean(cross_entropy_loss, name='cross_entropy_loss') #對batch_size長度的向量取平均    
    tf.add_to_collection(name='losses', value=cross_entropy_loss) #把張量cross_entropy_loss新增到字典集合中key='losses'的子集中  
    return tf.add_n(inputs=tf.get_collection(key='losses'), name='total_loss') #返回字典集合中key='losses'的子集中元素之和

(三)模型訓練部分(train.py)

       模型訓練的實質就是一個“引數尋優”的過程,最常見的優化演算法是mini-batch的隨機梯度下降法(mini-batch是相對於online learning而言的),尋找使得損失函式值最小的模型引數。為了防止過擬合,這裡的損失函式包含了正則化項,具體的程式碼解釋如下,

# -*- coding: utf-8 -*-
import input_dataset
import forward_prop
import tensorflow as tf
import os
import numpy as np
 
max_iter_num = 100000 #設定引數迭代次數
checkpoint_path = './checkpoint' #設定模型引數檔案所在路徑
event_log_path = './event-log' #設定事件檔案所在路徑,用於週期性儲存Summary快取物件
 
def train():
    with tf.Graph().as_default():    #指定當前圖為預設graph
        global_step = tf.Variable(initial_value=0, trainable=False)#設定trainable=False,是因為防止訓練過程中對global_step變數也進行滑動更新操作
        img_batch, label_batch = input_dataset.preprocess_input_data()#輸入影象的預處理,包括亮度、對比度、影象翻轉等操作
        # img_batch, label_batch = input_dataset.input_data(eval_flag=False)
        logits = forward_prop.network(img_batch) #影象訊號的前向傳播過程
        total_loss = forward_prop.loss(logits, label_batch) #計算損失
        one_step_gradient_update = forward_prop.one_step_train(total_loss, global_step) #返回一步梯度更新操作
        #建立一個saver物件,用於儲存引數到檔案中
        saver = tf.train.Saver(var_list=tf.all_variables()) #tf.all_variables return a list of `Variable` objects        
        all_summary_obj = tf.merge_all_summaries()#返回所有summary物件先merge再serialize後的的字串型別tensor
        initiate_variables = tf.initialize_all_variables()        
#log_device_placement引數可以記錄每一個操作使用的裝置,這裡的操作比較多,就不需要記錄了,故設定為False
        with tf.Session(config=tf.ConfigProto(log_device_placement=False)) as sess:
            sess.run(initiate_variables)  #變數初始化           
            tf.train.start_queue_runners(sess=sess) #啟動所有的queuerunners
            Event_writer = tf.train.SummaryWriter(logdir=event_log_path, graph=sess.graph) 
            for step in range(max_iter_num):
                _, loss_value = sess.run(fetches=[one_step_gradient_update, total_loss])
                assert not np.isnan(loss_value) #用於驗證當前迭代計算出的loss_value是否合理
                if step%10 == 0:
                    print('step %d, the loss_value is %.2f' % (step, loss_value))
                if step%100 == 0:
                    # 新增`Summary`協議快取到事件檔案中,故不能寫total_loss變數到事件檔案中,因為這裡的total_loss為普通的tensor型別
                    all_summaries = sess.run(all_summary_obj)
                    Event_writer.add_summary(summary=all_summaries, global_step=step)
                if step%1000 == 0 or (step+1)==max_iter_num:
                    variables_save_path = os.path.join(checkpoint_path, 'model-parameters.bin') #路徑合併,返回合併後的字串
                    saver.save(sess, variables_save_path, global_step=step)#把所有變數(包括moving average前後的模型引數)儲存在variables_save_path路徑下                 
if __name__ == '__main__':
    train()                

(四)模型效能評估部分(evaluate.py)

       機器學習模型訓練好之後,要在測試資料集上進行測試,從而判斷模型的效能,常見的效能指標有準確率、召回率等。順便提及一下,有的機器學習模型在訓練時,會把資料集分成三部分,訓練集(training dataset),正則集(validation dataset)和測試集(test dataset),正則集的作用也是為了防止過擬合,但我們這裡通過對模型引數正則化來防止過擬合,因此就不用像這樣劃分資料集了,具體的程式碼及解釋如下,

# -*- coding: utf-8 -*-
import tensorflow as tf
import input_dataset
import forward_prop
import train
import math
import numpy as np
 
def eval_once(summary_op, summary_writer, saver, predict_true_or_false):
    with tf.Session() as sess:
#從checkpoint檔案中返回checkpointstate模板
        checkpoint_proto = tf.train.get_checkpoint_state(checkpoint_dir=train.checkpoint_path)
        if checkpoint_proto and checkpoint_proto.model_checkpoint_path:
            saver.restore(sess, checkpoint_proto.model_checkpoint_path)#恢復模型變數到當前session中
        else:
            print('checkpoint file not found!')
            return
        # 啟動很多執行緒,並把coordinator傳遞給每一個執行緒    
        coord = tf.train.Coordinator() #返回一個coordinator類物件,這個類實現了一個簡單的機制,可以用來coordinate很多執行緒的結束
        try:
            threads = [] #使用coord統一管理所有執行緒
            for queue_runner in tf.get_collection(key=tf.GraphKeys.QUEUE_RUNNERS):
                threads.extend(queue_runner.create_threads(sess, coord=coord, daemon=True, start=True))
#計算測試資料塊的個數,並向上取整
            test_batch_num = math.ceil(input_dataset.test_samples_per_epoch/input_dataset.batch_size)
            iter_num = 0
            true_test_num = 0
#這裡使用取整後的測試資料塊個數,來計算測試樣例的總數目,理論上這樣算測試樣例總數會偏大啊,暫時還未理解???
            total_test_num = test_batch_num*input_dataset.batch_size
            
            while iter_num<test_batch_num and not coord.should_stop():
                result_judge = sess.run([predict_true_or_false])
                true_test_num += np.sum(result_judge)
                iter_num += 1
            precision = true_test_num/total_test_num
            print("The test precision is %.3f"  % precision)
        except:
            coord.request_stop()
        coord.request_stop()
        coord.join(threads)
                
def evaluate():
    with tf.Graph().as_default() as g:
        img_batch, labels = input_dataset.input_data(eval_flag=True)#讀入測試資料集
        logits = forward_prop.network(img_batch)#使用moving average操作前的模型引數,計算模型輸出值
#判斷targets是否在前k個predictions裡面,當k=1時等價於常規的計算正確率的方法,sess.run(predict_true_or_false)會執行符號計算
        predict_true_or_false = tf.nn.in_top_k(predictions=logits, targets=labels, k=1)
        #恢復moving average操作後的模型引數
        moving_average_op = tf.train.ExponentialMovingAverage(decay=forward_prop.moving_average_decay)
#返回要恢復的names到Variables的對映,也即一個map對映。如果一個變數有moving average,就使用moving average變數名作為the restore
# name, 否則就使用變數名
        variables_to_restore = moving_average_op.variables_to_restore()
        saver = tf.train.Saver(var_list=variables_to_restore)
        
        summary_op = tf.merge_all_summaries() #建立序列化後的summary物件
#建立一個event file,用於之後寫summary物件到logdir目錄下的檔案中
        summary_writer = tf.train.SummaryWriter(logdir='./event-log-test', graph=g)
        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]   #dim為tensor型別

又因為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.batch和tf.train.shuffle_batch函式中的關鍵字tensors改成tensor_list

(7)錯誤提示“UnboundLocalError: local variable 'CONSTANT' referenced before assignment”

錯誤原因:可以參見下面這段程式碼

CONSTANT = 0  

def modifyConstant() :  

         print CONSTANT  

      CONSTANT += 1

在函式內部修改了變數CONSTANT,Python認為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