tensorflow視訊記憶體、載入模型、優化器(個人筆記)
在使用tensorflow做實驗的這短暫一段時間內,遇到了不少問題,把還沒忘問題寫在這裡,方便以後查閱。
1. 執行sess=tf.Session() 或 sess=tf.InteractiveSession()後發現所有GPU的視訊記憶體全部佔滿
A:這是正常現象。為了節省資源,可以如下做:
import os
os.environ["CUDA_VISIBLE_DEVICES"] = '0' #指定第幾塊gpu被該程式發現(使用)
import tensorflow as tf
config = tf.ConfigProto()
config.gpu_options.per_process_gpu_memory_fraction = 0.3 #限制使用gpu視訊記憶體的百分之幾。如果只寫這句,沒有下一句的話,當限制的視訊記憶體不能滿足你的程式需求,就會報錯OOM
config.gpu_options.allow_growth = True #允許視訊記憶體的增長。如果當前限制的視訊記憶體不夠,沒關係可以繼續增加。如果只有這一句話,tensorflow執行後視訊記憶體從最低慢慢增長。
sess = tf.Session(config=config)
#sess = tf.InteractiveSession(config=config)
但佔用了的視訊記憶體是不會自動釋放的,即使當前沒使用這麼多視訊記憶體。
2. 寫了個基本網路,訓練後儲存為model. 在該基本網路上增加若干層並利用訓練好的基本網路繼續訓練,想restore model時發生錯誤
A: 正常現象,因為 tf.train.Saver() 發現儲存的model中並不存在你新加的那些Variable,因此模型不匹配,便會報錯。這個的解決方案找了一天,也許因為查詢的關鍵字不對,百度沒有找到。最終Google 用英文搜尋才解決。看一下 tf.train.Saver() 這個類的建構函式:
__init__(
var_list=None,
reshape=False,
sharded=False,
max_to_keep=5,
keep_checkpoint_every_n_hours=10000.0,
name=None,
restore_sequentially=False ,
saver_def=None,
builder=None,
defer_build=False,
allow_empty=False,
write_version=tf.train.SaverDef.V2,
pad_step_number=False,
save_relative_paths=False,
filename=None
)
第一個var_list 的官方解釋是
說明可以人為指定哪些 Variables 可以被儲存和載入,而且是以字典或 list 的形式指定。那麼這時,我們首先要知道有哪些 Variable。
all_variables = tf.contrib.framework.get_variables_to_restre() #得到該網路中所有Variable的資訊,返回的all_variables是個list。
variables_to_restore = [] # 顧名思義
variables_not_restore = []
for v in all_variables:
if v.name.split('/')[0] != 'New_layer':
variables_to_restore.append(v)
else:
variables_not_restore.append(v)
saver = tf.train.Saver(var_list=variables_to_restore,max_to_keep=1,write_version=1)
saver.restore(sess, './model-1')
sess.run(tf.variables_initializer(var_list=variables_not_restore) #未被restore的variable也要初始化。
#tf.variables_initializer(var_list=variables_not_restore).run()
得到當前網路的所有Variables後,我需要分辨哪些是預訓練模型中有的 (variables_to_restore
),哪些是我新新增的不需要restore的(variables_not_restore
),而且因為我新新增的所有變數是在 with tf.variable_scope( 'New_layer' )
下定義的,因此變數名的第一部分就是‘New_layer’,方便識別新舊變數。之後如程式所示,順利載入預訓練模型。值得注意的是,未被 restore 的 Variable 仍然需要初始化。tf.variable_initializer(var_list)
能初始化指定的 Variable。順便一提,tf.global_variables_initializer()
是 tf.variables_initializer( tf.global_variables())
的簡化寫法,官網如是說。
3. tf.nn.rnn_cell.BasicLSTMCell( num_units, forget_bias=1.0, state_is_tuple=True, activation=None, reuse=None) 處理的是以當前資料xt和上一時刻隱含狀態ht-1為輸入的LSTM單元,然而我需要當前兩個資料xt和yt以及ht-1作為LSTM單元的輸入。
A:個人認為tensorflow應該提供了這樣的LSTM類,但是由於不熟悉tensorflow的用法,並沒有找到。無奈仿照tf.nn.rnn_cell.BasicLSTMCell()的實現自己重寫了一個有特殊要求的LSTM類。主要是過載_linear()
和__call__()
兩個函式。由於從一開始就保持了state_is_tuple=False
,因此自己實現過程中索性強制要求state_is_tuple=False
(並不推薦)。程式碼如下:
class MyLSTM(tf.contrib.rnn.RNNCell):
def __init__(self, num_units, forget_bias=1.0, state_is_tuple=True,activation=None, reuse=None):
super(MyLSTM,self).__init__(_reuse=reuse)
assert state_is_tuple == False, "state_is_tuple should be 'False' in this implement"
self._num_units = num_units
self._forget_bias = forget_bias
self._state_is_tuple = state_is_tuple
self._activation = activation or tf.tanh
def _linear(self, args, output_size, bias, bias_initializer=None, kernel_initializer=None):
# args: is list of 2D, batch x n, Tensor
total_arg_size = 0
shapes = [ a.get_shape() for a in args]
for shape in shapes:
if shape.ndims != 2:
raise ValueError("linear is expecting 2D arguments: %s" % shapes)
if shape[1].value is None:
raise ValueError("linear expects shape[1] to be provided for shape %s, "
"but saw %s" % (shape, shape[1]))
else:
total_arg_size += shape[1].value
dtype = [a.dtype for a in args][0]
scope = tf.get_variable_scope()
with tf.variable_scope(scope) as outer_scope:
weights = tf.get_variable( "kernel",shape=[total_arg_size,output_size],dtype=dtype,initializer=kernel_initializer)
if len(args) == 1:
res = tf.matmul( args[0],weights)
else:
res = tf.matmul( tf.concat(args,axis=1), weights )
if not bias:
return res
with tf.variable_scope(outer_scope) as inner_scope:
inner_scope.set_partitioner(None)
if bias_initializer is None:
bias_initializer = tf.constant_initializer(value=0.0, dtype=dtype)
biases = tf.get_variable("bias",[output_size],dtype=dtype, initializer=bias_initializer)
return tf.nn.bias_add(res, biases)
@property
def state_size(self):
return 2*self._num_units
@property
def output_size(self):
return self._num_units
def __call__(self,input1,input2,state):
"""
:param input1: `2-D` tensor with shape `[batch_size x input_size]`
:param input2: same size as input1
:param state: a `Tensor` shaped `[batch_size x 2 * self.state_size] with state_is_tuple=False
:return: new_h, concat([new_c,new_h],1)
"""
sigmoid = tf.sigmoid
c, h = tf.split( value=state, num_or_size_splits=2, axis=1)
concat = self._linear( [input1,input2,h], 4*self._num_units,True) # (batch_size, 4*self._num_units)
i, j, f, o = tf.split(value=concat, num_or_size_splits=4, axis=1)
new_c = ( c*sigmoid(f+self._forget_bias) + sigmoid(i)*self._activation(j))
new_h = self._activation(new_c) * sigmoid(o)
if self._state_is_tuple:
new_state = tf.nn.rnn_cell.LSTMStateTuple(new_c,new_h)
else:
new_state = tf.concat(values=[new_c,new_h],axis=1 )
return new_h, new_state
4. 網路不大,但是執行到train_op = tf.train.AdamOptimizer(learning_rate).minimize(tf_loss)時視訊記憶體佔用巨大。(已經設定視訊記憶體隨需要增長)
A:原本我是這樣寫的:
train_op = tf.train.AdamOptimizer(learning_rate).minimize(tf_loss)
Google後改為這樣寫:
train_op = tf.train.AdamOptimizer(learning_rate).minimize(tf_loss,aggregation_method=tf.AggregationMethod.EXPERIMENTAL_ACCUMULATE_N)
或者:
train_op = tf.train.AdamOptimizer(learning_rate).minimize(tf_loss, aggregation_method=tf.AggregationMethod.EXPERIMENTAL_TREE)
就解決了。應該是因為我在for迴圈中計算tf_loss的緣故,具體原因沒搞清楚,但很管用。