Сегментация изображения — это процесс разделения изображения на разные области или сегменты на основе определенных критериев, таких как цвет, текстура или интенсивность. Это фундаментальная задача компьютерного зрения, которая используется в различных приложениях, таких как обнаружение объектов, анализ медицинских изображений и автономное вождение.
TensorFlow — это популярная платформа машинного обучения с открытым исходным кодом, которая предоставляет мощные инструменты для создания и обучения моделей глубокого обучения, в том числе для сегментации изображений.
Цель
В этом проекте мы будем использовать инфраструктуру машинного обучения TensorFlow для обучения и оценки нейронной сети сегментации изображений с использованием набора данных медицинских изображений. Мы выполним семантическую сегментацию, чтобы классифицировать каждый пиксель на МРТ-изображении сердца, независимо от того, является ли пиксель частью левого желудочка (ЛЖ) или нет.
Набор данных
Вам нужно будет зарегистрироваться на Веб-сайте Cardiac MR Left Ventricle Segmentation Challenge, и ссылки для скачивания набора данных будут отправлены вам по электронной почте. Набор данных представляет собой серию изображений сердца (в частности, МРТ-сканов с короткой осью (SAX)) с экспертной маркировкой.
Репрезентативный пример данных показан выше. Слева — МРТ-изображения, а справа — экспертно-сегментированные области (часто называемые контурами). Части изображений, входящие в состав LV, обозначены белым цветом. Извлечение данных из необработанных изображений и последующая подготовка этих изображений в этой статье не рассматриваются.
1. Визуализация набора данных
Мы определим функцию «отображение» для отображения изображения и его метки, а затем запустим ее в нашем обучении.
# function to display an image, it's label def display(display_list): plt.figure(figsize=(10, 10)) title = ['Input Image', 'Label'] for i in range(len(display_list)): display_resized = tf.reshape(display_list[i], [256, 256]) plt.subplot(1, len(display_list), i+1) plt.title(title[i]) plt.imshow(display_resized) plt.axis('off') plt.show() # display 3 random images and labels from the training set for image, label in train.take(3): sample_image, sample_label = image, label display([sample_image, sample_label])
Вывод:
# an image and label from validation data for image, label in val.take(1): sample_image, sample_label = image, label display([sample_image, sample_label])
Вывод:
2. Построение модели
Входными данными будут значения каждого пикселя, и, поскольку изображения черно-белые, мы будем использовать 1 цветовой канал. Слой ожидает векторное представление, а не матрицу, поэтому мы сгладим матричное представление изображений. Скрытый плотный слой будет иметь размер, который вы можете настроить на любое положительное целое число.
Каждый входной пиксель может относиться к двум классам; Левый желудочек (LV) или нет, поэтому это будет вывод. Затем мы изменим форму вектора, чтобы просмотреть его как изображение.
tf.keras.backend.clear_session() # set up the model architecture model = tf.keras.models.Sequential([ Flatten(input_shape=[256, 256, 1]), Dense(64, activation='relu'), Dense(256*256*2, activation='softmax'), Reshape((256, 256, 2)) ]) # specify how to train the model with algorithm, the loss function and metrics model.compile( optimizer='adam', loss=tf.keras.losses.SparseCategoricalCrossentropy(from_logits=True), metrics=['accuracy']) # plot the model including the sizes of the model tf.keras.utils.plot_model(model, show_shapes=True)
Вывод:
3. Обучение модели
EPOCHS = 20 STEPS_PER_EPOCH = len(list(parsed_train_data)) VALIDATION_STEPS = 26 model_history = model.fit(train_dataset, epochs=EPOCHS, steps_per_epoch=STEPS_PER_EPOCH, validation_steps=VALIDATION_STEPS, validation_data=test_dataset, callbacks=[tensorboard_callback])
Вывод:
Код будет выводить каждую эпоху и статистику ее модели.
4. Оценка модели
Оценка производительности модели.
# output model statistics loss = model_history.history['loss'] val_loss = model_history.history['val_loss'] accuracy = model_history.history['accuracy'] val_accuracy = model_history.history['val_accuracy'] epochs = range(EPOCHS) plt.figure() plt.plot(epochs, loss, 'r', label='Training loss') plt.plot(epochs, val_loss, 'bo', label='Validation loss') plt.title('Training and Validation Loss') plt.xlabel('Epoch') plt.ylabel('Loss Value') plt.ylim([0, 1]) plt.legend() plt.show()
Вывод:
#model evaluation on the test dataset model.evaluate(test_dataset)
Модель имела потери 0,6931 и точность 0,986. Модель не работала хорошо, так как функция потерь очень высока.
5. CNN с Dice Metric Loss
Одна метрика, которую мы можем использовать для более точного определения того, насколько хорошо наша сеть сегментирует LV, среди прочего называется метрикой Дайса или коэффициентом Соренсена-Дайса. Это метрика для сравнения сходства двух образцов. В нашем случае мы будем использовать его для сравнения двух областей интереса, то есть площади контура, помеченного экспертом, и площади нашего прогнозируемого контура.
#dice coef function def dice_coef(y_true, y_pred, smooth=1): indices = K.argmax(y_pred, 3) indices = K.reshape(indices, [-1, 256, 256, 1]) true_cast = y_true indices_cast = K.cast(indices, dtype='float32') axis = [1, 2, 3] intersection = K.sum(true_cast * indices_cast, axis=axis) union = K.sum(true_cast, axis=axis) + K.sum(indices_cast, axis=axis) dice = K.mean((2. * intersection + smooth)/(union + smooth), axis=0) return dice #clear the backend session to free up memory tf.keras.backend.clear_session() #define the layers of the model architecture layers = [ Conv2D(input_shape=[256, 256, 1], filters=100, kernel_size=5, strides=2, padding="same", activation=tf.nn.relu, name="Conv1"), MaxPool2D(pool_size=2, strides=2, padding="same"), Conv2D(filters=200, kernel_size=5, strides=2, padding="same", activation=tf.nn.relu), MaxPool2D(pool_size=2, strides=2, padding="same"), Conv2D(filters=300, kernel_size=3, strides=1, padding="same", activation=tf.nn.relu), Conv2D(filters=300, kernel_size=3, strides=1, padding="same", activation=tf.nn.relu), Conv2D(filters=2, kernel_size=1, strides=1, padding="same", activation=tf.nn.relu), Conv2DTranspose(filters=2, kernel_size=31, strides=16, padding="same") ] #create a sequential model with the defined layers model = tf.keras.models.Sequential(layers) #compiling the model model.compile( optimizer='adam', loss=tf.keras.losses.SparseCategoricalCrossentropy(from_logits=True), metrics=['accuracy']) #setting up and running the model EPOCHS = 20 STEPS_PER_EPOCH = len(list(parsed_train_data)) VALIDATION_STEPS = 26 model_history = model.fit(train_dataset, epochs=EPOCHS, steps_per_epoch=STEPS_PER_EPOCH, validation_steps=VALIDATION_STEPS, validation_data=test_dataset)
Вывод:
Модель имела убыток 0,0871 и точность 0,9830.
Мы снова запустим модель на этот раз с 30 эпохами и измерим потери метрики в кости.
tf.keras.backend.clear_session() layers=layers # the layers in our model architecture model = tf.keras.models.Sequential(layers) # the model model.compile( optimizer='adam', loss=tf.keras.losses.SparseCategoricalCrossentropy(from_logits=True), metrics=[dice_coef,'accuracy']) # setting up and running the model using 30 passes EPOCHS = 30 STEPS_PER_EPOCH = len(list(parsed_train_data)) model_history = model.fit(train_dataset, epochs=EPOCHS, steps_per_epoch=STEPS_PER_EPOCH, validation_data=test_dataset) #evaluating the model using the test dataset model.evaluate(test_dataset)
Вывод:
Модель улучшилась, дав потери 0,0863, коэффициент кости 0,049 и точность 0,983.