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