Keras UNET实施预测非常糟糕

Keras UNET实施预测非常糟糕,keras,conv-neural-network,image-segmentation,Keras,Conv Neural Network,Image Segmentation,我对深度学习还不熟悉,但我想成为一名专业人士。似乎,没有外部指导很难做到:-) 我正试图采用这种基于本文的方法来完成使用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, ModelCheckpoin

我对深度学习还不熟悉,但我想成为一名专业人士。似乎,没有外部指导很难做到:-)

我正试图采用这种基于本文的方法来完成使用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) 在数据集中

我的X_列车的一个样本是

对应的掩码如下所示

s = tf.keras.layers.Lambda(lambda x: x)(inputs)

每个X_序列可以有许多遮罩,但对于这个特定的图像,只有一个遮罩

每个X_系列图像的尺寸为227*227像素。在代码中,我将其大小(和掩码)调整为256*256

对于每个X_序列图像,我手动执行数据增强(我将X_序列和相应的遮罩旋转90、180、270度,并水平和垂直翻转)。正如我所提到的,所有的增强数据给了我141张X_列车图像

检查数据集是否存在问题的方法之一是生成更多的X_序列和掩码。然而,问题是这是一个手动过程,而且非常耗时。所以,在做这件事之前,我想知道我的解决方案还有什么问题


我还怀疑,作为问题的根源之一,面具可能有非常不同的形状。可能是掩码的非同质形状造成了这种糟糕的预测结果吗?

我看到了(不是解决问题,而是)重新检查代码/数据集的一些起点。我总结如下:

  • 您正在使用
    skimage.transform.resize
    调整训练数据的大小,但是您正在使用
    cv2.resize
    调整测试数据的大小。我会小心的。确保他们两个都做同样的事情。某些函数在调整大小时缩放值的范围
  • 您有一个lambda层,该层需要将[0,255]范围内的输入重新缩放到[0,1]范围。同样,请确保预处理调整大小功能尚未为您执行此操作
  • 通常,除以255.0是将输入图像重新缩放到[0,1]范围内的一个很好的快捷方式,它适用于RGB图像,因为像素值在[0,255]范围内,但请确保卫星图像也具有此范围,否则,此操作无法按预期工作,您需要将其除以您自己卫星图像中的最大值,而不是255

  • 希望能有帮助。祝你好运。

    我看到了(不是解决问题,而是)重新检查代码/数据集的一些起点。我总结如下:

  • 您正在使用
    skimage.transform.resize
    调整训练数据的大小,但是您正在使用
    cv2.resize
    调整测试数据的大小。我会小心的。确保他们两个都做同样的事情。某些函数在调整大小时缩放值的范围
  • 您有一个lambda层,该层需要将[0,255]范围内的输入重新缩放到[0,1]范围。同样,请确保预处理调整大小功能尚未为您执行此操作
  • 通常,除以255.0是将输入图像重新缩放到[0,1]范围内的一个很好的快捷方式,它适用于RGB图像,因为像素值在[0,255]范围内,但请确保卫星图像也具有此范围,否则,此操作无法按预期工作,您需要将其除以您自己卫星图像中的最大值,而不是255

  • 希望能有帮助。祝你好运。

    所以,我听从了巴希尔·卡齐米的建议,现在我看到了显著的进步

    首先,我必须提到,我用于训练的图像是灰度的,而不是我试图采用的样本中的RGB。我认为,这是造成这种不准确预测的主要原因

    我所做的 1) 在培训和测试中,将openCV的阅读和大小调整为略读 2) 删除输入到255的Lambda层划分

    对于2)我不确定我是否理解Bashir Kazimi的建议,但现在我知道没有必要将X_train图像缩放到[0255]范围,因为这些图像已经在这个范围内。这是我现在唯一改变的重要事情。是否还有其他假设

    现在lambda层看起来像这样

    s = tf.keras.layers.Lambda(lambda x: x)(inputs)
    

    所以,我遵循了巴希尔·卡齐米的建议,现在我看到了显著的改进

    首先,我必须提到,我用于训练的图像是灰度的,而不是我试图采用的样本中的RGB。我认为,这是造成这种不准确预测的主要原因

    我所做的 1) 在培训和测试中,将openCV的阅读和大小调整为略读 2) 删除输入到255的Lambda层划分

    对于2)我不确定我是否理解Bashir Kazimi的建议,但现在我知道没有必要将X_train图像缩放到[0255]范围,因为这些图像已经在这个范围内。这是我现在唯一改变的重要事情。是否还有其他假设

    现在lambda层看起来像这样

    s = tf.keras.layers.Lambda(lambda x: x)(inputs)
    

    很棒的观点!将对此进行检查并使用结果更新帖子。谢谢非常感谢你的建议。我不确定我是否理解第二点。对于X_序列,我在代码中没有看到将范围[0255]转换为[0,1]的情况。请你澄清一下好吗?第三点。。。因为我的X_系列图像是灰度的(这意味着每个图像都有不同的最大像素值),我应该跳过分割图像的值吗?我说的对吗?很好!将对此进行检查并使用结果更新帖子。谢谢非常感谢你的建议。我不确定我