1. 程式人生 > >tensorflow視訊記憶體、載入模型、優化器(個人筆記)

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的緣故,具體原因沒搞清楚,但很管用。

參考: