
В сети много статей, как нужно делать тот или иной проект, а эта статья о том, как не нужно делать. Возможно кому-то это сэкономит пару дней.
Я не волшебник, я только учусь и все описанное - это личные пробы и ошибки.
Данные
Все манипуляции будут происходить с данными по пневмонии, при этом определяться будет только её наличие, без определения вирусная или бактериальная. Упор ведётся на перекрёстное обучение и будет сравниваться с несложной свёрточной нейросетью.
Контрольная проверка нейросетей проводилась на тестовой выборке с сайта Kaggle.
Для обучения методом Transfer learning были выбраны сети ResNet50V2, InceptionV3, DenseNet169 и MobileNetV2. Каждая из выбранных предобученных моделей обучалась с постепенным размораживанием слоёв для тренировки начиная с полностью замороженными слоями предобученной модели и далее с шагом 25. Для оптимизации использовался Adam с начальной скорость обучения lr=0,001, дополнительно на 50% разморозки слоёв и полностью размороженной модели - скорость обучения понижалась кратностью 0,1. Дополнительно было введено понижение скорости обучения при условии, что ошибка валидационной выборки не понижается в течении 5 эпох. Лучшие веса сохранялись и загружались при каждом шаге обучения(разморозка весов).
reduce_lr = tf.keras.callbacks.ReduceLROnPlateau(monitor='val_loss',
factor=0.1,
patience=5,
min_lr=0.0000000001,
verbose=1)
checkpoint = tf.keras.callbacks.ModelCheckpoint(filepath='model.hdf5',
monitor='val_loss',
save_weights_only=True,
save_best_only=True,
verbose=1)Верх модели:
headModel = baseModel.output
headModel = MaxPooling2D()(headModel)
headModel = Flatten(name="flatten")(headModel)
headModel = Dense(10, activation="relu")(headModel)
headModel = Dropout(0.5)(headModel)
headModel = Dense(1, activation="sigmoid")(headModel)Случайным образом менялся pooling слой, на разных моделях( AveragePooling2D, MaxPooling2D, GlobalMaxPooling2D, GlobalAveragePooling2D).
Также в предпоследнем полносвязном слое менялось количество нейронов (10, 32, 64, 128).
При обучении модели, периодически давали очень хороший результат на валидационной выборке, при этом на тестовой показания были очень удручающими, начиная от 80% до 86%, что свидетельствовало о переобучении.

Для исправления ситуации попытался добавить разного рода аугментации.
Аугментация данных не дала ни регуляризационных эффектов ни прироста в точности, а наоборот понизила точность. Тест был проведён на 3 различных наборах датагенерации и контрольном - без аугментации. Разница на валидационной выборке = около 1%, разница на тесте дала прирост в 0,35% точности.
Закончив мучения с Transfer learning была протестирована сеть:
class MyModel(Model):
def __init__(self, do=0.1):
super().__init__()
self.conv1 = Conv2D(16, 3, padding = 'same')
self.conv2 = Conv2D(32, 3, padding = 'same')
self.conv3 = Conv2D(128, 3, padding = 'same')
self.flatten = Flatten()
self.dense = Dense(32, activation="relu")
self.out = Dense(1, activation="sigmoid")
self.act = Activation('relu')
self.pool = MaxPooling2D()
def call(self, inputs):
x = self.conv1(inputs)
x = self.act(x)
# x = self.batch(x)
x = self.pool(x)
# x = self.drop_layer(x)
x = self.conv2(x)
x = self.act(x)
# x = self.batch(x)
x = self.pool(x)
# x = self.drop_layer(x)
x = self.conv3(x)
x = self.act(x)
# x = self.batch(x)
x = self.pool(x)
x = self.flatten(x)
x = self.dense(x)
# x = self.batch(x)
return self.out(x)
model = MyModel(do=0.5)
model.compile(optimizer=Adam(learning_rate=0.001),
loss='binary_crossentropy', metrics=['accuracy'])
model.build(input_shape=(None, 192, 192, 1))
model.summary()Так же, как и в прошлых моделях, изменялись pooling слои, добавлялся Dropout и Batch Norm.
Батч нормализация дала очень интересный эффект, при 3 свёрточных и 2-х полносвязных добавление только одной батч нормализации после любого из свёрточных слоёв даёт небольшую регуляризацию. При этом последующее добавление после других слоёв полностью ухудшает сеть до 9,2% точности или скатывается в локальный минимум, почти сразу, до 90,8% точности. То же происходит и с одной батч нормализацией после полносвязного слоя.
После всех итераций удалось получить точность только 93,919%
Ещё один интересный момент. Своя сеть с 2,401,153 обучаемыми параметрами выдаёт расхождение в точности валидационной и тренировочной выборки в 0.5%. При этом сеть MobileNetV2 с рандомными начальными весами и весами ImageNet и верхушкой как и прежде.
и примерно 2,500,000 параметров всё равно уходило в переобучение и выдавало 82% точности на тесте.
Буду рад любым советам, так как мне не хватило опыта добить точность до желанных 96% на тесте.
Спасибо за внимание.