Tensorflow使用記錄

這個文檔作爲日常我使用tensorflow的一些小筆記。

學習資源

莫凡的python教學視頻

使用tensorboard進行網絡結構可視化

sess = tf.Session()
writer = tf.summary.FileWriter("logs/", sess.graph)  
writer.close()

在logs的上一個目錄打開powershell,運行:
tensorboard --logdir=logs --host=0.0.0.0
這樣就可以在瀏覽器中打開0.0.0.0進行網絡結構的查看了。–host也可以不加,我的chrome瀏覽器用不了默認的地址,所以這樣解決了。
如果shell端顯示了地址但是瀏覽器打不開,就換一個地址,經測試這個比較容易打開:
tensorboard --logdir=logs --host=127.0.0.1

tensor flow中的name_scope的理解與使用:

程序的運行過程中,可能訓練集與測試集會稍微改一下(不重要的)參數,那麼又希望測試集能複用訓練集的模型參數,就可以使用reuse方法,這與name_scope緊密相關。
看這段代碼,取自GANs網絡的一部分。

with tf.variable_scope('discriminator'):
    
	# 對抗網絡將真實數據與生成數據進行鑑別,這裏需要複用其參數
    D_00 = tf.layers.dense(input, 256, tf.nn.elu,name = 'latent')
    D_01 =  tf.layers.dense(D_00, 128, tf.nn.elu,name = 'latent_1')
    D_02 =  tf.layers.dense(D_01, 64, tf.nn.elu,name = 'latent_2')
    prob_real = tf.layers.dense(D_02, 1, tf.nn.sigmoid, name = 'out')
    
    # reuse the layers for generator
    D_l1 = tf.layers.dense(gen,256,tf.nn.elu,name='latent',reuse=True) #gen爲生成的數據,D_l1與D_00名字相同,並在同一個name_scope下reuse,那麼D_l1與D_l0完全相同
    D_l2 = tf.layers.dense(D_l1,128,tf.nn.elu,name='latent_1',reuse=True)
    D_l3 = tf.layers.dense(D_l2,64,tf.nn.elu,name='latent_2',reuse=True)
    prob_false = tf.layers.dense(D_l3,1,tf.nn.sigmoid,name= 'out', reuse = True)
#注,可以通過 var.name()打印查看變量的名字

LSTM的使用

看例子,單層lstm網絡

rnn_cell = tf.contrib.rnn.BasicLSTMCell(num_units=batch_size)
# 
outputs, final_state = tf.nn.dynamic_rnn(
        cell = rnn_cell,  # 選擇傳入的cell
        inputs = image,   # 傳入的數據,維度爲[time_step, input_size]
        initial_state = None, #初始化狀態
        dtype = tf.float32, #數據類型
        time_major = False,
        )
output = tf.layers.dense(inputs=outputs[:, -1, :], units=n_classes, activation=tf.nn.sigmoid)   # 取最後一個step的數據

output輸出的緯度爲[batch_size, time_step, num_units]。
也就是說它爲最後一層(如果爲多層神經網絡)一個step的輸出結果。我們想拿它輸出的最後一個step的數據,就通過output[:,-1,:]的方式。
而state是每一次最後那個step的輸出,那麼其維度爲[batch_size, num_units]。

MultiRNNCell

看下面這個例子

# 寫法一
# cell = tf.nn.rnn_cell.BasicLSTMCell(hidden_size, forget_bias=0.0, state_is_tuple=True)
# cell2 = tf.nn.rnn_cell.BasicLSTMCell(hidden_size2, forget_bias=0.0, state_is_tuple=True)
# mlstm_rnn = tf.contrib.rnn.MultiRNNCell([cell,cell2], state_is_tuple=True)
#寫法二
# 爲了簡便,導入rnn.
from tensorflow.contrib import rnn
mber_units = [128,64,128] #例如我要堆疊三層的lstm網絡
rnn_cell = [rnn.BasicLSTMCell(num_units=n) for n in number_units]
mlstm_rnn = rnn.MultiRNNCell(rnn_cell)
#
outputs, final_state = tf.nn.dynamic_rnn(
        cell = mlstm_rnn,  # 選擇傳入的cell
        inputs = image,   # 傳入的數據
        initial_state = None, #初始化狀態
        dtype = tf.float32, #數據類型
        time_major = False,
        )

out_put = tf.layers.dense(inputs=outputs[:, -1, :], units=n_classes, activation=tf.nn.sigmoid)   #

# 查看輸出的final_state,這裏final_state是一個元祖,其與網絡的層數有關.
print(final_state[0].h.shape)  #第一層的state的h state
print(final_state[1].h.shape) #第一層的state的c state
print(final_state[1].h.shape)

關於參數和輸出數據維度的理解
這是LSTM的網絡結構

  • 在圖中,每一個小方框爲一個前饋網絡層,num_units代表了這個層中隱藏的神經元的個數。那麼,h(t)的維度等於num_units, xtx_t爲 輸入向量,若其爲28維,則每一個前饋網絡層的輸入爲h(t1)h(t-1)xtx_t進行拼接,也就是156維。
  • 其實是隻有一個前饋網絡層(即圖中的小方框只有一個)的,不同的time_step共享同一套參數,並通過數據的不斷刷新而進行網絡參數的更新。12
  • 許多文章中,都是把num_units設置爲與batch_size相同的值,實際上這二者並沒有直接的聯繫。就像常規的神經網絡層的的維度可以自由設置。
  • state的輸出數據,與網絡的層數有關。看上面的代碼的最後三行。

回到tensorflow,一些基礎語法部分

後面打算利用tenorflow實現非負性矩陣填充算法(NMF),這裏先準備一些基礎的東西。

在使用梯度下降法**更新參數時,可以使用tf.assign()**方法。
看例子

import tensorflow as tf

x = tf.Variable(1)
x_new = tf.assign(x,2)  # x.assign(x+1)

sess = tf.Session()
sess.run(tf.global_variables_initializer())

sess.run(x)  #x 值爲1
sess.run(y) # x值更新爲2,同時將更新後的值賦予y
print(x.eval())

** tf的強大的求導功能**
以函數關係 y=f(x1,x2)y =f(x_1,x_2)爲例,我們想要求yy關於x1,x2x_1,x_2的偏導數,那麼直接使用函數:x1,x2=tf.gradients(xs=[x1,x2],ys=y)\partial x_1,\partial x_2 = tf.gradients(xs = [x_1,x_2], ys = y),代碼形式爲

dx1, dx2 = tf.gradients(xs=[x1,x2], ys=y)

非常的nice。
結合上面兩步,我們就可以進行參數更新了:

x1 = x1.assign( x1 - a * dx1)

tensorflow保存模型與重新加載

保存

#模型中會有一些佔位符作爲輸入
X = tf.placeholder(tf.float32, shape=[None, Col])  # 網絡輸入
Y = tf.placeholder(tf.float32,[None, Col]) # 網絡輸出
#模型的一些中間值或者輸出值

cost = tf.reduce_mean(tf.square(Y - output))  #output爲模型的一個返回值

#保存
saver = tf.compat.v1.train.Saver()
tf.add_to_collection('s_cost',cost)
sess = tf.Session()
#當模型完成了訓練之後
saver.save(sess,"save/my_model")  #會將模型保存到一個save文件夾下,名字爲my_model,實際上會生成四個這前綴的文件

文件二,模型的讀取

with tf.compat.v1.Session() as sess:
            saver = tf.compat.v1.train.import_meta_graph("save/model.meta")
            saver.restore(sess, tf.train.latest_checkpoint('save/'))
            mb_data = test[:mb_size,:] # minibatch data
            graph = tf.get_default_graph()
            # tensor_name_list = [tensor.name for tensor in graph.as_graph_def().node]# 得到當前圖中所有變量的名稱
            X = graph.get_tensor_by_name('Placeholder:0') # 網絡輸入
            Y = graph.get_tensor_by_name('Placeholder_1:0') # 網絡輸入
#            real = graph.get_operation_by_name('real')
            s_cost = graph.get_collection('s_cost')[0]
            cost= sess.run([s_cost],feed_dict={X:inputs, Y:mb_mat})

下面總結知識點

  • 保存的時候,非佔位符變量需要通過添加,如 tf.add_to_collection(‘s_cost’,cost),其中單引號的內容是它保存後的名字,在讀取的時候根據這個名字進行檢索
  • 佔位符保存的時候沒有名字,就通過如X = graph.get_tensor_by_name(‘Placeholder:0’) # 網絡輸入的方式來獲得。這個也是挺坑的,那麼,可以根據 tensor_name_list = [tensor.name for tensor in graph.as_graph_def().node] 得到當前圖中所有變量的名稱,將這個name list打印出來就可以查看一下。
  • 在讀取的時候,兩步,先通過 tf.compat.v1.train.import_meta_graph(‘模型名字.meta’),然後通過saver.restore(sess, tf.train.latest_checkpoint(‘save/’))讀取。
  • 獲取非佔位符,通過 graph.get_collection(‘s_cost’)[0],其中’s_cost’爲對應變量保存時的名字。末尾必須加[0]
  • 加載完需要的輸入輸出變量之後,就可以通過sess.run來跑模型了。

整體而言還是挺坑的,很多博客上的都不太行,自己搞了兩個小時才通。palceholder應該可以命名的,後面再說了。想去使用pytorch了==

將tensorflow的warning取消輸出

from warnings import simplefilter

simplefilter(action='ignore', category=FutureWarning)
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章