Как Tensorflow или Keras обрабатывают инициализацию веса модели и когда это происходит?

После прочтения ответа на этот вопрос я немного запутался, когда именно TensorFlow инициализирует переменные веса и смещения. Согласно ответам, Compile определяет функцию потерь, оптимизатор и метрики. Вот и все.

Поскольку метод compile() не инициализирует его, можно предположить, что это происходит во время выполнения метода fit().

Однако проблема в том, что в случае загрузки моделей или загрузки весов, как fit() узнать, что представленные веса действительно полезны и не должны быть выброшены, а затем назначены случайные значения вместо них.

Мы передаем тип инициализатора в аргументе kernel_initializer при объявлении слоя. Например:

dense02 = tf.keras.layers.Dense(units=10, 
                kernel_initializer='glorot_uniform',
                bias_initializer='zeros')

Таким образом, возникает очевидный вопрос: инициализируются ли веса слой за слоем во время прямого прохода первой эпохи или это происходит для всех слоев до первой эпохи.

(Я пытаюсь сказать, что если в модели имеется 5 плотных слоев, то происходит ли инициализация, скажем, слоя за раз, т.е. первый плотный слой инициализируется, затем для этого слоя происходит прямой проход, затем второй слой инициализируется, и происходит прямой проход для второго плотного слоя и так далее)

Другой аспект касается переноса обучения: при наложении пользовательских слоев поверх обученной модели слои обученной модели имеют веса, в то время как добавленные мной слои не будут иметь полезных слоев. Итак, откуда TensorFlow знать, что нужно только инициализировать переменные слоев, которые я добавил, а не испортить слои переданной модели (при условии, что у меня их нет trainable=False)

Как TensorFlow или Keras справляются с инициализацией веса?

Udacity Nanodegree Capstone Project: Классификатор пород собак
Udacity Nanodegree Capstone Project: Классификатор пород собак
Вы можете ознакомиться со скриптами проекта и данными на github .
1
0
675
2
Перейти к ответу Данный вопрос помечен как решенный

Ответы 2

Ответ принят как подходящий

Веса инициализируются при создании модели (когда инициализируется каждый слой в модели), то есть перед 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 обрабатывает веса переноса обучения и веса слоев, наложенных поверх него?

mb0850 27.12.2020 19:55

Это в основном то же самое, за исключением того, что веса загрузки базовой модели из файла после инициализации модели или загрузки всей модели из файла

Matrix Adventurer 28.12.2020 02:00

Проведя небольшое исследование, несмотря на то, что Ответ Mr. For Example верен, давайте немного углубимся в то, как работает инициализация в TensorFlow Keras.

Согласно tf.keras.layers.Layer Doc, мы можем создавать переменные следующими двумя способами:

  • __init__(self, ...): определяет пользовательские атрибуты слоя и создает переменную состояния слоя, которая не зависит от входных форм, с помощью add_weight()
  • build(self, input_shape): этот метод можно использовать для создания весов, которые зависят от формы (форм) входных данных, используя add_weight() кб

В приведенном ниже коде показан пример базового слоя с двумя переменными, которые выполняют вычисления: 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() вызывается, когда слою (после его инициализации) присваивается какой-то ввод, будь то фактические значения или просто заполнитель TensorFlow.

При использовании модели Keras Sequential мы добавляем слой в модель, он автоматически назначает входной заполнитель слою и одновременно инициализирует его.

Таким образом, мы видим веса перед вызовом compile() или fit() методов модели Кераса. (Обратите внимание, что __call__() автоматически создаст слой (если он еще не создан), вызвав build())

Что касается трансферного обучения, когда мы загружаем переданную модель, мы загружаем уже построенные слои, поэтому метод сборки не вызывается снова, когда вы добавляете слои в свою собственную модель.

Другими словами, слоям переданной модели уже был назначен входной заполнитель, и метод build() уже вызывался при обучении переданной модели.

Полезные ссылки:

Другие вопросы по теме