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()方法。

有用的参考资料: