1. 程式人生 > 其它 >tensorflow沒有這個引數_tensorflow的三種儲存格式總結-1(.ckpt)

tensorflow沒有這個引數_tensorflow的三種儲存格式總結-1(.ckpt)

技術標籤:tensorflow沒有這個引數

1.checkpoint(*.ckpt)

1.1檔案結構介紹:

---checkpoint

---model.ckpt-240000.data-00000-of-00001

---model.ckpt-240000.index

---model.ckpt-240000.meta
如圖所示,Tensorflow模型主要包括兩個方面內容:1)神經網路的結構圖graph;2)已訓練好的變數引數。

因此Tensorflow模型主要包含兩個檔案:

1)元資料圖(meta graph):

它儲存了tensorflow完整的網路圖結構。這個檔案以 *.meta為拓展名;

2)檢查點檔案(checkpoint file)

這是一個二進位制檔案,它包含權重變數,biases變數和其他變數。這個檔案以 *.ckpt 為拓展名; PS:從 0.11版本之後就不是單單一個 .ckpt檔案,除此之外還有一個 .index檔案,如下例所示:

1.mymodel.data-00000-of-00001

2.mymodel.index

3.checkpoint

其中 .data檔案是包含訓練變數的檔案; .index是描述variable中key和value的對應關係;checkpoint檔案是列出儲存的所有模型以及最近模型的相關資訊。因此,如果tensorflow版本高於0.10的話,檔案如下:

---checkpoint

---model.ckpt-240000.data-00000-of-00001

---model.ckpt-240000.index

---model.ckpt-240000.meta


1.2 使用的介紹:1.2.1 匯出ckpt檔案:

訓練完成後,我們希望把所有的變數和網路結構儲存下來,以供後面使用。在tensorflow中要儲存這些所有資訊,需使用:

tf.train.Saver()

需要注意的是,tensorflow變數的作用範圍是在一個session裡面,所以在儲存模型的時候,應該在session裡面通過save方法儲存。

import tensorflow as tf
w1 = tf.Variable(tf.random_normal(shape=[2]), name='w1')
w2 = tf.Variable(tf.random_normal(shape=[5]), name='w2')
saver = tf.train.Saver()
sess = tf.Session()
sess.run(tf.global_variables_initializer())
saver.save(sess, 'my_test_model')


如果我們希望在迭代1000次之後儲存模型,可以把當前的迭代步數傳進去:

saver.save(sess, 'my_test_model',global_step=1000)

在訓練的時候,假設每1000次就儲存一次模型,但是這些儲存的檔案中變化的僅僅是神經網路的variable,而網路結構沒有變化,沒必要重複儲存.meta檔案。所以我們可以設定只讓網路結構儲存一次:

saver.save(sess, 'my-model', global_step=step,write_meta_graph=False)

如果只想保留最新的4個模型,並希望每2個小時儲存一次,可以使用max_to_keep和keep_checkpoint_every_n_hours:

#saves a model every 2 hours and maximum 4 latest models are saved.
saver = tf.train.Saver(max_to_keep=4, keep_checkpoint_every_n_hours=2)

PS: 如果沒有在tf.train.Saver()指定任何引數,這樣表示預設儲存所有變數。如果我們不希望儲存所有變數,而只是其中的一部分,此時我們可以指點要儲存的變數或者集合:我們只需在建立tf.train.Saver的時候把一個列表或者要儲存變數的字典作為引數傳進去。

import tensorflow as tf
w1 = tf.Variable(tf.random_normal(shape=[2]), name='w1')
w2 = tf.Variable(tf.random_normal(shape=[5]), name='w2')
saver = tf.train.Saver([w1,w2])
sess = tf.Session()
sess.run(tf.global_variables_initializer())

saver.save(sess, 'my_test_model',global_step=1000)

1.2.2 匯入ckpt檔案:

1)從 .meta檔案匯入原始網路結構圖:

saver = tf.train.import_meta_graph('my_test_model-1000.meta')

載入了網路結構圖之後還需要載入變數資料。

2)載入變數

使用restore()方法恢復模型的變數引數。

with tf.Session() as sess:
new_saver = tf.train.import_meta_graph('my_test_model-1000.meta')
new_saver.restore(sess, tf.train.latest_checkpoint('./'))

在此之後, w1和w2 的tensor已經恢復:

with tf.Session() as sess: 
saver = tf.train.import_meta_graph('my-model-1000.meta')
saver.restore(sess,tf.train.latest_checkpoint('./'))
print(sess.run('w1:0'))
#Model has been restored. Above statement will print the saved value of w1.

1.2.3 從ckpt檔案恢復訓練模式

恢復任何預先訓練的模型,並用它進行inference,fine-tuning或者進一步訓練。在tensorflow中,如果有佔位符,那麼就需要將資料傳入佔位符中,但是當儲存tensorflow模型的時候,佔位符的資料是不會被儲存的(佔位符本身的變數是被儲存的)。

import tensorflow as tf
 
#Prepare to feed input, i.e. feed_dict and placeholders
w1 = tf.placeholder("float", name="w1")
w2 = tf.placeholder("float", name="w2")
b1= tf.Variable(2.0,name="bias")
feed_dict ={w1:4,w2:8}
 
#Define a test operation that we will restore
w3 = tf.add(w1,w2)
w4 = tf.multiply(w3,b1,name="op_to_restore")
sess = tf.Session()
sess.run(tf.global_variables_initializer())
 
#Create a saver object which will save all the variables
saver = tf.train.Saver()
 
#Run the operation by feeding input
print sess.run(w4,feed_dict)
#Prints 24 which is sum of (w1+w2)*b1 
 
#Now, save the graph
saver.save(sess, 'my_test_model',global_step=1000)

所以當需要恢復它,我們不僅要恢復網路結構和相關變數引數,而且還需要準備新的feed_dic(資料)傳入佔位符中。通過graph,get_tensor_by_name() 方法可以恢復所儲存的佔位符和opertor。比如下面的W1是一個佔位符,op_to_restore是一個運算元。

#How to access saved variable/Tensor/placeholders 
w1 = graph.get_tensor_by_name("w1:0")
 
## How to access saved operation
op_to_restore = graph.get_tensor_by_name("op_to_restore:0")

完整的example:
import tensorflow as tf;
import os;

model_saving_path = "./checkpoint"
model_name = 'saving_restoring';


def save():
    w1 = tf.placeholder(dtype=tf.float32, name='w1');
    w2 = tf.placeholder(dtype=tf.float32, name='w2');
    b1 = tf.Variable(2.0, name='bias');
    feed_dict = {w1:4, w2:8};

    w3 = tf.add(w1, w2)
    w4 = tf.multiply(w3, b1, name='op_to_restore');
    with tf.Session() as sess:
        sess.run(tf.global_variables_initializer())
        saver = tf.train.Saver();
        print(sess.run(w4, feed_dict));
        saver.save(sess, os.path.join(model_saving_path, model_name), global_step=1000);


def restore0():
    with tf.Session() as sess:
        saver = tf.train.import_meta_graph(
            os.path.join(model_saving_path, model_name+'-1000.meta'))
        saver.restore(sess, tf.train.latest_checkpoint(model_saving_path))

        graph = tf.get_default_graph();
        w1 = graph.get_tensor_by_name('w1:0');
        w2 = graph.get_tensor_by_name('w2:0');
        feed_dict = {w1:13.0, w2:17.0};

        op_to_restore = graph.get_tensor_by_name('op_to_restore:0');
        print(sess.run(op_to_restore, feed_dict))


def restore():
"""不能以這樣的方式恢復佔位符,會報錯:
InvalidArgumentError (see above for traceback):
 You must feed a value for placeholder tensor 'w1_1' with dtype float
因為對於一個佔位符而言,它所包含的不僅僅是佔位符變數的定義部分,
還包含資料,而tensorflow不儲存佔位符的資料部分。
應通過graph.get_tensor_by_name的方式獲取,然後在feed資料進去"""

    w1 = tf.placeholder(dtype=tf.float32, name='w1');
    w2 = tf.placeholder(dtype=tf.float32, name='w2');
    with tf.Session() as sess:
        saver = tf.train.import_meta_graph(
            os.path.join(model_saving_path, model_name+'-1000.meta'))
        saver.restore(sess, tf.train.latest_checkpoint(model_saving_path))

        graph = tf.get_default_graph();
        # w1 = graph.get_tensor_by_name('w1:0');
        # w2 = graph.get_tensor_by_name('w2:0');
        feed_dict = {w1:13.0, w2:17.0};

        op_to_restore = graph.get_tensor_by_name('op_to_restore:0');
        print(sess.run(op_to_restore, feed_dict))

save()
restore0();

1.2.4 從ckpt檔案恢復訓練模式,並修改模型結構:

如果想在原來的神經網路途中新增更加多的層,然後訓練它,在上面的例子中修改:

def restore2():
    with tf.Session() as sess:
        saver = tf.train.import_meta_graph(
            os.path.join(model_saving_path, model_name+'-1000.meta'))
        saver.restore(sess, tf.train.latest_checkpoint(model_saving_path))

        graph = tf.get_default_graph();
        w1 = graph.get_tensor_by_name('w1:0');
        w2 = graph.get_tensor_by_name('w2:0');
        feed_dict = {w1:13.0, w2:17.0};

        op_to_restore = graph.get_tensor_by_name('op_to_restore:0');
        # Add more to the current graph
        add_on_op = tf.multiply(op_to_restore, 2)
        print(sess.run(add_on_op, feed_dict))
        # This will print 120.

如果我只想恢復神經網路的一部分引數或者一部分運算元,然後利用這一部分引數或者運算元構建新的神經網路模型:我們可以使用graph.get_tensor_by_name() 方法。下面是個例子,在這裡我們使用.meta載入一個預訓練好的VGG網路,並做一些修改:

......
......
saver = tf.train.import_meta_graph('vgg.meta')
# Access the graph
graph = tf.get_default_graph()
## Prepare the feed_dict for feeding data for fine-tuning 

#Access the appropriate output for fine-tuning
fc7= graph.get_tensor_by_name('fc7:0')

#use this if you only want to change gradients of the last layer
fc7 = tf.stop_gradient(fc7) # It's an identity function
fc7_shape= fc7.get_shape().as_list()

new_outputs=2
weights = tf.Variable(tf.truncated_normal([fc7_shape[3], num_outputs], stddev=0.05))
biases = tf.Variable(tf.constant(0.05, shape=[num_outputs]))
output = tf.matmul(fc7, weights) + biases
pred = tf.nn.softmax(output)

# Now, you run this with fine-tuning data in sess.run()