Мгновенное увеличение точности при медленном увеличении кубиков (U-Net)

Я обучаю модель извлечению мозга на изображениях МРТ. Я использую 2D-архитектуру U-Net и предварительно обученный EfficientNetV2B3.

def dice_coefficients(y_true, y_pred, smooth=0):

    intersection = K.sum(y_true * y_pred)
    union = K.sum(y_true) + K.sum(y_pred)
    return (2 * intersection + smooth) / (union + smooth)


def dice_coefficients_loss(y_true, y_pred, smooth=0):
    return -dice_coefficients(y_true, y_pred, smooth)

def iou(y_true, y_pred, smooth=0):
    intersection = K.sum(y_true * y_pred)
    sum = K.sum(y_true + y_pred)
    iou = (intersection + smooth) / (sum - intersection + smooth)
    return iou


### COMPILE THE MODEL
opti = Adam(learning_rate=1e-4)
unet_model5.compile(optimizer=opti,
                  loss=dice_coefficients_loss,
                  metrics=["accuracy", iou, dice_coefficients])

# Early Stopping
early_stopping_unet = EarlyStopping(monitor='loss',
                                             patience=10)

# Learning Rate Adjustment
reduce_lr_unet = ReduceLROnPlateau(monitor='val_loss', factor=0.2,
                              patience=5, min_lr=1e-7)
model_history = unet_model5.fit(train_generator, batch_size = 16, epochs=200,validation_data=val_generator, callbacks = [early_stopping_unet, reduce_lr_unet])

Эволюция потери коэффициента Дайса:

Мгновенное увеличение точности при медленном увеличении кубиков (U-Net)

Эволюция коэффициента Дайса:

Мгновенное увеличение точности при медленном увеличении кубиков (U-Net)

Эволюция точности:

Мгновенное увеличение точности при медленном увеличении кубиков (U-Net)

Мои значения кубиков и точности довольно высоки, но я считаю, что будет лучше, если я смогу выяснить проблему модели, если она есть. Я попробовал изменить некоторые гиперпараметры, такие как скорость обучения, процент отсева, номера слоев. Я не могу увеличить пакетный размер выше 16, тогда это дает мне ошибку, ресурс исчерпан, но я использую 3060 Ti и убедился, что тензорный поток использует мой графический процессор. Я добавил пакетную норму, иначе val_accuracy не увеличится, по какой-то непонятной мне причине. Было бы удивительно, если бы вы могли объяснить. Я также изменил свою предварительно обученную модель на другие, такие как VGG16, InceptionResNetV2, и соответственно предварительно обработал ввод, а затем, наконец, EfficientNetV2B3, который дал лучший результат. (Я также использую раннюю остановку и уменьшаю количество обратных вызовов lr)

Почему точность увеличивается так мгновенно, в то время как коэффициенты игральных костей растут медленно и медленно? И как мне добиться точности, не застряв на 0,95?

Как вы рассчитываете значение точности на основе результатов сегментации?

simon 02.09.2024 14:18

@simon, я отредактировал вопрос и добавил строки компиляции и подгонки. Я надеюсь, что это ответит на ваш вопрос

EfeK0 02.09.2024 14:22

Спасибо за обновление, оно действительно полезно! Исходя из этого, я сам пытаюсь ответить на свой вопрос: из вашего кода я делаю вывод, что вы на самом деле используете Keras. Keras автоматически сопоставляет ключевые слова «точности» с одной из трех метрик. В вашем случае, я думаю (я не очень знаком с Керасом), это должно быть BinaryAccuracy.

simon 02.09.2024 14:29

О, это имеет смысл. Позвольте мне попробовать.

EfeK0 02.09.2024 14:31

Я попытался изменить точность наbinary_accuracy, которая по-прежнему остается на уровне 0,95 как для val, так и для обучения. 14-я эпоха, и они оба равны 0,95, а коэффициент кубика равен 0,8 для обучения и 0,68 для проверки. Значения 150-й эпохи и точности составляют 0,9542, а значения коэффициента кубика — 0,94. Все еще происходит то же самое. Значения точности составляли 0,9542 за последние 90 эпох. @саймон

EfeK0 02.09.2024 14:36

Я не ожидал каких-либо изменений, извините, если ввел вас в заблуждение. Я просто пытаюсь лучше понять вашу проблему.

simon 02.09.2024 14:43

Да, я предполагал, что точность изменится вbinary_accuracy, но это тоже не так. У меня есть 125 изображений в наборе данных. Может ли это быть причиной и что мне делать, если я не могу увеличить свой набор данных?

EfeK0 02.09.2024 14:45
Почему в Python есть оператор "pass"?
Почему в Python есть оператор "pass"?
Оператор pass в Python - это простая концепция, которую могут быстро освоить даже новички без опыта программирования.
Некоторые методы, о которых вы не знали, что они существуют в Python
Некоторые методы, о которых вы не знали, что они существуют в Python
Python - самый известный и самый простой в изучении язык в наши дни. Имея широкий спектр применения в области машинного обучения, Data Science,...
Основы Python Часть I
Основы Python Часть I
Вы когда-нибудь задумывались, почему в программах на Python вы видите приведенный ниже код?
LeetCode - 1579. Удаление максимального числа ребер для сохранения полной проходимости графа
LeetCode - 1579. Удаление максимального числа ребер для сохранения полной проходимости графа
Алиса и Боб имеют неориентированный граф из n узлов и трех типов ребер:
Оптимизация кода с помощью тернарного оператора Python
Оптимизация кода с помощью тернарного оператора Python
И последнее, что мы хотели бы показать вам, прежде чем двигаться дальше, это
Советы по эффективной веб-разработке с помощью Python
Советы по эффективной веб-разработке с помощью Python
Как веб-разработчик, Python может стать мощным инструментом для создания эффективных и масштабируемых веб-приложений.
1
7
50
1
Перейти к ответу Данный вопрос помечен как решенный

Ответы 1

Ответ принят как подходящий

Позвольте мне попытаться ответить на часть вашего вопроса: почему точность увеличивается так мгновенно, в то время как коэффициенты игральных костей растут медленно и медленно? Я думаю, это не проблема/ошибка вашей модели или реализации. Я бы сказал, на самом деле, это вообще не «проблема», а скорее свойство ваших метрик:

  • Точность (по пикселям) измеряет правильно назначенное количество пикселей по отношению к общему количеству пикселей. Таким образом, в некотором смысле это мера, которая одинаково оценивает пиксели переднего и заднего плана.
  • Значение Dice или IoU фокусируется только на пикселях переднего плана. Обратите внимание, что ваши реализации dice_coefficients() и iou() всегда подсчитывают только пиксели переднего плана, но не общее количество пикселей в вашем изображении.

Теперь предположим, что у вас есть маска сегментации, в которой всего несколько пикселей переднего плана по отношению к размеру изображения; скажем, ваша правильная маска сегментации — [0, 0, 0, 0, 0, 0, 0, 0, 1, 1]. Если бы ваш прогноз сети теперь был бы нулевым ([0, 0, 0, 0, 0, 0, 0, 0, 0, 0]), его точность уже была бы 0,8 (поскольку 80% пикселей были назначены правильно). Однако значения Dice и IoU будут равны нулю, поскольку ни один пиксель переднего плана еще не назначен правильно.

Следующий пример демонстрирует это с помощью еще нескольких итераций (я использовал NumPy для вычислений, но это не должно иметь значения):

import matplotlib.pyplot as plt
import numpy as np

def dice_coefficients(y_true, y_pred, smooth=0):
    intersection = np.sum(y_true * y_pred)
    union = np.sum(y_true) + np.sum(y_pred)
    return (2 * intersection + smooth) / (union + smooth)

def accuracy(y_true, y_pred, threshold=0.5):
    y_pred = y_pred > threshold
    return (y_true == y_pred).sum() / y_pred.size

y_true = np.asarray([0, 0, 0, 0, 0, 0, 0, 0, 1, 1])

# Round 1: Predict everything as ones
y_pred = np.asarray([1, 1, 1, 1, 1, 1, 1, 1, 1, 1])
print("Acc.", a1 := accuracy(y_true, y_pred))
print("Dice", d1 := dice_coefficients(y_true, y_pred))

# Round 2: Predict everything as zeros
y_pred = np.asarray([0, 0, 0, 0, 0, 0, 0, 0, 0, 0])
print(a2 := accuracy(y_true, y_pred))
print(d2 := dice_coefficients(y_true, y_pred))

# Round 3: Predict one foreground pixel correctly
y_pred = np.asarray([0, 0, 0, 0, 0, 0, 0, 0, 0, 1])
print(a3 := accuracy(y_true, y_pred))
print(d3 := dice_coefficients(y_true, y_pred))

# Round 4: Predict all foreground pixels correctly
y_pred = np.asarray([0, 0, 0, 0, 0, 0, 0, 0, 1, 1])
print(a4 := accuracy(y_true, y_pred))
print(d4 := dice_coefficients(y_true, y_pred))

plt.plot([1, 2, 3, 4], [a1, a2, a3, a4], label = "Acc.")
plt.plot([1, 2, 3, 4], [d1, d2, d3, d4], label = "Dice")
plt.legend()
plt.show()

Соответствующий сюжет

Итог: постарайтесь понять и почувствовать метрики, которые вы используете. Если они ведут себя не так, как вы ожидаете, иногда это может быть проблемой не вашей реализации, а ваших ожиданий.

Спасибо за это потрясающее объяснение. Могу ли я спросить, считается ли это переоснащением в моем случае? Должен ли я действовать так, как будто моя модель переоснащается, чтобы улучшить мои результаты или что? И все же, почему точность может быть такой стабильной на уровне 0,9542, в то время как точность кубика меняется от 0,68 до 0,95?

EfeK0 02.09.2024 16:06

Что касается переобучения: я бы не сказал, что вы испытываете переоснащение. Переоснащение будет означать, что ваши потери при обучении уменьшатся, в то время как ваши потери при проверке стабилизируются или снова увеличатся (или обратное значение для вашей точности/Dice). Это не то, что вы видите. Напротив: ваши потери при проверке в долгосрочной перспективе ведут себя так же, как и ваши потери при обучении; это означает, что ваша модель очень хорошо обобщает. На самом деле я думаю, что ваша модель уже достаточно хороша с Dice выше 0,95.

simon 02.09.2024 16:17

Что касается точности: рассмотрим y_true = [1 0 0] и (1) y_pred = [0 0 1] и (2) y_pred = [1 1 1]. В обоих случаях ваша точность будет 0,33 (одна треть правильно классифицированных пикселей), а ваша кость увеличится с 0,0 в случае (1) до 0,5 в случае (2). Опять же, это связано с тем, что точность и коэффициент Дайса по-разному учитывают (не)правильно назначенные фоновые пиксели.

simon 02.09.2024 16:17

Спасибо за объяснение как переобучения, так и точности. Замечательно! Я также мог бы довести оценку Дайса до 0,9707 ± 0,0007.

EfeK0 02.09.2024 16:51

Другие вопросы по теме