Вопрос или проблема
Я работаю над задачей верификации подписей, где мне нужно создать модель, которая даст среднюю достаточно хорошую точность валидации, чтобы получить полезную модель для тестирования (цель – выше 80%). Я вижу, что моя модель переобучается, так как точность на обучении почти 100%, а потеря при обучении довольно низкая по сравнению с валидацией (66% – максимальный пик). В чем может быть проблема?
Не могу понять, где ошибка в моем процессе, и мне кажется, что я перепробовал все. Вот несколько полезных изображений и ссылка на гитхаб, где вы можете найти сам ноутбук. https://github.com/boroszoltanOE/SiameseSignNotebook
#Этап предобработки
def cropping(ref_img):
# Найти внешние контуры белых областей
contours, _ = cv2.findContours(ref_img, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)
if contours:
# Найти ограничивающий прямоугольник для всех обнаруженных контуров
x, y, w, h = cv2.boundingRect(np.concatenate(contours))
return ref_img[y:y + h, x:x + w]
return ref_img
steps = {}
augment = (random.random() < random_percentage)
loaded_img = cv2.imread(image, cv2.IMREAD_GRAYSCALE)
steps['Loaded'] = loaded_img
blurred_img = cv2.GaussianBlur(loaded_img, (3, 3), 0)
steps['Blurred'] = blurred_img
_, thresholded_img = cv2.threshold(blurred_img, 0, 255, cv2.THRESH_BINARY_INV + cv2.THRESH_OTSU)
steps['Thresholded'] = thresholded_img
# Удаление белого пространства
cropped_image_np = cropping(thresholded_img)
steps['Cropped'] = cropped_image_np
# Изменение размера (перед скелетизацией)
resized_image = cv2.resize(cropped_image_np, (IMG_WIDTH, IMG_HEIGHT), interpolation=cv2.INTER_LINEAR)
steps['Resized'] = resized_image
#resized_image = cv2.GaussianBlur(resized_image, (3, 3), 0)
#_, resized_image = cv2.threshold(resized_image, 0, 255, cv2.THRESH_OTSU)
# Скелетизация (после увеличения, если таковое имеется)
#skeletonized_image = skeletonize(thresholded_img2 // 255) # Скелетизация ожидает бинарное изображение
#skeletonized_image = (skeletonized_image * 255).astype(np.uint8) # Преобразование обратно в диапазон 0-255
#steps['Skeletonized'] = skeletonized_image
# Нормализация
normalized_image = resized_image / 255.0
steps['Normalized'] = normalized_image
if augment:
normalized_image = cv2.GaussianBlur(normalized_image, (7, 7), 0)
steps['Noised'] = normalized_image
tensor_image = tf.convert_to_tensor(normalized_image, dtype=tf.float32)
tensor_image = tf.expand_dims(tensor_image, axis=-1)
Используемая модель
model = Sequential()
#1-й сверточный слой
model.add(Conv2D(32, (3, 3),input_shape=input_shape))
model.add(PReLU(alpha_initializer=Constant(value=0.25)))
model.add( MaxPooling2D(pool_size=(3,3)) )
#2-й сверточный слой
model.add(Conv2D(64, (3, 3)) )
model.add(PReLU(alpha_initializer=Constant(value=0.25)))
model.add( MaxPooling2D(pool_size=(3,3),strides=(2,2)) )
#3-й сверточный слой
model.add(Conv2D(128, (3, 3)) )
model.add(PReLU(alpha_initializer=Constant(value=0.25)))
#4-й сверточный слой
model.add(Conv2D(64, (3, 3)) )
model.add(PReLU(alpha_initializer=Constant(value=0.25)))
#5-й сверточный слой
model.add(Conv2D(128, (3, 3)) )
model.add(PReLU(alpha_initializer=Constant(value=0.25)))
model.add(MaxPooling2D(pool_size=(3,3),strides=(2,2)) )
model.add(Dropout(0.3) )
#Полносвязный слой
model.add(Flatten() )
model.add(Dense(256, kernel_regularizer=l2(l2_value)) )
model.add(PReLU(alpha_initializer=Constant(value=0.25)))
model.add(Dropout(0.5) )
model.add(Dense(256, kernel_regularizer=l2(l2_value)) )
model.add(PReLU(alpha_initializer=Constant(value=0.25)))
#Используемые метрики
def euclidean_distance(vects):
"""
Вычислить евклидово расстояние между двумя векторами
"""
x, y = vects
return K.sqrt(K.sum(K.square(x - y), axis=1, keepdims=True))
def contrastive_loss(y_true, y_pred):
"""
Функция контрастной потери
"""
margin = 1.0
return K.mean(y_true * K.square(y_pred) + (1 - y_true) * K.square(K.maximum(margin - y_pred, 0)))
def compute_accuracy(y_true, y_pred, threshold=0.5):
"""
Вычислить точность на основе порога расстояния
"""
return K.mean(K.equal(y_true, K.cast(y_pred < threshold, y_true.dtype)))
[![Лучший результат тренировок][2]][2]
Эпоха 1/10
655/655 [==============================] – 277s 418ms/step – loss: 0.9551 – compute_accuracy: 0.6448 – val_loss: 1.0018 – val_compute_accuracy: 0.5080 – lr: 1.0000e-05
Эпоха 2/10
655/655 [==============================] – 262s 400ms/step – loss: 0.8351 – compute_accuracy: 0.7990 – val_loss: 0.8995 – val_compute_accuracy: 0.6530 – lr: 1.0000e-05
Эпоха 3/10
655/655 [==============================] – 274s 418ms/step – loss: 0.7291 – compute_accuracy: 0.8974 – val_loss: 0.8454 – val_compute_accuracy: 0.6602 – lr: 1.0000e-05
Эпоха 4/10
655/655 [==============================] – 264s 403ms/step – loss: 0.6418 – compute_accuracy: 0.9420 – val_loss: 0.8005 – val_compute_accuracy: 0.6479 – lr: 1.0000e-05
Эпоха 5/10
655/655 [==============================] – 265s 405ms/step – loss: 0.5648 – compute_accuracy: 0.9726 – val_loss: 0.7524 – val_compute_accuracy: 0.6370 – lr: 1.0000e-05
Эпоха 6/10
655/655 [==============================] – 274s 418ms/step – loss: 0.4945 – compute_accuracy: 0.9885 – val_loss: 0.7111 – val_compute_accuracy: 0.6174 – lr: 1.0000e-05
Эпоха 7/10
655/655 [==============================] – 285s 435ms/step – loss: 0.4308 – compute_accuracy: 0.9941 – val_loss: 0.6692 – val_compute_accuracy: 0.5927 – lr: 1.0000e-05
Эпоха 8/10
655/655 [==============================] – 288s 440ms/step – loss: 0.3709 – compute_accuracy: 0.9968 – val_loss: 0.6156 – val_compute_accuracy: 0.5941 – lr: 1.0000e-05
Эпоха 9/10
655/655 [==============================] – 287s 438ms/step – loss: 0.3139 – compute_accuracy: 0.9980 – val_loss: 0.5699 – val_compute_accuracy: 0.5741 – lr: 1.0000e-05
Ответ или решение
Проблема переобучения в сиамской нейронной сети для верификации подписей
Переобучение (overfitting) представляет одну из наиболее распространённых и сложных проблем в области глубокого обучения, особенно в контексте верификации подписей с использованием сиамских нейронных сетей.
1. Понимание проблемы
Ваша модель демонстрирует высокую точность на обучающей выборке (практически 100%), в то время как точность на валидационной выборке значительно ниже (максимум 66%). Это указывает на то, что модель успешно запоминает признаки обучающих данных, но не может обобщить свои знания на новые, невидимые данные. Проблема заключается в следующем:
- Сложность модели: Возможно, ваша сеть слишком сложна для текущего набора данных. Многие слои, повышенное количество фильтров и отсутствие регуляризации могут способствовать переобучению.
- Недостаточное количество данных: Если объем доступных данных относительно невелик, это может привести к тому, что модель быстро осваивает их, запоминая детали, а не обучаясь общей схеме.
2. Возможные решения
Для снижения уровня переобучения можно рассмотреть следующие подходы:
2.1. Регуляризация
- Dropout: Вы уже используете Dropout, что хорошо. Однако можно попробовать увеличить степень Dropout (например, до 0.5 или 0.6) в некоторых слоях, чтобы уменьшить вероятность запоминания.
- L2-регуляризация: Убедитесь, что параметры L2 для слоев Dense правильно настроены. Попробуйте повысить значение регуляризации, чтобы предотвратить чрезмерное влияние весов.
2.2. Упрощение модели
- Рассмотрите возможность упрощения архитектуры модели. Например, уменьшите количество свёрточных слоев или количество фильтров в каждом слое.
- Попробуйте уменьшить размер Fully Connected layers, так как они обычно подвержены переобучению.
2.3. Увеличение данных
- Применяйте больше агрегации и увеличения данных на входных изображениях. Например, можно дообучать модель на сгенерированных данных с небольшими изменениями: вращение, изменение яркости, шум и т.д.
- Убедитесь, что данные вашего набора обучающей, валидационной и тестовой выборки разные и нет перекрытия.
2.4. Аргументирование и кросс-валидация
- Применяйте кросс-валидацию для более точного анализа производительности вашей модели. Это поможет вам понять, как модель показала бы себя на других подвыборках данных.
2.5. Динамическое изменение обучения
- Применяйте методы, такие как ранняя остановка (Early Stopping), чтобы предотвратить чрезмерное обучение, анализируя валидационные метрики во время тренировки и останавливая обучение, если валидационная метрика начинает ухудшаться.
3. Устранение ошибок в предобработке
Ваш код для предобработки изображений выглядит достойно. Однако, следует обратить внимание на следующее:
- Убедитесь, что аугментация изображений происходит правильно (и не приводит к избыточному шуму).
- Возможно, стоит улучшить процесс нормализации изображений. Проверяйте, что изображения действительно нормализованы в диапазоне [0, 1].
Заключение
Проблема переобучения в вашей сиамской нейронной сети может быть решена множеством методов. Применяйте регуляризацию, упрощайте модель, увеличивайте данные и используйте различные техники валидации, чтобы добиться желаемого результата выше 80% на валидационной выборке. Регулярный анализ и корректировка архитектуры, а также использование методов ранней остановки позволяют достичь хорошей обобщающей способности модели.