• 【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

  • 相关阅读:
    编写算法对输入的一个整数,判断它能否被 3,5,7 整除
    chrome driver下载、selenium安装及报错解决
    解决问题的思路很重要,运维领域,结果对,过程就对!
    vue 打包性能优化总结
    TDengine 跨版本迁移实战
    【Python刷题篇】——Python入门 011面向对象(一)
    AJAX学习日记——Day 4
    关于Windows 443端口被占用问题的解决
    6. 堪比JMeter的.Net压测工具 - Crank 实战篇 - 收集诊断跟踪信息与如何分析瓶颈
    Java-数据类型
  • 原文地址:https://blog.csdn.net/YWP_2016/article/details/126883291