实例
数据集
笔记本

笔记本

真实场景篡改图像检测挑战赛 —— 训练

暂无摘要
Dave上传于 3 years ago
标签
天池
PyTorch
浏览8379
笔记本内容
import os
if not os.path.exists("/home/featurize/data/anno.zip"):
    !featurize dataset download 757181ec-0841-4468-b701-54ea53ad2d3c
if not os.path.exists("/home/featurize/data/forgery_round1_train_20220217.zip"):
    !featurize dataset download e4dc9a7b-ded4-453d-b887-1f3fb04a5f94
from IPython.display import clear_output
%pip install minetorch seaborn albumentations segmentation_models_pytorch
clear_output()
import os
import cv2
import torch
import random
import minetorch

import numpy as np
import pandas as pd
import seaborn as sns
import albumentations as albu
import matplotlib.pyplot as plt
import segmentation_models_pytorch as smp

from albumentations.pytorch import ToTensorV2
from albumentations import Normalize, Compose
from torch.utils.data import DataLoader, Dataset
from sklearn.model_selection import train_test_split
from torch.optim.lr_scheduler import CosineAnnealingWarmRestarts

训练参数 #

CONFIG = {
    'DIR': 'Experiments',
    'img_size': 224,
    'model_name': 'timm-efficientnet-b0',
    'fold': 0,
    'lr': 1e-4,
    'batch_size': 128,
    'epoch': 20
}

创建 PyTorch Dataset #

class AliDataset(Dataset):

    def __init__(self, df, transforms, train=False):
        self.df = df
        self.transforms = transforms
        self.train = train
    
    def __getitem__(self, idx):
        row = self.df.iloc[idx]
        fn = row.image
        image = cv2.imread(os.path.join(row['image_path'], str(fn) + '.jpg'))
        image = cv2.cvtColor(image, cv2.COLOR_BGR2RGB)
        masks = cv2.imread(os.path.join(row['mask_path'], str(fn) + '.png'), cv2.IMREAD_GRAYSCALE)/255

        augmented = self.transforms(image=image, mask=masks)
        img, mask = augmented['image'], augmented['mask']

        return img.float(), mask.float()

    def __len__(self):
        return len(self.df)

def create_transformation(phase):
    
    transforms = albu.Compose([
        albu.RandomBrightnessContrast(p=0.5),
        albu.OneOf([
            albu.Rotate(limit=[90,90], p=0.5),
            albu.Rotate(limit=[270,270], p=0.5),
        ], p=0.5),
        albu.RandomResizedCrop(CONFIG['img_size'], CONFIG['img_size'], scale=(0.8, 1.0), ratio=(0.75, 1.3333333333333333)),
        albu.Resize(CONFIG['img_size'], CONFIG['img_size'], p=1),
        ToTensorV2()
    ])
    
    if phase == 'val':
        transforms = albu.Compose([
            albu.Resize(CONFIG['img_size'], CONFIG['img_size'], p=1),
            ToTensorV2()
        ])
    
    return transforms

评估代码 #

from minetorch.plugin import Plugin

def dice_coeff(pred, target):
    smooth = 1e-12
    num = pred.size(0)
    m1 = pred.view(num, -1).float()  # Flatten
    m2 = target.view(num, -1).float()  # Flatten
    intersection = (m1 * m2).sum().float()
    return (2. * intersection + smooth) / (m1.sum() + m2.sum() + smooth)

def iou_pytorch(outputs: torch.Tensor, labels: torch.Tensor):
    SMOOTH = 1e-12
    outputs = outputs.squeeze(1)  # BATCH x 1 x H x W => BATCH x H x W
    intersection = (outputs * labels).float().sum((1, 2))  
    union = (outputs + labels).float().sum((1, 2))
    iou = (intersection + SMOOTH) / (union - intersection + SMOOTH)
    return iou

class MultiClassesSegmentationMetricWithLogic(Plugin):
    """MultiClassesClassificationMetric
    This can be used directly if your loss function is torch.nn.CrossEntropy
    """

    def __init__(self,
                 miou=True,
                 mf1=True,
                 sheet_key_prefix=''):

        super().__init__(sheet_key_prefix)
        self.miou = miou
        self.mf1 = mf1


    def before_init(self):
        self.create_sheet_column('miou', 'miou')

    def before_epoch_start(self, epoch):
        self.iou = 0
        self.f1 = 0
        self.len = 0

    def after_val_iteration_ended(self, predicts, data, **ignore):

        predicts = (torch.sigmoid(predicts) > 0.5).int().detach().cpu()
        targets = data[1].detach().cpu()

        eps = 1e-12

        iou = iou_pytorch(predicts, targets)
        f1 = dice_coeff(predicts, targets)

        self.f1 += f1
        self.iou += iou.sum()
        self.len += 1

    def after_epoch_end(self, val_loss, **ignore):
        self.miou and self._iou()
        self.mf1 and self._f1()

    def _f1(self):
        mf1 = self.f1 / self.len
        png_file = self.scalars(
            {
                'mf1': mf1,
            }, 'mf1'
        )
        if png_file:
            self.update_sheet('f1', {'raw': png_file, 'processor': 'upload_image'})

    def _iou(self):
        miou = torch.sum(self.iou) / 800
        png_file = self.scalars(
            {
                'miou': miou,
            }, 'miou'
        )
        if png_file:
            self.update_sheet('iou', {'raw': png_file, 'processor': 'upload_image'})

读取数据 #

df = pd.read_csv('/home/featurize/data/train.csv')
df['image_path'] = '/home/featurize/data/train/img/'
df['mask_path'] = f'/home/featurize/data/train/mask/'

train_df = df[df.fold != CONFIG['fold']].reset_index(drop=True)
val_df = df[df.fold == CONFIG['fold']].reset_index(drop=True)

trainset = AliDataset(train_df, create_transformation('train'),train=True)
valset = AliDataset(val_df, create_transformation('val'))

train_loader = DataLoader(
    trainset,
    batch_size=CONFIG['batch_size'],
    num_workers=8,
    shuffle=True,
    pin_memory=True,
)
val_loader = DataLoader(
    valset,
    batch_size=CONFIG['batch_size'],
    num_workers=8,
    pin_memory=True
)
df.head()
image ratio fold image_path mask_path
0 146 1.1 0 /home/featurize/data/train/img/ /home/featurize/data/train/mask/
1 2168 7.0 0 /home/featurize/data/train/img/ /home/featurize/data/train/mask/
2 1689 6.8 0 /home/featurize/data/train/img/ /home/featurize/data/train/mask/
3 953 1.4 0 /home/featurize/data/train/img/ /home/featurize/data/train/mask/
4 2668 8.3 0 /home/featurize/data/train/img/ /home/featurize/data/train/mask/

创建模型 #

model = smp.UnetPlusPlus(
    CONFIG['model_name'],
    classes=1,
    encoder_weights='imagenet',
    activation=None,
)

优化器和 Scheduler #

optimizer = torch.optim.AdamW(model.parameters(), lr=CONFIG['lr'], betas=(0.9, 0.999), eps=1e-08, amsgrad=False)
scheduler = CosineAnnealingWarmRestarts(optimizer, T_0=5, T_mult=2, eta_min=1e-6, last_epoch=-1)
def after_epoch_end(miner, **payload):
    scheduler.step(miner.current_epoch)

损失函数 #

bce_loss = torch.nn.BCEWithLogitsLoss(pos_weight=torch.tensor([3.]).cuda()).cuda()
def forward_fn(trainer, data):
    images, masks = data
    images, masks = images.cuda(), masks.cuda()
    mask = model(images).squeeze(1)
    loss = bce_loss(mask, masks)
    return mask, loss

创建训练器 #

miner = minetorch.Miner(
    code=os.getenv('CODE', f'fold-{CONFIG["fold"]}'),
    alchemistic_directory=os.getenv('ALCHEMISTIC_DIRECTORY', f'/home/featurize/{CONFIG['DIR']}/{CONFIG["model_name"]}-{CONFIG["img_size"]}'),
    model=model.cuda(),
    forward=forward_fn,
    optimizer=optimizer,
    train_dataloader=train_loader,
    val_dataloader=val_loader,
    max_epochs=CONFIG['epoch'],
    in_notebook=True,
    loss_func=None,
    amp=True,
    plugins=[MultiClassesSegmentationMetricWithLogic()],
    hooks={
        'after_epoch_end': after_epoch_end,
    },
    trival=False,
    resume=False
)

训练 #

miner.train()
import IPython
IPython.display.Image('/home/featurize/Experiments/timm-efficientnet-b0-224/fold-0/graphs/loss.png')
IPython.display.Image('/home/featurize/Experiments/timm-efficientnet-b0-224/fold-0/graphs/miou.png')
IPython.display.Image('/home/featurize/Experiments/timm-efficientnet-b0-224/fold-0/graphs/mf1.png')

To Do: #

  • 更多 Augmentantion
  • Label Smooth
  • 添加 GAN
  • K-fold
  • Pseudo Labeling ...
评论(0条)