Вопрос или проблема
Я сталкиваюсь с необычной проблемой при попытке загрузить предварительно обученные веса в свертку (Conv2D) в модели Keras. Проблема возникает, когда я включаю конвейер аугментации изображений, используя tf.keras.layers.experimental.preprocessing (например, RandomCrop, RandomFlip) перед слоем Conv2D.
Наблюдаемое поведение:
-
Без конвейера аугментации слой Conv2D корректно загружает веса, используя layer.set_weights().
-
При добавлении конвейера аугментации перед слоем Conv2D вызов layer.set_weights() вызывает ошибку, указывая на то, что слой не ожидает получения весов.
-
При проверке слоев модели (через print(model.layers)) аугментационные слои явно не отображаются, но слой Conv2D, похоже, инициализируется по-другому.
Код:
data_aug = Sequential([
RandomCrop(height=384, width=384),
RandomZoom(height_factor=0.1),
RandomRotation(factor=0.0556),
Resizing(height=224, width=224)
])
# Переменная x_unlabeled хранит латентный вектор созданного представления (h-last)
feature_extraction = Sequential()
# Применяет аугментацию перед входом
feature_extraction.add(data_aug)
# Явно добавляет входной слой
feature_extraction.add(Input(shape=(224, 224, 1)))
# Цикл для добавления сверток и загрузки весов
for k in range(n_encoder):
feature_extraction.add(Conv2D(filters[k], (filter_convolution, filter_convolution), strides=stride,
activation=activation, padding='same'))
feature_extraction.layers[-1].set_weights(autoencoder_model.layers[k + 1].get_weights())
# Добавляет слой Flatten
feature_extraction.add(Flatten())
# Добавляет плотный слой и устанавливает его веса
feature_extraction.add(Dense(hidden, activation=activation))
feature_extraction.layers[-1].set_weights(autoencoder_model.layers[k + 3].get_weights())
Ошибка:
Cell In[1], line 233, in Representations.Generate_all(self, stride, activation, filter_convolution, filters, output_activation, size_input_data, n_hidden, n_encoder, kernel_initializer, padding, epochs, verbose, batch_size, seeds_rep, hidden_rep, arch_rep, number_of_repr, const, techs)
229 for k in range(n_encoder):
230 feature_extraction.add(Conv2D(filters[k], (filter_convolution, filter_convolution), strides=stride,
231 activation=activation, padding='same'))
--> 233 feature_extraction.layers[-1].set_weights(autoencoder_model.layers[k + 1].get_weights())
235 # Добавляет слой Flatten
236 feature_extraction.add(Flatten())
File c:\users\lffon\appdata\local\programs\python\python310\lib\site-packages\keras\src\layers\layer.py:696, in Layer.set_weights(self, weights)
694 layer_weights = self.weights
695 if len(layer_weights) != len(weights):
--> 696 raise ValueError(
697 f"You called `set_weights(weights)` on layer '{self.name}' "
698 f"with a weight list of length {len(weights)}, but the layer "
699 f"was expecting {len(layer_weights)} weights."
700 )
701 for variable, value in zip(layer_weights, weights):
702 if variable.shape != value.shape:
ValueError: Вы вызвали `set_weights(weights)` на слое 'conv2d_6' с списком весов длиной 2, но слой ожидал 0 весов.
Ответ или решение
Когда вы сталкиваетесь с проблемой загрузки предобученных весов в слой Conv2D Keras после добавления конвейера аугментации изображений, это может быть вызвано тем, что предварительная обработка влияет на структуру модели. Давайте детализируем данную проблему и предложим возможные пути решения.
1. Понимание поведения модели
Когда вы добавляете слои аугментации, такие как RandomCrop
, RandomFlip
и т.д. до слоя Conv2D, вы фактически меняете архитектуру сети. Основная причина заключается в том, что после добавления слоев аугментации Keras не видит слой Conv2D как слой, который ожидает весов. Это происходит из-за того, что слои аугментации могут не иметь фиксированного веса или не могут быть совместимыми с предварительно обученными весами.
Наблюдаемое поведение:
- Без аугментации: Теперь Conv2D принимает веса без проблем.
- С аугментацией: Ошибка указывает на то, что Conv2D не ожидает веса, что, как правило, связано с тем, что Keras считает, что этот слой является неинициализированным или находится в состоянии, когда ожидаемые веса не могут быть присвоены.
2. Структура кода
В вашем коде вы добавляете слой Input
после применения аугментации. Это важно, так как порядок слоев определяет входные данные для последующих слоев. Если попытаться загрузить веса до их инициализации, может возникнуть ошибка.
Код создания модели выглядит адекватно, но есть несколько нюансов:
# Слой ввода
feature_extraction.add(Input(shape=(224, 224, 1)))
# Добавление Conv2D с установкой весов
for k in range(n_encoder):
feature_extraction.add(Conv2D(filters[k], (filter_convolution, filter_convolution), strides=stride,
activation=activation, padding='same'))
feature_extraction.layers[-1].set_weights(autoencoder_model.layers[k + 1].get_weights())
Если в момент присвоения весов слой Conv2D оказывается неинициализированным, это и приведет к ошибке.
3. Решение проблемы
-
Инициализация слоев: Следует убедиться, что все слои правильно инициализированы перед присвоением весов. Проверьте, что все режимы слоев инициализации соответствуют ожиданиям вашего предобученного механизма.
-
Отложенное присвоение весов: Попробуйте отложить присвоение весов до завершения конфигурации модели. Вы можете собрать модель полностью, а затем вызвать метод
set_weights()
на нужных слоях. Это может выглядеть так:
# Модель создается без установки весов
for k in range(n_encoder):
feature_extraction.add(Conv2D(filters[k], (filter_convolution, filter_convolution), strides=stride,
activation=activation, padding='same'))
# Теперь устанавливаем веса
for k in range(n_encoder):
feature_extraction.layers[k + 3].set_weights(autoencoder_model.layers[k + 1].get_weights()) # Обратите внимание на индексы
-
Проверка формы входных данных: Убедитесь, что выходные данные слоев аугментации имеют правильный формат и соответствуют входным данным для Conv2D.
-
Использование Functional API: Если проблемы не исчезают, рассмотрите возможность использования API Functional, который может дать больше контроля над входными и выходными данными между слоями.
Заключение
Проблемы с загрузкой весов в слое Conv2D после добавления слоев аугментации часто возникают из-за неправильной инициализации объектов в момент вызова метода set_weights()
. Убедитесь в правильной последовательности добавления слоев и их инициализации. Также может помочь переход на более современный функциональный стиль программирования в Keras. Надеюсь, это поможет вам правильно загрузить веса и избежать дальнейших ошибок.