TensorFlow 2.0 如何从 tf.keras.layers 层获取可训练变量,例如 Conv2D 或 Dense
TensorFlow 2.0 How to get trainable variables from tf.keras.layers layers, like Conv2D or Dense
我一直在尝试从我的图层中获取可训练变量,但无法找到一种方法来使其发挥作用。所以这是我尝试过的:
我曾尝试直接访问 Dense 或 Conv2D 对象的内核和偏置属性,但无济于事。我得到的结果类型是 "Dense object has no attribute 'kernel'".
trainable_variables.append(conv_layer.kernel)
trainable_variables.append(conv_layer.bias)
同样,我试过按以下方式使用属性 "trainable_variables":
trainable_variables.extend(conv_layer.trainable_variables)
据我所知,这应该是 return 两个变量的列表,即权重和偏差变量。然而,我得到的是一个空列表。
知道如何从 TensorFlow 2.0 中的标签获取变量吗?我希望以后能够以类似于以下的方式将这些变量提供给优化器:
gradients = tape.gradient(loss, trainable_variables)
optimizer.apply_gradients(zip(gradients, trainable_variables))
编辑:
这是我当前代码的一部分,作为示例并帮助回答问题(希望它是可读的)
from tensorflow.keras.layers import Dense, Conv2D, Conv2DTranspose, Reshape, Flatten
...
class Network:
def __init__(self, params):
weights_initializer = tf.initializers.GlorotUniform(seed=params["seed"])
bias_initializer = tf.initializers.Constant(0.0)
self.trainable_variables = []
self.conv_layers = []
self.conv_activations = []
self.create_conv_layers(params, weights_initializer, bias_initializer)
self.flatten_layer = Flatten()
self.dense_layers = []
self.dense_activations = []
self.create_dense_layers(params, weights_initializer, bias_initializer)
self.output_layer = Dense(1, kernel_initializer=weights_initializer, bias_initializer=bias_initializer)
self.trainable_variables.append(self.output_layer.kernel)
self.trainable_variables.append(self.output_layer.bias)
def create_conv_layers(self, params, weight_init, bias_init):
nconv = len(params['stride'])
for i in range(nconv):
conv_layer = Conv2D(filters=params["nfilter"][i],
kernel_size=params["shape"][i], kernel_initializer=weight_init,
kernel_regularizer=spectral_norm,
use_bias=True, bias_initializer=bias_init,
strides=params["stride"][i],
padding="same", )
self.conv_layers.append(conv_layer)
self.trainable_variables.append(conv_layer.kernel)
self.trainable_variables.append(conv_layer.bias)
self.conv_activations.append(params["activation"])
def create_conv_layers(self, params, weight_init, bias_init):
nconv = len(params['stride'])
for i in range(nconv):
conv_layer = Conv2D(filters=params["nfilter"][i],
kernel_size=params["shape"][i], kernel_initializer=weight_init,
kernel_regularizer=spectral_norm,
use_bias=True, bias_initializer=bias_init,
strides=params["stride"][i],
padding="same", )
self.conv_layers.append(conv_layer)
self.trainable_variables.append(conv_layer.kernel)
self.trainable_variables.append(conv_layer.bias)
self.conv_activations.append(params["activation"])
如您所见,我正在尝试将所有可训练变量收集到一个名为 trainable_variables 的列表属性中。然而,正如我提到的,这段代码不起作用,因为我在尝试获取这些层对象的内核和偏置属性时遇到错误。
先以一个简单的模型为例,以便于解释和理解。
model = tf.keras.Sequential()
model.add(tf.keras.layers.Conv2D(1, (3, 3), activation='relu', input_shape=(32, 32, 3)))
model.add(tf.keras.layers.MaxPooling2D((2, 2)))
model.add(tf.keras.layers.Conv2D(1, (3, 3), activation='relu'))
model.add(tf.keras.layers.Flatten())
model.add(tf.keras.layers.Dense(10, activation='relu'))
model.add(tf.keras.layers.Dense(10, activation='relu'))
model.add(tf.keras.layers.Dense(3, activation='softmax'))
使用渐变带时,您传递 model.trainable_weights
其中 returns 整个模型的权重和偏差,并使用优化器应用渐变。
如果你打印model.trainable_weights
的输出,你会得到这个输出。 为了便于阅读,我删除了实际的权重和偏差。
[<tf.Variable 'conv2d/kernel:0' shape=(3, 3, 3, 1) dtype=float32, numpy=array([...], dtype=float32)>,
<tf.Variable 'conv2d/bias:0' shape=(1,) dtype=float32, numpy=array([...], dtype=float32)>,
<tf.Variable 'conv2d_1/kernel:0' shape=(3, 3, 1, 1) dtype=float32, numpy=array([...], dtype=float32)>,
<tf.Variable 'conv2d_1/bias:0' shape=(1,) dtype=float32, numpy=array([...], dtype=float32)>,
<tf.Variable 'dense/kernel:0' shape=(169, 10) dtype=float32, numpy=array([...], dtype=float32)>,
<tf.Variable 'dense/bias:0' shape=(10,) dtype=float32, numpy=array([...], dtype=float32)>,
<tf.Variable 'dense_1/kernel:0' shape=(10, 10) dtype=float32, numpy=array([...], dtype=float32)>,
<tf.Variable 'dense_1/bias:0' shape=(10,) dtype=float32, numpy=array([...], dtype=float32)>,
<tf.Variable 'dense_2/kernel:0' shape=(10, 3) dtype=float32, numpy=array([...], dtype=float32)>,
<tf.Variable 'dense_2/bias:0' shape=(3,) dtype=float32, numpy=array([...], dtype=float32)>]
如您所见,每一层的内核和偏差都以列表的形式输出。这与您传递给渐变带的输出相同。如果你只想传递一个特定的层,你可以切片列表并获得你想要训练的所需权重。
model.trainable_weights[0:2] # Get the first conv layer weights at index 0 and bias at index 1.
这将只输出第一个 conv 层的权重和偏差。
[<tf.Variable 'conv2d/kernel:0' shape=(3, 3, 3, 1) dtype=float32, numpy=array([...], dtype=float32)>,
<tf.Variable 'conv2d/bias:0' shape=(1,) dtype=float32, numpy=array([...], dtype=float32)>]
好的,所以我想我找到了问题。
在我使用给定的层对象之前,可训练变量不可用。在我 运行 我的前向传递之后,我可以检索 tf.keras.layers.Layer 对象的属性,如 trainable_variables 和权重。
然而,在我向前传递之前,我收到了一个空列表。为了让事情更清楚一点:
with tf.GradientTape() as tape:
print(dense_layers[0].trainable_variables)
self.forward_pass(X)
self.compute_loss()
print(dense_layers[0].trainable_variables)
在上面的代码中,属性 trainable_variables 在执行 self.forward_pass 之前是一个空列表。但是,紧随其后,我可以检索内核和偏置 numpy 数组。
我一直在尝试从我的图层中获取可训练变量,但无法找到一种方法来使其发挥作用。所以这是我尝试过的:
我曾尝试直接访问 Dense 或 Conv2D 对象的内核和偏置属性,但无济于事。我得到的结果类型是 "Dense object has no attribute 'kernel'".
trainable_variables.append(conv_layer.kernel)
trainable_variables.append(conv_layer.bias)
同样,我试过按以下方式使用属性 "trainable_variables":
trainable_variables.extend(conv_layer.trainable_variables)
据我所知,这应该是 return 两个变量的列表,即权重和偏差变量。然而,我得到的是一个空列表。
知道如何从 TensorFlow 2.0 中的标签获取变量吗?我希望以后能够以类似于以下的方式将这些变量提供给优化器:
gradients = tape.gradient(loss, trainable_variables)
optimizer.apply_gradients(zip(gradients, trainable_variables))
编辑: 这是我当前代码的一部分,作为示例并帮助回答问题(希望它是可读的)
from tensorflow.keras.layers import Dense, Conv2D, Conv2DTranspose, Reshape, Flatten
...
class Network:
def __init__(self, params):
weights_initializer = tf.initializers.GlorotUniform(seed=params["seed"])
bias_initializer = tf.initializers.Constant(0.0)
self.trainable_variables = []
self.conv_layers = []
self.conv_activations = []
self.create_conv_layers(params, weights_initializer, bias_initializer)
self.flatten_layer = Flatten()
self.dense_layers = []
self.dense_activations = []
self.create_dense_layers(params, weights_initializer, bias_initializer)
self.output_layer = Dense(1, kernel_initializer=weights_initializer, bias_initializer=bias_initializer)
self.trainable_variables.append(self.output_layer.kernel)
self.trainable_variables.append(self.output_layer.bias)
def create_conv_layers(self, params, weight_init, bias_init):
nconv = len(params['stride'])
for i in range(nconv):
conv_layer = Conv2D(filters=params["nfilter"][i],
kernel_size=params["shape"][i], kernel_initializer=weight_init,
kernel_regularizer=spectral_norm,
use_bias=True, bias_initializer=bias_init,
strides=params["stride"][i],
padding="same", )
self.conv_layers.append(conv_layer)
self.trainable_variables.append(conv_layer.kernel)
self.trainable_variables.append(conv_layer.bias)
self.conv_activations.append(params["activation"])
def create_conv_layers(self, params, weight_init, bias_init):
nconv = len(params['stride'])
for i in range(nconv):
conv_layer = Conv2D(filters=params["nfilter"][i],
kernel_size=params["shape"][i], kernel_initializer=weight_init,
kernel_regularizer=spectral_norm,
use_bias=True, bias_initializer=bias_init,
strides=params["stride"][i],
padding="same", )
self.conv_layers.append(conv_layer)
self.trainable_variables.append(conv_layer.kernel)
self.trainable_variables.append(conv_layer.bias)
self.conv_activations.append(params["activation"])
如您所见,我正在尝试将所有可训练变量收集到一个名为 trainable_variables 的列表属性中。然而,正如我提到的,这段代码不起作用,因为我在尝试获取这些层对象的内核和偏置属性时遇到错误。
先以一个简单的模型为例,以便于解释和理解。
model = tf.keras.Sequential()
model.add(tf.keras.layers.Conv2D(1, (3, 3), activation='relu', input_shape=(32, 32, 3)))
model.add(tf.keras.layers.MaxPooling2D((2, 2)))
model.add(tf.keras.layers.Conv2D(1, (3, 3), activation='relu'))
model.add(tf.keras.layers.Flatten())
model.add(tf.keras.layers.Dense(10, activation='relu'))
model.add(tf.keras.layers.Dense(10, activation='relu'))
model.add(tf.keras.layers.Dense(3, activation='softmax'))
使用渐变带时,您传递 model.trainable_weights
其中 returns 整个模型的权重和偏差,并使用优化器应用渐变。
如果你打印model.trainable_weights
的输出,你会得到这个输出。 为了便于阅读,我删除了实际的权重和偏差。
[<tf.Variable 'conv2d/kernel:0' shape=(3, 3, 3, 1) dtype=float32, numpy=array([...], dtype=float32)>,
<tf.Variable 'conv2d/bias:0' shape=(1,) dtype=float32, numpy=array([...], dtype=float32)>,
<tf.Variable 'conv2d_1/kernel:0' shape=(3, 3, 1, 1) dtype=float32, numpy=array([...], dtype=float32)>,
<tf.Variable 'conv2d_1/bias:0' shape=(1,) dtype=float32, numpy=array([...], dtype=float32)>,
<tf.Variable 'dense/kernel:0' shape=(169, 10) dtype=float32, numpy=array([...], dtype=float32)>,
<tf.Variable 'dense/bias:0' shape=(10,) dtype=float32, numpy=array([...], dtype=float32)>,
<tf.Variable 'dense_1/kernel:0' shape=(10, 10) dtype=float32, numpy=array([...], dtype=float32)>,
<tf.Variable 'dense_1/bias:0' shape=(10,) dtype=float32, numpy=array([...], dtype=float32)>,
<tf.Variable 'dense_2/kernel:0' shape=(10, 3) dtype=float32, numpy=array([...], dtype=float32)>,
<tf.Variable 'dense_2/bias:0' shape=(3,) dtype=float32, numpy=array([...], dtype=float32)>]
如您所见,每一层的内核和偏差都以列表的形式输出。这与您传递给渐变带的输出相同。如果你只想传递一个特定的层,你可以切片列表并获得你想要训练的所需权重。
model.trainable_weights[0:2] # Get the first conv layer weights at index 0 and bias at index 1.
这将只输出第一个 conv 层的权重和偏差。
[<tf.Variable 'conv2d/kernel:0' shape=(3, 3, 3, 1) dtype=float32, numpy=array([...], dtype=float32)>,
<tf.Variable 'conv2d/bias:0' shape=(1,) dtype=float32, numpy=array([...], dtype=float32)>]
好的,所以我想我找到了问题。
在我使用给定的层对象之前,可训练变量不可用。在我 运行 我的前向传递之后,我可以检索 tf.keras.layers.Layer 对象的属性,如 trainable_variables 和权重。
然而,在我向前传递之前,我收到了一个空列表。为了让事情更清楚一点:
with tf.GradientTape() as tape:
print(dense_layers[0].trainable_variables)
self.forward_pass(X)
self.compute_loss()
print(dense_layers[0].trainable_variables)
在上面的代码中,属性 trainable_variables 在执行 self.forward_pass 之前是一个空列表。但是,紧随其后,我可以检索内核和偏置 numpy 数组。