Как заставить модель Keras VGG16 показывать и включать подробные слои при использовании в новых настроенных моделях

Сводка. Как заставить keras.applications.VGG16 слои, а не vgg модель, отображать и включать в качестве слоев в новые настраиваемые модели.

Подробности:

  1. Я создавал индивидуальные модели (обозначенные как model) поверх keras.applications.VGG16 (обозначенных как conv_base). В частности, я заменяю последние плотные слои своими собственными слоями.

    conv_base = VGG16(weights='imagenet',  # pre-train with ImageNet
              include_top=False,  # exclude the three top layers
              input_shape=(64, 64, 3),
              pooling = 'max')
    model = models.Sequential()
    model.add(conv_base)
    model.add(layers.BatchNormalization())
    model.add(layers.Dropout(0.2))
    model.add(layers.Dense(256, activation='linear'))
    model.add(layers.BatchNormalization())
    model.add(layers.Dropout(0.2))
    model.add(layers.Dense(1, activation='linear'))
    
  2. Хотя я могу видеть слои в conv_base, когда conv_base.summary(), новая настроенная модель видит только слой vgg16 (тип Model), а не каждый слой внутри vgg16, когда model.summary() (показано на рисунке)

    conv_base.summary()
    

Рис. 1: Все слои показаны в conv_base.

    model.summary()

Рис. 2: подробные слои vgg не включены в структуру модели, вместо этого vgg содержится как Модель.

  1. Связанные вопросы

Хотя слои vgg могут быть доступны для model.get_layer('vgg16').layers, иногда это вызывает другие проблемы, в том числе:

(1) загрузка весов: иногда это мешает процессу загрузки веса.

    model.load_weights('~path/weights.hdf5')  

Ошибка загрузки весов

(2) построение новой модели: это также вызывает ошибки при вызове model слоев для построения новых моделей.

    model2 = Model(inputs=model.inputs, outputs=model.get_layer('vgg16').layers[1].output, name='Vis_Model') 

Ошибка при вызове слоев для построения новых моделей

Мысли: я мог бы частично исправить это, скопировав keras.application.VGG слоев один за другим в новую модель. Но как использовать предварительно натренированные веса может быть проблемой. Любая другая идея будет оценена по достоинству.


person Joey Fueng    schedule 27.07.2021    source источник


Ответы (1)


РЕДАКТИРОВАТЬ: на основе ваших комментариев вот обновленное решение.

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

import numpy as np
import tensorflow as tf
from tensorflow.keras.applications import VGG16
from tensorflow.keras import layers, Model, utils

#Instantiating the VGG model
conv_base = VGG16(weights='imagenet',  # pre-train with ImageNet
                  include_top=False,  # exclude the three top layers
                  input_shape=(64, 64, 3),
                  pooling = 'max')

#Defining secondary nested model
inp = layers.Input((64,64,3))
cnn = conv_base(inp)
x = layers.BatchNormalization()(cnn)
x = layers.Dropout(0.2)(x)
x = layers.Dense(256, activation='linear')(x)
x = layers.BatchNormalization()(x)
x = layers.Dropout(0.2)(x)
out = layers.Dense(1, activation='linear')(x)

model = Model(inp, out)

#Flattening nested model
def flatten_model(model_nested):
    layers_flat = []
    for layer in model_nested.layers:
        try:
            layers_flat.extend(layer.layers)
        except AttributeError:
            layers_flat.append(layer)
    model_flat = tf.keras.models.Sequential(layers_flat)
    return model_flat

model_flat = flatten_model(model)

model_flat.summary()
Model: "sequential_1"
_________________________________________________________________
Layer (type)                 Output Shape              Param #   
=================================================================
input_10 (InputLayer)        multiple                  0         
_________________________________________________________________
block1_conv1 (Conv2D)        (None, 64, 64, 64)        1792      
_________________________________________________________________
block1_conv2 (Conv2D)        (None, 64, 64, 64)        36928     
_________________________________________________________________
block1_pool (MaxPooling2D)   (None, 32, 32, 64)        0         
_________________________________________________________________
block2_conv1 (Conv2D)        (None, 32, 32, 128)       73856     
_________________________________________________________________
block2_conv2 (Conv2D)        (None, 32, 32, 128)       147584    
_________________________________________________________________
block2_pool (MaxPooling2D)   (None, 16, 16, 128)       0         
_________________________________________________________________
block3_conv1 (Conv2D)        (None, 16, 16, 256)       295168    
_________________________________________________________________
block3_conv2 (Conv2D)        (None, 16, 16, 256)       590080    
_________________________________________________________________
block3_conv3 (Conv2D)        (None, 16, 16, 256)       590080    
_________________________________________________________________
block3_pool (MaxPooling2D)   (None, 8, 8, 256)         0         
_________________________________________________________________
block4_conv1 (Conv2D)        (None, 8, 8, 512)         1180160   
_________________________________________________________________
block4_conv2 (Conv2D)        (None, 8, 8, 512)         2359808   
_________________________________________________________________
block4_conv3 (Conv2D)        (None, 8, 8, 512)         2359808   
_________________________________________________________________
block4_pool (MaxPooling2D)   (None, 4, 4, 512)         0         
_________________________________________________________________
block5_conv1 (Conv2D)        (None, 4, 4, 512)         2359808   
_________________________________________________________________
block5_conv2 (Conv2D)        (None, 4, 4, 512)         2359808   
_________________________________________________________________
block5_conv3 (Conv2D)        (None, 4, 4, 512)         2359808   
_________________________________________________________________
block5_pool (MaxPooling2D)   (None, 2, 2, 512)         0         
_________________________________________________________________
global_max_pooling2d_3 (Glob (None, 512)               0         
_________________________________________________________________
batch_normalization_4 (Batch (None, 512)               2048      
_________________________________________________________________
dropout_4 (Dropout)          (None, 512)               0         
_________________________________________________________________
dense_4 (Dense)              (None, 256)               131328    
_________________________________________________________________
batch_normalization_5 (Batch (None, 256)               1024      
_________________________________________________________________
dropout_5 (Dropout)          (None, 256)               0         
_________________________________________________________________
dense_5 (Dense)              (None, 1)                 257       
=================================================================
Total params: 14,849,345
Trainable params: 14,847,809
Non-trainable params: 1,536
_________________________________________________________________

Я бы рекомендовал использовать альтернативный способ резюмирования модели.

Для этой цели вы можете использовать utils.plot_model с expand_nested=True.

tf.keras.utils.plot_model(model, show_shapes=True, show_layer_names=True, expand_nested=True)

введите описание изображения здесь

person Akshay Sehgal    schedule 27.07.2021
comment
Спасибо что подметил это. Но, как описано в вопросе, отображение подробной информации - не единственная причина для принудительного включения слоев модели в новые модели. - person Joey Fueng; 27.07.2021
comment
хм, насколько я понимаю, у вас есть предварительно обученная модель, слои которой вы пытаетесь добавить в метамодель? останутся ли эти слои необучаемыми? - person Akshay Sehgal; 27.07.2021
comment
См. Связанную проблему (2). Я хочу использовать слой (внутри vgg) в model, чтобы построить новую модель для визуализации карт функций. - person Joey Fueng; 27.07.2021
comment
Помогите мне понять немного дальше. Связанная проблема (2) в основном заключается в том, что вы пытаетесь использовать те же входные данные, но только первый уровень вложенной модели VGG в качестве новой модели? - person Akshay Sehgal; 28.07.2021
comment
проверьте мое обновленное решение и дайте мне знать, поможет ли это. - person Akshay Sehgal; 28.07.2021
comment
Спасибо, Акшай. Думаю, это пока решает мой вопрос. Я просто немного удивлен, что функция expand nested не входит в состав самих keras или tf, но мне нужно обучить мою модель и загрузить веса, чтобы построить новую модель для тестирования. Чтобы ответить на ваш вопрос: да, проблема (2) заключается в том, что я использую те же входные данные и первый уровень вложенной модели VGG для построения новой модели. Я приму этот ответ после проверки. - person Joey Fueng; 28.07.2021
comment
@JoeyFueng, рад, что у вас сработало. Причина, по которой нет необходимости в плоской модели, заключается в том, что keras сам по себе является фреймворком очень высокого уровня, а подход вложенных моделей на самом деле довольно хорошо выполняется для моделей с точной настройкой. В вашем конкретном случае цель немного более продвинутая, чем стандартная задача точной настройки, поэтому необходимость в том же. - person Akshay Sehgal; 28.07.2021
comment
еще раз спасибо. Я принял ответ. - person Joey Fueng; 28.07.2021