国产 无码 综合区,色欲AV无码国产永久播放,无码天堂亚洲国产AV,国产日韩欧美女同一区二区

【計算機(jī)視覺 | Kaggle】飛機(jī)凝結(jié)軌跡識別 Baseline 分享和解讀(含源代碼)

這篇具有很好參考價值的文章主要介紹了【計算機(jī)視覺 | Kaggle】飛機(jī)凝結(jié)軌跡識別 Baseline 分享和解讀(含源代碼)。希望對大家有所幫助。如果存在錯誤或未考慮完全的地方,請大家不吝賜教,您也可以點(diǎn)擊"舉報違法"按鈕提交疑問。

一、導(dǎo)讀

【計算機(jī)視覺 | Kaggle】飛機(jī)凝結(jié)軌跡識別 Baseline 分享和解讀(含源代碼),計算機(jī)視覺,kaggle,計算機(jī)視覺,人工智能,語義分割,kaggle
比賽名稱:Google Research - Identify Contrails to Reduce Global Warming

https://www.kaggle.com/competitions/google-research-identify-contrails-reduce-global-warming

訓(xùn)練 ML 模型以識別衛(wèi)星圖像中的尾跡

比賽類型:計算機(jī)視覺、語義分割

二、比賽背景

Contrails 是“凝結(jié)軌跡”的縮寫,是在飛機(jī)發(fā)動機(jī)排氣中形成的線狀冰晶云,由飛機(jī)飛過大氣中的超潮濕區(qū)域時產(chǎn)生。持續(xù)的尾跡對全球變暖的貢獻(xiàn)與它們?yōu)轱w行所燃燒的燃料一樣多。

【計算機(jī)視覺 | Kaggle】飛機(jī)凝結(jié)軌跡識別 Baseline 分享和解讀(含源代碼),計算機(jī)視覺,kaggle,計算機(jī)視覺,人工智能,語義分割,kaggle
凝結(jié)尾跡占人類造成的全球變暖的大約 1%,使用衛(wèi)星圖像的目的是確認(rèn)已有的模型的預(yù)測效果。凝結(jié)尾跡是飛機(jī)發(fā)動機(jī)排氣中形成的冰晶云。它們可以通過在大氣中吸收熱量來促進(jìn)全球變暖。研究人員已經(jīng)開發(fā)出模型來預(yù)測凝結(jié)尾跡何時形成以及它們將導(dǎo)致多少變暖。但是,他們需要使用衛(wèi)星圖像來驗證這些模型。

三、比賽任務(wù)

在本次比賽中,您將使用地球靜止衛(wèi)星圖像來識別航空軌跡。原始衛(wèi)星圖像是從GOES-16 Advanced Baseline Imager (ABI)獲得的,它在Google Cloud Storage上公開可用。

  • 軌跡必須包含至少 10 個像素
  • 軌跡必須至少比寬度長 3 倍
  • 軌跡應(yīng)至少在兩個圖像中可見

【計算機(jī)視覺 | Kaggle】飛機(jī)凝結(jié)軌跡識別 Baseline 分享和解讀(含源代碼),計算機(jī)視覺,kaggle,計算機(jī)視覺,人工智能,語義分割,kaggle

四、比賽數(shù)據(jù)

  • train/ - 訓(xùn)練集;每個文件夾代表一個record_id
  • validation/ 與訓(xùn)練集相同,沒有單獨(dú)的標(biāo)簽注釋
  • test/ - 測試集
  • sample_submission.csv - 格式正確的樣本提交文件

五、評價指標(biāo)

為了減小提交文件的大小,我們的指標(biāo)對像素值使用游程編碼。評價指標(biāo)為 Dice coefficient:

2 ? ∣ X ∩ Y ∣ ∣ X ∣ + ∣ Y ∣ \frac{2 * |X \cap Y|}{|X| + |Y|} X+Y2?XY?
賽題是一個典型語義分割比賽,需要構(gòu)建語義分割的模型。相比與常規(guī)的語義分割比賽,本次比賽有兩個難點(diǎn):

  • 比賽數(shù)據(jù)集比較大,450GB
  • 包含時序圖片,并且標(biāo)簽和時序相關(guān)

六、Baseline

6.1 Training part

import sys
sys.path.append("../input/pretrained-models-pytorch")
sys.path.append("../input/efficientnet-pytorch")
sys.path.append("/kaggle/input/smp-github/segmentation_models.pytorch-master")
sys.path.append("/kaggle/input/timm-pretrained-resnest/resnest/")
import segmentation_models_pytorch as smp

具體來說,代碼做了以下幾個操作:

  1. 導(dǎo)入 sys 模塊,用于添加新的路徑到 Python 搜索路徑中。
  2. 使用 sys.path.append 將 “…/input/pretrained-models-pytorch”、“…/input/efficientnet-pytorch”、“/kaggle/input/smp-github/segmentation_models.pytorch-master” 和 “/kaggle/input/timm-pretrained-resnest/resnest/” 這四個路徑添加到 Python 搜索路徑中。
  3. 導(dǎo)入了 segmentation_models_pytorch 模塊,并使用別名 smp。

通過以上導(dǎo)入操作,你可以使用 smp 這個別名來調(diào)用 segmentation_models_pytorch 庫中的函數(shù)和類,例如圖像分割模型。

這樣做的目的是為了方便在 Kaggle 環(huán)境中使用預(yù)訓(xùn)練的 PyTorch 模型和相關(guān)的圖像分割工具,以便更輕松地進(jìn)行圖像分割任務(wù)的開發(fā)和實驗。

%%writefile config.yaml

data_path: "/kaggle/input/contrails-images-ash-color"
output_dir: "models"

folds:
    n_splits: 4
    random_state: 42
train_folds: [0, 1, 2, 3]
    
seed: 42

train_bs: 48
valid_bs: 128
workers: 2

progress_bar_refresh_rate: 1

early_stop:
    monitor: "val_loss"
    mode: "min"
    patience: 999
    verbose: 1

trainer:
    max_epochs: 20
    min_epochs: 20
    enable_progress_bar: True
    precision: "16-mixed"
    devices: 2

model:
    seg_model: "Unet"
    encoder_name: "timm-resnest26d"
    loss_smooth: 1.0
    image_size: 384
    optimizer_params:
        lr: 0.0005
        weight_decay: 0.0
    scheduler:
        name: "cosine_with_hard_restarts_schedule_with_warmup"
        params:
            cosine_with_hard_restarts_schedule_with_warmup:
                num_warmup_steps: 350
                num_training_steps: 3150
                num_cycles: 1

這段代碼是一個 YAML 格式的配置文件,用于配置一個圖像分割任務(wù)的參數(shù)。YAML 是一種簡單的數(shù)據(jù)序列化語言,用于配置和存儲數(shù)據(jù)。

這份配置文件中包含了以下內(nèi)容:

  1. 數(shù)據(jù)路徑和輸出目錄:定義了數(shù)據(jù)集的路徑和輸出模型的目錄。
  2. 交叉驗證的折數(shù):folds 部分指定了交叉驗證的折數(shù)和隨機(jī)種子,以便將數(shù)據(jù)集劃分為訓(xùn)練集和驗證集。
  3. 訓(xùn)練和驗證的批次大?。?code>train_bs 和 valid_bs 分別指定了訓(xùn)練和驗證時的批次大小。
  4. 訓(xùn)練的其他參數(shù):包括隨機(jī)種子 seed、工作線程數(shù)量 workers、進(jìn)度條刷新率 progress_bar_refresh_rate 等。
  5. 提前停止策略:early_stop 部分指定了提前停止的相關(guān)參數(shù),例如監(jiān)測的指標(biāo)、模式(最小化或最大化)、耐心值等。
  6. 訓(xùn)練器(Trainer)參數(shù):包括最大訓(xùn)練周期數(shù) max_epochs、最小訓(xùn)練周期數(shù) min_epochs、是否啟用進(jìn)度條等。
  7. 模型參數(shù):model 部分定義了圖像分割模型的相關(guān)參數(shù),如分割模型的類型 seg_model、編碼器的名稱 encoder_name、圖像大小 image_size、優(yōu)化器參數(shù)等。

這樣的配置文件可以讓你在運(yùn)行圖像分割任務(wù)時輕松地修改參數(shù)和配置,以便快速嘗試不同的設(shè)置和調(diào)整超參數(shù),提高模型性能和訓(xùn)練效率。

# Dataset
import torch
import numpy as np
import torchvision.transforms as T

class ContrailsDataset(torch.utils.data.Dataset):
    def __init__(self, df, image_size=256, train=True):
        self.df = df
        self.trn = train
        self.normalize_image = T.Normalize((0.485, 0.456, 0.406), (0.229, 0.224, 0.225))
        self.image_size = image_size
        if image_size != 256:
            self.resize_image = T.transforms.Resize(image_size)

    def __getitem__(self, index):
        row = self.df.iloc[index]
        con_path = row.path
        con = np.load(str(con_path))
        img = con[..., :-1]
        label = con[..., -1]
        label = torch.tensor(label)
        img = torch.tensor(np.reshape(img, (256, 256, 3))).to(torch.float32).permute(2, 0, 1)
        if self.image_size != 256:
            img = self.resize_image(img)
        img = self.normalize_image(img)
        return img.float(), label.float()

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

這段代碼定義了一個 PyTorch 數(shù)據(jù)集類 ContrailsDataset,用于加載和處理圖像分割任務(wù)的數(shù)據(jù)。

數(shù)據(jù)集類的主要功能包括:

  1. 初始化:在初始化過程中,數(shù)據(jù)集類接收一個數(shù)據(jù)幀(DataFrame) df,以及一個布爾值 train,用于標(biāo)識數(shù)據(jù)集是用于訓(xùn)練還是驗證。同時,它也接收一個整數(shù) image_size,表示圖像的大小,若該值不等于 256,則會使用 T.transforms.Resize 將圖像調(diào)整為指定大小。
  2. __getitem__ 方法:這是數(shù)據(jù)集類的核心方法,在使用索引來獲取數(shù)據(jù)樣本時會調(diào)用。在這個方法中,根據(jù)索引獲取數(shù)據(jù)幀中的一行,從中提取出圖像和標(biāo)簽,并對其進(jìn)行處理。具體地,它會將讀取的 numpy 數(shù)組轉(zhuǎn)換為 PyTorch 張量,并進(jìn)行大小和通道維度的調(diào)整,最后返回處理后的圖像和標(biāo)簽。
  3. __len__ 方法:這個方法返回數(shù)據(jù)集的樣本數(shù)量,以便在訓(xùn)練和驗證時知道數(shù)據(jù)集的總樣本數(shù)。

該數(shù)據(jù)集類適用于加載存儲在 numpy 格式中的圖像和標(biāo)簽數(shù)據(jù),并將其轉(zhuǎn)換為 PyTorch 張量,供神經(jīng)網(wǎng)絡(luò)模型使用。注意,在使用該數(shù)據(jù)集類之前,你需要根據(jù)實際數(shù)據(jù)的存儲方式和結(jié)構(gòu)來適配數(shù)據(jù)幀 df,以確保正確讀取圖像和標(biāo)簽數(shù)據(jù)。

self.normalize_image 是一個 torchvision 的數(shù)據(jù)轉(zhuǎn)換(transform),用于對圖像數(shù)據(jù)進(jìn)行歸一化操作。在深度學(xué)習(xí)中,歸一化是一個重要的預(yù)處理步驟,可以將圖像的像素值縮放到特定的范圍,以便更好地訓(xùn)練模型并提高模型的收斂性和穩(wěn)定性。

在 torchvision 中,T.Normalize(mean, std) 是一個常用的數(shù)據(jù)轉(zhuǎn)換,它將輸入的圖像數(shù)據(jù)進(jìn)行歸一化。它接受兩個參數(shù):

  1. mean:這是一個包含三個元素的元組或列表,表示圖像數(shù)據(jù)在每個通道上的均值。通常,這些均值是在大規(guī)模圖像數(shù)據(jù)集上計算得到的。在這里,(0.485, 0.456, 0.406) 是對應(yīng)于 ImageNet 數(shù)據(jù)集的 RGB 通道均值。
  2. std:這也是一個包含三個元素的元組或列表,表示圖像數(shù)據(jù)在每個通道上的標(biāo)準(zhǔn)差。同樣,這些標(biāo)準(zhǔn)差也是在大規(guī)模圖像數(shù)據(jù)集上計算得到的。在這里,(0.229, 0.224, 0.225) 是對應(yīng)于 ImageNet 數(shù)據(jù)集的 RGB 通道標(biāo)準(zhǔn)差。

T.Normalize 的作用是將圖像數(shù)據(jù)的每個通道減去均值,然后除以標(biāo)準(zhǔn)差,這樣處理后的圖像數(shù)據(jù)會具有零均值和單位方差,從而使數(shù)據(jù)的分布更穩(wěn)定。

ContrailsDataset 類中,self.normalize_image 這個數(shù)據(jù)轉(zhuǎn)換被用于對圖像數(shù)據(jù)進(jìn)行歸一化處理。在 __getitem__ 方法中,將加載的圖像數(shù)據(jù)轉(zhuǎn)換為 PyTorch 張量后,會應(yīng)用 self.normalize_image 來進(jìn)行歸一化處理,以便更好地輸入神經(jīng)網(wǎng)絡(luò)模型。這樣做可以有效地將數(shù)據(jù)縮放到合適的范圍,以加快訓(xùn)練速度和提高模型性能。

__getitem__ 方法的完整實現(xiàn)。該方法用于獲取數(shù)據(jù)集中的一個樣本。

  1. row = self.df.iloc[index]:從數(shù)據(jù)幀 df 中根據(jù)索引 index 獲取相應(yīng)行的數(shù)據(jù)。
  2. con_path = row.path:從該行數(shù)據(jù)中獲取路徑信息,該路徑指向一個數(shù)據(jù)文件,其中包含圖像數(shù)據(jù)和標(biāo)簽數(shù)據(jù)。
  3. con = np.load(str(con_path)):使用 NumPy 的 np.load() 方法加載數(shù)據(jù)文件,將其讀取為一個 NumPy 數(shù)組 con
  4. img = con[..., :-1]:從 con 數(shù)組中獲取圖像部分,... 表示所有維度的索引,:-1 表示除了最后一個維度之外的所有維度。
  5. label = con[..., -1]:從 con 數(shù)組中獲取標(biāo)簽部分,... 表示所有維度的索引,-1 表示最后一個維度。
  6. label = torch.tensor(label):將標(biāo)簽數(shù)據(jù)轉(zhuǎn)換為 PyTorch 張量。
  7. img = torch.tensor(np.reshape(img, (256, 256, 3))).to(torch.float32).permute(2, 0, 1):將圖像數(shù)據(jù)轉(zhuǎn)換為 PyTorch 張量,并進(jìn)行一系列預(yù)處理操作。np.reshape(img, (256, 256, 3)) 將圖像的通道維度移到最后,然后使用 torch.tensor() 將其轉(zhuǎn)換為張量,to(torch.float32) 將數(shù)據(jù)類型轉(zhuǎn)換為 float32,最后使用 permute(2, 0, 1) 將通道維度移到最前面,使其符合 PyTorch 的張量格式要求。
  8. if self.image_size != 256::檢查圖像的尺寸是否需要進(jìn)行調(diào)整。
  9. img = self.resize_image(img):如果需要,將圖像大小調(diào)整為 self.image_size。
  10. img = self.normalize_image(img):對圖像數(shù)據(jù)進(jìn)行標(biāo)準(zhǔn)化處理,將像素值縮放到固定的范圍內(nèi),以適應(yīng)模型的輸入要求。
  11. return img.float(), label.float():返回處理后的圖像和標(biāo)簽作為元組,并將它們轉(zhuǎn)換為 float 類型的張量。

在 PyTorch 中,permute() 是一個張量的操作函數(shù),用于重新排列張量的維度順序。它的作用是改變張量的維度排列,不改變張量中的元素值。

permute() 函數(shù)的輸入?yún)?shù)是一個表示新維度順序的整數(shù)元組。例如,對于一個四維張量 tensor,可以使用 tensor.permute(0, 2, 3, 1) 來將原先的維度排列 [0, 1, 2, 3] 調(diào)整為 [0, 2, 3, 1]。

下面是一個示例:

import torch

# 創(chuàng)建一個四維張量
tensor = torch.randn(2, 3, 4, 5)
# 打印原始維度排列
print("Original tensor shape:", tensor.shape)  # Output: (2, 3, 4, 5)
# 使用 permute() 調(diào)整維度排列
tensor_permuted = tensor.permute(0, 2, 3, 1)
# 打印調(diào)整后的維度排列
print("Permuted tensor shape:", tensor_permuted.shape)  # Output: (2, 4, 5, 3)

在上面的示例中,原始張量的維度排列是 [2, 3, 4, 5],使用 tensor.permute(0, 2, 3, 1) 調(diào)整為 [2, 4, 5, 3]。可以看到,張量的維度順序被重新排列,但張量中的元素值保持不變。permute() 函數(shù)是一種非常便捷的方式來進(jìn)行維度轉(zhuǎn)換,特別是在神經(jīng)網(wǎng)絡(luò)的數(shù)據(jù)處理過程中,經(jīng)常需要調(diào)整張量的維度以適應(yīng)模型的輸入要求。

# Lightning module

import torch
import pytorch_lightning as pl
import segmentation_models_pytorch as smp
from torch.optim.lr_scheduler import CosineAnnealingLR, ReduceLROnPlateau
from torch.optim import AdamW
import torch.nn as nn
from torchmetrics.functional import dice
from transformers import get_cosine_with_hard_restarts_schedule_with_warmup

seg_models = {
    "Unet": smp.Unet,
    "Unet++": smp.UnetPlusPlus,
    "MAnet": smp.MAnet,
    "Linknet": smp.Linknet,
    "FPN": smp.FPN,
    "PSPNet": smp.PSPNet,
    "PAN": smp.PAN,
    "DeepLabV3": smp.DeepLabV3,
    "DeepLabV3+": smp.DeepLabV3Plus,
}

class LightningModule(pl.LightningModule):
    def __init__(self, config):
        super().__init__()
        self.config = config
        self.model = model = seg_models[config["seg_model"]](
            encoder_name = config["encoder_name"],
            encoder_weights = "imagenet",
            in_channels = 3,
            classes = 1,
            activation = None,
        )
        self.loss_module = smp.losses.DiceLoss(mode="binary", smooth=config["loss_smooth"])
        self.val_step_outputs = []
        self.val_step_labels = []

    def forward(self, batch):
        imgs = batch
        preds = self.model(imgs)
        return preds

    def configure_optimizers(self):
        optimizer = AdamW(self.parameters(), **self.config["optimizer_params"])
        if self.config["scheduler"]["name"] == "CosineAnnealingLR":
            scheduler = CosineAnnealingLR(
                optimizer,
                **self.config["scheduler"]["params"]["CosineAnnealingLR"],
            )
            lr_scheduler_dict = {"scheduler": scheduler, "interval": "step"}
            return {"optimizer": optimizer, "lr_scheduler": lr_scheduler_dict}
        elif self.config["scheduler"]["name"] == "ReduceLROnPlateau":
            scheduler = ReduceLROnPlateau(
                optimizer,
                **self.config["scheduler"]["params"]["ReduceLROnPlateau"],
            )
            lr_scheduler = {"scheduler": scheduler, "monitor": "val_loss"}
            return {"optimizer": optimizer, "lr_scheduler": lr_scheduler}
        elif self.config["scheduler"]["name"] == "cosine_with_hard_restarts_schedule_with_warmup":
            scheduler = get_cosine_with_hard_restarts_schedule_with_warmup(
                optimizer,
                **self.config["scheduler"]["params"][self.config["scheduler"]["name"]],
            )
            lr_scheduler_dict = {"scheduler": scheduler, "interval": "step"}
            return {"optimizer": optimizer, "lr_scheduler": lr_scheduler_dict}

    def training_step(self, batch, batch_idx):
        imgs, labels = batch
        preds = self.model(imgs)
        if self.config["image_size"] != 256:
            preds = torch.nn.functional.interpolate(preds, size=256, mode='bilinear')
        loss = self.loss_module(preds, labels)
        self.log("train_loss", loss, on_step=True, on_epoch=True, prog_bar=True, batch_size=16)
        for param_group in self.trainer.optimizers[0].param_groups:
            lr = param_group["lr"]
        self.log("lr", lr, on_step=True, on_epoch=False, prog_bar=True)
        return loss

    def validation_step(self, batch, batch_idx):
        imgs, labels = batch
        preds = self.model(imgs)
        if self.config["image_size"] != 256:
            preds = torch.nn.functional.interpolate(preds, size=256, mode='bilinear')
        loss = self.loss_module(preds, labels)
        self.log("val_loss", loss, on_step=False, on_epoch=True, prog_bar=True)
        self.val_step_outputs.append(preds)
        self.val_step_labels.append(labels)

    def on_validation_epoch_end(self):
        all_preds = torch.cat(self.val_step_outputs)
        all_labels = torch.cat(self.val_step_labels)
        all_preds = torch.sigmoid(all_preds)
        self.val_step_outputs.clear()
        self.val_step_labels.clear()
        val_dice = dice(all_preds, all_labels.long())
        self.log("val_dice", val_dice, on_step=False, on_epoch=True, prog_bar=True)
        if self.trainer.global_rank == 0:
            print(f"\nEpoch: {self.current_epoch}", flush=True)

這段代碼定義了一個 PyTorch Lightning 模塊 LightningModule,用于訓(xùn)練圖像分割模型。

主要功能包括:

  1. 初始化:在初始化過程中,接收一個配置參數(shù) config,用于配置模型的參數(shù)和優(yōu)化器。
  2. 構(gòu)建圖像分割模型:根據(jù)配置中的 seg_modelencoder_name,從 seg_models 字典中選擇合適的圖像分割模型,并初始化該模型。
  3. 定義損失函數(shù):使用 smp.losses.DiceLoss 作為損失函數(shù),并根據(jù)配置中的 loss_smooth 參數(shù)初始化 Dice Loss。
  4. 前向傳播:在 forward 方法中,接收一個批次的圖像數(shù)據(jù) batch,將其輸入模型中進(jìn)行前向傳播,并返回預(yù)測結(jié)果 preds。
  5. 配置優(yōu)化器和學(xué)習(xí)率調(diào)度器:通過 configure_optimizers 方法配置優(yōu)化器和學(xué)習(xí)率調(diào)度器。根據(jù)配置中的 scheduler,選擇對應(yīng)的學(xué)習(xí)率調(diào)度器,例如 CosineAnnealingLR、ReduceLROnPlateaucosine_with_hard_restarts_schedule_with_warmup
  6. 訓(xùn)練步驟:在 training_step 方法中,接收一個批次的圖像數(shù)據(jù) batch 和批次索引 batch_idx,執(zhí)行模型的訓(xùn)練步驟。計算模型的預(yù)測結(jié)果 preds 和損失函數(shù)的值 loss,并輸出訓(xùn)練的損失值和學(xué)習(xí)率。
  7. 驗證步驟:在 validation_step 方法中,接收一個批次的圖像數(shù)據(jù) batch 和批次索引 batch_idx,執(zhí)行模型的驗證步驟。計算模型的預(yù)測結(jié)果 preds 和損失函數(shù)的值 loss,并輸出驗證的損失值。
  8. 驗證輪結(jié)束時操作:在 on_validation_epoch_end 方法中,進(jìn)行每個驗證輪結(jié)束后的操作。計算 Dice 指標(biāo),并打印當(dāng)前的訓(xùn)練輪數(shù)。

LightningModule 類為圖像分割任務(wù)提供了整體的訓(xùn)練和驗證流程,包括模型的初始化、損失函數(shù)的定義、前向傳播、優(yōu)化器和學(xué)習(xí)率調(diào)度器的配置,以及訓(xùn)練和驗證的具體步驟。它是 PyTorch Lightning 框架中的一個核心組件,可以大大簡化訓(xùn)練過程,并提供了豐富的功能和回調(diào)函數(shù)來定制化訓(xùn)練過程。

初始化的步驟:

  • __init__ 方法:初始化函數(shù),在創(chuàng)建類實例時被調(diào)用,用于定義模型的結(jié)構(gòu)和其他初始化操作。
    • config: 是一個字典,包含了模型的配置參數(shù)。
    • model: 初始化語義分割模型,通過 seg_models 字典中指定的 seg_modelencoder_name 來選擇特定的語義分割模型。
    • loss_module: 定義了用于計算損失的 DiceLoss,參數(shù) mode="binary" 表示計算二值分割的 Dice Loss。
    • val_step_outputsval_step_labels: 這是用于保存驗證步驟中的模型輸出和真實標(biāo)簽的列表,以便在 validation_step 方法中使用和跟蹤驗證指標(biāo)。

接下來,這個 LightningModule 類還包含其他幾個方法,用于實現(xiàn)模型的前向傳播、優(yōu)化器和學(xué)習(xí)率調(diào)度器的配置,以及訓(xùn)練和驗證步驟的定義。

前向傳播過程:

forward 方法定義了模型的前向傳播過程。它接收一個批次的輸入數(shù)據(jù) batch,其中 batch 是一個包含圖像數(shù)據(jù)的張量。在這里,imgs 表示輸入的圖像數(shù)據(jù)。

然后,self.model 表示定義的語義分割模型,根據(jù) config["seg_model"]config["encoder_name"] 來選擇相應(yīng)的模型結(jié)構(gòu)。self.model 接收 imgs 作為輸入,進(jìn)行前向傳播,得到預(yù)測的語義分割結(jié)果 preds。

最后,forward 方法返回預(yù)測結(jié)果 preds,這個結(jié)果將在訓(xùn)練過程中用于計算損失和優(yōu)化模型。

配置優(yōu)化器和學(xué)習(xí)率調(diào)度器:

在這個方法中,首先根據(jù)配置參數(shù) self.config["optimizer_params"] 創(chuàng)建一個 AdamW 優(yōu)化器對象 optimizer,其中使用了模型的參數(shù) self.parameters()。

然后,根據(jù)配置參數(shù) self.config["scheduler"]["name"] 來選擇相應(yīng)的學(xué)習(xí)率調(diào)度器。

  • 如果選擇的調(diào)度器是 CosineAnnealingLR,則創(chuàng)建一個 CosineAnnealingLR 調(diào)度器對象 scheduler,并使用 self.config["scheduler"]["params"]["CosineAnnealingLR"] 中的參數(shù)來配置調(diào)度器。
  • 如果選擇的調(diào)度器是 ReduceLROnPlateau,則創(chuàng)建一個 ReduceLROnPlateau 調(diào)度器對象 scheduler,并使用 self.config["scheduler"]["params"]["ReduceLROnPlateau"] 中的參數(shù)來配置調(diào)度器。
  • 如果選擇的調(diào)度器是 cosine_with_hard_restarts_schedule_with_warmup,則創(chuàng)建一個使用 get_cosine_with_hard_restarts_schedule_with_warmup 函數(shù)生成的調(diào)度器對象 scheduler,并使用 self.config["scheduler"]["params"][self.config["scheduler"]["name"]] 中的參數(shù)來配置調(diào)度器。

最后,根據(jù)選擇的調(diào)度器返回一個字典,其中包含了優(yōu)化器和學(xué)習(xí)率調(diào)度器的配置信息。這樣,在訓(xùn)練過程中,Lightning 就會自動地根據(jù)這些配置來進(jìn)行優(yōu)化和學(xué)習(xí)率調(diào)整。

在訓(xùn)練集上的一個前向傳播和損失計算的步驟:

這個方法接收一個批次的輸入數(shù)據(jù) batch 和批次的索引 batch_idx

首先,從輸入批次 batch 中解包得到圖像數(shù)據(jù) imgs 和對應(yīng)的標(biāo)簽 labels。然后,通過 self.model 對圖像數(shù)據(jù)進(jìn)行前向傳播,得到預(yù)測的語義分割結(jié)果 preds。

如果配置中的 image_size 不等于 256,那么會對預(yù)測結(jié)果 preds 進(jìn)行插值,將其調(diào)整為大小為 256x256 的分辨率。

接著,使用 self.loss_module 計算預(yù)測結(jié)果 preds 和真實標(biāo)簽 labels 之間的 Dice Loss。這里使用 Dice Loss 作為損失函數(shù)來度量預(yù)測結(jié)果和真實標(biāo)簽之間的相似度。

然后,通過 self.log 方法記錄訓(xùn)練損失 train_loss,并設(shè)置 on_step=Trueon_epoch=True,這樣在訓(xùn)練過程中會每個步驟和每個 epoch 都打印損失,并顯示在進(jìn)度條中。

接下來,獲取當(dāng)前優(yōu)化器的學(xué)習(xí)率 lr,并使用 self.log 方法記錄學(xué)習(xí)率 lr,設(shè)置 on_step=Trueon_epoch=False,這樣在訓(xùn)練過程中會每個步驟打印學(xué)習(xí)率,并顯示在進(jìn)度條中。

最后,返回計算得到的損失值 loss,這個值將用于進(jìn)行反向傳播和模型的優(yōu)化。

模型在驗證集上的一個前向傳播和損失計算的步驟:

這個方法接收一個批次的輸入數(shù)據(jù) batch 和批次的索引 batch_idx。

首先,從輸入批次 batch 中解包得到圖像數(shù)據(jù) imgs 和對應(yīng)的標(biāo)簽 labels。然后,通過 self.model 對圖像數(shù)據(jù)進(jìn)行前向傳播,得到預(yù)測的語義分割結(jié)果 preds。

如果配置中的 image_size 不等于 256,那么會對預(yù)測結(jié)果 preds 進(jìn)行插值,將其調(diào)整為大小為 256x256 的分辨率。

接著,使用 self.loss_module 計算預(yù)測結(jié)果 preds 和真實標(biāo)簽 labels 之間的 Dice Loss。這里使用 Dice Loss 作為損失函數(shù)來度量預(yù)測結(jié)果和真實標(biāo)簽之間的相似度。

然后,通過 self.log 方法記錄驗證損失 val_loss,設(shè)置 on_step=Falseon_epoch=True,這樣在每個 epoch 結(jié)束時打印驗證損失,并顯示在進(jìn)度條中。

接下來,將預(yù)測結(jié)果 preds 和標(biāo)簽 labels 添加到列表 self.val_step_outputsself.val_step_labels 中,這樣在每個 epoch 結(jié)束時可以使用這些數(shù)據(jù)來計算整個驗證集上的評估指標(biāo)。

注意,這里沒有返回任何值,因為在 Lightning 中,在驗證階段只需要計算驗證指標(biāo),不需要進(jìn)行反向傳播和優(yōu)化,因此不需要返回?fù)p失值。

完成了一個完整的驗證階段后進(jìn)行的操作:

該方法在每個 epoch 結(jié)束時被調(diào)用,用于對整個驗證集的預(yù)測結(jié)果進(jìn)行評估和記錄。

首先,將所有驗證步驟中得到的預(yù)測結(jié)果 self.val_step_outputs 和標(biāo)簽 self.val_step_labels 拼接起來,形成一個完整的預(yù)測結(jié)果和對應(yīng)的標(biāo)簽,分別存儲在 all_predsall_labels 中。

然后,對預(yù)測結(jié)果 all_preds 進(jìn)行 sigmoid 函數(shù)的轉(zhuǎn)換,將其轉(zhuǎn)換為概率值在 0 到 1 之間。

接著,使用 torchmetrics.functional.dice 函數(shù)計算預(yù)測結(jié)果 all_preds 和真實標(biāo)簽 all_labels 之間的 Dice 系數(shù)。Dice 系數(shù)是用于評估語義分割任務(wù)的一種指標(biāo),用于衡量預(yù)測結(jié)果與真實標(biāo)簽之間的相似度。

接下來,通過 self.log 方法記錄驗證集上的 Dice 系數(shù) val_dice,設(shè)置 on_step=Falseon_epoch=True,這樣在每個 epoch 結(jié)束時打印驗證集上的 Dice 系數(shù),并顯示在進(jìn)度條中。

最后,如果當(dāng)前進(jìn)程是全局排名為 0 的進(jìn)程(通常是主進(jìn)程),則打印當(dāng)前 epoch 的信息,例如顯示當(dāng)前 epoch 的編號,這里使用 self.current_epoch 來獲取當(dāng)前的 epoch 編號,并使用 print 函數(shù)打印該信息。

# Actual training
import warnings
warnings.filterwarnings("ignore")
import gc
import os
import torch
import yaml
import pandas as pd
import pytorch_lightning as pl
from pytorch_lightning.callbacks import ModelCheckpoint, EarlyStopping, TQDMProgressBar
from torch.utils.data import DataLoader
from sklearn.model_selection import KFold
from pytorch_lightning.loggers import CSVLogger

torch.set_float32_matmul_precision("medium")
with open("config.yaml", "r") as file_obj:
    config = yaml.safe_load(file_obj)
pl.seed_everything(config["seed"])
gc.enable()
contrails = os.path.join(config["data_path"], "contrails/")
train_path = os.path.join(config["data_path"], "train_df.csv")
valid_path = os.path.join(config["data_path"], "valid_df.csv")

train_df = pd.read_csv(train_path)
valid_df = pd.read_csv(valid_path)

train_df["path"] = contrails + train_df["record_id"].astype(str) + ".npy"
valid_df["path"] = contrails + valid_df["record_id"].astype(str) + ".npy"

df = pd.concat([train_df, valid_df]).reset_index()

Fold = KFold(shuffle=True, **config["folds"])
for n, (trn_index, val_index) in enumerate(Fold.split(df)):
    df.loc[val_index, "kfold"] = int(n)
df["kfold"] = df["kfold"].astype(int)

for fold in config["train_folds"]:
    print(f"\n###### Fold {fold}")
    trn_df = df[df.kfold != fold].reset_index(drop=True)
    vld_df = df[df.kfold == fold].reset_index(drop=True)
    dataset_train = ContrailsDataset(trn_df, config["model"]["image_size"], train=True)
    dataset_validation = ContrailsDataset(vld_df, config["model"]["image_size"], train=False)
    data_loader_train = DataLoader(
        dataset_train,
        batch_size=config["train_bs"],
        shuffle=True,
        num_workers=config["workers"],
    )
    data_loader_validation = DataLoader(
        dataset_validation,
        batch_size=config["valid_bs"],
        shuffle=False,
        num_workers=config["workers"],
    )
    checkpoint_callback = ModelCheckpoint(
        save_weights_only=True,
        monitor="val_dice",
        dirpath=config["output_dir"],
        mode="max",
        filename=f"model-f{fold}-{{val_dice:.4f}}",
        save_top_k=1,
        verbose=1,
    )
    progress_bar_callback = TQDMProgressBar(
        refresh_rate=config["progress_bar_refresh_rate"]
    )
    early_stop_callback = EarlyStopping(**config["early_stop"])

    trainer = pl.Trainer(
        callbacks=[checkpoint_callback, early_stop_callback, progress_bar_callback],
        logger=CSVLogger(save_dir=f'logs_f{fold}/'),
        **config["trainer"],
    )
    model = LightningModule(config["model"])
    trainer.fit(model, data_loader_train, data_loader_validation)

    del (
        dataset_train,
        dataset_validation,
        data_loader_train,
        data_loader_validation,
        model,
        trainer,
        checkpoint_callback,
        progress_bar_callback,
        early_stop_callback,
    )
    torch.cuda.empty_cache()
    gc.collect()

這段代碼實際上是執(zhí)行圖像分割模型的訓(xùn)練過程。它使用了 PyTorch Lightning 框架來簡化訓(xùn)練過程,并采用 K 折交叉驗證的方式來訓(xùn)練多個模型。

主要步驟如下:

  1. 讀取配置文件:首先,代碼通過讀取 “config.yaml” 配置文件來加載訓(xùn)練的參數(shù)設(shè)置。
  2. 數(shù)據(jù)準(zhǔn)備:代碼讀取數(shù)據(jù)集文件并構(gòu)建訓(xùn)練集和驗證集的數(shù)據(jù)幀(DataFrame)。然后,根據(jù) K 折交叉驗證的要求,將數(shù)據(jù)劃分為 K 份,其中 (K-1) 份作為訓(xùn)練集,1 份作為驗證集。
  3. 開始訓(xùn)練:通過 for 循環(huán),對每個折(fold)進(jìn)行訓(xùn)練。
  4. 構(gòu)建數(shù)據(jù)集和數(shù)據(jù)加載器:對于每個折,代碼通過構(gòu)建 ContrailsDataset 數(shù)據(jù)集類和數(shù)據(jù)加載器來加載訓(xùn)練和驗證數(shù)據(jù)。將數(shù)據(jù)集傳遞給數(shù)據(jù)加載器,以便進(jìn)行批量數(shù)據(jù)加載。
  5. 配置回調(diào)函數(shù):為訓(xùn)練過程配置回調(diào)函數(shù),包括模型保存回調(diào)、早?;卣{(diào)和進(jìn)度條回調(diào)。這些回調(diào)函數(shù)在訓(xùn)練過程中會根據(jù)設(shè)定的條件執(zhí)行相應(yīng)的操作。
  6. 配置 pl.Trainer:通過配置 pl.Trainer 類,指定訓(xùn)練過程中的一些設(shè)置,例如使用的 GPU 數(shù)量、最大訓(xùn)練周期數(shù)、最小訓(xùn)練周期數(shù)等。
  7. 創(chuàng)建 LightningModule 模型:創(chuàng)建一個 LightningModule 模型,將配置文件中的參數(shù)傳遞給模型。
  8. 訓(xùn)練模型:使用 trainer.fit 方法進(jìn)行模型的訓(xùn)練。在訓(xùn)練過程中,模型會自動執(zhí)行前向傳播、反向傳播、優(yōu)化器更新等操作。
  9. 清理資源:每完成一個折的訓(xùn)練后,代碼會釋放一些資源,如數(shù)據(jù)集、數(shù)據(jù)加載器、模型、回調(diào)函數(shù)等,以便于下一個折的訓(xùn)練。

整個訓(xùn)練過程會持續(xù)多個周期,每個周期(epoch)會對訓(xùn)練集進(jìn)行迭代訓(xùn)練,然后在驗證集上進(jìn)行驗證,并根據(jù)驗證結(jié)果選擇是否早?;虮4婺P汀W罱K,通過多次 K 折交叉驗證,可以得到多個訓(xùn)練好的模型,并從中選擇最好的模型進(jìn)行后續(xù)使用。

import seaborn as sn
import matplotlib.pyplot as plt

for fold in config["train_folds"]:
    metrics = pd.read_csv(f"/kaggle/working/logs_f{fold}/lightning_logs/version_0/metrics.csv")
    del metrics["step"]
    del metrics["lr"]
    del metrics["train_loss_step"]
    metrics.set_index("epoch", inplace=True)
    g = sn.relplot(data=metrics, kind="line")
    plt.title(f"Fold {fold}")
    plt.gcf().set_size_inches(15, 5)
    plt.grid()
    plt.show()

這段代碼用于繪制圖像分割模型訓(xùn)練過程中的一些指標(biāo)隨著訓(xùn)練周期的變化情況。它通過讀取每個折(fold)的訓(xùn)練日志文件,提取相應(yīng)的指標(biāo)數(shù)據(jù),并使用 seaborn 和 matplotlib 庫進(jìn)行可視化。

主要步驟如下:

  1. 通過 for 循環(huán)遍歷每個折(fold)。
  2. 讀取訓(xùn)練日志:使用 pd.read_csv 讀取每個折訓(xùn)練的日志文件,該日志文件保存了訓(xùn)練過程中的指標(biāo)數(shù)據(jù)。
  3. 數(shù)據(jù)預(yù)處理:刪除不需要的列,并將 “epoch” 列設(shè)置為數(shù)據(jù)幀的索引,以便后續(xù)繪圖。
  4. 繪制折(fold)的指標(biāo)曲線:使用 sn.relplot 繪制每個折的指標(biāo)隨著訓(xùn)練周期的變化情況。這里使用了 seaborn 中的 relplot 函數(shù)來繪制折線圖。
  5. 設(shè)置圖像屬性:設(shè)置圖像的標(biāo)題、尺寸和網(wǎng)格等屬性。
  6. 顯示圖像:使用 plt.show() 顯示繪制好的圖像。

通過以上步驟,代碼將繪制每個折的訓(xùn)練過程中指標(biāo)的變化曲線,以便觀察模型的訓(xùn)練情況、收斂性和性能。這樣的可視化有助于了解訓(xùn)練的進(jìn)展情況,并可以發(fā)現(xiàn)模型是否過擬合或欠擬合,以及在哪些周期達(dá)到了最佳性能等信息。

6.2 Submission part

import warnings
warnings.filterwarnings("ignore")
import gc
import os
import glob
import numpy as np
import pandas as pd
import torch
from torch import nn
from torch.utils.data import Dataset, DataLoader
import pytorch_lightning as pl
import torchvision.transforms as T
import yaml

這段代碼導(dǎo)入了一系列的 Python 庫和模塊,用于進(jìn)行圖像分割任務(wù)的實驗和開發(fā)。

具體的導(dǎo)入內(nèi)容包括:

  1. warnings:用于忽略警告信息,以便在實驗過程中不顯示警告。
  2. gc:Python 的垃圾回收模塊,用于處理內(nèi)存管理和垃圾回收。
  3. os:用于與操作系統(tǒng)進(jìn)行交互,比如文件路徑的操作和系統(tǒng)命令的執(zhí)行。
  4. glob:用于查找符合特定規(guī)則的文件路徑。
  5. numpy:用于處理數(shù)值計算和數(shù)組操作。
  6. pandas:用于數(shù)據(jù)處理和分析,特別是用于處理結(jié)構(gòu)化數(shù)據(jù),如 DataFrame。
  7. torch:PyTorch 深度學(xué)習(xí)框架的核心模塊。
  8. torch.nn:PyTorch 中的神經(jīng)網(wǎng)絡(luò)模塊,包含各種層和損失函數(shù)。
  9. DatasetDataLoader:PyTorch 中用于處理數(shù)據(jù)的模塊,用于加載數(shù)據(jù)集并構(gòu)建數(shù)據(jù)加載器。
  10. pytorch_lightning:PyTorch Lightning 是一個輕量級的 PyTorch 框架擴(kuò)展,用于簡化深度學(xué)習(xí)的訓(xùn)練和開發(fā)流程。
  11. torchvision.transforms:用于定義圖像數(shù)據(jù)的預(yù)處理和數(shù)據(jù)增強(qiáng)的模塊。
  12. yaml:用于讀取和解析 YAML 格式的配置文件。

這些導(dǎo)入語句為后續(xù)的圖像分割任務(wù)實驗提供了必要的基礎(chǔ)庫和模塊,可以方便地進(jìn)行數(shù)據(jù)處理、模型定義、訓(xùn)練和驗證等操作。同時,通過 PyTorch Lightning 的使用,還能進(jìn)一步簡化訓(xùn)練流程,并提供豐富的功能和回調(diào)函數(shù)來進(jìn)行定制化的實驗和調(diào)試。

batch_size = 32
num_workers = 1
THR = 0.5
device = torch.device('cuda' if torch.cuda.is_available() else 'cpu')
data = '/kaggle/input/google-research-identify-contrails-reduce-global-warming'
data_root = '/kaggle/input/google-research-identify-contrails-reduce-global-warming/test/'
submission = pd.read_csv(os.path.join(data, 'sample_submission.csv'), index_col='record_id')

這段代碼設(shè)置了一些變量和路徑,為進(jìn)行圖像分割任務(wù)的預(yù)測和提交結(jié)果做準(zhǔn)備。

具體的設(shè)置包括:

  1. batch_size = 32:定義每個批次中的樣本數(shù)量。
  2. num_workers = 1:定義數(shù)據(jù)加載器的工作線程數(shù)量。
  3. THR = 0.5:定義一個閾值(threshold),用于在進(jìn)行預(yù)測時對模型輸出進(jìn)行二值化,以得到最終的分割結(jié)果。
  4. device:定義計算設(shè)備,如果可用,則使用 CUDA 加速,否則使用 CPU 進(jìn)行計算。
  5. data:設(shè)置數(shù)據(jù)集的根路徑,此處指向 “/kaggle/input/google-research-identify-contrails-reduce-global-warming”,該路徑可能包含訓(xùn)練集和測試集等數(shù)據(jù)。
  6. data_root:設(shè)置測試集數(shù)據(jù)的路徑,指向 “/kaggle/input/google-research-identify-contrails-reduce-global-warming/test/”,該路徑是測試集數(shù)據(jù)存放的目錄。
  7. submission:讀取測試集的樣本提交文件 “sample_submission.csv”,并將 “record_id” 列作為數(shù)據(jù)幀的索引,該文件用于提交最終的預(yù)測結(jié)果。

通過上述設(shè)置,代碼為后續(xù)的測試數(shù)據(jù)加載、模型預(yù)測和結(jié)果提交做好了準(zhǔn)備。具體的預(yù)測和提交過程可能會在后續(xù)的代碼中進(jìn)行。

filenames = os.listdir(data_root)
test_df = pd.DataFrame(filenames, columns = ['record_id'])
test_df['path'] = data_root + test_df['record_id'].astype(str)

這段代碼用于構(gòu)建測試集的數(shù)據(jù)幀(DataFrame),以便在進(jìn)行圖像分割模型的預(yù)測時使用。

具體步驟如下:

  1. 使用 os.listdir(data_root) 獲取測試集數(shù)據(jù)目錄 data_root 中的所有文件名列表 filenamesos.listdir() 函數(shù)會返回指定目錄下的所有文件和子目錄的名稱。
  2. 創(chuàng)建一個新的數(shù)據(jù)幀 test_df,并將 filenames 列表作為一列 “record_id” 加入數(shù)據(jù)幀。
  3. 構(gòu)建 “path” 列:將 “record_id” 列中的每個文件名轉(zhuǎn)換為完整的文件路徑,并添加為 “path” 列。這樣,“path” 列中保存了測試集數(shù)據(jù)文件的完整路徑。

通過以上步驟,代碼將測試集數(shù)據(jù)的文件名和完整路徑保存在數(shù)據(jù)幀 test_df 中,方便后續(xù)加載數(shù)據(jù)和進(jìn)行模型的預(yù)測。每行數(shù)據(jù)表示測試集中的一個樣本,其中 “record_id” 列保存了樣本的文件名,“path” 列保存了樣本的完整文件路徑。

class ContrailsDataset(torch.utils.data.Dataset):
    def __init__(self, df, image_size=256, train=True):
        self.df = df
        self.trn = train
        self.df_idx: pd.DataFrame = pd.DataFrame({'idx': os.listdir(f'/kaggle/input/google-research-identify-contrails-reduce-global-warming/test')})
        self.normalize_image = T.Normalize((0.485, 0.456, 0.406), (0.229, 0.224, 0.225))
        self.image_size = image_size
        if image_size != 256:
            self.resize_image = T.transforms.Resize(image_size)
    
    def read_record(self, directory):
        record_data = {}
        for x in [
            "band_11", 
            "band_14", 
            "band_15"
        ]:
            record_data[x] = np.load(os.path.join(directory, x + ".npy"))
        return record_data

    def normalize_range(self, data, bounds):
        """Maps data to the range [0, 1]."""
        return (data - bounds[0]) / (bounds[1] - bounds[0])
    
    def get_false_color(self, record_data):
        _T11_BOUNDS = (243, 303)
        _CLOUD_TOP_TDIFF_BOUNDS = (-4, 5)
        _TDIFF_BOUNDS = (-4, 2)
        N_TIMES_BEFORE = 4
        r = self.normalize_range(record_data["band_15"] - record_data["band_14"], _TDIFF_BOUNDS)
        g = self.normalize_range(record_data["band_14"] - record_data["band_11"], _CLOUD_TOP_TDIFF_BOUNDS)
        b = self.normalize_range(record_data["band_14"], _T11_BOUNDS)
        false_color = np.clip(np.stack([r, g, b], axis=2), 0, 1)
        img = false_color[..., N_TIMES_BEFORE]
        return img
    
    def __getitem__(self, index):
        row = self.df.iloc[index]
        con_path = row.path
        data = self.read_record(con_path)    
        img = self.get_false_color(data)
        img = torch.tensor(np.reshape(img, (256, 256, 3))).to(torch.float32).permute(2, 0, 1)
        if self.image_size != 256:
            img = self.resize_image(img) 
        img = self.normalize_image(img)
        image_id = int(self.df_idx.iloc[index]['idx'])    
        return img.float(), torch.tensor(image_id)
    
    def __len__(self):
        return len(self.df)

這是一個名為 ContrailsDataset 的 PyTorch 數(shù)據(jù)集類,用于處理圖像分割任務(wù)中的數(shù)據(jù)加載和預(yù)處理。

類中包含以下方法:

  1. __init__(self, df, image_size=256, train=True):初始化方法,用于指定數(shù)據(jù)集的相關(guān)設(shè)置和參數(shù)。df 是包含樣本信息的數(shù)據(jù)幀,image_size 是圖像的尺寸,默認(rèn)為 256,train 是一個布爾值,用于標(biāo)識是否是訓(xùn)練集,如果為 True,則表示是訓(xùn)練集,否則表示是測試集。
  2. read_record(self, directory):用于從指定目錄 directory 讀取記錄數(shù)據(jù)。這個方法從不同文件中加載 “band_11”、“band_14” 和 “band_15” 數(shù)據(jù),然后返回這些數(shù)據(jù)組成的字典。
  3. normalize_range(self, data, bounds):用于將數(shù)據(jù)映射到指定范圍 [0, 1] 的方法。data 是要映射的數(shù)據(jù),bounds 是目標(biāo)范圍的上下界。
  4. get_false_color(self, record_data):用于生成偽彩色圖像的方法。該方法從記錄數(shù)據(jù)字典 record_data 中獲取 “band_11”、“band_14” 和 “band_15” 數(shù)據(jù),并通過歸一化和組合生成偽彩色圖像。
  5. __getitem__(self, index):用于獲取數(shù)據(jù)集中特定索引處的數(shù)據(jù)樣本。根據(jù)索引 index,讀取數(shù)據(jù)幀 df 中對應(yīng)的樣本信息,調(diào)用 read_record 方法讀取記錄數(shù)據(jù),并通過 get_false_color 方法生成偽彩色圖像。然后,對圖像進(jìn)行大小調(diào)整、標(biāo)準(zhǔn)化處理,并返回圖像和樣本的 ID。
  6. __len__(self):用于獲取數(shù)據(jù)集的長度,即樣本的數(shù)量。

通過這個自定義的數(shù)據(jù)集類,可以方便地加載數(shù)據(jù)、對圖像進(jìn)行預(yù)處理,并在訓(xùn)練和預(yù)測過程中使用 PyTorch 的數(shù)據(jù)加載器來加載批次數(shù)據(jù)。這樣,可以方便地將數(shù)據(jù)送入模型進(jìn)行訓(xùn)練和推理。

get_false_color 方法用于生成偽彩色圖像,主要是通過計算不同波段之間的像元值差異來構(gòu)造一張偽彩色圖像。在這里,該方法接受一個包含多個波段數(shù)據(jù)的字典 record_data 作為輸入,然后根據(jù)不同波段之間的范圍進(jìn)行歸一化,構(gòu)造偽彩色圖像并返回。

具體的步驟如下:

  1. _T11_BOUNDS_CLOUD_TOP_TDIFF_BOUNDS_TDIFF_BOUNDS 是用來指定不同波段的范圍。這些值用于將不同波段數(shù)據(jù)映射到 [0, 1] 范圍內(nèi)。
  2. N_TIMES_BEFORE 是一個常量,用于指定取偽彩色圖像的哪個時間點(diǎn)。在這里,根據(jù) img = false_color[..., N_TIMES_BEFORE] 選擇取第 N_TIMES_BEFORE 個時間點(diǎn)的偽彩色圖像。
  3. r、gb 是分別對應(yīng)于紅、綠、藍(lán)通道的像素值。計算這些通道的方法是通過對不同波段之間的像元值進(jìn)行差異計算,然后將差異值映射到指定的范圍內(nèi)。
  4. 使用 np.clip 函數(shù)將歸一化后的像素值限制在 [0, 1] 范圍內(nèi),然后通過 np.stack 函數(shù)將三個通道的像素值堆疊在一起,構(gòu)成一張偽彩色圖像 false_color。
  5. 最后,根據(jù)選定的時間點(diǎn) N_TIMES_BEFORE,從 false_color 中提取出對應(yīng)時間點(diǎn)的偽彩色圖像 img 并返回。

這樣,get_false_color 方法可以根據(jù)給定的波段數(shù)據(jù)構(gòu)造一張偽彩色圖像,用于在深度學(xué)習(xí)模型中進(jìn)行處理和訓(xùn)練。

def rle_encode(x, fg_val=1):
    """
    Args:
        x:  numpy array of shape (height, width), 1 - mask, 0 - background
    Returns: run length encoding as list
    """
    dots = np.where(
        x.T.flatten() == fg_val)[0]  # .T sets Fortran order down-then-right
    run_lengths = []
    prev = -2
    for b in dots:
        if b > prev + 1:
            run_lengths.extend((b + 1, 0))
        run_lengths[-1] += 1
        prev = b
    return run_lengths

def list_to_string(x):
    """
    Converts list to a string representation
    Empty list returns '-'
    """
    if x: # non-empty list
        s = str(x).replace("[", "").replace("]", "").replace(",", "")
    else:
        s = '-'
    return s

這段代碼定義了兩個輔助函數(shù) rle_encodelist_to_string,用于對圖像分割結(jié)果進(jìn)行 Run Length Encoding (RLE) 編碼和字符串轉(zhuǎn)換的操作。

  1. rle_encode(x, fg_val=1):該函數(shù)用于對圖像進(jìn)行 RLE 編碼。輸入?yún)?shù) x 是一個 NumPy 數(shù)組,表示一個二值化的圖像掩碼(mask),其中 1 表示目標(biāo)區(qū)域(前景),0 表示背景區(qū)域。函數(shù)會將前景區(qū)域的像素位置編碼成一串 RLE 格式的列表,返回的是一個包含像素位置和長度的列表。這個編碼方法常用于圖像分割任務(wù)的結(jié)果提交,以便減少提交文件的大小和計算量。
  2. list_to_string(x):該函數(shù)用于將列表轉(zhuǎn)換為字符串表示。輸入?yún)?shù) x 是一個列表,函數(shù)會將列表轉(zhuǎn)換為一個不包含方括號和逗號的字符串表示。如果列表為空,則返回 '-' 字符串。這個函數(shù)在對 RLE 編碼結(jié)果進(jìn)行字符串表示時很有用,方便保存到提交文件或其他輸出中。

通過使用這兩個輔助函數(shù),可以將圖像分割結(jié)果進(jìn)行編碼和轉(zhuǎn)換為指定格式的字符串表示,方便提交預(yù)測結(jié)果或保存到文件中。這在進(jìn)行圖像分割任務(wù)的評估和結(jié)果輸出時非常有用。

class LightningModule(pl.LightningModule):
    def __init__(self, config):
        super().__init__()
        self.model = smp.Unet(encoder_name=config["encoder_name"],
                              encoder_weights=None,
                              in_channels=3,
                              classes=1,
                              activation=None,
                              )
    def forward(self, batch):
        return self.model(batch)

這是一個 PyTorch Lightning 的子類 LightningModule,它定義了一個簡單的圖像分割模型。

該類包含以下方法:

  1. __init__(self, config):初始化方法,接受一個配置字典 config,并使用該配置創(chuàng)建 Unet 模型。encoder_name 指定了使用的編碼器名稱,encoder_weights 為 None 表示不使用預(yù)訓(xùn)練權(quán)重,in_channels=3 表示輸入圖像的通道數(shù)為 3(RGB 彩色圖像),classes=1 表示輸出的通道數(shù)為 1(二值化的分割掩碼),activation=None 表示不使用激活函數(shù)。
  2. forward(self, batch):前向傳播方法,接受一個批次的圖像 batch,并將其傳遞給 Unet 模型進(jìn)行前向計算,返回模型的輸出。

該類繼承了 PyTorch Lightning 的 pl.LightningModule,因此它具有 Lightning 模型所需的必要功能,如 training_step、validation_stepconfigure_optimizers 等方法。在實際的訓(xùn)練和驗證過程中,可以使用此 Lightning 模型類,以更簡潔的方式定義和管理模型,并進(jìn)行訓(xùn)練和推理。

MODEL_PATH = "/kaggle/working/models/"
#with open(os.path.join(MODEL_PATH, "config.yaml"), "r") as file_obj:
#    config = yaml.safe_load(file_obj)
test_ds = ContrailsDataset(
        test_df,
        config["model"]["image_size"],
        train = False
    )
test_dl = DataLoader(test_ds, batch_size=batch_size, num_workers = num_workers)

這部分代碼用于創(chuàng)建測試集的數(shù)據(jù)加載器(DataLoader),以便在模型推理(預(yù)測)階段使用。

  1. ContrailsDataset 是之前定義的用于加載測試數(shù)據(jù)的自定義數(shù)據(jù)集類,通過傳入測試數(shù)據(jù)的信息 test_df 和其他相關(guān)參數(shù),創(chuàng)建了 test_ds 對象。
  2. test_ds:是通過 ContrailsDataset 類創(chuàng)建的測試數(shù)據(jù)集對象,用于加載測試集的圖像數(shù)據(jù)并進(jìn)行預(yù)處理。
  3. config["model"]["image_size"]:通過訪問配置字典 config 中的 “model” 部分,并獲取 “image_size” 參數(shù)的值,即測試數(shù)據(jù)的圖像尺寸。
  4. train=False:將 train 參數(shù)設(shè)為 False,表示 test_ds 是測試數(shù)據(jù)集,以便在數(shù)據(jù)集類中進(jìn)行相應(yīng)處理。
  5. DataLoader 是 PyTorch 提供的數(shù)據(jù)加載器,用于批量加載數(shù)據(jù)。通過傳入 test_ds 數(shù)據(jù)集對象、batch_sizenum_workers 參數(shù),創(chuàng)建了 test_dl 數(shù)據(jù)加載器。
  6. batch_size=batch_size:指定每個批次中的樣本數(shù)量,這里使用之前設(shè)定的 batch_size 值。
  7. num_workers=num_workers:指定數(shù)據(jù)加載器的工作線程數(shù)量,這里使用之前設(shè)定的 num_workers 值。

通過創(chuàng)建測試數(shù)據(jù)加載器 test_dl,我們可以方便地批量加載測試數(shù)據(jù),然后將數(shù)據(jù)輸入到模型進(jìn)行預(yù)測,最終得到測試集的分割結(jié)果。

gc.enable()
all_preds = {}

for i, model_path in enumerate(glob.glob(MODEL_PATH + '*.ckpt')):
    print(model_path)
    model = LightningModule(config["model"]).load_from_checkpoint(model_path, config=config["model"])
    model.to(device)
    model.eval()
    model_preds = {}
    for _, data in enumerate(test_dl):
        images, image_id = data
        images = images.to(device)
        with torch.no_grad():
            predicted_mask = model(images[:, :, :, :])
        if config["model"]["image_size"] != 256:
            predicted_mask = torch.nn.functional.interpolate(predicted_mask, size=256, mode='bilinear')
        predicted_mask = torch.sigmoid(predicted_mask).cpu().detach().numpy()     
        for img_num in range(0, images.shape[0]):
            current_mask = predicted_mask[img_num, :, :, :]
            current_image_id = image_id[img_num].item()
            model_preds[current_image_id] = current_mask
    all_preds[f"f{i}"] = model_preds
    del model    
    torch.cuda.empty_cache()
    gc.collect() 

這段代碼使用已經(jīng)訓(xùn)練好的多個模型對測試集進(jìn)行預(yù)測,并將預(yù)測結(jié)果保存在 all_preds 字典中。

  1. gc.enable():啟用 Python 的垃圾回收,這有助于及時釋放不再使用的內(nèi)存。
  2. all_preds = {}:創(chuàng)建一個空字典 all_preds,用于存儲所有模型的預(yù)測結(jié)果。
  3. for i, model_path in enumerate(glob.glob(MODEL_PATH + '*.ckpt'))::使用 glob.glob() 函數(shù)獲取所有以 “.ckpt” 結(jié)尾的文件路徑,即訓(xùn)練好的模型的路徑。然后,通過循環(huán)遍歷所有的模型文件。
  4. model = LightningModule(config["model"]).load_from_checkpoint(model_path, config=config["model"]):加載指定路徑 model_path 的訓(xùn)練好的模型,并根據(jù)配置 config["model"] 創(chuàng)建 Lightning 模型。這里使用 .load_from_checkpoint() 方法來加載模型。
  5. model.to(device):將模型移動到指定的計算設(shè)備 device(GPU 或 CPU)上。
  6. model.eval():將模型設(shè)置為評估模式,即關(guān)閉 BatchNormalization 和 Dropout 層,以便在推理階段保持一致的行為。
  7. model_preds = {}:創(chuàng)建一個空字典 model_preds,用于存儲當(dāng)前模型的預(yù)測結(jié)果。
  8. for _, data in enumerate(test_dl)::使用 test_dl 數(shù)據(jù)加載器循環(huán)遍歷測試集的數(shù)據(jù)。
  9. images, image_id = data:從 test_dl 中獲取當(dāng)前批次的圖像數(shù)據(jù) images 和圖像 ID image_id。
  10. images = images.to(device):將圖像數(shù)據(jù)移動到指定的計算設(shè)備上。
  11. with torch.no_grad()::使用 torch.no_grad() 上下文管理器,關(guān)閉梯度計算,加速推理過程。
  12. predicted_mask = model(images[:, :, :, :]):對圖像進(jìn)行預(yù)測,得到模型輸出 predicted_mask。
  13. if config["model"]["image_size"] != 256::根據(jù)配置中的圖像尺寸,對模型輸出進(jìn)行大小調(diào)整。
  14. predicted_mask = torch.sigmoid(predicted_mask).cpu().detach().numpy():將模型輸出進(jìn)行sigmoid激活,并將結(jié)果轉(zhuǎn)換為NumPy數(shù)組。這里得到了每個圖像的預(yù)測掩碼。
  15. for img_num in range(0, images.shape[0])::遍歷當(dāng)前批次中的每張圖像。
  16. current_mask = predicted_mask[img_num, :, :, :]:獲取當(dāng)前圖像的預(yù)測掩碼。
  17. current_image_id = image_id[img_num].item():獲取當(dāng)前圖像的圖像 ID。
  18. model_preds[current_image_id] = current_mask:將當(dāng)前圖像的預(yù)測掩碼加入 model_preds 字典中,以圖像 ID 為鍵,掩碼為值。
  19. all_preds[f"f{i}"] = model_preds:將當(dāng)前模型的預(yù)測結(jié)果加入 all_preds 字典中,以模型編號 f{i} 為鍵,當(dāng)前模型的預(yù)測結(jié)果為值。
  20. del modeltorch.cuda.empty_cache()gc.collect():釋放模型占用的內(nèi)存并進(jìn)行垃圾回收,以便在下一次循環(huán)中使用新的模型。

通過上述循環(huán),代碼對測試集中的所有圖像使用多個訓(xùn)練好的模型進(jìn)行預(yù)測,并將每個模型的預(yù)測結(jié)果保存在 all_preds 字典中。每個模型的預(yù)測結(jié)果都是一個字典,其中每個圖像 ID 對應(yīng)一個預(yù)測掩碼,即每張圖像的分割預(yù)測結(jié)果。

for index in submission.index.tolist():
    for i in range(len(glob.glob(MODEL_PATH + '*.ckpt'))):
        if i == 0:
            predicted_mask = all_preds[f"f{i}"][index]
        else:
            predicted_mask += all_preds[f"f{i}"][index]
    predicted_mask = predicted_mask / len(glob.glob(MODEL_PATH + '*.ckpt'))
    predicted_mask_with_threshold = np.zeros((256, 256))
    predicted_mask_with_threshold[predicted_mask[0, :, :] < THR] = 0
    predicted_mask_with_threshold[predicted_mask[0, :, :] > THR] = 1
    submission.loc[int(index), 'encoded_pixels'] = list_to_string(rle_encode(predicted_mask_with_threshold))

這段代碼使用多個模型的預(yù)測結(jié)果來生成提交文件的 Run Length Encoding (RLE) 編碼。

  1. for index in submission.index.tolist()::對提交文件中的每個圖像 ID 進(jìn)行遍歷。
  2. for i in range(len(glob.glob(MODEL_PATH + '*.ckpt')))::遍歷之前訓(xùn)練好的多個模型的索引 i。
  3. if i == 0::如果是第一個模型的索引,將預(yù)測掩碼初始化為 all_preds[f"f{i}"][index]。
  4. else::對于其他模型的索引,將預(yù)測掩碼累加上 all_preds[f"f{i}"][index],以獲得多個模型的預(yù)測結(jié)果之和。
  5. predicted_mask = predicted_mask / len(glob.glob(MODEL_PATH + '*.ckpt')):將預(yù)測掩碼除以模型的總數(shù),以得到平均預(yù)測結(jié)果。
  6. predicted_mask_with_threshold = np.zeros((256, 256)):創(chuàng)建一個大小為 (256, 256) 的全零數(shù)組,用于存儲閾值化后的預(yù)測結(jié)果。
  7. predicted_mask_with_threshold[predicted_mask[0, :, :] < THR] = 0predicted_mask_with_threshold[predicted_mask[0, :, :] > THR] = 1:根據(jù)閾值 THR,將預(yù)測掩碼中小于閾值的像素設(shè)置為0,大于閾值的像素設(shè)置為1,得到二值化的分割結(jié)果。
  8. submission.loc[int(index), 'encoded_pixels'] = list_to_string(rle_encode(predicted_mask_with_threshold)):使用 RLE 編碼函數(shù)對二值化的分割結(jié)果進(jìn)行編碼,并將編碼后的結(jié)果保存在提交文件的相應(yīng)行中。

通過上述步驟,代碼將使用多個模型的預(yù)測結(jié)果進(jìn)行投票或平均,然后根據(jù)閾值 THR 進(jìn)行二值化處理,并最終將結(jié)果保存在提交文件中,用于在 Kaggle 上提交圖像分割任務(wù)的預(yù)測結(jié)果。文章來源地址http://www.zghlxwxcb.cn/news/detail-630002.html

到了這里,關(guān)于【計算機(jī)視覺 | Kaggle】飛機(jī)凝結(jié)軌跡識別 Baseline 分享和解讀(含源代碼)的文章就介紹完了。如果您還想了解更多內(nèi)容,請在右上角搜索TOY模板網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關(guān)文章,希望大家以后多多支持TOY模板網(wǎng)!

本文來自互聯(lián)網(wǎng)用戶投稿,該文觀點(diǎn)僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務(wù),不擁有所有權(quán),不承擔(dān)相關(guān)法律責(zé)任。如若轉(zhuǎn)載,請注明出處: 如若內(nèi)容造成侵權(quán)/違法違規(guī)/事實不符,請點(diǎn)擊違法舉報進(jìn)行投訴反饋,一經(jīng)查實,立即刪除!

領(lǐng)支付寶紅包贊助服務(wù)器費(fèi)用

相關(guān)文章

  • 基于計算機(jī)視覺的手勢識別技術(shù)

    基于計算機(jī)視覺的手勢識別技術(shù)

    一個不知名大學(xué)生,江湖人稱菜狗 original author: Jacky Li Email : 3435673055@qq.com Time of completion:2023.5.2 Last edited: 2023.5.2 手語是一種主要由聽力困難或耳聾的人使用的交流方式。這種基于手勢的語言可以讓人們輕松地表達(dá)想法和想法,克服聽力問題帶來的障礙。 這種便捷的交流方式

    2024年02月04日
    瀏覽(27)
  • 計算機(jī)視覺 - 理論 - 從卷積到識別

    計算機(jī)視覺 - 理論 - 從卷積到識別

    Vue框架: 從項目學(xué)Vue OJ算法系列: 神機(jī)百煉 - 算法詳解 Linux操作系統(tǒng): 風(fēng)后奇門 - linux C++11: 通天箓 - C++11 Python常用模塊: 通天箓 - python 計算機(jī)視覺系列博客分兩條主線:算法理論 + opencv實操 理論來源于[計算機(jī)視覺(本科) 北京郵電大學(xué) 魯鵬 清晰完整合集](https://www.

    2024年02月11日
    瀏覽(24)
  • 計算機(jī)視覺:從圖像識別到深度學(xué)習(xí)

    計算機(jī)視覺:從圖像識別到深度學(xué)習(xí)

    ?? 個人網(wǎng)站:【工具大全】【游戲大全】【神級源碼資源網(wǎng)】 ?? 前端學(xué)習(xí)課程:??【28個案例趣學(xué)前端】【400個JS面試題】 ?? 尋找學(xué)習(xí)交流、摸魚劃水的小伙伴,請點(diǎn)擊【摸魚學(xué)習(xí)交流群】 計算機(jī)視覺是人工智能領(lǐng)域中的一個重要分支,它致力于讓計算機(jī)能夠理解和處理

    2024年02月07日
    瀏覽(34)
  • 圖像識別與計算機(jī)視覺有什么區(qū)別?

    圖像識別與計算機(jī)視覺有什么區(qū)別?

    圖像識別和計算機(jī)視覺在很多方面存在差異,這些差異主要體現(xiàn)在以下幾個方面: 1. 研究范圍 圖像識別是計算機(jī)視覺領(lǐng)域的一個子集。計算機(jī)視覺不僅包括圖像識別,還涵蓋了更廣泛的內(nèi)容,如場景理解、目標(biāo)跟蹤、分割、識別和解釋等。簡而言之,計算機(jī)視覺是一種更廣

    2024年01月16日
    瀏覽(27)
  • 基于計算機(jī)視覺的學(xué)生上課姿態(tài)識別

    基于計算機(jī)視覺的學(xué)生上課姿態(tài)識別

    數(shù)據(jù)集 1.1? A VA 數(shù)據(jù)集介紹 AVA數(shù)據(jù)集為目前行為數(shù)據(jù)集中背景最復(fù)雜、人體目標(biāo)最多的數(shù)據(jù)集,是由Google在2018年所發(fā)表的一個用于訓(xùn)練動作檢測的數(shù)據(jù)集,該數(shù)據(jù)集注釋430個15分鐘電影切片中的80個原子視覺動作,在空間和時間上定位了動作,從而產(chǎn)生了1.62萬個動作標(biāo)簽。這

    2024年02月02日
    瀏覽(26)
  • 計算機(jī)視覺:使用opencv實現(xiàn)車牌識別

    計算機(jī)視覺:使用opencv實現(xiàn)車牌識別

    汽車車牌識別(License Plate Recognition)是一個日常生活中的普遍應(yīng)用,特別是在智能交通系統(tǒng)中,汽車牌照識別發(fā)揮了巨大的作用。汽車牌照的自動識別技術(shù)是把處理圖像的方法與計算機(jī)的軟件技術(shù)相連接在一起,以準(zhǔn)確識別出車牌牌照的字符為目的,將識別出的數(shù)據(jù)傳送至交

    2024年02月04日
    瀏覽(26)
  • 計算機(jī)視覺項目實戰(zhàn)-目標(biāo)檢測與識別

    計算機(jī)視覺項目實戰(zhàn)-目標(biāo)檢測與識別

    ?????? 歡迎來到本博客 ?????? 本次博客內(nèi)容將繼續(xù)講解關(guān)于OpenCV的相關(guān)知識 ?? 作者簡介 : ?????? 目前計算機(jī)研究生在讀。主要研究方向是人工智能和群智能算法方向。目前熟悉深度學(xué)習(xí)(keras、pytorch、yolov5),python網(wǎng)頁爬蟲、機(jī)器學(xué)習(xí)、計算機(jī)視覺(OpenCV)

    2024年02月02日
    瀏覽(24)
  • Python的計算機(jī)視覺與物體識別

    計算機(jī)視覺是一種通過計算機(jī)程序?qū)D像進(jìn)行處理和分析的技術(shù)。物體識別是計算機(jī)視覺中的一個重要分支,旨在識別圖像中的物體、特征和屬性。Python是一種流行的編程語言,擁有強(qiáng)大的計算機(jī)視覺庫和框架,如OpenCV、TensorFlow和PyTorch。因此,使用Python進(jìn)行計算機(jī)視覺和物

    2024年02月21日
    瀏覽(24)
  • 計算機(jī)視覺:場景識別(Scene Recognition)

    計算機(jī)視覺:場景識別(Scene Recognition)

    完整程序請移步至此鏈接下載 在這個項目中,我將對15個場景數(shù)據(jù)庫(Bedroom、Coast、Forest、Highway、Industrial、InsideCity、Kitchen、LivingRoom、Mountain、Office、OpenCountry、Store、Street、Suburb、TallBuilding)進(jìn)行訓(xùn)練和測試,借助HOG特征提取構(gòu)建詞袋模型,并利用集成學(xué)習(xí)分類器將場景分

    2024年02月07日
    瀏覽(31)
  • 計算機(jī)視覺之姿態(tài)識別(原理+代碼實操)

    計算機(jī)視覺之姿態(tài)識別(原理+代碼實操)

    ?人體分割使用的方法可以大體分為人體骨骼關(guān)鍵點(diǎn)檢測、語義分割等方式實現(xiàn)。這里主要分析與姿態(tài)相關(guān)的人體骨骼關(guān)鍵點(diǎn)檢測。人體骨骼關(guān)鍵點(diǎn)檢測輸出是人體的骨架信息,一般主要作為人體姿態(tài)識別的基礎(chǔ)部分,主要用于分割、對齊等。一般實現(xiàn)流程為: ?主要檢測人

    2023年04月16日
    瀏覽(22)

覺得文章有用就打賞一下文章作者

支付寶掃一掃打賞

博客贊助

微信掃一掃打賞

請作者喝杯咖啡吧~博客贊助

支付寶掃一掃領(lǐng)取紅包,優(yōu)惠每天領(lǐng)

二維碼1

領(lǐng)取紅包

二維碼2

領(lǐng)紅包