從初識tf開始,變量這個名詞就一直都很重要,因為深度模型往往所要獲得的就是通過參數和函數對某一或某些具體事物的抽象表達。而那些未知的數據需要通過學習而獲得,在學習的過程中它們不斷變化着,最終收斂達到較好的表達能力,因此它們無疑是變量。
正如三位大牛所言:深度學習是一種多層表示學習方法,用簡單的非線性模塊構建而成,這些模塊將上一層表示轉化成更高層、更抽象的表示。
原文如下: Deep-learning methods are representation-learning methods with multiple levels of representation, obtained by composing simple but non-linear modules that each transform the representation at one level (starting with the raw input) into a representation at a higher, slightly more abstract level.
必讀文獻之一:Deep Learning
當訓練模型時,用變量來存儲和更新參數。變量包含張量 (Tensor)存放於內存的緩存區。建模時它們需要被明確地初始化,模型訓練后它們必須被存儲到磁盤。這些變量的值可在之后模型訓練和分析是被加載。
通過之前的學習,可以例舉出以下tf的函數:
var = tf.get_variable(name, shape, initializer=initializer) global_step = tf.Variable(0, trainable=False) init = tf.initialize_all_variables()#高版本tf已經舍棄該函數,改用global_variables_initializer() saver = tf.train.Saver(tf.global_variables()) initial = tf.constant(0.1, shape=shape) initial = tf.truncated_normal(shape, stddev=0.1) tf.global_variables_initializer()
上述函數都和tf的參數有關,主要包含在以下兩類中:
從變量存在的整個過程來看上述兩類:變量的創建、初始化、更新、保存和加載。
- 創建
當創建一個變量時,將一個張量
作為初始值傳入構造函數Variable()
。tf提供了一系列操作符來初始化張量,初始值是常量或是隨機值。注意,所有這些操作符都需要你指定張量的shape。變量的shape通常是固定的,但TensorFlow提供了高級的機制來重新調整其行列數。
可以創建以下類型的變量:常數、序列、隨機數。例如:
#-*-coding:utf-8-*- #創建常數變量的例子 import tensorflow as tf #常數constant tensor=tf.constant([[1,3,5],[8,0,7]]) #創建tensor值為0的變量 x = tf.zeros([3,4]) #創建tensor值為1的變量 x1 = tf.ones([3,4]) #創建shape和tensor一樣的但是值全為0的變量 y = tf.zeros_like(tensor) #創建shape和tensor一樣的但是值全為1的變量 y1 = tf.ones_like(tensor) #用8填充shape為2*3的tensor變量 z = tf.fill([2,3],8) sess = tf.Session() sess.run(tf.global_variables_initializer()) print (sess.run(x)) print (sess.run(y)) print (sess.run(tensor)) print (sess.run(x1)) print (sess.run(y1)) print (sess.run(z))
#-*-coding:utf-8-*- #創建數字序列變量的例子 import tensorflow as tf x=tf.linspace(10.0, 15.0, 3, name="linspace") y=tf.lin_space(10.0, 15.0, 3) w=tf.range(8.0, 13.0, 2.0) z=tf.range(3, -3, -2) sess = tf.Session() sess.run(tf.global_variables_initializer()) print (sess.run(x)) print (sess.run(y)) print (sess.run(w)) print (sess.run(z))
隨機常量的創建詳見tensorflow隨機張量創建
#創建隨機變量的例子 weights = tf.Variable(tf.random_normal([784, 200], stddev=0.35), name="weights")
- 初始化
變量的初始化必須在模型的其它操作運行之前先明確地完成。最簡單的方法就是添加一個給所有變量初始化的操作,並在使用模型之前首先運行那個操作。使用tf.global_variables_initializer()添加一個操作對變量做初始化。例如:
# Create two variables. weights = tf.Variable(tf.random_normal([784, 200], stddev=0.35), name="weights") biases = tf.Variable(tf.zeros([200]), name="biases") ... # Add an op to initialize the variables. init = tf.global_variables_initializer() # Later, when launching the model with tf.Session() as sess: # Run the init operation. sess.run(init) ... # Use the model ...
有時候會需要用另一個變量的初始化值給當前變量初始化。由於tf.global_variables_initializer()是並行地初始化所有變量,所以用其它變量的值初始化一個新的變量時,使用其它變量的initialized_value()
屬性。你可以直接把已初始化的值作為新變量的初始值,或者把它當做tensor計算得到一個值賦予新變量。例如:
# Create a variable with a random value. weights = tf.Variable(tf.random_normal([784, 200], stddev=0.35), name="weights") # Create another variable with the same value as 'weights'. w2 = tf.Variable(weights.initialized_value(), name="w2") # Create another variable with twice the value of 'weights' w_twice = tf.Variable(weights.initialized_value() * 0.2, name="w_twice")
assign()函數也有初始化的功能,詳見assign()函數
另外,這里還應該說明的是還有三種讀取數據的方法:Feeding、文件中讀取、加載預訓練數據,它們都屬於給變量初始化的方式。為了不至於引起混淆,必須說明的是常量也是變量,而三種讀取數據的方法,都是讀取常量的方法,但依然是初始化的一種常見方式。詳見Tensorflow數據讀取的方式
- 更新
雖然assign()函數有對變量進行更新的作用,但是此處探討的更新卻不是如此簡單。而事實上,我們不需要做什么具體的事情,因為tf是自動求導求梯度,根據代價函數自動更新參數的。這是全局參數的更新,也是tf學習的機制自動確定的。那tf如何知道哪個究竟是變量,哪個究竟又是常量呢?很簡單,tf.variable()里面有個布爾型的參數trainable,表示這個參數是不是需要學習的變量,而它默認為true,因此很容易被忽略,就這樣tf圖會把它加入到GraphKeys.TRAINABLE_VARIABLES,從而對其進行更新。
- 保存
對於訓練的變量,成功的話,都是有意義的,需要將其保存在文件里,方便以后的測試和再訓練,這就是weights文件,是必不可少的。
在cifar10項目中當然也有保存這些變量,例如:
# Create a saver. saver = tf.train.Saver(tf.global_variables()) ...... # Save the model checkpoint periodically. if step % 1000 == 0 or (step + 1) == FLAGS.max_steps: checkpoint_path = os.path.join(FLAGS.train_dir, 'model.ckpt') saver.save(sess, checkpoint_path, global_step=step)
Saver類把變量存儲在二進制文件checkpoint里,主要包含從變量名到tensor值的映射關系。
- 加載
加載變量和保存變量是正反的過程,保存變量是要把模型里的變量信息保存到weights文件里,而加載變量就是要把這些有意義的變量值從weights文件加載到模型里。
同理在cifar10項目中測試訓練的模型時加載了上述保存的變量,例如:
with tf.Session() as sess: ckpt = tf.train.get_checkpoint_state(FLAGS.checkpoint_dir) if ckpt and ckpt.model_checkpoint_path: # Restores from checkpoint saver.restore(sess, ckpt.model_checkpoint_path) # Assuming model_checkpoint_path looks something like: # /my-favorite-path/cifar10_train/model.ckpt-0, # extract global_step from it. global_step = ckpt.model_checkpoint_path.split('/')[-1].split('-')[-1] else: print('No checkpoint file found') return
如果想選擇和加載某一部分變量,則可以通過變量名索引,例如:
# Create some variables. v1 = tf.Variable(..., name="v1") v2 = tf.Variable(..., name="v2") ... # Add ops to save and restore only 'v2' using the name "my_v2" saver = tf.train.Saver({"my_v2": v2}) # Use the saver object normally after that. ...
這里my_v2就是新的變量名,而v2就是它的值。