Переобучение в сиамской нейронной сети, связанное с проверкой подписей

Вопрос или проблема

Я работаю над задачей верификации подписей, где мне нужно создать модель, которая даст среднюю достаточно хорошую точность валидации, чтобы получить полезную модель для тестирования (цель – выше 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% на валидационной выборке. Регулярный анализ и корректировка архитектуры, а также использование методов ранней остановки позволяют достичь хорошей обобщающей способности модели.

Оцените материал
Добавить комментарий

Капча загружается...