1. 程式人生 > 實用技巧 >TensorFlow 筆記 ——1 —— GraphKeys,等待補充

TensorFlow 筆記 ——1 —— GraphKeys,等待補充

https://tensorflow.google.cn/versions/r1.15/api_docs/python/tf/GraphKeys?hl=zh_cn

Class GraphKeys

用於graph collections的標準名稱

別名:

  • Classtf.compat.v1.GraphKeys

標準庫使用各種眾所周知的名稱來收集和檢索與圖關聯的值。例如,如果指定為none,tf.Optimizer子類預設優化在tf.GraphKeys.TRAINABLE_VARIABLES下收集的變數,但是也可以傳遞顯式的變數列表。

所以這個類下面的變數就是各種collections的keys值,通過這些值為String變數的名稱,能夠通過get_collection()方法來得到對應的值

tf.get_collection

Graph.get_collection()的封裝,使用預設graph

tf.get_collection(
    key,
    scope=None
)

引數:

  • key: collection的key值。例如,GraphKeys類包含許多集合的標準名稱。
  • scope:(Optional):如果提供了此選項,則對結果列表進行篩選,以只包含名稱屬性使用re.match匹配的項。如果提供了scope值,並且choice或re.match表示沒有特殊標記的作用域通過字首篩選,則不返回沒有name屬性的項。

返回:

具有給定name的集合中的值列表,或者如果沒有向該集合中新增值,則為空列表。該列表按收集值的順序包含值。

定義瞭如下的標準keys:

  • GLOBAL_VARIABLES:變數物件的預設集合,跨分散式環境共享(模型變數(model variable)是其中的子集)。更多細節請參見tf.compat.v1.global_variables。通常,所有TRAINABLE_VARIABLES變數都在MODEL_VARIABLES中,而所有MODEL_VARIABLES變數都在GLOBAL_VARIABLES中。
  • LOCAL_VARIABLES:位於每臺機器區域性的變數物件的子集。通常用於臨時變數,如計數器。注意:使用tf.contrib.framework.local_variable將其新增到此集合中。
  • MODEL_VARIABLES:模型中用於推理(前向傳播)的變數物件的子集。注意:使用tf.contrib.framework.model_variable將其新增到這個集合中。
  • TRAINABLE_VARIABLES:將由優化器訓練的變數物件的子集。更多細節請參見tf.compat.v1.trainable_variables。
  • SUMMARIES:在graph中建立的summary張量物件。更多細節見tf.compat.v1.summary.merge_all。
  • QUEUE_RUNNERS:用於為計算生成輸入的QueueRunner物件。參見tf.compat.v1.train.start_queue_runners瞭解更多細節。
  • MOVING_AVERAGE_VARIABLES:保持移動平均值的可變物件的子集。更多細節請參見tf.compat.v1.moving_average_variables。
  • REGULARIZATION_LOSSES:在graph構造過程中收集的正則化損失。

還定義了以下標準keys,但是它們的集合不會像其他的那樣自動填充,就是你可以手動使用add_to_collection()手動填充:

  • WEIGHTS
  • BIASES
  • ACTIVATIONS

tf.add_to_collection

Graph.add_to_collection()的封裝,其使用了預設graph

別名:

  • tf.compat.v1.add_to_collection
tf.add_to_collection(
    name,
    value
)

根據給定的name值將value值儲存在對應的collection中

引數:

  • name:集合collection的鍵key。例如,GraphKeys類中包含的許多集合的標準名稱。
  • value:要新增到該collection的值

tf.add_to_collections

Graph.add_to_collections()的封裝,其使用了預設graph

別名:

  • tf.compat.v1.add_to_collections
tf.add_to_collections(
    names,
    value
)

將值儲存在由name給出的集合中。

注意,collections不是集合,因此可以多次向collection新增值。此函式確保忽略名稱中的重複項,但它不會檢查names中任何collections中value的預先存在的成員關係。

names可以是任何可迭代的,但如果names是字串,則將其視為單個集合名稱。

引數:

  • names:集合collection的鍵keys。例如,GraphKeys類中包含的許多集合的標準名稱。
  • value:要新增到該collection的值

其他的標準名稱如下:

  • ACTIVATIONS = 'activations'
  • ASSET_FILEPATHS = 'asset_filepaths'
  • BIASES = 'biases'
  • CONCATENATED_VARIABLES = 'concatenated_variables'
  • COND_CONTEXT = 'cond_context'
  • EVAL_STEP = 'eval_step'
  • GLOBAL_STEP = 'global_step'
  • GLOBAL_VARIABLES = 'variables'
  • INIT_OP = 'init_op'
  • LOCAL_INIT_OP = 'local_init_op'
  • LOCAL_RESOURCES = 'local_resources'
  • LOCAL_VARIABLES = 'local_variables'
  • LOSSES = 'losses'
  • METRIC_VARIABLES = 'metric_variables'
  • MODEL_VARIABLES = 'model_variables'
  • MOVING_AVERAGE_VARIABLES = 'moving_average_variables'
  • QUEUE_RUNNERS = 'queue_runners'
  • READY_FOR_LOCAL_INIT_OP = 'ready_for_local_init_op'
  • READY_OP = 'ready_op'
  • REGULARIZATION_LOSSES = 'regularization_losses'
  • RESOURCES = 'resources'
  • SAVEABLE_OBJECTS = 'saveable_objects'
  • SAVERS = 'savers'
  • SUMMARIES = 'summaries'
  • SUMMARY_OP = 'summary_op'
  • TABLE_INITIALIZERS = 'table_initializer'
  • TRAINABLE_RESOURCE_VARIABLES = 'trainable_resource_variables'
  • TRAINABLE_VARIABLES = 'trainable_variables'
  • TRAIN_OP = 'train_op'
  • UPDATE_OPS = 'update_ops'
  • VARIABLES = 'variables'
  • WEIGHTS = 'weights'
  • WHILE_CONTEXT = 'while_context'

下面舉例說明幾個常用的:

1. tf.GraphKeys.GLOBAL_VARIABLES

1) tf.global_variables

別名:

  • tf.compat.v1.global_variables
tf.global_variables(scope=None)

全域性變數是分散式環境中跨機器共享的變數。Variable()建構函式或get_variable()函式自動向Graph集合GraphKeys.GLOBAL_VARIABLES中新增新變數。這個方便的函式tf.global_variables()返回該集合的內容。

區域性變數是全域性變數的替代品。看到tf.compat.v1.local_variables

引數:

  • scope : (optional)一個字串。如果提供了,則對結果列表進行篩選,以使用re.match返回只包含名稱屬性與作用域匹配的項。如果提供了作用域,則不會返回沒有name屬性的項。match的選擇意味著沒有特殊標記的範圍通過字首進行篩選。

返回:

  • 變數物件列表

我們熟悉的tf.global_variables_initializer()就是初始化這個集合內的Variables。

2) tf.local_variables

別名:

  • tf.compat.v1.local_variables
tf.local_variables(scope=None)

區域性變數——每個程序變數,通常不儲存/恢復到checkpoint,用於臨時或中間值。例如,它們可以用作度量計算的計數器,或者機器讀取資料的epoch數。函式的作用是:將新變數自動新增到GraphKeys.LOCAL_VARIABLES中。這個方便的函式返回該集合的內容。

區域性變數的替代方法是全域性變數。看到tf.compat.v1.global_variables

引數:

  • scope(optional):一個字串。如果提供了,則對結果列表進行篩選,以使用re.match返回只包含名稱屬性與作用域匹配的項。如果提供了作用域,則不會返回沒有name屬性的項。match的選擇意味著沒有特殊標記的範圍通過字首進行篩選。

返回:

  • 區域性變數物件列表

例子:

import tensorflow as tf
sess = tf.Session()

#這裡沒有指定collections引數的值,則collections=None,等價於 collection=[tf.GraphKeys.GLOBAL_VARIABLES]
a = tf.get_variable("a", [3,112,112])
b = tf.get_variable("b", [64])
print("a is ", a)
print("b is  ", b)

返回:

a is  <tf.Variable 'a:0' shape=(3, 112, 112) dtype=float32_ref>
b is   <tf.Variable 'b:0' shape=(64,) dtype=float32_ref>

可見生成了兩個變數a和b,名字分別為'a:0'和'b:0'

print("tf.GraphKeys.GLOBAL_VARIABLES = ", tf.GraphKeys.GLOBAL_VARIABLES)
global_variables_list = tf.get_collection(tf.GraphKeys.GLOBAL_VARIABLES)
print("global_variables_list is ", global_variables_list)

返回:

tf.GraphKeys.GLOBAL_VARIABLES =  variables
global_variables_list is  [<tf.Variable 'a:0' shape=(3, 112, 112) dtype=float32_ref>, <tf.Variable 'b:0' shape=(64,) dtype=float32_ref>]

可見tf.GraphKeys.GLOBAL_VARIABLES對應的字串名稱為"variables",且其對應的collections中果然有a和b兩個變數

使用自定義的collections

c = tf.get_variable("c", [10], collections=["my_collections"])
d = tf.get_variable("d", [20], collections=["my_collections"])

my_variables_list = tf.get_collection("my_collections")
print("my_variables_list is ", my_variables_list)

返回:

my_variables_list is  [<tf.Variable 'c:0' shape=(10,) dtype=float32_ref>, <tf.Variable 'd:0' shape=(20,) dtype=float32_ref>]

tf.GraphKeys.REGULARIZATION_LOSSES

在使用tf.get_variable()時如果使用的了引數regularizer指定使用的正則化函式,則將新建立的變數應用正則化後的結果將新增到tf.GraphKeys.REGULARIZATION_LOSSES集合中,可用於正則化。

其實就是損失中添加了正則化項,輸入即這些變數權重weight值

接著上面的例子:

weight_decay = 0.1
l2_reg = tf.contrib.layers.l2_regularizer(weight_decay)
tmp = tf.constant([0,1,2,3], dtype=tf.float32)
k = tf.get_variable('k', regularizer=l2_reg, initializer=tmp)
global_variables_list = tf.get_collection("variables")
print("global_variables_list is ", global_variables_list)

#regularizer定義會將k加入REGULARIZATION_LOSSES集合
regular_variables_list = tf.get_collection(tf.GraphKeys.REGULARIZATION_LOSSES)
print("regular_variables_list is ", regular_variables_list)

with tf.Session() as sess:
    sess.run(tf.global_variables_initializer())
    print(sess.run(k))
    l2_loss = tf.add_n(regular_variables_list)#實現一個列表的元素的相加
    print("loss is ", sess.run(l2_loss))

返回:

global_variables_list is  [<tf.Variable 'a:0' shape=(3, 112, 112) dtype=float32_ref>, <tf.Variable 'b:0' shape=(64,) dtype=float32_ref>, <tf.Variable 'k:0' shape=(4,) dtype=float32_ref>]
regular_variables_list is  [<tf.Tensor 'k/Regularizer/l2_regularizer:0' shape=() dtype=float32>]
[0. 1. 2. 3.]
loss is  0.7

L2正則化的操作等價於:

tf.reduce_sum(a*a)*weight_decay/2 = 0.1*(0*0+1*1+2*2+3*3)/2=0.7

如果有多個變數都定義了regularizations引數,則:

weight_decay = 0.1
l2_reg = tf.contrib.layers.l2_regularizer(weight_decay)
tmp = tf.constant([0,1,2,3], dtype=tf.float32)
tmp2 = tf.constant([1,2,3,4], dtype=tf.float32)

k = tf.get_variable('k', regularizer=l2_reg, initializer=tmp)
k2 = tf.get_variable('k2', regularizer=l2_reg, initializer=tmp2)

global_variables_list = tf.get_collection("variables")
print("global_variables_list is ", global_variables_list)

#regularizer定義會將k加入REGULARIZATION_LOSSES集合
regular_variables_list = tf.get_collection(tf.GraphKeys.REGULARIZATION_LOSSES)
print("regular_variables_list is ", regular_variables_list)

with tf.Session() as sess:
    sess.run(tf.global_variables_initializer())
    l2_loss = tf.add_n(regular_variables_list) #實現一個列表的元素的相加
    print("loss is ", sess.run(l2_loss))

返回:

global_variables_list is  [<tf.Variable 'a:0' shape=(3, 112, 112) dtype=float32_ref>, <tf.Variable 'b:0' shape=(64,) dtype=float32_ref>, <tf.Variable 'k:0' shape=(4,) dtype=float32_ref>, <tf.Variable 'k2:0' shape=(4,) dtype=float32_ref>]
regular_variables_list is  [<tf.Tensor 'k/Regularizer/l2_regularizer:0' shape=() dtype=float32>, <tf.Tensor 'k2/Regularizer/l2_regularizer:0' shape=() dtype=float32>]
loss is  2.2

L2正則化的操作等價於:

tf.reduce_sum(k*k)*weight_decay/2 = 0.1*(0*0+1*1+2*2+3*3)/2=0.7
tf.reduce_sum(k2*k2)*weight_decay/2 = 0.1*(1*1+2*2+3*3+4*4)/2=1.5

所以:

l2_loss = tf.add_n([0.7, 1.5]) = 2.2

tf.GraphKeys.UPDATE_OPS

用來將一些在執行過程中需要更新,但是有不是隨著梯度後向傳播更新的引數新增到該collection中,然後用於更新引數

比如AM_softmax實現中:

def diam_softmax(prelogits, label, num_classes,
                    scale='auto', m=1.0, alpha=0.5, reuse=None):
    ''' Implementation of DIAM-Softmax, AM-Softmax with Dynamic Weight Imprinting (DWI), proposed in:
            Y. Shi and A. K. Jain. DocFace+: ID Document to Selfie Matching. arXiv:1809.05620, 2018.
        The weights in the DIAM-Softmax are dynamically updated using the mean features of training samples.
    '''
    num_features = prelogits.shape[1].value
    batch_size = tf.shape(prelogits)[0]
    with tf.variable_scope('AM-Softmax', reuse=reuse):
        weights = tf.get_variable('weights', shape=(num_classes, num_features),
                initializer=slim.xavier_initializer(),
                trainable=False,
                dtype=tf.float32)
        _scale = tf.get_variable('_scale', shape=(),
                regularizer=slim.l2_regularizer(1e-2),
                initializer=tf.constant_initializer(0.0),
                trainable=True,
                dtype=tf.float32)

        # Normalizing the vecotors
        prelogits_normed = tf.nn.l2_normalize(prelogits, dim=1)
        weights_normed = tf.nn.l2_normalize(weights, dim=1)

        # Label and logits between batch and examplars
        label_mat_glob = tf.one_hot(label, num_classes, dtype=tf.float32)
        label_mask_pos_glob = tf.cast(label_mat_glob, tf.bool) #將0轉成False,1轉成True,只有對應的那個類是True,其他類對應為False
        label_mask_neg_glob = tf.logical_not(label_mask_pos_glob) #取反操作,其他類為True

        logits_glob = tf.matmul(prelogits_normed, tf.transpose(weights_normed))
        # logits_glob = -0.5 * euclidean_distance(prelogits_normed, tf.transpose(weights_normed))
        logits_pos_glob = tf.boolean_mask(logits_glob, label_mask_pos_glob)
        logits_neg_glob = tf.boolean_mask(logits_glob, label_mask_neg_glob)

        logits_pos = logits_pos_glob
        logits_neg = logits_neg_glob

        if scale == 'auto':
            # Automatic learned scale
            scale = tf.log(tf.exp(0.0) + tf.exp(_scale))
        else:
            # Assigned scale value
            assert type(scale) == float

        # Losses
        _logits_pos = tf.reshape(logits_pos, [batch_size, -1])
        _logits_neg = tf.reshape(logits_neg, [batch_size, -1])

        _logits_pos = _logits_pos * scale
        _logits_neg = _logits_neg * scale
        _logits_neg = tf.reduce_logsumexp(_logits_neg, axis=1)[:,None]

        loss_ = tf.nn.softplus(m + _logits_neg - _logits_pos)
        loss = tf.reduce_mean(loss_, name='diam_softmax')

        # Dynamic weight imprinting
        # We follow the CenterLoss to update the weights, which is equivalent to
        # imprinting the mean features
        # 如temp = [1,11,21,31,41,51,61], indice=[0,3,5]
        # tf.gather(temp, indice)返回[1,31,51]
        weights_batch = tf.gather(weights, label) #根據label指向的類去得到對應的weight
        diff_weights = weights_batch - prelogits_normed
        # x=[1, 1, 2, 4, 4, 4, 7, 8, 8]
        # y, idx, count = unique_with_counts(x)
        # y ==> [1, 2, 4, 7, 8]
        # idx ==> [0, 0, 1, 2, 2, 2, 3, 4, 4]
        # count ==> [2, 1, 3, 1, 2]
        unique_label, unique_idx, unique_count = tf.unique_with_counts(label)
        appear_times = tf.gather(unique_count, unique_idx)
        appear_times = tf.reshape(appear_times, [-1, 1])
        diff_weights = diff_weights / tf.cast(appear_times, tf.float32)
        diff_weights = alpha * diff_weights
        #將weights中特定位置label的數與diff_weights對應的值分別進行減法運算
        #沒指定的位置值不變,來更新在mini_batch中出現的類的weight
        weights_update_op = tf.scatter_sub(weights, label, diff_weights)#將weights中特定位置label的數分別與diff_weights進行減法運算
        #tf.control_dependencies()此函式指定某些操作執行的依賴關係
        #即tf.assign()操作要在tf.control_dependencies([weights_update_op])指定的weights_update_op操作後才能執行
        with tf.control_dependencies([weights_update_op]): #weight權值通過weights_update_op操作更新後才執行下面的賦值操作
            # 之後sess.run(weights_update_op)後weights的值才變
            weights_update_op = tf.assign(weights, tf.nn.l2_normalize(weights,dim=1)) #將weights歸一化後的值賦值給weights,返回的結果就是引數中歸一化的weight
        tf.add_to_collection(tf.GraphKeys.UPDATE_OPS, weights_update_op) #將元素weights_update_op新增到列表tf.GraphKeys.UPDATE_OPS中
        
        return loss

這樣後面通過:

update_ops = tf.get_collection(tf.GraphKeys.UPDATE_OPS)
sess.run([update_ops])

進行更新

tf.GraphKeys.TRAINABLE_VARIABLES

由優化器Optimizer訓練的變數物件的子集

使用tf.get_variable()和tf.Variable()宣告的變數(即trainable=True,預設就為True)就會預設加入該子集中