深度学习学习笔记(四)—— Tensorflow2+BRRNet进行遥感图像的建筑物提取

深度学习学习笔记(四)—— Tensorflow2+BRRNet进行遥感图像的建筑物提取

文章目录

  • 深度学习学习笔记(四)—— Tensorflow2+BRRNet进行遥感图像的建筑物提取
    • 1 前言
    • 2 BRRNet模型简介
      • 2.1 模型总览
      • 2.2 预测模块(prediction module)
      • 2.3 残差修正模块(Residual Refinement module)
    • 3 程序设计
      • 3.1 数据源与图像裁切
      • 3.2 tfrecords文件的制作
      • 3.3 BRRNet模型的建立、训练和预测
    • 4 模型结果和遇到的问题
      • 4.1 论文理论结果和实际结果对比
      • 4.2 实验问题

1 前言

  过年前后两周确实懈怠了这方面的学习,进度不明显,基本都在原地踏步,所以这两周都没交周报。这一周还算做了点东西,加上之前零零散散的进度,写了寒假的第四次周报。

2 BRRNet模型简介

  BRRNet全称是Building Residual Refine Network,由预测模块(predict)和残差细化模块(residual refinement)两部分组成。基于编解码器结构的预测模块引入不同膨胀率的空洞卷积,逐步提取更多的全局特征特征提取过程中增强感受域。当预测模块输出对输入图像进行初步的建筑物提取结果,残差细化模块取预测模块的输出作为输入。它进一步细化的剩余之间的结果,预测模块与真实结果相匹配,从而提高了建筑物提取的准确性。
  此外,该模型在训练过程中使用Dice_loss作为损失函数,有效地缓解了数据不平衡,进一步提高了建筑物提取的准确性。实验结果预期优于其他五种最先进的方法(其中包含deeplabV3+)。

2.1 模型总览

深度学习学习笔记(四)—— Tensorflow2+BRRNet进行遥感图像的建筑物提取_第1张图片

2.2 预测模块(prediction module)

  这一部分的设计论文参考了U-Net和空洞卷积的结构,它由五个部分组成:输入、编码器、桥接、解码器和输出。我们的输入实验是遥感图像瓦片。编码器使用了U-Net编码器的前三块,其中每个块是一个两层卷积和一个最大池化层,窗口大小为 2 ∗ 2 2*2 22和步长为2。卷积运算后,Batch归一化,执行ReLu激活函数。在这些块中使用的卷积内核大小是 3 ∗ 3 3*3 33,以及内核的数量分别是64 128 256。预测模块的编码器删除了第四个块U-Net的编码器因为第4块有大量的参数。
  前面的从高分辨率图像中提取建筑物的深度学习方法通常存在问题,如不完整的建筑提取和不准确的建筑足迹提取。对于这些问题的一个重要原因,就是要避免输入图像的信息严重丢失,从而影响最终的效果与定位精度。对于只使用少量的池操作的网络。对于遥感影像,建筑物所占用的像素数会随着分辨率提高。我们称图像中像素更多的建筑为大型建筑,甚至更多在高分辨率的偏远地区,大型建筑的色调和纹理不一致或形状复杂,仅使用少量的池层会导致接受能力不足覆盖整个建筑和周围的背景。因此,不可能提取整个建筑具有全局特征,导致建筑提取不完整等问题以及不准确的建筑足迹提取。
  为了进一步提高接受能力提取更多的全局信息,同时避免了丢失的信息,在尽可能多的图像中,我们采用一种扩展的卷积级数结构,逐次递增,预测模块桥梁连接部分的膨胀率。卷积的大小kernel是 3 ∗ 3 3*3 33,卷积kernel的个数是512。膨胀率设置为1,2,4,8,16,依次是32个。这些超参数在实验验证集上进行调整。
  每个区块包括一个反卷积层和两个卷积层。反卷积操作是将前一阶段得到的特征图上采样2次次数,然后将更新的采样特征映射和相应的编码器映射连接起来。然后,通过两个卷积层提取特征。每一个卷积层后面是批处理标准化和ReLu激活功能。在解码器之后,我们使用一个卷积大小为1的kernel 1 ∗ 1 ∗ 64 1*1*64 1164将feature map的通道数转换为1,然后使用Sigmoid激活函数,最终得到预测的预测概率图模块。为了进一步纠正预测模块结果与实际结果之间的残差,将预测概率图输入残差细分模块。

2.3 残差修正模块(Residual Refinement module)

  它与上一个模块的bridge的结构相似(预测模块中的连接部分),它使用6个旋转卷积,膨胀率为1、2、4、8、16、32提取特征,然后将不同尺度的特征图融合的方式。每次卷积操作后,进行批处理归一化和ReLu激活函数使用。空洞卷积的核数是64。然后是一个具有大小的卷积核 3 ∗ 3 ∗ 64 3*3*64 3364, step size为1,将feature map的通道数转换为1。自输入的RRM_Bu图像包含了预测模块的初步信息,我们将其融合将这一阶段得到的特征映射以加性方式输入图像,然后输入将结果融合到Sigmoid函数中,得到最终的概率图。下图为RRM_Bu(b)和RRM_Lc(a)的对比。
深度学习学习笔记(四)—— Tensorflow2+BRRNet进行遥感图像的建筑物提取_第2张图片

3 程序设计

程序使用的环境为python3.7+tensorflow2.1.

3.1 数据源与图像裁切

  训练集、验证集和测试集均来源于ISPRS的Vaihingen数据。首先得把遥感图像进行裁剪成 256 ∗ 256 256*256 256256,为了增大训练集的数量,设置了裁切步长为64像素,大大地增加了数据集的总体数量。

def crop(imgs_in, segs_in, imgs_out, segs_out, size, stride):
    num = 0
    filename = glob.glob(imgs_in+'/*.tif')
    l = len(filename)
    for i in range(len(filename)):
        print("准备裁剪第%d张影像..."%(i+1))
        img = io.imread(imgs_in + '/' + filename[i].split('\\')[1])
        seg = io.imread(segs_in + '/' + filename[i].split('\\')[1])
        #seg = np.loadtxt(segs_in + '/' + filename[i].split('\\')[1].split('.')[0] + '.txt')
        seg = np.uint8(seg)
        length, width = img.shape[0:2]
        m = math.floor((length - size)/stride) + 1
        n = math.floor((width - size)/stride) + 1
        for j in range(m):
            for k in range(n):               
                img_patch = img[stride*j:stride*j+size, stride*k:stride*k+size, :]
                seg_patch = seg[stride*j:stride*j+size, stride*k:stride*k+size]
                # 影像块中白色部分的比例
                white_proportion = white_proportion_of_img(img_patch)
                # print("white proportion of img_patch:%f"%(white_proportion))
                if white_proportion<0.01:
                    io.imsave(imgs_out + '/' + str(num) + '.tif', img_patch)
                    io.imsave(segs_out + '/' + str(num) + '.tif', seg_patch)
                    num += 1
    print("共得到裁剪瓦片数目为:%d"%(num))

3.2 tfrecords文件的制作

  为了增强tensorflow框架读取数据的速度,这里设计了tfrecords文件,同时将img进行reshape,label转化成单通道。

def img2TFRecord(img_dir,label_dir,tfrecord_file,num_examples_txt_file):
    """
    将图像和对应的标签制作成TFRecord文件,之后使用tf.data.TFRecordDataset读取TFRecord文件制作成dataset
    :img_dir: 图像的文件夹
    :label_dir: 标签的文件夹
    :tfrecord_file: tfrecord文件,如 "train.tfrecords"
    :num_examples_txt_file: 存放样本数目的txt文件
    """
    # 要生成的tfrecord文件
    print("prepare to generate %s..."%(tfrecord_file))
    t0 = time.time()
    writer = tf.io.TFRecordWriter(tfrecord_file)
    img_filenames = glob.glob(img_dir+'/*.tif') # list all files in the img folder
    num_examples = len(img_filenames)
    # 把样本数目写入在一个txt中,之后需要用
    with open(num_examples_txt_file,'w') as f:
        f.write(str(num_examples))

    for i in range(len(img_filenames)):
        img_name = img_filenames[i].split("\\")[1]
        # 对应的label文件
        label_filename = label_dir + '/' + img_name
        #img = Image.open(img_filenames[i])
        img = io.imread(img_filenames[i])
        #label = Image.open(label_filename)
        label = io.imread(label_filename)

        # transfer label from RGB to gray value
        im_size = label.shape[:2]
        new_mask = np.zeros(im_size,dtype='uint8')
        c1 = np.stack([label[...,0]<50,label[...,1]<50,label[...,2]>200],axis=-1)
        new_mask[c1.all(-1)] = 255
        #label = new_mask

        # resize image and label (for test in the trial)
        # in practice, we have to crop the images to avoid artifacts 
        img = resize(img,(256,256,3),preserve_range=True)
        new_mask = resize(new_mask,(256,256),preserve_range=True)
        img = img.astype('uint8')
        new_mask = new_mask.astype('uint8')
        # 将图像和Label转化为二进制格式
        img_raw = img.tobytes()
        label_raw = new_mask.tobytes()
        # 对label和img进行封装
        example = tf.train.Example(features=tf.train.Features(feature={
     
            "label_raw": tf.train.Feature(bytes_list=tf.train.BytesList(value=[label_raw])),
            'img_raw': tf.train.Feature(bytes_list=tf.train.BytesList(value=[img_raw]))
        }))
        # 序列化为字符串
        writer.write(example.SerializeToString())

3.3 BRRNet模型的建立、训练和预测

  这里的原理在第二部分已经说过了,还有loss_Functionpredict().

#############自定义损失函数#####################
def dice_coeff(self,y_true, y_pred):
    smooth = 1.
    # Flatten
    y_true_f = tf.reshape(y_true, [-1])
    y_pred_f = tf.reshape(y_pred, [-1])
    intersection = tf.reduce_sum(y_true_f * y_pred_f)
    # something wrong
    # score = (2. * intersection + smooth) / (tf.reduce_sum(y_true_f) + tf.reduce_sum(y_pred_f) + smooth)
    score = (intersection) / (tf.reduce_sum(tf.square(y_true_f)) + tf.reduce_sum(tf.square(y_pred_f)))
    return score

def dice_loss(self, y_true, y_pred):
    loss = 1 - self.dice_coeff(y_true, y_pred)
    return loss
    
def predict(self,img_dir,save_dir):
    # 加载训练好的模型
    model = keras.models.load_model(self.savemodel_path,custom_objects={
     'dice_loss':self.dice_loss})
    filenames = glob.glob(img_dir+'/*.tif')
    for i in range(len(filenames)):
        img_name = filenames[i].split("\\")[1]
        img = io.imread(filenames[i])
        # 归一化
        img = np.float32(img) * (1.0/255)
        #print(img.shape)
        img = np.expand_dims(img,0)
        #print(img.shape)
        prediction = model.predict(img)
        prediction[prediction>0.5] = 1
        prediction[prediction<=0.5] = 0
        # 把4-d 改为2-d
        prediction = prediction[0,:,:,0]
        #print('prediction shape')
        #print(prediction.shape)
        io.imsave(save_dir+'/'+img_name,prediction)
    print("预测结果保存路径:%s"%(save_dir))

4 模型结果和遇到的问题

4.1 论文理论结果和实际结果对比

  • 理想结果

深度学习学习笔记(四)—— Tensorflow2+BRRNet进行遥感图像的建筑物提取_第3张图片

  • 实际结果
Parameters results
PA 0.2043365478515625
F1_score 0.33933462903883826
precision 0.2043365478515625
IOU 0.2043365478515625

深度学习学习笔记(四)—— Tensorflow2+BRRNet进行遥感图像的建筑物提取_第4张图片

4.2 实验问题

  • 模型复现结果与论文理论结果差距巨大……目前还在找原因,大概率是本人代码编写的问题,不过已经找了好几天了,没有啥收获。

1、参考论文-BRRNet: A Fully Convolutional Neural Network for Automatic Building Extraction From High-Resolution Remote Sensing Images
2、项目参考

你可能感兴趣的:(tensorflow,卷积神经网络)