Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

基于BasicTS,如何打造时间序列分类领域的开源库? #69

Open
Waterkin opened this issue Aug 31, 2023 · 6 comments
Open

Comments

@Waterkin
Copy link

Waterkin commented Aug 31, 2023

您好!看到BasicTS的架构和代码,感觉到非常规范、清晰和优雅,因此想要fork您的库做二次开发,以适用于时间序列分类及其相关应用领域。

经过阅读BasicTS主页的介绍和部分代码,我总结了以下需要修改的点,不知道理解的对不对,冒昧打扰,希望能和您请教:

  1. 数据预处理
  • 由于交通流预测的输入是[B, L, N, C],而时间序列分类中的输入是[B, L, C],因此在预处理时需要新增一个N维,且N=1。这样的话,是否可以不修改模型代码就适配已有的时序预测Baselines
  1. 训练过程
  • 由于交通流预测属于regression任务,时间序列分类属于classification任务,可重写cross-entropy loss在losses.py中。
  • 由于forward过程无需客制化,因此无需重写runner吗?
  1. 可视化
  1. 自动化调参,也方便记录实验结果
  • 想要使BasicTS支持wandb方便调参,但不知道实验结果记录在哪里(似乎是在base_tsf_runner.py这里么?)
  • 如果需要记录实验结果的metrics以及不同CFG,是否要改写runner呢,方便问下如何改写吗?

感谢作者~ 辛苦了!

@zezhishao
Copy link
Owner

zezhishao commented Aug 31, 2023

您好,非常感谢您的认可,非常开心看到您希望将其扩展到分类任务上。
事实上,BasicTS规划之初就是希望能支持不同的任务。我个人是做预测的,所以目前就只做了预测部分。

您问的这个问题比较大,不太好回答,我也没太想好整个架构应该是怎么样的,只能简单的回答一下您的问题和我的一些想法。

  • 您的问题:
  1. 理论上来说是这样的,大部分模型应该都能跑。
  2. 可以写一个celoss在loss.py中;forward比较复杂。runner的forward涉及数据的一点操作(比如将数据送到gpu上),所以可能会需要修改,这个需要根据你确定的数据存储和读取格式来。(见下一个comment)
  3. 略。
  4. 我没有用过wandb,也不清楚这是个啥,所以无法给出答案;你指的“实验结果”是什么?BasicTS的实验结果会自动log,并且会记录对应的tensorboard。您可以在checkpoints文件夹下找到相关结果;“记录实验结果的metric以及不同的cfg”是什么意思?

@zezhishao
Copy link
Owner

zezhishao commented Aug 31, 2023

其他的一些您可以参考的东西:

  • BasicTS中base_tsf_runner是用来做time series forcasting(tsf)的runner。他继承自base_runner(这是一个通用的runner。所以你可以通过模仿base_tsf_runner来实现分类的base runner。关于函数的含义和用法,不清楚的可以直接在这个issue下面问就行。我时间不够,没有办法为他写更详细的文档了😂 ;)

    1. 数据的存储和读取方式或许是需要首先确定的。确定好了之后,就可以写Datasets了。
    1. 根据数据的读取方式,就可以照着base_tsf_runner写一个base_tsc_runner就可以了。
    1. 之后,就可以写对应的损失函数、评价指标,添加一些常用的训练技巧(假如有的话),评测方式等等细节。

整个架构其实不难,但主要是得简洁、可扩展,要不然之后添加的模型多了还得再重构。

@Waterkin
Copy link
Author

Waterkin commented Sep 1, 2023

感谢您的详尽的解答,但由于对项目的架构、函数、参数等不太熟悉,目前我只能做到简单的增加:

  • Binary Cross Entropy Loss分类损失函数
  • ACC、MCC、F1分类评估指标

为了实现一个能简单跑通的时序分类baseline,我现在在试图改写一个时序分类的Datasetsbase_tsc_runner,但我遇到了一些问题,希望能得到作者的帮助!

具体到数据读取来说,我希望实现一个最简单的时序分类Datasets,以下是我预计需要做的事情:

  • 通过改写generate_training_data.py预处理数据得到data_file, index_file,其中:
    • data_file['processed_data'].shape=[N, L, C](N应该是样本条数?那么Node维去哪里了?)
    • index_file=[train,valid,test]
  • Datasets__getitem__()返回(labels, history_data),其他不变

具体到训练过程来说,我希望实现base_tsc_runnersimple_tsc_runner,但我不太理解:

  • 对于一个tsf任务,从头到尾,base_tsf_runner是如何运行的,即函数的执行顺序是怎样的?(因为函数太多,找不到runner的起点^^)
  • 在读取PEMS04时,明明没有Node维,但simple_tsf_runner中却注释数据维度应为[B, L, N, C],是在何时加入了Node维?
  • Datasetssimple_tsf_runner是如何交互的呢?

我想,理解以上问题对于扩展BasicTS到时间序列分类领域至关重要,希望可以得到作者的帮助~谢谢!

另外,关于前面提到的wandb,它是一个Logging的工具,类似于TensorBoard,不过它是有Web端页面的,同时支持自动调参、记录参数和实验结果,优势在于界面UI比较用户友好,因此想要引入。

@zezhishao
Copy link
Owner

zezhishao commented Sep 2, 2023

关于现有的数据预处理的方式,您可以参考我之前写过的一个简单的说明(有一些细节可能已经和现在的实现不一样了,但思想是一样的)。
简而言之,N不是样本条数,而是时间序列数量(即Node维)。data_file['processed_data']是归一化后的全部时间序列。样本的取样是通过index实验的:index相当于是一个滑动窗口,直接从data_file['processed_data']中截取数据。这样的好处是不需要在本地存储很多的数据。

假如是先处理好样本数据,然后存储到本地,存储量会非常大。这是因为sample是通过滑动窗口取的,所以相邻的sample之间是有重合的,这意味着同样的数据被存储了多份。


关于训练的流程,这个需要结合easytorch库内部的实现。假如您在使用vscode,可以将justMyCode选项设置为false,这样可以debug进入easytorch库。
BasicTS的函数入口在basicts/launcher.py,它调用了easytorch.launch_training。您可以重点关注easytorch.launcher.launcher.py中的training_func函数,以及easytorch.core.runner.pyRunner.train函数。真正的开始训练是Runner.train函数。这个是一切训练流程(包括测试验证)的入口。

@Waterkin
Copy link
Author

Waterkin commented Sep 4, 2023

好嘞好嘞,参照您的建议,我把lz的说明和预处理的方式搞懂了,感谢耐心指导~
目前我已经实现了数据部分,包括预处理的脚本generate_training_data.pyDatasets
接下来我会follow lz的建议,参照几个runner进行重写,但我发现了一些问题,目前还在work on them:

  • 为什么在train_iter()里需要rescale data?计算loss和metrics时如果不rescale data会带来误差么?
  • update_epoch_meter()似乎是在每个iter更新metrics,尽管对于分类的Accuracy可以这么做,但似乎MCC和F1-score不能通过累计加和求平均的方式得到。

btw,lz是博士吗,感觉这代码抽象得tql!很规范!以后写论文代码都可以参照这个模板去做了W_W

@zezhishao
Copy link
Owner

  • 时间序列预测的评测方式有两种。(i) rescale之后计算MAE、MAPE等指标。 (ii)不rescale直接在归一化之后的数据上计算MAE、MSE。前者通常被用在时空预测(例如交通预测问题中),后者则经常被长序列预测方向采用。您可以通过设定CFG.RESCALE来控制是否进行rescale。

个人的角度上讲,作为一种评测手段,rescale是更合理的。一方面,这样可以更直观地反映预测的准确率。另一方面,也方便计算MAPE、WAPE等相对误差指标。假如只在归一化后的数据上计算MAE、MSE,会让误差看起来特别小(零点几)。但实际的效果可能其实并不好。

  • update_epoch_meter()是计算每一个iter,然后最后会取平均(由easytorch在背后进行控制)。按理来说,应该是可以用的?这一块我也不能确定因为我没怎么用过MCC和F1-Score。
    代码的抽象主要是靠的easytorch库 XD,我也是模仿着来的。

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants