mirror of
https://github.com/wassname/ETSformer.git
synced 2026-06-27 18:02:52 +08:00
first commit
This commit is contained in:
@@ -0,0 +1,2 @@
|
||||
# Comment line immediately above ownership line is reserved for related other information. Please be careful while editing.
|
||||
#ECCN:Open Source
|
||||
@@ -0,0 +1,105 @@
|
||||
# Salesforce Open Source Community Code of Conduct
|
||||
|
||||
## About the Code of Conduct
|
||||
|
||||
Equality is a core value at Salesforce. We believe a diverse and inclusive
|
||||
community fosters innovation and creativity, and are committed to building a
|
||||
culture where everyone feels included.
|
||||
|
||||
Salesforce open-source projects are committed to providing a friendly, safe, and
|
||||
welcoming environment for all, regardless of gender identity and expression,
|
||||
sexual orientation, disability, physical appearance, body size, ethnicity, nationality,
|
||||
race, age, religion, level of experience, education, socioeconomic status, or
|
||||
other similar personal characteristics.
|
||||
|
||||
The goal of this code of conduct is to specify a baseline standard of behavior so
|
||||
that people with different social values and communication styles can work
|
||||
together effectively, productively, and respectfully in our open source community.
|
||||
It also establishes a mechanism for reporting issues and resolving conflicts.
|
||||
|
||||
All questions and reports of abusive, harassing, or otherwise unacceptable behavior
|
||||
in a Salesforce open-source project may be reported by contacting the Salesforce
|
||||
Open Source Conduct Committee at ossconduct@salesforce.com.
|
||||
|
||||
## Our Pledge
|
||||
|
||||
In the interest of fostering an open and welcoming environment, we as
|
||||
contributors and maintainers pledge to making participation in our project and
|
||||
our community a harassment-free experience for everyone, regardless of gender
|
||||
identity and expression, sexual orientation, disability, physical appearance,
|
||||
body size, ethnicity, nationality, race, age, religion, level of experience, education,
|
||||
socioeconomic status, or other similar personal characteristics.
|
||||
|
||||
## Our Standards
|
||||
|
||||
Examples of behavior that contributes to creating a positive environment
|
||||
include:
|
||||
|
||||
* Using welcoming and inclusive language
|
||||
* Being respectful of differing viewpoints and experiences
|
||||
* Gracefully accepting constructive criticism
|
||||
* Focusing on what is best for the community
|
||||
* Showing empathy toward other community members
|
||||
|
||||
Examples of unacceptable behavior by participants include:
|
||||
|
||||
* The use of sexualized language or imagery and unwelcome sexual attention or
|
||||
advances
|
||||
* Personal attacks, insulting/derogatory comments, or trolling
|
||||
* Public or private harassment
|
||||
* Publishing, or threatening to publish, others' private information—such as
|
||||
a physical or electronic address—without explicit permission
|
||||
* Other conduct which could reasonably be considered inappropriate in a
|
||||
professional setting
|
||||
* Advocating for or encouraging any of the above behaviors
|
||||
|
||||
## Our Responsibilities
|
||||
|
||||
Project maintainers are responsible for clarifying the standards of acceptable
|
||||
behavior and are expected to take appropriate and fair corrective action in
|
||||
response to any instances of unacceptable behavior.
|
||||
|
||||
Project maintainers have the right and responsibility to remove, edit, or
|
||||
reject comments, commits, code, wiki edits, issues, and other contributions
|
||||
that are not aligned with this Code of Conduct, or to ban temporarily or
|
||||
permanently any contributor for other behaviors that they deem inappropriate,
|
||||
threatening, offensive, or harmful.
|
||||
|
||||
## Scope
|
||||
|
||||
This Code of Conduct applies both within project spaces and in public spaces
|
||||
when an individual is representing the project or its community. Examples of
|
||||
representing a project or community include using an official project email
|
||||
address, posting via an official social media account, or acting as an appointed
|
||||
representative at an online or offline event. Representation of a project may be
|
||||
further defined and clarified by project maintainers.
|
||||
|
||||
## Enforcement
|
||||
|
||||
Instances of abusive, harassing, or otherwise unacceptable behavior may be
|
||||
reported by contacting the Salesforce Open Source Conduct Committee
|
||||
at ossconduct@salesforce.com. All complaints will be reviewed and investigated
|
||||
and will result in a response that is deemed necessary and appropriate to the
|
||||
circumstances. The committee is obligated to maintain confidentiality with
|
||||
regard to the reporter of an incident. Further details of specific enforcement
|
||||
policies may be posted separately.
|
||||
|
||||
Project maintainers who do not follow or enforce the Code of Conduct in good
|
||||
faith may face temporary or permanent repercussions as determined by other
|
||||
members of the project's leadership and the Salesforce Open Source Conduct
|
||||
Committee.
|
||||
|
||||
## Attribution
|
||||
|
||||
This Code of Conduct is adapted from the [Contributor Covenant][contributor-covenant-home],
|
||||
version 1.4, available at https://www.contributor-covenant.org/version/1/4/code-of-conduct.html.
|
||||
It includes adaptions and additions from [Go Community Code of Conduct][golang-coc],
|
||||
[CNCF Code of Conduct][cncf-coc], and [Microsoft Open Source Code of Conduct][microsoft-coc].
|
||||
|
||||
This Code of Conduct is licensed under the [Creative Commons Attribution 3.0 License][cc-by-3-us].
|
||||
|
||||
[contributor-covenant-home]: https://www.contributor-covenant.org (https://www.contributor-covenant.org/)
|
||||
[golang-coc]: https://golang.org/conduct
|
||||
[cncf-coc]: https://github.com/cncf/foundation/blob/master/code-of-conduct.md
|
||||
[microsoft-coc]: https://opensource.microsoft.com/codeofconduct/
|
||||
[cc-by-3-us]: https://creativecommons.org/licenses/by/3.0/us/
|
||||
+12
@@ -0,0 +1,12 @@
|
||||
Copyright (c) 2022, Salesforce.com, Inc.
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met:
|
||||
|
||||
* Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer.
|
||||
|
||||
* Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution.
|
||||
|
||||
* Neither the name of Salesforce.com nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
@@ -0,0 +1,33 @@
|
||||
# ETSformer: Exponential Smoothing Transformers for Time-series Forecasting
|
||||
|
||||
## Requirements
|
||||
|
||||
Official PyTorch code repository for the [ETSformer paper](https://arxiv.org/abs/2202.01381). Required dependencies can be installed by:
|
||||
```bash
|
||||
pip install -r requirements.txt
|
||||
```
|
||||
|
||||
## Data
|
||||
* Pre-processed datasets can be downloaded from the following links, [Tsinghua Cloud](https://cloud.tsinghua.edu.cn/d/e1ccfff39ad541908bae/) or [Google Drive](https://drive.google.com/drive/folders/1ZOYpTUa82_jCcxIdTmyr0LXQfvaM9vIy?usp=sharing), as obtained from [Autoformer's](https://github.com/thuml/Autoformer) GitHub repository.
|
||||
* Place the downloaded datasets into the `dataset/` folder, e.g. `dataset/ETT-small/ETTm2.csv`.
|
||||
|
||||
## Usage
|
||||
|
||||
1. Install Python 3.8, and the required dependencies.
|
||||
2. Download data as above, and place them in the folder, `dataset/`.
|
||||
3. Train the model. We provide the experiment scripts of all benchmarks under the folder `./scripts`, e.g. `./scripts/ETTm2.sh`. You might have to change permissions on the script files by running`chmod u+x scripts/*`.
|
||||
4. The script for grid search is also provided, and can be run by `./grid_search.sh`.
|
||||
|
||||
## Acknowledgements
|
||||
The implementation of ETSformer relies on resources from the following codebases and repositories, we thank the original authors for open-sourcing their work.
|
||||
* https://github.com/thuml/Autoformer
|
||||
* https://github.com/zhouhaoyi/Informer2020
|
||||
|
||||
## Citation
|
||||
Please consider citing if you find this code useful to your research.
|
||||
<pre>@article{woo2022etsformer,
|
||||
title={ETSformer: Exponential Smoothing Transformers for Time-series Forecasting},
|
||||
author={Gerald Woo and Chenghao Liu and Doyen Sahoo and Akshat Kumar and Steven C. H. Hoi},
|
||||
year={2022},
|
||||
url={https://arxiv.org/abs/2202.01381},
|
||||
}</pre>
|
||||
@@ -0,0 +1,7 @@
|
||||
## Security
|
||||
|
||||
Please report any security issue to [security@salesforce.com](mailto:security@salesforce.com)
|
||||
as soon as it is discovered. This library limits its runtime dependencies in
|
||||
order to reduce the total cost of ownership as much as can be, but all consumers
|
||||
should remain vigilant and have their security stakeholders review all third-party
|
||||
products (3PP) like this one and their dependencies.
|
||||
@@ -0,0 +1 @@
|
||||
|
||||
@@ -0,0 +1,51 @@
|
||||
from data_provider.data_loader import Dataset_ETT_hour, Dataset_ETT_minute, Dataset_Custom, Dataset_Pred
|
||||
from torch.utils.data import DataLoader
|
||||
|
||||
data_dict = {
|
||||
'ETTh1': Dataset_ETT_hour,
|
||||
'ETTh2': Dataset_ETT_hour,
|
||||
'ETTm1': Dataset_ETT_minute,
|
||||
'ETTm2': Dataset_ETT_minute,
|
||||
'custom': Dataset_Custom,
|
||||
}
|
||||
|
||||
|
||||
def data_provider(args, flag):
|
||||
Data = data_dict[args.data]
|
||||
timeenc = 0 if args.embed != 'timeF' else 1
|
||||
|
||||
if flag == 'test':
|
||||
shuffle_flag = False
|
||||
drop_last = True
|
||||
batch_size = args.batch_size
|
||||
freq = args.freq
|
||||
elif flag == 'pred':
|
||||
shuffle_flag = False
|
||||
drop_last = False
|
||||
batch_size = 1
|
||||
freq = args.freq
|
||||
Data = Dataset_Pred
|
||||
else:
|
||||
shuffle_flag = True
|
||||
drop_last = True
|
||||
batch_size = args.batch_size
|
||||
freq = args.freq
|
||||
|
||||
data_set = Data(
|
||||
root_path=args.root_path,
|
||||
data_path=args.data_path,
|
||||
flag=flag,
|
||||
size=[args.seq_len, args.label_len, args.pred_len],
|
||||
features=args.features,
|
||||
target=args.target,
|
||||
timeenc=timeenc,
|
||||
freq=freq
|
||||
)
|
||||
print(flag, len(data_set))
|
||||
data_loader = DataLoader(
|
||||
data_set,
|
||||
batch_size=batch_size,
|
||||
shuffle=shuffle_flag,
|
||||
num_workers=args.num_workers,
|
||||
drop_last=drop_last)
|
||||
return data_set, data_loader
|
||||
@@ -0,0 +1,394 @@
|
||||
import os
|
||||
import numpy as np
|
||||
import pandas as pd
|
||||
import os
|
||||
import torch
|
||||
from torch.utils.data import Dataset, DataLoader
|
||||
from sklearn.preprocessing import StandardScaler
|
||||
from utils.timefeatures import time_features
|
||||
import warnings
|
||||
|
||||
warnings.filterwarnings('ignore')
|
||||
|
||||
|
||||
class Dataset_ETT_hour(Dataset):
|
||||
def __init__(self, root_path, flag='train', size=None,
|
||||
features='S', data_path='ETTh1.csv',
|
||||
target='OT', scale=True, timeenc=0, freq='h'):
|
||||
# size [seq_len, label_len, pred_len]
|
||||
# info
|
||||
if size == None:
|
||||
self.seq_len = 24 * 4 * 4
|
||||
self.label_len = 24 * 4
|
||||
self.pred_len = 24 * 4
|
||||
else:
|
||||
self.seq_len = size[0]
|
||||
self.label_len = size[1]
|
||||
self.pred_len = size[2]
|
||||
# init
|
||||
assert flag in ['train', 'test', 'val']
|
||||
type_map = {'train': 0, 'val': 1, 'test': 2}
|
||||
self.set_type = type_map[flag]
|
||||
|
||||
self.features = features
|
||||
self.target = target
|
||||
self.scale = scale
|
||||
self.timeenc = timeenc
|
||||
self.freq = freq
|
||||
|
||||
self.root_path = root_path
|
||||
self.data_path = data_path
|
||||
self.__read_data__()
|
||||
|
||||
def __read_data__(self):
|
||||
self.scaler = StandardScaler()
|
||||
df_raw = pd.read_csv(os.path.join(self.root_path,
|
||||
self.data_path))
|
||||
|
||||
border1s = [0, 12 * 30 * 24 - self.seq_len, 12 * 30 * 24 + 4 * 30 * 24 - self.seq_len]
|
||||
border2s = [12 * 30 * 24, 12 * 30 * 24 + 4 * 30 * 24, 12 * 30 * 24 + 8 * 30 * 24]
|
||||
border1 = border1s[self.set_type]
|
||||
border2 = border2s[self.set_type]
|
||||
|
||||
if self.features == 'M' or self.features == 'MS':
|
||||
cols_data = df_raw.columns[1:]
|
||||
df_data = df_raw[cols_data]
|
||||
elif self.features == 'S':
|
||||
df_data = df_raw[[self.target]]
|
||||
|
||||
if self.scale:
|
||||
train_data = df_data[border1s[0]:border2s[0]]
|
||||
self.scaler.fit(train_data.values)
|
||||
data = self.scaler.transform(df_data.values)
|
||||
else:
|
||||
data = df_data.values
|
||||
|
||||
df_stamp = df_raw[['date']][border1:border2]
|
||||
df_stamp['date'] = pd.to_datetime(df_stamp.date)
|
||||
if self.timeenc == 0:
|
||||
df_stamp['month'] = df_stamp.date.apply(lambda row: row.month, 1)
|
||||
df_stamp['day'] = df_stamp.date.apply(lambda row: row.day, 1)
|
||||
df_stamp['weekday'] = df_stamp.date.apply(lambda row: row.weekday(), 1)
|
||||
df_stamp['hour'] = df_stamp.date.apply(lambda row: row.hour, 1)
|
||||
data_stamp = df_stamp.drop(['date'], 1).values
|
||||
elif self.timeenc == 1:
|
||||
data_stamp = time_features(pd.to_datetime(df_stamp['date'].values), freq=self.freq)
|
||||
data_stamp = data_stamp.transpose(1, 0)
|
||||
|
||||
self.data_x = data[border1:border2]
|
||||
self.data_y = data[border1:border2]
|
||||
self.data_stamp = data_stamp
|
||||
|
||||
def __getitem__(self, index):
|
||||
s_begin = index
|
||||
s_end = s_begin + self.seq_len
|
||||
r_begin = s_end - self.label_len
|
||||
r_end = r_begin + self.label_len + self.pred_len
|
||||
|
||||
seq_x = self.data_x[s_begin:s_end]
|
||||
seq_y = self.data_y[r_begin:r_end]
|
||||
seq_x_mark = self.data_stamp[s_begin:s_end]
|
||||
seq_y_mark = self.data_stamp[r_begin:r_end]
|
||||
|
||||
return seq_x, seq_y, seq_x_mark, seq_y_mark
|
||||
|
||||
def __len__(self):
|
||||
return len(self.data_x) - self.seq_len - self.pred_len + 1
|
||||
|
||||
def inverse_transform(self, data):
|
||||
return self.scaler.inverse_transform(data)
|
||||
|
||||
|
||||
class Dataset_ETT_minute(Dataset):
|
||||
def __init__(self, root_path, flag='train', size=None,
|
||||
features='S', data_path='ETTm1.csv',
|
||||
target='OT', scale=True, timeenc=0, freq='t'):
|
||||
# size [seq_len, label_len, pred_len]
|
||||
# info
|
||||
if size == None:
|
||||
self.seq_len = 24 * 4 * 4
|
||||
self.label_len = 24 * 4
|
||||
self.pred_len = 24 * 4
|
||||
else:
|
||||
self.seq_len = size[0]
|
||||
self.label_len = size[1]
|
||||
self.pred_len = size[2]
|
||||
# init
|
||||
assert flag in ['train', 'test', 'val']
|
||||
type_map = {'train': 0, 'val': 1, 'test': 2}
|
||||
self.set_type = type_map[flag]
|
||||
|
||||
self.features = features
|
||||
self.target = target
|
||||
self.scale = scale
|
||||
self.timeenc = timeenc
|
||||
self.freq = freq
|
||||
|
||||
self.root_path = root_path
|
||||
self.data_path = data_path
|
||||
self.__read_data__()
|
||||
|
||||
def __read_data__(self):
|
||||
self.scaler = StandardScaler()
|
||||
df_raw = pd.read_csv(os.path.join(self.root_path,
|
||||
self.data_path))
|
||||
|
||||
border1s = [0, 12 * 30 * 24 * 4 - self.seq_len, 12 * 30 * 24 * 4 + 4 * 30 * 24 * 4 - self.seq_len]
|
||||
border2s = [12 * 30 * 24 * 4, 12 * 30 * 24 * 4 + 4 * 30 * 24 * 4, 12 * 30 * 24 * 4 + 8 * 30 * 24 * 4]
|
||||
border1 = border1s[self.set_type]
|
||||
border2 = border2s[self.set_type]
|
||||
|
||||
if self.features == 'M' or self.features == 'MS':
|
||||
cols_data = df_raw.columns[1:]
|
||||
df_data = df_raw[cols_data]
|
||||
elif self.features == 'S':
|
||||
df_data = df_raw[[self.target]]
|
||||
|
||||
if self.scale:
|
||||
train_data = df_data[border1s[0]:border2s[0]]
|
||||
self.scaler.fit(train_data.values)
|
||||
data = self.scaler.transform(df_data.values)
|
||||
else:
|
||||
data = df_data.values
|
||||
|
||||
df_stamp = df_raw[['date']][border1:border2]
|
||||
df_stamp['date'] = pd.to_datetime(df_stamp.date)
|
||||
if self.timeenc == 0:
|
||||
df_stamp['month'] = df_stamp.date.apply(lambda row: row.month, 1)
|
||||
df_stamp['day'] = df_stamp.date.apply(lambda row: row.day, 1)
|
||||
df_stamp['weekday'] = df_stamp.date.apply(lambda row: row.weekday(), 1)
|
||||
df_stamp['hour'] = df_stamp.date.apply(lambda row: row.hour, 1)
|
||||
df_stamp['minute'] = df_stamp.date.apply(lambda row: row.minute, 1)
|
||||
df_stamp['minute'] = df_stamp.minute.map(lambda x: x // 15)
|
||||
data_stamp = df_stamp.drop(['date'], 1).values
|
||||
elif self.timeenc == 1:
|
||||
data_stamp = time_features(pd.to_datetime(df_stamp['date'].values), freq=self.freq)
|
||||
data_stamp = data_stamp.transpose(1, 0)
|
||||
|
||||
self.data_x = data[border1:border2]
|
||||
self.data_y = data[border1:border2]
|
||||
self.data_stamp = data_stamp
|
||||
|
||||
def __getitem__(self, index):
|
||||
s_begin = index
|
||||
s_end = s_begin + self.seq_len
|
||||
r_begin = s_end - self.label_len
|
||||
r_end = r_begin + self.label_len + self.pred_len
|
||||
|
||||
seq_x = self.data_x[s_begin:s_end]
|
||||
seq_y = self.data_y[r_begin:r_end]
|
||||
seq_x_mark = self.data_stamp[s_begin:s_end]
|
||||
seq_y_mark = self.data_stamp[r_begin:r_end]
|
||||
|
||||
return seq_x, seq_y, seq_x_mark, seq_y_mark
|
||||
|
||||
def __len__(self):
|
||||
return len(self.data_x) - self.seq_len - self.pred_len + 1
|
||||
|
||||
def inverse_transform(self, data):
|
||||
return self.scaler.inverse_transform(data)
|
||||
|
||||
|
||||
class Dataset_Custom(Dataset):
|
||||
def __init__(self, root_path, flag='train', size=None,
|
||||
features='S', data_path='ETTh1.csv',
|
||||
target='OT', scale=True, timeenc=0, freq='h'):
|
||||
# size [seq_len, label_len, pred_len]
|
||||
# info
|
||||
if size == None:
|
||||
self.seq_len = 24 * 4 * 4
|
||||
self.label_len = 24 * 4
|
||||
self.pred_len = 24 * 4
|
||||
else:
|
||||
self.seq_len = size[0]
|
||||
self.label_len = size[1]
|
||||
self.pred_len = size[2]
|
||||
# init
|
||||
assert flag in ['train', 'test', 'val']
|
||||
type_map = {'train': 0, 'val': 1, 'test': 2}
|
||||
self.set_type = type_map[flag]
|
||||
|
||||
self.features = features
|
||||
self.target = target
|
||||
self.scale = scale
|
||||
self.timeenc = timeenc
|
||||
self.freq = freq
|
||||
|
||||
self.root_path = root_path
|
||||
self.data_path = data_path
|
||||
self.__read_data__()
|
||||
|
||||
def __read_data__(self):
|
||||
self.scaler = StandardScaler()
|
||||
df_raw = pd.read_csv(os.path.join(self.root_path,
|
||||
self.data_path))
|
||||
|
||||
'''
|
||||
df_raw.columns: ['date', ...(other features), target feature]
|
||||
'''
|
||||
cols = list(df_raw.columns)
|
||||
cols.remove(self.target)
|
||||
cols.remove('date')
|
||||
df_raw = df_raw[['date'] + cols + [self.target]]
|
||||
# print(cols)
|
||||
num_train = int(len(df_raw) * 0.7)
|
||||
num_test = int(len(df_raw) * 0.2)
|
||||
num_vali = len(df_raw) - num_train - num_test
|
||||
border1s = [0, num_train - self.seq_len, len(df_raw) - num_test - self.seq_len]
|
||||
border2s = [num_train, num_train + num_vali, len(df_raw)]
|
||||
border1 = border1s[self.set_type]
|
||||
border2 = border2s[self.set_type]
|
||||
|
||||
if self.features == 'M' or self.features == 'MS':
|
||||
cols_data = df_raw.columns[1:]
|
||||
df_data = df_raw[cols_data]
|
||||
elif self.features == 'S':
|
||||
df_data = df_raw[[self.target]]
|
||||
|
||||
if self.scale:
|
||||
train_data = df_data[border1s[0]:border2s[0]]
|
||||
self.scaler.fit(train_data.values)
|
||||
data = self.scaler.transform(df_data.values)
|
||||
else:
|
||||
data = df_data.values
|
||||
|
||||
df_stamp = df_raw[['date']][border1:border2]
|
||||
df_stamp['date'] = pd.to_datetime(df_stamp.date)
|
||||
if self.timeenc == 0:
|
||||
df_stamp['month'] = df_stamp.date.apply(lambda row: row.month, 1)
|
||||
df_stamp['day'] = df_stamp.date.apply(lambda row: row.day, 1)
|
||||
df_stamp['weekday'] = df_stamp.date.apply(lambda row: row.weekday(), 1)
|
||||
df_stamp['hour'] = df_stamp.date.apply(lambda row: row.hour, 1)
|
||||
data_stamp = df_stamp.drop(['date'], 1).values
|
||||
elif self.timeenc == 1:
|
||||
data_stamp = time_features(pd.to_datetime(df_stamp['date'].values), freq=self.freq)
|
||||
data_stamp = data_stamp.transpose(1, 0)
|
||||
|
||||
self.data_x = data[border1:border2]
|
||||
self.data_y = data[border1:border2]
|
||||
self.data_stamp = data_stamp
|
||||
|
||||
def __getitem__(self, index):
|
||||
s_begin = index
|
||||
s_end = s_begin + self.seq_len
|
||||
r_begin = s_end - self.label_len
|
||||
r_end = r_begin + self.label_len + self.pred_len
|
||||
|
||||
seq_x = self.data_x[s_begin:s_end]
|
||||
seq_y = self.data_y[r_begin:r_end]
|
||||
seq_x_mark = self.data_stamp[s_begin:s_end]
|
||||
seq_y_mark = self.data_stamp[r_begin:r_end]
|
||||
|
||||
return seq_x, seq_y, seq_x_mark, seq_y_mark
|
||||
|
||||
def __len__(self):
|
||||
return len(self.data_x) - self.seq_len - self.pred_len + 1
|
||||
|
||||
def inverse_transform(self, data):
|
||||
return self.scaler.inverse_transform(data)
|
||||
|
||||
|
||||
class Dataset_Pred(Dataset):
|
||||
def __init__(self, root_path, flag='pred', size=None,
|
||||
features='S', data_path='ETTh1.csv',
|
||||
target='OT', scale=True, inverse=False, timeenc=0, freq='15min', cols=None):
|
||||
# size [seq_len, label_len, pred_len]
|
||||
# info
|
||||
if size == None:
|
||||
self.seq_len = 24 * 4 * 4
|
||||
self.label_len = 24 * 4
|
||||
self.pred_len = 24 * 4
|
||||
else:
|
||||
self.seq_len = size[0]
|
||||
self.label_len = size[1]
|
||||
self.pred_len = size[2]
|
||||
# init
|
||||
assert flag in ['pred']
|
||||
|
||||
self.features = features
|
||||
self.target = target
|
||||
self.scale = scale
|
||||
self.inverse = inverse
|
||||
self.timeenc = timeenc
|
||||
self.freq = freq
|
||||
self.cols = cols
|
||||
self.root_path = root_path
|
||||
self.data_path = data_path
|
||||
self.__read_data__()
|
||||
|
||||
def __read_data__(self):
|
||||
self.scaler = StandardScaler()
|
||||
df_raw = pd.read_csv(os.path.join(self.root_path,
|
||||
self.data_path))
|
||||
'''
|
||||
df_raw.columns: ['date', ...(other features), target feature]
|
||||
'''
|
||||
if self.cols:
|
||||
cols = self.cols.copy()
|
||||
cols.remove(self.target)
|
||||
else:
|
||||
cols = list(df_raw.columns)
|
||||
cols.remove(self.target)
|
||||
cols.remove('date')
|
||||
df_raw = df_raw[['date'] + cols + [self.target]]
|
||||
border1 = len(df_raw) - self.seq_len
|
||||
border2 = len(df_raw)
|
||||
|
||||
if self.features == 'M' or self.features == 'MS':
|
||||
cols_data = df_raw.columns[1:]
|
||||
df_data = df_raw[cols_data]
|
||||
elif self.features == 'S':
|
||||
df_data = df_raw[[self.target]]
|
||||
|
||||
if self.scale:
|
||||
self.scaler.fit(df_data.values)
|
||||
data = self.scaler.transform(df_data.values)
|
||||
else:
|
||||
data = df_data.values
|
||||
|
||||
tmp_stamp = df_raw[['date']][border1:border2]
|
||||
tmp_stamp['date'] = pd.to_datetime(tmp_stamp.date)
|
||||
pred_dates = pd.date_range(tmp_stamp.date.values[-1], periods=self.pred_len + 1, freq=self.freq)
|
||||
|
||||
df_stamp = pd.DataFrame(columns=['date'])
|
||||
df_stamp.date = list(tmp_stamp.date.values) + list(pred_dates[1:])
|
||||
if self.timeenc == 0:
|
||||
df_stamp['month'] = df_stamp.date.apply(lambda row: row.month, 1)
|
||||
df_stamp['day'] = df_stamp.date.apply(lambda row: row.day, 1)
|
||||
df_stamp['weekday'] = df_stamp.date.apply(lambda row: row.weekday(), 1)
|
||||
df_stamp['hour'] = df_stamp.date.apply(lambda row: row.hour, 1)
|
||||
df_stamp['minute'] = df_stamp.date.apply(lambda row: row.minute, 1)
|
||||
df_stamp['minute'] = df_stamp.minute.map(lambda x: x // 15)
|
||||
data_stamp = df_stamp.drop(['date'], 1).values
|
||||
elif self.timeenc == 1:
|
||||
data_stamp = time_features(pd.to_datetime(df_stamp['date'].values), freq=self.freq)
|
||||
data_stamp = data_stamp.transpose(1, 0)
|
||||
|
||||
self.data_x = data[border1:border2]
|
||||
if self.inverse:
|
||||
self.data_y = df_data.values[border1:border2]
|
||||
else:
|
||||
self.data_y = data[border1:border2]
|
||||
self.data_stamp = data_stamp
|
||||
|
||||
def __getitem__(self, index):
|
||||
s_begin = index
|
||||
s_end = s_begin + self.seq_len
|
||||
r_begin = s_end - self.label_len
|
||||
r_end = r_begin + self.label_len + self.pred_len
|
||||
|
||||
seq_x = self.data_x[s_begin:s_end]
|
||||
if self.inverse:
|
||||
seq_y = self.data_x[r_begin:r_begin + self.label_len]
|
||||
else:
|
||||
seq_y = self.data_y[r_begin:r_begin + self.label_len]
|
||||
seq_x_mark = self.data_stamp[s_begin:s_end]
|
||||
seq_y_mark = self.data_stamp[r_begin:r_end]
|
||||
|
||||
return seq_x, seq_y, seq_x_mark, seq_y_mark
|
||||
|
||||
def __len__(self):
|
||||
return len(self.data_x) - self.seq_len + 1
|
||||
|
||||
def inverse_transform(self, data):
|
||||
return self.scaler.inverse_transform(data)
|
||||
@@ -0,0 +1,37 @@
|
||||
import os
|
||||
import torch
|
||||
import numpy as np
|
||||
|
||||
|
||||
class Exp_Basic(object):
|
||||
def __init__(self, args):
|
||||
self.args = args
|
||||
self.device = self._acquire_device()
|
||||
self.model = self._build_model().to(self.device)
|
||||
|
||||
def _build_model(self):
|
||||
raise NotImplementedError
|
||||
return None
|
||||
|
||||
def _acquire_device(self):
|
||||
if self.args.use_gpu:
|
||||
os.environ["CUDA_VISIBLE_DEVICES"] = str(
|
||||
self.args.gpu) if not self.args.use_multi_gpu else self.args.devices
|
||||
device = torch.device('cuda:{}'.format(self.args.gpu))
|
||||
print('Use GPU: cuda:{}'.format(self.args.gpu))
|
||||
else:
|
||||
device = torch.device('cpu')
|
||||
print('Use CPU')
|
||||
return device
|
||||
|
||||
def _get_data(self):
|
||||
pass
|
||||
|
||||
def vali(self):
|
||||
pass
|
||||
|
||||
def train(self):
|
||||
pass
|
||||
|
||||
def test(self):
|
||||
pass
|
||||
+240
@@ -0,0 +1,240 @@
|
||||
from models.ETSformer.model import ETSformer
|
||||
from data_provider.data_factory import data_provider
|
||||
from exp.exp_basic import Exp_Basic
|
||||
from utils.tools import EarlyStopping, adjust_learning_rate
|
||||
from utils.metrics import metric
|
||||
from utils.Adam import Adam
|
||||
|
||||
import numpy as np
|
||||
import torch
|
||||
import torch.nn as nn
|
||||
|
||||
import os
|
||||
import time
|
||||
|
||||
import warnings
|
||||
import numpy as np
|
||||
|
||||
warnings.filterwarnings('ignore')
|
||||
|
||||
|
||||
class Exp_Main(Exp_Basic):
|
||||
def __init__(self, args):
|
||||
super(Exp_Main, self).__init__(args)
|
||||
|
||||
def _build_model(self):
|
||||
model_dict = {
|
||||
'ETSformer': ETSformer,
|
||||
}
|
||||
model = model_dict[self.args.model](self.args).float()
|
||||
|
||||
if self.args.use_multi_gpu and self.args.use_gpu:
|
||||
model = nn.DataParallel(model, device_ids=self.args.device_ids)
|
||||
return model
|
||||
|
||||
def _get_data(self, flag):
|
||||
data_set, data_loader = data_provider(self.args, flag)
|
||||
return data_set, data_loader
|
||||
|
||||
def _select_optimizer(self):
|
||||
if 'warmup' in self.args.lradj:
|
||||
lr = self.args.min_lr
|
||||
else:
|
||||
lr = self.args.learning_rate
|
||||
|
||||
if self.args.smoothing_learning_rate > 0:
|
||||
smoothing_lr = self.args.smoothing_learning_rate
|
||||
else:
|
||||
smoothing_lr = 100 * self.args.learning_rate
|
||||
|
||||
if self.args.damping_learning_rate > 0:
|
||||
damping_lr = self.args.damping_learning_rate
|
||||
else:
|
||||
damping_lr = 100 * self.args.learning_rate
|
||||
|
||||
nn_params = []
|
||||
smoothing_params = []
|
||||
damping_params = []
|
||||
for k, v in self.model.named_parameters():
|
||||
if k[-len('_smoothing_weight'):] == '_smoothing_weight':
|
||||
smoothing_params.append(v)
|
||||
elif k[-len('_damping_factor'):] == '_damping_factor':
|
||||
damping_params.append(v)
|
||||
else:
|
||||
nn_params.append(v)
|
||||
|
||||
model_optim = Adam([
|
||||
{'params': nn_params, 'lr': lr, 'name': 'nn'},
|
||||
{'params': smoothing_params, 'lr': smoothing_lr, 'name': 'smoothing'},
|
||||
{'params': damping_params, 'lr': damping_lr, 'name': 'damping'},
|
||||
])
|
||||
|
||||
return model_optim
|
||||
|
||||
def _select_criterion(self):
|
||||
criterion = nn.MSELoss()
|
||||
return criterion
|
||||
|
||||
def vali(self, vali_data, vali_loader, criterion):
|
||||
total_loss = []
|
||||
self.model.eval()
|
||||
with torch.no_grad():
|
||||
for i, (batch_x, batch_y, batch_x_mark, batch_y_mark) in enumerate(vali_loader):
|
||||
batch_x = batch_x.float().to(self.device)
|
||||
batch_y = batch_y.float()
|
||||
|
||||
batch_x_mark = batch_x_mark.float().to(self.device)
|
||||
batch_y_mark = batch_y_mark.float().to(self.device)
|
||||
|
||||
# decoder input
|
||||
dec_inp = torch.zeros_like(batch_y[:, -self.args.pred_len:, :]).float()
|
||||
dec_inp = torch.cat([batch_y[:, :self.args.label_len, :], dec_inp], dim=1).float().to(self.device)
|
||||
# encoder - decoder
|
||||
outputs = self.model(batch_x, batch_x_mark, dec_inp, batch_y_mark)
|
||||
f_dim = -1 if self.args.features == 'MS' else 0
|
||||
batch_y = batch_y[:, -self.args.pred_len:, f_dim:].to(self.device)
|
||||
|
||||
pred = outputs.detach().cpu()
|
||||
true = batch_y.detach().cpu()
|
||||
|
||||
loss = criterion(pred, true)
|
||||
|
||||
total_loss.append(loss)
|
||||
total_loss = np.average(total_loss)
|
||||
self.model.train()
|
||||
return total_loss
|
||||
|
||||
def train(self, setting):
|
||||
train_data, train_loader = self._get_data(flag='train')
|
||||
vali_data, vali_loader = self._get_data(flag='val')
|
||||
test_data, test_loader = self._get_data(flag='test')
|
||||
|
||||
path = os.path.join(self.args.checkpoints, setting)
|
||||
if not os.path.exists(path):
|
||||
os.makedirs(path)
|
||||
|
||||
time_now = time.time()
|
||||
|
||||
train_steps = len(train_loader)
|
||||
early_stopping = EarlyStopping(patience=self.args.patience, verbose=True)
|
||||
|
||||
model_optim = self._select_optimizer()
|
||||
criterion = self._select_criterion()
|
||||
|
||||
for epoch in range(self.args.train_epochs):
|
||||
iter_count = 0
|
||||
train_loss = []
|
||||
|
||||
self.model.train()
|
||||
epoch_time = time.time()
|
||||
for i, (batch_x, batch_y, batch_x_mark, batch_y_mark) in enumerate(train_loader):
|
||||
iter_count += 1
|
||||
model_optim.zero_grad()
|
||||
batch_x = batch_x.float().to(self.device)
|
||||
|
||||
batch_y = batch_y.float().to(self.device)
|
||||
batch_x_mark = batch_x_mark.float().to(self.device)
|
||||
batch_y_mark = batch_y_mark.float().to(self.device)
|
||||
|
||||
# decoder input
|
||||
dec_inp = torch.zeros_like(batch_y[:, -self.args.pred_len:, :]).float()
|
||||
dec_inp = torch.cat([batch_y[:, :self.args.label_len, :], dec_inp], dim=1).float().to(self.device)
|
||||
|
||||
# encoder - decoder
|
||||
outputs = self.model(batch_x, batch_x_mark, dec_inp, batch_y_mark)
|
||||
|
||||
f_dim = -1 if self.args.features == 'MS' else 0
|
||||
batch_y = batch_y[:, -self.args.pred_len:, f_dim:].to(self.device)
|
||||
loss = criterion(outputs, batch_y)
|
||||
train_loss.append(loss.item())
|
||||
|
||||
if (i + 1) % 100 == 0:
|
||||
print("\titers: {0}, epoch: {1} | loss: {2:.7f}".format(i + 1, epoch + 1, loss.item()))
|
||||
speed = (time.time() - time_now) / iter_count
|
||||
left_time = speed * ((self.args.train_epochs - epoch) * train_steps - i)
|
||||
print('\tspeed: {:.4f}s/iter; left time: {:.4f}s'.format(speed, left_time))
|
||||
iter_count = 0
|
||||
time_now = time.time()
|
||||
|
||||
loss.backward()
|
||||
torch.nn.utils.clip_grad_norm(self.model.parameters(), 1.0)
|
||||
model_optim.step()
|
||||
|
||||
print("Epoch: {} cost time: {}".format(epoch + 1, time.time() - epoch_time))
|
||||
train_loss = np.average(train_loss)
|
||||
vali_loss = self.vali(vali_data, vali_loader, criterion)
|
||||
test_loss = self.vali(test_data, test_loader, criterion)
|
||||
|
||||
print("Epoch: {0}, Steps: {1} | Train Loss: {2:.7f} Vali Loss: {3:.7f} Test Loss: {4:.7f}".format(
|
||||
epoch + 1, train_steps, train_loss, vali_loss, test_loss))
|
||||
early_stopping(vali_loss, self.model, path)
|
||||
if early_stopping.early_stop:
|
||||
print("Early stopping")
|
||||
break
|
||||
|
||||
adjust_learning_rate(model_optim, epoch + 1, self.args)
|
||||
|
||||
best_model_path = path + '/' + 'checkpoint.pth'
|
||||
self.model.load_state_dict(torch.load(best_model_path))
|
||||
|
||||
return self.model
|
||||
|
||||
def test(self, setting, data, save_vals=False):
|
||||
"""data - 'val' or 'test' """
|
||||
test_data, test_loader = self._get_data(flag=data)
|
||||
|
||||
print('loading model')
|
||||
self.model.load_state_dict(torch.load(os.path.join('./checkpoints/' + setting, 'checkpoint.pth')))
|
||||
|
||||
preds = []
|
||||
trues = []
|
||||
|
||||
self.model.eval()
|
||||
with torch.no_grad():
|
||||
for i, (batch_x, batch_y, batch_x_mark, batch_y_mark) in enumerate(test_loader):
|
||||
batch_x = batch_x.float().to(self.device)
|
||||
batch_y = batch_y.float().to(self.device)
|
||||
|
||||
batch_x_mark = batch_x_mark.float().to(self.device)
|
||||
batch_y_mark = batch_y_mark.float().to(self.device)
|
||||
|
||||
# decoder input
|
||||
dec_inp = torch.zeros_like(batch_y[:, -self.args.pred_len:, :]).float()
|
||||
dec_inp = torch.cat([batch_y[:, :self.args.label_len, :], dec_inp], dim=1).float().to(self.device)
|
||||
# encoder - decoder
|
||||
outputs = self.model(batch_x, batch_x_mark, dec_inp, batch_y_mark)
|
||||
|
||||
f_dim = -1 if self.args.features == 'MS' else 0
|
||||
outputs = outputs[:, -self.args.pred_len:, f_dim:]
|
||||
batch_y = batch_y[:, -self.args.pred_len:, f_dim:].to(self.device)
|
||||
outputs = outputs.detach().cpu().numpy()
|
||||
batch_y = batch_y.detach().cpu().numpy()
|
||||
|
||||
pred = outputs # outputs.detach().cpu().numpy() # .squeeze()
|
||||
true = batch_y # batch_y.detach().cpu().numpy() # .squeeze()
|
||||
|
||||
preds.append(pred)
|
||||
trues.append(true)
|
||||
|
||||
preds = np.array(preds)
|
||||
trues = np.array(trues)
|
||||
print('test shape:', preds.shape, trues.shape)
|
||||
preds = preds.reshape(-1, preds.shape[-2], preds.shape[-1])
|
||||
trues = trues.reshape(-1, trues.shape[-2], trues.shape[-1])
|
||||
print('test shape:', preds.shape, trues.shape)
|
||||
|
||||
# result save
|
||||
folder_path = './results/' + setting + '/'
|
||||
if not os.path.exists(folder_path):
|
||||
os.makedirs(folder_path)
|
||||
|
||||
mae, mse, rmse, mape, mspe = metric(preds, trues)
|
||||
print('mse:{}, mae:{}'.format(mse, mae))
|
||||
|
||||
np.save(folder_path + f'{data}_metrics.npy', np.array([mae, mse, rmse, mape, mspe]))
|
||||
|
||||
if save_vals:
|
||||
np.save(folder_path + 'pred.npy', preds)
|
||||
np.save(folder_path + 'true.npy', trues)
|
||||
|
||||
return
|
||||
@@ -0,0 +1,74 @@
|
||||
import torch
|
||||
import torch.nn as nn
|
||||
from einops import rearrange, reduce, repeat
|
||||
|
||||
|
||||
class DampingLayer(nn.Module):
|
||||
|
||||
def __init__(self, d_model, pred_len, nhead, dropout=0.1):
|
||||
super().__init__()
|
||||
self.pred_len = pred_len
|
||||
self.nhead = nhead
|
||||
self._damping_factor = nn.Parameter(torch.randn(1, nhead))
|
||||
self.dropout = nn.Dropout(dropout)
|
||||
|
||||
def forward(self, x):
|
||||
x = repeat(x, 'B () D -> B T D', T=self.pred_len)
|
||||
B, T, D = x.shape
|
||||
|
||||
powers = torch.arange(self.pred_len).to(self._damping_factor.device) + 1
|
||||
powers = powers.view(self.pred_len, 1)
|
||||
damping_factors = self.damping_factor ** powers
|
||||
damping_factors = damping_factors.cumsum(dim=0)
|
||||
x = x.view(B, T, self.nhead, -1)
|
||||
x = self.dropout(x) * damping_factors.unsqueeze(-1)
|
||||
return x.view(B, T, D)
|
||||
|
||||
@property
|
||||
def damping_factor(self):
|
||||
return torch.sigmoid(self._damping_factor)
|
||||
|
||||
|
||||
class DecoderLayer(nn.Module):
|
||||
|
||||
def __init__(self, d_model, nhead, c_out, pred_len, dropout=0.1):
|
||||
super().__init__()
|
||||
self.d_model = d_model
|
||||
self.nhead = nhead
|
||||
self.c_out = c_out
|
||||
self.pred_len = pred_len
|
||||
|
||||
self.growth_damping = DampingLayer(d_model, pred_len, nhead, dropout=dropout)
|
||||
self.dropout1 = nn.Dropout(dropout)
|
||||
|
||||
def forward(self, growth, season):
|
||||
growth_horizon = self.growth_damping(growth[:, -1:])
|
||||
growth_horizon = self.dropout1(growth_horizon)
|
||||
|
||||
seasonal_horizon = season[:, -self.pred_len:]
|
||||
return growth_horizon, seasonal_horizon
|
||||
|
||||
|
||||
class Decoder(nn.Module):
|
||||
|
||||
def __init__(self, layers):
|
||||
super().__init__()
|
||||
self.d_model = layers[0].d_model
|
||||
self.c_out = layers[0].c_out
|
||||
self.pred_len = layers[0].pred_len
|
||||
self.nhead = layers[0].nhead
|
||||
|
||||
self.layers = nn.ModuleList(layers)
|
||||
self.pred = nn.Linear(self.d_model, self.c_out)
|
||||
|
||||
def forward(self, growths, seasons):
|
||||
growth_repr = []
|
||||
season_repr = []
|
||||
|
||||
for idx, layer in enumerate(self.layers):
|
||||
growth_horizon, season_horizon = layer(growths[idx], seasons[idx])
|
||||
growth_repr.append(growth_horizon)
|
||||
season_repr.append(season_horizon)
|
||||
growth_repr = sum(growth_repr)
|
||||
season_repr = sum(season_repr)
|
||||
return self.pred(growth_repr), self.pred(season_repr)
|
||||
@@ -0,0 +1,172 @@
|
||||
import torch
|
||||
import torch.nn as nn
|
||||
import torch.nn.functional as F
|
||||
import torch.fft as fft
|
||||
|
||||
from einops import rearrange, reduce, repeat
|
||||
import math, random
|
||||
|
||||
from .modules import Feedforward
|
||||
from .exponential_smoothing import ExponentialSmoothing
|
||||
|
||||
|
||||
class GrowthLayer(nn.Module):
|
||||
|
||||
def __init__(self, d_model, nhead, d_head=None, dropout=0.1):
|
||||
super().__init__()
|
||||
self.d_head = d_head or (d_model // nhead)
|
||||
self.d_model = d_model
|
||||
self.nhead = nhead
|
||||
|
||||
self.z0 = nn.Parameter(torch.randn(self.nhead, self.d_head))
|
||||
self.in_proj = nn.Linear(self.d_model, self.d_head * self.nhead)
|
||||
self.es = ExponentialSmoothing(self.d_head, self.nhead, dropout=dropout)
|
||||
self.out_proj = nn.Linear(self.d_head * self.nhead, self.d_model)
|
||||
|
||||
assert self.d_head * self.nhead == self.d_model, "d_model must be divisible by nhead"
|
||||
|
||||
def forward(self, inputs):
|
||||
"""
|
||||
:param inputs: shape: (batch, seq_len, dim)
|
||||
:return: shape: (batch, seq_len, dim)
|
||||
"""
|
||||
B, T, D = inputs.shape
|
||||
values = self.in_proj(inputs).view(B, T, self.nhead, -1)
|
||||
values = torch.cat([repeat(self.z0, 'H D -> B () H D', B=B), values], dim=1)
|
||||
values = values[:, 1:] - values[:, :-1]
|
||||
out = self.es(values)
|
||||
out = torch.cat([repeat(self.es.v0, 'H D -> B () H D', B=B), out], dim=1)
|
||||
out = rearrange(out, 'B T H D -> B T (H D)')
|
||||
return self.out_proj(out)
|
||||
|
||||
|
||||
class FourierLayer(nn.Module):
|
||||
|
||||
def __init__(self, d_model, pred_len, k=None, low_freq=1):
|
||||
super().__init__()
|
||||
self.d_model = d_model
|
||||
self.pred_len = pred_len
|
||||
self.k = k
|
||||
self.low_freq = low_freq
|
||||
|
||||
def forward(self, x):
|
||||
"""x: (B T D)"""
|
||||
B, T, D = x.shape
|
||||
x_freq = fft.rfft(x, dim=1)
|
||||
|
||||
if T % 2 == 0:
|
||||
x_freq = x_freq[:, self.low_freq:-1]
|
||||
f = fft.rfftfreq(T)[self.low_freq:-1]
|
||||
else:
|
||||
x_freq = x_freq[:, self.low_freq:]
|
||||
f = fft.rfftfreq(T)[self.low_freq:]
|
||||
|
||||
x_freq, index_tuple = self.topk_freq(x_freq)
|
||||
f = repeat(f, 'F -> B F D', B=x_freq.size(0), D=x_freq.size(2))
|
||||
f = rearrange(f[index_tuple], 'B F D -> B F () D').to(x_freq.device)
|
||||
|
||||
return self.extrapolate(x_freq, f, T)
|
||||
|
||||
def extrapolate(self, x_freq, f, T):
|
||||
x_freq = torch.cat([x_freq, x_freq.conj()], dim=1)
|
||||
f = torch.cat([f, -f], dim=1)
|
||||
t = rearrange(torch.arange(T + self.pred_len, dtype=torch.float),
|
||||
'T -> () () T ()').to(x_freq.device)
|
||||
|
||||
amp = rearrange(x_freq.abs() / T, 'B F D -> B F () D')
|
||||
phase = rearrange(x_freq.angle(), 'B F D -> B F () D')
|
||||
|
||||
x_time = amp * torch.cos(2 * math.pi * f * t + phase)
|
||||
|
||||
return reduce(x_time, 'B F T D -> B T D', 'sum')
|
||||
|
||||
def topk_freq(self, x_freq):
|
||||
values, indices = torch.topk(x_freq.abs(), self.k, dim=1, largest=True, sorted=True)
|
||||
mesh_a, mesh_b = torch.meshgrid(torch.arange(x_freq.size(0)), torch.arange(x_freq.size(2)))
|
||||
index_tuple = (mesh_a.unsqueeze(1), indices, mesh_b.unsqueeze(1))
|
||||
x_freq = x_freq[index_tuple]
|
||||
|
||||
return x_freq, index_tuple
|
||||
|
||||
|
||||
class LevelLayer(nn.Module):
|
||||
|
||||
def __init__(self, d_model, c_out, dropout=0.1):
|
||||
super().__init__()
|
||||
self.d_model = d_model
|
||||
self.c_out = c_out
|
||||
|
||||
self.es = ExponentialSmoothing(1, self.c_out, dropout=dropout, aux=True)
|
||||
self.growth_pred = nn.Linear(self.d_model, self.c_out)
|
||||
self.season_pred = nn.Linear(self.d_model, self.c_out)
|
||||
|
||||
def forward(self, level, growth, season):
|
||||
B, T, _ = level.shape
|
||||
growth = self.growth_pred(growth).view(B, T, self.c_out, 1)
|
||||
season = self.season_pred(season).view(B, T, self.c_out, 1)
|
||||
growth = growth.view(B, T, self.c_out, 1)
|
||||
season = season.view(B, T, self.c_out, 1)
|
||||
level = level.view(B, T, self.c_out, 1)
|
||||
out = self.es(level - season, aux_values=growth)
|
||||
out = rearrange(out, 'B T H D -> B T (H D)')
|
||||
return out
|
||||
|
||||
class EncoderLayer(nn.Module):
|
||||
|
||||
def __init__(self, d_model, nhead, c_out, pred_len, k, dim_feedforward=None, dropout=0.1,
|
||||
activation='sigmoid', layer_norm_eps=1e-5):
|
||||
super().__init__()
|
||||
self.d_model = d_model
|
||||
self.nhead = nhead
|
||||
self.c_out = c_out
|
||||
self.pred_len = pred_len
|
||||
dim_feedforward = dim_feedforward or 4 * d_model
|
||||
self.dim_feedforward = dim_feedforward
|
||||
|
||||
self.growth_layer = GrowthLayer(d_model, nhead, dropout=dropout)
|
||||
self.seasonal_layer = FourierLayer(d_model, pred_len, k=k)
|
||||
self.level_layer = LevelLayer(d_model, c_out, dropout=dropout)
|
||||
|
||||
# Implementation of Feedforward model
|
||||
self.ff = Feedforward(d_model, dim_feedforward, dropout=dropout, activation=activation)
|
||||
self.norm1 = nn.LayerNorm(d_model, eps=layer_norm_eps)
|
||||
self.norm2 = nn.LayerNorm(d_model, eps=layer_norm_eps)
|
||||
|
||||
self.dropout1 = nn.Dropout(dropout)
|
||||
self.dropout2 = nn.Dropout(dropout)
|
||||
|
||||
def forward(self, res, level, attn_mask=None):
|
||||
season = self._season_block(res)
|
||||
res = res - season[:, :-self.pred_len]
|
||||
growth = self._growth_block(res)
|
||||
res = self.norm1(res - growth[:, 1:])
|
||||
res = self.norm2(res + self.ff(res))
|
||||
|
||||
level = self.level_layer(level, growth[:, :-1], season[:, :-self.pred_len])
|
||||
|
||||
return res, level, growth, season
|
||||
|
||||
def _growth_block(self, x):
|
||||
x = self.growth_layer(x)
|
||||
return self.dropout1(x)
|
||||
|
||||
def _season_block(self, x):
|
||||
x = self.seasonal_layer(x)
|
||||
return self.dropout2(x)
|
||||
|
||||
|
||||
class Encoder(nn.Module):
|
||||
|
||||
def __init__(self, layers):
|
||||
super().__init__()
|
||||
self.layers = nn.ModuleList(layers)
|
||||
|
||||
def forward(self, res, level, attn_mask=None):
|
||||
growths = []
|
||||
seasons = []
|
||||
for layer in self.layers:
|
||||
res, level, growth, season = layer(res, level, attn_mask=None)
|
||||
growths.append(growth)
|
||||
seasons.append(season)
|
||||
|
||||
return level, growths, seasons
|
||||
@@ -0,0 +1,67 @@
|
||||
import torch
|
||||
import torch.nn as nn
|
||||
import torch.fft as fft
|
||||
|
||||
from einops import rearrange, reduce, repeat
|
||||
from scipy.fftpack import next_fast_len
|
||||
|
||||
|
||||
def conv1d_fft(f, g, dim=-1):
|
||||
N = f.size(dim)
|
||||
M = g.size(dim)
|
||||
|
||||
fast_len = next_fast_len(N + M - 1)
|
||||
|
||||
F_f = fft.rfft(f, fast_len, dim=dim)
|
||||
F_g = fft.rfft(g, fast_len, dim=dim)
|
||||
|
||||
F_fg = F_f * F_g.conj()
|
||||
out = fft.irfft(F_fg, fast_len, dim=dim)
|
||||
out = out.roll((-1,), dims=(dim,))
|
||||
idx = torch.as_tensor(range(fast_len - N, fast_len)).to(out.device)
|
||||
out = out.index_select(dim, idx)
|
||||
|
||||
return out
|
||||
|
||||
|
||||
class ExponentialSmoothing(nn.Module):
|
||||
|
||||
def __init__(self, dim, nhead, dropout=0.1, aux=False):
|
||||
super().__init__()
|
||||
self._smoothing_weight = nn.Parameter(torch.randn(nhead, 1))
|
||||
self.v0 = nn.Parameter(torch.randn(nhead, dim))
|
||||
self.dropout = nn.Dropout(dropout)
|
||||
if aux:
|
||||
self.aux_dropout = nn.Dropout(dropout)
|
||||
|
||||
def forward(self, values, aux_values=None):
|
||||
B, T, H, D = values.shape
|
||||
|
||||
init_weight, weight = self.get_exponential_weight(T)
|
||||
output = conv1d_fft(self.dropout(values), weight, dim=1)
|
||||
v0 = repeat(self.v0, 'H D -> () () H D')
|
||||
output = init_weight * v0 + output
|
||||
|
||||
if aux_values is not None:
|
||||
aux_weight = weight / (1 - self.weight) * self.weight
|
||||
aux_output = conv1d_fft(self.aux_dropout(aux_values), aux_weight)
|
||||
output = output + aux_output
|
||||
|
||||
return output
|
||||
|
||||
def get_exponential_weight(self, T):
|
||||
# Generate array [0, 1, ..., T-1]
|
||||
powers = torch.arange(T, dtype=torch.float, device=self.weight.device)
|
||||
|
||||
# (1 - \alpha) * \alpha^t, for all t = T-1, T-2, ..., 0]
|
||||
weight = (1 - self.weight) * (self.weight ** torch.flip(powers, dims=(0,)))
|
||||
|
||||
# \alpha^t for all t = 1, 2, ..., T
|
||||
init_weight = self.weight ** (powers + 1)
|
||||
|
||||
return rearrange(init_weight, 'H T -> () T H ()'), \
|
||||
rearrange(weight, 'H T -> () T H ()')
|
||||
|
||||
@property
|
||||
def weight(self):
|
||||
return torch.sigmoid(self._smoothing_weight)
|
||||
@@ -0,0 +1,76 @@
|
||||
import torch
|
||||
import torch.nn as nn
|
||||
|
||||
from .modules import ETSEmbedding
|
||||
from .encoder import EncoderLayer, Encoder
|
||||
from .decoder import DecoderLayer, Decoder
|
||||
|
||||
|
||||
class Transform:
|
||||
def __init__(self, sigma):
|
||||
self.sigma = sigma
|
||||
|
||||
@torch.no_grad()
|
||||
def transform(self, x):
|
||||
return self.jitter(self.shift(self.scale(x)))
|
||||
|
||||
def jitter(self, x):
|
||||
return x + (torch.randn(x.shape).to(x.device) * self.sigma)
|
||||
|
||||
def scale(self, x):
|
||||
return x * (torch.randn(x.size(-1)).to(x.device) * self.sigma + 1)
|
||||
|
||||
def shift(self, x):
|
||||
return x + (torch.randn(x.size(-1)).to(x.device) * self.sigma)
|
||||
|
||||
|
||||
class ETSformer(nn.Module):
|
||||
|
||||
def __init__(self, configs):
|
||||
super().__init__()
|
||||
self.seq_len = configs.seq_len
|
||||
self.label_len = configs.label_len
|
||||
self.pred_len = configs.pred_len
|
||||
|
||||
self.configs = configs
|
||||
|
||||
assert configs.d_layers == configs.e_layers
|
||||
|
||||
# Embedding
|
||||
self.enc_embedding = ETSEmbedding(configs.enc_in, configs.d_model, dropout=configs.dropout)
|
||||
|
||||
# Encoder
|
||||
self.encoder = Encoder(
|
||||
[
|
||||
EncoderLayer(
|
||||
configs.d_model, configs.n_heads, configs.c_out, configs.pred_len, configs.K,
|
||||
dim_feedforward=configs.d_ff,
|
||||
dropout=configs.dropout,
|
||||
activation=configs.activation,
|
||||
) for _ in range(configs.e_layers)
|
||||
]
|
||||
)
|
||||
|
||||
# Decoder
|
||||
self.decoder = Decoder(
|
||||
[
|
||||
DecoderLayer(
|
||||
configs.d_model, configs.n_heads, configs.c_out, configs.pred_len,
|
||||
dropout=configs.dropout,
|
||||
) for _ in range(configs.d_layers)
|
||||
],
|
||||
)
|
||||
|
||||
self.transform = Transform(sigma=self.configs.std)
|
||||
|
||||
def forward(self, x_enc, x_mark_enc, x_dec, x_mark_dec,
|
||||
enc_self_mask=None, dec_self_mask=None, dec_enc_mask=None):
|
||||
with torch.no_grad():
|
||||
if self.training:
|
||||
x_enc = self.transform.transform(x_enc)
|
||||
res = self.enc_embedding(x_enc)
|
||||
level, growths, seasons = self.encoder(res, x_enc, attn_mask=enc_self_mask)
|
||||
|
||||
growth, season = self.decoder(growths, seasons)
|
||||
preds = level[:, -1:] + growth + season
|
||||
return preds
|
||||
@@ -0,0 +1,30 @@
|
||||
import torch.nn as nn
|
||||
import torch.nn.functional as F
|
||||
|
||||
|
||||
class ETSEmbedding(nn.Module):
|
||||
def __init__(self, c_in, d_model, dropout=0.1):
|
||||
super().__init__()
|
||||
self.conv = nn.Conv1d(in_channels=c_in, out_channels=d_model,
|
||||
kernel_size=3, padding=2, bias=False)
|
||||
self.dropout = nn.Dropout(p=dropout)
|
||||
nn.init.kaiming_normal_(self.conv.weight)
|
||||
|
||||
def forward(self, x,):
|
||||
x = self.conv(x.permute(0,2,1))[..., :-2]
|
||||
return self.dropout(x.transpose(1,2))
|
||||
|
||||
|
||||
class Feedforward(nn.Module):
|
||||
def __init__(self, d_model, dim_feedforward, dropout=0.1, activation='sigmoid'):
|
||||
# Implementation of Feedforward model
|
||||
super().__init__()
|
||||
self.linear1 = nn.Linear(d_model, dim_feedforward, bias=False)
|
||||
self.dropout1 = nn.Dropout(dropout)
|
||||
self.linear2 = nn.Linear(dim_feedforward, d_model, bias=False)
|
||||
self.dropout2 = nn.Dropout(dropout)
|
||||
self.activation = getattr(F, activation)
|
||||
|
||||
def forward(self, x):
|
||||
x = self.linear2(self.dropout1(self.activation(self.linear1(x))))
|
||||
return self.dropout2(x)
|
||||
@@ -0,0 +1,8 @@
|
||||
matplotlib==3.5.1
|
||||
numpy ==1.19.2
|
||||
pandas==1.4.2
|
||||
scikit-learn==1.0.2
|
||||
scipy==1.7.3
|
||||
torch==1.11.0
|
||||
tqdm==4.62.3
|
||||
einops==0.4.1
|
||||
@@ -0,0 +1,123 @@
|
||||
import argparse
|
||||
import os
|
||||
import torch
|
||||
from exp.exp_main import Exp_Main
|
||||
import random
|
||||
import numpy as np
|
||||
|
||||
|
||||
def set_seed(seed):
|
||||
random.seed(seed)
|
||||
seed += 1
|
||||
np.random.seed(seed)
|
||||
seed += 1
|
||||
torch.manual_seed(seed)
|
||||
|
||||
parser = argparse.ArgumentParser(description='ETSformer: Exponential Smoothing Transformers for Time-series Forecasting')
|
||||
|
||||
# basic config
|
||||
parser.add_argument('--model_id', type=str, required=True, default='test', help='model id')
|
||||
parser.add_argument('--model', type=str, required=True, default='ETSformer',
|
||||
help='model name, options: [ETSformer]')
|
||||
|
||||
# data loader
|
||||
parser.add_argument('--data', type=str, required=True, default='ETTm1', help='dataset type')
|
||||
parser.add_argument('--root_path', type=str, default='./data/ETT/', help='root path of the data file')
|
||||
parser.add_argument('--data_path', type=str, default='ETTh1.csv', help='data file')
|
||||
parser.add_argument('--features', type=str, default='M',
|
||||
help='forecasting task, options:[M, S, MS]; M:multivariate predict multivariate, S:univariate predict univariate, MS:multivariate predict univariate')
|
||||
parser.add_argument('--target', type=str, default='OT', help='target feature in S or MS task')
|
||||
parser.add_argument('--freq', type=str, default='h',
|
||||
help='freq for time features encoding, options:[s:secondly, t:minutely, h:hourly, d:daily, b:business days, w:weekly, m:monthly], you can also use more detailed freq like 15min or 3h')
|
||||
parser.add_argument('--checkpoints', type=str, default='./checkpoints/', help='location of model checkpoints')
|
||||
|
||||
# forecasting task
|
||||
parser.add_argument('--seq_len', type=int, required=True, help='input sequence length')
|
||||
parser.add_argument('--label_len', type=int, default=0, help='start token length')
|
||||
parser.add_argument('--pred_len', type=int, required=True, help='prediction sequence length')
|
||||
|
||||
# model define
|
||||
parser.add_argument('--enc_in', type=int, default=7, help='encoder input size')
|
||||
parser.add_argument('--dec_in', type=int, default=7, help='decoder input size')
|
||||
parser.add_argument('--c_out', type=int, default=7, help='output size')
|
||||
parser.add_argument('--d_model', type=int, default=512, help='dimension of model')
|
||||
parser.add_argument('--n_heads', type=int, default=8, help='num of heads')
|
||||
parser.add_argument('--e_layers', type=int, default=2, help='num of encoder layers')
|
||||
parser.add_argument('--d_layers', type=int, default=1, help='num of decoder layers')
|
||||
parser.add_argument('--d_ff', type=int, default=2048, help='dimension of fcn')
|
||||
parser.add_argument('--K', type=int, default=1, help='Top-K Fourier bases')
|
||||
parser.add_argument('--dropout', type=float, default=0.2, help='dropout')
|
||||
parser.add_argument('--embed', type=str, default='timeF',
|
||||
help='time features encoding, options:[timeF, fixed, learned]')
|
||||
parser.add_argument('--activation', type=str, default='sigmoid', help='activation')
|
||||
|
||||
parser.add_argument('--min_lr', type=float, default=1e-30)
|
||||
parser.add_argument('--warmup_epochs', type=int, default=3)
|
||||
parser.add_argument('--std', type=float, default=0.2)
|
||||
|
||||
parser.add_argument('--smoothing_learning_rate', type=float, default=0, help='optimizer learning rate')
|
||||
parser.add_argument('--damping_learning_rate', type=float, default=0, help='optimizer learning rate')
|
||||
|
||||
# optimization
|
||||
parser.add_argument('--optim', type=str, default='adam', help='optimizer')
|
||||
parser.add_argument('--num_workers', type=int, default=10, help='data loader num workers')
|
||||
parser.add_argument('--itr', type=int, default=1, help='experiments times')
|
||||
parser.add_argument('--train_epochs', type=int, default=15, help='train epochs')
|
||||
parser.add_argument('--batch_size', type=int, default=32, help='batch size of train input data')
|
||||
parser.add_argument('--patience', type=int, default=5, help='early stopping patience')
|
||||
parser.add_argument('--learning_rate', type=float, default=1e-4, help='optimizer learning rate')
|
||||
parser.add_argument('--des', type=str, default='test', help='exp description')
|
||||
parser.add_argument('--lradj', type=str, default='exponential_with_warmup', help='adjust learning rate')
|
||||
|
||||
# GPU
|
||||
parser.add_argument('--use_gpu', type=bool, default=True, help='use gpu')
|
||||
parser.add_argument('--gpu', type=int, default=0, help='gpu')
|
||||
parser.add_argument('--use_multi_gpu', action='store_true', help='use multiple gpus', default=False)
|
||||
parser.add_argument('--devices', type=str, default='0,1,2,3', help='device ids of multile gpus')
|
||||
|
||||
args = parser.parse_args()
|
||||
|
||||
args.use_gpu = True if torch.cuda.is_available() and args.use_gpu else False
|
||||
|
||||
if args.use_gpu and args.use_multi_gpu:
|
||||
args.dvices = args.devices.replace(' ', '')
|
||||
device_ids = args.devices.split(',')
|
||||
args.device_ids = [int(id_) for id_ in device_ids]
|
||||
args.gpu = args.device_ids[0]
|
||||
|
||||
print('Args in experiment:')
|
||||
print(args)
|
||||
|
||||
Exp = Exp_Main
|
||||
|
||||
for ii in range(args.itr):
|
||||
set_seed(ii)
|
||||
# setting record of experiments
|
||||
setting = '{}_{}_{}_ft{}_sl{}_pl{}_dm{}_nh{}_el{}_dl{}_df{}_K{}_lr{}_{}_{}'.format(
|
||||
args.model_id,
|
||||
args.model,
|
||||
args.data,
|
||||
args.features,
|
||||
args.seq_len,
|
||||
args.pred_len,
|
||||
args.d_model,
|
||||
args.n_heads,
|
||||
args.e_layers,
|
||||
args.d_layers,
|
||||
args.d_ff,
|
||||
args.K,
|
||||
args.learning_rate,
|
||||
args.des, ii)
|
||||
|
||||
if os.path.exists(os.path.join(args.checkpoints, setting)):
|
||||
continue
|
||||
|
||||
exp = Exp(args) # set experiments
|
||||
print('>>>>>>>start training : {}>>>>>>>>>>>>>>>>>>>>>>>>>>'.format(setting))
|
||||
exp.train(setting)
|
||||
|
||||
print('>>>>>>>testing : {}<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<'.format(setting))
|
||||
exp.test(setting, data='val')
|
||||
exp.test(setting, data='test')
|
||||
|
||||
torch.cuda.empty_cache()
|
||||
@@ -0,0 +1,77 @@
|
||||
python -u run.py \
|
||||
--root_path ./dataset/electricity/ \
|
||||
--data_path electricity.csv \
|
||||
--model_id ECL \
|
||||
--model ETSformer \
|
||||
--data custom \
|
||||
--features M \
|
||||
--seq_len 336 \
|
||||
--pred_len 96 \
|
||||
--e_layers 2 \
|
||||
--d_layers 2 \
|
||||
--enc_in 321 \
|
||||
--dec_in 321 \
|
||||
--c_out 321 \
|
||||
--des 'Exp' \
|
||||
--K 3 \
|
||||
--learning_rate 3e-4 \
|
||||
--itr 1
|
||||
|
||||
python -u run.py \
|
||||
--root_path ./dataset/electricity/ \
|
||||
--data_path electricity.csv \
|
||||
--model_id ECL \
|
||||
--model ETSformer \
|
||||
--data custom \
|
||||
--features M \
|
||||
--seq_len 336 \
|
||||
--pred_len 192 \
|
||||
--e_layers 2 \
|
||||
--d_layers 2 \
|
||||
--enc_in 321 \
|
||||
--dec_in 321 \
|
||||
--c_out 321 \
|
||||
--des 'Exp' \
|
||||
--K 3 \
|
||||
--learning_rate 3e-4 \
|
||||
--itr 1
|
||||
|
||||
python -u run.py \
|
||||
--is_training 1 \
|
||||
--root_path ./dataset/electricity/ \
|
||||
--data_path electricity.csv \
|
||||
--model_id ECL \
|
||||
--model ETSformer \
|
||||
--data custom \
|
||||
--features M \
|
||||
--seq_len 336 \
|
||||
--pred_len 336 \
|
||||
--e_layers 2 \
|
||||
--d_layers 2 \
|
||||
--enc_in 321 \
|
||||
--dec_in 321 \
|
||||
--c_out 321 \
|
||||
--des 'Exp' \
|
||||
--K 3 \
|
||||
--learning_rate 3e-4 \
|
||||
--itr 1
|
||||
|
||||
python -u run.py \
|
||||
--is_training 1 \
|
||||
--root_path ./dataset/electricity/ \
|
||||
--data_path electricity.csv \
|
||||
--model_id ECL \
|
||||
--model ETSformer \
|
||||
--data custom \
|
||||
--features M \
|
||||
--seq_len 336 \
|
||||
--pred_len 720 \
|
||||
--e_layers 2 \
|
||||
--d_layers 2 \
|
||||
--enc_in 321 \
|
||||
--dec_in 321 \
|
||||
--c_out 321 \
|
||||
--des 'Exp' \
|
||||
--K 3 \
|
||||
--learning_rate 1e-4 \
|
||||
--itr 1
|
||||
@@ -0,0 +1,75 @@
|
||||
python -u run.py \
|
||||
--root_path ./dataset/ETT-small/ \
|
||||
--data_path ETTm2.csv \
|
||||
--model_id ETTm2 \
|
||||
--model ETSformer \
|
||||
--data ETTm2 \
|
||||
--features M \
|
||||
--seq_len 96 \
|
||||
--pred_len 96 \
|
||||
--e_layers 2 \
|
||||
--d_layers 2 \
|
||||
--enc_in 7 \
|
||||
--dec_in 7 \
|
||||
--c_out 7 \
|
||||
--des 'Exp' \
|
||||
--K 3 \
|
||||
--learning_rate 1e-5 \
|
||||
--itr 1
|
||||
|
||||
python -u run.py \
|
||||
--root_path ./dataset/ETT-small/ \
|
||||
--data_path ETTm2.csv \
|
||||
--model_id ETTm2 \
|
||||
--model ETSformer \
|
||||
--data ETTm2 \
|
||||
--features M \
|
||||
--seq_len 96 \
|
||||
--pred_len 192 \
|
||||
--e_layers 2 \
|
||||
--d_layers 2 \
|
||||
--enc_in 7 \
|
||||
--dec_in 7 \
|
||||
--c_out 7 \
|
||||
--des 'Exp' \
|
||||
--K 3 \
|
||||
--learning_rate 1e-5 \
|
||||
--itr 1
|
||||
|
||||
python -u run.py \
|
||||
--root_path ./dataset/ETT-small/ \
|
||||
--data_path ETTm2.csv \
|
||||
--model_id ETTm2 \
|
||||
--model ETSformer \
|
||||
--data ETTm2 \
|
||||
--features M \
|
||||
--seq_len 96 \
|
||||
--pred_len 336 \
|
||||
--e_layers 2 \
|
||||
--d_layers 2 \
|
||||
--enc_in 7 \
|
||||
--dec_in 7 \
|
||||
--c_out 7 \
|
||||
--des 'Exp' \
|
||||
--K 3 \
|
||||
--learning_rate 1e-5 \
|
||||
--itr 1
|
||||
|
||||
python -u run.py \
|
||||
--root_path ./dataset/ETT-small/ \
|
||||
--data_path ETTm2.csv \
|
||||
--model_id ETTm2 \
|
||||
--model ETSformer \
|
||||
--data ETTm2 \
|
||||
--features M \
|
||||
--seq_len 96 \
|
||||
--pred_len 720 \
|
||||
--e_layers 2 \
|
||||
--d_layers 2 \
|
||||
--enc_in 7 \
|
||||
--dec_in 7 \
|
||||
--c_out 7 \
|
||||
--des 'Exp' \
|
||||
--K 3 \
|
||||
--learning_rate 1e-5 \
|
||||
--itr 1
|
||||
@@ -0,0 +1,75 @@
|
||||
python -u run.py \
|
||||
--root_path ./dataset/ETT-small/ \
|
||||
--data_path ETTm2.csv \
|
||||
--model_id ETTm2 \
|
||||
--model ETSformer \
|
||||
--data ETTm2 \
|
||||
--features S \
|
||||
--seq_len 96 \
|
||||
--pred_len $96 \
|
||||
--e_layers 2 \
|
||||
--d_layers 2 \
|
||||
--enc_in 1 \
|
||||
--dec_in 1 \
|
||||
--c_out 1 \
|
||||
--des 'Exp' \
|
||||
--K 2 \
|
||||
--learning_rate 1e-5 \
|
||||
--itr 1
|
||||
|
||||
python -u run.py \
|
||||
--root_path ./dataset/ETT-small/ \
|
||||
--data_path ETTm2.csv \
|
||||
--model_id ETTm2 \
|
||||
--model ETSformer \
|
||||
--data ETTm2 \
|
||||
--features S \
|
||||
--seq_len 96 \
|
||||
--pred_len 192 \
|
||||
--e_layers 2 \
|
||||
--d_layers 2 \
|
||||
--enc_in 1 \
|
||||
--dec_in 1 \
|
||||
--c_out 1 \
|
||||
--des 'Exp' \
|
||||
--K 2 \
|
||||
--learning_rate 1e-3 \
|
||||
--itr 1
|
||||
|
||||
python -u run.py \
|
||||
--root_path ./dataset/ETT-small/ \
|
||||
--data_path ETTm2.csv \
|
||||
--model_id ETTm2 \
|
||||
--model ETSformer \
|
||||
--data ETTm2 \
|
||||
--features S \
|
||||
--seq_len 96 \
|
||||
--pred_len 336 \
|
||||
--e_layers 2 \
|
||||
--d_layers 2 \
|
||||
--enc_in 1 \
|
||||
--dec_in 1 \
|
||||
--c_out 1 \
|
||||
--des 'Exp' \
|
||||
--K 1 \
|
||||
--learning_rate 1e-3 \
|
||||
--itr 1
|
||||
|
||||
python -u run.py \
|
||||
--root_path ./dataset/ETT-small/ \
|
||||
--data_path ETTm2.csv \
|
||||
--model_id ETTm2 \
|
||||
--model ETSformer \
|
||||
--data ETTm2 \
|
||||
--features S \
|
||||
--seq_len 720 \
|
||||
--pred_len 720 \
|
||||
--e_layers 2 \
|
||||
--d_layers 2 \
|
||||
--enc_in 1 \
|
||||
--dec_in 1 \
|
||||
--c_out 1 \
|
||||
--des 'Exp' \
|
||||
--K 3 \
|
||||
--learning_rate 3e-4 \
|
||||
--itr 1
|
||||
@@ -0,0 +1,75 @@
|
||||
python -u run.py \
|
||||
--root_path ./dataset/exchange_rate/ \
|
||||
--data_path exchange_rate.csv \
|
||||
--model_id Exchange \
|
||||
--model ETSformer \
|
||||
--data custom \
|
||||
--features M \
|
||||
--seq_len 336 \
|
||||
--pred_len 96 \
|
||||
--e_layers 2 \
|
||||
--d_layers 2 \
|
||||
--enc_in 8 \
|
||||
--dec_in 8 \
|
||||
--c_out 8 \
|
||||
--des 'Exp' \
|
||||
--K 0 \
|
||||
--learning_rate 3e-5 \
|
||||
--itr 1
|
||||
|
||||
python -u run.py \
|
||||
--root_path ./dataset/exchange_rate/ \
|
||||
--data_path exchange_rate.csv \
|
||||
--model_id Exchange \
|
||||
--model ETSformer \
|
||||
--data custom \
|
||||
--features M \
|
||||
--seq_len 720 \
|
||||
--pred_len 192 \
|
||||
--e_layers 2 \
|
||||
--d_layers 2 \
|
||||
--enc_in 8 \
|
||||
--dec_in 8 \
|
||||
--c_out 8 \
|
||||
--des 'Exp' \
|
||||
--K 0 \
|
||||
--learning_rate 1e-4 \
|
||||
--itr 1
|
||||
|
||||
python -u run.py \
|
||||
--root_path ./dataset/exchange_rate/ \
|
||||
--data_path exchange_rate.csv \
|
||||
--model_id Exchange \
|
||||
--model ETSformer \
|
||||
--data custom \
|
||||
--features M \
|
||||
--seq_len 336 \
|
||||
--pred_len 336 \
|
||||
--e_layers 2 \
|
||||
--d_layers 2 \
|
||||
--enc_in 8 \
|
||||
--dec_in 8 \
|
||||
--c_out 8 \
|
||||
--des 'Exp' \
|
||||
--K 0 \
|
||||
--learning_rate 3e-4 \
|
||||
--itr 1
|
||||
|
||||
python -u run.py \
|
||||
--root_path ./dataset/exchange_rate/ \
|
||||
--data_path exchange_rate.csv \
|
||||
--model_id Exchange \
|
||||
--model ETSformer \
|
||||
--data custom \
|
||||
--features M \
|
||||
--seq_len 192 \
|
||||
--pred_len 720 \
|
||||
--e_layers 2 \
|
||||
--d_layers 2 \
|
||||
--enc_in 8 \
|
||||
--dec_in 8 \
|
||||
--c_out 8 \
|
||||
--des 'Exp' \
|
||||
--K 0 \
|
||||
--learning_rate 1e-3 \
|
||||
--itr 1
|
||||
@@ -0,0 +1,76 @@
|
||||
python -u run.py \
|
||||
--root_path ./dataset/exchange_rate/ \
|
||||
--data_path exchange_rate.csv \
|
||||
--model_id Exchange \
|
||||
--model ETSformer \
|
||||
--data custom \
|
||||
--features S \
|
||||
--seq_len 96 \
|
||||
--pred_len 96 \
|
||||
--e_layers 2 \
|
||||
--d_layers 2 \
|
||||
--enc_in 1 \
|
||||
--dec_in 1 \
|
||||
--c_out 1 \
|
||||
--des 'Exp' \
|
||||
--K 0 \
|
||||
--learning_rate 1e-3 \
|
||||
--itr 1
|
||||
|
||||
python -u run.py \
|
||||
--root_path ./dataset/exchange_rate/ \
|
||||
--data_path exchange_rate.csv \
|
||||
--model_id Exchange \
|
||||
--model ETSformer \
|
||||
--data custom \
|
||||
--features S \
|
||||
--seq_len 96 \
|
||||
--pred_len 192 \
|
||||
--e_layers 2 \
|
||||
--d_layers 2 \
|
||||
--enc_in 1 \
|
||||
--dec_in 1 \
|
||||
--c_out 1 \
|
||||
--des 'Exp' \
|
||||
--K 0 \
|
||||
--learning_rate 1e-3 \
|
||||
--itr 1
|
||||
|
||||
python -u run.py \
|
||||
--root_path ./dataset/exchange_rate/ \
|
||||
--data_path exchange_rate.csv \
|
||||
--model_id Exchange \
|
||||
--model ETSformer \
|
||||
--data custom \
|
||||
--features S \
|
||||
--seq_len 192 \
|
||||
--pred_len 336 \
|
||||
--e_layers 2 \
|
||||
--d_layers 2 \
|
||||
--enc_in 1 \
|
||||
--dec_in 1 \
|
||||
--c_out 1 \
|
||||
--des 'Exp' \
|
||||
--K 1 \
|
||||
--learning_rate 3e-4 \
|
||||
--itr 1
|
||||
|
||||
python -u run.py \
|
||||
--root_path ./dataset/exchange_rate/ \
|
||||
--data_path exchange_rate.csv \
|
||||
--model_id Exchange \
|
||||
--model ETSformer \
|
||||
--data custom \
|
||||
--features S \
|
||||
--seq_len 720 \
|
||||
--pred_len 720 \
|
||||
--e_layers 2 \
|
||||
--d_layers 2 \
|
||||
--enc_in 1 \
|
||||
--dec_in 1 \
|
||||
--c_out 1 \
|
||||
--des 'Exp' \
|
||||
--K 1 \
|
||||
--learning_rate 3e-5 \
|
||||
--itr 1
|
||||
|
||||
@@ -0,0 +1,75 @@
|
||||
python -u run.py \
|
||||
--root_path ./dataset/illness/ \
|
||||
--data_path national_illness.csv \
|
||||
--model_id ili \
|
||||
--model ETSformer \
|
||||
--data custom \
|
||||
--features M \
|
||||
--seq_len 48 \
|
||||
--pred_len 24 \
|
||||
--e_layers 2 \
|
||||
--d_layers 2 \
|
||||
--enc_in 7 \
|
||||
--dec_in 7 \
|
||||
--c_out 7 \
|
||||
--des 'Exp' \
|
||||
--K 1 \
|
||||
--learning_rate 1e-3 \
|
||||
--itr 1
|
||||
|
||||
python -u run.py \
|
||||
--root_path ./dataset/illness/ \
|
||||
--data_path national_illness.csv \
|
||||
--model_id ili \
|
||||
--model ETSformer \
|
||||
--data custom \
|
||||
--features M \
|
||||
--seq_len 60 \
|
||||
--pred_len 36 \
|
||||
--e_layers 2 \
|
||||
--d_layers 2 \
|
||||
--enc_in 7 \
|
||||
--dec_in 7 \
|
||||
--c_out 7 \
|
||||
--des 'Exp' \
|
||||
--K 1 \
|
||||
--learning_rate 1e-3 \
|
||||
--itr 1
|
||||
|
||||
python -u run.py \
|
||||
--root_path ./dataset/illness/ \
|
||||
--data_path national_illness.csv \
|
||||
--model_id ili \
|
||||
--model ETSformer \
|
||||
--data custom \
|
||||
--features M \
|
||||
--seq_len 60 \
|
||||
--pred_len 48 \
|
||||
--e_layers 2 \
|
||||
--d_layers 2 \
|
||||
--enc_in 7 \
|
||||
--dec_in 7 \
|
||||
--c_out 7 \
|
||||
--des 'Exp' \
|
||||
--K 1 \
|
||||
--learning_rate 1e-3 \
|
||||
--itr 1
|
||||
|
||||
python -u run.py \
|
||||
--root_path ./dataset/illness/ \
|
||||
--data_path national_illness.csv \
|
||||
--model_id ili \
|
||||
--model ETSformer \
|
||||
--data custom \
|
||||
--features M \
|
||||
--seq_len 60 \
|
||||
--pred_len 60 \
|
||||
--e_layers 2 \
|
||||
--d_layers 2 \
|
||||
--enc_in 7 \
|
||||
--dec_in 7 \
|
||||
--c_out 7 \
|
||||
--des 'Exp' \
|
||||
--K 1 \
|
||||
--learning_rate 1e-3 \
|
||||
--itr 1
|
||||
@@ -0,0 +1,75 @@
|
||||
python -u run.py \
|
||||
--root_path ./dataset/traffic/ \
|
||||
--data_path traffic.csv \
|
||||
--model_id traffic \
|
||||
--model ETSformer \
|
||||
--data custom \
|
||||
--features M \
|
||||
--seq_len 336 \
|
||||
--pred_len 96 \
|
||||
--e_layers 2 \
|
||||
--d_layers 2 \
|
||||
--enc_in 862 \
|
||||
--dec_in 862 \
|
||||
--c_out 862 \
|
||||
--des 'Exp' \
|
||||
--K 3 \
|
||||
--learning_rate 1e-3 \
|
||||
--itr 1
|
||||
|
||||
python -u run.py \
|
||||
--root_path ./dataset/traffic/ \
|
||||
--data_path traffic.csv \
|
||||
--model_id traffic \
|
||||
--model ETSformer \
|
||||
--data custom \
|
||||
--features M \
|
||||
--seq_len 336 \
|
||||
--pred_len 192 \
|
||||
--e_layers 2 \
|
||||
--d_layers 2 \
|
||||
--enc_in 862 \
|
||||
--dec_in 862 \
|
||||
--c_out 862 \
|
||||
--des 'Exp' \
|
||||
--K 3 \
|
||||
--learning_rate 1e-3 \
|
||||
--itr 1
|
||||
|
||||
python -u run.py \
|
||||
--root_path ./dataset/traffic/ \
|
||||
--data_path traffic.csv \
|
||||
--model_id traffic \
|
||||
--model ETSformer \
|
||||
--data custom \
|
||||
--features M \
|
||||
--seq_len 336 \
|
||||
--pred_len 336 \
|
||||
--e_layers 2 \
|
||||
--d_layers 2 \
|
||||
--enc_in 862 \
|
||||
--dec_in 862 \
|
||||
--c_out 862 \
|
||||
--des 'Exp' \
|
||||
--K 3 \
|
||||
--learning_rate 1e-3 \
|
||||
--itr 1
|
||||
|
||||
python -u run.py \
|
||||
--root_path ./dataset/traffic/ \
|
||||
--data_path traffic.csv \
|
||||
--model_id traffic \
|
||||
--model ETSformer \
|
||||
--data custom \
|
||||
--features M \
|
||||
--seq_len 336 \
|
||||
--pred_len 720 \
|
||||
--e_layers 2 \
|
||||
--d_layers 2 \
|
||||
--enc_in 862 \
|
||||
--dec_in 862 \
|
||||
--c_out 862 \
|
||||
--des 'Exp' \
|
||||
--K 3 \
|
||||
--learning_rate 1e-3 \
|
||||
--itr 1
|
||||
@@ -0,0 +1,75 @@
|
||||
python -u run.py \
|
||||
--root_path ./dataset/weather/ \
|
||||
--data_path weather.csv \
|
||||
--model_id weather \
|
||||
--model ETSformer \
|
||||
--data custom \
|
||||
--features M \
|
||||
--seq_len 192 \
|
||||
--pred_len 96 \
|
||||
--e_layers 2 \
|
||||
--d_layers 2 \
|
||||
--enc_in 21 \
|
||||
--dec_in 21 \
|
||||
--c_out 21 \
|
||||
--des 'Exp' \
|
||||
--K 1 \
|
||||
--learning_rate 1e-3 \
|
||||
--itr 1
|
||||
|
||||
python -u run.py \
|
||||
--root_path ./dataset/weather/ \
|
||||
--data_path weather.csv \
|
||||
--model_id weather \
|
||||
--model ETSformer \
|
||||
--data custom \
|
||||
--features M \
|
||||
--seq_len 192 \
|
||||
--pred_len 192 \
|
||||
--e_layers 2 \
|
||||
--d_layers 2 \
|
||||
--enc_in 21 \
|
||||
--dec_in 21 \
|
||||
--c_out 21 \
|
||||
--des 'Exp' \
|
||||
--K 1 \
|
||||
--learning_rate 1e-3 \
|
||||
--itr 1
|
||||
|
||||
python -u run.py \
|
||||
--root_path ./dataset/weather/ \
|
||||
--data_path weather.csv \
|
||||
--model_id weather \
|
||||
--model ETSformer \
|
||||
--data custom \
|
||||
--features M \
|
||||
--seq_len 720 \
|
||||
--pred_len 336 \
|
||||
--e_layers 2 \
|
||||
--d_layers 2 \
|
||||
--enc_in 21 \
|
||||
--dec_in 21 \
|
||||
--c_out 21 \
|
||||
--des 'Exp' \
|
||||
--K 3 \
|
||||
--learning_rate 3e-4 \
|
||||
--itr 1
|
||||
|
||||
python -u run.py \
|
||||
--root_path ./dataset/weather/ \
|
||||
--data_path weather.csv \
|
||||
--model_id weather \
|
||||
--model ETSformer \
|
||||
--data custom \
|
||||
--features M \
|
||||
--seq_len 720 \
|
||||
--pred_len 720 \
|
||||
--e_layers 2 \
|
||||
--d_layers 2 \
|
||||
--enc_in 21 \
|
||||
--dec_in 21 \
|
||||
--c_out 21 \
|
||||
--des 'Exp' \
|
||||
--K 3 \
|
||||
--learning_rate 3e-4 \
|
||||
--itr 1
|
||||
@@ -0,0 +1,171 @@
|
||||
for lr in 1e-5 3e-5 1e-4 3e-4 1e-3; do
|
||||
for k in 0 1 2 3; do
|
||||
for pl in 96 192 336 720; do
|
||||
for sl in 96 192 336 720; do
|
||||
# ETTm2
|
||||
python -u run.py \
|
||||
--root_path ./dataset/ETT-small/ \
|
||||
--data_path ETTm2.csv \
|
||||
--model_id ETTm2 \
|
||||
--model ETSformer \
|
||||
--data ETTm2 \
|
||||
--features M \
|
||||
--seq_len ${sl} \
|
||||
--pred_len ${pl} \
|
||||
--e_layers 2 \
|
||||
--d_layers 2 \
|
||||
--enc_in 7 \
|
||||
--dec_in 7 \
|
||||
--c_out 7 \
|
||||
--des 'Exp' \
|
||||
--K ${k} \
|
||||
--learning_rate ${lr} \
|
||||
--itr 3
|
||||
|
||||
# ETTm2 univar
|
||||
python -u run.py \
|
||||
--root_path ./dataset/ETT-small/ \
|
||||
--data_path ETTm2.csv \
|
||||
--model_id ETTm2 \
|
||||
--model ETSformer \
|
||||
--data ETTm2 \
|
||||
--features S \
|
||||
--seq_len ${sl} \
|
||||
--pred_len ${pl} \
|
||||
--e_layers 2 \
|
||||
--d_layers 2 \
|
||||
--enc_in 1 \
|
||||
--dec_in 1 \
|
||||
--c_out 1 \
|
||||
--des 'Exp' \
|
||||
--K ${k} \
|
||||
--learning_rate ${lr} \
|
||||
--itr 3
|
||||
|
||||
# ECL
|
||||
python -u run.py \
|
||||
--root_path ./dataset/electricity/ \
|
||||
--data_path electricity.csv \
|
||||
--model_id ECL \
|
||||
--model ETSformer \
|
||||
--data custom \
|
||||
--features M \
|
||||
--seq_len ${sl} \
|
||||
--pred_len ${pl} \
|
||||
--e_layers 2 \
|
||||
--d_layers 2 \
|
||||
--enc_in 321 \
|
||||
--dec_in 321 \
|
||||
--c_out 321 \
|
||||
--des 'Exp' \
|
||||
--K ${k} \
|
||||
--learning_rate ${lr} \
|
||||
--itr 3
|
||||
|
||||
# Traffic
|
||||
python -u run.py \
|
||||
--root_path ./dataset/traffic/ \
|
||||
--data_path traffic.csv \
|
||||
--model_id traffic \
|
||||
--model ETSformer \
|
||||
--data custom \
|
||||
--features M \
|
||||
--seq_len ${sl} \
|
||||
--pred_len ${pl} \
|
||||
--e_layers 2 \
|
||||
--d_layers 2 \
|
||||
--enc_in 862 \
|
||||
--dec_in 862 \
|
||||
--c_out 862 \
|
||||
--des 'Exp' \
|
||||
--K ${k} \
|
||||
--learning_rate ${lr} \
|
||||
--itr 3
|
||||
|
||||
# Weather
|
||||
python -u run.py \
|
||||
--root_path ./dataset/weather/ \
|
||||
--data_path weather.csv \
|
||||
--model_id weather \
|
||||
--model ETSformer \
|
||||
--data custom \
|
||||
--features M \
|
||||
--seq_len ${sl} \
|
||||
--pred_len ${pl} \
|
||||
--e_layers 2 \
|
||||
--d_layers 2 \
|
||||
--enc_in 21 \
|
||||
--dec_in 21 \
|
||||
--c_out 21 \
|
||||
--des 'Exp' \
|
||||
--K ${k} \
|
||||
--learning_rate ${lr} \
|
||||
--itr 3
|
||||
|
||||
# Exchange
|
||||
python -u run.py \
|
||||
--root_path ./dataset/exchange_rate/ \
|
||||
--data_path exchange_rate.csv \
|
||||
--model_id Exchange \
|
||||
--model ETSformer \
|
||||
--data custom \
|
||||
--features M \
|
||||
--seq_len ${sl} \
|
||||
--pred_len ${pl} \
|
||||
--e_layers 2 \
|
||||
--d_layers 2 \
|
||||
--enc_in 8 \
|
||||
--dec_in 8 \
|
||||
--c_out 8 \
|
||||
--des 'Exp' \
|
||||
--K ${k} \
|
||||
--learning_rate ${lr} \
|
||||
--itr 3
|
||||
|
||||
# Exchange univar
|
||||
python -u run.py \
|
||||
--root_path ./dataset/exchange_rate/ \
|
||||
--data_path exchange_rate.csv \
|
||||
--model_id Exchange \
|
||||
--model ETSformer \
|
||||
--data custom \
|
||||
--features S \
|
||||
--seq_len ${sl} \
|
||||
--pred_len ${pl} \
|
||||
--e_layers 2 \
|
||||
--d_layers 2 \
|
||||
--enc_in 1 \
|
||||
--dec_in 1 \
|
||||
--c_out 1 \
|
||||
--des 'Exp' \
|
||||
--K ${k} \
|
||||
--learning_rate ${lr} \
|
||||
--itr 3
|
||||
done
|
||||
done
|
||||
|
||||
# ILI
|
||||
for pl in 24 36 48 60; do
|
||||
for sl in 24 36 48 60; do
|
||||
python -u run.py \
|
||||
--root_path ./dataset/illness/ \
|
||||
--data_path national_illness.csv \
|
||||
--model_id ili \
|
||||
--model ETSformer \
|
||||
--data custom \
|
||||
--features M \
|
||||
--seq_len ${sl} \
|
||||
--pred_len ${pl} \
|
||||
--e_layers 2 \
|
||||
--d_layers 2 \
|
||||
--enc_in 7 \
|
||||
--dec_in 7 \
|
||||
--c_out 7 \
|
||||
--des 'Exp' \
|
||||
--K ${k} \
|
||||
--learning_rate ${lr} \
|
||||
--itr 3
|
||||
done
|
||||
done
|
||||
done
|
||||
done
|
||||
+163
@@ -0,0 +1,163 @@
|
||||
import math
|
||||
import torch
|
||||
from torch import Tensor
|
||||
from typing import List, Optional
|
||||
from torch.optim.optimizer import Optimizer
|
||||
|
||||
|
||||
def adam(params: List[Tensor],
|
||||
grads: List[Tensor],
|
||||
exp_avgs: List[Tensor],
|
||||
exp_avg_sqs: List[Tensor],
|
||||
max_exp_avg_sqs: List[Tensor],
|
||||
state_steps: List[int],
|
||||
*,
|
||||
amsgrad: bool,
|
||||
beta1: float,
|
||||
beta2: float,
|
||||
lr: float,
|
||||
weight_decay: float,
|
||||
eps: float):
|
||||
r"""Functional API that performs Adam algorithm computation.
|
||||
See :class:`~torch.optim.Adam` for details.
|
||||
"""
|
||||
|
||||
for i, param in enumerate(params):
|
||||
|
||||
grad = grads[i]
|
||||
exp_avg = exp_avgs[i]
|
||||
exp_avg_sq = exp_avg_sqs[i]
|
||||
step = state_steps[i]
|
||||
|
||||
bias_correction1 = 1 - beta1 ** step
|
||||
bias_correction2 = 1 - beta2 ** step
|
||||
|
||||
if weight_decay != 0:
|
||||
grad = grad.add(param, alpha=weight_decay)
|
||||
|
||||
# Decay the first and second moment running average coefficient
|
||||
exp_avg.mul_(beta1).add_(grad, alpha=1 - beta1)
|
||||
exp_avg_sq.mul_(beta2).addcmul_(grad, grad.conj(), value=1 - beta2)
|
||||
if amsgrad:
|
||||
# Maintains the maximum of all 2nd moment running avg. till now
|
||||
torch.maximum(max_exp_avg_sqs[i], exp_avg_sq, out=max_exp_avg_sqs[i])
|
||||
# Use the max. for normalizing running avg. of gradient
|
||||
denom = (max_exp_avg_sqs[i].sqrt() / math.sqrt(bias_correction2)).add_(eps)
|
||||
else:
|
||||
denom = (exp_avg_sq.sqrt() / math.sqrt(bias_correction2)).add_(eps)
|
||||
|
||||
step_size = lr / bias_correction1
|
||||
|
||||
param.addcdiv_(exp_avg, denom, value=-step_size)
|
||||
|
||||
|
||||
class Adam(Optimizer):
|
||||
r"""Implements Adam algorithm.
|
||||
It has been proposed in `Adam: A Method for Stochastic Optimization`_.
|
||||
The implementation of the L2 penalty follows changes proposed in
|
||||
`Decoupled Weight Decay Regularization`_.
|
||||
Args:
|
||||
params (iterable): iterable of parameters to optimize or dicts defining
|
||||
parameter groups
|
||||
lr (float, optional): learning rate (default: 1e-3)
|
||||
betas (Tuple[float, float], optional): coefficients used for computing
|
||||
running averages of gradient and its square (default: (0.9, 0.999))
|
||||
eps (float, optional): term added to the denominator to improve
|
||||
numerical stability (default: 1e-8)
|
||||
weight_decay (float, optional): weight decay (L2 penalty) (default: 0)
|
||||
amsgrad (boolean, optional): whether to use the AMSGrad variant of this
|
||||
algorithm from the paper `On the Convergence of Adam and Beyond`_
|
||||
(default: False)
|
||||
.. _Adam\: A Method for Stochastic Optimization:
|
||||
https://arxiv.org/abs/1412.6980
|
||||
.. _Decoupled Weight Decay Regularization:
|
||||
https://arxiv.org/abs/1711.05101
|
||||
.. _On the Convergence of Adam and Beyond:
|
||||
https://openreview.net/forum?id=ryQu7f-RZ
|
||||
"""
|
||||
|
||||
def __init__(self, params, lr=1e-3, betas=(0.9, 0.999), eps=1e-8,
|
||||
weight_decay=0, amsgrad=False):
|
||||
if not 0.0 <= lr:
|
||||
raise ValueError("Invalid learning rate: {}".format(lr))
|
||||
if not 0.0 <= eps:
|
||||
raise ValueError("Invalid epsilon value: {}".format(eps))
|
||||
if not 0.0 <= betas[0] < 1.0:
|
||||
raise ValueError("Invalid beta parameter at index 0: {}".format(betas[0]))
|
||||
if not 0.0 <= betas[1] < 1.0:
|
||||
raise ValueError("Invalid beta parameter at index 1: {}".format(betas[1]))
|
||||
if not 0.0 <= weight_decay:
|
||||
raise ValueError("Invalid weight_decay value: {}".format(weight_decay))
|
||||
defaults = dict(lr=lr, betas=betas, eps=eps,
|
||||
weight_decay=weight_decay, amsgrad=amsgrad)
|
||||
super(Adam, self).__init__(params, defaults)
|
||||
|
||||
def __setstate__(self, state):
|
||||
super(Adam, self).__setstate__(state)
|
||||
for group in self.param_groups:
|
||||
group.setdefault('amsgrad', False)
|
||||
|
||||
@torch.no_grad()
|
||||
def step(self, closure=None):
|
||||
"""Performs a single optimization step.
|
||||
Args:
|
||||
closure (callable, optional): A closure that reevaluates the model
|
||||
and returns the loss.
|
||||
"""
|
||||
loss = None
|
||||
if closure is not None:
|
||||
with torch.enable_grad():
|
||||
loss = closure()
|
||||
|
||||
for group in self.param_groups:
|
||||
params_with_grad = []
|
||||
grads = []
|
||||
exp_avgs = []
|
||||
exp_avg_sqs = []
|
||||
max_exp_avg_sqs = []
|
||||
state_steps = []
|
||||
beta1, beta2 = group['betas']
|
||||
|
||||
for p in group['params']:
|
||||
if p.grad is not None:
|
||||
params_with_grad.append(p)
|
||||
if p.grad.is_sparse:
|
||||
raise RuntimeError('Adam does not support sparse gradients, please consider SparseAdam instead')
|
||||
grads.append(p.grad)
|
||||
|
||||
state = self.state[p]
|
||||
# Lazy state initialization
|
||||
if len(state) == 0:
|
||||
state['step'] = 0
|
||||
# Exponential moving average of gradient values
|
||||
state['exp_avg'] = torch.zeros_like(p, memory_format=torch.preserve_format)
|
||||
# Exponential moving average of squared gradient values
|
||||
state['exp_avg_sq'] = torch.zeros_like(p, memory_format=torch.preserve_format)
|
||||
if group['amsgrad']:
|
||||
# Maintains max of all exp. moving avg. of sq. grad. values
|
||||
state['max_exp_avg_sq'] = torch.zeros_like(p, memory_format=torch.preserve_format)
|
||||
|
||||
exp_avgs.append(state['exp_avg'])
|
||||
exp_avg_sqs.append(state['exp_avg_sq'])
|
||||
|
||||
if group['amsgrad']:
|
||||
max_exp_avg_sqs.append(state['max_exp_avg_sq'])
|
||||
|
||||
# update the steps for each param group update
|
||||
state['step'] += 1
|
||||
# record the step after step update
|
||||
state_steps.append(state['step'])
|
||||
|
||||
adam(params_with_grad,
|
||||
grads,
|
||||
exp_avgs,
|
||||
exp_avg_sqs,
|
||||
max_exp_avg_sqs,
|
||||
state_steps,
|
||||
amsgrad=group['amsgrad'],
|
||||
beta1=beta1,
|
||||
beta2=beta2,
|
||||
lr=group['lr'],
|
||||
weight_decay=group['weight_decay'],
|
||||
eps=group['eps'])
|
||||
return loss
|
||||
@@ -0,0 +1,26 @@
|
||||
import torch
|
||||
|
||||
|
||||
class TriangularCausalMask():
|
||||
def __init__(self, B, L, device="cpu"):
|
||||
mask_shape = [B, 1, L, L]
|
||||
with torch.no_grad():
|
||||
self._mask = torch.triu(torch.ones(mask_shape, dtype=torch.bool), diagonal=1).to(device)
|
||||
|
||||
@property
|
||||
def mask(self):
|
||||
return self._mask
|
||||
|
||||
|
||||
class ProbMask():
|
||||
def __init__(self, B, H, L, index, scores, device="cpu"):
|
||||
_mask = torch.ones(L, scores.shape[-1], dtype=torch.bool).to(device).triu(1)
|
||||
_mask_ex = _mask[None, None, :].expand(B, H, L, scores.shape[-1])
|
||||
indicator = _mask_ex[torch.arange(B)[:, None, None],
|
||||
torch.arange(H)[None, :, None],
|
||||
index, :].to(device)
|
||||
self._mask = indicator.view(scores.shape).to(device)
|
||||
|
||||
@property
|
||||
def mask(self):
|
||||
return self._mask
|
||||
@@ -0,0 +1,41 @@
|
||||
import numpy as np
|
||||
|
||||
|
||||
def RSE(pred, true):
|
||||
return np.sqrt(np.sum((true - pred) ** 2)) / np.sqrt(np.sum((true - true.mean()) ** 2))
|
||||
|
||||
|
||||
def CORR(pred, true):
|
||||
u = ((true - true.mean(0)) * (pred - pred.mean(0))).sum(0)
|
||||
d = np.sqrt(((true - true.mean(0)) ** 2 * (pred - pred.mean(0)) ** 2).sum(0))
|
||||
return (u / d).mean(-1)
|
||||
|
||||
|
||||
def MAE(pred, true):
|
||||
return np.mean(np.abs(pred - true))
|
||||
|
||||
|
||||
def MSE(pred, true):
|
||||
return np.mean((pred - true) ** 2)
|
||||
|
||||
|
||||
def RMSE(pred, true):
|
||||
return np.sqrt(MSE(pred, true))
|
||||
|
||||
|
||||
def MAPE(pred, true):
|
||||
return np.mean(np.abs((pred - true) / true))
|
||||
|
||||
|
||||
def MSPE(pred, true):
|
||||
return np.mean(np.square((pred - true) / true))
|
||||
|
||||
|
||||
def metric(pred, true):
|
||||
mae = MAE(pred, true)
|
||||
mse = MSE(pred, true)
|
||||
rmse = RMSE(pred, true)
|
||||
mape = MAPE(pred, true)
|
||||
mspe = MSPE(pred, true)
|
||||
|
||||
return mae, mse, rmse, mape, mspe
|
||||
@@ -0,0 +1,134 @@
|
||||
from typing import List
|
||||
|
||||
import numpy as np
|
||||
import pandas as pd
|
||||
from pandas.tseries import offsets
|
||||
from pandas.tseries.frequencies import to_offset
|
||||
|
||||
|
||||
class TimeFeature:
|
||||
def __init__(self):
|
||||
pass
|
||||
|
||||
def __call__(self, index: pd.DatetimeIndex) -> np.ndarray:
|
||||
pass
|
||||
|
||||
def __repr__(self):
|
||||
return self.__class__.__name__ + "()"
|
||||
|
||||
|
||||
class SecondOfMinute(TimeFeature):
|
||||
"""Minute of hour encoded as value between [-0.5, 0.5]"""
|
||||
|
||||
def __call__(self, index: pd.DatetimeIndex) -> np.ndarray:
|
||||
return index.second / 59.0 - 0.5
|
||||
|
||||
|
||||
class MinuteOfHour(TimeFeature):
|
||||
"""Minute of hour encoded as value between [-0.5, 0.5]"""
|
||||
|
||||
def __call__(self, index: pd.DatetimeIndex) -> np.ndarray:
|
||||
return index.minute / 59.0 - 0.5
|
||||
|
||||
|
||||
class HourOfDay(TimeFeature):
|
||||
"""Hour of day encoded as value between [-0.5, 0.5]"""
|
||||
|
||||
def __call__(self, index: pd.DatetimeIndex) -> np.ndarray:
|
||||
return index.hour / 23.0 - 0.5
|
||||
|
||||
|
||||
class DayOfWeek(TimeFeature):
|
||||
"""Hour of day encoded as value between [-0.5, 0.5]"""
|
||||
|
||||
def __call__(self, index: pd.DatetimeIndex) -> np.ndarray:
|
||||
return index.dayofweek / 6.0 - 0.5
|
||||
|
||||
|
||||
class DayOfMonth(TimeFeature):
|
||||
"""Day of month encoded as value between [-0.5, 0.5]"""
|
||||
|
||||
def __call__(self, index: pd.DatetimeIndex) -> np.ndarray:
|
||||
return (index.day - 1) / 30.0 - 0.5
|
||||
|
||||
|
||||
class DayOfYear(TimeFeature):
|
||||
"""Day of year encoded as value between [-0.5, 0.5]"""
|
||||
|
||||
def __call__(self, index: pd.DatetimeIndex) -> np.ndarray:
|
||||
return (index.dayofyear - 1) / 365.0 - 0.5
|
||||
|
||||
|
||||
class MonthOfYear(TimeFeature):
|
||||
"""Month of year encoded as value between [-0.5, 0.5]"""
|
||||
|
||||
def __call__(self, index: pd.DatetimeIndex) -> np.ndarray:
|
||||
return (index.month - 1) / 11.0 - 0.5
|
||||
|
||||
|
||||
class WeekOfYear(TimeFeature):
|
||||
"""Week of year encoded as value between [-0.5, 0.5]"""
|
||||
|
||||
def __call__(self, index: pd.DatetimeIndex) -> np.ndarray:
|
||||
return (index.isocalendar().week - 1) / 52.0 - 0.5
|
||||
|
||||
|
||||
def time_features_from_frequency_str(freq_str: str) -> List[TimeFeature]:
|
||||
"""
|
||||
Returns a list of time features that will be appropriate for the given frequency string.
|
||||
Parameters
|
||||
----------
|
||||
freq_str
|
||||
Frequency string of the form [multiple][granularity] such as "12H", "5min", "1D" etc.
|
||||
"""
|
||||
|
||||
features_by_offsets = {
|
||||
offsets.YearEnd: [],
|
||||
offsets.QuarterEnd: [MonthOfYear],
|
||||
offsets.MonthEnd: [MonthOfYear],
|
||||
offsets.Week: [DayOfMonth, WeekOfYear],
|
||||
offsets.Day: [DayOfWeek, DayOfMonth, DayOfYear],
|
||||
offsets.BusinessDay: [DayOfWeek, DayOfMonth, DayOfYear],
|
||||
offsets.Hour: [HourOfDay, DayOfWeek, DayOfMonth, DayOfYear],
|
||||
offsets.Minute: [
|
||||
MinuteOfHour,
|
||||
HourOfDay,
|
||||
DayOfWeek,
|
||||
DayOfMonth,
|
||||
DayOfYear,
|
||||
],
|
||||
offsets.Second: [
|
||||
SecondOfMinute,
|
||||
MinuteOfHour,
|
||||
HourOfDay,
|
||||
DayOfWeek,
|
||||
DayOfMonth,
|
||||
DayOfYear,
|
||||
],
|
||||
}
|
||||
|
||||
offset = to_offset(freq_str)
|
||||
|
||||
for offset_type, feature_classes in features_by_offsets.items():
|
||||
if isinstance(offset, offset_type):
|
||||
return [cls() for cls in feature_classes]
|
||||
|
||||
supported_freq_msg = f"""
|
||||
Unsupported frequency {freq_str}
|
||||
The following frequencies are supported:
|
||||
Y - yearly
|
||||
alias: A
|
||||
M - monthly
|
||||
W - weekly
|
||||
D - daily
|
||||
B - business days
|
||||
H - hourly
|
||||
T - minutely
|
||||
alias: min
|
||||
S - secondly
|
||||
"""
|
||||
raise RuntimeError(supported_freq_msg)
|
||||
|
||||
|
||||
def time_features(dates, freq='h'):
|
||||
return np.vstack([feat(dates) for feat in time_features_from_frequency_str(freq)])
|
||||
+112
@@ -0,0 +1,112 @@
|
||||
import numpy as np
|
||||
import torch
|
||||
import matplotlib.pyplot as plt
|
||||
import math
|
||||
|
||||
plt.switch_backend('agg')
|
||||
|
||||
|
||||
def adjust_learning_rate(optimizer, epoch, args):
|
||||
for param_group in optimizer.param_groups:
|
||||
if param_group['name'] == 'smoothing':
|
||||
continue
|
||||
elif param_group['name'] == 'damping':
|
||||
continue
|
||||
else:
|
||||
learning_rate = args.learning_rate
|
||||
|
||||
if args.lradj == 'exponential':
|
||||
lr_adjust = {epoch: learning_rate * (0.5 ** ((epoch - 1) // 1))}
|
||||
elif args.lradj == 'schedule':
|
||||
lr_adjust = {
|
||||
2: 5e-5, 4: 1e-5, 6: 5e-6, 8: 1e-6,
|
||||
10: 5e-7, 15: 1e-7, 20: 5e-8
|
||||
}
|
||||
elif args.lradj == 'cos':
|
||||
lr_adjust = {epoch: learning_rate * 0.5 * (1. + math.cos(math.pi * epoch / args.train_epochs))}
|
||||
elif args.lradj == 'cos_with_warmup':
|
||||
if epoch <= args.warmup_epochs:
|
||||
lr = args.min_lr + (learning_rate - args.min_lr) * (epoch / (args.warmup_epochs + 1))
|
||||
else:
|
||||
curr_epoch = epoch - args.warmup_epochs
|
||||
total_epochs = args.train_epochs - args.warmup_epochs
|
||||
lr = learning_rate * 0.5 * (1. + math.cos(math.pi * curr_epoch / total_epochs))
|
||||
lr_adjust = {epoch: lr}
|
||||
elif args.lradj == 'exponential_with_warmup':
|
||||
if epoch <= args.warmup_epochs:
|
||||
lr = args.min_lr + (learning_rate - args.min_lr) * (epoch / (args.warmup_epochs + 1))
|
||||
else:
|
||||
curr_epoch = epoch - args.warmup_epochs
|
||||
lr = learning_rate * (0.5 ** ((curr_epoch - 1) // 1))
|
||||
lr_adjust = {epoch: lr}
|
||||
else:
|
||||
raise NotImplementedError
|
||||
|
||||
if epoch in lr_adjust.keys():
|
||||
lr = lr_adjust[epoch]
|
||||
for param_group in optimizer.param_groups:
|
||||
param_group['lr'] = lr
|
||||
print('Updating learning rate to {}'.format(lr))
|
||||
|
||||
|
||||
class EarlyStopping:
|
||||
def __init__(self, patience=7, verbose=False, delta=0):
|
||||
self.patience = patience
|
||||
self.verbose = verbose
|
||||
self.counter = 0
|
||||
self.best_score = None
|
||||
self.early_stop = False
|
||||
self.val_loss_min = np.Inf
|
||||
self.delta = delta
|
||||
|
||||
def __call__(self, val_loss, model, path):
|
||||
score = -val_loss
|
||||
if self.best_score is None:
|
||||
self.best_score = score
|
||||
self.save_checkpoint(val_loss, model, path)
|
||||
elif score < self.best_score + self.delta:
|
||||
self.counter += 1
|
||||
print(f'EarlyStopping counter: {self.counter} out of {self.patience}')
|
||||
if self.counter >= self.patience:
|
||||
self.early_stop = True
|
||||
else:
|
||||
self.best_score = score
|
||||
self.save_checkpoint(val_loss, model, path)
|
||||
self.counter = 0
|
||||
|
||||
def save_checkpoint(self, val_loss, model, path):
|
||||
if self.verbose:
|
||||
print(f'Validation loss decreased ({self.val_loss_min:.6f} --> {val_loss:.6f}). Saving model ...')
|
||||
torch.save(model.state_dict(), path + '/' + 'checkpoint.pth')
|
||||
self.val_loss_min = val_loss
|
||||
|
||||
|
||||
class dotdict(dict):
|
||||
"""dot.notation access to dictionary attributes"""
|
||||
__getattr__ = dict.get
|
||||
__setattr__ = dict.__setitem__
|
||||
__delattr__ = dict.__delitem__
|
||||
|
||||
|
||||
class StandardScaler():
|
||||
def __init__(self, mean, std):
|
||||
self.mean = mean
|
||||
self.std = std
|
||||
|
||||
def transform(self, data):
|
||||
return (data - self.mean) / self.std
|
||||
|
||||
def inverse_transform(self, data):
|
||||
return (data * self.std) + self.mean
|
||||
|
||||
|
||||
def visual(true, preds=None, name='./pic/test.pdf'):
|
||||
"""
|
||||
Results visualization
|
||||
"""
|
||||
plt.figure()
|
||||
plt.plot(true, label='GroundTruth', linewidth=2)
|
||||
if preds is not None:
|
||||
plt.plot(preds, label='Prediction', linewidth=2)
|
||||
plt.legend()
|
||||
plt.savefig(name, bbox_inches='tight')
|
||||
Reference in New Issue
Block a user