Как реализовать трансфертное обучение с помощью собственной модели

#python #keras #conv-neural-network #transfer-learning

Вопрос:

Я пытаюсь сохранить модель CNN, которую я реализовал, и использовать ее для выполнения обучения передаче(TL) . Я хотел бы прояснить следующие четыре момента.
1.(код CNN) Является ли метод сохранения модели правильным или нет.
2.(Код TL) Является ли метод загрузки модели правильным или нет.
3.(Код TL) Как обычно устанавливается свойство «обучаемость» загруженной модели?
4.(Код TL) Правильно ли объединены модель предварительной подготовки и последующие слои (размер и т.д.)

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

 
#CNN

input = Input(shape=(100,100,3))
conv_0 = Conv2D(32,kernel_size=3,activation='relu')(input)
pool_0 = MaxPooling2D(pool_size=(2,2))(conv_0)
pool_0 = Dropout(0.25)(pool_0)
conv_1 = Conv2D(64,kernel_size=3,activation='relu')(pool_0)
pool_1 = MaxPooling2D(pool_size=(2,2))(conv_1)
pool_1 = Dropout(0.25)(pool_1)
conv_2 = Conv2D(32,kernel_size=3,activation='relu')(pool_1)
pool_2 = MaxPooling2D(pool_size=(2,2))(conv_2)
pool_2 = Dropout(0.25)(pool_2)
conv_3 = Conv2D(16,kernel_size=3,activation='relu')(pool_2)
pool_3 = MaxPooling2D(pool_size=(2,2))(conv_3)
conv_4 = Conv2D(8,kernel_size=3,activation='relu')(pool_3)
pool_4 = MaxPooling2D(pool_size=(2,2))(conv_4)
flat = Flatten()(pool_4)
denseL = Dense(64,activation='relu')(flat)
denseL = Dropout(0.25)(denseL)
A_output = Dense(1,name="a")(denseL)
B_output = Dense(1,name="b")(denseL)

model = Model(inputs=input, outputs=[A_output,B_output])
model.compile(Adam(learning_rate=0.001),
              loss = {'a':'mae','b':'mae'} ,
              metrics =  {'a':'mae','b':'mae'})

history = model.fit([np.array(Img_train)],[np.array(LabelA_train),np.array(LabelB_train)],
                    epochs=100, batch_size=16,
                    validation_data=([np.array(Img_test)],[np.array(LabelA_test),np.array(LabelB_test)]))

model.save('forTransferL.h5')

"""
Outputs for sumally()
__________________________________________________________________________________________________
Layer (type)                    Output Shape         Param #     Connected to
==================================================================================================
input_1 (InputLayer)            [(None, 100, 100, 3) 0
__________________________________________________________________________________________________
conv2d (Conv2D)                 (None, 98, 98, 32)   896         input_1[0][0]
__________________________________________________________________________________________________
max_pooling2d (MaxPooling2D)    (None, 49, 49, 32)   0           conv2d[0][0]
__________________________________________________________________________________________________
dropout (Dropout)               (None, 49, 49, 32)   0           max_pooling2d[0][0]
__________________________________________________________________________________________________
conv2d_1 (Conv2D)               (None, 47, 47, 64)   18496       dropout[0][0]
__________________________________________________________________________________________________
max_pooling2d_1 (MaxPooling2D)  (None, 23, 23, 64)   0           conv2d_1[0][0]
__________________________________________________________________________________________________
dropout_1 (Dropout)             (None, 23, 23, 64)   0           max_pooling2d_1[0][0]
__________________________________________________________________________________________________
conv2d_2 (Conv2D)               (None, 21, 21, 32)   18464       dropout_1[0][0]
__________________________________________________________________________________________________
max_pooling2d_2 (MaxPooling2D)  (None, 10, 10, 32)   0           conv2d_2[0][0]
__________________________________________________________________________________________________
dropout_2 (Dropout)             (None, 10, 10, 32)   0           max_pooling2d_2[0][0]
__________________________________________________________________________________________________
conv2d_3 (Conv2D)               (None, 8, 8, 16)     4624        dropout_2[0][0]
__________________________________________________________________________________________________
max_pooling2d_3 (MaxPooling2D)  (None, 4, 4, 16)     0           conv2d_3[0][0]
__________________________________________________________________________________________________
conv2d_4 (Conv2D)               (None, 2, 2, 8)      1160        max_pooling2d_3[0][0]
__________________________________________________________________________________________________
max_pooling2d_4 (MaxPooling2D)  (None, 1, 1, 8)      0           conv2d_4[0][0]
__________________________________________________________________________________________________
flatten (Flatten)               (None, 8)            0           max_pooling2d_4[0][0]
__________________________________________________________________________________________________
dense (Dense)                   (None, 64)           576         flatten[0][0]
__________________________________________________________________________________________________
dropout_3 (Dropout)             (None, 64)           0           dense[0][0]
__________________________________________________________________________________________________
a (Dense)                       (None, 1)            65          dropout_3[0][0]
__________________________________________________________________________________________________
b (Dense)                       (None, 1)            65          dropout_3[0][0]
=========================================================================================
"""
 
 
#TL

model = load_model('forTransferL.h5')
model.layers[0].trainable = False
x = model.layers[10].output

# The following is the same as part of CNN model.
conv_3 = Conv2D(16,kernel_size=3,activation='relu')(x)
pool_3 = MaxPooling2D(pool_size=(2,2))(conv_3)
conv_4 = Conv2D(8,kernel_size=3,activation='relu')(pool_3)
pool_4 = MaxPooling2D(pool_size=(2,2))(conv_4)
flat = Flatten()(pool_4)
denseL = Dense(64,activation='relu')(flat)
denseL = Dropout(0.25)(denseL)
A_output = Dense(1,name="a")(denseL)
B_output = Dense(1,name="b")(denseL)

model=Model(inputs=model.input,outputs=[A_output,B_output])
 

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

Спасибо вам за сотрудничество.

 #error message

During handling of the above exception, another exception occurred:

Traceback (most recent call last):
  File "c:/Users/userABC/OneDrive/Document/StudyAI/transferMymodel.py", line 158, in <module>
    pool_m4 = MaxPooling2D(pool_size=(2,2))(conv_m4)
  File "C:UsersuserABCanaconda3libsite-packageskerasenginebase_layer.py", line 1006, in __call__
    outputs = call_fn(inputs, *args, **kwargs)
  〜Omitted due to the limited number of characters.

ValueError: Negative dimension size caused by subtracting 2 from 1 for '{{node tf.compat.v1.nn.max_pool_1/MaxPool}} = MaxPool[T=DT_FLOAT, data_format="NHWC", explicit_paddings=[], ksize=[1, 2, 2, 1], padding="VALID", strides=[1, 2, 2, 1]](Placeholder)' with input shapes: [?,1,1,8].
 

Ответ №1:

Для пунктов 1 и 2 ваш код кажется достаточно правильным, хотя лично я предпочитаю загружать веса моделей вместо самой модели, когда речь заходит о моделях с пользовательскими слоями. Хотя на самом деле это не имеет значения для вашей ситуации.

По пунктам 3 см. https://keras.io/guides/transfer_learning/:

Если вы установите trainable = False для модели или любого слоя, имеющего подслои, все дочерние слои также станут необучаемыми.

Это означает, что в вашей ситуации установка «model.trainable = False» приведет к замораживанию всех весов загруженной части модели (предотвратит ее изменение).

Для пункта 4 предварительно обученная модель и более поздние слои выглядят правильно, но ошибка вызвана тем, что вы не установили заполнение= «то же самое» внутри слоев Conv2D (пример:

 conv_3 = Conv2D(16,kernel_size=3,activation='relu', padding='same')(x)
 

Это важно, потому что не указание одинакового заполнения означает, что каждый слой Conv2D уменьшает высоту и ширину изображения на 2, и, учитывая, что выходная форма вашей предварительно подготовленной модели равна (8, 8, 16), первая свертка даст выходную форму (6, 6, 16), первый максимальный пул даст (3, 3, 16), вторая свертка даст (1, 1, 8), и на данный момент второй максимальный пул больше не может объединять объекты, так как высота и ширина меньше (2, 2).