【天池赛事】零基础入门语义分割-地表建筑物识别

  • Task1:赛题理解与 baseline(3 天)
    – 学习主题:理解赛题内容解题流程
    – 学习内容:赛题理解、数据读取、比赛 baseline 构建
    – 学习成果:比赛 baseline 提交

  • Task2:数据扩增方法(3 天)
    – 学习主题:语义分割任务中数据扩增方法
    – 学习内容:掌握语义分割任务中数据扩增方法的细节和使用
    – 学习成果:数据扩增方法的实践

  • Task3:网络模型结构发展(3 天)
    – 学习主题:掌握语义分割模型的发展脉络
    – 学习内容: FCN、 Unet、 DeepLab、 SegNet、 PSPNet
    – 学习成果:多种网络模型的搭建

  • Task4:评价函数与损失函数(3 天)
    – 学习主题:语义分割模型各种评价函数与损失函数
    – 学习内容: Dice、 IoU、 BCE、 Focal Loss、 Lovász-Softmax
    – 学习成果:评价/损失函数的实践

  • Task5:模型训练与验证(3 天)
    – 学习主题:数据划分方法
    – 学习内容:三种数据划分方法、模型调参过程
    – 学习成果:数据划分具体操作

  • Task6:分割模型模型集成(3 天)
    – 学习主题:语义分割模型集成方法
    – 学习内容: LookaHead、 SnapShot、 SWA、 TTA
    – 学习成果:模型集成思路

Task1:赛题理解与 baseline

  • 1 学习目标
  • 2 赛题数据
  • 3 数据标签
  • 4 评价指标
  • 5 读取数据
  • 6 解题思路
  • 7 本章小结
  • 8 课后作业
  • 9 Baseline

本章将对语义分割赛题进行赛题背景讲解,对赛题数据读取进行说明,并给出解题思路。

  • 赛题名称:零基础入门语义分割-地表建筑物识别
  • 赛题目标:通过本次赛题可以引导大家熟练掌握语义分割任务的定义,具体的解题流程和相应的模型,并掌握语义分割任务的发展。
  • 赛题任务:赛题以计算机视觉为背景,要求选手使用给定的航拍图像训练模型并完成地表建筑物识
    别任务。

1 学习目标

• 理解赛题背景和赛题数据
• 完成赛题报名和数据下载,理解赛题的解题思路

2 赛题数据

遥感技术已成为获取地表覆盖信息最为行之有效的手段,遥感技术已经成功应用于地表覆盖检测、植被面积检测和建筑物检测任务。本赛题使用航拍数据,需要参赛选手完成地表建筑物识别,将地表航拍图像素划分为有建筑物和无建筑物两类。

如下图,左边为原始航拍图,右边为对应的建筑物标注。


赛题数据来源(Inria Aerial Image Labeling),并进行拆分处理。数据集报名后可见并可下载。赛题数据为航拍图,需要参赛选手识别图片中的地表建筑具体像素位置。

3 数据标签

赛题为语义分割任务,因此具体的标签为图像像素类别。在赛题数据中像素属于 2 类(无建筑物和有建筑物),因此标签为有建筑物的像素。赛题原始图片为 jpg 格式,标签为 RLE 编码的字符串。

RLE 全称(run-length encoding),翻译为游程编码或行程长度编码,对连续的黑、白像素数以不同的码字进行编码。 RLE 是一种简单的非破坏性资料压缩法,经常用在在语义分割比赛中对标签进行编码。

RLE 与图片之间的转换如下:

# rle编码的具体的读取代码如下:
import numpy as np
import pandas as pd
import cv2# 将图片编码为rle格式
def rle_encode(im):'''im: numpy array, 1 - mask, 0 - backgroundReturns run length as string formated'''pixels = im.flatten(order = 'F')pixels = np.concatenate([[0], pixels, [0]])runs = np.where(pixels[1:] != pixels[:-1])[0] + 1runs[1::2] -= runs[::2]return ' '.join(str(x) for x in runs)# 将rle格式进行解码为图片
def rle_decode(mask_rle, shape=(512, 512)):'''mask_rle: run-length as string formated (start length)shape: (height,width) of array to return Returns numpy array, 1 - mask, 0 - background'''s = mask_rle.split()starts, lengths = [np.asarray(x, dtype=int) for x in (s[0:][::2], s[1:][::2])]starts -= 1ends = starts + lengthsimg = np.zeros(shape[0]*shape[1], dtype=np.uint8)for lo, hi in zip(starts, ends):img[lo:hi] = 1return img.reshape(shape, order='F')

4 评价指标

赛题使用 Dice coefficient 来衡量选手结果与真实标签的差异性, Dice coefficient 可以按像素差异性来比较结果的差异性。 Dice coefficient 的具体计算方式如下:

2∗∣X∩Y∣∣X∣+∣Y∣{{2*|X\cap Y|}\over {|X|+|Y|}} ∣X∣+∣Y∣2∗∣X∩Y∣​

其中X是预测结果,Y为真实标签的结果。当X与Y完全相同时Dice coefficient为1,排行榜使用所有测试集图片的平均Dice coefficient来衡量,分数值越大越好。

5 读取数据

6 解题思路

由于本次赛题是一个典型的语义分割任务,因此可以直接使用语义分割的模型来完成:
• 步骤 1:使用 FCN 模型模型跑通具体模型训练过程,并对结果进行预测提交;
• 步骤 2:在现有基础上加入数据扩增方法,并划分验证集以监督模型精度;
• 步骤 3:使用更加强大模型结构(如 Unet 和 PSPNet)或尺寸更大的输入完成训练;
• 步骤 4:训练多个模型完成模型集成操作;

7 本章小结

本章主要对赛题背景和主要任务进行讲解,并多对赛题数据和标注读取方式进行介绍,最后列举了赛题解题思路。

8 课后作业

  1. 理解 RLE 编码过程,并完成赛题数据读取并可视化;
  2. 统计所有图片整图中没有任何建筑物像素占所有训练集图片的比例;
  3. 统计所有图片中建筑物像素占所有相似度的比例;
  4. 统计所有图片中建筑物区域平均区域大小;

9 Baseline

# -*- coding: utf-8 -*-
from google.colab import drive
drive.mount('/content/drive')# !unzip -n /content/drive/MyDrive/SemanticSegmentation/train.zip -d /content/data
# !unzip -n /content/drive/MyDrive/SemanticSegmentation/test_a.zip -d /content/data
# !unzip -n /content/drive/MyDrive/SemanticSegmentation/train_mask.csv.zip -d /content/data
# !cp /content/drive/MyDrive/SemanticSegmentation/test_a_samplesubmit.csv /content/data
# !pip install rasterio# Commented out IPython magic to ensure Python compatibility.
import numpy as np
import pandas as pd
import pathlib, sys, os, random, time
import numba, cv2, gc
from tqdm import tqdm_notebookimport matplotlib.pyplot as plt
# %matplotlib inlineimport warnings
warnings.filterwarnings('ignore')from tqdm.notebook import tqdmimport albumentations as Aimport rasterio
from rasterio.windows import Windowdef rle_encode(im):'''im: numpy array, 1 - mask, 0 - backgroundReturns run length as string formated'''pixels = im.flatten(order = 'F')pixels = np.concatenate([[0], pixels, [0]])runs = np.where(pixels[1:] != pixels[:-1])[0] + 1runs[1::2] -= runs[::2]return ' '.join(str(x) for x in runs)def rle_decode(mask_rle, shape=(512, 512)):'''mask_rle: run-length as string formated (start length)shape: (height,width) of array to return Returns numpy array, 1 - mask, 0 - background'''s = mask_rle.split()starts, lengths = [np.asarray(x, dtype=int) for x in (s[0:][::2], s[1:][::2])]starts -= 1ends = starts + lengthsimg = np.zeros(shape[0]*shape[1], dtype=np.uint8)for lo, hi in zip(starts, ends):img[lo:hi] = 1return img.reshape(shape, order='F')import torch
import torch.nn as nn
import torch.nn.functional as F
import torch.utils.data as Dimport torchvision
from torchvision import transforms as TEPOCHES = 20
BATCH_SIZE = 32
IMAGE_SIZE = 256
DEVICE = 'cuda' if torch.cuda.is_available() else 'cpu' trfm = A.Compose([A.Resize(IMAGE_SIZE, IMAGE_SIZE),A.HorizontalFlip(p=0.5),A.VerticalFlip(p=0.5),A.RandomRotate90(),
])class TianChiDataset(D.Dataset):def __init__(self, paths, rles, transform, test_mode=False):self.paths = pathsself.rles = rlesself.transform = transformself.test_mode = test_modeself.len = len(paths)self.as_tensor = T.Compose([T.ToPILImage(),T.Resize(IMAGE_SIZE),T.ToTensor(),T.Normalize([0.625, 0.448, 0.688],[0.131, 0.177, 0.101]),])# get data operationdef __getitem__(self, index):img = cv2.imread(self.paths[index])if not self.test_mode:mask = rle_decode(self.rles[index])augments = self.transform(image=img, mask=mask)return self.as_tensor(augments['image']), augments['mask'][None]else:return self.as_tensor(img), ''        def __len__(self):"""Total number of samples in the dataset"""return self.lentrain_mask = pd.read_csv('data/train_mask.csv', sep='\t', names=['name', 'mask'])
train_mask['name'] = train_mask['name'].apply(lambda x: 'data/train/' + x)img = cv2.imread(train_mask['name'].iloc[0])
mask = rle_decode(train_mask['mask'].iloc[0])print(rle_encode(mask) == train_mask['mask'].iloc[0])dataset = TianChiDataset(train_mask['name'].values,train_mask['mask'].fillna('').values,trfm, False
)image, mask = dataset[0]
plt.figure(figsize=(16,8))
plt.subplot(121)
plt.imshow(mask[0], cmap='gray')
plt.subplot(122)
plt.imshow(image[0]);valid_idx, train_idx = [], []
for i in range(len(dataset)):if i % 7 == 0:valid_idx.append(i)
#     else:elif i % 7 == 1:train_idx.append(i)train_ds = D.Subset(dataset, train_idx)
valid_ds = D.Subset(dataset, valid_idx)# define training and validation data loaders
loader = D.DataLoader(train_ds, batch_size=BATCH_SIZE, shuffle=True, num_workers=0)vloader = D.DataLoader(valid_ds, batch_size=BATCH_SIZE, shuffle=False, num_workers=0)def get_model():# model = torchvision.models.segmentation.fcn_resnet50(True)#     pth = torch.load("../input/pretrain-coco-weights-pytorch/fcn_resnet50_coco-1167a1af.pth")
#     for key in ["aux_classifier.0.weight", "aux_classifier.1.weight", "aux_classifier.1.bias", "aux_classifier.1.running_mean", "aux_classifier.1.running_var", "aux_classifier.1.num_batches_tracked", "aux_classifier.4.weight", "aux_classifier.4.bias"]:
#         del pth[key]# model.classifier[4] = nn.Conv2d(512, 1, kernel_size=(1, 1), stride=(1, 1))model = torchvision.models.segmentation.deeplabv3_resnet50(True)model.classifier[4] = nn.Conv2d(256, 1, kernel_size=(1, 1), stride=(1, 1))return model@torch.no_grad()
def validation(model, loader, loss_fn):losses = []model.eval()for image, target in loader:image, target = image.to(DEVICE), target.float().to(DEVICE)output = model(image)['out']loss = loss_fn(output, target)losses.append(loss.item())return np.array(losses).mean()model = get_model()
model.to(DEVICE);optimizer = torch.optim.AdamW(model.parameters(),lr=1e-4, weight_decay=1e-3)class SoftDiceLoss(nn.Module):def __init__(self, smooth=1., dims=(-2,-1)):super(SoftDiceLoss, self).__init__()self.smooth = smoothself.dims = dimsdef forward(self, x, y):tp = (x * y).sum(self.dims)fp = (x * (1 - y)).sum(self.dims)fn = ((1 - x) * y).sum(self.dims)dc = (2 * tp + self.smooth) / (2 * tp + fp + fn + self.smooth)dc = dc.mean()return 1 - dcbce_fn = nn.BCEWithLogitsLoss()
dice_fn = SoftDiceLoss()def loss_fn(y_pred, y_true):bce = bce_fn(y_pred, y_true)dice = dice_fn(y_pred.sigmoid(), y_true)return 0.8*bce+ 0.2*diceheader = r'''Train | Valid
Epoch |  Loss |  Loss | Time, m
'''
#          Epoch         metrics            time
raw_line = '{:6d}' + '\u2502{:7.3f}'*2 + '\u2502{:6.2f}'
print(header)EPOCHES = 60
best_loss = 10
for epoch in range(1, EPOCHES+1):losses = []start_time = time.time()model.train()for image, target in tqdm_notebook(loader):image, target = image.to(DEVICE), target.float().to(DEVICE)optimizer.zero_grad()output = model(image)['out']loss = loss_fn(output, target)loss.backward()optimizer.step()losses.append(loss.item())# print(loss.item())vloss = validation(model, vloader, loss_fn)print(raw_line.format(epoch, np.array(losses).mean(), vloss,(time.time()-start_time)/60**1))losses = []if vloss < best_loss:best_loss = vlosstorch.save(model.state_dict(), 'model_best.pth')torch.save(model.state_dict(), '/content/drive/MyDrive/SemanticSegmentation/model_best.pth')trfm = T.Compose([T.ToPILImage(),T.Resize(IMAGE_SIZE),T.ToTensor(),T.Normalize([0.625, 0.448, 0.688],[0.131, 0.177, 0.101]),
])subm = []# model.load_state_dict(torch.load("/content/drive/MyDrive/SemanticSegmentation/model_best.pth"))
model.load_state_dict(torch.load("./model_best.pth"))
model.eval()test_mask = pd.read_csv('data/test_a_samplesubmit.csv', sep='\t', names=['name', 'mask'])
test_mask['name'] = test_mask['name'].apply(lambda x: 'data/test_a/' + x)for idx, name in enumerate(tqdm_notebook(test_mask['name'].iloc[:])):image = cv2.imread(name)image = trfm(image)with torch.no_grad():image = image.to(DEVICE)[None]score = model(image)['out'][0][0]score_sigmoid = score.sigmoid().cpu().numpy()score_sigmoid = (score_sigmoid > 0.5).astype(np.uint8)score_sigmoid = cv2.resize(score_sigmoid, (512, 512))# breaksubm.append([name.split('/')[-1], rle_encode(score_sigmoid)])subm = pd.DataFrame(subm)
subm.to_csv('./tmp.csv', index=None, header=None, sep='\t')
subm.to_csv('/content/drive/MyDrive/SemanticSegmentation/tmp.csv', index=None, header=None, sep='\t')plt.figure(figsize=(16,8))
plt.subplot(121)
plt.imshow(rle_decode(subm[1].fillna('').iloc[0]), cmap='gray')
plt.subplot(122)
plt.imshow(cv2.imread('data/test_a/' + subm[0].iloc[0]));

【天池赛事】零基础入门语义分割-地表建筑物识别 Task1:赛题理解与 baseline相关推荐

  1. 【天池赛事】零基础入门语义分割-地表建筑物识别 Task6:分割模型模型集成

    [天池赛事]零基础入门语义分割-地表建筑物识别 Task1:赛题理解与 baseline(3 天) – 学习主题:理解赛题内容解题流程 – 学习内容:赛题理解.数据读取.比赛 baseline 构建 ...

  2. 【天池赛事】零基础入门语义分割-地表建筑物识别 Task5:模型训练与验证

    [天池赛事]零基础入门语义分割-地表建筑物识别 Task1:赛题理解与 baseline(3 天) – 学习主题:理解赛题内容解题流程 – 学习内容:赛题理解.数据读取.比赛 baseline 构建 ...

  3. 【天池赛事】零基础入门语义分割-地表建筑物识别 Task4:评价函数与损失函数

    [天池赛事]零基础入门语义分割-地表建筑物识别 Task1:赛题理解与 baseline(3 天) – 学习主题:理解赛题内容解题流程 – 学习内容:赛题理解.数据读取.比赛 baseline 构建 ...

  4. 【天池赛事】零基础入门语义分割-地表建筑物识别 Task3:网络模型结构发展

    [天池赛事]零基础入门语义分割-地表建筑物识别 Task1:赛题理解与 baseline(3 天) – 学习主题:理解赛题内容解题流程 – 学习内容:赛题理解.数据读取.比赛 baseline 构建 ...

  5. 【天池赛事】零基础入门语义分割-地表建筑物识别 Task2:数据扩增方法

    [天池赛事]零基础入门语义分割-地表建筑物识别 Task1:赛题理解与 baseline(3 天) – 学习主题:理解赛题内容解题流程 – 学习内容:赛题理解.数据读取.比赛 baseline 构建 ...

  6. 【天池赛事】零基础入门语义分割-地表建筑物识别

    https://tianchi.aliyun.com/competition/entrance/531872/introduction [天池赛事]零基础入门语义分割-地表建筑物识别:第一章 赛题及b ...

  7. 天池赛题解析:零基础入门语义分割-地表建筑物识别-CV语义分割实战(附部分代码)

    赛题内容 赛题背景 赛题以计算机视觉为背景,要求选手使用给定的航拍图像训练模型并完成地表建筑物识别任务.为更好的引导大家入门,我们为本赛题定制了学习方案和学习任务,具体包括语义分割的模型和具体的应用案 ...

  8. 零基础入门语义分割-地表建筑物识别 Task2 数据扩增 -学习笔记

    先给出task1的链接:task1-赛题理解 这一节进行数据扩增的试验 读取图片: train_mask = pd.read_csv('./data/train_mask.csv', sep='\t' ...

  9. 地表建筑物识别——Task01赛题理解

    前言:这次参加Datawhale与天池联合发起的零基础入门语义分割之地表建筑物识别挑战赛.自己在大四上(2018下半年)也简单接触过语义分割,当时是基于FCN做CT图像乳腺肿瘤的分割.现在参加这个入门 ...

最新文章

  1. 数据库中范式的理解1NF、2NF、3NF
  2. 前端三十二:超链接(a标签)
  3. 辽师大计算机科学与技术专业怎么样,性价比很高的大学,辽师大的优势专业分析!家长请收藏...
  4. linux 截取后缀名,Shell 截取文件名和后缀
  5. 以太坊solidity编程常见错误(不定期更新)
  6. 6174问题 --ACM解决方法
  7. IDEA创建SpringBoot
  8. 启动不起来_电脑启动不起来该怎么办
  9. Qt-Qt Creator的下载、安装与配置(Windows)
  10. DPDK AF_XDP
  11. Qt优秀开源项目之十四:SortFilterProxyModel
  12. 如何判断本地(路由器)分配的IP是否是公网IP?
  13. Jasper实现报表(Java)
  14. img取消无图片时的默认边框
  15. 数据结构——图的邻接表实现
  16. Vue项目antdv中scopedSlots的customRender和customRender函数冲突
  17. ASPICE SWE3之——C代码生成软件详细设计2 注释格式
  18. 【JZOJ 5498】 大佬的难题
  19. element ui input限制输入6位数字(短信验证码)
  20. android+360+手表,360智能手表

热门文章

  1. poj1364 King
  2. [异常解决] android studio检测不到手机的解决办法——ADB驱动自己安装
  3. BZOJ 1059 - 二分图匹配
  4. OC的项目网址(自己编写的项目)
  5. vmware如何安装solaris10
  6. Linux线程时间片如何修改,请教如何修改线程时间片
  7. python 格式化字符串长度_python-格式化字符串
  8. aes key长度_Go 语言 map 解析之 key 的定位核心流程
  9. JavaScript中的三种常用继承方法
  10. 放在每个定义前的html语言,html基础