【深度学习】使用Python+PyTorch预测野外火灾

作者 | Aishwarya Srinivasan 

编译 | VK 

来源 | Towards Data Science

联合国在实现其可持续发展目标方面面临的主要障碍之一是与自然灾害作斗争,而造成巨大破坏的首要障碍是野外火灾。

作为一名数据科学家,我真的希望为社会带来积极的变化。在读到最近在美国科罗拉多州和澳大利亚各地发生的野外火灾之后,我开始想知道是否有一种方法可以利用我的技能提前预测这些灾难,以便采取一些保护措施。

我在Kaggle上找到了这个数据集,它包含了美国188万场野外火灾,我开始使用PyTorch Lightning建立一个模型。继续阅读,看看我是如何使用这个数据集建立一个可以预测野外火灾强度的模型的。

气候变化与野外火灾

联合国可持续发展目标的重点是到2030年实现具体目标,其中涉及教育、贫困、气候变化和海洋生物等问题。联合国环境规划署负责协调联合国的环境活动,并协助发展中国家制定有利于环境的政策和做法。

我们有10年时间来实现联合国可持续发展倡议取得成功的目标和指标。

一个繁荣的环境直接影响到联合国制定的17个可持续发展目标,因此保护和保护环境免受自然和人为灾害是联合国的主要议程之一。根据联合国的各种报告,野外火灾确实影响了气候变化。随着全球气温的升高,野外火灾发生的可能性越来越大,它们对气候变化产生了重大影响。

2019年,澳大利亚遭遇了历史上最严重的火灾之一,由于极端高温季节,烧毁了约1800万公顷的土地(相比之下,相当于加州一半的土地)。日益升高的温度在森林和草原上造成了高度易燃的环境。同样,亚马逊森林在2019年也发生火灾,导致2240000英亩的烧毁面积。最近,在2020年,加州的野外火灾烧毁了4359517英亩的土地。

野外火灾产生大量的二氧化碳和温室气体,这反过来又提高了全球温度。火灾的微粒被远距离携带,造成空气污染。这些粒子也会沉积在雪上,导致对阳光的更高吸收。这种现象被称为气候反馈回路,它会逐渐恶化气候条件

用PyTorch Lightning预报野外火灾

不同行业的坚定分子做出了多种努力,利用历史野外火灾数据,并考察它们与天气、旅游等替代数据源的依赖性,建立预测火灾发生和强度的模型。在这个文章中,我使用PyTorch Lightning构建了一个机器学习模型。火灾强度的预测可以通过事先采取正确的补救措施来对抗火灾的影响。[3]

步骤1:连接到数据

从Kaggle下载数据后,我将其摄取到我的python环境中,并将其连接到jupyter笔记本界面。

conn = sqlite3.connect("FPA_FOD_20170508.sqlite")

在阅读了数据之后,我需要执行一些探索性的分析,以了解数据的特征及其分布,如下所示。

步骤2:一些探索性的数据分析

了解野外火灾在美国不同州的蔓延情况。在这里我们可以看到全美五大野外火灾规模。

df = pd.read_sql_query("SELECT SUM(FIRE_SIZE) AS SUM_FIRE_SIZE, State FROM Fires GROUP BY State;", conn)
df = df.set_index("STATE")
df[:5]

可视化野外火灾统计数据。它也有助于可视化数据,了解每个州的野外火灾数量。我们可以用图形化的方式绘制数据,看看受影响最大的州。

不同州的野外火灾规模
df["SUM_FIRE_SIZE"].sort_values(ascending=False)[:15].plot(kind="bar")

我们从中得知,AK的人数比其他受到严重影响的州高出一倍多。

我们可以试着分析过去几年野外火灾的数量是如何变化的。

不同年份的野外火灾规模
df = pd.read_sql_query("SELECT SUM(FIRE_SIZE) AS SUM_FIRE_SIZE, FIRE_YEAR FROM Fires GROUP BY FIRE_YEAR;", conn)
df.set_index("FIRE_YEAR").plot.bar()

我们看到在过去十年里,野外火灾的强度显著增加。

在了解了数据所包含的内容之后,我们对火大小的异常值进行简单的过滤。可以对异常值进行处理或缩放以对所有数据进行建模。为了简单起见,我们只研究发生最多的野外火灾类别。

步骤3:数据处理和训练测试分割

根据火力大小对数据集进行划分。

我们只考虑野外火灾规模在2000到10000个单位之间的情况。

analyze_df = analyze_df[analyze_df.FIRE_SIZE > 2000]
analyze_df = analyze_df[analyze_df.FIRE_SIZE < 10000]
将数据集拆分。

首先,我们对数值和离散类变量进行数据转换。对数值特征进行数据缩放,同时对离散特征进行标签编码。然后,合并两个特征子集。

X = analyze_df.drop(columns=["FIRE_SIZE"])
y = analyze_df["FIRE_SIZE"]

X_numerical = X.select_dtypes(include=["float", "int"])
fill_nan = lambda col: col.fillna(col.mean())
X_numerical = X_numerical.apply(fill_nan)
sc = StandardScaler()
num_cols = X_numerical.columns
X_numerical = pd.DataFrame(sc.fit_transform(X_numerical), columns=num_cols)
for col in X_categorical.columns:
    le = LabelEncoder()
    X_categorical[col] = le.fit_transform(X_categorical[col])

X_numerical.reset_index(drop=True, inplace=True)
X_categorical.reset_index(drop=True, inplace=True)

X = pd.concat([X_numerical, X_categorical], axis=1)
训练测试集分割

现在我们将数据分成80%的train+val和20%的测试集。然后我们进一步将train+val分成80%的训练和20%的验证数据集。

X_train_val, X_test, y_train_val, y_test = train_test_split(X, y, test_size=0.2, random_state=42)
X_train, X_val, y_train, y_val = train_test_split(X_train_val, y_train_val, test_size=0.2, random_state=42)
步骤4:使用PyTorch Lightning构建模型(这里只显示了一个片段,请按照下面的链接获取完整代码)

在本节中,我们开始使用PyTorch Lightning构建一个简单的回归神经网络模型。[2]

我从一个有17个输入特征的简单体系结构开始,第一个隐藏层有64个神经元,第二个隐藏层有32个神经元,最后一个是回归节点。PyTorch Lightning代码分为不同的部分:模型、数据加载器、优化器和训练验证测试步骤。

class Regression(pl.LightningModule):
    
### 模型 ### 

    
    def __init__(self):
        super(Regression, self).__init__()
        self.fc1 = nn.Linear(17, 64)
        self.fc2 = nn.Linear(64, 32)
        self.fc3 = nn.Linear(32, 8)
        self.fc4= nn.Linear(8, 1)
        self.dropout=torch.nn.Dropout(0.2)
        self.training_losses = []

    
    def forward(self, x):
        x = torch.sigmoid(self.fc1(x))
        x = self.dropout(x)
        x = torch.sigmoid(self.fc2(x))
        x = self.dropout(x)
        x = torch.sigmoid(self.fc3(x))
        x = self.dropout(x)
        x = self.fc4(x)
        return x
    ### 训练 ### 

    # 问:训练步骤应该是什么样的
    # 定义训练步骤
    def training_step(self, batch, batch_idx):
        x, y = batch
        logits = self.forward(x)
        train_loss = mse_loss(logits, y)
        self.training_losses.append(train_loss)
        # 添加
        return {'loss': train_loss}

### 验证 ### 
    
    # 问:验证步骤应该是什么样的
    # 定义验证步骤
    def validation_step(self, batch, batch_idx):
        x, y = batch
        logits = self.forward(x)
        loss = mse_loss(logits, y)
        return {'val_loss': loss}

    # 定义validation_epoch_end
    def validation_epoch_end(self, outputs):
        avg_loss = torch.stack([x['val_loss'] for x in outputs]).mean()
        return {'avg_val_loss': avg_loss}

### 测试 ###     

    # 问:测试步骤应该是什么样的
    # 定义测试步骤
    def test_step(self, batch, batch_idx):
        x, y = batch
        logits = self.forward(x)
        loss = mse_loss(logits, y)
        predictions_pred.append(logits)
        predictions_actual.append(y)
        return {'test_loss': loss, 'logits': logits}
    
    # 定义test_epoch_end
    def test_epoch_end(self, outputs):
        avg_loss = torch.stack([x['test_loss'] for x in outputs]).mean()
        logs = {'test_loss': avg_loss}      
        return {'avg_test_loss': avg_loss, 'log': logs, 'progress_bar': logs }
    
    ### The 优化器 ### 

    # 问:我将使用什么优化器?
    # 定义优化器函数:这里我们使用随机梯度下降
    def configure_optimizers(self):
        return optim.SGD(self.parameters(), lr=l_rate)

如果你有不同形状的数据,或者你希望创建一个不同的模型体系结构,你只需在上面的函数中更改模型参数。你可以在上面的configure_optimizers函数中更改模型中使用的优化器。

### 数据加载器 ###     
class WildfireDataLoader(pl.LightningDataModule):   
    # 问题:你希望如何将数据加载到模型中?
    # 为数据加载定义函数:训练/验证/测试
    def train_dataloader(self):
        train_dataset = TensorDataset(torch.tensor(X_train.values).float(), torch.tensor(y_train.values).float())
        train_loader = DataLoader(dataset = train_dataset, batch_size = 512)
        return train_loader
        
    def val_dataloader(self):
        validation_dataset = TensorDataset(torch.tensor(X_val.values).float(), torch.tensor(y_val.values).float())
        validation_loader = DataLoader(dataset = validation_dataset, batch_size = 512)
        return validation_loader
    
    def test_dataloader(self):
        test_dataset = TensorDataset(torch.tensor(X_test.values).float(), torch.tensor(y_test.values).float())
        test_loader = DataLoader(dataset = test_dataset, batch_size = 512)
        return test_loader
步骤5:运行模型

在这里,我们使用数据加载模块运行Lightning模型,并根据数据拟合。

data_loader_module = WildfireDataLoader()
model = Regression()
trainer = Trainer(max_epochs = 200,data_loader_module )  
trainer.fit(model, datamodule= data_loader_module)
步骤6:模型的最终结果

我们发现,模型的均方误差损失为0.2048,与Logistic回归(blog中未包含的代码)相比,这稍微好一些。

火灾数据似乎有很大的偏差,大部分数据点的火灾规模小于10个单位,其他数据点高达5万个单位以上。数据的这种偏斜使得回归问题很难解决。此外,数据集包含非常有限的变量。通过合并更多的特征变量和其他数据源(如天气数据),可以提高模型的性能。

其目的是演示使用Lightning框架构建高级机器学习模型的方法,因此并不代表最佳模型性能,而是提出一种采用数据驱动方法预测野外火灾的方法。

参考文献:

[1]https://towardsdatascience.com/predicting-california-wildfire-size-with-neural-networks-building-a-machine-learning-project-from-db0e57dce4c9

[2]https://github.com/shotleft/how-to-python/blob/master/How%20it%20works%20-%20Bike%20Share%20Regression%20PyTorch%20Lightning.ipynb

[3]https://www.techrepublic.com/article/fighting-fire-with-ai-using-deep-learning-to-help-predict-wildfires-in-the-us/


往期精彩回顾



适合初学者入门人工智能的路线及资料下载机器学习及深度学习笔记等资料打印机器学习在线手册深度学习笔记专辑《统计学习方法》的代码复现专辑
AI基础下载机器学习的数学基础专辑
获取本站知识星球优惠券,复制链接直接打开:
https://t.zsxq.com/qFiUFMV
本站qq群704220115。

加入微信群请扫码:

  • 2
    点赞
  • 44
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值