Если точнее, я получаю три разных типа оценок каждый раз, когда запускаю обучение. :
- Очень сильная первая эпоха, остальные быстро набрали >99,99% баллов.
- Очень слабая первая эпоха эпоха (99,99% баллов.
- Нормальная первая эпоха (от 60% до 80%, в зависимости от показателя), которая немного улучшается во время обучения .
Я не уверен, какая дополнительная информация может потребоваться, чтобы понять, что здесь происходит, но если вы можете мне помочь, буду очень признателен. В частности, я хочу:
- Понять, почему результаты так сильно различаются.
- Понять, почему результаты достигают 99,99 %. когда производительность сегментации не так хороша.
Весь код Unet можно найти в следующем блоке
''' 3D U-net for binary semantic segmentation'''
import numpy as np
from sklearn.model_selection import train_test_split
import os
import numpy as np
from tensorflow.keras.utils import to_categorical
import tensorflow as tf
from tensorflow.keras.layers import Input, Conv3D, MaxPooling3D, Conv3DTranspose, concatenate, BatchNormalization, ReLU, Dropout, UpSampling3D
from tensorflow.keras.metrics import IoU
from tensorflow.keras.models import Model
from tensorflow.keras import backend as K
# Custom Dice coefficient metric
def dice_coefficient(y_true, y_pred):
y_true_f = K.flatten(y_true)
y_pred_f = K.flatten(y_pred)
intersection = K.sum(y_true_f * y_pred_f)
return (2. * intersection + 1) / (K.sum(y_true_f) + K.sum(y_pred_f) + 1)
# Custom IoU metric
def iou_metric(y_true, y_pred):
y_true_f = K.flatten(y_true)
y_pred_f = K.flatten(y_pred)
intersection = K.sum(y_true_f * y_pred_f)
union = K.sum(y_true_f) + K.sum(y_pred_f) - intersection
return (intersection + 1) / (union + 1)
# U-net model for 64x64x64 images using the first custom architecture
def UNET_64x64x64_custom1(input_shape, n_classes):
inputs = Input(input_shape)
# Encoding path
c1 = Conv3D(32, (3, 3, 3), activation='relu', padding='same')(inputs)
c1 = Dropout(0.1)(c1)
c1 = Conv3D(32, (3, 3, 3), activation='relu', padding='same')(c1)
p1 = MaxPooling3D((2, 2, 2))(c1)
c2 = Conv3D(64, (3, 3, 3), activation='relu', padding='same')(p1)
c2 = Dropout(0.1)(c2)
c2 = Conv3D(64, (3, 3, 3), activation='relu', padding='same')(c2)
p2 = MaxPooling3D((2, 2, 2))(c2)
c3 = Conv3D(128, (3, 3, 3), activation='relu', padding='same')(p2)
c3 = Dropout(0.2)(c3)
c3 = Conv3D(128, (3, 3, 3), activation='relu', padding='same')(c3)
p3 = MaxPooling3D((2, 2, 2))(c3)
c4 = Conv3D(256, (3, 3, 3), activation='relu', padding='same')(p3)
c4 = Dropout(0.2)(c4)
c4 = Conv3D(256, (3, 3, 3), activation='relu', padding='same')(c4)
p4 = MaxPooling3D((2, 2, 2))(c4)
# Bottleneck
c5 = Conv3D(512, (3, 3, 3), activation='relu', padding='same')(p4)
c5 = Dropout(0.3)(c5)
c5 = Conv3D(512, (3, 3, 3), activation='relu', padding='same')(c5)
# Decoding path
u6 = UpSampling3D((2, 2, 2))(c5)
u6 = concatenate([u6, c4])
c6 = Conv3D(256, (3, 3, 3), activation='relu', padding='same')(u6)
c6 = Dropout(0.2)(c6)
c6 = Conv3D(256, (3, 3, 3), activation='relu', padding='same')(c6)
u7 = UpSampling3D((2, 2, 2))(c6)
u7 = concatenate([u7, c3])
c7 = Conv3D(128, (3, 3, 3), activation='relu', padding='same')(u7)
c7 = Dropout(0.2)(c7)
c7 = Conv3D(128, (3, 3, 3), activation='relu', padding='same')(c7)
u8 = UpSampling3D((2, 2, 2))(c7)
u8 = concatenate([u8, c2])
c8 = Conv3D(64, (3, 3, 3), activation='relu', padding='same')(u8)
c8 = Dropout(0.1)(c8)
c8 = Conv3D(64, (3, 3, 3), activation='relu', padding='same')(c8)
u9 = UpSampling3D((2, 2, 2))(c8)
u9 = concatenate([u9, c1])
c9 = Conv3D(32, (3, 3, 3), activation='relu', padding='same')(u9)
c9 = Dropout(0.1)(c9)
c9 = Conv3D(32, (3, 3, 3), activation='relu', padding='same')(c9)
outputs = Conv3D(n_classes, (1, 1, 1), activation='softmax')(c9)
model = Model(inputs=[inputs], outputs=[outputs])
return model
def custom_weighted_categorical_crossentropy(weights):
weights = K.variable(weights)
def loss(y_true, y_pred):
y_pred = K.clip(y_pred, K.epsilon(), 1 - K.epsilon())
y_pred /= K.sum(y_pred, axis=-1, keepdims=True)
cce = y_true * K.log(y_pred)
weighted_cce = cce * weights
return -K.sum(weighted_cce, axis=-1)
return loss
def main():
# Parameters model
input_shape = (64, 64, 64, 3)
architecture = UNET_64x64x64_custom1
epochs = 1
batch_size = 4
# Parameters input
input_dir = "data/Input"
img_file = "ADCs.npy"
mask_file = "Masks.npy"
# Parameters output
output_dir = 'output'
model_name = "output/model.h5"
# Binary classification
n_classes=2
# Read files
if not os.path.exists(output_dir):
os.makedirs(output_dir)
input_img = np.load(os.path.join(input_dir, img_file))
input_mask = np.load(os.path.join(input_dir, mask_file))
# Combine the first two dims to get N images
train_img = np.stack((input_img,)*3, axis=-1)
# Images to three channels.
train_mask = np.expand_dims(input_mask, axis=4)
# Binary masks to categorical.
train_mask = (train_mask > 0).astype(np.uint8)
train_mask_cat = to_categorical(train_mask, num_classes=n_classes)
# Divide training data between train and validation sets
X_train, X_val, y_train, y_val = train_test_split(train_img, train_mask_cat, test_size = 0.1, random_state = 0)
# Train
model = architecture(input_shape, n_classes)
model.compile(
optimizer='adam',
loss=custom_weighted_categorical_crossentropy([0.5005, 564.4044]),
metrics=[
'accuracy',
tf.keras.metrics.Recall(),
iou_metric,
dice_coefficient,
IoU(num_classes=2, target_class_ids=[0,1])
]
)
model.summary()
model.fit(X_train, y_train,
validation_data=(X_val, y_val),
epochs=epochs,
batch_size=batch_size
)
model.save(model_name, include_optimizer=True)
if __name__ == "__main__":
# We want to use the relative path of the file (instead of the project one).
current_dir = os.path.dirname(os.path.abspath(__file__))
os.chdir(current_dir)
main()
Подробнее здесь: https://stackoverflow.com/questions/790 ... -sometimes