Keras — 전송 학습 — 입력 텐서 모양 변경


15

이 게시물 은 내가 달성하려는 것이 불가능하다는 것을 나타내는 것 같습니다. 그러나 나는 이것을 확신하지 못합니다. 내가 이미 한 일을 감안할 때 왜 내가하고 싶은 일을 달성 할 수 없는지 알 수 없습니다 ...

하나는 모양 (480, 720, 3)의 이미지가 있고 다른 하나는 모양 (540, 960, 3)의 이미지가있는 두 개의 이미지 데이터 세트가 있습니다.

다음 코드를 사용하여 모델을 초기화했습니다.

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'])

이전 데이터 세트에서이 모델을 학습 했으므로 입력 텐서 레이어를 제거하고 후자의 데이터 세트의 이미지 크기와 일치하는 모양의 새 입력 텐서로 모델을 추가하고 싶습니다.

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')

이 오류가 발생합니다.

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'

내가 연결 한 게시물에서 maz는 모델의 입력 레이어를 변경하지 못하게하는 치수 불일치가 있다고 말합니다.이 경우라면 (480, 720, 3) 입력 레이어를 앞에 놓는 방법은 무엇입니까? (224, 224, 3) 이미지를 기대하는 VGG16 모델의

필자는 이전 모델의 출력 이이 게시물 에서 fchollet이 말한 내용에 따라 내가 제공하는 것과 다른 것을 기대하고 있다는 것이 더 큰 문제라고 생각합니다 . 나는 문법적으로 혼란스러워하지만 전체 x = Layer()(x)세그먼트가 입력-> 출력에서 ​​레이어별로 조각을 구성하고 있으며 단순히 다른 입력을 앞에 던지면 깨뜨릴 것이라고 생각합니다.

나는 정말로 모른다.

누군가 내가 내가하려는 일을 성취하는 방법을 가르쳐 줄 수 있습니까, 아니면 가능하지 않은 경우 왜 그렇지 않은지 설명해 주시겠습니까?


당신은 그것을 해결 했습니까?
tktktk0711

답변:


4

새 입력 모양으로 새 VGG16 모델 인스턴스를 만들고 new_shape모든 레이어 가중치를 복사 하여이 작업을 수행 할 수 있습니다 . 코드는 대략

new_model = VGG16(weights=None, input_shape=new_shape, include_top=False)
for new_layer, layer in zip(new_model.layers[1:], model.layers[1:]):
    new_layer.set_weights(layer.get_weights())

inceptionV3으로 이것을
시도해 보니

@ r- zip 오류가 발생합니다. 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) 입력 레이어이므로 [2:]?
mLstudent33

1

VGGnet의 출력 치수의 출력 폭과 높이는 입력 폭과 높이의 고정 부분입니다. 치수를 변경하는 레이어 만 풀링 레이어이기 때문입니다. 출력의 채널 수는 마지막 컨 볼루 셔널 레이어의 필터 수로 고정됩니다. 평평한 레이어는 모양을 가진 하나의 치수를 얻기 위해 이것을 재 형성합니다 :

((input_width * x) * (input_height * x) * channels)

여기서 x는 소수 <1입니다.

요점은 밀도 층에 대한 입력의 모양이 전체 모델에 대한 입력의 너비와 높이에 달려 있다는 것입니다. 밀도가 높은 레이어에 입력되는 모양은 신경망에서 노드를 추가하거나 제거한다는 의미이므로 변경할 수 없습니다.

이를 피하는 한 가지 방법은 평평한 레이어 (일반적으로 GlobalAveragePooling2D) 대신 글로벌 풀링 레이어를 사용하는 것입니다. 이것은 채널당 평균을 찾아서 밀도 레이어 (channels,)에 대한 입력 형태가 입력 형태에 의존하지 않는 원인이됩니다. 전체 모델.

이 작업이 완료되면 네트워크의 어떤 레이어도 입력의 너비와 높이에 의존하지 않으므로 입력 레이어는 다음과 같이 변경 될 수 있습니다

input_layer = InputLayer(input_shape=(480, 720, 3), name="input_1")
model.layers[0] = input_layer

model.layers[0] = input_layerTF 2.1에서는 작동하지 않습니다. 오류는 없지만 레이어는 실제로 교체되지 않습니다. 복사 가중치가 더 강력 해 보일 수 있습니다 (다른 답변 참조).
z0r

0

다음은 VGG 모델에만 국한되지 않은 다른 솔루션입니다.

밀도가 높은 레이어의 가중치는 복사 할 수 없으므로 새로 초기화됩니다. 이전 모델과 새 모델에서 가중치의 모양이 다르기 때문에 의미가 있습니다.

import keras
import numpy as np

def get_model():
    old_input_shape = (20, 20, 3)
    model = keras.models.Sequential()
    model.add(keras.layers.Conv2D(9, (3, 3), padding="same", input_shape=old_input_shape))
    model.add(keras.layers.MaxPooling2D((2, 2)))
    model.add(keras.layers.Flatten())
    model.add(keras.layers.Dense(1, activation="sigmoid"))
    model.compile(loss='binary_crossentropy', optimizer=keras.optimizers.Adam(lr=0.0001), metrics=['acc'], )
    model.summary()
    return model

def change_model(model, new_input_shape=(None, 40, 40, 3)):
    # replace input shape of first layer
    model._layers[1].batch_input_shape = new_input_shape

    # feel free to modify additional parameters of other layers, for example...
    model._layers[2].pool_size = (8, 8)
    model._layers[2].strides = (8, 8)

    # rebuild model architecture by exporting and importing via json
    new_model = keras.models.model_from_json(model.to_json())
    new_model.summary()

    # copy weights from old model to new one
    for layer in new_model.layers:
        try:
            layer.set_weights(model.get_layer(name=layer.name).get_weights())
        except:
            print("Could not transfer weights for layer {}".format(layer.name))

    # test new model on a random input image
    X = np.random.rand(10, 40, 40, 3)
    y_pred = new_model.predict(X)
    print(y_pred)

    return new_model

if __name__ == '__main__':
    model = get_model()
    new_model = change_model(model)

0

이 작업은 매우 쉬워야합니다 kerassurgeon. 먼저 라이브러리를 설치해야합니다. TensorFlow (tf 2.0 이상) 또는 Keras를 별도의 라이브러리로 통해 Keras를 사용하는지에 따라 다른 방법으로 설치해야합니다.

TF의 Keras : pip install tfkerassurgeon( https://github.com/Raukk/tf-keras-surgeon ). 독립형 Keras : pip install kerassurgeon( https://github.com/BenWhetton/keras-surgeon )

입력을 바꾸려면 (예 : TF 2.0, 현재 테스트되지 않은 코드) :

from tensorflow import keras  # or import keras for standalone version
from tensorflow.keras.layers import Input

model = load_model('path/to/my/trained/model.h5')
new_input = Input(shape=(540, 960, 3), name='image_input')

# or kerassurgeon for standalone Keras
from tfkerassurgeon import delete_layer, insert_layer

model = delete_layer(model.layers[0])
# inserts before layer 0
model = insert_layer(model.layers[0], new_input)

0

@gebbissimo answer는 단일 기능으로 아래에서 공유하는 작은 적응으로 TF2에서 나를 위해 일했습니다.

def change_input_size(model,h,w,ch=3):
   model._layers[0]._batch_input_shape = (None,h,w,ch)
   new_model = keras.models.model_from_json(model.to_json())
   new_model.summary()
   for layer,new_layer in zip(model.layers,new_model.layers):
      new_layer.set_weights(layer.get_weights())
   return new_model

0

이것은 Keras 모델에서 입력 크기를 변경하는 방법입니다. 입력 크기가 [None, None, 3] 인 모델과 입력 크기가 [512,512,3] 인 CNN 모델이 두 개 있습니다. 두 모델의 무게는 동일합니다. set_weights (model.get_weights ())를 사용하여 모델 1의 가중치를 모델 2로 전송할 수 있습니다

inputs = Input((None, None, 3))
.....
model = Model(inputs=[inputs], outputs=[outputs])
model.compile(optimizer='adam', loss='mean_squared_error')
model.load_weights('my_model_name.h5')

inputs2 = Input((512, 512, 3))
....
model2 = Model(inputs=[inputs2], outputs=[outputs])
model2.compile(optimizer='adam', loss='mean_squared_error')
model2.set_weights(model.get_weights())
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.