65.9K
CodeProject 正在变化。 阅读更多。
Home

使用 PyTorch 预测森林火灾

starIconstarIconstarIconstarIconstarIcon

5.00/5 (3投票s)

2023 年 12 月 18 日

CPOL

5分钟阅读

viewsIcon

6557

在 CPU 上使用迁移学习构建准确的图像分类器是一种有效的方法。

在本文中,我使用 PyTorch* 进行迁移学习,仅通过图像细节来根据火灾风险对航空照片进行分类。 MODIS 火灾数据集记录了 2018 年至 2020 年加利福尼亚州的已知火灾。MODIS(中分辨率成像光谱仪)数据集包含高分辨率图像和已标记的地图区域,涵盖特定日期范围,用于了解过去的山火地点。然后,我从 2016 年至 2017 年的两年期间,在已知未来火灾区域内部和附近的区域采样图像。迁移学习用于调整一个预训练的 ResNet 18 模型(该模型之前没有在航空照片上进行过训练),并补充了几百张标记为“火灾”和“无火灾”的图像。

对一个预训练模型(最初在 ImageNet 数据集上训练)进行微调,用于航空照片,是有效地从这些图像中提取有意义信息的、用于森林火灾预测的方法。ResNet 架构通过其深度层和跳跃连接,在各种计算机视觉任务中被证明是有效的,包括物体识别和图像分类。通过这种方法,我只需要几百张图像和大约 15 分钟的 CPU 时间即可构建一个准确的模型。请继续阅读以了解更多详细信息!

航空图像案例研究

我的方法是创建一个二元分类器,仅专注于通过 2016 年至 2021 年期间加利福尼亚州已知火灾和非火灾区域的航空图像进行预测。训练集是 2016 年至 2017 年的航空照片——在关键区域发生火灾之前。评估集是同一地点从 2018 年至 2020 年拍摄的图像(以及一个包含 2021 年图像的扩展集)。燃烧区域和非燃烧区域都进行了采样。森林火灾的可能性基于通过 MODIS 数据集获取的已知森林火灾区域。选定的区域位于萨克拉门托地区,从海岸到内华达山脉。该地区过去曾经历过许多大型致命火灾。

数据采集

数据采集和预处理遵循以下基本步骤。首先,我使用 Google Earth Engine* 和一个 JavaScript* 程序来收集 MODIS 火灾数据和航空照片。项目脚本可在 ForestFirePrediction 存储库中找到。接下来,我从美国农业部 USDA/NAIP/DOQQ 数据集生成了一张地图。最后,我从 NASA MODIS/006/MCD64A1 数据集中提取了航空照片。

2018 年至 2020 年 MODIS 定义的火灾和无火灾位置分别显示在**图 1 和图 2** 中。红色区域是燃烧区。橙色和青色图钉表示图像使用的采样位置,其中青色标记采样到的无火灾点,橙色标记采样到的火灾位置点。每张图像覆盖约 60 平方英里。

图 1. 使用 Google Earth Engine* 和 MODIS/006/MCD64A1 数据集采样的已知火灾位置

图 2. 使用 Google Earth Engine* 和 MODIS/006/MCD64A1 数据集采样的无火灾位置

NAIP/DOQQ 数据集用于采样航空照片。例如,**图 3** 显示了 2018 年影响该镇的大型火灾发生前,加利福尼亚州天堂镇附近的一张航空照片。

图 3. 来自 USDA/NAIP/DOQQ 数据集的加利福尼亚州天堂镇 2018 年火灾前航空照片样本

我有 106 张火灾区域的样本图像和 111 张无火灾区域的样本图像(**表 1**)。由于我使用的是迁移学习,我的数据集可以比从头开始训练模型的数据集小得多。训练、验证和测试图像的细分如下

 

训练

验证

测试

火灾

87

9

10

无火灾

90

10

11

代码

模型基于 ResNet-18。我创建了四个主要代码部分:实用函数、训练器类、模型类和指标类。此外,我还添加了代码来显示最终的混淆矩阵和模型准确率。

导入

import intel_extension_for_pytorch as ipex
import torch
import torch.nn as nn
import torchvision.models as models
from torch.utils.data import DataLoader
from torchvision import datasets, models, transforms 

为训练和验证创建数据集

下面,我们定义训练和验证图像的位置,并计算每个集中每张图像的图像增强。

num_physical_cores = psutil.cpu_count(logical=False)
data_dir = pathlib.Path("./data/output/")
TRAIN_DIR = data_dir / "train"
VALID_DIR = data_dir / "val"
… 

为训练和验证集定义数据集变换

下面,我们定义将在每张图像上执行的增强系列。

…
img_transforms = {
    "train": transforms.Compose(
        [
            transforms.RandomHorizontalFlip(),
            transforms.RandomVerticalFlip(),
            transforms.RandomRotation(45),
            transforms.ToTensor(),
            transforms.Normalize(*imagenet_stats),
    ),
…
}
… 

定义模型类

我们的模型是一个基于 ResNet18 的深度神经网络二元分类器。

class FireFinder(nn.Module):
…
    def __init__(self, backbone=18, simple=True, dropout= .4):
        super(FireFinder, self).__init__()
        backbones = {
            18: models.resnet18,
        }
            fc = nn.Sequential(
                nn.Linear(self.network.fc.in_features, 256),
                nn.ReLU(),
                nn.Dropout(dropout),
                nn.Linear(256, 2) 

定义训练器类

此处使用了 Intel® Extension for PyTorch*。它是 Intel® AI Analytics Toolkit 的一部分。

class Trainer:
…
        self.loss_fn = torch.nn.CrossEntropyLoss()
        self.ipx = ipx
        self.epochs = epochs
        if isinstance(optimizer, torch.optim.Adam):
            self.lr = 2e-3
        self.optimizer = optimizer(self.model.parameters(), lr=lr)

    def train(self):
        self.model.train()
        t_epoch_loss, t_epoch_acc = 0.0, 0.0
        start = time.time()
        for inputs, labels in tqdm(train_dataloader, desc="tr loop"):
            inputs, labels = inputs.to(self.device), labels.to(self.device)
            if self.ipx:
                inputs = inputs.to(memory_format=torch.channels_last)
            self.optimizer.zero_grad()
            loss, acc = self.forward_pass(inputs, labels)
            loss.backward()
            self.optimizer.step()
            t_epoch_loss += loss.item()
            t_epoch_acc += acc.item()
        return (t_epoch_loss, t_epoch_acc)
…
    def _to_ipx(self):
        self.model.train()
        self.model = self.model.to(memory_format=torch.channels_last)
        self.model, self.optimizer = ipex.optimize(
            self.model, optimizer=self.optimizer, dtype=torch.float32
        ) 

训练模型

模型训练 20 个 epoch,dropout 值为 0.33,学习率为 0.02

epochs = 20
ipx = True
dropout = .33
lr = .02

torch.set_num_threads(num_physical_cores)
os.environ["KMP_AFFINITY"] = "granularity=fine,compact,1,0"

start = time.time()
model = FireFinder(simple=simple, dropout= dropout)

trainer = Trainer(model, lr = lr, epochs=epochs, ipx=ipx)
tft = trainer.fine_tune(train_dataloader, valid_dataloader)

模型推理

我定义了用于对模型进行推理的类和函数。

class ImageFolderWithPaths(datasets.ImageFolder):
…
def infer(model, data_path: str):
    transform = transforms.Compose(
        [transforms.ToTensor(), transforms.Normalize(*imagenet_stats)]
    )

    data = ImageFolderWithPaths(data_path, transform=transform)

    dataloader = DataLoader(data, batch_size=4)
… 

以下示例代码演示了如何使用模型对图像进行评分。

images, yhats, img_paths = infer(model, data_path="./data//test/") 

模型准确率

下面的混淆矩阵显示,该模型在 21 个样本中有两个假阴性,整体准确率为 89.9%。

图 4 显示了所有样本(训练、验证和测试)的模型预测。空间覆盖显示模型在预测表明火灾与无火灾风险的面积方面做得非常好。绿色图钉是模型预测无火灾的位置,而红色图钉预测了我们预期会发生火灾的样本。红色多边形区域是 2018 年至 2020 年的真实火灾区域。

图 4. 所有样本的推理结果

图 5 放大显示了加利福尼亚州天堂镇附近的地图像。

图 5. 加利福尼亚州天堂镇附近模型结果的近距离检查

结论

我使用了 PyTorch 提供的图像分析功能和底层的 Intel 优化来训练和测试 ResNet18 模型,以演示准确的森林火灾预测。模型可以输入覆盖 60 平方英里的航空照片,以做出准确的火灾和无火灾预测。目前模型准确率约为 89%,但可能通过更多的迭代、更大的图像集以及更侧重于正则化来改进。

通过点击邀请链接加入我们的 Intel® DevHub Discord 进行进一步讨论。还可以查看新的 Intel® Developer Cloud,在最新的 Intel® 硬件上试用 Intel AI Analytics Toolkit。

使用 PyTorch 预测森林火灾 - CodeProject - 代码之家
© . All rights reserved.