天天看點

TensorFlow學習筆記(自用,持續更新)

TensorFlow 是一個端到端開源機器學習平台。 是開源的、基于 Python 的機器學習架構,用于幫助開發和訓練機器學習模型。

tensorflow最擅長的任務就是訓練深度神經網絡

TensorFlow采用資料流圖(data flow graphs)來計算, 首先得建立一個資料流圖, 然後再将資料(資料以張量(tensor)的形式存在)放在資料流圖中計算. 節點(Nodes)在圖中表示數學操作,圖中的線(edges)則表示在節點間互相聯系的多元資料數組, 即張量(tensor). 訓練模型時tensor會不斷的從資料流圖中的一個節點flow到另一節點, 這就是TensorFlow名字的由來.-》先建立結構,再放入資料進行計算。資料叫做tensor,在結構圖中flow

張量(Tensor): * 張量有多種. 零階張量為 純量或标量 (scalar) 也就是一個數值. 比如 [1] * 一階張量為 向量 (vector), 比如 一維的 [1, 2, 3] * 二階張量為 矩陣 (matrix)

tf.Session()

先把東西準備好,然後用session激活計算結果。相當于一個開關閘。

# method 1
sess = tf.Session()
result = sess.run(product)
print(result)
sess.close()

# method 2
with tf.Session() as sess: 
    result2 = sess.run(product) 
    print(result2)

           

如果是高版本的tf,可用tf.compat.v1.Session()。

tf.name_scope()和tf.variable_scope()

作用:

TensorFlow 可以有數以千計的節點,如此多以至于難以一下全部看到,也難以使用标準圖表工具展示。是以,通過tf.name_scope()和tf.variable_scope() 來為

op/tensor

名劃定範圍,并且用該資訊在可視化圖表中的節點上定義層級。預設情況下隻有頂層節點會顯示。簡單說,就是為了友善命名管理。

例如:

import tensorflow as tf
with tf.name_scope('hidden') as scope:
  a = tf.constant(5, name='alpha')
  W = tf.Variable(tf.random_uniform([1, 2], -1.0, 1.0), name='weights')
  b = tf.Variable(tf.zeros([1]), name='biases')
  print(a.name)
  print(W.name)
  print(b.name)
# 結果
# hidden/alpha
# hidden/weights
# hidden/biases
           

差別:

使用tf.Variable()的時候,tf.name_scope()和tf.variable_scope() 都會給 Variable 和 op 的 name屬性加上字首。

使用tf.get_variable()的時候,tf.name_scope()就不會給 tf.get_variable()建立出來的Variable加字首。但是 tf.Variable() 建立出來的就會受到 name_scope 的影響.

tf.reduce_mean()

tf.reduce_mean 函數用于計算張量tensor沿着指定的數軸(tensor的某一次元)上的平均值,主要用作降維或者計算tensor的平均值。

reduce_mean(input_tensor, # 待降維的tensor
                axis=None) # 指定的軸,如果不指定,則計算所有元素的均值;
           

例如

import tensorflow as tf
 
x = [[1,2,3],
      [1,2,3]]
 
xx = tf.cast(x,tf.float32)
 
mean_all = tf.reduce_mean(xx)
mean_0 = tf.reduce_mean(xx, axis=0)
mean_1 = tf.reduce_mean(xx, axis=1)
 
 
with tf.Session() as sess:
    m_a,m_0,m_1 = sess.run([mean_all, mean_0, mean_1])
 
print(m_a)   # output: 2.0
print(m_0)   # output: [ 1.  2.  3.]
print(m_1)   #output:  [ 2.  2.]
           

placeholder和feed_dict

    簡單說,建構graph時用placeholder占位(配置設定必要的記憶體),要run session的時候用feed_dict指派。

import tensorflow as tf
import numpy as np
 
input1 = tf.placeholder(tf.float32)
input2 = tf.placeholder(tf.float32)
 
output = tf.multiply(input1, input2)
 
with tf.Session() as sess:
    print(sess.run(output, feed_dict = {input1:[3.], input2: [4.]}))
           

tf.reduce_sum()

reduce表示降維,sum表示降維的方式。reduce_sum通過求和降維,reduce_mean通過求均值降維。

常用形式為

reduce_sum(arg1, arg2)

,參數

arg1

為要求和的資料,

arg2為求和的次元,0表示縱向,1表示橫向,省略表示對所有元素求和。

TensorFlow學習筆記(自用,持續更新)

tf.nn.sparse_softmax_cross_entropy_with_logits(logits, labels)

1.簡要說明

了解這個函數的輸入輸出,知道怎麼用它就行。這個函數的功能可以了解為對batch實作softmax+交叉熵的操作。sparse_softmax_cross_entropy_with_logits+reduce_mean是有監督學習中非常常用的loss形式。(交叉熵簡單了解就是對應真實值的那個預測值的機率的負對數值)

輸入:參數logits表示神經網絡的預測值(未經softmax),參數labels表示真實标簽值(序号形式,如果已經轉為了one-hot形式則可以用softmax_cross_entropy_with_logits()函數,本質上是一樣的)。通常logits的shape是[None, num_classes]其中None表示batch_size,num_classes表示分類的種數,例如[64, 2]表示batch_size為64、結果分為二類。

處理流程:先對logits求softmax,然後求其與labels的cross_entropy,就得到了輸出

輸出:[batch_size, ]也即batch中每個樣本的cross_entropy值。

後續處理:通常使用tf.nn.sparse_softmax_cross_entropy_with_logits的下一行會用tf.reduce_mean求該batch中所有樣本cross_entropy的平均值作為整個batch的loss。

# 使用執行個體
            self.logits = tf.matmul(out_put, output_w)+output_b 

        with tf.name_scope("loss"):
            self.loss = tf.nn.sparse_softmax_cross_entropy_with_logits(logits=self.logits+1e-10,labels=self.target)
            self.cost = tf.reduce_mean(self.loss)
           

2.具體一些

以神經網絡輸出層輸出64×2的向量為例,64就是batch_size,2是因為問題是二分類。相當于每個樣本經過神經網絡都要被分為兩類中的一類,例如第一個樣本,屬于類别一的值是0.00827,屬于類别二的值是-0.03050(不用糾結是負數,這隻是一個值),而這裡有64個樣本。經過softmax,把每個樣本屬于每個每個類别的值都歸一化),例如第一個樣本,屬于類别一的值(可以認為是機率)是0.50969,屬于類别二的值(可以認為是機率)是0.49030。經過softmax的結果還是64×2的向量。

交叉熵裡的樣本的真實label向量一般是one-hot向量,但是也可以換一種思路把它定義為one-hot向量裡的數字‘’1‘’對應的那一次元的序号。例如第一個樣本的label,用one-hot表示其實是[0,1],這裡,[0,1]裡的"1"對應的序号恰好也是1(序号從0開始,如果label是[0,0,1]則對應的序号是2),是以label用序号表示時取為1。sparse_softmax_cross_entropy_with_logits()這個函數裡其實就是用的序号表示。把每個樣本經過softmax的結果與label做交叉熵,得到一個loss,有64個樣本也就有64個loss。 簡而言之,label向量不管是one-hot表示還是序号表示,本質上都是一回事,如果用one-hot表示,用softmax_cross_entropy_with_logits()函數,如果用序号表示,用sparse_softmax_cross_entropy_with_logits()函數。(也許是序号表示簡單一點,是以函數名字前面加了個sparse)(摘自https://blog.csdn.net/ZJRN1027/article/details/80199248)

3.再次注意

這個函數的傳回值是[batch_size, ]的向量,而不是一個數。如果求交叉熵,需要再做reduce_sum對向量中所有元素求和才能得到;如果求loss,需要再做reduce_mean對向量求均值。

以下代碼說明了該函數的作用和自己先求softmax再求cross_entropy是一樣的。

# 例子說明
import tensorflow as tf
 
#our NN's output
logits=tf.constant([[1.0,2.0,3.0],[1.0,2.0,3.0],[1.0,2.0,3.0]])
#step1:do softmax
y=tf.nn.softmax(logits)
#true label
y_=tf.constant([[0.0,0.0,1.0],[0.0,0.0,1.0],[0.0,0.0,1.0]])
#step2:do cross_entropy
cross_entropy = -tf.reduce_sum(y_*tf.log(y))
#do cross_entropy just one step
cross_entropy2=tf.reduce_sum(tf.nn.softmax_cross_entropy_with_logits(logits, y_))#dont forget tf.reduce_sum()!!
 
with tf.Session() as sess:
    softmax=sess.run(y)
    c_e = sess.run(cross_entropy)
    c_e2 = sess.run(cross_entropy2)
    print("step1:softmax result=")
    print(softmax)
    print("step2:cross_entropy result=")
    print(c_e)
    print("Function(softmax_cross_entropy_with_logits) result=")
    print(c_e2)


# 輸出結果
step1:softmax result=
[[ 0.09003057  0.24472848  0.66524094]
 [ 0.09003057  0.24472848  0.66524094]
 [ 0.09003057  0.24472848  0.66524094]]
step2:cross_entropy result=
1.22282
Function(softmax_cross_entropy_with_logits) result=
1.2228
           

4.問題: 強化學習中并沒有所謂的真實值labels,那為什麼強化學習的損失函數也用該函數實作?

解答:輸入的labels是choose_action實際選擇的動作,在sparse_softmax_cross_entropy_with_logits公式裡其實就隻是起到一個讓交叉熵隻計算實際動作對應機率的負對數值的作用,沒采取的動作的labels對應0進而不計入交叉熵。例如某一step實際選擇了3号動作,則sparse_softmax_cross_entropy_with_logits傳回的就是3号動作對應預測機率的負對數值。之後再reduce_mean步驟中乘上該動作得到的未來折扣獎勵R,就得到了-(log_p * R)的loss。

簡單說,sparse_softmax_cross_entropy_with_logits傳回的就是所選動作的負對數,參數labels起到指明所選動作的作用。

與理論上根本的獎勵函數是一緻的,就是使期望獎勵最大,也就是獎勵*該獎勵對應的機率。使用對數機率是普遍做法,說法是對數形式有更高的收斂性。是以就說通了,強化學習損失函數的實作用該函數是正确的。

with tf.name_scope('loss'): 
            # 一個episode調用一次learn、傳入整個episode的資料、計算一次loss。
            # tf_acts是這個batch每一步的實際動作序号(由choose_action函數依照神經網絡輸出的機率随機選出),all_act應該是這個batch每一步對應網絡的輸出值,
            # 目标是讓total reward (log_p * R)最大,也就是讓-(log_p * R)最小。 
            # *R在reduce_mean的時候同時進行,是以sparse_softmax_cross_entropy_with_logits就是在求-log_p。也即該獎勵出現的機率的對數。
            # 該獎勵對應的是choose_action實際選擇的動作,理論上應該求神經網絡輸出該動作的機率。sparse_softmax_cross_entropy_with_logits也正是在求這個,就是機率的負對數值。

            # to maximize total reward (log_p * R) is to minimize -(log_p * R), and the tf only have minimize(loss)
            neg_log_prob = tf.nn.sparse_softmax_cross_entropy_with_logits(logits=all_act, labels=self.tf_acts)   # this is negative log of chosen action
            # all_act是神經網絡輸出的還沒轉成機率分布的各個動作對應值,self.tf_acts是實際采用的動作(互動時存儲并feed進來的),都是一個episode的資料
            # 一個episode調用一次learn,learn feed給self.train_op的是一個episode的資料也即三個清單,清單的長度即為該episode裡step的個數。step個數相當于是batch_size。計算neg_log_prob的時候是對每個step的資料計算,得到的是一個清單。

            # self.tf_vt也是一個清單,每個值表示該步的動作價值,也就是該步的未來折扣獎勵和。
            loss = tf.reduce_mean(neg_log_prob * self.tf_vt)  # 對這個episode所有step對應的loss求平均作為episode的loss。求loss時在sparse_softmax_cross_entropy_with_logits後面都會跟上reduce_mean。

        with tf.name_scope('train'):
            self.train_op = tf.train.AdamOptimizer(self.lr).minimize(loss) # 使用Adam梯度下降使loss最小
           

5.公式複習

TensorFlow學習筆記(自用,持續更新)

繼續閱讀