Я обучаю модель извлечению мозга на изображениях МРТ. Я использую 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])
Эволюция потери коэффициента Дайса:
Эволюция коэффициента Дайса:
Эволюция точности:
Мои значения кубиков и точности довольно высоки, но я считаю, что будет лучше, если я смогу выяснить проблему модели, если она есть. Я попробовал изменить некоторые гиперпараметры, такие как скорость обучения, процент отсева, номера слоев. Я не могу увеличить пакетный размер выше 16, тогда это дает мне ошибку, ресурс исчерпан, но я использую 3060 Ti и убедился, что тензорный поток использует мой графический процессор. Я добавил пакетную норму, иначе val_accuracy не увеличится, по какой-то непонятной мне причине. Было бы удивительно, если бы вы могли объяснить. Я также изменил свою предварительно обученную модель на другие, такие как VGG16, InceptionResNetV2, и соответственно предварительно обработал ввод, а затем, наконец, EfficientNetV2B3, который дал лучший результат. (Я также использую раннюю остановку и уменьшаю количество обратных вызовов lr)
Почему точность увеличивается так мгновенно, в то время как коэффициенты игральных костей растут медленно и медленно? И как мне добиться точности, не застряв на 0,95?
@simon, я отредактировал вопрос и добавил строки компиляции и подгонки. Я надеюсь, что это ответит на ваш вопрос
Спасибо за обновление, оно действительно полезно! Исходя из этого, я сам пытаюсь ответить на свой вопрос: из вашего кода я делаю вывод, что вы на самом деле используете Keras. Keras автоматически сопоставляет ключевые слова «точности» с одной из трех метрик. В вашем случае, я думаю (я не очень знаком с Керасом), это должно быть BinaryAccuracy.
О, это имеет смысл. Позвольте мне попробовать.
Я попытался изменить точность наbinary_accuracy, которая по-прежнему остается на уровне 0,95 как для val, так и для обучения. 14-я эпоха, и они оба равны 0,95, а коэффициент кубика равен 0,8 для обучения и 0,68 для проверки. Значения 150-й эпохи и точности составляют 0,9542, а значения коэффициента кубика — 0,94. Все еще происходит то же самое. Значения точности составляли 0,9542 за последние 90 эпох. @саймон
Я не ожидал каких-либо изменений, извините, если ввел вас в заблуждение. Я просто пытаюсь лучше понять вашу проблему.
Да, я предполагал, что точность изменится вbinary_accuracy, но это тоже не так. У меня есть 125 изображений в наборе данных. Может ли это быть причиной и что мне делать, если я не могу увеличить свой набор данных?
Позвольте мне попытаться ответить на часть вашего вопроса: почему точность увеличивается так мгновенно, в то время как коэффициенты игральных костей растут медленно и медленно? Я думаю, это не проблема/ошибка вашей модели или реализации. Я бы сказал, на самом деле, это вообще не «проблема», а скорее свойство ваших метрик:
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?
Что касается переобучения: я бы не сказал, что вы испытываете переоснащение. Переоснащение будет означать, что ваши потери при обучении уменьшатся, в то время как ваши потери при проверке стабилизируются или снова увеличатся (или обратное значение для вашей точности/Dice). Это не то, что вы видите. Напротив: ваши потери при проверке в долгосрочной перспективе ведут себя так же, как и ваши потери при обучении; это означает, что ваша модель очень хорошо обобщает. На самом деле я думаю, что ваша модель уже достаточно хороша с Dice выше 0,95.
Что касается точности: рассмотрим 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). Опять же, это связано с тем, что точность и коэффициент Дайса по-разному учитывают (не)правильно назначенные фоновые пиксели.
Спасибо за объяснение как переобучения, так и точности. Замечательно! Я также мог бы довести оценку Дайса до 0,9707 ± 0,0007.
Как вы рассчитываете значение точности на основе результатов сегментации?