• 【CV】Landslide4Sense-2022


    环境

    • 代码包来源:https://github.com/iarai/Landslide4Sense-2022、https://www.iarai.ac.at/landslide4sense/challenge/
    • 代码包路径:E:\Downloads\20220916-Landslide4Sense-2022-main\Landslide4Sense-2022-main(已传至百度网盘) 或 E:\Downloads\Landslide4Sense-2022-main (2)\Landslide4Sense-2022-main
    • 自用电脑运行环境:使用自建的Python 3.8虚拟环境,位于D:\software\anaconda3\envs\LandSlide_Detection_Faster-RCNN-main;常规Anaconda3 Python 3.9环境可能配置存在些许问题,运行代码报错 “Torch not compiled with CUDA enabled”,故未用
    图 1 Python 3.8虚拟环境设置

    数据

    • dataset数据情况:image_1.h5(128×128×14),其中,训练集有mask标注(mask_1.h5,128×128×2)。源代码Train.py的test_list路径指向训练数据集。
    • 查看h5文件:h5_visualization.py读取解压h5文件为图片(https://blog.csdn.net/qq_39909808/article/details/125047516),image_1.h5转为image_1.nii.gz后打开,如下图
    图 2 模型自带h5数据一览

    批量设置图像尺寸

    1. from PIL import Image
    2. import os
    3. file_path = r"E:\Downloads\Landslide4Sense-2022-main(2)-(2)\Landslide4Sense-2022-main\dataset\TrainData\mask\20220915mask" # 原始图像路径
    4. raw_files = os.walk(file_path) # 遍历所有图像
    5. width, height = 128, 128 # 修改后的图像尺寸大小
    6. save_path = r"E:\Downloads\Landslide4Sense-2022-main(2)-(2)\Landslide4Sense-2022-main\dataset\TrainData\mask\20220915mask\resize" # 修改后图像存储的路径
    7. if not os.path.exists(save_path): # 如果没有这个文件夹,就新建
    8. os.makedirs(save_path)
    9. for root, dirs, files in raw_files:
    10. for file in files: # 展现各文件
    11. picture_path = os.path.join(root, file) # 得到图像的绝对路径
    12. pic_org = Image.open(picture_path) # 打开图像
    13. pic_new = pic_org.resize((width, height), Image.ANTIALIAS) # 图像尺寸修改
    14. _, sub_folder = os.path.split(root) # 得到子文件夹名字
    15. pic_new_path = os.path.join(save_path, sub_folder)
    16. if not os.path.exists(pic_new_path):
    17. os.makedirs(pic_new_path) # 建立子文件夹
    18. pic_new_path = os.path.join(pic_new_path, file) # 新图像存储绝对路径
    19. pic_new.save(pic_new_path) # 存储文件
    20. print("%s have been resized!" %pic_new_path)

    图片转为.h5

    • 使用自己的图片建模,可按如下操作将图片转为.h5文件(原繁琐操作:先由代码得到group形式的.h5文件,可通过HDFView将其单独保存);再套用Landslide4Sense代码
    1. import numpy as np
    2. import h5py
    3. from PIL import Image
    4. import imageio
    5. from skimage.transform import resize as imresize
    6. content_image = imageio.imread(r'E:\Downloads\Landslide4Sense-2022-main(2)-(2)\Landslide4Sense-2022-main\dataset\TrainData\img\20220915img\resize\20220915img/df021.png')
    7. image = imresize(content_image, [128,128,3]) #此为制作128×128mask,或128×128×3图片
    8. #图片:image = imresize(content_image, [128,128,14])
    9. archive = h5py.File(r'E:\Downloads\Landslide4Sense-2022-main(2)-(2)\Landslide4Sense-2022-main\dataset\TrainData\img\20220915img\resize\20220915img/20.h5', 'w')
    10. archive.create_dataset('img', data=image)
    11. archive.close()
    图 3 转换后的h5示例

    训练

    U-Net

    • Train.py(原有代码+原有.h5数据)
    1. import argparse
    2. import numpy as np
    3. import time
    4. import os
    5. import torch
    6. import torch.nn as nn
    7. import torch.optim as optim
    8. from torch.utils import data
    9. import torch.backends.cudnn as cudnn
    10. from utils.tools import *
    11. from dataset.landslide_dataset import LandslideDataSet
    12. import importlib
    13. name_classes = ['Non-Landslide','Landslide']
    14. epsilon = 1e-14
    15. def importName(modulename, name):
    16. """ Import a named object from a module in the context of this function.
    17. """
    18. try:
    19. module = __import__(modulename, globals(), locals( ), [name])
    20. except ImportError:
    21. return None
    22. return vars(module)[name]
    23. def get_arguments():
    24. parser = argparse.ArgumentParser(description="Baseline method for Land4Seen")
    25. parser.add_argument("--data_dir", type=str, default='E:\Downloads/20220916-Landslide4Sense-2022-main\Landslide4Sense-2022-main\dataset/',
    26. help="dataset path.")
    27. parser.add_argument("--model_module", type =str, default='model.Networks',
    28. help='model module to import')
    29. parser.add_argument("--model_name", type=str, default='unet',
    30. help='modle name in given module')
    31. parser.add_argument("--train_list", type=str, default='./dataset/train.txt',
    32. help="training list file.")
    33. parser.add_argument("--test_list", type=str, default='./dataset/train.txt',
    34. help="test list file.")
    35. parser.add_argument("--input_size", type=str, default='128,128',
    36. help="width and height of input images.")
    37. parser.add_argument("--num_classes", type=int, default=2,
    38. help="number of classes.")
    39. parser.add_argument("--batch_size", type=int, default=32,
    40. help="number of images in each batch.")
    41. parser.add_argument("--num_workers", type=int, default=4,
    42. help="number of workers for multithread dataloading.")
    43. parser.add_argument("--learning_rate", type=float, default=1e-3,
    44. help="learning rate.")
    45. parser.add_argument("--num_steps", type=int, default=10, #原为default=5000
    46. help="number of training steps.")
    47. parser.add_argument("--num_steps_stop", type=int, default=10, #原为default=5000
    48. help="number of training steps for early stopping.")
    49. parser.add_argument("--weight_decay", type=float, default=5e-4,
    50. help="regularisation parameter for L2-loss.")
    51. parser.add_argument("--gpu_id", type=int, default=0,
    52. help="gpu id in the training.")
    53. parser.add_argument("--snapshot_dir", type=str, default='./exp/',
    54. help="where to save snapshots of the model.")
    55. return parser.parse_args()
    56. def main():
    57. args = get_arguments()
    58. os.environ["CUDA_VISIBLE_DEVICES"] = str(args.gpu_id)
    59. snapshot_dir = args.snapshot_dir
    60. if os.path.exists(snapshot_dir)==False:
    61. os.makedirs(snapshot_dir)
    62. w, h = map(int, args.input_size.split(','))
    63. input_size = (w, h)
    64. cudnn.enabled = True
    65. cudnn.benchmark = True
    66. # Create network
    67. model_import = importName(args.model_module, args.model_name)
    68. model = model_import(n_classes=args.num_classes)
    69. model.train()
    70. model = model.cuda()
    71. src_loader = data.DataLoader(
    72. LandslideDataSet(args.data_dir, args.train_list, max_iters=args.num_steps_stop*args.batch_size,set='labeled'),
    73. batch_size=args.batch_size, shuffle=True, num_workers=args.num_workers, pin_memory=True)
    74. test_loader = data.DataLoader(
    75. LandslideDataSet(args.data_dir, args.train_list,set='labeled'),
    76. batch_size=1, shuffle=False, num_workers=args.num_workers, pin_memory=True)
    77. optimizer = optim.Adam(model.parameters(),
    78. lr=args.learning_rate, weight_decay=args.weight_decay)
    79. interp = nn.Upsample(size=(input_size[1], input_size[0]), mode='bilinear')
    80. hist = np.zeros((args.num_steps_stop,3))
    81. F1_best = 0.5
    82. cross_entropy_loss = nn.CrossEntropyLoss(ignore_index=255)
    83. for batch_id, src_data in enumerate(src_loader):
    84. if batch_id==args.num_steps_stop:
    85. break
    86. tem_time = time.time()
    87. model.train()
    88. optimizer.zero_grad()
    89. images, labels, _, _ = src_data
    90. images = images.cuda()
    91. pred = model(images)
    92. pred_interp = interp(pred)
    93. # CE Loss
    94. labels = labels.cuda().long()
    95. cross_entropy_loss_value = cross_entropy_loss(pred_interp, labels)
    96. _, predict_labels = torch.max(pred_interp, 1)
    97. predict_labels = predict_labels.detach().cpu().numpy()
    98. labels = labels.cpu().numpy()
    99. batch_oa = np.sum(predict_labels==labels)*1./len(labels.reshape(-1))
    100. hist[batch_id,0] = cross_entropy_loss_value.item()
    101. hist[batch_id,1] = batch_oa
    102. cross_entropy_loss_value.backward()
    103. optimizer.step()
    104. hist[batch_id,-1] = time.time() - tem_time
    105. if (batch_id+1) % 1 == 0:
    106. print('Iter %d/%d Time: %.2f Batch_OA = %.1f cross_entropy_loss = %.3f'%(batch_id+1,args.num_steps,10*np.mean(hist[batch_id-9:batch_id+1,-1]),np.mean(hist[batch_id-9:batch_id+1,1])*100,np.mean(hist[batch_id-9:batch_id+1,0])))
    107. # evaluation per 500 iterations
    108. if (batch_id+1) % 1 == 0: #原为if (batch_id+1) % 500 == 0:
    109. print('Testing..........')
    110. model.eval()
    111. TP_all = np.zeros((args.num_classes, 1))
    112. FP_all = np.zeros((args.num_classes, 1))
    113. TN_all = np.zeros((args.num_classes, 1))
    114. FN_all = np.zeros((args.num_classes, 1))
    115. n_valid_sample_all = 0
    116. F1 = np.zeros((args.num_classes, 1))
    117. for _, batch in enumerate(test_loader):
    118. image, label,_, name = batch
    119. label = label.squeeze().numpy()
    120. image = image.float().cuda()
    121. with torch.no_grad():
    122. pred = model(image)
    123. _,pred = torch.max(interp(nn.functional.softmax(pred,dim=1)).detach(), 1)
    124. pred = pred.squeeze().data.cpu().numpy()
    125. TP,FP,TN,FN,n_valid_sample = eval_image(pred.reshape(-1),label.reshape(-1),args.num_classes)
    126. TP_all += TP
    127. FP_all += FP
    128. TN_all += TN
    129. FN_all += FN
    130. n_valid_sample_all += n_valid_sample
    131. OA = np.sum(TP_all)*1.0 / n_valid_sample_all
    132. for i in range(args.num_classes):
    133. P = TP_all[i]*1.0 / (TP_all[i] + FP_all[i] + epsilon)
    134. R = TP_all[i]*1.0 / (TP_all[i] + FN_all[i] + epsilon)
    135. F1[i] = 2.0*P*R / (P + R + epsilon)
    136. if i==1:
    137. print('===>' + name_classes[i] + ' Precision: %.2f'%(P * 100))
    138. print('===>' + name_classes[i] + ' Recall: %.2f'%(R * 100))
    139. print('===>' + name_classes[i] + ' F1: %.2f'%(F1[i] * 100))
    140. mF1 = np.mean(F1)
    141. print('===> mean F1: %.2f OA: %.2f'%(mF1*100,OA*100))
    142. if F1[1]>F1_best:
    143. F1_best = F1[1]
    144. # save the models
    145. print('Save Model')
    146. model_name = 'batch'+repr(batch_id+1)+'_F1_'+repr(int(F1[1]*10000))+'.pth'
    147. torch.save(model.state_dict(), os.path.join(
    148. snapshot_dir, model_name))
    149. if __name__ == '__main__':
    150. main()
    1. import numpy as np
    2. import torch
    3. from torch.utils import data
    4. from torch.utils.data import DataLoader
    5. import h5py
    6. class LandslideDataSet(data.Dataset):
    7. def __init__(self, data_dir, list_path, max_iters=None,set='label'):
    8. self.list_path = list_path
    9. self.mean = [-0.4914, -0.3074, -0.1277, -0.0625, 0.0439, 0.0803, 0.0644, 0.0802, 0.3000, 0.4082, 0.0823, 0.0516, 0.3338, 0.7819]
    10. self.std = [0.9325, 0.8775, 0.8860, 0.8869, 0.8857, 0.8418, 0.8354, 0.8491, 0.9061, 1.6072, 0.8848, 0.9232, 0.9018, 1.2913]
    11. self.set = set
    12. self.img_ids = [i_id.strip() for i_id in open(list_path)]
    13. if not max_iters==None:
    14. n_repeat = int(np.ceil(max_iters / len(self.img_ids)))
    15. self.img_ids = self.img_ids * n_repeat + self.img_ids[:max_iters-n_repeat*len(self.img_ids)]
    16. self.files = []
    17. if set=='labeled':
    18. for name in self.img_ids:
    19. img_file = data_dir + name
    20. label_file = data_dir + name.replace('img','mask').replace('image','mask')
    21. self.files.append({
    22. 'img': img_file,
    23. 'label': label_file,
    24. 'name': name
    25. })
    26. elif set=='unlabeled':
    27. for name in self.img_ids:
    28. img_file = data_dir + name
    29. self.files.append({
    30. 'img': img_file,
    31. 'name': name
    32. })
    33. def __len__(self):
    34. return len(self.files)
    35. def __getitem__(self, index):
    36. datafiles = self.files[index]
    37. if self.set=='labeled':
    38. with h5py.File(datafiles['img'], 'r') as hf:
    39. image = hf['img'][:]
    40. with h5py.File(datafiles['label'], 'r') as hf:
    41. label = hf['mask'][:]
    42. name = datafiles['name']
    43. image = np.asarray(image, np.float32)
    44. label = np.asarray(label, np.float32)
    45. image = image.transpose((-1, 0, 1))
    46. size = image.shape
    47. for i in range(len(self.mean)):
    48. image[i,:,:] -= self.mean[i]
    49. image[i,:,:] /= self.std[i]
    50. return image.copy(), label.copy(), np.array(size), name
    51. else:
    52. with h5py.File(datafiles['img'], 'r') as hf:
    53. image = hf['img'][:]
    54. name = datafiles['name']
    55. image = np.asarray(image, np.float32)
    56. image = image.transpose((-1, 0, 1))
    57. size = image.shape
    58. for i in range(len(self.mean)):
    59. image[i,:,:] -= self.mean[i]
    60. image[i,:,:] /= self.std[i]
    61. return image.copy(), np.array(size), name
    62. if __name__ == '__main__':
    63. train_dataset = LandslideDataSet(data_dir='/dataset/', list_path='./train.txt')
    64. train_loader = DataLoader(dataset=train_dataset,batch_size=1,shuffle=True,pin_memory=True)
    65. channels_sum,channel_squared_sum = 0,0
    66. num_batches = len(train_loader)
    67. for data,_,_,_ in train_loader:
    68. channels_sum += torch.mean(data,dim=[0,2,3])
    69. channel_squared_sum += torch.mean(data**2,dim=[0,2,3])
    70. mean = channels_sum/num_batches
    71. std = (channel_squared_sum/num_batches - mean**2)**0.5
    72. print(mean,std)
    73. #[-0.4914, -0.3074, -0.1277, -0.0625, 0.0439, 0.0803, 0.0644, 0.0802, 0.3000, 0.4082, 0.0823, 0.0516, 0.3338, 0.7819]
    74. #[0.9325, 0.8775, 0.8860, 0.8869, 0.8857, 0.8418, 0.8354, 0.8491, 0.9061, 1.6072, 0.8848, 0.9232, 0.9018, 1.2913]
    • 迭代5000次后,Precision: 84.33, Recall: 60.36, F1: 70.36
    图 4 模型自带数据训练结果

    • 其他网络:Semantic-segmentation-methods-for-landslide-detection-master(https://github.com/waterybye/Semantic-segmentation-methods-for-landslide-detection)内含多种网络代码,将其扩充至当前Landslide4Sense-2022-main代码包下的model,即可训练DeepLabV3+FCNGCN网络,对应Train.py修改如下:
    1. parser.add_argument("--model_module", type =str, default='model.deeplab3plus',
    2. help='model module to import')
    3. parser.add_argument("--model_name", type=str, default='DeepLabv3_plus',
    4. help='modle name in given module')
    • 注意:训练DeepLabV3plus网络,图片需以128×128×3三通道输入(对应上述转.h文件代码中的“image = imresize(content_image, [128,128])”);另外,还需修改channels、batch_size等参数(例如,设置迭代100次、batch_size为5),多加尝试对比
    • 注意:为对应Train.py中的“model = model_import(n_classes=args.num_classes)”,需要将具体网络代码“num_classes”修改为“n_classes”

    DeepLabv3+

    • 输入128×128×.h5图像,
    • Train.py 进行如下关键修改(同上代码段)
    • 注意:可能报错“CUDA out of memory” → 调整batch_size即可
    1. parser.add_argument("--data_dir", type=str, default='E:\Downloads/20220916-Landslide4Sense-2022-main\Landslide4Sense-2022-main\dataset/',
    2. help="dataset path.")
    3. parser.add_argument("--model_module", type=str, default='model.deeplab3plus',
    4. help='model module to import')
    5. parser.add_argument("--model_name", type=str, default='DeepLabv3_plus',
    6. help='modle name in given module')
    7. parser.add_argument("--train_list", type=str, default='./dataset/train_other.txt',
    8. help="training list file.")
    9. parser.add_argument("--test_list", type=str, default='./dataset/train_other.txt',
    10. help="test list file.")
    • landslide_dataset.py 进行如下修改
    1. self.mean = [-0.4914, -0.3074, -0.1277] #因输入数据通道数不同,U-Net外的其他网络需做相应修改
    2. self.std = [0.9325, 0.8775, 0.8860] #因输入数据通道数不同,U-Net外的其他网络需做相应修改
    1. if __name__ == '__main__':
    2. train_dataset = LandslideDataSet(data_dir='/dataset/', list_path='./train_other.txt')

    FCN

    • FCN(8s/16s/32s)类同上述修改,只是在Train.py的相应模型设置不同,如下
    1. parser.add_argument("--model_module", type=str, default='model.fcn',
    2. help='model module to import')
    3. parser.add_argument("--model_name", type=str, default='fcn8s',
    4. help='modle name in given module')

    GCN

    • GCN类同上述修改,只是在Train.py的相应模型设置不同,如下
    1. parser.add_argument("--model_module", type=str, default='model.gcn',
    2. help='model module to import')
    3. parser.add_argument("--model_name", type=str, default='GCN',
    4. help='modle name in given module')


    预测

    • Predict.py预测:Predict.py在调用模型权重文件时报错“RecursionError: maximum recursion depth exceeded while calling a Python object”或“Process finished with exit code -1073741571 (0xC00000FD)”,故直接将Predict.py相关代码附在Train.py →→→ 输出对应mask,位于文件夹…\exp

  • 相关阅读:
    使用dos安装mysql数据库和java开发工具
    JavaWeb后端
    2023腾讯云服务器优惠价格表_10月更新报价
    MySQL事务(清晰易懂)
    js之页面列表加载常用方法总结
    Vue3常用笔记
    音视频开发14 FFmpeg 视频 相关格式分析 -- H264 NALU格式分析
    Apache Kylin性能优化全景:释放大数据加速潜力
    如何使用注解管理Spring Bean的生命周期呢?
    Spring 源码笔记(二),核心概念的理解
  • 原文地址:https://blog.csdn.net/YWP_2016/article/details/126883291