Tensorflow 或 Keras 如何处理模型权重初始化以及何时发生?
How does Tensorflow or Keras handle model weight inititialization and when does it happen?
阅读 后,我对 TensorFlow 何时初始化权重和偏置变量感到有点困惑。
根据答案,Compile 定义了 损失函数 、 优化器 和 指标 。就这些了。
由于 compile()
方法没有初始化它,这表明它发生在 fit()
方法期间 运行.
然而,问题是,在加载模型或加载权重的情况下,fit()
如何知道权重,它所呈现的,实际上是有用的,不应该被丢弃,然后分配随机值代替那些。
我们在声明层时在参数 kernel_initializer
中传递了初始化程序的类型。例如:
dense02 = tf.keras.layers.Dense(units=10,
kernel_initializer='glorot_uniform',
bias_initializer='zeros')
所以一个明显的问题是权重是在第一个 epoch 前向传递期间逐层初始化,还是在第一个 epoch 之前对所有层都进行初始化。
(我想说的是,如果模型中有 5 个 Dense 层,那么初始化是否一次发生一个层,即第一个 Dense 层被初始化,然后正向传递发生在那个层层,然后第二层被初始化,第二个密集层的正向传播发生,依此类推)
另一个方面是关于迁移学习,当在经过训练的模型之上堆叠自定义层时,经过训练的模型层具有权重,而我添加的层不会有任何有用的图层。那么 TensorFlow 怎么知道只初始化我添加的层的变量而不是弄乱传输模型的层(前提是我没有trainable=False
)
TensorFlow 或 Keras 如何处理权重初始化?
权重在创建模型时初始化(当模型中的每一层都被初始化时),即在compile()
和fit()
之前:
import tensorflow as tf
from tensorflow.keras import models, layers
inputs = layers.Input((3, ))
outputs = layers.Dense(units=10,
kernel_initializer='glorot_uniform',
bias_initializer='zeros')(inputs)
model = models.Model(inputs=inputs, outputs=outputs)
for layer in model.layers:
print("Config:\n{}\nWeights:\n{}\n".format(layer.get_config(), layer.get_weights()))
输出:
Config:
{'batch_input_shape': (None, 3), 'dtype': 'float32', 'sparse': False, 'ragged': False, 'name': 'input_1'}
Weights:
[]
Config:
{'name': 'dense', 'trainable': True, 'dtype': 'float32', 'units': 10, 'activation': 'linear', 'use_bias': True, 'kernel_initializer': {'class_name': 'GlorotUniform', 'config': {'seed': None}}, 'bias_initializer': {'class_name': 'Zeros', 'config': {}}, 'kernel_regularizer': None, 'bias_regularizer': None, 'activity_regularizer': None, 'kernel_constraint': None, 'bias_constraint': None}
Weights:
[array([[-0.60352975, 0.08275259, -0.6521113 , -0.5860774 , -0.42276743,
-0.3142944 , -0.28118378, 0.07770532, -0.5644444 , -0.47069687],
[ 0.4611913 , 0.35170448, -0.62191975, 0.5837332 , -0.3390234 ,
-0.4033073 , 0.03493106, -0.06078851, -0.53159714, 0.49872506],
[ 0.43685734, 0.6160207 , 0.01610583, -0.3673877 , -0.14144647,
-0.3792309 , 0.05478126, 0.602067 , -0.47438127, 0.36463356]],
dtype=float32), array([0., 0., 0., 0., 0., 0., 0., 0., 0., 0.], dtype=float32)]
经过更多研究后,尽管 是正确的,但让我们更深入地了解一下 TensorFlow Keras 中的初始化工作原理。
根据tf.keras.layers.Layer Doc,我们可以通过以下两种方法创建变量:
__init__(self, ...)
:定义自定义层属性,并创建不依赖于输入形状的层状态变量,使用add_weight()
build(self, input_shape)
:此方法可用于创建取决于输入形状的权重,使用 add_weight()
kb
下面的代码显示了一个具有 2 个变量的基本层的示例,该变量执行计算:y = w . x + b
:
class SimpleDense(Layer):
def __init__(self, units=32):
super(SimpleDense, self).__init__()
self.units = units
def build(self, input_shape): # Create the state of the layer (weights)
w_init = tf.random_normal_initializer()
self.w = tf.Variable(
initial_value=w_init(shape=(input_shape[-1], self.units),
dtype='float32'),
trainable=True)
b_init = tf.zeros_initializer()
self.b = tf.Variable(
initial_value=b_init(shape=(self.units,), dtype='float32'),
trainable=True)
def call(self, inputs): # Defines the computation from inputs to outputs
return tf.matmul(inputs, self.w) + self.b
# Instantiates the layer.
linear_layer = SimpleDense(4)
# This will also call `build(input_shape)` and create the weights.
y = linear_layer(tf.ones((2, 2)))
assert len(linear_layer.weights) == 2
# These weights are trainable, so they're listed in `trainable_weights`:
assert len(linear_layer.trainable_weights) == 2
上面代码中最有趣的地方是调用build方法的时候。
build()
当层(初始化后)被分配某种输入时调用,无论是实际值还是只是一个 TensorFlow placeholder.
当使用 Keras Sequential 模型时,我们向模型添加一个层,它会自动将输入占位符分配给该层并同时对其进行初始化。
因此我们看到了在调用 Keras 模型的 compile()
或 fit()
方法之前的权重。 (请注意,__call__()
将通过调用 build()
自动构建层(如果尚未构建))
关于迁移学习,当我们加载迁移模型时,我们正在加载已经构建的层,所以构建方法是当您将图层添加到您自己的模型时,不会再次调用。
换句话说,转移模型的层已经分配了输入占位符,并且在训练转移模型时已经调用了build()
方法。
有用的参考资料:
阅读
由于 compile()
方法没有初始化它,这表明它发生在 fit()
方法期间 运行.
然而,问题是,在加载模型或加载权重的情况下,fit()
如何知道权重,它所呈现的,实际上是有用的,不应该被丢弃,然后分配随机值代替那些。
我们在声明层时在参数 kernel_initializer
中传递了初始化程序的类型。例如:
dense02 = tf.keras.layers.Dense(units=10,
kernel_initializer='glorot_uniform',
bias_initializer='zeros')
所以一个明显的问题是权重是在第一个 epoch 前向传递期间逐层初始化,还是在第一个 epoch 之前对所有层都进行初始化。
(我想说的是,如果模型中有 5 个 Dense 层,那么初始化是否一次发生一个层,即第一个 Dense 层被初始化,然后正向传递发生在那个层层,然后第二层被初始化,第二个密集层的正向传播发生,依此类推)
另一个方面是关于迁移学习,当在经过训练的模型之上堆叠自定义层时,经过训练的模型层具有权重,而我添加的层不会有任何有用的图层。那么 TensorFlow 怎么知道只初始化我添加的层的变量而不是弄乱传输模型的层(前提是我没有trainable=False
)
TensorFlow 或 Keras 如何处理权重初始化?
权重在创建模型时初始化(当模型中的每一层都被初始化时),即在compile()
和fit()
之前:
import tensorflow as tf
from tensorflow.keras import models, layers
inputs = layers.Input((3, ))
outputs = layers.Dense(units=10,
kernel_initializer='glorot_uniform',
bias_initializer='zeros')(inputs)
model = models.Model(inputs=inputs, outputs=outputs)
for layer in model.layers:
print("Config:\n{}\nWeights:\n{}\n".format(layer.get_config(), layer.get_weights()))
输出:
Config:
{'batch_input_shape': (None, 3), 'dtype': 'float32', 'sparse': False, 'ragged': False, 'name': 'input_1'}
Weights:
[]
Config:
{'name': 'dense', 'trainable': True, 'dtype': 'float32', 'units': 10, 'activation': 'linear', 'use_bias': True, 'kernel_initializer': {'class_name': 'GlorotUniform', 'config': {'seed': None}}, 'bias_initializer': {'class_name': 'Zeros', 'config': {}}, 'kernel_regularizer': None, 'bias_regularizer': None, 'activity_regularizer': None, 'kernel_constraint': None, 'bias_constraint': None}
Weights:
[array([[-0.60352975, 0.08275259, -0.6521113 , -0.5860774 , -0.42276743,
-0.3142944 , -0.28118378, 0.07770532, -0.5644444 , -0.47069687],
[ 0.4611913 , 0.35170448, -0.62191975, 0.5837332 , -0.3390234 ,
-0.4033073 , 0.03493106, -0.06078851, -0.53159714, 0.49872506],
[ 0.43685734, 0.6160207 , 0.01610583, -0.3673877 , -0.14144647,
-0.3792309 , 0.05478126, 0.602067 , -0.47438127, 0.36463356]],
dtype=float32), array([0., 0., 0., 0., 0., 0., 0., 0., 0., 0.], dtype=float32)]
经过更多研究后,尽管
根据tf.keras.layers.Layer Doc,我们可以通过以下两种方法创建变量:
__init__(self, ...)
:定义自定义层属性,并创建不依赖于输入形状的层状态变量,使用add_weight()
build(self, input_shape)
:此方法可用于创建取决于输入形状的权重,使用add_weight()
kb
下面的代码显示了一个具有 2 个变量的基本层的示例,该变量执行计算:y = w . x + b
:
class SimpleDense(Layer):
def __init__(self, units=32):
super(SimpleDense, self).__init__()
self.units = units
def build(self, input_shape): # Create the state of the layer (weights)
w_init = tf.random_normal_initializer()
self.w = tf.Variable(
initial_value=w_init(shape=(input_shape[-1], self.units),
dtype='float32'),
trainable=True)
b_init = tf.zeros_initializer()
self.b = tf.Variable(
initial_value=b_init(shape=(self.units,), dtype='float32'),
trainable=True)
def call(self, inputs): # Defines the computation from inputs to outputs
return tf.matmul(inputs, self.w) + self.b
# Instantiates the layer.
linear_layer = SimpleDense(4)
# This will also call `build(input_shape)` and create the weights.
y = linear_layer(tf.ones((2, 2)))
assert len(linear_layer.weights) == 2
# These weights are trainable, so they're listed in `trainable_weights`:
assert len(linear_layer.trainable_weights) == 2
上面代码中最有趣的地方是调用build方法的时候。
build()
当层(初始化后)被分配某种输入时调用,无论是实际值还是只是一个 TensorFlow placeholder.
当使用 Keras Sequential 模型时,我们向模型添加一个层,它会自动将输入占位符分配给该层并同时对其进行初始化。
因此我们看到了在调用 Keras 模型的 compile()
或 fit()
方法之前的权重。 (请注意,__call__()
将通过调用 build()
自动构建层(如果尚未构建))
关于迁移学习,当我们加载迁移模型时,我们正在加载已经构建的层,所以构建方法是当您将图层添加到您自己的模型时,不会再次调用。
换句话说,转移模型的层已经分配了输入占位符,并且在训练转移模型时已经调用了build()
方法。
有用的参考资料: