赞
踩
★★★ 本文源自AlStudio社区精品项目,【点击此处】查看更多精品内容 >>>
很多了解飞桨的同学们都知道,在庞大的飞桨工具库套件家族中,有一款知名的“零代码”全流程开发工具——PaddleX的图形化开发客户端。
但有些遗憾的是,PaddleX的全流程开发长期以来只提供了面向CV领域即图像分类、目标检测、图像分割的解决方案。
而飞桨其它方向的工具库,一直以来在“零代码”开发客户端方面还是有所欠缺的。随着Streamlit和Gradio等机器学习可视化web框架的引入,以及各类飞桨工具库的调用API愈加清晰、整齐,现在,给这些工具库插上“零代码”的翅膀,让更多初学者参与到深度学习应用开发中来,已不再是特别困难的事情了。
另一方面,本次“中国软件杯”大学生软件设计大赛——龙源风电赛道的区域赛阶段,也要求选手实现模型算法的落地。基于Gradio快速实现轻量级部署,也是选手们在设计时可以考虑的一种方向。
因此,本文就基于AI Studio提供的Gradio应用部署解决方案,以“中国软件杯”大学生软件设计大赛——龙源风电赛道的场景为例,介绍如何实现一个面向通用场景的PaddleTS全流程零代码开发案例。
参考资料:
!pip install paddlets
任何一个软件开发工具的实现,都离不开前期对整体结构的设计。根据一贯的从易到难迭代原则,本项目首先聚焦实现PaddleTS时间序列预测任务的全流程“零代码”开发。
注:红色字体为后续迭代内容。
下面,就逐一介绍一下工具箱重点实现的内容。
由于风电预测这个任务,数据集完全来自真实产业场景,前期数据预处理的任务非常关键,如:
因此,我们结合该项目设计的数据集参数选项,将会非常有代表性,基本覆盖时间序列任务可能要面临的各种情况。
在数据集参数设置中,最需要关注的是多列变量如何传参与后台处理——如:有多个协变量、多个预测值。
本项目采用的是手动设置分隔符,再在后台处理的方式。用户只需在不同字段名间输入空格,后台就通过split()
函数将字符串切成字典,从而让传入数据符合PaddleTS处理的格式要求。
时间序列预测任务的训练参数设置也是比较固定的,因为PaddleTS模型在这方面已经抽象得非常到位了。
以初始化MLPRegressor模型为例,只有两个必传的参数:
in_chunk_len
: 输入时序窗口的大小,代表每次训练以及预测时候输入到模型中的前序的时间步长。
out_chunk_len
: 输出时序窗口的大小,代表每次训练以及预测时候输出的后续的时间步长。
大部分时间序列预测模型的传参非常一致。
为简化页面复杂度,本项目只提取了其中最常用、最经常需要调整的batch_size
、lr
、epochs
进行界面传参,其余使用默认设置。
众所周知,深度学习模型训练都需要比较长的时间,尽管时间序列预测任务和CV、大模型类训练时长相比,已经算是“极速”了,但是在Gradio前端应用使用时,由于训练过程我们暂时无法实现可视化,一直等待页面加载模型训练结果会非常枯燥。而且,模型加载后的预测时间,相对于模型训练时间又非常地“微不足道”,要使得界面展示更加简洁美观,还需要进一步优化设计。
因此,本项目做了两个处理。
gr.Accordion()
折叠了未训练时的可视化结果展示页签gr.Tab()
把模型训练和模型加载完全分开尽管部署Gradio应用只需启动一个*.gradio.py
的脚本文件,但是本项目涉及到的输入输出和函数处理特别多,因此,把fn函数独立出来开发,会使得gradio脚本更加简洁。
另外,既然是面对通用时间序列预测任务的工具箱,在设计函数处理时,就应该尽可能避免单个场景数据的影响。时序训练的关键函数代码如下:
def get_ts_df(upfile, time_colunm, dayfirst, observed_colunms, trans_colunms, pred_colunms, time_freq, train_ratio, test_ratio, in_chunk_len, out_chunk_len, skip_chunk_len, choose_model, max_epochs, learning_rate, batch_size): df = pd.read_csv(upfile.name, parse_dates=[time_colunm], infer_datetime_format=True, dayfirst=dayfirst) df = df.drop_duplicates(subset=[time_colunm], keep='first') fig = altair.Chart(df[:1000]).mark_line().encode(x=time_colunm, y=pred_colunms.split()[-1]).configure_point( size=1200 ) df[trans_colunms.split()] = df[trans_colunms.split()].fillna( 0).astype(np.float64()) target_cov_dataset = TSDataset.load_from_dataframe( df, time_col=time_colunm, target_cols=pred_colunms.split(), observed_cov_cols=observed_colunms.split(), freq=time_freq, fill_missing_dates=True, fillna_method='pre') train_dataset, val_test_dataset = target_cov_dataset.split(train_ratio) val_dataset, test_dataset = val_test_dataset.split(test_ratio) scaler = StandardScaler() scaler.fit(train_dataset) ts_train_scaled = scaler.transform(train_dataset) ts_val_scaled = scaler.transform(val_dataset) ts_test_scaled = scaler.transform(test_dataset) if choose_model == 'MLP': model = MLPRegressor( in_chunk_len=int(in_chunk_len), out_chunk_len=int(out_chunk_len), skip_chunk_len=int(skip_chunk_len), max_epochs=int(max_epochs), batch_size=int(batch_size), optimizer_params=dict(learning_rate=learning_rate), ) elif choose_model == 'LSTM': model = LSTNetRegressor( in_chunk_len=int(in_chunk_len), out_chunk_len=int(out_chunk_len), skip_chunk_len=int(skip_chunk_len), max_epochs=int(max_epochs), batch_size=int(batch_size), optimizer_params=dict(learning_rate=learning_rate), ) elif choose_model == 'RNN': model = RNNBlockRegressor( in_chunk_len=int(in_chunk_len), out_chunk_len=int(out_chunk_len), skip_chunk_len=int(skip_chunk_len), max_epochs=int(max_epochs), batch_size=int(batch_size), optimizer_params=dict(learning_rate=learning_rate), ) elif choose_model == 'TCN': model = TCNRegressor( in_chunk_len=int(in_chunk_len), out_chunk_len=int(out_chunk_len), skip_chunk_len=int(skip_chunk_len), max_epochs=int(max_epochs), batch_size=int(batch_size), optimizer_params=dict(learning_rate=learning_rate), ) elif choose_model == 'Transformer': model = TransformerModel( in_chunk_len=int(in_chunk_len), out_chunk_len=int(out_chunk_len), skip_chunk_len=int(skip_chunk_len), max_epochs=int(max_epochs), batch_size=int(batch_size), optimizer_params=dict(learning_rate=learning_rate), ) model.fit(ts_train_scaled, ts_val_scaled) if os.path.exists("model"): os.remove("model") os.remove("model_model_meta") os.remove("model_network_statedict") model.save("model") subset_test_pred_dataset = model.predict(ts_val_scaled) subset_test_dataset, _ = ts_test_scaled.split(len(subset_test_pred_dataset.target)) mae = MAE() mae(subset_test_dataset, subset_test_pred_dataset) test_dataset = scaler.inverse_transform(ts_test_scaled) fig2 = altair.Chart( model.predict(test_dataset).to_dataframe().reset_index().rename( columns={"index": time_colunm})).mark_line().encode( x=time_colunm, y=pred_colunms.split()[-1]) result_df = model.predict(test_dataset).to_dataframe() result_df.reset_index().rename( columns={"index": time_colunm}).to_csv('res.csv') return df.head(), fig, fig2, mae(subset_test_dataset, subset_test_pred_dataset), result_df.reset_index().rename( fig, fig2, mae(subset_test_dataset, subset_test_pred_dataset), result_df.reset_index().rename( columns={"index": time_colunm}).head()
完整代码实现读者可以查阅项目的gradio_fns.py
和base.gradio.py
文件。
由于AI Studio上的Gradio做了一些网络限制,以及一些还需要完善的部署问题,实际开发时,还有以下注意事项:
in_chunk_len
通过gr.Number()
获取后需要强制转换为int
格式skip_chunk_len
参数,否则计算MAE时会出现错误读者可以到应用界面测试体验“零代码”时间序列预测效果。
本项目是基于PaddleTS和Gradio基本实现了时间序列预测任务的全流程可视化开发,在后续迭代中,将主要进行以下几方面的优化:
此文章为搬运
原项目链接
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。