Я новичок в Deep Learning, но я хочу стать профи. Кажется, как без внешнего руководства это трудно сделать: -)
Я пытаюсь принять этот подход https://www.youtube.com/watch?v=azM57JuQpQI&t=23s, который основан на этой статье https://www.depends-on-the-definition.com/unet-keras-segmenting-images/ к моей задаче сегментации спутниковых изображений с использованием UNET с Keras.
Вот мой код для обучения сети
import tensorflow as tf
import os
import random
import numpy as np
from tqdm import tqdm
import cv2
from keras.callbacks import EarlyStopping, ModelCheckpoint, ReduceLROnPlateau
from skimage.io import imread, imshow
from skimage.transform import resize
import matplotlib.pyplot as plt
os.environ['KERAS_BACKEND'] = 'tensorflow'
seed = 42
np.random.seed = seed
IMAGE_HEIGHT = 256
IMAGE_WIDTH = 256
IMAGE_CHANELS = 3
trainImageFolderPath = os.path.join(os.path.dirname(__file__), 'Bright Dunes Groups')
train_ids = next(os.walk(trainImageFolderPath))[1]
X_train = np.zeros((len(train_ids), IMAGE_HEIGHT, IMAGE_WIDTH, IMAGE_CHANELS), dtype=np.uint8)
Y_train = np.zeros((len(train_ids), IMAGE_HEIGHT, IMAGE_WIDTH, 1), dtype=np.bool)
print('Building training set...')
for n, id_ in tqdm(enumerate(train_ids), total=len(train_ids)):
path = os.path.join(trainImageFolderPath, id_)
imagePath = os.path.join(path, id_ + '.jpg')
img = cv2.imread(imagePath)
img = resize(img, (IMAGE_HEIGHT, IMAGE_WIDTH), mode='constant', preserve_range=True)
X_train[n] = img
mask = np.zeros((IMAGE_HEIGHT, IMAGE_WIDTH, 1), dtype=np.bool)
for mask_file in next(os.walk(os.path.join(path, 'masks')))[2]:
maskPath = os.path.join(path, 'masks', mask_file)
mask_ = cv2.imread(maskPath, cv2.IMREAD_GRAYSCALE)
mask_ = resize(mask_, (IMAGE_HEIGHT, IMAGE_WIDTH), mode='constant', preserve_range=True)
mask_ = np.expand_dims(mask_, axis=-1)
mask = np.maximum(mask, mask_)
Y_train[n] = mask
inputs = tf.keras.layers.Input((IMAGE_HEIGHT, IMAGE_WIDTH, IMAGE_CHANELS))
s = tf.keras.layers.Lambda(lambda x: x/255)(inputs)
c1 = tf.keras.layers.Conv2D(16, (3,3), activation='relu', kernel_initializer='he_normal', padding='same')(s)
c1 = tf.keras.layers.Dropout(0.1)(c1)
c1 = tf.keras.layers.Conv2D(16, (3,3), activation='relu', kernel_initializer='he_normal', padding='same')(c1)
p1 = tf.keras.layers.MaxPooling2D((2,2))(c1)
c2 = tf.keras.layers.Conv2D(32, (3,3), activation='relu', kernel_initializer='he_normal', padding='same')(p1)
c2 = tf.keras.layers.Dropout(0.1)(c2)
c2 = tf.keras.layers.Conv2D(32, (3,3), activation='relu', kernel_initializer='he_normal', padding='same')(c2)
p2 = tf.keras.layers.MaxPooling2D((2,2))(c2)
c3 = tf.keras.layers.Conv2D(64, (3,3), activation='relu', kernel_initializer='he_normal', padding='same')(p2)
c3 = tf.keras.layers.Dropout(0.2)(c3)
c3 = tf.keras.layers.Conv2D(64, (3,3), activation='relu', kernel_initializer='he_normal', padding='same')(c3)
p3 = tf.keras.layers.MaxPooling2D((2,2))(c3)
c4 = tf.keras.layers.Conv2D(128, (3,3), activation='relu', kernel_initializer='he_normal', padding='same')(p3)
c4 = tf.keras.layers.Dropout(0.2)(c4)
c4 = tf.keras.layers.Conv2D(128, (3,3), activation='relu', kernel_initializer='he_normal', padding='same')(c4)
p4 = tf.keras.layers.MaxPooling2D((2,2))(c4)
c5 = tf.keras.layers.Conv2D(256, (3,3), activation='relu', kernel_initializer='he_normal', padding='same')(p4)
c5 = tf.keras.layers.Dropout(0.3)(c5)
c5 = tf.keras.layers.Conv2D(256, (3,3), activation='relu', kernel_initializer='he_normal', padding='same')(c5)
u6 = tf.keras.layers.Conv2DTranspose(128, (2,2), strides=(2,2), padding='same')(c5)
u6 = tf.keras.layers.concatenate([u6, c4])
c6 = tf.keras.layers.Conv2D(128, (3,3), activation='relu', kernel_initializer='he_normal', padding='same')(u6)
c6 = tf.keras.layers.Dropout(0.2)(c6)
c6 = tf.keras.layers.Conv2D(128, (3,3), activation='relu', kernel_initializer='he_normal', padding='same')(c6)
u7 = tf.keras.layers.Conv2DTranspose(64, (2,2), strides=(2,2), padding='same')(c6)
u7 = tf.keras.layers.concatenate([u7, c3])
c7 = tf.keras.layers.Conv2D(64, (3,3), activation='relu', kernel_initializer='he_normal', padding='same')(u7)
c7 = tf.keras.layers.Dropout(0.2)(c7)
c7 = tf.keras.layers.Conv2D(64, (3,3), activation='relu', kernel_initializer='he_normal', padding='same')(c7)
u8 = tf.keras.layers.Conv2DTranspose(32, (2,2), strides=(2,2), padding='same')(c7)
u8 = tf.keras.layers.concatenate([u8, c2])
c8 = tf.keras.layers.Conv2D(32, (3,3), activation='relu', kernel_initializer='he_normal', padding='same')(u8)
c8 = tf.keras.layers.Dropout(0.1)(c8)
c8 = tf.keras.layers.Conv2D(32, (3,3), activation='relu', kernel_initializer='he_normal', padding='same')(c8)
u9 = tf.keras.layers.Conv2DTranspose(16, (2,2), strides=(2,2), padding='same')(c8)
u9 = tf.keras.layers.concatenate([u9, c1], axis=3)
c9 = tf.keras.layers.Conv2D(16, (3,3), activation='relu', kernel_initializer='he_normal', padding='same')(u9)
c9 = tf.keras.layers.Dropout(0.1)(c9)
c9 = tf.keras.layers.Conv2D(16, (3,3), activation='relu', kernel_initializer='he_normal', padding='same')(c9)
outputs = tf.keras.layers.Conv2D(1, (1,1), activation='sigmoid')(c9)
model = tf.keras.Model(inputs=[inputs], outputs=[outputs])
model.compile(optimizer='adam',
loss='binary_crossentropy',
metrics=['accuracy'])
model.summary()
######################################################################################################
callbacks = [
EarlyStopping(patience=5, verbose=1),
ReduceLROnPlateau(factor=0.2, patience=3, min_lr=0.001, verbose=1),
ModelCheckpoint('bright_Dunes_Groups_model.h5', verbose=1, save_best_only=True)
]
######################################################################################################
results = model.fit(X_train,
Y_train,
validation_split=0.25,
batch_size=16,
epochs=80,
callbacks = callbacks)
###############################################################
plt.figure(figsize=(8, 8))
plt.title("Learning curve")
plt.plot(results.history["loss"], label="loss")
plt.plot(results.history["val_loss"], label="val_loss")
plt.plot( np.argmin(results.history["val_loss"]), np.min(results.history["val_loss"]), marker="x", color="r", label="best model")
plt.xlabel("Epochs")
plt.ylabel("log_loss")
plt.legend()
###############################################################
idx = random.randint(0, len(X_train))
predictions_train = model.predict(X_train[:int(X_train.shape[0]*0.9)], verbose=1)
predictions_value = model.predict(X_train[int(X_train.shape[0]*0.9):], verbose=1)
predictions_train_t = (predictions_train > 0.5).astype(np.uint8)
predictions_value_t = (predictions_value > 0.5).astype(np.uint8)
###### random training sample
ix = random.randint(0, len(predictions_train_t))
imshow(X_train[ix])
plt.show()
imshow(np.squeeze(Y_train[ix]))
plt.show()
imshow(np.squeeze(predictions_train_t[ix]))
plt.show()
###### random validation sample
ix = random.randint(0, len(predictions_value_t))
imshow(X_train[int(X_train.shape[0]*0.9):][ix])
plt.show()
imshow(np.squeeze(Y_train[int(Y_train.shape[0]*0.9):][ix]))
plt.show()
imshow(np.squeeze(predictions_value_t[ix]))
plt.show()
Мой набор данных trainig состоит из 141 изображения (X_train) и набора масок для каждого из них. Я знаю, это небольшой объем данных, но я бы ожидал чего-то хотя бы от этого набора данных. Точность составляет около 75%, но когда я пытаюсь проверить ее с помощью приведенного ниже кода, я получаю очень плохие результаты.
import tensorflow as tf
import os
import random
import numpy as np
from tqdm import tqdm
import cv2
from skimage.io import imread, imshow
from skimage.transform import resize
import matplotlib.pyplot as plt
os.environ['KERAS_BACKEND'] = 'tensorflow'
IMAGE_HEIGHT = 256
IMAGE_WIDTH = 256
IMAGE_CHANELS = 3
modelFilePath = 'bright_Dunes_Groups_model.h5'
model = tf.keras.models.load_model(modelFilePath)
testImageFolderPath = os.path.join(os.path.dirname(__file__), 'TestDunes')
test_ids = next(os.walk(testImageFolderPath))[2]
for n, id_ in tqdm(enumerate(test_ids), total=len(test_ids)):
imagePath = os.path.join(testImageFolderPath, id_)
img = cv2.imread(imagePath)
img = cv2.resize(img, (IMAGE_HEIGHT, IMAGE_WIDTH))
imshow(img)
plt.show()
img = np.expand_dims(img, axis=0)
predictions = model.predict(img, verbose=1)
predictions_value_t = (predictions > 0.33).astype(np.uint8)
imshow(np.squeeze(predictions_value_t))
plt.show()
Прогнозы очень плохие.
Итак, я подозреваю, что проблема как минимум в 1 из 2 мест: 1) в коде 2) в наборе данных
One образца моего X_train это
образец X_train
Соответствующая маска выглядит следующим образом
Соответствующая маска X_train
Каждый X_train может иметь много масок, но для этого конкретного изображения есть только одна маска.
Каждое изображение X_train имеет размеры 227 * 227 пикселей. В коде я изменяю его размер (и маску) до 256 * 256
. Для каждого изображения X_train я выполняю увеличение данных вручную (поворачиваю X_train и соответствующую маску на 90, 180, 270 градусов и переворачиваю горизонтально и вертикально). Как я уже упоминал, все вместе дополненные данные дают мне 141 изображение X_train.
Один из способов проверить, не связана ли проблема с набором данных, - это генерировать больше X_train и масок. Однако проблема в том, что это ручной процесс и очень трудоемкая операция. Поэтому, прежде чем сделать это, я хочу знать, что еще может быть не так с моим решением.
То, что я также подозреваю как один из источников проблем, что маски могут иметь очень различную форму. Может ли быть так, что неоднородная форма маски создает такой плохой результат предсказания?