基于CNN和LSTM的气象图降水预测示例

news2024/11/17 2:38:57

我们是否可以通过气象图来预测降水量呢?今天我们来使用CNN和LSTM进行一个有趣的实验。

我们这里使用荷兰皇家气象研究所(也称为KNMI)提供的开放数据集和公共api,来获取数据集并且构建模型预测当地的降水量。

数据收集

KNMI提供的数据集,我们假设气象雷达产生的信号在反射时会被降水(雨、雪、冰雹等)反射。由雷达捕获的反射信号的强度称为反射率(以 dBZ 计算),我们可以粗略认为它与该点的降水强度成正比。当通过根据信号强度映射色标将此反射率数据转换为图像时(默认情况下,KNMI 提供的色标为“viridis”,紫色/深蓝色表示较低值,黄色表示较高值)产生 图像就像下图显示的那样。我们每 5 分钟通过 API 以原始格式获取这些数据。但是API 有一个配额,每小时只能获取 100 张图像。

定义问题

最原始的也是最简单的预测视频中的下一帧的内容的方法是使用CNN和LSTM。我们是否可以将预测天气雷达的下一个捕获信号的问题简化为预测视频中的下一帧的问题呢(雷达的讯号也是图像序列)。所以我收集了一些图像序列,并开始实验各种架构的卷积LSTM神经网络。每个训练数据点由36个连续的雷达原始文件(对应于间隔5分钟的3小时的测量)组成。然后将每个数据点分成两部分。前18帧用作“特征”(x),后18帧是神经网络在给定前18帧的情况下试图预测的内容(y)。在天气预报方面,给定过去1.5小时的降水数据,未来1.5小时的降水情况(帧间隔为5分钟,因此18帧对应1.5小时)。

为什么是卷积LSTM

如果你对神经网络和深度学习有点熟悉,你可能知道卷积神经网络(CNN)在涉及分析或发现图像中的特定特征和形状的任务上表现非常好。而长短期记忆(LSTM)神经网络在涉及时间维度(如时间序列预测)和数据序列(如图像序列、特定时间范围内的信号序列等)的任务上表现非常好。这主要是因为它们有能力学习数据中的长期依赖关系。因此,研究人员在2015年首次提出了一种结合卷积和LSTM层的架构,这样可以预测一系列图像中的下一个图像(他们对其进行基准测试的应用之一是降水预测),所以本文中也是用类似的模型。

数据预处理

我们使用了近160个连续的36次雷达扫描序列,我们使用h5py 库可以读取并轻松处理原始数据(如从 KNMI 接收的数据是这个格式)并对它们进行预处理。数据点是从 01-01-2019 到现在的随机日期和时间中挑选的。由于生成的图像的原始尺寸太大,所以将的图像从原始尺寸(700x765)缩小到(315x344)。这是模型可以在合理的时间内训练的最高分辨率,并且在过程中不会有任何的内存溢出问题。然后将每个序列分成两个相等的部分。前18帧用作“特征”(x),后18帧是神经网络试图预测的帧(y)(给定前18帧)。最后,我将数据集分成两个单独的数据集,分别用于训练(80%)和验证(20%)。

执行上述所有任务的代码如下面的代码片段所示:

 def create_dataset_from_raw(directory_path, resize_to):
     resize_width = resize_to[0]
     resize_height = resize_to[1]
     batch_names = [directory_path + name for name in os.listdir(directory_path) if os.path.isdir(os.path.join(directory_path, name))]
     dataset = np.zeros(shape=(len(batch_names),36,resize_height,resize_width)) # (samples, filters, rows = height, cols = width)
 
     for batch_idx,batch in enumerate(batch_names):
         files = [x for x in os.listdir(batch) if x != '.DS_Store']
         files.sort()
         crn_batch = np.zeros(shape=(36, resize_height, resize_width)) 
         for (idx,raster) in enumerate(files):
             fn = batch + '/' + raster
             img = h5py.File(fn)
             original_image = np.array(img["image1"]["image_data"]).astype(float)
             img = Image.fromarray(original_image)
             # note that here it is (width, heigh) while in the tensor is in (rows = height, cols = width)
             img = img.resize(size=(resize_width, resize_height)) 
             original_image = np.array(img)
             original_image = original_image / 255.0
             crn_batch[idx] = original_image
         dataset[batch_idx] = crn_batch
         print("Importing batch:" + str(batch_idx+1))
     return dataset
 
 def split_data_xy(data):
     x = data[:, 0 : 18, :, :]
     y = data[:, 18 : 36, :, :]
     return x, y
 
 dataset = create_dataset_from_raw('./data/raw/', resize_to=(315,344))
 dataset = np.expand_dims(dataset, axis=-1)
 dataset_x, dataset_y = split_data_xy(dataset)
 X_train, X_val, y_train, y_val = sk.train_test_split(dataset_x,dataset_y,test_size=0.2, random_state = 42)

模型

我使用Tensorflow和Keras框架进行开发。模型基本上是一个自编码器。自编码器是一种神经网络,它试图降低训练数据的维度,对数据进行压缩,然后可以从压缩后潜在空间的分布的近似值中采样,以生成“新”数据。

我们的模型看起来像这样:

模型共包含9层(输入、输出和7个隐藏层)。隐藏层在ConvLSTM2D层和BatchNormalization层之间交换。ConvLSTM2D层就像简单的LSTM层,但是它们的输入和循环转换卷积。ConvLSTM2D层在保留输入维度的同时,随着时间的推移执行卷积运算。你可以把它想象成一个简单的卷积层,它的输出被压平,然后作为输入传递到一个简单的LSTM层。ConvLSTM2D层接收形式为(samples, time, channels, rows, cols)的张量作为输入,输出形式(samples, timesteps, filters, new_rows, new_cols)。所以它们在一段时间内对一系列帧进行运算。

ConvLSTM2D层之间的BatchNormalization层进行归一化操作

对于所有的层(除了输出层),都使用LeakyRelu激活函数,他比ReLu好一些,并且和ReLu一样快。

该模型采用二元交叉熵损失函数和Adadelta梯度下降优化器进行拟合。由于数据的高维数,Adadelta会比经典Adam优化器有更好的结果。模型训练了25个epoch(之后开始过拟合)。

模型的代码如下所示:

 def create_model():
     model = Sequential()
     model.add(ConvLSTM2D(filters=64, kernel_size=(7, 7),
                     input_shape=(18,344,315,1),
                     padding='same',activation=LeakyReLU(alpha=0.01), return_sequences=True))
     model.add(BatchNormalization())
     model.add(ConvLSTM2D(filters=64, kernel_size=(5, 5),
                     padding='same',activation=LeakyReLU(alpha=0.01), return_sequences=True))
     model.add(BatchNormalization())
     model.add(ConvLSTM2D(filters=64, kernel_size=(3, 3),
                     padding='same',activation=LeakyReLU(alpha=0.01), return_sequences=True))
     model.add(BatchNormalization())
     model.add(ConvLSTM2D(filters=64, kernel_size=(1, 1),
                     padding='same',activation=LeakyReLU(alpha=0.01), return_sequences=True))
     model.add(Conv3D(filters=1, kernel_size=(3, 3, 3),
                 activation='sigmoid',
                 padding='same', data_format='channels_last'))
     return model
 
 model = create_model()
 
 model.compile(loss='binary_crossentropy', optimizer='adadelta')
 keras.utils.plot_model(model, to_file="model.png", show_dtype=True, show_layer_activations=True, show_shapes=True)
 print(model.summary())
 
 epochs = 25
 batch_size = 1
 
 #Fit the model
 model.fit(
     X_train,
     y_train,
     batch_size=batch_size,
     epochs=epochs,
     validation_data=(X_val, y_val),
     verbose=1,
 )

结果

在训练模型之后,使用来自验证数据集的示例数据进行测试。模型的输入是18个连续的帧(对应于雷达捕捉到的近1.5小时的信号),它返回下一个18个预测帧(对应于接下来的1.5小时)。

 # pick a random index from validation dataset
 random_index = np.random.choice(range(len(X_val)), size=1)
 test_serie_X = X_val[random_index[0]]
 test_serie_Y = y_val[random_index[0]]
 
 first_frames = test_serie_X
 original_frames = test_serie_Y
 # predict the next 18 fames
 new_prediction = model.predict(np.expand_dims(first_frames, axis=0))
 new_prediction = np.squeeze(new_prediction, axis=0)
 
 fig, axes = plt.subplots(2, 18, figsize=(20, 4))
 
 # Plot the ground truth frames.
 for idx, ax in enumerate(axes[0]):
     ax.imshow(np.squeeze(original_frames[idx]), cmap="viridis")
     ax.set_title(f"Frame {idx + 18}")
     ax.axis("off")
 
 # Plot the predicted frames.
 for idx, ax in enumerate(axes[1]):
     ax.imshow((new_prediction[idx]).reshape((344,315)), cmap="viridis")
     ax.set_title(f"Frame {idx + 18}")
     ax.axis("off")
 
 plt.show()

将预测的帧与实际情况进行比较,结果如下图所示。

真实帧与预测帧非常接近。这种可视化并没有清楚地呈现降水系统移动的时间维度和方向,因此下面的两个GIF动画可以更好地解释模型的输出。

下面是真值的GIF

下面是预测GIF

两个动画也非常接近,模型正确地捕捉到了降水系统的移动方向和强度(黄色更强烈,紫色/深蓝色强度较低)。

总结

ConvLSTM将深度学习的两个核心概念结合起来,并获得了很好的效果。本文的完整项目的代码在这里:

https://avoid.overfit.cn/post/da7a8bd23ec14fc6870e1e4b54e85283

作者:Petros Demetrakopoulos

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/107777.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

excel函数公式大全,最常用的6个公式

Excel中的函数引用一些预定义的公式,可以通过输入参数值来计算函数的对应函数,并且函数名称基本上与函数相对应,这很容易记住。在日常工作中,功能可用于数据统计、计算、处理和分析。本文主要介绍EXCEL中一些常用公式,…

视唱练耳训练小程序开发,摆脱传统训练制约性

视唱练耳作为一门综合性的音乐基础理论学科,对于声乐、器乐、舞蹈等音乐学科中的各个方面都起着十分重要的作用,尤其是突出表现在基本理论、基本技能和音乐审美上,对培养和发展学生的乐感、唱奏技巧以及音乐思维等都有着非常重要的意义。世界…

Databend 开源周报 #71

Databend 是一款强大的云数仓。专为弹性和高效设计,自由且开源。 即刻体验云服务:https://app.databend.com。 What’s New 探索 Databend 本周新进展,遇到更贴近你心意的 Databend 。 Features & Improvements Planner 优化集群模…

简单易用的监控告警系统 | HertzBeat 在 Rainbond 上的使用分享

在现有的监控告警体系中 Prometheus AlertManger Grafana 一直是主流,但对于中小团队或个人来说,这种体系显的较为复杂。而 HertzBeat 能让中小团队或个人很快速的搭建监控告警系统,并通过简单的配置实现应用、数据库、操作系统的监控与告警…

k8s HPA升级 KEDA 基于事件驱动的自动伸缩

说明:KEDA有啥用,相对HPA有啥优势。HPA针对于cpu,内存来进行弹性伸缩,有点不太精确。KEDA可以接入prometheus,根据prometheus的数据指标进行弹性伸缩,相比更加的精准实用。 安装k8s环境部署prometheus 创建ns&#xf…

HashMap最全面试题

文章目录一、 存储结构字段结构二、索引计算三、put方法四、扩容机制五、其他一、 存储结构 HashMap的底层数据结构是什么? 在JDK1.7 和JDK1.8 中有所差别: 在JDK1.7 中,由“数组链表”组成,数组是 HashMap 的主体,链…

Django学习Day6

1.ORM故障处理 1)当执行python manager.py makemigrations出现迁移问题时,如何进行解决。 处理方案:在models.py中,为book表的des非空字段设置一个默认值。 2)数据库的迁移文件混乱问题 数据库中的django_migrations记录了migra…

健康指标管理系统

开发工具(eclipse/idea/vscode等): 数据库(sqlite/mysql/sqlserver等): 功能模块(请用文字描述,至少200字): 模块划分:公告类型、公告信息、地区信息、用户信息、人员分类、人员信息、指标信息、健康信息 管理员功能&a…

Java+MYSQL基于ssm在线投票管理系统

随着社会的发展,人们在处理一些问题的时候不同意见越来越多,这源于人们对思想的解放和对社会的认识。所以在处理同一问题上,为了征求不同人的意见在线投票系统诞生了。 传统的投票模式都是通过人工手动填写问卷的方式来进行,这在很大程度上会造成人力和资源上的浪费。随着科技的…

擎创技术流 | ClickHouse实用工具—ckman教程(7)

​ ​一期一会的“ckman”教程又跟大家见面了,本期分享的重点主要针对上期后台陆续收到的问题展开,解答完问题后再带入一些关于“ckman”升级的相关讲解。感兴趣的朋友可以先关注一波。还是老规矩,先带大家复习下前几期的分享内容↓↓↓ 擎创…

springboot整合mongodb 保姆级教程

1、确保mongodb是否安装 Linux安装docker 保姆级教程_ 来杯咖啡的博客-CSDN博客&#xff08;可以看这篇文章&#xff09; 2、代码展示 2.1 使用 MongoTemplate 创建boot项目&#xff0c;导入架包。 <?xml version"1.0" encoding"UTF-8"?> <p…

带你深入了解一下vue.js中的this.$nextTick!

我们先看看nextTick究竟是个啥&#xff1f; console.log(this.$nextTick); // 控制台打印 if(fn){return nextTick(fn, this); } 我们可以看出nextTick就是一个方法&#xff0c;方法有两个参数&#xff1a;fn和this&#xff0c;fn就是需要传的回调函数&#xff0c;this就是所…

主轴承盖螺栓拧紧机PLC控制程序

HMI为西门子TP900触摸屏&#xff0c;支持屏幕触摸和按键操作 设备主要参数 设备外形尺寸&#xff1a;长*宽*高 2180*1900*2500mm 生产节拍&#xff1a; 55 S 电源电压&#xff1a; AC380V5%&#xff0c;50HZ&#xff0c;三相五线制 系统组态 常见故障处理 气缸报警 报警原…

Windows下安装VTK8.2.0

Windows下安装VTK8.2.0 1、依赖 VS2017 Qt5 cmake 2、前期准备 2.1、访问vtk官方下载VTK8.2.0源码 VTK源码下载地址&#xff1a;https://vtk.org/download/ 2.2、配置环境变量 配置CMAKE_PREFIX_PATH&#xff0c;值为Qt的bin路径 2.3、新建2个文件夹一个用于存放cm…

11 个有用的现代 JavaScript 技巧

在我们日常开发工作中&#xff0c;我们经常使用到字符串的转换、检查它是否存在的对象中的键、有条件地操作对象数据、过滤数组中的假值等。 在这里&#xff0c;我整理了一些很棒的JavaScript的技巧&#xff0c;这些技巧是我个人最喜欢的&#xff0c;因为它使我的代码更短更干…

亚马逊云科技:还在苦于ETL?Zero ETL的时代已全面到来

在2022亚马逊云科技re:Invent全球大会上&#xff0c;亚马逊云科技数据和机器学习副总裁Swami Sivasubramanian表示&#xff1a;“当前&#xff0c;客户管理的数据既庞大又复杂&#xff0c;这意味着他们不能只用单一技术或几个工具来分析和探索这些数据。在此次2022亚马逊云科技…

Java反射和new效率差距有多大?

1、创建对象的两种方式 //new 方式创建对象 ReflectDemo reflectDemo new ReflectDemo();//反射创建对象 反射创建对象的三种方式 (1)Class<ReflectDemo> reflectDemoClass ReflectDemo.class; (2)Class<?> aClass Class.forName ("com.whale.springtra…

网络ping不通,试试这8招

摘要&#xff1a;网络ping不通&#xff0c;该怎么办&#xff1f;本文教你8个大招&#xff0c;轻松找到问题根源。本文分享自华为云社区《网络ping不通&#xff0c;该怎么办&#xff1f;》&#xff0c;作者&#xff1a;wljslmz。 如下图&#xff0c;PC&#xff08;192.168.10.1…

使用windows系统给C盘分盘

前言 一般我们使用新电脑的时候&#xff0c;有的时候默认给我们分好了盘&#xff0c;有时候只会把全部的内存都放到C盘&#xff0c;这样就需要我们自己手动进行分配资源和分配其他硬盘资源 今天公司邮寄的新电脑到了&#xff0c;正好属于后者&#xff0c;借助这个机会分享下我…

【C语言进阶】六.预处理

&#xff08;1&#xff09;程序的翻译环境和执行环境 在ANSI C的任何一种实现中&#xff0c;存在两个不同的环境。 第1种是翻译环境&#xff0c;在这个环境中源代码被转换为可执行的机器指令。包含编译加链接第2种是执行环境&#xff0c;它用于实际执行代码。 &#xff08;2…