Tensorflow keras: проблема с загрузкой весов оптимизатора

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

Сначала я создаю эту новую модель

  input_tensor = Input(shape=train_generator.image_shape)

  base_model = applications.ResNet152(weights='imagenet', include_top=False, input_tensor=input_tensor)

  for layer in base_model.layers[:]:
    layer.trainable = False 

  x = Flatten()(base_model.output)
  x = Dense(1024, kernel_regularizer=tf.keras.regularizers.L2(l2=0.01), 
          kernel_initializer=tf.keras.initializers.HeNormal(), kernel_constraint=tf.keras.constraints.UnitNorm(axis=0))(x)
  x = LeakyReLU()(x)
  x = BatchNormalization()(x)
  x = Dropout(rate=0.1)(x)
  x = Dense(512, kernel_regularizer=tf.keras.regularizers.L2(l2=0.01), 
          kernel_initializer=tf.keras.initializers.HeNormal(), kernel_constraint=tf.keras.constraints.UnitNorm(axis=0))(x)
  x = LeakyReLU()(x)
  x = BatchNormalization()(x)
  
  predictions = Dense(num_classes, activation= 'softmax')(x)
  model = Model(inputs = base_model.input, outputs = predictions)

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

opt = tfa.optimizers.LazyAdam(lr=0.000074)

model.compile(
    loss='sparse_categorical_crossentropy',
    optimizer=opt,
    metrics=['accuracy']
    )

dummy_input = tf.random.uniform([32, 224, 224, 3]) 
dummy_label = tf.random.uniform([32,]) 
hist = model.fit(dummy_input, dummy_label)

Затем я загружаю веса для базовой модели:

base_model.load_weights('/content/drive/MyDrive/MODELS_SAVED/model_RESNET152/model_weights2.h5', by_name=True)

Затем я загружаю веса для оптимизатора:

import pickle
with open("/content/drive/MyDrive/weight_values2optimizer.pkl", "rb") as f: 
  weights = pickle.load(f) 
opt = model.optimizer.set_weights(weights) 

Это приводит к следующей ошибке:

ValueError: You called `set_weights(weights)` on optimizer LazyAdam 
with a  weight list of length 1245, 
but the optimizer was expecting 13 weights. 
Provided weights: [63504, array([[[[ 0.00000000e+00, -5.74126025e-04...

У кого-нибудь есть идеи, как это решить?

Если у вас есть решение с Адамом вместо LazyAdam, это тоже нормально (я понятия не имею, будет ли это иметь значение).

редактировать: Я пробовал много новых вещей за последние пару дней, но ничего не работает. Вот весь код, на котором я сейчас стою. Он включает в себя как часть, где я сохраняю, так и часть, где я загружаю.

import tarfile
my_tar2 = tarfile.open('test.tgz')
my_tar2.extractall('test') # specify which folder to extract to
my_tar2.close()

import zipfile
with zipfile.ZipFile("/content/tot_train_bremoved2.zip", 'r') as zip_ref:
    zip_ref.extractall("/content/train/")

import pandas as pd   

train_info = pd.read_csv("/content/drive/MyDrive/train_info.csv")
test_info = pd.read_csv("/content/drive/MyDrive/test_info.csv")
train_folder = "/content/train"
test_folder = "/content/test/test"

import tensorflow as tf
import tensorflow.keras as keras

from keras.layers import Input, Lambda, Dense, Flatten, BatchNormalization, Dropout, PReLU, GlobalAveragePooling2D, LeakyReLU, MaxPooling2D
from keras.models import Model
from tensorflow.keras.applications.resnet_v2 import ResNet152V2, preprocess_input
from keras import applications

from keras.preprocessing import image
from keras.preprocessing.image import ImageDataGenerator
from keras.losses import sparse_categorical_crossentropy

from keras.callbacks import ReduceLROnPlateau, ModelCheckpoint, EarlyStopping, TensorBoard

import tensorflow_addons as tfa

from sklearn.metrics import confusion_matrix
import numpy as np
import matplotlib.pyplot as plt

num_classes = 423
epochs = 20
batch_size = 32
img_height = 224
img_width = 224
IMAGE_SIZE = [img_height, img_width]

_train_generator = ImageDataGenerator(
        rotation_range=180,
        zoom_range=0.2,
        width_shift_range=0.2,
        height_shift_range=0.2,
        shear_range=0.3,
        horizontal_flip=True,
        vertical_flip=True,
        preprocessing_function=preprocess_input)


_val_generator = ImageDataGenerator(
        preprocessing_function=preprocess_input)

train_generator = _train_generator.flow_from_dataframe(dataframe = train_info, 
directory = train_folder, x_col = "filename", 
y_col = "artist", seed = 42,
batch_size = batch_size, shuffle = True, 
class_mode = "sparse", target_size = IMAGE_SIZE)

valid_generator = _val_generator.flow_from_dataframe(dataframe = test_info, 
directory = test_folder, x_col = "filename", 
y_col = "artist", seed = 42,
batch_size = batch_size, shuffle = True, 
class_mode = "sparse", target_size = IMAGE_SIZE)

def get_uncompiled_model():
   
  input_tensor = Input(shape=train_generator.image_shape)

  base_model = applications.ResNet152(weights='imagenet', include_top=False, input_tensor=input_tensor)

  for layer in base_model.layers[:]:
    layer.trainable = True

  x = Flatten()(base_model.output)
  
  predictions = Dense(num_classes, activation= 'softmax')(x)
  model = Model(inputs = base_model.input, outputs = predictions)

  return model

opt = keras.optimizers.Adam(lr=0.000074)

def get_compiled_model():
    model = get_uncompiled_model()
    model.compile(
    loss='sparse_categorical_crossentropy',
    optimizer=opt,
    metrics=['accuracy']
    )
    return model

earlyStopping = EarlyStopping(monitor='val_loss', patience=5, verbose=0, mode='min')

reduce_lr = ReduceLROnPlateau(monitor='val_loss', factor=0.5, patience=2, verbose=1, min_delta=1e-4, mode='min')

model = get_compiled_model()

from PIL import ImageFile
ImageFile.LOAD_TRUNCATED_IMAGES = True

model.fit(
  train_generator,
  validation_data=valid_generator,
  epochs=epochs,
  verbose = 1,
  steps_per_epoch=len_train // batch_size,
  validation_steps=len_test // batch_size,
  callbacks=[earlyStopping, reduce_lr]
)

import keras.backend as K
import pickle

model.save_weights('/content/drive/MyDrive/MODELS_SAVED/model_RESNET152/model_weights5.h5')
symbolic_weights = getattr(model.optimizer, 'weights')
weight_values = K.batch_get_value(symbolic_weights)
with open('/content/drive/MyDrive/MODELS_SAVED/optimizer3.pkl', 'wb') as f:
    pickle.dump(weight_values, f)

#Here i am building the new model and its from here i am having problems

  input_tensor = Input(shape=train_generator.image_shape)

  base_model = applications.ResNet152(weights='imagenet', include_top=False, input_tensor=input_tensor)

  for layer in base_model.layers[:]:
    layer.trainable = False 

  x = Flatten()(base_model.output)
 
  x = Dense(512, kernel_regularizer=tf.keras.regularizers.L2(l2=0.01), 
          kernel_initializer=tf.keras.initializers.HeNormal(), 
          kernel_constraint=tf.keras.constraints.UnitNorm(axis=0))(x)
  x = LeakyReLU()(x)
  x = BatchNormalization()(x)
  
  predictions = Dense(num_classes, activation= 'softmax')(x)
  model = Model(inputs = base_model.input, outputs = predictions)

model.compile(
    loss='sparse_categorical_crossentropy',
    optimizer='adam',
    metrics=['accuracy']
    )

base_model.load_weights('/content/drive/MyDrive/MODELS_SAVED/model_RESNET152/model_weights5.h5', by_name=True)

with open('/content/drive/MyDrive/MODELS_SAVED/optimizer3.pkl', 'rb') as f:
    weight_values = pickle.load(f)
model.optimizer.set_weights(weight_values)

from PIL import ImageFile
ImageFile.LOAD_TRUNCATED_IMAGES = True

epochs = 2

model.fit(
  train_generator,
  validation_data=valid_generator,
  epochs=epochs,
  steps_per_epoch=len_train // batch_size,
  validation_steps=len_test // batch_size,
  verbose = 1,
  callbacks=[earlyStopping, reduce_lr]
)


Теперь я получаю следующую ошибку при запуске этого блока кода (который выше в полном коде находится прямо перед model.fit):

with open('/content/drive/MyDrive/MODELS_SAVED/optimizer3.pkl', 'rb') as f:
    weight_values = pickle.load(f)
model.optimizer.set_weights(weight_values)
ValueError: You called `set_weights(weights)` on optimizer Adam with a  weight list of length 1245, but the optimizer was expecting 13 weights. Provided weights: [11907, array([[[[ 0.00000000e+00, -8.27514916e-04...

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

Откуда вы берете эти weight_values2optimizer.pkl весы?

Akshay Sehgal 16.12.2020 16:24

@AkshaySehgal Пожалуйста, взгляните на полный код, где вы видите, где я сохраняю и загружаю веса. Это просто другое имя файла. В полном коде я сохраняю и загружаю «/content/drive/MyDrive/MODELS_SAVED/optimizer3.pkl». Я делал то же самое с weight_values2optimizer.pkl.

JKnecht 16.12.2020 16:31

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

Dr. Snoopy 16.12.2020 22:37

@Dr.Snoopy Это имеет смысл. Но в каком порядке мне теперь выполнять действия, если я загружаю веса только для базовой модели? У меня это работало когда-то, оно начинало новую тренировку с приличной точностью, но теперь я забыл, как я это сделал, и в последние часы я пробовал много разных вещей, но это всегда начинается с самого начала с точностью 0. :(

JKnecht 17.12.2020 14:44

@Dr.Snoopy Итак, сначала я запускаю базовую модель, затем сохраняю веса, затем создаю новую модель с той же базой, затем компилирую ее, затем загружаю веса, затем подгоняю и снова начинаю тренироваться. .к сожалению, это не работает, снова начинается с начала - точность 0. Что я делаю неправильно?

JKnecht 17.12.2020 14:44
Почему в Python есть оператор "pass"?
Почему в Python есть оператор "pass"?
Оператор pass в Python - это простая концепция, которую могут быстро освоить даже новички без опыта программирования.
Некоторые методы, о которых вы не знали, что они существуют в Python
Некоторые методы, о которых вы не знали, что они существуют в Python
Python - самый известный и самый простой в изучении язык в наши дни. Имея широкий спектр применения в области машинного обучения, Data Science,...
Основы Python Часть I
Основы Python Часть I
Вы когда-нибудь задумывались, почему в программах на Python вы видите приведенный ниже код?
LeetCode - 1579. Удаление максимального числа ребер для сохранения полной проходимости графа
LeetCode - 1579. Удаление максимального числа ребер для сохранения полной проходимости графа
Алиса и Боб имеют неориентированный граф из n узлов и трех типов ребер:
Оптимизация кода с помощью тернарного оператора Python
Оптимизация кода с помощью тернарного оператора Python
И последнее, что мы хотели бы показать вам, прежде чем двигаться дальше, это
Советы по эффективной веб-разработке с помощью Python
Советы по эффективной веб-разработке с помощью Python
Как веб-разработчик, Python может стать мощным инструментом для создания эффективных и масштабируемых веб-приложений.
2
5
1 345
3
Перейти к ответу Данный вопрос помечен как решенный

Ответы 3

Пожалуйста, обратитесь к следующему блокноту: https://colab.research.google.com/drive/1j_zLqG1zUMi6UYPdc6gtmkJvHuawL4Sk?usp=sharing

  1. {save,load}_weights в модели включает веса оптимизатора. Это был бы предпочтительный способ инициализации весов оптимизатора.

  2. Вы можете скопировать оптимизатор из одной модели в другую.

  3. Причина, по которой вы получаете указанную выше ошибку, заключается в том, что оптимизатор не распределяет свои веса до тех пор, пока не начнется обучение; Если вы действительно хотите сделать это вручную, просто запустите model.fit() для 1 эпохи 1 точки данных, а затем загрузите данные вручную.

Вы можете заменить

base_model.load_weights('/content/drive/MyDrive/MODELS_SAVED/model_RESNET152/model_weights5.h5', by_name=True)

with open('/content/drive/MyDrive/MODELS_SAVED/optimizer3.pkl', 'rb') as f:
    weight_values = pickle.load(f)
model.optimizer.set_weights(weight_values)

с:

base_model.load_weights('/content/drive/MyDrive/MODELS_SAVED/model_RESNET152/model_weights5.h5', by_name=True)

model.optimizer = base_model.optimizer

Но вы используете ту же модель, когда загружаете веса. Это не так для меня и причина, по которой я получаю сообщение об ошибке. Я загружаю веса в модель, где я добавил пару слоев.

JKnecht 18.12.2020 08:48
Ответ принят как подходящий

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

Что вам нужно сделать, так это изменить способ создания новой модели, то есть вместо того, чтобы загружать исходную модель resnet в качестве базовой модели с помощью include_top = False, вы должны попробовать загрузить сохраненную модель и реализовать свой собственный include_top. Это можно сделать как:

for layer in saved_model.layers[:]:
    layer.trainable = False 

  x = Flatten()(saved_model.layers[-2].output)

Здесь ключевым моментом является saved_model.layers[-2].output, что означает вывод из предпоследнего слоя.

Надеюсь, это поможет, если нет, пожалуйста, проясните свои сомнения или дайте мне знать, что я пропустил.

@JKnecht, пожалуйста, примите ответ, если он решил проблему.

Prashant Gupta 28.12.2020 06:05

Извините за поздний ответ, у меня не было времени протестировать его до сегодняшнего дня. Это сработало! Слава богу, наконец :). (Для всех, кто сталкивается с этой проблемой, вам все равно нужно сохранить веса, а не всю модель, чтобы это работало. Затем вам нужно использовать «старый» model.input, как это, когда вы создаете экземпляр новой модели: new_model = Model(inputs =model.input, outputs = прогнозы))

JKnecht 30.12.2020 18:23

После сохранения веса первой модели с помощью model.save_weights('name.h5') вы должны построить вторую модель, точно такую ​​же, как и первая, назовем ее модель2. Затем загрузите в него веса, которые вы сохранили ранее. Код должен быть model2.load_weights('name.h5'). См. model.summary(), чтобы увидеть имена и количество слоев первой модели. Для каждого слоя вам нужно определить переменную и добавить эти веса (а также смещения) к этой переменной с помощью метода, называемого get_weights() . Вот пример:

x1 = model2.layers[1].get_weights()

Здесь я помещаю веса и смещения первого слоя (который в моем случае был слоем свертки) в переменную x1.

x1[0] — это список весов слоя №1.

x1[1] — это список смещений слоя №1.

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