1. 程式人生 > >tensorflow中的共享變數(sharing variables) 最佳方式variable_scope()名稱空間來完成

tensorflow中的共享變數(sharing variables) 最佳方式variable_scope()名稱空間來完成

當訓練複雜模型時,可能經常需要共享大量的變數。例如,使用測試集來測試已訓練好的模型效能表現時,需要共享已訓練好模型的變數,如全連線層的權值。

而且我們還會遇到以下問題:

比如,我們建立了一個簡單的影象濾波器模型。如果只使用tf.Variable,那麼我們的模型可能如下

複製程式碼

def my_image_filter(input_images):
    conv1_weights = tf.Variable(tf.random_normal([5, 5, 32, 32]),
        name="conv1_weights")
    conv1_biases = tf.Variable(tf.zeros([32]), name="conv1_biases")
    conv1 = tf.nn.conv2d(input_images, conv1_weights,
        strides=[1, 1, 1, 1], padding='SAME')
    relu1 = tf.nn.relu(conv1 + conv1_biases)

    conv2_weights = tf.Variable(tf.random_normal([5, 5, 32, 32]),
        name="conv2_weights")
    conv2_biases = tf.Variable(tf.zeros([32]), name="conv2_biases")
    conv2 = tf.nn.conv2d(relu1, conv2_weights,
        strides=[1, 1, 1, 1], padding='SAME')
    return tf.nn.relu(conv2 + conv2_biases)

複製程式碼

這個模型中有4個不同的變數:conv1_weightsconv1_biasesconv2_weights, and conv2_biases

當我們想再次使用這個模型的時候出現問題了:在兩個不同的圖片image1和image2上應用以上模型,當然,我們想這兩張圖片被相同引數的同一個濾波器處理。如果我們兩次呼叫my_image_filter()的話,則會建立兩個不同的變數集,每個變數集中各4個變數。

# First call creates one set of 4 variables.
result1 = my_image_filter(image1)
# Another set of 4 variables is created in the second call.
result2 = my_image_filter(image2)

共享變數的一種常見方法是在單獨的程式碼段中建立它們,並將它們傳遞給使用它們的函式。 例如通過使用字典:

複製程式碼

variables_dict = {
    "conv1_weights": tf.Variable(tf.random_normal([5, 5, 32, 32]),
        name="conv1_weights")
    "conv1_biases": tf.Variable(tf.zeros([32]), name="conv1_biases")
    ... etc. ...
}

def my_image_filter(input_images, variables_dict):
    conv1 = tf.nn.conv2d(input_images, variables_dict["conv1_weights"],
        strides=[1, 1, 1, 1], padding='SAME')
    relu1 = tf.nn.relu(conv1 + variables_dict["conv1_biases"])

    conv2 = tf.nn.conv2d(relu1, variables_dict["conv2_weights"],
        strides=[1, 1, 1, 1], padding='SAME')
    return tf.nn.relu(conv2 + variables_dict["conv2_biases"])

# Both calls to my_image_filter() now use the same variables
result1 = my_image_filter(image1, variables_dict)
result2 = my_image_filter(image2, variables_dict)

複製程式碼

但是像上面這樣在程式碼外面建立變數很方便, 破壞了封裝

  • 構建圖形的程式碼必須記錄要建立的變數的名稱,型別和形狀。
  • 程式碼更改時,呼叫者可能必須建立更多或更少或不同的變數。

解決問題的一種方法是使用類建立一個模型,其中類負責管理所需的變數。 一個較簡便的解決方案是,使用TensorFlow提供variable scope機制,通過這個機制,可以讓我們在構建模型時輕鬆共享命名變數。

 

如何實現共享變數

tensorflow中的變數共享是通過 tf.variab_scope() 和 tf.get_variable() 來實現的

  • tf.variable_scope(<scope_name>):  管理傳遞給tf.get_variable()的names的名稱空間
  • tf.get_variable(<name>, <shape>, <initializer>): 建立或返回一個給定名字的變數

為了看下tf.get_variable()如何解決以上問題,我們在一個單獨的函式裡重構建立一個卷積的程式碼,並命名為conv_relu:

複製程式碼

def conv_relu(input, kernel_shape, bias_shape):
    # Create variable named "weights".
    weights = tf.get_variable("weights", kernel_shape,
        initializer=tf.random_normal_initializer())
    # Create variable named "biases".
    biases = tf.get_variable("biases", bias_shape,
        initializer=tf.constant_initializer(0.0))
    conv = tf.nn.conv2d(input, weights,
        strides=[1, 1, 1, 1], padding='SAME')
    return tf.nn.relu(conv + biases)

複製程式碼

此這個函式使用“weights”和“biases”命名變數。 我們希望將它用於conv1和conv2,但變數需要具有不同的名稱。 這就是tf.variable_scope()發揮作用的地方:它為各變數分配名稱空間。

複製程式碼

def my_image_filter(input_images):
    with tf.variable_scope("conv1"):
        # Variables created here will be named "conv1/weights", "conv1/biases".
        relu1 = conv_relu(input_images, [5, 5, 32, 32], [32])
    with tf.variable_scope("conv2"):
        # Variables created here will be named "conv2/weights", "conv2/biases".
        return conv_relu(relu1, [5, 5, 32, 32], [32])

複製程式碼

現在,我們來看下兩次呼叫my_image_filter()會怎樣:

result1 = my_image_filter(image1)
result2 = my_image_filter(image2)
# Raises ValueError(... conv1/weights already exists ...)

如你所見,tf.get_variable() 會檢查已存在的變數是不是意外地共享。如果你想共享它們,你需要通過如下設定reuse_variables()來指定它。