出處:http://blog.csdn.net/nnnnnnnnnnnny/article/details/70177509?reload
很有必要了解:命令式編程與聲明式編程
命令式編程(imperative programming):每個語句都按原來的意思執行,可以精確控制行爲。通常可以無縫的和主語言交互,方便的利用主語言的各類算法,工具包,bug和性能調試器。缺點是實現統一的輔助函數困和提供整體優化都很困難。比如numpy和Torch。
聲明式語言(declarative programing):用戶只需要聲明要做什麼,而具體執行則由系統完成。在真正開始計算的時候已經拿到了整個計算圖,所以我們可以做一系列優化來提升性能。實現輔助函數也容易,例如對任何計算圖都提供forward和backward函數,對計算圖進行可視化,將圖保存到硬盤和從硬盤讀取。缺點是某些功能在主語言中實現簡單,但在這裏卻經常麻煩,例如if-else語句 ;debug也不容易,例如監視一個複雜的計算圖中的某個節點的中間結果並不簡單。比如Caffe,mxnet和TensorFlow。
參考:a short introduction to mxnet design and implementation (chinese)
基本概念
TensorFlow程序一般可以分爲兩個階段,
- 構造部分,使用tensor表示數據,使用graph來表示計算任務
- 執行部分,在被稱爲Session的context裏執行圖中的計算(使用feed和fetch可以爲任意的op賦值或從中獲取數據)
計算圖
TensorFlow中每一個計算都是計算圖上的一個節點。TensorFlow會自動生成一個默認的計算圖,如果沒有特殊指定,運算會自動加入這個計算圖中。
張量
在TensorFlow中,張量並沒有真正保存數字,它只是對TensorFlow中運算結果的引用。一個張量中主要保存了三個屬性:名字(name)、維度(shape)和類型(type)。張量的命名是通過“node:src_output”
的形式來給出,node
爲節點的名稱,src_ouput
表示當前張量來自節點的第幾個輸出(編號從0開始)。當計算圖構造完成後,可以通過會話(session)來得到張量的計算結果(或者藉助eval()),如tf.Session().run(result)
。
會話
TensorFlow中的會話(session)用來執行定義好的運算。TensorFlow不會自動生成默認的會話,需要手動指定。
placeholder機制
TensorFlow提供了placeholder機制用於提供輸入數據:placeholder相當於定義了一個位置,這個位置的數據在程序運行時再使用feed_dict來指定。
爲什麼會出現這個?若每輪迭代選取的數據都要通過常量來表示,計算圖的節點就會非常多。(那爲什麼不適用variable呢?我現在還沒想清楚)
collection集合
tf.add_to_collection('losses', mse_loss)
loss = tf.get_collection('losses')
- 1
- 2
在一個計算圖中,可以通過集合(collection)來管理不同類別的資源(可以是張量、變量或者運行Tensorflow程序所需要的隊列資源等)。比如通過tf.add_to_collection
函數可以將資源加入一個或多個集合中,然後通過tf.get_collection
獲取一個集合裏面的所有資源。
TensorFlow中也自動管理了一些最常用的集合,如:tf.GraphKeys.TRAINABLE_VARIABLES是可學習變量的集合,可通過tf.trainable_variables()
獲得。
見《TensorFlow實戰Google深度學習框架》P42。
tf.constant
a = tf.constant([1.0, 2.0], name='a')
tf.constant
是一個計算,這個計算的結果爲一個張量,保存在變量a中。
張量主要的三個屬性:名字(name)、維度(shape)和類型(type)。
見《TensorFlow實戰Google深度學習框架》P43。
tf.matmul
a=tf.matmul(x, w1)
tf.matmul
實現了矩陣乘法的功能。
tf.Variable
weights = tf.Variable(tf.random_normal([2, 3], stddev=2))
w2=tf.Variable(weights.initiallized_value())
- 1
- 2
變量tf.Variable
的作用就是保存和更新神經網絡中的參數,也支持通過其他變量的初始值來初始化新的變量。tf.Variable
是一個類。
tensorflow隨機數生成函數:tf.random_normal
、tf.truncated_normal
、tf.random_uniform
、tf.random_gamma
tensorflow常數生成函數:tf.zeros
、tf.ones
、tf.fill
、tf.constant
見《TensorFlow實戰Google深度學習框架》P43。
tf.get_variable() 和 tf.variable_scope()
和tf.Variable不同的一點是,tf.get_variable
必須包含一個指定變量名稱的參數,它會根據這個名字去創建或者獲取變量。如果需要通過tf.get_variable
獲取一個已經創建的變量,需要通過tf.variable_scope
函數生成一個上下文管理器。具體說來,當tf.variable_scope
函數使用參數reuse=True生成上下文管理器時,這個上下文管理器內所有的tf.get_variable
函數會直接獲取已經創建的變量,如果變量不存在則tf.get_variable
函數將報錯;相反,如果tf.variable_scope函數使用參數reuse=False生成上下文管理器時,tf.get_variable
操作將創建新的變量,如果同名的變量已經存在,則tf.get_variable
函數將報錯。說起來有點繞,可以看下書籍《TensorFlow實戰Google深度學習框架》5.3節
變量管理。
想一下,爲什麼這麼做呢?答:這種變量管理的方式就不需要將所有變量都作爲參數傳遞到不同的函數中了,並且大大提高程序的可讀性。
除此之外,tf.variable_scope
函數也會創建一個命名空間,在命名空間內創建的變量名稱都會帶上這個命名空間名作爲前綴。tf.name_scope
也會創建一個命名空間,但和前者的區別在於此函數將會自動忽略tf.get_variable
創建的變量。
參見:《TensorFlow實戰Google深度學習框架》5.3節 變量管理 ;What’s
the difference of name scope and a variable scope in tensorflow?
tf.assign
assign(ref, value, validate_shape=None, use_locking=None, name=None)
tf.assign用來更新模型中變量的值,效果等同於 ref = value。
tf.train.ExponentialMovingAverage滑動平均
ema = tf.train.ExponentialMovingAverage(decay, num_updates) # 定義了一個滑動平均類的對象,初始化時給定了衰減率deay和控制衰減率的變量num_updates
maintain_averages_op = ema.apply([v1]) #定義一個更新變量滑動平均的操作,每次執行這個操作時參數中的變量都會被更新
sess.run(maintain_averages_op) # 更新v1的滑動平均值
v1_shadow = ema.average(v1) # 獲取滑動平均之後變量的取值
- 1
- 2
- 3
- 4
滑動平均不會改變變量本身的取值,而是會維護一個影子變量來記錄其滑動平均值。所以當需要使用這個滑動平均值時,需要明確調用average函數。
參見《TensorFlow實戰Google深度學習框架》P90
tf.contrib.layer.l2_regularizer 正則化
TensorFlow提供了tf.contrib.layer.l2_regularizer
函數,它可以返回一個函數,這個函數可以計算一個給定參數的L2正則化的值。
loss_regular = tf.contrib.layer.l2_regularizer(lambda)(weights) # lambda爲正則化項的權重,weights爲需要正則化的值
- 1
參見《TensorFlow實戰Google深度學習框架》P88
tf.train.exponential_decay 指數衰減學習率
learning_rate = tf.train.exponential_decay(LEARNING_RATE_BASE, global_step, mnist.train.num_examples/BATCH_SIZE, LEARNING_RATE_DECAY) # (基礎學習率,當前迭代輪數,衰減速度(通常爲過完一次所有訓練數據需要的迭代次數),學習率衰減係數)
train_step = tf.train.GradientDescentOptimizer(learning_rate).minimize(my_loss, global_step=global_step) # 使用指數衰減的學習率。在minimize函數中傳入global_step將自動更新global_step參數,從而使得學習率也得到相應更新。
- 1
- 2
衰減公式:learning_rate=learning_rate_base∗decay_rate(global_step/decay_steps)
參見《TensorFlow實戰Google深度學習框架》P85
placeholder機制
爲什麼會出現這個?若每輪迭代選取的數據都要通過常量來表示,計算圖的節點就會非常多。爲了避免這個問題,TensorFlow提供了placeholder機制用於提供輸入數據:placeholder相當於定義了一個位置,這個位置的數據在程序運行時再使用feed_dict來指定。
x = tf.placeholder(tf.float32, shape=(3, 2), name="input")
sess.run(y, feed_dict={x:[[0.7, 0.9], [0.1, 0.4], [0.5, 0.8]]})
- 1
- 2
tf.control_dependencies控制依賴
with g.control_dependencies([a, b, c]):
# `d` 和 `e` 將在 `a`, `b`, 和`c`執行完之後運行
d = …
e = …
- 1
- 2
- 3
- 4
在訓練神經網絡模型時,每過一遍數據既要通過反向傳播來更新神經網絡中的參數,又要更新每一個參數的滑動平均值。爲了一次完成多個操作,TensorFlow提供了tf.control_dependencies和tf.group兩種機制。下面兩行程序和train_op = tf.group(train_step,
variables_averages_op)
是等價的。
with tf.control_dependencies([train_step, variables_averages_op]):
train_op = tf.no_op(name='train')
- 1
- 2
tf.nn.sparse_softmax_cross_entropy_with_logits交叉熵函數
cross_entropy = tf.nn.sparse_softmax_cross_entropy_with_logits(y, tf.argmax(y_, 1))
- 1
當分類問題只有一個正確答案時,可以使用這個函數來加速交叉熵的計算。這個函數的第一個參數時神經網絡不包括softmax層的前向傳播結果,第二個是訓練數據的正確答案。因爲標準答案是一個長度爲10的一維數組,而該函數需要提供的是一個正確答案的數字,所以需要使用tf.argmax函數來得到正確答案對應的類別編號。
tf.train.GradientDescentOptimizer優化算法
train_step = tf.train.GradientDescentOptimizer(learning_rate).minimize(loss, global_step=global_step)
- 1
使用其來優化損失函數,注意在這個函數中會把global_step
的值加1。
tf.train.Saver()保存加載模型
保存模型:
saver = tf.train.Saver()
saver.save(sess, path_to_save, global_step=global_step)
- 1
- 2
通過變量重命名的方式加載部分模型:
variable_averages = tf.train.ExponentialMovingAverage(mnist_train.MOVING_AVERAGE_DECAY)
variables_to_restore = variable_averages.variables_to_restore() # Returns a map of names to Variables to restore
saver = tf.train.Saver(variables_to_restore) #參數可以是一個dict(即這裏的用法)也可以是一個list
saver.restore(sess, path_saved)
- 1
- 2
- 3
- 4
參考:變量:創建、初始化、保存和加載;variables_to_restore(moving_avg_variables=None)
tf.gfile.FastGFile
一個文件讀寫的封裝類。
tf.gfile.FastGFile(image_path, ‘rb’).read() # Returns the contents of a file as a string.
參考:tf.gfile.FastGFile
tf.argmax
返回沿着某個維度最大值的位置。
a = np.arange(6).reshape(2,3)
a.argmax()
#輸出:5
a.argmax(0)
#輸出:array([1, 1, 1])
a.argmax(1)
#輸出:array([2, 2])
- 1
- 2
- 3
- 4
- 5
- 6
- 7
GPU配置
gpu_options = tf.GPUOptions(visible_device_list="0,1", allow_growth=True) # 指定使用的GPU設備號;允許運行過程中tf根據需求增長擴大顯存的使用
gpu_options = tf.GPUOptions(visible_device_list="0", per_process_gpu_memory_fraction=0.4) # 指定使用的GPU設備號;指定每個可用GPU上的顯存分配比率
session_config = tf.ConfigProto(gpu_options=gpu_options, allow_soft_placement=True, log_device_placement=True) # gpu配置;如果指定的設備不存在允許tf自動分配設備;打印設備分配日誌
sess = tf.Session(config=session_config)
- 1
- 2
- 3
- 4