簡體   English   中英

TensorFlow 2.0 Keras 層以自定義張量作為變量

[英]TensorFlow 2.0 Keras layers with custom tensors as variables

在 TF 1.x 中,可以使用自定義變量構建層。 這是一個例子:

import numpy as np
import tensorflow as tf

def make_custom_getter(custom_variables):
    def custom_getter(getter, name, **kwargs):
        if name in custom_variables:
            variable = custom_variables[name]
        else:
            variable = getter(name, **kwargs)
        return variable
    return custom_getter

# Make a custom getter for the dense layer variables.
# Note: custom variables can result from arbitrary computation;
#       for the sake of this example, we make them just constant tensors.
custom_variables = {
    "model/dense/kernel": tf.constant(
        np.random.rand(784, 64), name="custom_kernel", dtype=tf.float32),
    "model/dense/bias": tf.constant(
        np.random.rand(64), name="custom_bias", dtype=tf.float32),
}
custom_getter = make_custom_getter(custom_variables)

# Compute hiddens using a dense layer with custom variables.
x = tf.random.normal(shape=(1, 784), name="inputs")
with tf.variable_scope("model", custom_getter=custom_getter):
    Layer = tf.layers.Dense(64)
    hiddens = Layer(x)

print(Layer.variables)

構建的密集層的打印變量將是我們在custom_variables字典中指定的自定義張量:

[<tf.Tensor 'custom_kernel:0' shape=(784, 64) dtype=float32>, <tf.Tensor 'custom_bias:0' shape=(64,) dtype=float32>]

這允許我們創建層/模型,直接使用custom_variables中提供的張量作為它們的權重,以便我們可以進一步區分層/模型的 output 相對於custom_variables可能依賴的任何張量(對於實現調制中的功能特別有用子網參數生成元學習等)。

變量作用域用於輕松將所有圖形構建嵌套在具有自定義 getter 的作用域內,並在提供的張量之上構建模型作為其參數。 由於 TF 2.0 中不再建議使用會話和變量范圍(並且所有這些低級內容都已移至tf.compat.v1 ),使用 Keras 和 TF 2.0 實現上述內容的最佳實踐是什么?

GitHub 上的相關問題。)

根據下面的評論回答

鑒於您有:

kernel = createTheKernelVarBasedOnWhatYouWant() #shape (784, 64)
bias = createTheBiasVarBasedOnWhatYouWant() #shape (64,)

Dense復制代碼,制作一個簡單的 function :

def custom_dense(x):
    inputs, kernel, bias = x

    outputs = K.dot(inputs, kernel)
    outputs = K.bias_add(outputs, bias, data_format='channels_last')
    return outputs

Lambda層中使用 function:

layer = Lambda(custom_dense)
hiddens = layer([x, kernel, bias])

警告: kernelbias必須從 Keras 層產生,或者來自kernel = Input(tensor=the_kernel_var)bias = Input(tensor=bias_var)


如果上面的警告對您不利,您始終可以使用kernel並“從外部” bias ,例如:

def custom_dense(inputs):
    outputs = K.dot(inputs, kernel) #where kernel is not part of the arguments anymore
    outputs = K.bias_add(outputs, bias, data_format='channels_last')
    return outputs

layer = Lambda(custom_dense)
hiddens = layer(x)

最后一個選項使保存/加載模型變得更加復雜。

舊答案

您可能應該使用 Keras 密集層並以標准方式設置其權重:

layer = tf.keras.layers.Dense(64, name='the_layer')
layer.set_weights([np.random.rand(784, 64), np.random.rand(64)])

如果您需要這些權重不可訓練,請在編譯 keras model 之前設置:

model.get_layer('the_layer').trainable=False

如果您想直接訪問作為張量的變量,它們是:

kernel = layer.kernel    
bias = layer.bias

還有很多其他選擇,但這取決於您的確切意圖,這在您的問題中並不清楚。

下面是一個通用解決方案,適用於 TF2 中的任意 Keras 模型。

首先,我們需要定義一個輔助 function canonical_variable_name和一個具有以下簽名的上下文管理器custom_make_variable (參見元塊庫中的實現)。

def canonical_variable_name(variable_name: str, outer_scope: str):
    """Returns the canonical variable name: `outer_scope/.../name`."""
    # ...

@contextlib.contextmanager
def custom_make_variable(
    canonical_custom_variables: Dict[str, tf.Tensor], outer_scope: str
):
    """A context manager that overrides `make_variable` with a custom function.

    When building layers, Keras uses `make_variable` function to create weights
    (kernels and biases for each layer). This function wraps `make_variable` with
    a closure that infers the canonical name of the variable being created (of the
    form `outer_scope/.../var_name`) and looks it up in the `custom_variables` dict
    that maps canonical names to tensors. The function adheres the following logic:

    * If there is a match, it does a few checks (shape, dtype, etc.) and returns
      the found tensor instead of creating a new variable.
    * If there is a match but checks fail, it throws an exception.
    * If there are no matching `custom_variables`, it calls the original
      `make_variable` utility function and returns a newly created variable.
    """
    # ...

使用這些函數,我們可以使用自定義張量作為變量創建任意 Keras 模型:

import numpy as np
import tensorflow as tf

canonical_custom_variables = {
    "model/dense/kernel": tf.constant(
        np.random.rand(784, 64), name="custom_kernel", dtype=tf.float32),
    "model/dense/bias": tf.constant(
        np.random.rand(64), name="custom_bias", dtype=tf.float32),
}

# Compute hiddens using a dense layer with custom variables.
x = tf.random.normal(shape=(1, 784), name="inputs")
with custom_make_variable(canonical_custom_variables, outer_scope="model"):
    Layer = tf.layers.Dense(64)
    hiddens = Layer(x)

print(Layer.variables)

不完全確定我是否正確理解了您的問題,但在我看來,應該可以通過自定義層keras 功能 api的組合來做您想做的事情。

自定義層允許您以與 Keras 兼容的方式構建所需的任何層,例如:

class MyDenseLayer(tf.keras.layers.Layer):
    def __init__(self, num_outputs):
        super(MyDenseLayer, self).__init__()
        self.num_outputs = num_outputs

    def build(self, input_shape):
        self.kernel = self.add_weight("kernel", 
                                      shape=[int(input_shape[-1]), 
                                             self.num_outputs],
                                      initializer='normal')

        self.bias = self.add_weight("bias", 
                                    shape=[self.num_outputs,],
                                    initializer='normal')

    def call(self, inputs):
        return tf.matmul(inputs, self.kernel) + self.bias

和功能 api 允許您訪問所述層的輸出並重用它們:

inputs = keras.Input(shape=(784,), name='img')
x1 = MyDenseLayer(64, activation='relu')(inputs)
x2 = MyDenseLayer(64, activation='relu')(x1)
outputs = MyDenseLayer(10, activation='softmax')(x2)

model = keras.Model(inputs=inputs, outputs=outputs, name='mnist_model')

這里x1x2可以連接到其他子網。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM