Este post parece indicar que o que eu quero realizar não é possível. No entanto, não estou convencido disso - dado o que já fiz, não vejo por que o que quero fazer não pode ser alcançado ...
Eu tenho dois conjuntos de dados de imagens em que um possui imagens de forma (480, 720, 3) enquanto o outro possui imagens de forma (540, 960, 3).
Inicializei um modelo usando o seguinte código:
input = Input(shape=(480, 720, 3), name='image_input')
initial_model = VGG16(weights='imagenet', include_top=False)
for layer in initial_model.layers:
layer.trainable = False
x = Flatten()(initial_model(input))
x = Dense(1000, activation='relu')(x)
x = BatchNormalization()(x)
x = Dropout(0.5)(x)
x = Dense(1000, activation='relu')(x)
x = BatchNormalization()(x)
x = Dropout(0.5)(x)
x = Dense(14, activation='linear')(x)
model = Model(inputs=input, outputs=x)
model.compile(loss='mse', optimizer='adam', metrics=['mae'])
Agora que eu treinei esse modelo no antigo conjunto de dados, gostaria de destacar a camada do tensor de entrada e anexar o modelo a um novo tensor de entrada com uma forma que corresponda às dimensões da imagem do último conjunto de dados.
model = load_model('path/to/my/trained/model.h5')
old_input = model.pop(0)
new_input = Input(shape=(540, 960, 3), name='image_input')
x = model(new_input)
m = Model(inputs=new_input, outputs=x)
m.save('transfer_model.h5')
que gera esse erro:
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
File "/home/aicg2/.local/lib/python2.7/site-packages/keras/engine/topology.py", line 2506, in save
save_model(self, filepath, overwrite, include_optimizer)
File "/home/aicg2/.local/lib/python2.7/site-packages/keras/models.py", line 106, in save_model
'config': model.get_config()
File "/home/aicg2/.local/lib/python2.7/site-packages/keras/engine/topology.py", line 2322, in get_config
layer_config = layer.get_config()
File "/home/aicg2/.local/lib/python2.7/site-packages/keras/engine/topology.py", line 2370, in get_config
new_node_index = node_conversion_map[node_key]
KeyError: u'image_input_ib-0'
No post que vinculei, maz afirma que há uma incompatibilidade de dimensão que impede a alteração da camada de entrada de um modelo - se esse foi o caso, como é que eu coloco uma camada de entrada (480, 720, 3) na frente do modelo VGG16 que espera (224, 224, 3) imagens?
Acho que uma questão mais provável é que a produção do meu modelo anterior esteja esperando algo diferente do que estou dando, com base no que fchollet está dizendo neste post . Estou sintaticamente confuso, mas acredito que todo o x = Layer()(x)
segmento está construindo a camada peça por peça a partir de entrada-> saída e simplesmente jogar uma entrada diferente na frente está quebrando.
Eu realmente não tenho idéia ...
Alguém pode me esclarecer como realizar o que estou tentando fazer ou, se não for possível, me explicar por que não?
Respostas:
Você pode fazer isso criando uma nova instância do modelo VGG16 com o novo formato de entrada
new_shape
e copiando todos os pesos da camada. O código é aproximadamentefonte
Traceback (most recent call last): File "predict_video11.py", line 67, in <module> new_layer.set_weights(layer.get_weights()) File "/usr/local/lib/python2.7/dist-packages/keras/engine/base_layer.py", line 1057, in set_weights 'provided weight shape ' + str(w.shape)) ValueError: Layer weight shape (3, 3, 33, 64) not compatible with provided weight shape (3, 3, 9, 64)
e essa é a camada de entrada, então use[2:]
?A largura e a altura de saída das dimensões de saída do VGGnet são uma parte fixa da largura e da altura de entrada porque as únicas camadas que alteram essas dimensões são as camadas de pool. O número de canais na saída é fixo ao número de filtros na última camada convolucional. A camada plana achatará isso para obter uma dimensão com a forma:
((input_width * x) * (input_height * x) * channels)
onde x é algum decimal <1.
O ponto principal é que a forma da entrada nas camadas Densas depende da largura e altura da entrada para o modelo inteiro. A entrada de forma para a camada densa não pode mudar, pois isso significa adicionar ou remover nós da rede neural.
Uma maneira de evitar isso é usar uma camada de pool global em vez de uma camada plana (geralmente GlobalAveragePooling2D). Isso encontrará a média por canal, fazendo com que apenas o formato da entrada para as camadas densas seja
(channels,)
que não depende do formato de entrada. todo o modelo.Feito isso, nenhuma das camadas da rede depende da largura e altura da entrada, para que a camada de entrada possa ser alterada com algo como
fonte
Aqui está outra solução, não específica para o modelo VGG.
Observe que os pesos da camada densa não podem ser copiados (e, portanto, serão inicializados novamente). Isso faz sentido, porque a forma dos pesos difere no modelo antigo e no novo.
fonte
Isso deve ser bem fácil com
kerassurgeon
. Primeiro você precisa instalar a biblioteca; dependendo de se você estiver usando o Keras através do TensorFlow (com tf 2.0 e superior) ou Keras como uma biblioteca separada, ele precisará ser instalado de maneiras diferentes.Para Keras no TF:
pip install tfkerassurgeon
( https://github.com/Raukk/tf-keras-surgeon ). Para Keras autônomo:pip install kerassurgeon
( https://github.com/BenWhetton/keras-surgeon )Para substituir a entrada (exemplo pelo TF 2.0; código atualmente não testado):
fonte
A resposta @gebbissimo funcionou para mim no TF2 com apenas pequenas adaptações que compartilho abaixo em uma única função:
fonte
É assim que eu mudo o tamanho da entrada no modelo Keras. Eu tenho dois modelos CNN, um com tamanho de entrada [None, None, 3] enquanto o outro tem tamanho de entrada [512.512,3]. Ambos os modelos têm os mesmos pesos. Usando set_weights (model.get_weights ()), os pesos do modelo 1 podem ser transferidos para o modelo 2
fonte